Dependency Injection in ASP.NET Core: Complete Beginner's Guide
Dependency Injection (DI) is one of the most important concepts in modern ASP.NET Core development. It helps developers create applications that are easier to maintain, test, and scale.
ASP.NET Core includes a built-in Dependency Injection container, making it easy to register and consume services throughout your application. Understanding how Dependency Injection works is essential for building professional .NET applications.
- What is Dependency Injection?
- Why use Dependency Injection?
- Creating services
- Registering services
- Constructor Injection
- Service lifetimes
- Real-world examples
- Best practices
What Is Dependency Injection?
Dependency Injection is a design pattern that allows objects to receive their dependencies from an external source rather than creating them directly.
Instead of a class creating its own dependencies, those dependencies are provided to the class when it is instantiated.
This approach reduces coupling between components and improves code maintainability.
Without Dependency Injection
Consider the following example:
public class ProductController
{
private readonly EmailService _emailService;
public ProductController()
{
_emailService = new EmailService();
}
}
The controller directly creates an EmailService object.
Problems with this approach:
- Tight coupling between classes.
- Difficult unit testing.
- Harder to replace implementations.
- Reduced maintainability.
With Dependency Injection
public class ProductController
{
private readonly EmailService _emailService;
public ProductController(
EmailService emailService)
{
_emailService = emailService;
}
}
The dependency is now supplied externally instead of being created inside the controller.
This makes the code more flexible and easier to test.
Creating a Service
Services contain reusable business logic that can be injected into controllers, other services, and application components.
public class EmailService
{
public void SendEmail(
string recipient,
string subject)
{
Console.WriteLine(
$"Email sent to {recipient}");
}
}
Registering Services
Services are registered inside Program.cs.
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddScoped<EmailService>();
var app = builder.Build();
Once registered, ASP.NET Core automatically creates and manages service instances.
Using Constructor Injection
Constructor Injection is the most common way to use Dependency Injection.
public class HomeController : Controller
{
private readonly EmailService _emailService;
public HomeController(
EmailService emailService)
{
_emailService = emailService;
}
public IActionResult Index()
{
_emailService.SendEmail(
"user@example.com",
"Welcome");
return View();
}
}
ASP.NET Core automatically injects EmailService when creating the controller.
Using Interfaces
Most production applications register interfaces instead of concrete classes.
public interface IEmailService
{
void SendEmail(
string recipient,
string subject);
}
public class EmailService : IEmailService
{
public void SendEmail(
string recipient,
string subject)
{
Console.WriteLine("Email sent");
}
}
Register Interface
builder.Services.AddScoped<
IEmailService,
EmailService>();
Inject Interface
public class HomeController : Controller
{
private readonly IEmailService _emailService;
public HomeController(
IEmailService emailService)
{
_emailService = emailService;
}
}
Using interfaces improves flexibility and testability.
Service Lifetimes
ASP.NET Core supports three primary service lifetimes.
| Lifetime | Description |
|---|---|
| Transient | New instance every time requested. |
| Scoped | One instance per HTTP request. |
| Singleton | Single instance for application lifetime. |
Transient Services
builder.Services.AddTransient<
IEmailService,
EmailService>();
A new object is created every time the service is requested.
Good for lightweight and stateless services.
Scoped Services
builder.Services.AddScoped<
IEmailService,
EmailService>();
One instance is shared throughout a single request.
This is the most commonly used lifetime in web applications.
Singleton Services
builder.Services.AddSingleton<
IEmailService,
EmailService>();
A single instance is created and reused throughout the application's lifetime.
Suitable for configuration providers, caching services, and application-wide resources.
Real-World Example
A typical ASP.NET Core application may contain:
- Repository services
- Business logic services
- Email services
- Payment services
- Logging services
- API integration services
builder.Services.AddScoped<
IProductRepository,
ProductRepository>();
builder.Services.AddScoped<
IProductService,
ProductService>();
builder.Services.AddScoped<
IEmailService,
EmailService>();
Controllers then consume these services through constructor injection.
Benefits of Dependency Injection
- Improved maintainability.
- Better separation of concerns.
- Easier unit testing.
- Reduced code duplication.
- Greater flexibility.
- Simpler dependency management.
Common Mistakes
- Registering services with incorrect lifetimes.
- Injecting too many dependencies into a class.
- Creating services manually using new.
- Ignoring interfaces.
- Using Singleton for request-specific data.
Best Practices
- Prefer interfaces over concrete classes.
- Use constructor injection.
- Choose appropriate service lifetimes.
- Keep services focused on a single responsibility.
- Avoid service locator patterns.
- Organize service registrations clearly.
Frequently Asked Questions
Does ASP.NET Core include Dependency Injection?
Yes. ASP.NET Core has a built-in Dependency Injection container that supports service registration and resolution.
Which service lifetime should I use?
Scoped is typically the best choice for database access and business logic services in web applications.
Why use interfaces?
Interfaces make it easier to swap implementations and create unit tests using mock objects.
Can services depend on other services?
Yes. The Dependency Injection container automatically resolves nested dependencies when creating objects.
Related Tutorials
- Build a REST API in ASP.NET Core
- Repository Pattern in ASP.NET Core
- JWT Authentication in ASP.NET Core
- ASP.NET Core Middleware
- Background Services in .NET
- ASP.NET Core MVC Tutorial
Conclusion
Dependency Injection is a core feature of ASP.NET Core and a fundamental skill for every .NET developer.
By using services, interfaces, constructor injection, and proper service lifetimes, you can create applications that are easier to maintain, test, and extend as your projects grow.
Once you become comfortable with Dependency Injection, you'll find it much easier to build clean, scalable ASP.NET Core applications.