[翻譯]瞭解ASP.NET底層架構(六)

導讀:
  HttpRuntime,HttpContextHttpApplication
  當一個請求到來時,它被路由到ISAPIRuntime.ProcessRequest()方法.這個方法調用HttpRuntime.ProcessRequest方法,它作一些重要的事情(用Reflector查看System.Web.HttpRuntime.ProcessRequestInternal方法):
  
  爲請求創建一個新的HttpContext實例
  獲取一個HttpApplication實例
  調用HttpApplication.Init()方法來設置管道的事件
  Init()方法觸發開始ASP.NET管道處理的HttpApplication.ResumeProcessing()方法
  
  首先一個新的HttpContext對象被創建並用來傳遞ISAPIWorkerRequest(ISAPI ECB的包裝器).這個上下文在整個請求的生命週期總都是可用的並總可以通過靜態屬性HttpContext.Currect來訪問.正像名字所暗示的那樣,HttpContext對象代表了當前活動請求的上下文因爲他包含了在請求生命週期中所有典型的你需要訪問的重要對象:Request,Response,Application,Server,Cache.在請求處理的任何時候HttpContext.Current給你訪問所有這些的能力.
  
  HttpContext對象也包含一個非常有用的Items集合,你可以用它來保存針對特定請求的數據.上下文對象在請求週期的開始時被創建,在請求結束時被釋放,所有在Items集合中保存的數據只在這個特定的請求中可用.一個很好的使用的例子是請求日誌機制,當你通過想通過在Global.asax中掛接Application_BeginRequest和Application_EndRequest方法記錄請求的開始和結束時間(象在列表3中顯示的那樣).HttpContext對你就非常有用了-如果你在請求或頁面處理的不同部分需要數據,你自由的使用它.
  
  列表3-使用HttpContext.Items集合使你在不同的管道事件中保存數據
  protectedvoidApplication_BeginRequest(Object sender, EventArgs e)
  {
  //*** Request Logging
  if(App.Configuration.LogWebRequests)
  Context.Items.Add("WebLog_StartTime",DateTime.Now);
  }
  
  protectedvoidApplication_EndRequest(Object sender, EventArgs e)
  {
  // *** Request Logging
  if(App.Configuration.LogWebRequests)
  {
  try
  {
  TimeSpan Span = DateTime.Now.Subtract(
  (DateTime) Context.Items["WebLog_StartTime"]);
  intMiliSecs = Span.TotalMilliseconds;
  
  // do your logging
  WebRequestLog.Log(App.Configuration.ConnectionString,
  true,MilliSecs);
  }
  }
  
  一旦上下文被設置好,ASP.NET需要通過HttpApplication對象將收到的請求路由到適合的應用程序/虛擬目錄.每個ASP.NET應用程序必須被設置到一個虛擬目錄(或者Web根目錄)而且每個”應用程序”是被單獨的處理的.
  
  HttpApplication類似儀式的主人-它是處理動作開始的地方
  
  域的主人:HttpApplication
  每個請求都被路由到一個HttpApplication對象上.HttpApplicationFactory類根據應用程序的負載爲你的ASP.NET應用創建一個HttpApplication對象池併爲每個請求分發HttpApplication對象的引用.對象池的大小受machine.config文件中ProcessModel鍵中的MaxWorkerThreads設置限制,默認是20個(譯註:此處可能有誤,根據Reflector反編譯的代碼,池的大小應該是100個,如果池大小小於100,HttpApplicationFactory會創建滿100個,但是考慮到會有多個線程同時創建HttpApplication的情況,實際情況下有可能會超過100個).
  
  對象池以一個更小的數字開始通常是一個然後增長到和同時發生的需要被處理的請求數量一樣.對象池被監視,這樣在大負載下它可能會增加到最大的實例數量,當負載降低時會變回一個更小的數字.
  
  HttpApplication是你的Web程序的外部包裝器,而且它被映射到在Global.asax裏面定義的類上.它是進入HttpRuntime的第一個入口點.如果你查看Global.asax(或者對應的代碼類)你會發現這個類直接繼承自HttpApplication:
  publicclassGlobal : System.Web.HttpApplication
  HttpApplication的主要職責是作爲Http管道的事件控制器,所以它的接口主要包含的是事件.事件掛接是非常廣泛的,包括以下這些:
  l BeginRequest
  l AuthenticateRequest
  l AuthorizeRequest
  l ResolveRequestCache
  l AquireRequestState
  l PreRequestHandlerExecute
  l …Handler Execution…
  l PostRequestHandlerExecute
  l ReleaseRequestState
  l UpdateRequestCache
  l EndRequest
  
  每個事件在Global.assx文件中以Application_前綴開頭的空事件作爲實現.例如,Application_BeginRequest(), Application_AuthorizeRequest()..這些處理器爲了便於使用而提供因爲它們是在程序中經常被使用的,這樣你就不用顯式的創建這些事件處理委託了.
  
  理解每個ASP.NET虛擬目錄在它自己的應用程序域中運行,而且在應用程序域中有多個從ASP.NET管理的池中返回的HttpApplication實例同時運行,是非常重要的.這是多個請求可以被同時處理而不互相妨礙的原因.
  
  查看列表4來獲得應用程序域,線程和HttpApplication之間的關係.
  列表4-顯示應用程序域,線程和HttpApplication實例之間的關係
  privatevoidPage_Load(objectsender, System.EventArgs e)
  {
  // Put user code to initialize the page here
  this.ApplicationId =((HowAspNetWorks.Global)
  HttpContext.Current.ApplicationInstance).ApplicationId;
  this.ThreadId = AppDomain.GetCurrentThreadId();
  
  this.DomainId = AppDomain.CurrentDomain.FriendlyName;
  
  this.ThreadInfo = "ThreadPool Thread: "+
  System.Threading.Thread.CurrentThread.IsThreadPoolThread.ToString() +
  "<br>Thread Apartment: "+
  System.Threading.Thread.CurrentThread.ApartmentState.ToString();
  
  // *** Simulate a slow request so we can see multiple
  // requests side by side.
  System.Threading.Thread.Sleep(3000);
  }
  
  這是隨sample提供的demo的一部分,運行的結果在圖5中顯示.運行兩個瀏覽器,打開這個演示頁面可以看到不同的ID.
  
  
  
  
  圖5-你可以通過同時運行多個瀏覽器來簡單的查看應用程序域,應用程序池實例和請求線程是如何交互的.當多個請求同時發起,你可以看到線程ID和應用程序ID變化了,但是應用程序域還是同一個.
  
  你可能注意到在大多數請求上,當線程和HttpApplication ID變化時應用程序域ID卻保持不變,雖然它們也可能重複(指線程和HttpApplication ID).HttpApplication是從一個集合中取出,在隨後到來的請求中可以被複用的,所以它的ID有時是會重複的.注意Application實例並不和特定的線程綁定-確切的說它們是被指定給當前請求的活動線程.
  
  線程是由.NET的線程池管理的,默認是多線程套間(MTA)線程.你可以在ASP.NET的頁面上通過指定@Page指令的屬性ASPCOMPAT=”true”來覆蓋套間屬性.ASPCOMPAT意味着爲COM組件提供一個安全的執行環境,tmfc閱讀(1741) 評論(2) 編輯 收藏所屬分類: ASP.NET 

本文轉自
http://www.cnblogs.com/tmfc/archive/2006/09/02/492938.html  

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章