一、ASP.NET MVC核心机制回顾

  在ASP.NET MVC中,最核心的当属“路由系统”,而路由系统的核心则源于一个强大的System.Web.Routing.dll组件。

  在这个System.Web.Routing.dll中,有一个最重要的类叫做UrlRoutingModule,它是一个实现了IHttpModule接口的类,在请求处理管道中专门针对ASP.NET MVC请求进行处理。首先,我们要了解一下UrlRoutingModule是如何起作用的。

  (1)IIS网站的配置可以分为两个块:全局 Web.config 和本站 Web.config。Asp.Net Routing属于全局性的,所以它配置在全局Web.Config 中,我们可以在如下路径中找到:“$\Windows\Microsoft.NET\Framework\版本号\Config\Web.config“

 <?xml version="1.0" encoding="utf-8"?><!-- the root web configuration file --><configuration><system.web><httpModules><add name="UrlRoutingModule-4.0" type="System.Web.Routing.UrlRoutingModule" /></httpModules></system.web></configuration>

  (2)通过在全局Web.Config中注册 System.Web.Routing.UrlRoutingModule,IIS请求处理管道接到请求后,就会加载 UrlRoutingModule类型的Init()方法。

PS : 在UrlRoutingModule中为请求处理管道中的第七个事件PostResolveRequestCache注册了一个事件处理方法:OnApplicationPostResolveRequestCache。从这里可以看出:ASP.NET MVC的入口在UrlRoutingModule,即订阅了HttpApplication的第7个管道事件PostResolveRequestCahce。换句话说,是在HtttpApplication的第7个管道事件处对请求进行了拦截。

  现在我们将ASP.NET MVC的请求处理分为两个重要阶段来看看:

 ①在第七个事件中创建实现了IHttpHandler接口的MvcHandler

  当请求到达UrlRoutingModule的时候,UrlRoutingModule取出请求中的Controller、Action等RouteData信息,与路由表中的所有规则进行匹配,若匹配,把请求交给IRouteHandler,即MVCRouteHandler。我们可以看下UrlRoutingModule的源码来看看,以下是几句核心的代码:

View Code

  从源码片段中可以看出,最后将请求转移给了实现了IHttpHandler接口的处理程序进行后续的处理。在ASP.NET MVC的实现中,是将请求交给了MvcHandler这个类,通过执行其ProcessRequest方法来进行后续的处理。

 ②在第十一个事件与第十二个事件之间调用MvcHandler的ProcessRequest()方法

  (1)在WebForm中,此阶段会调用Page类对象的ProcessRequest()方法。在ASP.NET MVC中,会调用MvcHandler的ProcessRequest()方法,此方法会激活具体请求的Controller类对象,触发Action方法,返回ActionResult实例

  (2)如果ActionResult是非ViewResult,比如JsonResult, ContentResult,这些内容将直接被输送到Response响应流中,显示给客户端;如果是ViewResult,就会进入下一个渲染视图环节。

  (3)在渲染视图环节,ViewEngine找到需要被渲染的视图,View被加载成WebViewPage<TModel>类型,并渲染生成Html,最终返回Html。

二、我的MVC框架核心部分介绍

2.1 解决方案概览

  在该解决方案中,一共有两个项目:

  一个是App,它是一个由最小化的引用环境(只引用了System和System.Web,以及Mvc.Lib)搭建起来的一个Web应用项目,借助MVC核心类库(Mvc.Lib)实现了MVC模式。

  一个是Lib,它是一个模拟ASP.NET MVC框架的最小化、轻量级的迷你MVC框架,其中Mvc文件夹模拟System.Web.Mvc,Routing文件夹模拟System.Web.Routing,而View则简单地借助NVelocity模板引擎提供View视图服务。

2.2 MVC核心类库

  (1)Routing

  

  从第一部分我们可以知道,ASP.NET MVC的入口在于UrlRoutingModule,因此这里我们便模拟实现了一个UrlRoutingModule.

    /// <summary>/// 解析请求中的路由数据,并分发请求到Handler/// </summary>public class UrlRoutingModule : IHttpModule{public void Init(HttpApplication application){// 注册ASP.NET请求处理管道的第七个事件application.PostResolveRequestCache += Application_PostResolveRequestCache;}// 假设请求 http://www.edisonchou.cn/home/indexprivate void Application_PostResolveRequestCache(object sender, EventArgs e){var application = sender as HttpApplication;var context = application.Context;// 根据全局路由表解析当前请求的路径var requestUrl = context.Request.AppRelativeCurrentExecutionFilePath.Substring(2);// 遍历全局路由表中的路由规则解析数据IDictionary<string, object> routeData;var route = RouteTable.MatchRoutes(requestUrl, out routeData);if (route == null){// 404 Not Foundthrow new HttpException(404, "Not Found!");}// 获取处理请求的Handler处理程序if (!routeData.ContainsKey("controller")){// 404 Not Foundthrow new HttpException(404, "Not Found!");}var handler = route.GetRouteHandler(routeData);// 为当前请求指定Handler处理程序
            context.RemapHandler(handler);}public void Dispose(){this.Dispose();}}

  该UrlRoutingModule通过注册ASP.NET请求处理管道的第七个事件,来实现对URL地址进行路由规则的处理,并将最后生成的路由数据交给MvcHandler进行后续处理。这里我省略了ASP.NET MVC源码中MvcRouteHandler生成MvcHandler的步骤,直接丢给MvcHandler处理。

  核心部分有两点,一是路由规则的匹配,二是为请求指定handler。

  在路由规则的匹配中,通过设置路由数据键值对(Dictionary),并将设置好的路有数据传递给MvcHandler。具体的流程如下图所示,这里就不再展示源码,请自行下载DEMO查看:

  (2)Mvc

  在此文件夹中,实现了三个核心的部分:

  ① 最核心的处理者 : MvcHandler

    public class MvcHandler : IHttpHandler{private IDictionary<string, object> routeData;public MvcHandler(IDictionary<string, object> routeData){this.routeData = routeData;}public void ProcessRequest(HttpContext context){var controllerName = routeData["controller"].ToString();// 借助控制器工厂创建具体控制器实例IController controller = DefaultControllerFactory.CreateController(controllerName);// 确保有找到一个Controller处理请求if (controller == null){// 404 Not Found!throw new HttpException(404, "Not Found");}// 封装请求var requestContext = new RequestContext { HttpContext = context, RouteData = routeData };// 开始执行var result = controller.Execute(requestContext);result.Execute(requestContext);}public bool IsReusable{get{return false;}}}

  在MvcHandler类中,主要经历了以下事件:

  ② 花样的返回类型 : ActionResult 以及它的子类们

  在以往的ASP.NET MVC开发中,我们在Action方法的编写中,总会看到它们的返回类型都是以ActionResult为基类的各种Result类型。

    /// <summary>/// Action统一的返回类型/// </summary>public abstract class ActionResult{public abstract void Execute(RequestContext context);}

  因此,这里也实现了ActionResult这个抽象类,并以此为基础实现了ContentResult、JsonResult以及ViewResult。它们的区别就在于是不同的返回类型,因此有不同的处理。

  这里以ContentResult 和 JsonResult 为例,来看看具体做了什么处理。

  [ContentResult]

    public class ContentResult : ActionResult{private string content;private string contentType;public ContentResult(string content, string contentType){this.content = content;this.contentType = contentType;}public override void Execute(RequestContext context){context.HttpContext.Response.Write(content);context.HttpContext.Response.ContentType = contentType;}}

  [JsonResult]

    public class JsonResult : ActionResult{private object paraObj;public JsonResult(object paraObj){this.paraObj = paraObj;}public override void Execute(RequestContext context){JavaScriptSerializer jss = new JavaScriptSerializer();var json = jss.Serialize(paraObj);context.HttpContext.Response.Write(json);context.HttpContext.Response.ContentType = "application/json";}}

  相信有经验的读者一眼就看穿了,因此这里也就不再多说了。

  ③ 路由的扩展者 : RouteExtend

  在以往的ASP.NET MVC开发中,我们会在Global全局应用处理文件中为项目注册路由规则,但却不知道其实我们常用的MapRoute方法其实是一个扩展方法,它并不位于System.Web.Routing这个类库之中,而是位于System.Web.Mvc这个类库之中。

  因此,我们也在Mvc文件夹中实现了一个RouteExtend类,它为RouteTable类的Route集合实现了一个扩展方法:

    /// <summary>/// Route 的扩展方法所在类/// </summary>public static class RouteExtend{/// <summary>/// 指定MvcHandler来处理/// </summary>public static void MapRoute(this IList<Route> source, string urlTemplate, object defaults){MapRoute(source, urlTemplate, defaults, routeData => new MvcHandler(routeData));}/// <summary>/// 通过指定实现了IHttpHandler的处理程序来处理/// </summary>public static void MapRoute(this IList<Route> source, string urlTemplate, object defaults, Func<IDictionary<string, object>, IHttpHandler> handler){source.Add(new Route(urlTemplate, defaults, handler));}}

  可以看出,MvcHandler是在这里传入的(Mvc与Routing是单向依赖)。那么,为什么还要提供一个可传入自定义Handler的接口呢?因为,不同的路由规则有可能需要不同的实现IHttpHandler的处理程序来处理,也不一定就非得是MvcHandler。

  (3)View

  在ASP.NET MVC中提供了aspx与Razor等模板引擎,这里我偷了懒,直接借助了NVelocity模板引擎来实现。因此,这个文件夹中只有一个VelocityHelper类(我直接从网上搜索的),该类可以帮助我们找到指定的HTML并绑定Model实体。

View Code

三、我的MVC框架应用实例

3.1 MVC 应用DEMO介绍

  这是一个ASP.NET 空Web应用项目搭建起来的MVC Web应用项目,它移除了自带的所有引用项目,仅仅保留了System和System.Web,做到了尽可能地“纯净”。通过引入Mvc.Lib核心类库,建立Controller、Model和View文件夹以及对应的类和HTML来实现MVC模式。

  (1)引入Mvc.Lib核心类库之后,需要配置一下Web.config,使UrlRoutingModule能够正常工作:

  <system.web><compilation debug="true" targetFramework="4.5"/><httpRuntime targetFramework="4.5"/><!-- HttpModule配置(IIS6版本) --><httpModules><add name="UrlRoutingModule" type="Manulife.Web.Mvc.Lib.Routing.UrlRoutingModule"/></httpModules></system.web><system.webServer><!-- 配置不去校验是否是集成模式 --><validation validateIntegratedModeConfiguration="false"/><!-- HttpModule配置(IIS7及以上版本) --><modules><add name="UrlRoutingModule" type="Manulife.Web.Mvc.Lib.Routing.UrlRoutingModule"/></modules></system.webServer>

  (2)新建Global全局处理配置,在Application_Start事件中为项目添加路由规则:

    public class Global : System.Web.HttpApplication{protected void Application_Start(object sender, EventArgs e){// 注册路由规则1
            RouteTable.Routes.MapRoute(urlTemplate: "{controller}/{action}/{id}",defaults: new { controller = "Home", action = "Index" });// 注册路由规则2
            RouteTable.Routes.MapRoute(urlTemplate: "{controller}/{action}",defaults: new { controller = "Home", action = "Index" });// 注册路由规则3
            RouteTable.Routes.MapRoute(urlTemplate: "{controller}",defaults: new { controller = "Home", action = "Index" });}}

  (3)看看Controller是怎么写的?是不是很熟悉?

    public class HomeController : ControllerBase{public ActionResult Index(int id, string controller, string action){return new ContentResult(string.Format("<h1>Controller : {0}, Action : {1}, Id : {2}</h1>", controller, action, id), "text/html");}public ActionResult View(){return new ViewResult(new { Id = 1, Name = "Edison Chou", Age = 27, Gender = true });}}

  (4)看看View中的HTML呢?这里使用NVelocity模板引擎提供的语法,操作Model实体对象。

<!DOCTYPE html>
<html>
<head><meta http-equiv="Content-Type" content="text/html; charset=utf-8" /><title>Index - View</title><meta charset="utf-8" />
</head>
<body><h1>User Name : $model.Name</h1><h1>User Age : $model.Age</h1>
</body>
</html>

3.2 MVC 应用DEMO演示

  (1)默认路由 : home/index -> ContentResult

  (2)请求JsonResult

  (3)请求ViewResult

附件下载

  Manulife.Web.Mvc : 点我下载

作者:周旭龙

出处:http://edisonchou.cnblogs.com/

自己动手写一个简单的MVC框架(第二版)相关推荐

  1. 自己动手写一个简单的MVC框架(第一版)

    一.MVC概念回顾 路由(Route).控制器(Controller).行为(Action).模型(Model).视图(View) 用一句简单地话来描述以上关键点: 路由(Route)就相当于一个公司 ...

  2. 如何搭建python框架_从零开始:写一个简单的Python框架

    原标题:从零开始:写一个简单的Python框架 Python部落(python.freelycode.com)组织翻译,禁止转载,欢迎转发. 你为什么想搭建一个Web框架?我想有下面几个原因: 有一个 ...

  3. 自己动手写一个简单的bootloader

    自己动手写一个简单的bootloader 15年10月31日19:44:27 (一) start.S 写这一段代码前,先要清楚bootloader开始的时候都做什么了.无非就是硬件的初始化,我们想要写 ...

  4. 在Java中搭建一个简单的MVC框架

    搭建一个简单的Java MVC框架 一 . 前言 二. 代码实现 1. 思路分析 2. 代码实现 2.1 Controller注解 2.2 RequestMapping注解 2.3 UserContr ...

  5. 搭建一个简单的MVC框架

    背景 为何要用MVC框架?首先我们知道不用框架的话,在javaweb项目中每个请求都要写一个servlet,并且要在web.xml中对每个servlet类的映射作配置,不方便开发,因此引入MVC框架. ...

  6. 学写一个 Java Web MVC 框架(一)

    当前我们介绍的是一个简单的MVC,用8个类即实现完整Spring MVC核心功能,外加其他实用的小功能.它是怎么实现的呢?让我们来一探究竟! 源码在:https://gitee.com/sp42_ad ...

  7. 仿照源码,手写一个自定义 Spring MVC 框架

    毫无疑问,Spring 框架目前已经成为 Java 开发的行业标准,Spring MVC 作为其 Web 解决方案,是所有 Java 开发者都必须掌握的基本技能,理解其底层原理,才能更好地应用它进行实 ...

  8. 学写一个 Java Web MVC 框架(四)

    访问请求处理 当客户端发送一个请求,被自定义的过滤器MvcDispatcher拦截,解析请求地址和参数对象跳转到一个控制器的方法中,然后执行进行逻辑处理后返回响应内容给MvcDispatcher输出, ...

  9. 动手写一个简单版的谷歌TPU

    https://www.toutiao.com/a6701092937394029064/ 谷歌TPU是一个设计良好的矩阵计算加速单元,可以很好的加速神经网络的计算.本系列文章将利用公开的TPU V1 ...

最新文章

  1. 报文如何截取时间_5种报文、8种邻居状态机详解OSPF工作原理
  2. a标签跳页传参,以及截取URL参数
  3. GNU make manual 翻译( 一百零九)
  4. 一种实现(无须root)手机截屏方案
  5. Shift键关闭大小写
  6. 转: databasemetadata 无法获取数据库表备注的解决方法
  7. Feign api调用方式
  8. 大面积召回ES8影响交付 蔚来7月仅交付837辆汽车
  9. 探讨一个好算法——找出一百万个数字中十个最大数字的算法
  10. oc 协议 回调 静态成员_OC中特性、静态成员(static)以及协议的基本知识
  11. 关于国标码最后一位校验码计算方法
  12. Win10极限精简版Tiny10发布:仅占C盘4.3GB
  13. 相机标定—— 张正友标定法(2)
  14. 864. 二维数组区块计数
  15. 大学生面试20个经典问题及回答思路!
  16. python对英雄皮肤进行图片采集~
  17. 什么认证在云计算行业内的含金量最大?考试费用贵不贵?
  18. JS-打开新窗口(window.open)/关闭窗口(window.close)
  19. JAVA之线程和线程池
  20. 日语在线翻译网站大集合- -

热门文章

  1. JSP JavaBean
  2. 利用Python进行数据分析(7) pandas基础: Series和DataFrame的简单介绍 一、pandas 是什么 pandas 是基于 NumPy 的一个 Python 数据分析包,主
  3. ICML论文|这违反直觉的“升噪”方法,反而能很好的解决激活函数梯度弥散的问题
  4. Java8 - Future 接口
  5. 深入理解分布式技术 - 负载均衡实现之一致性哈希算法
  6. 深入理解分布式技术 - 分布式调用跟踪
  7. Spring JDBC-事务方法嵌套调用解读
  8. Spring JDBC-Spring事务管理之ThreadLocal基础知识
  9. matlab仿真疏散,276基于matlab的疏散仿真程序简介
  10. python爬虫抓收费图片_简单的Python抓taobao图片爬虫