[英]How is Delegate being cast to RequestDelegate in ASP.NET Core?
I looked into what MapGet()
is doing and found that one of the overloads takes a Delegate
type (class, not keyword, and not a RequestDelegate
), but then pass it on to MapMethods()
, which takes a RequestDelegate
.我查看了
MapGet()
正在做什么,发现其中一个重载采用Delegate
类型(类,不是关键字,而不是RequestDelegate
),然后将其传递给MapMethods()
,后者采用RequestDelegate
。 What I find very confusing is how this cast takes place.我觉得非常令人困惑的是这个演员是如何发生的。 A
RequestDelegate
has the signature delegate Task RequestDelegate(HttpContext httpContext)
. RequestDelegate
具有签名delegate Task RequestDelegate(HttpContext httpContext)
。 When casting a delegate to another, don't they a) need the same signature, b) actually need to pass a reference to the Invoke()
method of the delegate (that is to say you can't just convert a delegate to another despite their signatures matching, or so I read).将委托转换为另一个委托时,他们不是 a) 需要相同的签名,b) 实际上需要传递对委托的
Invoke()
方法的引用(也就是说,您不能只是将委托转换为另一个委托尽管他们的签名匹配,或者我读到了)。
Another thing I find extremely confusing is how one can pass in an arbitrary request handler to the Minimal API and it somehow being converted to a RequestDelegate
.我发现非常令人困惑的另一件事是如何将任意请求处理程序传递给 Minimal API 并以某种方式转换为
RequestDelegate
。 The documentation from Microsoft shows examples where the handler has no arguments like () =>...
, and also arbitrary arguments which will be resolved through the dependency injection mechanism like (MyClass a, HttpContext ctx, DbContext<MyClass> dbCtx) =>...
. 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. 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. But I have no clue at all where or how this happens.但我完全不知道这发生在哪里或如何发生。 It literally just takes in a Delegate and passes it into another method which takes a
RequestDelegate
, and magically it's now a valid RequestDelegate
?它实际上只是接受一个 Delegate 并将其传递给另一个接受
RequestDelegate
的方法,神奇的是它现在是一个有效的RequestDelegate
?
Anyone knows?有谁知道?
First, there is no magic.首先,没有魔法。 There are 2 distinct set of overloads for these routing methods.
这些路由方法有 2 组不同的重载。 Ones that take
RequestDelegate
and have been around since .NET Core 3.1, and the new minimal API methods that take Delegate
.采用
RequestDelegate
并且自 .NET Core 3.1 以来一直存在的方法,以及采用Delegate
的新的最小 API 方法。 For the first half of your question, there's no way to cast an arbitrary Delegate
to RequestDelegate
but the other way does work.对于您问题的前半部分,没有办法将任意的
Delegate
转换为RequestDelegate
,但另一种方式确实有效。 I'm not sure what code you were reading but it would help if you linked to it:).我不确定您正在阅读什么代码,但如果您链接到它会有所帮助:)。
As for the second part, that's basically how minimal APIs work.至于第二部分,这基本上就是最小 API 的工作方式。 We convert an arbitrary
Delegate
into a RequestDelegate
.我们将任意
Delegate
转换为RequestDelegate
。 That process is complex and generates code at runtime based on the parameters and the return value of the Delegate
passed in. The magic happens in the RequestDelegateFactory .该过程很复杂,并在运行时根据传入的
Delegate
的参数和返回值生成代码。魔法发生在RequestDelegateFactory中。 The input is a Delegate
and the output is a RequestDelegate
.输入是
Delegate
, output 是RequestDelegate
。 The RequestDelegate
that is returned follows these rules for parameter binding, and for how to interpret the return values.返回的
RequestDelegate
遵循这些参数绑定规则,以及如何解释返回值。
Under the covers we use dynamic code generation to create the RequestDelegate
.在幕后,我们使用动态代码生成来创建
RequestDelegate
。 A simple way to think about it is that we generate the code you would have written by hand to read data from the incoming request and then we call your function with this data.一种简单的思考方式是,我们生成您将手动编写的代码以从传入请求中读取数据,然后我们使用此数据调用您的 function。 Here's an example:
这是一个例子:
app.MapGet("/hello", (string? name) => $"Hello {name ?? "World"}");
Under this will get turned into:在这将变成:
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);
});
To show one more slightly more complex example:再举一个稍微复杂一点的例子:
app.MapPost("/api/products", (Product p) =>
{
...
return Results.Ok(p);
});
Turns into:变成:
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);
});
This translation is encapsulated in the RequestDelegateFactory
so you can even do things like this:此翻译被封装在
RequestDelegateFactory
中,因此您甚至可以执行以下操作:
app.Use(next =>
{
RequestDelegateResult result = RequestDelegateFactory.Create(() => "Hello World");
return result.RequestDelegate;
});
This middleware will write hello world to the response from the generated RequestDelegate
and will follow the same rules as minimal APIs but without the routing piece.该中间件将向生成的
RequestDelegate
的响应写入 hello world,并将遵循与最小 API 相同的规则,但没有路由部分。
Hopefully that explains some of the "magic".希望这能解释一些“魔法”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.