前言
本质上,中间件类也是一个普通的 .NET 类,它不需要继承任何父类或者实现任何接口。
但是有几个约定:
- 需要有一个构造方法
- 构造方法至少要有一个 RequestDelegate 类型的参数,用来指向下一个中间件。
- 需要定义一个名字为 Invoke 或 InvokeAsync 的方法
- 此方法中至少有一个 HttpContext 类型的参数
- 此个方法的返回值必须是 Task 类型
只要遵守以上这些约定,就可以轻松创建自己的中间件。
以下是一个 Step By Step 例子。
Step By Step 步骤
-
创建一个空 ASP.NET Core webapi 项目
-
定义一个用于中间件的实体类
public class CheckAndParsingMiddlewareModel {public int i { get; set; }public int j { get; set; } }
-
定义一个中间件类 CheckAndParsingMiddleware,留意注释
using System.Text.Json; using System.Text;/// <summary> /// 自定义中间类,要求如注释的 1~5 点 /// </summary> public class CheckAndParsingMiddleware {private readonly RequestDelegate next;// 1. 需要有一个构造方法// 2. 构造方法需要有一个 RequestDelegate 类型的参数,用于指向下一个中间件public CheckAndParsingMiddleware(RequestDelegate next){this.next = next;}// 3. 需要有一个名为 Invoke 或 InvokeAsync 的方法// 4. 此方法至少要有一个 HttpContext 类型参数// 5. 此方法的返回值必须是 Task 类型public async Task InvokeAsync(HttpContext context){string pwd = context.Request.Query["password"];if (pwd == "123"){if (context.Request.HasJsonContentType()){// 解析 Body 参数的值var reqStream = context.Request.BodyReader.AsStream();var jsonObj = JsonSerializer.Deserialize<CheckAndParsingMiddlewareModel>(reqStream);// 将数据存在Items中// HttpContext.Items 在同一个请求中是共享的,可以用它在多个中间件之间来传递数据context.Items["BodyJson"] = jsonObj; }// 把请求转给下一个中间件await next(context); }else{context.Response.StatusCode = 401;}} }
-
打开 Program.cs,编写使用自定义的中间件的代码,如:
var builder = WebApplication.CreateBuilder(args); var app = builder.Build();app.Map("/testForCustomMiddleware", async appbuild => { // 使用自定义的中间件appbuild.UseMiddleware<CheckAndParsingMiddleware>();// 执行appbuild.Run(async ctx => {ctx.Response.ContentType = "text/html";ctx.Response.StatusCode = 200;var jsonObj = (CheckAndParsingMiddlewareModel)ctx.Items["BodyJson"];int i = jsonObj.i;int j = jsonObj.j;await ctx.Response.WriteAsync($"{i}+{j}={i+j}");}); });app.Run();
-
其它:解析 Body 参数值的方法
// 方法 1 var reqStream = context.Request.BodyReader.AsStream(); var jsonObj = JsonSerializer.Deserialize<CheckAndParsingMiddlewareModel>(reqStream);// 方法 2 Stream reqStream = context.Request.Body; byte[] buffer = new byte[context.Request.ContentLength!.Value]; await reqStream.ReadAsync(buffer, 0, buffer.Length); var reqStr = Encoding.UTF8.GetString(buffer); dynamic jsonObj = JsonSerializer.Deserialize<dynamic>(reqStr)!;
扩展
中间件类的构造方法和 Invoke(或 InvokeAsync)方法还可以定义其他参数,其他参数会通过依赖注入自动赋值。