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.
- ASP.NET 2.0 installed.
- Setup the downloaded app in IIS, and choose ASP.NET 2.0.
- Have AJAX 1.0 installed on your machine.
- 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
.
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).
public WindowsLiveSearch()
{
ErrorMsg = "";
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;
sp = null;
}
The Search
method is as follows:
public IList<LiveSearchResults> Search(string searchQuery)
{
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 (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:
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:
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:
private IList<LiveSearchResults> CaptureResults(SearchResponse search_Response)
{
IList<LiveSearchResults> resultsCollector = new List<LiveSearchResults>();
foreach (SourceResponse response in search_Response.Responses)
{
Result[] response_results = null;
response_results = response.Results;
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("", "<strong>").Replace("", "</strong>");
row.Description = AntiXss.HtmlEncode(CheckForNull(response_result.Description))
.Replace("", "<strong>").Replace("", "</strong>");
row.DisplayURL = AntiXss.HtmlEncode(CheckForNull(response_result.DisplayUrl))
.Replace("", "<strong>").Replace("", "</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:
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