欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

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

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

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

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

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

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

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

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

internal class HttpApplicationFactory{
  internal const string applicationFileName = "global.asax"; //看到這里,就知道為什么入口文件是global.asax了,因為這里定義死了
  ...
  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進行綁定(前提是方法名是以Application_開頭的),

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

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

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

相關文章

最新評論