In today’s post, we will be working with services. As some of you know, I’m currently finishing my first book titled Silverlight 4 Data Access Cookbook. If all goes well, it will be available in early access preview somewhere in the coming week. Therefore, I decided I needed to write a post that’s in the same area as my book. More specifically, I’ll be creating a application that works together with the services API exposed by Bing.com, Microsoft’s new and successful search engine.
Bing has a very rich API that we can use to incorporate search functionalities in our applications, including Silverlight applications. It allows us to use WCF (SOAP) and REST communication, because it exposes endpoints for both these technologies. In this particular example, I’m using the SOAP interface for communication using a WCF service. To get a complete overview of the functionalities, you can download the PDF describing the entire API at http://www.bing.com/developers/s/API%20Basics.pdf . It also contains some sample code.
The very first thing we should before we can actually start building applications with Bing, is obtaining an API key. This key is required so Bing can check that your request is valid (this key will be part of every request you’ll send to Bing). Obtaining a key is free and can be done at http://www.bing.com/developers/createapp.aspx .
The provided sample is a Silverlight 4/VS2010 solution, all the code included however also works with Visual Studio 2008/Silverlight 3.
First, we need to generate a proxy using Visual Studio 2010. For this, we need the address of the WSDL (Web Service Description Language) file. In the documentation, we can find that this address is: http://api.search.live.net/search.wsdl?AppID=12345 where 12345 needs to be replaced with your obtained API key. In Visual Studio, we add the service reference using the dialog and I have set the namespace to BingSearchService.
Visual Studio will at this point create the proxy for the service. A proxy contains a client-side copy of the types exposed by the service and its methods. The contents of the methods is replaced with a call to the real service method. In the client-side code, we can now work with these types and methods.
In the screenshot a bit further, you can see the interface of the application. It contains a TextBox and a Button to search and a templated ListBox to display the results. Let’s first create the code for the event handler of the click event. Bing accepts quite a lot of parameters for the search it needs to perform. These are encapsulated in an object of type SearchRequest. Since we are conducting a normal web search, we specify this in the Sources property of the SearchRequest instance. A search with Bing is a service request, so all communication needs to be done asynchronously. We can see this at the way we are calling the service using the SearchCompleted event and SearchAsync() method. Below is the code.
private void SearchButton_Click(object sender, RoutedEventArgs e)
{ LiveSearchPortTypeClient soapClient = new LiveSearchPortTypeClient();
SearchRequest request = new SearchRequest();
request.AppId = "81691C6A195FBC3FB469594BAA30B50A99CF3D22";
request.Sources = new SourceType[] { SourceType.Web };
if (SearchTextBox.Text != string.Empty)
{ request.Query = SearchTextBox.Text;
soapClient.SearchCompleted +=
new EventHandler<SearchCompletedEventArgs>(soapClient_SearchCompleted);
soapClient.SearchAsync(request);
}
}
When the service completes asynchronously, meaning, when Bing’s results are ready and available, the *Completed event is called and executed. In this event handler, we have access to the results of the service call. The result can be found in the e.Result parameter and is always of the same type as returned by the service. In our specific case, the used type is a SearchResponse, again a type exposed by the Bing services. We can now loop through these results and using a simple LINQ query, create an IEnumberable<SearchResult> . SearchResult is a type created by us to allow us to data bind to the results. This type is very simple:
public class SearchResult
{ public string SearchResultTitle { get; set; } public string SearchResultDescription { get; set; } public string SearchResultUri { get; set; }}
The code for the event handler is shown next:
void soapClient_SearchCompleted(object sender, SearchCompletedEventArgs e)
{ SearchResponse response = e.Result;
if (response.Web.Results.Count() > 0)
{ var results = from result in response.Web.Results
select new SearchResult
{ SearchResultTitle = result.Title,
SearchResultUri = result.Url,
SearchResultDescription = result.Description
};
ResultListBox.ItemsSource = results.ToList();
}
}
The ListBox is as said templated; the ItemsTemplate has been replaced with a custom data template, as shown below:
<ListBox x:Name="ResultListBox" Grid.Row="1" Margin="3" Background="Black">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition></RowDefinition>
</Grid.RowDefinitions>
<TextBlock Text="{Binding SearchResultTitle}" FontWeight="Bold" FontSize="15" TextDecorations="Underline" Foreground="White"></TextBlock>
<TextBlock Text="{Binding SearchResultDescription}" Grid.Row="1" TextWrapping="Wrap" Width="400" HorizontalAlignment="Left"
Foreground="White"></TextBlock>
<TextBlock Text="{Binding SearchResultUri}" Grid.Row="2" Foreground="#568e71"> </TextBlock>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
When we now execute a search using our application, we see the following:
The complete sample can be downloaded here:
SLBing.zip (790.49 KB)