Validação de modelo no ASP.NET Core MVC e Razor PagesModel validation in ASP.NET Core MVC and Razor Pages

Este artigo explica como validar a entrada do usuário em um aplicativo em ASP.NET Core MVC ou Razor Pages.This article explains how to validate user input in an ASP.NET Core MVC or Razor Pages app.

Exibir ou baixar um código de exemplo (como baixar).View or download sample code (how to download).

Estado do modeloModel state

O estado do modelo representa erros que vêm de dois subsistemas: model binding e validação de modelo.Model state represents errors that come from two subsystems: model binding and model validation. Erros que se originam de model binding geralmente são erros de conversão de dados (por exemplo, um "x" é inserido em um campo que espera um inteiro).Errors that originate from model binding are generally data conversion errors (for example, an "x" is entered in a field that expects an integer). A validação do modelo ocorre após o model binding e relata os erros em que os dados não estão em conformidade com as regras de negócio (por exemplo, um 0 é inserido em um campo que espera uma classificação entre 1 e 5).Model validation occurs after model binding and reports errors where the data doesn't conform to business rules (for example, a 0 is entered in a field that expects a rating between 1 and 5).

O model binding e a validação ocorrem antes da execução de uma ação do controlador ou de um método de manipulador do Razor Pages.Both model binding and validation occur before the execution of a controller action or a Razor Pages handler method. Nos aplicativos Web, é responsabilidade do aplicativo inspecionar ModelState.IsValid e reagir adequadamente.For web apps, it's the app's responsibility to inspect ModelState.IsValid and react appropriately. Geralmente, os aplicativos Web reexibem a página com uma mensagem de erro:Web apps typically redisplay the page with an error message:

public async Task<IActionResult> OnPostAsync()
{
    if (!ModelState.IsValid)
    {
        return Page();
    }

    _context.Movie.Add(Movie);
    await _context.SaveChangesAsync();

    return RedirectToPage("./Index");
}

Os controladores de API Web não precisarão verificar ModelState.IsValid se eles tiverem o atributo [ApiController].Web API controllers don't have to check ModelState.IsValid if they have the [ApiController] attribute. Nesse caso, uma resposta automática HTTP 400 contendo detalhes do problema será retornada quando o estado do modelo for inválido.In that case, an automatic HTTP 400 response containing issue details is returned when model state is invalid. Para obter mais informações, veja Respostas automáticas HTTP 400.For more information, see Automatic HTTP 400 responses.

Executar validação novamenteRerun validation

A validação é automática, mas talvez seja necessário repeti-la manualmente.Validation is automatic, but you might want to repeat it manually. Por exemplo, você pode calcular um valor para uma propriedade e executar novamente a validação após a configuração da propriedade com o valor computado.For example, you might compute a value for a property and want to rerun validation after setting the property to the computed value. Para reexecutar a validação, chame o método TryValidateModel, conforme mostrado aqui:To rerun validation, call the TryValidateModel method, as shown here:

var movie = new Movie
{
    Title = title,
    Genre = genre,
    ReleaseDate = modifiedReleaseDate,
    Description = description,
    Price = price,
    Preorder = preorder,
};

TryValidateModel(movie);

if (ModelState.IsValid)
{
    _context.AddMovie(movie);
    _context.SaveChanges();

    return RedirectToAction(actionName: nameof(Index));
}

return View(movie);

Atributos de validaçãoValidation attributes

Os atributos de validação permitem que você especifique regras de validação para propriedades do modelo.Validation attributes let you specify validation rules for model properties. O exemplo a seguir do aplicativo de exemplo mostra uma classe de modelo que é anotada com atributos de validação.The following example from the sample app shows a model class that is annotated with validation attributes. O atributo [ClassicMovie] é um atributo de validação personalizado e os outros são atributos internos.The [ClassicMovie] attribute is a custom validation attribute and the others are built-in. (O [ClassicMovie2] não está exibido e mostra uma maneira alternativa de implementar um atributo personalizado.)(Not shown is [ClassicMovie2], which shows an alternative way to implement a custom attribute.)

public class Movie
{
    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [ClassicMovie(1960)]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    [Required]
    public Genre Genre { get; set; }

    public bool Preorder { get; set; }
}

Atributos internosBuilt-in attributes

Aqui estão alguns dos atributos de validação internos:Here are some of the built-in validation attributes:

  • [CreditCard]: valida se a propriedade tem um formato de cartão de crédito.[CreditCard]: Validates that the property has a credit card format.
  • [Compare]: valida se duas propriedades em um modelo são correspondentes.[Compare]: Validates that two properties in a model match.
  • [EmailAddress]: valida se a propriedade tem um formato de email.[EmailAddress]: Validates that the property has an email format.
  • [Phone]: valida se a propriedade tem um formato de número de telefone.[Phone]: Validates that the property has a telephone number format.
  • [Range]: valida se o valor da propriedade está dentro de um intervalo especificado.[Range]: Validates that the property value falls within a specified range.
  • [RegularExpression]: valida se o valor da propriedade corresponde à expressão regular especificada.[RegularExpression]: Validates that the property value matches a specified regular expression.
  • [Required]: valida se o campo não é nulo.[Required]: Validates that the field is not null. Consulte atributo [Required] para obter detalhes sobre o comportamento desse atributo.See [Required] attribute for details about this attribute's behavior.
  • [StringLength]: valida se um valor da propriedade de cadeia de caracteres não excede um limite de comprimento especificado.[StringLength]: Validates that a string property value doesn't exceed a specified length limit.
  • [Url]: valida se a propriedade tem um formato de URL.[Url]: Validates that the property has a URL format.
  • [Remote]: valida a entrada no cliente chamando um método de ação no servidor.[Remote]: Validates input on the client by calling an action method on the server. Consulte atributo [Remote] para obter detalhes sobre o comportamento desse atributo.See [Remote] attribute for details about this attribute's behavior.

