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的初始化

 1 private static readonly AppFunc NotFound = new NotFound().Invoke;    //将NotFound.Invoke绑定到AppBuilder.NotFound上
 2 internal class NotFound
 3     {
 4         private static readonly Task Completed = CreateCompletedTask();
 5 
 6         private static Task CreateCompletedTask()
 7         {
 8             var tcs = new TaskCompletionSource<object>();
 9             tcs.SetResult(null);
10             return tcs.Task;
11         }
12 
13         public Task Invoke(IDictionary<string, object> env)    //这是一个满足AppBuilder中对于AppFunc定义的一个方法,之前在这里老是被绕晕了
14         {
15             env["owin.ResponseStatusCode"] = 404;    //设置StatusCode
16             return Completed;    //返回一个Task
17         }
18     }

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

 1 private object BuildInternal(Type signature)
 2         {
 3             object app;
 4             if (!_properties.TryGetValue(Constants.BuilderDefaultApp, out app))    //尝试寻找默认的最后一步处理方法,如果寻找失败则将app指向NotFound
 5             {
 6                 app = NotFound;
 7             }
 8 
 9             foreach (var middleware in _middleware.Reverse())    //对List进行反向遍历,反向遍历很重要,这样上一节所说的UseStageMarker对stage.Name的处理方式才能理解
10             {
11                 Type neededSignature = middleware.Item1;    //解耦三元组
12                 Delegate middlewareDelegate = middleware.Item2;
13                 object[] middlewareArgs = middleware.Item3;
14 
15                 app = Convert(neededSignature, app);    //尝试将app的Invoke方法创建为一个委托,委托为needSignature所表示的Type,听起来有点绕,没关系,慢慢来
16     //这将涉及到pipeline中AppFunc与Middleware的转换,这是OWIN的精华所在
17                 object[] invokeParameters = new[] { app }.Concat(middlewareArgs).ToArray();    //将app作为第一个参数与args合并
18                 app = middlewareDelegate.DynamicInvoke(invokeParameters);
19                 app = Convert(neededSignature, app);    //这一步我也没大懂,到后面懂了再说
20             }
21 
22             return Convert(signature, app);    //同理这一步我也没大懂
23         }

从实际例子出发容易理解上面的流程一些,上一章讲到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做了什么。

 1 private object Convert(Type signature, object app)
 2         {
 3             if (app == null)
 4             {
 5                 return null;
 6             }
 7 
 8             object oneHop = ConvertOneHop(signature, app);
 9             if (oneHop != null)
10             {
11                 return oneHop;
12             }
13 
14             object multiHop = ConvertMultiHop(signature, app);
15             if (multiHop != null)
16             {
17                 return multiHop;
18             }
19             throw new ArgumentException(
20                 string.Format(CultureInfo.CurrentCulture, Resources.Exception_NoConversionExists, app.GetType(), signature),
21                 "signature");
22 
23         }

Covert实际上是对ConvertOneHopConvertMultiHop的封装。

先看看ConvertOneHop方法。

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

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

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

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

 1 public static Task ExitPointInvoked(IDictionary<string, object> env)
 2         {
 3             object value;
 4             if (env.TryGetValue(Constants.IntegratedPipelineContext, out value))    //尝试从environment中获取IntegratedPipelineContext实例,
 5             {
 6                 var self = (IntegratedPipelineContext)value;
 7                 return self._state.ExecutingStage.ExitPointInvoked(env);    //改变当前管道状态,使其可以流入下一管道
 8             }
 9             throw new InvalidOperationException();
10         }
11  public Task ExitPointInvoked(IDictionary<string, object> env)
12         {
13             _context.PreventNextStage = false;    //改变当前管道状态
14             return Epilog(env);    //进行最后的收尾工作
15         }
16 
17         private Task Epilog(IDictionary<string, object> env)
18         {
19             var tcs = new TaskCompletionSource<object>();
20             _responseShouldEnd = false;    //开启response,因为即将进行Stage的切换,与Stage刚开始执行的时候关闭response相对应
21             _context.PushLastObjects(env, tcs);    //验证当前pipeline所在Stage中的environment为null,TaskCompletionSource<object>为null,因为即将离开Stage,而Stage是公用的
22     //这与IntegratedPipelineContextStage.BeginEvent中的TakeLastEnvironment,TakeLastCompletionSource相对应,都是原子操作
23             StageAsyncResult result = Interlocked.Exchange(ref _result, null);
24             if (result != null)
25             {
26                 result.TryComplete();
27             }
28             return tcs.Task;
29         }

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

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

OwinMiddlewareType

Item2

CookieAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, CookieAuthenticationOptions options)  构造函数

Item3

[IAppBuilder app,  CookieAuthenticationOptions options] 长度为2object[]

再次执行

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的串联工作了,理应如此。下一节再验证这个问题。

posted @ 2016-03-21 17:36  幻暝玄冰  阅读(738)  评论(0编辑  收藏  举报