源碼參見Microsoft.Owin.Host.SystemWeb.OwinBuilderhtml
Microsoft.Owin.Builder.AppBuilderapp
Microsoft.Owin.Host.SystemWeb.OwinHttpModuleui
本節主要涉及app.UseStageMarkerthis
先提提遇到的的三篇文章,講得很詳細的(鄙視那些轉載不註明出處的)spa
C# 中的委託和事件(詳解)code
http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.htmlorm
Difference Between Invoke and DynamicInvokehtm
http://stackoverflow.com/questions/12858340/difference-between-invoke-and-dynamicinvokeblog
C#中dynamic的正確用法事件
http://www.cnblogs.com/qiuweiguo/archive/2011/08/03/2125982.html
前文講到OWIN初始化的時候最開始的入口點不知道在哪兒,通過兩天的閱讀,發現這個了這個入口
Microsoft.Owin.Host.SystemWeb.PreApplicationStart這個類上有個Attribute定義
[assembly: PreApplicationStartMethod(typeof(PreApplicationStart), "Initialize")]
這應該是告訴未開源的部分進行初始化的,PreApplicationStart.Initialize方法將被調用,其工做爲
HttpApplication.RegisterModule(typeof(OwinHttpModule))
於是在源碼中能夠預見OwinHttpModule將被初始化,其初始化代碼
1 public void Init(HttpApplication context) 2 { 3 IntegratedPipelineBlueprint blueprint = LazyInitializer.EnsureInitialized( 4 ref _blueprint, 5 ref _blueprintInitialized, 6 ref _blueprintLock, 7 InitializeBlueprint); 8 9 if (blueprint != null) 10 { 11 var integratedPipelineContext = new IntegratedPipelineContext(blueprint); 12 integratedPipelineContext.Initialize(context); 13 } 14 }
上面的代碼描述的是先確保_blueprint,_blueprintInitialized,_blueprintLock已被初始化,初始狀態很明顯_blueprint未被初始化(彷佛_blueprint一直未被初始化),因此會調用InitializeBlueprint進行初始化。
1 private IntegratedPipelineBlueprint InitializeBlueprint() 2 { 3 IntegratedPipelineBlueprintStage firstStage = null; 4 5 Action<IAppBuilder> startup = OwinBuilder.GetAppStartup(); //這就到了前面所講的流程了,尋找Startup,但在Invoke以前進行了EnableIntegratedPipeline調用 6 OwinAppContext appContext = OwinBuilder.Build(builder => 7 { 8 EnableIntegratedPipeline(builder, stage => firstStage = stage); 9 startup.Invoke(builder); 10 }); 11 12 string basePath = Utils.NormalizePath(HttpRuntime.AppDomainAppVirtualPath); //獲取虛擬路徑 13 return new IntegratedPipelineBlueprint(appContext, firstStage, basePath); //pipeline已經構建完畢,返回第一個stage 14 }
上面作的代碼在AppBuilder進行pipeline中的middleware構建以前,啓用IntegratedPipelineBlueprint
1 //EnableIntegratedPipeline的第二個參數是一個Action 2 private static void EnableIntegratedPipeline(IAppBuilder app, Action<IntegratedPipelineBlueprintStage> onStageCreated) 3 { 4 var stage = new IntegratedPipelineBlueprintStage { Name = "PreHandlerExecute" }; //新建一個pipelineStage,只有 Name = "PreHandlerExecute",其餘屬性未初始化 5 onStageCreated(stage); //實際上就是使firstStage指向剛新建的pipelineStage,若是你足夠仔細的話 6 //你會發現這其實是定義的pipelineStage的最後一個 7 Action<IAppBuilder, string> stageMarker = (builder, name) => 8 { 9 Func<AppFunc, AppFunc> decoupler = next => 10 { //next是一個AppFunc委託,若是當前stage.Name與傳入的name相同,則仍然返回next,next實際上就是下一個stage的入口 11 if (string.Equals(name, stage.Name, StringComparison.OrdinalIgnoreCase)) 12 { 13 // no decoupling needed when pipeline is already split at this name 14 return next; 15 } 16 if (!IntegratedPipelineContext.VerifyStageOrder(name, stage.Name)) //若是當前的stage.Name的order小於傳入的name,仍然返回next 17 { 18 // Stage markers added out of order will be ignored. 19 // Out of order stages/middleware may be run earlier than expected. 20 // TODO: LOG 21 return next; 22 } //若是當前的stage.Name的order大於傳入的name,將當前stage的入口點設置爲next,新建一個pipelineStage 23 stage.EntryPoint = next; 24 stage = new IntegratedPipelineBlueprintStage 25 { 26 Name = name, 27 NextStage = stage, 28 }; 29 onStageCreated(stage); //更新firstStage 30 return (AppFunc)IntegratedPipelineContext.ExitPointInvoked; //當前stage已經構建完畢,再用一個AppFunc做爲當前middleware的返回值 31 }; 32 app.Use(decoupler); //decouper是一個Func<AppFunc,AppFunc>委託,因此會使用前一章所說的第一種app.Use方法,直接將其壓入List中 33 }; 34 app.Properties[Constants.IntegratedPipelineStageMarker] = stageMarker; //這裏將stageMarker綁定到app.Properties中,這將是本文的重點 35 app.Properties[Constants.BuilderDefaultApp] = (Func<IDictionary<string, object>, Task>)IntegratedPipelineContext.DefaultAppInvoked; 36 }
上文的源代碼與咱們一般的思惟有些出入,各個middleware是按順序壓入List的,而遍歷List重建的時候確實反向的,因此是從pipelineStage的最後一項PreHandlerExecute一直向前,並將屬於一個stage的全部middleware包裝在一個Func<AppFunc,AppFunc>中,第一個AppFunc是本stage的EntryPoint,第二個AppFunc是IntegratedPipelineContext.ExitPointInvoked,第二個AppFunc主要負責本stage完成以後的收尾工做,以後將調用本stage中的NextStage找到下一個stage,從下一個stage.EntryPoint開始執行。
在前文的InitializeBlueprint中OwinBuilder.Build中完成了EnableIntegratedPipeline操做,接下來就是Startup的Configuration方法被調用,以新建MVC生成的默認的Configuration爲例,UseCookieAuthentication將會被調用。
1 public static IAppBuilder UseCookieAuthentication(this IAppBuilder app, CookieAuthenticationOptions options, PipelineStage stage) 2 { 3 if (app == null) 4 { 5 throw new ArgumentNullException("app"); 6 } 7 8 app.Use(typeof(CookieAuthenticationMiddleware), app, options); 9 app.UseStageMarker(stage); 10 return app; 11 }
對於上面的源代碼咱們只關注其先使用Use方法,再使用了UseStageMarker方法,標記了當前stage爲PipelineStage.Authenticate。
1 public static IAppBuilder UseStageMarker(this IAppBuilder app, string stageName) 2 { 3 if (app == null) 4 { 5 throw new ArgumentNullException("app"); 6 } 7 8 object obj; 9 if (app.Properties.TryGetValue(IntegratedPipelineStageMarker, out obj)) //尋找app.Propertise中的StageMarker方法,也就是上文OwinHttpModule存進去的方法 10 { 11 var addMarker = (Action<IAppBuilder, string>)obj; 12 addMarker(app, stageName); 13 } 14 return app; 15 16 }
stageMarker主要作的工做上面已經介紹,在這裏的實際效果是將一個委託壓進List中,而這個委託做的工做是當前的PipelineStage從PreHandlerExcute提早到了Authenticate,並完成了AuthenticateStage中的NextStage指向PreHandlerExcuteStage,PreHandlerExcuteStage的EntryPoint是最開始初始化的stage,只不過這個委託將在AppBuilder進行Build的時候纔會Invoke。
那麼AppBuilder是在什麼時候進行Build的呢?在前面的某章曾提到Microsoft.Owin.Host.SystemWeb.OwinAppContext類中的Initialize方法的最後一行,其代碼以下
AppFunc = (AppFunc)builder.Build(typeof(AppFunc))
上面的代碼即開始了AppBuilder.Build方法,也是pipeline重建的開始的地方,沒想到卻在如此不起眼的地方。
public object Build(Type returnType) { return BuildInternal(returnType); }
可見定義了returnType爲Func<IDictionary<string, object>, Task>的委託,而Build是對BuildInternal的封裝,下一章將閱讀BuilderInternal方法。
總結middleware注入與重建是兩個逆向的過程,按順序注入,反向遍歷重建,微軟工程師巧妙地保證了pipeline注入順序,且保證了在兩個StageMarker的middleware被包裝在一個Func<AppFunc,AppFunc>中,通過約定每一個middleware返回next,在未遇到ExitPointInvoked以前,都不會發生PipelineStage的切換。這將須要PipelineStage切換機制的支持和對middleware輸入參數、輸出參數的約定。如今還有些模糊的地方,在下一章將經過對IntegratedPipeline以及AppBuilder.Build的閱讀來講清楚這些流程。