一、在项目中使用添加一个案例使用AutoMapper
1、在接口 IBlogArticleServices.cs和 类BlogArticleServices.cs中,添加GetBlogDetails()方法,返回类型是BlogViewModels
请看这两个类
/// <summary> /// 博客文章实体类 /// </summary> public class BlogArticle { /// <summary> /// /// </summary> public int bID { get; set; } /// <summary> /// 创建人 /// </summary> public string bsubmitter { get; set; } /// <summary> /// 博客标题 /// </summary> public string btitle { get; set; } /// <summary> /// 类别 /// </summary> public string bcategory { get; set; } /// <summary> /// 内容 /// </summary> public string bcontent { get; set; } /// <summary> /// 访问量 /// </summary> public int btraffic { get; set; } /// <summary> /// 评论数量 /// </summary> public int bcommentNum { get; set; } /// <summary> /// 修改时间 /// </summary> public DateTime bUpdateTime { get; set; } /// <summary> /// 创建时间 /// </summary> public System.DateTime bCreateTime { get; set; } /// <summary> /// 备注 /// </summary> public string bRemark { get; set; } } ------------------------------------------------- /// <summary> /// 博客信息展示类 /// </summary> public class BlogViewModels { /// <summary> /// /// </summary> public int bID { get; set; } /// <summary>/// 创建人 /// </summary> public string bsubmitter { get; set; } /// <summary>/// 博客标题 /// </summary> public string btitle { get; set; } /// <summary>/// 摘要 /// </summary> public string digest { get; set; } /// <summary> /// 上一篇 /// </summary> public string previous { get; set; } /// <summary> /// 上一篇id /// </summary> public int previousID { get; set; } /// <summary> /// 下一篇 /// </summary> public string next { get; set; } /// <summary> /// 下一篇id /// </summary> public int nextID { get; set; } /// <summary>/// 类别 /// </summary> public string bcategory { get; set; } /// <summary>/// 内容 /// </summary> public string bcontent { get; set; } /// <summary> /// 访问量 /// </summary> public int btraffic { get; set; } /// <summary> /// 评论数量 /// </summary> public int bcommentNum { get; set; } /// <summary>/// 修改时间 /// </summary> public DateTime bUpdateTime { get; set; } /// <summary> /// 创建时间 /// </summary> public System.DateTime bCreateTime { get; set; } /// <summary>/// 备注 /// </summary> public string bRemark { get; set; } }
两个实体类字段还基本可以,不是很多,但是我曾经开发一个旅游网站的系统,有一个表字段都高达30多个,当然还有更多的,额,如果我们一个个赋值是这样的
BlogViewModels models = new BlogViewModels() { bsubmitter=blogArticle.bsubmitter, btitle = blogArticle.btitle, bcategory = blogArticle.bcategory, bcontent = blogArticle.bcontent, btraffic = blogArticle.btraffic, bcommentNum = blogArticle.bcommentNum, bUpdateTime = blogArticle.bUpdateTime, bCreateTime = blogArticle.bCreateTime, bRemark = blogArticle.bRemark, };
所以这个方法的全部代码是:
接口层也要添加:
public interface IBlogArticleServices :IBaseServices<BlogArticle> { Task<List<BlogArticle>> getBlogs(); Task<BlogViewModels> getBlogDetails(int id); }
image
/// <summary> /// 获取视图博客详情信息 /// </summary> /// <param name="id"></param> /// <returns></returns> public async Task<BlogViewModels> getBlogDetails(int id) { var bloglist = await dal.Query(a => a.bID > 0, a => a.bID); var idmin = bloglist.FirstOrDefault() != null ? bloglist.FirstOrDefault().bID : 0; var idmax = bloglist.LastOrDefault() != null ? bloglist.LastOrDefault().bID : 1; var idminshow = id; var idmaxshow = id; BlogArticle blogArticle = new BlogArticle(); blogArticle = (await dal.Query(a => a.bID == idminshow)).FirstOrDefault(); BlogArticle prevblog = new BlogArticle(); while (idminshow > idmin) { idminshow--; prevblog = (await dal.Query(a => a.bID == idminshow)).FirstOrDefault(); if (prevblog != null) { break; } } BlogArticle nextblog = new BlogArticle(); while (idmaxshow < idmax) { idmaxshow++; nextblog = (await dal.Query(a => a.bID == idmaxshow)).FirstOrDefault(); if (nextblog != null) { break; } } blogArticle.btraffic += 1; await dal.Update(blogArticle, new List<string> { "btraffic" }); BlogViewModels models = new BlogViewModels() { bsubmitter=blogArticle.bsubmitter, btitle = blogArticle.btitle, bcategory = blogArticle.bcategory, bcontent = blogArticle.bcontent, btraffic = blogArticle.btraffic, bcommentNum = blogArticle.bcommentNum, bUpdateTime = blogArticle.bUpdateTime, bCreateTime = blogArticle.bCreateTime, bRemark = blogArticle.bRemark, }; if (nextblog != null) { models.next = nextblog.btitle; models.nextID = nextblog.bID; } if (prevblog != null) { models.previous = prevblog.btitle; models.previousID = prevblog.bID; } return models; }
想了想这才是一个方法,一般的系统都会有少则几十,多则上百个这样的方法,这还不算,大家肯定遇到过一个情况,如果有一天要在页面多显示一个字段,噗!不是吧,首先要存在数据库,然后在该实体类就应该多一个,然后再在每一个赋值的地方增加一个,而且也没有更好的办法不是,一不小心就少了一个,然后被产品测试说咱们不细心,心塞哟,别慌!神器来了,一招搞定。
2、先来引入DTO讲解,以及它的原理
在学习EF的时候我们知道了ORM(Object Relational Mapping)映射,是一种对象关系的映射,对象-关系映射(ORM)系统一般以中间件的形式存在,主要实现程序对象到关系数据库数据的映射。
而Automapper是一种实体转换关系的模型,AutoMapper是一个.NET的对象映射工具。主要作用是进行领域对象与模型(DTO)之间的转换、数据库查询结果映射至实体对象。
下边的是基本原理,大家喵一眼就行:
Ø 什么是DTO?
数据传输对象(DTO)(DataTransfer Object),是一种设计模式之间传输数据的软件应用系统。数据传输目标往往是数据访问对象从而从数据库中检索数据。数据传输对象与数据交互对象或数据访问对象之间的差异是一个以不具有任何行为除了存储和检索的数据(访问和存取器)。Ø 为什么用?
它的目的只是为了对领域对象进行数据封装,实现层与层之间的数据传递。为何不能直接将领域对象用于数据传递?因为领域对象更注重领域,而DTO更注重数据。不仅如此,由于“富领域模型”的特点,这样做会直接将领域对象的行为暴露给表现层。需要了解的是,数据传输对象DTO本身并不是业务对象。数据传输对象是根据UI的需求进行设计的,而不是根据领域对象进行设计的。比如,Customer领域对象可能会包含一些诸如FirstName, LastName, Email, Address等信息。但如果UI上不打算显示Address的信息,那么CustomerDTO中也无需包含这个 Address的数据”。
Ø 什么是领域对象?
领域模型就是面向对象的,面向对象的一个很重要的点就是:“把事情交给最适合的类去做”,即:“你得在一个个领域类之间跳转,才能找出他们如何交互”。在我们的系统中Model(EF中的实体)就是领域模型对象。领域对象主要是面对业务的,我们是通过业务来定义Model的。
以上的这些大家简单看看原理即可,意思大家肯定都懂,下边开始讲解如何使用
3、在Blog.Core.Services项目中引用Nuget包,AutoMapper 和 AutoMapper.Extensions.Microsoft.DependencyInjection
AutoMapper.Extensions.Microsoft.DependencyInjection,这个是用来配合依赖注入的,看名字也能看的出来吧,大家回忆下,整个项目中,都是使用的依赖注入,所以尽量不要用new 来实例化,导致层耦合。
4、基于上边原理,在接口层Blog.Core 中,添加文件夹AutoMapper,然后添加映射配置文件 CustomProfile.cs,用来匹配所有的映射对象关系
public class CustomProfile : Profile { /// <summary> /// 配置构造函数,用来创建关系映射 /// </summary> public CustomProfile() { CreateMap<BlogArticle, BlogViewModels>(); } }
大家看下F12这个CreateMap方法
public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>();
第一个参数是原对象,第二个是目的对象,所以,要想好,是哪个方向转哪个,当然可以都写上,比如
CreateMap<BlogArticle, BlogViewModels>();
CreateMap<BlogViewModels, BlogArticle>();
5、修改上边服务层BlogArticleServices.cs 中getBlogDetails 方法中的赋值,改用AutoMapper,并用构造函数注入
最终的代码是
IBlogArticleRepository dal; IMapper IMapper; public BlogArticleServices(IBlogArticleRepository dal, IMapper IMapper) { this.dal = dal; base.baseDal = dal; this.IMapper = IMapper; } public async Task<BlogViewModels> getBlogDetails(int id) { var bloglist = await dal.Query(a => a.bID > 0, a => a.bID); var idmin = bloglist.FirstOrDefault() != null ? bloglist.FirstOrDefault().bID : 0; var idmax = bloglist.LastOrDefault() != null ? bloglist.LastOrDefault().bID : 1; var idminshow = id; var idmaxshow = id; BlogArticle blogArticle = new BlogArticle(); blogArticle = (await dal.Query(a => a.bID == idminshow)).FirstOrDefault(); BlogArticle prevblog = new BlogArticle(); while (idminshow > idmin) { idminshow--; prevblog = (await dal.Query(a => a.bID == idminshow)).FirstOrDefault(); if (prevblog != null) { break; } } BlogArticle nextblog = new BlogArticle(); while (idmaxshow < idmax) { idmaxshow++; nextblog = (await dal.Query(a => a.bID == idmaxshow)).FirstOrDefault(); if (nextblog != null) { break; } } blogArticle.btraffic += 1; await dal.Update(blogArticle, new List<string> { "btraffic" }); //注意就是这里 BlogViewModels models = IMapper.Map<BlogViewModels>(blogArticle); if (nextblog != null) { models.next = nextblog.btitle; models.nextID = nextblog.bID; } if (prevblog != null) { models.previous = prevblog.btitle; models.previousID = prevblog.bID; } return models; }
6、老规矩,还是在Startup中,注入服务
services.AddAutoMapper(typeof(Startup));//这是AutoMapper的2.0新特性
7、修改BlogController.cs中的 Get(int id)方法,运行项目,断点调试,发现已经成功了,是不是很方便,你也可以反过来试一试
[HttpGet("{id}", Name = "Get")] public async Task<object> Get(int id) { var model = await blogArticleServices.getBlogDetails(id);//调用该方法 var data = new { success = true, data = model }; return data; }
image
8、好啦,DTOs就到这里了,我们的ConfigureServices也基本告一段落了,主要有这些
image
二、Blog.Core项目打包发布在IIS
1、在项目Blog.Core中,右键,发布,选择文件,相信大家都会,不会的可以联系我
image
注意: 这里有一个坑,还记得我们用swagger中使用的两个xml文件么,编译的时候有,但是.net core官方限制了在发布的时候包含xml文件,所以我们需要处理下
在项目工程文件WebApplication1.csproj中,增加
<PropertyGroup>
<GenerateDocumentationFile>true</GenerateDocumentationFile></PropertyGroup>
当然我们还可以基于CLI的Publish命令进行发布,只需切换到Light.API根目录下,输入以下命令即可:
dotnet publish --framework netcoreapp1.1 --output "E:\Publish" --configuration Release
framework表示目标框架,output表示要发布到的目录文件夹,configuration表示配置文件,等同于和上面我们通过管理器来发布的操作
具体的大家可以自行实验
2、一定要在服务器中安装.Net Core SDK (已安装则跳过):
地址:https://www.microsoft.com/net/download
在CMD命令窗口下,输入 dotnet 查看
image
3、安装WindowsHosting(已安装则跳过)
IIS安装服务器上安装DotNetCore.X.X.X-WindowsHosting安装成功后重启IIS服务器。根据版本选择下载
下载地址:https://www.microsoft.com/net/download/windows
4、安装AspNetCoreModule托管模块(已安装则跳过),
下载地址:点击我下载
image
5、应用池配置为无托管代码
(网上解释:ASP.NET Core不再是由IIS工作进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是作为反向代理的角色转发请求到Kestrel不同端口的ASP.NET Core程序中,随后就将接收到的请求推送至中间件管道中去,处理完你的请求和相关业务逻辑之后再将HTTP响应数据重新回写到IIS中,最终转达到不同的客户端(浏览器,APP,客户端等)。而配置文件和过程都会由些许调整,中间最重要的角色便是AspNetCoreModule,它是其中一个的IIS模块,请求进入到IIS之后便立即由它转发,并迅速重定向到ASP.NET Core项目中,所以这时候我们无需设置应用程序池来托管我们的代码,它只负责转发请求而已)
image
6、如果需要读写根目录权限,要更改应用池 ApplicationPoolIdentity
7、如果没有出现正常的页面,你可以打开错误日志
在发布的时候,会有一个web.config出现,通过修改web.config 启用错误日志查看详细错误信息
将stdoutLogEnabled的修改为 true,并在应用程序根目录添加 logs 文件夹
一定要手动添加logs文件,不然会不出现
image
8、只要本地能通过,常见的错误就是生成的文件不全导致的,大家可以自行看看,如果有问题,也可以大家一起解决
9、在IIS中启动项目,或者直接输入服务器IP地址,加端口调试
注意:这里有一个小问题,因为发布以后,默认启动页是在开发环境中重定向到了swagger,但是在服务器部署以后,不能跳转,大家打开后会这样,404找不到,不要怕,
只需要在后边加上Swagger就行了
作者:SAYLINING
链接:https://www.jianshu.com/p/b18fe195eb6b