天天看点

AspNetCore中间件

ASPNetCore 中间件解析

    • 什么是中间件
    • 手敲源码
    • 如何改变文本的样式
    • HttpContext
    • Main
    • 代码解读
        • ApplicationBuilder
        • RequestDelegate
        • HttpContext
        • Main

什么是中间件

放在 ASP.NET Core 程序中,都会对应一个请求管道 (request pipeline),在这个请求管道中,我们可以动态配置各种业务逻辑对应的 中间件 (middleware) ,从而达到服务端可以针对不同用户做出不同的请求响应。在 ASP.NET Core 中,管道式编程是一个核心且基础的概念,它的很多中间件都是通过 管道式 的方式来最终配置到请求管道中的,所以理解这里面的管道式编程对我们编写更加健壮的 DotNetCore 程序相当重要 带上官网截图。

AspNetCore中间件

手敲源码

如何改变文本的样式

RequestDelegate

/// <summary>
    /// 处理请求的委托
    /// </summary>
    /// <param name="context"></param>
    /// <returns></returns>
    public delegate Task RequestDelegate(HttpContext context);

           

ApplicationBuilder

/// <summary>
    /// 给管道添加中间件核心类
    /// </summary>
    public class ApplicationBuilder
    {
        /// <summary>
        /// 所有的中间件(我理解为处理管道)
        /// </summary>
        private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();

        /// <summary>
        /// 增加中间件
        /// </summary>
        /// <returns></returns>
        public ApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
        {
            this._components.Add(middleware);
            return this;
        }

        
        /// <summary>
        /// 组合中间件
        /// </summary>
        /// <returns></returns>
        public RequestDelegate Builb()
        {
            //创建没有任何中间件 就返回此中间件结果
            RequestDelegate requestDelegate = new RequestDelegate((conetxt) =>
            {
                conetxt.Response += "\n404 没有任何中间件请求\n";
                return Task.CompletedTask;
            });

            //组合中间件  需要把中间件集合倒出来 后面讲到为什么
            foreach (var item in this._components.Reverse())
            {
                //这是指定中间件的下一个 
                requestDelegate = item(requestDelegate);
                
            }
            return requestDelegate;
        }
        

    }
           

HttpContext

/// <summary>
    /// 模拟的Http上下文
    /// </summary>
    public class HttpContext
    {
        public string Request { get; set; }

        public string Response { get; set; }

        public void Show()
        {
            Console.WriteLine($"Current Context  Response : \n{Response}");
        }

    }


           

Main

static void Main(string[] args)
        {
            //模拟请求进入
            var context = new HttpContext();       
            var app = new ApplicationBuilder();
            {
                
            }

            //开始处理管道
            app.Builb()(context);
            context.Show();
        }

           

代码解读

ApplicationBuilder

主要是 用来把所有中间件组合的核心类 其中的字段

_components 只要是全部中间件的一个集合

Use 只要是为中间件提供一共一个新增的方法 他的参数为 Func<RequestDelegate, RequestDelegate> 传入的参数和返回参数都是同一个

Builb 用来把所有的中间件组合成一个 RequestDelegate 然后把这个返回出去,等待程序调用来处理请求

RequestDelegate

上面总是用到这个委托但是这个委托到底是什么呢?

这个委托主要是为了处理 双下文的 他的参数为一个HttpContext 并且所有的都是共用一个 HttpContext

HttpContext

模拟的上下文 主要是为了好展示

Main

首先我们先使用 Use() 方法注册中间件试一下吧

app.Use((option) =>
                {
                    //这里构建一个返回结果 RequestDelegate委托中需要参数 HttpContext * 注意现在是不会调用 middlewareDelegate(或者说自己不够理解掉坑了)
                    RequestDelegate middlewareDelegate = new RequestDelegate((context) =>
                    {
                        //这里开始处理请求
                        context.Response += "Create middleware One Start\n";
                        //注意这里的 option  这里可以选择是否执行下一个中间件
                        option(context);
                        context.Response += "Create middleware One End\n";
                        return Task.CompletedTask;
                    });

                    return middlewareDelegate;
                });


           

