ASP .NET  - Consumindo uma Web API em um projeto WPF Application - V


Neste artigo vou mostrar como consumir o serviço REST criado sobre a plataforma .NET, no artigo anterior, usando o framework ASP .NET Web API em um projeto WPF Application.

No artigo anterior criamos nossa Web API usando o framework ASP .NET Web API com o nome WebApi2_Estudantes e já temos o serviço REST que expõe os serviços para realizar o acesso e as operações CRUD com as informações dos estudantes.

É neste momento que os serviços REST fazem a diferença em relação ao protocolo SOAP.  Consumir um serviço SOAP é mais complexo e precisa de todo um suporte de ferramentas visto que temos que formatar as mensagens de envio e interpretar as mensagens de erro

No caso da plataforma .NET a Microsoft facilitou bastante a nossa vida fornecendo recursos que facilitam o consumo de serviços REST (leia-se Web API).

Para consumirmos serviços REST em aplicações .NET, primeiro temos que usar os recursos do assembly System.Net.Http.dll. Neste assembly temos o namespace System.Net.Http, que possui tipos para consumir serviços baseados exclusivamente no protocolo HTTP.

Para fazer isso basta referenciar o pacote “Microsoft.AspNet.WebApi.Client“ (via nuget) no projeto cliente que vai consumir a Web API.

Do lado do cliente a classe principal é a HttpClient que é responsável por gerenciar toda a comunicação com um determinado serviço.

A classe HttpClient expõe os métodos para consumo dos serviços de forma assíncrona , e métodos nomeados aos principais verbos HTTP que trabalham com as classes HttpRequestMessage e HttpResponseMessage. (isso dá ao cliente o controle sobre a mensagem enviada e da resposta que é retornada)
 

Vou então mostrar consumir essa Web API em um projeto WPF Application.

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Criando o projeto WPF no VS 2015 Community

Abra o VS Community 2015 e clique em New Project;

Selecione a linguagem Visual C# ->WPF Application

Informe o nome Consumindo_WebAPI_Estudantes e clique no botão OK;

Será criado um projeto WPF com a seguinte estrutura exibida no Solution Explorer:

Referenciando o pacote Microsoft.AspNet.WebApi.Client no projeto via Nuget

Para poder acessar a Web API vamos precisar referenciar o pacote “Microsoft.AspNet.WebApi.Client" em nosso projeto WPF.

No menu Tools clique em Nuget Package Manager -> Manage Nuget Packages for Solution;

Localize o pacote e instale no projeto:

Definindo a classe Estudante

Precisamos definir uma classe Estudante com as mesmas propriedades da classe Estudante definida no projeto Web API:

public class Estudante
{

   public
string nome { get; set; }
   public
int id { get; set; }
   public
string genero { get; set; }
   public
int idade { get; set; }
}

Definindo a interface com o usuário

Vamos abrir o arquivo MainWindow.xaml e no editor XAML incluir os seguintes controles a partir da ToolBox:

A seguir disponha os controles conforme o leiaute abaixo:

O código completo do arquivo MainWindow.xaml é dado a seguir:

