赞
踩
源码参见
Microsoft.Owin.Builder.AppBuilder
Microsoft.Owin.Infrastructure.SignatureConversions
在AppBuilder
中遇到了_middleware
三元组的Item1
,微软工程师称之为signature
不一致的问题,一种是AppFunc
,一种是OwinMiddleware
,因此需要用到SignatureConversions
,这是在AppBuilder
实例化的时候完成的工作,先看看AppBuilder
的构造函数。
public AppBuilder()
{
_properties = new Dictionary<string, object>(); //初始化环境字典
_conversions = new Dictionary<Tuple<Type, Type>, Delegate>(); //初始化_conversion字典
_middleware = new List<Tuple<Type, Delegate, object[]>>(); //初始化_middleware链表
_properties[Constants.BuilderAddConversion] = new Action<Delegate>(AddSignatureConversion); //绑定AddSignatureConversion方法
_properties[Constants.BuilderDefaultApp] = NotFound; //绑定默认最后一步处理流程
SignatureConversions.AddConversions(this); //开始往_conversions中添加具体的处理方法
}
实际的_conversions
完成初始化由SignatureConversions.AddConversions
完成。
public static class SignatureConversions
{
/// <summary>
/// Adds adapters between <typeref name="Func<IDictionary<string,object>, Task>"/> and OwinMiddleware.
/// </summary>
/// <param name="app"></param>
public static void AddConversions(IAppBuilder app) //实际上是对Conversion1和Conversion2的包装,调用的是AppBuilderExtension中的方法
{
app.AddSignatureConversion<AppFunc, OwinMiddleware>(Conversion1); //完成从AppFunc到OwinMiddleware的转换
app.AddSignatureConversion<OwinMiddleware, AppFunc>(Conversion2); //完成从OwinMiddleware到AppFunc的转换
}
private static OwinMiddleware Conversion1(AppFunc next)
{
return new AppFuncTransition(next);
}
private static AppFunc Conversion2(OwinMiddleware next)
{
return new OwinMiddlewareTransition(next).Invoke;
}
}
来看看AddSignatureConversion
,还是一层封装
public static void AddSignatureConversion<T1, T2>(this IAppBuilder builder, Func<T1, T2> conversion)
{
AddSignatureConversion(builder, (Delegate)conversion); //实际会调用下面的方法
}
public static void AddSignatureConversion(this IAppBuilder builder, Delegate conversion)
{
if (builder == null)
{
throw new ArgumentNullException("builder");
}
object obj;
if (builder.Properties.TryGetValue("builder.AddSignatureConversion", out obj)) //寻找AppBuilder构造函数中绑定的AddSignatureConversion,是Action<Delegate>
{
var action = obj as Action<Delegate>; //还原为Action<Delegate>
if (action != null)
{
action(conversion); //将conversion存入_conversion字典
return;
}
}
throw new MissingMethodException(builder.GetType().FullName, "AddSignatureConversion");
}
来看看这个Action<Delegate>
在拿到private static OwinMiddleware Conversion1(AppFunc next)
这个方法之后做了什么。
private void AddSignatureConversion(Delegate conversion)
{
if (conversion == null)
{
throw new ArgumentNullException("conversion");
}
Type parameterType = GetParameterType(conversion); //以Conversion1为例,这里的parameterType为AppFunc,ReturnType为OwinMiddleware
if (parameterType == null)
{
throw new ArgumentException(Resources.Exception_ConversionTakesOneParameter, "conversion");
}
Tuple<Type, Type> key = Tuple.Create(conversion.Method.ReturnType, parameterType); //使用conversion的ReturnType和parameterType作为key,相当于签名
_conversions[key] = conversion; //记录conversion
}
同理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
,三元组解耦之后
在Convert(neededSignature, app)
的时候等同于Convert(typeof(OwinMiddleware), AppFunc)
signature.IsInstanceOfType(app)
和typeof(Delegate).IsAssignableFrom(signature)
均会返回false
,所以会进入本文的重点
foreach (var conversion in _conversions) //经过推断会调用Conversion1
{
Type returnType = conversion.Key.Item1; //returnType为OwinMiddleware
Type parameterType = conversion.Key.Item2; //parameterType为AppFunc
if (parameterType.IsInstanceOfType(app) &&
signature.IsAssignableFrom(returnType))
{
return conversion.Value.DynamicInvoke(app); //等同于调用new AppFuncTransition(app)
}
}
_conversions
字典中有两个conversion
,分别为Conversion1
和Conversion2
,由于我们需要从AppFunc
到OwinMiddleware
的转换,经过参数和返回值的检查,会调用Conversion1
进行转换实例化了一个AppFuncTransition
,参数为app
来看看AppFuncTransition
internal sealed class AppFuncTransition : OwinMiddleware
{
private readonly AppFunc _next;
/// <summary>
///
/// </summary>
/// <param name="next"></param>
public AppFuncTransition(AppFunc next) : base(null) //调用的是这个构造函数,base(null)父对象实例化一个空的middleware
{
_next = next; //使_next指向app
}
/// <summary>
///
/// </summary>
/// <param name="context"></param>
/// <returns></returns>
public override Task Invoke(IOwinContext context)
{
if (context == null)
{
throw new ArgumentNullException("context");
}
return _next(context.Environment);
}
}
可见上面的代码巧妙的返回一个Next=null的OwinMiddleware,而利用了(AppFunc)_next来记录链接关系,当调用这个OwinMiddleware的Invoke方法的时候,实际执行的还是_next(context.Environment),等同于还是执行的AppFunc(context.Envrionment),与原来并没有什么区别。
再看看OwinMiddlewareTransition
internal sealed class OwinMiddlewareTransition
{
private readonly OwinMiddleware _next;
/// <summary>
///
/// </summary>
/// <param name="next"></param>
public OwinMiddlewareTransition(OwinMiddleware next)
{
_next = next;
}
/// <summary>
///
/// </summary>
/// <param name="environment">OWIN environment dictionary which stores state information about the request, response and relevant server state.</param>
/// <returns></returns>
public Task Invoke(IDictionary<string, object> environment)
{
return _next.Invoke(new OwinContext(environment));
}
}
我们需要的是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
作为入口。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。