AppBuilder(二)UseStageMarker

源码参见Microsoft.Owin.Host.SystemWeb.OwinBuilder

Microsoft.Owin.Builder.AppBuilder

Microsoft.Owin.Host.SystemWeb.OwinHttpModule

本节主要涉及app.UseStageMarker

先提提遇到的的三篇文章,讲得很详细的(鄙视那些转载不注明出处的)

C# 中的委托和事件(详解)

http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html

Difference Between Invoke and DynamicInvoke

http://stackoverflow.com/questions/12858340/difference-between-invoke-and-dynamicinvoke

C#中dynamic的正确用法

http://www.cnblogs.com/qiuweiguo/archive/2011/08/03/2125982.html

前文讲到OWIN初始化的时候最开始的入口点不知道在哪儿,经过两天的阅读,发现这个了这个入口

Microsoft.Owin.Host.SystemWeb.PreApplicationStart这个类上有个Attribute定义

[assembly: PreApplicationStartMethod(typeof(PreApplicationStart), "Initialize")]

这应该是告诉未开源的部分进行初始化的,PreApplicationStart.Initialize方法将被调用,其工作为

HttpApplication.RegisterModule(typeof(OwinHttpModule))

因而在源码中可以预见OwinHttpModule将被初始化,其初始化代码

 1 public void Init(HttpApplication context)
 2         {
 3             IntegratedPipelineBlueprint blueprint = LazyInitializer.EnsureInitialized(
 4                 ref _blueprint,
 5                 ref _blueprintInitialized,
 6                 ref _blueprintLock,
 7                 InitializeBlueprint);
 8
 9             if (blueprint != null)
10             {
11                 var integratedPipelineContext = new IntegratedPipelineContext(blueprint);
12                 integratedPipelineContext.Initialize(context);
13             }
14         }

上面的代码描述的是先确保_blueprint,_blueprintInitialized,_blueprintLock已被初始化,初始状态很明显_blueprint未被初始化(似乎_blueprint一直未被初始化),所以会调用InitializeBlueprint进行初始化。

 1 private IntegratedPipelineBlueprint InitializeBlueprint()
 2         {
 3             IntegratedPipelineBlueprintStage firstStage = null;
 4
 5             Action<IAppBuilder> startup = OwinBuilder.GetAppStartup();    //这就到了前面所讲的流程了,寻找Startup,但在Invoke之前进行了EnableIntegratedPipeline调用
 6             OwinAppContext appContext = OwinBuilder.Build(builder =>
 7             {
 8                 EnableIntegratedPipeline(builder, stage => firstStage = stage);
 9                 startup.Invoke(builder);
10             });
11
12             string basePath = Utils.NormalizePath(HttpRuntime.AppDomainAppVirtualPath);    //获取虚拟路径
13             return new IntegratedPipelineBlueprint(appContext, firstStage, basePath);    //pipeline已经构建完毕,返回第一个stage
14         }

上面做的代码在AppBuilder进行pipeline中的middleware构建之前,启用IntegratedPipelineBlueprint

 1 //EnableIntegratedPipeline的第二个参数是一个Action
 2 private static void EnableIntegratedPipeline(IAppBuilder app, Action<IntegratedPipelineBlueprintStage> onStageCreated)
 3         {
 4             var stage = new IntegratedPipelineBlueprintStage { Name = "PreHandlerExecute" };    //新建一个pipelineStage,只有 Name = "PreHandlerExecute",其他属性未初始化
 5             onStageCreated(stage);    //实际上就是使firstStage指向刚新建的pipelineStage,如果你足够仔细的话
 6     //你会发现这实际上是定义的pipelineStage的最后一个
 7             Action<IAppBuilder, string> stageMarker = (builder, name) =>
 8             {
 9                 Func<AppFunc, AppFunc> decoupler = next =>
10                 {    //next是一个AppFunc委托,如果当前stage.Name与传入的name相同,则仍然返回next,next实际上就是下一个stage的入口
11                     if (string.Equals(name, stage.Name, StringComparison.OrdinalIgnoreCase))
12                     {
13                         // no decoupling needed when pipeline is already split at this name
14                         return next;
15                     }
16                     if (!IntegratedPipelineContext.VerifyStageOrder(name, stage.Name))    //如果当前的stage.Name的order小于传入的name,仍然返回next
17                     {
18                         // Stage markers added out of order will be ignored.
19                         // Out of order stages/middleware may be run earlier than expected.
20                         // TODO: LOG
21                         return next;
22                     }    //如果当前的stage.Name的order大于传入的name,将当前stage的入口点设置为next,新建一个pipelineStage
23                     stage.EntryPoint = next;
24                     stage = new IntegratedPipelineBlueprintStage
25                     {
26                         Name = name,
27                         NextStage = stage,
28                     };
29                     onStageCreated(stage);    //更新firstStage
30                     return (AppFunc)IntegratedPipelineContext.ExitPointInvoked;    //当前stage已经构建完毕,再用一个AppFunc作为当前middleware的返回值
31                 };
32                 app.Use(decoupler);    //decouper是一个Func<AppFunc,AppFunc>委托,所以会使用前一章所说的第一种app.Use方法,直接将其压入List中
33             };
34             app.Properties[Constants.IntegratedPipelineStageMarker] = stageMarker;    //这里将stageMarker绑定到app.Properties中,这将是本文的重点
35             app.Properties[Constants.BuilderDefaultApp] = (Func<IDictionary<string, object>, Task>)IntegratedPipelineContext.DefaultAppInvoked;
36         }

