Hace ya bastante tiempo hablamos por aquí de cómo funciona, aunque resumidamente podríamos decir que se trata de un almacén temporal en el que podemos guardar datos desde una acción y consultarlos desde otra, aunque sea en peticiones distintas; la información se quedará almacenada hasta que sea obtenida por primera vez, momento en el que será eliminada del repositorio utilizado.
El principal problema que encontramos al utilizarlo en proyectos reales es que la información se guarda en variables de sesión, lo que en determinados escenarios puede ser muy costoso o simplemente imposible, y esto hace que descartemos su uso y que tengamos que inventar alternativas para solucionar problemas que usando TempData ya tendríamos resueltos.
Sin embargo, el hecho de que se utilicen variables de sesión, como casi todo en el framework, es simplemente un comportamiento por defecto que puede ser reemplazado por otro. Podríamos guardar la información de TempData en una base de datos, archivos de texto o cualquier otro lugar donde nos interese hacerlo :-)
Y lo que vamos a ver en este post es una implementación muy sencilla para hacer persistir esta información en cookies. Así, cuando desde el servidor establezcamos un valor en el
TempData
, lo que haremos es enviárselo en una cookie al cliente, donde persistirá hasta que sea leído. Obviamente no se puede usar para guardar datos confidenciales ni nada parecido, ni tampoco es interesante para gran cantidad de datos puesto que éstos viajarán entre cliente y servidor hasta ser eliminados, pero puede ser útil en escenarios simples y creo que ilustra bastante bien el funcionamiento interno de esta interesante característica de ASP.NET MVC.TempData Providers
Todos los controladores tienen una propiedad llamadaTempDataProvider
, que es la encargada de suministrar el componente que se encargará de guardar y recuperar información. En su interior se encuentra un objeto que implementa el interfaz ITempDataProvider
, cuya definición vemos a continuación:public interface ITempDataProviderCuando el framework carga el controlador, antes de invocar la acción correspondiente llamará al método
{
IDictionary<string, object> LoadTempData(ControllerContext controllerContext);
void SaveTempData(ControllerContext controllerContext,
IDictionary<string, object> values);
}
TempDataProvider.LoadTempData()
para obtener la información salvada desde el almacén correspondiente y cargarla en el diccionario TempData
.De la misma forma, al finalizar el proceso de la acción, ASP.NET MVC ejecutará el método
TempDataProvider.SaveTempData()
para volcar la información almacenada en el diccionario TempData
al sistema de persistencia elegido.Decíamos antes que por defecto se utilizan variables de sesión, ¿verdad? Pues esto se debe a que internamente en
TempDataProvider
encontraremos inicialmente una instancia de SessionStateTempDataProvider
, cuya implementación lo único que hace es utilizar variables de sesión para almacenar y obtener la información.Para modificar este comportamiento lo único que tenemos que hacer es crear una clase que implemente ese sencillo interfaz, e introducir un objeto de este nuevo tipo en la propiedad
TempDataProvider
de los controladores. Fácil, ¿eh?Un TempDataProvider para cookies
El siguiente código muestra la implementación de nuestro flamanteCookieTempDataProvider
. Observad que aprovechamos el método SaveTempData()
para serializar en JSON el contenido del diccionario TempData
, y el método LoadTempData()
para realizar la operación inversa:public class CookieTempDataProvider : ITempDataProviderEl código de
{
private const string CookieName = "_TempData_";
public IDictionary<string, object> LoadTempData(
ControllerContext controllerContext)
{
var cookie = controllerContext.HttpContext.Request.Cookies.Get(CookieName);
if (cookie != null)
{
return Newtonsoft.Json.JsonConvert
.DeserializeObject<Dictionary<string, object>>(cookie.Value);
}
return null;
}
public void SaveTempData(ControllerContext controllerContext,
IDictionary<string, object> values)
{
if (values != null && values.Any())
{
var serializedData = Newtonsoft.Json.JsonConvert.SerializeObject(values);
var cookie = new HttpCookie(CookieName, serializedData);
controllerContext.HttpContext.Response.Cookies.Add(cookie);
}
else
{
var cookie = controllerContext.HttpContext.Request.Cookies[CookieName];
if (cookie != null)
{
cookie.Expires = DateTime.Now.AddDays(-1);
controllerContext.HttpContext.Response.Cookies.Set(cookie);
}
}
}
}
SaveTempData()
es un poco más extenso porque estamos incluyendo la lógica para eliminar la cookie cuando ya no sea necesaria, es decir, cuando no haya información almacenada en TempData
.Por supuesto, podríamos habernos parado un poco más en la creación de la cookie y definirla más detalladamente, por ejemplo estableciéndole la caducidad, visibilidad, etc., pero no es ese el objetivo en este momento…
Modificar el proveedor de TempData por defecto
Ya lo único que nos queda es introducir este nuevo proveedor en el pipeline de ASP.NET MVC. Esto tenemos varias formas de hacerlo, vamos a ver dos de ellas.Una forma muy sencilla es establecer el
TempDataProvider
desde los propios controladores, o bien desde una de sus clases base para no tener que repetir demasiado ese código. En este caso, podemos aprovechar que para instanciar estos proveedores el framework invoca al método virtual CreateTempData()
del controlador; basta con sobrescribirlo y tenemos ya todo el trabajo hecho:public class BaseController: ControllerAún más fácil resulta si estamos utilizando un contenedor de inversión de control como Unity o Ninject. En este caso, bastará con asociar el interfaz
{
protected override ITempDataProvider CreateTempDataProvider()
{
return new CookieTempDataProvider();
}
}
public class HomeController : BaseController
{
// We are now using the CookieTempDataProvider
...
}
ITempDataProvider
a nuestra clase y todo saldrá funcionando como por arte de magia, puesto que el Dependency Resolver es utilizado de forma interna para crear el proveedor. El siguiente código sería el registro usando Unity:
container.RegisterType<ITempDataProvider, CookieTempDataProvider>();Con cualquiera de estas dos técnicas ASP.NET MVC pasaría a utilizar cookies para persistir la información del TempData. Si en lugar de cookies preferís otro sitio simplemente habría que crear otro proveedor e implementar los métodos
LoadTempData()
y SaveTempData()
para tenerlo resuelto.¿Sencillo, eh?
Publicado en: Variable not found.