源码参见
Microsoft.Owin.Host.SystemWeb.OwinBuilder
Microsoft.Owin.Builder.AppBuilder
Microsoft.Owin.Host.SystemWeb.OwinHttpModule
本节主要涉及app.UseStageMarker
先提提遇到的的三篇文章,讲得很详细的(鄙视那些转载不注明出处的)
C# 中的委托和事件(详解)
http://www.cnblogs.com/SkySoot/archive/2012/04/05/2433639.html
Difference Between Invoke and DynamicInvoke
http://stackoverflow.com/questions/12858340/difference-between-invoke-and-dynamicinvoke
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
将被初始化,其初始化代码
public void Init(HttpApplication context)
{
IntegratedPipelineBlueprint blueprint = LazyInitializer.EnsureInitialized(
ref _blueprint,
ref _blueprintInitialized,
ref _blueprintLock,
InitializeBlueprint);
if (blueprint != null)
{
var integratedPipelineContext = new IntegratedPipelineContext(blueprint);
integratedPipelineContext.Initialize(context);
}
}
上面的代码描述的是先确保_blueprint
,_blueprintInitialized
,_blueprintLock
已被初始化,初始状态很明显_blueprint
未被初始化(似乎_blueprint
一直未被初始化),所以会调用InitializeBlueprint
进行初始化。
private IntegratedPipelineBlueprint InitializeBlueprint()
{
IntegratedPipelineBlueprintStage firstStage = null;
Action<IAppBuilder> startup = OwinBuilder.GetAppStartup(); //这就到了前面所讲的流程了,寻找Startup,但在Invoke之前进行了EnableIntegratedPipeline调用
OwinAppContext appContext = OwinBuilder.Build(builder =>
{
EnableIntegratedPipeline(builder, stage => firstStage = stage);
startup.Invoke(builder);
});
string basePath = Utils.NormalizePath(HttpRuntime.AppDomainAppVirtualPath); //获取虚拟路径
return new IntegratedPipelineBlueprint(appContext, firstStage, basePath); //pipeline已经构建完毕,返回第一个stage
}
上面做的代码在AppBuilder
进行pipeline
中的middleware
构建之前,启用IntegratedPipelineBlueprint
//EnableIntegratedPipeline的第二个参数是一个Action
private static void EnableIntegratedPipeline(IAppBuilder app, Action<IntegratedPipelineBlueprintStage> onStageCreated)
{
var stage = new IntegratedPipelineBlueprintStage { Name = "PreHandlerExecute" }; //新建一个pipelineStage,只有 Name = "PreHandlerExecute",其他属性未初始化
onStageCreated(stage); //实际上就是使firstStage指向刚新建的pipelineStage,如果你足够仔细的话
//你会发现这实际上是定义的pipelineStage的最后一个
Action<IAppBuilder, string> stageMarker = (builder, name) =>
{
Func<AppFunc, AppFunc> decoupler = next =>
{ //next是一个AppFunc委托,如果当前stage.Name与传入的name相同,则仍然返回next,next实际上就是下一个stage的入口
if (string.Equals(name, stage.Name, StringComparison.OrdinalIgnoreCase))
{
// no decoupling needed when pipeline is already split at this name
return next;
}
if (!IntegratedPipelineContext.VerifyStageOrder(name, stage.Name)) //如果当前的stage.Name的order小于传入的name,仍然返回next
{
// Stage markers added out of order will be ignored.
// Out of order stages/middleware may be run earlier than expected.
// TODO: LOG
return next;
} //如果当前的stage.Name的order大于传入的name,将当前stage的入口点设置为next,新建一个pipelineStage
stage.EntryPoint = next;
stage = new IntegratedPipelineBlueprintStage
{
Name = name,
NextStage = stage,
};
onStageCreated(stage); //更新firstStage
return (AppFunc)IntegratedPipelineContext.ExitPointInvoked; //当前stage已经构建完毕,再用一个AppFunc作为当前middleware的返回值
};
app.Use(decoupler); //decouper是一个Func<AppFunc,AppFunc>委托,所以会使用前一章所说的第一种app.Use方法,直接将其压入List中
};
app.Properties[Constants.IntegratedPipelineStageMarker] = stageMarker; //这里将stageMarker绑定到app.Properties中,这将是本文的重点
app.Properties[Constants.BuilderDefaultApp] = (Func<IDictionary<string, object>, Task>)IntegratedPipelineContext.DefaultAppInvoked;
}
上文的源代码与我们通常的思维有些出入,各个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
将会被调用。
public static IAppBuilder UseCookieAuthentication(this IAppBuilder app, CookieAuthenticationOptions options, PipelineStage stage)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
app.Use(typeof(CookieAuthenticationMiddleware), app, options);
app.UseStageMarker(stage);
return app;
}
对于上面的源代码我们只关注其先使用Use
方法,再使用了UseStageMarker
方法,标记了当前stage
为PipelineStage.Authenticate
。
public static IAppBuilder UseStageMarker(this IAppBuilder app, string stageName)
{
if (app == null)
{
throw new ArgumentNullException("app");
}
object obj;
if (app.Properties.TryGetValue(IntegratedPipelineStageMarker, out obj)) //寻找app.Propertise中的StageMarker方法,也就是上文OwinHttpModule存进去的方法
{
var addMarker = (Action<IAppBuilder, string>)obj;
addMarker(app, stageName);
}
return app;
}
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
的阅读来说清楚这些流程。