ASP.NET-自定义HttpModule与HttpHandler

简介:

在之前的ASP.NET是如何在IIS下工作的这篇文章中介绍了ASP.NET与IIS配合工作的机制,在http请求经过一系列处理后,最后到达ASP.NET管道中,这时,就是Http Modules和HttpHandler出场的时候了。

  再来摆出管道工作时序图来一看:

管道

   

HttpModule

HttpModule是类似于过滤器的作用,可以没有,也可以有任意个,每一个都可以订阅管道事件中的任意个事件,在每个订阅的事件中可自定义功能实现。

HttpModule是实现IHttpModule接口的类。接口如下:

 
  1. public interface IHttpModule  
  2.     {  
  3.         // 摘要:   
  4.         //     处置由实现 System.Web.IHttpModule 的模块使用的资源(内存除外)。  
  5.         void Dispose();  
  6.         //  
  7.         // 摘要:   
  8.         //     初始化模块,并使其为处理请求做好准备。  
  9.         //  
  10.         // 参数:   
  11.         //  context:  
  12.         //  一个 System.Web.HttpApplication,它提供对 ASP.NET 应用程序内所有应用程序对象的公用的方法、属性和事件的访问  
  13.         void Init(HttpApplication context);  
  14.     }  

下面实现一个HttpModule,并订阅管道中的一系列事件,订阅事件就是在Init方法中绑定EventHandler的过程:

