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

Concluído

Como parte do aplicativo que os engenheiros usam nas visitas ao local do cliente, você precisa adicionar um recurso que permita que um engenheiro procure os detalhes dos componentes elétricos. Esta informação será guardada numa base de dados e acedida através de um serviço Web REST. Também foi solicitado que você forneça uma interface que permita 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.

Gorjeta

Pode utilizar o botão Copiar para copiar comandos para a área de transferência. Para colar, 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 do Cloud Shell, execute o seguinte comando para clonar o repositório que contém o código para este exercício, incluindo o serviço Web Parts REST:

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

    cd mslearn-dotnetmaui-consume-rest-services/src
    
  3. Execute o seguinte comando para implantar o serviço Web Parts usando a área restrita do Azure Cloud Shell. Este comando disponibiliza o serviço através de um URL exclusivo. Anote este URL quando for apresentado. Você configurará o aplicativo para se conectar ao serviço Web usando essa URL.

    bash initenvironment.sh
    

Examine o código do serviço Web

Nota

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

  1. No computador, abra uma janela de 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
    

    Nota

    É melhor clonar ou baixar o conteúdo do exercício para um caminho de pasta curto, como C:\dev, para evitar que os arquivos gerados pela compilação 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. Esta solução contém uma cópia do código para o serviço Web que você implantou no Azure no procedimento anterior.

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

    • Peça.cs. A classe Part representa uma parte conforme fornecido pelo serviço Web REST. Os campos incluem o ID da peça, o nome da peça, o tipo de peça, a data de disponibilidade (quando a peça foi fornecida pela primeira vez) e uma lista de fornecedores. A propriedade Href retorna o URI relativo da peça, 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 peça como uma cadeia de caracteres.

    • PartsFactory.cs. A classe PartsFactory inicializa a lista de peças fornecidas pelo serviço, usando um pequeno conjunto de valores codificados. 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 ficheiros:

    • PartsController.cs. A classe PartsController implementa a API da Web para o serviço. Ele 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 dada a ID da peça (a versão sobrecarregada de Get), atualize os detalhes de uma peça (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).

Examine o código do aplicativo cliente .NET MAUI

Este módulo usa o SDK do .NET 8.0. Certifique-se de ter o .NET 8.0 instalado executando o seguinte comando no seu terminal de comando preferido:

dotnet --list-sdks

Saída semelhante ao exemplo a seguir 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]

Certifique-se de que 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. Esta 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á atualmente incompleta; 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.

    • Peça.cs. A classe Part modela uma parte armazenada no banco de dados. Ele 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 contendo os nomes dos fornecedores.

  3. Na janela Gerenciador de Soluções, expanda a pasta Páginas . Esta pasta contém a marcação e o código para 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 no CollectionView para editar uma parte no AddPartPage, ou você pode 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 peça. Os usuários podem especificar o nome da peça, o tipo de peça e um fornecedor inicial. O ID da peça e a data disponível da peça são gerados automaticamente.

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

Iniciar sessão no serviço

O serviço REST requer 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 trecho de código a seguir à classe PartsManager . Substitua o texto URL GOES HERE pelo URL do serviço Web REST que você observou anteriormente:

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

    private static string authorizationKey;
    
  4. Encontre o método GetClient . Esse método atualmente lança uma exceção NotImplementedException . Substitua o código existente neste método com o código a seguir. Esse código cria um objeto HttpClient e, em seguida, envia uma solicitação para o ponto de extremidade de login 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;
    }
    

Executar uma operação GET para recuperar informações de peças

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

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

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

    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 para o chamador.

    O método concluído deve 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 a aplicação. Quando o aplicativo for iniciado, a página Lista de peças será exibida e uma lista de partes recuperadas pelo método GetAll deve aparecer. A imagem a seguir mostra o aplicativo em execução no Android:

    A screenshot of the Parts Client app running on Android showing a list of parts.

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

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

  1. Na classe PartsManager, localize o método Add. Este método tem parâmetros para o nome da peça, 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 Connectivity classe. Se a internet não estiver presente, devolva um arquivo .Part

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

    • Defina o campo PartID como uma cadeia de caracteres vazia. Esse ID será gerado pelo serviço Web REST.
    • Crie uma nova 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 HttpRequestMessage objeto. Este objeto é usado para modelar a solicitação que é enviada para o serviço Web. Inicie-o com parâmetros que indiquem 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 útil para o serviço Web com as informações da peça a ser criada. Essa carga será serializada para JSON. A carga JSON será adicionada à propriedade e serializada HttpRequestMessage.Content com o JsonContent.Create método.

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

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

    Observe que o precedente usa o response.EnsureSuccessStatusCode método. 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, você poderá lê-lo fora HttpResponseMessagedo . Em seguida, você pode 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, devolva a nova Peça inserida.

    return insertedPart;
    
  11. Compile e execute a aplicação. Selecione o botão Adicionar nova peça e insira um nome, tipo e fornecedor para criar uma nova peça . Selecione Guardar. 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 da lista de peças reaparecerá com a nova parte na parte inferior da lista.

    A screenshot of the app running after a new part has been added. The new part is at the bottom of the list.

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

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

  1. Na classe PartsManager, localize o método Update. Este é um método assíncrono que usa um objeto Part como parâmetro. O método não tem um valor de retorno explícito. No entanto, o tipo de retorno é Task para que as exceções sejam retornadas corretamente ao 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 do HttpRequestMessage usando a função e o parâmetro part que foi passado para a ContentJsonContent.Create função.

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

    var client = await GetClient();
    
  7. Envie o pedido com o e, em HttpClient seguida, certifique-se de que foi bem-sucedido.

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

  9. Selecione Guardar. 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 da lista de peças reaparecerá se as alterações forem refletidas.

    A screenshot of the app running with the first item in the list updated.

    Nota

    A parte adicionada na tarefa anterior não aparecerá na página Lista de Peças . Os dados que o aplicativo usa são redefinidos para uma lista de partes predefinidas cada vez que o aplicativo é executado. Isso é para fornecer consistência para testar o aplicativo.

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

  1. Na classe PartsManager, localize o método Delete. Este é 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 novo HttpRequestMessage objeto. Só agora especifique o verbo HTTP DELETE e o 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á sucesso depois que ele retorna.

    var response = await client.SendAsync(msg);
    response.EnsureSuccessStatusCode();
    
  7. Compile e execute a aplicação. Selecione uma peça na lista e, em seguida, selecione Excluir na página Adicionar peça . Se for bem-sucedida, a página Lista de Peças reaparecerá e a parte excluída não estará mais visível.