zoukankan      html  css  js  c++  java
  • mvc源码解读(3)扩展:asp.net的两大核心组件HttpModule&&HttpHandler

           在前面两篇文章中,我们仅从mvc源码的层次上解析了mvc执行的一些前期准备工作,那么这一篇文章我们将再次深入的探讨一个HTTP请求如何在IIS服务器以及.Net FrameWork环境中被解析并返回给客户端。在处理客户端请求的时候,这里会涉及到两个模块:IIS服务器和.net FrameWork环境。IIS服务器是运行在非托管的环境下,Asp.net管道则是在托管环境下的,两者之间通过ISAPI接口连通在一起。我在前面也讲过mvc其实走的也是asp.net管道,只不过是让UrlRoutingModule 实现了IHttpModule接口,并在Init中注册了PostResolveRequestCache事件,在该事件中进行了相应的扩展使得用于处理HTTP请求的处理器不再是WebForm模式下的页面类的处理器或是一般处理程序,而是MvcHandler处理器。同时后期不再是执行页面生命周期,打造控件树,而是通过视图引擎将处理后的结果返回给用户。

          客户端的请求经过IIS的简单处理之后进入.net FrameWork环境,ISAPIRuntime会接管当前的HTTP请求,ISAPIRuntime首先会创建一个WorkRequest对象用于封装当前的HTTP请求,同时将WorkRequest对象传递给了Asp.net运行时HttpRuntime,到了这里意味着HTTP请求正式的进入到了Asp.net管道,在Asp.net事件管道里面涉及到两个十分重要的组件:HttpModule过滤器和HttpHanlder处理器。我们来一一介绍。

         首先,我们来看HttpModule,其实不论是HttpModule还是HttpHandler都只是一个统称而已,分别代表某一类的过滤器和处理器。所有的HttpModule都必须实现IHttpModule接口,该接口定义如下:

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

    它的强大之处在于它可以订阅任意的管道事件,有能力修改每个阶段的请求,将修改之后的请求交给HttpHandler处理器处理,因此这有可能影响到请求的处理。这主要体现在每一个HttpHandler都要实现了接口里面的Init(),因为web应用程序在启动的时候,会首先在配置文件中读取<modules></modules>节点,获取到相应的HttpModule处理器,并调用HttpModule里面的Init()方法实现订阅事件的目的。废话不多说,我们还是举一个URL重写的例子来讲解HttpModule的用法吧。我们自定义一个Httpmodule---MyUrlModule,让它实现IHttpModule接口,如下面代码所示:

              public class MyUrlModule:IHttpModule    

             { 

                    public void Init(HttpApplication context)        

                     {

                            context.BeginRequest += context_BeginRequest;        

                    }

            void context_BeginRequest(object sender, EventArgs e)        

             {            

                 HttpApplication app = sender as HttpApplication;            

                 app.Context.Response.ContentEncoding = System.Text.Encoding.UTF8;            

                 app.Context.Response.ContentType = "text/html"; 

                app.Context.Response.Write("原始路径为:" + app.Context.Request.Url.AbsolutePath);

                 //将原始路径:NewsPage.aspx/id/4转换为NewsPage.aspx?Id=4--即URL重写的本质://获得原始的路径---请求报文传递过来的URL            

                string sourcePath = app.Context.Request.Url.AbsolutePath+"/id/4"; //将URL进行分割            

                string[] urls = sourcePath.Split('/'); //获得类类名跟后缀名            

                string strClassName = urls[1];            

                string[] strClassAndExtend = strClassName.Split('.'); //获得类名            

                string className = strClassAndExtend[0];//获得后缀名            

                string extend = strClassAndExtend[1]; //获得传递过来的参数            

                string strParas = urls[2];//获得传递过来的参数值            

                string strParasValue = urls[3];//将伪装的静态页转换为动态页面            

                app.Context.RewritePath(className+"."+"aspx"+ "?" + strParas + "=" + strParasValue);        

           }

    同时HttpModule在Web.Config中配置文件的设置如下:

        <system.webServer>
          <modules>
            <add name="url" type="URLModule.MyUrlModule"/>
          </modules>
        </system.webServer>

           这样在web程序初始化的时候或是处理请求的时候都会调用HttpModule的Init事件,因此在这里面我们需要特别注意一点:Asp.net中会为每一个到达管道的请求(不包括只是请求.js,.css或者img等资源)都创建一个HttpApplication对象,当HttpApplication对象初始化的时候都会加载Web.Config中注册的HttpModule节点。而Asp.net中创建的HttpApplication对象并不是唯一的,也就是意味着HttpModule中的Init方法可能会被调用多次,因此对于类似初始化的操作这里还是不适合的。还有一点我们也需要注意,我们要为Httpmodule订阅合适的管道事件。我之前在项目开发的时候就遇到过这样的一个问题:利用Seesion(现在想想用session确实不怎么好)对用户的是否登录进行判断,当时也是订阅BeginRequest事件,但是怎么操作都无法显示预期的效果。后来才发现在PostAcquireRequestState与PostRequestHandlerExecute事件中才开始加载了页面类的Session对象,自然就无法在BeginRequest事件中做用户登录的判断了。

           我们再来看看HttpHandler处理器,所有的HttpHandler都是实现了IHttpHandler接口,HttpHandler是处理所有请求的核心对象。绝大多数的的请求都在PostMapRequestHandler事件中被映射到一个HttpHandler对象, 然后在PreRequestHandlerExecute事件中执行处理过程,因此也常把这类对象称为处理程序,像在WebForm模式下的一般处理程序.ashx和Page就是一个处理器。我个人认为一般处理程序.ashx文件就像一个纯正的处理器,在WebForm编程中,我使用一般处理程序的概率还是很高的,简洁高效且在js或是Ajax中可以直接指定要哪一个一般处理器来处理我们的请求。当然了我们依然也可以创建我们自己的Httphandler处理器,将某一类请求交给我们自己定义的Httphandler处理,这样的话我们就得在Web.Config中注册我们处理器。

     <httpHandlers>
        <add path="/MyTestHttpModule.axd" verb="*" validate="false" type="URL.MyTestHttpModule"/>
      </httpHandlers>

     那么在mvc中HttpHandler处理器就是MvcHandler,并由它处理请求实现了mvc。

     对HttpHandler这一块理解的还不是很透彻,写下愚见,望共勉~~~~

     

     

     

     

  • 相关阅读:
    PyMongo系列一:操作MongoDB
    MongoDB副本集配置系列十一:MongoDB 数据同步原理和自动故障转移的原理
    MongoDB副本集配置系列十:MongoDB local库详解和数据同步原理
    MongoDB副本集配置系列九:MongoDB 常见问题
    MongoDB副本集配置系列八:MongoDB监控
    MySQL模拟:线上误update的恢复
    Atlas+Keepalived系列二:管理Atlas
    BI 系列随笔列表 (SSIS, SSRS, SSAS, MDX, SQL Server)
    数据仓库设计小知识之一个属性的维度设计
    Microsoft 家族新成员 Datazen 移动BI 介绍
  • 原文地址:https://www.cnblogs.com/ghhlyy/p/2880889.html
Copyright © 2011-2022 走看看