Introduction
Dependency Injection (DI) is a design pattern used to achieve Inversion of Control (IoC) between classes and their dependencies. In ASP.NET Core, DI is a fundamental part of the framework, making it easier to manage dependencies and improve the modularity, testability, and maintainability of your applications.
In this article, we will cover the three primary DI lifecycles: Singleton, Transient, and Scoped. We will demonstrate how to register and use these services in an ASP.NET Core Web API application.
Prerequisites
To follow along, you should have
- Basic knowledge of ASP.NET Core.
- .NET SDK installed on your machine.
Step 1. Create a New ASP.NET Core Web API Project
First, create a new ASP.NET Core Web API project.
dotnet new webapi -n DependencyInjectionDemo
cd DependencyInjectionDemo
Step 2. Define the Services
Create interfaces and their implementations for Singleton, Transient, and Scoped services.
Interfaces
Create a new folder called Services and add the following interfaces.
// File: Services/ISingletonService.cs
public interface ISingletonService
{
Guid GetOperationId();
}
// File: Services/ITransientService.cs
public interface ITransientService
{
Guid GetOperationId();
}
// File: Services/IScopedService.cs
public interface IScopedService
{
Guid GetOperationId();
}
Implementations: Implement these interfaces in a single class.
// File: Services/OperationService.cs
public class OperationService : ISingletonService, ITransientService, IScopedService
{
private readonly Guid _operationId;
public OperationService()
{
_operationId = Guid.NewGuid();
}
public Guid GetOperationId()
{
return _operationId;
}
}
Step 3. Register the Services
Register these services in the Startup.cs file within the ConfigureServices method.
// File: Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
// Register the services
services.AddSingleton<ISingletonService, OperationService>();
services.AddTransient<ITransientService, OperationService>();
services.AddScoped<IScopedService, OperationService>();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
Step 4. Use the Services in a Controller
Create a controller that uses these services to demonstrate the differences in their lifecycles.
// File: Controllers/OperationsController.cs
using Microsoft.AspNetCore.Mvc;
using DependencyInjectionDemo.Services;
[ApiController]
[Route("api/[controller]")]
public class OperationsController : ControllerBase
{
private readonly ISingletonService _singletonService;
private readonly ITransientService _transientService;
private readonly IScopedService _scopedService;
public OperationsController(ISingletonService singletonService,
ITransientService transientService,
IScopedService scopedService)
{
_singletonService = singletonService;
_transientService = transientService;
_scopedService = scopedService;
}
[HttpGet]
public IActionResult Get()
{
return Ok(new
{
Singleton = _singletonService.GetOperationId(),
Transient = _transientService.GetOperationId(),
Scoped = _scopedService.GetOperationId()
});
}
}
Step 5. Run and Test the Application
Run the application.
dotnet run
Output
You should see an output similar to this.
{
"Singleton": "e1f3525e-2a92-4f5f-8d18-4e3c6e0326f2",
"Transient": "a4d4a7b5-4088-4f8f-9b44-5e5e8d5e5b0c",
"Scoped": "f61c76b5-786b-4eb0-a0d4-f7f73ed3a1f2"
}
Make multiple requests and observe the following behaviors.
- Singleton: The Singleton GUID remains the same across all requests, indicating that the same instance is used throughout the application's lifetime.
- Transient: The Transient GUID changes with every request, indicating a new instance is created each time.
- Scoped: The Scoped GUID changes with each new request but remains consistent within the same request, indicating the same instance is used within the scope of a single request.
Notice that the Singleton GUID remains the same, the Transient GUID changes with every request, and the Scoped GUID changes with each new request but remains consistent within the same request.
GitHub Project Link
https://github.com/SardarMudassarAliKhan/DI-InAspNetCore-WebAPI
Conclusion
In this article, we demonstrated how to use dependency injection in an ASP.NET Core Web API application with Singleton, Transient, and Scoped services. Understanding these lifecycles helps you manage service instances appropriately, improving the performance and maintainability of your applications. Use Singleton for application-wide shared services, Transient for stateless services, and Scoped for per-request services.