Aspnetcore: IValidatableObject.Validate Chamado somente se as regras de validação definidas por atributo forem aprovadas?

Criado em 11 jan. 2017  ·  3Comentários  ·  Fonte: dotnet/aspnetcore

Olá,

Eu tenho um objeto com uma propriedade [Required] -decorada que implementa IValidatableObject . Durante a vinculação do modelo, se a propriedade necessária for nula, o método Validate() do objeto nunca é chamado. Validate() só é chamado se a validação configurada por atributo for aprovada?

No meu caso, se um usuário enviar um formulário com erros de validação, ele verá primeiro uma mensagem sobre o campo ausente. Então, uma vez que o erro foi resolvido e o formulário reenviado, eles são apresentados com uma lista adicional de erros - desta vez, produzida por Validate() . Existe uma maneira de fazer com que todas as validações ocorram ao mesmo tempo, de forma que o usuário veja uma lista de _todos_ os erros que precisam de sua atenção ao enviar o formulário pela primeira vez?

Obrigado,
Ben

Versões: ASP.Net Core 1.1.0 / .Net 4.6.1

Código de exemplo

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

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

_Do 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);
  }

  // ...
}

Se o usuário não preencher o campo obrigatório, verá uma mensagem de erro sobre isso, mas não verá as outras mensagens de erro que Validate () pode adicionar.

Todos 3 comentários

Este problema está sendo resolvido porque não é atualizado há 3 meses.

Pedimos desculpas se isso causar algum inconveniente. Pedimos que, se você ainda estiver enfrentando esse problema, registre um novo problema com informações atualizadas e nós investigaremos.

Estou experimentando esse comportamento também no Asp.Net Core 2.0, com uma biblioteca de referência contendo um IValidatableObject direcionado ao .Net Standard 2.0.
Não é até que todas as validações [Required] sejam satisfeitas que as validações personalizadas em Validate() são executadas. Em outras palavras, tenho que postar um objeto no meu controlador com todos os campos obrigatórios antes que qualquer outra coisa seja relatada no modelstate.
O modelstate parece se importar primeiro com o requerido, depois com todo o resto. Eu não tentei outros atributos de validação padrão como [StringLength()] .

Este é um bug realmente irritante. Por que fechá-lo?

É difícil arquitetar coisas e dizer às pessoas que as anotações de dados funcionam, então você descobre que IValidatableObject.Validate é executado conforme descrito acima. É um problema e DEVE ser reaberto.

Enquanto isso, tenho que lidar com programadores que acham que isso é uma boa programação:
Lista pública estáticaValidateUpdateDates (comando ICommand)
{
var newErrors = nova 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."));
        }
Esta página foi útil?
0 / 5 - 0 avaliações

Questões relacionadas

BrennanConroy picture BrennanConroy  ·  3Comentários

githubgitgit picture githubgitgit  ·  3Comentários

mj1856 picture mj1856  ·  3Comentários

FourLeafClover picture FourLeafClover  ·  3Comentários

dotNETSanta picture dotNETSanta  ·  3Comentários