一、背景介紹
本文以ASP.NET Core 2.1.2版本API程序來說明。
在我們新建ASP.NET Core項目時,項目根目錄下會自動建立Program.cs和Startup.cs兩個類文件。
Program.cs 作為 Web 應用程序的默認入口,不做任何修改的情況下,會調用同目錄下 Startup.cs 中的 ConfigureServices 方法 和 Configure 方法。
應用啟動的流程如下圖所示:
本文主要介紹Startup.cs 類,認識其功能和作用,深入了解其內部運行機制,以便於更好地在項目中進行應用。
二、Program類介紹
Program.Main方法是應用程序的托管入口。
在構建應用程序的主機(WebHost)時,在主程序的Web Host生成器(IWebHostBuilder)的 UseStartup <TStartup>
擴展方法中指定啟動類名稱。ASP.NET Core應用程序的啟動類,按照慣例命名為Startup
。而Main入口通過主機生成器(IWebHostBuilder)調用Build時,生成對應的應用程序的主機(WebHost),並啟動運行(Run)。
1 public static void Main(string[] args) 2 { 3 CreateWebHostBuilder(args).Build().Run(); 4 } 5 6 public static IWebHostBuilder CreateWebHostBuilder(string[] args) => 7 WebHost.CreateDefaultBuilder(args) 8 .UseUrls("http://*:5002") 9 .UseStartup<Startup>();
三、Startup類介紹
Startup類用於配置服務和應用程序的請求管道。
當應用程序啟動時,運行時會調用Startup類的 ConfigureServices 和 Configure方法。
1 public class Startup 2 { 3 public static ILoggerRepository Repository { get; set; } 4 public Startup(IConfiguration configuration) 5 { 6 Configuration = configuration; 7 // 日志配置 8 Repository = LogManager.CreateRepository("NETCoreRepository"); 9 XmlConfigurator.Configure(Repository, new FileInfo("log4net.config")); 10 } 11 12 public IConfiguration Configuration { get; } 13 14 // This method gets called by the runtime. Use this method to add services to the container. 15 public void ConfigureServices(IServiceCollection services) 16 { 17 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1); 18 // 跨域,允許所有域名訪問 19 services.AddCors(options => options.AddPolicy("AllowCorsDomain", p => p.WithOrigins("*") 20 .AllowAnyMethod() 21 .AllowAnyHeader() 22 .AllowCredentials())); 23 } 24 25 // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. 26 public void Configure(IApplicationBuilder app, IHostingEnvironment env) 27 { 28 DefaultFilesOptions defaultFilesOptions = new DefaultFilesOptions(); 29 defaultFilesOptions.DefaultFileNames.Clear(); 30 defaultFilesOptions.DefaultFileNames.Add("index.html"); 31 app.UseDefaultFiles(defaultFilesOptions); 32 app.UseStaticFiles(); 33 34 if (env.IsDevelopment()) 35 { 36 app.UseDeveloperExceptionPage(); 37 } 38 39 app.UseMvc(); 40 app.UseCors("AllowCorsDomain"); 41 } 42 }
其中,Startup類必須定義Configure方法,但是可選擇定義一個ConfigureServices 方法,這些方法將在應用程序啟動時被調用。
1、ConfigureServices方法:用於設置應用程序所需要的服務。
ConfigureServices 方法在Configure方法配置應用程序服務之前被主機(WebHost)調用。其中按常規設置配置選項(appsettings.json)。
對於需要大量設置的功能,IServiceCollection 上有 Add{Service} 擴展方法,將服務添加到服務容器,使其在應用程序和Configure方法中可用。服務通過依賴關系注入(DI)或 ApplicationServices 進行解析。例如:
1 // 添加MVC設置兼容版本服務. 2 services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); 3 4 // 添加應用程序服務. 5 services.AddTransient<IEmailSender, AuthMessageSender>();
2、Configure方法:用於指定應用程序響應HTTP請求的方式。
可通過將中間件(middleware)組件添加到IApplicationBuilder實例來配置請求管道。Configure方法可使用 IApplicationBuilder,但未在服務容器中注冊。托管創建 IApplicationBuilder並將其直接傳遞到Configure。
請求管道中的每個中間件組件負責調用管道中的下一個組件,或在適當情況下使鏈發生短路。 如果中間件鏈中未發生短路,則每個中間件都有第二次機會在將請求發送到客戶端前處理該請求。該方法接受IApplicationBuilder作為參數,同時還可以接收其他一些可選參數,如IHostingEnvironment和ILoggerFactory。一般而言,只要將服務注冊到configureServices方法中時,都可以在該方法中使用。
3、擴展Startup方法:IStartupFilter
使用IStartupFilter來對Startup功能進行擴展,在應用的Configure中間件管道的開頭或末尾使用IStartupFilter來配置中間件。IStartupFilter有助於確保當庫在應用請求處理管道的開端或末尾添加中間件的前后運行中間件。
IStartupFilter
接口存在於Microsoft.AspNetCore.Hosting.Abstractions程序集中,它僅定義了一個接口方法。
1 namespace Microsoft.AspNetCore.Hosting 2 { 3 public interface IStartupFilter 4 { 5 Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next); 6 } 7 }
其中Configure
方法返回了一個變量Action
。
當創建一個ASP.NET Core應用程序的時候,IApplicationBuilder
負責配置ASP.NET Core的中間件管道。例如:
1 public void Configure(IApplicationBuilder app) 2 { 3 app.UseStaticFiles(); 4 5 app.UseMvc(routes => 6 { 7 routes.MapRoute( 8 name: "default", 9 template: "{controller=Home}/{action=Index}/{id?}"); 10 }); 11 }
在這個方法中,可以直接使用IApplicationBuilder
參數,並且可以向其中添加各種中間件。
使用IStartupFilter
, 可以指定並返回一個Action
類型的泛型委托,這意味除了可以使用方法提供的泛型委托配置IApplicationBuilder
對象, 還需要返回一個泛型委托。
IStartupFilter
方法可以接受一個配置IApplicationBuilder
的方法,換而言之IStartupFilter.Configure
方法可以使用Startup.Configure
方法作為參數。例如:
1 Startup _startup = new Startup(); 2 Action<IApplicationBuilder> startupConfigure = _startup.Configure; 3 4 // 將startupConfigure 作為filter1.Configure(startupConfigure)的參數 5 IStartupFilter filter1 = new StartupFilter1(); 6 Action<IApplicationBuilder> filter1Configure = filter1.Configure(startupConfigure) 7 8 // 將filter1Configure作為filter2.Configure(filter1Configure)的參數 9 IStartupFilter filter2 = new StartupFilter2(); 10 Action<IApplicationBuilder> filter2Configure = filter2.Configure(filter1Configure)
關於IStartupFilter的例子:
1 public class AutoRequestServicesStartupFilter : IStartupFilter 2 { 3 public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) 4 { 5 return builder => 6 { 7 builder.UseMiddleware<RequestServicesContainerMiddleware>(); 8 next(builder); 9 }; 10 } 11 }
默認情況下,WebHostBuilder
在初始化時會注冊一個IStartupFilter
- AutoRequestServicesStartupFilter。
本質上,它在中間件管道的開頭添加了一個額外的中間件,即RequestServicesContainerMiddleware
。
這是唯一一個默認注冊的IStartupFilter
,因此在這種情況下,參數next
將是Startup
類的Configure
方法。
注冊IStartupFilter
1 private IServiceCollection BuildHostingServices() 2 { 3 ... 4 services.AddTransient<IStartupFilter, AutoRequestServicesStartupFilter>(); 5 ... 6 }
參考資料: