【转】ASP.NET Process Model

 

ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI

转载:博客园 http://www.cnblogs.com/artech/

http://www.cnblogs.com/artech/archive/2007/09/09/887528.html

 

前几天有一个朋友在MSN上问我“ASP.NET 从最初的接收到Http request到最终生成Response的整个流程到底是怎样的?”我觉得这个问题涉及到IISASP.NETASP.NET Runtime的处理模型的问题,并不是三言两语就能说清楚的,所以决定写这样一篇介绍IISASP.NET Runtime Process Model的文章,谈谈我对此的一个粗浅的认识,如果有什么不对的地方,希望大家及时指正。

这篇文章大体分为两个部分,第一部分我将谈谈IIS的两个不同的版本—IIS 5.x IIS 6(虽然IIS 7已经Release很长时间了,而且较之前两个版本发生了非常大的变化,由于本人缺乏对IIS 7深入的了解,所以在这里就不再介绍了,不过以后我将这方面的内容补上)的处理模型:IIS如何监听来自外界的Http request,如何根据ISAPI Extension Mapping将对于不同Resource的请求分发给不同的ISAPI Extension,基于ASP.NET ResourceASP.NET ISAPI如何将Request传递给ASP.NET Runtime 环境。第二部分将着重介绍在一个托管的ASP.NET Runtime 环境对传入的Http request的处理过程。我们先来看看IIS 5.xIIS 6的处理过程。

1             一、IIS 5.x based Process Model

IIS 5.x一个显著的特征就是Web Server和真正的ASP.NET Application的分离。作为Web ServerIIS运行在一个名为InetInfo.exe的进程上,InetInfo.exe是一个Native Executive,并不是一个托管的程序,而我们真正的ASP.NET Application则是运行在一个叫做aspnet_wpWorker Process上面,在该进程初始化的时候会加载CLR,所以这是一个托管的环境。我们接下来将谈论aspnet_wp如何创建,aspnet_wpInetInfo.exe如何进行通信,以及简单介绍在aspnet_wp中,如何将Request 导入ASP.NET Rutime Pipeline

我们通过创建虚拟目录将资源HostIIS下,原则上,我们可以通过IIS访问置于虚拟目录下的所有Resource,这部仅仅包含一些静态资源文件,比如图片、纯Html文件、CSSJS等等,也包含一些需要动态执行的文件,比如aspxasmx等等,我们还可以将RemotingWCF Service HostIIS下。对于这些静态的文件,IIS直接提取对应的文件将其作为Http Response返回给Client,但是对于这些需要进一步处理的动态执行的文件,IIS必须将Request进一步传递给对应的处理程序,待处理程序执行完毕获得最终的Http Response通过IIS返回给Client。对于IIS来说,这些处理程序通过ISAPI Extension来体现。对于基于ASP.NETResource,其对应的ISAPI ExtensionASP.NET ISAPI,通过一个aspnet_isapi.dll承载。IISMetadata database维护着一个称为ISAPI Extension Mapping的数据表,负责将不同类型的Resource影射到对应的ISAPI Extension

1

上图像我们展示了IIS 5.x如何处理一个基于ASP.NET Resource(以aspx为例)的Http Request的大体流程。首先用户通过Browser请求一个aspx pageBrower向对于得Web Server,也就是目标主机的IIS。在上面我们提到过,IIS运行在一个称为InetInfo.exe的进程中,InetInfo.exe是一个Native Executive,并非一个托管的程序。IIS分析Request的目标资源文件的扩展名(这里是aspx),通过ISAPI Extension Mapping获知对应的ISPAIASP.NET ISAPI,于是加载aspnet_isapi.dll。到此为止,该Request的处理交由ASP.NET ISAPI,处理。ASP.NET ISAPI会创建一个叫做aspnet_wp.exeWorker Process(如果该进程不存在的话),在aspnet_wp.exe初始化的时候会加载CLR,从而为ASP.NET Application创建一个托管的运行环境,在CLR初始化的使用会加载两个重要的dllAppManagerAppDomainFactoryISAPIRuntime。通过AppManagerAppDomainFactoryCreate方法为Application创建一个Application Domain;通过ISAPIRuntimeProcessRequest处理Request,进而将流程拖入到ASP.NET Http Runtime Pipeline的范畴,ASP.NET Http Runtime PipelineHttp Request的处理是一个相对复杂的过程,相关的介绍会放在本篇文章的下一部份。在这里我们可以把它看成是一个黑盒,它接管Request,最终生成Html

这基本上就是整个处理流程,很简单。不过在这里有几点需要特别指出的。

1. 首先,同一台主机上再同一时间只能运行一个aspnet_wp进程,每个基于虚拟目录的ASP.NET Application对应一个Application Domain,也就是说每个Application都运行在同一个Worker Process中,Application之间的隔离是基于Application Domain的,而不是基于Process的。

2. 其次,ASP.NET  ISAPI不但负责创建aspnet_wp Worker Process,而且负责监控该进程,如果检测到aspnet_wpPerformance降低到某个设定的下限,ASP.NET  ISAPI会负责结束掉该进程。当aspnet_wp结束掉之后,后续的Request会导致ASP.NET ISAPI重新创建新的aspnet_wp Worker Process

3. 最后,由于IISApplication运行在他们各自的进程中,他们之间的通信必须采用特定的通信机制。本质上IIS所在的InetInfo进程和Worker Process之间的通信是同一台机器不同进程的通信(local interprocess communications),处于Performance的考虑,他们之间采用基于Named pipe的通信机制。ASP.NET ISAPIWorker Process之间的通信通过他们之间的一组Pipe实现。同样处于Performance的原因,ASP.NET ISAPI通过异步的方式将Request 传到Worker Process并获得Response,但是Worker Process则是通过同步的方式向ASP.NET ISAPI获得一些基于Server的变量。

2             二、IIS 6 based Process Model

Reliability Performance永远不我们从事软件开发不变的主题。作为Host 基于Http ApplicationIIS来说,这两方面就显得尤为重要了。我们从IIS 5.xIIS 6 的演变,不难看出IIS 6在前一个版本基础上所作的改进也是基于这两个方面。在介绍IIS 6的处理模型之前,我们先看看IIS 5.x都什么样缺陷:

1. 首先从Performance上看,IISapplication运行在不同的进程中,虽然他们之间采用了基于Named Pipe的异步通信方式,但是一个基于进程之间的通信对性能的影响确实不能从根本上解决。

2. 其次,从Reliability来考虑,一台机器上只能运行一个worker process,每个Application运行在同一个进程中,虽然基于Application Domain的隔离能提供一定的Reliability,但是一旦真个进程崩溃,所有的Application都受影响。所以我们有时候需要提供一个基于Process的隔离性。

基于Reliability的改进,IIS 6引入了Application Pool。顾名思义,Application Pool就是一个application的容器,在IIS 6中,我们可以创建若干Application Pool,在创建Web Application的时候,我们为它指定一个既定的application pool。在运行的时候,一个Application对应一个Worker Processw3wp.exe。也就是说,和前一个版本的IIS不同的是,对于IIS 6来说,同一台机器上可以同时运行多个Worker Process,每个Worker Process中的每个Application domain对应一个Application。这样,Application之间不但能提供Application Domain级别的隔离,你也可以将不同的Application置于不同的Application Pool中,从而基于Process级别的隔离。对于Host 一些重要的Application来说,这样的方式可以提供很好的Reliability

Performance方面,IIS 5.x是通过InetInfo.exe监听Request并把Request分发到Work Process。换句话说,在IIS 5.x中对Request的监听和分发是在User Mode中进行,在IIS 6中,这种工作被移植到kernel Mode中进行,所有的这一切都是通过一个新的组件:http.sys来负责。

注:为了避免用户应用程序访问或者修改关键的操作系统数据,windows提供了两种处理器访问模式:用户模式(User Mode)和内核模式(Kernel Mode)。一般地,用户程序运行在User mode下,而操作系统代码运行在Kernel Mode下。Kernel Mode的代码允许访问所有系统内存和所有CPU指令。关于User ModeKernel Mode以及一些Windows底层的一些内容,推荐大家看看《Microsoft Windows InternalFour Edition Authored by Mark E.Russinovich & David A. Solomon

注:HTTP.SYS 运行在windows 的内核模式下,作为驱动程序而存在。它是Windows 2003TCP/IP网络子系统的一部分,从结构上说,它是TCP之上的一个网络驱动程序,因此,HTTP.SYS不再属于IIS,它已经从IIS中独 立了出来。在TCP/IP的基础之上,HTTP.SYS的主要功能是:侦听用户的http请求(这个请求来自于TCPIP.sys驱动程序),并将请求转 发给相关的web应用程序处理,最后,HTTP.SYS将处理结果返回给用户(返回到TCPIP.sys驱动程序)

 

2

上图基本上演示了IIS 6整个处理过程。在User Mode下,http.sys接收到一个基于aspxhttp request,然后它会根据IIS中的Metabase查看该基于该RequestApplication属于哪个Application Pool,如果该Application Pool不存在,则创建之。否则直接将request发到对应Application PoolQueue中。我上面已经说了,每个Application Pool对应着一个Worker Processw3wp.exe,毫无疑问他是运行在User Mode下的。在IIS Metabase中维护着Application Poolworker processMappingWASWeb Administrative service)根据这样一个mapping,将存在于某个Application Pool Queuerequest 传递到对应的worker process(如果没有,就创建这样一个进程)。在worker process初始化的时候,加载ASP.NET ISAPIASP.NET ISAPI进而加载CLR。最后的流程就和IIS 5.x一样了:通过AppManagerAppDomainFactoryCreate方法为Application创建一个Application Domain;通过ISAPIRuntimeProcessRequest处理Request,进而将流程进入到ASP.NET Http Runtime Pipeline

IIS Process Model部分就介绍到这里,在下部分中,我将介绍ASP.NET Http Runtime Pipeline

 

ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline

一、ASP.NET Runtime Pipeline1

