从壹开始先后端分离【 .NET Core2.0/3.0 +Vue2.0 】框架之十三 || DTOs 对象映射使用,项目部署Windows+Linux完整版

本文3.0版本文章

 本文内容,和netcore2.0同样,不须要更新。
 

更新

不少小伙伴在用 IIS 发布的时候,老是会有一些问题,文章下边 #autoid-6-0-0 我也简单的动图展现了,如何 publish 到 IIS 的过程,若是你能看懂,却发现本身的项目有问题的话,能够直接down 我 published 好的项目,地址:https://github.com/anjoy8/Blog.Data.Share/blob/master/netcoreapp2.2.rar ,下载解压好后,先用 dotnet Blog.Core.dll 试试,确定能够,是5000的端口,而后再发布到你本身的 IIS 代理服务器中,看看是否能够:html

一、若是个人正常,你的还有问题,证实你的项目有问题,多半是缺乏文件;前端

二、若是个人项目都异常,那就是你服务器的环境有问题,大几率是运行时安装失败;linux

三、若是看不懂,我另外写了要给最新最全的部署文章,这篇看不懂,能够再看看这个 :《最全的部署方案 & 最丰富的错误分析
nginx

 

 

代码已上传Github+Gitee,文末有地址

番外:时间真快,今天终于到了系统打包的日子,虽然项目仍是有不少问题,虽而后边还有不少的内容要说要学,可是想着初级基本的.Net Core 用到的基本至少就这么多了(接口文档,项目框架,持久化ORM,依赖注入,AOP,分布式缓存,CORS跨域等等),中高级的,好比在Linux高级发布,Nginx代理,微服务,Dockers等等,这个在之后的更新中会慢慢提到,否则的话,Vue就一直说不到了 [哭笑哈哈],其实我还有不少要总结的,好比 Power BI系列(没用过的点击看看),好比C#7.0系列等文章,都在慢慢酝酿中,但愿能坚持下来,不过这两个系列目前还不会写到,若是有须要用或学微软PB的,能够加QQ群联系我,我在微软项目中已经用到了。仍是打算从下周一开始转战Vue的文章,固然后端也会一直穿插着,这里要说下,咱们的QQ群已经有一些小伙伴了,天天能够一块儿交流心得和问题,感受仍是很不错的,若是你有什么问题,或者其余技术上的须要讨论,我们的群是能够试试哟,我和其余小伙伴会一直在线给你们解答(咋感受像一个广告哈哈,你们随意哈)。git

  

正传:好啦,书接上文,昨天说到了《十二 || 三种跨域方式比较,DTOs(数据传输对象)初探》,由于下午时间的问题,只是讲解了四种跨域方法,没有讲解完DTO,其实这个东西很简单,说白了,就是把两个实体类进行转换,不用人工手动去一一赋值,今天呢,就简单说下常见DTO框架AutoMapper的使用,而后作一个打包处理,发布到个人windows服务器里,今天刚刚买了一个Ubuntu Linux服务器,由于若是开发.Net Core,必定会接触到Linux服务器,等各类,由于它跨域了,就是酱紫。可是尚未配置好,因此会在下边留下位置,慢慢补充在Ubuntu部署的讲解。github

 

零、今天完成右下角的深蓝色部分

 

1、在项目中使用添加一个案例使用AutoMapper

一、普通的模型映射

在接口 IBlogArticleServices.cs和 类BlogArticleServices.cs中,添加GetBlogDetails()方法,返回类型是BlogViewModelsweb

请看这两个类数据库

   /// <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多个,固然还有更多的,额,若是咱们一个个赋值是这样的json

            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,
            };    

 

因此这个方法的所有代码是:ubuntu

接口层也要添加:

   public interface IBlogArticleServices :IBaseServices<BlogArticle>
    {
        Task<List<BlogArticle>> getBlogs();
        Task<BlogViewModels> getBlogDetails(int id);
    }

 

