SOAP sta per Simple Object Access Protocol ed è un protocollo per lo scambio di messaggi tra due componenti software, adatto per effettuare chiamate a procedure remote, scenario perfetto per i Web Service. SOAP può essere utilizzato con molti protocolli, però è l'HTTP l'unico ad essere standardizzato da consorzio del W3C.
Silverlight può accedere a tutti i servizi SOAP conformi allo standard WS-I Basic Profile 1.0, in particolare SOAP 1.1 su HTTP. Questa caratteristica permette a Silverlight di accedere anche a servizi implementati con tecnologie non Microsoft.
È altrettanto vero che Microsoft offre due tecnologie per il .NET Framework, ben integrate con Visual Studio e Silverlight, che permettono di soddisfare in suddetti requisiti: ASP.NET Web Service e WCF (appositamente configurato per utilizzare basicHttpBinding
).
Per descrivere al meglio come usufruire di un servizio SOAP in questa lezione creeremo un semplice client di Bing (già Live Search), il motore di ricerca di casa Microsoft. L'interfaccia utente sarà minimale, in modo di mantenere la concentrazione sul meccanismo di comunicazione.
Possiamo interrogare Live Search con diversi protocolli e formati, per il nostro esempio utilizziamo il Protocollo SOAP. Tutte le informazioni necessarie per permettere agli sviluppatori di utilizzare i servizi esposti da Bing sono disponibili qui.
Sempre sul solito sito sarà possibile generare un AppID, un codice univoco da utilizzare obbligatoriamente nei messaggi di richiesta verso il servizio. Per generare un AppID abbiamo bisogno prima di tutto di un Windows Live ID.
Una volta sistemato il beckend, dobbiamo creare il proxy, operazione che si effettua aggiungendo al progetto Silverlight un Service Reference
.
Clicchiamo col il tasto destro sul progetto e scegliamo la voce Add Service Reference...
dal menu contestuale.
Successivamente impostiamo l'indirizzo (url) del servizio ed il nome del namespace che conterrà il codice delle classi proxy. L'url per il servizio Live Search (SOAP) è:
http://api.search.live.net/search.wsdl?AppID=<TuoAppId>
inserendo l'AppID
precedentemente generato.
Qualora sia necessario, nella sezione Advanced...
troviamo un insieme di opzioni che ci permettono di personalizzare le impostazione di creazione del proxy.
Una volta aggiunto il riferimento, Visual Studio crea tutte le classi che ci permettono di consumere il servizio ed il file ServiceReferences.ClientConfig
, che contiene le informazioni di configurazione: l'endpoint interessato, il protocollo, l'URL ed il contratto.
<configuration> <system.serviceModel> <bindings> <basicHttpBinding> <binding name="LiveSearchPortBinding" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647"> <security mode="None" /> </binding> </basicHttpBinding> </bindings> <client> <endpoint address="http://api.search.live.net:80/soap.asmx" binding="basicHttpBinding" bindingConfiguration="LiveSearchPortBinding" contract="LiveSearchServiceReferece.LiveSearchPortType" name="LiveSearchPort" /> </client> </system.serviceModel> </configuration>
Esplorando brevemente il modello ad oggetti generato da Visual Studio notiamo le seguenti classi:
Classe | Descrizione |
---|---|
LiveSearchPortTypeClient |
È il proxy vero e proprio, che espone il meotodo SearchAsync per effettuare la ricerca e l'evento SearchCompleted per attivare il callback |
SearchRequest |
È il messaggio di richiesta che verrà inviato al servizio tramite il metodo SearchAsync |
SearchResponse |
È il messaggio di risposta che sarà inviato al client ed esposto come proprietà della classe SearchCompletedEventArgs dell'evento SearchCompleted |
Lato client realizziamo la pagina Silverlight che ci permetterà di effettuare la ricerca e visualizzare parte del risultato. Con XAML definiamo l'interfaccia grafica e inseriamo una TextBox
per il testo da ricercare, un Button
per lanciare la ricerca ed una ListBox
per visualizzare il risultato:
<Grid x:Name="LayoutRoot" Background="Azure" Width="700" Height="700"> <Grid.RowDefinitions> <RowDefinition Height="Auto" /> <RowDefinition Height="*" /> </Grid.RowDefinitions> <Grid.ColumnDefinitions> <ColumnDefinition Width="100" /> <ColumnDefinition Width="*" /> <ColumnDefinition Width="80" /> </Grid.ColumnDefinitions> <TextBlock Grid.Row="0" Grid.Column="0" Margin="5" FontSize="12" VerticalAlignment="Center" Text="Topic:" /> <TextBox Grid.Row="0" Grid.Column="1" x:Name="txtSearch" Margin="5" FontSize="12" /> <Button Grid.Row="0" Grid.Column="2" x:Name="btnSearch" Margin="5" Width="60" Content="Search" Click="btnSearch_Click" /> <ListBox x:Name="lstSearchResult" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" FontSize="12"></ListBox> </Grid>
Non abbiamo ancora definito nessuna proprietà di layout per gli Items
della ListBox
, lo faremo in seguito. Proseguiamo assegnando il codice di chiamata al servizio all'evento Click
del Button
:
- istanziare il proxy
- impostare il metodo di callback come handler
- creare il messaggio di richiesta
- invocare il metodo
private void btnSearch_Click(object sender, RoutedEventArgs e) { var client = new LiveSearchPortTypeClient(); client.SearchCompleted += new EventHandler<SearchCompletedEventArgs>(client_SearchCompleted); var request = new SearchRequest(); request.AppId = liveSearchKey; request.Query = txtSearch.Text; request.Sources = new SourceType[] { SourceType.Web }; client.SearchAsync(request); }
Live Search può effettuare ricerche in più contesti differenti come Web, Immagini e Video, perciò, quando generiamo il messaggio di richiesta dobbiamo specificare il tipo di ricerca che vogliamo, in questo caso 'Web'. Altro aspetto importate e specifico di Live Search è l'impostazione dell'AppID nel messaggio di richiesta.
Nel metodo di callback verifichiamo la presenza di errori, se presenti notifichiamo opportunamente all'utente con una MessageBox, altrimenti impostiamo il risultato, contenuto nel messaggio di risposta, come ItemSource
della ListBox
:
public void client_SearchCompleted(object sender, SearchCompletedEventArgs e) { if (e.Error != null) { MessageBox.Show(e.Error.Message); return; } lstSearchResult.ItemsSource = e.Result.Web.Results.Take(20); }
Anche il messaggio di risposta può contenere i risultati nei contesti Web, Immagini e Video. Il primo è quello che ci interessa ed è rappresentato dalla proprietà WebResponse
, che coniene un'array di WebResult
. Ciascun WebResult
possiede le informazioni sul singolo risultato della ricerca (titolo, descrizione, URL).
Per limitare il numero di elementi visualizzati prendiamo solo i primi trenta risultati, sfruttando l'Extension Method Take
. Prima di eseguire l'applicazione torniamo nel markup XAML ed impostiamo la proprietà DisplayMemberPath
su Title
.
<ListBox x:Name="lstSearchResult"
Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="3" FontSize="12"
DisplayMemberPath="Title">
</ListBox>
L'applicazione in esecuzione risulterà all'incirca così: