web-dev-qa-db-fra.com

Validation du modèle MVC pour la date

Existe-t-il une validation par défaut pour MVC 5, dans laquelle je peux définir les valeurs min et max de date?

Dans mon modèle, je veux la validation de la date

    public class MyClass
    {               
        [Required(ErrorMessage="Start date and time cannot be empty")]
        //validate:Must be greater than current date
        [DataType(DataType.DateTime)]
        public DateTime StartDateTime { get; set; }

        [Required(ErrorMessage="End date and time cannot be empty")]
        //validate:must be greater than StartDate
        [DataType(DataType.DateTime)]
        public DateTime EndDateTime { get; set; }            
    }

Ps: Selon ce Site Web Asp.Net , l'utilisation du validateur Range pour DateTime pose un problème et n'est pas recommandée.

Remarque: la validation jQuery ne fonctionne pas avec l'attribut Range et DateTime. Par exemple, le code suivant affichera toujours une erreur de validation côté client, même lorsque la date est dans la plage spécifiée:

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]

Vous devrez désactiver la validation de date jQuery pour utiliser l'attribut Range avec DateTime. Il est généralement déconseillé de compiler des dates précises dans vos modèles. Il est donc déconseillé d'utiliser les attributs Range et DateTime.

Je sais aussi qu'il existe des packages Nuget tels que Validation Fluent et Foolproof qui permet de valider et de vérifier si une date est supérieure à une autre, mais je voulais savoir si, par défaut il y a quelque chose à vérifier les valeurs min et max de la date.

D'après ce que j'ai vu dans Quoi de neuf dans MVC 5.1 _, il existe un support pour la validation MaxLength et MinLength .

17
Cybercop

Il n'est pas nécessaire de désactiver la validation de la date de jQuery (et cela pourrait causer d'autres problèmes). Il vous suffit de remplacer la méthode range du $.validator.

Par défaut, il fonctionne avec des valeurs numériques (puis revient à une comparaison de chaîne), vous pouvez donc ajouter le script suivant (après jquery.validate.js et jquery.validate.unobtrusive.js, mais pas encapsulé dans $(document).ready.

$.validator.methods.range = function(value, element, param) {
    if ($(element).attr('data-val-date')) {
        var min = $(element).attr('data-val-range-min');
        var max = $(element).attr('data-val-range-max');
        var date = new Date(value).getTime();
        var minDate = new Date(min).getTime();
        var maxDate = new Date(max).getTime();
        return this.optional(element) || (date >= minDate && date <= maxDate);
    }
    // use the default method
    return this.optional( element ) || ( value >= param[ 0 ] && value <= param[ 1 ] );
};

Ensuite, vous pouvez utiliser la RangeAttribute sur votre propriété

[Range(typeof(DateTime), "1/1/1966", "1/1/2020")]
public DateTime Date { get; set; }
7
user3559349

Je le ferais avec l'interface IValidatableObject de System.ComponentModel.DataAnnotations, ce qui vous permet d'ajouter des règles de validation supplémentaires permettant de vérifier davantage. Ajoutez l'interface à votre classe, puis implémentez la méthode Validate, dans laquelle vous pouvez comparer StartDateTime à la date/heure actuelle, et également comparer EndDateTime à StartDateTime, par exemple.

public class MyClass : IValidatableObject
{               
    [Required(ErrorMessage="Start date and time cannot be empty")]
    //validate:Must be greater than current date
    [DataType(DataType.DateTime)]
    public DateTime StartDateTime { get; set; }

    [Required(ErrorMessage="End date and time cannot be empty")]
    //validate:must be greater than StartDate
    [DataType(DataType.DateTime)]
    public DateTime EndDateTime { get; set; }       

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        List<ValidationResult> results = new List<ValidationResult>();

        if (StartDateTime < DateTime.Now)
        {
            results.Add(new ValidationResult("Start date and time must be greater than current time", new []{"StartDateTime"}));
        }

        if (EndDateTime <= StartDateTime)
        {
            results.Add(new ValidationResult("EndDateTime must be greater that StartDateTime", new [] {"EndDateTime"}));
        }

        return results;
    }     
}

Le seul inconvénient potentiel est que Validate exécute côté serveur, pas dans la validation jQuery.

5
PhilPursglove

J'utilise normalement cette solution lorsque je veux valider quelque chose sur le serveur ..__ Je sais que vous pouvez compter sur le modèle de validation utilisé par MVC, mais lorsque j'effectue les validations, j'essaie d'utiliser un projet séparé au cas où besoin de faire des tests unitaires pour eux. Disons que vous avez deux applications, une Desktop et un Web, puis les deux peuvent partager le ValidationProject au lieu de répéter le code dans les deux applications pour le même "View"/"Screen". L'idée ici est d'isoler le projet de validation en tant que projet indépendant de votre solution.

Pour que vous puissiez télécharger le projet FluentValidation depuis NuGet, FluentValidation utilise des règles dans le constructeur, vous pouvez voir la documentation ici https://github.com/JeremySkinner/FluentValidation/wiki

Votre règle Date peut être utilisée de cette façon, par exemple, vous pouvez y définir des règles pour votre valeur minimale et votre valeur maximale:

public class CustomerValidator: AbstractValidator<Customer> {
  public CustomerValidator() {
                    RuleFor(customer => customer.startDate)
                    .NotNull()
                    .WithMessage("You should select a start date")
                    .Must(d => d.HasValue && d.Value <= DateTime.Today)
                    .WithMessage("The start date should not be greather than current month/year");
  }

Maintenant dans votre manette

[HttpPost]
public ActionResult Index(Customer c)
{
  if(ModelState.IsValid)
  {
    var validator= new CustomerValidator();
    var valResult = validator.Validate(c);

    if (valResult.Errors.Count != 0)
    {
       valResult.Errors.ForEach(x => ModelState.AddModelError(x.PropertyName, x.ErrorMessage));
       return View(vm);
    }

    //Your code here
  }
}
0
Zinov