此文是在官方文档的基础上做的个人总结,一些简单的内容就没用再列出来了,参考官方文档:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/middleware/write?view=aspnetcore-5.0

中间件是一种装配到应用管道用来处理请求与响应的组件。在前面的文章中我们介绍了框架自带的一些中间件,这次我们来介绍下如何自定义中间件。

一般有两种方式可以自定义中间件,会分别详细介绍:

  1. 基于约定创建
  2. 基于IMiddleware接口创建
1.基于约定的中间件(推荐,传参更灵活)

具体的约定是:

  1. 中间件类必须要有参数为RequestDelegate的公有构造函数
  2. 必须要有名字为InvokeInvokeAsync的公共方法,这个方法必须返回Task且方法的第一个参数类型是HttpContext.

1.1自定义中间件

首先自定义一个中间件类:

public class RequestCultureMiddleware
{
        private readonly RequestDelegate _next;
        public RequestCultureMiddleware(RequestDelegate next)
        {
            _next = next;
        }
        public async Task InvokeAsync(HttpContext context, ILogger<RequestCultureMiddleware> logger)
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                var culture = new CultureInfo(cultureQuery);
                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;
            }
            // Call the next delegate/middleware in the pipeline
            await _next(context);
        }
    }

然后在Configure方法中配置即可(当然也可以把这个UseMiddleware放到IApplicationBuilder的扩展方法里):

//括号里也可以跟入参数,会传入构造函数中
 app.UseMiddleware<RequestCultureMiddleware>();

1.2 中间件传参数的几种方法

中间件是在应用程序启动时构造的,而且只会构造一次。

  • 构造函数的入参,支持从DI容器中解析。
  • InvokeAsync方法的入参也支持从DI容器中解析,而且每次请求(per-request)时都会解析。
  • 也可以通过UseMiddleware<T>(params object[] args)传入其他参数。
2. 基于IMiddleware接口的中间件

如基于约定的中间件实现步骤不同,我们也可以通过实现IMiddleware接口来自定义中间件:

写一个类实现IMiddleware接口:

    public class MyMiddleware : IMiddleware
    {
        ILogger<MyMiddleware> _logger;
        public MyMiddleware(ILogger<MyMiddleware> logger)
        {
            _logger = logger;
        }
        public async Task InvokeAsync(HttpContext context, RequestDelegate next)
        {
            _logger.LogInformation("----->MyMiddleware Invoked");
            await next(context);
        }
    }

然后在configureService方法中注册服务:

services.AddTransient<MyMiddleware>();

然后在configure方法中添加use:

//因为MyMiddleware对象是DI容器构造的,所以这里即使传入参数也没用
app.UseMiddleware<MyMiddleware>();