本节内容不是MVC入门教程,主要讲MVC原理,实现一个和ASP.NET MVC类似基本原理的项目.
MVC原理是依赖于ASP.NET管道事件基础之上的.对于这块,可阅读上节内容
MVC简介
随着技术的发展,现在已经将MVC模式等同于三层模式。
如果要严格区分的话,UI层指View
和Controller
,BLL
,DAL
层和模型层都属于Model
中。
在建立MVC
项目的时候,选择空的项目,会建立一个如下的项目结构
由于MVC
具有以下优点
- 性能高,不需要经过复杂的控件生命周期
SEO
,页面干净,没有ViewState
,url
地址没后缀名- 扩展多,
ActionResult
各种子类,轻松返回JSON,string
Razor
视图引擎- …
所以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
请求流程
- 到达
URLModule
的第7个Application
事件 - 首先根据
URL
,找到并创建MVCHandle
(继承IHttpHandle
), - 映射
IHttpHandlehttpContext.RemapHandler(handler)
- 在第11个
Application
事件后,执行MVCHandle
的PR
方法 - 根据
URL
,创建指定Controller
(继承Controller,ControllerBase,IController
),调用IController
的Execute
的方法. - 在
ControllerBase
的Execute
方法的调用抽象方法ExecuteCore
- 在
Controller
的ExecuteCore
方法调用ActionInvoker
(这个属性实现类是ControllerActionInvoker
)的InvokeAction
方法 - 执行
MVC
过滤器 - 调用控制器的方法,得到
ActionResult
- 调用
ActionResult
的ExecuteResult
方法 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.Routing
2个程序集
代码效果
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
和面向接口的编程方式.