注意这里的 现在是不会执行里面的

Buibl

我们 Use 之后 已经增加一个中间件 我们把它拼装一下吧

public RequestDelegate Builb()
        {
            //创建没有任何中间件 就返回此中间件结果
            RequestDelegate requestDelegate = new RequestDelegate((conetxt) =>
            {
                conetxt.Response += "\n404 没有任何中间件请求\n";
                return Task.CompletedTask;
            });

            
            foreach (var item in this._components)
            {
               
                requestDelegate = item(requestDelegate);
                
            }
            return requestDelegate;
        }
           

当执行Builb 之后就会对 _components 进行拼装 把所有的委托组合成一个

开始执行之前 创建了一个默认的结果 requestDelegate 然后使用循环遍历 说白了也就是俄罗斯套娃,这里item为 Func<RequestDelegate, RequestDelegate> 他需要一个委托然后重新返回一个委托,这里执行将会把 默认的代入到第一个Use的方法

AspNetCore中间件

当执行第二个Use里面时

AspNetCore中间件

等到循环结束 会把最后一个委托给返回出去 return requestDelegate;

我们来看一下执行的顺序 最后返回出去的肯定是 最后一个委托

AspNetCore中间件

开始执行的时候回拼装 context.Response 随后执行 option(context); 注意这里执行的 Option大家还记得是怎么拼装的吗? 它是把它的上一个委托传入进来 所有在调用的时候将会调用

AspNetCore中间件

但是这个里面的 option 又是 默认的那个 所有紧接着调用

AspNetCore中间件

等待执行完成 就到出去的时候啦 逐个拼接 End方法

AspNetCore中间件

最终的结果为这个样子! 会发现执行的顺序不一致 应该先执行 完全倒序了 所以 我们在 Builb() 方法中应该把 _components 倒序过来让他是从 上往下执行处理HttpContext 的

//将倒序之后 第一个处理的 是最后一个Use 返回出去的是第一个Use 从指定上一个中间件变成了指定下一个中间件
foreach (var item in this._components.Reverse())
{          
    requestDelegate = item(requestDelegate);          
}
           

Reverse() 使用方法倒序集合 然后我们在执行一次

AspNetCore中间件

是不是这里就是自己添加的顺序了呢。但是现在出现了一个问题 默认的这个怎么去除? 这里我们已经知道了每一次调用都会有一个 option(context) 这里就是执行它的下一个委托 所以只要我们在最后一个Use的地方 不指定就好了

app.Use((option) =>
                {
                    //这里构建一个返回结果 RequestDelegate委托中需要参数 HttpContext * 注意现在是不会调用 middlewareDelegate(或者说自己不够理解掉坑了)
                    RequestDelegate middlewareDelegate = new RequestDelegate((context) =>
                    {
                        //这里开始处理请求
                        context.Response += "End All middleware";
                        //不调用 option() 做到短路
                        return Task.CompletedTask;
                    });
                    return middlewareDelegate;
                });
           

不调用option将可以做到短路的效果

AspNetCore中间件

大家肯定想每次这样写是不是觉得麻烦 现在我们把 Use方法进行进一步的扩展

/// <summary>
        /// Use 方法扩展
        /// </summary>
        /// <param name="app"></param>
        /// <param name="middleware"></param>
        /// <returns></returns>
        public static ApplicationBuilder Use(this ApplicationBuilder app, Func<HttpContext, Func<Task>, Task> middleware)
        {
            return app.Use( (next) =>
                delegate (HttpContext context)
                {
                    Func<Task> arg = () => next(context);
                    return middleware(context, arg);
                }
            );

        }
           

使用扩展方法注册

AspNetCore中间件
  1. 小白的第一张帖子 如遇错误请大神们指点 1 ↩︎
  2. Demo 地址 https://github.com/hwl962589950/CoreMiddleware.git 2 ↩︎