一個應用程式總有一個入口檔案,是應用啟動程式碼開始執行的地方,這裡往往也會涉及到應用的各種設定。當我們接觸到一個新框架的時候,可以從入口檔案入手,瞭解入口檔案,能夠幫助我們更好地理解應用的相關設定以及應用的工作方式。
.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 類承擔應用的啟動任務,是應用設定的主要地方。
Startup 類支援兩種定義方式,一種是實現 IStartup 介面,一種是基於約定的。無論哪一種,Startup 類的基本結構都包含以下兩個個關鍵函數。整體來說,基於約定的 Startup 類更加靈活。
Add{Service}
的擴充套件方法Use{Middleware}
的擴充套件方法另外還有建構函式,當使用通用主機時,Startup 建構函式支援注入以下三種服務型別,在 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>();
});
});
.NET Core 框架支援多環境開發,可以通過環境變數 ASPNETCORE_ENVIRONMENT
來設定應用當前的執行環境,以實現一套程式碼在不同環境下執行,根據環境區分一定的行為,支援開發、測試、預釋出、生成環境下不同條件、不同設定的執行場景。
我們可以直接在機器的環境變數中進行設定,在專案的 Properties 資料夾裡面的「launchSettings.json」檔案進行設定,該檔案是用於設定VS中專案啟動的,在 profiles 節點中通過不同的 json 物件設定當前應用的啟動模式,而描述啟動模式的 json 物件支援的欄位中有一個 environmentVariables
節點,可以通過鍵值對方式設定環境變數。
這裡設定的環境變數只會在當前專案中起作用。若應用執行環境中從未對 ASPNETCORE_ENVIRONMENT 環境變數進行設定,則預設為 Production 。而我們其實可以將 ASPNETCORE_ENVIRONMENT 設定為任意值。
之後,這些環境變數會在主機初始化的時候作為主機設定被載入到應用中,這些會在後面的設定系統中詳細講到。而在程式碼中,我們可以通過注入 IWebHostEnvironment 服務獲取到當前應用的執行環境。例如下面在 StartUp 中通過判斷環境執行不同的應用初始化邏輯。
IWebHostEnvironment 服務中預設提供對 Development、Production、Staging 三種環境進行判斷的擴充套件方法,如果是其他自定的環境,如 Test,可以使用 IsEnviroment() 方法進行判斷。
通過 IWebHostEnvironment 判斷不同環境,從而在 StartUp 類中使用不同的初始化初始化邏輯,這種方式適合於不同環境下程式碼差異較少的情況。除此之外還有兩種基於約定的方式,分別是 Startup 方法約定 和 StartUp 類名約定 。
StartUp 方法約定具體是指 StartUp 類中 ConfigureServices 和 Configure 方法還可以按照Configure{EnvironmentName}Services和Configure{EnvironmentName}Services 這樣的命名格式來寫,通過命名約定的 {EnvironmentName} 部分割區分不同環境,裝載不同環境的程式碼。
如果 StartUp 類中存在與當前環境名稱匹配的 Configure{EnvironmentName}Services和Configure{EnvironmentName}Services 方法的話,則應用啟動時會執行相應的方法中的邏輯,如果沒有則執行原始的 ConfigureServices 和 Configure 方法中的邏輯。
通過檢視原始碼,可以看到當我們明確設定一個 Startup 類作為應用啟動類的時候,會先判斷是否是實現了 IStartup 介面。
如果沒有的話,則通過 StartupLoader 判斷 Startup 類是否符合約定,最終構建出實現了 IStartup 介面的ConventionBasedStartup,並注入到容器中。這時候會結合環境變數,優先獲取帶有環境變數的方法,如果沒有則使用沒有帶環境變數的方法。
而 StartUp 類名約定和方法約定類似,程式啟動時,會優先尋找當前環境命名符合Startup{EnvironmentName}的 Startup 類,如果找不到,則使用名稱為Startup的類。類名約定的方式適用於多環境下,程式碼差異較大的情況。
類名約定的方式下,在設定使用 UseStartUp 的時候需要一點小改動:
檢視原始碼,可以看到在我們呼叫上面的方法的時候,實際上並沒有做具體的 Startup 類的構建操作,只是寫入了兩個設定,其實就是寫入到了設定系統中,其中 WebHostDefaults.StartupAssemblyKey 是關鍵。
之後在我們應用啟動,呼叫Build方法時,在構建ASP.NET Core 基本服務的時候才會根據設定去構建啟動類。
在這裡通過 StartupLoader 結合環境名稱查詢程式集中符合約定的 Startup 類。
參考文章:
ASP.NET Core 系列總結:
目錄:ASP.NET Core 系列總結
下一篇:ASP.NET Core - IStartupFilter與IHostingStartup