.NET Core开发实战课程备忘(13) -- 中间件:掌握请求处理过程的关键

核心对象

  • IApplicationBuilder:让我们注册我们自己的中间件
  • RequestDelegate:我们处理整个请求的委托

代码实现

创建项目

创建名字为MiddlewareDemoASP.NET Core项目,类型为API

直接注入委托

Startup.Configure方法里,在app.UseHttpsRedirection()中间件之前添加以下代码:

1
2
3
4
5
app.Use(async (context, next) =>
{
await next();
await context.Response.WriteAsync("Hello world -- my middleware in delegate");
});

运行代码访问/WeatherForecast,可以看到原本的json后面会添加Hello world -- my middleware in delegate这句话

对特定路径注册特定中间件

注释掉上面的代码,在原处新增以下代码

1
2
3
4
5
6
7
8
app.Map("/abc", builder =>
{
builder.Use(async (context, next) =>
{
await next();
await context.Response.WriteAsync("Hello world abc -- from map middleware");
});
});

运行代码访问/WeatherForecast,结果与初始项目运行一致,访问/abc,页面会返回Hello world abc -- from map middleware

对特定路径注册中间件升级版

当这个特定路径的判断比较复杂,可以使用MapWhen来注册,注释掉上一步代码,在原处新增以下代码:

1
2
3
4
5
6
7
8
app.MapWhen(context => { return context.Request.Query.Keys.Contains("abc"); }, builder =>
{
builder.Use(async (context, next) =>
{
await next();
await context.Response.WriteAsync("Hello world query abc -- from mapWhen middleware");
});
});

这里表示当url参数里包含abc这个函数,则触发指定的中间件,运行代码,运行代码访问/WeatherForecast,结果与初始项目运行一致,访问/WeatherForecast?abc=aaa,会在原有的返回结果后面添加Hello world query abc -- from mapWhen middleware

使用扩展方法来注册中间件(最佳姿势)

自定义中间件是按约定来调用的,即中间件里需要包含一个InvokeAsync方法,方法参数为HttpContext,通常中间件不直接对外暴露,所以类的访问修饰符通常是默认的internal,然后通过IApplicationBuilder的扩展方法向外暴露

在根目录创建文件夹Middlewares/MyMiddleware,在目录下创建两个文件MyMiddleware.csMyMiddlewareExtension.cs,具体代码如下:

MyMiddleware.cs代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;

namespace MiddlewareDemo.Middlewares.MyMiddleware
{
class MyMiddleware
{
private readonly RequestDelegate _next;
private readonly ILogger<MyMiddleware> _logger;

public MyMiddleware(RequestDelegate next,ILogger<MyMiddleware> logger)
{
_next = next;
_logger = logger;
}

public async Task InvokeAsync(HttpContext context)
{
using (_logger.BeginScope("TraceIdentifier:{TraceIdentifier}",context.TraceIdentifier))
{
_logger.LogDebug("开始执行MyMiddleware中间件");
await _next(context);
_logger.LogDebug("执行MyMiddleware中间件结束");
}
}
}
}

MyMiddlewareExtension.cs代码:

1
2
3
4
5
6
7
8
9
10
11
12
using Microsoft.AspNetCore.Builder;

namespace MiddlewareDemo.Middlewares.MyMiddleware
{
public static class MyMiddlewareExtension
{
public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder app)
{
return app.UseMiddleware<MyMiddleware>();
}
}
}

因为这里使用了日志作用域,所以还需要到appsettings.json里修改以下日志配置,具体内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
{
"Logging": {
"LogLevel": {
"Default": "Trace",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
},
"Console": {
"IncludeScopes": true,
"LogLevel": {
"MiddlewareDemo.Middlewares.MyMiddleware.MyMiddleware": "Trace"
}
}
},
"AllowedHosts": "*"
}

回到Startup.Configure,注释掉前面的测试代码,在原处新增以下代码:

1
app.UseMyMiddleware();

运行项目,访问/WeatherForecast,可以看到控制台打印出了对应的日志