Click here to Skip to main content
Licence CPOL
First Posted 13 Nov 2007
Views 23,242
Downloads 246
Bookmarked 41 times

Consuming the Windows Live Search Webservice using ASP.NET and AJAX 1.0

By | 20 Nov 2007 | Article
This application will bind search results from the Windows Live Search Webservice to a GridView control and make use of AJAX 1.0 for searching and paging.

Screenshot - search.jpg

Introduction

This application will bind search results from the Windows Live Search Webservice to a GridView control and make use of AJAX 1.0 for searching and paging. This application allows you to search multiple websites at once. A practical example can be found here. The city example, however, isn't AJAX-driven like the example in this article.

You can customize the search properties via the web.config file. Please have the following requirements met before proceeding.

  1. ASP.NET 2.0 installed.
  2. Setup the downloaded app in IIS, and choose ASP.NET 2.0.
  3. Have AJAX 1.0 installed on your machine.
  4. Obtain a Key from MS to use this Webservice (MSN). You can then add the key to the app setting in web.config.

Background

I found bits and pieces of random examples on the net but nothing substantially helpful. I thought this might be helpful for folks who wish to see a working example. You can always take out the AJAX and capture the search query via a querystring, with just a few minor changes.

Using the code

The WindowsLiveSearch class has one main method called Search. Instantiating the class will fill the required properties from web.config to use in the Search method.

The main configuration properties are organized as a type called LiveSearchProperties.

/// <summary>
/// Properties used for setting up web service
/// </summary>

public class LiveSearchProperties
{
    private string _searchLic;
    public string SearchLic
    {
        get { return _searchLic; }
        set { _searchLic = value; }
    }

    private int _resultsSize;
    public int ResultsSize
    {
        get { return _resultsSize; }
        set { _resultsSize = value; }
    }

    private string _searchSites;
    public string SearchSites
    {
        get { return _searchSites; }
        set { _searchSites = value; }
    }

    private SafeSearchOptions _searchOptions;
    public SafeSearchOptions SearchOptions
    {
        get { return _searchOptions; }
        set { _searchOptions = value; }
    }
}

In the constructor, the properties are filled. SP is the local property of WindowsLiveSearch of type LiveSearchProperties. Here, the configuration settings are stored in a new instance of LiveSearchProperties and then stored in SP (the WindowsLiveSearch property).

/// <summary>
/// Creates a WindowsLiveSearch and fills properties with values
/// </summary>

public WindowsLiveSearch()
{
    // -------------------------------

    // Initialize properties

    // -------------------------------


    // Error Property

    ErrorMsg = "";
    // LiveSearchProperties

    LiveSearchProperties sp = new LiveSearchProperties();
    sp.SearchLic = ConfigurationManager.AppSettings["SearchLic"];
    sp.ResultsSize = Int32.Parse(ConfigurationManager.AppSettings["ResultsSize"]);
    sp.SearchSites = ConfigurationManager.AppSettings["SearchSites"];
    sp.SearchOptions = SafeSearchOptions.Off;
    SP = sp; // Save instance to class property

    sp = null; // Null out unused object

}

The Search method is as follows:

/// <summary>  
/// This is the main function you call after object creation. 
/// You can pass the search query in here and get a list of 
/// results to work with. You can easily bind these results to an 
/// ASP.NET control if desired or foreach the list to get the data.
/// </summary>

/// <param name="searchQuery">The search query</param>

/// <returns>A generic list of search results</returns>

public IList<LiveSearchResults> Search(string searchQuery)
{
    // Basic checks

    if ((searchQuery == null) ||
        (searchQuery.Length == 0) ||
        (searchQuery.Trim() == ""))
        return null;

    IList<LiveSearchResults> resultsCollection = 
              new List<LiveSearchResults>();
    using (MSNSearchService s = new MSNSearchService())
    {
        SearchRequest searchRequest = new SearchRequest();
        searchRequest = SetUpRequest(searchRequest, searchQuery, SP);
        SearchResponse searchResponse;
        try
        {
            searchResponse = s.Search(searchRequest);
            resultsCollection = CaptureResults(searchResponse);
        }
        catch (Exception e)
        {
            ErrorMsg = e.ToString();
        }
        finally
        {
          // If there was an error

          if (ErrorMsg.Length > 0)
            LogMessage("There was an error with searchQuery: " +
              searchQuery);
          else
            LogMessage("A successful search was made with searchQuery: " +
              searchQuery);
        }
    }
    return resultsCollection;
}

The Search method uses the MSNSearchService class, which utilizes two main classes: SearchRequest and SearchResponse. The SearchRequest object consists of all the properties needed to allow the Search class to understand what type of search you are trying to make. In this example, we are going to do a web search.

The following is the SearchRequest method:

