AppBuilder(三)【BuildInternal】

源码参见Microsoft.Owin.Builder.AppBuilder

推荐三篇文章,对理解本文内容有帮助。

Delegate.CreateDelegate Method (Type,?Object,?MethodInfo) 官方文档

https://msdn.microsoft.com/en-us/library/74x8f551(v=vs.110).aspx

c#委托(delegate)揭秘

http://www.cnblogs.com/50614090/archive/2011/11/14/2248408.html

C#中delegate的机制原理

http://blog.csdn.net/argpunk/article/details/42121099

前文讲到的AppBuilder.Build方法开始pipeline的重建,其实际上是对AppBuilder.BuildInternal的封装,传入参数为typeof(Func<IDictionary<string, object>, Task>)Func的参数为IDictionary<string, object>,返回一个Task,这就是middleware能串起来所要遵循的规范之一,微软工程师将其称为middleware的签名。

先看看NotFound的初始化

private static readonly AppFunc NotFound = new NotFound().Invoke;    //将NotFound.Invoke绑定到AppBuilder.NotFound上
internal class NotFound
    {
        private static readonly Task Completed = CreateCompletedTask();

        private static Task CreateCompletedTask()
        {
            var tcs = new TaskCompletionSource<object>();
            tcs.SetResult(null);
            return tcs.Task;
        }

        public Task Invoke(IDictionary<string, object> env)    //这是一个满足AppBuilder中对于AppFunc定义的一个方法,之前在这里老是被绕晕了
        {
            env["owin.ResponseStatusCode"] = 404;    //设置StatusCode
            return Completed;    //返回一个Task
        }
    }

上面的代码展示了AppBuilder.NotFound是如何初始化为一个AppFunc的,这是对中间件的签名,对于后面的Convert方法来说至关重要。

private object BuildInternal(Type signature)
        {
            object app;
            if (!_properties.TryGetValue(Constants.BuilderDefaultApp, out app))    //尝试寻找默认的最后一步处理方法,如果寻找失败则将app指向NotFound
            {
                app = NotFound;
            }

            foreach (var middleware in _middleware.Reverse())    //对List进行反向遍历,反向遍历很重要,这样上一节所说的UseStageMarker对stage.Name的处理方式才能理解
            {
                Type neededSignature = middleware.Item1;    //解耦三元组
                Delegate middlewareDelegate = middleware.Item2;
                object[] middlewareArgs = middleware.Item3;

                app = Convert(neededSignature, app);    //尝试将app的Invoke方法创建为一个委托,委托为needSignature所表示的Type,听起来有点绕,没关系,慢慢来
    //这将涉及到pipeline中AppFunc与Middleware的转换,这是OWIN的精华所在
                object[] invokeParameters = new[] { app }.Concat(middlewareArgs).ToArray();    //将app作为第一个参数与args合并
                app = middlewareDelegate.DynamicInvoke(invokeParameters);
                app = Convert(neededSignature, app);    //这一步我也没大懂,到后面懂了再说
            }

            return Convert(signature, app);    //同理这一步我也没大懂
        }

从实际例子出发容易理解上面的流程一些,上一章讲到UseCookieAuthentication方法中先调用app.Use(typeof(CookieAuthenticationMiddleware), app, options),再调用app.UseStageMarker(stage),这实际上会调用app.Use(decoupler)方法,而decoulper是一个Func<AppFunc,AppFunc>委托,所以当前进行_middleware.Reverse遍历的时候,最先取到的就是app.Use(decoupler)压进去的委托。

而参考上上一章对AppBuilder.Use方法的总结,实际上会调用第一种Use处理流程,所以上面源代码中middleware中的三元组对应的类型如下

说明
Item1 GetParameterType(an instance of (Func<AppFunc,AppFunc>)),结果为typeof(AppFunc) = typeof(Func<Idictionary<string, object>, Task>) = a special Delegate,是一个委托
Item2 Func<AppFunc,AppFunc> 委托的一个实例,对应decoupler
Item3 New object[0] 为空

