Desenvolvimento - Web Services

Criando um cliente para Amazon Web Services (AWS) no Pocket PC

Recentemente eu adquiri um dispositivo IPAQ PocketPC, e depois de checar todos os aplicativos nativos, veio a idéia de criar meu primeiro programa usando o .Net Compact Framework (.Net CF)...

por Rodrigo Vieira



Recentemente eu adquiri um dispositivo IPAQ PocketPC, e depois de checar todos os aplicativos nativos, veio a idéia de criar meu primeiro programa usando o .Net Compact Framework (.Net CF).

Entre várias possibilidades, eu decidi pôr em prática uma idéia que sempre vinha à minha cabeça quando eu visitava livrarias em busca de livros técnicos importados, que é a possibilidade de checar a cotação (ou seja, o número de "estrelas") que o livro tem no site Amazon.com, que é um bom indicativo se o livro é bom ou se é uma "bomba".

A boa notícia é que a Amazon possui um conjunto de web services muito completo, "Amazon Web Services"(AWS), que permite checar todas as informacões relativos a livros, CDs e DVDs, bem como jogos e tudo mais que é vendido no site.

Tal aplicativo exige conexão à Internet, naturalmente, mas acredito ser uma questäo de tempo até as grandes lojas e shopping-centers no Brasil oferecerem serviço de internet wireless (Wi-Fi) para seus clientes, como já é comum nos EUA e Europa.

Apesar de ter sido escrito com .Net CF, o código que você verá abaixo é virtualmente idêntico ao que seria necessário em aplicacões ASP.Net e Windows.Forms (com excecão da interface com o usuário), e para quem não possui dispositivos móveis vale a pena lembrar que é possível usar emuladores para testar seus programas (veja como nesse ótimo artigo do site).

Vamos lá então!

1) Criando um projeto para aplicativos móveis, e adicionando a web reference à Amazon.com

O primeiro passo é criar um novo projeto no Visual Studio 2003: vamos selecionar "Smart Device Application" na janela "New Project" (dei ao projeto o nome de "Amazon"), e então "Pocket PC" para a plataforma-destino e "Windows Application" para o tipo de projeto.

Veremos então um windows.form em branco, e antes de mais nada podemos adicionar logo a web reference aos serviços da Amazon.com: na janela "Solution Explorer", clique com o botão direito do mouse no item "References" e então selecione "Add Web Reference". Entre o endereco para o web service, http://soap.amazon.com/schemas3/AmazonWebServices.wsdl, conforme a figura abaixo

Repare que esse servico expõe vários métodos, inclusive métodos avancados que permitem adicionar e alterar produtos no "carrinho de compras" e finalizar o pedido. Entretanto, em nosso programa nos ateremos às funções de procura. No campo "Web Reference Name", podemos alterar o valor para AmazonWS, mais amigável.

2) Criando um ID para o Amazon Web Services

Todo programa que acessa o AWS requer um ID único, que a Amazon utiliza para identificar as chamadas. Esse ID é muito fácil de ser obtido, e é gratuito. Basta ir nessa página e seguir as instrucões. Ao fim você receberá um e-mail com uma chave de identificacão (devtag).

3) Procurando livros com o AWS

Nosso aplicativo terá 2 funções:

- Procurar títulos por palavra-chave (título, autor, ISBN, etc);
- Ver os detalhes de um título, selecionado no resultado da busca.

Vamos então adicionar um TabControl ao formulário, composto por 2 abas: no primeiro será feita a busca, no segundo veremos os detalhes do livro selecionado.

Os botões "< Ant." e "Próx. >" permitem que o usuário navegue pelos resultados da busca sem ter que selecionar o título anterior ou posterior na primeira aba, tornando a navegacão mais cômoda, como num browser. Os demais controles adicionados são, acredito, auto-explicativos.

