Artech

Develop every application as an art using the most suitable technologies!

常用链接

统计

积分与排名

网上邻居

我的博文系列

最新评论

[原创]ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline - Part II

 

二、ASP.NET Runtime Pipeline(续ASP.NET Http Runtime Pipeline - Part I)

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


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。下面是真个方法的实现:

ProcessRequestInternal

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

HttpContext context = new HttpContext(wr, false);
 IHttpHandler applicationInstance 
= HttpApplicationFactory.GetApplicationInstance(context);

首先通过创建的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很简单,仅仅有两个成员:

[AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public interface IHttpModule
{
    
// Methods
    void Dispose();
    
void Init(HttpApplication context);
}

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

public class BasicAuthCustomModule : IHttpModule

      
public void Init(HttpApplication application)
      
{
            application.AuthenticateRequest 
+= 
                
new EventHandler(this.OnAuthenticateRequest);
      }

      
public void Dispose() { }
 
      
public void OnAuthenticateRequest(object source, EventArgs eventArgs)
      
{

      }
 
}

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

 

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

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

private void InitModules()
{
    
this._moduleCollection = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
    
this.InitModulesCommon();
}



private void InitModulesCommon()
{
    
int count = this._moduleCollection.Count;
    
for (int i = 0; i < count; i++)
    
{
        
this._currentModuleCollectionKey = this._moduleCollection.GetKey(i);
        
this._moduleCollection[i].Init(this);
    }

    
this._currentModuleCollectionKey = null;
    
this.InitAppLevelCulture();
}

HttpHandler

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

        <httpHandlers>
            
<add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler" />
            
<add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory" />
            
<add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory" />
            
<add verb="*" path="*.asmx" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="false"/> 
            
<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"/>
            
<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"/>
            
<add verb="*" path="*.asax" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.ascx" type="System.Web.HttpForbiddenHandler" />
            
<add verb="GET,HEAD" path="*.dll.config" type="System.Web.StaticFileHandler" />
            
<add verb="GET,HEAD" path="*.exe.config" type="System.Web.StaticFileHandler" />
            
<add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.cs" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.csproj" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.vb" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.vbproj" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.webinfo" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.asp" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.licx" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.resx" type="System.Web.HttpForbiddenHandler" />
            
<add verb="*" path="*.resources" type="System.Web.HttpForbiddenHandler" />
            
<add verb="GET,HEAD" path="*" type="System.Web.StaticFileHandler" />
            
<add verb="*" path="*" type="System.Web.HttpMethodNotAllowedHandler" />
        
</httpHandlers>

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

Reference:
A low-level Look at the ASP.NET Architecture

ASP.NET Process Model
[原创]ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI
[原创]ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline - Part I
[原创]ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline - Part II 

posted on 2007-09-13 02:15 Artech 阅读(5445) 评论(27)  编辑 收藏 网摘 所属分类: D. ASP.NET

评论

#1楼 2007-09-13 09:51 Clark Zheng      

专业!   回复  引用  查看    

#2楼[楼主] 2007-09-13 09:53 Artech      

@Clark Zheng
^_^
  回复  引用  查看    

#3楼 2007-09-13 09:55 appledou      

很期待对IIS7做个分析~~   回复  引用  查看    

#4楼[楼主] 2007-09-13 09:57 Artech      

--引用--------------------------------------------------
appledou: 很期待对IIS7做个分析~~
--------------------------------------------------------
IIS7变动太大了,得花一阵子去好好研究才行;)
  回复  引用  查看    

#5楼 2007-09-13 11:11 appledou      

经典在于质量不在于数量   回复  引用  查看    

#6楼 2007-09-19 15:40 不错[未注册用户]

文章写的非常好,不过不得不说错别字和语病实在太多了。。。   回复  引用    

#7楼[楼主] 2007-09-19 17:13 Artech      

@不错
写好了没检查过,但愿不影响阅读。
  回复  引用  查看    

#8楼 2007-09-21 17:17 hackace[未注册用户]

已达MVP水准,鉴定完毕!   回复  引用    

#9楼 2007-09-24 10:29 xiongjianwen[未注册用户]

楼主我还想问你一个问题
asp.net到底是一个什么样的东西?
是一个com 还是一个其它的什么的....
  回复  引用    

#10楼[楼主] 2007-09-27 00:05 Artech      

@hackace
你的标准很低嘛^_^
  回复  引用  查看    

#11楼[楼主] 2007-09-27 00:08 Artech      

