撰寫自訂的 ASP.NET Core 中介軟體Write custom ASP.NET Core middleware

Rick AndersonSteve Smith 撰寫By Rick Anderson and Steve Smith

中介軟體為組成應用程式管線的軟體,用以處理要求與回應。Middleware is software that's assembled into an app pipeline to handle requests and responses. ASP.NET Core 提供一組豐富的內建中介軟體元件,但在某些情況下,您可能想要撰寫自訂的中介軟體。ASP.NET Core provides a rich set of built-in middleware components, but in some scenarios you might want to write a custom middleware.

中介軟體類別Middleware class

中介軟體通常封裝在類別中,並以擴充方法公開。Middleware is generally encapsulated in a class and exposed with an extension method. 請考慮下列中介軟體,其會為來自查詢字串的目前要求設定文化特性:Consider the following middleware, which sets the culture for the current request from a query string:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use((context, next) =>
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                var culture = new CultureInfo(cultureQuery);

                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;
            }

            // Call the next delegate/middleware in the pipeline
            return next();
        });

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync(
                $"Hello {CultureInfo.CurrentCulture.DisplayName}");
        });

    }
}

上述範例程式碼用於示範中介軟體元件的建立。The preceding sample code is used to demonstrate creating a middleware component. 如需 ASP.NET Core 的內建當地語系化支援,請參閱 ASP.NET Core 全球化和當地語系化For ASP.NET Core's built-in localization support, see ASP.NET Core 全球化和當地語系化.

您可以藉由傳入文化特性來測試中介軟體。You can test the middleware by passing in the culture. 例如,http://localhost:7997/?culture=noFor example, http://localhost:7997/?culture=no.

下列程式碼會將中介軟體委派移至類別:The following code moves the middleware delegate to a class:

using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;

namespace Culture
{
    public class RequestCultureMiddleware
    {
        private readonly RequestDelegate _next;

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

        public async Task InvokeAsync(HttpContext context)
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                var culture = new CultureInfo(cultureQuery);

                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;

            }

            // Call the next delegate/middleware in the pipeline
            await _next(context);
        }
    }
}

中介軟體 Task 方法的名稱必須是 InvokeThe middleware Task method's name must be Invoke. 在 ASP.NET Core 2.0 或更新版本中,此名稱可以是 InvokeInvokeAsyncIn ASP.NET Core 2.0 or later, the name can be either Invoke or InvokeAsync.

中介軟體擴充方法Middleware extension method

下列擴充方法透過 IApplicationBuilder 公開中介軟體:The following extension method exposes the middleware through IApplicationBuilder:

using Microsoft.AspNetCore.Builder;

namespace Culture
{
    public static class RequestCultureMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestCulture(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestCultureMiddleware>();
        }
    }
}

下列程式碼會從 Startup.Configure 呼叫中介軟體:The following code calls the middleware from Startup.Configure:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.UseRequestCulture();

        app.Run(async (context) =>
        {
            await context.Response.WriteAsync(
                $"Hello {CultureInfo.CurrentCulture.DisplayName}");
        });

    }
}

中介軟體應於其建構函式中公開其相依性,以遵循明確的相依性原則Middleware should follow the Explicit Dependencies Principle by exposing its dependencies in its constructor. 中介軟體會在每次「應用程式存留期」就建構一次。Middleware is constructed once per application lifetime. 若您需要在要求內與中介軟體共用服務,請參閱依要求的相依性一節。See the Per-request dependencies section if you need to share services with middleware within a request.

中介軟體元件可透過建構函式參數,解析其來自相依性插入 (DI) 的相依性。Middleware components can resolve their dependencies from dependency injection (DI) through constructor parameters. UseMiddleware<T> 也可直接接受其它參數。UseMiddleware<T> can also accept additional parameters directly.

依要求的相依性Per-request dependencies

因為中介軟體建構於應用程式啟動時,而非依要求建構,所以在每個要求期間,中介軟體建構函式使用的「已限定範圍」存留期服務不會與其它插入相依性的類型共用。Because middleware is constructed at app startup, not per-request, scoped lifetime services used by middleware constructors aren't shared with other dependency-injected types during each request. 如果您必須在中介軟體和其他類型間共用「已限定範圍」的服務,請將這些服務新增至 Invoke 方法的簽章。If you must share a scoped service between your middleware and other types, add these services to the Invoke method's signature. Invoke 方法可以接受 DI 所填入的其他參數:The Invoke method can accept additional parameters that are populated by DI:

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

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

    // IMyScopedService is injected into Invoke
    public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
    {
        svc.MyProperty = 1000;
        await _next(httpContext);
    }
}

其他資源Additional resources