·您现在的位置: 云翼网络 >> 文章中心 >> 网站建设 >> 网站建设开发 >> ASP.NET网站开发 >> ASP.NET 运行机制

ASP.NET 运行机制

作者:佚名      ASP.NET网站开发编辑:admin      更新时间:2022-07-23

asp.net 运行机制

原本今天打算继续写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