<Window x:Class="Consumindo_WebAPI_Estudantes.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:Consumindo_WebAPI_Estudantes"
        mc:Ignorable="d"
        Title="Manutenção de Estudantes" Height="500" Width="525" Background="Chocolate">
        <Window.Resources>
            <ControlTemplate x:Key="btnTemplate" TargetType="Button">
                <Grid>
                    <Rectangle RadiusX="5" RadiusY="5" Fill="Aquamarine">
                    </Rectangle>
                    <ContentPresenter HorizontalAlignment="Center" VerticalAlignment="Center"></ContentPresenter>
                </Grid>
            </ControlTemplate>
            <Style TargetType="TextBlock">
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="FontSize" Value="13"></Setter>
            </Style>
            <Style x:Key="tbkStyle" TargetType="TextBlock">
                <Setter Property="Foreground" Value="White"/>
                <Setter Property="FontSize" Value="13"></Setter>
            </Style>
        </Window.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="*"></ColumnDefinition>
            <ColumnDefinition Width="2*"></ColumnDefinition>
        </Grid.ColumnDefinitions>
        <StackPanel x:Name="estudantePanel" Grid.Column="0">
            <TextBlock Text="Lista de Estudantes" FontSize="18" FontWeight="Bold"></TextBlock>
            <ListView x:Name="estudantesListView" Margin="0,10,0,0" Background="Transparent" Height="400" ScrollViewer.CanContentScroll="True">
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <StackPanel>
                            <TextBlock Style="{StaticResource tbkStyle}">
                                <TextBlock.Inlines>
                                    <Run Text="Nome : "></Run>
                                    <Run Text="{Binding nome}"></Run>
                                </TextBlock.Inlines>
                            </TextBlock>
                            <TextBlock Style="{StaticResource tbkStyle}">
                                <TextBlock.Inlines>
                                    <Run Text="ID : "></Run>
                                    <Run Text="{Binding id}"></Run>
                                </TextBlock.Inlines>
                            </TextBlock>
                            <TextBlock Style="{StaticResource tbkStyle}">
                                <TextBlock.Inlines>
                                    <Run Text="Gênero : "></Run>
                                    <Run Text="{Binding genero}"></Run>
                                </TextBlock.Inlines>
                            </TextBlock>
                            <TextBlock Style="{StaticResource tbkStyle}">
                                <TextBlock.Inlines>
                                    <Run Text="Idade : "></Run>
                                    <Run Text="{Binding idade}"></Run>
                                    <LineBreak/>
                                </TextBlock.Inlines>
                            </TextBlock>
                        </StackPanel>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>
        </StackPanel>
        <Grid Grid.Column="1">
            <Grid.RowDefinitions>
                <RowDefinition/>
                <RowDefinition/>
            </Grid.RowDefinitions>
            <StackPanel Grid.Row="0" Margin="10,0,0,0">
                <TextBlock Text="Adiciona ou Atualiza um estudante" FontSize="18" FontWeight="Bold"></TextBlock>
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <TextBlock Text="Nome" Width="75"></TextBlock>
                    <TextBox x:Name="txtNomeEstudante" Margin="10,0,0,0" Width="200"></TextBox>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <TextBlock Text="ID" Width="75"></TextBlock>
                    <TextBox x:Name="txtIDEstudante" Margin="10,0,0,0" Width="200"></TextBox>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <TextBlock Text="Genero" Width="75"></TextBlock>
                    <ComboBox x:Name="cbxGenero" Margin="10,0,0,0" Width="200" Text="--Selecione o sexo--" IsReadOnly="True" IsEditable="True"></ComboBox>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <TextBlock Text="Idade" Width="75"></TextBlock>
                    <TextBox x:Name="txtIdade" InputScope="Number" Margin="10,0,0,0" Width="200"></TextBox>
                </StackPanel>
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <Button x:Name="btnNovoEstudante" Template="{StaticResource btnTemplate}" Content=" Adiciona um estudante " Margin="0,0,10,0" Click="btnNovoEstudante_Click"></Button>
                    <Button x:Name="btnAtualiza" Template="{StaticResource btnTemplate}" Content=" Atualiza um estudante " Click="btnAtualiza_Click"></Button>
                </StackPanel>
            </StackPanel>
            <StackPanel Grid.Row="1" Margin="10,0,0,0">
                <TextBlock Text="Obtém ou Deleta um estudante" FontSize="18" FontWeight="Bold"></TextBlock>
                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <TextBlock Text="Informe o Id do Estudante" Width="150"></TextBlock>
                    <TextBox x:Name="txtID" InputScope="Number" Margin="10,0,0,0" Width="100"></TextBox>
                </StackPanel>
                <StackPanel x:Name="estudanteDetalhesPanel" Margin="10,0,0,0" Visibility="Collapsed">
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <TextBlock Text="Nome :" Width="75"></TextBlock>
                        <TextBlock x:Name="txbEstudanteNome" Text="{Binding nome}" Margin="10,0,0,0" Width="200"></TextBlock>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <TextBlock Text="ID : " Width="75"></TextBlock>
                        <TextBlock x:Name="txbEstudanteID" Margin="10,0,0,0" Text="{Binding id}" Width="200"></TextBlock>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <TextBlock Text="Gênero : " Width="75"></TextBlock>
                        <TextBlock x:Name="txbGenero" Margin="10,0,0,0" Text="{Binding genero}" Width="200"></TextBlock>
                    </StackPanel>
                    <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                        <TextBlock Text="Idade : " Width="75"></TextBlock>
                        <TextBlock x:Name="txbIdade" InputScope="Number" Margin="10,0,0,0" Width="200" Text="{Binding Idade}"></TextBlock>
                    </StackPanel>
                </StackPanel>

                <StackPanel Orientation="Horizontal" Margin="0,10,0,0">
                    <Button x:Name="btnGetEstudante" Template="{StaticResource btnTemplate}" Content=" Obtém um estudante " Margin="0,0,10,0" Click="btnGetEstudante_Click"></Button>
                    <Button x:Name="btnDeletaEstudante" Template="{StaticResource btnTemplate}" Content=" Deleta um estudante " Click="btnDeletaEstudante_Click"></Button>
                </StackPanel>
            </StackPanel>
        </Grid>
    </Grid>
