簡體   English   中英

如何在 ASP.NET 內核中將 Delegate 轉換為 RequestDelegate?

[英]How is Delegate being cast to RequestDelegate in ASP.NET Core?

我查看了MapGet()正在做什么,發現其中一個重載采用Delegate類型(類,不是關鍵字,而不是RequestDelegate ),然后將其傳遞給MapMethods() ,后者采用RequestDelegate 我覺得非常令人困惑的是這個演員是如何發生的。 RequestDelegate具有簽名delegate Task RequestDelegate(HttpContext httpContext) 將委托轉換為另一個委托時,他們不是 a) 需要相同的簽名,b) 實際上需要傳遞對委托的Invoke()方法的引用(也就是說,您不能只是將委托轉換為另一個委托盡管他們的簽名匹配,或者我讀到了)。

我發現非常令人困惑的另一件事是如何將任意請求處理程序傳遞給 Minimal API 並以某種方式轉換為RequestDelegate Microsoft 的文檔顯示了處理程序沒有 arguments 之類的示例() =>... ,以及任意 arguments 將通過依賴注入機制解決,例如(MyClass a, HttpContext ctx, DbContext<MyClass> dbCtx) =>... . I would assume this handler is somehow wrapped in another lambda that fits the RequestDelegate signature, so that ASP.NET Core can pass in a HttpContext and the wrapping lambda can then analyze the lambda passed in by the developer and decide how to resolve its depencies and such. 但我完全不知道這發生在哪里或如何發生。 它實際上只是接受一個 Delegate 並將其傳遞給另一個接受RequestDelegate的方法,神奇的是它現在是一個有效的RequestDelegate

有誰知道?

首先,沒有魔法。 這些路由方法有 2 組不同的重載。 采用RequestDelegate並且自 .NET Core 3.1 以來一直存在的方法,以及采用Delegate的新的最小 API 方法。 對於您問題的前半部分,沒有辦法將任意的Delegate轉換為RequestDelegate ,但另一種方式確實有效。 我不確定您正在閱讀什么代碼,但如果您鏈接到它會有所幫助:)。

至於第二部分,這基本上就是最小 API 的工作方式。 我們將任意Delegate轉換為RequestDelegate 該過程很復雜,並在運行時根據傳入的Delegate的參數和返回值生成代碼。魔法發生在RequestDelegateFactory中。 輸入是Delegate , output 是RequestDelegate 返回的RequestDelegate遵循這些參數綁定規則,以及如何解釋返回值。

在幕后,我們使用動態代碼生成來創建RequestDelegate 一種簡單的思考方式是,我們生成您將手動編寫的代碼以從傳入請求中讀取數據,然后我們使用此數據調用您的 function。 這是一個例子:

app.MapGet("/hello", (string? name) => $"Hello {name ?? "World"}");

在這將變成:

app.MapGet("/hello", (HttpContext context) =>
{
    string name = context.Request.Query["name"];
    // handler is the original delegate
    string result = handler(name);
    return context.Response.WriteAsync(result);
});

再舉一個稍微復雜一點的例子:

app.MapPost("/api/products", (Product p) =>
{
    ...
    return Results.Ok(p);
});

變成:

app.MapGet("/api/products", async (HttpContext context) =>
{
    var product = await context.Request.ReadFromJsonAsync<Product>();
    if (product is null)
    {
        context.Response.StatusCode = 400;
        return;
    }
    var result = handler(product);
    await result.ExecuteAsync(context);
});

此翻譯被封裝在RequestDelegateFactory中,因此您甚至可以執行以下操作:

app.Use(next =>
{
    RequestDelegateResult result = RequestDelegateFactory.Create(() => "Hello World");
    return result.RequestDelegate;
});

該中間件將向生成的RequestDelegate的響應寫入 hello world,並將遵循與最小 API 相同的規則,但沒有路由部分。

希望這能解釋一些“魔法”。

暫無
暫無

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

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