相信大家都使用过ASP.NET进行过基于Web的应用开发,ASP.NET是什么?如果站在一个相对High Level的角度,我们可以这样来定义ASP.NETASP.NET是一个基于Web的开发平台,提供构建企业级应用所需的ServiceProgramming ModelSoftwareInfrastructure。如果我们以一个Low Level的角度来看,它本质上就是一个消息处理器:他接受IIS(确切地说应该是ASP.NET ISAPIForwardHttp Request (我们可以看成是一个Request Message),经过一系列的处理,最终产生一个用户希望的Response(这也是一个Message,对于.aspx Page来说是一个Html document,对于一个Web Service来说是一个Soap)。所以本篇文章的主要目的在于站在一个相对Low Level的角度介绍ASP.NET的整个Http Request Processing Model。我们访问一个基于ASP.NET的资源,IIS是第一道屏障,在第一个部分我分别就IIS 5.xIIS 6的差异介绍了IISHttp Request的处理,今天我们来继续后面的故事。

一、Unmanaged EnvironmentManaged Environment

上一部分我们说到IIS收到一个基于ASP.NET资源文件的访问,它会把Http Request交给一个ASP.NET ISAPI Extension处理。ASP.NET ISAPI 会加载CLR,从而创建一个托管的环境。ASP.NET ISAPI Extension定义在一个名为aspnet_isapi.dll中,aspnet_isapi.dll是一个纯Native的、高效的Dll,也就是说,虽然ASP.NET ISAPI通过加载CLR创建一个托管的环境,但是ASP.NET ISAPI本省却运行在一个Unmanaged的环境中。而我们的ASP.NET Application确是完全的Managed code,运行在一个Managed的环境中。要了解ASP.NET Http Runtime Pipeline这个纯托管的Runtime,我们必须先了解从Unmanaged EnvironmentManaged Environment的这道桥梁。

3

上图简单表述了在IIS 6环境下,从非托管环境到托管环境的过程。从图中我们可以看到,ASP.NET ISAPI运行在一个非托管环境之中。ASP.NET ISAPI经过系列COM级别的class调用(由于这些被调用的Class都是一个个undocumented class,所以要真正说清楚调用流程中每个具体的细节是一件很难的事情,而且也确实没有很大的必要去挖掘它,因为具体的实现可能会经常变动,如果对此具有好奇心的朋友可以通过一些Tool,比如Reflector去仔细研究一下),最终的调用降临到一个托管的、继承自System.Web.Hosting.ISAPIRuntime类的对象上。ISAPIRuntime 是一个特殊的class,他实现了Interface System.Web.Hosting.IISAPIRuntime。下面是该Interface的定义。通过定义我们可以看到,这是一个基于COMInterface,也就是说Caller可以通过COM的方式调用实现该InterfaceClass的对象。在这里,这个最初的Caller就是ASP.NET ISAPI。从这里我们可以总结出:ASP.NET ISAPI通过调用System.Web.Hosting.ISAPIRuntime InstanceProcessRequest方法,进而从非托管的环境进入了托管的环境。

http://www.cnblogs.com/Images/OutliningIndicators/None.gif[ComImport, InterfaceType(ComInterfaceType.InterfaceIsIUnknown), Guid("08a2c56f-7c16-41c1-a8be-432917a1a2d1")]
http://www.cnblogs.com/Images/OutliningIndicators/None.gif
public interface IISAPIRuntime
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
void StartProcessing();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
void StopProcessing();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    [
return: MarshalAs(UnmanagedType.I4)]
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
int ProcessRequest([In] IntPtr ecb, [In, MarshalAs(UnmanagedType.I4)] int useProcessModel);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
void DoGCCollect();
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

ISAPI ECB (Execution Control Block) & ISAPIWorkerRequest

通过System.Web.Hosting.IISAPIRuntime Interface中的ProcessRequest方法的Siganature,我们可以看出该方法包含两个参数,其中一个是名为ecbUnmanaged Pointer,另一个是useProcessModelECB全称是Execution Control Block,在整个Http Request Processing过程中起着非常重要的作用,我们现在来简单介绍一个ECB

ISAPI顾名思义,就是实现了一些基于Internet ServerAPIAspnet_isapi.dll实现了这些API,对于IIS来说,它可以调用这些API进入托管的环境实现对ISAPIRuntime的调用,对于ISAPIRuntime来说,它需要调用ASP.NET ISAPI实现一些必要的功能,比如获得Server Variable的数据,获得通过Post Mehod传回Server的数据;以及最终将Response的内容返回给ASP.NET ISAPI,并通过ASP.NET ISAPI返回到Client。一般地ISAPIRuntime不能直接调用ASP.NET ISAPI,而是通过一个对象指针实现对其的调用,这个对象就是ECBECB实现了对ISAPI的访问。

还有一点特别需要强调的是,ISAPIISAPIRutime的调用是异步的,也就是说ISAPI调用ISAPIRutime之后立即返回。这主要是出于PerformanceResponsibility考虑的,因为ASP.NET Application天生就是一个多线程的应用,为了具有更好的响应能力,异步操作是最有效的解决方式。但是这里就会有一个问题,我们知道我们对ASP.NET 资源的调用本质上是一个Request/ResponseMessage Exchange Pattern,异步调用往往意味着ISAPIRequest传递给ISAPIRuntime,将不能得到ISAPIRuntime最终生成的Response,这显然是不能接受的。而ECB解决了这个问题,ISAPI在调用ISAPIRutimeProcessRequest方法时会将自己对应的ECB的指针传给它,ISAPIRutime不但可以将最终生成的Response返回给ISAPI,还能通过ECB调用ISAPI获得一些所需的数据。

明白ECB是怎么回事之后,我们通过Reflector简单了解一下ISAPIRutimeProcessRequest的实现:

http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifProcessRequest
http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic int ProcessRequest(IntPtr ecb, int iWRType)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    IntPtr zero = IntPtr.Zero;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
if (iWRType == 2)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        zero = ecb;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        ecb = UnsafeNativeMethods.GetEcb(zero);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    ISAPIWorkerRequest wr = 
null;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
try
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
bool useOOP = iWRType == 1;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr.Initialize();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
string appPathTranslated = wr.GetAppPathTranslated();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
string appDomainAppPathInternal = HttpRuntime.AppDomainAppPathInternal;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if ((appDomainAppPathInternal == null) || StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            HttpRuntime.ProcessRequestNoDemand(wr);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            
return 0;
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString("Hosting_Phys_Path_Changed", 
new object[] http://www.cnblogs.com/Images/dot.gif{ appDomainAppPathInternal, appPathTranslated }));
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
return 1;
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
catch (Exception exception)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
try
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            WebBaseEvent.RaiseRuntimeError(exception, 
this);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
catch
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if ((wr == null) || (wr.Ecb != IntPtr.Zero))
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            
throw;
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if (zero != IntPtr.Zero)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            UnsafeNativeMethods.SetDoneWithSessionCalled(zero);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if (exception is ThreadAbortException)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            Thread.ResetAbort();
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
return 0;
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

对于上面的代码,我觉得没有必要去深究,但是对于那些具有强烈好奇心的朋友除外J。基本上上面的代码完成下面两个任务:

通过传入的ECBiWRType创建一个叫做ISAPIWorkerRequest的对象:

http://www.cnblogs.com/Images/OutliningIndicators/None.gifbool useOOP = iWRType == 1;
http://www.cnblogs.com/Images/OutliningIndicators/None.gifwr = ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

然后调用HttpRuntime.ProcessRequestNoDemand(wr)通过将创建的ISAPIWorkerRequest的对象作为参数传入。

HttpRuntime.ProcessRequestNoDemand的调用真正进入了ASP.NET Runtime Pipeline,这是一个相对复杂的过程。在这里我想简单说说ISAPIWorkerRequest这个重要classISAPIWorkerRequest是一个Abstract class,它已通过ECB创建基于当前RequestContext的信息,针对不同的IIS版本,具有不同的ISAPIWorkerRequest subclass,比如:ISAPIWorkerRequestOutOfProcIIS 5.x, ISAPIWorkerRequestInProcForIIS6, ISAPIWorkerRequestInProcForIIS7ProcessRequest通过ISAPI传入的iWRType来创建不同HttpWorkerRequest,从而屏蔽了不同IIS的差异,后续的步骤就不需要考虑这种差异了,这是Abstract Factory的典型用法。

二、ASP.NET Runtime Pipeline2

现在我们真正进入ASP.NET管辖的范畴,下图基本上囊括整个处理过程涉及的对象,接下来我们一起来讨论这一系列的对象如何相互协作去处理Http Request,并最终生成我们所需的Http Response
4


HttpContext

上面我们介绍了ISAPI在调用ISAPIRuntime的时候将对应的ISAPI ECB Pointer作为参数传递给了ProcessRequest方法,这个ECB pointer可以看成是托管环境和非托管环境进行数据交换的唯一通道,Server VariableRequest Parameter通过它传入ASP.NET作为进一步处理的依据,ASP.NET最后生成的Response通过它传递给ISAPI,并进一步传递给IIS最终返回到Client端。

借助这个传进来的ECB Pointer,我们创建了一个ISAPIWorkerRequestISAPIWorkerRequest作为参数传入HttpRuntime.ProcessRequestNoDemand的调用。HttpRuntime.ProcessRequestNoDemand最终体现在调用ProcessRequestInternal。下面是真个方法的实现:

http://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifProcessRequestInternal
http://www.cnblogs.com/Images/OutliningIndicators/None.gifprivate void ProcessRequestInternal(HttpWorkerRequest wr)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    HttpContext context;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
try
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        context = 
new HttpContext(wr, false);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
catch
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr.SendStatus(400, "Bad Request");
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr.SendResponseFromMemory(bytes, bytes.Length);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr.FlushResponse(
true);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        wr.EndOfRequest();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
return;
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    wr.SetEndOfSendNotification(
this._asyncEndOfSendCallback, context);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    Interlocked.Increment(
ref this._activeRequestCount);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    HostingEnvironment.IncrementBusyCount();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
try
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
try
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            
this.EnsureFirstRequestInit(context);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
catch
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            
if (!context.Request.IsDebuggingRequest)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif            
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif                
throw;
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif            }
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        context.Response.InitResponseWriter();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if (applicationInstance == null)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            
throw new HttpException(SR.GetString("Unable_create_app_object"));
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if (EtwTrace.IsTraceEnabled(5, 1))
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, applicationInstance.GetType().FullName, "Start");
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
if (applicationInstance is IHttpAsyncHandler)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            context.AsyncAppHandler = handler2;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            handler2.BeginProcessRequest(context, 
this._handlerCompletionCallback, context);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
else
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif        
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            applicationInstance.ProcessRequest(context);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            
this.FinishRequest(context.WorkerRequest, context, null);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif        }
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
catch (Exception exception)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        context.Response.InitResponseWriter();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
this.FinishRequest(wr, context, exception);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

 对象上面的代码没有必要深究,我们只需要了解大体的执行流程就可以了,下面这一段伪代码基本上体现整个执行过程:

