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

Note

這不是這篇文章的最新版本。 關於目前版本,請參閱 本文的 .NET 10 版本。

Warning

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 關於目前版本,請參閱 本文的 .NET 10 版本。

本文說明 ASP.NET Core 應用程式如何啟動,以及如何配置服務與應用程式的請求管線。

有關補充或取代本文指導的Blazor 啟動指導,請參閱 ASP.NET Core Blazor 啟動。

該Program檔案

ASP.NET Core 應用程式會在應用程式檔案ProgramProgram.cs中初始化並設定啟動()。

檔案的第一部分 Program 著重於開發應用程式。 此階段會利用 WebApplication.CreateBuilder,在應用程式啟動前,使用預先設定好的預設值初始化 WebApplicationBuilder 類別的新執行個體。 ASP.NET Core 專案範本會將 Web 應用程式建構器指派給名為 builder 的變數:

var builder = WebApplication.CreateBuilder(args);

網頁應用程式建構器的特性包括:

應用程式是透過呼叫 WebApplicationBuilder.Build 來建構的,該呼叫會傳回建構好的 WebApplication。 ASP.NET Core 專案範本會將建置好的 Web 應用程式指派給一個名為 app 的變數:

var app = builder.Build();

Program 檔案的下一部分著重於將 HTTP 請求處理管線建構成一系列 中介軟體元件。 每個中介軟體都會對 HttpContext 執行作業,並呼叫管線中的下一個中介軟體,或終止要求。 依慣例,中介軟體元件會透過呼叫以「Use」開頭的擴充方法來加入管線。欲了解更多資訊,請參見 ASP.NET Core 中介軟體。

此 Run 方法啟動應用程式並封鎖呼叫執行緒,直到主機關閉:

app.Run();

執行時 Run ,應用程式會切換為一個正在執行的主動程序:

  1. 託管服務開始。

    主機會迴圈瀏覽所有註冊 的託管服務 (IHostedService 實例),並呼叫他們的 StartAsync 方法。 除非應用程式選擇同時啟動託管服務(.NET 8 或更新版本),否則託管服務會依照其 DI 容器註冊順序開始。 欲了解更多資訊,請參閱 ASP.NET Core 中託管服務的背景任務。

  2. 中介軟體管線已建置完成。

    當 builder.Build 被呼叫時,相依關係會被解決,但實際的處理流程尚未完全設定。 當 app.Run 執行時,框架會完成 HTTP 中介軟體管線的定案。 宣告的中介軟體方法與端點映射會編譯成單一的高效能執行代理序列。 更多資訊請參閱 ASP.NET Core 中介軟體。

  3. 網頁伺服器(Kestrel 預設)已經啟動。

    主機會查看其相依容器,找到註冊的伺服器實作(通常是 Kestrel),並觸發啟動週期。 Kestrel 然後:

    • 查詢設定、環境變數或命令列參數中定義的主機 URL 與埠碼。
    • 開啟並分配實體網路插槽。
    • 綁定埠口並開始監聽進來流量。

    欲了解更多資訊,請參閱 ASP.NET Core 中的 .NET 通用主機、ASP.NET Core 中的網頁伺服器實作,以及 Kestrel ASP.NET Core 中的網頁伺服器。

  4. 應用程式啟動的生命週期事件會被觸發。

    IHostApplicationLifetime 服務會觸發其 ApplicationStarted 權杖,進而叫用已在該權杖上註冊的回呼函式。 任何已設定為在權杖觸發時執行的回呼、資料庫種子程式或其他自訂事件監聽器,都會被觸發並開始處理。

  5. 主執行緒在應用程式執行時會被阻擋。

    Run app.Run()() 同步等待直到關機。

  6. 應用程式已準備好處理請求。

    此時,指令殼會記錄承載診斷資料:

    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: https://localhost:7123
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: http://localhost:5123
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    

應用程式會無限期維持這種狀態,透過中介軟體管線傳遞進來的網頁流量並發送回應。

當關閉訊號被通知時,例如執行應用程式的命令殼偵測到 Ctrl+c 或容器協調工具發送 SIGTERM 事件時, Run 封鎖解除並執行以下動作:

  1. ApplicationStopping 標記會被觸發,讓應用程式在關機程序開始前能執行邏輯。

  2. Kestrel伺服器會關閉,導致新連線失效。 伺服器會在關機逾時允許的時間內,等待現有連線上的請求完成。 伺服器會傳送連線關閉標頭,以取得現有連線上的進一步要求。

  3. 主機關閉了註冊的託管服務。 除非應用程式選擇同時停止託管服務(.NET 8 或更新版本),否則託管服務會依照其 DI 容器註冊的順序順序停止。 欲了解更多資訊,請參閱 ASP.NET Core 中託管服務的背景任務。

  4. ApplicationStopped 事件處理器會被觸發,讓應用程式在關閉後仍能執行邏輯。

  5. 主控台執行會正常結束,結束代碼為 0。