代码有点长,因为我把每一个事件都订阅了,这样一来可以清楚的看出哪些事件执行了,这些事件执行的先后顺序是什么。代码如下:

 
  1. public class MyModule : IHttpModule  
  2.     {  
  3.         #region IHttpModule Members  
  4.   
  5.         public void Dispose()  
  6.         {  
  7.             //此处放置清除代码。  
  8.         }  
  9.   
  10.         public void Init(HttpApplication context)  
  11.         {  
  12.             // 下面是如何处理 LogRequest 事件并为其   
  13.             // 提供自定义日志记录实现的示例  
  14.             context.LogRequest += new EventHandler(OnLogRequest);  
  15.             context.BeginRequest += new EventHandler(context_BeginRequest);  
  16.             context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);  
  17.             context.AcquireRequestState += new EventHandler(context_AcquireRequestState);  
  18.             context.AuthorizeRequest += new EventHandler(context_AuthorizeRequest);  
  19.             context.Disposed += new EventHandler(context_Disposed);  
  20.             context.Error += new EventHandler(context_Error);  
  21.             context.EndRequest += new EventHandler(context_EndRequest);  
  22.             context.MapRequestHandler += new EventHandler(context_MapRequestHandler);  
  23.             context.PostAcquireRequestState += new EventHandler(context_PostAcquireRequestState);  
  24.             context.PostAuthenticateRequest += new EventHandler(context_PostAuthenticateRequest);  
  25.             context.PostAuthorizeRequest += new EventHandler(context_PostAuthorizeRequest);  
  26.             context.PostLogRequest += new EventHandler(context_PostLogRequest);  
  27.             context.PostReleaseRequestState += new EventHandler(context_PostReleaseRequestState);  
  28.             context.PostRequestHandlerExecute += new EventHandler(context_PostRequestHandlerExecute);  
  29.             context.PostResolveRequestCache += new EventHandler(context_PostResolveRequestCache);  
  30.             context.PostUpdateRequestCache += new EventHandler(context_PostUpdateRequestCache);  
  31.             context.ReleaseRequestState += new EventHandler(context_ReleaseRequestState);  
  32.             context.RequestCompleted += new EventHandler(context_RequestCompleted);  
  33.             context.ResolveRequestCache += new EventHandler(context_ResolveRequestCache);  
  34.             context.UpdateRequestCache += new EventHandler(context_UpdateRequestCache);  
  35.             context.PreRequestHandlerExecute += new EventHandler(context_PreRequestHandlerExecute);  
  36.             context.PreSendRequestContent += new EventHandler(context_PreSendRequestContent);  
  37.             context.PreSendRequestHeaders += new EventHandler(context_PreSendRequestHeaders);  
  38.             context.PostMapRequestHandler += new EventHandler(context_PostMapRequestHandler);  
  39.   
  40.   
  41.         }  
  42.   
  43.         void context_Error(object sender, EventArgs e)  
  44.         {  
  45.             WriteLog("Error");  
  46.             //HttpContext.Current.Response.Write("Error<br />");  
  47.         }  
  48.   
  49.         void context_UpdateRequestCache(object sender, EventArgs e)  
  50.         {  
  51.             WriteLog("UpdateRequestCache");  
  52.             //HttpContext.Current.Response.Write("UpdateRequestCache<br />");  
  53.         }  
  54.   
  55.         void context_ResolveRequestCache(object sender, EventArgs e)  
  56.         {  
  57.             WriteLog("ResolveRequestCache");  
  58.             // HttpContext.Current.Response.Write("ResolveRequestCache<br />");  
  59.         }  
  60.   
  61.         void context_RequestCompleted(object sender, EventArgs e)  
  62.         {  
  63.             WriteLog("RequestCompleted");  
  64.             // HttpContext.Current.Response.Write("RequestCompleted<br />");  
  65.         }  
  66.   
  67.         void context_ReleaseRequestState(object sender, EventArgs e)  
  68.         {  
  69.             WriteLog("ReleaseRequestState");  
  70.             //HttpContext.Current.Response.Write("ReleaseRequestState<br />");  
  71.         }  
  72.   
  73.         void context_PostUpdateRequestCache(object sender, EventArgs e)  
  74.         {  
  75.             WriteLog("PostUpdateRequestCache");  
  76.             //HttpContext.Current.Response.Write("PostUpdateRequestCache<br />");  
  77.         }  
  78.   
  79.         void context_PostResolveRequestCache(object sender, EventArgs e)  
  80.         {  
  81.             WriteLog("PostResolveRequestCache");  
  82.             //HttpContext.Current.Response.Write("PostResolveRequestCache<br />");  
  83.         }  
  84.   
  85.         void context_PostRequestHandlerExecute(object sender, EventArgs e)  
  86.         {  
  87.             WriteLog("PostRequestHandlerExecute");  
  88.             //HttpContext.Current.Response.Write("PostRequestHandlerExecute<br />");  
  89.         }  
  90.   
  91.         void context_PostReleaseRequestState(object sender, EventArgs e)  
  92.         {  
  93.             WriteLog("PostReleaseRequestState");  
  94.             //HttpContext.Current.Response.Write("PostReleaseRequestState<br />");  
  95.         }  
  96.   
  97.         void context_PostLogRequest(object sender, EventArgs e)  
  98.         {  
  99.             WriteLog("PostLogRequest");  
  100.             //HttpContext.Current.Response.Write("PostLogRequest<br />");  
  101.         }  
  102.   
  103.         void context_PostAuthorizeRequest(object sender, EventArgs e)  
  104.         {  
  105.             WriteLog("PostAuthorizeRequest");  
  106.             //HttpContext.Current.Response.Write("PostAuthorizeRequest<br />");  
  107.         }  
  108.   
  109.         void context_PostAuthenticateRequest(object sender, EventArgs e)  
  110.         {  
  111.             WriteLog("PostAuthenticateRequest");  
  112.             //HttpContext.Current.Response.Write("PostAuthenticateRequest<br />");  
  113.         }  
  114.   
  115.         void context_PostAcquireRequestState(object sender, EventArgs e)  
  116.         {  
  117.             WriteLog("PostAcquireRequestState");  
  118.             //HttpContext.Current.Response.Write("PostAcquireRequestState<br />");  
  119.         }  
  120.   
  121.         void context_MapRequestHandler(object sender, EventArgs e)  
  122.         {  
  123.             WriteLog("MapRequestHandler");  
  124.             //HttpContext.Current.Response.Write("MapRequestHandler<br />");  
  125.         }  
  126.   
  127.         void context_Disposed(object sender, EventArgs e)  
  128.         {  
  129.             WriteLog("Disposed");  
  130.             //HttpContext.Current.Response.Write("Disposed<br />");  
  131.         }  
  132.   
  133.         void context_AuthorizeRequest(object sender, EventArgs e)  
  134.         {  
  135.             WriteLog("AuthorizeRequest");  
  136.             //HttpContext.Current.Response.Write("AuthorizeRequest<br />");  
  137.         }  
  138.   
  139.         void context_AcquireRequestState(object sender, EventArgs e)  
  140.         {  
  141.             WriteLog("AcquireRequestState");  
  142.             //HttpContext.Current.Response.Write("AcquireRequestState<br />");  
  143.         }  
  144.   
  145.   
  146.         void context_PreSendRequestHeaders(object sender, EventArgs e)  
  147.         {  
  148.             WriteLog("PreSendRequestHeaders");  
  149.             //HttpContext.Current.Response.Write("PreSendRequestHeaders<br />");  
  150.         }  
  151.   
  152.         void context_PreSendRequestContent(object sender, EventArgs e)  
  153.         {  
  154.             WriteLog("PreSendRequestContent");  
  155.             //HttpContext.Current.Response.Write("PreSendRequestContent<br />");  
  156.         }  
  157.   
  158.         void context_PreRequestHandlerExecute(object sender, EventArgs e)  
  159.         {  
  160.             WriteLog("PreRequestHandlerExecute");  
  161.             //HttpContext.Current.Response.Write("PreRequestHandlerExecute<br />");  
  162.         }  
  163.   
  164.         void context_EndRequest(object sender, EventArgs e)  
  165.         {  
  166.             WriteLog("EndRequest");  
  167.             //HttpContext.Current.Response.Write("EndRequest<br />");  
  168.         }  
  169.   
  170.         void context_BeginRequest(object sender, EventArgs e)  
  171.         {  
  172.             WriteLog("*******************************************************************************");  
  173.             HttpApplication app = sender as HttpApplication;  
  174.             WriteLog(app.Context.Request.Path);  
  175.             WriteLog("BeginRequest");  
  176.             //HttpContext.Current.Response.Write("BeginRequest<br />");  
  177.         }  
  178.   
  179.         void context_AuthenticateRequest(object sender, EventArgs e)  
  180.         {  
  181.             WriteLog("AuthenticateRequest");  
  182.             //HttpContext.Current.Response.Write("AuthenticateRequest<br />");  
  183.         }  
  184.         #endregion  
  185.   
  186.         public void OnLogRequest(Object source, EventArgs e)  
  187.         {  
  188.             //可以在此处放置自定义日志记录逻辑  
  189.             WriteLog("OnLogRequest");  
  190.             //HttpContext.Current.Response.Write("OnLogRequest<br />");  
  191.         }  
  192.   
  193.         public void context_PostMapRequestHandler(object sender, EventArgs e)  
  194.         {  
  195.             WriteLog("PostMapRequestHandler");  
  196.             //HttpContext.Current.Response.Write("PostMapRequestHandler<br />");  
  197.         }  
  198.   
  199.         public void WriteLog(string message)  
  200.         {  
  201.             string path = @"d:\aspnet\httpmodule.txt";  
  202.             StreamWriter writer = null;  
  203.             if (!File.Exists(path))  
  204.             {  
  205.                 writer = File.CreateText(path);  
  206.             }  
  207.             else  
  208.             {  
  209.                 FileInfo info = new FileInfo(path);  
  210.                 writer = info.AppendText();  
  211.   
  212.             }  
  213.             writer.WriteLine(message);  
  214.   
  215.             writer.Flush();  
  216.             writer.Close();  
  217.         }  
  218.     }  

