ASP.NET Core为什么要使用中间件?中间件处理应用程序发出的请求,可以增强和构建应用程序的高级功能,如身份验证、授权、日志记录等,ASP.NET Core 中有大量的内置中间件,我们可以在我们应用程序中使用这些中间件,删除不需要的中间件,从而优化我们应用程序的速度。
namespace AspNetCore.Configuration.Middlewares { public class ContentMiddleware { // 堆代码 duidaima.com 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对象表示下一个执行的中间件。
中间件定义了Invoke方法,当.NET 接收到http请求时这个方法被调用,Invoke方法有一个HttpContext的参数类型,该参数包含了Http 请求和返回客户端的响应。在ContentMiddleware.cs类中,Invoke方法检查HTTP请求并且检查请求的URL中是否包含/middleware , 如果有,它将发送简单的文本响应到客户端,如果没有,它将转发请求到下一个中间件。
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();运行应用程序然后进入https://localhost:7034/middleware,你会看到中间件输出的内容,如下图所示:
如果请求的URL不是 https://localhost:7034/middleware,ContextMiddleware传递请求到下一个中间件,注意请求管道中已经没有中间件,因此请求直接返回
using AspNetCore.Configuration.Services; namespace AspNetCore.Configuration.Middlewares { public class ContentMiddleware { // 堆代码 duidaima.com 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); } } } }运行应用程序,进入https://localhost:7034/middleware,现在你将看到总用户人数:
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); } } } }如果客户端浏览器使用的是firefox, ASP.NET Core中间件返回401 Unauthorized
context.Response.StatusCode = StatusCodes.Status401Unauthorized;现在进入Program.cs类注册这个短路中间件,确保在Context-Middleware.cs中间件之前注册该中间件
app.UseMiddleware<ShortCircuitMiddleware>(); app.UseMiddleware<ContentMiddleware>();记住中间件执行的顺序是按照在Program类中注册的顺序执行的,我们想让ShortCircuitMiddleware中间件在ContentMiddleware中间件之前执行,因此我们把它放在第一个位置。短路中间件检查User-Agent在请求头查找是否是firefox浏览器,如果是它不会将请求转发到下一个中间件,而是直接返回未授权状态码,针对除firefox以外的浏览器会将请求转发到ContextMiddleware.cs
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); } } }在上面代码中我们看到对HTTP请求进行修改而没有发送任何响应,首先检查请求是否来自于firefox浏览器,如果是我们往Http-Context字典中添加一个key为Firefox值为true的键值对,如下代码:
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)最新的ShortCircuitMiddleware代码如下:
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); } } } }我们把RequestEditingMiddleware.cs注册到ShortCircuitMid-dleware中间件前面
app.UseMiddleware<RequestEditingMiddleware>(); app.UseMiddleware<ShortCircuitMiddleware>(); app.UseMiddleware<ContentMiddleware>();
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>();
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?}");