Dependency Injection Basics
Dependency injection (DI) is a design pattern where a class receives the objects it depends on from an external source rather than constructing them itself, typically through its constructor. ASP.NET Core has a DI container built directly into the framework, so instead of a controller calling 'new OrderService()' internally, it declares an IOrderService parameter in its constructor and the framework supplies a concrete instance automatically at request time.
Cricket analogy: It's like a team management staff supplying a player with match-ready equipment before the game, rather than the player being expected to manufacture their own bat and pads from scratch.
Service Lifetimes
When you register a service with builder.Services, you choose one of three lifetimes: Transient creates a brand new instance every time it's requested, Scoped creates one instance per HTTP request and reuses it for the duration of that request, and Singleton creates exactly one instance for the entire lifetime of the application. Choosing the wrong lifetime is a common source of bugs, for example injecting a Scoped DbContext into a Singleton service can cause the DbContext to be reused across unrelated requests, leading to data corruption or threading exceptions.
Cricket analogy: It's like the difference between a fresh ball brought out every over (Transient), the same ball used for one full innings (Scoped), and the same trophy that stays with the tournament from the first match to the final (Singleton).
Registering and Resolving Services
Services are registered in Program.cs before builder.Build() using calls like builder.Services.AddScoped<IOrderService, OrderService>(), mapping an interface to a concrete implementation. Once registered, ASP.NET Core's constructor injection automatically resolves that dependency anywhere it's needed, controllers, other services, even middleware, without any manual 'new' calls or a service locator pattern scattered through the codebase.
Cricket analogy: It's like a selection committee formally naming a player to a specific batting position before the season starts, after that, the team sheet automatically slots them into every match without re-selecting them each time.
public interface IOrderService
{
Task<Order> GetOrderAsync(int id);
}
public class OrderService : IOrderService
{
private readonly AppDbContext _db;
public OrderService(AppDbContext db) => _db = db;
public Task<Order> GetOrderAsync(int id) =>
_db.Orders.FirstOrDefaultAsync(o => o.Id == id);
}
// Program.cs
builder.Services.AddScoped<IOrderService, OrderService>();
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlServer(builder.Configuration.GetConnectionString("Default")));
// Controller receives it automatically via constructor injection
public class OrdersController : ControllerBase
{
private readonly IOrderService _orderService;
public OrdersController(IOrderService orderService) => _orderService = orderService;
[HttpGet("{id}")]
public async Task<IActionResult> Get(int id) =>
Ok(await _orderService.GetOrderAsync(id));
}Injecting a Scoped service (like a DbContext) into a Singleton service is a classic 'captive dependency' bug: the Scoped instance gets captured for the app's entire lifetime instead of per-request, leading to stale data and thread-safety issues under concurrent load.
- Dependency injection lets classes receive their dependencies via constructor parameters instead of constructing them internally.
- ASP.NET Core ships with a built-in DI container, no third-party library is required.
- Transient services create a new instance on every resolution request.
- Scoped services create one instance per HTTP request.
- Singleton services create exactly one instance for the application's entire lifetime.
- Services are registered via builder.Services before builder.Build() is called.
- Injecting a Scoped dependency into a Singleton causes the 'captive dependency' bug.
Practice what you learned
1. What is the core idea behind dependency injection?
2. How long does a Scoped service instance live in ASP.NET Core?
3. What problem occurs when a Scoped service is injected into a Singleton service?
4. Where must services be registered relative to builder.Build() in Program.cs?
Was this page helpful?
You May Also Like
The Middleware Pipeline
How ASP.NET Core processes every HTTP request through an ordered chain of middleware components.
Project Structure and Program.cs
How a default ASP.NET Core project is laid out and how Program.cs bootstraps the host, services, and request pipeline.
Configuration and Environments
How ASP.NET Core layers configuration sources and switches behavior between Development, Staging, and Production environments.
Related Reading
Related Study Notes in Microsoft Technologies
Browse all study notesWindows 10 / UWP Development Study Notes
.NET · 30 topics
Microsoft TechnologiesWindows Batch Scripting Study Notes
Batch · 30 topics
Microsoft TechnologiesMFC (Microsoft Foundation Classes) Study Notes
C++ · 30 topics
Microsoft TechnologiesSilverlight Study Notes
.NET · 30 topics
Microsoft TechnologiesXAML Study Notes
.NET · 30 topics
Microsoft TechnologiesWPF (Windows Presentation Foundation) Study Notes
.NET · 30 topics