Para los que no sepan que es la inyección de dependencia vamos a explicarlo sencillamente. Básicamente, es un patrón el cual permite que en lugar de tener que instanciar los objetos dentro de nuestras clases, estos objetos sean suministrados a la clase que los necesita. Esto se hace por medio de un contenedor previamente cargado. Entonces, si una clase necesita un objeto lo único que necesita hacer es declarar el objeto en el constructor para recibirlo y luego utilizarlo. Este es el ejemplo más sencillo pero hay varias formas de hacerlo que no es el objetivo de este artículo.
Todos los que trabajamos en Asp.Net usamos inyección de dependencia en nuestros proyectos. Tal vez muchos no lo sepan, pero está por default en la plantilla de los proyectos. Lo único que tenemos que hacer es por medio de un carar nuestro contenedor de objetos y luego el se encargara de inyectar los objetos que cada clase o componente necesite.
En consola
Hace unos días, un compañero de trabajo me consultó porque no se usa en un proyecto de consola. Mi respuesta fue que no es que no se use, si no que en la plantilla de .Net no está este tipo de implementación. Recordemos que el proyecto de consola es lo más simple que podemos crear, aun así, no significa que no podamos implementar inyección de dependencia
Para poder utilizarlo en nuestro proyecto de consola lo primero que debemos hacer es agregar la dependencia al paquete nuget Microsoft.Extensions.DependencyInjection.
Ahora vamos a crear 2 interfaces que serán nuestros servicios a inyectar. Tendremos por ejemplo 2 servicios repositorios, uno para productos y otro para clientes.
interface IProductosRepository { void DesactivateProduct(int productId); } interface iCustomerRepository { void DeleteCustomer(); } }
Cada uno de estos servicios tendrá su propia implementación. Pero además lo haremos un poco más interesante. Usaremos un logger dentro de ellos, que por supuesto, será inyectado por medio del contenedor. Así que nuevamente agregaremos 2 paquetes nuget, el primero es Microsoft.Extensions.Logging y Microsoft.Extensiones.Logging.Console.
Veamos las implementaciones de las interfaces anteriores:
public class CustomerRepository : iCustomerRepository { private readonly ILogger<CustomerRepository> _logger; private readonly IProductRepository productosRepository; public CustomerRepository(IProductRepository productosRepository) => this.productosRepository = productosRepository; public void DeleteCustomer() { throw new NotImplementedException(); } } public class ProductRepository : IProductRepository { public void DesactivateProduct(int productId) { throw new NotImplementedException(); } }
Por último, lo que debemos hacer en un método Main es configurar la carga del contenedor con las clases que serán enviadas por medio del constructor.
class Program { static void Main(string[] args) { //cargar DI var serviceProvider = new ServiceCollection() .AddLogging() .AddSingleton<iCustomerRepository, CustomerRepository>() .AddSingleton<IProductRepository, ProductRepository>() .BuildServiceProvider(); var logger = serviceProvider.GetService<ILoggerFactory>() .CreateLogger<Program>(); logger.LogDebug("Starting application"); //usar var customer = serviceProvider.GetService<CustomerRepository>(); customer.DeleteCustomer(); logger.LogDebug("All done!"); } }
En la primera parte, donde dice «Cargar DI, podemos ver cada uno de nuestros servicios que serán cargados en el contenedor. En la sección de usar, vemos como invocamos a nuestro contenedor, le especificamos que es lo que vamos a utilizar, este nos construirá el objeto y se encarga de inyectar todo lo que necesite, en nuestro caso si vemos la implementación de la clase ProductoRepository.
Conclusiones
Es posible implementar inyección de dependencia al igual que la tenemos dentro de Asp.Net en un proyecto de consola. En la gran mayoría de los casos no ayuda a respetar un correcto orden de cómo debemos crear los objetos. Espero que lo disfruten.