ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇]

  ASP.NET Process Model索引

ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[上篇] ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇]

  二、ASP.NET Runtime Pipeline

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

  HttpContext

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

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

ProcessRequestInternal

private void ProcessRequestInternal(HttpWorkerRequest wr)

{

HttpContext context;

try

{

context = new HttpContext(wr, false);

}

catch

{

wr.SendStatus(400, "Bad Request");

wr.SendKnownResponseHeader(12, "text/html; charset=utf-8");

byte[] bytes = Encoding.ASCII.GetBytes("<html><body>Bad Request</body></html>");

wr.SendResponseFromMemory(bytes, bytes.Length);

wr.FlushResponse(true);

wr.EndOfRequest();

return;

}

wr.SetEndOfSendNotification(this._asyncEndOfSendCallback, context);

Interlocked.Increment(ref this._activeRequestCount);

HostingEnvironment.IncrementBusyCount();

try

{

try

{

this.EnsureFirstRequestInit(context);

}

catch

{

if (!context.Request.IsDebuggingRequest)

{

throw;

}

}

context.Response.InitResponseWriter();

IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);

if (applicationInstance == null)

{

throw new HttpException(SR.GetString("Unable_create_app_object"));

}

if (EtwTrace.IsTraceEnabled(5, 1))

{

EtwTrace.Trace(EtwTraceType.ETW_TYPE_START_HANDLER, context.WorkerRequest, applicationInstance.GetType().FullName, "Start");

}

if (applicationInstance is IHttpAsyncHandler)

{

IHttpAsyncHandler handler2 = (IHttpAsyncHandler) applicationInstance;

context.AsyncAppHandler = handler2;

handler2.BeginProcessRequest(context, this._handlerCompletionCallback, context);

}

else

{

applicationInstance.ProcessRequest(context);

this.FinishRequest(context.WorkerRequest, context, null);

}

}

catch (Exception exception)

{

context.Response.InitResponseWriter();

this.FinishRequest(wr, context, exception);

}

}

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

HttpContext context = new HttpContext(wr, false);

IHttpHandler applicationInstance = HttpApplicationFactory.GetApplicationInstance(context);

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

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

  HttpApplication

  就像其名称体现的一样,HttpApplication基本上可以看成是真个ASP.NET Application的体现。HttpApplication和置于虚拟根目录的Gloabal.asax对应。通过HttpApplicationFactory.GetApplicationInstance创建一个基于Gloabal.asax的HttpApplication对象。在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对象呢?答案是否定的。

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

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

  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)

{

}

}

  所有的HttpModule同machine.config或者Web.config的httpModules 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中,最后依次调用每个HttpModule的Init方法。下面是其实现:

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 Resource的Request。比如一个.apsx的Web 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

时间: 2024-07-30 09:59:31

ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇]的相关文章

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作为参数传递给了Process

一起谈.NET技术,ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇]

ASP.NET Process Model索引 ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[上篇] ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇] 二.ASP.NET Runtime Pipeline 现在我们真正进入ASP.NET管辖的范畴,下图基本上囊括整个处理过程涉及的对象

ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[上篇]

ASP.NET Process Model索引 ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[上篇] ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇] 相信大家都使用过ASP.NET进行过基于Web的应用开发,ASP.NET是什么?如果站在一个相对High Level的角度,我们可以

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

ASP.NET Process Model索引 ASP.NET Process Model之一:IIS 和 ASP.NET ISAPI ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[上篇] ASP.NET Process Model之二:ASP.NET Http Runtime Pipeline[下篇] 前几天有一个朋友在MSN上问我"ASP.NET 从最初的接收到Http request到最终生成Response的整个流程到底是怎样

ASP.NET Process Model之一 IIS 和 ASP.NET ISAPI_win服务器

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

ASP中 process的using指令集是什么?

问题描述 ASP中process的using指令集是什么? 解决方案 解决方案二:1.我怀疑你说的是ASP.Net2.你应该查MSDN.这次我先帮你查,下回你自己查:解决方案三:多谢多谢,问题已解决~~解决方案四:引用1楼xinyaping的回复: 1.我怀疑你说的是ASP.Net2.你应该查MSDN.这次我先帮你查,下回你自己查:http://msdn.microsoft.com/en-us/library/system.diagnostics.process.aspx 应该是,System.

七天学会ASP.NET MVC (二)——ASP.NET MVC 数据传递

通过第一天的学习之后,我们相信您已经对MVC有一些基本了解. 本节所讲的内容是在上节的基础之上,因此需要确保您是否掌握了上一节的内容.本章的目标是在今天学习结束时利用最佳实践解决方案创建一个小型的MVC项目,本节的主要目标是了解MVC之间的数据传递问题.我们会逐步深入讲解,并添加新功能,使项目越来越完善. 系列文章 七天学会ASP.NET MVC (一)--深入理解ASP.NET MVC 七天学会ASP.NET MVC (二)--ASP.NET MVC 数据传递 七天学会ASP.NET MVC

搭建你的Spring.Net+Nhibernate+Asp.Net Mvc 框架 (二)创建你的项目

本篇文章的目的:首先是创建解决方案.并创建相关的项目.先介绍一下项目的各自的作用: 从数据库层到表示层依次为: 数据库层:        1.接口IDao层:IDao        2.Dao层实现:HibernateDao和SqlDao             HibernateDao:由Hibernate实现的IDao部分             SqlDao:是由我们自己写sql实现的部分 业务逻辑层:        1.业务逻辑接口层:IBLL        2.业务逻辑接口的实现:BL

ASP与JSP的比较(二)

js|比较|js ASP与JSP的比较(二) 五.ServerSideIncludes 在服务器端引用上ASP和JSP有着相同之处.ASP和JSP都可以支持此功能的服务器(IIS,APACHE)上实现服务器端包含虚文件.但JSP是将动态页面的结果包含进来,而不是包含文件的代码本身.当你包含的文件在另一个服务器上时,不包含任何代码和对象是一个非常有效的功能. ASP: JSP:<%@includefile="subfile.jsp"--> 六.JAVA组件:JavaBeans