http://www.cnblogs.com/Images/OutliningIndicators/None.gifHttpContext context = new HttpContext(wr, false);
http://www.cnblogs.com/Images/OutliningIndicators/None.gif IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

首先通过创建的ISAPIWorkerRequest创建按一个HttpContext对象,随后通过HttpApplicationFactory.GetApplicationInstance创建一个IHttpHandler对象(一般情况下就是一个HttpApplication对象)。

正如他的名字体现的,HttpContext体现当前Request的上下文信息,它的生命周期知道整个Request处理结束或者处理超时。通过HttpContext对象我们可以访问属于当前Request的一系列常用的对象:ServerSessionCacheApplicationRequestResponseTraceUserProfile等等。此外我们可以认为将一些数据放在Items属性中作为状态管理的一种方式,不过这种状态管理和其他一些常用的方式,比如SessionCacheApplicationCookie等,具有根本性的不同之处是其生命周期仅仅维持在当前RequestContext中。

2             HttpApplication

就像其名称体现的一样,HttpApplication基本上可以看成是真个ASP.NET Application的体现。HttpApplication和置于虚拟根目录的Gloabal.asax对应。通过HttpApplicationFactory.GetApplicationInstance创建一个基于Gloabal.asaxHttpApplication对象。在HttpApplicationFactory.GetApplicationInstance方法返回创建的HttpApplication对象之前,会调用一个名为InitInternal的内部方法,该方法会做一些列的初始化的操作,在这些初始化操作中,最典型的一个初始化方法为InitModules(),该方法的主要的目的就是查看Config中注册的所有HttpModule,并根据配置信息加载相应的Assembly,通过Reflection创建对应的HttpModule,并将这些Module加到HttpApplication _moduleCollection Filed中。

