做者:依樂祝
原文連接:http://www.javashuo.com/article/p-hmpbfpjc-cd.htmlhtml
上篇文章我給你們講解了ASP.NET Core的概念及爲何使用它,接着帶着你一步一步的配置了.NET Core的開發環境並建立了一個ASP.NET Core的mvc項目,同時又經過一個實戰教你如何在頁面顯示一個Content的列表。不知道你有沒有跟着敲下代碼,千萬不要作眼高手低的人哦。這篇文章咱們就會設計一些複雜的概念了,由於要對ASP.NET Core的啓動及運行原理、配置文件的加載過程進行分析,依賴注入,控制反轉等概念的講解等。俗話說,授人以魚不如授人以漁,因此文章旨在帶着你們分析源碼,讓你們能知其然更能知其因此然。爲了偷懶,繼續使用上篇文章的例子了!有興趣的朋友能夠加羣637326624相互交流!
再次感謝張隊的審稿!vue
本文已收錄至.NET Core實戰項目之CMS 第一章 入門篇-開篇及整體規劃 點擊能夠查看更多教程。git
這部分我就帶着你們一塊兒看下asp.net core項目的運行流程吧!順帶着瞭解下asp.net core的運行原理,說的很差的話,但願你們給以指正,從而可以正確的幫助更多的人。github
首先上一下上篇文章的項目結構吧,以下所示,熟悉C#的朋友應該知道,要找程序的入庫,那麼就應該找到Main方法。而asp.net core的main方法就在Program.cs文件中。web
打開後看到以下的代碼,我加了註釋,大夥將就看下,下面咱們來一步一步的分析編程
/// <summary> /// Main方法,程序的入口方法 /// </summary> /// <param name="args"></param> public static void Main(string[] args) { CreateWebHostBuilder(args)//調用下面的方法,返回一個IWebHostBuilder對象 .Build()//用上面返回的IWebHostBuilder對象建立一個IWebHost .Run();//運行上面建立的IWebHost對象從而運行咱們的Web應用程序換句話說就是啓動一個一直運行監聽http請求的任務 } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args)//使用默認的配置信息來初始化一個新的IWebHostBuilder實例 .UseStartup<Startup>();// 爲Web Host指定了Startup類
能夠看到asp.net core程序實際上就是一個控制檯程序,運行一個webhost對象從而啓動一個一直運行的監聽http請求的任務。因此咱們的重點就是分析一下這個WebHost建立的過程:
建立IWebHostBuilder-》建立IWebHost-》而後運行建立的IWebHost。json
這裏咱們從IWebHostBuilder的Build分析下建立的過程,有興趣的朋友能夠看下,沒興趣的朋友能夠直接跳到下一個步驟繼續閱讀。c#
首先到aspnetcore的github開源地址https://github.com/aspnet/AspNetCore/tree/release/2.1 上去下載源碼(咱們使用的是2.1)。而後使用vscode打開解壓後的文件夾。至於vscode如何加載文件,你能夠看我這篇文章使用Visual Studio Code開發.NET Core看這篇就夠了 固然你也能夠在上面的網頁上直接找到相應的目錄瀏覽也是能夠的。(看結構好像是使用vscode進行開發的)mvc
根據IWebHostBuilder的命名空間咱們找到了它的實現,路徑爲src/Hosting/Hosting/src/WebHostBuilder.csapp
經過上面的代碼咱們能夠看到首先是經過BuildCommonServices來構建一個ServiceCollection。爲何說這麼說呢,先讓咱們咱們跳轉到BuidCommonServices方法中看下吧。
能夠看到,
var services = new ServiceCollection();
首先new一個ServiceCollection而後往services裏面注入不少內容,好比:WebHostOptions ,IHostingEnvironment ,IHttpContextFactory ,IMiddlewareFactory 等等(其實這裏已經設計到依賴注入的概念了,先思考下吧),而後咱們在後續就可使用了!最後這個BuildCommonServices就返回了這個services對象。在上面的依賴注入中有一個方法,不知道你們注意到沒有,由於咱們在步驟2貼出的代碼裏面有一個
UseStartup<Startup>()
其實在上面的BuildCommonServices方法中也有對IStartup
的注入的。首先,判斷Startup類是否繼承於IStartup接口,若是是繼承的,那麼就能夠直接加入在services 裏面去,若是不是繼承的話,就須要經過ConventionBasedStartup(methods)把method轉換成IStartUp後注入到services裏面去。結合上面咱們的代碼,貌似咱們平時用的時候注入的方式都是採用後者。咱們再回到build方法拿到了BuildCommonServices方法構建的ServiceCollection實例後,經過GetProviderFromFactory(hostingServices) 方法構造出了IServiceProvider 對象。到目前爲止,IServiceCollection和IServiceProvider都拿到了。而後根據IServiceCollection和IServiceProvider對象構建WebHost對象。構造了WebHost實例還不能直接返回,還須要經過Initialize對WebHost實例進行初始化操做。那咱們看看在初始化函數Initialize中,都作了什麼事情吧。
這裏咱們把代碼導航到src/Hosting/Hosting/src/Internal/WebHost.cs找到Initialize方法。以下圖所示:主要就是一個EnsureApplicationServices 方法。
咱們繼續導航查看這個方法的內容以下:就是拿到Startup 對象,而後把_applicationServiceCollection 中的對象注入進去。
至此咱們build中註冊的對象以及StartUp中註冊的對象都已經加入到依賴注入容器中了,接下來就是Run起來了。這個run的代碼在src\Hosting\Hosting\src\WebHostExtensions.cs中,代碼以下:
WebHost執行RunAsync運行web應用程序並返回一個只有在觸發或關閉令牌時才完成的任務(這裏又涉及到異步編程的知識了,我們之後再詳細講解) 。這就是咱們運行ASP.Net Core程序的時候,看到的那個命令行窗口了,若是不關閉窗口或者按Ctrl+C的話是沒法結束的。
至此啓動的過程的源碼分析完成了。
打開上篇文章咱們建立的項目,並在appsettings.json裏面加入以下內容:
{ "Logging": { "LogLevel": { "Default": "Warning" } }, "Content": { "Id": 1, "title": "title1", "content": "content1", "status": 1, "add_time": "2018-11-21 16:29", "modify_time": null }, "AllowedHosts": "*" }
而後在Startup類中ConfigureServices中註冊TOptions對象以下所示:
services.Configure<Content>(Configuration.GetSection("Content"));//註冊TOption實例對象
這段代碼也就是從appsettings.json這個配置文件中的Content
這個節點匹配到Content這個對象上。
修改下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} }); }
按下F5運行下,而後導航到Content目錄看到以下頁面:說明成功從appsettings.json這個文件中加載了內容。這一切是怎麼發生的呢?下面咱們就一步一步的來分析。
咱們回過頭來看咱們的Main方法,發現裏面有一個CreateDefaultBuilder方法,就是這個方法裏面爲咱們作了一些默認的設置,而後加載咱們的配置文件的!
咱們在源碼裏面找到CreateDefaultBuilder 的源碼(反正我找了半天,起初在Hosting下面找,實際上在MetaPackages下面的),位置在src\MetaPackages\src\Microsoft.AspNetCore\WebHost.cs 有的人可能找不到哦,能夠看到這個方法會在ConfigureAppConfiguration 的時候默認加載appsetting
文件,並作一些初始的設置,因此咱們不須要任何操做,就能加載appsettings
的內容了。
既然知道了原理後,咱們就試着重寫下這個ConfigureAppConfiguration
而後加載咱們自定義的json文件吧。
鼠標右鍵新建一個Content.json文件,而後輸入以下的內容:
{ "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 } }
而後打開Program.cs。按以下代碼進行改造:
/// <summary> /// Main方法,程序的入口方法 /// </summary> /// <param name="args"></param> public static void Main(string[] args) { CreateWebHostBuilder(args)//調用下面的方法,返回一個WebHostBuilder對象 .Build()//用上面返回的WebHostBuilder對象建立一個WebHost .Run();//運行上面建立的WebHost對象從而運行咱們的Web應用程序換句話說就是啓動一個一直運行監聽http請求的任務 } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args)//使用默認的配置信息來初始化一個新的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類
而後Startup裏面ConfigureServices中的代碼修改以下:
而後按下F5運行下代碼吧,以下圖所示,從咱們最新添加的json文件中加載出來數據了。
這裏多講一點,傳統asp.net的web.config文件若是有更改的話是必需要重啓站點才能使,配置文件生效的,可是asp.net core的配置文件是支持熱更新的,及不重啓網站也能加載更新,只須要設置一下屬性便可,以下圖所示:
配置文件的源碼解讀這塊就到這裏了。下面開始依賴注入的講解。
若是你們仔細閱讀文章的話,相信已經看出來了,我上面提到過好幾回依賴注入的概念。那麼究竟什麼是依賴注入呢?下面咱們就拿咱們上面的ContentController來好好的來理解下。
依賴注入:當一個對象ContentController須要另外一個對象Content來協同完成任務的時候,那麼這個ContentController就對這個Content對象產生了依賴關係。那麼在這個ContentController中,是怎麼注入的呢?就是從控制器中注入的了,以下圖所示:
從asp.net 轉過來的你是否是想起了以前的千篇一概的new對象啊。沒對象本身new(要是女友也能new多好啊……)固然除了單例對象,靜態哈。
這裏又設計一個概念就是控制反轉。
那麼什麼是控制反轉呢?你上面看到沒有,你本身new對象就是正轉,由於你本身建立本身所要使用的對象,。那麼這種不須要你本身new對象,而是直接傳進來就是控制反轉了。(不知道比喻的恰不恰當哈)
依賴注入與控制反轉你是否已經瞭解了呢,喜歡思考的朋友可能會問了,那這個構造函數裏面的IOptions<Content> option
又是怎麼出來的?這裏就要引入一個容器的概念了。
什麼是容器呢?
這裏建立IOptions<Content> option
這個對象的東西就是容器。還記得上面咱們分析源碼的時候,IServiceCollection 裏面注入了不少東西嗎?其實就是往IServiceCollection 這個容器裏面注入方法,這樣其餘地方使用的時候就能自動注入了。
這就是容器的好處,由容器來統一管理實例的建立和銷燬,你只須要關心怎麼用就好了,不須要關心怎麼建立跟銷燬。
固然容器建立的實例都是有生命週期的,。下面羅列一下,就不過多的講解了。
使用的方式也很簡單,我會在接下來的課程中詳細的經過實例來進行講解!由於如今的例子還沒發演示。
本文一步一步帶着你先分析了ASP.NET Core的啓動過程及運行的原理,緊接着給你講了配置文件的加載過程及原理,並經過示例代碼演示瞭如何加載自定義的配置文件,最後引出了依賴注入以及控制反轉的概念,並經過對咱們上面例子的分析來緊身對依賴注入以及控制反轉的理解。至此讓你知其然更知其因此然。對ASP.NET Core的原理相信你已經瞭然於胸了!有問題的小夥伴能夠加羣637326624
討論。那麼接下來讓咱們再準備下dapper,vue以及git的快速入門就開始咱們的asp.net core cms的實戰課程吧!仍是那句話基礎很重要,基礎打好,後面才能事半功倍。謝謝你們。