1/**//*InterfaceType(ComInterfaceType.InterfaceIsIUnknown)指明了這個接口將作為 IUnknown 派生接口向 COM 公開,這就使得isapi.dll可以以COM方式調用此接口。*/ 2[ComImport, Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] 3public interface IISAPIRuntime 4{ 5 void StartProcessing(); 6 void StopProcessing(); 7 /**//*ProcessRequest方法就是整個處理流程中托管代碼和非托管代碼的分界點,可以看到里面是以一個IntPtr結構傳入了調用方(也就是isapi.dll)的ECB地址*/ 8 [return: MarshalAs(UnmanagedType.I4)] 9 int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel); 10 void DoGCCollect(); 11} 12 13/**//*這個類實現了IISAPIRuntime接口。它的實例對象存在于每一個AppDomain中,作為整個Asp.net運行時的入口。*/ 14public sealed class ISAPIRuntime : MarshalByRefObject, IISAPIRuntime, IRegisteredObject 15{ 16 // Fields 17 private static int _isThisAppDomainRemovedFromUnmanagedTable; 18 private static string s_thisAppDomainsIsapiAppId; 19 20 // Methods 21 [AspNetHostingPermission(SecurityAction.Demand, Level=AspNetHostingPermissionLevel.Minimal), SecurityPermission(SecurityAction.Demand, Unrestricted=true)] 22 public ISAPIRuntime(); 23 public void DoGCCollect(); 24 public override object InitializeLifetimeService(); 25 /**//*處理請求的入口點方法,由isapi.dll以COM方式調用*/ 26 public int ProcessRequest(IntPtr ecb, int iWRType); 27 internal static void RemoveThisAppDomainFromUnmanagedTable(); 28 internal void SetThisAppDomainsIsapiAppId(string appId); 29 public void StartProcessing(); 30 public void StopProcessing(); 31 void IRegisteredObject.Stop(bool immediate); 32} |
1/**//*這是System.Web.Hosting.AppDomainFactory類型的Create方法,它調用的是實際工廠的Create方法。*/ 2[return: MarshalAs(UnmanagedType.Interface)] 3public object Create(string module, string typeName, string appId, string appPath, string strUrlOfAppOrigin, int iZone) 4{ 5 /**//*實際工廠是一個AppManagerAppDomainFactory類型的對象。*/ 6 return this._realFactory.Create(appId, appPath); 7} 8 9/**//*AppManagerAppDomainFactory.Create方法,請看代碼內的注釋。*/ 10[return: MarshalAs(UnmanagedType.Interface)] 11public object Create(string appId, string appPath) 12{ 13 object obj2; 14 try 15 { 16 if (appPath[0] == '.') 17 { 18 FileInfo info = new FileInfo(appPath); 19 appPath = info.FullName; 20 } 21 if (!StringUtil.StringEndsWith(appPath, '//')) 22 { 23 appPath = appPath + @"/"; 24 } 25 ISAPIApplicationHost appHost = new ISAPIApplicationHost(appId, appPath, false); 26 /**//*這個方法內部的調用鏈非常復雜,它一方面創建了一個應用程序域,一方面返回一個ISAPIRuntime對象。具體這個方法究竟是如何創建AppDomain對象的,大家可以用 27 JetBrain來跟蹤其調用棧。關于這部分內容更詳盡的信息,可參見ASP.NET Internals - The bridge between ISAPI and Application Domains一文。 28 另外,如果您使用JetBrain來調試系統程序集的話,有可能會因為缺少相應pdb文件而不能查看完整調試信息,這里提供一個根據已有程序集,先反匯編成中間碼, 29 再重新以調試模式生成dll和pdb文件的方法: 30 1)生成IL文件: ildasm /tok /byt system.web.dll /out=system.web.il 31 2)重新生成PDB/DLL: ilasm system.web.il /DEBUG /DLL /OUTPUT=System.Web.dll*/ 32 ISAPIRuntime o = (ISAPIRuntime) this._appManager.CreateObjectInternal(appId, typeof(ISAPIRuntime), appHost, false, null); 33 o.SetThisAppDomainsIsapiAppId(appId); 34 o.StartProcessing(); 35 obj2 = new ObjectHandle(o); 36 } 37 catch (Exception) 38 { 39 throw; 40 } 41 return obj2; 42} |
三.Asp.net運行時,我們等待已久的純托管代碼環境
好,經過上面長久的鋪墊,我們終于進入了托管代碼的領域。經過前面的內容,我們知道,在托管代碼中首先被執行的是一個ISAPIRuntime對象的ProcessRequest方法,那么下面我們就來看一看這個方法主要做了些什么:
1/**//*ISAPIRuntime的方法,處理請求的入口。*/ 2public int ProcessRequest(IntPtr ecb, int iWRType) 3{ 4 try 5 { 6 /**//*這里ecb被作為參數傳入,返回一個HttpWorkerRequest類型的對象,作為對一個請求的數據的封裝。但HttpWorkerRequest 7 *只是一個抽象基類,CreateWorkerRequest作為一個工廠方法,返回的實際類型是ISAPIWorkerRequestInProc, 8 *ISAPIWorkerRequestInProcForIIS6或ISAPIWorkerRequestOutOfProc。這些類型里面提供的方法,其實大多 9 *圍繞著如何從ecb中去獲取數據,所以都包含了很多對System.Web.UnsafeNativeMethods類型中靜態方法的調用。 10 **/ 11 HttpWorkerRequest wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, iWRType); 12 string appPathTranslated = wr.GetAppPathTranslated(); 13 string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal; 14 if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal)) 15 { 16 /**//*從這里開始,對請求的處理流程就交給了HttpRuntime。需要注意的是,ISAPI是多線程的,而且對ProcessRequest的調用是異步的, 17 *這就要求HttpRuntime.ProcessRequest方法是線程安全的??匆豢碒ttpRuntime.ProcessRequestNoDemand里的代碼大家就清楚, 18 *所有的請求會被排成一個隊列,順次執行,保證了并發安全。 19 *最終,HttpRuntime.ProcessRequestInternal方法會被調用,我們接下來就去看看那個方法。 20 **/ 21 HttpRuntime.ProcessRequestNoDemand(wr); 22 return 0; 23 } 24 HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", new object[] { appDomainAppPathInternal, appPathTranslated })); 25 } 26 catch (Exception exception) 27 { 28 Misc.ReportUnhandledException(exception, new string[] { SR.GetString("Failed_to_process_request") }); 29 throw; 30 } 31 return 1; 32} |
1/**//*在HttpRuntime.ProcessRequestInternal()方法里,有如下幾個重要的對象被創建出來: 2 *(1)HttpContext(包括其中的HttpRequest,HttpResponse) 3 *(2)HttpApplication 4 *同時,會執行HttpApplication對象的ProcessRequest方法, 5 */ 6private void ProcessRequestInternal(HttpWorkerRequest wr) 7{ 8 /**//*HttpContext對象在這里被創建。HttpWorkerRequest做為構造參數,而HttpWorkerRequest本身 9 *又圍繞著對ecb的處理建立了一群高層的方法,它的實例會被HttpContext傳給HttpRequest和HttpResponese 10 *做為他們的構造參數。所以,這里也能更清楚地看出HttpWorkerRequest作為ecb的托管環境封裝器的實質。 11 *另外,這里也能清楚地反映出,每一個請求都有一個自己的HttpContext對象(而每一個Htt瀀?潳楬?pContext對象都管理著 12 *一個HttpSession對象--參見HttpContext的Session屬性,這也就保證了每個訪問者有自己的session對象。),你可以 13 *使用HttpContext.Current來訪問到這個對象。 14 */ 15 HttpContext extraData = new HttpContext(wr, false); 16 wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, extraData); 17 Interlocked.Increment(ref this._activeRequestCount); 18 HostingEnvironment.IncrementBusyCount(); 19 try 20 { 21 try 22 { 23 this.EnsureFirstRequestInit(extraData); 24 } 25 catch 26 { 27 if (!extraData.Request.IsDebuggingRequest) 28 { 29 throw; 30 } 31 } 32 extraData.Response.InitResponseWriter(); 33 /**//*用應用程序工廠返回一個HttpApplication對象。 34 *和線程池對線程的管理相似,HttpApplicationFactory中以stack維護了一個HttpApplication的列表(參見HttpApplicationFactory 35 *的_freeList變量)。在這句方法調用的最后,實際是調用了 _theApplicationFactory.GetNormalApplicationInstance(context), 36 *里面就是從_freeList的棧頂pop出一個已經構造的HttpApplication實例。 37 *所以,對于每一個請求,由HttpContext作為上下文,由一個HttpApplication對象來控制整個應用處理的pipeline,整個 38 *處理過程是在由工作進程管理的線程池中的某個線程內完成的。 39 *另外,在一個應用程序域內,由于可以同時處理多個請求,所以就有多個HttpApplication實例和多個活動線程(您可以使用windbg的sos 40 *擴展來觀察它們之間的關系,本文就不繼續深入了)。 41 *還有,對所有HttpModules的加載就是發生在HttpApplication對象的創建過程之中(包括系統已經提供的Authentication等模塊兒和我們 42 *的自定義模塊)。我們可以在Web.config里聲明自己的自定義模塊。這些模塊的作用就是在整個HttpApplication處理管線的相關事件點上, 43 *掛上自己的處理。注意一下IHttpModule接口的Init()方法的聲明,這個方法的傳入參數就是要被創建的HttpApplication對象,所以,如果 44 *你自己的模塊想在緩存讀取上加入一些自定義操作,你只需進行如下處理即可: 45 public class YourCustomModule : IHttpModule 46 { 47 public void Init(HttpApplication application) 48 { 49 application.ResolveRequestCache += new EventHandler(this.YourCustomResolveRequestCache); 50 } 51 } 52 *另外,通過對HttpApplicationFactory.GetApplicationInstance方法內部實現方式的閱讀,你會發現在每一個HttpApplication對象被創建 53 *之后,會立刻調用這個對象的InitInternal方法,而這個方法里面做了很多重要的初始化操作,內容較多,我們將在下文中單獨介紹。 54 * 55 */ 56 IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(extraData); 57 if (applicationInstance == null) 58 { 59 throw new HttpException(SR.GetString("Unable_create_app_object")); 60 } 61 if (EtwTrace.IsTraceEnabled(5, 1)) 62 { 63 EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, extraData.WorkerRequest, applicationInstance.GetType().FullName, "Start"); 64 } 65 /**//*看一下System.Web.HttpApplication的類型聲明 66 *public class HttpApplication : IHttpAsyncHandler, IHttpHandler, IComponent, IDisposable 67 *你會發現它同時實現了同步和異步的IHandler,所以在默認情況下,Asp.net對請求的處理是異步的。 68 */ 69 if (applicationInstance is IHttpAsyncHandler) 70 { 71 IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance; 72 bgcolor="#e7e7e7" border="0" width="90%"> |
Page page = BuildManager.CreateInstanceFromVirtualPath(virtualPath, typeof(Page), context, true, true) as Page; |
internal interface IExecutionStep { // 每一個“執行步驟”的執行命令 void Execute(); // Properties bool CompletedSynchronously { get; } bool IsCancellable { get; } } |
public void Init(HttpApplication application) { application.BeginRequest += new EventHandler(this.YourCustomMethodForBeginRequestEvent); } |
1this.CreateEventExecutionSteps(EventBeginRequest, steps); 2this.CreateEventExecutionSteps(EventAuthenticateRequest, steps); 3this.CreateEventExecutionSteps(EventDefaultAuthentication, steps); 4this.CreateEventExecutionSteps(EventPostAuthenticateRequest, steps); 5this.CreateEventExecutionSteps(EventAuthorizeRequest, steps); 6this.CreateEventExecutionSteps(EventPostAuthorizeRequest, steps); 7this.CreateEventExecutionSteps(EventResolveRequestCache, steps); 8this.CreateEventExecutionSteps(EventPostResolveRequestCache, steps); 9steps.Add(new MapHandlerExecutionStep(this)); 10this.CreateEventExecutionSteps(EventPostMapRequestHandler, steps); 11this.CreateEventExecutionSteps(EventAcquireRequestState, steps); 12this.CreateEventExecutionSteps(EventPostAcquireRequestState, steps); 13this.CreateEventExecutionSteps(EventPreRequestHandlerExecute, steps); 14steps.Add(new CallHandlerExecutionStep(this));//從這里,您可以很容易看到Handler對頁面的解蚊 15 //有哪些應用程序事件在它之前,哪些在它之后 16this.CreateEventExecutionSteps(EventPostRequestHandlerExecute, steps); 17this.CreateEventExecutionSteps(EventReleaseRequestState, steps); 18this.CreateEventExecutionSteps(EventPostReleaseRequestState, steps); 19steps.Add(new CallFilterExecutionStep(this)); 20this.CreateEventExecutionSteps(EventUpdateRequestCache, steps); 21this.CreateEventExecutionSteps(EventPostUpdateRequestCache, steps); 22this._endRequestStepIndex = steps.Count; 23this.CreateEventExecutionSteps(EventEndRequest, steps); 24steps.Add(new NoopExecutionStep()); 25this._execSteps = new IExecutionStep[steps.Count]; 26steps.CopyTo(this._execSteps);//把整個數組拷貝給HttpApplication的私有變量_execSteps |
新聞熱點
疑難解答
圖片精選