Skip to main content

Dependency Injection in ASP.NET Core Attributes

When working with ASP.NET core one of the features now front and centre is dependency injection, built into the framework. Whether you're familiar with the pattern from using an IoC container from an external library, or are new to it with .NET core, the situations where you can't seem to make use of it start to stick out. In the post I'm going to share a few ways of tackling dependency injection with attributes and filters. These require a parameterless constructor and as such you can't use the typical pattern of constructor injection.

I've prepared a tiny GitHub repository with the three examples discussed here.

1. Using service location

This first approach isn't for the purists, and you'll risk other developers muttering "anti-pattern" at you, but it'll work. The idea is to use service location, in the constructor to retrieve the required services and set them to class level variables, where they can be used in the various methods. It's not great, as it makes testing the class more difficult - though not impossible - as you can't pass mocked or stubbed services so easily to the class under test's constructor. Also grabbing this "global state" is a bit of a code-smell; ideally a class will be provided its dependency rather than having to go out and get them.

In this example, we have an attribute responsible for adding an HTTP header to the response, using a value retrieved from a service. By referencing the Microsoft.Extensions.DependencyInjection namespace instances of any services registered with the IoC container can be requested and their methods called.

2. Using a Type Filter

In order to use constructor based dependency injection, we can instead make use of a TypeFilter.

In the following code, you'll see we're implementing IResultFilter rather than inheriting from ActionFilterAttribute, and using the registered service instance passed into the constructor.

The only downside to this is the application of the filter to a given controller or action method is a little more verbose:

3. Using an Attribute That Wraps a Type Filter

The last, and in my view nicest, approach is one the team working on the Umbraco .NET Core transition are using and who introduced it to me.

With this approach we have both dependency injection via the constructor and the simple attribution.

Here, we inherit from TypeFilterAttribute and in it's parameterless constructor pass an instance of a filter type to the base constructor. The filter we define as a private class within the attribute, encapsulating it to ensure it's not used by any other code in the solution. The filter is implemented in exactly the same way as in the second example, using constructor based dependency injection.

And we can attribute our controllers with it just like a standard attribute.

Comments

Post a Comment