httpHandlers与Http处理程序

ASP.NET HTTP 处理程序是响应对 ASP.NET Web 应用程序的请求而运行的过程(一般称为"终结点")。最经常使用的处理程序是处理 .aspx 文件的 ASP.NET 页处理程序。用户请求 .aspx 文件时,页经过页处理程序来处理请求。 html

ASP.NET 页处理程序仅仅是一种类型的处理程序。ASP.NET 还包括其余几种内置的处理程序,例如用于 .asmx 文件的 Web 服务处理程序。 web

若是您须要进行特殊处理(能够在应用程序中使用文件扩展名进行标识),能够建立自定义 HTTP 处理程序。例如,下面的方案就很好地利用了自定义 HTTP 处理程序: 数据库

  • RSS 源   若要为站点建立 RSS 源,能够建立一个可发出 RSS 格式 XML 的处理程序。而后将您应用程序中的 .rss 扩展名(举例)绑定到此自定义处理程序。当用户向站点发送以 .rss 结尾的请求时,ASP.NET 将调用您的处理程序来处理请求。
  • 图像服务器   若是但愿 Web 应用程序可以提供不一样大小的图像,能够编写一个自定义处理程序来调整图像大小,而后将调整后的图像做为处理程序的响应返回给用户。

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>

相关文章
相关标签/搜索