Проверки DataAnnotation и пользовательский ModelBinder

Я выполнял некоторые эксперименты с 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 в моем контроллере, кажется, не замечает недопустимые значения (скажите, пустой указатель) в свойствах [Required] реализации iPhoto.

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

6
задан Kyle Chafin 8 January 2010 в 19:23
поделиться

3 ответа

После проверки источника для 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);
        }
    }
}
7
ответ дан 8 December 2019 в 14:43
поделиться

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

0
ответ дан 8 December 2019 в 14:43
поделиться

У меня была такая же проблема. Ответ: вместо переопределения 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 делать свои дела с валидацией :-)

.
9
ответ дан 8 December 2019 в 14:43
поделиться
Другие вопросы по тегам:

Похожие вопросы: