從壹開始先後端分離【 .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

相關文章
相關標籤/搜索