Attributes are lousy decorators

Attributes allow developers to provide a mechanism to add metadata to types, assemblies, type members, method parameters, and just about anything else under the sun.  One of the first trends I noticed in my early days of combing the BCL with Reflector was that without fail, no attribute type provided any behavior.  The only information an attribute provided was its type and its properties, but I never found a method that did any work.  Which makes sense, as attributes define metadata, not behavior.

But in ASP.NET MVC, this pattern is broken with the ActionFilterAttribute.  Because a single controller can have many actions, it’s difficult to create a mechanism that executes code before or after any single action and not any other.  Since attributes can be placed on both method and class declarations, this would seem like an ideal candidate to specify before/after behavior on a controller action.

The problem is that attributes aren’t designed to have behavior, and are a lousy implementation of the decorator pattern.  It’s important to remember that developers have little to zero control over when attribute instances are created, which is why you never want an exception to be thrown in an attribute constructor.

Since you don’t have control over the construction, and can’t provide an alternative construction method like an IoC container to do the instantiation, you wind up having to do things like this:

public class BadBadFilterAttribute : ActionFilterAttribute
{
    private readonly ICustomerRepository _customerRepository;

    public BadBadFilterAttribute() : this(ObjectFactory.GetInstance<ICustomerRepository>())
    {
    }

    private BadBadFilterAttribute(ICustomerRepository customerRepository)
    {
        _customerRepository = customerRepository;
    }

    public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        // Fetch the customer or something
    }
}

We’re attempting to use StructureMap to locate the dependency for this attribute, a Customer repository.  However, since I don’t control when that constructor is called, I can get some weird behavior and exceptions when doing simple things like reflection.  But since reflection triggers attribute constructors, often I’ll see StructureMap spinning up trying to locate dependencies, when all I wanted to do was inspect the metadata.

Since attributes are the built-in mechanism for adding decorator behavior to an action, you can borrow the MonoRail method of providing action filters.  In addition to the MVC way, MonoRail allows you to simply specify the type of the IFilter, and it will create and execute that filter for you.  This way, you don’t need to create an attribute class, but instead just an implementation of IFilter.  This is easy to do in MVC as well:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class ContainerLocatedActionFilterAttribute : FilterAttribute, IActionFilter
{
    private readonly Type _actionFilter;

    public ContainerLocatedActionFilterAttribute(Type actionFilter)
    {
        _actionFilter = actionFilter;
    }

    public void OnActionExecuting(ActionExecutingContext filterContext)
    {
        var instance = (IActionFilter)ObjectFactory.GetInstance(_actionFilter);
        instance.OnActionExecuting(filterContext);
    }

    public void OnActionExecuted(ActionExecutedContext filterContext)
    {
        var instance = (IActionFilter)ObjectFactory.GetInstance(_actionFilter);
        instance.OnActionExecuted(filterContext);
    }
}

Our filter can simply be an IActionFilter (or some other interface, at this point, it really doesn’t matter), without worrying about thread safety and other issues with attribute instances.  Although attributes are nice in that they’re declarative and defined at the point of most usefulness (on the action or controller), attributes in general weren’t designed with behavior in mind.  It’s possible to get yourself into threading trouble if you don’t understand how attributes are instantiated and allocated, which usually requires a good read in the CLR via C# book.

There are other ways to provide decorators for actions, which I’ll look at in the next a future post.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in ASP.NET MVC. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://compiledexperience.com Nigel Sampson

    The other place I’ve noticed this (attributes providing more than data) is the ValidationAttribute in Dynamic Data. I’m not a fan of this either since it’s difficult to reuse any code stored in these attribute, especially complex validation (which certainly shouldn’t be in one).

  • http://mookid.dk/oncode Mogens Heller Grabe

    This is a great example on why it’s hard to create a framework. At first something seems like a cool and easy solution, but when people start using it, stuff like this just happens.

    Makes you wonder why Microsoft bother building MVC, the Entity Framework etc. when there are truly mature solutions like MonoRail and NHibernate around.

  • http://blog.brechtel.us James Brechtel

    Why not lazy load the ICustomerRepository on the BadBadFilterAttribute via a property?

  • http://www.lostechies.com/members/bogardj/default.aspx bogardj

    @James

    Because then we’re not using IoC. We want our dependencies explicit, and a lazy-loaded property makes it opaque or appear optional.

  • http://www.prospectsolution.com Writing Jobs

    The other place I’ve noticed this (attributes providing more than data) is the ValidationAttribute in Dynamic Data. I’m not a fan of this either since it’s difficult to reuse any code stored in these attribute, especially complex validation (which certainly shouldn’t be in one).

  • Luckykashyap4u

    Since attributes can be placed on both method and class declarations,
    this would seem like an ideal candidate to specify before/after behavior
    on a controller action.

    • Anonymous

      Yeah, I agree, but I don’t like that the attribute instance itself supplies the behavior. Attributes just really aren’t meant for that.