web-dev-qa-db-fra.com

Validation MVC inférieure/supérieure aux autres valeurs

Quelle est la meilleure façon de valider un modèle dans MVC.Net pour lequel je souhaite accepter un minimum/maximum?.

Pas de valeurs individuelles min/max pour un champ. Mais séparez les champs pour qu'un utilisateur spécifie un minimum/maximum.

public class FinanceModel{
   public int MinimumCost {get;set;}
   public int MaximumCost {get;set;}
}

Je dois donc veiller à ce que MinimumCost soit toujours inférieur au coût maximal.

24
Ben Ford

Vous pouvez utiliser un attribut de validation personnalisé voici mon exemple avec dates ..__ Mais vous pouvez aussi l'utiliser avec ints.

Tout d'abord, voici le modèle:

public DateTime Beggining { get; set; }

    [IsDateAfterAttribute("Beggining", true, ErrorMessageResourceType = typeof(LocalizationHelper), ErrorMessageResourceName = "PeriodErrorMessage")]
    public DateTime End { get; set; }

Et voici l'attribut lui-même:

public sealed class IsDateAfterAttribute : ValidationAttribute, IClientValidatable
{
    private readonly string testedPropertyName;
    private readonly bool allowEqualDates;

    public IsDateAfterAttribute(string testedPropertyName, bool allowEqualDates = false)
    {
        this.testedPropertyName = testedPropertyName;
        this.allowEqualDates = allowEqualDates;
    }

    protected override ValidationResult IsValid(object value, ValidationContext validationContext)
    {
        var propertyTestedInfo = validationContext.ObjectType.GetProperty(this.testedPropertyName);
        if (propertyTestedInfo == null)
        {
            return new ValidationResult(string.Format("unknown property {0}", this.testedPropertyName));
        }

        var propertyTestedValue = propertyTestedInfo.GetValue(validationContext.ObjectInstance, null);

        if (value == null || !(value is DateTime))
        {
            return ValidationResult.Success;
        }

        if (propertyTestedValue == null || !(propertyTestedValue is DateTime))
        {
            return ValidationResult.Success;
        }

        // Compare values
        if ((DateTime)value >= (DateTime)propertyTestedValue)
        {
            if (this.allowEqualDates && value == propertyTestedValue)
            {
                return ValidationResult.Success;
            }
            else if ((DateTime)value > (DateTime)propertyTestedValue)
            {
                return ValidationResult.Success;
            }
        }

        return new ValidationResult(FormatErrorMessage(validationContext.DisplayName));
    }

    public IEnumerable<ModelClientValidationRule> GetClientValidationRules(ModelMetadata metadata, ControllerContext context)
    {
        var rule = new ModelClientValidationRule
        {
            ErrorMessage = this.ErrorMessageString,
            ValidationType = "isdateafter"
        };
        rule.ValidationParameters["propertytested"] = this.testedPropertyName;
        rule.ValidationParameters["allowequaldates"] = this.allowEqualDates;
        yield return rule;
    }
22
Boranas

Il existe un package NuGet appelé Foolproof qui fournit ces annotations pour vous. Cela dit - écrire un attribut personnalisé est à la fois assez facile et une bonne pratique.

Utiliser Foolproof ressemblerait à ceci:

public class FinanceModel{
   public int MinimumCost {get;set;}

   [GreaterThan("MinimumCost")]
   public int MaximumCost {get;set;}
}
27
Matthew

Pour la validation côté client à l'aide des paramètres allowEqualDates et propertyTested (complément à la réponse Boranas ci-dessus mais trop long pour un commentaire):

// definition for the isdateafter validation rule
if ($.validator && $.validator.unobtrusive) {
    $.validator.addMethod('isdateafter', function (value, element, params) {
        value = Date.parse(value);
        var otherDate = Date.parse($(params.compareTo).val());
        if (isNaN(value) || isNaN(otherDate))
            return true;
        return value > otherDate || (value == otherDate && params.allowEqualDates);
    });
    $.validator.unobtrusive.adapters.add('isdateafter', ['propertytested', 'allowequaldates'], function (options) {
        options.rules['isdateafter'] = {
            'allowEqualDates': options.params['allowequaldates'],
            'compareTo': '#' + options.params['propertytested']
        };
        options.messages['isdateafter'] = options.message;
    });
}

Plus d'informations: validation non intrusive , validation jQuery

6
Nicolas Galler

Dans VB pour les entiers:

MOD&EGRAVE;LE

<UtilController.IsIntegerGreatherOrEqualThan("PropertyNameNumberBegins", "PeriodErrorMessage")>
        Public Property PropertyNameNumberEnds As Nullable(Of Integer)

VALIDATION 

Public Class IsIntegerGreatherOrEqualThan
        Inherits ValidationAttribute

        Private otherPropertyName As String
        Private errorMessage As String

        Public Sub New(ByVal otherPropertyName As String, ByVal errorMessage As String)
            Me.otherPropertyName = otherPropertyName
            Me.errorMessage = errorMessage
        End Sub

        Protected Overrides Function IsValid(thisPropertyValue As Object, validationContext As ValidationContext) As ValidationResult

            Dim otherPropertyTestedInfo = validationContext.ObjectType.GetProperty(Me.otherPropertyName)

            If (otherPropertyTestedInfo Is Nothing) Then
                Return New ValidationResult(String.Format("unknown property {0}", Me.otherPropertyName))
            End If

            Dim otherPropertyTestedValue = otherPropertyTestedInfo.GetValue(validationContext.ObjectInstance, Nothing)

            If (thisPropertyValue Is Nothing) Then
                Return ValidationResult.Success
            End If

            ''  Compare values
            If (CType(thisPropertyValue, Integer) >= CType(otherPropertyTestedValue, Integer)) Then
                Return ValidationResult.Success
            End If

            ''  Wrong
            Return New ValidationResult(errorMessage)
        End Function
    End Class
1
Dani