Contenedor de Inyección de Dependencias para C# (.NET): guía completa
La Inyección de Dependencias (DI) es uno de los patrones de diseño clave en el desarrollo moderno con C# y .NET. Permite crear aplicaciones débilmente acopladas, comprobables y fáciles de mantener. En este artículo, analizaremos en detalle qué es un contenedor de Inyección de Dependencias, cómo usarlo en .NET y proporcionaremos ejemplos prácticos de código.
¿Qué es la Inyección de Dependencias?
La Inyección de Dependencias (Dependency Injection) es un patrón en el cual un objeto recibe sus dependencias desde el exterior, en lugar de crearlas por sí mismo. Esto permite:
- Reducir el acoplamiento entre componentes
- Simplificar las pruebas (posibilidad de sustituir dependencias con mocks)
- Aumentar la flexibilidad y la reutilización del código
- Centralizar la gestión del ciclo de vida de los objetos
¿Qué es un contenedor DI?
Un contenedor DI (o contenedor IoC) es una biblioteca que automatiza el proceso de inyección de dependencias. Asume la responsabilidad de crear objetos y gestionar su tiempo de vida. En .NET, el contenedor DI principal es Microsoft.Extensions.DependencyInjection, que está integrado en ASP.NET Core y puede usarse en cualquier aplicación .NET.
Conceptos básicos del contenedor DI
El contenedor DI opera con los siguientes conceptos:
- Registro de servicios — proceso de agregar tipos y sus implementaciones al contenedor
- Resolución de dependencias — creación automática de objetos con sus dependencias
- Tiempo de vida de los servicios — determina cuánto tiempo existe un objeto (Transient, Scoped, Singleton)
Configuración del contenedor DI en .NET
Para comenzar a trabajar con el contenedor DI, es necesario instalar el paquete Microsoft.Extensions.DependencyInjection. Esto se puede hacer a través de NuGet:
dotnet add package Microsoft.Extensions.DependencyInjectionDespués de la instalación, se crea una instancia de ServiceCollection en la que se registran todas las dependencias:
using Microsoft.Extensions.DependencyInjection;
// Creamos la colección de serviciosvar services = new ServiceCollection();
// Registramos los serviciosservices.AddTransient<ILogger, ConsoleLogger>();services.AddScoped<IUserRepository, UserRepository>();services.AddSingleton<IConfiguration, AppConfiguration>();
// Construimos el proveedor de serviciosvar serviceProvider = services.BuildServiceProvider();Ejemplo de uso del contenedor DI
Consideremos un ejemplo real: una aplicación para la gestión de usuarios. Crearemos interfaces y sus implementaciones:
public interface IUserRepository{ User GetUser(int id);}
public interface IEmailService{ void SendEmail(string to, string subject);}
public class UserRepository : IUserRepository{ public User GetUser(int id) { // Lógica para obtener el usuario de la BD return new User { Id = id, Name = "John Doe" }; }}
public class EmailService : IEmailService{ public void SendEmail(string to, string subject) { Console.WriteLine($"Email enviado a {to}: {subject}"); }}Ahora crearemos la clase UserService, que utiliza estas dependencias:
public class UserService{ private readonly IUserRepository _userRepository; private readonly IEmailService _emailService;
public UserService(IUserRepository userRepository, IEmailService emailService) { _userRepository = userRepository; _emailService = emailService; }
public void NotifyUser(int userId) { var user = _userRepository.GetUser(userId); _emailService.SendEmail(user.Email, "¡Bienvenido!"); }}Registramos todo en el contenedor DI