簡體   English   中英

在 ASP.NET Core 中間件構造函數中混合依賴注入和手動傳遞的參數

[英]Mixing dependency injection and manually-passed parameter in ASP.NET Core middleware constructor

我正在為 ASP.NET Core 2.2 編寫自定義中間件。 根據關於編寫自定義中間件的Microsoft Docs

中間件組件可以通過構造函數參數從依賴注入(DI)中解析它們的依賴關系。 UseMiddleware<T>也可以直接接受額外的參數。

這看起來都很好,但它並沒有說明當我混合這兩種方式時會發生什么,例如使用 DI 並在UseMiddleware<T>傳遞參數。 例如,我有以下中間件:

public class CustomMiddleware
{
    public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger, CustomMiddlewareOptions options)
    { 
        ...
    }

    public async Task InvokeAsync(HttpContext context)
    {
        ...
    }

其中logger由 DI 提供, options提供如下:

app.UseMiddleware<CustomMiddleware>(new CustomMiddlewareOptions());

我自己對 2.2 的測試似乎表明這可以正常工作,並且構造函數中參數的順序無關緊要(我可以將 DI 參數放在手動傳遞的參數之前或之后,甚至在兩個手動傳遞的參數之間) . 但我正在尋找一些保證,即我所做的一切都沒有問題。 如果有人能指出一些支持這種用法的文檔或源代碼,那就太好了。 謝謝!

我自己對 2.2 的測試似乎表明這可以正常工作,並且構造函數中參數的順序無關緊要(我可以將 DI 參數放在手動傳遞的參數之前或之后,甚至在兩個手動傳遞的參數之間) . 但我正在尋找一些保證

是的。 閱讀源代碼后,我會說這很好。

這個怎么運作

你的CustomMiddleware是一個約定俗成的中間件(不同於基於工廠的中間件),它由ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs) 激活

var ctorArgs = new object[args.Length + 1];
ctorArgs[0] = next;
Array.Copy(args, 0, ctorArgs, 1, args.Length);     // 
var instance = ActivatorUtilities.CreateInstance(app.ApplicationServices, middleware, ctorArgs);

這里的args (Given Arguments) 是您傳遞給UseMiddleware<CustomMiddleware>(args) (沒有next )的參數數組。

准備構造函數參數時有兩個階段:

  1. 將給定的args與構造參數類型匹配。 並在類型匹配時設置值。 在此處查看源代碼
  2. 使用ServiceProvider.GetRequiredService<SomeService>()填充null元素。請參閱此處的源代碼 如果服務實例仍然為null ,則使用default值。

例如,讓我們說:

  1. 您有一個約定俗成的中間件,其構造函數具有以下簽名:
     public CustomMiddleware(RequestDelegate next, A a, B b, C c, D d, E e){ ... }
  2. 然后我們在注冊中間件時傳入兩個參數:

     app.UseMiddleware(c, a)

    其中cC Type 的實例, aA Type 的實例。 所以給定的givenParameters數組是[next,c, a]

要創建CustomMiddleware的實例,編譯器需要知道完整的構造函數參數值。 DI 擴展在兩個階段內獲取此構造函數參數值數組 ( _parameterValues )。參見:

在此處輸入圖片說明

stage2 的工作方式如下:

b'= sp.GetService(B); 
if b' == null :
    b' = default value of B

正如您在上面看到的, ActivatorUtilities.CreateInstance(sp,mw,args) API 自動處理順序和丟失的參數。


附帶說明一下,約定俗成的中間件在啟動時激活,並且始終是單例。 如果您想使用范圍服務,請參閱此線程

但我正在尋找一些保證,即我所做的一切都沒有問題。

嗯,這是基於意見的。 雖然在你的情況下一切正常,但我相信沒關系。 但我更喜歡使用ASP.NET Core引入的選項模式

public class CustomMiddleware
{
    private readonly RequestDelegate _next;
    private readonly ILogger<CustomMiddleware> _logger;
    private readonly CustomMiddlewareOptions _options;

    public CustomMiddleware(RequestDelegate next, ILogger<CustomMiddleware> logger, IOptions<CustomMiddlewareOptions> options)
    {
        _next = next;
        _logger = logger;
        _options = options.Value;
    }
    //...
}

為此,您需要在Startup配置CustomMiddlewareOptions

services.Configure<CustomMiddlewareOptions>(options =>
{
    options.Id = 1;
    options.Name = "options";
    //set other properties
});

在這種情況下,您應該添加不帶參數的中間件

app.UseMiddleware<CustomMiddleware>();

筆記

也值得一看RequestLocalizationMiddleware

public RequestLocalizationMiddleware(RequestDelegate next, IOptions<RequestLocalizationOptions> options)

以及框架如何讓您在ApplicationBuilderExtensions 中使用中間件

public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder app)
{
    //omitted
    return app.UseMiddleware<RequestLocalizationMiddleware>();
}

或者

public static IApplicationBuilder UseRequestLocalization(this IApplicationBuilder app, RequestLocalizationOptions options)
{
    //omitted
    return app.UseMiddleware<RequestLocalizationMiddleware>(Options.Create(options));
}

正如您所看到的, ASP.NET Core開發人員也更喜歡在中間件構造函數中使用IOptions ,並且在手動指定附加參數時,他們只是將它們包裝到Options

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM