源码参见Microsoft.Owin.Builder.AppBuilder
Microsoft.Owin.Infrastructure.SignatureConversions
在AppBuilder中遇到了_middleware三元组的Item1,微软工程师称之为signature不一致的问题,一种是AppFunc,一种是OwinMiddleware,因此需要用到SignatureConversions,这是在AppBuilder实例化的时候完成的工作,先看看AppBuilder的构造函数。
1 public AppBuilder() 2 { 3 _properties = new Dictionary<string, object>(); //初始化环境字典 4 _conversions = new Dictionary<Tuple<Type, Type>, Delegate>(); //初始化_conversion字典 5 _middleware = new List<Tuple<Type, Delegate, object[]>>(); //初始化_middleware链表 6 7 _properties[Constants.BuilderAddConversion] = new Action<Delegate>(AddSignatureConversion); //绑定AddSignatureConversion方法 8 _properties[Constants.BuilderDefaultApp] = NotFound; //绑定默认最后一步处理流程 9 10 SignatureConversions.AddConversions(this); //开始往_conversions中添加具体的处理方法 11 }
实际的_conversions完成初始化由SignatureConversions.AddConversions完成。
1 public static class SignatureConversions 2 { 3 /// <summary> 4 /// Adds adapters between <typeref name="Func<IDictionary<string,object>, Task>"/> and OwinMiddleware. 5 /// </summary> 6 /// <param name="app"></param> 7 public static void AddConversions(IAppBuilder app) //实际上是对Conversion1和Conversion2的包装,调用的是AppBuilderExtension中的方法 8 { 9 app.AddSignatureConversion<AppFunc, OwinMiddleware>(Conversion1); //完成从AppFunc到OwinMiddleware的转换 10 app.AddSignatureConversion<OwinMiddleware, AppFunc>(Conversion2); //完成从OwinMiddleware到AppFunc的转换 11 } 12 13 private static OwinMiddleware Conversion1(AppFunc next) 14 { 15 return new AppFuncTransition(next); 16 } 17 18 private static AppFunc Conversion2(OwinMiddleware next) 19 { 20 return new OwinMiddlewareTransition(next).Invoke; 21 } 22 }
来看看AddSignatureConversion,还是一层封装
1 public static void AddSignatureConversion<T1, T2>(this IAppBuilder builder, Func<T1, T2> conversion) 2 { 3 AddSignatureConversion(builder, (Delegate)conversion); //实际会调用下面的方法 4 } 5 public static void AddSignatureConversion(this IAppBuilder builder, Delegate conversion) 6 { 7 if (builder == null) 8 { 9 throw new ArgumentNullException("builder"); 10 } 11 object obj; 12 if (builder.Properties.TryGetValue("builder.AddSignatureConversion", out obj)) //寻找AppBuilder构造函数中绑定的AddSignatureConversion,是Action<Delegate> 13 { 14 var action = obj as Action<Delegate>; //还原为Action<Delegate> 15 if (action != null) 16 { 17 action(conversion); //将conversion存入_conversion字典 18 return; 19 } 20 } 21 throw new MissingMethodException(builder.GetType().FullName, "AddSignatureConversion"); 22 }
来看看这个Action<Delegate>在拿到private static OwinMiddleware Conversion1(AppFunc next)这个方法之后做了什么。
1 private void AddSignatureConversion(Delegate conversion) 2 { 3 if (conversion == null) 4 { 5 throw new ArgumentNullException("conversion"); 6 } 7 8 Type parameterType = GetParameterType(conversion); //以Conversion1为例,这里的parameterType为AppFunc,ReturnType为OwinMiddleware 9 if (parameterType == null) 10 { 11 throw new ArgumentException(Resources.Exception_ConversionTakesOneParameter, "conversion"); 12 } 13 Tuple<Type, Type> key = Tuple.Create(conversion.Method.ReturnType, parameterType); //使用conversion的ReturnType和parameterType作为key,相当于签名 14 _conversions[key] = conversion; //记录conversion 15 }
同理Conversion2也是这样的操作,不过parameterType为OwinMiddleware,而ReturnType为AppFunc。
解释一下转换原理,Conversion1这个方法return了一个AppFuncTransition实例,而AppFuncTransition继承自OwinMiddleware,自然就完成了转换。
而Conversion2这个方法返回的是OwinMiddlewareTransition实例的Invoke方法,自然就是一个AppFunc了
可见两种签名对应的是OwinMiddleware实例和AppFunc委托的相互转换。
回顾AppBuilder(三)中的_middleware.Reverse遍历操作:
第一次取到的是app.Use(decoupler)对应的middleware,第一次Convert操作完成了PipelineStage的切换,而且使得PreHandlerExcute这一Stage的EntryPoint为NotFound,新建的Authenticate这一Stage的NextStage指向PreHandlerExcute这一Stage,第二次Convert操作很快返回,现在app指向(AppFunc)IntegratedPipelineContext.ExitPointInvoked。
第二次取到的是app.Use(typeof(CookieAuthenticationMiddleware), app, options)对应的CookieAuthenticationMiddleware,三元组解耦之后
Item1 |
OwinMiddleware的Type |
Item2 |
CookieAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, CookieAuthenticationOptions options) 构造函数 |
Item3 |
[IAppBuilder app, CookieAuthenticationOptions options] 长度为2的object[] |
在Convert(neededSignature, app)的时候等同于Convert(typeof(OwinMiddleware), AppFunc)
signature.IsInstanceOfType(app)和typeof(Delegate).IsAssignableFrom(signature)均会返回false,所以会进入本文的重点
1 foreach (var conversion in _conversions) //经过推断会调用Conversion1 2 { 3 Type returnType = conversion.Key.Item1; //returnType为OwinMiddleware 4 Type parameterType = conversion.Key.Item2; //parameterType为AppFunc 5 if (parameterType.IsInstanceOfType(app) && 6 signature.IsAssignableFrom(returnType)) 7 { 8 return conversion.Value.DynamicInvoke(app); //等同于调用new AppFuncTransition(app) 9 } 10 }
_conversions字典中有两个conversion,分别为Conversion1和Conversion2,由于我们需要从AppFunc到OwinMiddleware的转换,经过参数和返回值的检查,会调用Conversion1进行转换实例化了一个AppFuncTransition,参数为app
来看看AppFuncTransition
1 internal sealed class AppFuncTransition : OwinMiddleware 2 { 3 private readonly AppFunc _next; 4 5 /// <summary> 6 /// 7 /// </summary> 8 /// <param name="next"></param> 9 public AppFuncTransition(AppFunc next) : base(null) //调用的是这个构造函数,base(null)父对象实例化一个空的middleware 10 { 11 _next = next; //使_next指向app 12 } 13 14 /// <summary> 15 /// 16 /// </summary> 17 /// <param name="context"></param> 18 /// <returns></returns> 19 public override Task Invoke(IOwinContext context) 20 { 21 if (context == null) 22 { 23 throw new ArgumentNullException("context"); 24 } 25 26 return _next(context.Environment); 27 } 28 }
可见上面的代码巧妙的返回一个Next=null的OwinMiddleware,而利用了(AppFunc)_next来记录链接关系,当调用这个OwinMiddleware的Invoke方法的时候,实际执行的还是_next(context.Environment),等同于还是执行的AppFunc(context.Envrionment),与原来并没有什么区别。
再看看OwinMiddlewareTransition
1 internal sealed class OwinMiddlewareTransition 2 { 3 private readonly OwinMiddleware _next; 4 5 /// <summary> 6 /// 7 /// </summary> 8 /// <param name="next"></param> 9 public OwinMiddlewareTransition(OwinMiddleware next) 10 { 11 _next = next; 12 } 13 14 /// <summary> 15 /// 16 /// </summary> 17 /// <param name="environment">OWIN environment dictionary which stores state information about the request, response and relevant server state.</param> 18 /// <returns></returns> 19 public Task Invoke(IDictionary<string, object> environment) 20 { 21 return _next.Invoke(new OwinContext(environment)); 22 } 23 }
我们需要的是OwinMiddlewareTransition.Invoke方法,这是一个AppFunc,也是Conversion2返回的,当调用这个Invoke方法的时候实际执行的是_next.Invoke(new OwinContext(environment)),等同于执行OwinMiddleware.Invoke(new OwinContext(envrionment)),与原来也并没有什么区别。
这里可以看出虽然实例和方法之间实现了转换,但因为都会调用Invoke方法,与不转换之前并没有什么区别,不改变执行的逻辑,只是改变了承载这个Invoke方法的载体而已,这也是pipeline中middleware和stage更换能够无缝衔接的原因。
现在我们知道经过Conversion1转换之后,app更新为Convert的返回值,由一个AppFunc变成了一个OwinMiddleware。
app = middlewareDelegate.DynamicInvoke(invokeParameters)执行的时候等同于执行OwinMiddleware.Invoke(OwinMiddleware, IAppBuilder app, CookieAuthenticationOptions options),返回一个CookieAuthenticationMiddleware。
对应的构造函数为
public CookieAuthenticationMiddleware(OwinMiddleware next, IAppBuilder app, CookieAuthenticationOptions options) : base(next, options)
最终达到的效果是CookieAuthenticationMiddleware执行Next.Invoke(conetxt)方法,实际上是执行的IntegratedPipelineContext.ExitPointInvoked(context.Environment),执行PipelineStage的切换工作。
此时app为CookieAuthenticationMiddleware的实例,同理这次的app = Convert(neededSignature, app)会很快返回,app不变。
至此已经可以解释很多东西了。
1 为什么要反向遍历?
因为每个OwinMiddleware的构造函数的第一个参数或者Func<AppFunc,AppFunc>的参数都是一个next,指向下一个要运行的组件,那么这个next不应该为空,而且要真实有效,反向遍历会先生成后面OwinMiddleware或者Func,然后用其作为前一个的参数,这能保证构造的pipeline的有效性。
2 OwinMiddleware或者Func是如何串起来的?
如上所述,每个OwinMiddleware或者Func的第一个参数都是一个next,OwinMiddleware或Func的方法都会调用其Invoke方法,不同的是OwinMiddleware的Invoke是一个可以重写的方法,参数为OwinContext,而Func是Delegate,其Invoke方法等同执行这个Func,参数为Envrionment。在Invoke中做了自己的工作之后,执行next.Invoke方法,并返回其结果,这样就串起来了。
3 PipelineStage是如何切换的?
这将是下一节所要涉及的内容,每个PipelineStage都记录了NextStage,Pipeline调度部分可以在所有异步处理完成之后启用NextStage,这主要是未开源的System.Web.Application来完成调度的,采用了事件的机制。
总结,每个PipelineStage有个EntryPoint和ExitPoint,他们以及他们之前的其他OwinMiddleware或者Func通过next串联起来,执行的时候,由HttpApplication触发相应的事件。pipeline能流动的关键因素是每个组件对于下一组件都有合法有效引用,所以采用反向遍历的方法来重建,Func调用下一Func为next.Invoke(environment),OwinMiddleware调用下一OwinMiddleware为Next.Invoke(context),所以conversion主要是OwinMiddleware或者Func看到的next都是跟自己一个类型的。OwinMiddleware为了与Func一致,都采用了Invoke作为入口。