欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

.NET Core源碼解析配置文件及依賴注入

 更新時間:2019年04月04日 09:08:23   作者:依樂祝  
這篇文章我們設(shè)計了一些復(fù)雜的概念,因為要對ASP.NET Core的啟動及運行原理、配置文件的加載過程進(jìn)行分析,依賴注入,控制反轉(zhuǎn)等概念的講解等
寫在前面

上篇文章我給大家講解了ASP.NET Core的概念及為什么使用它,接著帶著你一步一步的配置了.NET Core的開發(fā)環(huán)境并創(chuàng)建了一個ASP.NET Core的mvc項目,同時又通過一個實戰(zhàn)教你如何在頁面顯示一個Content的列表。不知道你有沒有跟著敲下代碼,千萬不要做眼高手低的人哦。

這篇文章我們就會設(shè)計一些復(fù)雜的概念了,因為要對ASP.NET Core的啟動及運行原理、配置文件的加載過程進(jìn)行分析,依賴注入,控制反轉(zhuǎn)等概念的講解等。

俗話說,授人以魚不如授人以漁,所以文章旨在帶著大家分析源碼,讓大家能知其然更能知其所以然。為了偷懶,繼續(xù)使用上篇文章的例子了!

ASP.NET Core啟動源碼解析

這部分我就帶著大家一起看下asp.net core項目的運行流程吧!順帶著了解下asp.net core的運行原理,說的不好的話,希望大家給以指正,從而能夠正確的幫助更多的人。

1.首先上一下上篇文章的項目結(jié)構(gòu)吧,如下所示,熟悉C#的朋友應(yīng)該知道,要找程序的入庫,那么就應(yīng)該找到Main方法。而asp.net core的main方法就在Program.cs文件中。

2.打開后看到如下的代碼,我加了注釋,大伙將就看下,下面我們來一步一步的分析

/// <summary>
 /// Main方法,程序的入口方法
 /// </summary>
 /// <param name="args"></param>
 public static void Main(string[] args)
 {
  CreateWebHostBuilder(args)//調(diào)用下面的方法,返回一個IWebHostBuilder對象
  .Build()//用上面返回的IWebHostBuilder對象創(chuàng)建一個IWebHost
  .Run();//運行上面創(chuàng)建的IWebHost對象從而運行我們的Web應(yīng)用程序換句話說就是啟動一個一直運行監(jiān)聽http請求的任務(wù)
 }

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
  WebHost.CreateDefaultBuilder(args)//使用默認(rèn)的配置信息來初始化一個新的IWebHostBuilder實例
  .UseStartup<Startup>();// 為Web Host指定了Startup類

3.可以看到asp.net core程序?qū)嶋H上就是一個控制臺程序,運行一個webhost對象從而啟動一個一直運行的監(jiān)聽http請求的任務(wù)。所以我們的重點就是分析一下這個WebHost創(chuàng)建的過程:

創(chuàng)建IWebHostBuilder-》創(chuàng)建IWebHost-》然后運行創(chuàng)建的IWebHost。

4.這里我們從IWebHostBuilder的Build分析下創(chuàng)建的過程,有興趣的朋友可以看下,沒興趣的朋友可以直接跳到下一個步驟繼續(xù)閱讀。

                1.首先到aspnetcore的github開源地址https://github.com/aspnet/AspNetCore/tree/release/2.1 上去下載源碼(我們使用的是2.1)。然后使用vscode打開解壓后的文件夾。至于vscode如何加載文件,你可以看我這篇文章使用Visual Studio Code開發(fā).NET Core看這篇就夠了 。

                2.根據(jù)IWebHostBuilder的命名空間我們找到了它的實現(xiàn),路徑為src/Hosting/Hosting/src/WebHostBuilder.cs

                3.通過上面的代碼我們可以看到首先是通過BuildCommonServices來構(gòu)建一個ServiceCollection。為什么說這么說呢,先讓我們我們跳轉(zhuǎn)到BuidCommonServices方法中看下吧。

