7.6中间件 ASP.NET Core只是完成了HTTP请求调度、报文解析等必要的工作,像检查用户身份、设置缓存报文头等操作都是在中间件中完成,中间件就是ASP.NET Core的一个组件,由前逻辑、next、后逻辑3部分组成,多个中间件组成一个管道 ,一个系统中可以有多个管道。ASP.NET Core执行的过程就是http请求和响应按照中间件组装的顺序在中间件之间流转的过程。
管道引入中间件 WebApplication针对中间件具有3个重要的概念,Map、Use、Run。Map是用来引入请求的,请求来到管道后,组成管道的多个Use负责对请求进行预处理,Run负责主要的业务规则。
方法 作用 Map 定义一个管道可以处理哪些请求 Use 每个Use引入一个中间件,一个管道有若干个Use Run 执行最终的业务逻辑,一般一个管道中只包含一个Run方法且在最后,因为Use引入的中间件可以把请求转到下一个中间件,但是执行Run方法处理就终止了
中间件演示 创建ASP.NET Core空项目,在Program.cs中添加:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.Map("/test" , async appbuilder => { appbuilder.Use(async (context, next) => { context.Response.ContentType = "text/html" ; await context.Response.WriteAsync("1 Start<br/>" ); await next.Invoke(); await context.Response.WriteAsync("1 End<br/>" ); }); appbuilder.Use(async (context, next) => { await context.Response.WriteAsync("2 Start<br/>" ); await next.Invoke(); await context.Response.WriteAsync("2 End<br/>" ); }); appbuilder.Run(async ctx => { await ctx.Response.WriteAsync("hello middleware <br/>" ); }); }); app.Run();
请求/test结果如下:
中间件类 中间件类是一个普通的类,该类中需要一个构造方法,构造方法至少有一个RequestDelegate
类型参数,该参数用来指向下一个中间件。类中还需要Invoke
或者InvokeAsync
的方法,方法中至少有一个HttpContext
类型参数,返回值为Task
类型。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class CheckAndParsingMiddleware { private readonly RequestDelegate next; public CheckAndParsingMiddleware (RequestDelegate next ) { this .next = next; } public async Task InvokeAsync (HttpContext context ) { string pwd = context.Request.Query["password" ]; if (pwd=="123" ) { context.Items["BodyJson" ] = "hellowrld" ; await next(context); } else { context.Response.StatusCode = 401 ; } } }
Program.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 var builder = WebApplication.CreateBuilder(args);var app = builder.Build();app.Map("/test" , async appbuilder => { appbuilder.UseMiddleware<CheckAndParsingMiddleware>(); appbuilder.Run(async ctx => { Console.WriteLine("run start" ); ctx.Response.ContentType = "text/html" ; ctx.Response.StatusCode = 200 ; await ctx.Response.WriteAsync(ctx.Items["BodyJson" ].ToString()); Console.WriteLine("run end" ); }); }); app.Run();
除了请求匹配的Map方法还有匹配Get请求的MapGet方法,匹配Post请求的MapPost方法。并且通过MapWhen方法中的Func<HttpContext,bool>参数可以过滤请求。
1 2 3 4 app.MapWhen(ctx => ctx.Request.Headers["AAA" ]=="123" ,async appbuilder =>{}); app.MapWhen(ctx => ctx.Request.Path.StartsWithSegments("/api" ),async appbuilder =>{});
中间件的组装顺序很重要,并且asp.net里面有很多内置的中间件在使用的时候一定要仔细阅读中间件组装顺序说明
筛选器和中间件的区别 ASP.NET Core MVC是由MVC中间件提供的框架,而筛选器数据MVC中间件中的功能
中间件 筛选器 ASP.NET Core提供的功能 ASP.NET Core MVC提供的功能 可以处理所有请求(控制器请求,静态文件等) 只能针对控制器的请求 无法处理IActionResult、ActionDescriptor等MVC特有概念 可以处理MVC框架中的概念 效率更高、范围更广、更底层
建议能使用中间件的情况尽量使用中间件,如果中间件和过滤器同时使用,则会先执行完所有的中间件前逻辑,然后执行过滤器,最后执行中间件的后逻辑。