Partilhar via


Parte 9, adicionar validação a um aplicativo ASP.NET Core MVC

Observação

Esta não é a versão mais recente deste artigo. Para a versão atual, consulte a versão .NET 10 deste artigo.

Advertência

Esta versão do ASP.NET Core não é mais suportada. Para obter mais informações, consulte a Política de suporte do .NET e do .NET Core. Para a versão atual, consulte a versão .NET 9 deste artigo.

Por Rick Anderson

Nesta secção:

  • A lógica de validação é adicionada ao modelo Movie.
  • Você garante que as regras de validação sejam aplicadas sempre que um usuário criar ou editar um filme.

Manter as coisas SECAS

Um dos princípios de design do MVC é DRY ("Don't Repeat Yourself"). ASP.NET MVC principal incentiva você a especificar a funcionalidade ou o comportamento apenas uma vez e, em seguida, fazer com que ele seja refletido em todos os lugares de um aplicativo. Isso reduz a quantidade de código que você precisa escrever e torna o código que você escreve menos propenso a erros, mais fácil de testar e mais fácil de manter.

O suporte de validação fornecido pelo MVC e pelo Entity Framework Core é um bom exemplo do princípio DRY em ação. Você pode especificar declarativamente as regras de validação em um só lugar (na classe de modelo) e as regras são aplicadas em todos os lugares do aplicativo.

Validação no .NET 10

No .NET 10, as APIs de validação unificadas foram movidas para o Microsoft.Extensions.Validation pacote NuGet. Essa alteração torna as APIs de validação disponíveis fora de ASP.NET cenários HTTP principais.

Para usar as Microsoft.Extensions.Validation APIs:

  • Adicione a seguinte referência de pacote:

    <PackageReference Include="Microsoft.Extensions.Validation" Version="10.0.0" />
    

    A funcionalidade permanece a mesma, mas agora requer uma referência explícita ao pacote.

  • Registrar serviços de validação com injeção de dependência:

    builder.Services.AddValidation();
    

Excluir os dados editados anteriormente

Na próxima etapa, são adicionadas regras de validação que não permitem valores nulos. Execute o aplicativo, navegue até /Movies/Index, exclua todos os filmes listados e pare o aplicativo. O aplicativo usará os dados de propagação na próxima vez que for executado.

Adicionar regras de validação ao modelo de filme

O namespace DataAnnotations fornece um conjunto de atributos de validação internos que são aplicados declarativamente a uma classe ou propriedade. DataAnnotations também contém atributos de formatação como DataType esses ajudam na formatação e não fornecem nenhuma validação.

Atualize a classe Movie para tirar proveito dos atributos de validação internos Required, StringLength, RegularExpression, Range e do atributo de formatação DataType.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Os atributos de validação especificam o comportamento que você deseja impor nas propriedades do modelo às quais são aplicados:

  • Os Required atributos e MinimumLength indicam que uma propriedade deve ter um valor, mas nada impede que um usuário insira um espaço em branco para satisfazer essa validação.

  • O RegularExpression atributo é usado para limitar quais caracteres podem ser inseridos. No código anterior, "Gênero":

    • Deve usar apenas letras.
    • A primeira letra deve ser maiúscula. Espaços em branco são permitidos enquanto números e caracteres especiais não são permitidos.
  • A RegularExpression "classificação":

    • Requer que o primeiro caractere seja uma letra maiúscula.
    • Permite caracteres especiais e números em espaços subsequentes. "PG-13" é válido para uma classificação, mas não é apropriado para um "Género".
  • O Range atributo restringe um valor a dentro de um intervalo especificado.

  • O StringLength atributo permite definir o comprimento máximo de uma propriedade string e, opcionalmente, seu comprimento mínimo.

  • Os tipos de valor (como decimal, int, float, DateTime) são inerentemente necessários e não precisam do [Required] atributo.

Ter regras de validação aplicadas automaticamente pelo ASP.NET Core ajuda a tornar seu aplicativo mais robusto. Ele também garante que você não pode esquecer de validar algo e, inadvertidamente, deixar dados ruins no banco de dados.

Interface do usuário de erro de validação

Execute o aplicativo e navegue até o controlador Filmes.

Selecione o link Criar novo para adicionar um novo filme. Preencha o formulário com alguns valores inválidos. Assim que a validação do lado do cliente jQuery deteta o erro, ele exibe uma mensagem de erro.

Formulário de visualização de filme com vários erros de validação do lado do cliente jQuery

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Observe como o formulário exibiu automaticamente uma mensagem apropriada de erro de validação em todos os campos que contêm um valor inválido. Os erros são impostos tanto do lado do cliente (usando JavaScript e jQuery) quanto do lado do servidor (no caso de um usuário ter o JavaScript desativado).

Um benefício significativo é que você não precisou alterar uma única linha de código na MoviesController classe ou na Create.cshtml exibição para habilitar essa interface do usuário de validação. O controlador e as visualizações que criou anteriormente neste tutorial selecionaram automaticamente as regras de validação que especificou, utilizando atributos de validação nas propriedades da classe de modelo Movie. Validação de teste usando o Edit método de ação, e a mesma validação é aplicada.

Os dados do formulário não são enviados para o servidor até que não haja erros de validação do lado do cliente. Você pode verificar isso colocando um ponto de interrupção no método, usando a HTTP Postferramenta Fiddler ou as ferramentas de desenvolvedor F12.

Como funciona a validação

Você pode se perguntar como a interface do usuário de validação foi gerada sem atualizações para o código no controlador ou exibições. O código a seguir mostra os dois Create métodos.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

O primeiro método de ação (HTTP GET) Create exibe o formulário Create inicial. A segunda versão ([HttpPost]) lida com o envio do formulário. O segundo Create método (A [HttpPost] versão) chama ModelState.IsValid para verificar se o filme tem algum erro de validação. Chamar esse método avalia todos os atributos de validação que foram aplicados ao objeto. Se o objeto tiver erros de validação, o Create método exibirá novamente o formulário. Se não houver erros, o método salva o novo filme no banco de dados. Em nosso exemplo de filme, o formulário não é postado no servidor quando há erros de validação detetados no lado do cliente; O segundo Create método nunca é chamado quando há erros de validação do lado do cliente. Se você desabilitar o JavaScript em seu navegador, a validação do cliente será desabilitada e você poderá testar o método Create HTTP POST ModelState.IsValid detetando quaisquer erros de validação.

Você pode definir um ponto de interrupção no [HttpPost] Create método e verificar se o método nunca é chamado, a validação do lado do cliente não enviará os dados do formulário quando erros de validação forem detetados. Se você desativar o JavaScript no seu navegador e, em seguida, enviar o formulário com erros, o ponto de interrupção será atingido. Você ainda obtém validação completa sem JavaScript.

A imagem a seguir mostra como desativar o JavaScript no navegador Firefox.

Firefox: Na guia Conteúdo de Opções, desmarque a caixa de seleção Ativar Javascript.

A imagem seguinte mostra como desativar o JavaScript no navegador Chrome.

Google Chrome: Na seção Javascript de Configurações de conteúdo, selecione Não permitir que nenhum site execute JavaScript.

Depois de desativar o JavaScript, envie dados inválidos e analise o depurador.

Ao efetuar a depuração numa postagem de dados inválidos, o Intellisense mostra que o valor de ModelState.IsValid é false.

Uma parte do Create.cshtml modelo de exibição é mostrada na seguinte marcação:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

A marcação anterior é usada pelos métodos de ação para exibir o formulário inicial e exibi-lo novamente no caso de um erro.

O Auxiliar de Tag de Entrada usa os atributos DataAnnotations e produz atributos HTML necessários para a Validação do jQuery no lado do cliente. O Auxiliar de Tag de Validação exibe erros de validação. Consulte Validação para obter mais informações.

O que é realmente bom sobre essa abordagem é que nem o controlador nem o Create modelo de exibição sabem nada sobre as regras de validação reais que estão sendo aplicadas ou sobre as mensagens de erro específicas exibidas. As regras de validação e as cadeias de caracteres de erro são especificadas somente na Movie classe. Essas mesmas regras de validação são aplicadas automaticamente à vista Edit e a quaisquer outros modelos de vista que possa criar para editar o seu modelo.

Quando você precisa alterar a lógica de validação, pode fazê-lo exatamente em um lugar, adicionando atributos de validação ao modelo (neste exemplo, a Movie classe). Você não terá que se preocupar com diferentes partes do aplicativo sendo inconsistentes com a forma como as regras são aplicadas — toda a lógica de validação será definida em um só lugar e usada em todos os lugares. Isso mantém o código muito limpo e facilita a manutenção e a evolução. E isso significa que você estará honrando totalmente o princípio DRY.

Usando Atributos de Tipo de Dados

Abra o Movie.cs arquivo e examine a Movie classe. O System.ComponentModel.DataAnnotations namespace fornece atributos de formatação, além do conjunto interno de atributos de validação. Já aplicamos um DataType valor de enumeração à data de lançamento e aos campos de preço. O código a seguir mostra as ReleaseDate propriedades e Price com o atributo apropriado DataType .

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Os DataType atributos fornecem apenas dicas para o mecanismo de exibição formatar os dados e fornecem elementos/atributos, como <a> URLs e <a href="mailto:EmailAddress.com"> e-mails. Você pode usar o RegularExpression atributo para validar o formato dos dados. O DataType atributo é usado para especificar um tipo de dados que é mais específico do que o tipo intrínseco do banco de dados, eles não são atributos de validação. Neste caso, queremos apenas acompanhar a data, não a hora. A DataType enumeração fornece para muitos tipos de dados, como data, hora, número de telefone, moeda, endereço de e-mail e muito mais. O DataType atributo também pode permitir que o aplicativo forneça automaticamente recursos específicos do tipo. Por exemplo, um mailto: link pode ser criado para DataType.EmailAddress, e um seletor de data pode ser fornecido nos DataType.Date navegadores que suportam HTML5. Os DataType atributos emitem atributos HTML 5 data- (pronuncia-se traço de dados) que os navegadores HTML 5 podem entender. Os DataType atributos não fornecem nenhuma validação.

DataType.Date não especifica o formato da data exibida. Por padrão, o campo de dados é exibido de acordo com os formatos padrão baseados no CultureInfo do servidor.

O DisplayFormat atributo é usado para especificar explicitamente o formato de data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

A ApplyFormatInEditMode configuração especifica que a formatação também deve ser aplicada quando o valor é exibido em uma caixa de texto para edição. (Talvez você não queira isso para alguns campos — por exemplo, para valores de moeda, provavelmente não deseja que o símbolo de moeda na caixa de texto seja editado.)

Você pode usar o DisplayFormat atributo por si só, mas geralmente é uma boa ideia usar o DataType atributo. O DataType atributo transmite a semântica dos dados em oposição a como renderizá-los em uma tela e fornece os seguintes benefícios que você não obtém com DisplayFormat:

  • O navegador pode habilitar recursos HTML5 (por exemplo, para mostrar um controle de calendário, o símbolo de moeda apropriado à localidade, links de e-mail, etc.)

  • Por padrão, o navegador renderizará dados usando o formato correto com base na sua localidade.

  • O DataType atributo pode permitir que o MVC escolha o modelo de campo certo para renderizar os dados (o DisplayFormat se usado por si só usa o modelo de cadeia de caracteres).

Observação

A validação do jQuery não funciona com os atributos Range e DateTime. Por exemplo, o código a seguir sempre exibirá um erro de validação do lado do cliente, mesmo quando a data estiver no intervalo especificado:

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

Você precisará desabilitar a validação de data do jQuery para usar o Range atributo com DateTime. Geralmente, não é uma boa prática compilar datas fixas ou rígidas nos modelos, portanto, usar o atributo Range e DateTime é desencorajado.

O código a seguir mostra a combinação de atributos em uma linha:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string? Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string? Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency), Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string? Rating { get; set; }
}

Na próxima parte da série, analisamos o app e fazemos algumas melhorias nos Details métodos Delete gerados automaticamente.

Recursos adicionais

Nesta secção:

  • A lógica de validação é adicionada ao modelo Movie.
  • Você garante que as regras de validação sejam aplicadas sempre que um usuário criar ou editar um filme.

Manter as coisas SECAS

Um dos princípios de design do MVC é DRY ("Don't Repeat Yourself"). ASP.NET MVC principal incentiva você a especificar a funcionalidade ou o comportamento apenas uma vez e, em seguida, fazer com que ele seja refletido em todos os lugares de um aplicativo. Isso reduz a quantidade de código que você precisa escrever e torna o código que você escreve menos propenso a erros, mais fácil de testar e mais fácil de manter.

O suporte de validação fornecido pelo MVC e pelo Entity Framework Core Code First é um bom exemplo do princípio DRY em ação. Você pode especificar declarativamente as regras de validação em um só lugar (na classe de modelo) e as regras são aplicadas em todos os lugares do aplicativo.

Excluir os dados editados anteriormente

Na próxima etapa, são adicionadas regras de validação que não permitem valores nulos. Execute o aplicativo, navegue até /Movies/Index, exclua todos os filmes listados e pare o aplicativo. O aplicativo usará os dados de propagação na próxima vez que for executado.

Adicionar regras de validação ao modelo de filme

O namespace DataAnnotations fornece um conjunto de atributos de validação internos que são aplicados declarativamente a uma classe ou propriedade. DataAnnotations também contém atributos de formatação como DataType esses ajudam na formatação e não fornecem nenhuma validação.

Atualize a classe Movie para tirar proveito dos atributos de validação internos Required, StringLength, RegularExpression, Range e do atributo de formatação DataType.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Os atributos de validação especificam o comportamento que você deseja impor nas propriedades do modelo às quais são aplicados:

  • Os Required atributos e MinimumLength indicam que uma propriedade deve ter um valor, mas nada impede que um usuário insira um espaço em branco para satisfazer essa validação.

  • O RegularExpression atributo é usado para limitar quais caracteres podem ser inseridos. No código anterior, "Gênero":

    • Deve usar apenas letras.
    • A primeira letra deve ser maiúscula. Espaços em branco são permitidos enquanto números e caracteres especiais não são permitidos.
  • A RegularExpression "classificação":

    • Requer que o primeiro caractere seja uma letra maiúscula.
    • Permite caracteres especiais e números em espaços subsequentes. "PG-13" é válido para uma classificação, mas não é apropriado para um "Género".
  • O Range atributo restringe um valor a dentro de um intervalo especificado.

  • O StringLength atributo permite definir o comprimento máximo de uma propriedade string e, opcionalmente, seu comprimento mínimo.

  • Os tipos de valor (como decimal, int, float, DateTime) são inerentemente necessários e não precisam do [Required] atributo.

Ter regras de validação aplicadas automaticamente pelo ASP.NET Core ajuda a tornar seu aplicativo mais robusto. Ele também garante que você não pode esquecer de validar algo e, inadvertidamente, deixar dados ruins no banco de dados.

Interface do usuário de erro de validação

Execute o aplicativo e navegue até o controlador Filmes.

Selecione o link Criar novo para adicionar um novo filme. Preencha o formulário com alguns valores inválidos. Assim que a validação do lado do cliente jQuery deteta o erro, ele exibe uma mensagem de erro.

Formulário de visualização de filme com vários erros de validação do lado do cliente jQuery

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Observe como o formulário exibiu automaticamente uma mensagem apropriada de erro de validação em todos os campos que contêm um valor inválido. Os erros são impostos tanto do lado do cliente (usando JavaScript e jQuery) quanto do lado do servidor (no caso de um usuário ter o JavaScript desativado).

Um benefício significativo é que você não precisou alterar uma única linha de código na MoviesController classe ou na Create.cshtml exibição para habilitar essa interface do usuário de validação. O controlador e as visualizações que criou anteriormente neste tutorial selecionaram automaticamente as regras de validação que especificou, utilizando atributos de validação nas propriedades da classe de modelo Movie. Validação de teste usando o Edit método de ação, e a mesma validação é aplicada.

Os dados do formulário não são enviados para o servidor até que não haja erros de validação do lado do cliente. Você pode verificar isso colocando um ponto de interrupção no método, usando a HTTP Postferramenta Fiddler ou as ferramentas de desenvolvedor F12.

Como funciona a validação

Você pode se perguntar como a interface do usuário de validação foi gerada sem atualizações para o código no controlador ou exibições. O código a seguir mostra os dois Create métodos.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

O primeiro método de ação (HTTP GET) Create exibe o formulário Create inicial. A segunda versão ([HttpPost]) lida com o envio do formulário. O segundo Create método (A [HttpPost] versão) chama ModelState.IsValid para verificar se o filme tem algum erro de validação. Chamar esse método avalia todos os atributos de validação que foram aplicados ao objeto. Se o objeto tiver erros de validação, o Create método exibirá novamente o formulário. Se não houver erros, o método salva o novo filme no banco de dados. Em nosso exemplo de filme, o formulário não é postado no servidor quando há erros de validação detetados no lado do cliente; O segundo Create método nunca é chamado quando há erros de validação do lado do cliente. Se você desabilitar o JavaScript em seu navegador, a validação do cliente será desabilitada e você poderá testar o método Create HTTP POST ModelState.IsValid detetando quaisquer erros de validação.

Você pode definir um ponto de interrupção no [HttpPost] Create método e verificar se o método nunca é chamado, a validação do lado do cliente não enviará os dados do formulário quando erros de validação forem detetados. Se você desativar o JavaScript no seu navegador e, em seguida, enviar o formulário com erros, o ponto de interrupção será atingido. Você ainda obtém validação completa sem JavaScript.

A imagem a seguir mostra como desativar o JavaScript no navegador Firefox.

Firefox: Na guia Conteúdo de Opções, desmarque a caixa de seleção Ativar Javascript.

A imagem seguinte mostra como desativar o JavaScript no navegador Chrome.

Google Chrome: Na seção Javascript de Configurações de conteúdo, selecione Não permitir que nenhum site execute JavaScript.

Depois de desativar o JavaScript, envie dados inválidos e analise o depurador.

Ao efetuar a depuração numa postagem de dados inválidos, o Intellisense mostra que o valor de ModelState.IsValid é false.

Uma parte do Create.cshtml modelo de exibição é mostrada na seguinte marcação:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

A marcação anterior é usada pelos métodos de ação para exibir o formulário inicial e exibi-lo novamente no caso de um erro.

O Auxiliar de Tag de Entrada usa os atributos DataAnnotations e produz atributos HTML necessários para a Validação do jQuery no lado do cliente. O Auxiliar de Tag de Validação exibe erros de validação. Consulte Validação para obter mais informações.

O que é realmente bom sobre essa abordagem é que nem o controlador nem o Create modelo de exibição sabem nada sobre as regras de validação reais que estão sendo aplicadas ou sobre as mensagens de erro específicas exibidas. As regras de validação e as cadeias de caracteres de erro são especificadas somente na Movie classe. Essas mesmas regras de validação são aplicadas automaticamente à vista Edit e a quaisquer outros modelos de vista que possa criar para editar o seu modelo.

Quando você precisa alterar a lógica de validação, pode fazê-lo exatamente em um lugar, adicionando atributos de validação ao modelo (neste exemplo, a Movie classe). Você não terá que se preocupar com diferentes partes do aplicativo sendo inconsistentes com a forma como as regras são aplicadas — toda a lógica de validação será definida em um só lugar e usada em todos os lugares. Isso mantém o código muito limpo e facilita a manutenção e a evolução. E isso significa que você estará honrando totalmente o princípio DRY.

Usando Atributos de Tipo de Dados

Abra o Movie.cs arquivo e examine a Movie classe. O System.ComponentModel.DataAnnotations namespace fornece atributos de formatação, além do conjunto interno de atributos de validação. Já aplicamos um DataType valor de enumeração à data de lançamento e aos campos de preço. O código a seguir mostra as ReleaseDate propriedades e Price com o atributo apropriado DataType .

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Os DataType atributos fornecem apenas dicas para o mecanismo de exibição formatar os dados e fornecem elementos/atributos, como <a> URLs e <a href="mailto:EmailAddress.com"> e-mails. Você pode usar o RegularExpression atributo para validar o formato dos dados. O DataType atributo é usado para especificar um tipo de dados que é mais específico do que o tipo intrínseco do banco de dados, eles não são atributos de validação. Neste caso, queremos apenas acompanhar a data, não a hora. A DataType enumeração fornece para muitos tipos de dados, como data, hora, número de telefone, moeda, endereço de e-mail e muito mais. O DataType atributo também pode permitir que o aplicativo forneça automaticamente recursos específicos do tipo. Por exemplo, um mailto: link pode ser criado para DataType.EmailAddress, e um seletor de data pode ser fornecido nos DataType.Date navegadores que suportam HTML5. Os DataType atributos emitem atributos HTML 5 data- (pronuncia-se traço de dados) que os navegadores HTML 5 podem entender. Os DataType atributos não fornecem nenhuma validação.

DataType.Date não especifica o formato da data exibida. Por padrão, o campo de dados é exibido de acordo com os formatos padrão baseados no CultureInfo do servidor.

O DisplayFormat atributo é usado para especificar explicitamente o formato de data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

A ApplyFormatInEditMode configuração especifica que a formatação também deve ser aplicada quando o valor é exibido em uma caixa de texto para edição. (Talvez você não queira isso para alguns campos — por exemplo, para valores de moeda, provavelmente não deseja que o símbolo de moeda na caixa de texto seja editado.)

Você pode usar o DisplayFormat atributo por si só, mas geralmente é uma boa ideia usar o DataType atributo. O DataType atributo transmite a semântica dos dados em oposição a como renderizá-los em uma tela e fornece os seguintes benefícios que você não obtém com DisplayFormat:

  • O navegador pode habilitar recursos HTML5 (por exemplo, para mostrar um controle de calendário, o símbolo de moeda apropriado à localidade, links de e-mail, etc.)

  • Por padrão, o navegador renderizará dados usando o formato correto com base na sua localidade.

  • O DataType atributo pode permitir que o MVC escolha o modelo de campo certo para renderizar os dados (o DisplayFormat se usado por si só usa o modelo de cadeia de caracteres).

Observação

A validação do jQuery não funciona com os atributos Range e DateTime. Por exemplo, o código a seguir sempre exibirá um erro de validação do lado do cliente, mesmo quando a data estiver no intervalo especificado:

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

Você precisará desabilitar a validação de data do jQuery para usar o Range atributo com DateTime. Geralmente, não é uma boa prática compilar datas fixas ou rígidas nos modelos, portanto, usar o atributo Range e DateTime é desencorajado.

O código a seguir mostra a combinação de atributos em uma linha:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Na próxima parte da série, analisamos o app e fazemos algumas melhorias nos Details métodos Delete gerados automaticamente.

Recursos adicionais

Nesta secção:

  • A lógica de validação é adicionada ao modelo Movie.
  • Você garante que as regras de validação sejam aplicadas sempre que um usuário criar ou editar um filme.

Manter as coisas SECAS

Um dos princípios de design do MVC é DRY ("Don't Repeat Yourself"). ASP.NET MVC principal incentiva você a especificar a funcionalidade ou o comportamento apenas uma vez e, em seguida, fazer com que ele seja refletido em todos os lugares de um aplicativo. Isso reduz a quantidade de código que você precisa escrever e torna o código que você escreve menos propenso a erros, mais fácil de testar e mais fácil de manter.

O suporte de validação fornecido pelo MVC e pelo Entity Framework Core Code First é um bom exemplo do princípio DRY em ação. Você pode especificar declarativamente as regras de validação em um só lugar (na classe de modelo) e as regras são aplicadas em todos os lugares do aplicativo.

Adicionar regras de validação ao modelo de filme

O namespace DataAnnotations fornece um conjunto de atributos de validação internos que são aplicados declarativamente a uma classe ou propriedade. DataAnnotations também contém atributos de formatação como DataType esses ajudam na formatação e não fornecem nenhuma validação.

Atualize a classe Movie para tirar proveito dos atributos de validação internos Required, StringLength, RegularExpression, Range e do atributo de formatação DataType.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string? Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }    

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string? Genre { get; set; }
    
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string? Rating { get; set; }
}

Os atributos de validação especificam o comportamento que você deseja impor nas propriedades do modelo às quais são aplicados:

  • Os Required atributos e MinimumLength indicam que uma propriedade deve ter um valor, mas nada impede que um usuário insira um espaço em branco para satisfazer essa validação.

  • O RegularExpression atributo é usado para limitar quais caracteres podem ser inseridos. No código anterior, "Gênero":

    • Deve usar apenas letras.
    • A primeira letra deve ser maiúscula. Espaços em branco são permitidos enquanto números e caracteres especiais não são permitidos.
  • A RegularExpression "classificação":

    • Requer que o primeiro caractere seja uma letra maiúscula.
    • Permite caracteres especiais e números em espaços subsequentes. "PG-13" é válido para uma classificação, mas não é apropriado para um "Género".
  • O Range atributo restringe um valor a dentro de um intervalo especificado.

  • O StringLength atributo permite definir o comprimento máximo de uma propriedade string e, opcionalmente, seu comprimento mínimo.

  • Os tipos de valor (como decimal, int, float, DateTime) são inerentemente necessários e não precisam do [Required] atributo.

Ter regras de validação aplicadas automaticamente pelo ASP.NET Core ajuda a tornar seu aplicativo mais robusto. Ele também garante que você não pode esquecer de validar algo e, inadvertidamente, deixar dados ruins no banco de dados.

Interface do usuário de erro de validação

Execute o aplicativo e navegue até o controlador Filmes.

Selecione o link Criar novo para adicionar um novo filme. Preencha o formulário com alguns valores inválidos. Assim que a validação do lado do cliente jQuery deteta o erro, ele exibe uma mensagem de erro.

Formulário de visualização de filme com vários erros de validação do lado do cliente jQuery

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Observe como o formulário exibiu automaticamente uma mensagem apropriada de erro de validação em todos os campos que contêm um valor inválido. Os erros são impostos tanto do lado do cliente (usando JavaScript e jQuery) quanto do lado do servidor (no caso de um usuário ter o JavaScript desativado).

Um benefício significativo é que você não precisou alterar uma única linha de código na MoviesController classe ou na Create.cshtml exibição para habilitar essa interface do usuário de validação. O controlador e as visualizações que criou anteriormente neste tutorial selecionaram automaticamente as regras de validação que especificou, utilizando atributos de validação nas propriedades da classe de modelo Movie. Validação de teste usando o Edit método de ação, e a mesma validação é aplicada.

Os dados do formulário não são enviados para o servidor até que não haja erros de validação do lado do cliente. Você pode verificar isso colocando um ponto de interrupção no método, usando a HTTP Postferramenta Fiddler ou as ferramentas de desenvolvedor F12.

Como funciona a validação

Você pode se perguntar como a interface do usuário de validação foi gerada sem atualizações para o código no controlador ou exibições. O código a seguir mostra os dois Create métodos.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

O primeiro método de ação (HTTP GET) Create exibe o formulário Create inicial. A segunda versão ([HttpPost]) lida com o envio do formulário. O segundo Create método (A [HttpPost] versão) chama ModelState.IsValid para verificar se o filme tem algum erro de validação. Chamar esse método avalia todos os atributos de validação que foram aplicados ao objeto. Se o objeto tiver erros de validação, o Create método exibirá novamente o formulário. Se não houver erros, o método salva o novo filme no banco de dados. Em nosso exemplo de filme, o formulário não é postado no servidor quando há erros de validação detetados no lado do cliente; O segundo Create método nunca é chamado quando há erros de validação do lado do cliente. Se você desabilitar o JavaScript em seu navegador, a validação do cliente será desabilitada e você poderá testar o método Create HTTP POST ModelState.IsValid detetando quaisquer erros de validação.

Você pode definir um ponto de interrupção no [HttpPost] Create método e verificar se o método nunca é chamado, a validação do lado do cliente não enviará os dados do formulário quando erros de validação forem detetados. Se você desativar o JavaScript no seu navegador e, em seguida, enviar o formulário com erros, o ponto de interrupção será atingido. Você ainda obtém validação completa sem JavaScript.

A imagem a seguir mostra como desativar o JavaScript no navegador Firefox.

Firefox: Na guia Conteúdo de Opções, desmarque a caixa de seleção Ativar Javascript.

A imagem seguinte mostra como desativar o JavaScript no navegador Chrome.

Google Chrome: Na seção Javascript de Configurações de conteúdo, selecione Não permitir que nenhum site execute JavaScript.

Depois de desativar o JavaScript, envie dados inválidos e analise o depurador.

Ao efetuar a depuração numa postagem de dados inválidos, o Intellisense mostra que o valor de ModelState.IsValid é false.

Uma parte do Create.cshtml modelo de exibição é mostrada na seguinte marcação:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

A marcação anterior é usada pelos métodos de ação para exibir o formulário inicial e exibi-lo novamente no caso de um erro.

