zoukankan      html  css  js  c++  java
  • 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方法,标记了当前stagePipelineStage.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指向PreHandlerExcuteStagePreHandlerExcuteStageEntryPoint是最开始初始化的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注入顺序,且保证了在两个StageMarkermiddleware被包装在一个Func<AppFunc,AppFunc>中,经过约定每个middleware返回next,在未遇到ExitPointInvoked之前,都不会发生PipelineStage的切换。这将需要PipelineStage切换机制的支持和对middleware输入参数、输出参数的约定。现在还有些模糊的地方,在下一章将通过对IntegratedPipeline以及AppBuilder.Build的阅读来说清楚这些流程。

  • 相关阅读:
    机器学习-数据归一化及哪些算法需要归一化
    目标检测中的mAP
    在Ubuntu内制作自己的VOC数据集
    目标检测算法之YOLOv3
    目标检测算法之YOLOv1与v2
    详谈Windows消息循环机制
    位和字节以及各类编码简述
    C++ 基础知识(一)
    Python 爬取高清桌面壁纸
    WPF 动画执行后属性无法修改
  • 原文地址:https://www.cnblogs.com/hmxb/p/5300342.html
Copyright © 2011-2022 走看看