最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Asp.net?MVC中的Http管道事件為什么要以Application_開頭(原因解析)

 更新時間:2024年12月03日 09:06:53   作者:jikhww  
在ASP.NET?MVC中,為了在API請求結(jié)束時釋放數(shù)據(jù)庫鏈接,避免連接池被爆掉,可以通過在Global.asax.cs文件中定義并實(shí)現(xiàn)Application_EndRequest方法來實(shí)現(xiàn),本文介紹Asp.net?MVC中的Http管道事件為什么要以Application_開頭,感興趣的朋友一起看看吧

今天遇到一個問題,需要在API請求結(jié)束時,釋放數(shù)據(jù)庫鏈接,避免連接池被爆掉。

按照以往的經(jīng)驗(yàn),需要實(shí)現(xiàn)IHttpModule,具體不展開了。
但是實(shí)現(xiàn)了IHttpModule后,還得去web.config中增加配置,這有點(diǎn)麻煩了,就想有沒有簡單的辦法。

其實(shí)是有的,就是在Global.asax.cs里面定義并實(shí)現(xiàn) Application_EndRequest 方法,在這個方法里面去釋放數(shù)據(jù)庫連接即可,經(jīng)過測試,確實(shí)能達(dá)到效果。
但是,為什么方法名必須是Application_EndRequest ?在這之前真不知道為什么,只知道baidu上是這么說的,也能達(dá)到效果。
還好我有一點(diǎn)好奇心,想搞清楚是怎么回事情,就把net framework的源碼拉下來(其實(shí)源代碼在電腦里面已經(jīng)躺了N年了) 分析了一下,以下是分析結(jié)果。

省略掉前面N個調(diào)用
第一個需要關(guān)注的是 HttpApplicationFactory.cs
從名字就知道,這是HttpApplication的工廠類,大家看看Gloabal.asax.cs 里面,是不是這樣定義的

public class MvcApplication : System.Web.HttpApplication
{
.....
}

兩者結(jié)合起來看,可以推測,HttpApplicationFactory 是用來獲取 MvcApplication 實(shí)例的,實(shí)際情況也是如此 上代碼(來自HttpApplicationFactory)

internal class HttpApplicationFactory{
  internal const string applicationFileName = "global.asax"; //看到這里,就知道為什么入口文件是global.asax了,因?yàn)檫@里定義死了
  ...
  private void EnsureInited() {
      if (!_inited) {
          lock (this) {
              if (!_inited) {
                  Init();
                  _inited = true;
              }
          }
      }
  }
  private void Init() {
      if (_customApplication != null)
          return;
      try {
          try {
              _appFilename = GetApplicationFile();
              CompileApplication();
          }
          finally {
              // Always set up global.asax file change notification, even if compilation
              // failed.  This way, if the problem is fixed, the appdomain will be restarted.
              SetupChangesMonitor();
          }
      }
      catch { // Protect against exception filters
          throw;
      }
  }
  private void CompileApplication() {
    // Get the Application Type and AppState from the global file
    _theApplicationType = BuildManager.GetGlobalAsaxType();
    BuildResultCompiledGlobalAsaxType result = BuildManager.GetGlobalAsaxBuildResult();
    if (result != null) {
        // Even if global.asax was already compiled, we need to get the collections
        // of application and session objects, since they are not persisted when
        // global.asax is compiled.  Ideally, they would be, but since <object> tags
        // are only there for ASP compat, it's not worth the trouble.
        // Note that we only do this is the rare case where we know global.asax contains
        // <object> tags, to avoid always paying the price (VSWhidbey 453101)
        if (result.HasAppOrSessionObjects) {
            GetAppStateByParsingGlobalAsax();
        }
        // Remember file dependencies
        _fileDependencies = result.VirtualPathDependencies;
    }
    if (_state == null) {
        _state = new HttpApplicationState();
    }
    // Prepare to hookup event handlers via reflection
    ReflectOnApplicationType();
  }   
  private void ReflectOnApplicationType() {
    ArrayList handlers = new ArrayList();
    MethodInfo[] methods;
    Debug.Trace("PipelineRuntime", "ReflectOnApplicationType");
    // get this class methods
    methods = _theApplicationType.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static);
    foreach (MethodInfo m in methods) {
        if (ReflectOnMethodInfoIfItLooksLikeEventHandler(m))
            handlers.Add(m);
    }
    // get base class private methods (GetMethods would not return those)
    Type baseType = _theApplicationType.BaseType;
    if (baseType != null && baseType != typeof(HttpApplication)) {
        methods = baseType.GetMethods(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Static);
        foreach (MethodInfo m in methods) {
            if (m.IsPrivate && ReflectOnMethodInfoIfItLooksLikeEventHandler(m))
                handlers.Add(m);
        }
    }
    // remember as an array
    _eventHandlerMethods = new MethodInfo[handlers.Count];
    for (int i = 0; i < _eventHandlerMethods.Length; i++)
        _eventHandlerMethods[i] = (MethodInfo)handlers[i];
  }
  private bool ReflectOnMethodInfoIfItLooksLikeEventHandler(MethodInfo m) {
    if (m.ReturnType != typeof(void))
        return false;
    // has to have either no args or two args (object, eventargs)
    ParameterInfo[] parameters = m.GetParameters();
    switch (parameters.Length) {
        case 0:
            // ok
            break;
        case 2:
            // param 0 must be object
            if (parameters[0].ParameterType != typeof(System.Object))
                return false;
            // param 1 must be eventargs
            if (parameters[1].ParameterType != typeof(System.EventArgs) &&
                !parameters[1].ParameterType.IsSubclassOf(typeof(System.EventArgs)))
                return false;
            // ok
            break;
        default:
            return false;
    }
    // check the name (has to have _ not as first or last char)
    String name = m.Name;
    int j = name.IndexOf('_');
    if (j <= 0 || j > name.Length-1)
        return false;
    // special pseudo-events
    if (StringUtil.EqualsIgnoreCase(name, "Application_OnStart") ||
        StringUtil.EqualsIgnoreCase(name, "Application_Start")) {
        _onStartMethod = m;
        _onStartParamCount = parameters.Length;
    }
    else if (StringUtil.EqualsIgnoreCase(name, "Application_OnEnd") ||
             StringUtil.EqualsIgnoreCase(name, "Application_End")) {
        _onEndMethod = m;
        _onEndParamCount = parameters.Length;
    }
    else if (StringUtil.EqualsIgnoreCase(name, "Session_OnEnd") ||
             StringUtil.EqualsIgnoreCase(name, "Session_End")) {
        _sessionOnEndMethod = m;
        _sessionOnEndParamCount = parameters.Length;
    }
    return true;
  }
}

上面代碼調(diào)用鏈路是EnsureInited->Init->CompileApplication->ReflectOnApplicationType->ReflectOnMethodInfoIfItLooksLikeEventHandler ,核心作用是:將MvcApplication中,方法名包含下劃線、方法參數(shù)為空或者有2個參數(shù)(第一個參數(shù)的類型是Object,第二個參數(shù)的類型是EventArgs) 的方法加入到_eventHandlerMethods 中
那么事件是怎么綁定的呢?繼續(xù)上代碼

