Gerardo Contijoch

Experiencias del día a día trabajando con .NET – ASP.NET, C#, ASP.NET MVC y demas…

Restaurar ViewData luego de hacer un Redirect en ASP.NET MVC

Posted by Gerardo Contijoch en mayo 9, 2009

Una de las consecuencias de hacer un redirect desde una acción en ASP.NET MVC es que se pierde toda la información que tenemos guardada en el ViewData así como también en el ModelState. Esto se debe a que esos dos diccionario se utilizan para pasarle información desde los controladores a las vistas y si hacemos un redirect, lógicamente no vamos a estar devolviendo ninguna vista, por lo que sus valores son descartados cuando comienza la ejecución de la acción a la que redirigimos. Para evitar esto, se pueden guardar estos valores en la propiedad TempData, la cual es persistida entre requests. Como esto se puede volver un poco tedioso y repetitivo (por no decir poco elegante), decidí crear un par de ActionFilters que se encarguen de persistir valores del ViewData y de recuperarlos cuando sea necesario. El siguiente código esta basado en este post, el cual contiene la solución para persistir el ModelState.

Les presento un ejemplo de como se utilizan estos atributos y a continuación el código de los mismos.

   1: public class TestController : Controller {
   2:
   3:     [ExportarViewDataItem("Nombre")]
   4:     public RedirectToRouteResult AccionConRedirect() {
   5:         // ...
   6:         ViewData["Nombre"] = "Gerardo";
   7:         // ...
   8:         return RedirectToAction("Index");
   9:     }
  10:
  11:     [ImportarViewDataItem("Nombre")]
  12:     public ViewResult Index() {
  13:         string nombre = ViewData["nombre"].ToString();
  14:         // ...
  15:         return View();
  16:     }
  17:
  18: }

La implementación actual de los atributos requiere que se especifique un key a exportar e importar, pero los atributos son muy fácilmente modificables para que exporte e importe el ViewData completo sin necesidad de especificar cada uno de los keys.

Aca esta el código:

   1: /// <summary>
   2: /// Clase base para los atributos que exportan e importan valores de ViewData.
   3: /// </summary>
   4: public abstract class ViewDataTransferAttribute : ActionFilterAttribute {
   5:
   6:     public string Key { get; set; }
   7:
   8:     protected ViewDataTransferAttribute(string key) {
   9:         if (string.IsNullOrEmpty(key)) {
  10:             throw new ArgumentException("El parámetro key no puede ser null o vacío.", "key");
  11:         }
  12:
  13:         Key = key;
  14:     }
  15:
  16:     /// <summary>
  17:     /// Key interna para referenciar al valor guardado.
  18:     /// </summary>
  19:     /// <remarks>Se usa una key intena para asegurarnos de que no hay conflictos de keys con valores ya existentes.</remarks>
  20:     protected string InternalKey { get { return "_viewDataItem_" + Key; } }
  21: }
  22:
  23: [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
  24: public class ExportarViewDataItemAttribute : ViewDataTransferAttribute {
  25:
  26:     public ExportarViewDataItemAttribute(string key) : base(key){}
  27:
  28:     public override void OnActionExecuted(ActionExecutedContext filterContext) {
  29:
  30:         // Si no hacemos un redirect, entonces no tiene sentido respaldar los valores
  31:         if (filterContext.Result is RedirectResult || filterContext.Result is RedirectToRouteResult) {
  32:
  33:             var valor = filterContext.Controller.ViewData[Key];
  34:
  35:             if (valor != null) {
  36:                 var tempData = filterContext.Controller.TempData;
  37:                 if (tempData.ContainsKey(InternalKey)) {
  38:                     tempData.Remove(InternalKey);
  39:                 }
  40:                 tempData.Add(InternalKey, valor);
  41:             }
  42:         }
  43:
  44:         base.OnActionExecuted(filterContext);
  45:     }
  46: }
  47:
  48: [AttributeUsage(AttributeTargets.Method, AllowMultiple = true, Inherited = false)]
  49: public class ImportarViewDataItemAttribute : ViewDataTransferAttribute {
  50:
  51:     public ImportarViewDataItemAttribute(string key) : base(key) { }
  52:
  53:     public override void OnActionExecuting(ActionExecutingContext filterContext) {
  54:
  55:         var valor = filterContext.Controller.TempData[InternalKey];
  56:
  57:         if (valor != null) {
  58:             var viewData = filterContext.Controller.ViewData;
  59:             if (viewData.ContainsKey(Key)) {
  60:                 viewData.Remove(Key);
  61:             }
  62:             viewData.Add(Key, valor);
  63:             // Limpiamos TempData
  64:             filterContext.Controller.TempData.Remove(InternalKey);
  65:         }
  66:
  67:         base.OnActionExecuting(filterContext);
  68:     }
  69: }

Se puede bajar el proyecto con los atributos y los tests asociados desde aquí.

¡Nos vemos en el próximo post!

Publicado originalmente en https://gerardocontijoch.wordpress.com.

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

 
A %d blogueros les gusta esto: