ASP.NET Core 中的應用程式啟動App startup in ASP.NET Core

作者:Rick AndersonTom DykstraLuke Latham 以及 Steve SmithBy Rick Anderson, 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
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

上述範例適用於 Razor Pages與 MVC 版本類似。The preceding sample is for Razor Pages; the MVC version is similar.

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 when the app's host is built. Startup 類別通常會藉由呼叫主機產生器上的 WebHostBuilderExtensions.UseStartup<TStartup> 方法來指定:The Startup class is typically 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>();
}
public class Program
{
    public static void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.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 available in Configure and throughout the app.

使用 IHostBuilder 時,只能將下列服務型別插入 Startup 建構函式:Only the following service types can be injected into the Startup constructor when using IHostBuilder:

public class Startup
{
    private readonly IWebHostEnvironment _env;
    public IConfiguration Configuration { get; }

    public Startup(IWebHostEnvironment env, IConfiguration configuration)
    {
        Configuration = configuration;
        _env = env;
    }

    public void ConfigureServices(IServiceCollection services)
    {
        if (_env.IsDevelopment())
        {
        }
        else
        {
        }
        //   _config["key"]
    }
}

在呼叫 Configure 方法之前,大部分的服務都無法使用。Most services are not available until the Configure method is called.

主機會提供可供 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"]
    }
}

在呼叫 Configure 方法之前,大部分的服務都無法使用。Most services are not available until the Configure method is called.

多次啟動Multiple StartUp

應用程式針對不同的環境定義個別的 Startup 類別 (例如 StartupDevelopment) 時,會在執行階段選取適當的 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.

如需主機的詳細資訊,請參閱主機See The host for more information on 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.

主機可能會在呼叫 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. 例如 AddDbContext、AddDefaultIdentity、AddEntityFrameworkStores 和 AddRazorPages:For example, AddDbContext, AddDefaultIdentity, AddEntityFrameworkStores, and AddRazorPages:

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        services.AddDbContext<ApplicationDbContext>(options =>
            options.UseSqlServer(
                Configuration.GetConnectionString("DefaultConnection")));
        services.AddDefaultIdentity<IdentityUser>(
            options => options.SignIn.RequireConfirmedAccount = true)
            .AddEntityFrameworkStores<ApplicationDbContext>();

        services.AddRazorPages();
    }
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 以取得 SetCompatibilityVersion 的詳細資訊。See 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. IApplicationBuilder 可用於 Configure 方法,但它未註冊在服務容器中。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 class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddRazorPages();
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Error");
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

        app.UseAuthorization();

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

上述範例適用於 Razor Pages與 MVC 版本類似。The preceding sample is for Razor Pages; the MVC version is similar.

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. 例如,UseStaticFiles 會設定中介軟體來提供靜態檔案For instance, UseStaticFiles configures middleware to serve static files.

要求管線中的每個中介軟體元件負責叫用管線中的下一個元件,或於適當時,對鏈結執行最少運算。Each middleware component in the request pipeline is responsible for invoking the next component in the pipeline or short-circuiting the chain, if appropriate.

IWebHostEnvironmentILoggerFactory 或任何在 ConfigureServices 中定義的其他服務,也可以在 Configure 方法簽章中指定。Additional services, such as IWebHostEnvironment, ILoggerFactory, or anything defined in ConfigureServices, can be specified in the Configure method signature. 這些服務在可用時即會插入。These services are injected if they're available.

IHostingEnvironmentILoggerFactory 等其他服務,或任何在 ConfigureServices 中定義的項目,也可以在 Configure 方法簽章中指定。Additional services, such as IHostingEnvironment and ILoggerFactory, or anything defined in ConfigureServices, can be specified in the Configure method signature. 這些服務在可用時即會插入。These 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 中介軟體.

在不啟動的情況下設定服務Configure services without Startup

若要設定服務及要求處理管線,且不使用 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 void Main(string[] args)
    {
        CreateHostBuilder(args).Build().Run();
    }

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
           .ConfigureAppConfiguration((hostingContext, config) =>
           {
           })
        .ConfigureServices(services =>
        {
            services.AddControllersWithViews();

        }).ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.Configure(app =>
            {
                var loggerFactory = app.ApplicationServices
                        .GetRequiredService<ILoggerFactory>();
                var logger = loggerFactory.CreateLogger<Program>();
                var env = app.ApplicationServices.GetRequiredService<IWebHostEnvironment>();
                var config = app.ApplicationServices.GetRequiredService<IConfiguration>();

                logger.LogInformation("Logged in Configure");

                if (env.IsDevelopment())
                {
                    app.UseDeveloperExceptionPage();
                }
                else
                {
                    app.UseExceptionHandler("/Home/Error");
                    app.UseHsts();
                }

                var configValue = config["MyConfigKey"];
            }
            );
        });
}
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"];

                ...
            });
}

使用啟動篩選條件來擴充啟動Extend Startup with startup filters

使用 IStartupFilter 在應用程式的 Configure 中介軟體管線的開頭或結尾設定中介軟體。Use IStartupFilter to configure middleware at the beginning or end of an app's Configure middleware pipeline. IStartupFilter 用來建立 Configure 方法的管線。IStartupFilter is used to create a pipeline of Configure methods. IStartupFilter.Configure 可以將中介軟體設為在程式庫新增中介軟體之前或之後執行。IStartupFilter.Configure can set a middleware to run before or after middleware added by libraries.

IStartupFilter 會實作 Configure,其會接收並傳回 Action<IApplicationBuilder>IStartupFilter implements 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 can add 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;

    public RequestSetOptionsMiddleware( RequestDelegate next )
    {
        _next = next;
    }

    // Test with https://localhost:5001/Privacy/?option=Hello
    public async Task Invoke(HttpContext httpContext)
    {
        var option = httpContext.Request.Query["option"];

        if (!string.IsNullOrWhiteSpace(option))
        {
            httpContext.Items["option"] = WebUtility.HtmlEncode(option);
        }

        await _next(httpContext);
    }
}

RequestSetOptionsMiddleware 設定在 RequestSetOptionsStartupFilter 類別中:The 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);
        };
    }
}
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);
    }
}

RequestSetOptionsMiddleware 設定在 RequestSetOptionsStartupFilter 類別中:The 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);
        };
    }
}

IStartupFilter 註冊在 ConfigureServices 的服務容器中。The IStartupFilter is registered in the service container in ConfigureServices.

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

    public static IHostBuilder CreateHostBuilder(string[] args) =>
        Host.CreateDefaultBuilder(args)
           .ConfigureAppConfiguration((hostingContext, config) =>
           {
           })
         .ConfigureWebHostDefaults(webBuilder =>
         {
             webBuilder.UseStartup<Startup>();
         })
        .ConfigureServices(services =>
        {
            services.AddTransient<IStartupFilter,
                      RequestSetOptionsStartupFilter>();
        });
}
WebHost.CreateDefaultBuilder(args)
    .ConfigureServices(services =>
    {
        services.AddTransient<IStartupFilter, 
            RequestSetOptionsStartupFilter>();
    })
    .UseStartup<Startup>()
    .Build();

提供 option 的查詢字串參數時,中介軟體會在 ASP.NET Core 中介軟體轉譯回應之前,先處理值指派。When a query string parameter for option is provided, the middleware processes the value assignment before the ASP.NET Core 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 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