As part of validating and playing with some of the extensibility features in .NET RIA Services, I needed to write a LINQ provider. This was also a good opportunity to delve into some of the deeper technical aspects of the IQueryable construct, expression trees and related concepts, which I had not gotten into first-hand until now. For my prototyping, I decided to write a LINQ provider for querying Bing to search for pages and images. This post will focus on using the LINQ provider itself, and seeing it in action, and in my next post I'll tie it all back to .NET RIA Services. I am calling this BLinq. :-)
Bing has a new search API that provides you the option of using REST interface (XML or JSON) or a SOAP interface. My LINQ provider provides a more natural LINQ syntax that you can now use without having to worry about protocol details, web requests, URIs etc. Under the covers the LINQ functionality builds on the REST/XML API.
Here is an example of a basic search for pages using BLinq:
BingContext bing = new BingContext(appKey);
IQueryable<PageSearchResult> pagesQuery =
from p in bing.Pages
where p.Query == "nikhil"
select p;
foreach (PageSearchResult page in pagesQuery) {
// Write out page members (title, uri, description, display URL and date)
}
Simple enough? BingContext is very much like a Linq-to-SQL DataContext. It has a Pages property of type IQueryable<PageSearchResult> (ala a Table<T> in a DataContext). Of course this is LINQ, and so you can use standard LINQ constructs like Skip and Take for example to page over the search results. For example:
// Get the first search result...
pagesQuery = pagesQuery.Take(1);
BLinq provides a fluent interface to configure one or more additional options when invoking a search request. For example, say I want to search for pizza in Redmond:
IQueryable<PageSearchResult> pagesQuery =
from p in bing.Pages.LocalResults("Redmond")
where p.Query == "pizza"
select p;
Other options include scoping results to a particular site. For example, I want to search for Silverlight-related content on my site:
IQueryable<PageSearchResult> pagesQuery =
from p in bing.Pages.ScopeResults("nikhilk.net")
where p.Query == "silverlight"
select p;
So far I've been showing examples that search for pages. BLinq also supports searching for images. For example, say I want to search for images of Yellowstone, and turn on the strict filter (another example of an option I can specify on the query):
IQueryable<ImageSearchResult> imagesQuery =
from img in bing.Images.SafeResults()
where img.Query == "Yellowstone"
select img;
var imagesPage1 = imagesQuery.Take(10).ToList();
var imagesPage2 = imagesQuery.Skip(10).Take(10).ToList();
foreach (ImageSearchResult img in imagesPage1.Union(imagesPage2)) {
// Write out image title, image URI, image size, containing page URI,
// thumbnail URI, and thumbnail size.
}
Generally speaking, BLinq works like any other LINQ provider for the set of capabilities provided by the underlying API (where clause on the Query member, Skip and Take). As a result, not only does the code look consistent with other LINQ code, but standard tools for LINQ just work (as well as higher level frameworks). Here is a screenshot of experimenting with BLinq in the LINQPad tool.

The Implementation

Under the covers, BLinq contains an implementation of IQueryable that is backed by a Bing-based implementation of IQueryProvider. This query provider is responsible for walking the LINQ expression trees created by the app developer and turning the expression tree into a corresponding URI suitable for use with the Bing API. When asked to execute the expression, the query provider uses that URI to issue a web request, and materialize search results from the resulting response XML. If you're interested in understanding the basics of writing such a LINQ provider, you might find BLinq an interesting sample to study, as is is both self-contained without lots of dependencies, and a small enough implementation to understand it all the way through. I've kept this post focused on using BLinq... if you have questions on the implementation, feel free to post in the comments. You can also check out LINQ Programming or LINQ in Action, which go deeper into concepts like LINQ expressions, lambdas, and building your own LINQ provider above and beyond using LINQ.
Next Steps
This is just a start. It would be interesting to fully flesh out BLinq to enable searching for spellings, related searches, ads etc. to cover the full capabilities of the underlying Bing API. Perhaps the folks from the Bing team would be interested in getting this functionality into the Bing SDK. Also, as mentioned above stay tuned for the next post, where I'll show how this can be integrated with .NET RIA Services on the server and client, as .NET RIA Services also builds on the same LINQ building blocks.
You can download the sample framework, which implements the LINQ functionality, and the sample code. Note that you'll also need to get an API key by registering for using the service if you'd like to compile and run the code associated with this post on your end.
Posted on Saturday, 8/22/2009 @ 10:35 AM
| #
Projects