源碼參見Microsoft.Owin.Builder.AppBuilderapp
Microsoft.Owin.Infrastructure.SignatureConversions異步
在AppBuilder中遇到了_middleware三元組的Item1,微軟工程師稱之爲signature不一致的問題,一種是AppFunc,一種是OwinMiddleware,所以須要用到SignatureConversions,這是在AppBuilder實例化的時候完成的工做,先看看AppBuilder的構造函數。ide
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,仍是一層封裝ui
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)這個方法以後作了什麼。this
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。spa
解釋一下轉換原理,Conversion1這個方法return了一個AppFuncTransition實例,而AppFuncTransition繼承自OwinMiddleware,天然就完成了轉換。code
而Conversion2這個方法返回的是OwinMiddlewareTransition實例的Invoke方法,天然就是一個AppFunc了orm
可見兩種簽名對應的是OwinMiddleware實例和AppFunc委託的相互轉換。server
回顧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做爲入口。