Dependency Injection in ASP.NET Core
DI = Don't use new Service(). Ask for it in constructor. ASP.NET Core creates it and gives it to you.
60-Second Version: Register services in
Program.cs: builder.Services.AddScoped<IProductService, ProductService>(). Inject in constructor: public ProductsController(IProductService svc). Use 3 lifetimes: Singleton = 1 per app, Scoped = 1 per request, Transient = new every time.1. Register Services in Program.cs
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllersWithViews();
builder.Services.AddScoped<IProductService, ProductService>();
builder.Services.AddDbContext<AppDbContext>(opt =>
opt.UseSqlite(builder.Configuration.GetConnectionString("Default")));
var app = builder.Build();
2. Service Lifetimes - Pick the Right One
| Lifetime | Created When | Use For |
|---|---|---|
AddSingleton | Once per app startup | Config, caching, stateless |
AddScoped | Once per HTTP request | DbContext, EF repos |
AddTransient | Every time injected | Lightweight services |
Rule: DbContext MUST be Scoped. Put it in Singleton and you get crashes + data leaks.
3. Constructor Injection
public class ProductsController : Controller
{
private readonly IProductService _service;
private readonly AppDbContext _db;
public ProductsController(IProductService service, AppDbContext db)
{
_service = service; // ASP.NET injects these
_db = db;
}
public async Task<IActionResult> Index()
{
var products = await _service.GetAllAsync();
return View(products);
}
}
4. Why DI Matters
- Testable: Mock
IProductServicein unit tests - Decoupled: Controller doesn't care if service uses EF or Dapper
- No memory leaks: Container calls
Dispose()for you
Beginner Trap: Priya registers
DbContext as Singleton. First request works. Second request crashes: "Cannot access disposed object". Fix: Use AddDbContext which defaults to Scoped.
Quick Check ๐ง
Next: Filters & Middleware in MVC - Action filters, exception filters, and the request pipeline.
No comments yet. Be the first to share your thoughts!