Dependency Injected Action Filters in ASP.NET MVC2

Posted May 6th, 2010 in Software Development by ryan

On one of our current projects utilizing all the latest Microsoft has to offer (MVC2, EF4, Unity, .NET 4) we found ourselves creating a number of Action Filters for encapsulating often used behavior, such as Auditing, Authorization, and temp data management. Action filters are an incredibly powerful tool in MVC, capable of manipulating any piece of the request/response and making that behavior easy to reuse. The problem with Action Filters, on the surface, is that there is no immediately apparent method of injecting dependencies into those filters – they’re just attributes on a method in your controller, or on the class of the controller itself, such as below:

[Authorized]
public class WidgetController : MyControllerBase
{
 [Audit("Doing something")]
 public ActionResult DoSomething()
 {
 ...
 }
}

In the case where your attribute has dependencies that should be resolved by your DI container, you may find yourself manually resolving those dependencies every time, which can get tedious and error prone. The answer to this lies in the Controller, but first we need a little background on how the Action Filters are actually executed.

When the MVC routing system finds the Controller for the current request, it uses an instance of that controller create to an ActionInvoker, which will be used in executing the action(s) on the controller. This ControllerActionInvoker is responsible for finding the appropriate action given the route on that controller, as well as invoking the action AND the actions filters. Since the ControllerActionInvoker is responsible for actually creating instances of the Filters, it’s the ideal location to put code responsible for building up the dependencies of any Filters on your action methods. With a minimal amount of code, we should be able to usurp the ActionFilter creation process and inject our dependencies before the filter executes.

First, we’ll need a DI wrapper. The one below is a snippet from mine which acts as a shell around Unity:

public static class ServiceResolver
{
        public static T InjectDependencies(T instance)
        {
            return (T)_container.BuildUp(instance.GetType(), instance);
        }
 ...
}

Now, the custom action invoker, which for these purposes only needs to override GetFilters(…), since this is the method responsible for getting the filters on a given Action:

public class MyActionInvoker : ControllerActionInvoker
{
        protected override FilterInfo GetFilters(ControllerContext controllerContext, 
            ActionDescriptor actionDescriptor)
        {
            var filters = base.GetFilters(controllerContext, actionDescriptor);
 
            filters.ActionFilters.ForEach(
               f => ServiceResolver.InjectDependencies(f));
            filters.AuthorizationFilters.ForEach(
               f => ServiceResolver.InjectDependencies(f));
            filters.ExceptionFilters.ForEach(
               f => ServiceResolver.InjectDependencies(f));
            filters.ResultFilters.ForEach(
               f => ServiceResolver.InjectDependencies(f));
            return filters;
        }
}

Note that we iterate over all the different filter collections that are returned as a result of the call to base.GetFilters(…). This ensures that any filters we create for any part of the action process will have dependencies resolved. Now you need to make sure your custom ActionInvoker is used any time MVC is trying to invoke an action on your controllers, so you’ll need a common base Controller class that all of your controllers will inherit from.

public abstract class MyControllerBase : Controller
{
        protected override IActionInvoker CreateActionInvoker()
        {
            return new MyActionInvoker();
        }
}

Now any ActionFilters which have property-based dependencies will be automatically fulfilled by the new ActionInvoker, such as the AuditAttribute show below:

public class AuditAttribute : System.Web.Mvc.ActionFilterAttribute
{
        [Dependency]
        public IUserRepository UserRepository { get; set; }
        [Dependency]
        public ILogger Logger { get; set; }
...
}
Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)

MVC2 Areas, T4MVC and sharing actions

Posted April 29th, 2010 in Software Development by cody

Using T4MVC: T4 templates to rid your MVC2 application of “magic strings”, strings representing action, controller and view names, can be extremely useful in making your code much more stable. It can help eliminate run-time errors and instead will generate compile errors notifying you that you have a reference to an action or view that doesn’t exist. Allowing you to do the following:

[HttpGet]
public virtual ActionResult LogOn()
{
	return View(Views.LogOn);
}

As opposed to:

[HttpGet]
public virtual ActionResult LogOn()
{
	return View("LogOn");
}

This post is not going into T4 templates, if you are not familiar with them check out Code Generation and Text Templates for an overview. Using them can present some challenges though and one of those is what I will be addressing in this post.

The Challenge

If you are using areas in your MVC application and you have functionality that crosses those boundaries, T4 templating causes issues when that logic needs to display views or redirect to actions for each area.

The easy solution is to have a controller that encapsulates the logic that both areas use but then you have to resort to magic strings and this could result in run-time errors if a view or action is moved or renamed later.

The Solution

What we did was simply use an abstract base controller that resides in the main controller folder of the project and created derived classes in the respective areas. The base class is where all the common logic exists and the derived classes implement the desired logic and displays the area specific views.

For example:
(In base class)

public abstract ActionResult Index();

(In derived class1)

[HttpGet]
public override ActionResult Index()
{
	return View(MVC.MainArea.Home.Views.Index, null);
}

(In derived class2)

[HttpGet]
public override ActionResult Index()
{
	return View(MVC.OtherArea.Home.Views.Index, null);
}

This allows the application to use the T4 templates and still generate compile time errors if someone changes any views or actions referenced in the derived controllers.

Digg This
Reddit This
Stumble Now!
Buzz This
Vote on DZone
Share on Facebook
Bookmark this on Delicious
Kick It on DotNetKicks.com
Shout it
Share on LinkedIn
Bookmark this on Technorati
Post on Twitter
Google Buzz (aka. Google Reader)