ASP.NET Core Web (中间件)

发布时间 2023-09-27 15:57:32作者: 摧残一生

中间件

中间件类似于装配器,请求处理管道由一系列的中间件组件组成,每个组件在HttpContext上执行操作,按顺序调用管道中的下一个中间件或结束,特定的中间件在通道中装配以后可以获取数据并进行一系列的操作。

该图表示request到response的相关流程,每个节点的输入输出。

通过调用Use{Feature}扩展方法,向管道添加中间件组件。

设置处理所有请求的单个请求委托:

// 当未找到管道时可执行
app.Run(async context =>
{
	// 在特定管道中输出"Hello world!"
    await context.Response.WriteAsync("Hello world!");
});
app.Run();

使用Use方法将多个请求委托链接起来,next表示下一个委托:

app.Use(async (context, next) =>
{
    // 写入响应的工作
    // 当不进行Invoke调用时,该管道会短路,短路的主要作用是避免不必要的工作。
    await next.Invoke();
    // 进行日志记录或其他不写入响应的工作
});

根据请求路径给定的路径开头,执行分支

// 给定路径开头执行HandleMapTest*方法
app.Map("/map1", HandleMapTest1);
app.Map("/map2/seg1", HandleMultiSeg);
app.MapWhen(context => context.Request.Query.ContainsKey("branch"), HandleBranch);
app.Run();

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

static void HandleMultiSeg(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        await context.Response.WriteAsync("Map Test 2");
    });
}
static void HandleBranch(IApplicationBuilder app)
{
    app.Run(async context =>
    {
        var branchVer = context.Request.Query["branch"];
        await context.Response.WriteAsync($"Branch used = {branchVer}");
    });
}
HTTP模块和处理程序迁移到中间件
简单添加中间件

将一个HTTP模块类(IHttpModule)转换为中间件的类,该类采用HttpContext并返回Task的Invoke方法,例如:

using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace MyApp.Middleware
{
	// 中间件
	public class MyMiddleware
	{
		private readonly RequestDelegate _next;
		public MyMiddleware(RequestDelegate next){
			_next = next;
		}
		public async Task Invoke(HttpContext context)
		{
			// 请求开始时会调用该方法
            // TerminateRequest:如果没有中止求情则进行执行
            if(!TerminateRequest()){
				await _next.Invoke(context);
            }
		}
	}
	// 可引入中间件的方法
	public static calss MyMiddlewareExtensions
	{
		public static IApplicationBuilder UseMyMiddleware(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<MyMiddleware>();
        }
	}
}

此时MyMiddlewareExtensions帮助类可以轻松的在Program中配置中间件。

使用app.UseMyMiddleware();来作为中间件的引用。

添加中间件处理类
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using System.Threading.Tasks;

namespace MyApp.Middleware
{
    public class MyHandlerMiddleware
    {
        //必须具有具有此签名的构造函数,否则在运行时发生异常
        public MyHandlerMiddleware(RequestDelegate next)
        {
        }

        public async Task Invoke(HttpContext context)
        {
            string response = GenerateResponse(context);

            context.Response.ContentType = GetContentType();
            await context.Response.WriteAsync(response);
        }
        // 获取标题并返回标题信息
        private string GenerateResponse(HttpContext context)
        {
            string title = context.Request.Query["title"];
            return string.Format("Title of the report: {0}", title);
        }
        private string GetContentType()
        {
            return "text/plain";
        }
    }

    // 可引用的中间件处理程序
    public static class MyHandlerExtensions
    {
        public static IApplicationBuilder UseMyHandler(this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<MyHandlerMiddleware>();
        }
    }
}

在Program类中使用MapWhen扩展方法来对管道进行分支操作

app.MapWhen(
    context => context.Request.Path.ToString().EndsWith(".report"),
    appBranch => {
    // 可以选择向该分支添加更多中间件
    appBranch.UseMyHandler();
});

MapWhen 采用以下参数:

  1. 一个 lambda,它采用 HttpContext,并在请求应沿着分支向下前进时返回 true。 这意味着不仅可以基于请求扩展名,还可以基于请求标头、查询字符串参数等对请求进行分支。
  2. 一个 lambda,它采用 IApplicationBuilder 并为分支添加所有中间件。 这意味着可以将其他中间件添加到处理程序中间件前面的分支。