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方法来说至关重要。

扫描二维码关注公众号,回复: 2020457 查看本文章
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的串联工作了,理应如此。下一节再验证这个问题。

猜你喜欢

转载自blog.csdn.net/WuLex/article/details/80962802