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
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’.