zoukankan      html  css  js  c++  java
  • AppBuilder(四)SignatureConversions

    源码参见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&lt;IDictionary&lt;string,object&gt;, Task&gt;"/> 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也是这样的操作,不过parameterTypeOwinMiddleware,而ReturnTypeAppFunc

    解释一下转换原理,Conversion1这个方法return了一个AppFuncTransition实例,而AppFuncTransition继承自OwinMiddleware,自然就完成了转换

    Conversion2这个方法返回的是OwinMiddlewareTransition实例的Invoke方法,自然就是一个AppFunc

    可见两种签名对应的是OwinMiddleware实例和AppFunc委托的相互转换。

    回顾AppBuilder(三)中的_middleware.Reverse遍历操作:

    第一次取到的是app.Use(decoupler)对应的middleware第一次Convert操作完成了PipelineStage的切换,而且使得PreHandlerExcute这一StageEntryPointNotFound,新建的Authenticate这一StageNextStage指向PreHandlerExcute这一Stage第二次Convert操作很快返回,现在app指向(AppFunc)IntegratedPipelineContext.ExitPointInvoked

    第二次取到的是app.Use(typeof(CookieAuthenticationMiddleware), app, options)对应的CookieAuthenticationMiddleware,三元组解耦之后

    Item1

    OwinMiddlewareType

    Item2

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

    Item3

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

    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,分别为Conversion1Conversion2,由于我们需要从AppFuncOwinMiddleware的转换,经过参数和返回值的检查,会调用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=nullOwinMiddleware,而利用了(AppFunc)_next来记录链接关系,当调用这个OwinMiddlewareInvoke方法的时候,实际执行的还是_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方法的载体而已,这也是pipelinemiddlewarestage更换能够无缝衔接的原因。

    现在我们知道经过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的切换工作。

    此时appCookieAuthenticationMiddleware的实例,同理这次的app = Convert(neededSignature, app)会很快返回app不变

    至此已经可以解释很多东西了。

    1 为什么要反向遍历?

    因为每个OwinMiddleware的构造函数的第一个参数或者Func<AppFunc,AppFunc>的参数都是一个next,指向下一个要运行的组件,那么这个next不应该为空,而且要真实有效,反向遍历会先生成后面OwinMiddleware或者Func,然后用其作为前一个的参数,这能保证构造的pipeline的有效性。

    2 OwinMiddleware或者Func是如何串起来的?

    如上所述,每个OwinMiddleware或者Func的第一个参数都是一个nextOwinMiddlewareFunc的方法都会调用其Invoke方法,不同的是OwinMiddlewareInvoke是一个可以重写的方法,参数为OwinContext,而FuncDelegate,其Invoke方法等同执行这个Func,参数为Envrionment。在Invoke中做了自己的工作之后,执行next.Invoke方法,并返回其结果,这样就串起来了。

    3 PipelineStage是如何切换的?

    这将是下一节所要涉及的内容,每个PipelineStage都记录了NextStagePipeline调度部分可以在所有异步处理完成之后启用NextStage,这主要是未开源的System.Web.Application来完成调度的,采用了事件的机制。

    总结,每个PipelineStage有个EntryPointExitPoint,他们以及他们之前的其他OwinMiddleware或者Func通过next串联起来,执行的时候,由HttpApplication触发相应的事件。pipeline能流动的关键因素是每个组件对于下一组件都有合法有效引用,所以采用反向遍历的方法来重建,Func调用下一Funcnext.Invoke(environment)OwinMiddleware调用下一OwinMiddlewareNext.Invoke(context),所以conversion主要是OwinMiddleware或者Func看到的next都是跟自己一个类型的。OwinMiddleware为了与Func一致,都采用了Invoke作为入口。

  • 相关阅读:
    Generate Parentheses
    Length of Last Word
    Maximum Subarray
    Count and Say
    二分搜索算法
    Search Insert Position
    Implement strStr()
    Remove Element
    Remove Duplicates from Sorted Array
    Remove Nth Node From End of List
  • 原文地址:https://www.cnblogs.com/hmxb/p/5303940.html
Copyright © 2011-2022 走看看