ASP.NET是如何在IIS下工做的

 

ASP.NET與IIS是緊密聯繫的,因爲IIS6.0與IIS7.0的工做方式的不一樣,致使ASP.NET的工做原理也發生了相應的變化。數據庫

 

IIS6(IIS7的經典模式)與IIS7的集成模式的不一樣api

IIS6的運行過程:瀏覽器

IIS6運行圖示

分析上圖可知:服務器

    在 User Mode 下,http.sys 接收到 http request,而後它會根據 IIS 中的 Metabase 查看基於該 Request 的 Application 屬於哪一個 Application Pool, 若是該 Application Pool 不存在,則建立之。不然直接將 request 發到對應 Application Pool 的 Queue中。每一個 Application Pool 對應着一個 Worker Process — w3wp.exe,(運行在 User Mode 下)。app

    在 IIS Metabase 中維護着 Application Pool 和 Worker Process 的Mapping。WAS(Web Administrative Service)根據這樣一個 mapping,將存在於某個 Application Pool Queue 的 request 傳遞到對應的 Worker Process (若是沒有,就建立這樣一個進程)。在 Worker Process 初始化的時候,加載 ASP.NET ISAPI,ASP.NET ISAPI 進而加載 CLR。最後經過 AppManagerAppDomainFactory 的 Create 方法爲 Application 建立一個 Application Domain;經過 ISAPIRuntime 的  ProcessRequest 處理 Request,進而將流程進入到 ASP.NET Http Runtime Pipeline。asp.net

   幾個知識點:ide

  • HTTP.SYS:(Kernel)的一個組件,它負責偵聽(Listen)來自於外部的HTTP請求,根據請求的URL將其轉發給相應的應用程序池 (Application Pool)。當此HTTP請求處理完成時,它又負責將處理結果發送出去.爲了提供更好的性能,HTTP.SYS內部創建了一個緩衝區,將最近的HTTP請求處理結果保存起來。
  • Application Pool:  IIS總會保持一個單獨的工做進程:應用程序池。全部的處理都發生在這個進程裏,包括ISAPI dll的執行。對於IIS6而言,應用程序池是一個重大的改進,由於它們容許以更小的粒度控制一個指定進程的執行。你能夠爲每個虛擬目錄或者整個Web 站點配置應用程序池,這可使你很容易的把每個應用程序隔離到各自的進程裏,這樣就能夠把它與運行在同一臺機器上其餘程序徹底隔離。從Web處理的角度看,若是一個進程死掉,至少它不會影響到其它的進程。 
    當應用程序池接收到HTTP請求後,交由在此應用程序池中運行的工做者進程Worker Process: w3wp.exe來處理此HTTP請求。
  • Worker Process: 當工做者進程接收到請求後,首先根據後綴找到並加載對應的ISAPI擴展 (如:aspx 對應的映射是aspnet_isapi.dll),工做者進程加載完aspnet_isapi.dll後,由aspnet_isapi.dll負責加載 ASP.NET應用程序的運行環境即CLR (.NET Runtime)。 
    Worker Process運行在非託管環境,而.NET中的對象則運行在託管環境之上(CLR),它們之間的橋樑就是ISAPI擴展。
  • WAS(Web Admin Service):這是一個監控程序,它一方面能夠存取放在InetInfo元數據庫(Metabase)中的各類信息,另外一方面也負責監控應用程序池(Application Pool)中的工做者進程的工做狀態況,必要時它會關閉一個老的工做者進程並建立一個新的取而代之。

IIS7的運行過程:oop

     IIS7運行圖示

分析上圖可知:post

    一、當客戶端瀏覽器開始 HTTP 請求一個WEB 服務器的資源時,HTTP.sys 攔截到這個請求。性能

    二、HTTP.sys 聯繫 WAS 獲取配置信息。

    三、WAS 向配置存儲中心(applicationHost.config)請求配置信息。

    四、WWW 服務接收到配置信息,配置信息指相似應用程序池配置信息,站點配置信息等等。

    五、WWW 服務使用配置信息去配置 HTTP.sys 處理策略。

    六、WAS爲請求建立一個進程(若是不存在的話)。

    七、工做者進程處理請求並對HTTP.sys作出響應。

    八、客戶端接受處處理結果信息。

 

