闽公网安备 35020302035485号
                
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?}");