Aspnetcore: IValidatableObject.Validate ¿Solo se llama si se aprueban las reglas de validación definidas por atributos?

Creado en 11 ene. 2017  ·  3Comentarios  ·  Fuente: dotnet/aspnetcore

Hola,

Tengo un objeto con una propiedad [Required] decorada que implementa IValidatableObject . Durante el enlace del modelo, si la propiedad requerida es nula, nunca se llama al método Validate() del objeto. ¿Se llama a Validate() solo si pasa la validación configurada por atributos?

En mi caso, si un usuario envía un formulario con errores de validación, primero ve un mensaje sobre el campo que falta. Luego, una vez que se ha resuelto ese error y se ha vuelto a enviar el formulario, se les presenta una lista adicional de errores, esta vez, producida por Validate() . ¿Hay alguna manera de activar toda la validación para que se produzca al mismo tiempo, de modo que al usuario se le presente una lista de _todos_ los errores que necesitan su atención cuando envía el formulario por primera vez?

Gracias,
Ben

Versiones: ASP.Net Core 1.1.0 / .Net 4.6.1

Código de ejemplo

public class Import : IValidatableObject
{
  [Required]
  public IFormFile File { get; set; }

  public IEnumerable<ValidationResult> Validate(ValidationContext validationContext) { /* ... */ }
  //...
}

_Desde el controlador: _

[HttpPost, ActionName("Index")]
[ValidateAntiForgeryToken]
public async Task<IActionResult> IndexPost()
{
  var model = new ViewModels.Import();

  var bindingResult = await TryUpdateModelAsync(model, "", i => i.StartDate, i => i.EndDate, i => i.ImportTypeId, i => i.File);
  if (!bindingResult || ModelState.ValidationState != ModelValidationState.Valid) {
    return View(model);
  }

  // ...
}

Si el usuario no completa el campo requerido, verá un mensaje de error al respecto, pero no verá los otros mensajes de error que Validate () podría agregar.

Todos 3 comentarios

Este problema se está cerrando porque no se ha actualizado en 3 meses.

Pedimos disculpas si esto le causa algún inconveniente. Le pedimos que si todavía tiene este problema, registre un nuevo problema con información actualizada e investigaremos.

También estoy experimentando este comportamiento en Asp.Net Core 2.0, con una biblioteca referenciada que contiene un IValidatableObject destino .Net Standard 2.0.
No es hasta que todas las validaciones [Required] están satisfechas que se ejecutan las validaciones personalizadas en Validate() . En otras palabras, tengo que publicar un objeto en mi controlador con todos los campos obligatorios antes de que se informe cualquier otra cosa en modelstate.
El modelstate parece preocuparse por lo requerido primero, luego todo lo demás. No he probado otros atributos de validación estándar como [StringLength()] .

Este es un error realmente molesto. ¿Por qué cerrarlo?

Es difícil diseñar cosas y decirle a la gente que las anotaciones de datos funcionan, entonces encuentras IValidatableObject.Validate se ejecuta como se indica arriba. Es un problema y DEBERÍA reabrirse.

Mientras tanto, tengo que lidiar con programadores que piensan que esta es una buena programación:
lista estática públicaValidateUpdateDates (comando ICommand)
{
var newErrors = nueva lista();

        var validator = new DataAnnotationsValidator();
        var results = new List<ValidationResult>();
        var isValid = validator.TryValidate(command, out results);

        if (!(command is UpdatePromotionCommand cpc))
            return newErrors;

        newErrors.AddRange(ValidateDatesAreValidFormat(cpc));

        if (
          !string.IsNullOrEmpty(cpc.PurchasePeriodStart)
          && !string.IsNullOrEmpty(cpc.PurchasePeriodEnd)
          && DateTime.TryParse(cpc.PurchasePeriodStart, out DateTime purchasePeriodStartDate)
          && DateTime.TryParse(cpc.PurchasePeriodEnd, out DateTime purchasePeriodEndDate)
          && purchasePeriodStartDate > purchasePeriodEndDate
        )
        {
            newErrors.Add(new ECError("Purchase Period End cannot be before Purchase Period Start."));
        }

        if (
          !string.IsNullOrEmpty(cpc.ClaimPeriodStart)
          && !string.IsNullOrEmpty(cpc.ClaimPeriodEnd)
          && DateTime.TryParse(cpc.ClaimPeriodStart, out DateTime claimPeriodStartDate)
          && DateTime.TryParse(cpc.ClaimPeriodEnd, out DateTime claimPeriodEndDate)
          && claimPeriodStartDate > claimPeriodEndDate
        )
        {
            newErrors.Add(new ECError("Claim Period End cannot be before Claim Period Start."));
        }
¿Fue útil esta página
0 / 5 - 0 calificaciones