ASP .NET Core - Criando uma aplicação ASP .NET Core MVC com o VS 2017 - VI

 Neste artigo eu vou mostrar como criar uma aplicação ASP .NET Core MVC usando o VS 2017.

Continuando a quinta parte do artigo vamos ajustar os métodos do controller FilmesController e das respectivas Views geradas.

Vamos começar abrindo o arquivo Filme na pasta Models e incluir as linhas de código destacas em azul conforme mostrado a seguir:

using System;
using System.ComponentModel.DataAnnotations;
namespace MvcFilme.Models
{
    public class Filme
    {
        public int ID { get; set; }
        public string Titulo { get; set; }

        [Display(Name = "Data de Lançamento")]
        [DataType(DataType.Date)]
        public DateTime Lancamento { get; set; }

        [Display(Name = "Gênero")]
        public string Genero { get; set; }

        [Display(Name = "Preço")]
        public decimal Preco { get; set; }
    }
}

Incluimos alguns atributos que vão alterar a exibição e a formatação das propriedades. Esses atributos são conhecidos como atributos Data Annotations.

Os atributos Data Annotations foram introduzido no .NET 3.5 como uma forma de adicionar a validação para as classes usadas por aplicações ASP.NET.

Para usar este recurso devemos incluir o namespace System.ComponentModel.DataAnnotations, pois é ele que provê atributos de classes (usados para definir metadados) e métodos que podemos usar em nossas classes para alterar as convenções padrão e definir um comportamento personalizado que pode ser usado em vários cenários.

Incluimos os atributos Display nas propriedades Lancamento, Genero e Preco e o atributo DataType no atributo Lancamento. Esses atributos permitem validar e alterar a exibição do texto das propriedades.

O atributo Display especifica oque exibir para o nome do campo. No exemplo iremos exibir o nome Data de Lançamento para o campo Lancamento e os nomes Gênero e Preço para os respectivos campos.

O atributo DataType especifica o tipo de dados (Date), de forma que a informação armazenada será a data e hora mas somente a data será exibida na view.

Após essas alterações vamos executar a aplicação e clicar no link para exibir os filmes. Iremos obter o seguinte resultado:

Observe que a View agora exibe os nomes  Data de Lançamento, Gênero e Preço conforme a definição usada nos atributos na classe Filme.

Veja também que cada filme exibe links para realizar a edição do filme, exibir os detalhes do filme e deletar o filme no final da linha de cada filme.

Podemos ver a definição desses links no arquivo Index.cshtml da pasta Views/Filmes. Abaixo vemos o trecho de código que mostra esta definição :

             ...
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Genero)
            </td>
            <td>
                @Html.DisplayFor(modelItem => item.Preco)
            </td>
            <td>
                <a asp-action="Edit" asp-route-id="@item.ID">Edit</a> |
             <a asp-action="Details" asp-route-id="@item.ID">Details</a> |
             <a asp-action="Delete" asp-route-id="@item.ID">Delete</a>
            </td>
        </tr>
}
    </tbody>
</table>

Os links Edit, Details e Delete são gerados pela Tag Helper MVC Core Anchor no arquivo /Filmes/Index.cshtml.

As Tag Helpers permitem que o código do lado do servidor participe na criação e renderização de elementos HTML nos arquivos Razor. No código acima, a tag helper Anchor gera dinamicamente o valor do atributo HTML href a partir do método Action do controlador e do id da rota.

Assim, esta tag helper foi usada para gerar atributos href para vincular(link) para uma determinada ação do controlador ou rota MVC. Ela é uma alternativa ao uso de métodos @Html.ActionLink ou @Url.Action. Veja um exemplo comparando as abordagens abaixo:

@Html.ActionLink("Registrar", "Registrar", "Conta")
<a href="@Url.Action("Registrra", "Conta")">Registrar</a>
<a asp-controller="Conta" asp-action="Registrar">Registrar</a>

Abaixo vemos como o código acima é renderizado após a página ser exibida no navegador:

      ....
     <td>
          <a href="/Filmes/Edit/5">Edit</a> |
          <a href="/Filmes/Details/5">Details</a>     |
          <a href="/Filmes/Delete/5">Delete</a>
    </td>
     .....

Mas qual a lógica é usada para renderizar o link nesse formato ?

Para saber isso devemos ver as configurações de roteamento no arquivo Startup.cs :

        ....
       app.UseMvc(routes =>
       {
                routes.MapRoute(
                    name: "default",
                    template: "{controller=Home}/{action=Index}/{id?}");     
            });
            SeedData.Initialize(app.ApplicationServices);
        }
    }
}

Seguindo a lógica definida no roteamento a ASP.NET Core converte a url http://localhost:1234/Filmes/Edit/4 em uma requisição (request) para o método Action Edit do controlador FilmesController com o parâmetro Id igual 4.

No controlador FilmesController temos dois métodos Edit. Vamos examinar cada um deles. Abra o arquivo FilmesController na pasta Controllers no primeiro método Action Edit visto a seguir:

       // GET: Filmes/Edit/5
        public async Task<IActionResult> Edit(int? id)
        {
            if (id == null)
            {
                return NotFound();
            }
            var filme = await _context.Filme.SingleOrDefaultAsync(m => m.ID == id);
            if (filme == null)
            {
                return NotFound();
            }
            return View(filme);
        }       

Este código mostra o método HTTP GET Edit, que localiza o filme com o id informado e preenche o formulário para edição de dados gerado pelo arquivo Razor Edit.cshtml na pasta Home/Filmes.

Agora a seguir temos o segundo método Edit:

        // POST: Filmes/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("ID,Titulo,Lancamento,Genero,Preco")] Filme filme)
        {
            if (id != filme.ID)
            {
                return NotFound();
            }
            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(filme);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!FilmeExists(filme.ID))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction("Index");
            }
            return View(filme);
      }

Este código mostra o método HTTP POST Edit que processa os valores dos filmes postados no formulário quando da edição dos dados e quando o formulário for enviado(POST) ao servidor.

O atributo [Bind] é uma maneira de proteger contra a sobreposição e evitar que dados sejam injetados na requisição pois serão aceitas somente as propriedades informadas no Bind. Você só deve incluir propriedades no atributo [Bind] que você deseja alterar. (Usar ViewModels fornecer uma abordagem alternativa para evitar a sobreposição.)

O atributo [HttPost] especifica que este método Edit só pode ser invocado para requisições HTTP POST. (O atributo [HttpGet] é o padrão e não precisa ser aplicado explicitamente)

O atributo ValidateAntiForgeryToken é usado para evitar a falsificação de uma requisição POST e funciona em conjunto com o token anti-falsificação gerada na respectiva view Edit.cshtml que é gerado na view  pela tag helper Form<form asp-action="Edit">

Assim, a tag helper Form gera um token anti-falsificação oculto que deve corresponder ao token anti-falsificação [ValidateAntiForgeryToken] gerado no método Edit do controlador FilmesController.

Quando o sistema de scaffolding cria a View Edit, ele examinou a classe Filme e criou o código para renderizar elementos <label> e <input> para cada propriedade da classe.

Abaixo temos o código da View Edit gerada:

@model MvcFilme.Models.Filme
@{
    ViewData["Title"] = "Edit";
}
<h2>Edit</h2>
<form asp-action="Edit">
    <div class="form-horizontal">
        <h4>Filme</h4>
        <hr />
        <div asp-validation-summary="ModelOnly" class="text-danger"></div>
        <input type="hidden" asp-for="ID" />
        <div class="form-group">
            <label asp-for="Titulo" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Titulo" class="form-control" />
                <span asp-validation-for="Titulo" class="text-danger"></span>
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Lancamento" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Lancamento" class="form-control" />
                <span asp-validation-for="Lancamento" class="text-danger"></span>
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Genero" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Genero" class="form-control" />
                <span asp-validation-for="Genero" class="text-danger"></span>
            </div>
        </div>
        <div class="form-group">
            <label asp-for="Preco" class="col-md-2 control-label"></label>
            <div class="col-md-10">
                <input asp-for="Preco" class="form-control" />
                <span asp-validation-for="Preco" class="text-danger"></span>
            </div>
        </div>
        <div class="form-group">
            <div class="col-md-offset-2 col-md-10">
                <input type="submit" value="Save" class="btn btn-default" />
            </div>
        </div>
    </div>
