ASP.NET Core 管道和中间件(pipeline) - zLulus/My_Note GitHub Wiki

管道和中间件

.net core 管道是请求抵达服务器到响应结果返回的中间的一系列的处理过程
在ASP.NET Core中,针对HTTP请求采用pipeline也就是通常说的管道方式来处理,而管道容器内可以挂载很多中间件(处理逻辑)“串联”来处理HTTP请求,每一个中间件都有权决定是否需要执行下一个中间件,或者直接做出响应。
这样的机制使得HTTP请求能够很好的被层层处理和控制,并且层次清晰处理起来甚是方便。
439526-20160804170538465-88176146
为了再次说明管道和中间件的概念,举一个官方给出的权限验证的例子,中间件A,B分别按顺序挂载在管道容器中,A为权限验证中间件,只有通过A的权限验证才能执行B,如果没有通过A的验证,A有权中断管道处理直接返回相应的错误提示例如401等。这样必须由上一节点来调用的串行递归执行方式就是pipeline,而每一个节点就是中间件或者叫中间组件。

内置中间件

.net core 给我们内置了很多中间件: 1 2

自定义中间件

Use将多个请求委托链接在一起。 next 参数表示管道中的下一个委托。 可通过不调用 next 参数使管道短路。 通常可在下一个委托前后执行操作。

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

当委托不将请求传递给下一个委托时,它被称为“让请求管道短路” 。 通常需要短路,因为这样可以避免不必要的工作。 例如,静态文件中间件可以处理对静态文件的请求,并让管道的其余部分短路,从而起到终端中间件 的作用。 如果中间件添加到管道中,且位于终止进一步处理的中间件前,它们仍处理 next.Invoke 语句后面的代码。
Run 委托不会收到 next 参数。 第一个 Run 委托始终为终端,用于终止管道。 Run 是一种约定。

public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Use(async (context, next) =>
        {
            // Do work that doesn't write to the Response.
            await next.Invoke();
            // Do logging or other work that doesn't write to the Response.
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}

在前面的示例中,Run 委托将 "Hello from 2nd delegate." 写入响应,然后终止管道。 如果在 Run 委托之后添加了另一个 Use 或 Run 委托,则不会调用该委托。

中间件执行顺序

485374-20190418112242536-1923548873
按照Startup.cs的Configure方法添加中间件组件的顺序定义了针对请求调用这些组件的顺序,以及响应的相反顺序。 此顺序对于安全性、性能和功能至关重要。

// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{

       // Middleware A
       app.Use(async (context, next) =>
       {
            Console.WriteLine("A (before)");
            await next();
            Console.WriteLine("A (after)");
       });

       // Middleware B
       app.Use(async (context, next) =>
       {
            Console.WriteLine("B (before)");
            await next();
            Console.WriteLine("B (after)");
       });

       // Middleware C (terminal)
       app.Run(async context =>
       {
            Console.WriteLine("C");
            await context.Response.WriteAsync("Hello world");
       });

}

执行情况如下:
485374-20190419114423096-1026323478

实现:记录方法的执行时间等信息

.net core有实现好的方法.NET Core 和 ASP.NET Core 中的日志记录
原理:
1.自定义计时中间件,在进入管道时(next()方法之前)开始计时,在离开管道时(next()之后)停止计时
2.自定义豁免Attribute,以AOP的方式,豁免不需要计时中间件的方法
豁免Attribute的实现,是在管道计时中间件里面,查询当前方法的Attribute列表中是否存在豁免Attribute,如果是,则不进行计时操作
示例代码

参考资料

官方资料
ASP.NET Core - 中间件与管道(1)
.net core 中间件管道底层剖析
ASP.NET Core中的中间件