ASP.NET 由于采用了管道式设计,具有很好的扩展性。整个ASP.NET MVC应用框架就是通过扩展ASP.NET实现的。通过ASP.NET的管道设计,我们知道,ASP.NET的扩展点主要是体现在HttpModule和HttpHandler这两个核心组件之上,实际上整个ASP.NET MVC的框架就是通过自定义的HttoModule和HttpHandler建立起来的。

当然,要从整体上把握ASP.NET MVC 的工作机制,我们可以通过查看其源码或自己实现一个“迷你版”的ASP.NET MVC 来了解其运行原理。

RouteData

ASP.NET定义了一个全局的路由表,路由表中的每个路由对象报刊一个URL模板。目标Controller和Action的名称可以通过路由变量以占位符(比如“{controller}”和“{action}”)定义在URL模板中,也可以作为路有对象的默认值。对于每一个抵达的HTTP请求,ASP.NET MVC会便利路由表找到一个具有与当前请求URL模式相匹配的路由对象,并最终解析出以Controller和Action名称为核心的路由数据。

   1:      public class RouteData
   2:      {
   3:          /// <summary>
   4:          /// 变量列表
   5:          /// </summary>
   6:          public IDictionary<string, object> Values { get; private set; }
   7:   
   8:          /// <summary>
   9:          /// 其他来源的变量列表
  10:          /// </summary>
  11:          public IDictionary<string, object> DataTokens { get; private set; }
  12:   
  13:          public IRouteHandler RouteHandler { get; set; }
  14:   
  15:          public RouteBase Route { get; set; }
  16:   
  17:          public RouteData()
  18:          {
  19:              this.Values = new Dictionary<string, object>();
  20:              this.DataTokens = new Dictionary<string, object>();
  21:              this.DataTokens.Add("namespaces", new List<string>());
  22:          }
  23:   
  24:          /// <summary>
  25:          /// 获取控制器名称
  26:          /// </summary>
  27:          public string Controller
  28:          {
  29:              get
  30:              {
  31:                  object controllerName = string.Empty;
  32:                  this.Values.TryGetValue("controller", out controllerName);
  33:                  return controllerName.ToString();
  34:              }
  35:          }
  36:   
  37:          /// <summary>
  38:          /// 获取方法名称
  39:          /// </summary>
  40:          public string ActionName
  41:          {
  42:              get
  43:              {
  44:                  object actionName = string.Empty;
  45:                  this.Values.TryGetValue("action", out actionName);
  46:                  return actionName.ToString();
  47:              }
  48:          }
  49:      }

RouteData的RouteHandler属性类型为IRouteHandler接口,该接口具有一个GetHttpHandler方法,用于返回真正用于处理HTTP请求的HttpHandler对象。

   1:      public interface IRouteHandler
   2:      {
   3:          IHttpHandler GetHttpHandler(RequestContext requestContext);
   4:      }

IRouteHandler接口的GetHttpHandler方法接受一个类型为RequestContext的参数,RequestContext表示当前HTTP请求的上下文,其核心就是对当前HttpContext和RouteData的封装。

   1:      public class RequestContext
   2:      {
   3:          public virtual HttpContextBase HttpContext { get; set; }
   4:   
   5:          public virtual RouteData RouteData { get; set; }
   6:      }

Route和RouteTable

RouteData具有一个类型为RouteBase的Route属性,该属性表示生成路由数据对应的路由对象。RouteBase是一个抽象类,它包含一个GetRouteData的方法,该方法用于判断是否与当前请求相匹配。并在匹配的情况下返回用于封装路由数据的RoutData对象。该方法接受一个表示当前HTTP上下文的HttpContextBase对象,如果与当前请求不匹配,则返回null。

   1:      public abstract class RouteBase
   2:      {
   3:          public abstract RouteData GetRouteData(HttpContextBase httpContext);
   4:      }

ASP.NET MVC 提供的基于URL模板的路由机制是通过其子类Route实现的。

   1:      public class Route : RouteBase
   2:      {
   3:   
   4:          public IRouteHandler RouteHandler { get; set; }
   5:   
   6:          public string Url { get; set; }
   7:   
   8:          public IDictionary<string, object> DataTokens { get; set; }
   9:   
  10:          public Route()
  11:          {
  12:              this.DataTokens = new Dictionary<string, object>();
  13:              this.RouteHandler = new MvcRouteHandler();
  14:          }
  15:   
  16:          public override RouteData GetRouteData(System.Web.HttpContextBase httpContext)
  17:          {
  18:              IDictionary<string, object> variables;
  19:              if(this.Match(httpContext.Request.AppRelativeCurrentExecutionFilePath.Substring(2),out variables))
  20:              {
  21:                  RouteData routeData = new RouteData();
  22:                  foreach (var item in variables)
  23:                  {
  24:                      routeData.Values.Add(item.Key, item.Value);
  25:                  }
  26:                  routeData.RouteHandler = this.RouteHandler;
  27:                  return routeData;
  28:              }
  29:              return null;
  30:          }
  31:   
  32:          public bool Match(string requestUrl, out IDictionary<string, object> variables)
  33:          {
  34:              variables = new Dictionary<string, object>();
  35:              string[] strArray1 = requestUrl.Split('/');
  36:              string[] strArray2 = this.Url.Split('/');
  37:              if (strArray1.Length != strArray2.Length)
  38:              {
  39:                  return false;
  40:              }
  41:              for (int i = 0; i < strArray2.Length; i++)
  42:              {
  43:                  if (strArray2[i].StartsWith("{") && strArray2[i].EndsWith("}"))
  44:                  {
  45:                      variables.Add(strArray2[i].Trim("{}".ToCharArray()), strArray1[i]);
  46:                  }
  47:                  else
  48:                  {
  49:                      if(string.Compare(strArray1[i],strArray2[i],true)!=0)
  50:                      {
  51:                          return false;
  52:                      }
  53:                  }
  54:              }
  55:              return true;
  56:          }
  57:      }

由于同一个Web应用可以采用多种不同的URL模式,所欲需要注册多个继承自RouteBase的路由对象,多个路由对象组成一个路由表。

   1:      public class RouteTable
   2:      {
   3:          public static RouteDictionary Routes { get; private set; }
   4:   
   5:          static RouteTable()
   6:          {
   7:              Routes = new RouteDictionary();
   8:          },
   9:      }

RouteDictionary表示一个具名的路由对象列表。这里我们让它继承自Dictionary<string,RouteBase>,其中key表示路由对象的注册名称。在System.Web.Routing中,它实际上是继承自RouteCollection对象。

   1:      public class RouteDictionary:Dictionary<string,RouteBase>
   2:      {
   3:          public RouteData GetRouteData(HttpContextBase httpContext)
   4:          {
   5:              foreach (var route in this.Values)
   6:              {
   7:                  RouteData routeData = route.GetRouteData(httpContext);
   8:                  if (routeData != null)
   9:                  {
  10:                      return routeData;
  11:                  }
  12:              }
  13:              return null;
  14:          }
  15:      }

UrlRoutingModule

路由表的作用是对当前的HTTP请求的URL进行解析,从而获取一个以Controller和Action名称为核心的路由数据,即上面介绍的RouteData对象。整个解析过程是通过一个类型为UrlRoutingModule的自定义HttpModule来完成的。

   1:      public class UrlRoutingModule:IHttpModule
   2:      {
   3:          public void Dispose()
   4:          {
   5:              
   6:          }
   7:   
   8:          public void Init(HttpApplication context)
   9:          {
  10:              context.PostResolveRequestCache += OnPostResolveRequestCache;
  11:          }
  12:   
  13:          protected virtual void OnPostResolveRequestCache(object sender, EventArgs e)
  14:          {
  15:              HttpContextWrapper httpContext = new HttpContextWrapper(HttpContext.Current);
  16:              RouteData routeData = RouteTable.Routes.GetRouteData(httpContext);
  17:              if (routeData == null)
  18:              {
  19:                  return;
  20:              }
  21:              RequestContext requestContext = new RequestContext
  22:              {
  23:                  RouteData = routeData,
  24:                  HttpContext = httpContext
  25:              };
  26:              IHttpHandler handler = routeData.RouteHandler.GetHttpHandler(requestContext);
  27:              httpContext.RemapHandler(handler);
  28:          }
  29:      }

当PostResolveRequestCache事件触发之后,UrlRoutingModule通过RouteTable的静态子都属性Routes得到表示全局路由表的RouteDictionary对象,然后调用其GetRouteData方法并传入用于封装当前HttpContext的HttpContextWrapper对象,最终得到一个封装路由数据的RouteData对象。然后根据该对象和之前得到的HttpContextWrapper对象创建一个表示当前请求上下文的RequestContext对象并将其作为参数传入RouteData和RouteHandler的GetHttpHandler方法中,得到一个HttpContext对象,最后我们调用HttpContextWrapper对象的RemapHandler将Handler重新映射,使之用于对当前HTTP请求进行处理。

本学习内容和代码来自《ASP.NET MVC 4 框架揭秘》

