Integrating Bing Search Results Within A Web App Using .NET

Add to FacebookAdd to DiggAdd to Del.icio.usAdd to StumbleuponAdd to RedditAdd to BlinklistAdd to TwitterAdd to TechnoratiAdd to Yahoo BuzzAdd to Newsvine

A few months ago I was faced with the challenge of including a site search in a web system we maintain.

The main goals for the search tool were meaningful results, ease of use, and low cost of implementation.

After evaluating the search offerings from Google, Bing and Yahoo we went with Bing. Microsoft offers high flexibility and no fees for using the Bing Search API. The only thing they request is that you show some type of image or statement crediting Bing with the search results.

The Bing Search API is part of Project Silk Road it offers many options for choosing the source type and output protocol (JSON, SOAP, XML) as well as flexible presentation options (No restrictions on ordering and blending of result). This allows you to integrate custom results with the Bing results without violating the usage terms.

Below are some code snippets to reference:

Retrieves the XML document containing search results from Bing and loads them into an object collection.

public BingSearchResult(string title, string description, string url)
{
     this.Title = title;
     this.Description = description;
     this.Url = url;
}

private static BingSearchResultCollection GetResults(string searchQuery, int pageNum, int resultsPerPage)
{
int offset = ((pageNum - 1) * resultsPerPage);

string url = "http://api.search.live.net/xml.aspx?Appid={0}&sources={1}&query={2}&{1}.count={3}&{1}.offset={4}";
string completeUri = String.Format(url, appID, "web", "site:www.yoursite.org " + searchQuery, resultsPerPage, offset);

HttpWebRequest webRequest = null;
HttpWebResponse webResponse = null;
XmlReader xmlReader = null;
webRequest = (HttpWebRequest)WebRequest.Create(completeUri);
webResponse = (HttpWebResponse)webRequest.GetResponse();
            
//Handles an invalid xml document
try
{
    xmlReader = XmlReader.Create(webResponse.GetResponseStream());
}
catch (System.Security.SecurityException)
{
    return new BingSearchResultCollection();
}

XDocument xmlDoc = XDocument.Load(xmlReader);
            
//Loops through the results and creates BingSearchResult objects
if (GetElementsByName(xmlDoc, "SearchResponse").Any())
{
    XElement searchResponse = GetElementsByName(xmlDoc, "SearchResponse").First();
    if(GetElementsByName(searchResponse, "Web").Any())
    {
        XElement web = GetElementsByName(searchResponse, "Web").First();
        if (GetElementsByName(web, "Total").Any())
        {
                        
            int totalResults = Convert.ToInt32(GetElementsByName(web, "Total").First().Value);
            var list = new BingSearchResultCollection(totalResults, searchQuery);

            if (GetElementsByName(web, "Results").Any())
            {
                XElement results = GetElementsByName(web, "Results").First();
                if (GetElementsByName(web, "Results").Any())
                {
                    if (GetElementsByName(results, "WebResult").Any())
                    {
                        var webResults = GetElementsByName(results, "WebResult");

                        foreach (XElement el in webResults)
                        {
                            string resTitle = "";
                            string resUrl = "";
                            string resDescr = "";
                            if (GetElementsByName(el, "Title").Any())
                                resTitle = GetElementsByName(el, "Title").First().Value;
                            if (GetElementsByName(el, "Url").Any())
                                resUrl = GetElementsByName(el, "Url").First().Value;
                            if (GetElementsByName(el, "Description").Any())
                                resDescr = GetElementsByName(el, "Description").First().Value; ;

                            if (IsValidUrl(resUrl))
                                list.Add(new BingSearchResult(resTitle, resDescr, resUrl));
                        }

                        return list;
                    }
                }
            }
        }
    }
}

return new BingSearchResultCollection();
}

private static IEnumerable<XElement> GetElementsByName(XContainer cont, String name)
{
     return (from el in cont.Elements()
          where el.Name.LocalName == name
          select el);
}

The reason I ended up using a custom LINQ function to traverse the tree was because I couldn’t figure out how to get a collection of WebResult elements.

The XML document returned from Bing is structured like this:

<?xml version="1.0" encoding="utf-8" ?> 
<?pageview_candidate ?> 
<SearchResponse xmlns="http://schemas.microsoft.com/LiveSearch/2008/04/XML/element" Version="2.2">
     <Query>
          <SearchTerms>site:www.yoursite.com SearchTerm</SearchTerms> 
     </Query>
     <web:Web xmlns:web="http://schemas.microsoft.com/LiveSearch/2008/04/XML/web">
     <web:Total>1350000</web:Total> 
     <web:Offset>0</web:Offset> 
     <web:Results>
          <web:WebResult>
               <web:Title>Result Title</web:Title> 
               <web:Description>Description of Result</web:Description> 
               <web:Url>http://www.resulturl.com</web:Url> 
               <web:CacheUrl>http://cc.bingj.com/cache.aspx?somecashobjecthere</web:CacheUrl> 
               <web:DisplayUrl>www.resulturl.com</web:DisplayUrl> 
               <web:DateTime>2010-07-02T20:27:32Z</web:DateTime> 
         </web:WebResult>
     </web:Results>
     </web:Web>
</SearchResponse>

Hopefully this gives you an idea of what you need to hit the floor running when implementing the Bing Search API in your project(s).

Here are some helpful resources:
http://www.bing.com/developers/
http://www.bing.com/developers/s/API%20Basics.pdf

If you need a powered by Bing image you can use the one I created here.

Leave a comment