MVC系列——MVC源碼學習:打造自己的MVC框架(二:附源碼)


前言:上篇介紹了下 MVC5 的核心原理,整篇文章比較偏理論,所以相對比較枯燥。今天就來根據上篇的理論一步一步進行實踐,通過自己寫的一個簡易MVC框架逐步理解,相信通過這一篇的實踐,你會對MVC有一個更加清晰的認識。

本文原創地址:http://www.cnblogs.com/landeanfen/p/6000978.html

MVC源碼學習系列文章目錄:

這篇博主打算從零開始一步一步來加上MVC里面用到的一些技術,整篇通過三個版本,逐步完善。

一、版本一:搭建環境,實現MVC請求

通過上篇的介紹,我們知道,MVC里面兩個最核心的部件:MvcHandler和UrlRoutingModule。現在我們就來一步一步實現它們。為了更加真實,我們完全從零開始。

1、新建一個類庫項目,我們暫且命名為Swift.MVC.

2、新建MvcHandler和UrlRoutingModule

我們新建兩個文件,然后實現IHttpHandler和IHttpModule。我們知道這兩個接口都在System.Web里面,首先我們在類庫項目里面引用Syste.Web這個dll,然后來看具體的代碼。

MvcHandler.cs代碼:

namespace Swift.MVC
{
    public class MvcHandler : IHttpHandler
    {
        public bool IsReusable
        {
            get { return false; }
        }

        public void ProcessRequest(HttpContext context)
        {
            context.Response.Write("當前頁面地址:" + context.Request.Url.AbsoluteUri + "    ");
            context.Response.Write("Hello MVC");
        }
    }
}

UrlRoutingModule.cs代碼:

namespace Swift.MVC
{
    public class UrlRoutingModule : IHttpModule
    {
        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public void Init(HttpApplication app)
        {
            app.PostResolveRequestCache += app_PostResolveRequestCache;
        }

        void app_PostResolveRequestCache(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;

            app.Context.RemapHandler(new MvcHandler());
        }
    }
}

如果你看過博主的上篇,這個應該很好理解。UrlRoutingModule注冊PostResolveRequestCache事件,通過這個事件攔截當前的請求,攔截到請求之后,再交由MvcHandler去處理當前的http請求。整個過程就是這么簡單,我們最最基礎的“框架”就搭好了。

3、新建一個空的Web項目測試Swift.MVC

第一步,新建一個空的Web項目,添加對Swift.MVC的引用,或者直接將Swift.MVC.dll拷貝到web項目的bin目錄下面,兩種方式都行,這里為了方便測試,我們直接添加解決方案中的項目引用。

第二步,配置Web項目的web.config文件。上篇我們就介紹過,HttpHandler和HttpModule的實現類要生效,就必須要在Web.config里面注冊。注冊之后整個Web.config的內容如下:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <system.web>
    <compilation debug="true" targetFramework="4.5" />
    <httpRuntime targetFramework="4.5" />
  </system.web>

<system.webServer>
   <handlers>
        <add name="swifthandler" verb="*" path="*" type="Swift.MVC.MvcHandler, Swift.MVC" preCondition="integratedMode" />
    </handlers>
    <modules>
        <add name="swiftmodule" type="Swift.MVC.UrlRoutingModule, Swift.MVC" preCondition="integratedMode" />
    </modules>
</system.webServer>
</configuration>

 得到結果

 

這里博主想要說明兩點:

  1. 如果你調試程序你會發現,app_PostResolveRequestCache()和ProcessRequest()都進了兩遍,這是因為在web.config里面配置的是所有的請求都會被攔截,添加監視發現原來當我們訪問http://localhost:16792/Home/Index地址的時候實際上是發了兩次請求:
  2. 上篇我們就介紹過 app.Context.RemapHandler(new MvcHandler()); 這一句表示將當前請求交給Mvchandler這個去處理,既然是這里指定的MvcHandler,那我們在Web.config里面配置的 <handlers> 節點還有什么意義呢?也就是說,這里配置的即使是另外一個HttpHandler,那么最終程序還是會轉給MvcHandler,是不是這樣呢?既然我們感覺這里的handlers節點配置了也沒用,那我們將handlers節點去掉再試試呢?結果是去掉handlers節點之后,仍然得到的是上面的結果。這一點說明app.Context.RemapHandler()這一句的優先級要比web.config里面的handlers節點的高。