订阅的事件实现中,将事件名称保存到我本地D盘的一个文本文件中。

代码实现完毕了,下一步就是要代码起作用了,很简单,只需要在web.config中简单配置就可以了。配置中注意IIS7集成模式和IIS7经典模式(包括IIS6)的区别,配置如下:

 
  1. <!--IIS6或者IIS7经典模式-->  
  2. <system.web>  
  3.     <httpModules>  
  4.       <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>  
  5.     </httpModules>  
  6.   </system.web>  
  7. <!--IIS7集成模式-->  
  8. <system.webServer>  
  9.     <modules>  
  10.       <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>  
  11.     </modules>  
  12. </system.webServer>  

如此一来,一个HttpModule及其配置工作就完成了,接下来,发布网站到IIS或者直接在VS中运行,随便访问项目中的一个文件(任何文件类型都可以),我的项目中有一个WebForm2.aspx的页面,我在浏览器中访问这个页面,发现页面是空白的,因为页面中我什么都没写,上面的Module实现中,我把输出全部放到本地D盘的一个文本文件中了,ok,打开那个文本文件。如图:

image

我们看到输出内容,第2行是访问的页面地址,下面依次为订阅的事件输出,我们清楚的看到了事件的执行顺序。

 
  1. BeginRequest                #发出信号表示创建任何给定的新请求。 此事件始终被引发,并且始终是请求处理期间发生的第一个事件  
  2. AuthenticateRequest         #发出信号表示配置的身份验证机制已对当前请求进行了身份验证。 订阅 AuthenticateRequest 事件可确保在处理附加模块或事件处理程序之前对请求进行身份验证  
  3. PostAuthenticateRequest     #预订 PostAuthenticateRequest 事件的功能可以访问由 PostAuthenticateRequest 处理的任何数据  
  4. AuthorizeRequest            #发出信号表示 ASP.NET 已对当前请求进行了授权。 订阅 AuthorizeRequest 事件可确保在处理附加的模块或事件处理程序之前对请求进行身份验证和授权  
  5. PostAuthorizeRequest        #发出信号表示 ASP.NET 已对当前请求进行了授权。 订阅 PostAuthorizeRequest 事件可确保在处理附加的模块或处理程序之前对请求进行身份验证和授权  
  6. ResolveRequestCache         #引发这个事件来决定是否可以使用从输出缓冲返回的内容来结束请求。这依赖于Web应用程序的输出缓冲时怎样设置的  
  7. PostResolveRequestCache     #在 ASP.NET 跳过当前事件处理程序的执行并允许缓存模块满足来自缓存的请求时发生  
  8. MapRequestHandler           #ASP.NET 基础结构使用 MapRequestHandler 事件来确定用于当前请求的请求处理程序  
  9. PostMapRequestHandler       #在 ASP.NET 已将当前请求映射到相应的事件处理程序时发生  
  10. AcquireRequestState         #当 ASP.NET 获取与当前请求关联的当前状态(如会话状态)时发生  
  11. PostAcquireRequestState     #预订 AcquireRequestState 事件的功能可以访问由 PostAcquireRequestState 处理的任何数据  
  12. PreRequestHandlerExecute    #在ASP.NET开始执行HTTP请求的处理程序之前引发这个事件。在这个事件之后,ASP.NET 把该请求转发给适当的HTTP处理程序  
  13. PostRequestHandlerExecute   #在 ASP.NET 事件处理程序(例如,某页或某个 XML Web service)执行完毕时发生  
  14. ReleaseRequestState         #在 ASP.NET 执行完所有请求事件处理程序后发生。 该事件将使状态模块保存当前状态数据  
  15. PostReleaseRequestState     #在 ASP.NET 已完成所有请求事件处理程序的执行并且请求状态数据已存储时发生  
  16. UpdateRequestCache          #当 ASP.NET 执行完事件处理程序以使缓存模块存储将用于从缓存为后续请求提供服务的响应时发生  
  17. PostUpdateRequestCache      #在 ASP.NET 完成缓存模块的更新并存储了用于从缓存中为后续请求提供服务的响应后,发生此事件  
  18. OnLogRequest                #恰好在 ASP.NET 为当前请求执行任何记录之前发生,即使发生错误,也会引发 LogRequest 事件  
  19. PostLogRequest              #在 ASP.NET 处理完 LogRequest 事件的所有事件处理程序后发生  
  20. EndRequest                  #在 ASP.NET 响应请求时作为 HTTP 执行管线链中的最后一个事件发生  
  21. PreSendRequestContent       #恰好在 ASP.NET 向客户端发送内容之前发生,可能发生多次  
  22. PreSendRequestHeaders       #恰好在 ASP.NET 向客户端发送 HTTP 标头之前发生  
  23. RequestCompleted            #在任何托管模块和处理程序执行后,它使模块清理资源  

 

