HttpApplication处理对象与HttpModule处理模块 (第三篇)

一、HttpApplication对象简述

  在HttpRuntime创建了HttpContext对象之后,HttpRuntime将随后创建一个用于处理请求的对象,这个对象的类型为HttpApplication。

  HttpRuntime管理一个定义在System.Web命名空间下的HttpApplicationFactory类的时候,HttpApplicationFactory通过工厂模式管理HttpApplication对象。在HttpApplicationFactory内部维护了一个HttpApplication对象池,使得被创建的HttpApplication对象可以被重复使用。但是,每一个HttpApplication对象每一次仅仅用于处理一个请求,这样就不需要考虑HttpApplication中多个请求并发的处理问题了。

  在HttpApplication中,利用.Net中的事件机制,通过在处理过程中依次发出的多个事件,将这个处理过程分解为多个步骤,这个处理机制通常我们称为处理管道。

  处理管道,就是处理复杂问题的时候,将处理的过程分解为多个处理步骤,我们将这种经过多个步骤的处理方式称为处理管道。在.Net中,借助于事件的强大威力,我们可以通过处理管道将复杂的处理步骤封装起来,通过事件将处理过程的多个步骤暴露给程序员,以便于程序员对管理管道进行扩展。

  HttpApplication处理管道示意图:

  

二、HttpApplication暴露的事件

  但是,对于一个有着众多事件的类来说,定义大量的事件意味着创建对象的时候需要付出创建事件的成本,定义多个事件,意味着在创建的对象中将会需要更多的存储空间。System.ComponentModel.Component类中,提供了处理多个事件的基础:Events属性,它的类型为System.ComponentModel.EventHandlerList,这是一个线性的字段,当需要事件的时候,就通过key将事件保存到集合中,没有对应的事件,就不会付出创建事件的成本,这样,通过EventHandlerList可以在一个集合中管理多个事件对象,节省了事件对象占用的空间。

  1、System.ComponentModel.EventHandlerList

  该类的常用成员:

成员定义 说明
void AddHandler() 将一个委托加入到集合中,key为委托所对应事件的对象
void RemoveHandler() 删除一个委托
Delegate this[Object key] 通过表示事件的Key取得对应的委托

  这个类在使用的时候很简单,首先从Component派生一个类,这个类继承Component的Events集合属性。对于这个派生类所需要定义的每一个事件,在类中定义一个对应的作为key的对象,以后,通过这个key对象来访问有Events集合管理的事件。当然,用一个类似字典的集合也能够完成这个任务。

  下面试试这个类如何用:

namespace ComponentListTest
{
    class Program
    {
        static void Main(string[] args)
        {
            //这里是Asp.net程序员写的代码,对于程序员而言,只需要写处理事件就可以了
            ProcessPipeline process = new ProcessPipeline();
            process.StartProcess += new EventHandler(process_StartProcess);
            process.EndProcess += new EventHandler(process_EndProcess);
            process.Process();

            Console.ReadKey();
        }

        static void process_StartProcess(object sender, EventArgs e)
        {
            Console.WriteLine("开始事件执行");
        }

        static void process_EndProcess(object sender, EventArgs e)
        {
            Console.WriteLine("结束事件执行");
        }
    }

    public class ProcessPipeline : System.ComponentModel.Component
    {
        private static readonly object startEvent = new object();
        private static readonly object endEvent = new object();

        public event EventHandler StartProcess
        {
            add { this.Events.AddHandler(startEvent, value); }
            remove { this.Events.RemoveHandler(startEvent, value); }
        }
        public event EventHandler EndProcess
        {
            add { this.Events.AddHandler(endEvent, value); }
            remove { this.Events.RemoveHandler(endEvent, value); }
        }

        protected void OnStartProcess(EventArgs e)
        {
            if (this.Events[startEvent] != null)
            {
                (this.Events[startEvent] as EventHandler)(this, e);
            }
        }