HttpApplication本身并包含对Request的任何处理,他的工作方式是通过在不同阶段出发不同Event来调用我们注册的Event Hander

下面列出了HttpApplication所有的Event,并按照触发的时间先后顺序排列:

  • BeginRequest
  • AuthenticateRequest & Post AuthenticateRequest
  • AuthorizeRequest & Post AuthorizeRequest
  • ResolveRequestCache & Post ResolveRequestCache
  • PostMapRequestHandler:
  • AcquireRequestState & AcquireRequestState:
  • PreRequestHandlerExecute & Post RequestHandlerExecute:
  • ReleaseRequestState & Post ReleaseRequestState
  • UpdateRequestCache & PostUpdateRequestCache
  • EndRequest:

ASP.NET Application, AppDomain and HttpApplication

对于一个ASP.NET Application来说,一个Application和一个虚拟目录相对应,那么是不是一个Application 对应着一个AppDomain呢?一个Application是否就唯一对应一个Httpapplication对象呢?答案是否定的。

我们首先来看看ApplicationHttpApplication的关系,虽然我们对一个ApplicationRequest最终都由一个HttpApplication对象来承载。但不能说一个Application就唯一对应一个固定的HttpApplication对象。原因很简单,ASP.NET天生具有多线程的特性,需要通过相应不同的Client的访问,如果我们只用一个HttpApplication来处理这些并发的请求,会对Responsibility造成严重的影响,通过考虑到Performance的问题,ASP.NETHttpApplication的使用采用Pool的机制:当Request到达,ASP.NET会现在HttpApplication Pool中查找未被使用的HttpApplication对象,如果没有,则创建之,否则从Pool直接提取。对于Request处理完成的HttpApplication对象,不会马上销毁,而是把它放回到Pool中供下一个Request使用。

