Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Dependency resolution in .NET Core

I created a sample to test my understanding of dependency resolutions (particularly their order, if any) on .NET Core.
It did clarify some points, but left me with one unanswered.

Consider the following Worker Service template code:

Foo

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

        public class Foo : IFoo
        {
            private readonly IGoo Goo;
    
            public Foo(IGoo goo)
            {
                Goo = goo;
                Console.WriteLine($"Instance of [{this.GetType().Name}] being created...");
            }
        }
    
        public interface IFoo
        {
        }

Goo


        public class Goo : IGoo
        {
            private readonly IWoo Woo;
            public Goo(IWoo woo)
            {
                Woo = woo;
                Console.WriteLine($"Instance of [{this.GetType().Name}] being created...");
            }
        }
    
        public interface IGoo
        {
        }

Woo


        public class Woo : IWoo
        {
            IFoo Foo;
            public Woo(IFoo foo)
            {
                Foo = foo;
                Console.WriteLine($"Instance of [{this.GetType().Name}] being created...");
            }
        }
    
        public interface IWoo
        {
        }

Worker Service


        public class Worker : BackgroundService
        {
            private readonly ILogger<Worker> _logger;
            //private readonly IFoo Foo;
            private readonly IGoo Goo;
            //private readonly IWoo Woo;
    
            public Worker(ILogger<Worker> logger, /*IFoo foo,*/ IGoo goo/*, IWoo woo*/)
            {
                _logger = logger;
                //Foo = foo;
                Goo = goo;
                //Woo = woo;
            }
    
            protected override async Task ExecuteAsync(CancellationToken stoppingToken)
            {
                while (!stoppingToken.IsCancellationRequested)
                {
                    _logger.LogInformation("Worker running at: {time}", DateTimeOffset.Now);
                    await Task.Delay(1000, stoppingToken);
                }
            }
        }

Program.cs


        public class Program
        {
            public static void Main(string[] args)
            {
                CreateHostBuilder(args).Build().Run();
            }
    
            public static IHostBuilder CreateHostBuilder(string[] args) =>
                Host.CreateDefaultBuilder(args)
                    .ConfigureServices((hostContext, services) =>
                    {
                        services.AddHostedService<Worker>();
                        services.AddSingleton<IFoo, Foo>();
                        services.AddSingleton<IGoo, Goo>();
                        services.AddSingleton<IWoo, Woo>();
                    });
        }

At first I wanted to make sure the dependency order declaration inside ConfigureServices does not matter.
Running the code above, however, prints Instance of [Goo] being created... only.
I would expect to have Instance of [Woo] being created... printed as well, given it is a dependency of Goo, which is resolved.
I would expect Woo to be required resolution as well, and therefore its constructor being invoked. But this happens only for Goo, not for Woo.

Why is that?

>Solution :

Because build in DI does not support property injection so Woo does not have anything to resolve:

public class Woo : IWoo
{
    IFoo Foo;
    public void WooM1(IFoo foo)
    {
        Foo = foo;
        Console.WriteLine($"Instance of [{this.GetType().Name}] being created...");
    }
}

From the docs:

The built-in service container is designed to serve the needs of the framework and most consumer apps. We recommend using the built-in container unless you need a specific feature that it doesn’t support, such as:

  • Property injection

If you add the ctor:

IFoo Foo;

public Woo(IFoo foo)
{
    Foo = foo;
}

Then you will get the circular dependency exception as expected:

Lifetime: Singleton ImplementationType: TestWorker.Worker’: A circular dependency was detected for the service of type ‘TestWorker.IGoo’.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading