ASP.NET Core基礎知識(二)【應用啟動】

風靈使發表於2019-02-17

Startup 類配置服務和應用的請求管道。

Startup

ASP.NET Core 應用使用 Startup 類,按照約定命名為 StartupStartup 類:

  • 可選擇性地包括Microsoft.AspNetCore.Hosting.StartupBase.ConfigureServices方法以配置應用的服務。 服務是一個提供應用功能的可重用元件。 在 ConfigureServices 中配置配置(也稱為“註冊”)並通過依存關係注入 (DI) 或 Microsoft.AspNetCore.Builder.IApplicationBuilder.ApplicationServices在整個應用中使用。
  • 包括Microsoft.AspNetCore.Hosting.StartupBase.Configure方法以建立應用的請求處理管道。

當應用啟動時,執行時呼叫 ConfigureServicesConfigure

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)
    {
        ...
    }
}

在構建應用的主機時,系統為應用指定 Startup 類。 在 Program 類的主機生成器上呼叫 Build 時,將生成應用的主機。 通常通過在主機生成器上呼叫 WebHostBuilderExtensions.UseStartup<TStartup>方法來指定 Startup 類:

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

    public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
        WebHost.CreateDefaultBuilder(args)
            .UseStartup<Startup>();
}

主機提供 Startup 類建構函式可用的某些服務。 應用通過 ConfigureServices 新增其他服務。 然後,主機和應用服務都可以在 Configure 和整個應用中使用。

Startup 類中注入依賴關係的常見用途為注入:

  • IHostingEnvironment按環境配置服務。
  • IConfigurationBuilder讀取配置。
  • ILoggerFactory 在記錄器中建立 Startup.ConfigureServices
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 的替代方法是使用基於約定的方法。 應用為不同的環境(例如,StartupDevelopment)單獨定義 Startup 類時,相應的 Startup 類會在執行時被選中。 優先考慮名稱字尾與當前環境相匹配的類。 如果應用在開發環境中執行幷包含 Startup 類和 StartupDevelopment 類,則使用 StartupDevelopment 類。 有關詳細資訊,請參閱使用多個環境

要了解有關主機的詳細資訊,請參閱 ASP.NET Core 中的 Web 主機和通用主機。 有關在啟動過程中處理錯誤的資訊,請參閱啟動異常處理。

ConfigureServices 方法

ConfigureServices方法:

  • 可選。
  • Configure 方法配置應用服務之前,由主機呼叫。
  • 其中按常規設定配置選項

典型模式是呼叫所有 Add{Service} 方法,然後呼叫所有 services.Configure{Service} 方法。 有關示例,請參閱配置標識服務

主機可能會在呼叫 Startup 方法之前配置某些服務。 有關更多資訊,請參見ASP.NET Core 中的 Web 主機和通用主機

對於需要大量設定的功能,IServiceCollection上有 Add{Service} 擴充套件方法。 典型 ASP.NET Core 應用將為實體框架、標識和 MVC 註冊服務:

public void ConfigureServices(IServiceCollection services)
{
    // Add framework services.
    services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

    services.AddIdentity<ApplicationUser, IdentityRole>()
        .AddEntityFrameworkStores<ApplicationDbContext>()
        .AddDefaultTokenProviders();

    services.AddMvc();

    // Add application services.
    services.AddTransient<IEmailSender, AuthMessageSender>();
    services.AddTransient<ISmsSender, AuthMessageSender>();
}

將服務新增到服務容器,使其在應用和 Configure 方法中可用。 服務通過依賴關係注入ApplicationServices進行解析。

Configure 方法

Configure 方法用於指定應用響應 HTTP 請求的方式。 可通過將中介軟體元件新增到 IApplicationBuilder例項來配置請求管道。 Configure 方法可使用 IApplicationBuilder,但未在服務容器中註冊。 託管建立 IApplicationBuilder 並將其直接傳遞到 Configure

ASP.NET Core 模板配置的管道支援:

  • 開發人員異常頁
  • 異常處理程式
  • HTTP 嚴格傳輸安全性 (HSTS)
  • HTTPS 重定向
  • 靜態檔案
  • 一般資料保護條例 (GDPR)
  • ASP.NET Core MVC 和 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 擴充套件方法將路由中介軟體新增到請求管道,並將MVC配置為預設處理程式。

請求管道中的每個中介軟體元件負責呼叫管道中的下一個元件,或在適當情況下使鏈發生短路。 如果中介軟體鏈中未發生短路,則每個中介軟體都有第二次機會在將請求傳送到客戶端前處理該請求。

其他服務(如 IHostingEnvironmentILoggerFactory),也可以在 Configure 方法簽名中指定。 如果指定,其他服務如果可用,將被注入。

有關如何使用 IApplicationBuilder 和中介軟體處理順序的詳細資訊,請參閱 ASP.NET Core 中介軟體

便利方法

若要配置服務和請求處理管道,而不使用 Startup 類,請在主機生成器上呼叫 ConfigureServicesConfigure 便捷方法。 多次呼叫 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) =>
            {
                HostingEnvironment = hostingContext.HostingEnvironment;
                Configuration = config.Build();
            })
            .ConfigureServices(services =>
            {
                ...
            })
            .Configure(app =>
            {
                var loggerFactory = app.ApplicationServices
                    .GetRequiredService<ILoggerFactory>();
                var logger = loggerFactory.CreateLogger<Program>();

                logger.LogInformation("Logged in Configure");

                if (HostingEnvironment.IsDevelopment())
                {
                    ...
                }
                else
                {
                    ...
                }

                var configValue = Configuration["subsection:suboption1"];

                ...
            });
}

使用 Startup 篩選器擴充套件 Startup

在應用的Configure中介軟體管道的開頭或末尾使用 IStartupFilter來配置中介軟體。 IStartupFilter 有助於確保中介軟體在應用請求處理管道的開始或結束時由庫新增的中介軟體之前或之後執行。

IStartupFilter 實現單個方法(即 Configure),該方法接收並返回Action<IApplicationBuilder>
IApplicationBuilder定義用於配置應用請求管道的類。 有關詳細資訊,請參閱使用 IApplicationBuilder 建立中介軟體管道

在請求管道中,每個 IStartupFilter 實現一個或多箇中介軟體。 篩選器按照新增到服務容器的順序呼叫。 篩選器可在將控制元件傳遞給下一個篩選器之前或之後新增中介軟體,從而附加到應用管道的開頭或末尾。

下面的示例演示如何使用 IStartupFilter 註冊中介軟體。

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"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            _injectedOptions.Value.Option = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsStartupFilter 類中配置 RequestSetOptionsMiddleware

public class RequestSetOptionsStartupFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            builder.UseMiddleware<RequestSetOptionsMiddleware>();
            next(builder);
        };
    }
}

IStartupFilterConfigureServices的服務容器中註冊,引數 StartupStartup 類外部註冊:

WebHost.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddTransient<IStartupFilter, 
            RequestSetOptionsStartupFilter>();
    })
    .UseStartup<Startup>()
    .Build();

當提供 option 的查詢字串引數時,中介軟體在 MVC 中介軟體呈現響應之前處理分配值:
在這裡插入圖片描述
中介軟體執行順序由 IStartupFilter 註冊順序設定:

  • 多個 IStartupFilter 實現可能與相同的物件進行互動。 如果順序很重要,請將它們的 IStartupFilter 服務註冊進行排序,以匹配其中介軟體應有的執行順序。
  • 庫可能新增包含一個或多個 IStartupFilter 實現的中介軟體,這些實現在向 IStartupFilter 註冊的其他應用中介軟體之前或之後執行。 若要在庫的 IStartupFilter 新增中介軟體之前呼叫 IStartupFilter 中介軟體,請在將庫新增到服務容器之前定位服務註冊。 若要在此後呼叫,請在新增庫之後定位服務註冊。

在啟動時從外部程式集新增配置

通過IHostingStartup實現,可在啟動時從應用 Startup 類之外的外部程式集嚮應用新增增強功能。 有關更多資訊,請參見在 ASP.NET Core 中使用承載啟動程式集

相關文章