O Auxiliar de Tag de Entrada usa os atributos DataAnnotations e produz atributos HTML necessários para a Validação do jQuery no lado do cliente. O Auxiliar de Tag de Validação exibe erros de validação. Consulte Validação para obter mais informações.

O que é realmente bom sobre essa abordagem é que nem o controlador nem o Create modelo de exibição sabem nada sobre as regras de validação reais que estão sendo aplicadas ou sobre as mensagens de erro específicas exibidas. As regras de validação e as cadeias de caracteres de erro são especificadas somente na Movie classe. Essas mesmas regras de validação são aplicadas automaticamente à vista Edit e a quaisquer outros modelos de vista que possa criar para editar o seu modelo.

Quando você precisa alterar a lógica de validação, pode fazê-lo exatamente em um lugar, adicionando atributos de validação ao modelo (neste exemplo, a Movie classe). Você não terá que se preocupar com diferentes partes do aplicativo sendo inconsistentes com a forma como as regras são aplicadas — toda a lógica de validação será definida em um só lugar e usada em todos os lugares. Isso mantém o código muito limpo e facilita a manutenção e a evolução. E isso significa que você estará honrando totalmente o princípio DRY.

Usando Atributos de Tipo de Dados

Abra o Movie.cs arquivo e examine a Movie classe. O System.ComponentModel.DataAnnotations namespace fornece atributos de formatação, além do conjunto interno de atributos de validação. Já aplicamos um DataType valor de enumeração à data de lançamento e aos campos de preço. O código a seguir mostra as ReleaseDate propriedades e Price com o atributo apropriado DataType .

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }    

Os DataType atributos fornecem apenas dicas para o mecanismo de exibição formatar os dados e fornecem elementos/atributos, como <a> URLs e <a href="mailto:EmailAddress.com"> e-mails. Você pode usar o RegularExpression atributo para validar o formato dos dados. O DataType atributo é usado para especificar um tipo de dados que é mais específico do que o tipo intrínseco do banco de dados, eles não são atributos de validação. Neste caso, queremos apenas acompanhar a data, não a hora. A DataType enumeração fornece para muitos tipos de dados, como data, hora, número de telefone, moeda, endereço de e-mail e muito mais. O DataType atributo também pode permitir que o aplicativo forneça automaticamente recursos específicos do tipo. Por exemplo, um mailto: link pode ser criado para DataType.EmailAddress, e um seletor de data pode ser fornecido nos DataType.Date navegadores que suportam HTML5. Os DataType atributos emitem atributos HTML 5 data- (pronuncia-se traço de dados) que os navegadores HTML 5 podem entender. Os DataType atributos não fornecem nenhuma validação.

DataType.Date não especifica o formato da data exibida. Por padrão, o campo de dados é exibido de acordo com os formatos padrão baseados no CultureInfo do servidor.

O DisplayFormat atributo é usado para especificar explicitamente o formato de data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

A ApplyFormatInEditMode configuração especifica que a formatação também deve ser aplicada quando o valor é exibido em uma caixa de texto para edição. (Talvez você não queira isso para alguns campos — por exemplo, para valores de moeda, provavelmente não deseja que o símbolo de moeda na caixa de texto seja editado.)

Você pode usar o DisplayFormat atributo por si só, mas geralmente é uma boa ideia usar o DataType atributo. O DataType atributo transmite a semântica dos dados em oposição a como renderizá-los em uma tela e fornece os seguintes benefícios que você não obtém com DisplayFormat:

  • O navegador pode habilitar recursos HTML5 (por exemplo, para mostrar um controle de calendário, o símbolo de moeda apropriado à localidade, links de e-mail, etc.)

  • Por padrão, o navegador renderizará dados usando o formato correto com base na sua localidade.

  • O DataType atributo pode permitir que o MVC escolha o modelo de campo certo para renderizar os dados (o DisplayFormat se usado por si só usa o modelo de cadeia de caracteres).

Observação

A validação do jQuery não funciona com os atributos Range e DateTime. Por exemplo, o código a seguir sempre exibirá um erro de validação do lado do cliente, mesmo quando a data estiver no intervalo especificado:

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

Você precisará desabilitar a validação de data do jQuery para usar o Range atributo com DateTime. Geralmente, não é uma boa prática compilar datas fixas ou rígidas nos modelos, portanto, usar o atributo Range e DateTime é desencorajado.

O código a seguir mostra a combinação de atributos em uma linha:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models;

public class Movie
{
    public int Id { get; set; }
    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }
    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }
    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }
    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Na próxima parte da série, analisamos o app e fazemos algumas melhorias nos Details métodos Delete gerados automaticamente.

Recursos adicionais

Nesta secção:

  • A lógica de validação é adicionada ao modelo Movie.
  • Você garante que as regras de validação sejam aplicadas sempre que um usuário criar ou editar um filme.

Manter as coisas SECAS

Um dos princípios de design do MVC é DRY ("Don't Repeat Yourself"). ASP.NET MVC principal incentiva você a especificar a funcionalidade ou o comportamento apenas uma vez e, em seguida, fazer com que ele seja refletido em todos os lugares de um aplicativo. Isso reduz a quantidade de código que você precisa escrever e torna o código que você escreve menos propenso a erros, mais fácil de testar e mais fácil de manter.

O suporte de validação fornecido pelo MVC e pelo Entity Framework Core Code First é um bom exemplo do princípio DRY em ação. Você pode especificar declarativamente as regras de validação em um só lugar (na classe de modelo) e as regras são aplicadas em todos os lugares do aplicativo.

Adicionar regras de validação ao modelo de filme

O namespace DataAnnotations fornece um conjunto de atributos de validação internos que são aplicados declarativamente a uma classe ou propriedade. DataAnnotations também contém atributos de formatação como DataType esses ajudam na formatação e não fornecem nenhuma validação.

Atualize a Movie classe para aproveitar os atributos internos Required, StringLength, RegularExpressione Range de validação.

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        [Required]
        public string? Title { get; set; }

        [Display(Name = "Release Date")]
        [DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [Range(1, 100)]
        [DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
        [Required]
        [StringLength(30)]
        public string? Genre { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
        [StringLength(5)]
        [Required]
        public string? Rating { get; set; }
    }
}

Os atributos de validação especificam o comportamento que você deseja impor nas propriedades do modelo às quais são aplicados:

  • Os Required atributos e MinimumLength indicam que uma propriedade deve ter um valor, mas nada impede que um usuário insira um espaço em branco para satisfazer essa validação.

  • O RegularExpression atributo é usado para limitar quais caracteres podem ser inseridos. No código anterior, "Gênero":

    • Deve usar apenas letras.
    • A primeira letra deve ser maiúscula. Espaços em branco são permitidos enquanto números e caracteres especiais não são permitidos.
  • A RegularExpression "classificação":

    • Requer que o primeiro caractere seja uma letra maiúscula.
    • Permite caracteres especiais e números em espaços subsequentes. "PG-13" é válido para uma classificação, mas não é apropriado para um "Género".
  • O Range atributo restringe um valor a dentro de um intervalo especificado.

  • O StringLength atributo permite definir o comprimento máximo de uma propriedade string e, opcionalmente, seu comprimento mínimo.

  • Os tipos de valor (como decimal, int, float, DateTime) são inerentemente necessários e não precisam do [Required] atributo.

Ter regras de validação aplicadas automaticamente pelo ASP.NET Core ajuda a tornar seu aplicativo mais robusto. Ele também garante que você não pode esquecer de validar algo e, inadvertidamente, deixar dados ruins no banco de dados.

Interface do usuário de erro de validação

Execute o aplicativo e navegue até o controlador Filmes.

Selecione o link Criar novo para adicionar um novo filme. Preencha o formulário com alguns valores inválidos. Assim que a validação do lado do cliente jQuery deteta o erro, ele exibe uma mensagem de erro.

Formulário de visualização de filme com vários erros de validação do lado do cliente jQuery

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Observe como o formulário exibiu automaticamente uma mensagem apropriada de erro de validação em todos os campos que contêm um valor inválido. Os erros são impostos tanto do lado do cliente (usando JavaScript e jQuery) quanto do lado do servidor (no caso de um usuário ter o JavaScript desativado).

Um benefício significativo é que você não precisou alterar uma única linha de código na MoviesController classe ou na Create.cshtml exibição para habilitar essa interface do usuário de validação. O controlador e as visualizações que criou anteriormente neste tutorial selecionaram automaticamente as regras de validação que especificou, utilizando atributos de validação nas propriedades da classe de modelo Movie. Validação de teste usando o Edit método de ação, e a mesma validação é aplicada.

Os dados do formulário não são enviados para o servidor até que não haja erros de validação do lado do cliente. Você pode verificar isso colocando um ponto de interrupção no método, usando a HTTP Postferramenta Fiddler ou as ferramentas de desenvolvedor F12.

Como funciona a validação

Você pode se perguntar como a interface do usuário de validação foi gerada sem atualizações para o código no controlador ou exibições. O código a seguir mostra os dois Create métodos.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
// To protect from overposting attacks, enable the specific properties you want to bind to.
// For more details, see http://go.microsoft.com/fwlink/?LinkId=317598.
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create([Bind("Id,Title,ReleaseDate,Genre,Price,Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction(nameof(Index));
    }
    return View(movie);
}

O primeiro método de ação (HTTP GET) Create exibe o formulário Create inicial. A segunda versão ([HttpPost]) lida com o envio do formulário. O segundo Create método (A [HttpPost] versão) chama ModelState.IsValid para verificar se o filme tem algum erro de validação. Chamar esse método avalia todos os atributos de validação que foram aplicados ao objeto. Se o objeto tiver erros de validação, o Create método exibirá novamente o formulário. Se não houver erros, o método salva o novo filme no banco de dados. Em nosso exemplo de filme, o formulário não é postado no servidor quando há erros de validação detetados no lado do cliente; O segundo Create método nunca é chamado quando há erros de validação do lado do cliente. Se você desabilitar o JavaScript em seu navegador, a validação do cliente será desabilitada e você poderá testar o método Create HTTP POST ModelState.IsValid detetando quaisquer erros de validação.

Você pode definir um ponto de interrupção no [HttpPost] Create método e verificar se o método nunca é chamado, a validação do lado do cliente não enviará os dados do formulário quando erros de validação forem detetados. Se você desativar o JavaScript no seu navegador e, em seguida, enviar o formulário com erros, o ponto de interrupção será atingido. Você ainda obtém validação completa sem JavaScript.

A imagem a seguir mostra como desativar o JavaScript no navegador Firefox.

Firefox: Na guia Conteúdo de Opções, desmarque a caixa de seleção Ativar Javascript.

A imagem seguinte mostra como desativar o JavaScript no navegador Chrome.

Google Chrome: Na seção Javascript de Configurações de conteúdo, selecione Não permitir que nenhum site execute JavaScript.

Depois de desativar o JavaScript, envie dados inválidos e analise o depurador.

Ao efetuar a depuração numa postagem de dados inválidos, o Intellisense mostra que o valor de ModelState.IsValid é false.

Uma parte do Create.cshtml modelo de exibição é mostrada na seguinte marcação:

<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>

            @*Markup removed for brevity.*@

A marcação anterior é usada pelos métodos de ação para exibir o formulário inicial e exibi-lo novamente no caso de um erro.

O Auxiliar de Tag de Entrada usa os atributos DataAnnotations e produz atributos HTML necessários para a Validação do jQuery no lado do cliente. O Auxiliar de Tag de Validação exibe erros de validação. Consulte Validação para obter mais informações.

O que é realmente bom sobre essa abordagem é que nem o controlador nem o Create modelo de exibição sabem nada sobre as regras de validação reais que estão sendo aplicadas ou sobre as mensagens de erro específicas exibidas. As regras de validação e as cadeias de caracteres de erro são especificadas somente na Movie classe. Essas mesmas regras de validação são aplicadas automaticamente à vista Edit e a quaisquer outros modelos de vista que possa criar para editar o seu modelo.

Quando você precisa alterar a lógica de validação, pode fazê-lo exatamente em um lugar, adicionando atributos de validação ao modelo (neste exemplo, a Movie classe). Você não terá que se preocupar com diferentes partes do aplicativo sendo inconsistentes com a forma como as regras são aplicadas — toda a lógica de validação será definida em um só lugar e usada em todos os lugares. Isso mantém o código muito limpo e facilita a manutenção e a evolução. E isso significa que você estará honrando totalmente o princípio DRY.

Usando Atributos de Tipo de Dados

Abra o Movie.cs arquivo e examine a Movie classe. O System.ComponentModel.DataAnnotations namespace fornece atributos de formatação, além do conjunto interno de atributos de validação. Já aplicamos um DataType valor de enumeração à data de lançamento e aos campos de preço. O código a seguir mostra as ReleaseDate propriedades e Price com o atributo apropriado DataType .

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
[Column(TypeName = "decimal(18, 2)")]
public decimal Price { get; set; }

Os DataType atributos fornecem apenas dicas para o mecanismo de exibição formatar os dados e fornecem elementos/atributos, como <a> URLs e <a href="mailto:EmailAddress.com"> e-mails. Você pode usar o RegularExpression atributo para validar o formato dos dados. O DataType atributo é usado para especificar um tipo de dados que é mais específico do que o tipo intrínseco do banco de dados, eles não são atributos de validação. Neste caso, queremos apenas acompanhar a data, não a hora. A DataType enumeração fornece para muitos tipos de dados, como data, hora, número de telefone, moeda, endereço de e-mail e muito mais. O DataType atributo também pode permitir que o aplicativo forneça automaticamente recursos específicos do tipo. Por exemplo, um mailto: link pode ser criado para DataType.EmailAddress, e um seletor de data pode ser fornecido nos DataType.Date navegadores que suportam HTML5. Os DataType atributos emitem atributos HTML 5 data- (pronuncia-se traço de dados) que os navegadores HTML 5 podem entender. Os DataType atributos não fornecem nenhuma validação.

DataType.Date não especifica o formato da data exibida. Por padrão, o campo de dados é exibido de acordo com os formatos padrão baseados no CultureInfo do servidor.

O DisplayFormat atributo é usado para especificar explicitamente o formato de data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

A ApplyFormatInEditMode configuração especifica que a formatação também deve ser aplicada quando o valor é exibido em uma caixa de texto para edição. (Talvez você não queira isso para alguns campos — por exemplo, para valores de moeda, provavelmente não deseja que o símbolo de moeda na caixa de texto seja editado.)

Você pode usar o DisplayFormat atributo por si só, mas geralmente é uma boa ideia usar o DataType atributo. O DataType atributo transmite a semântica dos dados em oposição a como renderizá-los em uma tela e fornece os seguintes benefícios que você não obtém com DisplayFormat:

  • O navegador pode habilitar recursos HTML5 (por exemplo, para mostrar um controle de calendário, o símbolo de moeda apropriado à localidade, links de e-mail, etc.)

  • Por padrão, o navegador renderizará dados usando o formato correto com base na sua localidade.

  • O DataType atributo pode permitir que o MVC escolha o modelo de campo certo para renderizar os dados (o DisplayFormat se usado por si só usa o modelo de cadeia de caracteres).

Observação

A validação do jQuery não funciona com os atributos Range e DateTime. Por exemplo, o código a seguir sempre exibirá um erro de validação do lado do cliente, mesmo quando a data estiver no intervalo especificado:

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

Você precisará desabilitar a validação de data do jQuery para usar o Range atributo com DateTime. Geralmente, não é uma boa prática compilar datas fixas ou rígidas nos modelos, portanto, usar o atributo Range e DateTime é desencorajado.

O código a seguir mostra a combinação de atributos em uma linha:

using System;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace MvcMovie.Models
{
    public class Movie
    {
        public int Id { get; set; }

        [StringLength(60, MinimumLength = 3)]
        public string Title { get; set; }

        [Display(Name = "Release Date"), DataType(DataType.Date)]
        public DateTime ReleaseDate { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
        public string Genre { get; set; }

        [Range(1, 100), DataType(DataType.Currency)]
        [Column(TypeName = "decimal(18, 2)")]
        public decimal Price { get; set; }

        [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
        public string Rating { get; set; }
    }
}

Na próxima parte da série, analisamos o app e fazemos algumas melhorias nos Details métodos Delete gerados automaticamente.

Recursos adicionais

Nesta secção:

  • A lógica de validação é adicionada ao modelo Movie.
  • Você garante que as regras de validação sejam aplicadas sempre que um usuário criar ou editar um filme.

Manter as coisas SECAS

Um dos princípios de design do MVC é DRY ("Don't Repeat Yourself"). ASP.NET MVC principal incentiva você a especificar a funcionalidade ou o comportamento apenas uma vez e, em seguida, fazer com que ele seja refletido em todos os lugares de um aplicativo. Isso reduz a quantidade de código que você precisa escrever e torna o código que você escreve menos propenso a erros, mais fácil de testar e mais fácil de manter.

O suporte de validação fornecido pelo MVC e pelo Entity Framework Core Code First é um bom exemplo do princípio DRY em ação. Você pode especificar declarativamente as regras de validação em um só lugar (na classe de modelo) e as regras são aplicadas em todos os lugares do aplicativo.

Adicionar regras de validação ao modelo de filme

O namespace DataAnnotations fornece um conjunto de atributos de validação internos que são aplicados declarativamente a uma classe ou propriedade. DataAnnotations também contém atributos de formatação como DataType esses ajudam na formatação e não fornecem nenhuma validação.

Atualize a Movie classe para aproveitar os atributos internos Required, StringLength, RegularExpressione Range de validação.

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

    [StringLength(60, MinimumLength = 3)]
    [Required]
    public string Title { get; set; }

    [Display(Name = "Release Date")]
    [DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [Range(1, 100)]
    [DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$")]
    [Required]
    [StringLength(30)]
    public string Genre { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$")]
    [StringLength(5)]
    [Required]
    public string Rating { get; set; }
}

Os atributos de validação especificam o comportamento que você deseja impor nas propriedades do modelo às quais são aplicados:

  • Os Required atributos e MinimumLength indicam que uma propriedade deve ter um valor, mas nada impede que um usuário insira um espaço em branco para satisfazer essa validação.

  • O RegularExpression atributo é usado para limitar quais caracteres podem ser inseridos. No código anterior, "Gênero":

    • Deve usar apenas letras.
    • A primeira letra deve ser maiúscula. Espaços em branco são permitidos, enquanto números e caracteres especiais não são permitidos.
  • A RegularExpression "classificação":

    • Requer que o primeiro caractere seja uma letra maiúscula.
    • Permite caracteres especiais e números em espaços subsequentes. "PG-13" é válido para uma classificação, mas não é apropriado para um "Género".
  • O Range atributo restringe um valor a dentro de um intervalo especificado.

  • O StringLength atributo permite definir o comprimento máximo de uma propriedade string e, opcionalmente, seu comprimento mínimo.

  • Os tipos de valor (como decimal, int, float, DateTime) são inerentemente necessários e não precisam do [Required] atributo.

Ter regras de validação aplicadas automaticamente pelo ASP.NET Core ajuda a tornar seu aplicativo mais robusto. Ele também garante que você não pode esquecer de validar algo e, inadvertidamente, deixar dados ruins no banco de dados.

Interface do usuário de erro de validação

Execute o aplicativo e navegue até o controlador Filmes.

Toque no link Criar novo para adicionar um novo filme. Preencha o formulário com alguns valores inválidos. Assim que a validação do lado do cliente jQuery deteta o erro, ele exibe uma mensagem de erro.

Formulário de visualização de filme com vários erros de validação do lado do cliente jQuery

Observação

Talvez não seja possível inserir vírgulas decimais em campos decimais. Para dar suporte à validação do jQuery para localidades diferentes do inglês que usam uma vírgula (",") para um ponto decimal e formatos de data não US-English, você deve tomar medidas para globalizar seu aplicativo. Consulte este comentário 4076 do GitHub para obter instruções sobre como adicionar vírgula decimal.

Observe como o formulário exibiu automaticamente uma mensagem apropriada de erro de validação em todos os campos que contêm um valor inválido. Os erros são impostos tanto do lado do cliente (usando JavaScript e jQuery) quanto do lado do servidor (no caso de um usuário ter o JavaScript desativado).

Um benefício significativo é que você não precisou alterar uma única linha de código na MoviesController classe ou na Create.cshtml exibição para habilitar essa interface do usuário de validação. O controlador e as visualizações que criou anteriormente neste tutorial selecionaram automaticamente as regras de validação que especificou, utilizando atributos de validação nas propriedades da classe de modelo Movie. Validação de teste usando o Edit método de ação, e a mesma validação é aplicada.

Os dados do formulário não são enviados para o servidor até que não haja erros de validação do lado do cliente. Você pode verificar isso colocando um ponto de interrupção no método, usando a HTTP Postferramenta Fiddler ou as ferramentas de desenvolvedor F12.

Como funciona a validação

Você pode se perguntar como a interface do usuário de validação foi gerada sem atualizações para o código no controlador ou exibições. O código a seguir mostra os dois Create métodos.

// GET: Movies/Create
public IActionResult Create()
{
    return View();
}

// POST: Movies/Create
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Create(
    [Bind("ID,Title,ReleaseDate,Genre,Price, Rating")] Movie movie)
{
    if (ModelState.IsValid)
    {
        _context.Add(movie);
        await _context.SaveChangesAsync();
        return RedirectToAction("Index");
    }
    return View(movie);
}

O primeiro método de ação (HTTP GET) Create exibe o formulário Create inicial. A segunda versão ([HttpPost]) lida com o envio do formulário. O segundo Create método (A [HttpPost] versão) chama ModelState.IsValid para verificar se o filme tem algum erro de validação. Chamar esse método avalia todos os atributos de validação que foram aplicados ao objeto. Se o objeto tiver erros de validação, o Create método exibirá novamente o formulário. Se não houver erros, o método salva o novo filme no banco de dados. Em nosso exemplo de filme, o formulário não é postado no servidor quando há erros de validação detetados no lado do cliente; O segundo Create método nunca é chamado quando há erros de validação do lado do cliente. Se você desabilitar o JavaScript em seu navegador, a validação do cliente será desabilitada e você poderá testar o método Create HTTP POST ModelState.IsValid detetando quaisquer erros de validação.

Você pode definir um ponto de interrupção no [HttpPost] Create método e verificar se o método nunca é chamado, a validação do lado do cliente não enviará os dados do formulário quando erros de validação forem detetados. Se você desativar o JavaScript no seu navegador e, em seguida, enviar o formulário com erros, o ponto de interrupção será atingido. Você ainda obtém validação completa sem JavaScript.

A imagem a seguir mostra como desativar o JavaScript no navegador Firefox.

Firefox: Na guia Conteúdo de Opções, desmarque a caixa de seleção Ativar Javascript.

A imagem seguinte mostra como desativar o JavaScript no navegador Chrome.

Google Chrome: Na seção Javascript de Configurações de conteúdo, selecione Não permitir que nenhum site execute JavaScript.

Depois de desativar o JavaScript, envie dados inválidos e analise o depurador.

Ao efetuar a depuração numa postagem de dados inválidos, o Intellisense mostra que o valor de ModelState.IsValid é false.

A parte do Create.cshtml modelo de exibição é mostrada na seguinte marcação:


<h4>Movie</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form asp-action="Create">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <div class="form-group">
                <label asp-for="Title" class="control-label"></label>
                <input asp-for="Title" class="form-control" />
                <span asp-validation-for="Title" class="text-danger"></span>
            </div>           
       
        @*Markup removed for brevity.*@

A marcação anterior é usada pelos métodos de ação para exibir o formulário inicial e exibi-lo novamente no caso de um erro.

O Auxiliar de Tag de Entrada usa os atributos DataAnnotations e produz atributos HTML necessários para a Validação do jQuery no lado do cliente. O Auxiliar de Tag de Validação exibe erros de validação. Consulte Validação para obter mais informações.

O que é realmente bom sobre essa abordagem é que nem o controlador nem o Create modelo de exibição sabem nada sobre as regras de validação reais que estão sendo aplicadas ou sobre as mensagens de erro específicas exibidas. As regras de validação e as cadeias de caracteres de erro são especificadas somente na Movie classe. Essas mesmas regras de validação são aplicadas automaticamente à vista Edit e a quaisquer outros modelos de vista que possa criar para editar o seu modelo.

Quando você precisa alterar a lógica de validação, pode fazê-lo exatamente em um lugar, adicionando atributos de validação ao modelo (neste exemplo, a Movie classe). Você não terá que se preocupar com diferentes partes do aplicativo sendo inconsistentes com a forma como as regras são aplicadas — toda a lógica de validação será definida em um só lugar e usada em todos os lugares. Isso mantém o código muito limpo e facilita a manutenção e a evolução. E isso significa que você estará honrando totalmente o princípio DRY.

Usando Atributos de Tipo de Dados

Abra o Movie.cs arquivo e examine a Movie classe. O System.ComponentModel.DataAnnotations namespace fornece atributos de formatação, além do conjunto interno de atributos de validação. Já aplicamos um DataType valor de enumeração à data de lançamento e aos campos de preço. O código a seguir mostra as ReleaseDate propriedades e Price com o atributo apropriado DataType .

[Display(Name = "Release Date")]
[DataType(DataType.Date)]
public DateTime ReleaseDate { get; set; }

[Range(1, 100)]
[DataType(DataType.Currency)]
public decimal Price { get; set; }

Os atributos DataType fornecem apenas dicas para o mecanismo de exibição formatar os dados, fornecendo elementos/atributos, como <a> para URLs e <a href="mailto:EmailAddress.com"> para e-mails. Você pode usar o RegularExpression atributo para validar o formato dos dados. O DataType atributo é usado para especificar um tipo de dados que é mais específico do que o tipo intrínseco do banco de dados, eles não são atributos de validação. Neste caso, queremos apenas acompanhar a data, não a hora. A DataType enumeração fornece para muitos tipos de dados, como data, hora, número de telefone, moeda, endereço de e-mail e muito mais. O DataType atributo também pode permitir que o aplicativo forneça automaticamente recursos específicos do tipo. Por exemplo, um mailto: link pode ser criado para DataType.EmailAddress, e um seletor de data pode ser fornecido nos DataType.Date navegadores que suportam HTML5. Os DataType atributos emitem atributos HTML 5 data- (pronuncia-se traço de dados) que os navegadores HTML 5 podem entender. Os DataType atributos não fornecem nenhuma validação.

DataType.Date não especifica o formato da data exibida. Por padrão, o campo de dados é exibido de acordo com os formatos padrão baseados no CultureInfo do servidor.

O DisplayFormat atributo é usado para especificar explicitamente o formato de data:

[DisplayFormat(DataFormatString = "{0:yyyy-MM-dd}", ApplyFormatInEditMode = true)]
public DateTime ReleaseDate { get; set; }

A ApplyFormatInEditMode configuração especifica que a formatação também deve ser aplicada quando o valor é exibido em uma caixa de texto para edição. (Talvez você não queira isso para alguns campos — por exemplo, para valores de moeda, provavelmente não deseja que o símbolo de moeda na caixa de texto seja editado.)

Você pode usar o DisplayFormat atributo por si só, mas geralmente é uma boa ideia usar o DataType atributo. O DataType atributo transmite a semântica dos dados em oposição a como renderizá-los em uma tela e fornece os seguintes benefícios que você não obtém com DisplayFormat:

  • O navegador pode habilitar recursos HTML5 (por exemplo, para mostrar um controle de calendário, o símbolo de moeda apropriado à localidade, links de e-mail, etc.)

  • Por padrão, o navegador renderizará dados usando o formato correto com base na sua localidade.

  • O DataType atributo pode permitir que o MVC escolha o modelo de campo certo para renderizar os dados (o DisplayFormat se usado por si só usa o modelo de cadeia de caracteres).

Observação

A validação do jQuery não funciona com os atributos Range e DateTime. Por exemplo, o código a seguir sempre exibirá um erro de validação do lado do cliente, mesmo quando a data estiver no intervalo especificado:

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

Você precisará desabilitar a validação de data do jQuery para usar o Range atributo com DateTime. Geralmente, não é uma boa prática compilar datas fixas ou rígidas nos modelos, portanto, usar o atributo Range e DateTime é desencorajado.

O código a seguir mostra a combinação de atributos em uma linha:

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

    [StringLength(60, MinimumLength = 3)]
    public string Title { get; set; }

    [Display(Name = "Release Date"), DataType(DataType.Date)]
    public DateTime ReleaseDate { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z\s]*$"), Required, StringLength(30)]
    public string Genre { get; set; }

    [Range(1, 100), DataType(DataType.Currency)]
    [Column(TypeName = "decimal(18, 2)")]
    public decimal Price { get; set; }

    [RegularExpression(@"^[A-Z]+[a-zA-Z0-9""'\s-]*$"), StringLength(5)]
    public string Rating { get; set; }
}

Na próxima parte da série, analisamos o app e fazemos algumas melhorias nos Details métodos Delete gerados automaticamente.

Recursos adicionais