ASP.NET MVC开发专题博客

ASP.NET MVC开发专题博客,为您精选ASP.NET MVC开发教程,助您开发愉快!

公告信息
欢迎光临ASP.NET MVC开发专题博客,祝您开发愉快!
文章档案
最新评论

ASP.NET MVC Controller创建及调用内幕-MVC原理系列5

上节:ASP.NET MVC路由机制扩展及Area原理-MVC原理系列4中,我们讲解了ASP.NET MVC 是如何实现Area机制的及MVC自定义扩展路由机制

本节,我们将MvcRouteHandler,即MV框架入口处,开展解说,且看下文:

 

ASP.NET MVC Controller的创建过程:Builder和Factory

MvcRouteHandler的实现仅仅是通过GetHttpHandler方法返回一个MvcHandler实例,MvcHandler从RouteData中获得controller名字负责创建一个ControllerBuilder的实例,并通过ControllerBuilder的GetControllerFactory返回一个IControllerFactory的实例,这个实例就是DefaultControllerFactory,它的 CreateController方法负责创建需要的Controller实例。下面这段代码来自MvcHandler:

1// Get the controller type
2string controllerName = RequestContext.RouteData.GetRequiredString("controller");
3// Instantiate the controller and call Execute
4factory = ControllerBuilder.GetControllerFactory();
5controller = factory.CreateController(RequestContext, controllerName);

DefaultControllerFactory创建Controller分两步:

1Type controllerType = GetControllerType(requestContext, controllerName);
2IController controller = GetControllerInstance(requestContext, controllerType);

GetControllerInstance最终是这样创建controller的:

1return (IController)Activator.CreateInstance(controllerType);

这就使得要使用DI设计模式十分困难。好在我们可以重写GetControllerInstance,并应用各种DI。受书中的影响,个人使用的是Ninject

另外,为了加快GetControllerType方法,DefaultControllerFactory内部运用缓存机制将当前程序和所有引用程序集的类型缓存成哈希表。

还可以通过如下方法,提供某些名字空间较高的优先级来优化搜索。

1protected void Application_Start()
2{
3    RegisterRoutes(RouteTable.Routes);
4    ControllerBuilder.Current.DefaultNamespaces.Add("MyApp.Controllers.*");
5    ControllerBuilder.Current.DefaultNamespaces.Add("OtherAssembly.MyNamespace.*");
6}

上面这种设置名字空间的优先级仍然低于在设置路由表时为某个路由指定的名字空间,Areas机制就是靠在设置路由表时指定名字空间实现的,详见深入理解ASP.NET MVC(4)

也可以在ControllerBuilder层面上替换ControllerFactory:

1protected void Application_Start()
2{
3    RegisterRoutes(RouteTable.Routes);
4    ControllerBuilder.Current.SetControllerFactory(new MyControllerFactory());
5}

 

ASP.NET MVC Controller的调用:Controller只是普通的.NET类

MvcHandler依靠ControllerBuilder和IControllerFactory获得Controller的实例后,调用Controller实例的Execute方法,在该方法返回后再调用IControllerFactory的ReleaseController收尾。由此看出Controller的Execute做了所有的事情,看似“功能强大”,其实它只是.NET的普通类, MVC框架赋予其“非凡”的能力:

所有的Controller只要实现一个接口,IController,接口的定义了Execute方法:

1namespace System.Web.Mvc {
2    using System.Web.Routing;
3 
4    public interface IController {
5        void Execute(RequestContext requestContext);
6    }
7}

从接口定义可以看出,当Controller被“调用”的时候,应该负责完成Execute方法,参数RequestContext封装了HttpContext,所以可以像下面这样直接实现一个Controller,同样可以工作:

1public class HelloWorldController : IController 
2{
3    public void Execute(RequestContext requestContext)
4    {
5        requestContext.HttpContext.Response.Write("Hello, world!");
6    }
7}

然而,需要的逻辑和架构远比这个复杂的多,因此MVC框架提供了如下类关系:

IController->ControllerBase->Controller

其中ControllerBase实现Execute,Execute在内部调用ExecuteCore,ExecuteCore作为一个抽象方法,延迟到Controller中实现。ControllerBase只提供了诸如TempData、ViewData等,Controller的ExecuteCore方法真正invoke了action机制,是action的入口。下面的代码是ExecuteCore的实现:

01PossiblyLoadTempData();
02try {
03    string actionName = RouteData.GetRequiredString("action");
04                if (!ActionInvoker.InvokeAction(ControllerContext, actionName)) {
05                    HandleUnknownAction(actionName);
06                }
07     }
08 finally {
09                PossiblySaveTempData();
10            }

可以看到RouteData在这里又提供了action参数,可以想象InvokeAction方法依靠这个action的名字调用action,并实现诸多验证机制。下节开始讨论action逻辑。


本节:ASP.NET MVC Controller创建及调用内幕-MVC原理系列5,到此收笔,谢谢欣赏。


如果涉及数据库操作,推荐一款配套的ORM框架:CYQ.Data 通用数据层框架

2011/9/8 0:24:17 | ASP.NET MVC教程 | |

  • 发表评论