internal class HttpApplicationFactory{
......
  using (new ApplicationImpersonationContext()) {
      app.InitInternal(context, _state, _eventHandlerMethods);
  }
......
......
  using (new ApplicationImpersonationContext()) {
      app.InitInternal(context, _state, _eventHandlerMethods);
  }
......
}
// HttpApplication.cs
public class HttpApplication{
  internal void InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) {
    .....    
      if (handlers != null) {
          HookupEventHandlersForApplicationAndModules(handlers);
      }
    .....
  }
  internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers) {
    .....
      if (handlers != null)        
        HookupEventHandlersForApplicationAndModules(handlers);
    .....
  }
  private void HookupEventHandlersForApplicationAndModules(MethodInfo[] handlers) {
      _currentModuleCollectionKey = HttpApplicationFactory.applicationFileName;
      if(null == _pipelineEventMasks) {
          Dictionary<string, RequestNotification> dict = new Dictionary<string, RequestNotification>();
          BuildEventMaskDictionary(dict);
          if(null == _pipelineEventMasks) {
              _pipelineEventMasks = dict;
          }
      }
      for (int i = 0; i < handlers.Length; i++) {
          MethodInfo appMethod = handlers[i];
          String appMethodName = appMethod.Name;
          int namePosIndex = appMethodName.IndexOf('_');
          String targetName = appMethodName.Substring(0, namePosIndex);
          // Find target for method
          Object target = null;
          if (StringUtil.EqualsIgnoreCase(targetName, "Application"))
              target = this;
          else if (_moduleCollection != null)
              target = _moduleCollection[targetName];
          if (target == null)
              continue;
          // Find event on the module type
          Type targetType = target.GetType();
          EventDescriptorCollection events = TypeDescriptor.GetEvents(targetType);
          string eventName = appMethodName.Substring(namePosIndex+1);
          EventDescriptor foundEvent = events.Find(eventName, true);
          if (foundEvent == null
              && StringUtil.EqualsIgnoreCase(eventName.Substring(0, 2), "on")) {
              eventName = eventName.Substring(2);
              foundEvent = events.Find(eventName, true);
          }
          MethodInfo addMethod = null;
          if (foundEvent != null) {
              EventInfo reflectionEvent = targetType.GetEvent(foundEvent.Name);
              Debug.Assert(reflectionEvent != null);
              if (reflectionEvent != null) {
                  addMethod = reflectionEvent.GetAddMethod();
              }
          }
          if (addMethod == null)
              continue;
          ParameterInfo[] addMethodParams = addMethod.GetParameters();
          if (addMethodParams.Length != 1)
              continue;
          // Create the delegate from app method to pass to AddXXX(handler) method
          Delegate handlerDelegate = null;
          ParameterInfo[] appMethodParams = appMethod.GetParameters();
          if (appMethodParams.Length == 0) {
              // If the app method doesn't have arguments --
              // -- hookup via intermidiate handler
              // only can do it for EventHandler, not strongly typed
              if (addMethodParams[0].ParameterType != typeof(System.EventHandler))
                  continue;
              ArglessEventHandlerProxy proxy = new ArglessEventHandlerProxy(this, appMethod);
              handlerDelegate = proxy.Handler;
          }
          else {
              // Hookup directly to the app methods hoping all types match
              try {
                  handlerDelegate = Delegate.CreateDelegate(addMethodParams[0].ParameterType, this, appMethodName);
              }
              catch {
                  // some type mismatch
                  continue;
              }
          }
          // Call the AddXXX() to hook up the delegate
          try {
              addMethod.Invoke(target, new Object[1]{handlerDelegate});
          }
          catch {
              if (HttpRuntime.UseIntegratedPipeline) {
                  throw;
              }
          }
          if (eventName != null) {
              if (_pipelineEventMasks.ContainsKey(eventName)) {
                  if (!StringUtil.StringStartsWith(eventName, "Post")) {
                      _appRequestNotifications |= _pipelineEventMasks[eventName];
                  }
                  else {
                      _appPostNotifications |= _pipelineEventMasks[eventName];
                  }
              }
          }
      }
  }
}

核心方法:HookupEventHandlersForApplicationAndModules,其作用就是將前面獲取到的method與HttpApplication的Event進(jìn)行綁定(前提是方法名是以Application_開頭的),

后面就是向IIS注冊事件通知了,由于看不到IIS源碼,具體怎么做的就不知道了。

最后安利一下,還是用net core吧,更加清晰、直觀,誰用誰知道。

