聊聊 ASP.NET Core 中间件(三):如何创建自己的中间件?

前言

本质上,中间件类也是一个普通的 .NET 类,它不需要继承任何父类或者实现任何接口。

但是有几个约定:

  1. 需要有一个构造方法
  2. 构造方法至少要有一个 RequestDelegate 类型的参数,用来指向下一个中间件。
  3. 需要定义一个名字为 Invoke 或 InvokeAsync 的方法
  4. 此方法中至少有一个 HttpContext 类型的参数
  5. 此个方法的返回值必须是 Task 类型

只要遵守以上这些约定,就可以轻松创建自己的中间件。

以下是一个 Step By Step 例子。

Step By Step 步骤

  1. 创建一个空 ASP.NET Core webapi 项目

  2. 定义一个用于中间件的实体类

    c# 复制代码
    public class CheckAndParsingMiddlewareModel
    {
    	public int i { get; set; }
    	public int j { get; set; }
    }
  3. 定义一个中间件类 CheckAndParsingMiddleware,留意注释

    c# 复制代码
    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;
    		}
    	}
    }
  4. 打开 Program.cs,编写使用自定义的中间件的代码,如:

    c# 复制代码
    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();
  5. 其它:解析 Body 参数值的方法

    c# 复制代码
    // 方法 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)方法还可以定义其他参数,其他参数会通过依赖注入自动赋值。

相关推荐
TIF星空2 小时前
【使用 C# 获取 USB 设备信息及进行通信】
开发语言·经验分享·笔记·学习·microsoft·c#
csdn_aspnet4 小时前
如何在 C# 中自定义 Datagridview 标题
c#·winform·datagridview
津津有味道4 小时前
MIFARE DESFire Light 卡C#读写更改卡片密钥源码
c#·light·desfire·ev2
炯哈哈7 小时前
【上位机——WPF】Window标签常用属性
开发语言·c#·wpf·上位机
江沉晚呤时13 小时前
C# 实现雪花算法(Snowflake Algorithm)详解与应用
c#·.net
酷炫码神16 小时前
C#语法基础
开发语言·c#
酷炫码神18 小时前
C#数据类型
java·服务器·c#
CodeCraft Studio19 小时前
国产化Word处理控件Spire.Doc教程:通过C# 删除 Word 文档中的超链接
开发语言·c#·word
ghost1431 天前
C#学习第22天:网络编程
开发语言·学习·c#
神仙别闹1 天前
基于C#实现中央定位服务器的 P2P 网络聊天系统
服务器·网络·c#