One of my MVC attributes has a dependancy on a service which I was hoping to inject via the constructor. Obviously the MVC attribute requires a parameterless constructor too.
public MyAttribute()
{
...
}
public MyAttribute(IMyService)
{
...
}
I was thinking I could do a property injection rather than constructor injection however my controllers(and their attributes) are in a seperate class library with no reference to an IoC container.
Is there are way of using a service within an attribute filter without referencing the IoC container?
For what it's worth I'm using Ninject for MVC3
Thanks
The Dependency Injection (DI) Design Pattern The Dependency Resolver in ASP.NET MVC can allow you to register your dependency logic somewhere else (e.g. a container or a bag of clubs). The advantages of using Dependency Injection pattern and Inversion of Control are the following: Reduces class coupling.
As a general solution (without any special integration support of your DI framework), MVC3 asks the IDependencyResolver
for an IFilterProvider
. In other words, the trick is to:
FilterAttributeFilterProvider
from the System.Web.Mvc.FilterProviders
collection.IDependencyResolver
for your particular DI framework (if you're not already doing that).IFilterProvider
in your container that can inject the properties of any requested attribute.This looks like this:
var container = new [your favorite container];
// 1. Remove the FilterAttributeFilterProvider from the collection.
var providers = FilterProviders.Providers
.OfType<FilterAttributeFilterProvider>().ToList();
providers.ForEach(p => FilterProviders.Providers.Remove(p));
// 2. Register a IDependencyResolver
DependencyResolver.SetResolver(new YourDiResolver(container));
// 3. Register a customer IFilterProvider.
container.Register<IFilterProvider, YourAttributeFilterProvider>();
The YourAttributeFilterProvider
will look like this:
private class YourAttributeFilterProvider
: FilterAttributeFilterProvider
{
private readonly [your favorite container] container;
public YourAttributeFilterProvider(
[your favorite container] container)
: base(false)
{
this.container = container;
}
public override IEnumerable<Filter> GetFilters(
ControllerContext controllerContext,
ActionDescriptor actionDescriptor)
{
var filters = base.GetFilters(controllerContext,
actionDescriptor).ToList();
// Inject properties into attribute here.
filters.ForEach(f => container.InjectProperties(f.Instance));
return filters;
}
}
Many frameworks, such as Ninject and Autofac, have built-in support for this through their MVC integration packages. Still it is valuable to understand how to do this manually.
WARNING:
One big warning about dependency injection in MVC filter attributes. MVC caches attributes and reuses instances for the duration of app domain. This means that they practically become singletons, and they drag their dependencies along. In other words: those dependencies will become singletons as well, which is also known as the captive dependency problem. So be sure you only inject singletons into your attributes, because your production system will be troubled by concurrency bugs if you don't.
Although most DI frameworks have support for injection into filter attributes, none of the frameworks helps into fixing this issue. So a better solution instead is to keep your attributes passive, as explained here and here.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With