        protected void OnEndProcess(EventArgs e)
        {
            if (this.Events[endEvent] != null)
            {
                (this.Events[endEvent] as EventHandler)(this, e);
            }
        }

        public void Process()
        {
            Console.WriteLine("事件开始顺序执行!");
            this.OnStartProcess(EventArgs.Empty);
            this.OnEndProcess(EventArgs.Empty);
        }
    }
}

  HttpApplication对象是Asp.net中处理请求的重要对象,但是,这种类型的对象实例不是由程序员来创建,而是由Asp.net帮助我们创建。为了便于扩展处理,Asp.net暴露了大量的事件给程序员,这些事件按照固定的处理顺序依次触发,程序员通过编写事件处理方法就可以自定义每一个请求的扩展处理过程。

  HttpApplication的19个标准事件如下:

事件名称 说明
BeginRequest Asp.net处理的第一个事件,表示处理的开始
AuthenticateRequest 验证请求,一般用来取得请求用户的信息
PostAuthenticateRequest 已经获取请求用户的信息
AuthorizeRequest 授权,一般用来检查用户的请求是否获得权限
PostAuthorizeRequest 用户请求已经得到授权
ResolveRequestCache 获取以前处理缓存的处理结果,如果以前缓存过,那么,不必再进行请求的处理工作,直接返回缓存结果
PostResolveRequestCache 已经完成缓存的获取操作
PostMapRequestHandler 已经根据用户的请求,创建了处理请求的处理器对象
AcquireRequestState 取得请求的状态,一般用于Session
PostAcquireRequestState 已经取得了Session
PreRequestHandlerExecute 准备执行处理程序
PostRequestHandlerExecute 已经执行了处理程序
ReleaseRequestState 释放请求的状态
PostReleaseRequestState 已经释放了请求的状态
UpdateRequestCache 更新缓存
PostUpdateRequestCache 已经更新了缓存
LogRequest 请求的日志操作
PostLogRequest 已经完成了请求的日志操作
EndRequest 本次请求处理完成

  2、事件简要介绍

  Asp.net服务器对于每一次请求的处理过程都相同,都要经过这个HttpApplication处理管道。管道内部的处理过程是固定的,在服务器处理请求的各个阶段,伴随着处理的进行,依次触发对应的事件,以便于程序员在处理的各个阶段完成自定义的处理工作。

  1、最先触发的事件是BeginRequest,这个事件标志着Asp.net服务器处理工作得开始,也是程序员在Asp.net中针对请求所能够处理的第一个事件。

  2、开始处理请求后,第一个重要工作就是确定请求用户的身份以实现安全机制,这个工作通过AuthenticateRequest和PostAuthenticateRequest两个事件提供检查当前请求用户身份的机会。检查后的用户可以通过HttpContext的User属性获取到。如:

    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
        string UserName = HttpContext.Current.User.Identity.Name;
    }

  3、获取用户身份之后,将开始检查权限的工作。如果没有通过安全检查,一般情况下,都跳过剩下的事件,直接出发EndRequest事件,结束请求的处理过程。

  4、当用户通过了权限检查,为了最快获得结果,Asp.net将进行缓存检查,看看是否可以从以前的缓存中直接取得处理的结果。

  5、当不能从缓存中获取结果的时候,必须通过一次处理来计算出当前请求的结果。在Asp.net中,用于 处理请求以得到结果的对象称为处理程序Handler,在Asp.net中提供了许多的处理程序,程序员也 可以自定义处理程序。为了处理这个请求,Asp.net必须按照匹配规则找到一个处理当前请求的处理 程序,PostMapRequestHandler事件表示Asp.net已经获取了这个处理程序,HttpContext的Handler 属性就表示这个处理程序对象。从上面的分析可以看到,HttpContext的Handler属性到这里才有实 际的意义。

  6、虽然有了处理程序对象,但是还不能立即开始处理,因为会话状态还未获取,还需要先获取Session然后才能获取事件处理程序。
