6 ASP.NET Core中间件
ASP.NET Core 中间件是位于请求处理管道的一系列组件,用来处理请求和响应,在请求管道线上可以有一个或者多个中间件
1 生成响应并且发送响应到客户端

注意中间件执行的顺序按照他们在应用程序中注册的顺序执行,响应的顺序则按照相反的方向执行,假设我们有4个中间件-M1,M2,M3和M4,他们在应用程序中定义的顺序M1>M2>M3>M4,针对一个请求
1 中间件处理的顺序是M1>M2>M3>M4.
2 中间件响应返回到客户端的顺序为M4>M3>M2>M1
6.1 ASP.NET Core客户自定义中间件
在ASP.NET Core中我们可以自定义中间件,客户自定义的中间件有下列四种形式:
1 内容生成中间件(Content-Generating middleware)
2 短路中间件(Short-Circuiting middleware)
3 请求编辑中间件(Request-Editing middleware)
4 响应编辑中间件(Response-Editing middleware)
6.1.1 内容生成中间件(Content-Generating middleware)
内容生成中间件生成内容或响应,我们创建这个中间件返回响应到客户端,我们通过一个简单例子来理解如何工作
在根目录一下创建一个Moddlewares文件夹,在这个文件夹下添加一个ContextMiddleware.cs文件,代码如下:
namespace AspNetCore.Configuration.Middlewares{public class ContentMiddleware{private RequestDelegate _nextDelegate;public ContentMiddleware(RequestDelegate next){_nextDelegate = next;}public async Task Invoke(HttpContext httpContext){if (httpContext.Request.Path == "/middleware"){await httpContext.Response.WriteAsync("这是Context 中间件");}else{_nextDelegate(httpContext);}}}}
注意中间件类没有实现任何接口或者继承任何公共基类,它有一个构造函数使用了RequestDelegate类型,构造函数的参数由MVC自动提供,RequestDelegate对象表示下一个执行的中间件
using AspNetCore.Configuration.Middlewares;using AspNetCore.Configuration.Services;var builder = WebApplication.CreateBuilder(args);builder.Services.AddControllersWithViews();builder.Services.AddRazorPages();builder.Services.AddSingleton<TotalUsers>();var app = builder.Build();// Configure the HTTP request pipeline.if (!app.Environment.IsDevelopment()){app.UseExceptionHandler("/Home/Error");// The default HSTS value is 30 days.app.UseHsts();}app.UseHttpsRedirection();app.UseStaticFiles();app.UseMiddleware<ContentMiddleware>();app.UseRouting();app.UseAuthorization();app.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");app.Run();

中间件中使用依赖注入
using AspNetCore.Configuration.Services;namespace AspNetCore.Configuration.Middlewares{public class ContentMiddleware{private RequestDelegate _nextDelegate;private TotalUsers _totalUsers;public ContentMiddleware(RequestDelegate next, TotalUsers totalUsers){_nextDelegate = next;_totalUsers = totalUsers;}public async Task Invoke(HttpContext httpContext){if (httpContext.Request.Path == "/middleware"){await httpContext.Response.WriteAsync("this message come from ContextMiddleware" +" TotalUsers=" + _totalUsers.TUsers());}else{_nextDelegate(httpContext);}}}}

短路中间件会阻止后面中间件的执行,因为它会使整个请求管道短路,让我们创建一个短路中间件
在Middlewares文件夹下创建一个ShortCircuitMiddleware.cs类,在这个类中添加如下代码:
namespace AspNetCore.Configuration.Middlewares{public class ShortCircuitMiddleware{private RequestDelegate _next;public ShortCircuitMiddleware(RequestDelegate requestDelegate){_next = requestDelegate;}public async Task Invoke(HttpContext context){if (context.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox"))){context.Response.StatusCode = StatusCodes.Status401Unauthorized;}else{await _next(context);}}}}
context.Response.StatusCode = StatusCodes.Status401Unauthorized;app.UseMiddleware<ShortCircuitMiddleware>();app.UseMiddleware<ContentMiddleware>();


在别的浏览器中输入https://localhost:7034/middleware

6.1.3 请求编辑中间件(Request-Editing middleware)
namespace AspNetCore.Configuration.Middlewares{public class RequestEditingMiddleware{private RequestDelegate _next;public RequestEditingMiddleware(RequestDelegate next) => _next = next;public async Task Invoke(HttpContext httpContext){httpContext.Items["Firefox"] = httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox"));await _next(httpContext);}}}
httpContext.Items["Firefox"] = httpContext.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox"));现在我们修改一下ShortCircuitMiddleware.cs中间件,删除下面代码:
if (context.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox")))用下面代码替换
if(context.Items["Firefox"] as bool? == true)namespace AspNetCore.Configuration.Middlewares{public class ShortCircuitMiddleware{private RequestDelegate _next;public ShortCircuitMiddleware(RequestDelegate requestDelegate){_next = requestDelegate;}public async Task Invoke(HttpContext context){//if (context.Request.Headers["User-Agent"].Any(v => v.Contains("Firefox")))if(context.Items["Firefox"] as bool? == true){context.Response.StatusCode = StatusCodes.Status401Unauthorized;}else{await _next(context);}}}}
因此在Program.cs中注册中间件的顺序如下:
app.UseMiddleware<RequestEditingMiddleware>();app.UseMiddleware<ShortCircuitMiddleware>();app.UseMiddleware<ContentMiddleware>();

运行程序,firefox输入https://localhost:7034/middleware ,由于返回未授权的http因此你获取一个空白页
6.1.4 响应编辑中间件(Response-Editing middleware)
namespace AspNetCore.Configuration.Middlewares{public class ResponseEditingMiddleware{private RequestDelegate _next;public ResponseEditingMiddleware(RequestDelegate next){_next=next;}public async Task Invoke(HttpContext httpContext){await _next(httpContext);if (httpContext.Response.StatusCode==401){await httpContext.Response.WriteAsync("Firefox browser not authorized");}else if(httpContext.Response.StatusCode==404){await httpContext.Response.WriteAsync("No Response Generated");}}}}
在上面的代码如果HTTP响应的状态码是401,我们添加文本Firefox browser not authorized到响应中,回想一下我们在Short-Circuiting中间中生成401未授权的响应
响应编辑中间件仅仅编辑其它中间件的响应,因此它必须放到请求管道其它中间件的前面,所以注册的位置很重要
app.UseMiddleware<ResponseEditingMiddleware>();app.UseMiddleware<RequestEditingMiddleware>();app.UseMiddleware<ShortCircuitMiddleware>();app.UseMiddleware<ContentMiddleware>();

现在运行你的应用程序并且在Firefox浏览器中输入URL-https://localhost:7034/middleware,你将获取到响应文本-Firefox browser not unthorized , 图片显示如下

else if(httpContext.Response.StatusCode==404){await httpContext.Response.WriteAsync("No Response Generated");}
当状态码是404时执行该代码,当请求的资源在应用程序中没有发现时该状态码会自动生成
在浏览器输入一个url-https://localhost:7034/tutorials,你会在浏览器中看到No Response Generated 消息

app.MapControllerRoute(name: "default",pattern: "{controller=Home}/{action=Index}/{id?}");
总结