As you say, your two individual requirements are natively supported by AutoFac.
However, there doesn't appear to be direct support for using these two constructs together. I.e. the following does not work:
public enum ServiceType
{
ServiceA,
ServiceB
}
public class MyComponent
{
public MyComponent(Func<string, IIndex<ServiceType, IService> factory)
{
var service = factory("some_string")[ServiceType.ServiceA];
}
}
My work around for this has always been to move the resolution of the service to a factory per service implementation. This then works as follows:
- Components with a dependency on a specific service implementation take in an AutoFac factory delegate that resolves to the factory specific to the required service implementation
- In turn, the service factories have a dependency on an AutoFac factory delegate that knows how to create the specific service implementation from the (runtime) constructor parameters of the service
- This approach uses the native AutoFac constructs and doesn't have any dependencies on AutoFac outside of the container wiring.
Heres a rough-and-ready example. Note the multiple factories could be reduced to a single generic factory - but I've left it as-is for clarity:
Service implementations
public enum ServiceType
{
NotSet,
ServiceA,
ServiceB
}
public interface IService
{
string DoWork();
}
public class ServiceA : IService
{
private readonly string _name;
public ServiceA(string name)
{
_name = name;
}
public string DoWork()
{
throw new NotImplementedException();
}
}
public class ServiceB : IService
{
private readonly string _name;
public ServiceB(string name)
{
_name = name;
}
public string DoWork()
{
throw new NotImplementedException();
}
}
Service factories
public interface IServiceFactory
{
IService Create(string name);
}
public class ServiceAFactory : IServiceFactory
{
private readonly Func<string, ServiceA> _factory;
public ServiceAFactory(Func<string, ServiceA> factory)
{
_factory = factory;
}
public IService Create(string name)
{
return _factory(name);
}
}
public class ServiceBFactory : IServiceFactory
{
private readonly Func<string, ServiceB> _factory;
public ServiceBFactory(Func<string, ServiceB> factory)
{
_factory = factory;
}
public IService Create(string name)
{
return _factory(name);
}
}
Service registrations
builder.RegisterType<ServiceA>().As<ServiceA>();
builder.RegisterType<ServiceB>().As<ServiceB>();
builder.RegisterType<ServiceAFactory>().Keyed<IServiceFactory>(ServiceType.ServiceA);
builder.RegisterType<ServiceBFactory>().Keyed<IServiceFactory>(ServiceType.ServiceB);
builder.RegisterType<ComponentWithServiceDependency>().As<ComponentWithServiceDependency>();
Example usage
public class ComponentWithServiceDependency
{
private readonly IService _service;
public ComponentWithServiceDependency(IIndex<ServiceType, IServiceFactory> serviceFactories)
{
// Resolve the ServiceB service implementation,
// using the string "test" as its constructor dependency
_service = serviceFactories[ServiceType.ServiceB].Create("test");
}
public string Test()
{
return _service.DoWork();
}
}