原本今天打算繼續寫ASP.NET MVC第四天的。但是由于里面涉及到asp.net運行機制的原理,如果不分析一下這里,mvc想說清楚還是挺困難的。既然要提到asp.net運行機制,所以打算還是說詳細一點的好。記錄mvc第一天的時候就說過,asp.net mvc也是基于asp.net運行機制的(也就是原理)。網上也有很多講解asp.net運行機制的,我在這里說一下自己的認識,我們開始吧。
我們從web程序的入口開始。那就要先說到iis了,大家都知道,這是web服務軟件。將web程序部署到iis過的人都知道,如果不做任何處理,我們寫的webform是不能運行的。為什么非要執行aspnet_regiis才可以呢?我們看一下電腦路徑C:/Windows/Microsoft.NET/Framework/v4.0.30319,aspnet_regiis.exe就在這里路徑下。我們簡單說一下原因,看下iis的歷史,在百度上沒有查到iis軟件發布的年限,但至少iis在windows 2000的時候就存在了,而我們的.net framework在2002-02-13的時候才發布1.0版本,是啊,我們都知道微軟很厲害,但就是在厲害他也不會強大到可以預測幾年后的軟件運行機制吧。也就是說iis對.net framework還說就是個“古董”,他不可能會知道.net framewrok運行機制,更不可能知道asp.net的運行機制。早起的iis也只能處理靜態頁面,也就類似于html,js,圖片之類的東西。但現在如果我們想將asp.net 程序部署到iis上怎么辦呢?對,擴展,使用擴展程序,我們運行aspnet_regiis.exe也就是將擴展程序(aspnet_isapi)注入到iis中,這樣iis就可以處理了?---------哈哈,iis還是處理處理不了asp.net程序,但是后注入的程序可以告訴iis,我擴展程序可以處理什么樣的程序,你如果處理不了,可以嘗試交給我處理。
看一下上面說到的路經下面有個aspnet_isapi.dll,我們只是簡單的說一下這里,這個dll是使用c/c++寫的,并不是c#寫的,所以我們無法反編譯成c#代碼。這是個承上啟下的動態庫,因為c/c++并不是我們考慮的范圍內,我們直接認為這個程序將請求交給我們“在乎”的程序,下面我們開始反編譯我們“在乎”程序。反編譯工具中查找ISAPIRuntime這個類,下面是我反編譯出來的結果這個類是system.web程序集下的類

1 public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IISAPIRuntime2, IRegisteredObject 2 { 3 // Fields 4 PRivate static int _isThisAppDomainRemovedFromUnmanagedTable; 5 private const int WORKER_REQUEST_TYPE_IN_PROC = 0; 6 private const int WORKER_REQUEST_TYPE_IN_PROC_VERSION_2 = 2; 7 private const int WORKER_REQUEST_TYPE_OOP = 1; 8 9 // Methods10 [SecurityPermission(SecurityAction.Demand, Unrestricted=true)]11 public ISAPIRuntime();12 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]13 public void DoGCCollect();14 public override object InitializeLifetimeService();15 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]16 public int ProcessRequest(IntPtr ecb, int iWRType);17 internal static void RemoveThisAppDomainFromUnmanagedTable();18 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]19 public void StartProcessing();20 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)]21 public void StopProcessing();22 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]23 void IISAPIRuntime2.DoGCCollect();24 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]25 int IISAPIRuntime2.ProcessRequest(IntPtr ecb, int iWRType);26 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]27 void IISAPIRuntime2.StartProcessing();28 [TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]29 void IISAPIRuntime2.StopProcessing();30 void IRegisteredObject.Stop(bool immediate);31 }32 33 34 Expand Methods35 View Code其實我貼出代碼沒有別的意思,就是想用事實說話,過多的內容我們不看,我們只看里面的public int ProcessRequest(IntPtr ecb, int iWRType)處理請求方法。我們先看一下參數類型吧,IntPtr?有調c/c++動態庫的人會知道這是c/c++里面指針類型,我們不用過多的考慮。我自己分析的,不知道對不對,正因為這是IntPtr,所以該類應該是調用了c/c++相關的動態庫了,不然這里也沒有必要用到。這樣流程就出來了,IIS——》aspnet_isapi(c/c++相關動態庫)——》ISAPIRuntime類;需要提到一點的是,IntPtr是個指針,指針會指向一塊內存區域,可能很大,也可能很小。我認為請求的內容放在了這塊區域中,從這里面可以獲取到瀏覽器請求頭的內容下面是ProcessRequest方法的內容

1 [SecurityPermission(SecurityAction.LinkDemand, Unrestricted=true)] 2 public int ProcessRequest(IntPtr ecb, int iWRType) 3 { 4 IntPtr zero = IntPtr.Zero; 5 if (iWRType == 2) 6 { 7 zero = ecb; 8 ecb = UnsafeNativeMethods.GetEcb(zero); 9 }10 ISAPIWorkerRequest wr = null;11 try12 {13 bool uSEOOP = iWRType == 1;14 wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);15 wr.Initialize();16 string appPathTranslated = wr.GetAppPathTranslated();17 string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;18 if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))19 {20 HttpRuntime.ProcessRequestNoDemand(wr);21 return 0;22 }23 HttpRuntime.ShutdownAppDomain(applicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated }));24 return 1;25 }26 catch (Exception exception)27 {28 try29 {30 WebBaseEvent.RaiseRuntimeError(exception, this);31 }32 catch33 {34 }35 if ((wr == null) || !(wr.Ecb == IntPtr.Zero))36 {37 throw;38 }39 if (zero != IntPtr.Zero)40 {41 UnsafeNativeMethods.SetDoneWithsessionCalled(zero);42 }43 if (exception is ThreadAbortException)44 {45 Thread.ResetAbort();46 }47 return 0;48 }49 }50 51 52 53 View Code下面我們來分析一下這里面的代碼,我們只分析重要的部分。
這里新建了一個ISAPIWorkerRequest wr = null;類,進行創建封裝該對象,wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);上面說了ecb是個指針,里面可以存儲很多請求內容的。緊接著對wr進行初始化wr.Initialize();我們著重看HttpRuntime.ProcessRequestNoDemand(wr);注意這里使用的是HttpRuntime,一會我們還會分析該類,現在我們進入ProcessRequestNoDemand方法里面看看。這里面應該是關于多線程模型了

1 internal static void ProcessRequestNoDemand(HttpWorkerRequest wr) 2 { 3 RequestQueue queue = _theRuntime._requestQueue; 4 wr.UpdateInitialCounters(); 5 if (queue != null) 6 { 7 wr = queue.GetRequestToExecute(wr); 8 } 9 if (wr != null)10 {11 CalculateWaitTimeAndUpdatePerfCounter(wr);12 wr.ResetStartTime();13 ProcessRequestNow(wr);14 }15 }16 17 18 19 View Code這時ISAPIRuntime已經將請求交給HttpRuntime類了,HttpRuntime類調用RequestQueue queue = _theRuntime._requestQueue;該類試圖獲取請求處理隊列,我們可以簡單的認為服務器在求情一個線程來處理該次瀏覽器的請求。wr = queue.GetRequestToExecute(wr);我們進入到GetRequestToExecute方法,

1 internal HttpWorkerRequest GetRequestToExecute(HttpWorkerRequest wr) 2 { 3 int num; 4 int num2; 5 int num3; 6 ThreadPool.GetAvailableThreads(out num, out num2); 7 if (this._iis6) 8 { 9 num3 = num;10 }11 else12 {13 num3 = (num2 > num) ? num : num2;14 }15 if ((num3 < this._minExternFreeThreads) || (this._count != 0))16 {17 bool isLocal = IsLocal(wr);18 if ((isLocal && (num3 >= this._minLocalFreeThreads)) && (this._count == 0))19 {20
新聞熱點
疑難解答