ASP.NET Core 3.1--中间件源码解读--RequestDelegate--ApplicationBuilder.Use

Posted 健康-是最好的时光

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ASP.NET Core 3.1--中间件源码解读--RequestDelegate--ApplicationBuilder.Use相关的知识,希望对你有一定的参考价值。

一、RequestDelegate的定义
从RequestDelegate定义可以看出,RequestDelegate是接收请求上下文HttpContext的一个委托,RequestDelegate既然是一个委托,委托就是一个方法,所以RequestDelegate就是个方法,是个接受请求上下文的方法。

public delegate Task RequestDelegate(HttpContext context);

二、 IApplicationBuilder.Use的定义
我们对比来看,下面这个func是接收1个int 类型的参数,返回1个string类型的委托

Func<int, string> func = new Func<int, string>(i => 
{
    return "abc";
});
string result = func(123);

在看ApplicationBuilder.Use()的定义
ApplicationBuilder.Use方法接收1个Func委托,这个Func接收1个RequestDelegate类型的参数,返回1个RequestDelegate类型,上面说了RequestDelegate是个方法,那么也就是说ApplicationBuilder.Use方法接收1个方法,返回1个方法。

IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);

三、ApplicationBuilder.Use需要的参数的简写
这时候requestdelegate是个方法,但是是什么方法,我们还不知道,我们往下看

//1、Func委托,这个Func接收1个RequestDelegate类型的参数,返回1个RequestDelegate类型
Func<RequestDelegate, RequestDelegate> func = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) =>
{
    return new RequestDelegate(async (context) =>
    {
        await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返回RequestDelegate类型的委托");
    });
});

//2、简写这个委托
Func<RequestDelegate, RequestDelegate> func = (requestdelegate =>
{
    return new RequestDelegate(async (context) =>
    {
        await context.Response.WriteAsync("简写func委托!");
    });
});

//3、Use中间件,最终简写
app.Use(requestdelegate =>
{
    return new RequestDelegate(async (context) =>
    {
        await context.Response.WriteAsync("Use中间件!");
    });
});

四、看源码解读中间件注册和执行流程

1、为什么输出顺序是This is Middleware 3=>This is Middleware 2=>This is Middleware 1?
2、为什么输出顺序是This is Hello World 1 Start=>This is Hello World 2 Start=>This is Hello World 3 Start=>This is Hello World 3 End=>This is Hello World 2 End=>This is Hello World 1 End?
public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
{ 
    app.Use(next =>
    {
        Console.WriteLine("This is Middleware 1");
        return new RequestDelegate(
            async context =>
            {
                await context.Response.WriteAsync("This is Hello World 1 Start");
                await next.Invoke(context);
                await context.Response.WriteAsync("This is Hello World 1 End");
            });
    });
    app.Use(next =>
    {
        Console.WriteLine("This is Middleware 2");
        return new RequestDelegate(
            async context =>
            {
                await context.Response.WriteAsync("This is Hello World 2 Start");
                await next.Invoke(context);
                await context.Response.WriteAsync("This is Hello World 2 End");
            });
    });
    app.Use(next =>
    {
        Console.WriteLine("This is Middleware 3");
        return new RequestDelegate(
            async context =>
            {
                await context.Response.WriteAsync("This is Hello World 3 Start");
                await context.Response.WriteAsync("This is Hello World 3 End");
            });
    });  
}

1、ApplicationBuilder.Use方法源码解读
从源码看出ApplicationBuilder.Use方法就是把Func<RequestDelegate, RequestDelegate> middleware添加到_components这个集合里,而从_components的定义看出_components是个委托集合。

 

2、中间件执行源码解读

Build()的时候执行注册的中间件
从源码看出有个默认的RequestDelegate app,把委托集合反转,遍历执行。
 
第3个中间件的next是默认的RequestDelegate app=>第2个中间件的next是第3个中间件的返回值=>第1个中间件的next是第2个中间件的返回值
 
所以先输出This is Middleware 3,后输出This is Middleware 2,最后输出This is Middleware 1,最终返回的是第1个中间件,最终Application就是Middleware 1。
 
所以最后的输出顺序是This is Hello World 1 Start--->This is Hello World 2 Start--->This is Hello World 3 Start--->This is Hello World 3 End--->This is Hello World 2 End--->This is Hello World 1 End

 总结中间件

1、中间件就像俄罗斯套娃一样,一环套一环
2、最后返回的是第1个中间件

以上是关于ASP.NET Core 3.1--中间件源码解读--RequestDelegate--ApplicationBuilder.Use的主要内容,如果未能解决你的问题,请参考以下文章

NET CORE 管道模型及中间件使用解读

在 asp.net core 3.1+ 中使用多个中间件进行身份验证和授权

Asp.Net Core 中间件应用实践中你不知道的那些事

ASP.NET Core 3.1 中的 Ocelot API Gateway 自定义聚合器问题

ASP.NET Core项目解读之launchSettings.json

ASP.NET Core项目解读之launchSettings.json