martes, 12 de mayo de 2015
Seguimos hablando de novedades que acompañarán a ASP.NET Core MVC, y esta vez le toca el turno a otra de los grandes ausencias que podemos notar cuando creamos desde cero una aplicación utilizando estos frameworks: las variables de sesión.
Bueno, en realidad no se trata tanto de una ausencia como de un desplazamiento de esta característica. Resumidamente, las variables de sesión seguirán existiendo, pero no son parte del core de ASP.NET, como ocurría desde la primera versión de ASP.NET, sino un componente totalmente opcional implementado en forma de middleware que deberá ser instalado y configurado de forma independiente.
Pero antes de continuar, recordad que tanto MVC como ASP.NET Core siguen estando en proceso de desarrollo, por lo que algunas de las cosas que contaremos podrían cambiar en las versiones definitivas, aunque espero que no demasiado.
Y dicho esto, vamos al lío: ¿cómo utilizamos variables de sesión en aplicaciones basadas en ASP.NET Core?
Como es habitual, la descarga e instalación la realizaremos a través del interfaz de Nuget en Visual Studio, o bien añadiendo manualmente la referencia al archivo project.json. El nombre del paquete que nos interesa es
(Nota: los espacios de nombres mostrados en la captura anterior no son válidos debido al cambio de nombre a ASP.NET Core)
Una vez hecho esto, ya tenemos en nuestro proyecto los componentes básicos que necesitamos para poder usar variables de sesión. Continuamos el proceso…
El hecho de posicionarse en el pipeline y ser “atravesado” por la petición brinda a este middleware la posibilidad de establecer la cookie de sesión que distinguirá de forma única al usuario, preparar el acceso a sus datos y almacenar los cambios producidos durante el proceso de la petición.
Y ojo, que esto es importante: hay que añadir el middleware que proporciona el estado de sesión antes que el propio framework MVC. De no ser así, la petición será procesada por MVC antes de el middleware de sesión sea ejecutado, por lo que desde nuestras aplicaciones no tendremos acceso a las variables de sesión.
El siguiente ejemplo muestra cómo introducir el middleware en el pipeline, utilizando la memoria como almacenamiento para el estado de sesión:
En aplicaciones pequeñas y sin demasiadas aspiraciones, almacenar las variables de sesión en memoria es una solución efectiva y razonable. Sin embargo, cuando la aplicación debe crecer a varios servidores o se necesita una solución menos volátil, podemos usar otros mecanismos de persistencia, utilizando el extensor
Como suele ser habitual a la hora de añadir módulos al pipeline, es posible indicar opciones de configuración:
El acceso a las variables de sesión se realiza utilizando la propiedad
Los que ya habéis usado antes variables de sesión, seguro que os sorprende esos métodos
Hasta ahora podíamos introducir cualquier tipo de objeto en variables de sesión, y el abuso de esta capacidad ha generado muchísimos problemas. He llegado a ver incluso contextos de datos o conexiones a bases de datos mantenidas en memoria de esta forma, creando unos problemas terribles en tiempo de ejecución. También ha sido tradicionalmente un limitante de la posibilidad de escalado de las aplicaciones (aunque puede solventarse usando algunos trucos de balanceado), y un problema para la fiabilidad de los sistemas (recordad que un reseteo del servidor, de IIS o incluso un reciclado del pool limpia la memoria).
Para evitar esto, a partir de ASP.NET Core sólo podremos guardar en variables de sesión objetos serializados, y esto se manifiesta en el tipo de dato que es ahora el diccionario
El framework nos proporciona métodos extensores para facilitar las tareas de serialización y deserialización en escenarios comunes, como el almacenamiento y recuperación de variables de sesión de tipo entero y cadenas de texto, mediante los métodos
Si por cualquier motivo queremos guardar un objeto o grafo complejo, tendremos que crear nuestro propio mecanismo de serialización. Aunque la primera tentación puede ser crear un serializador binario usando la clase
Pero sí podríamos, por ejemplo, serializarlo a JSON y guardarlo como
Así, ya podríamos usar construcciones más sencillas como las siguientes:
Nota: existen conversaciones en Github sobre la inclusión de métodos genéricos Set<T>() y Get<T>() que permitan indicar un componente de serialización como Protobuf o Bond, así que posiblemente las versiones finales de ASP.NET Core encontremos algo de ello.
Por otra parte, para eliminar variables de sesión podemos seguir utilizando el método
Comenzaremos diciendo que en ASP.NET Core no existe (al menos de momento) un método
Y una última cosa interesante a tener en cuenta es que ya no están disponibles los eventos
Bueno, pues de momento lo dejaremos aquí. Espero que lo visto os sea de utilidad para continuar interiorizando los cambio que se avecinan con las nuevas plataformas y que la transición a ellas sea un poco menos dolorosa ;)
Publicado en Variable not found.
Bueno, en realidad no se trata tanto de una ausencia como de un desplazamiento de esta característica. Resumidamente, las variables de sesión seguirán existiendo, pero no son parte del core de ASP.NET, como ocurría desde la primera versión de ASP.NET, sino un componente totalmente opcional implementado en forma de middleware que deberá ser instalado y configurado de forma independiente.
Pero antes de continuar, recordad que tanto MVC como ASP.NET Core siguen estando en proceso de desarrollo, por lo que algunas de las cosas que contaremos podrían cambiar en las versiones definitivas, aunque espero que no demasiado.
Y dicho esto, vamos al lío: ¿cómo utilizamos variables de sesión en aplicaciones basadas en ASP.NET Core?
1. Descarga e instalación del middleware proveedor de sesión
Siguiendo la nueva filosofía modular de ASP.NET Core, los mecanismos de almacenamiento y recuperación de variables de sesión son ahora un componente que podemos añadir a nuestras aplicaciones de forma opcional.Como es habitual, la descarga e instalación la realizaremos a través del interfaz de Nuget en Visual Studio, o bien añadiendo manualmente la referencia al archivo project.json. El nombre del paquete que nos interesa es
Microsoft.AspNetCore.Session
, como se muestra en la siguiente captura de pantalla:(Nota: los espacios de nombres mostrados en la captura anterior no son válidos debido al cambio de nombre a ASP.NET Core)
Una vez hecho esto, ya tenemos en nuestro proyecto los componentes básicos que necesitamos para poder usar variables de sesión. Continuamos el proceso…
2. Añadir el middleware al pipeline
El estado de sesión es proporcionado por el middlewareSessionMiddleware
, presente en el paquete que acabamos de descargar. Este middleware, insertado en el pipeline de proceso de las peticiones, ofrecerá a los frameworks o componentes posicionados tras él la capacidad de usar variables de sesión.El hecho de posicionarse en el pipeline y ser “atravesado” por la petición brinda a este middleware la posibilidad de establecer la cookie de sesión que distinguirá de forma única al usuario, preparar el acceso a sus datos y almacenar los cambios producidos durante el proceso de la petición.
Y ojo, que esto es importante: hay que añadir el middleware que proporciona el estado de sesión antes que el propio framework MVC. De no ser así, la petición será procesada por MVC antes de el middleware de sesión sea ejecutado, por lo que desde nuestras aplicaciones no tendremos acceso a las variables de sesión.
El siguiente ejemplo muestra cómo introducir el middleware en el pipeline, utilizando la memoria como almacenamiento para el estado de sesión:
En aplicaciones pequeñas y sin demasiadas aspiraciones, almacenar las variables de sesión en memoria es una solución efectiva y razonable. Sin embargo, cuando la aplicación debe crecer a varios servidores o se necesita una solución menos volátil, podemos usar otros mecanismos de persistencia, utilizando el extensor
UseDistributedSession()
en lugar de UseInMemorySession()
visto anteriormente. No entraremos en más detalle en este post, lo dejaremos para más adelante, pero es muy interesante el hecho de que esto descanse sobre el sistema de caching de ASP.NET, del que ha hablado el gran Unai hace poco.Como suele ser habitual a la hora de añadir módulos al pipeline, es posible indicar opciones de configuración:
3. Establecer, obtener y eliminar variables de sesión
En primer lugar, es importante tener en cuenta que los pasos anteriores son obligatorios si queremos utilizar variables de sesión. Cualquier intento de utilización de las mismas sin haber instalado y configurado previamente los componentes que las proporcionan provocarán la aparición de un error:El acceso a las variables de sesión se realiza utilizando la propiedad
Context.Session
, es decir, la clase Controller
no proporciona ya una propiedad Session
como en versiones anteriores de MVC, aunque obviamente siempre podríamos crearnos un atajo (por cierto, fijaos qué limpio queda usando las nuevas expresiones lambda en miembros de función de C# 6):Los que ya habéis usado antes variables de sesión, seguro que os sorprende esos métodos
GetInt()
y SetInt()
de la propiedad Session
. Pues sí, esto otro cambio importante sobre las versiones anteriores del framework.Hasta ahora podíamos introducir cualquier tipo de objeto en variables de sesión, y el abuso de esta capacidad ha generado muchísimos problemas. He llegado a ver incluso contextos de datos o conexiones a bases de datos mantenidas en memoria de esta forma, creando unos problemas terribles en tiempo de ejecución. También ha sido tradicionalmente un limitante de la posibilidad de escalado de las aplicaciones (aunque puede solventarse usando algunos trucos de balanceado), y un problema para la fiabilidad de los sistemas (recordad que un reseteo del servidor, de IIS o incluso un reciclado del pool limpia la memoria).
Para evitar esto, a partir de ASP.NET Core sólo podremos guardar en variables de sesión objetos serializados, y esto se manifiesta en el tipo de dato que es ahora el diccionario
Session
: un array de bytes. Con esto, se acabó el establecer o leer objetos completos directos como hemos hecho siempre, tendremos que serializarlos a un array de bytes para guardarlos el almacén de sesión, así como deserializarlos para poder acceder a ellos. De esta forma, simplificamos el uso de almacenamientos distintos a la memoria local para esta información, facilitando la escalabilidad y mejorando la fiabilidad.El framework nos proporciona métodos extensores para facilitar las tareas de serialización y deserialización en escenarios comunes, como el almacenamiento y recuperación de variables de sesión de tipo entero y cadenas de texto, mediante los métodos
GetInt()
, SetInt()
, GetString()
y SetString()
, como se muestra en el siguiente ejemplo:Si por cualquier motivo queremos guardar un objeto o grafo complejo, tendremos que crear nuestro propio mecanismo de serialización. Aunque la primera tentación puede ser crear un serializador binario usando la clase
BinaryFormatter
de toda la vida, resulta que la serialización binaria no está soportada en .NET Core, supongo que debido al carácter cross platform de este framework. Pero sí podríamos, por ejemplo, serializarlo a JSON y guardarlo como
string
en la variable de sesión y realizar el proceso inverso al recuperar el valor, o bien crear nuestras propias funciones extensoras para facilitarnos la vida en el futuro:Así, ya podríamos usar construcciones más sencillas como las siguientes:
Nota: existen conversaciones en Github sobre la inclusión de métodos genéricos Set<T>() y Get<T>() que permitan indicar un componente de serialización como Protobuf o Bond, así que posiblemente las versiones finales de ASP.NET Core encontremos algo de ello.
Por otra parte, para eliminar variables de sesión podemos seguir utilizando el método
Remove()
, al igual que hemos hecho siempre:
4. Otros cambios respecto a versiones anteriores
Por último, vamos a comentar un par de detalles que han sido modificados respecto a versiones anteriores de ASP.NET.Comenzaremos diciendo que en ASP.NET Core no existe (al menos de momento) un método
Abandon()
. En cambio, se añade un método Clear()
que permite eliminar toda la información de sesión del usuario conectado.Y una última cosa interesante a tener en cuenta es que ya no están disponibles los eventos
Session_Start()
y Session_End()
que podíamos capturar en el Global.asax en versiones anteriores del framework.Bueno, pues de momento lo dejaremos aquí. Espero que lo visto os sea de utilidad para continuar interiorizando los cambio que se avecinan con las nuevas plataformas y que la transición a ellas sea un poco menos dolorosa ;)
Publicado en Variable not found.
7 Comentarios:
Hola Jose María, tengo varias preguntas sobre este artículo que después de estos años todavía no tengo muy claras y me gustaría conocer tu opinión a este respecto, he oído varias veces que no es muy aconsejable utilizar objetos de sesión, para minimizar el uso de cookies, en Mvc introdujeron el diccionario TempDat que internamente utiliza una variable de sesión para almacenar su estado, ViewBag o ViewData permiten almacenar datos para el request actual y la utilización de patrones como singleton se pueden aplicar para evitar o minimizar el uso de la sesión, bajo tu punto de vista, ¿cuándo se deberían utilizar las variables de sesión?, ¿son necesarias?, ¿podemos evitarlas?, ¿si nuestro sistema crece, que problemas pueden plantearnos?, ya sé que son muchas preguntas, pero los sistemas que he desarrollado siempre han sido para pocos clientes concurrentes y nunca he observado problemas utilizándolas o no, me gustaría conocer cuáles son las mejores prácticas a este respecto. Gracias.
Deberías buscar mas información sobre el uso de sesiones y TempDat.
El usar una variable de tipo sesión depende del contexto en donde te encuentres.
Hola!
En aplicaciones pequeñitas, con poca carga de usuarios y siempre que no te importe que los datos de sesión se pierdan si se reinicia el servidor, puedes usarlas con tranquilidad usando la memoria como almacenamiento (la opción por defecto de ASP.NET).
El problema viene cuando quieres que crezcan esas aplicaciones que empezaron siendo pequeñas. En ese momento se te complican algo más las cosas porque las variables de sesión tienen algunas limitaciones (bloqueos de hilos, dificultad para compartirlas entre servidores...)
Personalmente, llevo años si usarlas y tampoco las echo en falta especialmente.
Saludos!
Hola José, como siempre un excelente post.
Una alternativa cuando nuestro sistema comienza a crecer es tener esas sesiones es otro sistema, algo que permita escalar y compartirse entre diferentes instancias/servidores, un buen sistema puede ser Redis
Saludos!
Hola!
Sí, sin duda. Para escalar y para tener persistencia más allá de la memoria Redis es una de las opciones más recomendables.
Y además, en ASP.NET 5 la posibilidad de usar Redis viene incluida de serie :)
Muchas gracias por comentar!
Hola,
He intentado hacer la clase SessionExtensions y me genera 2 errores
-uno en GetObject
-otro en SetObject
Estoy usando ASP .NET MVC Core 1.0
Hola!
Las cosas han cambiando bastante estos últimos meses... :(
Aquí tienes información más actualizada:
https://docs.asp.net/en/latest/fundamentals/app-state.html#installing-and-configuring-session
Saludos!
Enviar un nuevo comentario