2011-09-07 1 views
6

Come si creano le proprietà richieste condizionalmente con il framework MVC 3 che funzionerà con Client Side Validation e Convalida lato server quando JS è disabilitato? Ad esempio:MVC 3 Proprietà richieste condizionatamente

public class PersonModel 
{ 
    [Required] // Requried if Location is not set 
    public string Name {get; set;} 
    [Range(1, 5)] // Requried if Location is not set 
    public int Age {get; set;} 

    [Required] // Only required if Name and Age are not set. 
    public string Location {get; set;} 
} 

Le regole in questo esempio sono:

  1. Name e Age sono necessari se Location non è impostato.
  2. Location è necessario solo se Name e Age non sono impostati.
  3. Non importa se Nome, Età e Posizione sono tutti impostati.

Nella vista, ho bisogno del risultato inviato a un Action se Nome/Età sono impostati. E un diverso Action se la Posizione è impostata. Ho provato con 2 moduli separati con diversi Get Url; questo funziona benissimo tranne che le regole di validazione stanno causando problemi. Preferibilmente, vorrei l'uso di 2 azioni Get separata URL del, vale a dire,

@model PersonModel 

@using(Html.BeginForm("Age", "Person", FormMethod.Post)) 
{ 
    @Html.TextBoxFor(x => x.Name) 
    @Html.ValidationMessageFor(x => x.Name) 
    @Html.TextBoxFor(x => x.Age) 
    @Html.ValidationMessageFor(x => x.Age) 
    <input type="submit" value="Submit by Age" /> 
} 

@using(Html.BeginForm("Location", "Person", FormMethod.Post)) 
{ 
    @Html.TextBoxFor(x => x.Location) 
    @Html.ValidationMessageFor(x => x.Location) 
    <input type="submit" value="Submit by Location" /> 
} 

Sulla base della PersonModel sopra, se la posizione è stata presentata, la validazione fallirà poiché il PersonModel si aspetta il nome e l'età per essere impostare pure. E viceversa con Nome/Età.

Dato l'esempio precedente deriso up, come si fa a creare le proprietà condizionale richiesti con l'MVC 3 quadro che lavorano con validazione lato client e lato server di convalida quando JS è disattivato?

risposta

1

È possibile aggiungere una convalida personalizzata al proprio modello o sottoclasse ValidationAttribute o all'implementazione di IValidatableObject.

Il ValidationAttribute consente di aggiungere la convalida lato client in modo relativamente semplice implementando IClientValidatable e registrando un nuovo adattatore e un metodo tramite jQuery. Vedere Perform client side validation for custom attribute.

IValidatableObject è più adatto a requisiti di convalida una tantum dove il riutilizzo non è un'opzione. Porta anche a un codice leggermente più semplice. Sfortunatamente, non esiste un modo semplice per implementare la validazione lato client usando questo metodo.

0

Ho creato il mio discendente RequiredAttribute. Accetta un nome di proprietà booleana, quale dovrebbe essere la condizione della convalida. Nota che questo codice non è pronto per la produzione, manca il controllo degli errori e si potrebbe fare un po 'di raffinazione sul controllo di null.

[Localizable(false),AttributeUsage(AttributeTargets.Property, AllowMultiple = false)] 
public class RequiredIfAttribute : RequiredAttribute 
{ 
    public string BoolProperty { get; private set; } 
    public RequiredIfAttribute(string boolProperty) 
    { 
     BoolProperty = boolProperty; 
    } 

    protected override ValidationResult IsValid(object value, ValidationContext validationContext) 
    { 
     if (!Equals(value, null) || !string.IsNullOrEmpty(value as string)) 
      return ValidationResult.Success; 
     var boolProperty = validationContext.ObjectInstance.GetType().GetProperty(BoolProperty); 
     var boolValue = (bool)boolProperty.GetValue(validationContext.ObjectInstance, null); 
     if (!boolValue) 
      return ValidationResult.Success; 
     return new ValidationResult(FormatErrorMessage(validationContext.DisplayName)); 
    } 
} 

È possibile creare una proprietà di sola lettura per rappresentare la condizione come di seguito. Si noti inoltre che la proprietà Age non può essere "vuota" nel codice. Se vuoi supportarlo, dovresti usare un tipo nullable int (int?) Per quella proprietà.

public class PersonModel 
{ 
    // helper properties 
    public bool LocationNotSet { get { return string.IsNullOrEmpty(Location); } }  
    public bool NameAndAgeNotSet { get { return string.IsNullOrEmpty(Name) && Age <= 0; } } 

    [RequiredIf("LocationNotSet")] // Requried if Location is not set 
    public string Name {get; set;} 
    [Range(1, 5), RequiredIf("LocationNotSet")] // Requried if Location is not set 
    public int Age {get; set;} 

    [RequiredIf("NameAndAgeNotSet")] // Only required if Name and Age are not set. 
    public string Location {get; set;} 
}