繁体   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