正文

前言:上篇介绍了下 MVC5 的核心原理,整篇文章比较偏理论,所以相对比较枯燥。今天就来根据上篇的理论一步一步进行实践,通过自己写的一个简易MVC框架逐步理解,相信通过这一篇的实践,你会对MVC有一个更加清晰的认识。

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

MVC源码学习系列文章目录:

这篇博主打算从零开始一步一步来加上MVC里面用到的一些技术,整篇通过三个版本,逐步完善。

回到顶部

一、版本一:搭建环境,实现MVC请求

通过上篇的介绍,我们知道,MVC里面两个最核心的部件:MvcHandler和UrlRoutingModule。现在我们就来一步一步实现它们。为了更加真实,我们完全从零开始。

回到顶部

1、新建一个类库项目,我们暂且命名为Swift.MVC.

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

回到顶部

2、新建MvcHandler和UrlRoutingModule

我们新建两个文件,然后实现IHttpHandler和IHttpModule。我们知道这两个接口都在System.Web里面,首先我们在类库项目里面引用Syste.Web这个dll,然后来看具体的代码。

MvcHandler.cs代码:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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");
        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

UrlRoutingModule.cs代码:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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());
        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

如果你看过博主的上篇,这个应该很好理解。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的内容如下:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

<?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>

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

 得到结果

 移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

这里博主想要说明两点:

  1. 如果你调试程序你会发现,app_PostResolveRequestCache()和ProcessRequest()都进了两遍,这是因为在web.config里面配置的是所有的请求都会被拦截,添加监视发现原来当我们访问http://localhost:16792/Home/Index地址的时候实际上是发了两次请求:移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

  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的完整代码如下:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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);
        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

 上述代码基本都是从Framework源码里面拷贝出来的,注释中的0、1、2、3、4、5分别对应着MVC路由过程中的各个步骤,详见上篇

这里我们自定义了一个实现IRouteHandler的类型,用来返回处理请求的HttpHandler是哪个,比如这里我们定义的MvcRouteHandler返回的HttpHandler是MvcHandler。它的代码如下:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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();
        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

回到顶部

2、MvcHandler部分的完善

首先还是抛出MvcHandler.cs的源码:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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);
            }

        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

关于上述代码,我们说明以下几点。

2.1、关于控制器工厂

上述代码注释中的步骤1、2不难理解,就是从配置的路由规则中获取当前请求控制器的名称。要理解步骤3,需要先说一说MVC源码里面的控制器工厂。先来看看源码里面这段如何实现:

在源码里面的MvcHandler的ProcessRequest方法里面有这么一句: factory = ControllerBuilder.GetControllerFactory(); 。在MvcHandler里面ControllerBuilder这样定义:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

原来在MvcHandler中创建控制器工厂并不是直接使用IControllerFactroy的实现,而是使用了ControllerBuilder这个对象,这个对象采用了单例模式的实现;MvcHandler通过ControllerBuilder对象获取到一个实例,然后通过ControllerBuilder创建出IControllerFactory实现,ControllerBuilder管理着IControllerFactory的创建过程。

关于ControllerBuilder里面的GetControllerFactory()方法的实现,我们不必细究,但是我们需要知道的是在MVC里面有一个默认的控制器工厂的实现类DefaultControllerFactory。我们来看看

IControllerFactory接口的定义:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

DefaultControllerFactory的定义:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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();
            }
        }        //......    
    }

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

上述的两个方法CreateController()和ReleaseController()通过名字都可以很好理解,分别对应着创建控制器和释放控制器。

了解了上述MVC里面控制器工厂的实现细节,我们自己也来建一个自己的控制器工厂,不过为了简化,我们这里直接去new了一个工厂的实现类。先来看看我们Swift.MVC的控制器工厂。

控制器工厂接口:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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);
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

控制器工厂实现类:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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

2.2、控制器的父类实现

上述介绍了控制器工厂的实现。除了控制器工厂,还有我们的控制器接口以及父类的相关实现。

控制器接口的定义:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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);
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

控制器抽象Base类的实现:(这个抽象类的作用更多在于定义一些约束、检查之类)

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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);
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

控制器抽象子类的实现:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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();        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

这里让Controller类实现IDispose接口,照应了上文控制器工厂里面的ReleaseController()方法,主要起到释放资源的作用。

回到顶部

3、测试及代码释疑

由于上述代码用到了System.Web.Routing里面的组件,所以,需要在测试项目里面配置路由规则,这里需要注意一点,我们上面的MvcRouteHandler就是在这里注入进去的。在测试项目里面新建一个全局配置文件如下:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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)
        {

        }    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

然后在测试项目里面模拟MVC新建一个Controllers文件夹,里面新建一个测试的控制器HomeController:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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");
        }
    }
}

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

然后启动项目,访问http://localhost:16792/Home/Index。运行过程以及代码释疑如下:

(1)来看看 RouteData routeData = this.RouteCollection.GetRouteData(context); 这一句

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

通过上图可知,this.RouteCollection里面保存的是上述全局配置文件里面添加进去的路由规则,然后调用GetRouteData(context)方法,传入当前请求的上下文,得到当前请求的RouteData对象,我们可以看到在这个RouteData对象里面,已经包含了当前请求的控制器和action的名称。

(2)监视 IRouteHandler routeHandler = routeData.RouteHandler; 

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

通过上图可以看到在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); 这一句

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

 

上文注释(2) 里面说了,routeHandler对象实际上是一个MvcRouteHandler对象,当它调用GetHttpHandler(),看下定义即可明白:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

这里就是返回了一个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名称。结果如下:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

(8)得到控制器工厂这个没什么说的,为了简化,我们直接new了一个默认的控制器工厂。下面重点来看看 IController controller = factory.CreateController(context.Request.RequestContext, controllerName); 这一句。在控制器工厂的实现类里面实现了CreateController()这个方法。

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

        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;
        }

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

原理不难理解,主要还是反射,因为我们当前请求的控制器类在测试项目里面,所以反射的时候需要指定当前测试项目的程序集,通过这里的代码可以看出,在UrlRoutingModule里面封装的RequestContext对象实在是太重要了,因为各个地方都需要用到它。博主觉得这里还有待优化,等想到更好的办法再来逐步优化。此步得到结果:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

(9)得到控制器对象之后,就是执行Action方法了: controller.Execute(context.Request.RequestContext); 。这里博主按照源码里面的构造封装了IController、ControllerBase、Controller三个级别的接口以及父类。Execute方法的实现在Controller里面:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

   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[] { });//调用方法        }
    }

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

这里再次用到了RequestContext对象,由此可以看出,RequestContext对象几乎贯穿整个MvcHandler,再次应征了上述注释(3)中说的它的重要性。

上述代码就是通过反射Action方法,然后执行该方法,之后请求就会尽到我们HomeController的Index()方法里面。

(10)执行Index()方法

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

请求进入到Index()方法之后,然后就是从Model里面获取数据,再然后就是返回View,整个MVC的原理就是如此。当然博主这里的Swift.MVC还只是将请求转到了Index里面,剩余的Model可以自己写,但是View的部分还完全没有,待有时间完善。

(11)执行完Action之后,最后就是释放当前的Controller对象了。在finally里面有这么一句: factory.ReleaseController(controller); 。还是来看看ReleaseController方法的定义:

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

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

移动开发培训,Android培训,安卓培训,手机开发培训,手机维修培训,手机软件培训

至此,我们通过地址http://localhost:16792/Home/Index访问,整个请求的开始、执行、资源释放就基本