本節內容不是MVC入門教程,主要講MVC原理,實現一個和ASP.NET MVC類似基本原理的項目.
MVC原理是依賴於ASP.NET管道事件基礎之上的.對於這塊,可閱讀上節內容
[ASP.NET]談談IIS與ASP.NET管道
本節目錄:
隨着技術的發展,現在已經將MVC模式等同於三層模式。
如果要嚴格區分的話,UI層指View和Controller,BLL,DAL層和模型層都屬於Model中。
在建立MVC項目的時候,選擇空的項目,會建立一個如下的項目結構

由於MVC具有以下優點
- 性能高,不需要經過復雜的控件生命周期
- SEO,頁面干凈,沒有ViewState,url地址沒后綴名
- 擴展多,ActionResult各種子類,輕松返回JSON,string
- Razor視圖引擎
- ....
所以MVC不得不成為ASP.NET的首選開發
擴展
Action的本質就是方法,只要是public的方法,外部都能訪問到
路由系統
類圖

代碼圖
路由對象

路由系統

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用到的類都實現出來,完全脫離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和面向接口的編程方式.
