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

作者 Fiyaz HasanRick AndersonSteve Smith

中介軟體為組成應用程式管線的軟體,用以處理要求與回應。 ASP.NET Core 提供一組豐富的內建中介軟體元件,但在某些情況下,您可能想要撰寫自訂的中介軟體。

本主題描述如何撰寫慣例型中介軟體。 如需使用強型別和依要求啟用的方法,請參閱 ASP.NET Core 的 Factory 中介軟體啟用

中介軟體類別

中介軟體通常封裝在類別中,並以擴充方法公開。 請考慮下列內嵌中介軟體,其會為來自查詢字串的目前要求設定文化特性:

using System.Globalization;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseHttpsRedirection();

app.Use(async (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.
    await next(context);
});

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

app.Run();

前述醒目提示的內嵌中介軟體是用來示範藉由呼叫 Microsoft.AspNetCore.Builder.UseExtensions.Use 來建立中介軟體元件。 前述 Use 擴充方法會將內嵌定義的中介軟體委派新增至應用程式的要求管線中。

Use 擴充功能提供兩種多載:

  • 一是採用 HttpContextFunc<Task>。 在沒有任何參數的情況下叫用 Func<Task>
  • 另一項則是採用 HttpContextRequestDelegate。 透過傳遞 HttpContext 來叫用 RequestDelegate

建議使用第二項多載,因為其會儲存兩個內部依要求配置,該配置在使用其他多載時為必要項目。

藉由傳入文化特性來測試中介軟體。 例如,要求 https://localhost:5001/?culture=es-es

如需 ASP.NET Core 的內建當地語系化支援,請參閱ASP.NET Core 的全球化與當地語系化

下列程式碼會將中介軟體委派移至類別:

using System.Globalization;

namespace Middleware.Example;

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

中介軟體類別必須包含:

  • 具有 RequestDelegate 類型參數的公用建構函式。
  • 名為 InvokeInvokeAsync 的公用方法。 此方法必須:
    • 傳回 Task
    • 接受 HttpContext 類型的第一個參數。

建構函式和 Invoke/InvokeAsync 的其他參數會由相依性插入 (DI) 所填入。

一般而言,會建立擴充方法,以透過 IApplicationBuilder 公開中介軟體:

using System.Globalization;

namespace Middleware.Example;

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

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

下列程式碼會從 Program.cs 呼叫中介軟體:

using Middleware.Example;
using System.Globalization;

var builder = WebApplication.CreateBuilder(args);
var app = builder.Build();

app.UseHttpsRedirection();

app.UseRequestCulture();

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

app.Run();

中介軟體相依性

中介軟體應於其建構函式中公開其相依性,以遵循明確的相依性原則。 中介軟體會在每次「應用程式存留期」就建構一次。

中介軟體元件可透過建構函式參數,解析其來自相依性插入 (DI) 的相依性。 UseMiddleware 也可直接接受其它參數。

依要求的中介軟體相依性

中介軟體會在應用程式啟動時建構,因此具有應用程式存留期。 在每個要求期間,中介軟體建構函式使用的有限範圍存留期服務不會與其它插入相依性的型別共用。 若要在中介軟體和其他型別間共用有限範圍的服務,請將這些服務新增至 InvokeAsync 方法的簽章。 InvokeAsync 方法可以接受 DI 所填入的其他參數:

namespace Middleware.Example;

public class MyCustomMiddleware
{
    private readonly RequestDelegate _next;

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

    // IMessageWriter is injected into InvokeAsync
    public async Task InvokeAsync(HttpContext httpContext, IMessageWriter svc)
    {
        svc.Write(DateTime.Now.Ticks.ToString());
        await _next(httpContext);
    }
}

public static class MyCustomMiddlewareExtensions
{
    public static IApplicationBuilder UseMyCustomMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<MyCustomMiddleware>();
    }
}

存留期和註冊選項包含具有有限範圍存留期服務的中介軟體完整範例。

下列程式碼是用來測試上述中介軟體:

using Middleware.Example;
var builder = WebApplication.CreateBuilder(args);

builder.Services.AddScoped<IMessageWriter, LoggingMessageWriter>();

var app = builder.Build();

app.UseHttpsRedirection();

app.UseMyCustomMiddleware();

app.MapGet("/", () => "Hello World!");

app.Run();

IMessageWriter 介面和實作:

namespace Middleware.Example;

public interface IMessageWriter
{
    void Write(string message);
}

public class LoggingMessageWriter : IMessageWriter
{

    private readonly ILogger<LoggingMessageWriter> _logger;

    public LoggingMessageWriter(ILogger<LoggingMessageWriter> logger) =>
        _logger = logger;

    public void Write(string message) =>
        _logger.LogInformation(message);
}

其他資源

Rick AndersonSteve Smith 撰寫

中介軟體為組成應用程式管線的軟體,用以處理要求與回應。 ASP.NET Core 提供一組豐富的內建中介軟體元件,但在某些情況下,您可能想要撰寫自訂的中介軟體。

注意

本主題描述如何撰寫慣例型中介軟體。 如需使用強型別和依要求啟用的方法,請參閱 ASP.NET Core 的 Factory 中介軟體啟用

中介軟體類別

中介軟體通常封裝在類別中,並以擴充方法公開。 請考慮下列中介軟體,其會為來自查詢字串的目前要求設定文化特性:

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (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
            await next();
        });

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

    }
}

上述範例程式碼用於示範中介軟體元件的建立。 如需 ASP.NET Core 的內建當地語系化支援,請參閱ASP.NET Core 的全球化與當地語系化

藉由傳入文化特性來測試中介軟體。 例如,要求 https://localhost:5001/?culture=no

下列程式碼會將中介軟體委派移至類別:

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

中介軟體類別必須包含:

  • 具有 RequestDelegate 類型參數的公用建構函式。
  • 名為 InvokeInvokeAsync 的公用方法。 此方法必須:
    • 傳回 Task
    • 接受 HttpContext 類型的第一個參數。

建構函式和 Invoke/InvokeAsync 的其他參數會由相依性插入 (DI) 所填入。

中介軟體相依性

中介軟體應於其建構函式中公開其相依性,以遵循明確的相依性原則。 中介軟體會在每次「應用程式存留期」就建構一次。 若您需要在要求內與中介軟體共用服務,請參閱依要求的中介軟體相依性一節。

中介軟體元件可透過建構函式參數,解析其來自相依性插入 (DI) 的相依性。 UseMiddleware 也可直接接受其它參數。

依要求的中介軟體相依性

因為中介軟體建構於應用程式啟動時,而非依要求建構,所以在每個要求期間,中介軟體建構函式使用的「已限定範圍」存留期服務不會與其它插入相依性的類型共用。 如果您必須在中介軟體和其他類型間共用「已限定範圍」的服務,請將這些服務新增至 InvokeAsync 方法的簽章。 InvokeAsync 方法可以接受 DI 所填入的其他參數:

public class CustomMiddleware
{
    private readonly RequestDelegate _next;

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

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

存留期和註冊選項包含具有有限範圍存留期服務的中介軟體完整範例。

中介軟體擴充方法

下列擴充方法透過 IApplicationBuilder 公開中介軟體:

using Microsoft.AspNetCore.Builder;

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

下列程式碼會從 Startup.Configure 呼叫中介軟體:

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

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

其他資源