ASP.NET Core - 入口檔案

啊晚發表於2023-02-11

1. 入口檔案

  一個應用程式總有一個入口檔案,是應用啟動程式碼開始執行的地方,這裡往往也會涉及到應用的各種配置。當我們接觸到一個新框架的時候,可以從入口檔案入手,瞭解入口檔案,能夠幫助我們更好地理解應用的相關配置以及應用的工作方式。

  .Net Core 應用的入口檔案是 Program.cs,這裡是應用啟動的地方。在 .Net 6 之前的版本,Program.cs 檔案是下面這樣的,這是建立一個 Web 專案時的預設程式碼。

public class Program
{
	public static void Main(string[] args)
	{
		CreateHostBuilder(args).Build().Run();
	}

	public static IHostBuilder CreateHostBuilder(string[] args) =>
		Host.CreateDefaultBuilder(args)
			.ConfigureWebHostDefaults(webBuilder =>
			{
				webBuilder.UseStartup<Startup>();
			});
}

  其中 Main 方法就是應用啟動的入口。可以看到在應用啟動的時候,透過 建造者模式 建立了一個主機,並進行了相關的配置,最後將其執行起來。

  從程式碼中可以看到,在對主機進行配置的時候,使用到了 Startup 類,在 .Net 6 之前的版本,Startup 類承擔應用的啟動任務,是應用配置的主要地方。

2. Startup 類

2.1 Startup類結構

  Startup 類支援兩種定義方式,一種是實現 IStartup 介面,一種是基於約定的。無論哪一種,Startup 類的基本結構都包含以下兩個個關鍵函式。整體來說,基於約定的 Startup 類更加靈活。

  • ConfigureServices方法
  • Configure方法

image

2.1.2 ConfigureServices 方法

  • 該方法是可選的
  • 該方法用於新增服務到DI容器中
  • 該方法在 Configure 方法之前被呼叫
  • 基於約定的情況下,該方法要麼無引數,要麼只能有一個引數且型別必須為 IServiceCollection
  • 該方法內的程式碼大多是形如 Add{Service} 的擴充套件方法

2.1.3 Configure方法

  • 該方法是必須的
  • 該方法用於配置 HTTP 請求管道,透過向管道新增中介軟體,應用不同的響應方式。
  • 該方法在 ConfigureServices 方法之後被呼叫
  • 基於約定的情況下,該方法中的引數可以接受任何已注入到DI容器中的服務
  • 該方法內的程式碼大多是形如 Use{Middleware} 的擴充套件方法
  • 該方法內中介軟體的註冊順序與程式碼的書寫順序是一致的,先註冊的先執行,後註冊的後執行

  另外還有建構函式,當使用通用主機時,Startup 建構函式支援注入以下三種服務型別,在 Startup 類中全域性進行使用:

  • IConfiguration
  • IWebHostEnvironment
  • IHostEnvironment

2.2 預設Startup

  所謂預設Startup,就是應用啟動配置不用 Startup 類,直接在 ConfigureWebHostDefaults 中進行配置。

publicstaticIHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
          // ConfigureServices 可以呼叫多次,最終會將結果聚合
	  webBuilder.ConfigureServices(services =>
	  {
	  })
	  // Configure 如果呼叫多次,則只有最後一次生效.
	  .Configure(app =>
	  {
		// Configure呼叫之前,ConfigureServices已經呼叫,容器物件已經生成,所以這裡可以透過容器直接解析需要的物件
		var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
          });
        });

2.3 多環境配置

  .NET Core 框架支援多環境開發,可以透過環境變數 ASPNETCORE_ENVIRONMENT 來設定應用當前的執行環境,以實現一套程式碼在不同環境下執行,根據環境區分一定的行為,支援開發、測試、預釋出、生成環境下不同條件、不同配置的執行場景。

  我們可以直接在機器的環境變數中進行設定,在專案的 Properties 資料夾裡面的“launchSettings.json”檔案進行配置,該檔案是用於配置VS中專案啟動的,在 profiles 節點中透過不同的 json 物件配置當前應用的啟動模式,而描述啟動模式的 json 物件支援的欄位中有一個 environmentVariables 節點,可以透過鍵值對方式配置環境變數。

image

  這裡配置的環境變數只會在當前專案中起作用。若應用執行環境中從未對 ASPNETCORE_ENVIRONMENT 環境變數進行配置,則預設為 Production 。而我們其實可以將 ASPNETCORE_ENVIRONMENT 設定為任意值。

  之後,這些環境變數會在主機初始化的時候作為主機配置被載入到應用中,這些會在後面的配置系統中詳細講到。而在程式碼中,我們可以透過注入 IWebHostEnvironment 服務獲取到當前應用的執行環境。例如下面在 StartUp 中透過判斷環境執行不同的應用初始化邏輯。

image

  IWebHostEnvironment 服務中預設提供對 Development、Production、Staging 三種環境進行判斷的擴充套件方法,如果是其他自定的環境,如 Test,可以使用 IsEnviroment() 方法進行判斷。

image

  透過 IWebHostEnvironment 判斷不同環境,從而在 StartUp 類中使用不同的初始化初始化邏輯,這種方式適合於不同環境下程式碼差異較少的情況。除此之外還有兩種基於約定的方式,分別是 Startup 方法約定 和 StartUp 類名約定 。

  StartUp 方法約定具體是指 StartUp 類中 ConfigureServices 和 Configure 方法還可以按照Configure{EnvironmentName}Services和Configure{EnvironmentName}Services 這樣的命名格式來寫,透過命名約定的 {EnvironmentName} 部分割槽分不同環境,裝載不同環境的程式碼。

  如果 StartUp 類中存在與當前環境名稱匹配的 Configure{EnvironmentName}Services和Configure{EnvironmentName}Services 方法的話,則應用啟動時會執行相應的方法中的邏輯,如果沒有則執行原始的 ConfigureServices 和 Configure 方法中的邏輯。

image

  透過檢視原始碼,可以看到當我們明確配置一個 Startup 類作為應用啟動類的時候,會先判斷是否是實現了 IStartup 介面。

image

  如果沒有的話,則透過 StartupLoader 判斷 Startup 類是否符合約定,最終構建出實現了 IStartup 介面的ConventionBasedStartup,並注入到容器中。這時候會結合環境變數,優先獲取帶有環境變數的方法,如果沒有則使用沒有帶環境變數的方法。

image
image
image

  而 StartUp 類名約定和方法約定類似,程式啟動時,會優先尋找當前環境命名符合Startup{EnvironmentName}的 Startup 類,如果找不到,則使用名稱為Startup的類。類名約定的方式適用於多環境下,程式碼差異較大的情況。

image

  類名約定的方式下,在配置使用 UseStartUp 的時候需要一點小改動:
image

  檢視原始碼,可以看到在我們呼叫上面的方法的時候,實際上並沒有做具體的 Startup 類的構建操作,只是寫入了兩個設定,其實就是寫入到了配置系統中,其中 WebHostDefaults.StartupAssemblyKey 是關鍵。

image

image

  之後在我們應用啟動,呼叫Build方法時,在構建ASP.NET Core 基本服務的時候才會根據設定去構建啟動類。

image

image

image

  在這裡透過 StartupLoader 結合環境名稱查詢程式集中符合約定的 Startup 類。



參考文章:

理解ASP.NET Core - Startup

ASP.NET CORE 3.1 — 應用啟動



ASP.NET Core 系列總結:

目錄:ASP.NET Core 系列總結
下一篇:ASP.NET Core - IStartupFilter與IHostingStartup

相關文章