欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

详解Asp.net 5中的ApplicationBuilder

程序员文章站 2022-06-18 11:41:58
applicationbuilder(iapplicationbuilder接口),是owin的基础,而且里面都是代理、代理的代理,各种lambda表达式,估计要看这部分代码,很多人得头昏脑涨。今天就...

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;
        }

    }

requestdelegate的定义如下:

public delegate task requestdelegate(myhttpcontext context);

从applicationbuilder的源代码中我们可以关注3个点:_components、use方法、build方法。

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

build之前

详解Asp.net 5中的ApplicationBuilder

build之后

详解Asp.net 5中的ApplicationBuilder

我们还可以从代码中看到item1的参数给的是“404”,而返回结果是requestdelegate类型。也就是说这个返回类似于voidrequestdelegate(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);
        }
    }

首先说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();
        }

执行结果:

详解Asp.net 5中的ApplicationBuilder

示例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();
        }

执行结果:

详解Asp.net 5中的ApplicationBuilder

示例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();
        }

执行结果:

详解Asp.net 5中的ApplicationBuilder

 到此这篇关于详解asp.net 5中的applicationbuilder的文章就介绍到这了。希望对大家的学习有所帮助,也希望大家多多支持。