Uma lista completa de atributos de validação pode ser encontrada no namespace System.ComponentModel.DataAnnotations.A complete list of validation attributes can be found in the System.ComponentModel.DataAnnotations namespace.

Mensagens de erroError messages

Os atributos de validação permitem que você especifique a mensagem de erro a ser exibido para uma entrada inválida.Validation attributes let you specify the error message to be displayed for invalid input. Por exemplo:For example:

[StringLength(8, ErrorMessage = "Name length can't be more than 8.")]

Internamente, a chamada de atributos String.Format com um espaço reservado para o nome do campo e, às vezes, espaços reservados adicionais.Internally, the attributes call String.Format with a placeholder for the field name and sometimes additional placeholders. Por exemplo:For example:

[StringLength(8, ErrorMessage = "{0} length must be between {2} and {1}.", MinimumLength = 6)]

Quando aplicada a uma propriedade Name, a mensagem de erro criada pelo código anterior seria "Comprimento do nome ter entre 6 e 8.".When applied to a Name property, the error message created by the preceding code would be "Name length must be between 6 and 8.".

Para descobrir quais parâmetros são passados para String.Format no caso de uma mensagem de erro de um atributo específico, consulte o código-fonte de DataAnnotations.To find out which parameters are passed to String.Format for a particular attribute's error message, see the DataAnnotations source code.

Atributo [Required][Required] attribute

Por padrão, o sistema de validação trata parâmetros não anuláveis ou propriedades como se tivessem um atributo [Required].By default, the validation system treats non-nullable parameters or properties as if they had a [Required] attribute. Tipos de valor como decimal e int são não anuláveis.Value types such as decimal and int are non-nullable.

Validação de [Required] no servidor[Required] validation on the server

No servidor, um valor obrigatório será considerado ausente se a propriedade for nula.On the server, a required value is considered missing if the property is null. Um campo não anulável é sempre válido e a mensagem de erro do atributo [Required] nunca é exibida.A non-nullable field is always valid, and the [Required] attribute's error message is never displayed.

No entanto, o model binding para uma propriedade que não permite valor nulo pode falhar, resultando em uma mensagem de erro como The value '' is invalid.However, model binding for a non-nullable property may fail, resulting in an error message such as The value '' is invalid. Para especificar uma mensagem de erro personalizada para a validação de tipos não anuláveis do lado do servidor, você tem as seguintes opções:To specify a custom error message for server-side validation of non-nullable types, you have the following options:

  • Tornar o campo anulável (por exemplo, decimal? em vez de decimal).Make the field nullable (for example, decimal? instead of decimal). Tipos de valor Nullable<T> são tratados como tipos que permitem valor nulo padrão.Nullable<T> value types are treated like standard nullable types.

  • Especifique a mensagem de erro padrão a ser usada pelo model binding, conforme mostrado no exemplo a seguir:Specify the default error message to be used by model binding, as shown in the following example:

    services.AddMvc(options => 
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                (_) => "The field is required.");
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddSingleton
        <IValidationAttributeAdapterProvider, 
         CustomValidationAttributeAdapterProvider>();
    

    Para obter mais informações sobre erros de model binding para os quais você pode definir mensagens padrão, consulte DefaultModelBindingMessageProvider.For more information about model binding errors that you can set default messages for, see DefaultModelBindingMessageProvider.

Validação de [Required] no cliente[Required] validation on the client

Cadeias de caracteres e tipos que não permitem valor nulo são tratados de maneira diferente no cliente em comparação com servidor.Non-nullable types and strings are handled differently on the client compared to the server. No cliente:On the client:

  • Um valor será considerado presente apenas se a entrada for inserida para ele.A value is considered present only if input is entered for it. Portanto, a validação do lado do cliente lida com tipos que não permitem valor nulo da mesma maneira que com tipos que permitem valor nulo.Therefore, client-side validation handles non-nullable types the same as nullable types.
  • O espaço em branco em um campo de cadeia de caracteres é considerado uma entrada válida pelo método required do jQuery Validation.Whitespace in a string field is considered valid input by the jQuery Validation required method. A validação do lado do servidor considerará um campo de cadeia de caracteres necessário inválido somente se o espaço em branco for inserido.Server-side validation considers a required string field invalid if only whitespace is entered.

Conforme observado anteriormente, os tipos que não permitem valor nulo são tratados como se tivessem um atributo [Required].As noted earlier, non-nullable types are treated as though they had a [Required] attribute. Isso significa que você obtém a validação do lado do cliente mesmo que não aplique o atributo [Required].That means you get client-side validation even if you don't apply the [Required] attribute. Mas se não for usar o atributo, você obterá uma mensagem de erro padrão.But if you don't use the attribute, you get a default error message. Para especificar uma mensagem de erro personalizada, use o atributo.To specify a custom error message, use the attribute.

Atributo [Remote][Remote] attribute