访问一个页面的过程中,依次触发了23个事件,而HttpModule可订阅的事件个数为25个,观察发现,Error和Disposed这两个事件没有触发。Error事件在发生错误的情况下执行,而Disposed事件,当我们关闭刚才打开的页面,再到文本文件里查看,发现Disposed事件出现了,所以Disposed在会话结束后触发。

由于HttpModule的个数可以有多个,我们可以按照上面的方式定义HttpModule实现类,然后再web.config中增加配置项,就可以实现多个HttpModule同时订阅管道事件了。

 

介绍完HttpModule,那么HttpHandler又是什么呢,它又在什么什么时候执行呢?接下来看一下HttpHandler。

HttpHandler

HttpHandler是HTTP请求的处理中心,真正地对客户端请求的服务器页面做出编译和执行,并将处理过后的信息附加在HTTP请求信息流中再次返回到HttpModule中。  
HttpHandler与HttpModule不同,一旦定义了自己的HttpHandler类,那么它对系统的HttpHandler的关系将是“覆盖”关系。

HttpHandler是实IHttpHandler接口的类,IHttpHandler接口定义如下:

 
  1. public interface IHttpHandler  
  2. {  
  3.     // 摘要:   
  4.     //     获取一个值,该值指示其他请求是否可以使用 System.Web.IHttpHandler 实例。  
  5.     //  
  6.     // 返回结果:   
  7.     //     如果 System.Web.IHttpHandler 实例可再次使用,则为 true;否则为 false。  
  8.     bool IsReusable { get; }  
  9.   
  10.     // 摘要:   
  11.     //     通过实现 System.Web.IHttpHandler 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。  
  12.     //  
  13.     // 参数:   
  14.     //   context:  
  15.     //     System.Web.HttpContext 对象,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session  
  16.     //     和 Server)的引用。  
  17.     void ProcessRequest(HttpContext context);  
  18. }  

