Dependency Injection
Dependency Injection is a way to implement Inversion of Control (IoC). In this case, a dependency is an object that another object depends on. It involves abstracting classes into interfaces, so that the interface can be injected into the constructor of classes which depend on it. This allows implementation details to be changed at compile-time (e.g., to be used for automated testing), but does not change how things run at run-time.
Scopes
- Singleton: A single instance of the dependency is used for all requests
- Used for classes that are expensive to create, or maintain a common state.
- The implementation needs to be thread-safe
- e.g. logger
- Scoped: A single instance of the dependency is used for each request
- Used for something that needs to maintain state within a request, but not beyond it, like a shopping cart.
- Transient: A new instance is used every time the dependency is requested.
- Useful for lightweight stateless services
Here's an example of code without dependency injection
public class Worker : BackgroundService
{
// INSTANTIATING THE DEPENDENCY AS AN OBJECT
private readonly MessageWriter _messageWriter = new();
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
_messageWriter.Write($"Worker running at: {DateTimeOffset.Now}");
await Task.Delay(1_000, stoppingToken);
}
}
}
Here's an example of code with dependency injection
namespace DependencyInjection.Example;
// THE DEPENDENCY IS PASSED IN THE CONSTRUCTOR, USING AN INTERFACE
public sealed class Worker(IMessageWriter messageWriter) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
while (!stoppingToken.IsCancellationRequested)
{
messageWriter.Write($"Worker running at: {DateTimeOffset.Now}");
await Task.Delay(1_000, stoppingToken);
}
}
}
The concrete class to be used during DI is set up in the Program.cs
file for C# applications.
// Example in Program.cs
var builder = WebApplication.CreateBuilder(args);
// Register your services here
builder.Services.AddSingleton<IMessageWriter, MessageWriter>();
builder.Services.AddScoped<IOtherService, OtherService>();
builder.Services.AddTransient<IDataRepository, DataRepository>();
var app = builder.Build();
// ... further configuration and running the app
app.Run();