O atributo [Remote] implementa a validação do lado do cliente, exigindo a chamada de um método no servidor para determinar se a entrada do campo é válida.The [Remote] attribute implements client-side validation that requires calling a method on the server to determine whether field input is valid. Por exemplo, o aplicativo pode precisar verificar se um nome de usuário já está em uso.For example, the app may need to verify whether a user name is already in use.

Para implementar a validação remota:To implement remote validation:

  1. Crie um método de ação para JavaScript para chamar.Create an action method for JavaScript to call. O método remoto do jQuery Validate espera uma resposta JSON:The jQuery Validate remote method expects a JSON response:

    • "true" significa que os dados de entrada são válidos."true" means the input data is valid.
    • "false", undefined ou null significa que a entrada é inválida."false", undefined, or null means the input is invalid. Exiba a mensagem de erro padrão.Display the default error message.
    • Qualquer outra cadeia de caracteres significa que a entrada é inválida.Any other string means the input is invalid. Exiba a cadeia de caracteres como uma mensagem de erro personalizada.Display the string as a custom error message.

    Aqui está um exemplo de um método de ação que retorna uma mensagem de erro personalizada:Here's an example of an action method that returns a custom error message:

    [AcceptVerbs("Get", "Post")]
    public IActionResult VerifyEmail(string email)
    {
        if (!_userRepository.VerifyEmail(email))
        {
            return Json($"Email {email} is already in use.");
        }
    
        return Json(true);
    }
    
  2. Na classe de modelo, anote a propriedade com um atributo [Remote] que aponta para o método de ação de validação, conforme mostrado no exemplo a seguir:In the model class, annotate the property with a [Remote] attribute that points to the validation action method, as shown in the following example:

    [Remote(action: "VerifyEmail", controller: "Users")]
    public string Email { get; set; }
    

    O atributo [Remote] está no namespace Microsoft.AspNetCore.Mvc.The [Remote] attribute is in the Microsoft.AspNetCore.Mvc namespace. Instale o pacote NuGet Microsoft.AspNetCore.Mvc.ViewFeatures se você não estiver usando o metapacote Microsoft.AspNetCore.App ou Microsoft.AspNetCore.All.Install the Microsoft.AspNetCore.Mvc.ViewFeatures NuGet package if you're not using the Microsoft.AspNetCore.App or Microsoft.AspNetCore.All metapackage.

Campos adicionaisAdditional fields

A propriedade AdditionalFields do atributo [Remote] permite validar combinações de campos em relação aos dados no servidor.The AdditionalFields property of the [Remote] attribute lets you validate combinations of fields against data on the server. Por exemplo, se o modelo User tinha as propriedades FirstName e LastName, pode ser interessante verificar se nenhum usuário existente já tem esse par de nomes.For example, if the User model had FirstName and LastName properties, you might want to verify that no existing users already have that pair of names. O exemplo a seguir mostra como usar AdditionalFields:The following example shows how to use AdditionalFields:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName))]
public string FirstName { get; set; }
[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(LastName))]
public string LastName { get; set; }

AdditionalFields pode ser definido de forma explícita com as cadeias de caracteres "FirstName" e "LastName", mas o uso do operador nameof, simplifica a refatoração posterior.AdditionalFields could be set explicitly to the strings "FirstName" and "LastName", but using the nameof operator simplifies later refactoring. O método de ação para essa validação deve aceitar os argumentos de primeiro nome e de sobrenome:The action method for this validation must accept both first name and last name arguments:

[AcceptVerbs("Get", "Post")]
public IActionResult VerifyName(string firstName, string lastName)
{
    if (!_userRepository.VerifyName(firstName, lastName))
    {
        return Json(data: $"A user named {firstName} {lastName} already exists.");
    }

    return Json(data: true);
}

Quando o usuário insere o primeiro nome ou o sobrenome, o JavaScript faz uma chamada remota para ver se esse par de nomes foi usado.When the user enters a first or last name, JavaScript makes a remote call to see if that pair of names has been taken.

Para validar dois ou mais campos adicionais, forneça-os como uma lista delimitada por vírgulas.To validate two or more additional fields, provide them as a comma-delimited list. Por exemplo, para adicionar uma propriedade MiddleName ao modelo, defina o atributo [Remote], conforme mostrado no seguinte exemplo:For example, to add a MiddleName property to the model, set the [Remote] attribute as shown in the following example:

[Remote(action: "VerifyName", controller: "Users", AdditionalFields = nameof(FirstName) + "," + nameof(LastName))]
public string MiddleName { get; set; }

AdditionalFields, como todos os argumentos de atributo, deve ser uma expressão de constante.AdditionalFields, like all attribute arguments, must be a constant expression. Portanto, não use uma cadeia de caracteres interpolada nem chame Join para inicializar AdditionalFields.Therefore, don't use an interpolated string or call Join to initialize AdditionalFields.

Alternativas aos atributos internosAlternatives to built-in attributes

Se precisar de validação não fornecida por atributos internos, você poderá:If you need validation not provided by built-in attributes, you can:

Atributos personalizadosCustom attributes

Para cenários não compatíveis com os atributos de validação internos, você pode criar atributos de validação personalizados.For scenarios that the built-in validation attributes don't handle, you can create custom validation attributes. Crie uma classe que herda de ValidationAttribute e substitua o método IsValid.Create a class that inherits from ValidationAttribute, and override the IsValid method.

