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

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

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

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

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

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

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

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

兩者結(jié)合起來(lái)看,可以推測(cè),HttpApplicationFactory 是用來(lái)獲取 MvcApplication 實(shí)例的,實(shí)際情況也是如此 上代碼(來(lái)自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個(gè)參數(shù)(第一個(gè)參數(shù)的類型是Object,第二個(gè)參數(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注冊(cè)事件通知了,由于看不到IIS源碼,具體怎么做的就不知道了。

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

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

相關(guān)文章

  • GridView分頁(yè)代碼簡(jiǎn)單萬(wàn)能實(shí)用

    GridView分頁(yè)代碼簡(jiǎn)單萬(wàn)能實(shí)用

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

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

    這篇文章主要為大家詳細(xì)介紹了Asp.net使用SignalR實(shí)現(xiàn)酷炫端對(duì)端聊天功能,感興趣的小伙伴們可以參考一下
    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添加序號(hào)列的方法

    ASP.NET repeater添加序號(hào)列的方法

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

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

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

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

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

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

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

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

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

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

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

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

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

最新評(píng)論

桓仁| 明水县| 德州市| 大姚县| 夹江县| 德州市| 鄯善县| 淳化县| 宁夏| 寿光市| 平安县| 阿城市| 柳州市| 汉沽区| 搜索| 靖边县| 河北区| 江永县| 娄底市| 淮滨县| 舟山市| 页游| 霍林郭勒市| 永济市| 融水| 政和县| 射阳县| 阿拉尔市| 罗源县| 金溪县| 青岛市| 岑巩县| 临泽县| 绥棱县| 渝北区| 临安市| 西林县| 温宿县| 池州市| 龙南县| 墨竹工卡县|