I'm currently working on a ASP.NET Core Project and want to use the built-in Dependency Injection (DI) functionality.
Well, I started with an interface:
ICar
{
string Drive();
}
and want to implement the ICar
interface multiple times like
public class BMW : ICar
{
public string Drive(){...};
}
public class Jaguar : ICar
{
public string Drive(){...};
}
and add the following in the Startup
class
public void ConfigureServices(IServiceCollection services)
{
// Add framework services.
services.AddMvc();
services.AddTransient<ICar, BMW>();
// or
services.AddTransient<ICar, Jaguar>();
}
Now I have to make a decision between two implementations and my decided class will set in every constructor that needs an ICar implementation. But my idea was to say, if the requested Controller is BMWController, then use BMW implementation or use Jaguar if the JaguarController is requested.
Otherwise DI don't make sense for me. How can i handle this issue properly?
For better understanding my problem take a look to this pic: https://media-www-asp.azureedge.net/media/44907/dependency-injection-golf.png?raw=true How does the dependency resolver work and where can i set it up in ASP.NET Core?
In Unity it's possible to make something like this
container.RegisterType<IPerson, Male>("Male");
container.RegisterType<IPerson, Female>("Female");
and call the correct type like this
[Dependency("Male")]IPerson malePerson
The functionality you are looking for isn't easy to implement, at least when you are using it in the controller because controllers are treated a bit specially (By default, controllers aren't registered with
ServiceCollection
and hence not resolved/instantiated by the container and instead instantiated by ASP.NET Core during the request, see also the explanation and example on my related answer).With built-in IoC container, you can only do it via factory method, here with an example on a
BmwCarFactory
class:The default IoC container is intentionally kept simple to provide basics of dependency injection to get you started and for other IoC containers to be able to easily plugin in there and replace the default implementation.
For more advanced scenarios the users are encouraged to use an IoC of their choice which supports more advanced features (assembly scan, decorators, conditional/parameterized dependencies, etc.
AutoFac (which I use in my projects) supports such advanced scenarios. In the AutoFac documentation there are 4 scenarios (altogether with the 3rd which @pwas suggested in the comments):
1. Redesign your classes
Needs some additional overhead of refactoring your code and class hierarchy but heavily simplifies the consumption of injected services
2. Change the registrations
The docs describe it here, if you are unwilling or unable to change the code.
3. Using keyed services (here)
It is pretty similar to the previous approach to 2. but resolves the services based on a key, rather than their concrete type
4. Use Metadata
This is quite similar to 3. but you define the keys via attribute.
Other containers like Unity have special attributes, like
DependencyAttribute
which you can use to annotate the dependency, likeBut this and the 4th option of Autofac make the IoC container leak into your services and you should consider the other approaches.
Alternatively you create classes and factories which resolve your services based on some conventions. For example a
ICarFactory
:Then use it like
Alternative to IServiceProvider