Exercício – Consumir um serviço REST com HttpClient

Concluído

Como parte do aplicativo que os engenheiros usam em visitas ao site do cliente, você precisa adicionar um recurso que permita que um engenheiro pesquise os detalhes dos componentes elétricos. Essas informações serão mantidas em um banco de dados e acessadas por meio de um serviço Web REST. Você também foi solicitado a fornecer uma interface que permite que um administrador crie, remova e modifique os detalhes das partes mantidas no banco de dados usando o mesmo serviço Web REST.

Neste exercício, você implantará o serviço Web REST no Azure e, em seguida, verificará se pode acessá-lo usando um navegador da Web. Em seguida, você adicionará funcionalidade a um aplicativo existente que usa o serviço Web REST para recuperar, adicionar, excluir e atualizar os detalhes dos componentes elétricos.

Você executará este exercício usando a área restrita do Azure.

Dica

Use o botão Copiar para copiar os comandos para a área de transferência. Para colar o conteúdo, clique com o botão direito do mouse em uma nova linha no terminal do Cloud Shell e selecione Colar ou use o atalho de teclado Shift + Insert (⌘ + V no macOS).

Implantar o serviço Web REST do Parts

  1. Na janela Cloud Shell, execute o seguinte comando para clonar o repositório que contém o código deste exercício, incluindo o serviço Web REST do Parts:

    git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
    
  2. Mova para a pasta Consume-REST-services:

    cd mslearn-dotnetmaui-consume-rest-services/src
    
  3. Execute o comando a seguir para implantar o serviço Web Parts usando a área restrita do Azure Cloud Shell. Esse comando disponibiliza o serviço por meio de uma URL exclusiva. Anote essa URL quando ela for exibida. Você configurará o aplicativo para se conectar ao serviço Web usando essa URL.

    bash initenvironment.sh
    

Examinar o código do serviço Web

Observação

Você executará o restante deste exercício em seu computador de desenvolvimento local.

  1. No computador, abra uma janela do prompt de comando e clone o repositório para este exercício. O código está no repositório net-maui-learn-consume-rest-services.

    git clone https://github.com/microsoftdocs/mslearn-dotnetmaui-consume-rest-services
    

    Observação

    Recomendamos clonar ou baixar o conteúdo do exercício para um caminho de pasta curto, como C:\dev, para evitar que os arquivos gerados pelo build excedam o comprimento máximo do caminho.

  2. Vá para a pasta src\webservice\PartsServer no clone do repositório e abra a solução PartsServer.sln usando o Visual Studio ou a pasta no Visual Studio Code. Essa solução contém uma cópia do código do serviço Web implantado no Azure no procedimento anterior.

  3. Na janela Gerenciador de Soluções, expanda a pasta Modelos. Esta pasta contém dois arquivos:

    • Part.cs. A classe Part representa uma parte, conforme fornecido pelo serviço Web REST. Os campos incluem a ID da parte, o nome da parte, o tipo de parte, a data de disponibilidade (quando a parte foi fornecida pela primeira vez) e uma lista de fornecedores. A propriedade Href retorna o URI relativo da parte; um cliente REST pode usar esse URI para fazer referência a essa parte específica no serviço Web REST. A propriedade Suppliers retorna a lista de fornecedores da parte como uma cadeia de caracteres.

    • PartsFactory.cs. A classe PartsFactory inicializa a lista de partes fornecidas pelo serviço, usando um pequeno conjunto de valores embutidos em código. No mundo real, esses dados seriam recuperados de um banco de dados.

  4. Na janela Gerenciador de Soluções, expanda a pasta Controladores. Esta pasta contém os seguintes arquivos:

    • PartsController.cs. A classe PartsController implementa a API Web para o serviço. Ela inclui métodos que permitem que um aplicativo cliente recupere uma lista de todas as partes (Get), encontre os detalhes de uma parte específica considerando a ID da parte (a versão sobrecarregada de Get), atualize os detalhes de uma parte (Put), adicione uma nova parte à lista (Post) e remova uma parte da lista (Delete).

    • LoginController.cs. A classe LoginController implementa uma forma simples de autenticação para o serviço Web. Um aplicativo deve enviar uma solicitação HTTP GET para esse controlador, que retorna um token de autorização. Esse token de autorização é usado para autenticar as solicitações enviadas ao PartsController.

    • BaseController.cs. A classe BaseController contém a lógica usada para autenticar solicitações. A classe PartsController herda dessa classe. Se o cliente tentar chamar métodos na classe PartsController sem fornecer um token de autenticação válido, os métodos retornarão uma resposta HTTP 401 (não autorizada).

Examinar o código do aplicativo cliente .NET MAUI

Este módulo usa o SDK do .NET 8.0. Verifique se você tem o .NET 8.0 instalado executando o seguinte comando em seu terminal de comando preferencial:

dotnet --list-sdks

Uma saída semelhante ao seguinte exemplo aparece:

6.0.317 [C:\Program Files\dotnet\sdk]
7.0.401 [C:\Program Files\dotnet\sdk]
8.0.100 [C:\Program Files\dotnet\sdk]

Verifique se uma versão que começa com 8 está listada. Se nenhum estiver listado ou o comando não for encontrado, instale o SDK do .NET 8.0 mais recente.

  1. Feche a solução PartsServer e abra a solução PartsClient na pasta src\client\PartsClient no repositório clonado. Essa solução contém uma implementação parcial de um aplicativo cliente .NET MAUI que usa o serviço Web PartsServer.

  2. Na janela Gerenciador de Soluções, expanda a pasta Dados. Esta pasta contém o código para duas classes:

    • PartsManager.cs. A classe PartsManager fornece os métodos que o aplicativo cliente usa para interagir com o serviço Web REST. Esta classe está incompleta no momento; você adicionará o código necessário durante este exercício. Quando concluído, o método GetClient se conecta ao serviço Web REST. O método GetAll retorna uma lista de partes do serviço Web REST. O método Add adiciona uma nova parte à lista de partes gerenciadas pelo serviço Web REST. O método Update modifica os detalhes de uma parte armazenada pelo serviço Web REST e o método Delete remove uma parte.

    • Part.cs. A classe Part modela uma parte armazenada no banco de dados. Ela expõe propriedades que um aplicativo pode usar para acessar os campos PartID, PartName, PartAvailableDate, PartType e PartSuppliers. A classe também fornece um método utilitário chamado SupplierString que um aplicativo pode usar para recuperar uma cadeia de caracteres formatada que contém os nomes do fornecedor.

  3. Na janela Gerenciador de Soluções, expanda a pasta Páginas. Esta pasta contém a marcação e o código de duas páginas:

    • PartsPage.xaml. Esta página usa um layout CollectionView com um DataTemplate para exibir os detalhes das partes disponíveis como uma lista. O DataTemplate usa a associação de dados para conectar os dados exibidos às partes recuperadas do serviço Web. Você pode selecionar uma linha em CollectionView para editar uma parte em AddPartPage ou selecionar o botão Adicionar nova parte para adicionar uma nova parte.

    • AddPartPage.xaml. Esta página permite que os usuários insiram e salvem os detalhes de uma nova parte. Os usuários podem especificar o nome da parte, o tipo de parte e um fornecedor inicial. A ID da parte e a data disponível da parte são geradas automaticamente.

  4. Na janela Gerenciador de Soluções, expanda a pasta ViewModels. Esta pasta contém duas classes: AddPartViewModel.cs e PartsViewModel.cs. Esses são os modelos de exibição para suas respectivas páginas e contêm propriedades e lógica que a página precisa para exibir e manipular dados.

Entrar serviço

O serviço REST exige que você entre primeiro para obter um token de autorização. Não há autenticação de usuário. Você chama um ponto de extremidade específico primeiro para obter um token de autorização e, em seguida, envia o token de volta para o servidor em cada solicitação subsequente no cabeçalho HTTP.

  1. Abra o arquivo PartsManager.cs na pasta Dados.

  2. Adicione campos estáticos BaseAddress e Url, conforme definido no snippet de código a seguir, para a classe PartsManager. Substitua o texto URL GOES HERE pela URL do serviço Web REST que você anotou anteriormente:

    public class PartsManager
    {
        static readonly string BaseAddress = "URL GOES HERE";
        static readonly string Url = $"{BaseAddress}/api/";
        ...
    }
    
  3. Adicione o campo a seguir à classe, após o campo Url. Esse campo conterá o token de autorização retornado quando o usuário entrar:

    private static string authorizationKey;
    
  4. Localize o método GetClient. Atualmente, esse método gera uma exceção NotImplementedException. Substitua o código existente nesse método pelo código a seguir. Esse código cria um objeto HttpClient e envia uma solicitação para o ponto de extremidade de logon do serviço Web REST. O serviço deve responder com uma mensagem que contém o token de autorização. Desserialize esse token e adicione-o como um cabeçalho de solicitação de autorização padrão para solicitações subsequentes enviadas usando o objeto HttpClient:

    private static async Task<HttpClient> GetClient()
    {
        if (client != null)
            return client;
    
        client = new HttpClient();
    
        if (string.IsNullOrEmpty(authorizationKey))
        {                
            authorizationKey = await client.GetStringAsync($"{Url}login");
            authorizationKey = JsonSerializer.Deserialize<string>(authorizationKey);
        }
    
        client.DefaultRequestHeaders.Add("Authorization", authorizationKey);
        client.DefaultRequestHeaders.Add("Accept", "application/json");
    
        return client;
    }
    

