這篇文章簡單記錄 ASP.NET Core中 ,startup類的一些使用。
一.前言
在 Startup類中,一般有兩個方法:
- ConfigureServices 方法: 用來配置應用的 service 。
- Configure 方法:建立應用的請求處理管道
它們都在應用啟動時,被ASP.NET Core runtime 呼叫:
public class Startup { // Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { ... } // Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app) { ... } }
當應用的 host 被built(建立)時,Startup類被指定到應用中。
而在 Program 中,當 host builder 上的 Build 被呼叫時,應用的 host 被 built 。
而Startup類是通過呼叫WebHostBuilderExtensions.UseStartup<TStartup>方法指定的。
public class Program { public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); //Build方法被呼叫時,應用的host被建立,同時Startup被指定到應用中 } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .UseStartup<Startup>(); }
在startup類中,一種依賴注入的常見用法:
- IHostingEnvironment : 根據enviironment (環境) 配置 services .
- IConfiguration : 讀取配置
- ILoggerFactory : 在Startup.ConfigureServices中建立 logger .
public class Startup { private readonly IHostingEnvironment _env; private readonly IConfiguration _config; private readonly ILoggerFactory _loggerFactory; public Startup(IHostingEnvironment env, IConfiguration config, ILoggerFactory loggerFactory) { _env = env; _config = config; _loggerFactory = loggerFactory; } public void ConfigureServices(IServiceCollection services) { var logger = _loggerFactory.CreateLogger<Startup>(); if (_env.IsDevelopment()) { // Development service configuration logger.LogInformation("Development environment"); } else { // Non-development service configuration logger.LogInformation($"Environment: {_env.EnvironmentName}"); } // Configuration is available during startup. // Examples: // _config["key"] // _config["subsection:suboption1"] } }
注入IHostingEnvironment , 當定義不同環境的Startup (例如,StartupDevelopment 等),在執行時,選擇合適的Startup。
二.ConfigureServices方法
它有三個特點:
- 可選的
- 在呼叫Configure方法之前呼叫 ConfigureServices
- Configuration options 按約定設定
1. 比較典型的是呼叫 Add{Service} 和 services.Configure{Service} 。例如:Configure Identity services.
2. host 可能會 在Startup方法被呼叫之前,配置一些服務。 例如: The host.
在startup被呼叫之前,CreateDefaultBuilder方法配置了一個host 。
3. Add{Service}是IServiceCollection的擴充套件方法,下面是一些使用:
public void ConfigureServices(IServiceCollection services) { services.AddDbContext<ApplicationDbContext>(options => options.UseSqlServer( Configuration.GetConnectionString("DefaultConnection"))); services.AddDefaultIdentity<IdentityUser>() .AddDefaultUI(UIFramework.Bootstrap4) .AddEntityFrameworkStores<ApplicationDbContext>(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); // Add application services. 新增應用的服務 services.AddTransient<IEmailSender, AuthMessageSender>(); services.AddTransient<ISmsSender, AuthMessageSender>(); }
新增 services 到 service container 使它們在應用和Configure方法中可用。services方法可以通過 dependency injection 或 ApplicationServices 解析。
三.The Configure method
Configure方法用來指定應用怎樣 處理HTTP request。請求管道(request pipeline)通過新增中間元件到IApplicationBuilder例項中來配置。
ASP.NET Core 模板 配置的管道:
- Developer Exception Page
- Exception handler
- HTTP Strict Transport Security (HSTS)
- HTTPS redirection
- Static files
- General Data Protection Regulation (GDPR)
- ASP.NET Core MVC and Razor Pages
public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); app.UseHsts(); } app.UseHttpsRedirection(); app.UseStaticFiles(); app.UseCookiePolicy(); app.UseMvc(); }
使用Use擴充套件方法新增一個或多箇中間元件到請求管道。例如,UseMvc擴充套件方法新增 Routing Middleware 到請求管道 並且配置MVC 作為一個預設的處理器。
四.Convenience methods
不使用Startup類配置services和request processing pipeline。在host builder 上呼叫ConfigureServices和Configure的簡便方法。如果存在多個ConfigureServices的呼叫,會依次新增。如果存在多個Configure方法的呼叫,最後一個Configure的呼叫會被使用。
public class Program { public static IHostingEnvironment HostingEnvironment { get; set; } public static IConfiguration Configuration { get; set; } public static void Main(string[] args) { CreateWebHostBuilder(args).Build().Run(); } public static IWebHostBuilder CreateWebHostBuilder(string[] args) => WebHost.CreateDefaultBuilder(args) .ConfigureAppConfiguration((hostingContext, config) => { }) .ConfigureServices(services => { ... }) .Configure(app => { var loggerFactory = app.ApplicationServices .GetRequiredService<ILoggerFactory>(); var logger = loggerFactory.CreateLogger<Program>(); var env = app.ApplicationServices.GetRequiredServices<IHostingEnvironment>(); var config = app.ApplicationServices.GetRequiredServices<IConfiguration>(); logger.LogInformation("Logged in Configure"); if (env.IsDevelopment()) { ... } else { ... } var configValue = config["subsection:suboption1"]; ... }); }
五.Extend Startup with startup filters (使用startup filter擴充套件 Startup)
使用 IStartupFilter ,在應用的Configure 中介軟體管道的開頭或末尾配置中介軟體。
IStartupFilter 實現Configure方法,它會接收和返回一個Action<IApplicationBuilder>。而IApplicationBuilder定義了一個類來配置一個應用的請求管道。
這些filters會按照新增到services container的順序被呼叫。
下面是一個例子:
RequestSetOptionsMiddleware
public class RequestSetOptionsMiddleware { private readonly RequestDelegate _next; private IOptions<AppOptions> _injectedOptions; public RequestSetOptionsMiddleware( RequestDelegate next, IOptions<AppOptions> injectedOptions) { _next = next; _injectedOptions = injectedOptions; } public async Task Invoke(HttpContext httpContext) { Console.WriteLine("RequestSetOptionsMiddleware.Invoke"); var option = httpContext.Request.Query["option"]; //取請求中的option引數 if (!string.IsNullOrWhiteSpace(option)) { _injectedOptions.Value.Option = WebUtility.HtmlEncode(option); } await _next(httpContext); } }
RequestSetOptionsMiddleware 中介軟體被配置在 RequestSetOptionsStartupFilter 類中:
public class RequestSetOptionsStartupFilter : IStartupFilter { public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next) { return builder => { builder.UseMiddleware<RequestSetOptionsMiddleware>(); next(builder); }; } }
IStartupFilter 在 ConfigureServices中被註冊到 service container, 並且從Startup類的外部增強Startup:
WebHost.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddTransient<IStartupFilter, RequestSetOptionsStartupFilter>(); }) .UseStartup<Startup>() .Build();
當option的查詢字串存在時,中介軟體會在MVC中介軟體之前處理這個值
中介軟體的執行順序是按照IStartupFilter的註冊順序
六. 補充
這裡晚上補充下 ApplicationServices 解析services的使用
參考網址:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-2.2