</Window>

Este código desenha a nossa interface na aplicação WPF. Vamos agora implementar o código no arquivo code-behind MainWindow.xaml.cs.

Definindo o código do projeto WPF

Abra o arquivo MainWindow.xaml.cs e defina o código que irá acessar a nossa Web API - WebApi2_Estudantes criada no artigo anterior.

Vamos começar definindo os namespaces usados. Inclua no início do arquivo as seguintes declaração de namespaces:

using System;
using
System.Collections.Generic;
using
System.Net.Http;
using
System.Net.Http.Headers;
using
System.Threading.Tasks;
using
System.Windows;
using
System.Windows.Documents;

A seguir vamos criar uma instância da classe HttpClient que iremos usar no projeto.

HttpClient client = new HttpClient();

Do lado do cliente a classe principal é a HttpClient que é responsável por gerenciar toda a comunicação com um determinado serviço.

A classe HttpClient expõe os métodos para consumo dos serviços de forma assíncrona , e métodos nomeados aos principais verbos HTTP que trabalham com as classes HttpRequestMessage e HttpResponseMessage. (isso dá ao cliente o controle sobre a mensagem enviada e da resposta que é retornada)

Definindo o código no método MainWindow()

O método MainWindow() será executado quando a aplicação WPF for iniciada. Logo após a chamada do método InitializeComponent() vamos definir o código que realiza as seguintes tarefas:

        public MainWindow()
        {
            InitializeComponent();
            List<string> generoLista = new List<string>();
            generoLista.Add("Masculino");
            generoLista.Add("Feminino");
            cbxGenero.ItemsSource = generoLista;
            client.BaseAddress = new Uri("http://localhost:51133");
            client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
            this.Loaded += MainWindow_Loaded;
        }

A seguir o código do evento Loaded :

         async void MainWindow_Loaded(object sender, RoutedEventArgs e)
        {
            try
            {
                HttpResponseMessage response = await client.GetAsync("/api/estudantes");
                response.EnsureSuccessStatusCode(); // Lança um código de erro
                var estudantes = await response.Content.ReadAsAsync<IEnumerable<Estudante>>();
                estudantesListView.ItemsSource = estudantes;
            }
            catch(Exception)
            {
                //MessageBox.Show("Erro : " + ex.Message);
            }
        }

O evento assíncrono envia uma requisição GET de forma assíncrona usando a URI - /api/estudantes - e receber a resposta exibindo no ListView - estudantesListView através da propriedade ItemSource.

Vemos o resultado exibido na figura abaixo:

Assim ao iniciar teremos a lista de estudantes exibida no ListView.

Vamos definir um método chamado GetAllEstudantes() que será usado no projeto para atualizar a exibição do controle ListView exibindo as informações após realizarmos uma operação :

O código deste método é dado a seguir :

        public async Task<IEnumerable<Estudante>> GetAllEstudantes()
        {
            HttpResponseMessage response = await client.GetAsync("/api/estudantes");
            response.EnsureSuccessStatusCode(); //lança um código de erro
            var estudantes = await response.Content.ReadAsAsync<IEnumerable<Estudante>>();
            return estudantes;
        }

 

Este código envia uma requisição GET para a URI indicada e retorna uma lista de objeto Estudante.

Agora vamos definir os métodos que irão acessar a Web API e realizar as operações desejadas:

1- Obter um estudante pelo seu id

        private async void btnGetEstudante_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                HttpResponseMessage response = await client.GetAsync("/api/estudantes/" + txtID.Text);
                response.EnsureSuccessStatusCode(); //lança um código de erro
                var estudantes = await response.Content.ReadAsAsync<Estudante>();
                estudanteDetalhesPanel.Visibility = Visibility.Visible;
                estudanteDetalhesPanel.DataContext = estudantes;
            }
            catch (Exception)
            {
                MessageBox.Show("Estudante não localizado");
            }
      }

