ASP .NET Core MVC -  Consumindo uma Web API - III


  Neste artigo vamos iniciar a criação de uma WEB API usando a ASP .NET Core 3.0 para a seguir mostrar como consumir a API em uma aplicação ASP .NET Core MVC.

Continuando a segunda parte do artigo vamos agora consumir a WEB API - ReservasController criada usando uma aplicação ASP .NET Core MVC.

Vamos iniciar criando o projeto ASP .NET Core MVC usando o .NET Core 3.0.

Criando o projeto ASP .NET Core MVC

Abra o Visual Studio 2019 Community Preview e clique em New Project:

No menu File selecione Add -> New Project;

A seguir selecione :

Escolha o template ASP .NET Core Web Application e clique em Next :

A seguir informe o nome Mvc_Reservas e clique em Create.

Selecione .NET Core e ASP .NET Core 3.0 e o template Web Application (Model-View-Controller) e clique em Create:

Nosso projeto ASP .NET Core MVC foi criado.

Crie uma pasta chamada icon dentro da pasta wwwroot e inclua as imagens dos ícones que iremos usar no projeto:

Criando a entidade Reserva

Vamos criar na pasta Models do projeto a classe Reserva que vai funcionar como um DTO para que possamos consumir a Web API do projeto ApiReservas criado nos artigos anteriores. Essa classe terá a mesma estrutura definida na criação da Web API:

    public class Reserva
    {
        public int ReservaId { get; set; }
        public string Nome { get; set; }
        public string InicioLocacao { get; set; }
        public string FimLocacao { get; set; }
    }

Criando o controlador ReservasController

Vamos agora criar o controlador ReservasController onde vamos definir os métodos Action que vão consumir a API ApiReservas. Para isso vamos ter que fazer requisições a nossa API e vamos usar a classe HttpClient.

Para poder fazer a requisição teremos que informar a URL onde nossa Web API esta atendendo, e, para isso vamos excutar o projeto Web API e obter o seu endereço de URL.

A nossa Web API esta atendendo no endereço: https://localhost:44311/api/reservas

Para desserializar o JSON para o objeto Reserva, vamos usar os recursos do pacote Newtonsoft.Json.

Assim clique com o botão direito do mouse sobre a pasta Controllers e a seguir em Add -> Controller;

A seguir selecione o template - MVC Controller - Empty e clique em Add;

Informe o nome ReservasController e clique em Add.

Agora vamos definir os métodos Action e suas respectivas Views no projeto MVC.

No início do arquivo vamos definir a URL da API:

private readonly string apiUrl = " https://localhost:44311/api/reservas";

A seguir vamos criar o método Action Index com o código abaixo:

       public async Task<IActionResult> Index()
        {
            List<Reserva> listaReservas = new List<Reserva>();

            using (var httpClient = new HttpClient())
            {
                using (var response = await httpClient.GetAsync(apiUrl))
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    listaReservas = JsonConvert.DeserializeObject<List<Reserva>>(apiResponse);
                }
            }
            return View(listaReservas);
        }

Observe que o método Action Index é assíncrono (async) e que retorna um Task<IActionResult>, e que a classe HttpClient faz uma requisição assíncrona usando await e o método GetAsync() usando a Url da API. A resposta será armazenada na variável response.

Como a resposta esta no formato JSON, para poder desserializar facilmente o JSON para uma lista de objetos Reserva, ustou usando a biblioteca Newtonsoft.Json, e o código:

 listaReservas = JsonConvert.DeserializeObject<List<Reserva>>(apiResponse);

A lista de objetos reserva que são armazenados na variável "listaReservas " serão retornados à view Index como um model.

Ajustando o arquivo _Layout.cshtml

Vamos ajustar o arquivo _Layout.cshtml para exibir um link para acessar as reservas. Para isso altere o código deste arquivo incluindo as linhas de código em azul, conforme mostrado a seguir:

...

  <div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
      <ul class="navbar-nav flex-grow-1">
      <li class="nav-item">
       <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
       </li>
         <li class="nav-item">
           <a class="nav-link text-dark" asp-area="" asp-controller="
Reservas" asp-action="Index">Reservas</a>
         </li>

      </ul>
  </div>
...

Criando o arquivo de leiaute das views

Agora temos que criar a view Index na pasta Views/Reservas para exibir a lista de reservas existente.

Antes disso vamos criar uma partial view chamada _reservaLayout.cshtml na pasta /Views/Shared onde vamos definir o leiaute das todas as views usando o código abaixo neste arquivo:

<!DOCTYPE html>

<html>
<head>
    <meta name="viewport" content="width=device-width" />
    <title>@ViewBag.Title</title>
    <link asp-href-include="lib/bootstrap/dist/css/*.min.css" rel="stylesheet" />
</head>
<body>
    <div class="container-fluid">
        @RenderBody()
    </div>
</body>
</html>

Agora todas as views do nosso controlador ReservasController vão usar esse leiaute.

Clique com o botão direto do mouse no método Action Index e a seguir em Add View;

Na janela Add MVC View informe os dados conforme mostra a figura:

Note que estamos definindo como página de leiaute o nosso arquivo de leiaute: _reservaLayout.cshtml.

Criando a view Index : Exibindo uma lista de reservas

A seguir inclua o código no arquivo Index.cshtml gerado na pasta /Views/Reservas :

@model IEnumerable<Reserva>
@{
    ViewData["Title"] = "Todas as Reservas";
    Layout = "~/Views/Shared/_reservaLayout.cshtml";
}

<a asp-action="AddReserva" class="btn btn-sm btn-primary">Incluir Reserva</a>
<a asp-action="GetReserva" class="btn btn-sm btn-secondary">Obter Reserva</a>

<table class="table table-sm table-striped table-bordered m-2">
    <thead><tr>
        <th>ID</th><th>Nome</th><th>Início</th><th>Fim</th><th>Atualiza</th><th>Deleta</th>
    </tr></thead>
    <tbody>
        @foreach (var r in Model)
        {
            <tr>
                <td>@r.ReservaId</td>
                <td>@r.Nome</td>
                <td>@r.InicioLocacao</td>
                <td>@r.FimLocacao</td>

                <td>
                    <a asp-action="UpdateReserva" asp-route-id="@r.ReservaId"><img src="/icon/edit.png" /></a>
                </td>
                <td>
                    <form asp-action="DeleteReserva" method="post">
                        <input type="hidden" value="@r.ReservaId" name="ReservaId" />
                        <input type="image" src="/icon/close.png" />
                    </form>
                </td>
            </tr>
        }
    </tbody>
</table>

Este código usa os recursos do Bootstrap para definir a view que mostra a lista de reservas. A view é fortemente tipada recebendo um tipo IEnumerable<Reserva> como seu model e usar o laço foreach para popular a tabela com os dados.

Executando o projeto MVC (lembre-se que o projeto API deve estar em execução) iremos obter o seguinte resultado:

Clicando no link - Reservas - iremos acionar o método Action Index do controlador ReservasController para exibir as reservas.

Note que existem links cuja funcionalidade iremos implementar mais adiante.

Obtendo uma reserva pelo Id

Vamos agora implementar a funcionalidade de obter  uma reserva pelo seu Id. Para isso vamos criar um método Action chamado GetReserva no controlador ReservasController:

        public ViewResult GetReserva() => View();

        [HttpPost]
        public async Task<IActionResult> GetReserva(int id)
        {
            Reserva reserva = new Reserva();

            using (var httpClient = new HttpClient())
            {
                using (var response = await httpClient.GetAsync(apiUrl + "/" + id))
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    reserva = JsonConvert.DeserializeObject<Reserva>(apiResponse);
                }
            }
            return View(reserva);
        }

Aqui temos o método GetReserva primeiro para o GET e a seguir para o POST.

A versão GET da Action apenas retorna a View. Já a versão POST faz uma requisição para a API para obter a reserva passando o Id da reserva usando a classe HttpClient. A resposta é um objeto Reserva que é desserializado em um objeto Reserva sendo retornado para view como um model.

Vamos então criar a view GetReserva’  na pasta ‘Views/Reservas’ com o código abaixo:

@model Reserva

@{
    ViewData["Title"] = "GetReserva";
    Layout = "~/Views/Shared/_reservaLayout.cshtml";
}

<h2>Obter reserva pelo Id <a asp-action="Index" class="btn btn-sm btn-success">Retornar</a></h2>

<form method="post">
    <div class="form-group">
        <label for="id">Id:</label>
        <input class="form-control" name="id" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Obter Reserva</button>
    </div>
