• ASP.NET Core 5 中间件


    • 中间件管道模型
    • 中间件的配置
    • 自定义中间件

    中间件是一类装配在应用管道的代码,负责处理请求和响应。每个中间件都可在管道中的下一个组件前后执行工作,并选择是否将请求传递到管道中的下一个中间件。在Startup.Configure方法中可以进行中间件的装配。

    中间件管道模型

    中间件管道模型如下图所示:
    中间件管道模型

    ASP.NET Core请求管道包含一系列请求委托,沿黑色箭头依次被调用执行,每个委托均可在下一个委托前后执行操作。这种模型也被形象地称为“俄罗斯套娃”。

    一个中间件可以是匿名方法的显示嵌入到管道中,也可以封装为单独的类便于重用,嵌入式的中间件就像这样:

    复制代码
    public void Configure(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello, World!");
        });
    }
    复制代码

    中间件的配置

    配置中间件会使用到三个扩展方法:

    • Use
    • Run
    • Map

    Use

    Use用来将多个中间件按添加顺序链接到一起:

    复制代码
    app.Use(async (context, next) =>
    {
        await context.Response.WriteAsync("middleware1 begin\r\n");
        await next.Invoke();
        await context.Response.WriteAsync("middleware1 end\r\n");
    });
    
    app.Use(async (context, next) =>
    {
        await context.Response.WriteAsync("middleware2 begin\r\n");
        await next.Invoke();
        await context.Response.WriteAsync("middleware2 end\r\n");
    });
    
    app.Run(async context =>
    {
        await context.Response.WriteAsync("end of pipeline.\r\n");
    });
    复制代码

    这三个中间件配置到管道后,输出的结果与管道模型的图示是一致的:

    middleware1 begin
    middleware2 begin
    end of pipeline.
    middleware2 end
    middleware1 end

    可以看到除了最后一个中间件,前面的中间件都调用了await next.Invoke(),next参数表示管道中的下一个委托,如果不调用 next,后面的中间件就不知执行,这称为管道的短路。
    通常中间件都应该自觉调用下一个中间件,但有的中间件会故意造成短路,比如授权中间件、静态文件中间件等。

    Run
    Run的委托中没有next参数,这就意味着它会称为最后一个中间件(终端中间件),此外可以故意短路的Use委托也可能会成为终端中间件。

    Map,提供了创建管道分支的能力
    Map扩展用作约定来创建管道分支,会基于给定请求路径的匹配项来创建请求管道分支,如果请求路径以给定路径开头,则执行分支。

    复制代码
    private static void HandleMapTest1(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 1");
        });
    }
    
    private static void HandleMapTest2(IApplicationBuilder app)
    {
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Map Test 2");
        });
    }
    
    public void Configure(IApplicationBuilder app)
    {
        app.Map("/map1", HandleMapTest1);
    
        app.Map("/map2", HandleMapTest2);
    
        app.Run(async context =>
        {
            await context.Response.WriteAsync("Hello from non-Map delegate. <p>");
        });
    }
    复制代码

    自定义中间件

    在开始封装前,先了解一下对中间件的要求:

    中间件必须具有类型为RequestDelegate的参数的公共构造函数,之前代码中看到next.Invoke(),其中next就是下一个中间件的RequestDelegate;
    名为 Invoke 或 InvokeAsync 的公共方法。而且这个方法的返回类型为Task,且第一个参数的必须是HttpContext,其它的参数由DI容器解析。
    基于上述要求,编写的中间件为:

    复制代码
    public class RequestCultureMiddleware
    {
        private readonly RequestDelegate _next;
    
        public RequestCultureMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        public async Task InvokeAsync(HttpContext context)
        {
            var cultureQuery = context.Request.Query["culture"];
            if (!string.IsNullOrWhiteSpace(cultureQuery))
            {
                var culture = new CultureInfo(cultureQuery);
    
                CultureInfo.CurrentCulture = culture;
                CultureInfo.CurrentUICulture = culture;
            }
    
            // Call the next delegate/middleware in the pipeline
            //await _next.Invoke(context);
            await _next(context);
        }
    }
    复制代码

    然后就可以使用了:

    app.UseMiddleware<RequestCultureMiddleware>();

    还可以进一步封装为IApplicationBuilder的扩展方法:

    复制代码
    public static class RequestCultureMiddlewareExtensions
    {
        public static IApplicationBuilder UseRequestCulture(
            this IApplicationBuilder builder)
        {
            return builder.UseMiddleware<RequestCultureMiddleware>();
        }
    }
    复制代码

    然后就可以像内置的中间件一样了:

    app.UseRequestCulture();

     如果需要依赖项则可使用依赖注入:

    复制代码
    public class CustomMiddleware
    {
        private readonly RequestDelegate _next;
    
        public CustomMiddleware(RequestDelegate next)
        {
            _next = next;
        }
    
        // IMyScopedService is injected into Invoke
        public async Task Invoke(HttpContext httpContext, IMyScopedService svc)
        {
            svc.MyProperty = 1000;
            await _next(httpContext);
        }
    }
  • 相关阅读:
    021.NET5_Autofac多种注入方式
    020.NET5_Autofac初识
    018-019 NET5_内置容器支持依赖注入+IServiceCollection的生命周期
    017.NET5_内置容器基本使用
    设计库和表从哪些方面考虑(MYSQL)
    MD5的如何加密空字符串的(PHP)
    Think php 5登陆注册session储存
    think php 5(命令行)创建控制器、model
    PHP面试题(个人总结)————(暂不更新)
    PHP中的curl库使用
  • 原文地址:https://www.cnblogs.com/lzjsky/p/15777443.html
Copyright © 2020-2023  润新知