Neste código enviamos uma requisição GET usando a URI - /api/estudantes/" + txtID.Text - onde txtID.Text é o código do estudante.

A resposta é exibida no Panel - estudanteDetalhesPanel - usando a propriedade DataContext:

2- Adicionar um estudante

       private async void btnNovoEstudante_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var estudante = new Estudante()
                {
                    nome = txtNomeEstudante.Text,
                    id = int.Parse(txtIDEstudante.Text),
                    genero = cbxGenero.SelectedItem.ToString(),
                    idade = int.Parse(txtIdade.Text)
                };
                var response = await client.PostAsJsonAsync("/api/estudantes/", estudante);
                response.EnsureSuccessStatusCode(); //lança um código de erro
                MessageBox.Show("Estudante incluído com sucesso", "Result", MessageBoxButton.OK, MessageBoxImage.Information);
                estudantesListView.ItemsSource = await GetAllEstudantes();
                estudantesListView.ScrollIntoView(estudantesListView.ItemContainerGenerator.Items[estudantesListView.Items.Count - 1]);
            }
            catch (Exception)
            {
                MessageBox.Show("O Estudante não foi incluído. (Verifique se o ID não esta duplicado)");
           }
      }

Neste código cria uma instância da classe Estudante e atribui a ela os dados informados no formulário. A seguir, usando o método  PostAsJsonAsync, envia uma requisição POST como uma operação assíncrona para a URI - /api/estudate - passando o objeto estudante serializado.

Para exibir o resultado e atualizar a exibição do controle ListView chamamos o método GetAllEstudantes().

3- Atualiza um estudante

      private async void btnAtualiza_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                var estudante = new Estudante()
                {
                    nome = txtNomeEstudante.Text,
                    id = int.Parse(txtIDEstudante.Text),
                    genero = cbxGenero.SelectedItem.ToString(),
                    idade = int.Parse(txtIdade.Text)
                };
                var response = await client.PutAsJsonAsync("/api/estudantes/", estudante);
                response.EnsureSuccessStatusCode(); //lança um código de erro
                MessageBox.Show("Estudante atualizado com sucesso", "Result", MessageBoxButton.OK, MessageBoxImage.Information);
                estudantesListView.ItemsSource = await GetAllEstudantes();
                estudantesListView.ScrollIntoView(estudantesListView.ItemContainerGenerator.Items[estudantesListView.Items.Count - 1]);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

Neste código cria uma instância da classe Estudante e atribui a ela os dados informados no formulário. A seguir, usando o método  PutAsJsonAsync, envia uma requisição PUT como uma operação assíncrona para a URI - /api/estudate - passando o objeto estudante serializado.

Para exibir o resultado e atualizar a exibição do controle ListView chamamos o método GetAllEstudantes().

4- Deleta um estudante

        private async void btnDeletEstudante_Click(object sender, RoutedEventArgs e)
        {
            try
            {
                HttpResponseMessage response = await client.DeleteAsync("/api/estudantes/" + txtID.Text);
                response.EnsureSuccessStatusCode(); //lança um código de erro
                MessageBox.Show("Estudante deletado com sucesso");
                estudantesListView.ItemsSource = await GetAllEstudantes();
                estudantesListView.ScrollIntoView(estudantesListView.ItemContainerGenerator.Items[estudantesListView.Items.Count - 1]);
            }
            catch (Exception)
            {
                MessageBox.Show("Estudante deletado com sucesso");
            }
        }

Neste código usamos o método DeleteAsync, envia uma requisição DELETE como uma operação assíncrona para a URI -/api/estudantes/" + txtID.Text - onde txtID.Text é o id do estudante.

Para exibir o resultado e atualizar a exibição do controle ListView chamamos o método GetAllEstudantes().

Temos assim a nossa Web API definida no projeto WebApi2_Estudante sendo consumida em um projeto WPF Application.

Pegue o projeto WPF completo aqui :  Consumindo_WebAPI_Estudantes.zip (sem as referências)

Porque toda a carne é como a erva, e toda a glória do homem como a flor da erva. Secou-se a erva, e caiu a sua flor;
Mas a palavra do Senhor permanece para sempre.E esta é a palavra que entre vós foi evangeliza
da.
1 Pedro 1:24-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 ?

Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ?

 

  Gostou ?   Compartilhe no Facebook   Compartilhe no Twitter

 

Referências:


José Carlos Macoratti