Tapping the full potential of RIA applications means involving remote Web services. In this article, I'll present techniques that demonstrate how to communicate between Silverlight and Live Search using Silverlight's services infrastructure.

This article is excerpted from John Papa's book, Data-Driven Services with Silverlight 2, published by O'Reilly Media, Inc. ISBN-13: 978-0596523091 and is reprinted with the author's permission.

Silverlight 2 brings a tremendous number of tools to the client to allow creating a rich user interface. It also has the ability to consume a variety of services across a network or the Internet. The ability to communicate with different types of Web services in different ways (through RESTful services, syndicated feeds, and SOAP services to name a few) allows Silverlight 2 applications to take advantage of the features these services expose. Silverlight 2 clients provide a robust user experience and the ability to interact with a variety of services, which makes Silverlight 2 a great choice for interactive and service-based applications. This article demonstrates how to build a Silverlight application that communicates with the Live Search Web services.

There are many services available on the Web that can be called. Some of these Web services are discoverable like Live Search and others are not and use REST, like Amazon ECS. Most of these services require a unique key be sent to the service so that the request can be tied back to whoever the key belongs. Live Search calls their key an AppID.

Instructions for creating an AppID for Live 
Search can be found at 
http://<a href="http://msdn.microsoft.com/en-us/library/bb266187.asp";>msdn.microsoft.com/en-us/library/bb266187.asp<;/a>x. Instructions for using 
the Live Search service can be found at 
http://<a href="http://msdn.microsoft.com/en-us/library/bb251808.asp";>msdn.microsoft.com/en-us/library/bb251808.asp<;/a>x.

The following example shows how you can conduct a simple search using a SOAP-based Web service provided by Live Search. First, the AppID must be requested and used in the LiveSearchClient sample program (available from the CoDe Magazine site for download). Next, you must add a service reference to the Live Search service. (You can find this service at http://soap.search.msn.com/webservices.asmx?wsdl.) The sample names the service LiveSearchService as shown in Figure 1.

Figure 1:  Referencing Live Search.
Figure 1: Referencing Live Search.

Once you've referenced the service you can create a proxy to the service and invoke its SearchAsync method. This method requires a SearchRequest parameter, which can include a lot of intricate parameters defining the type of search. This Live Search example will keep the search parameters simple and simply return the first 10 hits (shown by the Offset property in Listing 1). Listing 1 shows the creation of the proxy object, the setup of the search parameters, the adding of the event handler for the completion of the search, and the asynchronous SearchAsync method call to the Web service.

Once the search has been completed, the proxy_SearchCompleted event handler (shown in Listing 2) executes and binds the result to the ListBox control. A DataTemplate simply displays the Title, Url and Description of each search result in the ListBox. Figure 2 shows the results of a sample search.

Figure 2: Live Search Results.
Figure 2: Live Search Results.

When the Silverlight client makes the Web service request, the call originates from the local Web site that hosts the Silverlight application on the Live Search domain. This call crosses the domain boundary. Silverlight will request the clientaccesspolicy.xml file and will find it (shown in Listing 3).

The clientaccesspolicy.xml file indicates that it will allow any SOAP request from any domain to use the Web services located anywhere on the Web site, which is http://soap.search.msn.com.

Wrap Up

Silverlight clients can call any discoverable Web services using ASMX Web services and WCF Web services. While Silverlight can also call services that do not describe themselves, such as REST services, self-describing services are beneficial since they can tell the client application exactly how they should be called and what type of data they will return (if any).

Listing 1: Searching asynchronously

' C#
private void btnSearch_Click(object sender, RoutedEventArgs e)
{
    MSNSearchPortTypeClient proxy = new MSNSearchPortTypeClient();
    proxy.SearchCompleted += new 
    EventHandler<SearchCompletedEventArgs>(proxy_SearchCompleted);

    SourceRequest[] sourceRequests = new SourceRequest[1];
    sourceRequests[0] = new SourceRequest();
    sourceRequests[0].Source = SourceType.Web;
    sourceRequests[0].ResultFields = 
          ResultFieldMask.All | ResultFieldMask.SearchTagsArray;
    sourceRequests[0].Count = 10;
    sourceRequests[0].Offset = 0;

    SearchRequest searchRequest = new SearchRequest();
    searchRequest.AppID = appID;
    searchRequest.Query = tbSearch.Text;
    searchRequest.CultureInfo = "en-US";
    searchRequest.Requests = sourceRequests;
    searchRequest.SafeSearch = SafeSearchOptions.Moderate;
    searchRequest.Flags = SearchFlags.None;

    proxy.SearchAsync(searchRequest);
}

// VB

Private Sub btnSearch_Click(ByVal sender As Object, _
ByVal e As RoutedEventArgs)
   Dim proxy As New MSNSearchPortTypeClient()
   AddHandler proxy.SearchCompleted, _
      AddressOf proxy_SearchCompleted

   Dim sourceRequests(0) As SourceRequest
   sourceRequests(0) = New SourceRequest()
   sourceRequests(0).Source = SourceType.Web
   sourceRequests(0).ResultFields = ResultFieldMask.All _
     Or ResultFieldMask.SearchTagsArray
   sourceRequests(0).Count = 10
   sourceRequests(0).Offset = 0

   Dim searchRequest As New SearchRequest()
   searchRequest.AppID = appID
   searchRequest.Query = tbSearch.Text
   searchRequest.CultureInfo = "en-US"
   searchRequest.Requests = sourceRequests
   searchRequest.SafeSearch = SafeSearchOptions.Moderate
   searchRequest.Flags = SearchFlags.None

   proxy.SearchAsync(searchRequest)
End Sub

Listing 2: Binding the Live Search results

'  C#
private void proxy_SearchCompleted(object sender, 
SearchCompletedEventArgs e)
{
    if (e.Error != null)
    {
        lbMessage.Text = e.Error.Message;
        return;
    }

    SearchResponse searchResponse = e.Result;
    var resultsList = searchResponse.Responses[0].Results;
    lstResults.DataContext = resultsList;
}
// VB

Private Sub proxy_SearchCompleted(ByVal sender As Object, _
ByVal e As SearchCompletedEventArgs)
   If e.Error IsNot Nothing Then
      lbMessage.Text = e.Error.Message
      Return
   End If

   Dim searchResponse As SearchResponse = e.Result
   Dim resultsList = searchResponse.Responses(0).Results
   lstResults.DataContext = resultsList
End Sub
<?xml version="1.0" encoding="utf-8" ?> 
<access-policy>
   <cross-domain-access>
      <policy>
       <allow-from http-request-headers="SOAPAction,Content-
        Type">
          <domain uri="*" /> 
         </allow-from>
         <grant-to>
          <resource path="/" include-subpaths="true" /> 
         </grant-to>
    </policy>
   </cross-domain-access>
</access-policy>