Startup 類別可設定服務和應用程式的要求管線。

Startup 類別

ASP.NET Core 應用程式使用一個啟動類別,該類別依慣例命名Startup。 Startup 類別:

  • 選擇性地包含 ConfigureServices 方法來設定應用程式的服務。 服務的定義是可提供應用程式功能的可重複使用元件。 在應用程式中,服務會註冊於並透過ConfigureServices或消費服務。
  • 包含 Configure 方法來建立應用程式的要求處理管線。

應用程式啟動時,ASP.NET Core 執行階段會呼叫 ConfigureServices 與 Configure:

public class Startup
{
    public void ConfigureServices(IServiceCollection services)
    {
        ...
    }

    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        ...
    }
}

當應用程式的 Startup 被建置時,會指定 類別。 該 Startup 類別通常透過呼叫 WebHostBuilderExtensions.UseStartup 主機建構者來指定:

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 類別建構函式使用的服務。 應用程式會透過 ConfigureServices 新增其他服務。 主機和應用程式服務都可在 Configure 及應用程式的各個部分中使用。

使用 Startup () 時,只能將下列服務類型插入 IHostBuilder 建構函式:

public class Startup
{
    private readonly IWebHostEnvironment _env;

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

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        if (_env.IsDevelopment())
        {
        }
        else
        {
        }
    }
}

在呼叫 Configure 方法之前,大多數服務都無法使用。

Note

前述範例 IWebHostEnvironment 中的私有欄位以底線_env()命名。 當私有欄位使用this關鍵字this.env = env(在建構子和env.IsDevelopment()ConfigureServices方法中)時,採用與注入IWebHostEnvironmentenv欄位名稱相同的編碼慣例也是可以接受的。

.NET 8 和 C# 12 之前的 ASP.NET Core 專案範本不採用主要建構子,但如果組織使用 .NET 8 或更新 SDK,且應用程式目標為 C# 12 或更新版本(例如 <LangVersion>12.0</LangVersion>)。 欲了解更多資訊,請參閱「宣告主建構子關於類別與結構」(C# 文件教學)及主建構子(C# 指南)。

多個 Startup 類別

應用程式針對不同的環境定義個別的 Startup 類別 (例如 StartupDevelopment) 時,會在執行階段選取適當的 Startup 類別。 將優先使用其名稱尾碼符合目前環境的類別。 如果應用程式在 Development 環境中執行,且包含一個 Startup 類別和一個 StartupDevelopment 類別,則會使用該 StartupDevelopment 類別。 如需詳細資訊,請參閱使用多重環境。

ConfigureServices 方法

可選的 ConfigureServices 方法為:

  • 由主機在 Configure 方法之前呼叫,來設定應用程式的服務。
  • 組態選項按照慣例進行設定。

主機可能會在呼叫 Startup 方法之前,設定一些服務。 如需詳細資訊,請參閱 ASP.NET Core 基本概念概觀。

對於需要大量設定的功能,IServiceCollection 上有 Add{Service} 擴充方法,例如:

  • AddDbContext
  • AddDefaultIdentity
  • AddEntityFrameworkStores
  • 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();
    }
}

將服務新增至服務容器,使其可在應用程式和 Configure 方法內使用。 服務可透過依賴注入或從 ApplicationServices 獲得解析。

Configure 方法

Configure 方法可用來指定應用程式對 HTTP 要求的回應方式。 藉由將中介軟體元件新增至 IApplicationBuilder 執行個體,即可設定要求管線。 IApplicationBuilder 可用於 Configure 方法,但它未註冊在服務容器中。 裝載會建立 IApplicationBuilder,並將它直接傳遞到 Configure。

ASP.NET Core 範本將管線配置為支援以下內容:

以下範例展示了典型 Razor Pages 應用程式的中介軟體:

public class Startup
{
    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.UseEndpoints(endpoints =>
        {
            endpoints.MapRazorPages();
        });
    }
}

上述範例適用於 Razor Pages;MVC 版本也類似。

各 Use 擴充方法會將一或多個中介軟體元件新增到要求管線。 例如,UseStaticFiles 會設定中介軟體來提供靜態檔案。

在請求管線中,每個中介件負責呼叫管線中的下一個元件,或在適當情況下中斷鏈結。

IWebHostEnvironment、ILoggerFactory 或任何在 ConfigureServices 中定義的其他服務,也可以在 Configure 方法簽章中指定。 這些服務會在可用時注入。

欲了解更多如何使用IApplicationBuilder及中介軟體處理順序,請參見 ASP.NET Core 中介軟體。

配置不使用 Startup 類別的服務

若要設定服務及要求處理管線,且不使用 Startup 類別,請在主機建立器上呼叫 ConfigureServices 及 Configure 便利方法。 多次呼叫 ConfigureServices 會互相追加。 若多個 Configure 方法呼叫存在,則會使用最後的 Configure 呼叫。

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.ConfigureServices(services =>
                {
                    ...
                })
                .Configure(app =>
                {
                    ...
                });
        });
}

啟動篩選器

雖然應用程式通常會建立明確的中介軟體執行管線,但啟動過濾器(IStartupFilter)對於以下用途非常有用:

  • 建立一個共享函式庫/NuGet 套件,自動載入自訂中介軟體,而不需要應用程式明確呼叫中介軟體的「Use」方法。 例如,圖書館的使用者不必在應用程式的請求處理管線中呼叫 app.UseImageProcessingMiddleware 影像處理中介軟體。
  • 確保一個中介軟體在其他中介軟體之前或之後執行,無論開發者如何修改應用程式的請求處理流程。

啟動篩選器實作提供一個 IStartupFilter.Configure 方法,此方法會接收並傳回 Action<IApplicationBuilder>。 介面 IApplicationBuilder 用來配置應用程式的請求管線。 欲了解更多資訊,請參閱 「建立使用 IApplicationBuilder 的中介軟體管線」。

每個啟動過濾器實作都可以在請求管線中新增一個或多個中介軟體。 過濾器會依其加入服務容器的順序依序叫用。 過濾器可以在將控制權交給下一個過濾器之前或之後加入中介軟體,因此它們會附加在管線的開始或結束處。

以下範例示範如何使用 IStartupFilter 註冊中介軟體。 CustomResponseHeaderFilter啟動過濾器會利用中介軟體在應用程式執行前,為所有回應附加自訂標頭(X-Custom-Header)。

CustomResponseHeaderFilter.cs:

using System;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;

public class CustomResponseHeaderFilter : IStartupFilter
{
    public Action<IApplicationBuilder> Configure(Action<IApplicationBuilder> next)
    {
        return builder =>
        {
            // 1. Add middleware that runs BEFORE subsequent middlewares
            builder.Use(async (context, nextMiddleware) =>
            {
                context.Response.Headers.Append("X-Custom-Header", "VALUE");
                await nextMiddleware();
            });

            // 2. Call the rest of the application's configuration pipeline
            next(builder);

            // 3. (Optional) Add middleware that runs AFTER the rest of the pipeline
        };
    }
}

啟動過濾器的實作註冊在以下 Program 檔案中:

builder.Services.AddTransient<IStartupFilter, CustomResponseHeaderFilter>();

啟動過濾器的實作會註冊於 Startup.ConfigureServices:

services.AddTransient<IStartupFilter, CustomResponseHeaderFilter>();

中介軟體的執行順序由啟動過濾器註冊的順序決定:

  • 多個實作可能會與相同的物件互動。 如果排序很重要,請讓他們的服務註冊順序與中介軟體應有的運行順序相符。
  • 函式庫可以新增具有一或多個實作的中介軟體,且這些實作會在使用 IStartupFilter 註冊的其他應用程式中介軟體之前或之後執行。 要在函式庫啟動過濾器新增的中介軟體之前呼叫啟動過濾器中介軟體:
    • 將啟動篩選服務註冊置於函式庫新增至服務容器之前。
    • 若要在後續叫用,請在加入程式庫後放置服務註冊。

Note

當你覆寫 `Configure` 委派時,就無法使用啟動篩選器來擴充 ASP.NET Core 應用程式。 欲了解更多資訊,請參閱 WebApplicationFactory 用戶端對所有使用 Overriding Configure 方法dotnet/aspnetcore (#45372)的請求回傳 NotFound。

在啟動時從外部組件新增組態

IHostingStartup 實作可讓您在應用程式啟動時,從應用程式的 Program 檔案或 Startup 類別之外的外部組件新增增強功能。 如需詳細資訊,請參閱使用 ASP.NET Core 的主機啟動組件 (部分機器翻譯)。

Startup類別(ConfigureServices及其Configure方法)

雖然支援針對 .NET 6 或更新版本的 ASP.NET Core 應用程式,但不建議使用類別Startup。 如需詳細資訊,請參閱 從 .NET 5 中的 ASP.NET Core 移轉至 .NET 6。

如需了解如何搭配最小主控模型使用 ConfigureServices 和 Configure 方法的資訊,請參閱以下內容:

衡量新創公司績效

ASP.NET Core EventSource 主機會發出該ServerReady事件,代表伺服器準備好回應請求的時刻,並可用來衡量啟動時間。 如需進一步了解,請參閱 .NET 和 ASP.NET Core 中的日誌功能。