Asp.net 5中的ApplicationBuilder怎么理解

发布时间:2022-01-13 21:07:06 作者:iii
来源:亿速云 阅读:192

本文小编为大家详细介绍“Asp.net 5中的ApplicationBuilder怎么理解”,内容详细,步骤清晰,细节处理妥当,希望这篇“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;
        }

    }

RequestDelegate的定义如下:

public delegate Task RequestDelegate(MyHttpContext context);

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

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怎么理解”文章已经介绍完毕,想要掌握这篇文章的知识点还需要大家自己动手实践使用过才能领会,如果想了解更多相关内容的文章,欢迎关注亿速云行业资讯频道。

推荐阅读:
  1. 如何理解asp.net的分页控件
  2. 如何理解ASP.NET

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

asp.net

上一篇:java fastjson传输long数据接收到了int的问题怎么解决

下一篇:springboot整合quartz定时任务框架的方法是什么

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》