• <一>ASP.NET Core 管道


    ASP.NET Core应用程序提供了处理每个请求的完整控制。在这个请求管道中,我们可以动态配置各种业务逻辑对应的中间件(middleware),从而达到服务端可以针对不同用户做出不同的请求响应。

    一、管道

    ASP.NET Core应用程序在创建程序宿主之前需要构建一个管道。而IApplicationBuilder 是用来构建请求管道的.而请求管道,本质上就是对 HttpContext 的一系列操作,即通过对 Request 的处理,来生成 Reponse

    namespace Microsoft.AspNetCore.Builder
    {
        //
        // 摘要:
        //     Defines a class that provides the mechanisms to configure an application's request
        //     pipeline.
        public interface IApplicationBuilder
        {
            //
            // 摘要:
            //     Gets or sets the System.IServiceProvider that provides access to the application's
            //     service container.
            IServiceProvider ApplicationServices
            {
                get;
                set;
            }
    
            //
            // 摘要:
            //     Gets the set of HTTP features the application's server provides.
            IFeatureCollection ServerFeatures
            {
                get;
            }
    
            //
            // 摘要:
            //     Gets a key/value collection that can be used to share data between middleware.
            IDictionary<string, object?> Properties
            {
                get;
            }
    
            //
            // 摘要:
            //     Adds a middleware delegate to the application's request pipeline.
            //
            // 参数:
            //   middleware:
            //     The middleware delegate.
            //
            // 返回结果:
            //     The Microsoft.AspNetCore.Builder.IApplicationBuilder.
            IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware);
    
            //
            // 摘要:
            //     Creates a new Microsoft.AspNetCore.Builder.IApplicationBuilder that shares the
            //     Microsoft.AspNetCore.Builder.IApplicationBuilder.Properties of this Microsoft.AspNetCore.Builder.IApplicationBuilder.
            //
            // 返回结果:
            //     The new Microsoft.AspNetCore.Builder.IApplicationBuilder.
            IApplicationBuilder New();
    
            //
            // 摘要:
            //     Builds the delegate used by this application to process HTTP requests.
            //
            // 返回结果:
            //     The request handling delegate.
            RequestDelegate Build();
        }
    }

    从上面接口源代码中,IApplicationBuilder提供了几个管道构建的方法

    1、Use  注册中间件

    Use是我们非常熟悉的注册中间件的方法,就是将注册的中间件保存到其内部属性 _components 中。注册多个中间件的时候围绕着Next分别对RequestRespone做出相应的处理,B的执行会嵌套在A的里面,因此A是第一个处理Request,

    并且最后一个收到Respone,这样就构成一个经典的的U型管道。

    public IApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
    {
        _components.Add(middleware);
        return this;
    }
     app.Use(next =>
        {
            Console.WriteLine("A");
            return async (context) =>
            {
                // 1. 对Request做一些处理
                // TODO
     
                // 2. 调用下一个中间件
                Console.WriteLine("A-BeginNext");
                await next(context);
                Console.WriteLine("A-EndNext");
     
                // 3. 生成 Response
                //TODO
            };
        });
    var app = builder.Build();
    app.UseHttpsRedirection();
    app.UseStaticFiles();
    app.UseRouting();

    2、Build  创建一个请求管道

     Build 方法创建一个 RequestDelegate 类型的委托。可以看到首先定义了一个 404 的中间件,然后使用了Reverse函数将注册的中间件列表进行反转,因此首先执行我们所注册的最后一个中间件,输入参数便是一个 404 ,

    依次执行到第一个中间件,按我们的注册顺序从里到外,一层套一层。那么根据多中间件注册的u型管道模型,最后response的信息是第一个注册的中间件,即返回404。

    public RequestDelegate Build()
    {
        RequestDelegate app = context =>
        {
            context.Response.StatusCode = 404;
            return Task.CompletedTask;
        }; 
        foreach (var component in _components.Reverse())
        {
            app = component(app);
        } 
        return app;
    var builder = WebApplication.CreateBuilder(args);  //创建程序宿主
    
    // Add services to the container.
    builder.Services.AddRazorPages();
    
    var app = builder.Build();    //创建管道

     3、Run 结束管道向下调用

    在注册的中间件中,是通过 Next 委托串连起来的,如果在某一个中间件中没有调用 Next 委托,则该中间件将做为管道的终点。因此通过管道的串联调用,可以在管道中进行拦截,比如授权中间件,当授权成功后才进入Next,如果授权不成功则response。

    如果流程正常走,那我们在最后一个中间件不应该再调用 Next 委托,而使用Run 扩展方法来注册最后一个中间件。

    public static class RunExtensions
    {
        public static void Run(this IApplicationBuilder app, RequestDelegate handler)
        {
            if (app == null)
            {
                throw new ArgumentNullException(nameof(app));
            }
     
            if (handler == null)
            {
                throw new ArgumentNullException(nameof(handler));
            }
            app.Use(_ => handler);
        }
    }
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapRazorPages();
    
    app.Run();

    二、中间件

    1、app.UseMiddleware()自定义中间件委托函数

    从Use方法中可以看到所谓的中间件实际上就是个委托(Func<RequestDelegate, RequestDelegate>) 。 ASP.NET Core 提供了一个更加具体的中间件的概念,我们在大部分情况下都会将中间件定义成一个单独的类型,使代码更加清晰。

    因此一般都使用自定义中间件委托函数注入中间件。自定义使用中间件有两种方式:

    • 通过继承IMiddleware实现(需要注入服务)
    public class TestMiddleWare : IMiddleware
        {
            public Task InvokeAsync(HttpContext context, RequestDelegate next)
            {
                context.Response.WriteAsync("中间件类A");
                return next(context);
            }
        }
    services.AddSingleton<TestMiddleWare>();  
    app.UseMiddleware<TestMiddleWare>();
    • 通过约定实现
    public class TestMiddleWare
        {
            public readonly RequestDelegate _next;
            public TestMiddleWare(RequestDelegate next)
            {
                _next = next;
            }
            public Task InvokeAsync(HttpContext context)
            {
                context.Response.WriteAsync("中间件类A");
                return _next(context);
            }
        }
    app.UseMiddleware<TestMiddleWare>();
  • 相关阅读:
    齐文词根词缀---1、第一讲
    元音发音规则
    英语重读规则
    英语单词重读规则
    unicode,ansi,utf-8,unicode big endian编码的区别
    Netty中粘包和拆包的解决方案
    【转载】 DirectByteBuffer内存释放
    Netty 中ChannelOption的含义以及使用的场景Netty 中ChannelOption的含义以及使用的场景
    Connection reset原因分析和解决方案
    Netty实现Socket
  • 原文地址:https://www.cnblogs.com/choii/p/16180108.html
Copyright © 2020-2023  润新知