web-dev-qa-db-fra.com

ASP.NET MVC: Validation personnalisée par DataAnnotation

J'ai un modèle avec 4 propriétés qui sont de type chaîne. Je sais que vous pouvez valider la longueur d'une propriété unique en utilisant l'annotation StringLength. Cependant, je veux valider la longueur des 4 propriétés combinées.

Quelle est la méthode MVC pour ce faire avec l'annotation de données?

Je pose la question parce que je suis nouveau chez MVC et que je veux le faire correctement avant de créer ma propre solution.

104

Vous pouvez écrire un attribut de validation personnalisé:

public class CombinedMinLengthAttribute: ValidationAttribute
{
    public CombinedMinLengthAttribute(int minLength, params string[] propertyNames)
    {
        this.PropertyNames = propertyNames;
        this.MinLength = minLength;
    }

    public string[] PropertyNames { get; private set; }
    public int MinLength { get; private set; }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var properties = this.PropertyNames.Select(validationContext.ObjectType.GetProperty);
        var values = properties.Select(p => p.GetValue(validationContext.ObjectInstance, null)).OfType<string>();
        var totalLength = values.Sum(x => x.Length) + Convert.ToString(value).Length;
        if (totalLength < this.MinLength)
        {
            return new ValidationResult(this.FormatErrorMessage(validationContext.DisplayName));
        }
        return null;
    }
}

et alors vous pourriez avoir un modèle de vue et décorer une de ses propriétés avec elle:

public class MyViewModel
{
    [CombinedMinLength(20, "Bar", "Baz", ErrorMessage = "The combined minimum length of the Foo, Bar and Baz properties should be longer than 20")]
    public string Foo { get; set; }
    public string Bar { get; set; }
    public string Baz { get; set; }
}
168
Darin Dimitrov

Modèle auto validé

Votre modèle doit implémenter une interface IValidatableObject. Mettez votre code de validation dans la méthode Validate:

public class MyModel : IValidatableObject
{
    public string Title { get; set; }
    public string Description { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Title == null)
            yield return new ValidationResult("*", new [] { nameof(Title) });

        if (Description == null)
            yield return new ValidationResult("*", new [] { nameof(Description) });
    }
}

Veuillez noter qu'il s'agit d'une validation côté serveur. Cela ne fonctionne pas du côté client. Votre validation ne sera effectuée qu'après la soumission du formulaire.

89
Andrei

ExpressiveAnnotations vous donne une telle possibilité:

[Required]
[AssertThat("Length(FieldA) + Length(FieldB) + Length(FieldC) + Length(FieldD) > 50")]
public string FieldA { get; set; }
22
jwaliszko

Contexte:

Des validations de modèles sont nécessaires pour garantir que les données reçues que nous recevons sont valides et correctes, afin que nous puissions effectuer le traitement suivant avec ces données. Nous pouvons valider un modèle dans une méthode d'action. Les attributs de validation intégrés sont Compare, Range, RegularExpression, Required, StringLength. Cependant, nous pouvons avoir des scénarios dans lesquels nous avons besoin d'attributs de validation autres que ceux intégrés.

Attributs de validation personnalisés

public class EmployeeModel 
{
    [Required]
    [UniqueEmailAddress]
    public string EmailAddress {get;set;}
    public string FirstName {get;set;}
    public string LastName {get;set;}
    public int OrganizationId {get;set;}
}

Pour créer un attribut de validation personnalisé, vous devez dériver cette classe de ValidationAttribute.

public class UniqueEmailAddress : ValidationAttribute
{
    private IEmployeeRepository _employeeRepository;
    [Inject]
    public IEmployeeRepository EmployeeRepository
    {
        get { return _employeeRepository; }
        set
        {
            _employeeRepository = value;
        }
    }
    protected override ValidationResult IsValid(object value,
                        ValidationContext validationContext)
    {
        var model = (EmployeeModel)validationContext.ObjectInstance;
        if(model.Field1 == null){
            return new ValidationResult("Field1 is null");
        }
        if(model.Field2 == null){
            return new ValidationResult("Field2 is null");
        }
        if(model.Field3 == null){
            return new ValidationResult("Field3 is null");
        }
        return ValidationResult.Success;
    }
}

J'espère que cela t'aides. À votre santé !

Références

9
Yasser

Pour améliorer la réponse de Darin, cela peut être un peu plus court:

public class UniqueFileName : ValidationAttribute
{
    private readonly NewsService _newsService = new NewsService();

    public override bool IsValid(object value)
    {
        if (value == null) { return false; }

        var file = (HttpPostedFile) value;

        return _newsService.IsFileNameUnique(file.FileName);
    }
}

Modèle:

[UniqueFileName(ErrorMessage = "This file name is not unique.")]

Notez qu'un message d'erreur est requis, sinon l'erreur sera vide.

9
Jamie

Un peu tard pour répondre, mais pour qui cherche. Vous pouvez facilement le faire en utilisant une propriété supplémentaire avec l'annotation de données:

public string foo { get; set; }
public string bar { get; set; }

[MinLength(20, ErrorMessage = "too short")]
public string foobar 
{ 
    get
    {
        return foo + bar;
    }
}

C'est tout ce que c'est aussi ça vraiment. Si vous voulez vraiment afficher à un endroit spécifique l'erreur de validation, vous pouvez l'ajouter à votre vue:

@Html.ValidationMessage("foobar", "your combined text is too short")

cela peut être utile si vous souhaitez effectuer la localisation.

J'espère que cela t'aides!

1
Leo Muller