asp.net core 系列之Startup

這篇文章簡單記錄 ASP.NET Core中 ,startup類的一些使用。api

 一.前言

Startup類中,通常有兩個方法:mvc

  • ConfigureServices 方法: 用來配置應用的 service 。 
  • Configure 方法:建立應用的請求處理管道

它們都在應用啓動時,被ASP.NET Core runtime 調用:app

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類被指定到應用中。async

而在 Program 中,當 host builder 上的 Build 被調用時,應用的 host 被 built 。ide

Startup類是經過調用WebHostBuilderExtensions.UseStartup<TStartup>方法指定的。ui

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類中,一種依賴注入的常見用法:this

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。 spa

二.ConfigureServices方法

它有三個特色:code

  • 可選的 
  • 在調用Configure方法以前調用 ConfigureServices
  • Configuration options 按約定設置

1. 比較典型的是調用 Add{Service} 和 services.Configure{Service} 。例如:Configure Identity services.orm

 

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 模板 配置的管道:

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的使用

IApplicationBuilder app 

app.ApplicationServices.GetService 方法

如上,IApplicationBuilder類型,便可獲得ApplicationServices,而後利用其方法來解析services

 

參考網址:

https://docs.microsoft.com/en-us/aspnet/core/fundamentals/startup?view=aspnetcore-2.2

相關文章
相關標籤/搜索