Pregunta

He estado corriendo algunos experimentos con ASP.NET MVC2 y se han topado con un problema interesante.

Me gustaría definir una interfaz en torno a los objetos que serán utilizados como modelos en la aplicación MVC. Además, me gustaría aprovechar la nueva DataAnnotation funcionalmente por el marcado de los miembros de esta interfaz con atributos de validación.

Por lo tanto, si mi sitio tiene un objeto "Foto", voy a definir la interfaz siguiente:

public interface IPhoto 
{ 
 [Required]
 string Name { get; set; }

 [Required]
 string Path { get; set; }
}

Y voy a definir la siguiente implementación:

public class PhotoImpl : IPhoto 
{
 public string Name { get; set; }
 public string Path { get; set; }
}

Mi controlador MVC App podría incluir métodos como:

public class PhotoController : Controller
{
 [HttpGet]
 public ActionResult CreatePhoto()
 {
  return View(); 
 }

 [HttpPost]
 public ActionResult CreatePhoto(IPhoto photo)
 {
  if(ModelState.IsValid)
  {
   return View(); 
  }
  else
  {
   return View(photo);
  }

 }
}

Y, por último, a fin de obligar a los parámetros PhotoImpls en estos métodos de acción, que podría poner en práctica las siguientes extensiones a la DefaultModelBinder:

public class PhotoModelBinder : DefaultModelBinder
{
 public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
  if(bindingContext.ModelType == typeof(IPhoto))
  {
   IPhoto photo = new PhotoImpl();
   // snip: set properties of photo to bound values
   return photo; 
  }

  return base.BindModel(controllerContext, bindingContext);
 }
}

Todo parece trabajar muy bien, excepto que la propiedad ModelState.IsValid en mi controlador no parece darse cuenta de valores no válidos (por ejemplo, null) en las propiedades [requerido] de la aplicación iPhoto.

Sospecho que estoy dejando de establecer alguna pieza importante del estado en mi aplicación ModelBinder. ¿Alguna pista?

¿Fue útil?

Solución 2

Después de la inspección de la fuente de System.Web.MVC.DefaultModelBinder, parece que esto se puede solucionar utilizando un enfoque ligeramente diferente. Si nos basamos en mayor medida de la implementación base de bindModel, parece que podemos construir un objeto PhotoImpl mientras sigue tirando de los atributos de validación desde iPhoto.

Algo así como:

public class PhotoModelBinder : DefaultModelBinder
{
    public override object BindModel(ControllerContext controllerContext, ModelBindingContext bindingContext)
    {
        if (bindingContext.ModelType == typeof(IPhoto))
        {
            ModelBindingContext newBindingContext = new ModelBindingContext()
            {
                ModelMetadata = ModelMetadataProviders.Current.GetMetadataForType(
                    () => new PhotoImpl(), // construct a PhotoImpl object,
                    typeof(IPhoto)         // using the IPhoto metadata
                ),
                ModelState = bindingContext.ModelState,
                ValueProvider = bindingContext.ValueProvider
            };

            // call the default model binder this new binding context
            return base.BindModel(controllerContext, newBindingContext);
        }
        else
        {
            return base.BindModel(controllerContext, bindingContext);
        }
    }
}

Otros consejos

Yo tenía el mismo problema. La respuesta es en lugar de anular bindModel () en su carpeta de modelos personalizados, anular CreateModel () ...

protected override object CreateModel(ControllerContext controllerContext, ModelBindingContext bindingContext, System.Type modelType)
{
    if (modelType == typeof(IPhoto))
    {
        IPhoto photo = new PhotoImpl();
        // snip: set properties of photo to bound values
        return photo;
    }

    return base.CreateModel(controllerContext, bindingContext, modelType);
}

A continuación, puede dejar que la clase bindModel base de hacer sus cosas con la validación: -)

Ha intentado colocar el atributo [Obligatorio] en su modelo y volver a probar? Se puede estar teniendo dificultades para aplicar el atributo a una interfaz.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top