I am wondering why .Net IoC containers do not easily support multiple implementations for a single interface! May be I am wrong, but as far I have seen, frameworks like Nin
My container Griffin.Container supports it.
registrar.RegisterConcrete<OneImplementation>();
registrar.RegisterConcrete<AnotherImplementation>();
And to fetch:
var services = container.Resolve<ITheService>();
However, you can't get one specific implementation. It's a design decision. It's much better to register a factory in the container if have to get a specific implementation. Read more here in the best practices section.
Griffin.Container can be found at github: https://github.com/jgauffin/griffin.container
StructureMap provides these abilities:
For<IMyInterface>().Add<MyInterfaceImpl1>().Named("MyInterfaceImpl1");
For<IUsingInterface>().Add<UsingInterfaceImpl>().Ctor<IMyInterface>().Is(i => i.GetInstance<IMyInterface>("MyInterfaceImpl1"));
Unity has the same functionality
Register named dependency
var container = new UnityContainer();
container.RegisterType<IConnector, Connector>("TestConnector");
Resolve by name
container.Resolve<IConnector>("TestConnector");
the same approach
[Dependency("TestConnector")]
public IConnector Connector { get; set; }
Windsor has the same
class Program
{
static void Main(string[] args)
{
var container = new WindsorContainer()
.Register(Component.For<IConnector>().ImplementedBy<ConnectorA>().Named("ConnectorA"))
.Register(Component.For<IConnector>().ImplementedBy<ConnectorB>().Named("ConnectorB"));
var connectorA = container.Resolve<IConnector>("ConnectorA");
Console.WriteLine("Connector type: {0}", connectorA.GetType());
var connectorB = container.Resolve<IConnector>("ConnectorB");
Console.WriteLine("Connector type: {0}", connectorB.GetType());
Console.ReadKey();
}
}
public interface IConnector
{
}
public class ConnectorA : IConnector
{
}
public class ConnectorB : IConnector
{
}
If you want to access implementations with certain conditions, you can use Dictionary.
UC_Login: The user must validate their credentials according to the Authentication Mode (By Database or Active Directory), each authentication mode has different business logic.
My code: I have an Interface called IAuthService.cs I have two classes called DatabaseAuthService.cs and ActiveDirectoryAuthService.cs both with the same IsValidCredential (User user) method that depend on the same Interface.
public interface IAuthService
{
Task<bool> IsValidCredentialAsync(User user);
}
public class DatabaseAuthService : IAuthService
{
private readonly IDatabaseAuthRepository _databaseAuthRepository;
// User IServiceProvider for access to any other interfaces
// using Microsoft.Extensions.DependencyInjection; using System;
public DatabaseAuthService(IServiceProvider serviceProvider)
=> _databaseAuthRepository = serviceProvider.GetService<IDatabaseAuthRepository>();
public async Task<bool> IsValidCredentialAsync(User user)
{
// return await _databaseAuthRepository.something...
}
}
public class LdapAuthService : IAuthService
{
public LdapAuthService()
{
}
public async Task<bool> IsValidCredentialAsync(User user)
{
// something...
}
}
Condition Implemented: I use the AuthenticationAppServiceclass, with the LoginAsync (LoginDto dto) method.
public class AuthenticationAppService
{
private readonly Dictionary<AuthenticationModeEnum, IAuthService> _authProviders =
new Dictionary<AuthenticationModeEnum, IAuthService>();
public AuthenticationAppService(IServiceProvider serviceProvider)
{
_authProviders.Add(AuthenticationModeEnum.Database, new DatabaseAuthService(serviceProvider));
_authProviders.Add(AuthenticationModeEnum.ActiveDirectory, new LdapAuthService());
}
public Task<bool> LoginAsync(LoginDto dto)
{
var user = Mapper.Map<user, LoginDto>(dto);
return await _authProviders[(AuthenticationModeEnum)dto.AuthMode].IsValidCredentialAsync(user);
}
}
maybe not on topic, but hope it helps.
Your question is a bit vague, since you don't supply a concrete example of when you think you need this. In most cases there is a problem in your application or design, or you aren't following DI best practices.
All containers allow you to register multiple dependencies with the same interface as an IEnumerable<ThatInterface>
, even if they do not have deep support for multiple instances. Injecting lists of services into other services however, is a design smell, and it would be better to hide this list behind a Composite. This hides the fact that there are multiple implementations behind the abstraction, and allows you to easily change the way those multiple implementations are used, by changing just a single place in the application. I don't believe any IoC framework has any support for generating composites for you, since the there is no one default way of processing the wrapped implementations. You'll have to write this Composite yourself. However, since writing such a composite is really, really simple, this justifies not having such feature in the framework.
If you want to have multiple implementations, but always need one to be returned, based on some configuration, there are always ways to do this. Most containers allow you to configure those dependencies in an XML configuration file. But even if a container does not contain such feature, reading this value from the configuration file manually and registering the right type in the container is very easy.
If you have one implementation of a certain interface for production and another implementation for unit testing purposes, you should only register the production implementation in the container. Your unit tests should be clear of any DI container, and you should manually create a class under test, and inject fake dependencies in its constructor, by simply new
ing the type up. Using a DI container, pollutes and complicates your tests. To pull this off, you will need to design such type around the constructor injection pattern. Don't call the container (or any other facade over the container) inside the service under test, to retrieve dependencies.
I advice to look at Convention over Configuration and especially Convention Based Dependency Injection and context-based dependency injection. Most of IoC if not all supports both approaches. You could find many interesting samples with different IoC libraries, when several implementation bind to one interface, and how useful it could be.
For example ninject does support binding of several implementation of one interface: depends on context or attributes, by names, and so one.
Following snippet binds on implemetation depends on target type automaticaly:
Bind<IWarrior>().To<Samurai>().WhenInjectedInto(typeof(OnLandAttack));
Bind<IWarrior>().To<SpecialNinja>().WhenInjectedInto(typeof(AmphibiousAttack));
Very helpful when you configuration is in XML or database. Take into account InNamedScope also:
Bind<IWeapon>().To<Shuriken>().Named("Strong");
Bind<IWeapon>().To<Dagger>().Named("Weak");
With different dependency configuration at different parts of your project.