上一篇博文《ASP.NET那点不为人知的事(一)》中我们提到HttpApplication有19个标准事件,在HttpApplication的第8个事件PostMapRequestHandlerExcute触发的时候,标志着已经获取了处理当前请求的处理程序对象,在第11个事件PreRequestHandlerExcute之后,HttpApplication将执行这个处理程序,接下来我们继续讨论以下话题:
HttpContext状态管理 什么是HttpContext状态管理 HttpContext通过属性User和Handler传递了当前请求的用户和处理请求所使用的处理程序。如果我们还需要从HttpApplication 前面的事件向后面的事件处理程序传递一些参数,我们可以通过HttpContext的Items属性来完成,用Reflect查看可知这是一个字典:
public IDictionary Items
{
get
{
if (this._items == null)
{
this._items = new Hashtable();
}
return this._items;
}
}
由于HttpContext对象贯穿了整个HttpApplication的管道事件的处理过程,所以,根据Items这个属性,从处理过程的前面阶段将数据传递给后面的处理过程。所以这种传递参数的方式称为基于HttpContext的状态管理。 处理HttpApplication的事件 有必要再回顾一下HttpApplication的19个管道事件。
HttpApplication提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程的扩展。 由于HttpApplication对象是由ASP.NETt基础架构来创建和维护的,那么如何才能获取这个对象的引用呢,以便于注册HttpApplication对象的事件?我们可以通过IHttpModule来创建HttpApplication的事件处理程序。
public interface IHttpModule
{
// Methods
void Dispose();
void Init(HttpApplication context);
}
实现了IHttpModule接口的类称为HttpModule。 IHttpModule接口中的Init方法,接受一个HttpApplicaton类型的参数。在ASP.NET中,每当创建一个HttpApplication对象实例,将遍历注册的HttpModule类型,通过反射,依次创建每个注册HttpModule类型的一个对象,并将这个HttpApplication实例通过Init方法传递给各个HttpModule,这个HttpModule就可以再第一时间完成针对HttpApplication对象的事件注册了。 常见的HttpModule 在ASP.NET中已经预定了许多HttpModule,已经在服务器的网站配置文件(C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\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=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" />
<add name="ScriptModule-4.0" type="System.Web.Handlers.ScriptModule, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35"/>
</httpModules>
根据前一篇文章分析,我们再来回顾一下HttpModule是怎样注册HttpApplication的事件的:
internal void InitInternal(HttpContext context, HttpApplicationState state, MethodInfo[] handlers)
{
this._state = state;
PerfCounters.IncrementCounter(AppPerfCounter.PIPELINES);
try
{
try
{
this._initContext = context;
this._initContext.ApplicationInstance = this;
//是在这儿初始化吗?我猜的( ⊙ o ⊙ )
context.ConfigurationPath = context.Request.ApplicationPathObject;
..... }
点击查看ApplicationInstance: public HttpApplication ApplicationInstance
{
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
get
{
return this._appInstance;
}
set
{
if ((this._isIntegratedPipeline && (this._appInstance != null)) && (value != null))
{
throw new InvalidOperationException(SR.GetString("Application_instance_cannot_be_changed"));
}
this._appInstance =value;
}
}
点击查看_appInstance 是什么类型
private HttpApplication _appInstance;
private void InitModules()
{
HttpModuleCollection modules = RuntimeConfig.GetAppConfig().HttpModules.CreateModules();
HttpModuleCollection other = this.CreateDynamicModules();
modules.AppendCollection(other);
this._moduleCollection = modules;
this.InitModulesCommon();
}
[PermissionSet(SecurityAction.Assert, Unrestricted=true)]
internal static object CreateNonPublicInstance(Type type, object[] args)
{
return Activator.CreateInstance(type, BindingFlags.CreateInstance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance, null, args, null);
}
if (HttpRuntime.UseIntegratedPipeline)
{
this._stepManager = new PipelineStepManager(this);
}
else
{
this._stepManager = new ApplicationStepManager(this);
}
this._stepManager.BuildSteps(this._resumeStepsWaitCallback);
}
......
internal override void BuildSteps(WaitCallback stepCallback)
{
......
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(app.CreateImplicitAsyncPreloadExecutionStep());
steps.Add(newHttpApplication.CallHandlerExecutionStep(app));
//---------------------->用于创建处理用户请求的对象(Handler)
......
}
了解了HttpModule对HttpApplication对象的事件注册后,我们再来分析一下:
接下来我们再一一分析下:
处理程序工厂 处理程序工厂(实现IHttpHandlerFactory接口)的优点:因为我们知道,实现了处理程序接口的类就可以被用来创建处理程序对象直接使用,如果需要对处理程序对象进行管理,例如:我们可以创建一个处理程序对象池,就可以不用再每次使用处理程序的时候创建一个新的对象,而是直接可以从池中取一个现有的对象直接使用,提高效率。 常见的处理程序工厂:
internal class SimpleHandlerFactory : IHttpHandlerFactory2, IHttpHandlerFactory
{
// Methods
[TargetedPatchingOptOut("Performance critical to inline this type of method across NGen image boundaries")]
internal SimpleHandlerFactory();
public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path);
public virtual void ReleaseHandler(IHttpHandler handler);
IHttpHandler IHttpHandlerFactory2.GetHandler(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath);
}
可以通过GetHandler方法来从这个处理程序工厂获得一个处理程序对象实例。通过配置文件,对于扩展名为ashx的请求是通过SimpleHandlerFactory处理程序工厂完成的,当请求一个ashx扩展名的服务器上资源时,SimpleHandlerFactory将找到对应的ashx文件,通过这个文件找到对应的处理程序。最后,SimpleHandlerFactory通过反射创建一个此类型处理程序对象实例
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="True" />
页面处理程序工厂:PageHandlerFactory(重点)
[PermissionSet(SecurityAction.InheritanceDemand, Unrestricted=true), PermissionSet(SecurityAction.LinkDemand, Unrestricted=true)]
public class PageHandlerFactory : IHttpHandlerFactory2, IHttpHandlerFactory
{
// Fields
private bool _isInheritedInstance;
// Methods
protected internal PageHandlerFactory();
public virtual IHttpHandler GetHandler(HttpContext context, string requestType, string virtualPath, string path);
private IHttpHandler GetHandlerHelper(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath);
public virtual void ReleaseHandler(IHttpHandler handler);
IHttpHandler IHttpHandlerFactory2.GetHandler(HttpContext context, string requestType, VirtualPath virtualPath, string physicalPath);
}
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="True" />
public sealed class PageParser : TemplateControlParser
{
......
public static IHttpHandler GetCompiledPageInstance(string virtualPath, string inputFile, HttpContext context);
......
}
[SecurityPermission(SecurityAction.Demand, Unrestricted=true)]
public static IHttpHandler GetCompiledPageInstance(string virtualPath, string inputFile, HttpContext context)
{
if (!string.IsNullOrEmpty(inputFile))
{
inputFile = Path.GetFullPath(inputFile);
}
return GetCompiledPageInstance(VirtualPath.Create(virtualPath), inputFile, context);
}
private static IHttpHandler GetCompiledPageInstance(VirtualPath virtualPath, string inputFile, HttpContext context)
{
IHttpHandler handler;
.......
BuildResultCompiledType type = (BuildResultCompiledType) BuildManager.GetVPathBuildResult(context, virtualPath, false, true, true, true);
handler = (IHttpHandler) HttpRuntime.CreatePublicInstance(type.ResultType);
.......
return handler;
}
internal static BuildResult GetVPathBuildResult(HttpContext context, VirtualPath virtualPath, bool noBuild, bool allowCrossApp, bool allowBuildInPrecompile, [Optional, DefaultParameterValue(true)] bool ensureIsUpToDate)
{
if (HttpRuntime.IsFullTrust)
{
return GetVPathBuildResultWithNoAssert(context, virtualPath, noBuild, allowCrossApp, allowBuildInPrecompile, true, ensureIsUpToDate);
}
return GetVPathBuildResultWithAssert(context, virtualPath, noBuild, allowCrossApp, allowBuildInPrecompile, true, ensureIsUpToDate);
}
Reflect反编译网站看究竟
由上面分析得知,下面是一个合并的类:
下面这个类派生自_Default类,最终通过反射创建实际的页面对象,它实现了IHttpHandler接口,也就是一个处理程序HttpHandler,所以页面毫无疑问也是一个处理程序
我们可以看到default_aspx里面主要是初始化了控件树(BuildControlTree)和ProcessRequest方法启动页面生成过程。
页面的事件处理管道 页面对象的ProcessRequest方法将会启动页面的生成过程,这个过程是通过页面的事件处理管道来完成,在处理过程中页面对象将会依次触发一系列事件。
总结 未完,待续。