Reputation: 2970
I have a Docker DotNet Core console app that processes messages from a queue.
There is a class called SimulationEngine
and I was expecting that ILogger
is passed by Dependency Injection automatically
public class SimulationEngine
{
ILogger<SimulationEngine> logger;
public SimulationEngine(ILogger<SimulationEngine> logger)
{
this.logger = logger;
}
This is how the instance is created:
public class RunsQueueProcessor : ...
{
public RunsQueueProcessor(..., ILogger<RunsQueueProcessor> logger)
{
}
protected override async Task ProcessMessage(...)
{
this.logger.LogInformation(...);
// Here DI is not working
var engine = new SimulationEngine();
DI works fine to inject logger into RunsQueueProcessor
, but it fails when I try to new SimulationEngine()
with the following error:
Error CS7036 There is no argument given that corresponds to the required formal parameter 'logger' of 'SimulationEngine.Simui lationEngine(ILogger<SimulationEngine>)'
How can I tell DotNet to use DI for that constructor?
--- EDIT ---
I wrote this question because I am working on a PoC and I don't need Dependency Injection everywhere. I only need it in few places where I am doing Unit Testing to validate specific algorithms.
A more concrete questions is if there is a way to configure DotNet DI framework to inject dependencies when using the new
statement or manually instantiating objects.
Thanks to all comments and answers, Now I understand more about how DotNet DI works.
Upvotes: 2
Views: 1909
Reputation: 3116
According to your last comment, you want more focus on explaining the Dependency Injection: The Other option, which is the traditional and the right way to do is:
ISimulationEngine
.ISimulationEngine
in SimulationEngine
IServiceCollection
(in startup.cs)it
in the constructor of RunsQueueProcessor
class so the app understands you want to use SimulationEngine
.The marker interface
public interface ISimulationEngine
{
void DoSomthing();
}
The Service that implements the interface
public class SimulationEngine : ISimulationEngine
{
private readonly ILogger<SimulationEngine> _logger;
public SimulationEngine(ILogger<SimulationEngine> logger) //<-- here you are injecting the registered Singleton of ILogger
{
_logger = logger;
}
public async void DoSomthing()
{
throw new NotImplementedException();
}
}
Suppose another service implements the interface
public class AnotherService: ISimulationEngine
{
public async void DoSomthing()
{
throw new NotImplementedException();
}
}
The registration of service in startup.cs
public void ConfigureServices(IServiceCollection services)
{
//...
// this means whenever ISimulationEngine injected that class can use
// SimulationEngine service
services.AddTransient<ISimulationEngine, SimulationEngine>();
//...
}
Note that you registered the interface ISimulationEngine
for SimulationEngine
but not for AnotherService
which is also implementing the same marker but because of the registration in the container says whenever you see ISimulationEngine injected go and use SimulationEngine
Now inject the ISimulationEngine in the class that you want to use
public class RunsQueueProcessor
{
private readonly ILogger<RunsQueueProcessor> _logger;
private readonly ISimulationEngine _service;
public RunsQueueProcessor(ILogger<RunsQueueProcessor> logger, //<-- here AGAIN you are injecting the registered Singleton of ILogger
ISimulationEngine service //<-- her you inject the Marker Interface so you can use any class implement this interface
)
{
_logger = logger;
_service = service;
}
protected async Task ProcessMessage()
{
_logger.LogInformation("fdfdfd");
await _service.DoSomthing();
// Here DI is not working
//var engine = new SimulationEngine();
}
}
As a conclusion: You can imagine the process of injecting like the class say go and check the DI container, which service is defined for this interface?! let me use it.
you may ask what is the different between AdTransient and AddSingleton (there is AddScoped as well) check the link AddTransient, AddScoped and AddSingleton Services Differences
Upvotes: 4