除了IIS的總體運行方式不一樣以外,IIS7相比IIS6最大的不一樣之處在於它提供了兩種應用程序池管道模式:

經典模式:是與IIS 6或者以前版本保持兼容的一種模式,一個典型問題就是,在處理ASP.NET這種動態網站的時候,它是經過一個所謂的ISAPI程序,做爲插件的方式來工做的。針對不一樣的動態應用程序(例如ASP,PHP等),會須要不一樣的ISAPI(Internet Server Application Programe Interface,互聯網服務器應用程序接口)。如圖,在IIS中,打開「處理程序映射」,能夠看到aspx類型頁面的處理程序爲aspnet_isapi.dll。

經典模式處理程序映射

下圖展現了IIS7經典模式與IIS6的應用程序池管道模式運行原理,針對不一樣的請求,會指定不一樣的ISAPI(dll)進行處理:

經典模式運行圖

 

集成模式:asp.net再也不像IIS6同樣只限定於aspnet_isapi.dll中,而是被解放出來,從IIS接收到HTTP請求開始,即進入asp.net的控制範圍,asp.net能夠存在於一個請求在IIS中各個處理階段。容許咱們將ASP.NET更好地與IIS集成,甚至容許咱們在ASP.NET中編寫一些功能(例如Module)來改變IIS的行爲(擴 展)。集成的好處是,再也不經過ISAPI的方式,提升了速度和穩定性。至於擴展,則可使得咱們對於IIS,以及其餘類型的請求有更多的控制。(例如,我 們但願靜態網頁也具有一些特殊的行爲)。如圖

集成模式運行圖

 

 

以下圖在IIS7集成模式中,打開處理程序映射,能夠看到aspx類型頁面所對應的再也不是一個dll,而是一個類型。

集成模式處理程序映射

 

總結與擴展:

對於處理ASP.NET應用程序而言,IIS6及IIS7的經典模式須要aspnet_isapi.dll來處理,而IIS7集成模式不須要aspnet_isapi.dll來處理,而能夠直接根據文件擴展名找到相應的處理程序接口。例如aspx的處理程序是System.Web.UI.PageHandlerFactory類型。

 

介紹完IIS的工做原理,來看一下ASP.NET內部的運行機制。

首先看一下IIS處理模型:

image

 

上面介紹IIS工做原理時,已經介紹了從發起HTTP請求,到響應請求的過程,這裏主要介紹當請求到達.NET Runtime以後,.NET運行時所發生的一系列工做。

先看以下的.NET運行時工做序列圖:

.net運行時序列圖

 


