ASP.NET Core 的 Factory 中介軟體啟用Factory-based middleware activation in ASP.NET Core

作者:Luke LathamBy Luke Latham

IMiddlewareFactory/IMiddleware中介軟體啟用的擴充點。IMiddlewareFactory/IMiddleware is an extensibility point for middleware activation.

UseMiddleware 擴充方法會檢查中介軟體的已註冊類型是否實作 IMiddlewareUseMiddleware extension methods check if a middleware's registered type implements IMiddleware. 如果是,系統會使用容器中已註冊的 IMiddlewareFactory 執行個體來解析 IMiddleware 實作,而不是使用以慣例為基礎的中介軟體啟用邏輯。If it does, the IMiddlewareFactory instance registered in the container is used to resolve the IMiddleware implementation instead of using the convention-based middleware activation logic. 中介軟體會註冊為應用程式服務容器中的範圍服務或暫時性服務The middleware is registered as a scoped or transient service in the app's service container.

優點:Benefits:

  • 依據用戶端要求啟用 (插入範圍服務)Activation per client request (injection of scoped services)
  • 強型別的中介軟體Strong typing of middleware

IMiddleware 是依據用戶端要求 (連線) 來啟用,因此範圍服務可以插入中介軟體的建構函式中。IMiddleware is activated per client request (connection), so scoped services can be injected into the middleware's constructor.

檢視或下載範例程式碼 (英文) (如何下載)View or download sample code (how to download)

IMiddlewareIMiddleware

IMiddleware 可定義應用程式要求管線的中介軟體。IMiddleware defines middleware for the app's request pipeline. InvokeAsync(HttpContext, RequestDelegate) 方法會處理要求,並傳回 Task 以代表中介軟體的執行。The InvokeAsync(HttpContext, RequestDelegate) method handles requests and returns a Task that represents the execution of the middleware.

依據慣例啟用的中介軟體:Middleware activated by convention:

public class ConventionalMiddleware
{
    private readonly RequestDelegate _next;

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

    public async Task InvokeAsync(HttpContext context, AppDbContext db)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "ConventionalMiddleware", 
                    Value = keyValue
                });

            await db.SaveChangesAsync();
        }

        await _next(context);
    }
}

MiddlewareFactory 啟用的中介軟體:Middleware activated by MiddlewareFactory:

public class FactoryActivatedMiddleware : IMiddleware
{
    private readonly AppDbContext _db;

    public FactoryActivatedMiddleware(AppDbContext db)
    {
        _db = db;
    }

    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        var keyValue = context.Request.Query["key"];

        if (!string.IsNullOrWhiteSpace(keyValue))
        {
            _db.Add(new Request()
                {
                    DT = DateTime.UtcNow, 
                    MiddlewareActivation = "FactoryActivatedMiddleware", 
                    Value = keyValue
                });

            await _db.SaveChangesAsync();
        }

        await next(context);
    }
}

您可為中介軟體建立延伸模組:Extensions are created for the middlewares:

public static class MiddlewareExtensions
{
    public static IApplicationBuilder UseConventionalMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<ConventionalMiddleware>();
    }

    public static IApplicationBuilder UseFactoryActivatedMiddleware(
        this IApplicationBuilder builder)
    {
        return builder.UseMiddleware<FactoryActivatedMiddleware>();
    }
}

您無法使用 UseMiddleware 將物件傳遞給由 Factory 啟用的中介軟體:It isn't possible to pass objects to the factory-activated middleware with UseMiddleware:

public static IApplicationBuilder UseFactoryActivatedMiddleware(
    this IApplicationBuilder builder, bool option)
{
    // Passing 'option' as an argument throws a NotSupportedException at runtime.
    return builder.UseMiddleware<FactoryActivatedMiddleware>(option);
}

由 Factory 所啟用中介軟體會新增至 Startup.ConfigureServices 中的內建容器:The factory-activated middleware is added to the built-in container in Startup.ConfigureServices:

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<AppDbContext>(options =>
        options.UseInMemoryDatabase("InMemoryDb"));

    services.AddTransient<FactoryActivatedMiddleware>();

    services.AddMvc()
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}

這兩個中介軟體都會在要求處理管線的 Startup.Configure 中註冊:Both middlewares are registered in the request processing pipeline in Startup.Configure:

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

    app.UseConventionalMiddleware();
    app.UseFactoryActivatedMiddleware();

    app.UseStaticFiles();
    app.UseMvc();
}

IMiddlewareFactoryIMiddlewareFactory

IMiddlewareFactory 提供建立中介軟體的方法。IMiddlewareFactory provides methods to create middleware. 中介軟體 Factory 實作會在容器中註冊為範圍服務。The middleware factory implementation is registered in the container as a scoped service.

預設的 IMiddlewareFactory 實作是 MiddlewareFactory,其位於 Microsoft.AspNetCore.Http 套件中。The default IMiddlewareFactory implementation, MiddlewareFactory, is found in the Microsoft.AspNetCore.Http package.

其他資源Additional resources