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

相关推荐
未来之窗软件服务9 小时前
幽冥大陆(二)RDIFSDK 接口文档:布草洗涤厂高效运营的技术桥梁C#—东方仙盟
开发语言·c#·rdif·仙盟创梦ide·东方仙盟
1uther10 小时前
Unity核心概念⑨:Screen
开发语言·游戏·unity·c#·游戏引擎
阿幸软件杂货间11 小时前
Office转PDF转换器v1.0.py
开发语言·pdf·c#
sali-tec11 小时前
C# 基于halcon的视觉工作流-章34-环状测量
开发语言·图像处理·算法·计算机视觉·c#
Tiger_shl12 小时前
【层面一】C#语言基础和核心语法-02(反射/委托/事件)
开发语言·c#
mudtools16 小时前
.NET驾驭Word之力:COM组件二次开发全攻略之连接Word与创建你的第一个自动化文档
后端·c#
王维志17 小时前
LiteDB详解
数据库·后端·mongodb·sqlite·c#·json·database
程序猿多布17 小时前
XLua教程之热补丁技术
unity·c#·lua·xlua
咕白m62518 小时前
C# Excel 读取入门教程:免费实现方法
c#·.net
相与还19 小时前
godot+c#使用godot-sqlite连接数据库
数据库·c#·godot