所以Convert(neededSignature, app)可以替换成Convert(a special Delegate, an instance of Func<Idictionary<string, object>, Task>)

来看看Convert做了什么。

private object Convert(Type signature, object app)
        {
            if (app == null)
            {
                return null;
            }

            object oneHop = ConvertOneHop(signature, app);
            if (oneHop != null)
            {
                return oneHop;
            }

            object multiHop = ConvertMultiHop(signature, app);
            if (multiHop != null)
            {
                return multiHop;
            }
            throw new ArgumentException(
                string.Format(CultureInfo.CurrentCulture, Resources.Exception_NoConversionExists, app.GetType(), signature),
                "signature");

        }

Covert实际上是对ConvertOneHopConvertMultiHop的封装。

先看看ConvertOneHop方法。

private object ConvertOneHop(Type signature, object app)
        {
            if (signature.IsInstanceOfType(app))    //针对上面的例子,app确实是signature的一个实例,都对应Func<Idictionary<string, object>, Task>
            {
                return app;    //所以第一次调用会直接返回
            }
            if (typeof(Delegate).IsAssignableFrom(signature))    //如果signature是对Delegate的继承
            {
                Delegate memberDelegate = ToMemberDelegate(signature, app);    //尝试将app的Invoke方法创建为一个signature所表示的Type类型的委托
                if (memberDelegate != null)
                {
                    return memberDelegate;
                }
            }
            foreach (var conversion in _conversions)    //如果app的Invoke方法与signature的Invoke方法冲突,需要进行转换
    //这是Middleware与AppFunc之间的重要转换,也是pipeline的重点,留到后文详述
            {
                Type returnType = conversion.Key.Item1;
                Type parameterType = conversion.Key.Item2;
                if (parameterType.IsInstanceOfType(app) &&
                    signature.IsAssignableFrom(returnType))
                {
                    return conversion.Value.DynamicInvoke(app);
                }
            }
            return null;
        }

再回头看看_middleware.Rerverse遍历的第一次中,Convert(needSignature,app)会很快返回,值就是app,也就是Func<Idictionary<string, object>, Task>的一个实例,再运行app = middlewareDelegate.DynamicInvoke(invokeParameters)的时候,因为app已经合并进invokeParameters中所以,等同于执行

app =>
    {
                    if (string.Equals(name, stage.Name, StringComparison.OrdinalIgnoreCase))    //name = "Authenticate", stage.Name = "PreHandlerExecute",返回false
                    {
                        // no decoupling needed when pipeline is already split at this name
                        return app ;
                    }
                    if (!IntegratedPipelineContext.VerifyStageOrder(name, stage.Name))    //name = "Authenticate", stage.Name = "PreHandlerExecute",name < stage.Name,返回false,注意前面有个'!'
                    {
                        // Stage markers added out of order will be ignored.
                        // Out of order stages/middleware may be run earlier than expected.
                        // TODO: LOG
                        return app ;
                    }
                    stage.EntryPoint = app ;    //设置PreHandlerExecute这一Stage的EntryPoint为app,此时的app就是NotFound.Invoke方法
                    stage = new IntegratedPipelineBlueprintStage    //为Authenticate新建一个IntegratedPipelineBlueprintStage,NextStage绑定到PreHandlerExcute这一Stage上
    //所以两个PipelineStage就链接起来了
                    {
                        Name = name,
                        NextStage = stage,
                    };
                    onStageCreated(stage);    //更新firstStage,使其指向Autenticate这一Stage
                    return (AppFunc)IntegratedPipelineContext.ExitPointInvoked;    //返回ExitPointInvoked方法
                };

上面的代码演示了PreHandlerExcuteAuthenticate两个PipelineStage是如何串接在一起的,再来看看IntegratedPipelineContext.ExitPointInvoked到底干了什么。

