zoukankan      html  css  js  c++  java
  • ASP.NET1.0HttpModule的生存周期

         HttpModule是ASP.NET提供的一个非常有用的功能扩展手段。通过HttpModule我们可以简单的在HttpApplication实例上挂接事件,通过响应HttpApplication触发的事件使我们就机会在Session建立或者销毁、请求处理之前或者请求处理之后等一些特殊的时机做一些额外的工作。使用HttpModule的好处是我们不需要将这些额外工作的代码显示的加入到业务代码中,是我们能够透明的增加额外的功能。微软自生也提供了大量的HttpModule的默认实现,例如: DefaultAuthenticationModule、FileAuthorizationModule等。
        虽然HttpModule应用的非常广泛,但是我们基本上没有考虑过HttpModule的生存周期。在写这篇文章之前,我一直认为HttpModule 对象的生存周期与Application的生存周期一致,也就是一个Application中只有一个HttpModule。但是通过我对微软的代码进行反射分析,发现HttpModule的生存周期与HttpApplication的生存周期是一致的,代码如下:
     1 internal void InitInternal()
     2 {
     3     this._state = state;
     4     PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
     5     this._initContext = context;
     6     this._initContext.ApplicationInstance = this;
     7     try
     8     {
     9         try
    10         {
    11             context.ConfigPath = context.Request.ApplicationPath;
    12             using (HttpContextWrapper wrapper = new HttpContextWrapper(context))
    13             {
    14                 this.InitModules();
    15                 if (handlers != null)
    16                 {
    17                     this.HookupEventHandlersForAppplicationAndModules(handlers);
    18                 }
    19                 this._context = context;
    20                 this._hideRequestResponse = true;
    21                 try
    22                 {
    23                     this.Init();
    24                 }
    25                 catch (Exception exception)
    26                 {
    27                     this.RecordError(exception);
    28                 }
    29             }
    30      
    31 
    32 private void InitModules()
    33 {
    34     HttpModulesConfiguration appConfig =
                    (HttpModulesConfiguration) HttpContext.GetAppConfig(
    "system.web/httpModules");
    35     if (appConfig == null)
    36     {
    37         throw new HttpException(HttpRuntime.FormatResourceString("Missing_modules_config"));
    38     }
    39     this._moduleCollection = appConfig.CreateModules();
    40     int count = this._moduleCollection.Count;
    41     for (int i = 0; i < count; i++)
    42     {
    43         this._moduleCollection[i].Init(this);
    44     }
    45     GlobalizationConfig config = (GlobalizationConfig) HttpContext.GetAppConfig("system.web/globalization");
    46     if (config != null)
    47     {
    48         this._appLevelCulture = config.Culture;
    49         this._appLevelUICulture = config.UICulture;
    50     }
    51 }
        通过代码可以发现每次创建HttpApplication的时候都回初始化HttpModule。接下来我们在看HttpApplication的生存周期,代码如下:HttpRuntime类的ProcessRequest方法,这个方法是Web请求的入口方法。
        注意:一个HttpRuntime对应一个WebApplication。在Windows2003下(IIS6),下一个w3wp.exe对应一个ApplicationPool,一个ApplicationPool中可以容纳多个WebApplication,每一个WebApplication对应一个AppDomain。如果是XP的话所有的WebApplication都处于iis_asp.exe(名字记得不太清楚了)这个进程中,使用AppDomain来分隔不同的AppDomain.
     1    public static void ProcessRequest(HttpWorkerRequest wr)
     2 {
     3     InternalSecurityPermissions.AspNetHostingPermissionLevelMedium.Demand();
     4     if (wr == null)
     5     {
     6         throw new ArgumentNullException("custom");
     7     }
     8     RequestQueue queue = _theRuntime._requestQueue;
     9     if (queue != null)
    10     {
    11         wr = queue.GetRequestToExecute(wr);
    12     }
    13     if (wr != null)
    14     {
    15         CalculateWaitTimeAndUpdatePerfCounter(wr);
    16         ProcessRequestNow(wr);
    17     }
    18 }
        注意下划线标注出来的两个方法。其中GetRequestToExecute方法去检查当前的线程池,判断是否有空闲的线程来处理这个请求,如果没有空闲的线程处理这个请求则将请加入到等待请求队列。接下来我们进一步的分析ProcessRequestNow这个方法。我们最终可以追踪到请求最终在HttpRuntime类的ProcessRequestInternal方法中被处理,代码如下:
     1 private void ProcessRequestInternal(HttpWorkerRequest wr)
     2 {
     3     HttpContext extraData = new HttpContext(wr, false);
     4     wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, extraData);
     5     Interlocked.Increment(ref this._activeRequestCount);
     6     try
     7     {
     8         if (this._beforeFirstRequest)
     9         {
    10             lock (this)
    11             {
    12                 if (this._beforeFirstRequest)
    13                 {
    14                     this._firstRequestStartTime = DateTime.UtcNow;
    15                     this.FirstRequestInit(extraData);
    16                     this._beforeFirstRequest = false;
    17                 }
    18             }
    19         }
    20         extraData.Impersonation.Start(truefalse);
    21         try
    22         {
    23             extraData.Response.InitResponseWriter();
    24         }
    25         finally
    26         {
    27             extraData.Impersonation.Stop();
    28         }
    29         IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(extraData);
    30         if (applicationInstance == null)
    31         {
    32             throw new HttpException(FormatResourceString("Unable_create_app_object"));
    33         }
    34         if (applicationInstance is IHttpAsyncHandler)
    35         {
    36             IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
    37             extraData.AsyncAppHandler = handler2;
    38             handler2.BeginProcessRequest(extraData, this._handlerCompletionCallback, extraData);
    39         }
    40         else
    41         {
    42             applicationInstance.ProcessRequest(extraData);
    43             this.FinishRequest(extraData.WorkerRequest, extraData, null);
    44         }
    45     }
    46     catch (Exception exception)
    47     {
    48         extraData.Response.InitResponseWriter();
    49         this.FinishRequest(wr, extraData, exception);
    50     }
    51 }
    我们继续来关注HttpApplicationFactory.GetApplicationInstance(extraData)这个代码。继续追踪,最终定位到HttpApplicationFactory类的GetNormalApplicationInstance方法和CreateNonPublicInstance方法,代码如下:
     1 private HttpApplication GetNormalApplicationInstance(HttpContext context)
     2 {
     3     HttpApplication application = null;
     4     lock (this._freeList)
     5     {
     6         if (this._numFreeAppInstances > 0)
     7         {
     8             application = (HttpApplication) this._freeList.Pop();
     9             this._numFreeAppInstances--;
    10         }
    11     }
    12     if (application == null)
    13     {
    14         application = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
    15         context.Impersonation.Start(truefalse);
    16         try
    17         {
    18             try
    19             {
    20                 application.InitInternal(context, this._state, this._eventHandlerMethods);
    21                 return application;
    22             }
    23             finally
    24             {
    25                 context.Impersonation.Stop();
    26             }
    27         }
    28         catch
    29         {
    30             throw;
    31         }
    32     }
    33     return application;
    34 }
    35 
    36 internal static object CreateNonPublicInstance(Type type)
    37 {
    38     return CreateNonPublicInstance(type, null);
    39 }
        看到没有,如果在_freeList中没有空闲的HttpApplication的时候就会创建新的HttpApplication,并且这个Application在Session结束的时候会被回收,具体的代码可以查看相关代码。在这段代码中我们又发现了InitInternal这个面熟的方法,就是在这个方法中初始化HttpModule的,事情到这里就明白了,HttpModule的生存周期是跟HttpApplication的生存周期一致的,并且在同一个WebApplication中可能同时存在多个HttpApplication的实例。如果处理了Global.asax,也就是特殊HttpApplcation的话最大数目大概是20,如果是标准的HttpApplication的话最大数目是100,代码如下:
     1  private void RecycleNormalApplicationInstance(HttpApplication app)
     2 {
     3     if (this._numFreeAppInstances < 100)
     4     {
     5         lock (this._freeList)
     6         {
     7             this._freeList.Push(app);
     8             this._numFreeAppInstances++;
     9             return;
    10         }
    11     }
    12     app.DisposeInternal();
    13 }
    14 
    15  
    16 private void RecycleSpecialApplicationInstance(HttpApplication app)
    17 {
    18     if (this._numFreeSpecialAppInstances < 20)
    19     {
    20         lock (this._specialFreeList)
    21         {
    22             this._specialFreeList.Push(app);
    23             this._numFreeSpecialAppInstances++;
    24         }
    25     }
    26 }
        而且同时存在的HttpApplication的数目有并发请求的数目和最大能够允许的HttpApplication的实例数目共同决定的。所以如果期望在HttpModule中做处理的时候,如果需要保存共享数据时就需要注意HttpModule的生存期,不过如果使用静态变量的话就没有问题了,静态变量的生存周期跟AppMomain的生存周期一致。

  • 相关阅读:
    WinForm 下的 Wizard(向导) 控件, 提供设计时支持!
    关于安装VS2005或MSDN时遇到“Please insert the disk:XXXXXXX” 错误提示的解决方法!
    Welcome
    Latex 入门教程
    图形学 旋转与投影矩阵3
    图形学 旋转与投影矩阵—2
    算法希尔排序可视化
    图形学 旋转与投影矩阵—1
    BlinnPhong反射模型实践(web实现)
    贝塞尔曲线(面)二三维可视化(Three+d3)
  • 原文地址:https://www.cnblogs.com/zengezenge/p/825687.html
Copyright © 2011-2022 走看看