接口中只有一个属性和一个方法,所以实现一个HttpHandler也很简单,下面实现一个简单的HttpHandler,代码如下:

 
  1. public class MyIISHandler : IHttpHandler  
  2.     {  
  3.         /// <summary>  
  4.         /// 您将需要在网站的 Web.config 文件中配置此处理程序   
  5.         /// 并向 IIS 注册它,然后才能使用它。有关详细信息,  
  6.         /// 请参见下面的链接: http://go.microsoft.com/?linkid=8101007  
  7.         /// </summary>  
  8.         #region IHttpHandler Members  
  9.   
  10.         public bool IsReusable  
  11.         {  
  12.             // 如果无法为其他请求重用托管处理程序,则返回 false。  
  13.             // 如果按请求保留某些状态信息,则通常这将为 false。  
  14.             get { return true; }  
  15.         }  
  16.   
  17.         public void ProcessRequest(HttpContext context)  
  18.         {  
  19.             //在此处写入您的处理程序实现。  
  20.             WriteLog("请求一个asox页面");  
  21.         }  
  22.   
  23.         #endregion  
  24.     }  

上面我实现了一个很简单的HttpHandler类,在ProcessRequest方法中,调用上面的HttpModule类中写文本文件的方法,在文本文件中写入“请求一个asox页面”,没错,是一个asox页面,我自己定义的文件格式,下面我会在web.config中添加配置项:

 
  1. <!--IIS6或者IIS7经典模式-->  
  2.   <system.web>  
  3.     <httpHandlers>  
  4.       <add name="mycustomhandler" path="*.asox" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>  
  5.     </httpHandlers>  
  6.   </system.web>  
  7.    
  8. <!--IIS7集成模式-->  
  9.   <system.webServer>  
  10.     <handlers>  
  11.        <add name="mycustomhandler" path="*.asox" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>  
  12.     </handlers>  
  13.   </system.webServer>  

