A la hora de abordar un desarrollo Web, un aspecto fundamental es decidir dónde guardamos los datos que se están generando de la propia navegación, es decir, esos datos, que no tienen que estar en la base de datos, pero que son necesarios para que el usuario visualice la información por pantalla.
Un caso muy común es cuando en un desarrollo ASP.NET MVC utilizamos el patrón Model View View Model (MVVM) donde guardamos el ViewModel y están los datos que se muestran en la vista. Por regla general tenemos dos opciones: utilizar la Session del usuario, o bien utilizar una Cache.
¿Cuándo utilizar una u otro?: La Session es por usuario, mientras que la Cache es por la aplicación. En la Session, la informaciónsolo está durante el tiempo que el usuario navega la aplicación (cuando cierra el navegador dicha información desaparece), mientras que la Cache tiene un tiempo de vigencia.
Ahora bien, seguro que muchos de nosotros nos hemos encontrado con problemas cuando hemos trabajado con la Session. El principal motivo es cuando nuestra aplicación escala o cambia de nodo de ejecución. Esto, cuando lo tenemos almacenado en un Cloud como Azure, hace que nuestra aplicación se pueda volver inestable o tengamos que buscar una solución para que los datos de la Session perduren (con lo que estaríamos utilizando una Cache pero sin sus beneficios).
¿Qué hacer? Para evitar este problema, en los últimos proyectos que hemos abordado estamos utilizando Cache Manager, un paquete Nugget que se encarga de la gestión de la Cache, sumado a características propias del desarrollo (como tipado de los elementos que almacenamos en ella).
Cómo empezar a utilizar Cache Manager
En primer lugar, tendremos que instalar el paquete Nuget del mismo. Para ello, bien lo podemos buscar desde la propia interfaz, o bien ejecutar el siguiente comando desde la consola de Administración de los paquetes de Nuget:
Install-Package CacheManager.Core
A partir de este momento, tendremos que ver cómo configurar el Cache Manager. Esto lo podemos hacer con código:
var manager = CacheFactory.Build<int>(settings => { settings .WithSystemRuntimeCacheHandle() .And .WithRedisConfiguration("redis", config => { config.WithAllowAdmin() .WithDatabase(0) .WithEndpoint("localhost", 6379); }) .WithMaxRetries(100) .WithRetryTimeout(50) .WithRedisBackplane("redis") .WithRedisCacheHandle("redis", true); }); manager.Add("test", 123456);
También lo podemos utilizar añadiendo la configuración en el Web.Config, por ejemplo:
<cacheManager xmlns="http://cachemanager.net/schemas/CacheManagerCfg.xsd"> <managers> <cache name="cacheProfile" enableStatistics="false" serializerType="CacheManager.Serialization.Json.JsonCacheSerializer, CacheManager.Serialization.Json"> <handle name="redis1" ref="redisHandle" expirationMode="None" isBackplaneSource="true" /> </cache> </managers> <cacheHandles> <handleDef id="runtimeHandle" type="CacheManager.SystemRuntimeCaching.MemoryCacheHandle`1, CacheManager.SystemRuntimeCaching" defaultExpirationMode="Sliding" defaultTimeout="5m" /> <handleDef id="redisHandle" type="CacheManager.Redis.RedisCacheHandle`1, CacheManager.StackExchange.Redis" defaultExpirationMode="Sliding" defaultTimeout="5m" /> </cacheHandles> </cacheManager> <cacheManager.Redis> <connections> <connection id="redis1" database="1" strictCompatibilityModeVersion="3.0" connectionString="xxxxx" /> </connections> </cacheManager.Redis>
Desde el código, le tendremos que indicar que la configuración de nuestro Cache Manager esta en dicha sección. Para ello hay que añadir el siguiente código:
var cacheConfig = ConfigurationBuilder.LoadConfiguration("cacheProfile");
Una vez tenemos el Cache Manager configurado, el siguiente paso es ver cuáles son las opciones para almacenar y guardar los valores.
Para guardar nuestros objetos tendríamos que poner un código similar al siguiente:
Profile viewProfile = new Profile(this.ProfileService, this.Logger, User.Identity.Name, Literals.Culture.Name); Cache.Put($"Profile", viewProfile );
Donde Cache es un objeto de tipo ICacheManager, el código no tiene mucho más misterio. Instanciamos un viewModel que nos da las propiedades de un usuario y estas propiedades las guardamos en el Cache Manager.
¿Cómo obtenemos esos valores?:
Profile viewProfile= Cache.Get($"Profile");
Así de simple, y sin tener que hacer ninguna conversión «extra».
Extra Bonus: Inyeccion de dependencias
Otra de las cosas buenas que tiene es que lo podemos utilizar dentro de nuestro contenedor de inyección de dependencias como una dependencia más de nuestro proyecto.
Un ejemplo utilizando AutoFac sería el siguiente código:
var serviceLocator = new ServiceLocator(); serviceLocator.Builder.RegisterControllers(Assembly.GetExecutingAssembly()).PropertiesAutowired(); var cacheConfig = ConfigurationBuilder.LoadConfiguration("cacheProfile"); serviceLocator.Builder.RegisterGeneric(typeof(BaseCacheManager<>)) .WithParameters(new[] { new TypedParameter(typeof(ICacheManagerConfiguration), cacheConfig) }) .As(typeof(ICacheManager<>)) .SingleInstance(); serviceLocator.Builder.RegisterModule(new DataModule()); serviceLocator.Builder.RegisterModule(new InfraestructureModule()); serviceLocator.Builder.RegisterModule(new ServicesModule()); serviceLocator.BuildContainer(); DependencyResolver.SetResolver(new AutofacDependencyResolver(serviceLocator.Container));
Ojo… con el tema de la inyección de dependencias hay que tener muy claro cómo se utiliza, puesto que una mala utilización puede provocar que no se liberen las conexiones correctamente y haga que nuestra Cache caiga. Si no tenéis claro cómo hacerlo, os sugiero que leáis este post .
Resumen
A lo largo de este post hemos visto cómo hacer uso de Cache Manager, un framework para gestionar los elementos de Cache dentro de nuestros desarrollos. A la hora de utilizar una dll/proyecto externo, hay que tener muy claro para qué se utiliza, y si nos aporta valor dentro de dicho proyecto. En este caso, creo que Cache Manager es una de esas soluciones que hay que utilizar sí o sí, en el caso de que nuestro desarrollo utilice Cache.
Aporta simplicidad e independencia respecto al proveedor de cache que queramos utilizar, e incluso nos aporta otros beneficios dentro del desarrollo, como el tipado de los datos que se almacenan en el mismo.