</form>
<div>
    <a asp-action="Index">Back to List</a>
</div>
@section Scripts {
    @{await Html.RenderPartialAsync("_ValidationScriptsPartial");}
}

O código gerado pelo Scaffolding usa vários métodos Tag Helper para simplificar a marcação HTML. A tag helper Label exibe o nome do campo ("Titulo", "Data do Lançamento", "Gênero" ou "Preço"). A tag Helper Input renderiza o elemento HTML <input>. A Tag Helper validation exibe todas as mensagens de validação associadas a essa propriedade.

Os elementos <input> estão em um elemento HTML <form> cujo atributo Action está definido para ser postado na URL /Filmes/Edit/id.

Os dados do formulário serão postados para o servidor quando o botão Salvar for clicado. A última linha antes do elemento </form> de fechamento mostra o token XSRF oculto gerado pelo tag helper do formulário.

Vejamos novamente o código do método Action Edit do controlador FilmesController:

        // POST: Filmes/Edit/5
        [HttpPost]
        [ValidateAntiForgeryToken]
        public async Task<IActionResult> Edit(int id, [Bind("ID,Titulo,Lancamento,Genero,Preco")] Filme filme)
        {
            if (id != filme.ID)
            {
                return NotFound();
            }
            if (ModelState.IsValid)
            {
                try
                {
                    _context.Update(filme);
                    await _context.SaveChangesAsync();
                }
                catch (DbUpdateConcurrencyException)
                {
                    if (!FilmeExists(filme.ID))
                    {
                        return NotFound();
                    }
                    else
                    {
                        throw;
                    }
                }
                return RedirectToAction("Index");
            }
            return View(filme);
      }

O Model Binding aceita os valores enviados do formulários e cria um objeto Filme que é passado como o parâmetro de filme.

O método ModelState.IsValid verifica se os dados enviados no formulário podem ser usados ​​para modificar (editar ou atualizar) um objeto Filme. Se os dados estiverem válidos, serão salvos.

Os dados de filme atualizados (editados) são salvos no banco de dados chamando o método SaveChangesAsync do contexto do banco de dados.

Depois de salvar os dados, o código redireciona o usuário para o método Action Index da classe FilmesController, que exibe a coleção de filmes, incluindo as alterações feitas.

Antes de o formulário ser postadso no servidor, a validação do lado do cliente verifica as regras de validação nos campos. Se houver algum erro de validação, uma mensagem de erro é exibida e o formulário não é postado.

Se o JavaScript estiver desativado, você não terá a validação do lado do cliente, mas o servidor detectará os valores postados que não são válidos e os valores do formulário serão exibidos novamente com mensagens de erro.

Todos os métodos HttpGet em FilmesController seguem um padrão semelhante. Eles obtêm um objeto filme (ou lista de objetos, no caso de Index) e passam o objeto (modelo) para a view.

O método Create passa um objeto filme vazio para a view Create. Todos os métodos que criam, editam, excluem ou modificam dados fazem isso na sobrecarga [HttpPost] do método.

A modificação de dados em um método HTTP GET é um risco de segurança. A modificação de dados em um método HTTP GET também viola as melhores práticas HTTP e o padrão REST, que especifica que as solicitações GET não devem alterar o estado de seu aplicativo. Em outras palavras, executar uma operação GET deve ser uma operação segura que não tem efeitos colaterais e não modifica os dados persistentes.

Para concluir vamos alterar todos os textos das views geradas traduzindo-os para o português. Abaixo vemos o resultado na view Index:

Na próxima parte do artigo vamos incluir a funcionalidade de procurar dados na nossa aplicação.

(Disse Jesus) "Quem ama a sua vida perdê-la-á, e quem neste mundo odeia a sua vida, guardá-la-á para a vida eterna."
João 12:25
Veja os Destaques e novidades do SUPER DVD Visual Basic (sempre atualizado) : clique e confira !

Quer migrar para o VB .NET ?

Quer aprender C# ??

Quer aprender os conceitos da Programação Orientada a objetos ?

Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ?

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

Referências:


José Carlos Macoratti