zoukankan      html  css  js  c++  java
  • [Asp.net 5] ApplicationBuilder详解

    ApplicationBuilder(IApplicationBuilder接口),是OWIN的基础,而且里面都是代理、代理的代理,各种lambda表达式,估计要看这部分代码,很多人得头昏脑涨。今天就对个类以及几个扩展方法进行讲解。

    按惯例先贴代码(这是我修改后的,将接口继承去掉了、HttpContext类修改成自己的MyHttpContext类)

    public class ApplicationBuilder
        {
            private readonly IList<Func<RequestDelegate, RequestDelegate>> _components = new List<Func<RequestDelegate, RequestDelegate>>();
    
            public ApplicationBuilder() { }
    
            private ApplicationBuilder(ApplicationBuilder builder)
            {
            }
    
            public ApplicationBuilder Use(Func<RequestDelegate, RequestDelegate> middleware)
            {
                _components.Add(middleware);
                return this;
            }
    
            public ApplicationBuilder New()
            {
                return new ApplicationBuilder(this);
            }
    
            public RequestDelegate Build()
            {
                RequestDelegate app = context =>
                {
                    context.StatusCode = "404";
                    System.Console.WriteLine("404");
                    return Task.FromResult(0);
                };
    
                foreach (var component in _components.Reverse())
                {
                    app = component(app);
                }
    
                return app;
            }
    
        }
    View Code

     RequestDelegate的定义如下:

    public delegate Task RequestDelegate(MyHttpContext context);

    从ApplicationBuilder的源代码中我们可以关注3个点:_components、Use方法、Build方法。

    • _components是也一个列表(IList)对象,不过里面类型有点特殊——是以代理RequestDelegate为参数、代理RequestDelegate为返回值的一个代理。这里用代理说有点别嘴,可以把代理叫做函数,就是里面的类型是一个函数,这个函数的参数也是函数,返回值也是函数。
    • Use方法,就是在上面的列表对象后面添加一条新记录。
    • Build方法就是将_components数组按照反向顺序,制作成一个链式结构(有点类似链表的感觉)。下面用俩幅图说明下:

      Build之前

     

      Build之后

      我们还可以从代码中看到Item1的参数给的是“404”,而返回结果是RequestDelegate类型。也就是说这个返回类似于void RequestDelegate(MyHttpContext context)。如果系统给我们一个context变量,那么这个管道就可以从头到尾的跑下去了。而事实上在Asp.net5中,这个管道就是用于替代传统的IHttpModule的(可能不准确),那现在问题就来了,Item1的参数是这个管道的第一环还是最后一环呢?从图形来看应该是第一环,但是事实上这是一个误解。因为箭头两面一个是参数,一个是执行体(参数是一个方法,会在执行体内调用执行)。在执行体内,可能在开始就执行参数的内容,之后执行具体的内容;也可以是先执行具体内容,之后执行参数,最后在执行一部分具体内容;还可以先执行具体内容,之后参数;还可能无视参数,直接直接自己的内容,那么之前的参数就会被忽略。也就是说无所谓顺序,404可能是管道的第一环,也可能是最后一环,也可能是中间环节,还可能压根就不执行。这个和Item1、Item2等内容具体的写法有关系。(虽然也是链式结构是不是和链表感觉不一样

      是不是感觉太零活了,源码还对ApplicationBuilder做了俩个扩展方法,代码整理如下:

       public static class RunExtensions
        {
    
            public static ApplicationBuilder Use(this ApplicationBuilder app, Func<MyHttpContext, Func<Task>, Task> middleware)
            {
                return app.Use(next =>
                {
                    return context =>
                    {
                        Func<Task> simpleNext = () => next(context);
                        return middleware(context, simpleNext);
                    };
                });
            }
    
            public static void Run(this ApplicationBuilder app, RequestDelegate handler)
            {
                if (app == null)
                {
                    throw new ArgumentNullException("why?");
                }
    
                if (handler == null)
                {
                    throw new ArgumentNullException("How?");
                }
                app.Use(_ => handler);
            }
        }
    View Code

       首先说Use方法,改方法是对之前Use方法的一个更改。将传入的参数更改为 Func<MyHttpContext, Func<Task>, Task>。这样做有什么好处?之前的Func<RequestDelegate, RequestDelegate>对象并不能给人清楚的明了的感觉,而Func<MyHttpContext, Func<Task>, Task>就非常明确了。传入的参数:MyHttpContext就是Context对象,Func<Task>就是next的执行体。返回值是一个Task(类似于void)。一目了然。

      再说Run方法,显而易见,Run方法只执行自己的内容,并没有执行参数体。所以链式结构的在其前的都会被舍弃,不会被执行。

      最后把自己的测试例子贴出来,供大家参考

    示例1:

    static void Main(string[] args)
            {
    
                MyHttpContext context = new MyHttpContext() { StatusCode = "A" };
    
                Func<MyHttpContext, Func<Task>, Task> middleware =
                    (x, y) => { context.StatusCode += "C"; System.Console.WriteLine(context.StatusCode); return y(); };
    
                Func<MyHttpContext, Func<Task>, Task> middleware2 =
                  (x, y) => { context.StatusCode += "End1"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); };
    
                ApplicationBuilder builder = new ApplicationBuilder();
    
                builder.Use(
                    next =>
                    {
                        return (MyHttpContext o) =>
                        {
                            o.StatusCode += "B";
                            System.Console.WriteLine(context.StatusCode);
                            next(o);
                            return Task.FromResult(0);
                        };
                    }
                );
    
                builder.Use(middleware);
                //builder.Use(middleware2);
                //builder.Use(middleware);
                //builder.Run(o => { o.StatusCode += "End2"; return Task.FromResult(0); });
    
                builder.Build().Invoke(context);
                System.Console.ReadLine();
            }
    View Code

    执行结果:

    示例2:

    static void Main(string[] args)
            {
    
                MyHttpContext context = new MyHttpContext() { StatusCode = "A" };
    
                Func<MyHttpContext, Func<Task>, Task> middleware =
                    (x, y) => { context.StatusCode += "C"; System.Console.WriteLine(context.StatusCode); return y(); };
    
                Func<MyHttpContext, Func<Task>, Task> middleware2 =
                  (x, y) => { context.StatusCode += "End1"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); };
    
                ApplicationBuilder builder = new ApplicationBuilder();
    
                builder.Use(
                    next =>
                    {
                        return (MyHttpContext o) =>
                        {
                            o.StatusCode += "B";
                            System.Console.WriteLine(context.StatusCode);
                            next(o);
                            return Task.FromResult(0);
                        };
                    }
                );
    
                builder.Use(middleware);
                builder.Use(middleware2);
                //builder.Use(middleware);
                //builder.Run(o => { o.StatusCode += "End2"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); });
    
                builder.Build().Invoke(context);
                System.Console.ReadLine();
            }
    View Code

    执行结果:

    示例3:

    static void Main(string[] args)
            {
    
                MyHttpContext context = new MyHttpContext() { StatusCode = "A" };
    
                Func<MyHttpContext, Func<Task>, Task> middleware =
                    (x, y) => { context.StatusCode += "C"; System.Console.WriteLine(context.StatusCode); return y(); };
    
                Func<MyHttpContext, Func<Task>, Task> middleware2 =
                  (x, y) => { context.StatusCode += "End1"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); };
    
                ApplicationBuilder builder = new ApplicationBuilder();
    
                builder.Use(
                    next =>
                    {
                        return (MyHttpContext o) =>
                        {
                            o.StatusCode += "B";
                            System.Console.WriteLine(context.StatusCode);
                            next(o);
                            return Task.FromResult(0);
                        };
                    }
                );
    
                builder.Use(middleware);
                //builder.Use(middleware2);
                //builder.Use(middleware);
                builder.Run(o => { o.StatusCode += "End2"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(0); });
    
                builder.Build().Invoke(context);
                System.Console.ReadLine();
            }
    View Code

    执行结果:

  • 相关阅读:
    关于WinForm控件在asp.net中应用的问题。
    评“SuperMap Objects"
    news about matlab r2006a
    one good website for opensource
    a WebSite for MapXtreme2005 Crack
    Asp.net RegularExpressionValidator 控件验证输入值验证输入值是否匹配正则表达式指定的模式
    EditPlus配置手记
    关于asp.net中页面事件加载的先后顺序
    Jquery汇总
    JavaScript必看资源
  • 原文地址:https://www.cnblogs.com/watermoon2/p/5075002.html
Copyright © 2011-2022 走看看