Dependency Injection in ASP.NET MVC: Action Results
On a recent, very large project, we started to notice a distinct trend in our controllers. All of our “POST” actions started to look very similar. Check form validation, run business rule validation. If validation succeeds, execute the actual business logic. If it fails, just show the view with the original form.
The problem we ran into was how to encapsulate this common behavior. We first went with some abomination of a base, CRUD controller. I should have listened to the OO luminaries, “Favor composition over inheritance”.
Our solution was to instead capture the common paths in a custom ActionResult, passing in the pieces of behavior that change into our ActionResult. The outcome was that we needed a way to inject services into our action results. The ExecuteResult method needed external services, which needed to be injected.
But that brought us to one of the fundamental problems with the design of an ActionResult. If you examine its responsibilities, it comes down to two things:
- WHAT to do
- HOW to do it
Unfortunately for us, these two responsibilities are intertwined on ActionResult. For example, in the ViewResult object, I set up the ViewName to render and so on. This makes it great for testing purposes, I only need to test the WHAT for controller actions.
However, the HOW for ActionResults usually winds up opening a huge can o’ worms. Taking ViewResult, the ExecuteResult method has a metric ton of behavior around it, choosing a view engine, finding the view, rendering the view and so on. Quite a lot for an object that just had a ViewName property on it.
We could go the route of filters, and perform property injection for the pieces needed in the ExecuteResult method. But property injection is mostly a hack, and should only be reserved in extreme cases.
Instead, I’ll take a route similar to the “Better Action Result” post, and clearly separate the WHAT of an action result from the HOW. The result solidifies the controller’s responsibility as a traffic controller, solely directing traffic.
The WHAT: an action method result
What I’m shooting for here is a POCO action method result. It has zero behavior, and only holds a representation of what I want to happen as the result of an action. If you took all of the existing action results and subtracted their “ExecuteResult” method, this is what I’m going for.
To make it sane, I’ll just create a new representation of an action method result in the form of a marker interface. Although it’s not completely POCO, a marker interface helps later on when integrating into the ControllerActionInvoker pipeline:
public interface IActionMethodResult { }
Those wanting to create custom action method results just need to implement this interface, and add any data in the implementing class.
The HOW: an action method result invoker
These custom action method results will still basically build up the regular action results. They will do whatever custom logic, and return an action result that will be consumed as normal by the MVC pipeline. The reasoning here is that all the custom action results I’ve ever needed to build always built up the existing action results. Staying with the eventual result of an ActionResult also lets me keep the concept of the ResultFilters in place.
Our action method result invoker will then take in an action method result, and return an ActionResult:
public interface IActionMethodResultInvoker<T> where T : IActionMethodResult { ActionResult Invoke(T actionMethodResult, ControllerContext context); } public interface IActionMethodResultInvoker { ActionResult Invoke(object actionMethodResult, ControllerContext context); }
I defined two invokers, simple because it’s easier to perform the generic conversions of what’s all object-based to one that’s generic-based, through a simple facade:
public class ActionMethodResultInvokerFacade<T> : IActionMethodResultInvoker where T : IActionMethodResult { private readonly IActionMethodResultInvoker<T> _invoker; public ActionMethodResultInvokerFacade(IActionMethodResultInvoker<T> invoker) { _invoker = invoker; } public ActionResult Invoke(object actionMethodResult, ControllerContext context) { return _invoker.Invoke((T) actionMethodResult, context); } }
Implementers of an action method result invoker can use the generic interface, where I’ll wrap that generic version with a non-generic one and do the casting myself.
Finally, I need to override the CreateActionResult method in our custom action invoker:
protected override ActionResult CreateActionResult( ControllerContext controllerContext, ActionDescriptor actionDescriptor, object actionReturnValue) { if (actionReturnValue is IActionMethodResult) { var openWrappedType = typeof(ActionMethodResultInvokerFacade<>); var actionMethodResultType = actionReturnValue.GetType(); var wrappedResultType = openWrappedType.MakeGenericType(actionMethodResultType); var invokerFacade = (IActionMethodResultInvoker) _container.GetInstance(wrappedResultType); var result = invokerFacade.Invoke(actionReturnValue, controllerContext); return result; } return base.CreateActionResult(controllerContext, actionDescriptor, actionReturnValue); }
Based on the action return value, I check to see if it’s an instance of our marker interface. If so, I’ll then construct the closed generic type of our invoker facade. This facade lets me call an “Invoke” method that accepts something of type “object”, instead of the “T” of the generic action method invoker interface.
Once I create the closed type of the invoker facade, I use the container to create an instance of this facade type. Since the facade also depends on the generic invoker, I’ll get the real invoker as well. Finally, I call the Invoke method, passing in the action return value (an IActionMethodResult), and return the result of that.
Example: Executing commands
Now that I have an entry point for setting up external invokers that don’t have to rely on hokey property injection, or worse, service location, I can start to do really interesting invocation patterns in our controller actions. As I alluded earlier, our POST actions had the same pattern over and over again. I can now capture this in an action method result:
public class CommandMethodResult<TModel> : IActionMethodResult { public CommandMethodResult(TModel model, Func<ActionResult> successContinuation, Func<ActionResult> failureContinuation) { Model = model; SuccessContinuation = successContinuation; FailureContinuation = failureContinuation; } public TModel Model { get; private set; } public Func<ActionResult> SuccessContinuation { get; private set; } public Func<ActionResult> FailureContinuation { get; private set; } }
This action method result represents the model of handling the form, plus what to on success and what to do on failure. The handler of this action method result can then contain the common path of validation, execution and success/failure:
public class CommandMethodResultInvoker<TModel> : IActionMethodResultInvoker<CommandMethodResult<TModel>> { private readonly ICommandMessageHandler<TModel> _handler; public CommandMethodResultInvoker(ICommandMessageHandler<TModel> handler) { _handler = handler; } public ActionResult Invoke( CommandMethodResult<TModel> actionMethodResult, ControllerContext context) { if (!context.Controller.ViewData.ModelState.IsValid) { return actionMethodResult.FailureContinuation(); } _handler.Handle(actionMethodResult.Model); return actionMethodResult.SuccessContinuation(); } }
In the Invoke action, I first check to see if there are any validation errors. If so, then I’ll just return the failure result continuation (that Func
If there are no validation errors, then I hand off the form to an individual handler, an ICommandMessageHandler
public interface ICommandMessageHandler<T> { void Handle(T message); }
In this handler, I’ll have all the logic, services, etc. needed to process this form. Because I’m only responsible for the success path here, you won’t see any mixed responsibilities of creating ActionResults, checking ModelState and so on. To make it easier to build up the action method result, I’ll create a helper method on our controller layer supertype class:
protected CommandMethodResult<T> Command<T>( T model, Func<ActionResult> successContinuation) { return new CommandMethodResult<T>( model, successContinuation, () => View(model)); }
Since the default of a failure action is just to show the same view with the same model, I pass that in as the default. Our controller action for POST then becomes very, very thin:
[HttpPost] public CommandMethodResult<FooEditModel> Edit(FooEditModel form) { return Command(form, () => RedirectToAction("Index")); }
One line! Testing this action also becomes a breeze, as I don’t need to set up some crazy failure/success paths, I only need to test the model property and the success/failure continuations in isolation. Finally, our handler for the form can do whatever it needs:
public class FooEditModelHandler : ICommandMessageHandler<FooEditModel> { private readonly IFooService _service; public FooEditModelHandler(IFooService service) { _service = service; } public void Handle(FooEditModel message) { // handle this edit model somehow } }
Because my handler has no responsibilities around ModelState, ViewData, ActionResults or anything else of that nature, it becomes very tightly focused and easy to maintain.
Finally, I need to configure StructureMap for all this new generic wiring:
Scan(scanner => { scanner.TheCallingAssembly(); scanner.WithDefaultConventions(); scanner.ConnectImplementationsToTypesClosing(typeof (IActionMethodResultInvoker<>)); scanner.ConnectImplementationsToTypesClosing(typeof (ICommandMessageHandler<>)); scanner.Convention<CommandMessageConvention>(); });
I connect all closed implementations of the invokers and handlers, as well as add a custom convention to connection the pieces needed for the IActionMethodResultInvoker<CommandMethodResult
public class CommandMessageConvention : IRegistrationConvention { public void Process(Type type, Registry registry) { if (type.ImplementsInterfaceTemplate(typeof(ICommandMessageHandler<>))) { var interfaceType = type.FindFirstInterfaceThatCloses(typeof (ICommandMessageHandler<>)); var commandMessageType = interfaceType.GetGenericArguments()[0]; var openCommandMethodResultType = typeof (CommandMethodResult<>); var closedCommandMethodResultType = openCommandMethodResultType.MakeGenericType(commandMessageType); var openActionMethodInvokerType = typeof (IActionMethodResultInvoker<>); var closedActionMethodInvokerType = openActionMethodInvokerType.MakeGenericType(closedCommandMethodResultType); var openCommandMethodResultInvokerType = typeof (CommandMethodResultInvoker<>); var closedCommandMethodResultInvokerType = openCommandMethodResultInvokerType.MakeGenericType(commandMessageType); registry.For(closedActionMethodInvokerType).Use(closedCommandMethodResultInvokerType); } } }
That last piece is a little crazy, but it can sometimes be a bit annoying to deal with open and closed generics with the reflection API.
Wrapping it up
One of my biggest pet peeves in the MVC framework is the places where the WHAT is combined with the HOW. Filters and action results are two of these places. With filters, I opted for property injection to supply the needed services. With action results, I instead chose to separate those concerns.
The result is a much cleaner and extensible abstraction. I can modify the HOW of an action method result, without modifying the classes responsible for the WHAT. The action method results stay POCO, and the action method result invokers can get as complex as need be, but with the added power of dependency injection. My invokers can depend on whatever services they need to function, all completely orthogonal to pieces built from my controller actions.