O método IsValid aceita um objeto chamado valor, que é a entrada a ser validada.The IsValid method accepts an object named value, which is the input to be validated. Uma sobrecarga também aceita um objeto ValidationContext, que fornece informações adicionais, como a instância do modelo criada pelo model binding.An overload also accepts a ValidationContext object, which provides additional information, such as the model instance created by model binding.

O exemplo a seguir valida se a data de lançamento de um filme no gênero Clássico não é posterior a um ano especificado.The following example validates that the release date for a movie in the Classic genre isn't later than a specified year. O atributo [ClassicMovie2] verificará o gênero primeiro e continuará apenas se for Clássico.The [ClassicMovie2] attribute checks the genre first and continues only if it's Classic. Para filmes identificados como clássicos, ele verifica a data de lançamento para garantir que não seja posterior ao limite passado ao construtor de atributo).For movies identified as classics, it checks the release date to make sure it's not later than the limit passed to the attribute constructor.)

public class ClassicMovieAttribute : ValidationAttribute
{
    private int _year;

    public ClassicMovieAttribute(int year)
    {
        _year = year;
    }

    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        var movie = (Movie)validationContext.ObjectInstance;
        var releaseYear = ((DateTime)value).Year;

        if (movie.Genre == Genre.Classic && releaseYear > _year)
        {
            return new ValidationResult(GetErrorMessage());
        }

        return ValidationResult.Success;
    }

    public int Year => _year;

    public string GetErrorMessage()
    {
        return $"Classic movies must have a release year no later than {_year}.";
    }
}

A variável movie no exemplo anterior representa um objeto Movie que contém os dados do envio do formulário.The movie variable in the preceding example represents a Movie object that contains the data from the form submission. O método IsValid verifica a data e o gênero.The IsValid method checks the date and genre. Após a validação bem-sucedida, o IsValid retorna um código ValidationResult.Success.Upon successful validation, IsValid returns a ValidationResult.Success code. Quando a validação falha, um ValidationResult com uma mensagem erro será retornado.When validation fails, a ValidationResult with an error message is returned.

IValidatableObjectIValidatableObject

O exemplo anterior funciona apenas com tipos Movie.The preceding example works only with Movie types. Outra opção para validação de nível de classe é implementar IValidatableObject na classe de modelo, conforme mostrado no exemplo a seguir:Another option for class-level validation is to implement IValidatableObject in the model class, as shown in the following example:

public class MovieIValidatable : IValidatableObject
{
    private const int _classicYear = 1960;

    public int Id { get; set; }

    [Required]
    [StringLength(100)]
    public string Title { get; set; }

    [Required]
    public DateTime ReleaseDate { get; set; }

    [Required]
    [StringLength(1000)]
    public string Description { get; set; }

    [Range(0, 999.99)]
    public decimal Price { get; set; }

    [Required]
    public Genre Genre { get; set; }

    public bool Preorder { get; set; }

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        if (Genre == Genre.Classic && ReleaseDate.Year > _classicYear)
        {
            yield return new ValidationResult(
                $"Classic movies must have a release year earlier than {_classicYear}.",
                new[] { "ReleaseDate" });
        }
    }
}

Validação de nó de nível superiorTop-level node validation

Os nós de nível superior incluem:Top-level nodes include:

  • Parâmetros de açãoAction parameters
  • Propriedades do controladorController properties
  • Parâmetros do manipulador de páginaPage handler parameters
  • Propriedades do modelo de páginaPage model properties

Os nós de nível superior associados ao modelo são validados além de validar as propriedades do modelo.Model-bound top-level nodes are validated in addition to validating model properties. No exemplo a seguir do aplicativo de exemplo, o método VerifyPhone usa o RegularExpressionAttribute para validar o parâmetro de ação phone:In the following example from the sample app, the VerifyPhone method uses the RegularExpressionAttribute to validate the phone action parameter:

[AcceptVerbs("Get", "Post")]
public IActionResult VerifyPhone(
    [RegularExpression(@"^\d{3}-\d{3}-\d{4}$")] string phone)
{
    if (!ModelState.IsValid)
    {
        return Json($"Phone {phone} has an invalid format. Format: ###-###-####");
    }

    return Json(true);
}

Os nós de nível superior podem usar BindRequiredAttribute com atributos de validação.Top-level nodes can use BindRequiredAttribute with validation attributes. No exemplo a seguir do aplicativo de exemplo, o método CheckAge especifica que o parâmetro age deve ser associado da cadeia de caracteres de consulta quando o formulário é enviado:In the following example from the sample app, the CheckAge method specifies that the age parameter must be bound from the query string when the form is submitted:

