您的位置:首页 > 编程语言 > ASP

ASP.NET MVC Controller的激活机制

2015-10-10 13:57 826 查看
ASP.NET MVC 从最初的版本到现在,已经不断地完善,发展成为一个非常成熟的、设计优良的Web框架。从剖析ASP.NET MVC的一些设计及机制能够加深我们对于MVC模式的理解,帮助我们更好地扩展ASP.NET MVC框架,甚至使用设计思想,设计其他的软件架构。

1.概要

ASP.NET MVC 与传统的ASP.NET最大的区别在于,用户通过浏览器发起的请求不再是直接访问某个物理文件,而是访问某个Action。由Action及传给Action的参数决定如何呈现View给用户。这种方式大大地提升了应用程序的灵活性,使得One app for all platform的设计初衷得以实现。这个架构最重要的连个方面,一个是路由,一个是控制器。路由的机制今后再探讨,这里我们聊一聊控制器(Controller)的激活机制。

2.Controller的执行

从Controller类的源码中我们可以看到,Controller类实现了IController接口。

using System.Web.Routing;

namespace System.Web.Mvc
{
/// <summary>
/// 定义控制器所需的方法。
/// </summary>
public interface IController
{
/// <summary>
/// 执行指定的请求上下文。
/// </summary>
/// <param name="requestContext">请求上下文。</param>
void Execute(RequestContext requestContext);
}
}Controller类的部分结构如下:



IController只有一个方法-Execute,这个方法根据上下文来具体执行相应的逻辑,现在关键的问题是如何得到这个IController对象呢?
整个ASP.NET MVC框架是通过自定义的HttpModule和HttpHandler对象ASP.NET进行扩展实现的。自定义HttpModule就是UrlRoutingModule,而这个自定义的HttpHandler则是我们要重点介绍的MvcHandler。下面的的代码片断体现了MvcHandler的整个定义,在实现的ProcessRequest中实现了对Controller对象的激活和执行。

public class MvcHandler: IHttpHandler
{
public bool IsReusable
{
get{return false;}
}
public RequestContext RequestContext { get; private set; }
public MvcHandler(RequestContext requestContext)
{
this.RequestContext = requestContext;
}
public void ProcessRequest(HttpContext context)
{
string controllerName = this.RequestContext.RouteData.Controller;
IControllerFactory controllerFactory = ControllerBuilder.Current.GetControllerFactory();
IController controller = controllerFactory.CreateController(this.RequestContext, controllerName);
controller.Execute(this.RequestContext);
}
}
这里通过的核心方法ProcessRequest里面通过RouteData里面解析出来ControllerName,ControllerFactory通过名字和上下文得到IController实例,使用该实例调用Execute方法,这和我们上面讲到的完全吻合。

那么现在的问题时,如何获取到正确的Controller呢?这里面的机制又是怎么样的?

激活Controller类型的前提是能够正确解析出Controller的真实类型。作为CreateController方法输入参数的controllerName仅仅表示Controller的名称,我们需要加上Controller字符后缀作为类型名称。此外我们还需要得到类型的命名空间,而命名空间具有两个来源,即RouteData和当前ControllerBuilder。在DefualtControllerFactory初始化过程中,我们通过BuildManager加载所有应用的程序集,并加载所有实现了接口IController的类型并保存起来,而在CreateController方法中根据Controller的名称和命名空间从保存的Controller类型列表中得到对应的Controller类型,并通过反射的方式创建它。

注意:这里加载实现了IController接口的程序集,这个动作非常重要,确保了Controller的正确激活,因为Controller类都是实现了IController接口的,即被打上了某种标签的,通过实现是否了IController接口来决定是否加载这个程序集,从而确保了有效识别。

下面的代码演示和如何做到这一点

public class DefaultControllerFactory : IControllerFactory
{
private List<Type> controllerTypes = new List<Type>();
public DefaultControllerFactory()
{
foreach (Assembly assembly in BuildManager.GetReferencedAssemblies())
{
foreach (Type type in assembly.GetTypes().Where(type => typeof(IController).IsAssignableFrom(type)))
{
controllerTypes.Add(type);
}
}
}
public IController CreateController(RequestContext requestContext, string controllerName)
{
string typeName = controllerName + "Controller";
List<string> namespaces = new List<string>();
namespaces.AddRange(requestContext.RouteData.Namespaces);
namespaces.AddRange(ControllerBuilder.Current.DefaultNamespaces);
foreach (var ns in namespaces)
{
string controllerTypeName = string.Format("{0}.{1}", ns, typeName);
Type controllerType = controllerTypes.FirstOrDefault(type => string.Compare(type.FullName, controllerTypeName, true) == 0);
if (null != controllerType)
{
return (IController)Activator.CreateInstance(controllerType);
}
}
return null;
}
}了解了Controller的激活原理,我们还需要关注Controller的Action是如何被执行的。通过实现IContrller接口,我们为具有的Controller定义了一个具有如下定义的ControllerBase抽象基类。从中我们可以看到在实现的Execute方法中,ControllerBase通过一个实现了接口IActionInvoker的对象完成了针对Action方法的执行。
public abstract class ControllerBase: IController
{
protected IActionInvoker ActionInvoker { get; set; }
public ControllerBase()
{
this.ActionInvoker = new ControllerActionInvoker();
}
public void Execute(RequestContext requestContext)
{
ControllerContext context = new ControllerContext { RequestContext = requestContext, Controller = this };
string actionName = requestContext.RouteData.ActionName;
this.ActionInvoker.InvokeAction(context, actionName);
}
}3.说明
这篇文章是看过蒋金楠的<ASP.NET MVC 框架解密>及相关博客后的一个总结,前一段事件使用这种设计思想,设计了公司一个项目的架构,优点心得,故记录下来,感谢蒋金楠的书籍及博客。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  mvc 框架 架构