這里通過以上實現和配置,我們的Swift.MVC已經具有處理http請求的能力,但還不能算一個完整意義上的框架,下面來繼續完善。

二、版本二:完善MvcHandler和UrlRoutingModule

這個版本,UrlRoutingModule我們還是沿用的System.Web.Routing里面的機制,我們主要來看看MvcHandler這部分的實現。

1、UrlRoutingModule的完善

UrlRoutingModule.cs的完整代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;
using System.Web.Routing;

namespace Swift.MVC
{
    public class UrlRoutingModule : IHttpModule
    {
        #region Property
        private RouteCollection _routeCollection;

        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
            Justification = "This needs to be settable for unit tests.")]
        public RouteCollection RouteCollection
        {
            get
            {
                if (_routeCollection == null)
                {
                    _routeCollection = RouteTable.Routes;
                }
                return _routeCollection;
            }
            set
            {
                _routeCollection = value;
            }
        }
        #endregion

        public void Dispose()
        {
            //throw new NotImplementedException();
        }

        public void Init(HttpApplication app)
        {
            app.PostResolveRequestCache += app_PostResolveRequestCache;
        }

        void app_PostResolveRequestCache(object sender, EventArgs e)
        {
            var app = (HttpApplication)sender;
            //0.將HttpContext轉換為HttpContextWrapper對象(HttpContextWrapper繼承HttpContextBase)
            var contextbase = new HttpContextWrapper(app.Context);
            PostResolveRequestCache(contextbase);
        }

        public virtual void PostResolveRequestCache(HttpContextBase context)
        {
            //1.傳入當前上下文對象,得到與當前請求匹配的RouteData對象
            RouteData routeData = this.RouteCollection.GetRouteData(context);
            if (routeData == null)
            {
                return;
            }
            //2.從RouteData對象里面得到當前的RouteHandler對象。
            IRouteHandler routeHandler = routeData.RouteHandler;
            if (routeHandler == null)
            {
                return;
            }

            //3.根據HttpContext和RouteData得到RequestContext對象
            RequestContext requestContext = new RequestContext(context, routeData);
            context.Request.RequestContext = requestContext;

            //4.根據RequestContext對象得到處理當前請求的HttpHandler(MvcHandler)。
            IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext);
            if (httpHandler == null)
            {
                return;
            }

            //5.請求轉到HttpHandler進行處理(進入到ProcessRequest方法)。這一步很重要,由這一步開始,請求才由UrlRoutingModule轉到了MvcHandler里面
            context.RemapHandler(httpHandler);
        }
    }
}

 上述代碼基本都是從Framework源碼里面拷貝出來的,注釋中的0、1、2、3、4、5分別對應着MVC路由過程中的各個步驟,詳見上篇

這里我們自定義了一個實現IRouteHandler的類型,用來返回處理請求的HttpHandler是哪個,比如這里我們定義的MvcRouteHandler返回的HttpHandler是MvcHandler。它的代碼如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Routing;

namespace Swift.MVC
{
    public class MvcRouteHandler:IRouteHandler
    {
        public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new MvcHandler();
        }
    }
}

2、MvcHandler部分的完善

首先還是拋出MvcHandler.cs的源碼:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web;

namespace Swift.MVC
{
    public class MvcHandler : IHttpHandler
    {
        public virtual bool IsReusable
        {
            get { return false; }
        }

        public virtual void ProcessRequest(HttpContext context)
        {
            //寫入MVC的版本到HttpHeader里面
            //AddVersionHeader(httpContext);
            //移除參數
            //RemoveOptionalRoutingParameters();

            //步驟1.從上下文的Request.RequestContext中取到RouteData對象。這里和UrlRoutingModule里面的context.Request.RequestContext = requestContext;對應。
            var routeData = context.Request.RequestContext.RouteData;

            //步驟2.從當前的RouteData里面得到請求的控制器名稱
            string controllerName = routeData.GetRequiredString("controller");

            //步驟3.得到控制器工廠
            IControllerFactory factory = new SwiftControllerFactory();

            //步驟4.通過默認控制器工廠得到當前請求的控制器對象
            IController controller = factory.CreateController(context.Request.RequestContext, controllerName);
            if (controller == null)
            {
                return;
            }

            try
            {
                //步驟5.執行控制器的Action
                controller.Execute(context.Request.RequestContext);
            }
            catch { 
            
            }
            finally
            {
                //步驟6.釋放當前的控制器對象
                factory.ReleaseController(controller);
            }

        }
    }
}

關於上述代碼,我們說明以下幾點。

2.1、關於控制器工廠

上述代碼注釋中的步驟1、2不難理解,就是從配置的路由規則中獲取當前請求控制器的名稱。要理解步驟3,需要先說一說MVC源碼里面的控制器工廠。先來看看源碼里面這段如何實現:

在源碼里面的MvcHandler的ProcessRequest方法里面有這么一句: factory = ControllerBuilder.GetControllerFactory(); 。在MvcHandler里面ControllerBuilder這樣定義:

        internal ControllerBuilder ControllerBuilder
        {
            get
            {
                if (_controllerBuilder == null)
                {
                    _controllerBuilder = ControllerBuilder.Current;
                }
                return _controllerBuilder;
            }
            set { _controllerBuilder = value; }
        }

原來在MvcHandler中創建控制器工廠並不是直接使用IControllerFactroy的實現,而是使用了ControllerBuilder這個對象,這個對象采用了單例模式的實現;MvcHandler通過ControllerBuilder對象獲取到一個實例,然后通過ControllerBuilder創建出IControllerFactory實現,ControllerBuilder管理着IControllerFactory的創建過程。

關於ControllerBuilder里面的GetControllerFactory()方法的實現,我們不必細究,但是我們需要知道的是在MVC里面有一個默認的控制器工廠的實現類DefaultControllerFactory。我們來看看

IControllerFactory接口的定義:

    public interface IControllerFactory
    {
        IController CreateController(RequestContext requestContext, string controllerName);
        SessionStateBehavior GetControllerSessionBehavior(RequestContext requestContext, string controllerName);
        void ReleaseController(IController controller);
    }

DefaultControllerFactory的定義:

public class DefaultControllerFactory : IControllerFactory
    {
         public virtual IController CreateController(RequestContext requestContext, string controllerName)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            if (String.IsNullOrEmpty(controllerName) && !requestContext.RouteData.HasDirectRouteMatch())
            {
                throw new ArgumentException(MvcResources.Common_NullOrEmpty, "controllerName");
            }

            Type controllerType = GetControllerType(requestContext, controllerName);
            IController controller = GetControllerInstance(requestContext, controllerType);
            return controller;
        }
        public virtual void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

        //......
    
    }

上述的兩個方法CreateController()和ReleaseController()通過名字都可以很好理解,分別對應着創建控制器和釋放控制器。

了解了上述MVC里面控制器工廠的實現細節,我們自己也來建一個自己的控制器工廠,不過為了簡化,我們這里直接去new了一個工廠的實現類。先來看看我們Swift.MVC的控制器工廠。

控制器工廠接口:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Routing;

namespace Swift.MVC
{
    //控制器創建工廠
    public interface IControllerFactory
    {
        //創建控制器
        IController CreateController(RequestContext requestContext, string controllerName);
        
        //釋放控制器
        void ReleaseController(IController controller);
    }
}

控制器工廠實現類:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Swift.MVC
{
    public class SwiftControllerFactory:IControllerFactory
    {
        #region Public
        //通過當前的請求上下文和控制器名稱得到控制器的對象
        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            if (string.IsNullOrEmpty(controllerName))
            {
                throw new ArgumentException("controllerName");
            }
            //得到當前的控制類型
            Type controllerType = GetControllerType(requestContext, controllerName);
            if (controllerType == null)
            {
                return null;
            }
            //得到控制器對象
            IController controller = GetControllerInstance(requestContext, controllerType);
            return controller;
        }
            
        //釋放控制器對象
        public void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }
        #endregion

        #region Privates
        //得到當前請求的控制器實例
        private IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            var oRes = Activator.CreateInstance(controllerType) as IController;
            return oRes;
        }

        //得到當前請求的控制器類型
        private Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            //從路由配置信息里面讀取命名空間和程序集
            object routeNamespaces;
            object routeAssembly;
            requestContext.RouteData.Values.TryGetValue("namespaces", out routeNamespaces);
            requestContext.RouteData.Values.TryGetValue("assembly", out routeAssembly);

            //通過反射得到控制器的類型
            var type = Assembly.Load(routeAssembly.ToString()).GetType(routeNamespaces.ToString() + "." + controllerName + "Controller");

            return type;
        }
        #endregion
    }
}

這里博主主要用到了反射去實例化控制器實例。

2.2、控制器的父類實現

上述介紹了控制器工廠的實現。除了控制器工廠,還有我們的控制器接口以及父類的相關實現。

控制器接口的定義:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Web.Routing;

namespace Swift.MVC
{
    public interface IController
    {
        void Execute(RequestContext requestContext);
    }
}

控制器抽象Base類的實現:(這個抽象類的作用更多在於定義一些約束、檢查之類)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Swift.MVC
{
    //這個類主要定義約束
    public abstract class ControllerBase:IController
    {

        public abstract void Execute(System.Web.Routing.RequestContext requestContext);
    }
}

控制器抽象子類的實現:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Swift.MVC
{
    public abstract class Controller:ControllerBase,IDisposable
    {
        public override void Execute(System.Web.Routing.RequestContext requestContext)
        {
            //反射得到Action方法
            Type type = this.GetType();
            string actionName = requestContext.RouteData.GetRequiredString("action");
            System.Reflection.MethodInfo mi = type.GetMethod(actionName);

            //執行該Action方法
            mi.Invoke(this, new object[] { });//調用方法
        }

        public void Dispose()
        {
            //throw new NotImplementedException();
        }
    }
}

這里讓Controller類實現IDispose接口,照應了上文控制器工廠里面的ReleaseController()方法,主要起到釋放資源的作用。

3、測試及代碼釋疑

由於上述代碼用到了System.Web.Routing里面的組件,所以,需要在測試項目里面配置路由規則,這里需要注意一點,我們上面的MvcRouteHandler就是在這里注入進去的。在測試項目里面新建一個全局配置文件如下:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Routing;
using System.Web.Security;
using System.Web.SessionState;

namespace MyTestMVC
{
    public class Global : System.Web.HttpApplication
    {

        protected void Application_Start(object sender, EventArgs e)
        {
            RouteTable.Routes.Add("defaultRoute", new Route("{controller}/{action}/{id}", new RouteValueDictionary(new { controller = "Home", action = "Index", id = "", namespaces = "MyTestMVC.Controllers", assembly = "MyTestMVC" }), new Swift.MVC.MvcRouteHandler()));
        }

        protected void Application_BeginRequest(object sender, EventArgs e)
        {

        }
    }
}

然后在測試項目里面模擬MVC新建一個Controllers文件夾,里面新建一個測試的控制器HomeController:

using Swift.MVC;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace MyTestMVC.Controllers
{
    public class HomeController : Controller
    {
        public void Index()
        {
            HttpContext.Current.Response.Write("Hello MVC");
        }
    }
}