PreRequestHandlerExecute通知程序员,马上开始调用处理程序了,有什么没有准备好的赶紧准备。
  7、调用处理程序。
  8、在处理程序完成之后,服务器开始进行扫尾工作,PostRequestHandlerExecute事件通知程序员,Asp.net服务器的处理程序已经完成。在处理完成之后,由于在处理程序中,用户可能修改了用户特定的专属数据,那么修改之后的用户状态数据可能需要进行序列化或者进行保存处理。ReleaseRequestState事件通知程序员需要释放这些状态数据,PostReleaseRequestState则表示已经释放完成。
  9、在处理完成之后,如果希望将这次处理的结果缓存起来,以便在后继的请求中可以直接使用这个结果,UpdateRequestCache事件提供了处理的机会,PostUpdateRequestCache则表示缓存已经更新完成。
  10、在Asp.net 4.0之后,新增加了两个时间完成处理的日志工作:LogRequest表示将这次请求记入日志中,PostLogRequest表示完成了日志工作。
EndRequest是所有请求都要经过的最后一个HttpApplication处理管道的事件,也是程序员处理Asp.net处理请求中的最后一个机会。这个事件之后,处理的结果将被回应道浏览器,完成Asp.net服务器的处理工作。

三、HttpContext状态管理

  HttpContext通过属性User和Handler传递了当前请求的用户和处理请求所使用的处理程序信息。如果我们还需要从HttpApplication前面的事件向后面的事件处理程序传递一些参数,那么可以通过HttpContext的Items属性来完成。

  HttpContext类中定义了一个Items属性,这是一个字典,定义如下:

public IDictionary Items{ get; }

  由于HttpContext对象贯穿整个HttpApplication的处理过程,所以,可以借助于这个属性,从处理过程的前面的步骤中,将数据传递给后面的处理步骤,而不需要通过方法的参数或者对象的成员,这种传递参数的方式称为基于HttpContext的状态管理。

  这种状态管理方式是Asp.net中周期最短的状态管理方式,因此有着极高的内存使用效率,但是仅仅能够用在服务器端的一次处理过程中。

四、处理HttpApplication事件

  HttpApplication提供了基于事件的扩展机制,允许程序员借助于处理管道中的事件进行处理过程扩展。由于HttpApplication对象是由Asp.net基础架构来创建和维护的,那么,如何才能获取这个对象的引用,以便于注册HttpApplication对象的事件处理,在Asp.net中,提供了两种方式来解决这个问题:IHttpModule方式和golbal.asax方式。这两种方式的核心都是IHttpModule接口。

  1、通过IHttpModule创建HttpApplication的事件处理程序

  在Asp.net中,创建在System.Web命名空间下的IHttpModule接口专门用来定义HttpApplication对象的事件处理。实现IHttpModule接口的类称为HttpModule(Http模块)。

  IHttpModule接口的定义如下,其中仅仅包含两个成员:

public interface IHttpModule
{
    void Dispose();
    void Init(HttpApplication context)
}

  其中,Dispose方法用于回收Module所使用的非托管资源,如果没有的话,直接返回即可。

  最重要的是Init方法,可以看到,这个方法接收一个HttpApplication类型的参数,在Asp.net中,每当创建一个HttpApplication对象实例,将遍历注册的HttpModule类型,通过反射,依次每个注册HttpModule类型的一个实例对象,并将这个HttpApplication实例通过Init方法传递给各个HttpModule,这样HttpModule就可以在第一时间完成针对HttpApplication对象的事件注册了。

  例如:希望写一个处理PostAuthenticateRequest事件的HttpModule,那么可以完成如下事件的注册:

