2010-09-19 2 views
15

так согласно GuIValidatableObject.Validate() должен вызываться, когда контроллер проверяет это модель (т.е. до ModelState.IsValid), однако просто сделать модель реализации IValidatableObject, кажется, не работает, потому что Validate(..) не дозвонились ,ModelState.IsValid против IValidateableObject в MVC3

Кто-нибудь знает, есть ли что-то еще, что я должен подключить, чтобы заставить это работать?

EDIT:

Вот код, в соответствии с просьбой.

public class LoginModel : IValidatableObject 
{ 
    [Required] 
    [Description("Email Address")] 
    public string Email { get; set; } 

    [Required] 
    [Description("Password")] 
    [DataType(DataType.Password)] 
    public string Password { get; set; } 

    [DisplayName("Remember Me")] 
    public bool RememberMe { get; set; } 

    public int UserPk { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     var result = DataContext.Fetch(db => { 

      var user = db.Users.FirstOrDefault(u => u.Email == Email); 

      if (user == null) return new ValidationResult("That email address doesn't exist."); 
      if (user.Password != User.CreateHash(Password, user.Salt)) return new ValidationResult("The password supplied is incorrect."); 

      UserPk = user.UserPk; 
      return null; 
     }); 

     return new List<ValidationResult>(){ result }; 
    } 
} 

Действие. (Я ничего особенного не делать в контроллере ...)

[HttpPost] 
public ActionResult Login(LoginModel model) 
{ 
    if (ModelState.IsValid) 
    { 
     FormsAuthentication.SetAuthCookie(model.Email, model.RememberMe); 
     return Redirect(Request.UrlReferrer.AbsolutePath); 
    } 

    if (ControllerContext.IsChildAction || Request.IsAjaxRequest()) 
     return View("LoginForm", model); 

    return View(model); 
} 

я поставил точку останова на первой линии LoginModel.Validate() и не кажется, чтобы получить удар.

+0

Вы код выглядит просто отлично. Точно так, как должно. Просто точка интереса, но у вас есть дублирующая модель? Я знаю, что у меня есть модель представления и модель db для каждого объекта. Может ли ваш контроллер ссылаться на неправильную модель? – Buildstarted

+2

Кроме того, в качестве примечания стороны: вы обязательно должны вернуть только одну ошибку, если имя пользователя или пароль недействительны и не являются отдельными ошибками. Это просто для безопасности, так как я могу проверить каждое поле отдельно, чтобы найти имя пользователя, а затем работать с паролем для этого пользователя. Это не требуется, но это хорошая идея :) – Buildstarted

+0

Вы можете использовать 'yield return DataContext ...' вместо того, чтобы возвращать новый список. Это будет красивее и быстрее. – pipedreambomb

ответ

18

Нет ничего более, чем просто добавить его к модели, которую вы проверяете. Вот пример проверки

public class User : IValidatableObject { 
    public Int32 UserID { get; set; } 
    public string Name { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { 
     //do your validation 

     return new List<ValidationResult>(); 
    } 
} 

И ваш контроллер будет использовать эту модель

public ActionResult Edit(User user) { 
    if (ModelState.IsValid) { 
    } 
} 

Надеется, что это помогает. Другими требованиями являются .net 4 и аннотации данных, для которых вам явно нужен jsut для ivalidatableobject. Опубликуйте любые проблемы, и мы увидим, не можем ли мы их разрешить - например, опубликовать вашу модель и ваш контроллер ... возможно, что вы что-то упустили.

+23

Вы правы, одна оговорка в том, что если у вас есть какие-либо атрибуты проверки, которые приводят к недействительности модели, Validate никогда не будет вызван. Это была моя проблема. –

+0

А как интересно. Спасибо за это. – Buildstarted

+2

Это предостережение мне кажется очень полезным, чтобы знать :) +1 к обоим –

6

Подтверждение с использованием DefaultModelBinder - двухэтапный процесс. Сначала проверяются Data Annotations. Тогда (и только если проверка аннотаций данных привела к ошибкам нуля), вызывается IValidatableObject.Validate(). Это происходит автоматически, когда ваше действие post имеет параметр viewmodel. ModelState.IsValid ничего не делает. Скорее, он просто сообщает, не имеет ли какой-либо элемент в коллекции ModelStateModelErrorCollection.

+0

Я всегда задумывался об этом. Независимо от того, была ли автоматическая авторизация в DefaultModelBinder, или если ModelState.IsValid проверил некоторое скрытое свойство '_hadBeenValidated' и вызвало проверку, если' _hasBeenValidated == false'. –

+2

Описанное поведение не совсем реально: см. Http://stackoverflow.com/questions/8153602/ivalidatableobject-validate-combined-with-dataannotations – Diego

Смежные вопросы