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