@xiongjianwen
这个还真不好说,可以理解为处理基于ASP.NET HttpRequest,生成所需的Http Response 的管道。
  回复  引用  查看    

#12楼 2007-09-27 11:21 xiongjianwen[未注册用户]

谢谢楼主的回答,有很多东西不理解,只知道表面.....
还想请教你一个问题.
在创建一个派生类的对象时,会不会创建它基类的类型对象呢??
比如
public class A:object
{}
A a=new A();
会创建object的类型对象吗?
  回复  引用    

#13楼[楼主] 2007-09-27 15:18 Artech      

@xiongjianwen
调用A()的时候会调用Object的Constructor,你可以通过IL很清楚看到这点:IL_0001: call instance void [mscorlib]System.Object::.ctor()

.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
{
// Code size 7 (0x7)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.Object::.ctor()
IL_0006: ret
} // end of method A::.ctor
  回复  引用  查看    

#14楼 2007-11-28 12:45 蛙蛙池塘      

我的一个服务ASP.NET APP v2.0\request excuting总是在一个固定的值降不下来,这正常吗?抓dump,看到当时并没有线程执行不下去呀。   回复  引用  查看    

#15楼 2008-08-27 09:28 allan123      

学习了 , 总的来说写的不错 , 除了一些错别字外.....
希望楼主继续这个专题直到大白asp.net于天下

HttpContext context = new HttpContext(wr, false);
IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);


这里的IHttpHandler应该是HttpApplication吧 ????



  回复  引用  查看    

#16楼[楼主] 2008-08-27 09:36 Artech      

@allan123
HttpApplicationFactory.GetApplicationInstance返回的就是IHandler, 有点奇怪,不过就是这样:)
  回复  引用  查看    

#17楼 2008-12-24 16:34 武汉-法子[未注册用户]

我有有点不明白,ASP.NET Application, Application和HttpApplication
指的是什么?
ASP.NET Application = Application
ApplicationPool 中放的就是Application,
Application 就是httpapplication 不?
但有点问题就是Application 在非托管环境中,
httpapplication在托管环境中,能否详细楼主?
谢谢!
  回复  引用    

#18楼 2009-04-11 20:14 sq[未注册用户]

这篇文章是我看过最专业、最通俗的描述整个HTTP请求的过程的文章,请继续最好再出个详细的HttpHandler的描述!!!!!   回复  引用    

#19楼[楼主] 2009-04-13 08:26 Artech      

--引用--------------------------------------------------
sq: 这篇文章是我看过最专业、最通俗的描述整个HTTP请求的过程的文章,请继续最好再出个详细的HttpHandler的描述!!!!!
--------------------------------------------------------
HttpHandler是最简单,也是最复杂的对象。说它复杂是因为像基于.aspx Page, asmx web service, .svc WCF service这样的IHttpHandler的实现相对复杂;说它简单是因为IHttpHandler接口定义很简单,你可以自定义一些很简单的IHttpHandler。
  回复  引用  查看    

#20楼 2009-04-15 02:12 sq[未注册用户]

是的,毕竟我们接收的请求主要是通过这个接口的实现去处理的,处理得方式是多种多样的   回复  引用    

#21楼 2009-05-19 12:48 shewea[未注册用户]

你好,我学asp.net有段时间了,还是有很多东西不懂,如果你有空请帮我解答一下,谢谢。我的问题有如下这些:asp.net涉及到这么多类:httpRuntime,httpApplication,httpSession...它们之间的关系是怎么样的?就是说是包含与被包含???还是并列的,只是从这个类的结果传到下一个类???还有HTTP很重要的一个特征是“无状态性”,请问这些类是如何工作来体现这个特征的???还有客户端的问题:哪些类是所有客户端可以访问的,不知道访问这个词合不合适,哪些类是私有的,就是说一个特定的客户端只能访问,其他的客户端不能访问???如果条件允许,希望你能发到我的邮箱,谢谢...   回复  引用    

#22楼 2009-05-30 10:25 酱板猪      

每次看楼主的文章都收获颇丰...
谢谢楼主..
如果能有IIS7的分析,那就更好了.
  回复  引用  查看    

#23楼[楼主] 2009-05-30 14:32 Artech      

--引用--------------------------------------------------
酱板猪: 每次看楼主的文章都收获颇丰...
谢谢楼主..
如果能有IIS7的分析,那就更好了.
--------------------------------------------------------
IIS 7稍微复杂一点,过几天发!
  回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 891266




相关文章:

相关链接: