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 = "";
System.Console.WriteLine("");
return Task.FromResult();
}; 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之前

 

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

  首先说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(); }; ApplicationBuilder builder = new ApplicationBuilder(); builder.Use(
next =>
{
return (MyHttpContext o) =>
{
o.StatusCode += "B";
System.Console.WriteLine(context.StatusCode);
next(o);
return Task.FromResult();
};
}
); 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();
}

执行结果:

示例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(); }; ApplicationBuilder builder = new ApplicationBuilder(); builder.Use(
next =>
{
return (MyHttpContext o) =>
{
o.StatusCode += "B";
System.Console.WriteLine(context.StatusCode);
next(o);
return Task.FromResult();
};
}
); 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();
}

执行结果:

示例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(); }; ApplicationBuilder builder = new ApplicationBuilder(); builder.Use(
next =>
{
return (MyHttpContext o) =>
{
o.StatusCode += "B";
System.Console.WriteLine(context.StatusCode);
next(o);
return Task.FromResult();
};
}
); builder.Use(middleware);
//builder.Use(middleware2);
//builder.Use(middleware);
builder.Run(o => { o.StatusCode += "End2"; System.Console.WriteLine(context.StatusCode); return Task.FromResult(); }); builder.Build().Invoke(context);
System.Console.ReadLine();
}

执行结果:

[Asp.net 5] ApplicationBuilder详解的更多相关文章

  1. ASP.NET 操作Cookie详解 增加,修改,删除

    ASP.NET 操作Cookie详解 增加,修改,删除 Cookie,有时也用其复数形式Cookies,指某些网站为了辨别用户身份而储存在用户本地终端上的数据(通常经过加密).定义于RFC2109.它 ...

  2. ASP.NET 运行时详解 揭开请求过程神秘面纱

    对于ASP.NET开发,排在前五的话题离不开请求生命周期.像什么Cache.身份认证.Role管理.Routing映射,微软到底在请求过程中干了哪些隐秘的事,现在是时候揭晓了.抛开乌云见晴天,接下来就 ...

  3. ASP.NET运行时详解 集成模式和经典模式

    遗留问题 在<ASP.NET运行时详解 生命周期入口分析>中遗留两个问题,包括Application的InitInternal方法执行细节.IIS6和II7经典模式请求管道管理类Appli ...

  4. ASP.NET生命周期详解

    最近一直在学习ASP.NET MVC的生命周期,发现ASP.NET MVC是建立在ASP.NET Framework基础之上的,所以原来对于ASP.NET WebForm中的很多处理流程,如管道事件等 ...

  5. ASP.NET生命周期详解 [转]

    最近一直在学习ASP.NET MVC的生命周期,发现ASP.NET MVC是建立在ASP.NET Framework基础之上的,所以原来对于ASP.NET WebForm中的很多处理流程,如管道事件等 ...

  6. ASP.NET生命周期详解(转)

    看到好文章需要分享. 最近一直在学习ASP.NET MVC的生命周期,发现ASP.NET MVC是建立在ASP.NET Framework基础之上的,所以原来对于ASP.NET WebForm中的很多 ...

  7. 如何利用IIS调试ASP.NET网站程序详解

    如何利用IIS调试ASP.NET网站程序详解 更新时间:2019年01月13日 08:44:13   作者:江湖逍遥    我要评论   这篇文章主要给大家介绍了关于如何利用IIS调试ASP.NET网 ...

  8. asp.net MVC ViewData详解

    转自:http://www.cnblogs.com/gaopin/archive/2012/11/13/2767515.html 控制器向视图中传值ViewData详解 1.将一个字符串传值到视图中 ...

  9. ASP.NET性能监视参数详解

    性能监视器- Performance Monitor 性能监视器是Windows自带的系统资源和性能监视工具. 性能监视器能够量化地提供CPU使用率, 内存分配状况, 异常派发情况, 线程调度频率等信 ...

随机推荐

  1. WebAPi之SelfHost自创建证书启动Https疑难解惑及无法正确返回结果

    前言 话说又来需求了,之前对于在SelfHost中需要嵌套页面并操作为非正常需求,这回来正常需求了,客户端现在加了https,老大过来说WebAPi访问不了了,这是什么情况,我去试了试,还真是这个情况 ...

  2. 谈谈一些有趣的CSS题目(六)-- 全兼容的多列均匀布局问题

    开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...

  3. javascript动画系列第一篇——模拟拖拽

    × 目录 [1]原理介绍 [2]代码实现 [3]代码优化[4]拖拽冲突[5]IE兼容 前面的话 从本文开始,介绍javascript动画系列.javascript本身是具有原生拖放功能的,但是由于兼容 ...

  4. 介绍一款原创的四则运算算式生成器:CalculateIt2

    家里小朋友读一年级了,最近每天都有一些10以内的加减法口算练习,作为程序员爸爸,自然也是想办法能够偷懒,让电脑出题,给小朋友做些练习.于是,自己在业余时间开发了一个四则运算算式生成器,名为:Calcu ...

  5. 基于注解的bean配置

    基于注解的bean配置,主要是进行applicationContext.xml配置.DAO层类注解.Service层类注解. 1.在applicationContext.xml文件中配置信息如下 &l ...

  6. 使用DeviceOne实现微信小程序功能

    微信小程序即将推出,还没推出就火的不行了.基于微信这个巨大平台,小程序必然能有巨大成功.不过它并不能完全取代App,该开发App还得开发.如果我们自己想实现一个基于自己的APP包含类似微信的小程序功能 ...

  7. Linux环境变量设置

    修改环境变量PATH 最近为root添加一个环境变量发现sudo su进去没有变化所以总结了一下所有设置环境变量的方法: 查看PATH:echo $PATH 直接在命令行修改,就可以使用,但是只有在当 ...

  8. [jquery]jquery正则表达式验证(手机号、身份证号、中文名称)

    数字判断方法:isNaN()函数 test()方法 判断字符串中是否匹配到正则表达式内容,返回的是boolean值 ( true / false ) // 验证中文名称 function isChin ...

  9. Linux上课笔记--随手记Linux命令

    初次接触Linux就是感觉这系统不够友好不够人性化,因为首先接触电脑就是win,图形化界面什么操作都可以清晰看到.随着更多的接触越来越发现Linux的强大,虽然我只是一个小白,可我就是爱上他了.现在就 ...

  10. SQL开发技巧(二)

    本系列文章旨在收集在开发过程中遇到的一些常用的SQL语句,然后整理归档,本系列文章基于SQLServer系列,且版本为SQLServer2005及以上-- 文章系列目录 SQL开发技巧(一) SQL开 ...