配置项属性的解释:

path:指定了需要调用处理程序的路径和文件名(可以包含通配符)。“*”、“*.aspx”、“booklist.aspx”、“test1.aspx,test2.aspx”、“*.asox”、“*.txt”。

verb:指定了处理程序支持的HTTP动作。*-支持所有的HTTP动作;“GET”-支持Get操作;“POST”-支持Post操作;“GET, POST”-支持两种操作。

type:用名字空间、类名称和程序集名称的组合形式指定处理程序或处理程序工厂的实际类型。ASP.NET运行时首先搜索bin目录中的DLL,接着在GAC中搜索。

 

接着,发布站点到IIS。打开IIS,找到当前站点的“处理程序映射”,会发现多了刚刚配置的HttpHandler,如图:

2014-04-15_181203

没错,关于对*.asox这种类型的文件,就可以映射到上面创建的HttpHandler来进行处理,观察其它条目发现,像*.aspx、*.ashx的处理程序是System.Web.UI.PageHandlerFactory和System.Web.UI.SimpleHandlerFactory这样的工厂类型。没错,可以指定处理程序为一个HttpHandler,也可以指定为一个抽象工厂类型。先不说工厂类型的事儿,访问一下网站中的asox页面,看一下文本文件的记录情况。

image

起作用了,在HttpModule输出的一堆信息中,夹杂着HttpHandler的输出,当然这仅限于访问asox类型的页面,因为我只对路径为*.asox的文件格式做了设置,修改下配置文件,例如将path=”*.asox”改为path=”*.aspx”,那么ASP.NET对*.aspx页面原有的解析机制将被我们设置的处理程序所覆盖。

 

回到上面的输出内容,我们观察HttpHandler输出内容所在的位置,位于PreRequestHandlerExecute和PostRequestHandlerExecute这两个事件之间,这与HttpApplication类中的管道事件的创建过程有关。

 

前面说到了,处理处理程序可以指定为一个工厂类型,下面,我就创建一个工厂类型的处理程序。

这里所说的工厂类型的处理程序,就是实现了IHttpHandlerFactory接口的类,IHttpHandlerFactory接口定义如下:

 
  1. public interface IHttpHandlerFactory  
  2.     {  
  3.         // 摘要:   
  4.         //     返回实现 System.Web.IHttpHandler 接口的类的实例。  
  5.         //  
  6.         // 参数:   
  7.         //   context:  
  8.         //     System.Web.HttpContext 类的实例,它提供对用于为 HTTP 请求提供服务的内部服务器对象(如 Request、Response、Session  
  9.         //     和 Server)的引用。  
  10.         //  
  11.         //   requestType:  
  12.         //     客户端使用的 HTTP 数据传输方法(GET 或 POST)。  
  13.         //  
  14.         //   url:  
  15.         //     所请求资源的 System.Web.HttpRequest.RawUrl。  
  16.         //  
  17.         //   pathTranslated:  
  18.         //     所请求资源的 System.Web.HttpRequest.PhysicalApplicationPath。  
  19.         //  
  20.         // 返回结果:   
  21.         //     处理请求的新的 System.Web.IHttpHandler 对象。  
  22.         IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated);  
  23.         //  
  24.         // 摘要:   
  25.         //     使工厂可以重用现有的处理程序实例。  
  26.         //  
  27.         // 参数:   
  28.         //   handler:  
  29.         //     要重用的 System.Web.IHttpHandler 对象。  
  30.         void ReleaseHandler(IHttpHandler handler);  
  31.     }  

同样很简单,也是只有两个接口方法,下面是实现这个接口的工厂,代码如下:

 
  1. public class MyHttpHandlerFactory:IHttpHandlerFactory  
  2. {  
  3.         public IHttpHandler GetHandler(HttpContext context, string requestType, string url, string pathTranslated)  
  4.         {  
  5.             //写日志  
  6.             WriteLog(string.Format("requestType:{0}|url:{1}|pathTranslated:{2}", requestType, url, pathTranslated));  
  7.               
  8.             //生成一个IHttpHandler  
  9.             Type t = typeof(MyIISHandler);  
  10.             IHttpHandler handler =  Activator.CreateInstance(t) as IHttpHandler;  
  11.             return handler;  
  12.         }  
  13.   
  14.         public void ReleaseHandler(IHttpHandler handler)  
  15.         {  
  16.         }  
  17. }  

方法中,返回了前面创建的那个HttpHander类,依然调用记录文本文件的方法输出内容,方便观察执行的实际和具体内容。配置文件改改为这个工厂类。

 
  1. <add name="mycustomFactoryHandler" path="*.asox" verb="*" type="fengzheng.MyHttpHandlerFactory,handler_modules"/>  

配置完毕后,访问网站中的asox页面,打开文本文件,内容如下:

image

我们发现,工厂类中构造IHttpHandler接口的方法发生在HttpModule的MapRequestHandler之后,这同样与HttpApplication类中构造管道事件有关。

 

说了这么多,那么,HttpModule和HttpHandler究竟能干什么呢?

HttpModule很常用的一个作用就是Url重写,URLRewriter就是基于HttpModule实现的。

另外,有通过HttpHandler对图片加水印,防止盗链的。

具体的可以参考这篇文章

 

部署网站注意事项:

网站采用.net 4.0集成模式部署,集成模式是一种统一的请求处理管道,它将ASP.NET请求管道与IIS核心管道组合在一起,这种模式能够提供更好的性能,能够实现配置和治理的模块化,而且增加了使用托管代码模块扩展IIS时的灵活性。IIS经典模式与集成模式的区别

集成模式和经典模式的配置文件稍有不同,部署时需要注意针对不同的部署模式,修改配置文件。在vs2013中新建的web应用程序,默认的web.config内容如下:

 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!--  
  3.   有关如何配置 ASP.NET 应用程序的详细信息,请访问  
  4.   http://go.microsoft.com/fwlink/?LinkId=169433  
  5.   -->  
  6. <configuration>  
  7.   <system.web>  
  8.     <compilation debug="true" targetFramework="4.5" />  
  9.     <httpRuntime targetFramework="4.5" />  
  10.   </system.web>  
  11. </configuration>  
  • 按照经典模式部署,配置文件应该如下:
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!--  
  3.   有关如何配置 ASP.NET 应用程序的详细信息,请访问  
  4.   http://go.microsoft.com/fwlink/?LinkId=169433  
  5.   -->  
  6. <configuration>  
  7.   <system.web>  
  8.     <compilation debug="true" targetFramework="4.5" />  
  9.     <httpRuntime targetFramework="4.5" />  
  10.     <httpModules>  
  11.       <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>  
  12.     </httpModules>  
  13.     <httpHandlers>  
  14.       <add name="mycustomhandler" path="*.asox" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>  
  15.     </httpHandlers>  
  16.   </system.web>  
  17. </configuration>  

经典模式经测试总是出现如下错误,500.21 - 模块无法识别:

 
  1. HTTP 错误 500.21 - Internal Server Error  
  2. 处理程序“PageHandlerFactory-ISAPI-4.0_64bit”在其模块列表中有一个错误模块“IsapiModule”  

