来源:http://www.cnblogs.com/firstyi
在我的上一篇文章中说到了HttpModule、HttpHandle的简单使用,我们可以利用它们在页面请求的过程中加入自己的事件处理程序。那么在一个aspx页面请求时后台到底做了什么?当然asp.net做了很多事情,过程也比较复杂,本文主要分析一下大体的流程。总体流程如下:
请求一个页面时首先被WWW服务截获(inetinfo.exe进程),这个进程首先判断页面的后缀,然后根据IIS中的配置来决定调用哪个扩展程序,比如aspx的页面就会调用c:/windows/microsoft.net/framework/v2.0.50727/aspnet_isapi.dll,aspnet_isapi.dll将请求发送给w3wp.exe进程(我们在调试IIS中网站时就是把VS2005附加到这个进程上的)。
接下来w3wp.exe进程就会调用.net类库进行具体处理:
ISAPIRuntime-->HttpRuntime-->HttpApplicationFactory-->HttpApplication-->HttpModule--HttpHandlerFactory-->HttpHandler 这也是本文主要分析的地方。
下面只是列出主要流程,如果喜欢钻研的同学可以用Reflector去查看
一:ISAPIRuntime
bool
useOOP
=
iWRType
==
1
;
wr
=
ISAPIWorkerRequest.CreateWorkerRequest(ecb, useOOP);
wr.Initialize();
string
appPathTranslated
=
wr.GetAppPathTranslated();
string
appDomainAppPathInternal
=
HttpRuntime.AppDomainAppPathInternal;
if
((appDomainAppPathInternal
==
null
)
||
StringUtil.EqualsIgnoreCase(appPathTranslated, appDomainAppPathInternal))
{
HttpRuntime.ProcessRequestNoDemand(wr);
return
0
;
}
HttpRuntime.ShutdownAppDomain(ApplicationShutdownReason.PhysicalApplicationPathChanged, SR.GetString(
"
Hosting_Phys_Path_Changed
"
,
new
object
[] { appDomainAppPathInternal, appPathTranslated }));
return
1
;
它的主要作用是调用一些非托管代码生成HttpWorkerRequest对象,该对象包含当前请求的所有信息,然后传递给HttpRuntime,这里生成的HttpWorkerRequest对象可以直接在我们的页面中调用的,通过它取得原始的请求信息:
IServiceProvider provider =
(IServiceProvider)HttpContext.Current;
HttpWorkerRequest wr = (HttpWorkerRequest)provider.GetService(typeof
(HttpWorkerRequest));
二:HttpRuntime
最主要的就是private void ProcessRequestInternal(HttpWorkerRequest wr)方法:
context = new HttpContext(wr, false
);
IHttpHandler applicationInstance =
HttpApplicationFactory.GetApplicationInstance(context);
IHttpAsyncHandler handler2 =
(IHttpAsyncHandler) applicationInstance;
context.AsyncAppHandler =
handler2;
handler2.BeginProcessRequest(context, this
._handlerCompletionCallback, context);
1、根据HttpWorkerRequest对象生成HttpContext,HttpContext应该大家都很熟悉的,它包含request、response等属性,在页面中经常会用到的;
2、调用HttpApplicationFactory来生成IHttpHandler(这里生成的是一个默认的HttpApplication对象,HttpApplication也是IHttpHandler接口的一个实现)
3、调用HttpApplication对象执行请求
三:HttpApplicationFactory
正如2.2中所提到的,这里主要是生成一个HttpApplication对象:
internal static string
GetApplicationFile()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
return Path.Combine(HttpRuntime.AppDomainAppPathInternal, "global.asax");
}
首先会查看是否存在global.asax文件,如果有的话就用它来生成HttpApplication对象,从这里我们可以看到global.asax的文件名是在asp.net的框架中写死的,不能修改的。如果这个文件不存在就使用默认的对象。
创建好HttpApplication之后对它进行初始化:
application
=
(HttpApplication) HttpRuntime.CreateNonPublicInstance(
this
._theApplicationType);
using
(ApplicationImpersonationContext context2
=
new
ApplicationImpersonationContext())
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
application.InitInternal(context, this._state, this._eventHandlerMethods);
}
四、HttpApplication
这个是比较复杂也比较重要的一个对象
首先是执行初始化操作,比较重要的一步就是进行HttpModule的初始化:
private
void
InitModules()
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this._moduleCollection = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
this.InitModulesCommon();
}
它会读取web.config中所有HttpModule的配置
在HookupEventHandlersForApplicationAndModules方法中绑定Module的事件处理程序
接着进行事件实际绑定:
if
(HttpRuntime.UseIntegratedPipeline)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this._stepManager = new PipelineStepManager(this);
}
else
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this._stepManager = new ApplicationStepManager(this);
}
this
._stepManager.BuildSteps(
this
._resumeStepsWaitCallback);
在ApplicationStepManager的BuildSteps方法中可以看到事件的绑定执行顺序:
app.CreateEventExecutionSteps(HttpApplication.EventBeginRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAuthenticateRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventDefaultAuthentication, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAuthenticateRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAuthorizeRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAuthorizeRequest, steps);
app.CreateEventExecutionSteps(HttpApplication.EventResolveRequestCache, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostResolveRequestCache, steps);
steps.Add(
new
HttpApplication.MapHandlerExecutionStep(app));
app.CreateEventExecutionSteps(HttpApplication.EventPostMapRequestHandler, steps);
app.CreateEventExecutionSteps(HttpApplication.EventAcquireRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostAcquireRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPreRequestHandlerExecute, steps);
steps.Add(
new
HttpApplication.CallHandlerExecutionStep(app));
app.CreateEventExecutionSteps(HttpApplication.EventPostRequestHandlerExecute, steps);
app.CreateEventExecutionSteps(HttpApplication.EventReleaseRequestState, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostReleaseRequestState, steps);
steps.Add(
new
HttpApplication.CallFilterExecutionStep(app));
app.CreateEventExecutionSteps(HttpApplication.EventUpdateRequestCache, steps);
app.CreateEventExecutionSteps(HttpApplication.EventPostUpdateRequestCache, steps);
this
._endRequestStepIndex
=
steps.Count;
app.CreateEventExecutionSteps(HttpApplication.EventEndRequest, steps);
steps.Add(
new
HttpApplication.NoopExecutionStep());
注意上面红色标注的MapHandlerExecutionStep(读取所有的HttpHandler配置)、CallHandlerExecutionStep就是对Handle程序进行处理的,也就是说在web.config中配置的HttpHandler都是在这里进行处理的,执行顺序如上所示
然后就是调用2.3中的方法执行请求:
IAsyncResult IHttpAsyncHandler.BeginProcessRequest(HttpContext context, AsyncCallback cb,
object
extraData)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
this._context = context;
this._context.ApplicationInstance = this;
this._stepManager.InitRequest();
this._context.Root();
HttpAsyncResult result = new HttpAsyncResult(cb, extraData);
this.AsyncResult = result;
if (this._context.TraceIsEnabled)
![](https://i-blog.csdnimg.cn/blog_migrate/37c8bf68cdc3cc81759c34160776bc53.gif)
...{
HttpRuntime.Profile.StartRequest(this._context);
}
this.ResumeSteps(null);
return result;
}
五、HttpModule
在系统web.config中默认的配置有:
基本使用方法可以参见我的上一篇文章
<
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
="RoleManager"
type
="System.Web.Security.RoleManagerModule"
/>
<
add
name
="UrlAuthorization"
type
="System.Web.Security.UrlAuthorizationModule"
/>
<
add
name
="FileAuthorization"
type
="System.Web.Security.FileAuthorizationModule"
/>
<
add
name
="AnonymousIdentification"
type
="System.Web.Security.AnonymousIdentificationModule"
/>
<
add
name
="Profile"
type
="System.Web.Profile.ProfileModule"
/>
<
add
name
="ErrorHandlerModule"
type
="System.Web.Mobile.ErrorHandlerModule, System.Web.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"
/>
<
add
name
="ServiceModel"
type
="System.ServiceModel.Activation.HttpModule, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</
httpModules
>
六、HttpHandlerFactory、HttpHandler
这两个对象在web.config中的配置方法是相同的,默认配置有:
<add path="*.rules" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="true"/>
<add path="WebResource.axd" verb="GET" type="System.Web.Handlers.AssemblyResourceLoader" validate="true"/>
<add path="*.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="true"/>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="true"/>
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="true"/>
<add path="*.asmx" verb="*" type="System.Web.Services.Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" validate="false"/>
<add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.browser" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="true"/>
<add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler" validate="true"/>
<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.csproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.vb" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.vbproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.webinfo" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.licx" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.resx" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.resources" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.mdb" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.vjsproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.java" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.jsl" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.ldb" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.ad" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.dd" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.ldd" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.sd" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.cd" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.adprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.lddprototype" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.sdm" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.sdmDocument" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.mdf" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.ldf" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.exclude" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.refresh" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"/>
<add path="*.svc" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false"/>
<add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="true"/>
<add path="*" verb="*" type="System.Web.HttpMethodNotAllowedHandler" validate="true"/>
</httpHandlers>
要注意的是相同的后缀名配置多次的话,后面的配置会把前面的覆盖。
这里我们重点看一下aspx的配置:System.Web.UI.PageHandlerFactory
这是一个HttpHandlerFactory对象,根据不同的Page生成不同的HttpHandler对象(我们自己的Page页面都是一个IHttpHandler):
Page page
=
BuildManager.CreateInstanceFromVirtualPath(virtualPath,
typeof
(Page), context,
true
,
true
)
as
Page;
if
(page
==
null
)
![](https://i-blog.csdnimg.cn/blog_migrate/a41954a27d6ad96fa2c2cf816e677448.gif)
...
{
return null;
}
page.TemplateControlVirtualPath
=
virtualPath;
return
page;
这里会调用web.config中的buildProviders配置编译页面:
<
buildProviders
>
<
add
extension
=".aspx"
type
="System.Web.Compilation.PageBuildProvider"
/>
<
add
extension
=".ascx"
type
="System.Web.Compilation.UserControlBuildProvider"
/>
<
add
extension
=".master"
type
="System.Web.Compilation.MasterPageBuildProvider"
/>
<
add
extension
=".asmx"
type
="System.Web.Compilation.WebServiceBuildProvider"
/>
<
add
extension
=".ashx"
type
="System.Web.Compilation.WebHandlerBuildProvider"
/>
<
add
extension
=".soap"
type
="System.Web.Compilation.WebServiceBuildProvider"
/>
<
add
extension
=".resx"
type
="System.Web.Compilation.ResXBuildProvider"
/>
<
add
extension
=".resources"
type
="System.Web.Compilation.ResourcesBuildProvider"
/>
<
add
extension
=".wsdl"
type
="System.Web.Compilation.WsdlBuildProvider"
/>
<
add
extension
=".xsd"
type
="System.Web.Compilation.XsdBuildProvider"
/>
<
add
extension
=".js"
type
="System.Web.Compilation.ForceCopyBuildProvider"
/>
<
add
extension
=".lic"
type
="System.Web.Compilation.IgnoreFileBuildProvider"
/>
<
add
extension
=".licx"
type
="System.Web.Compilation.IgnoreFileBuildProvider"
/>
<
add
extension
=".exclude"
type
="System.Web.Compilation.IgnoreFileBuildProvider"
/>
<
add
extension
=".refresh"
type
="System.Web.Compilation.IgnoreFileBuildProvider"
/>
<
add
extension
=".xoml"
type
="System.ServiceModel.Activation.WorkflowServiceBuildProvider, System.WorkflowServices, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"
/>
<
add
extension
=".svc"
type
="System.ServiceModel.Activation.ServiceBuildProvider, System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
/>
</
buildProviders
>
这样就可以进入我们的Page执行了,大的执行顺序可以参见第四部分的描述,它也就是一个HttpHandler.
在ResumeSteps中就是执行事件处理程序。