源码参见
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
作为入口。