[ASP.NET]分析MVC5源碼,並實現一個ASP.MVC


本節內容不是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和面向接口的編程方式.


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM