[英]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.