本节内容不是MVC入门教程,主要讲MVC原理,实现一个和ASP.NET MVC类似基本原理的项目.

MVC原理是依赖于ASP.NET管道事件基础之上的.对于这块,可阅读上节内容

[ASP.NET]谈谈IIS与ASP.NET管道

本节目录:

MVC简介

随着技术的发展,现在已经将MVC模式等同于三层模式。

如果要严格区分的话,UI层指View和Controller,BLL,DAL层和模型层都属于Model中。

在建立MVC项目的时候,选择空的项目,会建立一个如下的项目结构

由于MVC具有以下优点

  1. 性能高,不需要经过复杂的控件生命周期
  2. SEO,页面干净,没有ViewState,url地址没后缀名
  3. 扩展多,ActionResult各种子类,轻松返回JSON,string
  4. Razor视图引擎
  5. ....

所以MVC不得不成为ASP.NET的首选开发

扩展

Action的本质就是方法,只要是public的方法,外部都能访问到

MVC原理

路由系统

类图

代码图

路由对象

路由系统

RouteTable

路由表,有个RouteDictionary属性,存放RouteBase的实现类Route。通过Route能返回RouteData.

RouteData中包括

路由系统原理

首先添加一条路由对象,路由对象相当于定制一个url模板

然后创建一个Controller工厂,用来反射调用Controller方法,并缓存所有Controller Type,将其赋值给ControllerBuilder,这个是一个单例对象.

UrlRoutingModule

注册第7个事件,并且根据HttpContext(实际就是读取URL),从RouteTable中获取到RouteData,

然后通过RouteData获取IHttpHandler

扩展:

路由系统依赖UrlRoutingModule,而这个在默认配置的Web.config中已经配置,所以路由并不是ASP.Net MVC专属,而是Asp.Net必经之路.

ActionResult

我们的Action实际上就是返回一个ActionResult.

实际上ActionResult是HttpHandle中PR方法最终输出也是最核心的方法.

这里看下ActionResult源码和JsonResult源码

  public abstract class ActionResult
{
public abstract void ExecuteResult(ControllerContext context);
}
  public class JsonResult : ActionResult
{
public object Data { get; set; } public JsonRequestBehavior JsonRequestBehavior { get; set; } public JsonResult()
{
this.JsonRequestBehavior = JsonRequestBehavior.DenyGet;
} public override void ExecuteResult(ControllerContext context)
{
JavaScriptSerializer scriptSerializer = new JavaScriptSerializer();
if (this.MaxJsonLength.HasValue)
scriptSerializer.MaxJsonLength = this.MaxJsonLength.Value;
if (this.RecursionLimit.HasValue)
scriptSerializer.RecursionLimit = this.RecursionLimit.Value;
response.Write(scriptSerializer.Serialize(this.Data));
}
}

MVC请求流程

  1. 到达URLModule的第7个Application事件
  2. 首先根据URL,找到并创建MVCHandle(继承IHttpHandle),
  3. 映射IHttpHandlehttpContext.RemapHandler(handler)
  4. 在第11个Application事件后,执行MVCHandle的PR方法
  5. 根据URL,创建指定Controller(继承Controller,ControllerBase,IController),调用IController的Execute的方法.
  6. 在ControllerBase的Execute方法的调用抽象方法ExecuteCore
  7. 在Controller的ExecuteCore方法调用ActionInvoker(这个属性实现类是ControllerActionInvoker)的InvokeAction方法
  8. 执行MVC过滤器
  9. 调用控制器的方法,得到ActionResult
  10. 调用ActionResult的ExecuteResult方法
  11. Response输出

IController

  public interface IController
{
void Execute(RequestContext requestContext);
}

ControllerBase(精简源码)

    protected virtual void Execute(RequestContext requestContext)
{
this.Initialize(requestContext);
using (ScopeStorage.CreateTransientScope())
this.ExecuteCore();
}

Controller

    protected override void ExecuteCore()
{
this.PossiblyLoadTempData();
try
{
string requiredString = this.RouteData.GetRequiredString("action");
if (this.ActionInvoker.InvokeAction(this.ControllerContext, requiredString))
return;
this.HandleUnknownAction(requiredString);
}
finally
{
this.PossiblySaveTempData();
}
}