可以看到,var services = new ServiceCollection();首先new一個ServiceCollection然后往services里面注入很多內(nèi)容,比如:WebHostOptions ,IHostingEnvironment ,IHttpContextFactory ,IMiddlewareFactory 等等(其實這里已經(jīng)設(shè)計到依賴注入的概念了,先思考下吧),然后我們在后續(xù)就可以使用了!最后這個BuildCommonServices就返回了這個services對象。

                4.在上面的依賴注入中有一個方法,不知道大家注意到?jīng)]有,因為我們在步驟2貼出的代碼里面有一個UseStartup<Startup>() 其實在上面的BuildCommonServices方法中也有對IStartup的注入的。首先,判斷Startup類是否繼承于IStartup接口,如果是繼承的,那么就可以直接加入在services 里面去,如果不是繼承的話,就需要通過ConventionBasedStartup(methods)把method轉(zhuǎn)換成IStartUp后注入到services里面去。結(jié)合上面我們的代碼,貌似我們平時用的時候注入的方式都是采用后者。

                5.我們再回到build方法拿到了BuildCommonServices方法構(gòu)建的ServiceCollection實例后,通過GetProviderFromFactory(hostingServices) 方法構(gòu)造出了IServiceProvider 對象。到目前為止,IServiceCollection和IServiceProvider都拿到了。然后根據(jù)IServiceCollection和IServiceProvider對象構(gòu)建WebHost對象。構(gòu)造了WebHost實例還不能直接返回,還需要通過Initialize對WebHost實例進(jìn)行初始化操作。那我們看看在初始化函數(shù)Initialize中,都做了什么事情吧。

                6.這里我們把代碼導(dǎo)航到src/Hosting/Hosting/src/Internal/WebHost.cs找到Initialize方法。如下圖所示:主要就是一個EnsureApplicationServices 方法。

                7.我們繼續(xù)導(dǎo)航查看這個方法的內(nèi)容如下:就是拿到Startup 對象,然后把_applicationServiceCollection 中的對象注入進(jìn)去。

                8.至此我們build中注冊的對象以及StartUp中注冊的對象都已經(jīng)加入到依賴注入容器中了,接下來就是Run起來了。這個run的代碼在src\Hosting\Hosting\src\WebHostExtensions.cs中,代碼如下:

WebHost執(zhí)行RunAsync運行web應(yīng)用程序并返回一個只有在觸發(fā)或關(guān)閉令牌時才完成的任務(wù)(這里又涉及到異步編程的知識了,咱們以后再詳細(xì)講解) 。這就是我們運行ASP.Net Core程序的時候,看到的那個命令行窗口了,如果不關(guān)閉窗口或者按Ctrl+C的話是無法結(jié)束的。

                9.至此啟動的過程的源碼分析完成了。

配置文件

上面給大家介紹了ASP.NET Core的啟動過程,中間牽扯到了一些依賴注入的概念。關(guān)于依賴注入的概念呢,我們后面再說,這里先給大家講解下配置文件的加載過程。

4.打開上篇文章我們創(chuàng)建的項目,并在appsettings.json里面加入如下內(nèi)容:

{
 "Logging": {
 "LogLevel": {
 "Default": "Warning"
 }
 },
 "Content": {
 "Id": 1,
 "title": "title1",
 "content": "content1",
 "status": 1,
 "add_time": "2018-11-21 16:29",
 "modify_time": null
 },
 "AllowedHosts": "*"
}

5.然后在Startup類中ConfigureServices中注冊TOptions對象如下所示:

services.Configure<Content>(Configuration.GetSection("Content"));//注冊TOption實例對象

這段代碼也就是從appsettings.json這個配置文件中的Content這個節(jié)點匹配到Content這個對象上。

6.修改下ContentController這個控制器代碼如下:

private readonly Content contents;
 public ContentController(IOptions<Content> option)
 {
  contents = option.Value;
 }
 /// <summary>
 /// 首頁顯示
 /// </summary>
 /// <returns></returns>
 public IActionResult Index()
 {

  return View(new ContentViewModel { Contents=new List<Content> { contents} });
 }

7.按下F5運行下,然后導(dǎo)航到Content目錄看到如下頁面:說明成功從appsettings.json這個文件中加載了內(nèi)容。這一切是怎么發(fā)生的呢?下面我們就一步一步的來分析。

8.我們回過頭來看我們的Main方法,發(fā)現(xiàn)里面有一個CreateDefaultBuilder方法,就是這個方法里面為我們做了一些默認(rèn)的設(shè)置,然后加載我們的配置文件的!

9.我們在源碼里面找到CreateDefaultBuilder 的源碼(反正我找了半天,起初在Hosting下面找,實際上在MetaPackages下面的),位置在src\MetaPackages\src\Microsoft.AspNetCore\WebHost.cs 有的人可能找不到哦,可以看到這個方法會在ConfigureAppConfiguration 的時候默認(rèn)加載appsetting文件,并做一些初始的設(shè)置,所以我們不需要任何操作,就能加載appsettings 的內(nèi)容了。

10.既然知道了原理后,我們就試著重寫下這個ConfigureAppConfiguration 然后加載我們自定義的json文件吧。

11.鼠標(biāo)右鍵新建一個Content.json文件,然后輸入如下的內(nèi)容:

{
 "ContentList": 
 {
 "Id": 1,
 "title": "title1 from diy json",
 "content": "content1 from diy json",
 "status": 1,
 "add_time": "2018-11-21 16:29",
 "modify_time": null
 }

}

12.然后打開Program.cs。按如下代碼進(jìn)行改造:

