ModelState.IsValid vs IValidateableObject in MVC3

2019-04-04 02:07发布

问题:

so according to Gu IValidatableObject.Validate() should get called when a controller validates it's model (i.e. before ModelState.IsValid) however simply making the model implement IValidatableObject doesn't seem to work, because Validate(..) doesn't get called.

Anyone know if there is something else I have to wire up to get this to work?

EDIT:

Here is the code as requested.

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

The action. ( I don't do anything special in the Controller...)

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

I set a break point on the first line of LoginModel.Validate() and it doesn't seem to get hit.

回答1:

There isn't anything more than that you just have to add it to the model you're validating. Here's an example of validation

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

And your controller would use this model

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

Hope this helps. Other requirements are .net 4 and data annotations - which you obviously need jsut for ivalidatableobject. Post any issues and we'll see if we can't resolve them - like post your model and your controller...you might be missing something.



回答2:

Validation using the DefaultModelBinder is a two stage process. First, Data Annotations are validated. Then (and only if the data annotations validation resulted in zero errors), IValidatableObject.Validate() is called. This all takes place automatically when your post action has a viewmodel parameter. ModelState.IsValid doesn't do anything as such. Rather it just reports whether any item in the ModelState collection has non-empty ModelErrorCollection.