1.HTTP請求進入Web服務器後,首先由HTTP.SYS來判斷請求的頁面是否存在,若是存在的話將把請求信息轉交給.NET Runtime。在這部分實際是完成兩個步驟,在將請求轉交給.NET Runtime的同時將請求信息封存在HTTPWorkRequest類中供其它步驟調用。HttpWorkRequest類在之後的操做中相當重要,它第一次將Http請求信息轉換爲類信息。 
2.當請求到達.NET Runtime後,接下來的操做將會在託管環境中完成,這時請求就真正進入了.NET中,對請求信息的操做是由.NET的底層類庫來實現。首先.NET Runtime將會針對請求信息作兩個動做,一是準備HostingEnvironment;二是調用ApplicationManager類爲HTTP請求動態的分配AppDomain,並把處理權交給AppDomain。 
3.HTTP請求進入AppDomain後,將由對象ISAPIRuntime來接管,一方面經方法ProcessRequest()獲得HttpWorkerRequest對象,另外一方面由方法StartProcessing()生成HttpRuntime對象,接下來把處理權交給了HttpRuntime(HttpWorkerRequest對象將做爲HttpRuntime方法中的參數被使用)。 
4.HTTPRuntime接收到Http請求後,方法ProcessRequest處理請求。將對第1步中的HTTPWorkRequest類中的信息進行操做,具體的實現由ProcessRequest方法實現。內部代碼以下:

  1. [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Medium)]  
  2. public static void ProcessRequest(HttpWorkerRequest wr)  
  3. {  
  4.     if (wr == null)  
  5.     {  
  6.         throw new ArgumentNullException("wr");  
  7.     }  
  8.     if (UseIntegratedPipeline)  
  9.     {  
  10.         throw new PlatformNotSupportedException(System.Web.SR.GetString("Method_Not_Supported_By_Iis_Integrated_Mode", new object[] { "HttpRuntime.ProcessRequest" }));  
  11.     }  
  12.     ProcessRequestNoDemand(wr);  
  13. }  
  14. internal static void ProcessRequestNoDemand(HttpWorkerRequest wr)  
  15. {  
  16.     RequestQueue queue = _theRuntime._requestQueue;  
  17.     if (queue != null)  
  18.     {  
  19.         wr = queue.GetRequestToExecute(wr);  
  20.     }  
  21.     if (wr != null)  
  22.     {  
  23.         CalculateWaitTimeAndUpdatePerfCounter(wr);  
  24.         wr.ResetStartTime();  
  25.         ProcessRequestNow(wr);  
  26.     }  
  27. }  
  28. internal static void ProcessRequestNow(HttpWorkerRequest wr)  
  29. {  
  30.     _theRuntime.ProcessRequestInternal(wr);  
  31. }  

5.在HttpRunTime中通過一系列的驅動後,將會在ProcessRequestInternal方法中爲Http請求分配應用程序。在這一步中還將建立HttpContext對象。

  1. context = new HttpContext(wr, false); // 基於HttpWorkerRequest生成HttpContext  
  2. IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context); // 獲得HttpApplication  
  3. handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context); // 由HttpApplication處理請求  

6.通過步驟5後HTTP請求信息才由基本信息轉交給了Asp.net中的各個對象。接下來的操做會觸發一些列的管道事件,這時的請求才真正轉到HttpModule和HttpHandler中。 
接下來咱們看看常說的管道事件的建立過程:

  1. internal override void BuildSteps(WaitCallback stepCallback)  
  2. {  
  3.     ArrayList steps = new ArrayList();  
  4.     HttpApplication app = base._application;  
  5.     bool flag = false;  
  6.     UrlMappingsSection urlMappings = RuntimeConfig.GetConfig().UrlMappings;  
  7.     flag = urlMappings.IsEnabled && (urlMappings.UrlMappings.Count > 0);  
  8.     steps.Add(new HttpApplication.ValidatePathExecutionStep(app));  
  9.     if (flag)  
  10.     {  
  11.         steps.Add(new HttpApplication.UrlMappingsExecutionStep(app));  
  12.     }  
  13.     app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);  
  14.     app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);  
  15.     app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);  
  16.     app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);  
  17.     app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);  
  18.     app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);  
  19.     app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);  
  20.     app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);  
  21.     steps.Add(new HttpApplication.MapHandlerExecutionStep(app));  
  22.     app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);  
  23.     app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);  
  24.     app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);  
  25.     app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);  
  26.     steps.Add(new HttpApplication.CallHandlerExecutionStep(app));  //調用HttpHandler  
  27.     app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);  
  28.     app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);  
  29.     app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);  
  30.     steps.Add(new HttpApplication.CallFilterExecutionStep(app));  
  31.     app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);  
  32.     app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);  
  33.     this._endRequestStepIndex = steps.Count;  
  34.     app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);  
  35.     steps.Add(new HttpApplication.NoopExecutionStep());  
  36.     this._execSteps = new HttpApplication.IExecutionStep[steps.Count];  
  37.     steps.CopyTo(this._execSteps);  
  38.     this._resumeStepsWaitCallback = stepCallback;  
  39. }  

管道事件請求序列圖以下:

管道

相關文章
相關標籤/搜索