上文的源代码与我们通常的思维有些出入,各个middleware是按顺序压入List的,而遍历List重建的时候确实反向的,所以是从pipelineStage的最后一项PreHandlerExecute一直向前,并将属于一个stage的所有middleware包装在一个Func<AppFunc,AppFunc>中,第一个AppFunc是本stageEntryPoint第二个AppFuncIntegratedPipelineContext.ExitPointInvoked,第二个AppFunc主要负责本stage完成之后的收尾工作,之后将调用本stage中的NextStage找到下一个stage,从下一个stage.EntryPoint开始执行。

在前文的InitializeBlueprintOwinBuilder.Build中完成了EnableIntegratedPipeline操作,接下来就是StartupConfiguration方法被调用,以新建MVC生成的默认的Configuration为例UseCookieAuthentication将会被调用。

 1 public static IAppBuilder UseCookieAuthentication(this IAppBuilder app, CookieAuthenticationOptions options, PipelineStage stage)
 2         {
 3             if (app == null)
 4             {
 5                 throw new ArgumentNullException("app");
 6             }
 7
 8             app.Use(typeof(CookieAuthenticationMiddleware), app, options);
 9             app.UseStageMarker(stage);
10             return app;
11         }

对于上面的源代码我们只关注其先使用Use方法,再使用了UseStageMarker方法,标记了当前stage为PipelineStage.Authenticate

 1 public static IAppBuilder UseStageMarker(this IAppBuilder app, string stageName)
 2         {
 3             if (app == null)
 4             {
 5                 throw new ArgumentNullException("app");
 6             }
 7
 8             object obj;
 9             if (app.Properties.TryGetValue(IntegratedPipelineStageMarker, out obj))    //寻找app.Propertise中的StageMarker方法,也就是上文OwinHttpModule存进去的方法
10             {
11                 var addMarker = (Action<IAppBuilder, string>)obj;
12                 addMarker(app, stageName);
13             }
14             return app;
15
16         }

stageMarker主要做的工作上面已经介绍,在这里的实际效果是将一个委托压进List中,而这个委托作的工作是当前的PipelineStagePreHandlerExcute提前到了Authenticate,并完成了AuthenticateStage中的NextStage指向PreHandlerExcuteStage,PreHandlerExcuteStage的EntryPoint是最开始初始化的stage,只不过这个委托将在AppBuilder进行Build的时候才会Invoke。

那么AppBuilder是在何时进行Build的呢?在前面的某章曾提到Microsoft.Owin.Host.SystemWeb.OwinAppContext类中的Initialize方法的最后一行,其代码如下

AppFunc = (AppFunc)builder.Build(typeof(AppFunc))

上面的代码即开始了AppBuilder.Build方法,也是pipeline重建的开始的地方,没想到却在如此不起眼的地方。

public object Build(Type returnType)
        {
            return BuildInternal(returnType);
        }

可见定义了returnTypeFunc<IDictionary<string, object>, Task>的委托,而Build是对BuildInternal的封装,下一章将阅读BuilderInternal方法。

总结middleware注入与重建是两个逆向的过程,按顺序注入,反向遍历重建,微软工程师巧妙地保证了pipeline注入顺序,且保证了在两个StageMarker的middleware被包装在一个Func<AppFunc,AppFunc>中,经过约定每个middleware返回next,在未遇到ExitPointInvoked之前,都不会发生PipelineStage的切换。这将需要PipelineStage切换机制的支持和对middleware输入参数、输出参数的约定。现在还有些模糊的地方,在下一章将通过对IntegratedPipeline以及AppBuilder.Build的阅读来说清楚这些流程。

时间: 2024-10-10 22:11:01

AppBuilder(二)UseStageMarker的相关文章

