【ASP.NET Core 3.1】-中间件源码解读-RequestDelegate_ApplicationBuilder.Use()_ApplicationBuilder.Build()

一.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个方法。

middleware这里不就是双层委托,middleware自己是个委托,而RequestDelegate又是个委托。

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中间件!");
    });
});

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

a.为什么输出顺序是This is Middleware 3=>This is Middleware 2=>This is Middleware 1?
b.为什么输出顺序是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");
            });
    });  
}

4.1.注册中间件链-ApplicationBuilder.Use()方法中间件注册源码解读

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

 

每一个middleware是独立的,它们之间是没有关系的,我们要让它们有关系,那怎么才能让它们之间有关系?
1 private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
2 public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
3 {
4     _components.Add(middleware);
5     return this;
6 }

 

 

 

 

4.2.构建中间件管道-ApplicationBuilder.Builder()方法中间件执行源码解读

ApplicationBuilder.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个中间件
3.委托传递,组装、再组装委托,最后一次性执行
4.多个中间件构成的中间件管道,请求从一个中间件进入下一个中间件进行处理,最终在以相反的顺序跑出来
5.利用的双层委托(middleware)+ 委托嵌套(Build())
 

 

 

posted @ 2020-06-09 22:53  David.Meng  阅读(1148)  评论(1编辑  收藏  举报