Autor en Google+
Saltar al contenido

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web ASP.NET, ASP.NET Core, MVC, SignalR, Entity Framework, C#, Azure, Javascript... y lo que venga ;)

10 años online 🎂

el blog de José M. Aguilar

Inicio El autor Contactar

Artículos, tutoriales, trucos, curiosidades, reflexiones y links sobre programación web
ASP.NET, ASP.NET Core, MVC, SignalR, Entity Framework, C#, Azure, Javascript...

¡Microsoft MVP!
miércoles, 17 de febrero de 2010
ASP.NET MVC 2TempData es un diccionario disponible a nivel de controladores y vistas del framework ASP.NET MVC que nos permite almacenar objetos de forma similar a la colección ViewData, pero, a diferencia de ésta, es capaz de mantener su contenido entre peticiones.

De hecho, es un recurso habitualmente utilizado cuando necesitamos enviar información desde una acción a otra tras realizar una redirección. Por ejemplo, ante una petición dirigida hacia la acción “Milestone” en un controlador como el siguiente:

public ActionResult Milestone() 
{
  TempData["Message"] = "He pasado por aquí";
  RedirectToAction("ShowMessage");
}
 
public ActionResult ShowMessage()
{
  return View();
} 

… podríamos tener en la plantilla de vista ShowMessage.aspx acceso directo a la entrada del TempData almacenada en la petición que inició la secuencia:

<p class="msg"><strong><%= TempData["Message"] %></strong></p>

Pues bien, la beta de ASP.NET MVC 2 introdujo en el comportamiento de este diccionario una serie de cambios que merecen ser comentados.

En primer lugar, ha sido modificado el ciclo de vida de las entradas existentes en el TempData. Ahora cada elemento del diccionario es analizado al finalizar la ejecución del controlador (concretamente su método ExecuteCore()); aquellos que estén “marcados” continuarán viviendo en el mecanismo de persistencia elegido (por defecto, en una variable de sesión del usuario) y el resto serán eliminados sin piedad.

Internamente se procede de la siguiente manera: al comenzar el proceso de la petición, se cargan en la propiedad TempData del controlador los valores almacenados en el proveedor de datos temporales,  un objeto que implementa el interfaz ITempDataProvider. La implementación por defecto utiliza la clase SessionStateTempDataProvider para almacenar la información en  la variable de sesión “__ControllerTempData”.

En este momento, todas las entradas presentes en el diccionario son marcadas como candidatas a ser conservadas.To be or not to be...

Si desde cualquier punto del código del controlador o la vista se obtiene el valor de una entrada del diccionario, como en el ejemplo de vista ShowMessage anteriormente mostrado, se eliminará la marca de supervivencia y pasarán a estar en la cuerda floja.

Al finalizar la ejecución del controlador, se recorren aquellas entradas del diccionario que no estén marcadas y se eliminan del diccionario. Finalmente, éste es salvado a través del proveedor de datos temporales actual.

Sólo hay una excepción para el caso anterior: las redirecciones. Éstas, en su método ExecuteResult(), incluyen una llamada al método Keep() del diccionario TempData actual, lo que provoca que todas las entradas del mismo sean marcadas para su conservación. Por tanto, una acción que retorne un tipo RedirectToRouteResult, siempre conservará el TempData intacto.

Como consecuencia, una forma de evitar la eliminación de una entrada y forzar su conservación al finalizar la petición actual es utilizando TempData.Keep(key), siendo key la clave de la misma,  o generalizando como en el caso anterior, TempData.Keep(), que salvará todas las entradas almacenadas.

Pero ojo, que esto puede provocar un efecto no deseado. Dado que por defecto las entradas al diccionario no van a eliminarse salvo que sean leídas, puede dar lugar a contenidos perennes en el estado de sesión del usuario. O en otras palabras, si introducimos en TempData una entrada con un objeto pesado y éste nunca es obtenido, permanecerá en la sesión del usuario hasta que ésta desaparezca... supongo que no es necesario comentar lo desastroso que puede ser esto, no? ;-D

Otro aspecto curioso es que cualquier consulta al TempData hará que la entrada sea marcada para su eliminación… incluso si estamos consultándola desde el depurador de Visual Studio. Por tanto, cuidado con esto, que puede provocar algún dolor de cabeza.

Aunque algo denostado, TempData sigue siendo una opción válida para el traspaso de información entre distintas peticiones, aunque siempre usado con moderación y sentido común. 

Publicado en: Variable not found.
Hey, ¡estoy en twitter!

Estos contenidos se publican bajo una licencia de Creative Commons Licencia Reconocimiento-No comercial-Compartir bajo la misma licencia 3.0 España de Creative Commons

4 Comentarios:

Fernando H dijo...

Jose, te hago una pregunta

Si yo quisiera conservar todo lo cargado en un formulario (unos doce valores por decir algo) para impactarlo luego de una confirmacion en otro formulario posterior puedo utilizar TempData o existe otra manera de poder persistir los datos?

José M. Aguilar dijo...

Hola, Fernando!

La solución más natural, en mi opinión, sería guardar los datos en campos hidden. Es decir, la página de confirmación mostraría los valores al usuario, y montaría un formulario con un hidden por cada propiedad del objeto a persistir.

También puedes serializarlo completamente usando MvcFutures. En este post encontrarás más información sobre ello.

Espero que te sea de ayuda.

Saludos & gracias por comentar.

pablosguajardo dijo...

Hola yo lo uso para hacer una especie de multiview, como en mvc no existe creo mis propios step y en los tempdata guardo los datos del modelo q no voy a usar en el step actual, pero si para finalizar todos los step… medio loco, pero funciona!!! En si los campos texto o numéricos los guardo en hidden pero si es algún objeto con más datos los guardo en TempData
Mi caso es el siguiente mando un modelo a la vista con un montón de datos, los datos útiles para el step los muestro, los textos y numéricos los pongo en hidden y los objetos un poco más complejos en TempData. Después en la próximo step, ya en el controler, me llega todo el modelo gracias a que guarde lo q no usaba en ese momento en los hidden y en el tempdata, esto se repite la cantidad de veces como step tenga. Esto sería una buena práctica?
Según leo en tu blog, no haría falta ponerlo en la vista ya q todo esto lo podría manejar en el controler, ya que el tempdata se guardaría hasta que sea “consultado”, eso es así?
Otra: si no se “consulta” el tempdata ¿se elimina si el usuario abandona la aplicación? O por más que este la abandone el tempdata sigue ocupando memoria? De ser asi existe alguna manera de vaciarlo?
GRACIAS!!!!

José M. Aguilar dijo...

Hola, Pablo!

Efectivamente, el TempData se almacena hasta que el valor es consultado... el problema es que si no es consultado nunca (por ejemplo, si como comentas, cuando el usuario abandona el sitio), los datos permanecerán en memoria hasta que finalice la sesión.

Dado que por defecto se usan variables de sesióbn, en teoría podrías eliminarlos invocando al método TempData.Clear() o limpiando la entrada Session["__ControllerTempData"], aunque se trata de un hack no demasiado recomendable.

Tienes otra posibilidad, que consiste en serializar en la vista los objetos que quieras persistir, como se describe en este post.

Espero que te sea de ayuda.

Un saludo & gracias por comentar. :-)