/// <summary>
 /// Main方法,程序的入口方法
 /// </summary>
 /// <param name="args"></param>
 public static void Main(string[] args)
 {
  CreateWebHostBuilder(args)//調(diào)用下面的方法,返回一個WebHostBuilder對象
  .Build()//用上面返回的WebHostBuilder對象創(chuàng)建一個WebHost
  .Run();//運行上面創(chuàng)建的WebHost對象從而運行我們的Web應(yīng)用程序換句話說就是啟動一個一直運行監(jiān)聽http請求的任務(wù)
 }

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
  WebHost.CreateDefaultBuilder(args)//使用默認(rèn)的配置信息來初始化一個新的IWebHostBuilder實例
  .ConfigureAppConfiguration((hostingContext, config) =>
  {
  var env = hostingContext.HostingEnvironment;

  config.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
   .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true)
   .AddJsonFile("Content.json",optional:false,reloadOnChange:false)
   .AddEnvironmentVariables();

  })
  .UseStartup<Startup>();// 為Web Host指定了Startup類

13.然后Startup里面ConfigureServices中的代碼修改如下:

14.然后按下F5運行下代碼吧,如下圖所示,從我們最新添加的json文件中加載出來數(shù)據(jù)了。

15.這里多講一點,傳統(tǒng)asp.net的web.config文件如果有更改的話是必須要重啟站點才能使,配置文件生效的,但是asp.net core的配置文件是支持熱更新的,及不重啟網(wǎng)站也能加載更新,只需要設(shè)置一下屬性即可,如下圖所示:

16.配置文件的源碼解讀這塊就到這里了。下面開始依賴注入的講解。

依賴注入與控制反轉(zhuǎn)

如果大家仔細(xì)閱讀文章的話,相信已經(jīng)看出來了,我上面提到過好幾次依賴注入的概念。那么究竟什么是依賴注入呢?下面我們就拿我們上面的ContentController來好好的來理解下。

依賴注入:當(dāng)一個對象ContentController需要另一個對象Content來協(xié)同完成任務(wù)的時候,那么這個ContentController就對這個Content對象產(chǎn)生了依賴關(guān)系。那么在這個ContentController中,是怎么注入的呢?就是從控制器中注入的了,如下圖所示:

從asp.net 轉(zhuǎn)過來的你是不是想起了之前的千篇一律的new對象啊。沒對象自己new(要是女朋友也能new多好啊……)當(dāng)然除了單例對象,靜態(tài)哈。

這里又設(shè)計一個概念就是控制反轉(zhuǎn)。

那么什么是控制反轉(zhuǎn)呢?你上面看到?jīng)]有,你自己new對象就是正轉(zhuǎn),因為你自己創(chuàng)建自己所要使用的對象,。那么這種不需要你自己new對象,而是直接傳進(jìn)來就是控制反轉(zhuǎn)了。(不知道比喻的恰不恰當(dāng)哈)

依賴注入與控制反轉(zhuǎn)你是否已經(jīng)了解了呢,喜歡思考的朋友可能會問了,那這個構(gòu)造函數(shù)里面的IOptions<Content> option 又是怎么出來的?這里就要引入一個容器的概念了。

什么是容器呢?

這里創(chuàng)建IOptions<Content> option 這個對象的東西就是容器。還記得上面我們分析源碼的時候,IServiceCollection 里面注入了很多東西嗎?其實就是往IServiceCollection 這個容器里面注入方法,這樣其他地方使用的時候就能自動注入了。

這就是容器的好處,由容器來統(tǒng)一管理實例的創(chuàng)建和銷毀,你只需要關(guān)心怎么用就行了,不需要關(guān)系怎么創(chuàng)建跟銷毀。

當(dāng)然容器創(chuàng)建的實例都是有生命周期的,。下面羅列一下,就不過多的講解了。

  • Transient: 每一次訪問都會創(chuàng)建一個新的實例
  • Scoped: 在同一個Scope內(nèi)只初始化一個實例 ,可以理解為( 每一個request級別只創(chuàng)建一個實例,同一個http request會在一個 scope內(nèi))
  • Singleton :整個應(yīng)用程序生命周期以內(nèi)只創(chuàng)建一個實例

使用的方式也很簡單,我會在接下來的課程中詳細(xì)的通過實例來進(jìn)行講解!因為現(xiàn)在的例子還沒發(fā)演示。

總結(jié)

本文一步一步帶著你先分析了ASP.NET Core的啟動過程及運行的原理,緊接著給你講了配置文件的加載過程及原理,并通過示例代碼演示了如何加載自定義的配置文件,最后引出了依賴注入以及控制反轉(zhuǎn)的概念,并通過對我們上面例子的分析來緊身對依賴注入以及控制反轉(zhuǎn)的理解。至此讓你知其然更知其所以然。對ASP.NET Core的原理相信你已經(jīng)了然于胸了!那么接下來讓我們再準(zhǔn)備下dapper,vue以及git的快速入門就開始我們的asp.net core cms的實戰(zhàn)課程吧!還是那句話基礎(chǔ)很重要,基礎(chǔ)打好,后面才能事半功倍。謝謝大家。

相關(guān)文章

最新評論