AppBuilder(一)Use汇总

源码参见Microsoft.Owin.Host.SystemWeb.OwinBuilder Microsoft.Owin.Builder.AppBuilder 前文讲到 internal static OwinAppContext Build() { Action<IAppBuilder> startup = GetAppStartup(); return Build(startup); } GetAppStartup()已经寻找到Startup类,并封装了其中的Configuration方法

python接口自动化测试(二)-requests.post()

上一节介绍了  requests.get()  方法的基本使用,本节介绍  requests.post()  方法的使用: 本文目录: 一.方法定义 二.post方法简单使用 1.带数据的post 2.带header的post 3.带json的post 4.带参数的post 5.普通文件上传 6.定制化文件上传 7.多文件上传 一.方法定义: 1.到官方文档去了下requests.post()方法的定义,如下: 2.源码: 3.常用返回信息: 二.post方法简单使用: 1.带数据的post:

二维码扫码积分系统定制开发

微信积分系统 二维码扫码积分系统定制开发找丽姐[158.1816.6626/电微]二维码营销模式系统定制开发 微信扫二维码营销系统开发 扫码领积分系统开发 一.如何实现扫二维码领红包功能? 1.使用扫描二维码领取红包对活动进行设置,包括红包数量.红包金额.促销地区.中奖概率等. 2.将生成的二维码赋到商品上面并赋涂层,一方面可以起到保证二维码的一次性,另一方面也可以引起消费者的好奇心. 3.通过手机微信打开扫一扫,扫码商品二维码关注公众号并领取红包,如果参与分享还可以获得抽奖的机会. 二.微信扫

微信生成二维码 只需一个网址即刻 还有jquery生成二维码

<div class="orderDetails-info"> <img src="http://qr.topscan.com/api.php?text=http://123.net/index.php?s=/Home/Index/yanzheng/mai/{$dange.id}" style="width: 5rem; margin-bottom: 1rem;" > </div> http://qr.tops

家电二维码售后服务平台系统开发

家电二维码售后服务平台系统开发,家电二维码售后系统开发,小吴183.2071.6434微电,家电二维码售后软件开发,家电二维码售后平台开发. 互联网平台的节点有两大类型:第一基数节点,也就是弱连接的节点,其规模要大,越大越好,互联网的价值与节点数的平比成正比.第二活跃节点,也就是强连接的节点,其能量要强,越强越好,互联网的价值与其强度成正比. 一.家电维修行业"维修黑幕"层出不穷 记者从一位从事家电维修人士那里了解到,目前行业公认当前家电维修行业有陷阱,"维修黑幕"

MySQL(九)之数据表的查询详解(SELECT语法)二

上一篇讲了比较简单的单表查询以及MySQL的组函数,这一篇给大家分享一点比较难得知识了,关于多表查询,子查询,左连接,外连接等等.希望大家能都得到帮助! 在开始之前因为要多表查询,所以搭建好环境: 1)创建数据表suppliers 前面已经有一张表是book表,我们在建立一张suppliers(供应商)表和前面的book表对应. 也就是说 让book中s_id字段值指向suppliers的主键值,创建一个外键约束关系. 其实这里并没有达到真正的外键约束关系,只是模拟,让fruits中的s_id中

winform学习日志(二十三)---------------socket(TCP)发送文件

一:由于在上一个随笔的基础之上拓展的所以直接上代码,客户端: using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Net.Sockets; using Sys

算法 排序NB二人组 堆排序 归并排序

参考博客:基于python的七种经典排序算法     常用排序算法总结(一) 序前传 - 树与二叉树 树是一种很常见的非线性的数据结构,称为树形结构,简称树.所谓数据结构就是一组数据的集合连同它们的储存关系和对它们的操作方法.树形结构就像自然界的一颗树的构造一样,有一个根和若干个树枝和树叶.根或主干是第一层的,从主干长出的分枝是第二层的,一层一层直到最后,末端的没有分支的结点叫做叶子,所以树形结构是一个层次结构.在<数据结构>中,则用人类的血统关系来命名,一个结点的分枝叫做该结点的"

python接口自动化测试(二)-requests.get()

环境搭建好后,接下来我们先来了解一下requests的一些简单使用,主要包括: requests常用请求方法使用,包括:get,post requests库中的Session.Cookie的使用 其它高级部分:认证.代理.证书验证.超时配置.错误异常处理等. 本节首先来了解一下requests库中如何发送get请求: 一.看下方法定义: 1.到官方文档去了下requests.get()方法的定义,如下: 2.点击右上角的[source],看一下它的源码如下: 看到最后一行return,get方法