/// <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 blogArticle = (await dal.Query(a => a.bID == id)).FirstOrDefault();
    BlogViewModels models = null;

    if (blogArticle != null)
    {
        BlogArticle prevblog;
        BlogArticle nextblog;
        int blogIndex = bloglist.FindIndex(item => item.bID == id);
        if (blogIndex >= 0)
        {
            try
            {
                // 上一篇
                prevblog = blogIndex > 0 ? (((BlogArticle)(bloglist[blogIndex - 1]))) : null;
                // 下一篇
                nextblog = blogIndex + 1 < bloglist.Count() ? (BlogArticle)(bloglist[blogIndex + 1]) : null;


 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;
                }
            }
            catch (Exception) { }
        }
        blogArticle.btraffic += 1;
        await dal.Update(blogArticle, new List<string> { "btraffic" });
    }

    return models;

}

 

 

想了想这才是一个方法,通常的系统都会有少则几十,多则上百个这样的方法,这还不算,你们确定遇到过一个状况,若是有一天要在页面多显示一个字段,噗!不是吧,首先要存在数据库,而后在该实体类就应该多一个,而后再在每个赋值的地方增长一个,并且也没有更好的办法不是,一不当心就少了一个,而后被产品测试说我们不细心,心塞哟,别慌!神器来了,一招搞定。

 

二、先来引入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的。

以上的这些你们简单看看原理便可,意思你们确定都懂,下边开始讲解如何使用

 

三、引入 AutoMapper 的相关包

在Blog.Core.Services项目中引用Nuget包,AutoMapper 和 AutoMapper.Extensions.Microsoft.DependencyInjection

AutoMapper.Extensions.Microsoft.DependencyInjection,这个是用来配合依赖注入的,看名字也能看的出来吧,你们回忆下,整个项目中,都是使用的依赖注入,因此尽可能不要用new 来实例化,致使层耦合。

 

四、添加映射文件 CustomProfile.cs

基于上边原理,在接口层Blog.Core 中,添加文件夹AutoMapper,而后添加映射配置文件 CustomProfile.cs,用来匹配全部的映射对象关系

     public class CustomProfile : Profile
    {
        /// <summary>
        /// 配置构造函数,用来建立关系映射
        /// </summary>
        public CustomProfile()
        {
            CreateMap<BlogArticle, BlogViewModels>();
        }
    }

 

下边是来自热心网友@菜工的解惑:

Profile不知有什么用,经过百度了解才了解是services.AddAutoMapper是会自动找到全部继承了Profile的类而后进行配置,

并且个人这个配置文件是在api层的,若是Profile配置类放在别的层(好比Service层),

若是没解耦的话,能够services.AddAutoMapper(),参数留空,AutoMapper会从全部引用的程序集里找继承Profile的类,若是解耦了,就得services.AddAutoMapper(Assembly.Load("Blog.Core.Service"))。

 

 

你们看下F12这个CreateMap方法:

public IMappingExpression<TSource, TDestination> CreateMap<TSource, TDestination>();

 

第一个参数是原对象,第二个是目的对象,因此,要想好,是哪一个方向转哪一个,固然能够都写上,好比

CreateMap<BlogArticle, BlogViewModels>();

CreateMap<BlogViewModels, BlogArticle>(); 

 

//若是不想一个一个的配置,能够用接口的形式,批量导入
//这是一个思路,我没有具体去写,留个坑吧

//public interface IMapperTo<TDestination>{}
//而后一样来个Profile集中处理这些interface
/// <summary>
/// 根据IMapperTo<>接口 自动初始化AutoMapper
/// </summary>
public class AutoMapperProfile : Profile
{
    public override string ProfileName
    {
        get
        {
            return "AutoForIMapperTo";
        }
    }

