Oxite分析之自定义Action返回值





change set:42353

download :http://oxite.codeplex.com/SourceControl/ListDownloadableCommits.aspx


查看一些Module下的Controller就会发现,里面有一些“特别”的public方法。比如Oxite.Modules.Core.Controllers.SiteController下有一个方法:


1: public virtual OxiteViewModel Dashboard()
2: {
3:  return new OxiteViewModel { Container = new AdminDashboardPageContainer() };
4: }  

OxiteViewModel 具体是什么类型我们在这里不去深究,可以肯定的是它没有直接或间接继承自ActionResult类。而这个方法在这里不是一个普通的方法,而是一个“Action”——它的返回值不是一个ActionResult。如果思想还禁锢在ASP.NET MVC模板提供的Action上,而又没对System.Web.Mvc源码进行分析的话,很可能会想不通。

Oxite通过自定义Controller的ActionInvoker来实现这一点的。

下面是System.Web.Mvc.ControllerActionInvoker : IActionInvoker的CreateActionResult方法的源码:

1: protected virtual ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) {
2:  if (actionReturnValue == null) {
3:  return new EmptyResult();
4:  }
5:  
6:  ActionResult actionResult = (actionReturnValue as ActionResult) ??
7:  new ContentResult { Content = Convert.ToString(actionReturnValue, CultureInfo.InvariantCulture) };
8:  return actionResult;
9: }

对比一下Oxite.Infrastructure.OxiteControllerActionInvoker的CreateActionResult方法的源码:

 1: protected override ActionResult CreateActionResult(ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue)
 2: {
 3:  if (actionReturnValue == null)
 4:  {
 5:  controllerContext.Controller.ViewData.Model = new OxiteViewModel { Container = new NotFoundPageContainer() };
 6:  
 7:  return new NotFoundResult();
 8:  }
 9:  
10:  if (typeof(ActionResult).IsAssignableFrom(actionReturnValue.GetType()))
11:  return actionReturnValue as ActionResult;
12:  
13:  controllerContext.Controller.ViewData.Model = actionReturnValue;
14:  
15:  return new ViewResult { ViewData = controllerContext.Controller.ViewData, TempData = controllerContext.Controller.TempData };
16: }
17:  

在Oxite中,不只允许返回非ActionResult型数据,还允许返回void。如果返回值为不null,则将返回值设置为Model的值。

另外,将Oxite.Infrastructure.OxiteControllerActionInvoker设置为Controller的ActionInvoker是在自定义ControllerFactory中进行的。
Oxite.Infrastructure.OxiteControllerFactory源码:

 1: namespace Oxite.Infrastructure
 2: {
 3:  public class OxiteControllerFactory : DefaultControllerFactory
 4:  {
 5:  private readonly IUnityContainer container;
 6:  
 7:  public OxiteControllerFactory(IUnityContainer container)
 8:  {
 9:  this.container = container;
10:  }
11:  
12:  protected override IController GetControllerInstance(Type controllerType)
13:  {
14:  IController iController = container.Resolve(controllerType) as IController;
15:  
16:  if (typeof(Controller).IsAssignableFrom(controllerType))
17:  {
18:  Controller controller = iController as Controller;
19:  
20:  if (controller != null)
21:  controller.ActionInvoker = container.Resolve<IActionInvoker>();
22:  
23:  return iController;
24:  }
25:  
26:  return iController;
27:  }
28:  }
29: }
30:  

controller.ActionInvoker = container.Resolve<IActionInvoker>();

OxiteControllerActionInvoker的注入在Oxite.Modules.Core.OxiteModule的RegisterWithContainer方法中进行的:

1: public void RegisterWithContainer()
2: {
3:  container
4:  .RegisterType<IActionInvoker, OxiteControllerActionInvoker>()
5:  //...
6:  }
7:  

 

我觉得最最重要的是,应该通过阅读System.Web.Mvc源码的方式了解一下ASP.NET MVC的生命周期,知道在哪些地方可以进行扩展或替换。

ASP.NET MVC生命周期相关文章推荐:

Asp.net MVC生命周期: http://www.cnblogs.com/me-sa/archive/2009/06/01/MVCLifecycle.html
使用 ASP.NET Web 窗体路由: http://msdn.microsoft.com/zh-cn/magazine/2009.01.extremeaspnet.aspx

posted @ 2009-09-08 12:04  alby  阅读(825)  评论(0编辑  收藏  举报