概述
此系列是根据自己在看源码和大佬的博客总结得出,大概有3篇,因为自己看了源码和看大佬博客之后,很容易忘记,因此想先记录下来,如果哪里有错误的话,欢迎留言,如果这系列能帮上你,我也很开心。
下面的内容讲解的ASP.NET MVC是如何对HttpApplication进行初始化
一.简单的过程图
因为没有长截图,所以分段截图了= = ,如果想看全图,可以点击下面链接
https://www.processon.com/view/link/5cdd5111e4b0052864851feb
IIS在处理请求的时候,会根据网站设置的应用线程池,来决定是使用IIS6/IIS7的经典模式,还是使用IIS7的集成模式
个人理解的两种模式的区别:
执行IIS6/IIS7的经典模式的话,ASP.NET管道事件作为一个扩展插件(ISAPI)的形式存在,当IIS判断请求时请求静态文件的时候,就会由IIS进行处理,如果是一个ASP.NET请求,就会交给扩展插件(ISAPI)处理。
使用经典模式的话,会使用ISAPIRuntime来处理
执行使用IIS7的集成模式的话,ASP.NET管道就会覆盖IIS的管道,不管静态文件还是ASP.NET请求,都由ASP.NET 管道来处理。
使用集成模式的话,会使用PipelineRuntime来处理
虽说两者在HttpRuntime和HttpApplication里处理思想相似,但在具体处理方式还是各有不同。
而我们这章总结的是图中标记的1,也就是对HttpApplication的初始化
二.初始化HttpApplication
在图中ProcessRequestInternal方法和ProcessRequestNotificationPrivate方法里都会有下面这段代码。
ProcessRequestInternal:
IHttpHandler app = HttpApplicationFactory.GetApplicationInstance(context);
ProcessRequestNotificationPrivate:
IHttpHandler handler = null;
handler = HttpApplicationFactory.GetApplicationInstance(context);
而这段代码是对我们Global.asax,HttpAppliation的初始化。
internal static IHttpHandler GetApplicationInstance(HttpContext context)
{
//判断是否有自定义的IHttpHandler
if (_customApplication != null)
{
return _customApplication;
}
if (context.Request.IsDebuggingRequest)
{
return new HttpDebugHandler();
}
//编译目录下的Global.asax文件
_theApplicationFactory.EnsureInited();
//调用Global.asax文件的Application_Start方法
_theApplicationFactory.EnsureAppStartCalled(context);
//创造一个HttpApplication
return _theApplicationFactory.GetNormalApplicationInstance(context);
}
上面的源代码解释了当程序启动的时候,为什么会先调用Global.asax文件的Application_Start方法,下面我们来看看GetNormalApplicationInstance方法
private HttpApplication GetNormalApplicationInstance(HttpContext context)
{
HttpApplication result=null;
//ConcurrentBag<HttpApplication> _freeList
//判断HttpAppliciation池里面有无实例,如果有,TryTake方法
//会返回true并把元素赋值给result
if (!_freeList.TryTake(out result))
{
//如果没有,则会使用CreateNonPublicInstantce方法进行创造
result = (HttpApplication)HttpRuntime.CreateNonPublicInstance(_theApplicationType);
using (new ApplicationImpersonationContext())
{
//初始化管道
result.InitInternal(context, _state, _eventHandlerMethods);
}
}
if (AppSettings.UseTaskFriendlySynchronizationContext)
{
result.ApplicationInstanceConsumersCounter = new CountdownTask(1);
result.ApplicationInstanceConsumersCounter.Task.ContinueWith(delegate(Task _, object o)
{
RecycleApplicationInstance((HttpApplication)o);
}, result, TaskContinuationOptions.ExecuteSynchronously);
}
return result;
}
在代码中,我们简单了解了ASP.NET的HttpApplication是如何创造且初始化的,而初始化,也就是InitInternal方法,也要通过源码分析分析。
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
{
using (new DisposableHttpContextWrapper(context))
{
//忽略其他代码
//判断Runtime是不是使用集成管道
if (HttpRuntime.UseIntegratedPipeline)
{
try
{
context.HideRequestResponse = true;
_hideRequestResponse = true;
//初始化配置信息的集成Modules
InitIntegratedModules();
}
finally
{
context.HideRequestResponse = false;
_hideRequestResponse = false;
}
}
else
{
//初始化配置信息的经典Modules
InitModules();
}
if (handlers != null)
{
//如果在MVC程序中,MvcApplication写了方法(例如 Application_AuthenticateRequest),
//也将这些绑定到事件去
HookupEventHandlersForApplicationAndModules(handlers);
}
//忽略其它代码
//根据IIS的模式来创建不同的StepManager实例
if (HttpRuntime.UseIntegratedPipeline)
{
_stepManager = new PipelineStepManager(this);
}
else
{
_stepManager = new ApplicationStepManager(this);
}
_stepManager.BuildSteps(_resumeStepsWaitCallback);
//忽略其他代码
}
由于 InitInternal方法代码量有点多,我只挑选了几个关键的地方。
而InitModules或者InitIntegratedModules方法最终都会调用一个方法,那就是InitModulesCommon方法。
private void InitModulesCommon()
{
for (int i = 0; i < count; i++)
{
_currentModuleCollectionKey = _moduleCollection.GetKey(i);
//调用每个HttpModules的Init方法。
_moduleCollection[i].Init(this);
}
_currentModuleCollectionKey = null;
InitAppLevelCulture();
}
InitModulesCommon方法调用了在I_moduleCollection集合中所有HttpModules的init方法,用于管道事件的添加。
总结
1.IIS中,我们了解到了两种模式的处理的区别和对请求的处理方式。
2.知道了在初始化HttpApplication的时候,会对Global.asax进行编译和对配置文件的HttpModules进行初始化。