[HttpPost]
public IActionResult CheckAge(
    [BindRequired, FromQuery] int age)
{

Na página Verificar Idade (CheckAge.cshtml), há dois formulários.In the Check Age page (CheckAge.cshtml), there are two forms. O primeiro formulário envia um valor Age de 99 como uma cadeia de caracteres de consulta: https://localhost:5001/Users/CheckAge?Age=99.The first form submits an Age value of 99 as a query string: https://localhost:5001/Users/CheckAge?Age=99.

Quando um parâmetro age formatado corretamente da cadeia de caracteres de consulta é enviado, o formulário é validado.When a properly formatted age parameter from the query string is submitted, the form validates.

O segundo formulário na página Verificar Idade envia o valor Age no corpo da solicitação e a validação falha.The second form on the Check Age page submits the Age value in the body of the request, and validation fails. A associação falha porque o parâmetro age deve vir de uma cadeia de caracteres de consulta.Binding fails because the age parameter must come from a query string.

Ao executar com CompatibilityVersion.Version_2_1 ou posterior, a validação do nó de nível superior é habilitada por padrão.When running with CompatibilityVersion.Version_2_1 or later, top-level node validation is enabled by default. Caso contrário, a validação do nó de nível superior ficará desabilitada.Otherwise, top-level node validation is disabled. A opção padrão pode ser substituída pela configuração da propriedade AllowValidatingTopLevelNodes em (Startup.ConfigureServices), conforme mostrado aqui:The default option can be overridden by setting the AllowValidatingTopLevelNodes property in (Startup.ConfigureServices), as shown here:

services.AddMvc(options => 
    {
        options.MaxModelValidationErrors = 50;
        options.AllowValidatingTopLevelNodes = false;
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

Máximo de errosMaximum errors

A validação para quando o número máximo de erros é atingido (200 por padrão).Validation stops when the maximum number of errors is reached (200 by default). Você pode configurar esse número com o seguinte código no Startup.ConfigureServices:You can configure this number with the following code in Startup.ConfigureServices:

services.AddMvc(options => 
    {
        options.MaxModelValidationErrors = 50;
        options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
            (_) => "The field is required.");
    })
    .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
services.AddSingleton
    <IValidationAttributeAdapterProvider, 
     CustomValidationAttributeAdapterProvider>();

Recursão máximaMaximum recursion

ValidationVisitor percorre o grafo de objeto do modelo que está sendo validado.ValidationVisitor traverses the object graph of the model being validated. Para modelos que são muito profundos ou que são infinitamente recursivos, a validação pode resultar em estouro de pilha.For models that are very deep or are infinitely recursive, validation may result in stack overflow. O MvcOptions.MaxValidationDepth fornece uma maneira de interromper a validação antes que a recursão visitante exceda uma profundidade configurada.MvcOptions.MaxValidationDepth provides a way to stop validation early if the visitor recursion exceeds a configured depth. O valor padrão de MvcOptions.MaxValidationDepth é 200 durante a execução com CompatibilityVersion.Version_2_2 ou posterior.The default value of MvcOptions.MaxValidationDepth is 200 when running with CompatibilityVersion.Version_2_2 or later. Para versões anteriores, o valor é nulo, o que significa que não há nenhuma restrição de profundidade.For earlier versions, the value is null, which means no depth constraint.

Curto-circuito automáticoAutomatic short-circuit

A validação sofrerá curto-circuito (será ignorada) automaticamente se o grafo do modelo não exigir validação.Validation is automatically short-circuited (skipped) if the model graph doesn't require validation. Objetos em que o tempo de execução ignora a validação para inclusão de coleções de primitivos (como byte[], string[] e Dictionary<string, string>) e grafos de objetos complexos que não têm um validador.Objects that the runtime skips validation for include collections of primitives (such as byte[], string[], Dictionary<string, string>) and complex object graphs that don't have any validators.

Desabilitar validaçãoDisable validation

Para desabilitar a validação:To disable validation:

  1. Crie uma implementação de IObjectModelValidator que não marque nenhum campo como inválido.Create an implementation of IObjectModelValidator that doesn't mark any fields as invalid.

    public class NullObjectModelValidator : IObjectModelValidator
    {
        public void Validate(
            ActionContext actionContext,
            ValidationStateDictionary validationState,
            string prefix,
            object model)
        {
        }
    }
    
  2. Adicione o seguinte código ao Startup.ConfigureServices para substituir a implementação IObjectModelValidator padrão no contêiner de injeção de dependência.Add the following code to Startup.ConfigureServices to replace the default IObjectModelValidator implementation in the dependency injection container.

    // There is only one `IObjectModelValidator` object,
    // so AddSingleton replaces the default one.
    services.AddSingleton<IObjectModelValidator>(new NullObjectModelValidator());
    

Talvez você ainda veja erros de estado de modelo que se originam do model binding.You might still see model state errors that originate from model binding.

Validação do lado do clienteClient-side validation

A validação do lado do cliente impede o envio até que o formulário seja válido.Client-side validation prevents submission until the form is valid. O botão Enviar executa o JavaScript que envia o formulário ou exibe mensagens de erro.The Submit button runs JavaScript that either submits the form or displays error messages.

A validação do lado do cliente evita uma viagem de ida e volta desnecessária ao servidor quando há erros de entrada em um formulário.Client-side validation avoids an unnecessary round trip to the server when there are input errors on a form. O script a seguir faz referência nas validações de suporte _Layout.cshtml e _ValidationScriptsPartial.cshtml no lado do cliente:The following script references in _Layout.cshtml and _ValidationScriptsPartial.cshtml support client-side validation:

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.17.0/jquery.validate.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validation-unobtrusive/3.2.11/jquery.validate.unobtrusive.min.js"></script>

O script do jQuery Unobtrusive Validation é uma biblioteca de front-end personalizada da Microsoft que se baseia no popular plug-in jQuery Validate.The jQuery Unobtrusive Validation script is a custom Microsoft front-end library that builds on the popular jQuery Validate plugin. Sem o jQuery Unobtrusive Validation, você teria que codificar a mesma lógica de validação em dois locais: uma vez nos atributos de validação do lado do servidor nas propriedades do modelo e, em seguida, novamente nos scripts do lado do cliente.Without jQuery Unobtrusive Validation, you would have to code the same validation logic in two places: once in the server-side validation attributes on model properties, and then again in client-side scripts. Em vez disso, os Auxiliares de Marca e os Auxiliares HTML usam os atributos de validação e os metadados de tipo das propriedades do modelo para renderizar atributos data- de HTML 5 para os elementos de formulário que precisam de validação.Instead, Tag Helpers and HTML helpers use the validation attributes and type metadata from model properties to render HTML 5 data- attributes for the form elements that need validation. O jQuery Unobtrusive Validation analisa os atributos data- e passa a lógica para o jQuery Validate, "copiando" efetivamente a lógica de validação do lado do servidor para o cliente.jQuery Unobtrusive Validation parses the data- attributes and passes the logic to jQuery Validate, effectively "copying" the server-side validation logic to the client. Você pode exibir erros de validação no cliente usando os auxiliares de marca conforme mostrado aqui:You can display validation errors on the client using tag helpers as shown here:

<div class="form-group">
    <label asp-for="ReleaseDate" class="col-md-2 control-label"></label>
    <div class="col-md-10">
        <input asp-for="ReleaseDate" class="form-control" />
        <span asp-validation-for="ReleaseDate" class="text-danger"></span>
    </div>
</div>

Os auxiliares de marca acima renderizam o HTML a seguir.The preceding tag helpers render the following HTML.

<form action="/Movies/Create" method="post">
    <div class="form-horizontal">
        <h4>Movie</h4>
        <div class="text-danger"></div>
        <div class="form-group">
            <label class="col-md-2 control-label" for="ReleaseDate">ReleaseDate</label>
            <div class="col-md-10">
                <input class="form-control" type="datetime"
                data-val="true" data-val-required="The ReleaseDate field is required."
                id="ReleaseDate" name="ReleaseDate" value="">
                <span class="text-danger field-validation-valid"
                data-valmsg-for="ReleaseDate" data-valmsg-replace="true"></span>
            </div>
        </div>
    </div>
</form>

Observe que os atributos data- na saída HTML correspondem aos atributos de validação da propriedade ReleaseDate.Notice that the data- attributes in the HTML output correspond to the validation attributes for the ReleaseDate property. O atributo data-val-required conterá uma mensagem de erro a ser exibida se o usuário não preencher o campo de data de lançamento.The data-val-required attribute contains an error message to display if the user doesn't fill in the release date field. O jQuery Unobtrusive Validation passa esse valor para o método required() do jQuery Validate, que, por sua vez, exibe essa mensagem no elemento <span> complementar.jQuery Unobtrusive Validation passes this value to the jQuery Validate required() method, which then displays that message in the accompanying <span> element.

A validação de tipo de dados é baseada no tipo .NET de uma propriedade, a menos que seja substituída por um atributo [DataType].Data type validation is based on the .NET type of a property, unless that is overridden by a [DataType] attribute. Os navegadores têm suas próprias mensagens de erro padrão, mas o pacote de validação do jQuery Validation Unobtrusive pode substituir essas mensagens.Browsers have their own default error messages, but the jQuery Validation Unobtrusive Validation package can override those messages. Os atributos [DataType] e as subclasses como [EmailAddress] permitem que você especifique a mensagem de erro.[DataType] attributes and subclasses such as [EmailAddress] let you specify the error message.

Adicionar validação a formulários dinâmicosAdd Validation to Dynamic Forms

O jQuery Unobtrusive Validation passa parâmetros e a lógica de validação para o jQuery Validate quando a página é carregada pela primeira vez.jQuery Unobtrusive Validation passes validation logic and parameters to jQuery Validate when the page first loads. Portanto, a validação não funciona automaticamente em formulários gerados dinamicamente.Therefore, validation doesn't work automatically on dynamically generated forms. Para habilitar a validação é necessário instruir o jQuery Unobtrusive Validation a analisar o formulário dinâmico imediatamente depois de criá-lo.To enable validation, tell jQuery Unobtrusive Validation to parse the dynamic form immediately after you create it. Por exemplo, o código a seguir define a validação do lado do cliente em um formulário adicionado por meio do AJAX.For example, the following code sets up client-side validation on a form added via AJAX.

$.get({
    url: "https://url/that/returns/a/form",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add form. " + errorThrown);
    },
    success: function(newFormHTML) {
        var container = document.getElementById("form-container");
        container.insertAdjacentHTML("beforeend", newFormHTML);
        var forms = container.getElementsByTagName("form");
        var newForm = forms[forms.length - 1];
        $.validator.unobtrusive.parse(newForm);
    }
})

O método $.validator.unobtrusive.parse() aceita um seletor do jQuery para um argumento seu.The $.validator.unobtrusive.parse() method accepts a jQuery selector for its one argument. Esse método instrui o jQuery Unobtrusive Validation a analisar os atributos data- de formulários nesse seletor.This method tells jQuery Unobtrusive Validation to parse the data- attributes of forms within that selector. Depois, os valores desses atributos são passados para o plug-in do jQuery Validate.The values of those attributes are then passed to the jQuery Validate plugin.

Adicionar validação a controles dinâmicosAdd Validation to Dynamic Controls

O método $.validator.unobtrusive.parse() funciona em um formulário inteiro, não em controles individuais gerados dinamicamente, como <input> e <select/>.The $.validator.unobtrusive.parse() method works on an entire form, not on individual dynamically generated controls, such as <input> and <select/>. Para uma nova análise do formulário, remova os dados de validação que foram adicionados ao formulário mesmo quando foi analisado anteriormente, conforme mostrado no exemplo a seguir:To reparse the form, remove the validation data that was added when the form was parsed earlier, as shown in the following example:

$.get({
    url: "https://url/that/returns/a/control",
    dataType: "html",
    error: function(jqXHR, textStatus, errorThrown) {
        alert(textStatus + ": Couldn't add control. " + errorThrown);
    },
    success: function(newInputHTML) {
        var form = document.getElementById("my-form");
        form.insertAdjacentHTML("beforeend", newInputHTML);
        $(form).removeData("validator")    // Added by jQuery Validate
               .removeData("unobtrusiveValidation");   // Added by jQuery Unobtrusive Validation
        $.validator.unobtrusive.parse(form);
    }
})

Validação personalizada do lado do clienteCustom client-side validation

A validação personalizada do lado do cliente é feita por meio da geração de atributos de HTML data- que funcionam com um adaptador do jQuery Validate personalizado.Custom client-side validation is done by generating data- HTML attributes that work with a custom jQuery Validate adapter. O seguinte código do adaptador de exemplo foi escrito para os atributos ClassicMovie e ClassicMovie2 que foram apresentados no início deste artigo:The following sample adapter code was written for the ClassicMovie and ClassicMovie2 attributes that were introduced earlier in this article:

$.validator.addMethod('classicmovie',
    function (value, element, params) {
        // Get element value. Classic genre has value '0'.
        var genre = $(params[0]).val(),
            year = params[1],
            date = new Date(value);
        if (genre && genre.length > 0 && genre[0] === '0') {
            // Since this is a classic movie, invalid if release date is after given year.
            return date.getUTCFullYear() <= year;
        }

        return true;
    });

$.validator.unobtrusive.adapters.add('classicmovie',
    ['year'],
    function (options) {
        var element = $(options.form).find('select#Genre')[0];
        options.rules['classicmovie'] = [element, parseInt(options.params['year'])];
        options.messages['classicmovie'] = options.message;
    });

Para obter informações sobre como escrever adaptadores, consulte a documentação do jQuery Validate.For information about how to write adapters, see the jQuery Validate documentation.

O uso de um adaptador para um determinado campo é disparado por atributos data- que:The use of an adapter for a given field is triggered by data- attributes that:

  • Marcam o campo como sujeito à validação do sinalizador (data-val="true").Flag the field as being subject to validation (data-val="true").
  • Identifique o nome de uma regra de validação e o texto da mensagem de erro (por exemplo, data-val-rulename="Error message.").Identify a validation rule name and error message text (for example, data-val-rulename="Error message.").
  • Forneça os parâmetros adicionais que o validador precisa (por exemplo, data-val-rulename-parm1="value").Provide any additional parameters the validator needs (for example, data-val-rulename-parm1="value").

A exemplo a seguir mostra os atributos data- para o atributo ClassicMovie do aplicativo de exemplo:The following example shows the data- attributes for the sample app's ClassicMovie attribute:

<input class="form-control" type="datetime"
    data-val="true"
    data-val-classicmovie1="Classic movies must have a release year earlier than 1960."
    data-val-classicmovie1-year="1960"
    data-val-required="The ReleaseDate field is required."
    id="ReleaseDate" name="ReleaseDate" value="">

Conforme observado anteriormente, os Auxiliares de Marca e Auxiliares de HTML usam informações de atributos de validação para renderizar atributos data-.As noted earlier, Tag Helpers and HTML helpers use information from validation attributes to render data- attributes. Há duas opções para escrever código que resulte na criação de atributos HTML data- personalizados:There are two options for writing code that results in the creation of custom data- HTML attributes:

  • Criar uma classe que deriva de AttributeAdapterBase<TAttribute> e uma classe que implementa IValidationAttributeAdapterProvider e registrar o atributo e o adaptador na DI.Create a class that derives from AttributeAdapterBase<TAttribute> and a class that implements IValidationAttributeAdapterProvider, and register your attribute and its adapter in DI. Este método segue a entidade de segurança de responsabilidade única em que o código de validação relacionado ao cliente e ao servidor fica em classes separadas.This method follows the single responsibility principal in that server-related and client-related validation code is in separate classes. O adaptador também tem a vantagem de que, uma vez que ele é registrado na DI, outros serviços da DI ficam disponíveis para ele, se necessário.The adapter also has the advantage that since it is registered in DI, other services in DI are available to it if needed.
  • Implementar IClientModelValidator em na classe ValidationAttribute.Implement IClientModelValidator in your ValidationAttribute class. Esse método poderá ser adequado se o atributo não fizer nenhuma validação do lado do servidor e não precisar de um serviço da DI.This method might be appropriate if the attribute doesn't do any server-side validation and doesn't need any services from DI.

AttributeAdapter para validação do lado do clienteAttributeAdapter for client-side validation

Esse método de renderização de atributos data- em HTML é usado pelo atributo ClassicMovie no aplicativo de exemplo.This method of rendering data- attributes in HTML is used by the ClassicMovie attribute in the sample app. Para adicionar a validação do cliente usando esse método:To add client validation by using this method:

  1. Crie uma classe de adaptador de atributo para o atributo de validação personalizado.Create an attribute adapter class for the custom validation attribute. Derive a classe de AttributeAdapterBase<T>.Derive the class from AttributeAdapterBase<T>. Criar um método AddValidation que adiciona atributos data- à saída renderizada, conforme mostrado neste exemplo:Create an AddValidation method that adds data- attributes to the rendered output, as shown in this example:

    public class ClassicMovieAttributeAdapter : AttributeAdapterBase<ClassicMovieAttribute>
    {
        private int _year;
    
        public ClassicMovieAttributeAdapter(ClassicMovieAttribute attribute, IStringLocalizer stringLocalizer) : base (attribute, stringLocalizer)
        {
            _year = attribute.Year;
        }
        public override void AddValidation(ClientModelValidationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
    
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage(context));
    
            var year = Attribute.Year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
        public override string GetErrorMessage(ModelValidationContextBase validationContext)
        {
            return Attribute.GetErrorMessage();
        }
    }
    
  2. Crie uma classe de provedor de adaptador que implementa IValidationAttributeAdapterProvider.Create an adapter provider class that implements IValidationAttributeAdapterProvider. No método GetAttributeAdapter, passe o atributo personalizado para o construtor do adaptador, conforme mostrado neste exemplo:In the GetAttributeAdapter method pass in the custom attribute to the adapter's constructor, as shown in this example:

    public class CustomValidationAttributeAdapterProvider :
        IValidationAttributeAdapterProvider
    {
        IValidationAttributeAdapterProvider baseProvider =
            new ValidationAttributeAdapterProvider();
        public IAttributeAdapter GetAttributeAdapter(ValidationAttribute attribute,
            IStringLocalizer stringLocalizer)
        {
            if (attribute is ClassicMovieAttribute)
            {
                return new ClassicMovieAttributeAdapter(
                    attribute as ClassicMovieAttribute, stringLocalizer);
            }
            else
            {
                return baseProvider.GetAttributeAdapter(attribute, stringLocalizer);
            }
        }
    }
    
  3. Registre o provedor de adaptador para DI em Startup.ConfigureServices:Register the adapter provider for DI in Startup.ConfigureServices:

    services.AddMvc(options => 
        {
            options.MaxModelValidationErrors = 50;
            options.ModelBindingMessageProvider.SetValueMustNotBeNullAccessor(
                (_) => "The field is required.");
        })
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
    services.AddSingleton
        <IValidationAttributeAdapterProvider, 
         CustomValidationAttributeAdapterProvider>();
    

IClientModelValidator para validação do lado do clienteIClientModelValidator for client-side validation

Esse método de renderização de atributos data- em HTML é usado pelo atributo ClassicMovie2 no aplicativo de exemplo.This method of rendering data- attributes in HTML is used by the ClassicMovie2 attribute in the sample app. Para adicionar a validação do cliente usando esse método:To add client validation by using this method:

  • No atributo de validação personalizado, implemente a interface IClientModelValidator e crie um método AddValidation.In the custom validation attribute, implement the IClientModelValidator interface and create an AddValidation method. No método AddValidation, adicione atributos data- para validação, conforme mostrado no exemplo a seguir:In the AddValidation method, add data- attributes for validation, as shown in the following example:

    
    public class ClassicMovie2Attribute : ValidationAttribute, IClientModelValidator
    {
        private int _year;
    
        public ClassicMovie2Attribute(int year)
        {
            _year = year;
        }
    
        protected override ValidationResult IsValid(
            object value, ValidationContext validationContext)
        {
            var movie = (Movie)validationContext.ObjectInstance;
            var releaseYear = ((DateTime)value).Year;
    
            if (movie.Genre == Genre.Classic && releaseYear > _year)
            {
                return new ValidationResult(GetErrorMessage());
            }
    
            return ValidationResult.Success;
        }
    
        public void AddValidation(ClientModelValidationContext context)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
    
            MergeAttribute(context.Attributes, "data-val", "true");
            MergeAttribute(context.Attributes, "data-val-classicmovie", GetErrorMessage());
    
            var year = _year.ToString(CultureInfo.InvariantCulture);
            MergeAttribute(context.Attributes, "data-val-classicmovie-year", year);
        }
        private bool MergeAttribute(IDictionary<string, string> attributes, string key, string value)
        {
            if (attributes.ContainsKey(key))
            {
                return false;
            }
    
            attributes.Add(key, value);
            return true;
        }
        protected string GetErrorMessage()
        {
            return $"Classic movies must have a release year no later than {_year} [from attribute 2].";
        }
    }
    

Desabilitar validação do lado do clienteDisable client-side validation

O código a seguir desabilita a validação de cliente nas exibições do MVC:The following code disables client validation in MVC views:

services.AddMvc().AddViewOptions(options =>
{
    if (_env.IsDevelopment())
    {
        options.HtmlHelperOptions.ClientValidationEnabled = false;
    }
});

E em Razor Pages:And in Razor Pages:

services.Configure<HtmlHelperOptions>(o => o.ClientValidationEnabled = false);

Outra opção para desabilitar a validação do cliente é comentar a referência ao _ValidationScriptsPartial em seu arquivo .cshtml.Another option for disabling client validation is to comment out the reference to _ValidationScriptsPartial in your .cshtml file.

Recursos adicionaisAdditional resources