</form>

@if (Model != null)
{
    <h2>Reserva</h2>
    <table class="table table-sm table-striped table-bordered m-2">
        <thead><tr><th>ID</th><th>Nome</th><th>Início</th><th>Fim</th></tr></thead>
        <tbody>
            <tr>
                <td>@Model.ReservaId</td>
                <td>@Model.Nome</td>
                <td>@Model.InicioLocacao</td>
                <td>@Model.FimLocacao</td>

            </tr>
        </tbody>
    </table>
}

Esta view temos um formulário onde podemos informar o Id da reserva e clicar no botão para enviar uma requisição para a web api.

A expressão @if (Model != null) verifica se o model não é null e exibe os dados obtidos da API.

Executando o projeto novamente e clicando em Obter Reserva teremos o seguinte resultado:

Incluindo uma reserva

Para adicionar uma nova reserva, devemos fazer uma requisição HTTP POST para a web api ApiReservas usando o método PostAsync() da classe HttpClient.

Para isso vamos criar o método Action AddReserva() no controlador onde teremos o GET e o POST.

        public ViewResult AddReserva() => View();

        [HttpPost]
        public async Task<IActionResult> AddReserva(Reserva reserva)
        {
            Reserva reservaRecebida = new Reserva();

            using (var httpClient = new HttpClient())
            {
                StringContent content = new StringContent(JsonConvert.SerializeObject(reserva),
                                                  Encoding.UTF8, "application/json");

                using (var response = await httpClient.PostAsync(apiUrl, content))
                {
                    string apiResponse = await response.Content.ReadAsStringAsync();
                    reservaRecebida = JsonConvert.DeserializeObject<Reserva>(apiResponse);
                }
            }
            return View(reservaRecebida);
        }

Como a API precisará dos novos dados de reserva no formato JSON, estamos serializando os dados da classe Reserva para JSON e depois convertendo-os em um objeto StringContent:

 StringContent content = new StringContent(JsonConvert.SerializeObject(reserva),
                                  Encoding.UTF8, "application/json");

O objeto StringContent é então adicionado à requisição da API, adicionando-o ao segundo parâmetro do método PostAsync().

A API adicionará a nova reserva ao seu repositório e, em seguida, enviará de volta esse objeto de reserva, juntamente com o ID da reserva, como resposta.

A resposta é então desserializada para a classe Reserva e é enviada para a view como um model.

Agora basta criar a view 'AddReserva' na pasta 'Views/Reservas' com o seguinte código:

@model Reserva
@{
    ViewData["Title"] = "AddReserva";
    Layout = "~/Views/Shared/_reservaLayout.cshtml";
}

<h2>Nova Reserva <a asp-action="Index" class="btn btn-sm btn-outline-success">Retorna</a></h2>

<form asp-action="AddReserva" method="post">
    <div class="form-group">
        <label for="Name">Nome:</label>
        <input class="form-control" name="Nome" />
    </div>
    <div class="form-group">
        <label for="InicioLocacao">Início da Locação:</label>
        <input class="form-control" name="InicioLocacao" />
    </div>
    <div class="form-group">
        <label for="FimLocacao">Fim da Locação:</label>
        <input class="form-control" name="FimLocacao" />
    </div>
    <div class="text-center panel-body">
        <button type="submit" class="btn btn-sm btn-primary">Nova Reserva</button>
    </div>

</form>

@if (Model != null)
{
    <h2>Reserva</h2>
    <table class="table table-sm table-striped table-bordered m-2">
        <thead><tr><th>ID</th><th>Nome</th><th>Inicio</th><th>Fim</th></tr></thead>
        <tbody>
            <tr>
                <td>@Model.ReservaId</td>
                <td>@Model.Nome</td>
                <td>@Model.InicioLocacao</td>
                <td>@Model.FimLocacao</td>

            </tr>
        </tbody>
    </table>
}

Executando o projeto teremos o resultado abaixo:

Na próxima parte do artigo vamos continuar implementando a atualização e exclusão de reservas.

"Porque Deus não nos destinou para a ira, mas para a aquisição da salvação, por nosso Senhor Jesus Cristo,
Que morreu por nós, para que, quer vigiemos, quer durmamos, vivamos juntamente com ele."

1 Tessalonicenses 5:9,10

Referências:


José Carlos Macoratti