/// <summary>  
/// Sets up the MSN SearchRequest Object
/// </summary>

/// <param name="searchRequest">A SearchRequest Object</param>
/// <param name="searchQuery">The search query</param>
/// <param name="sp">LiveSearchProperties Object</param>

/// <returns>The SearchRequest Object</returns>

private SearchRequest SetUpRequest(
    SearchRequest searchRequest,
    string searchQuery,
    LiveSearchProperties sp)
{
   SourceRequest[] sr = new SourceRequest[1];
   sr[0] = new SourceRequest();
   sr[0].Source = SourceType.Web;
   sr[0].ResultFields = ResultFieldMask.All;
   sr[0].Count = sp.ResultsSize;
   sr[0].Offset = 0;

   searchRequest.Requests = sr;

   searchRequest.Query = searchQuery + " " + sp.SearchSites;
   searchRequest.SafeSearch = sp.SearchOptions;
   searchRequest.AppID = sp.SearchLic;
   searchRequest.Flags = SearchFlags.MarkQueryWords;
   searchRequest.CultureInfo = "en-US";
   return searchRequest;
}

After you setup the Request, you can use the Webservice to get a SearchResponse. I created a method called CaptureResults to do this. To store the captured results, I created a type called LiveSearchResults.

The LiveSearchResults properties:

/// <summary>
/// Properties used to store search results
/// </summary>

public class LiveSearchResults
{
   private string _url;
   public string URL
   {
       get { return _url; }
       set { _url = value; }
   }

   private string _title;
   public string Title
   {
       get { return _title; }
       set { _title = value; }
   }

   private string _description;
   public string Description
   {
       get { return _description; }
       set { _description = value; }
   }

   private string _displayURL;
   public string DisplayURL
   {
       get { return _displayURL; }
       set { _displayURL = value; }
   }

   private string _cachedURL;
   public string CachedURL
   {
       get { return _cachedURL; }
       set { _cachedURL = value; }
   }
}

This is the CaptureResults method:

/// <summary>
/// Creates a list of Search Results
/// </summary>

/// <param name="search_Response">The LiveSearch Response</param>

/// <returns>A collection of search results</returns>

private IList<LiveSearchResults> CaptureResults(SearchResponse search_Response)
{
 // Create a collection object to build list

 IList<LiveSearchResults> resultsCollector = new List<LiveSearchResults>();
 //Get data from web service

 foreach (SourceResponse response in search_Response.Responses)
 {
   Result[] response_results = null;
   response_results = response.Results;
   //Secure and store output

   foreach (Result response_result in response_results)
   {
      LiveSearchResults row = new LiveSearchResults();
      row.URL = AntiXss.HtmlEncode(CheckForNull(response_result.Url));
      row.Title = AntiXss.HtmlEncode(CheckForNull(response_result.Title))
          .Replace("&#57344;", "<strong>").Replace("&#57345;", "</strong>");
      row.Description = AntiXss.HtmlEncode(CheckForNull(response_result.Description))
          .Replace("&#57344;", "<strong>").Replace("&#57345;", "</strong>");
      row.DisplayURL = AntiXss.HtmlEncode(CheckForNull(response_result.DisplayUrl))
          .Replace("&#57344;", "<strong>").Replace("&#57345;", "</strong>");
      row.CachedURL = AntiXss.HtmlEncode(CheckForNull(response_result.CacheUrl));
      resultsCollector.Add(row);
   }
 }
 return resultsCollector;
}

This method uses the AntiXssLibrary.dll from MS. This will prevent unwanted cross-site scripting data from getting stored in the results. This method builds and returns a generic list to the Search method, which will enable you to bind the results to a Web Control.

The Presentation layer

The ObjectDataSource does all the work.

<asp:ObjectDataSource ID="ObjectDataSource1" runat="server" SelectMethod="Search"
 TypeName="Windows.Live.Search.WindowsLiveSearch" OnSelected="ObjectDataSource1_Selected">
 <SelectParameters>
   <asp:FormParameter FormField="searchBox" Name="searchQuery" Type="String" />
 </SelectParameters>
</asp:ObjectDataSource>

As shown, you can see that I included the class in the TypeName parameter. I then selected the method "Search" from the class.

The OnSelected event is used to get the total results count. This was the only way I knew how to accomplish this, considering the GridView Count property only gives the count of the results actually shown on the screen.

The OnSelected method:

// Get the total number of records

protected void ObjectDataSource1_Selected(object sender, 
               ObjectDataSourceStatusEventArgs e)
{
  Instructionlbl.Text = "";

  try
  {
    IList<LiveSearchResults> resultsCollection = 
             new List<LiveSearchResults>();
    resultsCollection = (IList<LiveSearchResults>)e.ReturnValue;
    resultsTotal = resultsCollection.Count;
    if (resultsTotal == 0)
      Instructionlbl.Text = "Your search provided no results.";
  }
  catch (System.NullReferenceException)
  {
    Instructionlbl.Text = "Please enter a search term.";
  }
}