Terminada a interface com o usuário, podemos entrar com o código no arquivo .vb do formulário. Vamos começar pela funcão-chave de nosso código, que conecta ao web service da Amazon, e realiza busca por palavra-chave:

  1     Dim products As AmazonWS.ProductInfo
  2     Dim currIndex As Short
  3 
  4     "--- essa constante eh o seu Subscription ID
  5     Private Const DEVTAG = "XXXXXXXXXXXXXXXXXXXXX"
  6 
  7     Sub SearchAmazon(ByVal str As String)
  8         Cursor.Current = Cursors.WaitCursor
  9 
 10         "---- define o parametro de busca
 11         Dim keywordReq As New AmazonWS.KeywordRequest
 12         With keywordReq
 13             .type = "heavy"
 14             .devtag = DEVTAG
 15             .tag = DEVTAG
 16             .mode = "books"
 17             .locale = "us"
 18             .sort = "reviewrank"
 19             .page = 1
 20             .keyword = str.Trim
 21         End With
 22 
 23         "---- conecta ao web service e realiza a busca
 24         Try
 25             Dim AmazWS As New AmazonWS.AmazonSearchService
 26             products = AmazWS.KeywordSearchRequest(keywordReq)
 27         Catch err As Exception
 28             Cursor.Current = Cursors.Default
 29             MsgBox(err.Message, MsgBoxStyle.Critical, "Erro na procura")
 30             Exit Sub
 31         End Try
 32 
 33         "---- lista os resultados
 34         If Not products Is Nothing AndAlso Not products.Details Is Nothing Then
 35             For Each item As AmazonWS.Details In products.Details
 36                 lbResultado.Items.Add(item.ProductName)
 37             Next
 38             Cursor.Current = Cursors.Default
 39         Else
 40             Cursor.Current = Cursors.Default
 41             MsgBox("Nenhum produto encontrado")
 42         End If
 43 
 44     End Sub
No topo, declaramos uma variável global à aplicacão, "products", do tipo ProductInfo, que armazenará todos os produtos retornados pela busca.

A constante DEVTAG deverá ser preenchida com o seu Subscription ID, conforme explicado na seção 2 do artigo.

A busca no web service é feita pela funcão KeywordSearchRequest (linha 26), que recebe como parâmetro um objeto do tipo KeywordRequest que foi definido entre as linhas 11 e 21. O parâmetro "type" (linha 13) aceita 2 valores, "lite" e "heavy", sendo que o primeiro faz que a busca retorne apenas dados básicos sobre os títulos (nome, ISBN) e o segundo traz informacões completas, tais como cotacão, preco, reviews, etc. Como uma busca pode retornar muitos títulos, o servico retorna apenas 10 de cada vez, em "páginas" de 10 itens, por razões de tráfego: para buscar mais resultados, devemos setar o parâmetro "page" (linha 19) para a página desejada. No nosso caso, estamos interessados apenas nos 10 primeiros resultados, então fixamos page=1. Finalmente, o "keyword" contém a(s) palavra(s)-chave que queremos buscar.

Agora podemos fazer o primeiro teste! Vamos entrar "vb.net" na caixa de texto e apertar "Procura": após 2 ou 3 segundos, recebemos o resultado:

Perfeito! Agora podemos fazer o código que mostra os detalhes de um título selecionado. Os comentários no código explicam o que é feito em cada bloco.

  1 Private Sub lbResultado_SelectedIndexChanged(…)
  2     MostraDetalhes(lbResultado.SelectedIndex)
  3 End Sub
  4 
  5 Sub MostraDetalhes(ByVal index As Short)
  6     "essa variavel controla qual item estamos vendo
  7     "na lista "products"
  8     currIndex = index
  9 
 10     "desabilita o botao "< Ant" se o usuario estiver no 1o item
 11     btAnterior.Enabled = (currIndex > 0)
 12 
 13     "desabilita o botao "Prox >" se o usuario estiver no ultimo item
 14     btProximo.Enabled = (currIndex < products.Details.Length - 1)
 15 
 16     Dim currProduct As AmazonWS.Details = products.Details(currIndex)
 17     With currProduct
 18         lblTitulo.Text = .ProductName
 19 
 20         "alguns titulos nao possuem informacao sobre autor,
 21         "entao precisamos checar antes
 22         If Not .Authors Is Nothing Then
 23             lblAutor.Text = .Authors(0)
 24             If .Authors.Length > 1 Then
 25                 lblAutor.Text &= " (et al)"
 26             End If
 27         Else
 28             lblAutor.Text = "N/A"
 29         End If
 30 
 31         "o campo "Reviews" tb pode eventualmente
 32         "vir em branco, embora nao seja comum
 33         If Not .Reviews Is Nothing Then
 34             lblCotacao.Text = .Reviews.AvgCustomerRating
 35         Else
 36             lblCotacao.Text = "N/A"
 37         End If
 38 
 39         lblPreco.Text = .OurPrice
 40         lblISBN.Text = .Isbn
 41         lblDisponibilidade.Text = .Availability
 42     End With
 43 
 44     "vamos selecionar a tab com os detalhes automaticamente
 45     TabControl1.SelectedIndex = 1
 46 End Sub

