.net core 5.0 之自定义中间件
微软官方自定义中间件文档: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 扩展方法来配置请求委托。 可将一个单独的请求委托并行指定为匿名方法(称为并行中间件),或在可重用的类中对其进行定义。 这些可重用的类和并行匿名方法即为中间件,也叫中间件组件。 请求管道中的每个中间件组件负责调用管道中的下一个组件,或使管道短路。 当中间件短路时,它被称为“终端中间件”,因为它阻止中间件进一步处理请求。
2. 管道中间件官方建议的执行顺序
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/之后的运行结果:
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."); }); } }
- 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
的请求和响应。
- app.MapWhen() : 基于给定前面的谓词的结果来创建请求管道分支。
MapWhen(this IApplicationBuilder app, Func<HttpContext, bool> predicate, Action<IApplicationBuilder> configuration)简单来说就是predicate如果为true则执行后面的configuration委托
- app.UseWhen() : 也基于给定谓词的结果创建请求管道分支。 与
MapWhen
不同的是,如果这个分支不发生短路或包含终端中间件,则会重新加入主管道。