中间件官网文档解释:中间件是一种装配到应用管道以处理请求和响应的软件 每个中间件:

  • 选择是否将请求传递到管道中的下一个组件。
  • 可在管道中的下一个组件前后执行工作。

使用 IApplicationBuilder 创建中间件管道

ASP.NET Core 请求管道包含一系列请求委托,依次调用。 下图演示了这一概念。 沿黑色箭头执行。

.NET Core 3.0 中间件 Middleware-LMLPHP

IApplicationBuilder提供了三个扩展方法配置请求委托

  • app.Run 作用添加一个终端中间件,因为不在向下传递请求,常常公开在管道末尾运行。实例代码
  app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello, middleware!");
        });
  • app.Use 将多个请求委托链接在一起。next 参数表示管道中的下一个委托。 可通过不 调用 next 参数使管道短路等同于aap.run。 通常可在下一个委托前后执行操作,如以下示例所示:
  app.Use(async (context, next) =>
        {
            // 传递前操作
            await next.Invoke();
            // 传递前操作
        });

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from 2nd delegate.");
        });
    }
  • Map 扩展用作约定来创建管道分支。 Map 基于给定请求路径的匹配项来创建请求管道分支。 如果请求路径以给定路径开头,则执行分支。实例代码如下
  private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }

    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);

        app.Map("/map2", HandleMapTest2);

        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
        });
    }

自定义中间件

以下演示记录api输入输出参数的中间件。

1.创建一个webapi项目,在默认的WeatherForecastController控制器中添加一个简单的post方法,代码如下

 [HttpPost]
        public string PostWeatherForecast(int TemperatureC)
        {
            return "添加成功";
        }

2.新建一个中间件类.CS文件如图

.NET Core 3.0 中间件 Middleware-LMLPHP

选择之后默认代码如下:

 // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
    public class LogReqResponseMiddleware
    {
        private readonly RequestDelegate _next;

        public LogReqResponseMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public Task Invoke(HttpContext httpContext)
        {

            return _next(httpContext);
        }
    }

    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class LogReqResponseMiddlewareExtensions
    {
        public static IApplicationBuilder UseLogReqResponseMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<LogReqResponseMiddleware>();
        }
    }

脚手架自动帮我们创建一个 Invoke方法,传递给下一个中间件。一个将自定义的中间件添加到了http请求管道的扩展方法UseLogReqResponseMiddleware。

上面invoke不是异步的,我们自己可以改动,以下代码展示 一个api请求的输入参数和输出信息的日志打印

 // You may need to install the Microsoft.AspNetCore.Http.Abstractions package into your project
    public class LogReqResponseMiddleware
    {
        private readonly RequestDelegate _next;

        public LogReqResponseMiddleware(RequestDelegate next)
        {
            _next = next;
        }

        public async Task Invoke(HttpContext httpContext, ILogger<LogReqResponseMiddleware> logger)
        {
            var request = httpContext.Request;
            var buffer = new byte[Convert.ToInt32(request.ContentLength)];
            await request.Body.ReadAsync(buffer, 0, buffer.Length);
            //把请求body流转换成字符串
            var bodyAsText = Encoding.UTF8.GetString(buffer);

            //记录请求信息
            var requestStr = $"{request.Scheme} {request.Host}{request.Path} {request.QueryString} {bodyAsText}";
            logger.LogDebug("Request:" + requestStr);


            var originalBodyStream = httpContext.Response.Body;
            using (var responseBody = new MemoryStream())
            {
                httpContext.Response.Body = responseBody;
                await _next(httpContext);

                var response = httpContext.Response;
                response.Body.Seek(0, SeekOrigin.Begin);
                //转化为字符串
                string text = await new StreamReader(response.Body).ReadToEndAsync();
                //从新设置偏移量0
                response.Body.Seek(0, SeekOrigin.Begin);

                //记录返回值
                var responsestr = $"{response.StatusCode}: {text}";
                logger.LogDebug("Response:" + responsestr);

                await responseBody.CopyToAsync(originalBodyStream);
            }
        }



    }
    // Extension method used to add the middleware to the HTTP request pipeline.
    public static class LogReqResponseMiddlewareExtensions
    {
        public static IApplicationBuilder UseLogReqResponseMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<LogReqResponseMiddleware>();
        }
    }

然后在Startup类的Configure方法中添加下面一行代码,把自定义的中间添加到了HTTP请求的管道中。

app.UseLogReqResponseMiddleware();//记录http请求 输入、输出值;

我们在postman中模拟请求

.NET Core 3.0 中间件 Middleware-LMLPHP

控制台上打印的信息如下:

.NET Core 3.0 中间件 Middleware-LMLPHP

11-06 00:49