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将被初始化,其初始化代码

public void Init(HttpApplication context)
        {
            IntegratedPipelineBlueprint blueprint = LazyInitializer.EnsureInitialized(
                ref _blueprint,
                ref _blueprintInitialized,
                ref _blueprintLock,
                InitializeBlueprint);

            if (blueprint != null)
            {
                var integratedPipelineContext = new IntegratedPipelineContext(blueprint);
                integratedPipelineContext.Initialize(context);
            }
        }

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

private IntegratedPipelineBlueprint InitializeBlueprint()
        {
            IntegratedPipelineBlueprintStage firstStage = null;

            Action<IAppBuilder> startup = OwinBuilder.GetAppStartup();    //这就到了前面所讲的流程了,寻找Startup,但在Invoke之前进行了EnableIntegratedPipeline调用
            OwinAppContext appContext = OwinBuilder.Build(builder =>
            {
                EnableIntegratedPipeline(builder, stage => firstStage = stage);
                startup.Invoke(builder);
            });

            string basePath = Utils.NormalizePath(HttpRuntime.AppDomainAppVirtualPath);    //获取虚拟路径
            return new IntegratedPipelineBlueprint(appContext, firstStage, basePath);    //pipeline已经构建完毕,返回第一个stage
        }

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

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

上文的源代码与我们通常的思维有些出入,各个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将会被调用。

public static IAppBuilder UseCookieAuthentication(this IAppBuilder app, CookieAuthenticationOptions options, PipelineStage stage)
        {
            if (app == null)
            {
                throw new ArgumentNullException("app");
            }

            app.Use(typeof(CookieAuthenticationMiddleware), app, options);
            app.UseStageMarker(stage);
            return app;
        }

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

public static IAppBuilder UseStageMarker(this IAppBuilder app, string stageName)
        {
            if (app == null)
            {
                throw new ArgumentNullException("app");
            }

            object obj;
            if (app.Properties.TryGetValue(IntegratedPipelineStageMarker, out obj))    //寻找app.Propertise中的StageMarker方法,也就是上文OwinHttpModule存进去的方法
            {
                var addMarker = (Action<IAppBuilder, string>)obj;
                addMarker(app, stageName);
            }
            return app;

        }

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的阅读来说清楚这些流程。

阅读更多

软件发布:'AppBuilder综合开发平台'

08-23

软件下载,详细资料请访问:http://www.csdn.net/softs/softview.asp?ID=2108rn软件简介:'AppBuilder是什么rnAppBuilder是一套帮助你在VC下面编写完全基于ODBC API的数据库程序的开发系统,它包含了一套从MFC继承的类库,GWC类库,和一个完整的开发系统,此系统能够将数据库编写界同VC程序连接起来,此系统完全解决了在VC下面开发高性能数据库应用程序编程复杂,资源繁杂,以及开发管理系统代码需要重复不断的书写的问题,系统提供的GWC有超过100个新增类,能够开发类似于MONEY风格的数据库管理系统!rn使用AppBuilder为你开发的5大理由! rn 1、如果你决定选择VC作为你开发数据库应用的的平台,但是你有对VC不是非常熟悉,那么AppBuilder是你正确的选择! rn 在AppBuilder中,我们为你产生了开发数据库调用的所有完整的过程,每个过程都包含了完整的代码和注释,你可以通过代码了学习如何在VC下面开发数据库的程序,同时,你也可以将代码完整的复制到你在VC中需要的位置。 rn 2、如果你是VC的熟练的开发工程师,你现在已经在VC上面采用VC的数据库类进行开发,但是你又对VC开发数据库程序的烦琐,和效率低下感到为难的时候,那么试试AppBuilder吧!rn rn AppBuilder能够完整的产生VC工程文件,以及VC的所有资源,同时AppBuilder又具有自己的对话框编辑器,菜单编辑器,和视资源编辑器,基于窗口的资源编辑器等等,你可以在这个集成开发环境中完成所有的开发任务。同时AppBuilder的所有的数据库调用完全基于ODBC API调用的方式。解决了直接利用VC 开发的效率低下的问题。 rn 3、如果你是VC的忠实的使用者,你已经非常习惯了VC的开发环境,对于AppBuilder的开发环境你会习惯吗? rn 其实,你只需要运行运行AppBuilder你就知道了,AppBuilder的开发环境和代码编写环境,同VC具有惊人的相识,我想除了他是中文的界面,VC是E文的界面外我想还没有其他的差别。 rn rn 4、如果你对C++Builder产生容余代码,和其低下的编译效率感到失望的时候,你可能在没有运行AppBuilder之前就对他失去了信心。 rn 其实在AppBuilder中除了帮助你编写代码之外,我们没有帮助你做其他任何事情,你的编译效率和程序的最终产生,完全在VC中进行。而且我们配合的是一套类库,而没有任何的其他OCX控制,我想你是可以非常容易的修改代码,或者在我们提供的类库上面更改。 rn 5、如果你正在为在VC下面开发但是又不能对你原来开发的书对话框,视图和基于窗口的类进行重用而苦恼的时候,那么AppBuilder将为你解决上述问题。 rn 在AppBuilder中,我们提供了自己的资源编辑器,你可以在程序运行的时候让,你的代码完全脱离开发环境,而不需要将资源同基于窗口的雷管连起来,这样,你就可以对他们进行任意的重用。 rnrnrn'

没有更多推荐了,返回首页