二、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 Variable和Request Parameter通过它传入ASP.NET作为进一步处理的依据,ASP.NET最后生成的Response通过它传递给ISAPI,并进一步传递给IIS最终返回到Client端。
借助这个传进来的ECB Pointer,我们创建了一个ISAPIWorkerRequest。ISAPIWorkerRequest作为参数传入HttpRuntime.ProcessRequestNoDemand的调用。HttpRuntime.ProcessRequestNoDemand最终体现在调用ProcessRequestInternal。下面是真个方法的实现:
ProcessRequestInternal
<!--<br />
<br />
Code highlighting produced by Actipro CodeHighlighter (freeware)<br />
http://www.CodeHighlighter.com/<br />
<br />
-->privatevoidProcessRequestInternal(HttpWorkerRequestwr)
{
HttpContextcontext;
try
{
context=newHttpContext(wr,false);
}
catch
{
wr.SendStatus(400,"BadRequest");
wr.SendKnownResponseHeader(12,"text/html;charset=utf-8");
byte[]bytes=Encoding.ASCII.GetBytes("<html><body>BadRequest</body></html>");
wr.SendResponseFromMemory(bytes,bytes.Length);
wr.FlushResponse(true);
wr.EndOfRequest();
return;
}
wr.SetEndOfSendNotification(this._asyncEndOfSendCallback,context);
Interlocked.Increment(refthis._activeRequestCount);
HostingEnvironment.IncrementBusyCount();
try
{
try
{
this.EnsureFirstRequestInit(context);
}
catch
{
if(!context.Request.IsDebuggingRequest)
{
throw;
}
}
context.Response.InitResponseWriter();
IHttpHandlerapplicationInstance=HttpApplicationFactory.GetApplicationInstance(context);
if(applicationInstance==null)
{
thrownewHttpException(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(applicationInstanceisIHttpAsyncHandler)
{
IHttpAsyncHandlerhandler2=(IHttpAsyncHandler)applicationInstance;
context.AsyncAppHandler=handler2;
handler2.BeginProcessRequest(context,this._handlerCompletionCallback,context);
}
else
{
applicationInstance.ProcessRequest(context);
this.FinishRequest(context.WorkerRequest,context,null);
}
}
catch(Exceptionexception)
{
context.Response.InitResponseWriter();
this.FinishRequest(wr,context,exception);
}
}
对象上面的代码没有必要深究,我们只需要了解大体的执行流程就可以了,下面这一段伪代码基本上体现整个执行过程:
HttpContextcontext=newHttpContext(wr,false);
IHttpHandlerapplicationInstance=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中。
2. 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并存的现象。
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)]
publicinterfaceIHttpModule
{
//Methods
voidDispose();
voidInit(HttpApplicationcontext);
}
我们只要在Init方法中注册相应的HttpApplication Event Handler就可以了:
publicclassBasicAuthCustomModule:IHttpModule
{
publicvoidInit(HttpApplicationapplication)
{
application.AuthenticateRequest+=
newEventHandler(this.OnAuthenticateRequest);
}
publicvoidDispose(){}
publicvoidOnAuthenticateRequest(objectsource,EventArgseventArgs)
{
}
}
所有的HttpModule同machine.config或者Web.config的httpModules Section定义,下面是Machine.config定义的所有httpModule。
<httpModules>
<addname="OutputCache"type="System.Web.Caching.OutputCacheModule"/>
<addname="Session"type="System.Web.SessionState.SessionStateModule"/>
<addname="WindowsAuthentication"type="System.Web.Security.WindowsAuthenticationModule"/>
<addname="FormsAuthentication"type="System.Web.Security.FormsAuthenticationModule"/>
<addname="PassportAuthentication"type="System.Web.Security.PassportAuthenticationModule"/>
<addname="UrlAuthorization"type="System.Web.Security.UrlAuthorizationModule"/>
<addname="FileAuthorization"type="System.Web.Security.FileAuthorizationModule"/>
<addname="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方法。下面是其实现:
privatevoidInitModules()
{
this._moduleCollection=RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
this.InitModulesCommon();
}
privatevoidInitModulesCommon()
{
intcount=this._moduleCollection.Count;
for(inti=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中的定义。
相关推荐
ASP.NET Core 1.1 For Beginners: How to Build a MVC Website by Jonas Fagerberg English | 19 May 2017 | ASIN: B071VX7KN4 | 411 Pages | PDF | 6.66 MB Want to learn how to build ASP.NET Core 1.1 MVC Web ...
资源分类:Python库 所属语言:Python 资源全名:elyra-pipeline-editor-extension-3.6.0rc0.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
Practical ASP.NET Web API,基于dotnetfx4.5。 Chapter 1: Building a Basic Web API Chapter 2: Debugging and Tracing Chapter 3: Media-Type Formatting CLR Objects Chapter 4: Customizing Response Chapter 5...
ASP.NET MVC Pipeline
资源分类:Python库 所属语言:Python 资源全名:cli_pipeline-1.5.234-py2.py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:watchmen-pipeline-surface-16.0.20.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:cdk-pipeline-status-0.0.22.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:pyannote.pipeline-1.1-py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:tanbih-pipeline-0.7.0.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:outsystems-pipeline-0.2.12.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:network-pipeline-1.0.15.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:django-pipeline-1.5.1.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:cli-pipeline-1.5.10.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:cli-pipeline-1.5.2.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:segmentation_pipeline-0.26-py2.py3-none-any.whl 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
jenkins-pipeline-library:具有针对CICD环境的通用功能的Jenkins管道库,主要用于实现https:indigo-dc.github.iosqa-baseline的SQA基线要求的实现
资源分类:Python库 所属语言:Python 资源全名:users_pipeline-0.2.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:streamcorpus_pipeline-0.5.0.tar.gz 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
资源分类:Python库 所属语言:Python 资源全名:streamcorpus_pipeline-0.4.5.dev5-py2.7.egg 资源来源:官方 安装方法:https://lanzao.blog.csdn.net/article/details/101784059
python库,解压后可用。 资源全名:ts_forecasting_pipeline-0.3.3-py2.py3-none-any.whl