public void Init(System.Web.HttpApplication application)
{
    application.PostAuthenticateRequest += new EventHandler(Application_PostAuthenticateRequest);
}

  2、注册HttpModule

  在Asp.net中,实现IHttpModule接口只是实现HttpModule的第一步,在Asp.net中所使用的HttpModule还必须在网站配置文件中进行注册才能真正生效,并在Asp.net中使用。

  配置文件有3个级别,详细可在配置文件系列中找到:http://www.cnblogs.com/kissdodog/category/468516.html

  下面以web.config示例进行说明如何注册HttpModule:

  system.web配置元素的子元素httpModules用来配置网站所使用的HttpModule;httpModules的子元素add用来增加一个新的HttpModule;clear将清除前面注册的所有HttpModule。

  add元素有两个必选的属性name和type,简介如下:

  • name表示这个HttpModule在程序中的名字,在网站应用程序中,可以通过这个名字来找到HttpModule对象的引用。HttpApplication的Modules属性表示这个对象所关联的所有HttpModule对象,通过这个name作为索引器,可以找到对应的HttpModule对象。
  • type表示HttpModule对象的类型名,Asp.net网站可以使用这个类型名,通过反射来动态创建HttpModule对象。类型的写法就是反射中要求的类型名称写法,如果这个类定义在网站中,那么,就是一个包含命名空间的类的全名,否则,在全名的后面,使用逗号(,)分隔,还需要跟上类型所在的程序集的名称,这个程序集的名称不需要包含.dll扩展名。

  对于IIS7.0来说,需要在配置文件的system.webServer配置节中注册HttpModule。注意此时的配置元素名称变为了modules。在IIS7.0中,可以为MapRequestHandler,LogRequest和PostLogRequest事件添加处理程序。

  只要在IIS7.0集成模式下运行并且与.Net Framework3.0或更高版本一起运行的应用程序,才可以支持这些事件。

<system.webServer>
    <modules>
      <add name="ModuleExample" type="Samples.ModeleExample">
    </modules>
</system.webServer>

  3、非配置文件的方式注册HttpModule

  在Asp.net4.0中,可以不修改配置文件也能达到完成Moudle注册的目的。从.Net 3.5开始,新提供的PreApplicationStartMethodAttribute特征可以应用在程序集上,使得自定义的网站初始化代码可以在Web应用程序的Application_Start初始化环节之前就执行。这个步骤甚至在动态编译和执行Application_Start之前。对于每个程序集,可以定义一次。特征的定义如下:

[AttributeUsageAttribute(AttributeTargets.Assembly,AllowMultiple = false)]
public sealed class PreApplicationStartMethodAttribute:Attribute
{
    public Type Type{ get; }
    public string MethodName{ get; }
    ...
}

  Type用来指定定义了初始化方法的类型,MethodName用来指定将要执行的初始化方法。

  这样,可以不在配置文件中固定配置HttpModule,而是定义一个方法,这个方法可以返回需要动态注册的HttpModule,将这个方法以委托的形式登记在一个集合中。在网站启动之后,每当HttpApplicationFactory创建一个HttpApplication对象,完成正常注册的HttpModule创建及初始化之后,再来创建我们动态注册的这些HttpModule。

  .

  .

  .

  .

  .

  暂时忽略这些东东,先写下面的

  4、常见的HttpModule

  在Asp.net中,已经预定义了许多HttpModule,甚至已经在服务器的网站配置文件中进行了注册,在系统文件夹C:\Windows\Microsoft.NET\Framework\v4.0.30319\Config\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的解释如下:

  1、OutputCacheModule完成Asp.net的输出缓存管理工作:

  OutputCacheModule的配置参数通过system.web配置元素的caching子元素的outputCache元素进行定义。当启用输出缓存之后(启用还是通过配置文件,下同),OutputCacheModule将注册HttpApplication的ResolveRequestCache和UpdateRequestCache两个事件完成输出缓存的管理。

  2、SessionStateModule完成Session的管理工作:

  这个Module的配置参数通过配置文件中的system.web配置元素的sessionState子元素进行配置。当启用Session状态管理之后,SessionStateModule将注册HttpApplication的AcquireRequestState、ReleaseRequestState、EndRequest三个事件完成Session状态的管理工作。

  3、ProfileModule提供个性化数据管理:
  这是一个自定义的类似于Session的会话状态管理,但是,个性化数据的读取和保存可以由程序员完全控制,并且提供了强类型的数据访问方式。这个Module的配置参数在system.web的子元素profile中进行说明。当启用了个性化数据管理之后,Module将注册HttpApplication的AcquireRequestState和EndRequest事件处理。

  4、AnonymousIdentificationModule提供匿名用户的标志:
  是否启用匿名用户标志在配置文件的system.web配置元素的子元素anonymousIdentification中定义,还可以配置匿名标识的管理方式。由于在AuthenticateRequest事件中将验证用户,获取用户名,所以这个Module注册了PostAuthenticateRequest的事件处理,当用户没有经过验证的时候,为用户分配一个唯一的匿名标识。

  5、WindowsAuthenticationModule、FormsAuthenticationModule和PassportAuthenticationModule用来完成用户的验证工作。
