Inyección de Dependencias en ASP.NET Core – I
Una de las características que nos ofrece .NET Core es la de tener la posibilidad de utilizar el patrón Inyección de Dependencias que nos permitirá hacer la IoC o inversión de control sin tener que utilizar otro software de terceros, lo cuál nos simplifica enormemente las necesidades más generales de la IoC.
No obstante, es posible que alguna de las características del IoC que viene «de serie» en .NET Core se pudiera quedar corta en un momento dado.
Si esto llegara a ser así, tendríamos ahí sí, que buscar una solución diferente a la que nos ofrece out-of-the-box el propio .NET Core, pero casi siempre no será necesario ir a software de terceros.
La magia de todo esto se logra gracias al namespace Microsoft.Extensions.DependencyInjection y a la correspondiente implementación para el soporte por defecto de la inyección por constructor.
Como siempre que utilizamos IoC, lo único que debemos hacer es registrar de alguna manera la interfaz y la implementación a utilizar de forma que al resolverse se haga de forma automática, para luego recuperarla con el objetivo de poder trabajar con ella en la parte de código que tenga la necesidad de utilizarla.
En esta entrada voy a explicar cómo funciona el mecanismo de IoC dentro de una aplicación Web de ASP.NET Core y cómo utilizarla.
Veremos con un ejemplo, un caso de uso típico.
Supongamos que tenemos una interfaz que vamos a hacer muy simple y de cero, y que corresponde con el siguiente código:
public interface ILog { void Write(string message); }
Ahora supongamos que tenemos la siguiente implementación de la interfaz que hemos preparado:
public class MyLog : ILog { public void Write(string message) { Debug.WriteLine(message); } }
Como podemos apreciar, se trata de un ejemplo muy sencillo que escribirá en la ventana Output de Visual Studio el texto que pasemos en el método Write de la implementación de la interfaz.
Dentro de la clase Startup y en concreto en el método public void ConfigureServices(IServiceCollection services) agregaré un servicio definiendo la interfaz y su implementación.
Cabe mencionar antes de continuar que tenemos dos tipos de servicios.
Los servicios propios del Framework, y los servicios de aplicación.
El método ConfigureServices de la clase Startup nos permitirá configurar o registrar los servicios de aplicación.
En el método Configure de la clase Startup crearemos la canalización del procesado de las peticiones de la aplicación, lo que encontrarás en inglés como HTTP request pipeline.
El runtime llamará al iniciar la aplicación a ConfigureServices y Configure.
El contenedor de IoC tendrá que inyectar nuestros servicios de aplicación de forma directa cuando solicitemos su implementación, así que tendremos que registrarlo en el contenedor de IoC de esta forma (en ConfigureServices por lo tanto):
services.Add(new ServiceDescriptor(typeof(ILog), new MyLog()));
Nota: Hay más maneras de añadir las interfaces e implementaciones, pero de momento vamos a verlo de esta forma.
En el código vemos que llamamos a ServiceDescriptor.
ServiceDescriptor nos permite especificar el tipo de servicio y su instancia.
En nuestro caso, el contenedor de IoC creará un Singleton de nuestra clase recuperando la instancia de la clase en la aplicación Web cuando la queramos utilizar.
Así que una vez hecho esto y suponiendo que en el método Configure de la misma clase Startup tenemos definida también la ruta que servirá el controlador y acción, vamos a centrarnos ahora en el controlador.
El código del controlador que he preparado es el siguiente:
public class FooController : Controller { private readonly ILog _log; public FooController(ILog log) { _log = log; } public IActionResult Index() { _log.Write("\t Log => Executing /foo/index"); return View(); } }
Atendiendo al código de nuestro controlador, vemos que en el constructor estamos resolviendo la implementación y recuperando la instancia del Singleton que hemos definido en la clase Startup.
El contenedor de IoC resolverá de forma automática la instancia de MyLog al constructor del controlador.
El contenedor IoC se encargará también de gestionar el ciclo de vida de la instancia de tipo ILog que hemos pasado.
Si ejecutamos nuestra aplicación y vamos al controlador/acción que hemos preparado, escribirá en Output de Visual Studio el texto que hemos indicado en la acción.
Llegados a este punto, vemos que el uso de IoC en ASP.NET Core es realmente sencillo y no requiere de excesivos esfuerzos por nuestra parte.
En próximas entradas del blog veremos en algo más de profundidad las diferentes opciones que tenemos en .NET Core a la hora de trabajar con IoC.
Happy Coding!
3 Responsesso far
Buenos días !
Soy un programador web en crecimiento, aun estoy en la facultad y este tipo de información no nos la enseñan, siendo de suma importancia ya que ahora que trabajo y a la vez estudio, requiero de utilizar inyección de dependencias y no entendía casi en NADA de como se hace y/o que es ese servicio.
Muchas gracias por tu articulo en verdad es muy sencillo y me esperaba algo mas supercomplejo de entender.
Hola, muy claro, pero ¿cuál es el escenario adecuado para cada una de las tres opciones que nos ofrece el framework: Por ejemplo en una interface IEmpleado, para un CRUD, cuál sería la más adecuada Singleton, Scoped o Transient?
Hola Juan Carlos, esas opciones que mencionas en realidad son los tiempos de vida de los objetos:
-Trasient(Transitorio): Se crea una nueva instancia cada vez que se solicite al contenedor. -Scoped: El objeto se crea para cada request y -Singleton: El objeto se creará la primera vez que lo soliciten y vivirá durante todo el tiempo de vida de la aplicación. Ahora tu sabrías cual te funciona de la mejor manera que se adapte a tu aplicación.