[英]how asp.net core run the "default" RequestDelegate in the reuqest pipeline?
[英]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.