¿Transient, Scoped o Singleton? .NET Core como si estuvieras en 1º
¿Por qué este articulo?
Si al igual que yo has desarrollado en algún momento aplicaciones para ti o para otros en ASP.NET te habrás preguntado, ¿Que diantres es esto de la inyección de dependencias? ¿Que clase de magia arcana inyecta mis objetos para poder usarlos? ¿Y que son esos adjetivos raros que utiliza el lenguaje para clasificarlos? Pues bien, aquí hablaremos someramente y de la manera más especifica posible (a todos nos duele leer horribles tochos de texto como este sobre algo que queremos saber YA).
Introducción
Bien. Si sigues aquí es que al menos tengo tu atención durante este rato. Lo principal cuando desarrollas una aplicación usando .NET Core es saber que vas a tener que gestionar de alguna manera el ciclo de vida de los objetos y servicios que el propio funcionamiento de la aplicación necesite.
Aquí entra la inyección de dependencias, en vez de crear el objeto o instanciar el servicio de forma directa en el componente que tendrá que usarlo, podemos recurrir a la inyección para que se encargue de crearlo y gestionarlo…
…y aquí es donde entra en acción como hayas declarado dicha inyección: Singleton, Scoped y Transient.
¿Inyección?
La definición de aquellos servicios y objetos que el inyector de dependencias podrá inyectar en tu aplicación ha de definirse en Program.cs .
Aunque si estas usando una versión previa a .NET Core 6, lo más seguro es que tengas un Startup.cs con un “ConfigureServices()” donde podrás configurarlo.
La definición podría hacerse de la siguiente manera, interfaz que utilizaremos en el proceso de inyección y la clase concreta que lo implementa.
services.AddScoped<IService, Service>();
Singleton
services.AddSingleton<IService, Service>();
¿Recuerdas ese patrón de diseño que generaba estructuras tan feas de código para impedir que una clase se instanciara más de una vez en tu aplicación? Pues esto es lo mismo, pero sin ser feo.
Un Servicio añadido como singleton solo se instanciará una vez y todos aquellos módulos que lo utilicen usarán la misma instancia. Es interesante saber que este tipo de servicios son Lazy loading, es decir, que únicamente se instancian cuando se necesitan.
Un ejemplo de servicio que sería interesante sería un Logging, utilizado por toda la aplicación y donde podamos centralizar todo el sistema de log de todas las partes que necesitamos lo utilicen.
Scoped
services.AddScoped<IService, Service>();
Un servicio Scoped se restringe al ámbito de una operación dentro de la aplicación. Esto es, por ejemplo, una request o un operación atómica. Todas las dependencias de este servicio reciben el mismo tratamiento y tendrán el mismo ciclo de vida.
Usar un servicio Scoped es interesante cuando quieres utilizarlo a lo largo de toda una operación pero no quieres que peticiones u operaciones similares utilicen el mismo servicio, evitando de esta manera conflictos.
Transient
services.AddTransient<IService, Service>();
El último, el que tiene por diseño el ciclo de vida más corto, sería un servicio Transient, del que se crearía una instancia cada vez que esta sea solicitada.
Nos puede ser útil si queremos por ejemplo crear servicios para cálculos sencillos o clases de utilidad.
¿Una imagen vale más que mil palabras?
Si, si, esto esta muy bien, pero el refrán esta por algo, ¿vale más una imagen que mil palabras? Pues seguramente, por eso creo que la mejor manera de ver en que momento utilizar uno u otro tipo de servicio es esta:
¡Y eso es todo!