Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DataAnnotation Validations and Custom ModelBinder

I've been running some experiments with ASP.NET MVC2 and have run into an interesting problem.

I'd like to define an interface around the objects that will be used as Models in the MVC app. Additionally, I'd like to take advantage of the new DataAnnotation functionally by marking up the members of this interface with validation attributes.

So, if my site has a "Photo" object, I'll define the following interface:

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

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

And I'll define the following implementation:

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

My MVC App controller might include methods like:

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);
  }

 }
}

And finally, in order to bind PhotoImpls to the parameters in these action methods, I might implement the following extensions to the 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);
 }
}

Everything appears to working great, except that the ModelState.IsValid property in my controller doesn't appear to notice invalid values (say, null) in the [Required] properties of the IPhoto implementation.

I suspect that I'm neglecting to set some important piece of state in my ModelBinder implementation. Any hints?

like image 967
Kyle Chafin Avatar asked Jan 08 '10 19:01

Kyle Chafin


1 Answers

I had the same issue. The answer is instead of overriding BindModel() in your custom model binder, override 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);
}

You can then let the base BindModel class do its stuff with validation :-)

like image 110
Russell Giddings Avatar answered Sep 20 '22 22:09

Russell Giddings