<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12
      代碼改變世界

      MVC之前的那點(diǎn)事兒系列(5):Http Pipeline詳細(xì)分析(下)

      2014-06-04 08:50  湯姆大叔  閱讀(7469)  評論(4)    收藏  舉報(bào)

      文章內(nèi)容

      接上面的章節(jié),我們這篇要講解的是Pipeline是執(zhí)行的各種事件,我們知道,在自定義的HttpModule的Init方法里,我們可以添加自己的事件,比如如下代碼:

      public class Test : IHttpModule
      {
          public void Init(HttpApplication context)
          {
              context.BeginRequest += new EventHandler(context_BeginRequest);
              context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
          }
      
          void context_AuthenticateRequest(object sender, EventArgs e)
          {
              throw new NotImplementedException();
          }
      
          void context_BeginRequest(object sender, EventArgs e)
          {
              throw new NotImplementedException();
          }
      }

      然后添加的代碼,在Pipeline里執(zhí)行的時(shí)候就會把這些事件給執(zhí)行了,那么如何執(zhí)行并且按照什么順序執(zhí)行的呢? 在了解這些之前,我們先看看這些事件是如何在HttpApplication里暴露出來了,添加事件存放在何處的呢?閱讀HttpApplication的源碼,我們可以看到,所有的事件都是按照如下的形式暴露的,選擇其中兩個(gè)看一下:

      /// <devdoc><para>[To be supplied.]</para></devdoc> 
      public event EventHandler BeginRequest {
          add { AddSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest); }
          remove { RemoveSyncEventHookup(EventBeginRequest, value, RequestNotification.BeginRequest); }
      } 
      
       
      /// <devdoc><para>[To be supplied.]</para></devdoc> 
      public event EventHandler AuthenticateRequest {
          add { AddSyncEventHookup(EventAuthenticateRequest, value, RequestNotification.AuthenticateRequest); } 
          remove { RemoveSyncEventHookup(EventAuthenticateRequest, value, RequestNotification.AuthenticateRequest); }
      }

      可以發(fā)現(xiàn),所有的事件都是調(diào)用AddSyncEventHookup方法添加進(jìn)去的,其中第一個(gè)參數(shù)是以Event+事件名稱的值,這個(gè)值是如何得來的,我們找到聲明的代碼:

      private static readonly object EventDisposed = new object();
      private static readonly object EventErrorRecorded = new object();
      private static readonly object EventPreSendRequestHeaders = new object(); 
      private static readonly object EventPreSendRequestContent = new object();
       
      private static readonly object EventBeginRequest = new object(); 
      private static readonly object EventAuthenticateRequest = new object();
      private static readonly object EventDefaultAuthentication = new object(); 
      private static readonly object EventPostAuthenticateRequest = new object();
      private static readonly object EventAuthorizeRequest = new object();
      private static readonly object EventPostAuthorizeRequest = new object();
      private static readonly object EventResolveRequestCache = new object(); 
      private static readonly object EventPostResolveRequestCache = new object();
      private static readonly object EventMapRequestHandler = new object(); 
      private static readonly object EventPostMapRequestHandler = new object(); 
      private static readonly object EventAcquireRequestState = new object();
      private static readonly object EventPostAcquireRequestState = new object(); 
      private static readonly object EventPreRequestHandlerExecute = new object();
      private static readonly object EventPostRequestHandlerExecute = new object();
      private static readonly object EventReleaseRequestState = new object();
      private static readonly object EventPostReleaseRequestState = new object(); 
      private static readonly object EventUpdateRequestCache = new object();
      private static readonly object EventPostUpdateRequestCache = new object(); 
      private static readonly object EventLogRequest = new object(); 
      private static readonly object EventPostLogRequest = new object();
      private static readonly object EventEndRequest = new object(); 

      再結(jié)合add和remove方法,可以大膽猜想,這些值應(yīng)該是作為key值用的,我們先看完第2個(gè)參數(shù),再來驗(yàn)證我們的猜想,第2個(gè)參數(shù)是枚舉類型RequestNotification,這里我們再猜想一下,所有的事件都應(yīng)該放在統(tǒng)一的地方,然后用這個(gè)枚舉來區(qū)分。讓我們先看看這個(gè)枚舉類的代碼:

      [Flags]
      public enum RequestNotification
      {
          BeginRequest = 1,
          AuthenticateRequest = 2,
          AuthorizeRequest = 4,
          ResolveRequestCache = 8,
          MapRequestHandler = 16,
          AcquireRequestState = 32,
          PreExecuteRequestHandler = 64,
          ExecuteRequestHandler = 128,
          ReleaseRequestState = 256,
          UpdateRequestCache = 512,
          LogRequest = 1024,
          EndRequest = 2048,
          SendResponse = 536870912,
      }

      發(fā)現(xiàn)什么了沒有?雖然使用了Flags標(biāo)記來記錄以便進(jìn)行異或查詢,但是這里的枚舉類型好像少了一些吧,仔細(xì)對照代碼發(fā)現(xiàn)所有以Post開頭的事件都沒出現(xiàn)在這個(gè)枚舉類里,為什么呢?那這些事件是如何聲明的?回到HttpApplication類來繼續(xù)查看代碼,

      /// <devdoc><para>[To be supplied.]</para></devdoc>
      public event EventHandler PostAuthenticateRequest {
          add { AddSyncEventHookup(EventPostAuthenticateRequest, value, RequestNotification.AuthenticateRequest, true); } 
          remove { RemoveSyncEventHookup(EventPostAuthenticateRequest, value, RequestNotification.AuthenticateRequest, true); }
      } 

      突然發(fā)現(xiàn),這個(gè)AddSyncEventHookup方法多了一個(gè)參數(shù)true,這是干什么的呢?我們?nèi)ゲ榭催@個(gè)看看究竟。

      internal void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification) { 
          AddSyncEventHookup(key, handler, notification, false); 
      }
      private void AddSyncEventHookup(object key, Delegate handler, RequestNotification notification, bool isPostNotification) { 
          ThrowIfEventBindingDisallowed(); 
      
          // add the event to the delegate invocation list 
          // this keeps non-pipeline ASP.NET hosts working
          Events.AddHandler(key, handler);
      
          // For integrated pipeline mode, add events to the IExecutionStep containers only if 
          // InitSpecial has completed and InitInternal has not completed.
          if (IsContainerInitalizationAllowed) { 
              // lookup the module index and add this notification 
              PipelineModuleStepContainer container = GetModuleContainer(CurrentModuleCollectionKey);
              //WOS 1985878: HttpModule unsubscribing an event handler causes AV in Integrated Mode 
              if (container != null) {
      #if DBG
                  container.DebugModuleName = CurrentModuleCollectionKey;
      #endif 
                  SyncEventExecutionStep step = new SyncEventExecutionStep(this, (EventHandler)handler);
                  container.AddEvent(notification, isPostNotification, step); 
              } 
          }
      } 

      原來這個(gè)方法有2個(gè)重新,第2個(gè)多了一個(gè)isPostNotification的布爾值參數(shù),也就是說通過這個(gè)參數(shù)節(jié)約了很多枚舉類型的聲明。

      我們來仔細(xì)看一下上述的代碼,在剛開始的時(shí)候通過調(diào)用Events.AddHandler方法,將事件添加到Events集合里,同時(shí)這個(gè)key就是我們上面猜想的那些Event+事件名稱,通過注釋我們也可以知道Events是為non-pipeline來準(zhǔn)備的,在結(jié)合if語句上面的注釋,我們發(fā)現(xiàn)在IIS7的集成模式下這些事件是添加到另外一個(gè)地方的(通過將事件hanlder包裝成SyncEventExecutionStep類型,然后調(diào)用container.AddEvent方法將事件添加到另外一個(gè)地方),也就是說if上面的Events集合是給IIS6和IIS7經(jīng)典模式用的,下面的Container里的數(shù)據(jù)是給IIS7集成模式用的。

      注:經(jīng)典模式使用了Event+事件名稱做為key值,但集成模式使用了RequestNotification枚舉+ isPostNotification布爾值集合做為key值,這點(diǎn)區(qū)別需要注意一下。

      那到底IIS7集成模式下的是存放在何處呢?通過GetModuleContainer方法,最終我們可以查到,這些事件是存放在HttpApplication的ModuleContainers屬性里,這個(gè)屬性的類型是PipelineModuleStepContainer[],個(gè)數(shù)就是HttpModules的個(gè)數(shù),也就是說每個(gè)HttpModule在HttpApplication上添加的事件都放在各自的PipelineModuleStepContainer容器里。

      現(xiàn)在我們重新回頭繼續(xù)來看上個(gè)章節(jié)的代碼:

      // Construct the execution steps array 
      if (HttpRuntime.UseIntegratedPipeline) { 
          _stepManager = new PipelineStepManager(this);
      } 
      else {
          _stepManager = new ApplicationStepManager(this);
      }
       
      _stepManager.BuildSteps(_resumeStepsWaitCallback);

      集成模式和經(jīng)典模式(或IIS6)使用的是不同的StepManager,這個(gè)類的BuildSteps方法就是為了創(chuàng)建有序的ExecutionStep,其中包括各種事件的事情以及其它在各時(shí)間周期之間穿插的操作,最主要的操作,大家以前就應(yīng)該知道的,比如哪個(gè)周期可以判定使用哪個(gè)HttpHandler,以及在哪個(gè)周期內(nèi)執(zhí)行這個(gè)HttpHandler的BeginProcessRequest方法。

       

      由于不同的StepManager處理方式不同,我們先看IIS6以及IIS7經(jīng)典模式的處理代碼:

      internal override void BuildSteps(WaitCallback stepCallback ) { 
          ArrayList steps = new ArrayList();
          HttpApplication app = _application;
      
          bool urlMappingsEnabled = false; 
          UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
          urlMappingsEnabled = urlMappings.IsEnabled && ( urlMappings.UrlMappings.Count > 0 ); 
       
          steps.Add(new ValidateRequestExecutionStep(app));
          steps.Add(new ValidatePathExecutionStep(app)); 
      
          if (urlMappingsEnabled)
              steps.Add(new UrlMappingsExecutionStep(app)); // url mappings
       
          app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps); 
          app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps); 
          app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps); 
          app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
          steps.Add(new MapHandlerExecutionStep(app));     // map handler 
          app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps); 
          app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps); 
          app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
          steps.Add(new CallHandlerExecutionStep(app));  // execute handler 
          app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
          steps.Add(new CallFilterExecutionStep(app));  // filtering 
          app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps); 
          _endRequestStepIndex = steps.Count; 
          app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
          steps.Add(new NoopExecutionStep()); // the last is always there 
      
          _execSteps = new IExecutionStep[steps.Count];
          steps.CopyTo(_execSteps);
       
          // callback for async completion when reposting to threadpool thread
          _resumeStepsWaitCallback = stepCallback; 
      } 

      看著上面的代碼是不是有似曾相識的感覺,很多講聲明周期的文章都會提到20多個(gè)的事件(BeginRequest, EndRequest等),我們來看看這個(gè)方法的完整功能都是做了什么,歸納總結(jié)有5點(diǎn):

      1. 對請求的Request進(jìn)行驗(yàn)證,ValidateRequestExecutionStep。
      2. 對請求的路徑進(jìn)行安全檢查,禁止非法路徑訪問(ValidatePathExecutionStep)。 
      3. 如果設(shè)置了UrlMappings, 進(jìn)行RewritePath(UrlMappingsExecutionStep)。
      4. 執(zhí)行事件處理函數(shù),比如將BeginRequest、AuthenticateRequest轉(zhuǎn)化成可執(zhí)行ExecutionStep在正式調(diào)用時(shí)候執(zhí)行。
      5. 在這18個(gè)事件操作處理期間,根據(jù)不同的時(shí)機(jī)加了4個(gè)特殊的ExecutionStep。
        1. MapHandlerExecutionStep:查找匹配的HttpHandler
        2. CallHandlerExecutionStep:執(zhí)行HttpHandler的BeginProcessRequest
        3. CallFilterExecutionStep:調(diào)用Response.FilterOutput方法過濾輸出
        4. NoopExecutionStep:空操作,留著以后擴(kuò)展用

      需要注意的是所有的ExecuteionStep都保存在ApplicationStepManager實(shí)例下的私有字段_execSteps里,而HttpApplication的BeginProcessRequest方法最終會通過該實(shí)例的ResumeSteps方法來執(zhí)行這些操作(就是我們所說的那些事件以及4個(gè)特殊的Steps)。

      OK,我們繼續(xù)來看IIS7集成模式下是如何處理的,上代碼:

      internal override void BuildSteps(WaitCallback stepCallback) {
          Debug.Trace("PipelineRuntime", "BuildSteps"); 
          //ArrayList steps = new ArrayList();
          HttpApplication app = _application;
      
          // add special steps that don't currently 
          // correspond to a configured handler
       
          IExecutionStep materializeStep = new MaterializeHandlerExecutionStep(app); 
      
          // implicit map step 
          app.AddEventMapping(
              HttpApplication.IMPLICIT_HANDLER,
              RequestNotification.MapRequestHandler,
              false, materializeStep); 
      
          // implicit handler routing step 
          IExecutionStep handlerStep = new CallHandlerExecutionStep(app); 
      
          app.AddEventMapping( 
              HttpApplication.IMPLICIT_HANDLER,
              RequestNotification.ExecuteRequestHandler,
              false, handlerStep);
       
          // add implicit request filtering step
          IExecutionStep filterStep = new CallFilterExecutionStep(app); 
       
          // normally, this executes during UpdateRequestCache as a high priority module
          app.AddEventMapping( 
              HttpApplication.IMPLICIT_FILTER_MODULE,
              RequestNotification.UpdateRequestCache,
              false, filterStep);
       
          // for error conditions, this executes during LogRequest as a high priority module
          app.AddEventMapping( 
              HttpApplication.IMPLICIT_FILTER_MODULE, 
              RequestNotification.LogRequest,
              false, filterStep); 
      
          _resumeStepsWaitCallback = stepCallback;
      }

      以上代碼有2個(gè)地方和IIS6不相同:

      1. IIS7集成模式?jīng)]有使用MapHandlerExecutionStep來裝載ExecutionStep(也就是查找對應(yīng)的HttpHandler),而是通過MaterializeHandlerExecutionStep類來獲得HttpHandler,方式不一樣,但最終都是調(diào)用HttpApplication.GetFactory方法來獲取的,只不過IIS7集成模式有一些特殊操作而已罷了。
      2. IIS7集成模式是通過HttpApplication的AddEventMapping方法來添加事件的,從而將事件再次加入到前面所說的ModuleContainers容器。

      另外有個(gè)很有技巧的代碼:上述4個(gè)Steps所加的周期都不是準(zhǔn)確的周期,比如CallHandlerExecutionStep應(yīng)該是加載RequestNotification的枚舉值PreExecuteRequestHandler 和ExecuteRequestHandler之間,為什么呢?因?yàn)楸旧鞢allHandlerExecutionStep只是一個(gè)特殊的step而不暴露事件的,所以枚舉里也沒有,那怎么辦?回頭看看AddEventMapping方法的第一個(gè)參數(shù),它代表的是HttpModule的名字,查看其中的代碼得知,在執(zhí)行所有事件的時(shí)候,會遍歷所有HttpModuel名稱集合然后先執(zhí)行全部BeginRequest事件,再全部執(zhí)行AuthenticateRequest事件,以此類推,那我們能不能來偽造一個(gè)HttpModule的名稱作為參數(shù)傳遞給AddEventMapping方法呢,答案是肯定的,看上面的代碼,發(fā)現(xiàn)有2個(gè)偽造的名稱分別是常量字符串HttpApplication.IMPLICIT_FILTER_MODULE(值為AspNetFilterModule)和HttpApplication.IMPLICIT_HANDLER(值為ManagedPipelineHandler),而因?yàn)橹捌渌麳ttpModule里的各種事件都已經(jīng)load完了,所以這2個(gè)偽造HttpModule的是放在集合的最后面,所以在執(zhí)行ExecuteRequestHandler類別的事件的時(shí)候,最后一個(gè)事件肯定就是這個(gè)偽造HttpModule的事件,再加上偽造HttpModule里沒有別的事件,所以它對應(yīng)的ExecutionStep的執(zhí)行效果其實(shí)和IIS6里CallHandlerExecutionStep的效果是一樣的,就這樣,通過一個(gè)很奇特的技巧達(dá)到同樣的目的。

      最后,我們來總結(jié)一下,在IIS6和IIS7經(jīng)典模式下,是用 Event+事件名稱做key將所有事件的保存在HttpApplication的Events屬性對象里,然后在BuildSteps里統(tǒng)一按照順序組裝,中間加載4個(gè)特殊的ExecutionStep,最后在統(tǒng)一執(zhí)行;在IIS7集成模式下,是通過HttpModule名稱+RequestNotification枚舉值作為key將所有的事件保存在HttpApplication的ModuleContainers屬性對象里,然后也在BuildSteps里通過偽造HttpModule名稱加載那4個(gè)特殊的ExecutionStep,最后按照枚舉類型的順序,遍歷所有的HttpModule按順序來執(zhí)行這些事件。讀者可以自行編寫一個(gè)自定義的HttpModuel來執(zhí)行這些事件看看效果如何。

      最后關(guān)于Pipeline完整的圖如下:

       

       

       

      最后,需要注意的是:HttpApplication不是HttpRuntime所創(chuàng)建,HttpRuntime只是向HttpApplicationFactory提出請求,要求返回一個(gè)HttpApplication對象。 HttpApplicationFactory在接收到請求后,會先檢查是否有已經(jīng)存在并空閑的對象,如果有就取出一個(gè)HttpApplication對象返回給HttpRuntime,如果沒有的話,則要?jiǎng)?chuàng)建一個(gè)HttpApplication對象給HttpRunTime。

       

      參考資料:

      http://msdn.microsoft.com/en-us/library/bb470252.aspx

      http://www.rzrgm.cn/zhaoyang/archive/2011/11/16/2251200.html

      http://www.brainbell.com/tutorials/ASP/The_ASP.NET_Pipeline.html

      http://learn.iis.net/page.aspx/243/aspnet-integration-with-iis/

      同步與推薦

      本文已同步至目錄索引:MVC之前的那點(diǎn)事兒系列

      MVC之前的那點(diǎn)事兒系列文章,包括了原創(chuàng),翻譯,轉(zhuǎn)載等各類型的文章,如果對你有用,請推薦支持一把,給大叔寫作的動力。

       

      主站蜘蛛池模板: 实拍女处破www免费看| 日本深夜福利在线观看| 性一交一乱一伦| 囯产精品久久久久久久久久妞妞| 中文字幕少妇人妻精品| 一区三区在线专区在线| 蜜桃视频一区二区三区四| 99久久久无码国产精品动漫| 国产免费一区二区不卡| 亚洲欧美综合精品成| 国产肥臀视频一区二区三区| 国产自产视频一区二区三区| 国产亚洲av手机在线观看| 激情国产一区二区三区四区| 少妇性bbb搡bbb爽爽爽欧美| 在线高清理伦片a| 国产美女久久久亚洲综合| 激情伊人五月天久久综合| 国产sm重味一区二区三区| av无码小缝喷白浆在线观看| 亚洲一国产一区二区三区| 日区中文字幕一区二区| 成在线人免费| 女同另类激情在线三区| 精品国产熟女一区二区三区| 女人张开腿无遮无挡视频| 越西县| 日韩午夜无码精品试看| 国产精品天干天干综合网| 久久一日本道色综合久久| 国产综合精品一区二区三区| 日韩中文字幕人妻精品| 亚洲暴爽av天天爽日日碰| 精品伊人久久久香线蕉| 久久99精品国产麻豆婷婷| 被c到高潮疯狂喷水国产| 国内不卡的一区二区三区| 国产成人啪精品午夜网站| 久久精品国产亚洲精品2020| 亚洲中文字幕有综合久久| 亚洲精品久荜中文字幕|