程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> .NET實例教程 >> ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline

ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline

編輯:.NET實例教程
導讀:
  相信大家都使用過ASP.NET進行過基於Web的應用開發,ASP.NET是什麼?如果站在一個相對High Level的角度,我們可以這樣來定義ASP.Net:ASP.Net是一個基於Web的開發平台,提供構建企業級應用所需的ServiceProgramming ModelSoftwareInfrastructure。如果我們以一個Low Level的角度來看,它本質上就是一個消息處理器:他接受IIS(確切地說應該是ASP.NET ISAPI)Forward的Http Request (我們可以看成是一個Request Message),經過一系列的處理,最終產生一個用戶希望的Response(這也是一個Message,對於.ASPx Page來說是一個Html document,對於一個Web Service來說是一個Soap)。所以本篇文章的主要目的在於站在一個相對Low Level的角度介紹ASP.NET的整個Http Request Processing Model。我們訪問一個基於ASP.Net的資源,IIS是第一道屏障,在第一個部分我分別就IIS 5.x和IIS 6的差異介紹了IIS對Http Request的處理,今天我們來繼續後面的故事。
  一、從Unmanaged Environment到Managed Environment
  上一部分我們說到IIS收到一個基於ASP.NET資源文件的訪問,它會把Http Request交給一個ASP.NET ISAPI Extension處理。ASP.NET ISAPI 會加載CLR,從而創建一個托管的環境。ASP.NET ISAPI Extension定義在一個名為aspnet_isapi.dll中,aspnet_isapi.dll是一個純Native的、高效的Dll,也就是說,雖然ASP.NET ISAPI通過加載CLR創建一個托管的環境,但是ASP.NET ISAPI本省卻運行在一個Unmanaged的環境中。而我們的ASP.NET Application確是完全的Managed code,運行在一個Managed的環境中。要了解ASP.Net Http Runtime Pipeline這個純托管的Runtime,我們必須先了解從Unmanaged Environment到Managed Environment的這道橋梁。
  
  
  上圖簡單表述了在IIS 6環境下,從非托管環境到托管環境的過程。從圖中我們可以看到,ASP.NET ISAPI運行在一個非托管環境之中。ASP.Net ISAPI經過系列COM級別的class調用(由於這些被調用的Class都是一個個undocumented class,所以要真正說清楚調用流程中每個具體的細節是一件很難的事情,而且也確實沒有很大的必要去挖掘它,因為具體的實現可能會經常變動,如果對此具有好奇心的朋友可以通過一些Tool,比如Reflector去仔細研究一下),最終的調用降臨到一個托管的、繼承自System.Web.Hosting.ISAPIRuntime類的對象上。ISAPIRuntime 是一個特殊的class,他實現了Interface System.Web.Hosting.IISAPIRuntime。下面是該Interface的定義。通過定義我們可以看到,這是一個基於COM的Interface,也就是說Caller可以通過COM的方式調用實現該Interface的Class的對象。在這裡,這個最初的Caller就是ASP.NET ISAPI。從這裡我們可以總結出:ASP.Net ISAPI通過調用System.Web.Hosting.ISAPIRuntimeInstance的ProcessRequest方法,進而從非托管的環境進入了托管的環境。
  
  
  [ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1")]
  
  public interface IISAPIRuntime
  
  
  
  
  
  {
  
  
  void StartProcessing();
  
  
  void StopProcessing();
  
  
  [return: MarshalAs(UnmanagedType.I4)]
  
  
  int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
  
  
  void DoGCCollect();
  
  
  }
  
  
  ISAPI ECB (Execution Control Block) &ISAPIWorkerRequest通過System.Web.Hosting.IISAPIRuntime Interface中的ProcessRequest方法的Siganature,我們可以看出該方法包含兩個參數,其中一個是名為ecb的Unmanaged Pointer,另一個是useProcessModel。ECB全稱是Execution Control Block,在整個Http Request Processing過程中起著非常重要的作用,我們現在來簡單介紹一個ECB。
  ISAPI顧名思義,就是實現了一些基於Internet Server的API。Aspnet_isapi.dll實現了這些API,對於IIS來說,它可以調用這些API進入托管的環境實現對ISAPIRuntime的調用,對於ISAPIRuntime來說,它需要調用ASP.NET ISAPI實現一些必要的功能,比如獲得Server Variable的數據,獲得通過Post Mehod傳回Server的數據;以及最終將Response的內容返回給ASP.NET ISAPI,並通過ASP.NET ISAPI返回到ClIEnt。一般地ISAPIRuntime不能直接調用ASP.Net ISAPI,而是通過一個對象指針實現對其的調用,這個對象就是ECB,ECB實現了對ISAPI的訪問。
  還有一點特別需要強調的是,ISAPIISAPIRutime的調用是異步的,也就是說ISAPI調用ISAPIRutime之後立即返回。這主要是出於Performance和Responsibility考慮的,因為ASP.NET Application天生就是一個多線程的應用,為了具有更好的響應能力,異步操作是最有效的解決方式。但是這裡就會有一個問題,我們知道我們對ASP.Net 資源的調用本質上是一個Request/Response的Message Exchange Pattern,異步調用往往意味著ISAPI將Request傳遞給ISAPIRuntime,將不能得到ISAPIRuntime最終生成的Response,這顯然是不能接受的。而ECB解決了這個問題,ISAPI在調用ISAPIRutime的ProcessRequest方法時會將自己對應的ECB的指針傳給它,ISAPIRutime不但可以將最終生成的Response返回給ISAPI,還能通過ECB調用ISAPI獲得一些所需的數據。
  明白ECB是怎麼回事之後,我們通過Reflector簡單了解一下ISAPIRutime的ProcessRequest的實現:
  
  
  
  
  ProcessRequest
  
  public int ProcessRequest(IntPtr ecb, int iWRType)
  
  
  

  {
  
  
  IntPtr zero = IntPtr.Zero;
  
  
  if (iWRType == 2)
  
  
  
  
  
  
  {
  
  
  zero = ecb;
  
  
  ecb = UnsafeNativeMethods.GetEcb(zero);
  
  
  }
  
  null
  
  try
  
  
  
  
  
  {
  
  
  bool uSEOOP = iWRType == 1
  
  wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, uSEOOP);
  
  
  wr.Initialize();
  
  
  string appPathTranslated = wr.GetAppPathTranslated();
  
  
  string appDomainAppPathInternal =
  
  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
  
  }
  
  catch (Exception exception)
  
  
  
  
  
  
  {
  
  
  try
  
  
  
  
  
  {
  
  
  WebBaseEvent.RaiseRuntimeError(exception, this);
   
  }
  
  
  
  
  
  
  
  {
  
  
  }
  
  if ((wr == null) || (wr.Ecb != IntPtr.Zero))
  
  
  
  
  
  
  {
  
  
  throw
  
  }
  
  if (zero != IntPtr.Zero)
  
  
  
  
  
  
  {
  
  
  UnsafeNativeMethods.SetDoneWithSessionCalled(zero);
  
  
  }
  
  if ThreadAbortException)
  
  
  
  
  
  
  {
  
  
  Thread.ResetAbort();
  
  
  }
  
  return 0
  
  
  
  
  對於上面的代碼,我覺得沒有必要去深究,但是對於那些具有強烈好奇心的朋友除外J。基本上上面的代碼完成下面兩個任務:
  通過傳入的ECB和iWRType創建一個叫做ISAPIWorkerRequest的對象:
  
  
  bool uSEOOP = iWRType == 1
  
  wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, uSEOOP);
  
  
  然後調用HttpRuntime.ProcessRequestNoDemand(wr)通過將創建的ISAPIWorkerRequest的對象作為參數傳入。
  HttpRuntime.ProcessRequestNoDemand的調用真正進入了ASP.Net Runtime Pipeline,這是一個相對復雜的過程。在這裡我想簡單說說ISAPIWorkerRequest這個重要class,ISAPIWorkerRequest是一個Abstract class,它已通過ECB創建基於當前Request的Context的信息,針對不同的IIS版本,具有不同的ISAPIWorkerRequest subclass,比如:ISAPIWorkerRequestOutOfProcIIS 5.x, ISAPIWorkerRequestInProcForIIS6, ISAPIWorkerRequestInProcForIIS7。ProcessRequest通過ISAPI傳入的iWRType來創建不同HttpWorkerRequest,從而屏蔽了不同IIS的差異,後續的步驟就不需要考慮這種差異了,這是Abstract Factory的典型用法。
  通過 ASP.Net Http Runtime Pipeline - Part II進入第二部分。
  Reference:A low-level Look at the ASP.Net Architecture
  ASP.Net Process Model
  [原創]ASP.NET Process Model之一:IIS 和 ASP.Net ISAPI
  [原創]ASP.NET Process Model之二:ASP.Net Http Runtime Pipeline - Part I
  [原創]ASP.NET Process Model之二:ASP.Net Http Runtime Pipeline - Part II
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved