Gerardo Contijoch

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

Inicialización del ModelState en ASP.NET MVC

Posted by Gerardo Contijoch en junio 21, 2009

Hoy mientras trabajaba en un site ASP.NET MVC aprendí una lección que espero no olvidar jamás (su olvido me podría traer muchos dolores de cabeza).

El problema se presentó cuando uno de los campos del form con el que estaba trabajando no se actualizaba luego de un postback. El form no tenia nada de especial, sólo un par de campos, y su posteo provocaba la ejecución de una acción que tampoco hacia nada muy loco. Lo único destacable era que el parámetro con problemas era cargado con un ModelBinder personalizado, pero el mismo funcionaba bien y lo inicializaba correctamente al valor. Lo primero que hice fue verificar que las variables del post lleguen correctamente al server. También verifiqué que no haya ningún código javascript interfiriendo con el llenado de campos. Lo que más me desconcertó fue que dentro de la acción, el parámetro cuyo valor tenia problemas estaba correctamente inicializado, cosa que no esperaba (lo que me llevó a pensar que no había un error en el ModelBinder). Sin embargo había un detalle que pasé de largo: entre los valores del ModelState del request no se encontraba el parámetro con problemas. Fue cuando descubrí eso que supe donde estaba el problema. Un poco más de investigación me confirmó las sospechas. Pero antes de explicarles el problema, veamos el código del ModelBinder:

   1: public class TipoDeOperacionModelBinder : IModelBinder {
   2:     #region IModelBinder Members
   3:
   4:     public object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext) {
   5:
   6:         if (bindingContext == null) {
   7:             throw new ArgumentNullException("bindingContext");
   8:         }
   9:
  10:         ValueProviderResult val;
  11:         if (!bindingContext.ValueProvider.TryGetValue(bindingContext.ModelName, out val)) {
  12:             // Si no encontramos el valor, devolvemos null y ASP.NET MVC se encarga de provocar la excepción necesaria
  13:             return null;
  14:         }
  15:
  16:         int realVal = (int)val.ConvertTo(typeof(int));
  17:         return (TipoDeOperacion)realVal;
  18:     }
  19:
  20:     #endregion
  21: }

Este ModelBinder simplemente toma un valor (indicado por bindingContext.ModelName) y lo transforma en un Enum de tipo TipoDeOperacion. Cabe aclarar que este ModelBinder esta registrado para el tipo TipoDeOperacion, por lo que el propio framework es el encargado de hacer uso del mismo cuando necesite hacer el binding de un parámetro de tipo TipoDeOperacion.

Como dije antes, el parámetro en cuestión se inicializaba correctamente, lo que confirmaba que las variables del post llegaban sin problemas. El problema estaba en que no se encontraba dentro del ModelState y eso se debe sencillamente a que en ningún lugar del código del ModelBinder lo estoy agregando. Resulta que el ModelBinder no solo es responsable de cargar los parámetros de las acciones y actualizar el modelo con el que estamos trabajando, sino que ¡también debe inicializar el ModelState! El resto de los parámetros de la acción no tenían problemas ya que eran procesados por la clase DefaultModelBinder, la cual se encarga de todo. Todo se resolvió cuando agregué el siguiente código en la línea 15:

bindingContext.ModelState.SetModelValue(bindingContext.ModelName, val);

Parece una pavada de detalle, pero esa sola línea de código me hizo perder varias horas de trabajo por no saber que el ModelState era cargado por los ModelBinders. Esto demuestra la importancia de entender bien las herramientas y frameworks con los que uno trabaja. ASP.NET MVC nos provee de montones de puntos de extensión, pero de nada sirve si no los sabemos aprovechar correctamente.

¡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: