100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
C#

Dependency Injection Basics

How ASP.NET Core's built-in dependency injection container registers and supplies services throughout your application.

FoundationsIntermediate9 min readJul 10, 2026
Analogies

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.

csharp
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

Was this page helpful?

Topics covered

#ASPNETCoreStudyNotes#MicrosoftTechnologies#DependencyInjectionBasics#Dependency#Injection#Service#Lifetimes#StudyNotes#SkillVeris#ExamPrep