Overview
As a vital component of modern software development, dependency injection promotes decoupling and maintainability. With .NET 8, dependency injection is a first-class citizen, so developers can manage and inject dependencies more easily. In this article, we'll explore the ins and outs of dependency injection in .NET 8, covering best practices and common scenarios.
Understanding Dependency Injection
The dependency injection design pattern facilitates the inversion of control (IoC) in an application by injecting the required dependencies from outside rather than creating instances of them within a class. This promotes modularity, testability, and ease of maintenance.
Add Required NuGet Packages
If you want to use dependency injection in .NET 8, you will need to install the necessary packages. The built-in DI container is part of the Microsoft.Extensions.DependencyInjection package.
Three Ways to Add NuGet Packages
In this section of the article, we will look at the three ways to get the NuGet Packages installed on our .net C# project. I have kept the steps very simple to follow.
Using Visual Studio 2022 IDE
Step 1
Open our Project in Visual Studio 2022 IDE
Step 2
Right-click on our Project in the Solution Explorer.
Step 3
Select the Manage NuGet Packages
Step 4
In the Browse Tab search for Microsoft.Extensions.DependencyInjection
Step 5
Select the page and click Install.
Using Visual Studio Code IDE
Step 1
Open Visual Studio Code: Launch Visual Studio Code on our computer.
Step 2
Open our Project: Open the project in which you want to install the NuGet package.
Step 3
Open Terminal: In Visual Studio Code, open the integrated terminal. You can do this by navigating to the View menu and selecting "Terminal" or by pressing Ctrl+` (backtick) on your keyboard.
Step 4
Navigate to Your Project Directory: Use the terminal to navigate to the directory of your project where the project file (.csproj) is located.
Step 5
Install the NuGet Package: In the terminal, type the following command to install the NuGet package using the .NET CLI:
dotnet add package Microsoft.Extensions.DependencyInjection
Step 6
Press Enter: After typing the command, press Enter to execute it. The .NET CLI will download and install the specified NuGet package along with its dependencies.
Step 7
Verify Installation: Once the installation process is complete, you can verify that the NuGet package was installed successfully by checking your project file (.csproj) to see if the package reference has been added.
Using .NET CLI
Step 1
Open Command Prompt :Open Command Prompt (Windows).
Step 2
Navigate to Your Project Directory: Use the cd command to navigate to the directory of your project where the project file (.csproj) is located.
Step 3
Install the NuGet Package: In the Command Prompt or Terminal, use the following command to install the NuGet package:
dotnet add package Microsoft.Extensions.DependencyInjection
Step 4
Press Enter: After entering the command, press Enter to execute it. The .NET CLI will download and install the specified NuGet package along with its dependencies.
Step 5
Verify Installation: Once the installation process is complete, you can verify that the NuGet package was installed successfully by checking your project file (.csproj) to see if the package reference has been added. By first selecting the project file .csproj.
Step 6
Then right-click and open with notepad to see whether the NuGet package has been installed successfully.
Configure Services in Program.cs
Within the ConfigureServices method of your Program.cs file, configure the services your application requires.
using DI.NET8_CSharp10_Guide_ZiggyRafiq.Services.Interfaces;
using DI.NET8_CSharp10_Guide_ZiggyRafiq.Services;
using Microsoft.Extensions.DependencyInjection;
Console.WriteLine("Hello, I am Ziggy Rafiq and I work for Capgemini!");
// Setup dependency injection container
var serviceProvider = new ServiceCollection()
.AddTransient<IFooService, FooService>()
.AddScoped<IBarService, BarService>()
.AddSingleton<IBazService, BazService>()
.BuildServiceProvider();
// Resolve services and use them
var fooService = serviceProvider.GetService<IFooService>();
var barService = serviceProvider.GetService<IBarService>();
var bazService = serviceProvider.GetService<IBazService>();
// Use the services Example One
fooService?.DoSomething();
barService?.DoSomethingElse();
bazService?.DoAnotherThing();
// Use the services Example Two
serviceProvider.GetService<IFooService>()?.DoSomething();
serviceProvider.GetService<IBarService>()?.DoSomethingElse();
serviceProvider.GetService<IBazService>()?.DoAnotherThing();
A service instance's lifetime and its sharing between components are determined by the service lifetimes AddTransient, AddScoped, and AddSingleton. You can read my blog post here https://blog.ziggyrafiq.com/2023/02/aspnet-core-services-lifetime.html
Best Practices
Favor Constructor Injection
Using class constructors to inject dependencies ensures that dependencies are explicitly declared and easily discoverable.
using DI.NET8_CSharp10_Guide_ZiggyRafiq.Services.Interfaces;
namespace DI.NET8_CSharp10_Guide_ZiggyRafiq.ConstructorInjection;
public class ZiggyRafiqService
{
private readonly IFooService _fooService;
public ZiggyRafiqService(IFooService fooService)
{
_fooService = fooService;
}
public void DoSomething()
{
// Use the IFooService instance
_fooService.DoSomething();
}
}
Use Dependency Injection in Controllers
For better testability and maintainability, controllers in ASP.NET Core should utilize constructor injection.
using DI.NET8_CSharp10_Guide_ZiggyRafiq.Services.Interfaces;
using Microsoft.AspNetCore.Mvc;
namespace DI.NET8_CSharp10_Guide_ZiggyRafiq.Controller;
public class ZiggyRafiqController: ControllerBase
{
private readonly IFooService _fooService;
public ZiggyRafiqController(IFooService fooService)
{
_fooService = fooService;
}
// Action method to handle GET requests
[HttpGet]
public IActionResult Get()
{
// Perform some action using IFooService
_fooService.DoSomething();
// Return an IActionResult
return Ok("GET request handled");
}
}
Register Services with Interfaces
Service implementations should always be registered as interfaces rather than concrete implementations to allow for flexibility and easy swapping of implementations.
services.AddScoped< IFooService, FooService >();
Common Scenarios
Multiple Implementations
To distinguish between multiple implementations of an interface, use named or typed registrations.
services.AddScoped<IShoppingCartService, StandardShoppingCartService>();
services.AddScoped<IShoppingCartService, PremiumShoppingCartService>("premium");
Conditional Registrations
Configure or runtime conditions can be used to register services conditionally.
services.AddScoped<IFeatureService>(sp => configuration.GetValue<bool>("UseFeatureX") ? sp.GetService<FeatureXService>() : sp.GetService<DefaultFeatureService>());
Scoped Services in Background Tasks
Prevent memory leaks by properly handling scoped services when using dependency injection in long-running background tasks.
public class ZiggyRafiqBackgroundService : BackgroundService
{
private readonly IServiceScopeFactory _scopeFactory;
public ZiggyRafiqBackgroundService(IServiceScopeFactory scopeFactory)
{
_scopeFactory = scopeFactory;
}
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
using (var scope = _scopeFactory.CreateScope())
{
var myScopedService = scope.ServiceProvider.GetRequiredService<IMyScopedService>();
while (!stoppingToken.IsCancellationRequested)
{
// Background task logic using myScopedService
await Task.Delay(1000, stoppingToken);
}
}
}
}
Summary
With dependency injection in .NET 8, you can use it to promote modularity and testability in your applications by following best practices and understanding common scenarios. Dependency injection is a key component for building maintainable and scalable software for ASP.NET Core web applications, console applications, and background services.
I would greatly appreciate your support by following me on LinkedIn at https://www.linkedin.com/in/ziggyrafiq/ and liking this article. Your encouragement and support mean everything to me, and I truly appreciate it. ๐