I know I’ve been quiet for the past couple of weeks, so hopefully this post makes up for some of the silence. :)

A while back, on how actions within should be small and to the point. After this post, I started to think on how we can make ASP.NET MVC do more for us based on a convention.  Take the following code as example:

   1: [HandleError]
   2: public class HomeController : Controller
   3: {
   4:     public ActionResult Index()
   5:     {
   6:         ViewData["Message"] = "Welcome to ASP.NET MVC!";
   7:  
   8:         return View();
   9:     }
  10:  
  11:     public ActionResult About()
  12:     {
  13:         return View();
  14:     }
  15: }

As you can see, the About action doesn’t contain any logic and just returns the default for that action.  Sure, the method is small and it doesn’t add that much burden to the controller. However, wouldn’t it be nice not to go through that much for an action that simple?

Now take a look at this code snippet:

   1: [HandleError]
   2: public class HomeController : InferredController
   3: {
   4:     // No need for Index and About simple actions 
   5:     // since the inferred controller will handle
   6:     // the dispatching of the action to the correct
   7:     // view.
   8:  
   9:     // Since this action is defined, it will not be processed by
  10:     // the InferredActionInvoker class since it would be found by
  11:     // it's parent class.
  12:     public ActionResult Uninferred()
  13:     {
  14:         ViewData["Message"] = "I'm an un-inferred action!";
  15:         return View();
  16:     }
  17: }

In essence, the InferredController will handle all actions that are requested but not defined within the controller. This way, we define the views for the inferred (empty) actions then when the need arises, the controller action can be implemented.

How does it work?

All of this is possible thanks to the extensibility points of MVC, in particular the class.  The logic is simple,

  1. Find the action within the controller and return it.
  2. If not found, then return a stub that will infer the execution of the action.
   1: using System.Web.Mvc;
   2:  
   3: public class InferredActionInvoker : ControllerActionInvoker
   4: {
   5:     protected override ActionDescriptor FindAction(ControllerContext controllerContext,
   6:                                                    ControllerDescriptor controllerDescriptor, string actionName)
   7:     {
   8:         ActionDescriptor action = base.FindAction(controllerContext, controllerDescriptor, actionName) ??
   9:                                   new InferredActionDescriptor(actionName, controllerDescriptor);
  10:  
  11:         return action;
  12:     }
  13: }

 

If the action is inferred, then we just want to execute the action on the requests behalf and return a ViewResult for the action:

   1: public override object Execute(ControllerContext controllerContext, IDictionary<string, object> parameters)
   2: {
   3:    return new ViewResult { ViewName = ActionName };
   4: }

 

And voila, you’re done!

inferred_about_action

Feel free to check out the code and see if it suits your needs. Or if you want contribute conversation, leave a comment! :)