IHttpHandler and HttpModule

ASP.Net中自定义Http处理及应用之HttpHandler篇

     在开发基于Microsoft IIS的应用时,开发者除了可以编写ASP程序外,还可以使用Visual C++等开发工具,开发ISAPI应用,以获取更为强大的功能。可以编写两种ISAPI扩展:一种是ISAPI Server Extention,另一种是ISAPI Filter,但是,ISAPI扩展应用的编写通常对开发者有比较高的要求,开发和部署的难度比较大。 在开发ASP.Net应用时,我们仍然可以编写ISAPI应用,以扩充IIS的功能,但是,ASP.Net为我们提供了另外一种选择——使用HTTP Handler 和HTTP Module。这是通过使用IHttpHandler 和 IHttpModule接口来实现的。HTTP Handler提供了类似于ISAPI Server Extention的功能,而HttpModule实现了类似于ISAPI Filter的功能,并且,比ISAPI,在开发和部署上都要简单的多。 应用HttpHandler和HttpModule,使应用程序可以与IIS Web服务器的低级别请求和响应服务交互。本文首先介绍HttpHandler和HttpModule的概念和基本使用方法,并介绍了一个应用HttpModule实现权限系统的案例。
  HTTP 处理管道的基本模型
  要对HttpModule和IHttpHandler进行研究,必须先对ASP.Net的处理管道有一个了解。 在ASP.Net应用程序中,系统使用一组相关的类,通过一定的顺序来处理客户端的请求(Request),ASP.NET应用程序的处理模式可称之为HTTP处理管道。HttpModule和IhttpHandler就是这个处理管道上的两个处理环节。 HTTP处理管道中的类在System.Web名称空间中定义,主要有以下类型: · HttpWorkerRequest 抽象类定义了ASP.Net页面处理请求的基本方法; · HttpRuntime 提供了处理应用的一组服务; · HttpContext 保存了处理一次请求的所有相关上下文信息; · HttpApplicationFactory 提供相关目录的应用程序; · HttpApplication 定义了所有ASP.Net应用程序的通用的方法、属性和事件。这个类也是在用户在global.asax文件中定义的应用的基类; · Modules 处理请求前和响应后的事件; · HandlerFactories 提供应用程序中的Handlers; · Handlers 处理请求和响应。 HTTP处理管道的模型如下:
  
  图1:HTTP 处理管道
  在Windows平台上,HTTP Pipline需要IIS的支持。为了运行ASP.NET应用,IIS需要以下两个文件:ASPNET_ISAPI.DLL和ASPNET_WP.EXE · ASPNET_ISAPI.DLL是一个ISAPI Extention他将发向IIS的请转交ASPNET_WP.EXE处理 · ASPNET_WP.EXE使用HttpRuntime对请求进行具体处理 处理的过程可以用图表示如下:
  
  图2:IIS上的HTTP处理管道