对于ApplicationAppDomain的关系,可能你会说一个Application肯定只用运行在一个AppDomain之中。在一般情况下这句话无可厚非,但是这却忽略了一种特殊的场景:在当前Application正在处理Request的时候,我们把web.config以及其他一些相关文件修改了,而且这种改变是可以马上被ASP.NET检测到的,为了使我们的变动能够及时生效,对于改动后的第一个RequestASP.NET会为期创建一个新的AppDomain,而对于原来的AppDomain,也许还在处理修改前的Request,所有原来的Appdomain会持续到将原来的Request处理结束之后,所以对于一个Application,可能出现多个AppDomain并存的现象。

3             HttpModule

我们上面提到HttpApplication就是一个ASP.NET Application的体现,HttpApplication本身并不提供对Request的处理功能,而是通过在不同阶段出发不同的Event。我们能做的只能是根据我们具体的需求将我们的功能代码作为Event Handler注册到需要的HttpApplication Event上面。注册这些Event Handler,我们首先想到的肯定就直接在HttpApplication对应的Global.asax中定义我们的EventHandler好了。这是最直接的办法,而且Global.asax提供一个简洁的方式是我们的实现显得简单:不需要向一般注册Event一样将Delegate添加到对应的Event上面,而是直接通过方法名称和对应的Event匹配的方式直接将对应的方法作为相关的Event Handler。比如Application_ AcquireRequestState就是AcquireRequestState Event handler

但是这种方式在很多情况下却达不到我们的要求,更多地,我们需要的是一种Plug-in的实现方式:我们在外部定义一些Request Processing的功能,需要直接运用到我们的Application之中。通过使用HttpModule封装这些功能模块,并将其注册到我们的Application的发式可以很简单的实现这种功能。

HttpModule实现了System.Web.IHttpModule interface,该Interface很简单,仅仅有两个成员:

http://www.cnblogs.com/Images/OutliningIndicators/None.gif[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
http://www.cnblogs.com/Images/OutliningIndicators/None.gif
public interface IHttpModule
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
// Methods
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
    void Dispose();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
void Init(HttpApplication context);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

我们只要在Init方法中注册相应的HttpApplication Event Handler就可以了:

http://www.cnblogs.com/Images/OutliningIndicators/None.gifpublic class BasicAuthCustomModule : IHttpModule
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif      
public void Init(HttpApplication application)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif      
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif            application.AuthenticateRequest += 
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif                
new EventHandler(this.OnAuthenticateRequest);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif      }
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif      
public void Dispose() http://www.cnblogs.com/Images/dot.gif{ }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif 
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif      
public void OnAuthenticateRequest(object source, EventArgs eventArgs)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif      
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif      } 
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

所有的HttpModulemachine.config或者Web.confighttpModules Section定义,下面是Machine.config定义的所有httpModule

 

http://www.cnblogs.com/Images/OutliningIndicators/None.gif<httpModules>
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="Session" type="System.Web.SessionState.SessionStateModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="WindowsAuthentication" type="System.Web.Security.WindowsAuthenticationModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="FormsAuthentication" type="System.Web.Security.FormsAuthenticationModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="PassportAuthentication" type="System.Web.Security.PassportAuthenticationModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif 
</httpModules>
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

但是HttpModule如何起作用的,我们来回顾一下上面一节介绍的:HttpApplicationFactory.GetApplicationInstance方法返回创建的HttpApplication对象之前,会调用一个名为InitInternal的内部方法,该方法会做一些列的初始化的操作,在这些初始化操作中,最典型的一个初始化方法为InitModules(),该方法的主要的目的就是查看Config中注册的所有HttpModule,并根据配置信息加载相应的Assembly,通过Reflection创建对应的HttpModule,并将这些Module加到HttpApplication _moduleCollection Filed中,最后依次调用每个HttpModuleInit方法。下面是其实现:

http://www.cnblogs.com/Images/OutliningIndicators/None.gifprivate void InitModules()
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
this._moduleCollection = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
this.InitModulesCommon();
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif
http://www.cnblogs.com/Images/OutliningIndicators/None.gif
http://www.cnblogs.com/Images/OutliningIndicators/None.gif
private void InitModulesCommon()
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
int count = this._moduleCollection.Count;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
for (int i = 0; i < count; i++)
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockStart.gifhttp://www.cnblogs.com/Images/OutliningIndicators/ContractedSubBlock.gif    
http://www.cnblogs.com/Images/dot.gif{
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
this._currentModuleCollectionKey = this._moduleCollection.GetKey(i);
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif        
this._moduleCollection[i].Init(this);
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedSubBlockEnd.gif    }
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
this._currentModuleCollectionKey = null;
http://www.cnblogs.com/Images/OutliningIndicators/InBlock.gif    
this.InitAppLevelCulture();
http://www.cnblogs.com/Images/OutliningIndicators/ExpandedBlockEnd.gif}
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

HttpHandler

如果说HttpModule关注的是所有Inbound Request的处理的话,Handler确实关注基于某种类型的ASP.NET ResourceRequest。比如一个.apsxWeb Page通过一个System.Web.UI.Page来处理。HttpHandler和他所处理的Resource通过Config中的system.web/handlers section来定义,下面是Machine.config中的定义。

http://www.cnblogs.com/Images/OutliningIndicators/None.gif        <httpHandlers>
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.asmx" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="false"/> 
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.rem" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.soap" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.asax" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.ascx" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="GET,HEAD" path="*.dll.config" type="System.Web.StaticFileHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="GET,HEAD" path="*.exe.config" type="System.Web.StaticFileHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.cs" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.csproj" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.vb" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.vbproj" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.webinfo" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.asp" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.licx" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.resx" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*.resources" type="System.Web.HttpForbiddenHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="GET,HEAD" path="*" type="System.Web.StaticFileHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif            
<add verb="*" path="*" type="System.Web.HttpMethodNotAllowedHandler" />
http://www.cnblogs.com/Images/OutliningIndicators/None.gif        
</httpHandlers>
http://www.cnblogs.com/Images/OutliningIndicators/None.gif

需要注意的是,我们不但可以单纯地定义一个实现了System.Web.IHttpHandlerType,也可以定义一个实现了System.Web.IHttpHandlerFactory TypeSystem.Web.UI.Page是一个典型的Httphandler,相信对此大家已经很熟悉了。在最后还说说另一个典型的HttpHandlerSystem.Web.HttpForbiddenHandler,从名称我们不难看出,它用于那些禁止访问的Resource,现在应该知道了为了Global.asax不同通过IIS访问了吧。

 

注:

ASP.Net处理Http Request时,使用Pipeline(管道)方式,由各个HttpModule对请求进行处理,然后到达 HttpHandlerHttpHandler处理完之后,仍经过Pipeline中各个HttpModule的处理,最后将HTML发送到客户端浏览 器中。

生命周期中涉及到几个非常重要的对 象:HttpHandler,HttpModule,IHttpHandlerFactory,他们的执行(顺序)大致的执行过程是这样的:client 端发送页面请求,被IIS的某个进程截获,它根据申请的页 面后缀(.aspx)不同,调用不同的页面处理程序(.asp->asp.dll; .aspx->ISAPI.dll).而页面处理程序在处理过程中,则要经历HttpModule,HttpHandler的处理:前者HttpModule用于页面处理前和处理后的一些事件的处理后者HttpHandler进行真正的页面的处理
如前所说,HttpModule会在页面处理前和后对页面进行处理,所以它不会影响真正的页面请求。通常用在给每个页面的头部或者尾部添加一些信息(如版 权声明)等.曾经见过一些免费的空间,我们的页面上传上去后,浏览的时候发现,在每个页面的头部和尾部多了很多小广告....,如果理解了 HttpModule的原理,要做这个就不是很难了~


IHttpModule
IHttpHandler的区别整理
1.
先后次序.IHttpModule,IHttpHandler. :Module要看你响应了哪个事件,一些事件是在Handler之前运行的,一些是在Handler之后运行的
2.
对请求的处理上:
   IHttpModule
是属于大小通吃类型,无论客户端请求的是什么文件,都会调用到它;例如aspx,rar,html的请求.
   IHttpHandler
则属于挑食类型,只有ASP.net注册过的文件类型(例如aspx,asmx等等)才会轮到调用它.
3.IHttpHandler
按照你的请求 生成响应的内容,IHttpModule对请求进行预处理,如验证、修改、过滤等等,同时也可以对响应进行处理

http://www.cnblogs.com/cyan/archive/2009/02/04/1383580.html

posted @ 2009-03-12 09:52  深潭  阅读(280)  评论(0编辑  收藏  举报