到此這篇關(guān)于Asp.net MVC中的Http管道事件為什么要以Application_開頭的文章就介紹到這了,更多相關(guān)Asp.net MVC Http管道事件內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • GridView分頁代碼簡單萬能實(shí)用

    GridView分頁代碼簡單萬能實(shí)用

    GridView在使用.net技術(shù)搭建的后臺,在商品列表或者是信息列表經(jīng)常會出現(xiàn);它的作用在于有效的管理信息,增刪改查等等最主要的是還可以實(shí)現(xiàn)分頁,這一點(diǎn)是無可比靡的,接下來介紹如何使用GridView實(shí)現(xiàn)分頁,需要了解的朋友可以參考下
    2012-12-12
  • Asp.net使用SignalR實(shí)現(xiàn)酷炫端對端聊天功能

    Asp.net使用SignalR實(shí)現(xiàn)酷炫端對端聊天功能

    這篇文章主要為大家詳細(xì)介紹了Asp.net使用SignalR實(shí)現(xiàn)酷炫端對端聊天功能,感興趣的小伙伴們可以參考一下
    2016-04-04
  • ASP.NET實(shí)現(xiàn)QQ、微信、新浪微博OAuth2.0授權(quán)登錄

    ASP.NET實(shí)現(xiàn)QQ、微信、新浪微博OAuth2.0授權(quán)登錄

    本文主要介紹了QQ、微信、新浪微博OAuth2.0授權(quán)登錄的示例,主要就是GET、POST遠(yuǎn)程接口,返回相應(yīng)的數(shù)據(jù),這里列出相關(guān)的代碼,供大家參考。
    2016-03-03
  • ASP.NET repeater添加序號列的方法

    ASP.NET repeater添加序號列的方法

    在項(xiàng)目開發(fā)過程中,會經(jīng)常遇到ASP.NET repeater控件添加序號列,有些新手可能還不會,網(wǎng)上搜集整理了一些,需要的朋友可以參考下
    2012-11-11
  • WPF圖片按鈕的實(shí)現(xiàn)方法

    WPF圖片按鈕的實(shí)現(xiàn)方法

    這篇文章主要為大家詳細(xì)介紹了WPF圖片按鈕的實(shí)現(xiàn)方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • asp.net頁面狀態(tài)管理cookie和服務(wù)器狀態(tài)管理Session

    asp.net頁面狀態(tài)管理cookie和服務(wù)器狀態(tài)管理Session

    Session變量將在服務(wù)器為每個連接建立一個字典對象,使用的是服務(wù)端保存。Cookie可能會有一個按照年月日來判斷的作廢日期,而Session級別的變量在連接超時后就作廢
    2010-09-09
  • IIS和.NET(1.1/2.0)的安裝順序及錯誤解決方法

    IIS和.NET(1.1/2.0)的安裝順序及錯誤解決方法

    安裝順序及錯誤的解決方法:基于.net2.0的情況與基于.net1.1的情況,分別給予解決方法,遇到此問題的朋友可以了解下,或許對你的學(xué)習(xí)有所幫助
    2013-02-02
  • Asp.net FileUpload+Image制作頭像效果示例代碼

    Asp.net FileUpload+Image制作頭像效果示例代碼

    個人信息中通常需要自己的頭像或者照片,今天主要介紹一下使用FileUpload+img控件上傳照片,感興趣的朋友可以參考下
    2013-08-08
  • .Net?Core3.0?WebApi?項(xiàng)目框架搭建之使用Serilog替換掉Log4j

    .Net?Core3.0?WebApi?項(xiàng)目框架搭建之使用Serilog替換掉Log4j

    Serilog 是一個用于.NET應(yīng)用程序的日志記錄開源庫,配置簡單,接口干凈,并可運(yùn)行在最新的.NET平臺上,這篇文章主要介紹了.Net?Core3.0?WebApi?項(xiàng)目框架搭建之使用Serilog替換掉Log4j,需要的朋友可以參考下
    2022-02-02
  • ASP.NET解除堆棧溢出問題的具體步驟和方案

    ASP.NET解除堆棧溢出問題的具體步驟和方案

    ASP.NET中堆棧溢出通常由無限遞歸或過深方法調(diào)用鏈引發(fā),無法通過try-catch捕獲,解決核心是預(yù)防為主,包括定位根源、優(yōu)化代碼,定位方法包括查看異常日志和本地復(fù)現(xiàn)調(diào)試,修復(fù)方法主要針對無限遞歸和遞歸深度過深的問題,感興趣的朋友跟隨小編一起看看吧
    2025-11-11

最新評論

图片| 华安县| 甘泉县| 江源县| 莲花县| 柳河县| 芜湖县| 介休市| 高要市| 称多县| 延寿县| 胶南市| 穆棱市| 柳江县| 阿瓦提县| 电白县| 屏东市| 淳安县| 晋城| 延庆县| 礼泉县| 西平县| 石首市| 成都市| 兴化市| 巴楚县| 乌什县| 洛川县| 丹寨县| 沐川县| 九江县| 巴楚县| 北宁市| 阿坝| 普定县| 太仆寺旗| 台南市| 金阳县| 清河县| 襄樊市| 普定县|