.NET dependency injection explained with example
.NET dependency injection explained with example
Dependency Injection container (DI container)
- Services (like email service, database service) are used generally by the application logic to interface with the external systems
- DI container is a collection of dependencies (aka services)
- Application logic can request an instance of a required service from the DI container
Service Lifetimes
When requesting a service instance from a DI container
- A new service instance is created every time if it is a Transient service
- A single instance of a service is reused every time if it is a Singleton service
- A service instance is reused through out a http request if it is a Scoped service. Scoped service is applicable only in web applications
Inversion of Control for Dependency Injection
- While adding a service to the DI container, the service signature can be mentioned as an interface. An example is shown below.
services.AddSingleton<IMyService, MyService>():
- In this example, MyService class should implement IMyService interface in order to be registered.
- This is called Inversion of Control (IOC) / Dependency Inversion since the service (dependency) should comply to the application’s interface.
- The service can be retrieved from the DI container by specifying the interface instead of concrete class
var srv = serviceProvider.GetService<IMyService>();
- Dependency Inversion makes testing and code maintenance easy since the application is concerned only with the service interface instead of its implementation. The service implementation can be swapped with another implementation, and the application code will not change since it is concerned with the interface.
DI in console apps
- The followig example demonstrates how to use DI container in console apps.
- Install Microsoft.Extensions.DependencyInjection package
using Microsoft.Extensions.DependencyInjection;
//setup DI container
var serviceProvider = new ServiceCollection()
.AddSingleton<IMyService, MyService>()
.BuildServiceProvider();
//get a service instance from DI container and use it
var srv = serviceProvider.GetService<IMyService>();
srv?.DoSomething();
Console.WriteLine("Completed!");
public interface IMyService
{
void DoSomething();
}
public class MyService : IMyService
{
public void DoSomething()
{
Console.WriteLine("MyService is doing something.");
}
}
DI in web apps
- ASP.NET Core web application builder provides access to DI container using the
Services
property - For example
builder.Services.AddSingleton<IMessageWriter, MessageWriter>();
will add a Singleton service to the DI container
// Program.cs
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddRazorPages();
// Add required service to the container
builder.Services.AddSingleton<IMessageWriter, MessageWriter>();
// adding service in more readable way using extension method
//builder.Services.AddMessageWriter();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
// The default HSTS value is 30 days. You may want to change this for production scenarios, see <https://aka.ms/aspnetcore-hsts>.
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.MapStaticAssets();
app.MapRazorPages()
.WithStaticAssets();
app.Run();
public interface IMessageWriter
{
void Write(string message);
}
public class MessageWriter : IMessageWriter
{
public void Write(string message)
{
Console.WriteLine(message);
}
}
public static class MessageWriterExtensions
{
public static IServiceCollection AddMessageWriter(this IServiceCollection services)
{
services.AddSingleton<IMessageWriter, MessageWriter>();
return services;
}
}
- The service instance can be accessed in razor pages or any middleware from constructor. In this example the
IMessageWriter
service instance can be accessed from Index page as follows
// Pages/Index.cshtml.cs
using DIWebAppDemo.Services;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace DIWebAppDemo.Pages;
public class IndexModel(IMessageWriter writer) : PageModel
{
public IActionResult OnGet()
{
writer.Write("Index page reached");
return Page();
}
}
References
- Dependency injection docs - https://learn.microsoft.com/en-us/dotnet/core/extensions/dependency-injection
Comments
Post a Comment