翔如菲菲

其实天很蓝,阴云总会散;其实海不宽,此岸连彼岸.

导航

ASP.NET Http Runtime Pipeline II

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.LinkDemand, Level=AspNetHostingPermissionLevel.Minimal), AspNetHostingPermission(SecurityAction.InheritanceDemand, Level=AspNetHostingPermissionLevel.Minimal)]
public interface IHttpModule
{
    
// Methods
    void Dispose();
    
void Init(HttpApplication context);
}

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

 ASP.NET路由Module的实现:

public class UrlRoutingModule : IHttpModule
{
    
// Fields
    private static readonly object _contextKey = new object();
    
private static readonly object _requestDataKey = new object();
    
private RouteCollection _routeCollection;
    
// Methods
    protected virtual void Dispose()
    {
    }
    
protected virtual void Init(HttpApplication application)
    {
        
if (application.Context.Items[_contextKey] == null)
        {
            application.Context.Items[_contextKey] 
= _contextKey;
            application.PostResolveRequestCache 
+= new EventHandler(this.OnApplicationPostResolveRequestCache);//第七个事件
        }
    }
    
private void OnApplicationPostResolveRequestCache(object sender, EventArgs e)
    {
        HttpContextBase context 
= new HttpContextWrapper(((HttpApplication) sender).Context);
        
this.PostResolveRequestCache(context);
    }
    
public virtual void PostResolveRequestCache(HttpContextBase context)
    {
        RouteData routeData 
= this.RouteCollection.GetRouteData(context);
        
if (routeData != null)
        {
            IRouteHandler routeHandler 
= routeData.RouteHandler;
            
if (routeHandler == null)
            {
                
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoRouteHandler"), new object[0]));
            }
            
if (!(routeHandler is StopRoutingHandler))
            {
                RequestContext requestContext 
= new RequestContext(context, routeData);
                context.Request.RequestContext 
= requestContext;
                IHttpHandler httpHandler 
= routeHandler.GetHttpHandler(requestContext);
                
if (httpHandler == null)
                {
                    
throw new InvalidOperationException(string.Format(CultureInfo.CurrentUICulture, SR.GetString("UrlRoutingModule_NoHttpHandler"), new object[] { routeHandler.GetType() }));
                }
                
if (httpHandler is UrlAuthFailureHandler)
                {
                    
if (!FormsAuthenticationModule.FormsAuthRequired)
                    {
                        
throw new HttpException(0x191, SR.GetString("Assess_Denied_Description3"));
                    }
                    UrlAuthorizationModule.ReportUrlAuthorizationFailure(HttpContext.Current, 
this);
                }
                
else
                {
                    context.RemapHandler(httpHandler);
                }
            }
        }
    }
    
void IHttpModule.Dispose()
    {
        
this.Dispose();
    }
    
void IHttpModule.Init(HttpApplication application)
    {
        
this.Init(application);
    }
    
// Properties
    public RouteCollection RouteCollection
    {
        
get
        {
            
if (this._routeCollection == null)
            {
                
this._routeCollection = RouteTable.Routes;
            }
            
return this._routeCollection;
        }
        
set
        {
            
this._routeCollection = value;
        }
    }

HttpModule的实现:

internal class HttpModule : IHttpModule
{
    
// Fields
    private static bool disabled;

    
// Methods
    public void Dispose()
    {
    }

    [SecurityCritical]
    
public void Init(HttpApplication context)
    {
        context.PostAuthenticateRequest 
+= new EventHandler(HttpModule.ProcessRequest);//第5个事件
    }

    [SecurityCritical]
    
private static void ProcessRequest(object sender, EventArgs e)
    {
        
if (!disabled)
        {
            
try
            {
                ServiceHostingEnvironment.SafeEnsureInitialized();
            }
            
catch (SecurityException exception)
            {
                disabled 
= true;
                
if (DiagnosticUtility.ShouldTraceWarning)
                {
                    DiagnosticUtility.ExceptionUtility.TraceHandledException(exception, TraceEventType.Warning);
                }
                
return;
            }
            HttpApplication application 
= (HttpApplication) sender;
            
string currentExecutionFilePathExtension = application.Request.CurrentExecutionFilePathExtension;
            
if (!string.IsNullOrEmpty(currentExecutionFilePathExtension))
            {
                ServiceHostingEnvironment.ServiceType serviceType 
= ServiceHostingEnvironment.GetServiceType(currentExecutionFilePathExtension);
                
if (serviceType != ServiceHostingEnvironment.ServiceType.Unknown)
                {
                    
if (ServiceHostingEnvironment.AspNetCompatibilityEnabled)
                    {
                        
if ((serviceType == ServiceHostingEnvironment.ServiceType.Workflow) && ServiceHostingEnvironment.IsConfigurationBasedService(application))
                        {
                            application.Context.RemapHandler(
new HttpHandler());
                        }
                    }
                    
else
                    {
                        
switch (serviceType)
                        {
                            
case ServiceHostingEnvironment.ServiceType.WCF:
                                HostedHttpRequestAsyncResult.ExecuteSynchronous(application, 
falsefalse);
                                
return;

                            
case ServiceHostingEnvironment.ServiceType.Workflow:
                                HostedHttpRequestAsyncResult.ExecuteSynchronous(application, 
falsetrue);
                                
break;
                        }
                    }
                }
            }
        }
    }
}

所有的HttpModulemachine.config或者Web.confighttpModules Section定义,下面是Web.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="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如何起作用的,我们来回顾一下上面一节介绍的: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来定义,下面是Web.config中的定义。

        <httpHandlers>
            
<add path="eurl.axd" verb="*" type="System.Web.HttpNotFoundHandler" validate="True" />
            
<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 verb="*" path="*_AppService.axd" type="System.Web.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False" />
            
<add verb="GET,HEAD" path="ScriptResource.axd" type="System.Web.Handlers.ScriptResourceHandler, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            
<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.Script.Services.ScriptHandlerFactory, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False" />

            
<add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="False" />
            
<add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=4.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.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            
<add path="*.rules" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            
<add path="*.xoml" verb="*" type="System.ServiceModel.Activation.HttpHandler, System.ServiceModel.Activation, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>
            
<add path="*.xamlx" verb="*" type="System.Xaml.Hosting.XamlHttpHandlerFactory, System.Xaml.Hosting, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" validate="False"/>

            
<add path="*.aspq" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            
<add path="*.cshtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            
<add path="*.cshtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            
<add path="*.vbhtm" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            
<add path="*.vbhtml" verb="*" type="System.Web.HttpForbiddenHandler" validate="True"/>
            
<add path="*" verb="GET,HEAD,POST" type="System.Web.DefaultHttpHandler" validate="True" />
            
<add path="*" verb="*" type="System.Web.HttpMethodNotAllowedHandler" validate="True" />
        
</httpHandlers>

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

posted on 2011-08-26 09:37  翔如飞飞  阅读(272)  评论(0编辑  收藏  举报