Execute uma operação GET para recuperar informações de partes

  1. No arquivo PartsManager.cs, localize o método GetAll. Esse é um método assíncrono que retorna uma lista enumerável de partes. Esse método ainda não foi implementado.

  2. Nesse método, exclua o código que gera a exceção NotImplementedException.

  3. Verifique se o dispositivo tem conectividade com a Internet usando a classe Connectivity. Se a Internet não estiver presente, retorne um List<Part> vazio.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new List<Part>();
    
  4. Chame o método GetClient para recuperar um objeto HttpClient com o qual trabalhar. Lembre-se de que GetClient é assíncrono, portanto, use o operador await para capturar o objeto retornado por esse método.

  5. Chame o método GetStringAsync do objeto HttpClient e forneça a URL base para recuperar uma matriz de partes do serviço Web REST. Os dados são retornados de forma assíncrona como uma cadeia de caracteres JSON.

  6. Desserialize a cadeia de caracteres JSON retornada por esse método em uma lista de objetos Part usando o método JsonSerializer.Deserialize. Retorne essa lista ao chamador.

    O método completo deverá ter esta aparência:

    public static async Task<IEnumerable<Part>> GetAll()
    {
        if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
            return new List<Part>();
    
        var client = await GetClient();
        string result = await client.GetStringAsync($"{Url}parts");
    
        return JsonSerializer.Deserialize<List<Part>>(result, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            });                     
    }
    
  7. Compile e execute o aplicativo. Quando o aplicativo for iniciado, a página Part List será exibida e uma lista de partes recuperadas pelo método GetAll deverá aparecer. A imagem a seguir mostra o aplicativo em execução no Android:

    Captura de tela do aplicativo cliente de partes em execução no Android mostrando uma lista de partes.

  8. Quando terminar de navegar nos dados, feche o aplicativo e retorne ao Visual Studio ou ao Visual Studio Code.

Executar uma operação POST para adicionar uma nova parte ao banco de dados

  1. Na classe PartManager, localize o método Adicionar. Esse método tem parâmetros para o nome da parte, um fornecedor e o tipo de peça. O método é assíncrono. A finalidade do método é inserir uma nova parte no banco de dados e retornar um objeto Part que representa o item recém-criado.

  2. Exclua o código existente no método.

  3. Verifique se o dispositivo tem conectividade com a Internet usando a classe Connectivity. Se a Internet não estiver presente, retorne um Part vazio.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return new Part();
    
  4. Crie um objeto Part. Preencha os campos com os dados passados:

    • Defina o campo PartID como uma cadeia de caracteres vazia. Essa ID será gerada pelo serviço Web REST.
    • Crie uma Lista para conter o nome do fornecedor.
    • Defina o campo PartAvailableDate como DateTime.Now.
    • Obtenha um cliente HTTP do método GetClient.
    var part = new Part()
    {
        PartName = partName,
        Suppliers = new List<string>(new[] { supplier }),
        PartID = string.Empty,
        PartType = partType,
        PartAvailableDate = DateTime.Now.Date
    };
    
  5. Chame o método GetClient para recuperar um objeto HttpClient com o qual trabalhar.

  6. Crie um objeto HttpRequestMessage. Esse objeto é usado para modelar a solicitação que é enviada ao serviço Web. Inicie-o com parâmetros que indicam com qual verbo HTTP usar e a URL do serviço Web com o qual se comunicar.

    var msg = new HttpRequestMessage(HttpMethod.Post, $"{Url}parts");
    
  7. Você precisa enviar uma carga para o serviço Web com as informações da Parte a ser criada. Essa carga será serializada em JSON. A carga JSON será adicionada à propriedade HttpRequestMessage.Content e será serializada com o método JsonContent.Create.

    msg.Content = JsonContent.Create<Part>(part);
    
  8. Agora, envie a mensagem para o serviço Web com a função HttpClient.SendAsync. Essa função retornará um objeto HttpResponseMessage que contém informações sobre a operação no servidor. Como códigos de resposta HTTP e informações passadas do servidor.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    

    Observe que o anterior usa o método response.EnsureSuccessStatusCode. Isso gerará um erro se algo diferente de um código de status HTTP 2xx for retornado.

  9. Se o serviço Web retornar informações, como um objeto serializado em JSON, será possível lê-lo no HttpResponseMessage. Em seguida, é possível desserializar o JSON usando JsonSerializer.Deserialize.

    var returnedJson = await response.Content.ReadAsStringAsync();
    
    var insertedPart = JsonSerializer.Deserialize<Part>(returnedJson, new JsonSerializerOptions
            {
                PropertyNameCaseInsensitive = true,
            });
    
  10. Por fim, retorne a nova Parte inserida.

    return insertedPart;
    
  11. Compile e execute o aplicativo. Selecione o botão Adicionar Nova Parte e insira um nome, tipo e fornecedor para criar uma nova parte. Selecione Salvar. O método Add na classe PartsManager será invocado, o que cria a nova parte no serviço Web. Se a operação for bem-sucedida, a página de lista de partes reaparecerá com a nova parte na parte inferior da lista.

    Captura de tela do aplicativo em execução após a adição de uma parte. A nova parte está no final da lista.

  12. Quando terminar de navegar nos dados, feche o aplicativo e retorne ao Visual Studio ou ao Visual Studio Code.

Execute uma operação PUT para atualizar os detalhes de uma parte no banco de dados

  1. Na classe PartsManager, localize o método Update. Esse é um método assíncrono que usa um objeto Part como o parâmetro. O método não tem um valor retornado explícito. No entanto, o tipo de retorno é Task para que as exceções sejam retornadas corretamente para o chamador. Vamos implementar a funcionalidade PUT.

  2. Exclua o código existente.

  3. Como antes, verifique se há uma conexão com a Internet.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return;
    
  4. Crie um novo HttpRequestMessage, desta vez especificando uma operação PUT e a URL para atualizar partes.

    HttpRequestMessage msg = new(HttpMethod.Put, $"{Url}parts/{part.PartID}");
    
  5. Defina a propriedade Content de HttpRequestMessage usando a função JsonContent.Create e o parâmetro parte que foi passado para a função.

    msg.Content = JsonContent.Create<Part>(part);
    
  6. Obtenha um cliente HTTP do método GetClient.

    var client = await GetClient();
    
  7. Envie a solicitação com HttpClient e verifique se ela foi bem-sucedida.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  8. Compile e execute o aplicativo. Selecione uma das partes da lista. A página AddPart será exibida, desta vez com as propriedades já preenchidas. Atualize o que quiser.

  9. Selecione Salvar. Isso chama o método Update na classe PartsManager para enviar as alterações para o serviço Web. Se for bem-sucedida, a página de lista de partes será exibida novamente.

    Captura de tela do aplicativo em execução com o primeiro item da lista atualizado.

    Observação

    A parte que você adicionou na tarefa anterior não aparecerá na página Lista de Partes. Os dados que o aplicativo usa são redefinidos para uma lista de partes predefinidas sempre que o aplicativo é executado. Isso é para fornecer consistência para testar o aplicativo.

Execute uma operação DELETE para remover os detalhes de uma parte do banco de dados

  1. Na classe PartsManager, localize o método Excluir. Esse é um método assíncrono que usa uma cadeia de caracteres partId e retorna uma Task.

  2. Exclua o código existente.

  3. Verifique se há uma conexão com a Internet.

    if (Connectivity.Current.NetworkAccess != NetworkAccess.Internet)
        return;
    
  4. Crie um objeto HttpRequestMessage. Agora, especifique apenas o verbo DELETE HTTP e a URL para excluir uma parte.

    HttpRequestMessage msg = new(HttpMethod.Delete, $"{Url}parts/{partID}");
    
  5. Obtenha um cliente HTTP do método GetClient.

    var client = await GetClient();
    
  6. Envie a solicitação para o serviço Web. Verifique se há êxito depois que ele retornar.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  7. Compile e execute o aplicativo. Selecione uma parte na lista e, em seguida, selecione Excluir na página Adicionar parte. Se tiver êxito, a página Lista de Partes será exibida novamente e a parte excluída não ficará mais visível.