ASP.NET Core 中的应用启动App startup in ASP.NET Core

作者:Tom DykstraLuke LathamSteve SmithBy Tom Dykstra, Luke Latham, and Steve Smith

Startup 类配置服务和应用的请求管道。The Startup class configures services and the app's request pipeline.

Startup 类The Startup class

ASP.NET Core 应用使用 Startup 类,按照约定命名为 StartupASP.NET Core apps use a Startup class, which is named Startup by convention. Startup 类:The Startup class:

  • 可选择性地包括 ConfigureServices 方法以配置应用的服务。Optionally includes a ConfigureServices method to configure the app's services. 服务是一个提供应用功能的可重用组件。A service is a reusable component that provides app functionality. ConfigureServices 中配置配置(也称为“注册”)并通过依存关系注入 (DI)ApplicationServices 在整个应用中使用。Services are configured—also described as registered—in ConfigureServices and consumed across the app via dependency injection (DI) or ApplicationServices.
  • 包括 Configure 方法以创建应用的请求处理管道。Includes a Configure method to create the app's request processing pipeline.

在应用启动时,ASP.NET Core 运行时会调用 ConfigureServicesConfigureConfigureServices and Configure are called by the ASP.NET Core runtime when the app starts:

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 类。The Startup class is specified to the app when the app's host is built. Program 类的主机生成器上调用 Build 时,将生成应用的主机。The app's host is built when Build is called on the host builder in the Program class. 通常通过在主机生成器上调用 WebHostBuilderExtensions.UseStartup<TStartup> 方法来指定 Startup 类:The Startup class is usually specified by calling the WebHostBuilderExtensions.UseStartup<TStartup> method on the host builder:

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 类构造函数可用的某些服务。The host provides services that are available to the Startup class constructor. 应用通过 ConfigureServices 添加其他服务。The app adds additional services via ConfigureServices. 然后,主机和应用服务都可以在 Configure 和整个应用中使用。Both the host and app services are then available in Configure and throughout the app.

Startup 类中注入依赖关系的常见用途为注入:A common use of dependency injection into the Startup class is to inject:

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 的替代方法是使用基于约定的方法。An alternative to injecting IHostingEnvironment is to use a conventions-based approach. 应用为不同的环境(例如,StartupDevelopment)单独定义 Startup 类时,相应的 Startup 类会在运行时被选中。When the app defines separate Startup classes for different environments (for example, StartupDevelopment), the appropriate Startup class is selected at runtime. 优先考虑名称后缀与当前环境相匹配的类。The class whose name suffix matches the current environment is prioritized. 如果应用在开发环境中运行并包含 Startup 类和 StartupDevelopment 类,则使用 StartupDevelopment 类。If the app is run in the Development environment and includes both a Startup class and a StartupDevelopment class, the StartupDevelopment class is used. 有关详细信息,请参阅使用多个环境For more information, see Use multiple environments.

要详细了解有关主机的详细信息,请参阅主机To learn more about the host, see The host. 有关在启动过程中处理错误的信息,请参阅启动异常处理For information on handling errors during startup, see Startup exception handling.

ConfigureServices 方法The ConfigureServices method

ConfigureServices 方法:The ConfigureServices method is:

  • 可选。Optional.
  • Configure 方法配置应用服务之前,由主机调用。Called by the host before the Configure method to configure the app's services.
  • 其中按常规设置配置选项Where configuration options are set by convention.

典型模式是调用所有 Add{Service} 方法,然后调用所有 services.Configure{Service} 方法。The typical pattern is to call all the Add{Service} methods and then call all of the services.Configure{Service} methods. 有关示例,请参阅配置标识服务For example, see Configure Identity services.

主机可能会在调用 Startup 方法之前配置某些服务。The host may configure some services before Startup methods are called. 有关详细信息,请参阅主机For more information, see The host.

对于需要大量设置的功能,IServiceCollection 上有 Add{Service} 扩展方法。For features that require substantial setup, there are Add{Service} extension methods on IServiceCollection. 典型 ASP.NET Core 应用将为实体框架、标识和 MVC 注册服务:A typical ASP.NET Core app registers services for Entity Framework, Identity, and MVC:

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>();
}

将服务添加到服务容器,使其在应用和 Configure 方法中可用。Adding services to the service container makes them available within the app and in the Configure method. 服务通过依赖关系注入ApplicationServices 进行解析。The services are resolved via dependency injection or from ApplicationServices.

若要详细了解 SetCompatibilityVersion,请参阅 SetCompatibilityVersionSee SetCompatibilityVersion for more information on SetCompatibilityVersion.

Configure 方法The Configure method

Configure 方法用于指定应用响应 HTTP 请求的方式。The Configure method is used to specify how the app responds to HTTP requests. 可通过将中间件组件添加到 IApplicationBuilder 实例来配置请求管道。The request pipeline is configured by adding middleware components to an IApplicationBuilder instance. Configure 方法可使用 IApplicationBuilder,但未在服务容器中注册。IApplicationBuilder is available to the Configure method, but it isn't registered in the service container. 托管创建 IApplicationBuilder 并将其直接传递到 ConfigureHosting creates an IApplicationBuilder and passes it directly to Configure.

ASP.NET Core 模板配置的管道支持:The ASP.NET Core templates configure the pipeline with support for:

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 扩展方法将一个或多个中间件组件添加到请求管道。Each Use extension method adds one or more middleware components to the request pipeline. 例如,UseMvc 扩展方法将路由中间件添加到请求管道,并将 MVC 配置为默认处理程序。For instance, the UseMvc extension method adds Routing Middleware to the request pipeline and configures MVC as the default handler.

请求管道中的每个中间件组件负责调用管道中的下一个组件,或在适当情况下使链发生短路。Each middleware component in the request pipeline is responsible for invoking the next component in the pipeline or short-circuiting the chain, if appropriate. 如果中间件链中未发生短路,则每个中间件都有第二次机会在将请求发送到客户端前处理该请求。If short-circuiting doesn't occur along the middleware chain, each middleware has a second chance to process the request before it's sent to the client.

其他服务(如 IHostingEnvironmentILoggerFactory),也可以在 Configure 方法签名中指定。Additional services, such as IHostingEnvironment and ILoggerFactory, may also be specified in the Configure method signature. 如果指定,其他服务如果可用,将被注入。When specified, additional services are injected if they're available.

有关如何使用 IApplicationBuilder 和中间件处理顺序的详细信息,请参阅 ASP.NET Core 中间件For more information on how to use IApplicationBuilder and the order of middleware processing, see ASP.NET Core 中间件.

便利方法Convenience methods

若要配置服务和请求处理管道,而不使用 Startup 类,请在主机生成器上调用 ConfigureServicesConfigure 便捷方法。To configure services and the request processing pipeline without using a Startup class, call ConfigureServices and Configure convenience methods on the host builder. 多次调用 ConfigureServices 将追加到另一个。Multiple calls to ConfigureServices append to one another. 如果存在多个 Configure 方法调用,则使用最后一个 Configure 调用。If multiple Configure method calls exist, the last Configure call is used.

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.GetRequiredService<IHostingEnvironment>();
                var config = app.ApplicationServices.GetRequiredService<IConfiguration>();

                logger.LogInformation("Logged in Configure");

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

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

                ...
            });
}

使用 Startup 筛选器扩展 StartupExtend Startup with startup filters

在应用的 Configure 中间件管道的开头或末尾使用 IStartupFilter 来配置中间件。Use IStartupFilter to configure middleware at the beginning or end of an app's Configure middleware pipeline. IStartupFilter 有助于确保中间件在应用请求处理管道的开始或结束时由库添加的中间件之前或之后运行。IStartupFilter is useful to ensure that a middleware runs before or after middleware added by libraries at the start or end of the app's request processing pipeline.

IStartupFilter 实现单个方法(即 Configure),该方法接收并返回 Action<IApplicationBuilder>IStartupFilter implements a single method, Configure, which receives and returns an Action<IApplicationBuilder>. IApplicationBuilder 定义用于配置应用请求管道的类。An IApplicationBuilder defines a class to configure an app's request pipeline. 有关详细信息,请参阅使用 IApplicationBuilder 创建中间件管道For more information, see Create a middleware pipeline with IApplicationBuilder.

在请求管道中,每个 IStartupFilter 实现一个或多个中间件。Each IStartupFilter implements one or more middlewares in the request pipeline. 筛选器按照添加到服务容器的顺序调用。The filters are invoked in the order they were added to the service container. 筛选器可在将控件传递给下一个筛选器之前或之后添加中间件,从而附加到应用管道的开头或末尾。Filters may add middleware before or after passing control to the next filter, thus they append to the beginning or end of the app pipeline.

下面的示例演示如何使用 IStartupFilter 注册中间件。The following example demonstrates how to register a middleware with IStartupFilter.

RequestSetOptionsMiddleware 中间件从查询字符串参数中设置选项值:The RequestSetOptionsMiddleware middleware sets an options value from a query string parameter:

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 类中配置 RequestSetOptionsMiddlewareThe RequestSetOptionsMiddleware is configured in the RequestSetOptionsStartupFilter class:

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

IStartupFilterConfigureServices 的服务容器中注册,参数 StartupStartup 类外部注册:The IStartupFilter is registered in the service container in ConfigureServices and augments Startup from outside of the Startup class:

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

当提供 option 的查询字符串参数时,中间件在 MVC 中间件呈现响应之前处理分配值:When a query string parameter for option is provided, the middleware processes the value assignment before the MVC middleware renders the response:

浏览器窗口显示已呈现的索引页。

中间件执行顺序由 IStartupFilter 注册顺序设置:Middleware execution order is set by the order of IStartupFilter registrations:

  • 多个 IStartupFilter 实现可能与相同的对象进行交互。Multiple IStartupFilter implementations may interact with the same objects. 如果顺序很重要,请将它们的 IStartupFilter 服务注册进行排序,以匹配其中间件应有的运行顺序。If ordering is important, order their IStartupFilter service registrations to match the order that their middlewares should run.
  • 库可能添加包含一个或多个 IStartupFilter 实现的中间件,这些实现在向 IStartupFilter 注册的其他应用中间件之前或之后运行。Libraries may add middleware with one or more IStartupFilter implementations that run before or after other app middleware registered with IStartupFilter. 若要在库的 IStartupFilter 添加中间件之前调用 IStartupFilter 中间件,请在将库添加到服务容器之前定位服务注册。To invoke an IStartupFilter middleware before a middleware added by a library's IStartupFilter, position the service registration before the library is added to the service container. 若要在此后调用,请在添加库之后定位服务注册。To invoke it afterward, position the service registration after the library is added.

在启动时从外部程序集添加配置Add configuration at startup from an external assembly

通过 IHostingStartup 实现,可在启动时从应用 Startup 类之外的外部程序集向应用添加增强功能。An IHostingStartup implementation allows adding enhancements to an app at startup from an external assembly outside of the app's Startup class. 有关更多信息,请参见在 ASP.NET Core 中使用承载启动程序集For more information, see 在 ASP.NET Core 中使用承载启动程序集.

其他资源Additional resources