分析MVC5原始碼,並實現一個ASP.MVC
本節內容不是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
和麵向介面的程式設計方式.
相關文章
- 如何實現一個 Virtual DOM 及原始碼分析原始碼
- JNI原始碼分析(並實現JNI動態註冊)原始碼
- Vue原始碼分析之實現一個簡易版的VueVue原始碼
- HashMap原始碼實現分析HashMap原始碼
- Seata原始碼分析(一). AT模式底層實現原始碼模式
- 手動實現一個promise(原始碼)Promise原始碼
- 基於vue實現一個簡單的MVVM框架(原始碼分析)VueMVVM框架原始碼
- MVVM原始碼 - 如何實現一個MVVM框架MVVM原始碼框架
- 一個golang並行庫原始碼解析Golang並行原始碼
- 如何實現一個HTTP請求庫——axios原始碼閱讀與分析HTTPiOS原始碼
- HashMap 實現原理與原始碼分析HashMap原始碼
- HashMap實現原理及原始碼分析HashMap原始碼
- Promise 原始碼:實現一個簡單的 PromisePromise原始碼
- OkHttp 3.7原始碼分析(二)——攔截器&一個實際網路請求的實現HTTP原始碼
- Tomcat原始碼分析2 之 Protocol實現分析Tomcat原始碼Protocol
- [Redis原始碼閱讀]實現一個redis命令--nonzerodecrRedis原始碼
- vuex 原始碼:如何實現一個簡單的 vuexVue原始碼
- 從kratos分析BBR限流原始碼實現原始碼
- 《Spring原始碼分析》IOC的實現Spring原始碼
- musl中strlen原始碼實現和分析原始碼
- TCC-Transaction 原始碼分析 —— TCC 實現原始碼
- ConcurrentHashMap 實現原理和原始碼分析HashMap原始碼
- 【MyBatis原始碼分析】外掛實現原理MyBatis原始碼
- 實現一個簡單版本的Vue及原始碼解析(一)Vue原始碼
- 手寫一個Promise,附原始碼分析Promise原始碼
- 五分鐘實現一個chrome外掛(含原始碼)Chrome原始碼
- PhxPaxos原始碼分析——Paxos演算法實現原始碼演算法
- 深度 Mybatis 3 原始碼分析(一)SqlSessionFactoryBuilder原始碼分析MyBatis原始碼SQLSessionUI
- 40行python程式碼,搭建一個網站並實現使用者登陸功能(附原始碼下載)Python網站原始碼
- WiFiAp探究實錄--功能實現與原始碼分析WiFi原始碼
- MVC5使用Angular.Js實現CrudMVCAngularJS
- 動手擼一個ARouter (ARouter原始碼分析)原始碼
- React原始碼分析與實現(一):元件的初始化與渲染React原始碼元件
- WPF原始碼分析系列一:剖析WPF模板機制的內部實現(一)原始碼
- 實現一個簡單版本的vue及原始碼解析(二)Vue原始碼
- 實現一個簡單的視訊聊天室(原始碼)原始碼
- 實現一個簡單的語音聊天室(原始碼)原始碼
- 一對一直播原始碼,實現一個簡單的登入介面原始碼