微软官方自定义中间件文档:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/write?view=aspnetcore-5.0#per-request-middleware-dependencies

1. 中间件的定义:(官方文档) https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/?view=aspnetcore-5.0

  中间件是一种装配到应用管道以处理请求和响应的软件。 每个组件:     

    a. 选择是否将请求传递到管道中的下一个组件。

               b. 可在管道中的下一个组件前后执行工作。

  请求委托用于生成请求管道。 请求委托处理每个 HTTP 请求。

  使用 RunMap 和 Use 扩展方法来配置请求委托。 可将一个单独的请求委托并行指定为匿名方法(称为并行中间件),或在可重用的类中对其进行定义。 这些可重用的类和并行匿名方法即为中间件,也叫中间件组件。 请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。 当中间件短路时,它被称为“终端中间件”,因为它阻止中间件进一步处理请求。

 

 

 

aps.net core 零基础 aspnetcore5.0_匿名方法

 

 

 

2.  管道中间件官方建议的执行顺序

aps.net core 零基础 aspnetcore5.0_aps.net core 零基础_02

 

 

 3. 自定义中间件实现必须满足两点条件

      3.1. 具有类型为 RequestDelegate 的参数的公共构造函数。

      3.2. 名为 Invoke 或 InvokeAsync 的公共方法。 此方法必须:

            a. 返回 Task

            b.  接受类型 HttpContext 的第一个参数。

 4. 实现示例

             

public class CustomMiddleware
    {
        public string _msg;
        public RequestDelegate _requestDelegate;
        public CustomMiddleware(RequestDelegate requestDelegate, string msg)
        {
            _requestDelegate = requestDelegate;
            _msg = msg;
        }
        public async Task InvokeAsync(HttpContext httpContext)
        {
            Console.WriteLine(_msg);
           
            await _requestDelegate(httpContext);
        }
    }
public static class MiddlewareExtension
    {
        public static IApplicationBuilder Custom(this IApplicationBuilder app,string msg)
        {
            return app.UseMiddleware<CustomMiddleware>(msg);
        }
    }

 startup更改:

app.Custom("hello");

 

请求http://localhost:5000/之后的运行结果:

 

aps.net core 零基础 aspnetcore5.0_.Net Core_03

 

 

 5. 扩展资料:

.net core 都是通过 IApplicationBuilder 来添加中间件创建管道,所以中间件都是围绕它来创建的。请求管道包含一系列请求委托,依次调用。每个委托均可在下一个委托前后执行操作。 应尽早在管道中调用异常处理委托,这样它们就能捕获在管道的后期阶段发生的异常。

配置请求委托的几种方式:

  • app.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.");
        });
    }
}

 

aps.net core 零基础 aspnetcore5.0_aps.net core 零基础_04

 

 

  •    app.Run():委托不会收到 next 参数。 第一个 Run 委托始终为终端,用于终止管道。如果在 Run 委托之后添加了另一个 Use 或 Run 委托,则不会调用该委托。
public class Startup
{
    public void Configure(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
}
  •  app.map() : 用作约定来创建管道分支。 Map 基于给定请求路径的匹配项来创建请求管道分支。 如果请求路径以给定路径开头,则执行分支。
public class Startup
{
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }

    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);

        app.Map("/map2", HandleMapTest2);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
        });
    }
}

 下表使用前面的代码显示来自 http://localhost:1234 的请求和响应。

aps.net core 零基础 aspnetcore5.0_.Net Core_05

 

  •  app.MapWhen() : 基于给定前面的谓词的结果来创建请求管道分支。

MapWhen(this IApplicationBuilder app, Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration)简单来说就是predicate如果为true则执行后面的configuration委托

  •  app.UseWhen() : 也基于给定谓词的结果创建请求管道分支。 与 MapWhen 不同的是,如果这个分支不发生短路或包含终端中间件,则会重新加入主管道。