Проверки аннотации данных и пользовательский связыватель моделей - PullRequest
6 голосов
/ 08 января 2010

Я провел несколько экспериментов с ASP.NET MVC2 и столкнулся с интересной проблемой.

Я бы хотел определить интерфейс вокруг объектов, которые будут использоваться в качестве моделей в приложении MVC. Кроме того, я хотел бы функционально использовать преимущества новой DataAnnotation, помечая элементы этого интерфейса атрибутами проверки.

Итак, если на моем сайте есть объект «Фото», я определю следующий интерфейс:

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

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

И я определю следующую реализацию:

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

Мой контроллер приложения MVC может содержать такие методы, как:

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

 }
}

И, наконец, чтобы связать PhotoImpls с параметрами в этих методах действия, я мог бы реализовать следующие расширения 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);
 }
}

Кажется, что все работает отлично, за исключением того, что свойство ModelState.IsValid в моем контроллере не замечает недопустимых значений (скажем, null) в свойствах [Required] реализации IPhoto.

Я подозреваю, что я пренебрегаю установкой некоторого важного элемента состояния в моей реализации ModelBinder. Есть намеки?

Ответы [ 3 ]

9 голосов
/ 27 мая 2010

У меня была такая же проблема. Ответ заключается в том, чтобы вместо переопределения BindModel () в привязке пользовательской модели переопределить 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);
}

Затем вы можете позволить базовому классу BindModel выполнять свою работу с проверкой: -)

7 голосов
/ 12 января 2010

После проверки источника для System.Web.MVC.DefaultModelBinder, похоже, что это можно решить, используя немного другой подход. Если мы в большей степени полагаемся на базовую реализацию BindModel, похоже, что мы можем создать объект PhotoImpl, все еще извлекая атрибуты проверки из IPhoto.

Что-то вроде:

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);
        }
    }
}
0 голосов
/ 10 января 2010

Вы пытались разместить атрибут [Требуется] на вашей модели и провести повторное тестирование? Может возникнуть проблема с применением атрибута к интерфейсу.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...