If the search query is blank, then there will be a System.NullReferenceException. So, that is where the Instruction Label comes in to ask the user to "Please enter a search term".

AJAX stuff

To get this to work, you must surround the controls you want updated in an AJAX UpdatePanel. In this example, I put the GridView control and the Instruction Label in the UpdatePanel.

To trigger the update panel, you simply supply the following:

<Triggers>
  <asp:AsyncPostBackTrigger ControlID="SearchButton" EventName="click" />
</Triggers>

This simply states to trigger the update panel when a Click event occurs.

Points of interest

Everything you need will be in the project download. You should be able to take what I did and customize it to your needs. You can play around with the Search settings in the web.config file. You can also change the default sites to search. All the settings are the same as if you were doing an advanced search with the Live Search Engine.

History

  • 11/13/2007
    • Added project to The Code Project.
  • 11/20/2007
    • Added logging (Optional feature in web.config)
    • Fixed Field Null Reference Error
    • Added search
    • Provided a No Results message

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Daniel Penrod

Web Developer

United States United States

Member

Daniel works as an Application Development Specialist. He primarily uses: Java, C#.NET and occasionally Ruby.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board. (secure sign-in)
 
Search this forum  
 FAQ
    Noise  Layout  Per page   
  Refresh
QuestionUrgent Query. PinmemberMSambyal23:24 11 Jan '09  
GeneralDoesn't work within Masterpages Pinmemberitsmeagain2:24 13 Feb '08  
AnswerRe: Doesn't work within Masterpages Pinmemberfifuk10:24 10 Apr '08  
GeneralSome questions Pinmembershalan9922:27 26 Nov '07  
AnswerRe: Some questions PinmemberDaniel Penrod2:42 27 Nov '07  
shalan99,
 
Thanks, I will try to shed some light on your concerns.
 
"1) At any point, will Microsoft start charging for consuming the service? I have heard some mention of "no more than 1000 hits a day"."
 
It is actually 10,000 queries per day. They claim that it will always remain free under 10,000 queries. Sadly, each time a user chooses another page in the Gridview's paging it will constitute another query. One way you can save hits is by adding the "searchResponse" object to a user session. I didn't do this in this demo mainly to keep it simplistic but also because most people complain about sessions. I have done this in a production application I built and it works great! I haven't had a problem yet, but the website only gets about 3,000 users a day.
 
"2) Will my pages that have dynamic content (I have some content stored in database for certain pages using a mini-CMS that I created) be able to be indexed and searched?"
 
This application does nothing locally but return results from the Windows Live index. It would be dependent upon whether the Live Search Engine can index your site. If it indexes your site then you can use this web service to get the results. To answer your question, dynamic content can be indexed in Google and Windows Live.
 
"3) I hav been noticing bloggers who are stating that the actual search results returned by consuming the Google Custom Search API is better than that of the Live Search API. Personally, I don't know how to differetiate, but could you shed some light on this please?"
 
Google has always been revered as the #1 search engine on the block. I will not try and say anything different about that. The limitation though of the Google Search API is the fact that it is purely JavaScript driven and it will always be Ajax. That limits your ability as a developer to customize a solution. The Google Search API also will not return as many results as the Live Search API. I combined the two on this site: http://www.ci.fayetteville.nc.us/. Perform a search in the upper right hand corner to see. I would not compare the two services because they are entirely different. The Google Search API is more of a JavaScript widget whereas the Windows Live Search API is a full blown SOAP web service.
 

 

QuestionRe: Some questions [modified] Pinmembershalan997:13 27 Nov '07  
AnswerRe: Some questions PinmemberDaniel Penrod9:54 27 Nov '07  
GeneralRe: Some questions Pinmembershalan9910:54 27 Nov '07  
QuestionPlease Assistant to the solution of this problem PinmemberMena Malak23:22 17 Nov '07  
AnswerRe: Please Assistant to the solution of this problem PinmemberDaniel Penrod3:16 19 Nov '07  
GeneralRe: Please Assistant to the solution of this problem PinmemberMena Malak0:17 20 Nov '07  
AnswerRe: Please Assistant to the solution of this problem PinmemberDaniel Penrod9:43 20 Nov '07  

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

Permalink | Advertise | Privacy | Mobile
Web04 | 2.5.120529.1 | Last Updated 20 Nov 2007
Article Copyright 2007 by Daniel Penrod
Everything else Copyright © CodeProject, 1999-2012
Terms of Use
Layout: fixed | fluid