HttpHandler的实现
  HttpHandler实现了类似于ISAPI Extention的功能,他处理请求(Request)的信息和发送响应(Response)。HttpHandler功能的实现通过实现IHttpHandler接口来达到。实际上,我们在编写ASP.Net页面时,ASP.Net页面所继承的基类——System.Web.UI.Page——也实现了HttpHandler接口,也是一个HttpHandler,看一下它的定义就知道了(C#):
  public class Page : TemplateControl, IhttpHandler
  
  
  接口IHttpHandler的定义如下:
  interface IHttpHandler
  {
  void ProcessRequest(HttpContext ctx);
  bool IsReuseable { get; }
  }
  
  
  接口中ProcessRequest是添加自己的代码,进行相应处理的地方。IsReuseable属性指明该HttpHandler的实现类是否需要缓存。 下面的示例展示了HttpHandler的基本使用: 1、建立一个名为MyNameSpace的工程,添加一个类,名称为MyHandler,代码如下:
  例1:
  namespace MyNameSpace
  {
  public class MyHandler : IHttpHandler
  {
  public void ProcessRequest(HttpContext ctx)
  {
  HttpResponse Response
  Response.Write("This is my handler");}
  public bool IsReusable
  {
  get { return true; }
  }
  }
  }
  
  
  2、将上面的代码编译,生成MyNameSpace.Dll文件; 3、建立一个新的WebApplication项目,或打开一个WebApplication项目,将文件MyNameSpace.Dll添加到项目的引用中,或复制到项目的bin目录下; 4、修改Web.Config,添加如下内容:
  <configuration>
   <system.web>
   <httpHndlers>
  <add verb="*" path="*.aspx"
  type=" MyNameSpace.MyHandr, MyNameSpace" />
   </httpHndlers>
  </system.web>
  </configuration>
  
  
  配置文件中的选项说明: · verb可以是"GET"或"POST",表示对GET或POST的请求进行处理。"*"表示对所有请求进行处理。 · Path指明对相应的文件进行处理,"*.aspx"表示对发给所有ASPX页面的请求进行处理。可以指明路径,如"/test/*.aspx",表明只对test目录下的ASPX文件进行处理。 · Type属性中,逗号前的字符串指明HttpHandler的实现类的类名,后面的字符串指明Dll文件的名称。 现在,请求项目中的任何ASPX页面,页面上显示的始终只有如下一行字:
  This is my handler
  
  
  因为,我们自定义的Handler截获了所有发向ASPX页面的请求,并且用自己的的方法来处理这些请求了。 为了使我们的ASPX页面能够顺利运行,我们需要修改Web.Config文件:
  <configuration>
   <system.web>
   <httpHndlers>
  <add verb="*" path="*.foo"
  type=" MyNameSpace.MyHandr,hander" />
   </httpHndlers>
  </system.web>
  </configuration>
  
  
  
  为了让对后缀名为.foo的文件的请求能够被我们的Handler截获运行,我们还需要一些额外的工作。打开IIS的管理控制台,又键单击站点,选择"属性",跳出站点的属性对话框。选择主目录选项。如图3:
  
  
  
  图3:Web站点属性对话框 
  选择配置,弹出应用程序配置对话框,将".foo"添加到应用程序映射中,如图4:
  
  图4:添加应用程序映射
  好了,我们现在可以在项目中添加一个.foo文件,当向该文件发送请求时,浏览器显示:
  This is my handler
  
  
  
  而对其他ASPX文件的访问不受影响。
  实现Handler Factory
  实现HttpHandler功能的另外一个选择是实现一个Handler Factory,这是通过实现IHttpHandlerFactory接口来实现的。 IHttpHandlerFactory接口的定义如下:
  interface IHttpHandlerFactory
  {
  IHttpHandler GetHandler(HttpContext ctx,
  string requestType,
  string url,
  string pathTranslated);
  void ReleaseHandler(IHttpHandler handler);
  }
  
  
  
  GetHandler方法在请求开始的时候被调用,而ReleaseHandler在请求结束,所有的Handler都不再需要的时候被调用。 使用HttpHandlerFactory的过程一般如下: 首先定义实际处理HttpHandler的类,这个类会在HandlerFactory中被调用以进行实际的处理:
  public class BasicHandler : IHttpHandler { ... }
  
  
  
  然后,定义自己的HandlerFactory:
  public class BasicHandlerFactory : IHttpHandlerFactory
  {
  public IHttpHandler GetHandler(HttpContext ctx,
  string requestType,
  string url,
  string pathTranslated)
  {
  return new BasicHandler();
  }
  public void ReleaseHandler(IHttpHandler handler) {}
  }
  
  
  
  最后,在Web.Config文件中注册这个Factory:
  <configuration>
  <system.web>
  <httpHandlers>
  <add verb="POST" path="*.foo"
  type="MyNamespace.BasicHandlerFactory, MyAssembly" />
  </httpHandlers>
  </system.web>
  </configuration>
  
  异步Handler
  通过实现IHttpAsyncHandler可以实现对HTTP请求的异步处理。IHttpAsyncHandler接口继承IHttpHandler,也需要实现ProcessRequest 方法和 IsReusable 属性,同时,需要实现 BeginProcessRequest 和 EndProcessRequest 方法。BeginProcessRequest 启动异步调用以处理单个的 HTTP 请求,而 EndProcessRequest 则在该进程结束时执行清理代码。 IHttpAsyncHandler的实现和注册同IHttpHandler类似,读者可以参考MSDN的相关文档。 现在,大家是否对HTTP Handler的概念和应用有了一定的了解?在下一篇文章中,我们将主要介绍HTTP Module的的应用,并给出使用HttpModule实现权限系统的实例。 
   

ASP.NET 页面对象模型

     作者:Dino Esposito、Wintellect
  
  摘要:
  
  讨论关于建立ASP.NET Web页的事件模型和转化为HTML的各个过程的细节。ASP.NET HTTP 运行时管理着把请求URL转换成一个页面类的具体实例的对象管道,接下来把这些实例转换成一般的HTML文本格式。本文对代表各个页面生命周期的事件、怎么控制页面执行、开发人员怎么干预这些标准行为的执行过程进行了讲解。
  
  
  
  介绍
  
  
  
  每当请求IIS容纳的ASP.NET页时,总是要把请求转交给了ASP.NET HTTP 管道。HTTP管道是一组被控对象,这些对象按顺序处理请求并且把这些请求转换成一般HTML文本。HTTP管道的入口是HttpRuntime 类。ASP.NET的底层结构为每一个应用程序域 ( AppDomain )的工作进程建立了一个这个类(HttpRuntime)的实例(注意,一个工作进程只能支持一个正在运行的ASP.NET应用域)。
  
  
  
  HttpRuntime 类从内部程序池中选择一个 HttpApplcation 对象,并且在接收到请求的时候使它工作。Http应用管理程序的主要工作是寻找这样的类使之能够处理请求。例如:当请求一个.aspx资源时,处理句柄就是一个从Page继承类的实例。请求资源的类型和相关处理句柄的关系映射表被保存在应用程序的配置文件里。更确切的说,这个映射表就定义在machie.config里的<httpHandlers>一节里。但是,应用程序能在web.config里对这个HTTP处理句柄映射列表进行重定义。下面这行语句说明了定义.aspx资源请求的处理句柄:
  
  
  
  <add verb=”*” path=”*.aspx” type=”System.Web.UI.PageHandlerFactroy”/>
  
  一个扩展可以和一个句柄类联系起来,更一般说,是和一个句柄工厂类相联系。在所有情况下,负责处理请求的HttpApplication对象得到一个从IHttpHandler接口具体实现的对象。如果是根据HTTP句柄来处理资源和相关处理类的关系,则返回类是直接实现相关的接口的;如果资源是绑定到一个句柄工厂的话,将必须经过另外一个阶段:具体实现IHttpHandlerFactory接口的句柄工厂类的GetHandler方法将返回一个基于IHttpHandler的对象。
  
  Http运行时怎么结束一个周期或关闭一个页面请求的进程呢?IHttpHandler接口的ProcessRequest方法拥有这个功能。调用代表被请求页面的对象的该方法,ASP.NET底层结构打开一个进程来为浏览器产生输出。
  
  
  
  Page类
  
  
  
  一个页面的HTTP处理句柄的类型取决于URL。当这个URL被首次访问,一个新的类将被构建并动态的编译成一个程序集。一个分析aspx文件的进程从aspx文件中分离出这个类的代码。在默认情况下,这个类被加入到一个叫做asp的名字空间里,并且把URL作为这个类的类名。例如,如果请求的URL是page.aspx,则这个类就是ASP.Page_aspx。这个类名,可以通过设置@Page预处理指令的ClassName属性来修改。
  
  
  
  HTTP句柄的基础类是Page类。这个类定义了一组最小方法和属性集,这些方法和属性被所有的页面处理句柄所共享。Page类具体实现了IHttpHandler接口。
  
  
  
  在另外一种和上述相对应的情况中,实际处理页面的句柄的基础类并不是Page类,而是一个别的类。当使用后代码模式时,这个情况就发生了。后代码是一种将C#或VB.NET代码和页面分离的技术。页面代码是一组事件处理句柄和其他一些方法的集合,这些方法定义了页面的各种行为。这些代码可以以内联形式用<script runat=server>标签定义,或者你可以用外部类形式来写——这就是后代码模式。后代码类是从Page类继承的,但是具体化或者重新定义了一些其他的方法。在指定了页面的后代码类后,这个后代码类就作为HTTP处理句柄。
  
  
  
  在其他的情况下,如果应用程序的配置文件中重定义了<pages>节的PageBaseType属性,则HTTP处理句柄不是基于Page类的,例如:
  
  
  
  <pages PageBaseType = “Classes.MyOage , mypage” />
  
  
  
  PageBaseType属性指明了包含页面处理句柄父类的类型和程序集。来自Page类的这些类自动赋予一些通常或扩展的方法和属性的集合给处理句柄。
  
  
  
  页面生命周期
  
  
  
  一旦HTTP页面处理句柄被明确的定义了,ASP.NET运行时调用处理句柄的ProcessRequest方法来处理请求。通常,没有必要改变Page类提供的执行方法。
  
  
  
  页面执行是从FrameworkInitialize方法开始的,这个方法为页面构建控件树。该方法是TemplageControl类的受保护并且是虚方法。任何为aspx资源动态生成的句柄覆盖了该方法。在这个方法里,页面的所有控件树都被构建了。
  
  
  
  接下来,ProcessRequest方法使页面经历了不同的几个阶段:初始化、加载视图状态信息、回传数据、加载页面代码和执行回传的服务器事件。在这之后,页面转换到了显示模式:收集被更新的视图状态;产生HTML代码,并且传送到控制台。最后,页面卸载,请求的全部服务结束了。
  
  
  
  在各个不同阶段里,页面处理了与web控件相关、程序员代码能够干预并解决一定问题的事件。其间一些事件是专门为那些内嵌控件和不能在.aspx代码级别处理的控件而设计的。
  
  
  
  一个页面要解决这样的事件,它能明确的注册成为合适的句柄。但是,为了和原有的Visual Basic编程模式有后向兼容性,ASP.NET也支持了隐含事件的形式。在默认情况下,页面会寻找和事件相关的方法名;如果找到和事件相匹配的方法,这个方法就被认为是这种事件的处理程序。ASP.NET提供了六种专门的方法名,他们是 Page_Init , Page_Load , Page_DataBind , Page_PreRender 和 Page_Unload 。这些方法这些方法在Page类中已经被定义过,他们是相应事件的处理程序。HTTP运行时将自动的将这些方法绑定到相关的页面事件,而不需要程序员去编写把事件和方法联系起来的代码。举个例子来说,在下面的代码中, Page_Load方法和页面的加载事件相关联:
  
  
  
  this.Load + = new EventHandler(this.Page_Load);
  
  
  
  这种自动识别是被 @Page 预指令的AutoEventWireup 属性控制的。如果这个属性被置false ,应用程序必须显式声明和事件相关的方法。不自动关联页面事件代码的页面执行起来会快一些,是因为他们不需要在匹配上做过多的工作。在Visual Studio.NET 工程里可以把这个属性关闭掉。但是,默认设置是true,这意味着Page_Load方法被自动识别并被关联到相关的事件。
  
  
  
  页面执行包含了下表中按顺序列出的几个阶段,他们被标志成为应用程序级别的事件,同时也可能是一些受保护、重定义的方法:
  
  
  
  阶段
   页面事件
   可重定义的方法
  
  页面初始化
   Init
  
  
  视图状态加载
  
   LoadViewState
  
  回传数据处理
  
   控件里实现了IPostBackDataHandler接口的LoadPostData方法
  
  页面加载
   Load
  
  
  回传数据变化检查
  
   控件里实现了IPostBackDataHandler接口的RaisePostDataChangedEvent方法
  
  回传事件处理
   控件里定义的回传事件
   控件里实现了IPostBackEventHandler接口的RaisePostBackEvent方法
  
  页面预返回阶段
   PreRender
  
  
  页面返回阶段
  
   Render
  
  页面卸载阶段
   Unload
  
  
  
  
  
  
  上表中列出的阶段有的在页面级别是不可见的,他们只是在服务器控件的作者编写继承于Page的类时会使用到。Init , Load , PreRender , Unload,再加上定义在内嵌控件中的回传处理事件,他们构成了页面的整个生命周期。
  
  
  
  各个阶段的执行
  
  
  
  页面生命周期的第一阶段是初始化。这个阶段被Init事件所描述,这个事件在控件树被构建出来后执行。换句话说,当Init事件发生时,所有在.aspx文件中静态声明的控件被实例化并被赋予了默认值。在Init事件中可以初始化任何的在页面生命周期里需要的设置。例如:在这个阶段,控件可以加载外部的摸版文件或者是为事件建立处理句柄。需要注意的是,任何的视图状态信息在这个阶段里是不能用的。
  
  
  
  紧接着初始化结束后,页面构架为页面加载视图状态。视图状态是 名称/值 对的集合,控件或页面在这里保存的数据在整个web请求过程中必须是稳固的。视图状态代表着页面的上下文。典型的,它保存着页面上次在服务器上被执行时控件的状态。视图状态在会话开始的第一个页面请求时是空的。在默认情况下,试图状态被保存在一个隐藏域里,这个隐藏域是被自动添加到页面里的。这个隐藏域的名称是 __VIEWSTATE。如果覆盖了LoadViewState方法——在Control类里被声明为受保护的方法——组件开发者可以控制视图状态的保存和它是如何和内部状态形成映射。
  
  
  
  象LoadPageStateFormPersistenceMedium这样的方法和与其相对应的SavePageStateToPersistenceMedium方法可以用来加载或者保存视图状态到其他的存储中介里,例如:会话、数据库或者是服务器上的文件。和LoadViewState方法不相同的是,上面提到的方法只能在Page的继承类里使用。
  
  
  
  一旦视图状态加载完毕了,页面里的控件被赋予了和上一次发送到浏览器时一样的状态。下一个阶段是将他们更新,使之与服务器端发生的变化相一致。在回传数据处理阶段,控件更新他们的状态,使之和客户端的HTML元素的状态相一致。例如,服务器控件TextBox有和它相对应的HTML控件<input type=text>。在回传数据阶段,TextBox控件将得到<input>标签的值,并且用他来更新他的内部状态。每一个控件都可以从回传数据中取得自己数据的能力,并且把自己的状态更新。TextBox控件将更新它的Text属性,同样的,CheckBox控件也会将他们的Checked属性刷新。服务器控件和HTML元素的匹配是通过两者的ID来进行的。
  
  
  
  在回传数据处理的最后阶段,所有的页面控件反映了上一个被更新的状态,这些都是由于客户端的输入变化所引起的。接下来,Load事件将被页面执行。
  
  
  
  有一些控件,在两次请求中如果某些敏感属性发生了变化,他们需要对此作出响应,并且完成一定的任务。例如,如果客户端的textbox控件的文本发生变化,这个控件就激发了TextChanged事件。根据自客户端的数据,如果控件的一个或多个属性发生了变化,每一个控件都可以精确的激发合适的事件来处理。这些控件实现了IPostBackDataHandler接口,这个接口中的LoadPostData方法在Load事件之后就被执行了。通过重定义LoadPostData方法,控件可以验证两次请求中发生的变化并且激起相关的事件处理程序。
  
  
  
  在一个页面周期中的关键事件是那些由客户端事件激发在服务器执行一段代码的事件。例如,当用户点击一个按钮,页面就需要回传。这个事件的处理是从按钮ID和值的收集开始的。如果控件是实现了IPostBackEventHandler接口(Button和LinkButton就是这样的情况),页面构架将调用RaisePostBackEvent方法。这个方法的具体情况是取决于控件的类型的。在上面提到的Button和LinkButton控件,这个方法就将寻找Click事件处理程序。
  
  
  
  处理了回传事件之后,页面就准备被发送出去了。这个阶段是从PreRender事件开始的。这对于控件来说,那些需要在视图信息被保存与结果被发送之前这段时间里执行的动作,这是一个很好的时机。下一步就是SaveViewState ,所有的空间和页面本身就把视图状态的集合内容保存起来。接下来,视图状态被串行化、哈希编码、Base64 编码,并且保存在__VIEWSTATE隐藏域里。
  
  
  
  各个控件的发送机制可以通过重定义Render方法来改变。这个方法构建了一个HTML writer对象,用它来为控件产生HTML代码。对Page类里Render方法的默认执行包含了对所有成员控件的递归调用。页面为每一个控件调用一次Render方法,并缓冲HTML输出。
  
  
  
  页面生命周期的最后阶段是卸载事件,这个事件在页面对象消失前被激发。在这个事件里,你应该把任何临界资源释放掉(例如:文件、图形对象、数据库连接)。
  
  
  
  最后,浏览器接收到了HTTP响应,并且把页面显示出来。
  
  
  
  总结
  
  
  
  ASP.NET页面对象模型是一个有特点的新颖的模型,因为它是基于事件机制的。一个Web页由一些控件组成,这些控件拥有丰富的基于HTML的用户接口,同时通过事件和用户进行交互。在Web应用程序上下文环境中构建一个事件模型是富有挑战性的。使客户端产生的事件和服务器上的代码关联起来是令人惊异的,这个过程是输出同HTML也一样是可见的,只不过他们在需要的时候被恰当的修改。
  
  
  
  要了解页面生命周期的各个阶段、页面对象是怎样实例化并被HTTP运行时所使用,掌握这个模型是很重要的。
  
  
  
  
  
  关于作者:
  
  Dino Esposito是罗马的技术训练师和咨询师。Wintellect小组的成员,Dino花了大量的时间在欧洲和美国讲授ASP.NET和ADO.NET,同时提供咨询。值得一提的是,Dino为Wintellect提供ADO.NET课件,并且为MSDN杂志的Cutting Edge专栏撰写文章。联系方法:mailto:%20dinoe@wintellect.com 
  
关于http handles
   ASP.NET的请求过程是基于一个管道(pipeline)模型的,ASP.NET会把所有的http请求(Requests)都发送给这个管道里的http组件(modules)。每个组件在接收到http请求后进行一些相应的动作。当http请求通过了所有的http modules程序后,将会被交由一个http handle程序来处理,处理后的结果又将通过管道里http modules返回。这整个过程中,被调用的http module可以有多个,然而调用的http handle只能是一个。其过程如图:
  
   可以看出每个输入的http请求都会最终被一个http handle程序处理。http handle是一个实现了System.Web.IHttpHandler接口的类的实例,有些类似ISAPI扩展。在http handles中实现的有:
  ProcessRequest:该方法用来处理http请求,是http handles最核心的方法
  IsReusable:一个属性,返回一个bool值,来表示这http handle的实例是否能被重用来处理多个同类型的http请求。
  
  二、在配置文件中注册http handles
   http handles的类可以在web.config或machine.config文件里注册。这样,一旦有相应的http请求输入,这个http handle类就会被实例化。在web.config或machine.config文件里我们用<httpHandlers>和<add>节点来为我们的应用程序添加http handle类:
  <httpHandlers>
   <add verb="supported http verbs" path="path" type="namespace.classname, assemblyname" />
  <httpHandlers>
  
  在<add>里
  1、verb属性说明了该handle所支持的http请求方式,例如支持post和get方式,verb属性则为"POST,GET";如果支持所有的请求方式,verb属性则用"*"。
  2、path属性说明了对哪些文件的请求才调用该handle来处理,例如你只想在请求my.possible文件时才调用该handle,则path属性为"my.possible",如果你想所有后缀名为possible的文件(*.possible)都由该handle来处理,则path属性为"*.possible"。
  3、type属性中指定了handle类的命名空间、类名和配件名(工程名)。ASP.NET runtime会首先到应用程序的bin目录下查找该配件的dll,如果没有找到再到GAC里查找。
  
  其实ASP.NET自身里的许多功能也是使用HTTP handlers来实现,ASP.NET使用了许多的handle类来处理.aspx, .asmx, .soap 和一些其它的ASP.NET文件。你可以在machine.config文件里找到如下代码:
  <httpHandlers>
  <add verb="*" path="trace.axd" type="System.Web.Handlers.TraceHandler"/>
  
   <add verb="*" path="*.aspx" type="System.Web.UI.PageHandlerFactory"/>
  
   <add verb="*" path="*.ashx" type="System.Web.UI.SimpleHandlerFactory"/>
  
   <add verb="*" path="*.config" type="System.Web.HttpForbiddenHandler"/>
  
   <add verb="GET,HEAD" path="*" type="System.Web.StaticFileHandler"/>
  
   . . . . . .
   . . . . . .
  </httpHandlers>
  从上面的配置可以看出来对.aspx文件的请求是交由System.Web.UI.PageHandlerFactory类来处理的,而象.config文件是被System.Web.HttpForbiddenHandler类来处理,可以猜想这个类将会返回一个该类文件不能被请求的错误。
  
  三、http handles类的实现
   在这里我们用C#来创建一个新的handle类来处理新的文件类型,比如以.possible为后缀名的文件。
  1、我们先在vs.net里创建web应用程序的工程,名为MyHandler,然后添加一个类文件NewHandler.cs来建立实现了IHttpHandler接口的类:
  
  using System;
  using System.Web;
  
  namespace MyHandler
  {
   /// <summary>
   /// Summary description for NewHandler.
   /// </summary>
   public class NewHandler : IHttpHandler
   {
   public NewHandler()
   {
   //
   // TODO: Add constructor logic here
   //
   }
  
   #region Implementation of IHttpHandler
   public void ProcessRequest(System.Web.HttpContext context)
   {
   HttpResponse objResponse = context.Response ;
   objResponse.Write("<html><body><br><br><center>Hi,This is a test! ") ;
   objResponse.Write("</center></body></html>") ;
   }
  
   public bool IsReusable
   {
   get
   {
   return true;
   }
   }
   #endregion
   }
  }
  在ProcessRequest方法的实现里,我们只是简单的获取了HttpContext的HttpResponse对象,并象客户端发送了一些html。在IsReusable的实现里返回true,表示该handle类的实例可以处理多个对.possible文件的请求。
  
  注意:如果想在HTTP handlers里使用session,那么还需要实现IRequiresSessionState接口,而IRequiresSessionState接口只是一个标志,不需要实现任何的具体方法,所以只需要把类申明改为:public class NewHandler : IHttpHandler,IRequiresSessionState即可。
  
  2、打开web.config文件,注册上面新创建的handle类:
  <httpHandlers>
   <add verb="*" path="*.possible" type="MyHandler.NewHandler,MyHandler"/>
  </httpHandlers>
  
  3、在IIS中添加ISAPI扩展,将我们的新后缀名.possible添加进去,具体过程为:
  IIS--》选中“默认网站”点右键--》选“属性”--》“主目录”--》“配置”--》点“映射”里的“添加”按钮--》在弹出对话框里点击“浏览”按钮,选择aspnet_isapi.dll文件,并在扩展名里填possible,如下图所示:
  
  最后点击确定按钮。
  
  这样我们就可以在浏览器里输入http://localhost/MyHandler/xxx.possible,来调用该handle了。当然我们这里只是举了个简单例子,所以输入任何*.possible都是一样的效果。我们可以在NewHandler的ProcessRequest方法里先分析请求的url,然后根据不同url作出不同的相应,比如跳转到不同的真实存在的aspx页面,这也正是web设计模式中MVC模式在asp.net中通过Front Controller实现的核心部分之一,具体请见:http://msdn.microsoft.com/architecture/patterns/default.aspx?pull=/library/en-us/dnpatterns/html/DesFrontController.asp。 
最近需要做一个对特定请求进行响应的接口,只是在内部处理,不存在UI,机于这种情况,当然是使用实现IHttpHandler来进行处理,可以减掉加载HTML 控件的时间。本来都是这样想的,对于IHttpHandler 中定义了两个方法,ProcessRequest(HttpContext ctx) 和 IsRunable() 这两个,看到在ProcessRequest(HttpContext ctx) 中有个HttpContext的输入参数,本来以为通过这个就可以对所有的服务器对象进行使用,只是在前面需要对HttpContext的引用。不过问题出现了,在这个自定义HTTP 响应处理头中需要写入Session,对于其他Request和Response 都可以通过使用HttpContext来引用使用,不过Session 就是不行,总是出现对象未进行引用的错误,真是百思不得其解,好好的HTTPCONTEXT 里面都列出了可以使用的服务器对象,但是就是SESSION 用不了!真苦,只好将自定义HTTPHANDLER 的内容做到普通的WEBFORM 中。就在做好后,却无意中发现在自定义HTTPHANDLER 中使用SESSION 的方法!
  1、先引用System.Web.SessionState 这个命名空间,
  2、如果是要在HttpHandler 中读取Session的内容,就要在实现IHttpHandler 的类中同时实现IReadOnlySessionState 这个接口。
  3、如果是要在HttpHandler 中读写Session的内容,就要在实现IHttpHandler 的类中同时实现IRequiresSessionState
  
  这样就可以在自定义的HttpHandler 中正常的使用Session了。 
    
原文地址:https://www.cnblogs.com/hq2008/p/1012243.html