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

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

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

      ASP.NET那點不為人知的事(一)

      我們上網(wǎng)時,在瀏覽器地址輸入網(wǎng)址:Http://www.rzrgm.cn,按下回車,一張網(wǎng)頁就呈現(xiàn)在我們眼前。這究竟發(fā)生了什么?對于一名優(yōu)秀的Programmer來說,我想有必要一下熟悉瀏覽器--->服務(wù)器請求的過程。

      ASP.NET

      ASP.NET是運行在公共語言運行時刻時(CLR)上的應(yīng)用程序框架。他用來在服務(wù)器端構(gòu)建功能強(qiáng)大的web應(yīng)用程序。當(dāng)瀏覽器請求 ASP.NET 文件時,IIS 會把該請求傳遞給服務(wù)器上的 ASP.NET 引擎,ASP.NET 引擎會逐行地讀取該文件,并執(zhí)行文件中的腳本,最后,ASP.NET 文件會以純 HTML 的形式返回瀏覽器。

      客戶端瀏覽器和服務(wù)器之間的請求響應(yīng)是通過Socket進(jìn)行通信,基于HTTP協(xié)議,客戶端發(fā)送一次HTTP請求,服務(wù)器接收到請求,處理之后向瀏覽器回應(yīng)響應(yīng)報文。那么什么是HTTP協(xié)議呢?

      HTTP協(xié)議:

      當(dāng)瀏覽器尋找到Web服務(wù)器地址后,瀏覽器將幫助我們把對服務(wù)器的請求轉(zhuǎn)換為一系列參數(shù)(消息)發(fā)給Web服務(wù)器,瀏覽器和Web服務(wù)器的對話中,需要使用雙方都能理解語法規(guī)范進(jìn)行通信,這種程序之間進(jìn)行通信的語法規(guī)定,我們稱之為協(xié)議。瀏覽器與服務(wù)器之間的協(xié)議是應(yīng)用層協(xié)議,當(dāng)前遵循的協(xié)議是HTTP/1.1。HTTP/1.1協(xié)議時Web開發(fā)的基礎(chǔ),這是一個無狀態(tài)協(xié)議,客戶端瀏覽器和服務(wù)器通過Socket通信進(jìn)行請求和響應(yīng)完成一次會話。每次會話中,通信雙方發(fā)送的數(shù)據(jù)稱為消息,分為兩種:請求消息和響應(yīng)消息。

      對于消息而言,一般他有三部分組成,并且消息的頭和消息體之間用一個空行進(jìn)行分隔:

      我們通過瀏覽器插件HttpWatch Professional可以清晰看到瀏覽器和服務(wù)器之間的通信內(nèi)容:

      了解了什么是HTTP協(xié)議之后,我們在回到先前提出的那個問題,瀏覽器的請求怎樣到達(dá)服務(wù)器?

      HTTP.SYS組件

      我們知道要訪問一個網(wǎng)站,必須要其部署在相應(yīng)服務(wù)器軟件上(如IIS),瀏覽器向服務(wù)器發(fā)送請求之后,當(dāng)請求通過Socket到達(dá)服務(wù)器時,首先服務(wù)器Windows內(nèi)核中的HTTP.SYS組件捕獲請求,根據(jù)URL的請求地址將其轉(zhuǎn)發(fā)到應(yīng)用程序池(Application Pool,ASP.NET應(yīng)用程序必須運行在一個應(yīng)用程序池中),再由運行在應(yīng)用程序池里的工作者進(jìn)程(Worker Process,用于裝載專門處理ASP.NET頁面的一個ISAPI擴(kuò)展程序:aspnet_isapi.dll)響應(yīng)請求,當(dāng)請求處理完成時,HTTP.SYS又將結(jié)果發(fā)送出去(HTTP.SYS會在內(nèi)部建立一個緩存區(qū),用于緩存近期的處理結(jié)果)。當(dāng)HTTP.SYS請求分析這是一個需要交給IIS服務(wù)器處理的HTTP請求時,HTTP.SYS組件就會把這次請求交給IISl處理,服務(wù)器軟件(IIS)會判斷用戶請求的是靜態(tài)頁面(Html)還是動態(tài)頁面(Aspx.Ashx),如果請求的是Html靜態(tài)頁面或者js,css,xml以及圖片等,IIS直接返回請求的Html靜態(tài)頁面和js等相應(yīng)文件。那么如果請求的是動態(tài)頁面呢?還是向處理靜態(tài)頁面一樣嗎?顯然是不可能的。IIS服務(wù)器會分析請求的類型,然后從處理程序映射(即下文IIS服務(wù)器擴(kuò)展)表中去匹配,當(dāng)在處理程序映射表中能夠匹配到請求的類型時,那么IIS服務(wù)器就將請求交給處理程序映射表中所對應(yīng)的程序來處理。當(dāng)IIS發(fā)現(xiàn),在處理程序映射表中沒有能匹配的項的時候,就直接返回請求所對應(yīng)物理路徑下的文件,如Html,JS,CSS,JPG,PNG等。

       

      IIS服務(wù)器擴(kuò)展

      由于IIS服務(wù)器在設(shè)計時引入了開放的ISAPI接口標(biāo)準(zhǔn),具備極高的可擴(kuò)展性。在核心組件不變的情況下可靈活支持不同類型不同版本的ASP.NET應(yīng)用程序。

      ISAPI(Internet Server Application Programming Interface)

      ISAPI(服務(wù)器應(yīng)用編程接口),它為開發(fā)人員提供了強(qiáng)大的可編程能力,只要按照標(biāo)準(zhǔn)接口開發(fā)不同類型的Web應(yīng)用程序的ISAPI擴(kuò)展程序,就能實現(xiàn)對IIS功能上的擴(kuò)展,從而使IIS可以處理不同類型的客戶端請求。IIS管理器提供了應(yīng)用程序配置功能,可以對不同的客戶端請求配置不同的ISAPI擴(kuò)展程序ISAPI擴(kuò)展程序通常以DLL形式存在,可以被IIS加載并調(diào)用。有了基于ISAPI的擴(kuò)展擴(kuò)展程序,IIS服務(wù)器就可以根據(jù)客戶端請求的資源擴(kuò)展名,來決定應(yīng)由哪個ISAPI擴(kuò)展程序來處理客戶端請求,然后就可以將請求轉(zhuǎn)發(fā)給合適的ISAPI擴(kuò)展程序。

      IIS7處理程序映射

      ASP.NET的后臺輔助進(jìn)程aspnet_wp.exe

      實際上客戶發(fā)起的請求最終要由aspnet_isapi.dll(被工作者進(jìn)程Worker Process裝載)傳遞給aspnet_wp.exe去處理,.NET平臺下稱其為ASP.NET Process(簡稱為WP),該文件位于.Net Framework安裝目錄下,與aspnet_isapi.dll所在位置相同。當(dāng)aspnet_isapi接收到IIS轉(zhuǎn)發(fā)的ASP.NET請求后,會將請求放入隊列,并根據(jù)實際情況分配請求處理任務(wù)給WP進(jìn)程。一旦請求被轉(zhuǎn)送給WP進(jìn)程,WP進(jìn)程便會通知aspnet_isapi請求正在被處理。這個通知的過程是通過同步I/O完成的,這么實現(xiàn)目的是為了保證處理過程的完整性,因為只有當(dāng)請求在aspnet_isapi內(nèi)部被標(biāo)記為"executing"后,WP才會真正開始處理該請求。此后請求便在WP的上下文環(huán)境中執(zhí)行。當(dāng)執(zhí)行結(jié)束后處理結(jié)果會通過一個異步的開放管道回送給aspnet_isapi,這時請求的狀態(tài)會被更新為“Done”。接著請求就會從隊列中清除。如果WP進(jìn)程崩潰,所有正在處理中的請求都將維持“executing”狀態(tài)一段時間,等到aspnet_isapi檢測到WP進(jìn)程死掉后,會自動丟棄所有的請求并釋放已經(jīng)分配的資源。

      WP會分析每一個請求的信息解析出其中的虛擬目錄信息,并檢查該虛擬目錄對應(yīng)的AppDomain(應(yīng)用程序域)是否已經(jīng)存在,如果不存在,則創(chuàng)建一個新的AppDomain(ApplicationManager創(chuàng)建應(yīng)用程序域),然后使用它。否則直接重用已經(jīng)建立的AppDomain對象。這里的AppDomain指的是.NET中引入的應(yīng)用程序域的概念,程序集管理的最小邏輯單位為應(yīng)用程序域,包括四個重要的機(jī)制,隔離、卸載、安全、配置,它可以理解為一個進(jìn)程或一個邊界或一個容器,它是應(yīng)用程序的執(zhí)行環(huán)境.NET下所有的應(yīng)用程序都運行在AppDomain中,每一個ASP.NET應(yīng)用程序IIS中的站點或者虛擬目錄都會有一個AppDomain與之對應(yīng),它保存了Applcation對象、Cache等全局變量。

      由一張流程圖回顧上述瀏覽器到達(dá)服務(wù)器的過程

       

       

       ISAPIRuntme.ProcessRequest方法第一個進(jìn)入ASP.NET

      當(dāng)aspnet_wp.exe接受到aspnet_isapi.dll的請求后,就將請求轉(zhuǎn)給指定虛擬目錄對應(yīng)的AppDomain中的ISAPIRuntime對象,ISAPIRuntime.ProcessRequest()開始進(jìn)入ASP.NET,并將瀏覽器發(fā)送請求消息封裝成HttpWorkerRequest類(抽象類,開發(fā)環(huán)境中對應(yīng)SimpleWorkRequest)。之后再執(zhí)行HttpRuntime的靜態(tài)方法:ProcessRequestNoDemand(參數(shù)為封裝了瀏覽器請求的信息:HttpWorkerRequest)

       

       補(bǔ)充:默默無聞的工作者對象HttpWorkerRequest

      在Asp.Net中,準(zhǔn)備用于處理的請求,必須封裝為HttpWorkerRequest類型的對象,這是一個抽象類:

       

      [ComVisibleAttribute(false)]
      public abstract class HttpWorkerRequest

       

      客戶的請求首先會被ISAPIRuntme對象ProcessRequest方法處理

      創(chuàng)建了HttpWorkerRequest 類型的wr對象,因為ISAPIWorkerRequest 繼承于HttpWorkerRequest

       

      [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]
      public int ProcessRequest(IntPtr ecb, int iWRType)
      {
          IntPtr zero = IntPtr.Zero;
          if (iWRType == 2)
          {
              zero = ecb;
              ecb = UnsafeNativeMethods.GetEcb(zero);
          }
          ISAPIWorkerRequest wr = null;
          try
          {
              bool useOOP = iWRType == 1;
              wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
              wr.Initialize();
              ......
              if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
              {
                  HttpRuntime.ProcessRequestNoDemand(wr);
                  return 0;
              }
              HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated }));
              return 1;
          }
        ......
      }

      HttpRuntime調(diào)用ProcessRequestNoDemand方法:

       

      internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)
      {
          RequestQueue queue = _theRuntime._requestQueue;
          wr.UpdateInitialCounters();
          if (queue != null)
          {
              wr = queue.GetRequestToExecute(wr);
          }
          if (wr != null)
          {
              CalculateWaitTimeAndUpdatePerfCounter(wr);
              wr.ResetStartTime();
              ProcessRequestNow(wr);
          }
      }
      

      該方法先從請求隊列中取出一個請求,然后更新請求的引用計數(shù)器的信息,然后ProcessRequestNow方法處理請求。

       

       在這兒終于找到了HttpRuntime這個對象了:

      internal static void ProcessRequestNow(HttpWorkerRequest wr)
      {
          _theRuntime.ProcessRequestInternal(wr);
      }
      
       _theRuntime就是HttpRuntime類型的對象,他在HttpRuntime的靜態(tài)構(gòu)造函數(shù)初始化。
      static HttpRuntime()
      {
         ......
          _theRuntime = new HttpRuntime();
          _theRuntime.Init();
          AddAppDomainTraceMessage("HttpRuntime::cctor*");
      }
      

      點擊進(jìn)入ProcessRequsetNow(Wr)方法,Wr即封裝了HTTP Message的HttpWorkRequest對象

      在HttpRuntime接受到請求后,立刻通過HttpWorkerRequest傳遞的參數(shù)進(jìn)行分析和分解,創(chuàng)建方便用戶網(wǎng)站應(yīng)用程序處理用的對象。HttpRequest,HttpResponse

      終于發(fā)現(xiàn)了HttpContext,根據(jù)HttpWorkerRequest初始化HttpContext

      private void ProcessRequestInternal(HttpWorkerRequest wr)
      {
          ......
          else
          {
              HttpContext context;
              try
              {
                  context = new HttpContext(wr, false);
              }
              catch
              {
                  try
                  {
                      wr.SendStatus(400, "Bad Request");
                      wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
                      byte[] data = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
                      wr.SendResponseFromMemory(data, data.Length);
                      wr.FlushResponse(true);
                      wr.EndOfRequest();
                      return;
                  }
                  finally
                  {
                      Interlocked.Decrement(ref this._activeRequestCount);
                  }
              }
              wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context);
              HostingEnvironment.IncrementBusyCount();
              try
              {
                  try
                  {
                      this.EnsureFirstRequestInit(context);
                  }
                  catch
                  {
                      if (!context.Request.IsDebuggingRequest)
                      {
                          throw;
                      }
                  }
         ......
          }
      }
      

       

      在進(jìn)入看看:根據(jù)WR,初始化了請求參數(shù)的類型HttpRequest對象和處理回應(yīng)類型HttpReponse對象

      internal HttpContext(HttpWorkerRequest wr, bool initResponseWriter)
      {
          this._timeoutStartTimeUtcTicks = -1;
          this._timeoutTicks = -1;
          this._threadAbortOnTimeout = true;
          this.ThreadContextId = new object();
          this._wr = wr;
          this.Init(new HttpRequest(wr, this), new HttpResponse(wr, this));
          if (initResponseWriter)
          {
              this._response.InitResponseWriter();
          }
          PerfCounters.IncrementCounter(AppPerfCounter.REQUESTS_EXECUTING);
      }
      

      privatevoid ProcessRequestInternal(HttpWorkerRequest wr) ProcessRequestInternal這個方法很重要,前面分析了它創(chuàng)建了上下文對象HttpContext,接下來分析HttpApplication的創(chuàng)建。

      {
                  .....
                  IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
                  ......
      try
      {
      this.EnsureFirstRequestInit(context);
      }
      ......
      context.Response.InitResponseWriter();
      ......if (applicationInstance is IHttpAsyncHandler) { IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance; context.AsyncAppHandler = handler2; handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context); } ...... } } }
      • EnsureFirstRequestInit()方法完成第一次請求初始化工作,該方法鎖定全局變量_beforeRequestFirst,然后調(diào)用FirstRequestInit(context)完成配置文件的加載,初始化請求隊列,裝載Bin目錄下所有程序集工作,然后更新_beforeRequestFirst=false;context.FirstRequest=true;
      private void EnsureFirstRequestInit(HttpContext context)
      {
          if (this._beforeFirstRequest)
          {
              lock (this)
              {
                  if (this._beforeFirstRequest)
                  {
                      this._firstRequestStartTime = DateTime.UtcNow;
                      this.FirstRequestInit(context);
                      this._beforeFirstRequest = false;
                      context.FirstRequest = true;
                  }
              }
          }
      }
       
      • 執(zhí)行InitResponseWrite創(chuàng)建HttpWrite對象,用于寫入結(jié)果返回信息。
      • 創(chuàng)建HttpApplication實例,HttpApplicationFactory.GetApplicationInstance(注意其實不是這個方法直接創(chuàng)建,而是通過這個方法里面又調(diào)用了GetNormalApplicationInstance方法來創(chuàng)建默認(rèn)的HttpApplication實例
      • 那什么是HttpApplicationFactotry?
      • HttpApplicationFactotry用于負(fù)責(zé)管理一個HttpApplication的對象池。

      看一下HttpApplication這個類的申明:

      [ToolboxItem(false)]
      public class HttpApplication : IComponent, IDisposable, IHttpAsyncHandler, IHttpHandler, IRequestCompletedNotifier, ISyncContext
      {

      }


      調(diào)用HttpApplicationFactory對象的GetNormalApplicationInstance得到一個HttpApplication實例:

       

      internal static IHttpHandler GetApplicationInstance(HttpContext context)
      {
          ......return _theApplicationFactory.GetNormalApplicationInstance(context);
      }

      GetApplicationInstance方法生成一個默認(rèn)的HttpApplication對象,HttpApplication實現(xiàn)了IHttpAsyncHandler接口。

      調(diào)用HttpApplication對象(實現(xiàn)了IHttpAsyncHandler接口)的BeginProcessRequest方法執(zhí)行客戶請求。

       if (applicationInstance is IHttpAsyncHandler)
      {
      IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
      context.AsyncAppHandler = handler2;
      handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);
      }

      OK,回到前一步,再深入一步,進(jìn)入GetNormalApplicationInstance方法之后,我們看到了HttpApplication對象是如何被創(chuàng)建和初始化:

       

      private HttpApplication GetNormalApplicationInstance(HttpContext context)
      {
          HttpApplication state = null;
        ......
          if (state == null)
          {
              state = (HttpApplication) HttpRuntime.CreateNonPublicInstance(this._theApplicationType);
              using (new ApplicationImpersonationContext())
              {
                  state.InitInternal(context, this._state, this._eventHandlerMethods);
              }
          }
       ......
      }

       

      internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)我們發(fā)現(xiàn)HttpApplication類提供了一個名為InitInternal的方法,調(diào)用它來完成HttpApplication實例的初始化工作,點擊進(jìn)入InitInternal方法內(nèi)部:

       

      internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
      {
      
          this._state = state;
          PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
      
      ......
                      this.InitModules();
                  Label_006B:
                      if (handlers != null)
                      {
                          this.HookupEventHandlersForApplicationAndModules(handlers);
                      }
                   ......
                .....
                  if (HttpRuntime.UseIntegratedPipeline)
                  {
                      this._stepManager = new PipelineStepManager(this);
                  }
                  else
                  {
                      this._stepManager = new ApplicationStepManager(this);
                  }
                  this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
              }
       ......
      }

      首先初始化Modules(InitModules

       

      private void InitModules()
      {
          HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
          HttpModuleCollection other = this.CreateDynamicModules();
          modules.AppendCollection(other);
          this._moduleCollection = modules;
          this.InitModulesCommon();
      }

      接下來完成事件的綁定(19個管道事件):BuildSteps: 

       

                if (HttpRuntime.UseIntegratedPipeline)
                  {
                      this._stepManager = new PipelineStepManager(this);
                  }
                  else
                  {
                      this._stepManager = new ApplicationStepManager(this);
                  }
                  this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
              }
       ......

       BuildSteps完成HttpApplication19個管道事件的注冊:

      internal override void BuildSteps(WaitCallback stepCallback)
      {
          ArrayList steps = new ArrayList();
          HttpApplication app = base._application;
          bool flag = false;
          UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;
          flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);
          steps.Add(new HttpApplication.ValidateRequestExecutionStep(app));
          steps.Add(new HttpApplication.ValidatePathExecutionStep(app));
          if (flag)
          {
              steps.Add(new HttpApplication.UrlMappingsExecutionStep(app));
          }
          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 HttpApplication.MapHandlerExecutionStep(app));//---------------------->
          app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
          app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
          steps.Add(app.CreateImplicitAsyncPreloadExecutionStep());
          steps.Add(newHttpApplication.CallHandlerExecutionStep(app));//---------------------->用于創(chuàng)建處理用戶請求的對象(Handler)
      private void CreateEventExecutionSteps(object eventIndex, ArrayList steps)
      {
          AsyncAppEventHandler handler = this.AsyncEvents[eventIndex];
          if (handler != null)
          {
              handler.CreateExecutionSteps(this, steps);
          }
          EventHandler handler2 = (EventHandler) this.Events[eventIndex];
          if (handler2 != null)
          {
              Delegate[] invocationList = handler2.GetInvocationList();
              for (int i = 0; i < invocationList.Length; i++)
              {
                  steps.Add(new SyncEventExecutionStep(this, (EventHandler) invocationList[i]));
              }
          }
      }
      
      
      

      HttpApplication對象初始化時,首先會調(diào)用InitModules方法來加載在web.config文件中配置的所有HttpModule模塊。

      接著HookupEventHandlersForApplicationAndModules方法被調(diào)用,這個方法完成global.asax文件中配置的HttpModuleHttpApplication事件的綁定

      最后ApplicationStopManager對象的BuildSteps方法被調(diào)用,完成HttpApplication19個管道事件的注冊。這個方法很重要,它將創(chuàng)建各種HttpApplication.IExecutionStep保存到一個數(shù)組列表:

       

      internal override void BuildSteps(WaitCallback stepCallback)
      {
      .....
      this._execSteps = new HttpApplication.IExecutionStep[steps.Count];
      steps.CopyTo(this._execSteps);
      .....
      }

      以便在BeginProcessRequest方法內(nèi)部調(diào)用ResumeSteps方法依次執(zhí)行這些對象的Execute()方法,完成各種處置。 

       

       調(diào)用BeginProcessRequest方法來實現(xiàn)IHttpAsyncHandler接口中定義的方法處理請求:

      IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
      {
          this._context = context;
          this._context.ApplicationInstance = this;
          this._stepManager.InitRequest();
          this._context.Root();
          HttpAsyncResult result = new HttpAsyncResult(cb, extraData);
          this.AsyncResult = result;
          if (this._context.TraceIsEnabled)
          {
              HttpRuntime.Profile.StartRequest(this._context);
          }
          this.ResumeSteps(null);//---------->依次執(zhí)行管道事件
          return result;
      }
      

       

      BeginProcessRequest執(zhí)行過程

      • 在取得HttpApplication對象實例之后HttpRuntime對象開始調(diào)用其的BeginProcessRequest方法來實現(xiàn)IHttpAsyncHandler接口中定義的方法處理請求:
      • 該方法首先調(diào)用ApplicationStepManager對象的InitRequest方法完成一些初始化工作例如將記錄當(dāng)前執(zhí)行步驟的變量清0、置請求處理完成標(biāo)志為false等。
      • 然后根據(jù)上下文創(chuàng)建HttpAsyncResult對象記錄執(zhí)行結(jié)果最后ResumeSteps方法被調(diào)用這個方法會依次取出在數(shù)組列表中的HttpApplication.IExecutionStep對象傳遞給HttpApplication的ExecuteStep方法由它調(diào)用執(zhí)行IExecutionStep對象的Execute方法。
      • 當(dāng)執(zhí)行到MapHandlerExecutionStep時會執(zhí)行如下代碼獲取最終執(zhí)行請求:context.Handler = this._application.MapHttpHandler()。HttpApplication對象的MapHttpHandler方法將根據(jù)配置文件結(jié)合請求類型和URL以調(diào)用相應(yīng)的IHttpHandlerFactory來獲取HttpHandler對象。例如與.aspx頁面對應(yīng)的Page類就是一種HttpHandler。此后請求處理的執(zhí)行權(quán)被轉(zhuǎn)交至對應(yīng)的HttpHandler對象上。下面代碼演示了過程:
          void HttpApplication.IExecutionStep.Execute()
          {
              HttpContext context = this._application.Context;
              HttpRequest request = context.Request;
              if (EtwTrace.IsTraceEnabled(5, 1))
              {
                  EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_ENTER, context.WorkerRequest);
              }
              context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false);
              if (EtwTrace.IsTraceEnabled(5, 1))
              {
                  EtwTrace.Trace(EtwTraceType.ETW_TYPE_MAPHANDLER_LEAVE, context.WorkerRequest);
              }
          }

       這兒調(diào)用了一個很重要的方法MapHttpHandler:

       context.Handler = this._application.MapHttpHandler(context, request.RequestType, request.FilePathObject, request.PhysicalPathInternal, false);
      internal IHttpHandler MapHttpHandler(HttpContext context, string requestType, VirtualPath path, string pathTranslated, bool useAppConfig)
      {
          IHttpHandler handler = (context.ServerExecuteDepth == 0) ? context.RemapHandlerInstance : null;
         ...
              IHttpHandlerFactory factory = this.GetFactory(mapping);
              try
              {
                  IHttpHandlerFactory2 factory2 = factory as IHttpHandlerFactory2;
                  if (factory2 != null)
                  {
                      handler = factory2.GetHandler(context, requestType, path, pathTranslated);
                  }
                  else
                  {
                      handler = factory.GetHandler(context, requestType, path.VirtualPathString, pathTranslated);
                  }
              }
           ...
              ....
          }
          return handler;
      }

      通過實現(xiàn)了IHttpHandlerFactory(PageHandlerFactory 或者 SimpleHandlerFactory等)創(chuàng)建了HttpHandler

       因為steps.Add(new HttpApplication.MapHandlerExecutionStep(app))注冊了Handler,所以會在第八個事件里通過反射創(chuàng)建了頁面請求的對象(實現(xiàn)了IHttpHandler接口)。
      void HttpApplication.IExecutionStep.Execute()
      {
          HttpContext context = this._application.Context;
          IHttpHandler handler = context.Handler;
        .....
        ...
              IHttpAsyncHandler handler2 = (IHttpAsyncHandler) handler;
              this._sync = false;
              this._handler = handler2;
       ....
      }
      
      然后再第11個和12個事件之間,會調(diào)用了第八個事件創(chuàng)建的頁面對象的ProcessRequest方法,具體內(nèi)容詳看我下一篇文章:《ASP.NET那點不為人知的事(二)》

        
      補(bǔ)充:BuildSteps方法里注冊的HttpApplication管道的19個事件:

      19個事件的處理過程:

      • 在Asp.Net中,Asp.Net服務(wù)器對于每一次請求的處理過程是相同的,都要經(jīng)過HttpApplication處理管道,管道內(nèi)部的處理過程是固定的,在服務(wù)器處理請求的各個階段,伴隨著處理的進(jìn)行,一次觸發(fā)對應(yīng)的事件,以便程序員在處理的各個階段完成自定義的處理工作。

      • 首先觸發(fā)的事件是BeginRequest,這個事件標(biāo)志著ASP.NET服務(wù)器處理工作的開始,也是程序員在ASP.NET中針對請求能夠處理的第一個事件。

      • 開始處理請求后,第一個重要的工作就是確定請求用戶的身份以及實現(xiàn)安全機(jī)制。這個工作通過AuthenticateRequest和PostAuthenticateRequest兩個事件提供檢查當(dāng)前請求用戶身份的機(jī)會。PostAuthenticateRequest則表示用戶身份已經(jīng)檢查完成,檢查后的用戶可以通過HttpContextUser屬性獲取列。

      public IPrincipal User
      {
          get
          {
              return this._principalContainer.Principal;
          }
          [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries"), SecurityPermission(SecurityAction.Demand, ControlPrincipal=true)]
          set
          {
              this.SetPrincipalNoDemand(value);
          }
      }
       

       Iprincipal又有一個名為Identity,類型了System.Security.Principal.IIdentity屬性

      [ComVisible(true), __DynamicallyInvokable]
      public interface IPrincipal
      {
          // Methods
          [__DynamicallyInvokable]
          bool IsInRole(string role);
      
          // Properties
          [__DynamicallyInvokable]
          IIdentity Identity { [__DynamicallyInvokable] get; }
      }

       

      [ComVisible(true), __DynamicallyInvokable]
      public interface IIdentity
      {
          // Properties
          [__DynamicallyInvokable]
          string AuthenticationType { [__DynamicallyInvokable] get; }
          [__DynamicallyInvokable]
          bool IsAuthenticated { [__DynamicallyInvokable] get; }
          [__DynamicallyInvokable]
          string Name { [__DynamicallyInvokable] get; }
      }
      
      IsAuthenticated表示當(dāng)前請求用戶是否已經(jīng)被驗證,IsAuthenticated =false,那么表示這是一個匿名用戶,如果為True,那么通過IIdentity類型為string的Name屬性,
      這就表示當(dāng)前請求的用戶名。
      • 當(dāng)ASP.NET獲取用戶身份后,根據(jù)當(dāng)前請求的用戶身份,開始請求權(quán)限的檢查工作。當(dāng)?shù)谒膫€事件AuthorizeRequest觸發(fā)的時候開始進(jìn)行用戶的權(quán)限檢查,而第五個事件PostAuthorizeRequest則標(biāo)志已經(jīng)完成用戶權(quán)限檢查工作。如果用戶沒有通過安檢,一般情況下將跳過剩余事件,直接觸發(fā)EndRequest事件結(jié)束處理請求過程。

       

      • 當(dāng)用戶獲取了請求權(quán)限,那么服務(wù)器開始準(zhǔn)備用最快的方式來使用戶得到回應(yīng)結(jié)果。ResolveRequestCache事件標(biāo)志著到從前緩存的結(jié)果進(jìn)行檢查,看看是否可以直接從以前的緩存結(jié)果中直接獲取處理結(jié)果,PostResolveRequestCache表示緩存檢查結(jié)束。

       

      • 當(dāng)不能從緩存中獲取結(jié)果時,必須通過一次處理來計算出當(dāng)前請求的結(jié)果。在ASP.NET中,用戶處理請求以得到結(jié)果的對象稱為處理程序Handler。為了處理這個這個請求,ASP.NET必須按照匹配規(guī)則找到一個處理當(dāng)前請求的處理程序,PostMapRequestHandler事件表示當(dāng)前ASP.NET已經(jīng)獲取了這個處理程序,HttpContextHandler屬性就表示這個處理程序?qū)ο蟆?/strong>

       

      • 得到了處理程序之后,還不能馬上開始進(jìn)行處理,這是由于處理請求還需要與這個請求有關(guān)的數(shù)據(jù),比如說這個用戶上一次向服務(wù)器發(fā)送請求的時候,在服務(wù)器上報錯了一些這個用戶特有的數(shù)據(jù)。由于HTTP協(xié)議的無狀態(tài)性,狀態(tài)管理問題是個核心問題,所以ASP時代就引入Session,提供基于會話狀態(tài)的管理。為了獲取這個用戶在以前保存的數(shù)據(jù),通過AcquireRequestState事件取得請求狀態(tài),PostAcquireRequest事件則表示已經(jīng)完成了用戶數(shù)據(jù)的獲取工作,可以再處理中使用了。

      • PreRequestHandlerExcute事件用來通知程序員,處理程序就要開始進(jìn)行處理工作了,如果用戶的狀態(tài)已經(jīng)獲取之后,還有需要的處理程序之進(jìn)行的工作,那么就在這個事件中處理吧。在PreRequestHandlerExcute事件之后,ASP.NET服務(wù)器將通過執(zhí)行處理程序完成請求處理工作。這個處理程序有可能是一個WebForm,也可能是Web服務(wù)。這個工作是在第11個事件和第12個事件之間完成的。

       

      • 處理程序之后,服務(wù)器開始進(jìn)行掃尾工作,PostRequestHandlerExcute事件通知程序員,ASP.NET服務(wù)器處理程序已經(jīng)完成。

      • 在處理完成之后,由于處理程中,用戶可能修改了用于特定的專屬數(shù)據(jù),那么修改之后的用戶狀態(tài)數(shù)據(jù)需要進(jìn)行序列化或者進(jìn)行保存處理。ReleaseRequestState事件通知程序員需要釋放這些狀態(tài)數(shù)據(jù),PostReleaseRequestState則表示已經(jīng)釋放完成。

       

      • 在處理完成之后,如果需要將這次處理結(jié)果緩存起來,以便于后繼的請求可以直接使用這個結(jié)果,UpdateRequestCache事件提供了處理的機(jī)會,PostUpdateRequestCache則表示緩存已經(jīng)更新完畢。

      • 在ASP.NET4.0中,新增加了兩個事件完成處理的日志工作:LogRequest表示將這次請求加入日志,PostLogRequest表示完成了日志工作。

      • 在前面的事件中,請求并不一定要經(jīng)過所有的事件,比如說,用戶沒用經(jīng)過授權(quán)的檢查,那么將跳過后面的事件,但是,EndRequest事件是所有請求都要經(jīng)過的最后一個HttpApplication處理管道的事件,也是程序員處理的ASP.NET處理請求中的最后一個機(jī)會。這個事件之后,處理的結(jié)果將被回應(yīng)到瀏覽器,完成ASP.NET服務(wù)器的處理工作。

       小結(jié)

       未完,待續(xù)。

       

      posted @ 2012-08-13 04:05  木宛哥說編程  閱讀(23698)  評論(112)    收藏  舉報
      multifunction lasers
      訪問人數(shù)

      主站蜘蛛池模板: 亚洲欧洲一区二区精品| 成人拍拍拍无遮挡免费视频| 国产色无码专区在线观看| ww污污污网站在线看com | 中文字幕成熟丰满人妻| 久久精品第九区免费观看| 武冈市| 人妻中文字幕不卡精品| 国产精品福利中文字幕| 四虎永久在线精品无码视频| 69天堂人成无码免费视频| 91亚洲国产成人精品性色| 国产精品午夜福利免费看| 久久久久久人妻一区精品| 国偷自产一区二区三区在线视频 | 欧美成人精品手机在线| 在线观看潮喷失禁大喷水无码| 四虎成人精品无码| 午夜成人精品福利网站在线观看| 国产一区二区精品久久岳| 免费大片av手机看片高清| 一亚洲一区二区中文字幕| 中文字幕少妇人妻精品| 松阳县| 90后极品粉嫩小泬20p | 国偷自产av一区二区三区| 26uuu另类亚洲欧美日本| 久章草在线毛片视频播放| 亚洲一区二区精品动漫| 69天堂人成无码免费视频| 江达县| 精品久久人人妻人人做精品| 公天天吃我奶躁我的在| 视频一区视频二区制服丝袜| 亚洲精品在线视频自拍| 国产亚洲精品成人aa片新蒲金 | a级亚洲片精品久久久久久久| 五月婷婷深开心五月天| 日韩人妻一区中文字幕| 蜜臀av在线一区二区三区| 亚洲丶国产丶欧美一区二区三区|