    protected override void Configure()
    {
        base.Configure();

        typeof(SaveBuyerDemandRequest).Assembly.GetTypes()//SaveBuyerDemandRequest是TSource同属的Assembly底下的任意类,要包含多个Aeembly的话本身扩展咯
            .Where(i => i.GetInterfaces().Any(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IMapperTo<>)))
            .ToList().ForEach(item =>
            {
                item.GetInterfaces()
                    .Where(t => t.IsGenericType && t.GetGenericTypeDefinition() == typeof(IMapperTo<>))
                    .ToList()//这里能够支持多个IMapperTo
                    .ForEach(i => {
                        var t2 = i.GetGenericArguments()[0];
                        Mapper.CreateMap(item, t2);
                        Mapper.CreateMap(t2, item);
                    });
            });
    }
}

//Class For Example
public class SaveBuyerDemandRequest : IMapperTo<BuyerDemandEntity>
{

}

 

 

 

五、使用AutoMapper实现模型映射,并注入

 

老规矩,仍是在Startup中,注入服务

services.AddAutoMapper(typeof(Startup));//这是AutoMapper的2.0新特性

 

修改上边服务层BlogArticleServices.cs 中getBlogDetails 方法中的赋值,改用AutoMapper,并用构造函数注入

最终的代码是:

 // 依赖注入 
 IBlogArticleRepository dal;
 IMapper IMapper;
 public BlogArticleServices(IBlogArticleRepository dal, IMapper IMapper)
 {
     this.dal = dal;
     base.baseDal = dal;
     this.IMapper = IMapper;
 }
 /// <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 blogArticle = (await dal.Query(a => a.bID == id)).FirstOrDefault();
            BlogViewModels models = null;

            if (blogArticle != null)
            {
                BlogArticle prevblog;
                BlogArticle nextblog;
                int blogIndex = bloglist.FindIndex(item => item.bID == id);
                if (blogIndex >= 0)
                {
                    try
                    {
                        // 上一篇
                        prevblog = blogIndex > 0 ? (((BlogArticle)(bloglist[blogIndex - 1]))) : null;
                        // 下一篇
                        nextblog = blogIndex + 1 < bloglist.Count() ? (BlogArticle)(bloglist[blogIndex + 1]) : null;

                        // 注意就是这里,mapper
                        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;
                        }
                    }
                    catch (Exception) { }
                }
                blogArticle.btraffic += 1;
                await dal.Update(blogArticle, new List<string> { "btraffic" });
            }

            return models;

        }

 

修改BlogController.cs中的 Get(int id)方法,运行项目,断点调试,发现已经成功了,是否是很方便,你也能够反过来试一试

     [HttpGet("{id}", Name = "Get")]
        public async Task<object> Get(int id)
        {
            var model = await _blogArticleServices.getBlogDetails(id);//调用该方法,这里 _blogArticleServices 是依赖注入的实例,不是类
            var data = new { success = true, data = model };
            return data;
        }

 

 

好啦,到目前为止,我们已经注入了这些服务了:

 

 

六、复杂深拷贝映射

 有的小伙伴问,你这个这个简单,都是相同字段的,那固然很方便啦,要是一个复杂的,好比属性名字不同的,或者说有子类等嵌入型的咋办?放心,同样是能够的,请看

一、属性名称不同
   CreateMap<Student, StudentViewModel>()
       .ForMember(d => d.CountyName, o => o.MapFrom(s => s.County))
       .ForMember(d => d.ProvinceName, o => o.MapFrom(s => s.Province))
       ;

 

二、若是是还有子类的复杂类型
      CreateMap<Student, StudentViewModel>()
      .ForMember(d => d.County, o => o.MapFrom(s => s.Address.County))
      .ForMember(d => d.Province, o => o.MapFrom(s => s.Address.Province))
      .ForMember(d => d.City, o => o.MapFrom(s => s.Address.City))
      .ForMember(d => d.Street, o => o.MapFrom(s => s.Address.Street))
      ;


   public class Student : Entity
    {
        public string Name { get; private set; }
        public string Email { get; private set; }
        public string Phone { get; private set; }
        public DateTime BirthDate { get; private set; }
        public Address Address { get; private set; }
    }

    public class StudentViewModel
    {
        public Guid Id { get; set; }
        public string Name { get; set; }
        public string Email { get; set; }
        public DateTime BirthDate { get; set; }
        public string Phone { get; set; }
        public string Province { get; set; }
        public string City { get; set; }
        public string County { get; set; }
        public string Street { get; set; }
    }

 

 

2、Blog.Core项目打包发布在IIS

一、项目打包发布

在项目Blog.Core中,右键,发布,选择文件,相信你们都会,不会的能够联系我

 

 

 

 

注意1: 这里有一个坑,还记得咱们用swagger中使用的两个xml文件,记得是两个文件,编译的时候有,可是.net core官方限制了在发布的时候包含xml文件,因此咱们须要处理下

在发布以前,咱们手动在项目工程文件 blog.core.csproj中,增长

<PropertyGroup>
  <GenerateDocumentationFile>true</GenerateDocumentationFile>
</PropertyGroup>

 

或者,右键xml文档,属性,始终复制,这些都是 net 的基本技能,有问题百度下就知道了。

----------------------------------------------------------------------

固然咱们还能够基于CLI的Publish命令进行发布,只需切换到Light.API根目录下,输入如下命令便可:

dotnet publish --framework netcoreapp1.1 --output "E:\Publish" --configuration Release

framework表示目标框架,output表示要发布到的目录文件夹,configuration表示配置文件,等同于和上面咱们经过管理器来发布的操做

具体的你们能够自行实验

 

注意2:若是你想发布到其余文件夹,可使用生成命令:

是由于我在 api 层的项目属性中,配置了生成命令:

 

Copy "$(ProjectDir)bin\Debug\netcoreapp2.2\" "$(SolutionDir)Blog.Core\bin\Debug\"

 

 

提示:

咱们发布项目的时候,会生成一个web.config文件,这个web.config文件是为了IIS而做用的,若是用基于CLI的dotnet命令启动,则不须要这个config。

 

二、安装运行时Runtime(只能运行.net core应用程序,不能开发)

好比服务器里,能够仅仅安装运行时便可,若是不安装,你可能会遇到这个错误:

下载地址:https://www.microsoft.com/net/download/windows

 

 

在CMD命令窗口下,输入 dotnet 和  dotnet --list-runtimes 查看

 

 注意:若是你是本地开发,还要安装SDK,下文会提到,若是只想服务器中运行,只安装上边的运行时便可,(这里的运行是能dotnet xxx.dll跑起来,而不是命令行dotnet run启动)

好比你安装后,输入 dotnet --version 会报错,下边这个错误须要安装 SDK,不用理会,只要保证 dotnet 的命令 能正常就行

 

怎么保证安装好了呢,直接在服务器中的项目目录下,执行 dotnet xxxx.dll,经过kestrel服务器运行,若是正常则安装成功,能够继续配置iis,若是报错,就是没有安装成功。

至于为啥没有安装成功,我知道的三点:

一、没有重启

二、有的服务器是x64的,可是须要安装x86的

三、执行命令,dotnet --list-runtimes  没有找到相应的版本

 

三、安装SDK(windows服务器不用安装)

https://dotnet.microsoft.com/download/visual-studio-sdks?utm_source=getdotnetsdk&utm_medium=referral

https://www.microsoft.com/net/learn/dotnet/hello-world-tutorial

 

四、安装AspNetCoreModule托管模块(已安装则跳过),

  下载地址:点击我下载

 

五、应用池配置为无托管代码

