Reputation: 251062
I have Unity running great for all the controllers in my ASP.NET Web API project - just using the default set up that comes out of the NuGet box. I have also managed to hook it up to MVC Filter Attributes - but can't seem to do the same for ASP.NET Web API filter attributes.
How to I extend this default implementation to inject a dependency into an ActionFilterAttribute, for example...
public class BasicAuthenticationAttribute : ActionFilterAttribute
{
[Dependency]
public IMyService myService { get; set; }
public BasicAuthenticationAttribute()
{
}
}
This filter is applied to controllers using attributes:
[BasicAuthentication]
I'm pretty sure I need to hook up the Unity container so it handles the creation of the attribute class, but need some clues about where to start as it does not use the same extensibility points as the MVC filters.
I just wanted to add, other things I have tried include service location rather than dependency injection, but the DependencyResolver you get back is not the same one you configure.
// null
var service = actionContext.Request.GetDependencyScope().GetService(typeof(IMyService));
Or
// null
var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IApiUserService));
Upvotes: 4
Views: 3191
Reputation: 4933
The problem is that the Attribute class is created by .NET and not by the WebAPI framework.
Before reading farther, did you forget to configure your DependencyResolver with your IApiUserService?
(IUnityContainer)container;
container.RegisterType<IApiUserService, MyApiUserServiceImpl>();
...
var service = GlobalConfiguration.Configuration.DependencyResolver.GetService(typeof(IApiUserService));
I created an App_Start\UnityConfig class that holds my UnityContainer:
public class UnityConfig {
#region Unity Container
private static Lazy<IUnityContainer> container = new Lazy<IUnityContainer>(() => {
var container = new UnityContainer();
RegisterTypes(container);
return container;
});
/// <summary>
/// Gets the configured Unity container.
/// </summary>
public static IUnityContainer GetConfiguredContainer() {
return container.Value;
}
#endregion
public static void Configure(HttpConfiguration config) {
config.DependencyResolver = new UnityDependencyResolver(UnityConfig.GetConfiguredContainer());
}
/// <summary>Registers the type mappings with the Unity container.</summary>
/// <param name="container">The unity container to configure.</param>
/// <remarks>There is no need to register concrete types such as controllers or API controllers (unless you want to
/// change the defaults), as Unity allows resolving a concrete type even if it was not previously registered.</remarks>
private static void RegisterTypes(IUnityContainer container) {
// NOTE: To load from web.config uncomment the line below. Make sure to add a Microsoft.Practices.Unity.Configuration to the using statements.
// container.LoadConfiguration();
// TODO: Register your types here
// container.RegisterType<IProductRepository, ProductRepository>();
container.RegisterType<MyClass>(new PerRequestLifetimeManager(), new InjectionConstructor("connectionStringName"));
}
}
The UnityDependencyResolver
and PerRequestLifetimeManager
came from this blog post and Unity.WebApi (Project/Nuget Package) which I internalized. (since it's a bootstrap)
When I need to make use of the UnityContainer in my other code, I passed it into the constructor:
config.Filters.Add(new MyFilterAttribute(UnityConfig.GetConfiguredContainer()));
Upvotes: 7