3

Until now, I have used the Unity IOC container to resolve dependencies, which works just fine. With the Unity DI, I normally resolve instances in the following way:

Public class TestClass {
    public TestClass()
    {
        var instance = IOC.resolve<InterfaceClassToResolve>();
    }
}

This works great, but seeing that .net core now provides me with an out of the box DI container, I would much rather like to use that - There is just one problem compared to the Unity IOC, namely that it is injected as a constructor argument, and not resolved like the example above.

In most cases, I figured that it forces me to chain my dependencies throughout multiple classes, instead of just resolving my dependency in the classes that actually needs them.

I have been looking at ways to solve this, and as far as I can see, the only option is to do something like this:

Public class TestClass {
    public TestClass(IServiceProvider serviceProvider)
    {
        var instance = serviceProvider.GetService<InterfaceClassToResolve>();
    }
}

And then we are back to square one again...

Therefore, am I missing some of the functionality behind the .net core IOC, or is there some secret sauce to why most examples wants me use the .net core IOC via constructor arguments?

Jeppe Christensen
  • 1,680
  • 2
  • 21
  • 50
  • 3
    In both your code examples you are using the Service Locator pattern, not Dependency Injection. `...namely that it is injected as a constructor argument, and not resolved like the example above` that's how DI works. Can provide more information for the problem you are trying to solve? – Jonesopolis Feb 24 '20 at 12:05
  • 2
    I think the secret sauce is that the [Service Locator pattern is nowadays often considered to be an anti-pattern](https://blog.ploeh.dk/2010/02/03/ServiceLocatorisanAnti-Pattern/), which is possibly why it isn't supported by .Net Core. – Matthew Watson Feb 24 '20 at 12:06
  • First, IoC means not specific library at all. IoC simply means: Inversion of Control, and that's what it does. Dependencies are passed as constructor parameters rather than `new`ing them (Service Locator essentially is almost same as `new`ing except that it manages live time). And DI means: Dependency **injection**, can be done w/o any framework by just passing the object via constructor. Service Locator hides dependencies (someone inspecting the class doesnt know what it is requesting, hence can't efficiently unit test it w/o knowing the source. – Tseng Feb 24 '20 at 12:14
  • 1
    Constructor injection makes dependencies obvious and shows you code smells / design flaws/single-responsibility principle violations very obvious – Tseng Feb 24 '20 at 12:15
  • 1
    That makes perfect sense! So chaining dependencies in a class hierarchy is actually a good thing in this case, rather than having to `new` up for each class in which i need the dependency. – Jeppe Christensen Feb 24 '20 at 12:16
  • There's a good discussion about service locator in [this questopn](https://stackoverflow.com/questions/22795459/is-servicelocator-an-anti-pattern) – stuartd Feb 24 '20 at 12:51

2 Answers2

0

As already commented, Service Locator pattern is not the best method and considered an anti-pattern. I understand the necessity, though, of finding a way to easily convert existing code to the out-of-the-box DI system without going mad. I therefore suggest you to do something like this:

1) Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        services.AddDbContext<DatabaseContext>(
            options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));

        // other services configuration here

        // IMPORTANT: This should be the last line of ConfigureServices!
        IOC.CurrentProvider = services.BuildServiceProvider();
    }
...

2) IOC.cs

public class IOC
{
    public static IServiceProvider CurrentProvider { get; internal set; }

    public static T resolve<T>()
    {
        return CurrentProvider.GetService<T>();
    }
}

This should allow you to use dotnet core DI with existing service locator code based on Unity, with minimal fixes (basically just some using declarations to be fixed), as long as you solemnly promise to refactor your code as soon as possible to get rid of all that Service Locator code :D

Claudio Valerio
  • 2,302
  • 14
  • 24
  • This is not going to work, as you don't have lifetime handling. First, you will have two application level containers: First one created by ASP.NET Core after `ConfigureServices` method but before calling `Configure` and second the one created via `services.BuildServiceProvider();` which is an application level container. Services resolved from it won't be disposed by the end of the request – Tseng Feb 24 '20 at 13:03
0

You can use DI without constructors like:

On the ConfigureServices

services.AddSingleton<YourClass>()

Then inject it like this:

private YourClass YourClass
{
    get
    {
        return this.serviceProvider.GetRequiredService<YourClass>();
    }
}
Kiril1512
  • 3,231
  • 3
  • 16
  • 41