1

I have two MVC controllers.

Both controllers have an dependency on the IFileContainer interface.

In one controller I want resolve FsFileContainer and in second controller I want resolve FtpFileContainer.

Register:

    serviceCollection.AddTransient<IFileContainer, FsFileContainer>();
    serviceCollection.AddTransient<IFileContainer, FtpFileContainer>();

How to resolve container in this case?

Raskolnikov
  • 3,791
  • 9
  • 43
  • 88
  • 2
    Please, don't use MVC6 tags anymore. It's for a future version of ASP.NET MVC based on the old webstack (MVC5). ASP.NET Core is a complete new and incompatible, portable version based on .NET Core. Use [tag:asp.net-core-mvc] and/or [tag:asp.net-core] tags instead and your question is more likely to be found by people who can help you with the issue. Second, don't use dnx anymore, it's not being developed anymore. the new versions only work with the dotnet-cli tooling chain found here https://www.microsoft.com/net/core#windows. Upgrade to 1.0 RTM as soon as possible – Tseng Jul 08 '16 at 12:08

1 Answers1

2

The easiest way is to use a factory instead as the ASP.NET Core IoC Container doesn't support named dependencies or use a 3rd party IoC container which supports it.

public class FileContainerFactory : IFileContainerFactory 
{
    private readonly IServiceProvider provider;
    public class FileContainerFactory(IServiceProvider provider)
    {
        this.provider = provider;
    }

    public IFileContainer CreateFileSystemContainer() 
    {
        // resolve it via built in IoC
        return provider.GetService<FsFileContainer>();
    }

    public IFileContainer CreateFtpContainer() 
    {
        // resolve it via built in IoC
        return provider.GetService<FtpFileContainer>();
    }
}

Then inject the IFileContainerFactory into your controller.

An alternative is to mark your interfaces with a marker interface and register/inject these

// It defines no new methods or properties, just inherits it and acts as marker
public interface IFsFileContainer : IFileContainer {}
public interface IFtpFileContainer : IFileContainer {}

public class FsFileContainer : IFsFileContainer
{
    ...
}

in Startup.cs

services.AddTransient<IFsFileContainer, IFileContainer>();
services.AddTransient<IFtpFileContainer, IFileContainer>();
Tseng
  • 61,549
  • 15
  • 193
  • 205
  • 1
    I wouldn't recommend the first option. Using some sort of Service locator pattern is not very nice. See here: http://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/ – Jamie Rees Jul 08 '16 at 14:12
  • 1
    @JamieR: Factory pattern isn't a service locator, the provider within is injected by the IoC framework (rather than injecting the container into your services or have a static class for resolving), hence it's not hiding dependencies like service locator does. The interface can be mocked for unit test and the most common way to instantiate object which require runtime parameters. Also don't forget, most factory implementations are not part of business/domain layer, it belongs to the application layer and application services can be aware of the IoC container. Domain and infrastructure shouldn't – Tseng Jul 08 '16 at 15:48
  • 1
    And quite funny you quote Mark Seemann, as he's an advocate of the Abstract Factory pattern. http://stackoverflow.com/questions/2045904/dependency-inject-di-friendly-library/2047657#2047657. Third alternative is of course to use facade pattern and provide both instances as properties or using the strategy pattern. Without more information its hard to suggest concrete strategies, as we don't know if OP is in control of the implementations of if they are 3rd party implementations, then it may be hard to enforce a marker interface as this would require the 3rd party to update the implementation – Tseng Jul 08 '16 at 15:49