通过源码简单理解ASP.NET MVC中的消息管道(1)

概述


此系列是根据自己在看源码和大佬的博客总结得出,大概有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来处理

虽说两者在HttpRuntimeHttpApplication里处理思想相似,但在具体处理方式还是各有不同。

而我们这章总结的是图中标记的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集合中所有HttpModulesinit方法,用于管道事件的添加。

总结


1.IIS中,我们了解到了两种模式的处理的区别和对请求的处理方式。
2.知道了在初始化HttpApplication的时候,会对Global.asax进行编译和对配置文件的HttpModules进行初始化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值