然后啟動項目,訪問http://localhost:16792/Home/Index。運行過程以及代碼釋疑如下:

(1)來看看 RouteData routeData = this.RouteCollection.GetRouteData(context); 這一句

通過上圖可知,this.RouteCollection里面保存的是上述全局配置文件里面添加進去的路由規則,然后調用GetRouteData(context)方法,傳入當前請求的上下文,得到當前請求的RouteData對象,我們可以看到在這個RouteData對象里面,已經包含了當前請求的控制器和action的名稱。

(2)監視 IRouteHandler routeHandler = routeData.RouteHandler; 

通過上圖可以看到在routeData里面我們的RouteHandler已經是MvcRouteHandler對象了,還記得我們在全局配置文件里面有這樣一個配置:

RouteTable.Routes.Add("defaultRoute", new Route("{controller}/{action}/{id}", new RouteValueDictionary(new { controller = "Home", action = "Index", id = "", namespaces = "MyTestMVC.Controllers", assembly = "MyTestMVC" }), new Swift.MVC.MvcRouteHandler()));

在Add方法的最后需要傳一個IRouteHandler的對象,我們上文定義過一個MvcRouteHandler去實現了IRouteHandler,這個MvcRouteHandler在這里就派上用場了,原來我們的RouteHandler是可以自定義的。就是因為這里配置過這個,所以在GetRouteData()方法里面,就將MvcRouteHandler對象給了routeData對象的RouteHandler屬性,終於知道這里的MvcRouteHandler是如何過來的了。這里可配置IRouteHandler也說明了MVC原理的靈活性,我們可以自定義RouteHandler,然后再IRouteHandler接口的GetHttpHandler()方法里面自定義處理當前請求的HttpHandler。

(3) RequestContext requestContext = new RequestContext(context, routeData);context.Request.RequestContext = requestContext; 這兩句看上去不起眼,就是封裝了一個RequestContext對象,然后將它給到了當前上下文的Request.RequestContext。實際上,這里非常重要,因為這個requestContext對象包含了我們當前請求的路由信息,后面MvcHandler里面需要從這里取到當前請求的控制器和Action的名稱,待會看了后面的代碼,你會更加清晰。

(4)再來看 IHttpHandler httpHandler = routeHandler.GetHttpHandler(requestContext); 這一句

 

上文注釋(2) 里面說了,routeHandler對象實際上是一個MvcRouteHandler對象,當它調用GetHttpHandler(),看下定義即可明白:

    public class MvcRouteHandler:IRouteHandler
    {
        public System.Web.IHttpHandler GetHttpHandler(RequestContext requestContext)
        {
            return new MvcHandler();
        }
    }

這里就是返回了一個MvcHandler,用來處理Http請求。

(5) context.RemapHandler(httpHandler); 這一句自然不必多說,請當前攔截到的請求交給MvcHandler的ProcessRequest方法處理,這一句執行完成之后,請求便轉入到MvcHandler的ProcessRequest方法里面。縱觀上述幾個過程,可以說是一環扣一環,每一句都有它的意義所在,最后封裝完成之后,真正處理請求還是在MvcHandler里面。接下來我們來看看ProcessRequest里面的代碼。

(6)下面我們來看看MvcHandler類里面ProcessRequest方法這一句: var routeData = context.Request.RequestContext.RouteData; 。還記得上述注釋3中封裝的RequestContext對象嗎,沒錯,這里就用到了這個對象,我們從這個對象里面取到當前請求的RouteData對象。

(7) string controllerName = routeData.GetRequiredString("controller"); 這一句不難理解:取到當前請求的的Controller名稱。結果如下:

(8)得到控制器工廠這個沒什么說的,為了簡化,我們直接new了一個默認的控制器工廠。下面重點來看看 IController controller = factory.CreateController(context.Request.RequestContext, controllerName); 這一句。在控制器工廠的實現類里面實現了CreateController()這個方法。

        public IController CreateController(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            if (requestContext == null)
            {
                throw new ArgumentNullException("requestContext");
            }

            if (string.IsNullOrEmpty(controllerName))
            {
                throw new ArgumentException("controllerName");
            }
            //得到當前的控制類型
            Type controllerType = GetControllerType(requestContext, controllerName);
            if (controllerType == null)
            {
                return null;
            }
            //得到控制器對象
            IController controller = GetControllerInstance(requestContext, controllerType);
            return controller;
        }

     //得到當前請求的控制器實例
        private IController GetControllerInstance(System.Web.Routing.RequestContext requestContext, Type controllerType)
        {
            var oRes = Activator.CreateInstance(controllerType) as IController;
            return oRes;
        }

        //得到當前請求的控制器類型
        private Type GetControllerType(System.Web.Routing.RequestContext requestContext, string controllerName)
        {
            //從路由配置信息里面讀取命名空間和程序集
            object routeNamespaces;
            object routeAssembly;
            requestContext.RouteData.Values.TryGetValue("namespaces", out routeNamespaces);
            requestContext.RouteData.Values.TryGetValue("assembly", out routeAssembly);

            //通過反射得到控制器的類型
            var type = Assembly.Load(routeAssembly.ToString()).GetType(routeNamespaces.ToString() + "." + controllerName + "Controller");

            return type;
        }

原理不難理解,主要還是反射,因為我們當前請求的控制器類在測試項目里面,所以反射的時候需要指定當前測試項目的程序集,通過這里的代碼可以看出,在UrlRoutingModule里面封裝的RequestContext對象實在是太重要了,因為各個地方都需要用到它。博主覺得這里還有待優化,等想到更好的辦法再來逐步優化。此步得到結果:

(9)得到控制器對象之后,就是執行Action方法了: controller.Execute(context.Request.RequestContext); 。這里博主按照源碼里面的構造封裝了IController、ControllerBase、Controller三個級別的接口以及父類。Execute方法的實現在Controller里面:

   public abstract class Controller:ControllerBase,IDisposable
    {
        public override void Execute(System.Web.Routing.RequestContext requestContext)
        {
            //反射得到Action方法
            Type type = this.GetType();
            string actionName = requestContext.RouteData.GetRequiredString("action");
            System.Reflection.MethodInfo mi = type.GetMethod(actionName);

            //執行該Action方法
            mi.Invoke(this, new object[] { });//調用方法
        }
    }

這里再次用到了RequestContext對象,由此可以看出,RequestContext對象幾乎貫穿整個MvcHandler,再次應征了上述注釋(3)中說的它的重要性。

上述代碼就是通過反射Action方法,然后執行該方法,之后請求就會盡到我們HomeController的Index()方法里面。

(10)執行Index()方法

請求進入到Index()方法之后,然后就是從Model里面獲取數據,再然后就是返回View,整個MVC的原理就是如此。當然博主這里的Swift.MVC還只是將請求轉到了Index里面,剩余的Model可以自己寫,但是View的部分還完全沒有,待有時間完善。

(11)執行完Action之后,最后就是釋放當前的Controller對象了。在finally里面有這么一句:  factory.ReleaseController(controller); 。還是來看看ReleaseController方法的定義:

        //釋放控制器對象
        public void ReleaseController(IController controller)
        {
            IDisposable disposable = controller as IDisposable;
            if (disposable != null)
            {
                disposable.Dispose();
            }
        }

至此,我們通過地址http://localhost:16792/Home/Index訪問,整個請求的開始、執行、資源釋放就基本結束。現在回過頭來理解這個原理,你覺得還難嗎~~

4、向Swift.MVC里面加入Model

如果你還嫌上述例子太簡單,我們可以來個稍微復雜點的例子。我們向測試項目里面引入jquery、bootstrap等組件,添加Models文件夾,向下面加入User.cs

