Dependency Injection in ASP.NET Razor Pages
Dependency Injection (DI) is a fundamental design pattern in modern application development. ASP.NET Core has a built-in, lightweight DI container that makes it easy to implement DI in your Razor Pages applications. This allows for better testability, maintainability, and looser coupling between components.
What is Dependency Injection?
Instead of a class creating its own dependencies (objects it needs to function), those dependencies are "injected" into the class, typically through its constructor. This makes the class less reliant on the concrete implementation of its dependencies, allowing you to swap them out easily, especially for testing.
Configuring Services in Startup.cs
The configuration for your application's services happens in the Startup.cs
file (or Program.cs
in newer .NET versions, where the configuration is often integrated). You register your services in the ConfigureServices
method using the IServiceCollection
.
Common Scopes: Transient, Scoped, and Singleton
- Transient: A new instance of the service is created every time it's requested.
- Scoped: A single instance of the service is created per client request (or scope). This is common for services that need to maintain state within a single HTTP request.
- Singleton: A single instance of the service is created and reused for the entire application lifetime.
Example: Registering a Service
Let's say you have a service for retrieving data:
public interface IDataService
{
IEnumerable<string> GetData();
}
public class MockDataService : IDataService
{
public IEnumerable<string> GetData()
{
return new List<string> { "Data Item 1", "Data Item 2", "Data Item 3" };
}
}
In your Startup.cs
(or Program.cs
):
// For Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
// Registering MockDataService as a Scoped service
services.AddScoped<IDataService, MockDataService>();
}
// For Program.cs (minimal API style)
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddScoped<IDataService, MockDataService>();
var app = builder.Build();
// ...
Injecting Services into Razor Pages
Once a service is registered, you can inject it into your Razor Page model's constructor. The DI container will automatically resolve and provide the instance when the page is created.
Example: Injecting into a Page Model
using Microsoft.AspNetCore.Mvc.RazorPages;
public class IndexModel : PageModel
{
private readonly IDataService _dataService;
public IndexModel(IDataService dataService)
{
_dataService = dataService;
}
public IEnumerable<string> Items { get; private set; }
public void OnGet()
{
Items = _dataService.GetData();
}
}
Using Injected Services in the Razor View
You can then access the injected data in your Razor view (.cshtml file) through the page model's properties.
Example: Using Data in the View
@page
@model IndexModel
@{
ViewData["Title"] = "Home page";
}
<h1>Welcome to Our Page!</h1>
<p>Here are some items from our data service:</p>
<ul>
@foreach (var item in Model.Items)
{
<li>@item</li>
}
</ul>
Advanced Scenarios
- Injecting into Tag Helpers: Services can also be injected into custom Tag Helpers.
- Factory Patterns: For more complex service creation, consider using factory interfaces.
- Configuration: Use
IOptions<T>
to inject configuration settings.
By leveraging ASP.NET Core's built-in DI container, you can build robust, scalable, and maintainable Razor Pages applications.