ASP.NET 学习小记 -- “迷你”MVC实现(1)的更多相关文章

  1. ASP.NET 学习小记 -- “迷你”MVC实现(2)

    Controller的激活 ASP.NET MVC的URL路由系统通过注册的路由表对HTTO请求进行解析从而得到一个用户封装路由数据的RouteData对象,而这个过程是通过自定义的UrlRoutin ...

  2. <转>ASP.NET学习笔记之MVC 3 数据验证 Model Validation 详解

    MVC 3 数据验证 Model Validation 详解  再附加一些比较好的验证详解:(以下均为引用) 1.asp.net mvc3 的数据验证(一) - zhangkai2237 - 博客园 ...

  3. ASP.NET学习笔记1—— MVC

    MVC项目文件夹说明 1.App_Data:用来保存数据文件 2.App_Start:包含ASP.NET-MVC系统启动的相关类文件 3.Controllers:存放整个项目"控制器&quo ...

  4. asp.net学习资料,mvc学习资料

    http://www.asp.net/mvc/tutorials/getting-started-with-aspnet-mvc3/cs/adding-validation-to-the-model

  5. asp.net学习资源汇总

    名称:快速入门地址:http://chs.gotdotnet.com/quickstart/描述:本站点是微软.NET技术的快速入门网站,我们不必再安装.NET Framework中的快速入门示例程序 ...

  6. 迷你 MVC

    深入研究 蒋金楠(Artech)老师的 MiniMvc(迷你 MVC),看看 MVC 内部到底是如何运行的 2014-04-05 13:52 by 自由的生活, 645 阅读, 2 评论, 收藏, 编 ...

  7. 深入研究 Mini ASP.NET Core(迷你 ASP.NET Core),看看 ASP.NET Core 内部到底是如何运行的

    前言 几年前,Artech 老师写过一个 Mini MVC,用简单的代码告诉读者 ASP.NET MVC 内部到底是如何运行的.当时我研究完以后,受益匪浅,内心充满了对 Artech 老师的感激,然后 ...

  8. ASP.NET Core 2.0 MVC项目实战

    一.前言 毕业后入职现在的公司快有一个月了,公司主要的产品用的是C/S架构,再加上自己现在还在学习维护很老的delphi项目,还是有很多不情愿的.之前实习时主要是做.NET的B/S架构的项目,主要还是 ...

  9. ASP.NETCore学习记录(一)

    ASP.NETCore学习记录(一) asp.net core介绍  Startup.cs  ConfigureServices  Configure  0. ASP.NETCore 介绍 ASP.N ...

随机推荐

  1. 初学Node.js第一天

    最近开始下班到家不知道该做啥,因为水平太菜,要学的东西实在太多,反而陷入了不知道该学什么的困境,结果天天就是看别人的博客,看到什么标题比较感兴趣就点进去,没有一个目标. 今天突然兴起,决定要捣鼓捣鼓N ...

  2. [C++]对象的销毁机制

    销毁时会按照从后向前的顺序销毁,也就是说,越在后面定义的对象会越早销毁.其中的原因就是函数是在栈中保存的,因此,先定义的对象先压栈,所以在退栈时就会后销毁.而如果参数有多个的话,大多数编译器是从右开始 ...

  3. velocity properties

    resource.loader=webapp webapp.resource.loader.class=org.apache.velocity.tools.view.servlet.WebappLoa ...

  4. 如何让PHP支持Redis

    原理:php默认扩展库不含有redis扩展:要支持redis扩展,需要有redis.so这个扩展文件 所以我们的目标就是生成redis.so扩展文件,并修改php.ini 让其支持redis扩展. 准 ...

  5. aggregation 详解3(bucket aggregation)

    概述 桶分聚合不进行权值的计算,他们对文档根据聚合请求中提供的判断条件(比如:{"from":0,  "to":100})来进行分组(桶分). 桶分聚合还会额外 ...

  6. c数组和指针的理解

    #include<stdio.h> int main(void) { ,,,,}; ); printf(,*(p-)); // ] = &a; √ // ] = a; × // ] ...

  7. 关于git的基本命令

    git环境的搭建这里就先不说.本篇主要是普通开发工作者在开发过程中所使用的命令. 作为开发者,别人搭建git服务器之后,你呢就配置个人的客户端: 设置Git的配置变量,这个是一次性的工作.即这些设置会 ...

  8. 回环栅栏CyclicBarrier

    通过它可以实现让一组线程等待至某个状态之后再全部同时执行.叫做回环是因为当所有等待线程都被释放以后,CyclicBarrier可以被重用.我们暂且把这个状态就叫做barrier,当调用await()方 ...

  9. mstsc 终端服务器超出了最大允许连接的解决办法

    终端服务器超出了最大允许连接的解决办法   win7系统:运行,输入mstsc /v xxx.xxx.xxx.xxx /admin win2003系统:运行,输入mstsc /v xxx.xxx.xx ...

  10. asp生成静态HTML(动态读取)

    这样的代码多用于我们没有实现设计生成静态的功能,但又想临时将一些动态页面生成静态的,直接获取动态内容并保存为静态的 复制代码代码如下: <!--#include file="admin ...