namespace MyTestMVC.Models
{
    public class User
    {
        public int Id { get; set; }
        public string UserName { get; set; }
        public int Age { get; set; }
        public string Address { get; set; }
        public string Remark { get; set; }
    }
}

然后我們向HomeController里面另一個Action定義如下:

    public void BootstrapTest()
        {
            var lstUser = new List<User>();
            lstUser.Add(new User() { Id = 1, UserName = "Admin", Age = 20, Address = "北京", Remark = "超級管理員" });
            lstUser.Add(new User() { Id = 2, UserName = "張三", Age = 37, Address = "湖南", Remark = "呵呵" });
            lstUser.Add(new User() { Id = 3, UserName = "王五", Age = 32, Address = "廣西", Remark = "呵呵" });
            lstUser.Add(new User() { Id = 4, UserName = "韓梅梅", Age = 26, Address = "上海", Remark = "呵呵" });
            lstUser.Add(new User() { Id = 5, UserName = "呵呵", Age = 18, Address = "廣東", Remark = "呵呵" });

            string strUser = string.Empty;
            foreach (var oUser in lstUser)
            {
                strUser += "<tr><td>" + oUser.Id + "</td><td>" + oUser.UserName + "</td><td>" + oUser.Age + "</td><td>" + oUser.Address + "</td><td>" + oUser.Remark + "</td></tr>";
            }

            HttpContext.Current.Response.Write(@"
<html>
    <head>
        <link href='/Content/bootstrap/css/bootstrap.min.css' rel='stylesheet' />
        <script src='/Content/jquery-1.9.1.min.js'></script>
        <script src='/Content/bootstrap/js/bootstrap.min.js'></script>
    </head>
    <body>
         <div class='panel-body' style='padding-bottom:0px;'>
        <div class='panel panel-primary'>
            <div class='panel-heading'>bootstrap表格</div>
            <div class='panel-body'>
                <table id='tbarrivequeue' class='table table-bordered table-striped'>
                    <thead>
                        <tr>
                            <th>用戶ID</th>
                            <th>用戶名</th>
                            <th>年齡</th>
                            <th>地址</th>
                            <th>備注</th>
                        </tr>
                    </thead>
                    <tbody>
                       " + strUser + @"
                    </tbody>
                </table>
            </div>
        </div>  
     </div>     

        
    </div>
    </body>
</html>");

得到結果:

按照MVC的機制,我們的Swift.MVC里面“M”和“C”都有了,就差“V”了,等有時間我們也來封裝一個自己的“V”。

三、版本三:加入自己的路由模塊

有了第二個版本的支持,博主已經對MVC的原理有了一個清晰的認識。在第三個版本里面,博主打算不用System.Web.Routing里面的屬性和方法,完全自己去解析請求,封裝上下文,執行MVC,這樣才算是真正意義上自己的MVC。考慮到篇幅的問題,也給博主一些准備時間,第三個版本留在下篇發,有興趣的園友可以先看看版本二,如果你能透徹理解版本二里面的原理,相信你對MVC 已經有一個清晰的認識了。

四、總結

 至此,此篇到此結束,版本二里面我們MvcHandler基本上是完全重寫的,雖然很多原理是參考MVC源碼里面來進行的,但是它卻和源碼已經沒有任何聯系。而UrlRoutingModule部分仍然使用的System.Web.Routing里面的組件去解析路由的,這個將在第三個版本里面完善。源碼已經在github上面開源,有興趣可以看看:源碼下載

如果你覺得本文能夠幫助你,可以右邊隨意 打賞 博主,也可以 推薦 進行精神鼓勵。你的支持是博主繼續堅持的不懈動力。

本文原創出處:http://www.cnblogs.com/landeanfen/

歡迎各位轉載,但是未經作者本人同意,轉載文章之后必須在文章頁面明顯位置給出作者和原文連接,否則保留追究法律責任的權利

 


免責聲明!

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



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