Podemos então testar o novo código, selecionando um dos títulos retornados pela busca:

Repare que o botão Anterior está desabilitado, pois estamos vendo o primeiro item da lista (linha 11).

Agora só falta fazermos o código para os botões "Ant" e "Próx", que é trivial:

  1 Private Sub btAnterior_Click(…) Handles btAnterior.Click
  2     If currIndex > 0 Then
  3         MostraDetalhes(currIndex - 1)
  4     End If
  5 End Sub
  6 
  7 Private Sub btProximo_Click(…) Handles btProximo.Click
  8     If currIndex < products.Details.Length - 1 Then
  9         MostraDetalhes(currIndex + 1)
 10     End If
 11 End Sub

4) Terminado o programa. Hora do "eye-candy"!

Bem, o nosso programa está pronto no que se refere a consumir os web services da Amazon.com, mas seria legal se pudéssemos também mostrar a capa dos livros, não?

Isso requer o uso da biblioteca System.Net do .Net Framework, e um trecho que código que permite salvar arquivos via HTTP. Também é bom criar uma variável do tipo Hashtable que funcionará como um cache de imagens, para que não tenhamos que baixar o mesmo arquivo duas vezes.

Então vamos adicionar um controle do tipo PictureBox na aba de detalhes, e o seguinte código:

  1 Dim coverCache As New Hashtable "guarda todas capas ja baixadas
  2 
  3 Private Function BaixaCapa(ByVal url As String) As Image
  4     If url = "" Then
  5         Return Nothing
  6     Else
  7         "se ja temos a capa no nosso cache, podemos retorna-la diretamente
  8         If coverCache.Contains(url) Then
  9             Return coverCache(url)
 10         Else
 11             Try
 12                 Cursor.Current = Cursors.WaitCursor
 13 
 14                 Dim webRequest As System.Net.HttpWebRequest
 15                 webRequest = System.Net.HttpWebRequest.Create(url)
 16                 "tenta acessar por 3 segundos no maximo
 17                 webRequest.Timeout = 3000
 18 
 19                 Dim webResponse As System.Net.HttpWebResponse
 20                 webResponse = webRequest.GetResponse
 21                 Dim bmp As New Bitmap(webResponse.GetResponseStream)
 22                 webResponse.Close()
 23 
 24                 Cursor.Current = Cursors.Default
 25                 If Not bmp Is Nothing AndAlso bmp.Width > 1 Then
 26                     coverCache.Add(url, bmp)
 27                     Return bmp
 28                 Else
 29                     coverCache.Add(url, Nothing)
 30                     Return Nothing
 31                 End If
 32             Catch e As Exception
 33                 Cursor.Current = Cursors.Default
 34                 MsgBox("Erro baixando capa:" & e.Message)
 35                 Return Nothing
 36             End Try
 37         End If
 38     End If
 39 End Function

Para mostrar a capa na aba de detalhes, basta adicionar o comando

  1 Dim capa As Image = BaixaCapa(.ImageUrlSmall)
  2 pbCapa.Image = capa

entre as linhas 41 e 42 na funcão MostraDetalhes.

Testando o nosso programa, podemos agora ver a capa, o que torna o aplicativo muito mais atraente:

Bem, um último detalhe para deixar o programa realmente legal seria trocar o campo "cotação" por estrelas, como no site da Amazon, mas isso fica como exercício para você ;-)

Espero que este artigo seja útil!

Até a próxima.

Rodrigo Vieira

Rodrigo Vieira - MCSD e MCAD, formado em Ciência da Computacão, trabalhando há 5 anos em uma empresa de telecomunicacões em Oslo, Noruega, desenvolvendo aplicativos para Intranet nas plataformas .Net e Oracle. Entusiasta de Python, Mono, Linux e software livre em geral.
Blog The Spoke:
http://br.thespoke.net/MyBlog/rodviking/MyBlog.aspx