ControllerActionInvoker

public virtual bool InvokeAction(ControllerContext controllerContext, string actionName)
{
if (controllerContext == null)
throw new ArgumentNullException("controllerContext");
if (string.IsNullOrEmpty(actionName))
throw new ArgumentException(MvcResources.Common_NullOrEmpty, "actionName");
ControllerDescriptor controllerDescriptor = this.GetControllerDescriptor(controllerContext);
ActionDescriptor action = this.FindAction(controllerContext, controllerDescriptor, actionName);
if (action == null)
return false;
FilterInfo filters = this.GetFilters(controllerContext, action);
try
{
AuthorizationContext authorizationContext = this.InvokeAuthorizationFilters(controllerContext, filters.AuthorizationFilters, action);
if (authorizationContext.Result != null)
{
this.InvokeActionResult(controllerContext, authorizationContext.Result);
}
else
{
if (controllerContext.Controller.ValidateRequest)
ControllerActionInvoker.ValidateRequest(controllerContext);
IDictionary<string, object> parameterValues = this.GetParameterValues(controllerContext, action);
ActionExecutedContext actionExecutedContext = this.InvokeActionMethodWithFilters(controllerContext, filters.ActionFilters, action, parameterValues);
this.InvokeActionResultWithFilters(controllerContext, filters.ResultFilters, actionExecutedContext.Result);
}
}
catch (ThreadAbortException ex)
{
throw;
}
catch (Exception ex)
{
ExceptionContext exceptionContext = this.InvokeExceptionFilters(controllerContext, filters.ExceptionFilters, ex);
if (!exceptionContext.ExceptionHandled)
throw;
else
this.InvokeActionResult(controllerContext, exceptionContext.Result);
}
return true;
}

从这个方法中,也可以看出MVC过滤器的执行顺序.

(MVC没有WebForm的控件生命周期,但是提供过滤器实现类似效果性能更高.)

这个方法中的InvokeActionResult方法实际就是调用

    protected virtual void InvokeActionResult(ControllerContext controllerContext, ActionResult actionResult)
{
actionResult.ExecuteResult(controllerContext);
}

也就到达我们最上面的ActionResult的抽象方法中了.

至此MVC核心源码分析结束了.

实现MVC

看完MVC源码,实现一个MVC源码也很简单,这里我们干脆把路由系统和MVC用到的类都实现出来,完全脱离System.MVC和System.Web.Routing2个程序集

代码效果

Global文件

    public class Global : HttpApplication
{
protected void Application_Start(object sender, EventArgs e)
{
RouteTable.Routes.Add("default", new Route());
}
}

HomeController

    public class HomeController : Controller
{
public ActionResult Index()
{
return Content("Hello World");
}
}

运行效果

性能

后台代码

点击下载

说明:本实现代码主要偏MVCHandle一块

扩展

从微软的源码中可以看出微软偏爱于AOP和面向接口的编程方式.

[ASP.NET]分析MVC5源码,并实现一个ASP.MVC的更多相关文章

  1. 如何分析SpringBoot源码模块及结构?--SpringBoot源码(二)

    注:该源码分析对应SpringBoot版本为2.1.0.RELEASE 1 前言 本篇接 如何搭建自己的SpringBoot源码调试环境?--SpringBoot源码(一). 前面搭建好了自己本地的S ...

  2. Android源码分析--CircleImageView 源码详解

    源码地址为 https://github.com/hdodenhof/CircleImageView 实际上就是一个圆形的imageview 的自定义控件.代码写的很优雅,实现效果也很好, 特此分析. ...

  3. ASP.NET Core 框架源码地址

    ASP.NET Core 框架源码地址 https://github.com/dotnet/corefx 这个是.net core的 开源项目地址 https://github.com/aspnet  ...

  4. 一 分析easyswoole源码(启动服务)

    分析easyswoole源码 1以启动为例 //检查是否已经安装 installCheck();//检查锁文件是否存在,不存在结束 //启动服务 serverStart showLogo();//显示 ...

  5. 分析jQuery源码时记录的一点感悟

    分析jQuery源码时记录的一点感悟      1.  链式写法      这是jQuery语法上的最大特色,也许该改改POJO里的set方法,和其他的非get方法什么的,可以把多行代码合并,减去每次 ...

  6. Linux内核(2) - 分析内核源码如何入手(上)

    透过现象看本质,兽兽们无非就是一些人体艺术展示.同样往本质里看过去,学习内核,就是学习内核的源代码,任何内核有关的书籍都是基于内核,而又不高于内核的. 既然要学习内核源码,就要经常对内核代码进行分析, ...

  7. STM32F103 ucLinux开发之一(BOOT分析及源码)

    STM32F103 ucLinux开发BOOT STM3210E-EVAL官方开发板主芯片STM32F103ZET6: 片内512K Flash,地址0x0800 0000 ~ 0x0807 FFFF ...

  8. Activiti架构分析及源码详解

    目录 Activiti架构分析及源码详解 引言 一.Activiti设计解析-架构&领域模型 1.1 架构 1.2 领域模型 二.Activiti设计解析-PVM执行树 2.1 核心理念 2. ...

  9. JVM源码分析-JVM源码编译与调试

    要分析JVM的源码,结合资料直接阅读是一种方式,但是遇到一些想不通的场景,必须要结合调试,查看执行路径以及参数具体的值,才能搞得明白.所以我们先来把JVM的源码进行编译,并能够使用GDB进行调试. 编 ...

