Reputation: 3746
I am working on a web application which is built on ASP.NET Core and I am using Autofac for dependency injection.
I have an interface as ICacheProvider
, and there are 3 concrete implementations of this interface - OrderCacheProvider
, ProductsCacheProvider
and CustomerCacheProvider
. The infrastructure and logic are different for the different cache providers. They are registered as below:
builder.RegisterType<CustomerCacheProvider>()
.Keyed<ICacheProvider>(CacheType.Customer);
builder.RegisterType<OrderCacheProvider>()
.Keyed<ICacheProvider>(CacheType.Order);
builder.RegisterType<ProductCacheProvider>()
.Keyed<ICacheProvider>(CacheType.Product);
Now I have 3 controllers - OrdersController
, ProductsController
and CustomerController
. Each controller expects an ICacheProvider
in the below fashion
public class OrdersController: BaseController {
private readonly ICacheProvider _cacheProvider;
public OrdersController(ICacheProvider cacheProvider) {
_cacheProvider = cacheProvider;
}
}
Now my problem is how do I inject OrderCacheProvider
is injected in OrdersController
? The same goes for the CustomerCacheProvder
to CustomersController
and ProductsCacheProvider
?
Upvotes: 2
Views: 1596
Reputation: 16192
You can use the WithParameter
method when you register your controller to specify which ICacheProvider
it should use
builder.RegisterType<OrdersController>()
.WithParameter(ResolvedParameter.ForKeyed<ICacheProvider>(CacheType.Order));
Another option would be to use the KeyFilter
attribute
public class OrdersController
{
public OrdersController([KeyFilter(CacheType.Order)]ICacheProvider cacheProvider)
{ }
}
I prefer the first solution than this one which looks more pure, your component just has to request ICacheProvider
nothing more.
Another solution would be to create a custom module that will add the parameter for each controller based on conventions.
protected override void AttachToComponentRegistration(
IComponentRegistry componentRegistry, IComponentRegistration registration)
{
base.AttachToComponentRegistration(componentRegistry, registration);
if (registration.Activator.LimitType.IsSubclassOf(typeof(BaseController)))
{
String controllerName = registration.Activator.LimitType.Name;
controllerName = controllerName.Substring(0, controllerName.Length - 10);
if (Enum.TryParse<CacheType>(controllerName, out CacheType cacheType))
{
registration.Preparing += (sender, e) =>
{
e.Parameters = new Parameter[]
{
ResolvedParameter.ForKeyed<ICacheProvider>(cacheType)
}
.Concat(e.Parameters);
};
}
else
{
// throw, use default cache, do nothing, etc.
throw new Exception($"No cache found for controller {controllerName}");
}
}
}
}
It is more code but you don't have to use the WithParameter
for every controller registration, it can be great if you have lot of controller. You still have to register the module :
builder.RegisterModule<CacheProviderModule>();
Upvotes: 1