它们通过配置文件中system.web的子元素authentication子元素定义,mode属性用来指定网站当前使用的验证方式,也就是哪一个Module将被用来完成验证工作。在启用验证的情况下,FormsAuthenticationModule和PassportAuthenticationModule将注册HttpApplication的AuthenticateRequest和EndRequest事件进行用户的验证处理。WindowsAuthenticationModule将注册AuthenticateRequest的事件处理。

  6、RoleManagerModule、UrlAuthorizationModule、FileAuthorizationModule用来完成用户的授权管理:

  授权管理的配置参数来自system.web的authorization子元素。UrlAuthorizationModule和FileAuthorizationModule注册了HttpApplication的AuthorizeRequest事件处理,用来检查Url和文件的访问授权。RoleManagerModule在Url和文件访问授权检查通过之后,通过用户的标识和角色来完成用户的授权检查,RoleManagerModule注册了HttpApplication的PostAuthenticateRequest和EndRequest事件处理。

  5、HttpModule事件

  每个HttpModule也可以触发自定义的事件,但是,处理这些HttpModule事件更加麻烦一些,因为这些HttpModule对象实例也不是我们自己创建的。

  一般情况下,通过HttpApplication的Modules属性获取特定的HttpModule,这个属性的定义如下:

public HttpModuleCollection Modules{ get; }

  可以使用定义HttpModule时候的name作为索引来获取对应的HttpModule。例如,获取前面定义的HttpModule对象的引用:

