AspNetCore中的中间件详解
1 什么鸣做中间件?
ASP.NET Core处理哀求的方式观做是一个管道,中间件是组装到应用程序管道中用来处理哀求和响应的组件。通常是一个可重用的类方法
每个中间件可以:
(1)选择是否将哀求传递给管道中的下一个组件。
(2)可以在调用管道中的下一个组件之前和之后执行业务逻辑。
其中关于哀求管道配置的一个重要方法在startup中的Configure(IApplicationBuilder app, IWebHostEnvironment env)方法。可用Use、Map、Run方法来配置需要使用的中间件。通常使用
IApplicationBuilder的拓铺方法来配置哀求管道,加进指定的中间件。
IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
中间件类的本质其实是委托类
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { //判定是否为开发环境 if (env.IsDevelopment()) { //使用异常开发页面中间件 app.UseDeveloperExceptionPage(); } //静态文件中间件 app.UseStaticFiles(); //HTTP哀求转HTTPS哀求 app.UseHttpsRedirection(); //身份验证 app.UseAuthentication(); //相较于netcore2来说,Routing 中间件是拆分出来的,原来是属于MVC中间件的一部分 app.UseRouting(); //端点中间件,哀求处理路径,结合Routing中间件一起使用的 app.UseEndpoints(endpoints => { //当哀求"/"时,响应输出HelloWorld【可通过lamda表达式入行配置】 endpoints.MapGet("/", async context => { await context.Response.WriteAsync("Hello World!"); }); //哀求路径匹配到 /home/index/1 这种路径时,将会到指定的handler处理器上,默认会处理到 endpoints.MapControllerRoute("default","/{controller=home}/{action=index}/{id?}"); }); }
2 哀求短路与中间件顺序
哀求会按照顺序依次经过每个加进管道的中间件,值得注重的是,中间件可以决定是否将哀求交给下一个委托,当中间件拒尽将哀求传递到下一个中间件时,鸣做哀求短路,可以避免不必要的工作。
中间件的执行与调用的顺序有关,在响应式以相反的顺序返归。哀求在每一步都有可能短路,所以需要准确的添加中间件,如异常处理的中间件,需要放在哀求管道的前面,这样就可以一开始捕捉异常,以及后面中间件中可能发生的异常,做出返归处理。
3 中间件配置方法Use、Run、Map
ASP.NET 中的核心哀求管道是通过一个个哀求委托串联而来的,详细是通过IApplicationBuilder的Use、Run、Map方法来实现的。
在讲解中间件配置方法之前,需要了解什么是RequestDelegate、和代码语言描述的中间件Func<RequestDelegate, RequestDelegate> middleware
//一个能处理哀求的方法 public delegate Task RequestDelegate(HttpContext context); //中间件原生定义,委托,输进是一个RequestDelegate,输出也是一个RequestDelegate, Func<RequestDelegate, RequestDelegate> middleware = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) => { return new RequestDelegate(async (context) => { await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返归RequestDelegate类型的委托"); }); }); // 上述中间件的定义代码可根据lamda表达式规则入行缩写 Func<RequestDelegate, RequestDelegate> middleware = new Func<RequestDelegate, RequestDelegate>((RequestDelegate requestdelegate) => { return new RequestDelegate(async (context) => { await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返归RequestDelegate类型的委托"); }); }); Func<RequestDelegate, RequestDelegate> middleware = (request=>{ return new RequestDelegate(async (context) => { await context.Response.WriteAsync("接收1个带RequestDelegate类型的参数,返归RequestDelegate类型的委托"); }); });
3.1Use 方法配置中间件
//增加中间件到哀求管道中 IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
Use 扩铺可以使用两个重载:
一个重载采用 HttpContext 和 Func < Task >。 不使用任何参数调用 Func< Task >。
app.Use(async (context, next) => { await context.Response.WriteAsync(" Rquest The first middleware"); //调用下一个中间件 await next.Invoke(); await context.Response.WriteAsync(" Response The first middleware"); });
另一个重载采用 HttpContext 和 RequestDelegate。 通过传递 HttpContext 调用 RequestDelegate。
优先使用后面的重载,因为它省往了使用其他重载时所需的两个内部每哀求分配。
app.Use(next => { return new RequestDelegate(async context => { await context.Response.WriteAsync(" Rquest The first middleware"); await next.Invoke(context); await context.Response.WriteAsync(" Response The first middleware"); }); } );
上面两种方法实现的功能一致。值得注重的是,next参数表示管道中的下一个中间件。通过不调用下一个中间件,会导致哀求短路或中断,所以需要谨慎的选择是否需要调用下一个中间件。
3.2Run 方法配置中间件
public static void Run(this IApplicationBuilder app, RequestDelegate handler);
Run 方法配置哀求管道时,会使得哀求管道短路,因为它不调用下一个哀求。因此Run方法一般只在管道的底部使用。
app.Run( async context=> { await context.Response.WriteAsync(" Rquest The final middleware"); });
3.2Map 方法配置中间件
//pathMatch 哀求路径匹配字符串 //configuration 符合匹配规则时采取的 哀求处理逻辑. //configuration 是一个无返归,哀求参数类型为 IApplicationBuilder的归调函数。 public static IApplicationBuilder Map(this IApplicationBuilder app, PathString pathMatch, Action<IApplicationBuilder> configuration);
Map 方法是一种可以基于哀求路径的不同来配置分支中间件。
app.Map("/secondturl", appBuilder => { appBuilder.Run(async context => { await context.Response.WriteAsync(" the request'url is secondturl" + "\n"); }); });
且可以在嵌套使用Map方法往配置分支中间件
4 自定义中间件
虽然中间件的本质是一个Func<RequestDelegate, RequestDelegate> middleware 对象,
中间件的类型可分为两种,下面自定义实现以及记录哀求IP地址的中间件
弱类型中间件
(1) 定义Ip中间件
public class RequestIpMiddleware { private readonly RequestDelegate requestDelegate; public RequestIpMiddleware(RequestDelegate requestDelegate) { this.requestDelegate = requestDelegate; } public async Task Invoke(HttpContext context) { context.Response.WriteAsync("The Request Ip is " + context.Request.HttpContext.Connection.RemoteIpAddress.ToString()+"\n"); //调用下一个哀求中间件 await requestDelegate.Invoke(context); } }
(2)增加Use的拓铺方法
/// <summary> /// 调用中间件的扩铺方法 /// </summary> public static class MiddlewareExtensions { /// <summary> ///this 要害字不能省略 /// </summary> /// <param name="app"></param> /// <returns></returns> public static IApplicationBuilder UseIpMiddleware( this IApplicationBuilder app ) { return app.UseMiddleware<RequestIpMiddleware>(); } }
(3)Configure方法中使用该中间件
app.UseIpMiddleware();
强类型中间件
可以在Use方法中调用这个匿名内部类,但是最好是将中间件定义成一个强类型,利于阅读,且符合编程习惯。
IApplicationBuilder 提供了一种拓铺方法来配置强类型的中间件
public static IApplicationBuilder UseMiddleware<TMiddleware>(this IApplicationBuilder app, params object[] args);
/// <summary> /// 自定义中间件 /// </summary> public class IPMiddleware : IMiddleware { /// <summary> /// IMiddleware接口定义了唯一的InvokeAsync方法,用来实现对哀求的处理。 /// </summary> /// <param name="context"> 当前哀求上下文</param> /// <param name="next">下一个哀求requestDelegate</param> /// <returns></returns> public Task InvokeAsync(HttpContext context, RequestDelegate next) { //获取哀求的IP var ip = context.Request.HttpContext.Connection.RemoteIpAddress.ToString(); context.Response.WriteAsync("IP is "+ip+"\n"); //调用下一个中间件 return next.Invoke(context); } }
值得注重的是在使用这个中间件时,需要将当前中间件注进到容器中,否则哀求管道中的这个中间件无法生效。
到此这篇关于AspNetCore中的中间件详解的文章就介绍到这了,更多相关AspNetCore中间件内容请搜索以前的文章或继承浏览下面的相关文章希望大家以后多多支持!