Dependency Injection
Relevant source files
The following files were used as context for generating this wiki page:
Dependency Injection (DI) is a core software design pattern used throughout the WEBAPI project to achieve Inversion of Control (IoC) between classes and their dependencies. The application leverages the built-in service container provided by ASP.NET Core to manage the lifecycle and instantiation of services, such as the database context and business logic services. This approach promotes loose coupling, making the application more modular, easier to maintain, and simpler to test.
Dependencies are defined using interfaces (contracts) and are "injected" into dependent classes (like controllers and other services) through their constructors. The configuration and registration of these services and their lifetimes are centralized in the Program.cs file, which acts as the composition root for the application.
Service Registration
All services that are managed by the DI container must be registered. This registration process occurs at application startup within Program.cs. The application uses different service lifetimes to control how and when dependencies are created.
Sources: Program.cs:12-42
Service Lifetimes
The project utilizes the following service lifetimes for registration:
| Interface | Implementation | Lifetime | Description |
|---|---|---|---|
UserDBContext | UserDBContext | Scoped | A single instance is created for each client request (scope). Registered via AddDbContext. |
IUserService | UserService | Transient | A new instance is created every time it is requested from the service container. |
IProductService | ProductService | Scoped | A single instance is created for each client request (scope). |
IOrderService | OrderService | Scoped | A single instance is created for each client request (scope). |
Sources: Program.cs:25-42
The following diagram illustrates the registration process in Program.cs.
This diagram shows services being registered into the DI container at application startup.
Sources: Program.cs:25-42
Registration Code
The following code from Program.cs shows how the UserDBContext and various application services are registered with the DI container.
// Program.cs
builder.Services.AddDbContext<UserDBContext>(option =>
{
option.UseSqlServer(builder.Configuration.GetConnectionString("UserDataBase"));
});
// ...
builder.Services.AddTransient<IUserService, UserService>();
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddScoped<IOrderService, OrderService>();
Sources: Program.cs:25-30, Program.cs:40-42
Constructor Injection
The primary mechanism for resolving dependencies in this project is constructor injection. The DI container automatically provides the required service instances to a class's constructor when it is created.
Injecting Services into Controllers
Controllers declare their dependencies on service interfaces in their constructors. The DI container resolves these dependencies and injects the concrete implementations.
For example, the UserController depends on IUserService:
// Controllers/Login/UserController.cs
public class UserController : ControllerBase
{
private readonly IUserService _userService;
public UserController(IUserService userService)
{
_userService = userService;
}
// ...
}
Sources: Controllers/Login/UserController.cs:18-24
Similarly, the OrderController depends on IOrderService:
// Controllers/Order/OrderController.cs
public class OrderController : ControllerBase
{
private readonly IOrderService _orderService;
public OrderController(IOrderService orderService)
{
_orderService = orderService;
}
// ...
}
Sources: Controllers/Order/OrderController.cs:13-17
Injecting DbContext into Services
Services themselves can also have dependencies. The UserService requires an instance of UserDBContext to interact with the database. This is also supplied via constructor injection.
// Service/user/UserService.cs
public class UserService : IUserService
{
private readonly UserDBContext _userDBContext;
public UserService(UserDBContext userDBContext)
{
_userDBContext = userDBContext;
}
// ...
}
Sources: Service/user/UserService.cs:13-18
Dependency Resolution Flow
The following sequence diagram demonstrates how dependencies are resolved and utilized during an API request to the api/v1/user/{id} endpoint.
This diagram shows the sequence of events for a request, highlighting how the DI container creates and injects UserService and UserDBContext instances.
Sources: Controllers/Login/UserController.cs:26-34, Service/user/UserService.cs:26-29
Component Relationships
The class diagram below visualizes the relationships between the interfaces, concrete classes, and their dependencies involved in the user management feature.
This diagram shows that UserController depends on the IUserService interface, which is implemented by UserService. UserService in turn depends on UserDBContext.
Sources: Controllers/Login/UserController.cs:18-24, Service/user/IUserService.cs, Service/user/UserService.cs:13-18, Data/UserDBContext.cs:41
Summary
The WEBAPI project effectively uses the dependency injection pattern to create a decoupled and maintainable architecture. By registering services like UserDBContext, IUserService, and IOrderService in Program.cs, the application allows the ASP.NET Core runtime to manage object creation and lifetimes. This enables components like UserController and UserService to receive their dependencies through constructor injection, adhering to the Dependency Inversion Principle and simplifying unit testing by allowing mock implementations to be injected.