2010-09-19 4 views
15

so nach GuIValidatableObject.Validate() soll aufgerufen werden, wenn ein Controller-Modell, es ist bestätigt (dh vor ModelState.IsValid) aber einfach macht das Modell IValidatableObject implementieren nicht zu funktionieren scheint, weil Validate(..) nicht genannt Bekommen .ModelState.IsValid vs IValidateableObject in MVC3

Wer weiß, ob es noch etwas gibt, das ich anschließen muss, um das zu funktionieren?

EDIT:

Hier ist der Code wie angefordert.

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

Die Aktion. (Ich mache nichts besonderes im 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); 
} 

ich einen Haltepunkt in der ersten Zeile von LoginModel.Validate() und es scheint nicht getroffen werden.

+0

Ihr Code sieht gut aus. Genau wie es sollte. Nur ein Punkt von Interesse, aber haben Sie ein doppeltes Modell? Ich weiß, dass ich ein Ansichtsmodell und ein DB-Modell für jedes Objekt habe. Könnte Ihr Controller auf das falsche Modell verweisen? – Buildstarted

+2

Auch eine Randnotiz: Sie sollten definitiv nur einen Fehler zurückgeben, wenn der Benutzername oder das Passwort ungültig ist und keine eindeutigen Fehler. Dies dient nur der Sicherheit, da ich jedes Feld einzeln testen kann, um einen Benutzernamen zu finden und dann das Passwort für diesen Benutzer zu bearbeiten. Es ist nicht erforderlich, aber es ist eine gute Idee :) – Buildstarted

+0

Sie könnten 'yield return DataContext ...' anstelle einer neuen Liste verwenden. Es wäre schöner und schneller. – pipedreambomb

Antwort

18

Es gibt nichts mehr als das Sie es nur dem Modell hinzufügen müssen, das Sie validieren. Hier ist ein Beispiel für die Validierung

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

Und Ihre Controller verwenden würde dieses Modell

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

Hoffnung, das hilft. Andere Anforderungen sind. Net 4 und Daten Annotationen - die Sie offensichtlich nur für ivalidatableObjekt benötigen. Veröffentlichen Sie alle Probleme und wir werden sehen, ob wir sie nicht lösen können - wie zum Beispiel Ihr Modell und Ihren Controller ... Sie könnten etwas verpassen.

+23

Sie haben Recht, der einzige Vorbehalt ist, dass Validate nie aufgerufen wird, wenn Sie Validierungsattribute haben, die dazu führen, dass das Modell ungültig ist. Das war mein Problem. –

+0

Ah, wie interessant. Dank dafür. – Buildstarted

+2

Dieser Vorbehalt erscheint mir als eine sehr praktische Sache zu wissen :) +1 zu beiden –

6

Validierung mit dem DefaultModelBinder ist ein zweistufiger Prozess. Zuerst werden Data Annotations validiert. Dann (und nur wenn die Validierung der Datenannotation zu null Fehlern führte) wird IValidatableObject.Validate() aufgerufen. Dies alles geschieht automatisch, wenn Ihre Post-Aktion einen Viewmodel-Parameter hat. ModelState.IsValid tut nichts als solches. Stattdessen wird nur gemeldet, ob ein Artikel in der ModelState Sammlung nicht leer ist ModelErrorCollection.

+0

Ich habe mich immer gefragt. Ob die Validierung automatisch im DefaultModelBinder aufgerufen wurde oder ob ModelState.IsValid eine versteckte '_hadBeenValidated'-Eigenschaft überprüft und validate aufgerufen hat, wenn' _hasBeenValidated == false'. –

+2

Das beschriebene Verhalten ist nicht genau das richtige: siehe http://stackoverflow.com/questions/8153602/ivalidatableobject-validate-combined-with-dataannotations – Diego