application.Modules["online"]

  然后就可以定义这个HttpModule的事件处理了。

  6、通过global.asax创建HttpApplication的事件处理程序

  在Visual Studio中创建的Asp.net项目中的Global.asax代码如下:

    public class Global : System.Web.HttpApplication
    {

        void Application_Start(object sender, EventArgs e)
        {
            // 在应用程序启动时运行的代码

        }

        void Application_End(object sender, EventArgs e)
        {
            //  在应用程序关闭时运行的代码

        }

        void Application_Error(object sender, EventArgs e)
        {
            // 在出现未处理的错误时运行的代码

        }

        void Session_Start(object sender, EventArgs e)
        {
            // 在新会话启动时运行的代码

        }

        void Session_End(object sender, EventArgs e)
        {
            // 在会话结束时运行的代码。
            // 注意: 只有在 Web.config 文件中的 sessionstate 模式设置为
            // InProc 时,才会引发 Session_End 事件。如果会话模式设置为 StateServer
            // 或 SQLServer,则不会引发该事件。

        }
    }

  下面给出一个HttpModule捕捉异常的示例,在Application:

    protected void Application_Error()
    {
        var error = Server.GetLastError();
        var code = (error is HttpException) ? (error as HttpException).GetHttpCode() : 500;

        //如果不是HttpException记录错误信息
        if (code != 404)
        {
            //此处邮件或日志记录错误信息
        }

        Response.Write("出错");
        Server.ClearError();

        string path = Request.Path;
        Context.RewritePath(string.Format("~/Errors/Http{0}", code), false);
        IHttpHandler httpHandler = new MvcHttpHandler();
        httpHandler.ProcessRequest(Context);
        Context.RewritePath(path, false);
    }

  这样,就不用把try{}catch{}写得整个系统都是了!

  7、global.asax中HttpApplication事件的自动注册

  在global.asax中,针对HttpApplication的事件处理,可以通过定义特殊命名的方法来实现。首先,这些方法必须符合System.EventHandler,因为所有的HttpApplication管道事件都使用这个委托定义。第二,方法的作用域必须是public。第三,方法的命名格式必须如下:Application_注册的事件名称。按照这种命名方法定义在global.asax中的方法将被自动注册到对应的事件中。

  例如,希望在global.asax中注册PostAuthenticateRequest事件处理,那么在global.asax中应该定义一个如下的方法:

    void Application_PostAuthenticateRequest(object sender, EventArgs e)
    {
        Response.Write("验证通过事件!");
    }

  这对所有请求都有效,来看效果:

  

  8、特殊的HttpApplication事件处理

  通过global.asax文件,可以简单地完成一些特殊的事件处理,只要按照特定的命名形式,就可以使定义的方法自动注册到对应的事件中。在Asp.net中,有些事件甚至只能通过global.asax来完成处理。

  1、Start事件

  这个不是HttpApplication处理管道中的事件,当网站启动后,第一次请求到达网站之后,Asp.net网站将首先触发一次这个事件,而且在网站的整个生命周期中,也仅仅触发一次。由System.Web.HttpApplicationFactory对象触发,所以,也不能通过HttpApplication对象来获取相关的请求参数。在这个事件处罚的时候,第一次请求的上下文对象HttpContext也已经创建,所以,可以通过HttpContext.Current获取第一次的上下文请求对象,然后通过这个上下文对象来获取相关信息。

  由于这个事件在网站第一次请求的时候触发,所以非常适合针对网站全局的数据进行初始化工作,在Asp.net MVC中,RouteTablle就是在这个事件中创建的。

  2、End事件

当网站应用程序被关闭的时候,将触发这个事件。

  3、Error事件

  当网站应用程序出现错误,或者处理过程中出现未捕获的异常时,HttpApplication将抛出这个事件 。

  这个事件的事件源是HttpApplication,当前的异常信息可以通过HttpApplication的Server属性获取HttpServerUtility的对象实例来完成。HttpServerUtility对象的GetLasError()方法将返回最后一次的异常,这个方法的定义如下:

public Exception GetLastError();

  这个异常是一个经过包装的异常,它的InnerException属性指向网站最后一次抛出的未处异常。

  常见的处理如下:

    void Application_Error(object sender, EventArgs e)
    {
        HttpServerUtility server = (sender as HttpApplication).Server;
        Exception exception = server.GetLastError().InnerException;
        //针对异常的处理
        Response.Write("异常信息:" + exception.Message);
        //清理这个异常
        server.ClearError();
    }

  模拟输出一个异常:

    protected void Page_Load(object sender, EventArgs e)
    {
        throw new Exception("模拟异常");
    }

  输出如下:

  

  4、Session的Start事件

  当Asp.net每次创建了一个新的Session后,换句话说,创建了一个新的SessionID之后,就会触发Session的Start事件。需要注意到,在Asp.net中,支持会话的HttpModule在配置文件中注册的name就是Session。

  5、Session的End事件

  当一个Session过期之后,或者通过调用Abandon方法被丢弃之后,将会触发Session的End事件。这个事件的事件源实际上是SessionStateModule,而不是HttpApplication。需要注意的是,关闭浏览器不会导致Session的End事件。而且,如果Session的管理模式是StateServer或者SQLServer的话,将不会触发这个事件。

  6、HttpModule的事件注册

  从Session的处理可以看出,对于注册到网站中的HttpModule,如果这些Module也会抛出事件,而我们希望能够处理这些HttpModule事件的时候,可以在global.asax通过定义如下名称形式的方法来处理HttpModule的事件。

HttpModule注册名称_事件名称

  HttpApplication_BeginRequest(BeginRequest是19个事件的名称)。当然,方法必须首先要符合事件的委托定义。

  在Asp.net 2.0之后,提供了匿名用户的标识支持,这是通过一个注册名为AnonymousIdentification的HttpModule实现的,它同事提供了一个名为Creating的事件,定义事件的委托如下:

public delegate void AnonymousIdentificationEventHandler(object sender,AnonymousIdentificationEventArgs e)

  那么,在global.asax中,可以定义如下命名形式的方法来处理这个事件。

public void AnonymousIdentificaton_Creating(object sender,AnonymousIdentificationEventArgs args)
{

}

  例如个性化数据Profile的事件处理。个性化数据是通过注册名为Profile的HttpModule进行处理的,它的实际类型为ProfileModule,这个类提供了一个名为MigrateAnonymous的合并匿名用户数据的事件,这个事件的委托定义如下:

public delegate void ProfileMigrateEventHandler(object sender,ProfileMigrateEventArgs)

  所以,可以在global.asax中定义如下形式的方法进行处理。

public void Profile_OnMigrateAnonymous(object sender,ProfileMigrateEventArgs args)
{
    ProfileCommon anonymousProfile = Profile.GetProfile(args.AnonymousID);
    ProfileManager.DeleteProfile(args.AnonymousID);
    AnonymousIdentificationModule.ClearAnonymousIdentifier();
    Membership.DeleteUser(args.AnonymousID,true);
}

五、两个特殊事件

  1、PreSendRequestHeaders

  当准备通过HttpResponse回应发送HTTP的Header之前,HttpApplication将会触发PreSendRequestHeaders事件。在这个事件中,可以根据发送的Header来动态设置一些参数,比如,如果通过Content-Type参数获知发送的内容是text/html网页,那么,可以通过启用输出的压缩来提高网络的传输速度。这个操作可以通过设置一个特殊的Header来通知浏览器。

  2、PreSendRequestContent

  当准备通过HttpResponse回应发送HTTP的Body内容之前,HttpApplication将会触发PreSendRequestContent事件。如果配置了输出到客户端的压缩,那么可以在这个事件中包装输出到浏览器的流以实现输出的压缩。

HttpApplication处理对象与HttpModule处理模块 (第三篇),布布扣,bubuko.com

时间: 2024-10-19 14:11:17

HttpApplication处理对象与HttpModule处理模块 (第三篇)的相关文章

JavaScript基础对象创建模式之模块模式(Module Pattern)(025)

模块模式可以提供软件架构,为不断增长的代码提供组织形式.JavaScript没有提供package的语言表示,但我们可以通过模块模式来分解并组织 代码块,这些黑盒的代码块内的功能可以根据不断变化的软件需求而不断的被添加,替代和删除.模块模式由几种我们已经介绍过的模式共同组成: 命名空间模式 即时函数模式 私有成员与访问控制方法模式 依赖声明模式 模块模式的第一步是建立一个命名空间.首先我们用先前介绍的namespace()方法创建一个工具模块例子,这个例子模块提供一些数组功能: MYAPP.na

HttpApplication、HttpContext、HttpModule、HttpHandler

http://www.cnblogs.com/ljzforever/archive/2010/03/07/1680311.html http://runboliu.blog.163.com/blog/static/13459317201101352357218/ HttpApplication.HttpContext.HttpModule.HttpHandler,布布扣,bubuko.com

nodejs第三天(核心模块与文件模块,核心模块和文件模块引入的区别,从模块外部访问模块内部,使用exports对象,npm包管理工具package.json文件,模块对象属性,将模块定义分类,npm发布流程,安装淘宝镜像,模块的管理)