随机推荐

  1. Spark使用总结与分享

    背景 使用spark开发已有几个月.相比于python/hive,scala/spark学习门槛较高.尤其记得刚开时,举步维艰,进展十分缓慢.不过谢天谢地,这段苦涩(bi)的日子过去了.忆苦思甜,为了 ...

  2. nginx-upstream-keepalive;accept_mutex-proxy_http_version-1.1-proxy_set_header-connection

    nginx+resin+redis+mysql的架构: 有外部模拟用户请求的大量攻击:它尝试请求了80就断开:看到的现象是在跑有nginx80的主机上TCP连接数少 : ESTABLISHED少: 在 ...

  3. 解决Maven关于本地jar包的打包处理

    在使用maven进行jar包管理时,通过我们都是通过maven去下载一些jar包,但有些jar在maven上没有,所以就就可能在本地直接手动加入一些需要用到的外部jar包.但如果我们用maven pa ...

  4. ubuntu 12.04 安装Docker 实战

    2016-3-8 从网络服务商那里申请到一台Ubuntu测试服务器,用来测试安装Docker环境. 注:本人初学Docker,对Linux命令也仅是稍稍了解,如有错误,烦请告知. 查看系统相关信息 可 ...

  5. UiAutomator源代码分析之UiAutomatorBridge框架

    上一篇文章<UIAutomator源代码分析之启动和执行>我们描写叙述了uitautomator从命令行执行到载入測试用例执行測试的整个流程.过程中我们也描写叙述了UiAutomatorB ...

  6. Window bat expdp 定时任务逻辑备份 定时删除N天前的旧文件

    点击进入:Linux shell crontab expdp 定时任务逻辑备份 定时删除旧文件 首先建一个备份数据库用批处理文件,内容如下: rem expdp sz set sz_file=SZ_% ...

  7. Source Insight 使用

    1.括号配对高亮:“在前括号左侧,后括号左侧” 双击鼠标左键,可以选定匹配括号和其中内容(<>,(),L{R},[]之间) 2.让{ 和 } 不缩进:Options -> Docum ...

  8. (笔记)Linux内核学习(六)之并发和同步概念

    一 临界区和竞争条件 临界区:访问和操作共享数据的代码段. 竞争条件:多个执行线程处于同一个临界区中. 处于竞争条件:造成访问的数据或者资源不一致状态: 对资源i的访问:ProcessA和B访问后得到 ...

  9. Linux Unix 环境变量设置实例

    背景 从第一次写Hello World我们便开始接触环境变量.这最基础的系统设置是必须要掌握的,尤其在是Linux/Unix系统中.比如,哪天某个Java进程出现问题,我们想分析一下其线程堆栈,却发现 ...

  10. ODAC(V9.5.15) 学习笔记(十七)主从模式

    主从模式(Master/Detail mode)是指建立主表和从表关系的多个数据集集合模式. 1. 关系设置 要设置主从模式,必须有一个主表数据集(TDataSet)和一个从表数据集(TDataSet ...