ASP.NET HTTP 处理程序是响应对 ASP.NET Web 应用程序的请求而运行的过程(一般称为"终结点")。最经常使用的处理程序是处理 .aspx 文件的 ASP.NET 页处理程序。用户请求 .aspx 文件时,页经过页处理程序来处理请求。 html
ASP.NET 页处理程序仅仅是一种类型的处理程序。ASP.NET 还包括其余几种内置的处理程序,例如用于 .asmx 文件的 Web 服务处理程序。 web
若是您须要进行特殊处理(能够在应用程序中使用文件扩展名进行标识),能够建立自定义 HTTP 处理程序。例如,下面的方案就很好地利用了自定义 HTTP 处理程序: 数据库
HTTP 处理程序能够访问应用程序上下文,包括请求用户的标识(若是已知)、应用程序状态和会话信息等。当请求 HTTP 处理程序时,ASP.NET 将调用相应处理程序上的 ProcessRequest 方法。处理程序的 ProcessRequest 方法建立一个响应,此响应随后发送回请求浏览器。就像任何页请求那样,响应将途经订阅了处理程序运行后所发生事件的全部 HTTP 模块。有关处理 Web 服务器请求的更多信息,请参见 ASP.NET 应用程序生命周期概述。浏览器
HTTP 处理程序能够是同步的也能够是异步的。同步处理程序在完成对为其调用该处理程序的 HTTP 请求的处理后才会返回。异步处理程序运行进程的行为与向用户发送响应无关。当您须要启动一个可能耗费很长时间的应用程序进程,而用户又无需等候进程完成以便从服务器获取响应时,异步处理程序很是有用。 缓存
ASP.NET 中的内置 HTTP 处理程序 服务器
ASP.NET 根据文件扩展名将 HTTP 请求映射到 HTTP 处理程序。每一个 HTTP 处理程序都可以处理应用程序中的单个 HTTP URL 或 URL 扩展名组。ASP.NET 包括几种内置的 HTTP 处理程序,以下表所列。 app
处理程序异步 |
说明async |
ASP.NET 页处理程序 (*.aspx)性能 |
用于全部 ASP.NET 页的默认 HTTP 处理程序。 |
Web 服务处理程序 (*.asmx) |
用于使用 ASP.NET 建立的 Web 服务页的默认 HTTP 处理程序。 |
ASP.NET 用户控件处理程序 (*.ascx) |
用于全部 ASP.NET 用户控件页的默认 HTTP 处理程序。 |
跟踪处理程序 (trace.axd) |
显示当前页跟踪信息的处理程序。有关详细信息,请参见如何:使用跟踪查看器查看 ASP.NET 跟踪信息。 |
如上面配置所示,.NET Framework配置中添加的Handler,实际后面还跟了一堆,不过都是同一种HttpFrobiddenHandler
建立自定义 HTTP 处理程序
若要建立一个自定义 HTTP 处理程序,能够建立一个可实现 IHttpHandler 接口的类以建立同步处理程序,或者建立一个可实现 IHttpAsyncHandler的类以建立异步处理程序。两种处理程序接口都要求您实现 IsReusable 属性和 ProcessRequest 方法。IsReusable 属性指定 IHttpHandlerFactory对象(实际调用适当处理程序的对象)是否能够将您的处理程序放置在池中,而且从新使用它们以提升性能,或是否在每次须要处理程序时都必须建立新实例。ProcessRequest 方法负责实际处理单个 HTTP 请求。
建立文件扩展名
建立一个类文件做为您的 HTTP 处理程序时,可让您的处理程序响应还没有在 IIS 和 ASP.NET 中映射的任何文件扩展名。例如,若是您在建立用于生成 RSS 源的 HTTP 处理程序,则能够将处理程序映射到扩展名 .rss。为了让 ASP.NET 知道哪一个处理程序将用于您的自定义文件扩展名,必须在 IIS 中将处理程序类文件的扩展名映射到 ASP.NET,而且在您的应用程序中将该扩展名映射到您的自定义处理程序。
默认状况下,ASP.NET 为自定义 HTTP 处理程序映射文件扩展名 .ashx 的方式与将扩展名 .aspx 映射到 ASP.NET 页处理程序的方式相同。所以,若是您建立具备文件扩展名 .ashx 的 HTTP 处理程序类,该处理程序将自动注册到 IIS 和 ASP.NET。
若是想要为您的处理程序建立自定义文件扩展名,则必须显式将该扩展名注册到 IIS 和 ASP.NET。不使用文件扩展名 .ashx 的好处是您的处理程序随后能够从新用于其余扩展名映射。例如,在某个应用程序中,您的自定义处理程序可能响应以 .rss 结尾的请求,而在另外一个应用程序中,您的自定义处理程序可能响应以 .feed 结尾的请求。再举一例,您的处理程序可能映射到同一应用程序中的两个文件扩展名,但可能基于扩展名建立两个不一样的响应。
下面经过一个例子来演示httpHandler的创建,注册以及效果
在App_Code中添加类ApkHandler实现接口IHttpHandler
namespace FastDoge.Study { public class ApkHandler : IHttpHandler { public void ProcessRequest(HttpContext context) { HttpRequest Request = context.Request; HttpResponse Response = context.Response; // This handler is called whenever a file ending // in .sample is requested. A file with that extension // does not need to exist. Response.Write("<html>"); Response.Write("<body>"); Response.Write("<h1>Hello from a synchronous custom HTTP handler.</h1>"); Response.Write("</body>"); Response.Write("</html>"); } public bool IsReusable { // To enable pooling, return true here. // This keeps the handler in memory. get { return false; } } } }
接着到Web.config中注册Hanler,这里对于两个不一样版本的IIS也会有出入
在 IIS 6.0 和 IIS 7.0 经典模式下运行的Web.config添加如下配置
<httpHandlers> <add verb="*" path="*.apk" type="FastDoge.Study.ApkHandler" /> </httpHandlers>
verb指定谓词列表能够是逗号分隔的 HTTP 谓词列表(例如,"GET, PUT, POST"),也能够是开始脚本映射(如星号 [*] 通配符)。
path:指定路径属性能够包含单个 URL 路径或简单的通配符字符串(如 *.aspx)。
type:指定逗号分隔的类/程序集组合。ASP.NET 首先在应用程序的专用 \bin 目录中搜索程序集 DLL,而后在系统程序集缓存中搜索程序集 DLL。
IIS7集成模式配置以下
<system.webServer> <handlers> <add name="ApkHandler" verb="*" path="*.apk" type="FastDoge.Study.ApkHandler" resourceType="Unspecified" /> </handlers> </system.webServer>
在运行后在浏览器中输入一个以apk为后缀的url
在MSDN中提到的能够在IIS中经过图形界面注册,这里就不尝试了,可参考https://msdn.microsoft.com/zh-cn/library/bb515343(v=vs.100).aspx。固然若是不在配置文件中添加,要是在HttpModule中指定,要与HttpModule耦合在一块儿的话就如上篇所说调用HttpContext.RemapHandler方法,如在上篇提到的MyModule类中做如下改动
private void Application_BeginRequest(Object source, EventArgs e) { HttpApplication application = (HttpApplication)source; HttpContext context = application.Context; context.Response.Write("<h1><font color=red>" + "HelloWorldModule: Beginning of Request" + "</font></h1><hr>"); string filePath = context.Request.FilePath; string fileExtension = VirtualPathUtility.GetExtension(filePath); if (fileExtension.Equals(".apk", StringComparison.InvariantCultureIgnoreCase) && context.Request.HttpMethod.Equals("GET")) { context.RemapHandler(new ApkHandler()); } }
去掉Web.config的配置,访问以上URL有一样的效果。
异步 HTTP 处理程序
利用异步 HTTP 处理程序能够启动一个外部进程(例如对远程服务器的方法调用),而后继续处理程序的处理工做,而无需等待外部进程结束。在异步 HTTP 处理程序的处理期间,ASP.NET 将一般用于外部进程的线程放回线程池中,直处处理程序收到来自外部进程的回调。这样能够避免阻止线程,并大幅改善了性能,由于一次所能执行的线程数量是有限的。若是许多用户都在请求依赖于外部进程的同步 HTTP 处理程序,那么操做系统可能很快就会用完全部线程,由于大量线程被阻止,正在等待外部进程。
建立异步处理程序时,除了实现 IHttpAsyncHandler 接口,还必须实现 BeginProcessRequest 以启动异步调用来处理单个 HTTP 请求。还必须实现 EndProcessRequest 方法,以便在进程结束时运行清理代码。
下面则定义了一个AsyncApkHandler的异步处理程序,在BeginProcessRequest时调用一个AsynchOperation,该类实现IAsyncResult接口,须要异步操做的代码在方法StartAsyncWork()中调用
namespace FastDoge.Study { public class AsyncApkHandler : IHttpAsyncHandler { public bool IsReusable { get { return false; } } public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, Object extraData) { context.Response.Write("<p>Begin IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + " " + DateTime.Now + " " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n"); AsynchOperation asynch = new AsynchOperation(cb, context, extraData); asynch.StartAsyncWork(); return asynch; } public void EndProcessRequest(IAsyncResult result) { if (result is AsynchOperation) { (result as AsynchOperation).Context.Response.Write("<p>End IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + " "+DateTime.Now+" " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n"); } } public void ProcessRequest(HttpContext context) { throw new InvalidOperationException(); } } class AsynchOperation : IAsyncResult { private bool _completed; private Object _state; private AsyncCallback _callback; private HttpContext _context; bool IAsyncResult.IsCompleted { get { return _completed; } } WaitHandle IAsyncResult.AsyncWaitHandle { get { return null; } } Object IAsyncResult.AsyncState { get { return _state; } } bool IAsyncResult.CompletedSynchronously { get { return false; } } public HttpContext Context { get { return _context; } } public AsynchOperation(AsyncCallback callback, HttpContext context, Object state) { _callback = callback; _context = context; _state = state; _completed = false; } public void StartAsyncWork() { ThreadPool.QueueUserWorkItem(new WaitCallback(StartAsyncTask), null); } private void StartAsyncTask(Object workItemState) { Thread.Sleep(3000); _context.Response.Write("<p>Completion IsThreadPoolThread is " + Thread.CurrentThread.IsThreadPoolThread + " " + DateTime.Now + " " + Thread.CurrentThread.ManagedThreadId + "</p>\r\n"); _context.Response.Write("Hello World from Async Handler!"); _completed = true; _callback(this); } } }
配置方式如以前的方式。效果以下
自定义 IHttpHandlerFactory 类
IHttpHandlerFactory 类接收请求并负责向相应的 HTTP 处理程序转发请求。您能够经过建立一个实现了 IHttpHandlerFactory 接口的类来建立自定义 HTTP 处理程序工厂。建立自定义处理程序工厂能够更好地控制对 HTTP 请求的处理,由于这样能够基于运行时条件建立不一样的处理程序。例如,使用自定义 HTTP 处理程序工厂,能够在 HTTP 请求方法为 PUT 时为某个文件类型实例化一个 HTTP 处理程序,而在该方法为 GET 时实例化另外一个 HTTP 处理程序。又例如,经过使用 HTTP 处理程序工厂,能够建立有限数量的 HTTP 处理程序对象,来访问诸如数据库链接等昂贵或有限的资源。而后,能够在之后的请求中重用这些处理程序对象。
IHttpHandlerFactory 有两个方法
IHttpHandler GetHandler:返回实现 System.Web.IHttpHandler 接口的类的实例;
void ReleaseHandler:使工厂能够重用现有的处理程序实例。
下面则定义个ApkHanlderFactory,同时在ApkHandler 输出的内容上有稍做修改(输出当前HttpHandler的HashCode)
namespace FastDoge.Study { public class ApkHanlderFactory : IHttpHandlerFactory { private ApkHandler _cacheHandler; private ApkHandler CacheHandler { get { if (_cacheHandler == null) { _cacheHandler = new ApkHandler(); } return _cacheHandler; } } public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated) { if (context.Request.QueryString.AllKeys.Contains("IsCache") && context.Request["IsCache"].ToLower().Equals("true", StringComparison.InvariantCultureIgnoreCase)) { return CacheHandler; } return new ApkHandler(); } public void ReleaseHandler(IHttpHandler handler) { } } }
配置文件方面与注册IHttpHandler基本一致,只是type特性中填写的是实现IHttpHandlerFactory接口的类名,可是在Module中经过编码的形式指定的方式暂时没找到,估计须要看源码了。
请求URL以下URL时,响应的html内容一直不变
若是去除IsCache参数时,内容则每次都在变化。
参考内容
HTTP 处理程序介绍
来自 <https://msdn.microsoft.com/zh-cn/library/ms227675(v=vs.100).aspx>
HTTP 处理程序和 HTTP 模块概述
来自 <https://msdn.microsoft.com/zh-cn/library/bb398986(v=vs.100).aspx>