核心模块与文件模块 ndejs是一个js运行环境,是一个平台.nodejs基于操作系统,封装了一些功能,http,tcp,udp,i/o模块,path,fs,stream等等 通过nodejs内置的模块,他们就称为核心模块.(他们都是nodejs内置的)http,fs,path等 文件模块:只要写一个js文件,每一个文件都是模块 .(自己写的js文件都被称为文件模块) 核心模块和文件模块引入的区别 核心模块有环境变量做调度 文件模块需要给出文件路径 注意:核心模块是nodejs内置的一些功能模块

python成长之路第三篇(4)_作用域,递归,模块,内置模块(os,ConfigParser,hashlib),with文件操作

打个广告欢迎加入linux,python资源分享群群号:478616847 目录: 1.作用域 2.递归 3.模块介绍 4.内置模块-OS 5.内置模块-ConfigParser 6.内置模块-hashlib 7.with文件操作 代码执行环境默认为3.5.1 一.作用域 (1)什么是作用域,官方来说作用域就是就是有不同的命名空间,就像下面的代码一样,a=1它的作用域是全局的,也在全局的命名空间当中,当函数 action中的a=2它就在局部的作用域中,也在局部的命名空间当中. a = 1def

传感器仿真平台——数据生成模块(三)

数据生成模块有下面这样一种情况: 对于不同的传感器仿真实验,所使用的数据类型,数据数量不一样. 如实验一是进行最大覆盖率实验,则他需要的数据格式可能是如下所示: 1 Class Sensor 2 { 3 public int x; 4 public int y; 5 public double direction; //方向 6 public double sweep;//扇形大小 7 } 实验二进行的是信号强度实验,则他可能还需要一个用来作为覆盖物的目标,如下: 1 Class Target

(转).net程序员转战android第三篇---登录模块之静态登录

这一篇我将分2个部分记录登录界面,第一部分是静态登录, 这部分将如何从界面布局.控件使用.文件关系.数据验证.登陆实现等5小块记录. 第二部分是动态登录,这块会基于上面的4小块,在数据验证不是静态数据, 而是通过WebService获取网络数据,然后解析网络数据,验证成功在进行文件关联,然后页面跳转,最后实现自动登陆; 需求分析 如图所见,对于一个程序员来说,不管你是做android\.NET\IOS,如果让你来做上图效果, 大家都会明白从哪里入手. 1:界面布局(分为3块,顶部标题栏.表单提交

客户管理系统之模块设计(三)

三,客户模块设计 对客户管理模块的设计,要重点从三块来设计.一是加入模块,二是更改模块,三是浏览模块. 1.客户管理模块 客户管理模块在窗口上包括一个ToolStrip控件和一个DataGridView控件.ToolStrip控件中加入三个Label项.用来对DataGridView控件中所选择的行进行加入.删除和改动. 客户管理模块的设计演示样例为: 客户管理模块设计的窗口和控件的属性设置文档为: 接着就是要进行代码的写入: (1)对于toolStrip1控件的代码写入是基本的.这里面包括加入

常用模块(三)——shelve、xml、hashlib、configparser

常用模块(三) 一.shelve模块 1.shelve模块也是一种序列化模块,内部使用的是pickle模块,所以也存在跨平台性差的问题 2.特点: 只要提供一个文件名即可 读写的方式和字典一样 将数据以类似字典的形式在文件中读写 3.应用场景 在单击的程序中使用 4.使用方法 (1)序列化 1 import shelve 2 3 s1= shelve.open('a.txt') # 打开文件 4 s1['week']=["Sun", "Mon", "Tue

Python学习 :常用模块(三)

常用模块(三) 七.logging模块 日志中包含的信息应有正常的程序访问日志,还可能有错误.警告等信息输出 python的 logging 模块提供了标准的日志接口,你可以通过它存储各种格式的日志,logging 的日志可以分为 debug() , info() , warning() , error() , critical() 5个级别 Eg.简单的日志记录 import logging logging.debug('debug message') logging.info('info m