public static Task ExitPointInvoked(IDictionary<string, object> env)
        {
            object value;
            if (env.TryGetValue(Constants.IntegratedPipelineContext, out value))    //尝试从environment中获取IntegratedPipelineContext实例,
            {
                var self = (IntegratedPipelineContext)value;
                return self._state.ExecutingStage.ExitPointInvoked(env);    //改变当前管道状态,使其可以流入下一管道
            }
            throw new InvalidOperationException();
        }
 public Task ExitPointInvoked(IDictionary<string, object> env)
        {
            _context.PreventNextStage = false;    //改变当前管道状态
            return Epilog(env);    //进行最后的收尾工作
        }

        private Task Epilog(IDictionary<string, object> env)
        {
            var tcs = new TaskCompletionSource<object>();
            _responseShouldEnd = false;    //开启response,因为即将进行Stage的切换,与Stage刚开始执行的时候关闭response相对应
            _context.PushLastObjects(env, tcs);    //验证当前pipeline所在Stage中的environment为null,TaskCompletionSource<object>为null,因为即将离开Stage,而Stage是公用的
    //这与IntegratedPipelineContextStage.BeginEvent中的TakeLastEnvironment,TakeLastCompletionSource相对应,都是原子操作
            StageAsyncResult result = Interlocked.Exchange(ref _result, null);
            if (result != null)
            {
                result.TryComplete();
            }
            return tcs.Task;
        }

扯了好远,在没有进行调试的情况下推断这些运行流程还真是很累的一件事儿。这对于前面没有搞懂的地方有很大帮助,看代码。

app = middlewareDelegate.DynamicInvoke(invokeParameters)执行之后,app = (AppFunc)IntegratedPipelineContext.ExitPointInvoked了,这就是PreHandlerExecute的收尾工作。

之后再次执行了app = Convert(neededSignature, app),此时的参数app仍然是一个AppFunc,所以还是会很快返回,进入下一循环。

这次_middleware.Rerverse遍历获取到的应该是app.Use(typeof(CookieAuthenticationMiddleware), app, options)压进去的CookieAuthenticationMiddleware

参考AppBuilder(一)那一节所分析的结果,因为传入的参数是一个Typeargs长度为2,所以会采用第四种方法来处理,如下

private static Tuple<Type, Delegate, object[]> ToConstructorMiddlewareFactory(object middlewareObject, object[] args, ref Delegate middlewareDelegate)

这个方法尝试寻找middlewareObject类中的参数个数为args长度+1,即是3个的构造函数。以下是对应的构造函数

public CookieAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, CookieAuthenticationOptions options) : base(next, options)

所以可以推断出此时取到的middleware三元组为

说明
Item1 OwinMiddleware的Type
Item2 CookieAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, CookieAuthenticationOptions options) 构造函数
Item3 [IAppBuilder app, CookieAuthenticationOptions options] 长度为2的object[]

再次执行

app = Convert(needSignature, app)…>object oneHop = ConvertOneHop(signature, app)

此时的参数app是一个AppFunc,而signature是一个OwinMiddleware,会用到_conversions,这将是OwinMiddlewareAppFunc之间互相转换的实现,需要用到AppBuilder时候对_conversions初始化的知识,留待下一章再说。

总结AppBuilder.BuildeInternalmiddlewareList遍历是反向的,虽然现在还不明白为什么如此设计,而且如何在一个PipelineStage中执行多个middleware也还不明朗,曾经以为是使用类似Invoke += Middleware.Invoke实现的,但既然是反向的,这不就顺序反了吗?

目前能确定下来的时候每个PipelineStageEntryPoint已经显式指定了,刚刚大概又想了一下,为了保证PipelineStage的规范性,那么每个PipelineStage应该都是一个Func<AppFunc, AppFunc>形式的才对,而Middleware应该是被封装在这两个AppFunc之间的,这么说,应该是_conversions来完成了同一个PipelineStage中的Middleware的串联工作了,理应如此。下一节再验证这个问题。

阅读更多

软件发布:'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'

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