2011-05-24 4 views
17

Je suis nouveau avec l'annotation de données. Je voudrais savoir s'il est possible (et comment) d'ajouter de la validation de façon dynamique. Il est très complet pour expliquer pourquoi, mais j'ai un ViewModel qui reçoit et objecte lorsqu'il est créé. Dans cet objet je dois vérifier certaines propriétés et en fonction de sa valeur je devrais avoir ou non des validations.ASP.NET MVC 3 Données Annotation: Ajouter dynamiquement la validation

Un exemple:

public class ProfileViewModel 
{ 
    [Required(ErrorMessage = "The field {0} is required")] 
    [Display(Name = "Client Code")] 
    public int ClientCode { get; set; } 

    [Required(ErrorMessage = "The field {0} is required")] 
    [StringLength(100, ErrorMessage = "The field {0} must have up to 100 characters.")] 
    [Display(Name = "Company")] 
    public string Company { get; set; } 

    [StringLength(50, ErrorMessage = "The field {0} must have up to 50 characters.")] 
    [Display(Name = "Name")] 
    public string Name { get; set; } 

    [StringLength(50, ErrorMessage = "The field {0} must have up to 50 characters.")] 
    [Display(Name = "LastName")] 
    public string LastName { get; set; } 

    public ProfileViewModel(User usr) 
    { 
     if (usuario.ClientCode != null) 
     { 
      ClientCode = Convert.ToInt32(usr.ClientCode); 
     } 
     else 
     { 
      //ClientCode and Company are not yet required. 
      //Name and LastName are now required. 
     } 
     Company = usr.Company; 
     Name = usr.Name; 
     LastName = usr.LastName; 
    } 
} 

Répondre

9

Je pense que la façon la plus simple de faire ce que je voulais met en œuvre IValidatableObject:

public class Product : IValidatableObject 
{ 
    public int Prop1 { get; set; } 
    public int Prop2 { get; set; } 

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) 
    { 
     if (Prop1 < Prop2) 
      yield return new ValidationResult("Property 1 can't be less than Property 2"); 
    } 
} 

Voir aussi: Class-Level Model Validation with ... ASP.NET MVC 3

+1

Le problème est, cela n'ajoute pas la validation côté client. Donc, si vous utilisez déjà la validation côté client en fonction des attributs, cela provoque une expérience utilisateur incohérente. MS a eu tout faux en liant la validation aux attributs. – xr280xr

+0

Vous avez raison. Cela n'ajoute pas de validation côté client. Si vous en avez besoin, je crois que le meilleur moyen serait d'écrire votre propre script pour ajouter cette validation. – Diego

5

personnalisés Attributs:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true, Inherited = true)] 
public class CustomRequiredIfAttribute : CustomAttribute 
{ 
    private RequiredAttribute innerAttribute = new RequiredAttribute(); 
    public string DependentProperty { get; set; } 
    public object TargetValue { get; set; } 

    public CustomRequiredIfAttribute() 
    { 
    } 

    public CustomRequiredIfAttribute(string dependentProperty, object targetValue) 
     : base() 
    { 
     this.DependentProperty = dependentProperty; 
     this.TargetValue = targetValue; 
    } 

    public override bool IsValid(object value) 
    { 
     return innerAttribute.IsValid(value); 
    } 
} 


sur mesure RequiredIfValidator

using System; 
using System.Collections.Generic; 
using System.Web.Mvc; 

namespace Custom.Web.Validation 
{ 
    public class RequiredIfValidator : DataAnnotationsModelValidator<CustomRequiredIfAttribute> 
    { 
     public RequiredIfValidator(ModelMetadata metadata, ControllerContext context, CustomRequiredIfAttribute attribute) 
      : base(metadata, context, attribute) 
     { 
     } 

     public override IEnumerable<ModelClientValidationRule> GetClientValidationRules() 
     { 
      return base.GetClientValidationRules(); 
     } 

     public override IEnumerable<ModelValidationResult> Validate(object container) 
     { 
      // get a reference to the property this validation depends upon 
      var field = Metadata.ContainerType.GetProperty(Attribute.DependentProperty); 

      if (field != null) 
      { 
       // get the value of the dependent property 
       object value = field.GetValue(container, null); 

       // compare the value against the target value 
       if (this.IsEqual(value) || (value == null && Attribute.TargetValue == null)) 
       { 
        // match => means we should try validating this field 
        if (!Attribute.IsValid(Metadata.Model)) 
        { 
         // validation failed - return an error 
         yield return new ModelValidationResult { Message = ErrorMessage }; 
        } 
       } 
      } 
     } 

     private bool IsEqual(object dependentPropertyValue) 
     { 
      bool isEqual = false; 

      if (Attribute.TargetValue != null && Attribute.TargetValue.GetType().IsArray) 
      { 
       foreach (object o in (Array)Attribute.TargetValue) 
       { 
        isEqual = o.Equals(dependentPropertyValue); 
        if (isEqual) 
        { 
         break; 
        } 
       } 
      } 
      else 
      { 
       isEqual = Attribute.TargetValue.Equals(dependentPropertyValue); 
      } 

      return isEqual; 
     } 
    } 
} 


Inscrivez-DataAnnotationsModelValidatorProvider personnalisé

DataAnnotationsModelValidatorProvider.RegisterAdapter(typeof(CustomRequiredIfAttribute), typeof(RequiredIfValidator)); 


Utilisez cette CustomRequiredIf dans le ViewModel

[CustomRequiredIf("CategoryId", 3, ErrorMessageResourceName = GlobalResourceLiterals.AccountGroup_Required)] 
public string AccountGroup { get; set; } 
Questions connexes