至于错误原因:目前还不是很清楚。

 

  • 按照集成模式部署,配置文件应该如下,将配置信息放到system.webServer节点之下
 
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <!--  
  3.   有关如何配置 ASP.NET 应用程序的详细信息,请访问  
  4.   http://go.microsoft.com/fwlink/?LinkId=169433  
  5.   -->  
  6. <configuration>  
  7.   <system.web>  
  8.     <compilation debug="true" targetFramework="4.5" />  
  9.     <httpRuntime targetFramework="4.5" />  
  10.   </system.web>  
  11.   <system.webServer>  
  12.     <modules>  
  13.       <add name="mycustommodule" type="fengzheng.MyModule,handler_modules"/>  
  14.     </modules>  
  15.     <handlers>  
  16.       <add name="mycustomhandler" path="*" verb="*" type="fengzheng.MyIISHandler,handler_modules"/>  
  17.     </handlers>  
  18.   </system.webServer>  
  19. </configuration>  
本文转自左正博客园博客,原文链接:http://www.cnblogs.com/soundcode/p/3746236.html ,如需转载请自行联系原作者
相关文章
|
开发框架 JSON .NET
ASP.NET Core 自定义配置警告信息
自定义配置警告信息需要在 startup 类中的 ConfigureService 方法中进行配置示例: // 注册 控制器服务 services.AddControllers(configure: setup => { setup.ReturnHttpNotAcceptable = true; ...
85 0
|
XML 存储 JSON
使用自定义XML配置文件在.NET桌面程序中保存设置
本文将详细介绍如何在.NET桌面程序中使用自定义的XML配置文件来保存和读取设置。除了XML之外,我们还将探讨其他常见的配置文件格式,如JSON、INI和YAML,以及它们的优缺点和相关的NuGet类库。最后,我们将重点介绍我们为何选择XML作为配置文件格式,并展示一个实用的示例。
131 0
|
1月前
|
Windows
.NET 隐藏/自定义windows系统光标
【10月更文挑战第20天】在.NET中,可以使用`Cursor`类来控制光标。要隐藏光标,可将光标设置为`Cursors.None`。此外,还可以通过从文件或资源加载自定义光标来更改光标的样式。例如,在表单加载时设置`this.Cursor = Cursors.None`隐藏光标,或使用`Cursor.FromFile`方法加载自定义光标文件,也可以将光标文件添加到项目资源中并通过资源管理器加载。这些方法适用于整个表单或特定控件。
|
3月前
|
开发框架 .NET Docker
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
【Azure 应用服务】App Service .NET Core项目在Program.cs中自定义添加的logger.LogInformation,部署到App Service上后日志不显示Log Stream中的问题
|
5月前
|
安全 程序员 Shell
老程序员分享:NSIS自定义界面,下载并安装Net.Framework4.8
老程序员分享:NSIS自定义界面,下载并安装Net.Framework4.8
|
5月前
|
存储 分布式计算 大数据
MaxCompute操作报错合集之自定义udf的函数,引用了import net.sourceforge.pinyin4j.PinyinHelper;但是上传资源后,出现报错,是什么原因
MaxCompute是阿里云提供的大规模离线数据处理服务,用于大数据分析、挖掘和报表生成等场景。在使用MaxCompute进行数据处理时,可能会遇到各种操作报错。以下是一些常见的MaxCompute操作报错及其可能的原因与解决措施的合集。
108 0
|
6月前
|
XML API 数据库
七天.NET 8操作SQLite入门到实战 - 第六天后端班级管理相关接口完善和Swagger自定义配置
七天.NET 8操作SQLite入门到实战 - 第六天后端班级管理相关接口完善和Swagger自定义配置
129 0
|
Windows
基于.Net Core实现自定义皮肤WidForm窗口
基于.Net Core实现自定义皮肤WidForm窗口
131 0
|
开发框架 中间件 .NET
ASP.NET CORE 自定义中间件
ASP.NET CORE 自定义中间件
63 0
|
存储
.NET Core - 自定义配置数据源:低成本实现定制化配置方案
.NET Core - 自定义配置数据源:低成本实现定制化配置方案
下一篇
无影云桌面