(网上解释:ASP.NET Core再也不是由IIS工做进程(w3wp.exe)托管,而是使用自托管Web服务器(Kestrel)运行,IIS则是做为反向代理的角色转发请求到Kestrel不一样端口的ASP.NET Core程序中,随后就将接收到的请求推送至中间件管道中去,处理完你的请求和相关业务逻辑以后再将HTTP响应数据从新回写到IIS中,最终转达到不一样的客户端(浏览器,APP,客户端等)。而配置文件和过程都会由些许调整,中间最重要的角色即是AspNetCoreModule,它是其中一个的IIS模块,请求进入到IIS以后便当即由它转发,并迅速重定向到ASP.NET Core项目中,因此这时候咱们无需设置应用程序池来托管咱们的代码,它只负责转发请求而已)

 

老张:若是须要读写根目录权限,要更改应用池 ApplicationPoolIdentity

 

六、能够打开错误日志

在发布的时候,会有一个web.config出现,经过修改web.config 启用错误日志查看详细错误信息

 将stdoutLogEnabled的修改成 true,并在应用程序根目录添加 logs 文件夹

必定要手动添加logs文件,否则会不出现

 

可是这个文件名应该不能被修改:

 

 

七、只要本地能经过,常见的错误就是生成的文件不全致使的,你们能够自行看看,若是有问题,也能够你们一块儿解决

 好比错误

一、缺乏一个补丁

其中一个问题是少一个补丁,发现须要打个补丁(Windows6.1-KB2533623-x64.msu),下载地址:点我点我

 


 

 

 

八、在IIS中启动项目,或者直接输入服务器IP地址,加端口调试

注意:这里有一个小问题,由于发布之后,默认启动页是在开发环境中重定向到了swagger,可是在服务器部署之后,不能跳转,你们打开后会这样,404找不到,不要怕,

只须要在后边加上Swagger就好了

 

九、配置域名

 当前端口配置域名的时候,须要在IIS的应用程序池中,修改“加载用户配置文件”为 True

 

3、项目在Liunx Ubuntu中部署(简单版,慢慢完善)

一、在腾讯云购买Ubuntu服务器后,登录,而后进入命令页面

 

二、部署Linux系统中的微软环境

继续执行下面的命令

Register the trusted Microsoft signature key:

curl https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor > microsoft.gpg

继续

sudo mv microsoft.gpg /etc/apt/trusted.gpg.d/microsoft.gpg

根据系统版本,执行下面的命令

sudo sh -c 'echo "deb [arch=amd64] https://packages.microsoft.com/repos/microsoft-ubuntu-xenial-prod xenial main" > /etc/apt/sources.list.d/dotnetdev.list'

好了,环境部署完毕,下面咱们安装 SDK

 

三、部署.Ne Core 环境

sudo apt-get install apt-transport-https
sudo apt-get update
sudo apt-get install dotnet-sdk-2.1.4

 安装成功后,输入命令 dotnet 

 

证实安装成功啦

 

四、安装代码上传工具,Fillzila或者winSCP均可以,(我用的是winSCP)

软件下好打开后界面是这样的,咱们须要填的就是主机名(你服务器的公网IP)、用户名(服务器的用户名)、密码(你买服务器时设置的密码),那个文件协议就是SFTP,不用改变

 

五、登录进去默认是 /Home/ubuntu 文件夹,咱们都在这里操做

 

 

 六、下面咱们在服务器新建一个控制台项目测试一下

dotnet new console -o myApp

而后就在winSCP发现多了一个项目

 

 七、而后运行咱们刚刚建立的项目

cd myApp
dotnet run

代码一块儿正常!

 

八、把咱们的项目发布上去,注意这里不是我们发布的版本!不是发布的版本!

由于咱们本地发布的是windows版本的,若是把publish打包版本发布上去,会报错,各类错

因此应该是把整个解决方法提交上去,固然git就别提交了

而后呢,进入到咱们要发布的接口层项目

cd Blog.Core,而后再cd Blog.Core

最后执行 dotnet run 便可

 

 

 

4、发布到Ubuntu

参考文章  @发布 ASP.NET Core 2.x 应用到 Ubuntu

 

一、安装.NET Core 

首先须要安装.NET Core Runtime: https://www.microsoft.com/net/download

点击以后,根据您的Linux发行版不一样,选择相应的操做步骤:

最后执行dotnet --info验证安装是否成功:

 

二、安装Nginx

另外还须要安装Nginx,直接查看官网文档吧:https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.1&tabs=aspnetcore2x#install-nginx

安装好后,访问这个页面:http://你的ip地址/index.nginx-debian.html,若是看到以下效果说明安装成功:

 

三、在服务器构建源码并发布

而后就是发布程序了,发布有两种办法:

  • 在开发机上执行dotnet publish而后把发布的文件复制到服务器上
  • 或者直接在服务器上使用源码构建并发布,我通常是这样作的。

因为我是直接在服务器上构建发布,因此我须要安装.NET Core SDK:https://www.microsoft.com/net/learn/get-started-with-dotnet-tutorial

 

而后就可使用发布命令了:dotnet publish --configuration Release

发布好的文件在bin/Release/netcoreapp*.*/publish下面。

再把publish下的全部文件复制到个人目标文件夹便可:

在个人目标目录下,有这些文件:

 

若是执行 dotnet test.dll,这个程序就会在localhost:5000运行:

 

四、配置Nginx

而后咱们再回来配置Nginx,进入/etc/nginx/sites-available,里面有一个Default文件,把它改个名,而后咱们再创建一个新的Default文件:

 

保存后执行sudo nginx -t检验这个配置文件。

而后再执行 nginx -s reload 来重启nginx。

随后须要再把发布后的程序运行一下:dotnet test.dll:

 

在我使用网址访问80端口的时候,会自动跳转到5001端口,致使链接失败:

这是由于项目里默认使用了HTTPS Redirection。由于我没有证书,因此为了演示,我把HTTPS Redirection相关的代码注释掉,再发布:

 

重复上述步骤以后,经过网址的80端口,就能够正常访问了:

 

五、NGINX配置证书和HTTPS

配置HTTPS和证书相关的内容直接去看官方文档:https://docs.microsoft.com/en-us/aspnet/core/host-and-deploy/linux-nginx?view=aspnetcore-2.1&tabs=aspnetcore2x#configure-ssl

添加proxy.conf和编辑nginx.conf后重启nginx便可。

 

按照操做,运行后若是不能使用https正常访问网站,那么有多是没法绑定443端口致使的。

查看nginx错误日志:/var/log/nginx/error.log,若是出现下面的错误:

能够执行下列命令来解决:

sudo fuser -k 443/tcp
service nginx restart

 

而后再次访问https网址:

这样就能够正常访问https的网址了。

 

5、NetCore 部署到 WINDOWS服务

 微软有提供 如何在windows服务托管asp.net core ,不过步骤比较麻烦,还须要改源码,网上找到一种方法 使用NSSM把.Net Core部署至windows服务

  简单说一下步骤

1. 下载nssm:http://www.nssm.cc/download

2. 运行cmd,定位到nssm.exe文件路径,运行nssm install

3. 在弹出的窗口配置:    

  Path:dotnet所在的目录,通常默认是在C:\Program Files\dotnet\dotnet.exe;

  Startup directory:程序所在的目录,就是最后程序dll所在的目录;

  Arguments:程序dll的名称,通常是项目名加上.dll;

  Service name:在此写上服务的名称便可。

  最后点击install service 完成windows服务安装。

  在windows服务找到对应服务名,启动,而后根据launchSettings.json配置的端口访问,便可调取接口。

 

6、结语

今天暂时就先写到这里,咱们学到了如何用AutoMapper来实现DTO数据对象映射,也学会了在windows下的IIS中发布项目,最后就是Linux系统中,搭建环境和运行.net core 。之后呢我还会讲到Docker 容器,Nginx代理等等,你们拭目以待吧

 

7、CODE

 

https://github.com/anjoy8/Blog.Core

https://gitee.com/laozhangIsPhi/Blog.Core