Building Web Sites with ASP.NET - Part 1
page 5 of 6
by Brian Mains
Feedback
Average Rating: This article has not yet been rated.
Views (Total / Last 10 Days): 29230/ 28

Searching

Most applications have some sort of search capability built into a site. This makes it convenient to quickly access related content that is being sought for. Sometimes it can be helpful to see what has been searched for in the past, along with how many instances of that search item have been found.

The following markup exists in the master page, a perfect place to put a search textbox.

Listing 6

<asp:TextBox ID="txtSearch" runat="server" />
<ajax:TextBoxWatermarkExtender ID="extSearch" runat="server" 
      TargetControlID="txtSearch"
      WatermarkText="Type to Search" />
<ajax:AutoCompleteExtender ID="extSearch2" runat="server" 
      TargetControlID="txtSearch"
      ServicePath="~/Services/SearchService.asmx" 
      ServiceMethod="GetTopSearchPhrases"
      MinimumPrefixLength="1" CompletionListItemCssClass="AutoCompleteItemStyle" 
      CompletionListHighlightedItemCssClass="AutoCompleteSelectedItemStyle"
      OnClientItemSelected="autoComplete_itemSelected" />
<asp:LinkButton ID="lnkSearch" runat="server" CssClass="SiteLayoutMenuBarItem"
      OnClick="lnkSearch_Click">Search</asp:LinkButton>

There is quite the number of .NET controls for implementing a search. Outside of the textbox that retains search criteria and a linkbutton that triggers the search, the two extenders help add on additional functionality without requiring a custom control. The TextBoxWatermarkExtender helps by providing a message to the user identifying the purpose of the search textbox. The second extender, the AutoCompleteExtender, is a powerful extender that queries the database, looking for existing search results and returning the list.

The AutoCompleteExtender works by using a web service and web method to get the items that match the text that the user has entered. The web service has to conform to a specific signature for this to work, which I will discuss in a moment.

As the user clicks the submit button, whatever is searched for is logged to the database. There are several schemes that can be implemented to track what the user searches for, and create a popularity ranking. The first question you have to ask is shall whatever the user enters be logged or only searches that have results? Should low to high volume results be differentiated?

In this example, whatever the user enters is stored in the database, but more ideally any search text that has actual results should be stored. This could be done whenever loading the search page or search results.

Another question is what is the search querying? Is the search using a full-text index in the database, index server, or some other mechanism? This is important too, though I do not have a solution implemented in this example; I am only focused on storing the user's query.

Let us start with the web service definition. As I mentioned before, a web service used by the AutoCompleteExtender needs to conform to a specific signature, shown below.

Listing 7

[WebMethod]
public string[] GetTopSearchPhrases(string prefixText, int count)
{
  SearchManager manager = SearchManager.GetManager();
  SearchPhraseCollection phraseCollection =
  manager.GetTopSearchPhrases(prefixText, count);
  return (from p in phraseCollection
  select string.Format("{0} ({1} occurrence(s))", p.Phrase,
  p.ResultCount.ToString())).ToArray();
}

The method takes two to three parameters, depending on the configuration. In this example, the method takes the prefixText, which is the characters the user has entered, and the count, the total number of items to limit the search by. The latter value is specified in the body of the AutoCompleteExtender; it is configurable by changing the CompletionSetCount property value.

If the UseContextKey property of that extender is set to true, a third parameter, contextKey, can be added as well. Notice that an array of strings is returned to the caller. This is also required.  Notice the specialized output, which will include items in the format of "Toasters (12 occurrence(s))."

As the user enters keys, the user is prompted with a selection of items as shown in the screenshot below.

Figure 5

These entries can be selected using the mouse, or by clicking the up and down arrow. Selecting an entry places the item in the textbox. These entries are stored in the database using the following code in the search button click event (next to the textbox, but not shown above).

Listing 8

protected void lnkSearch_Click(object sender, EventArgs e)
{
  if (string.IsNullOrEmpty(this.txtSearch.Text))
  return;
  string text = this.txtSearch.Text.Trim();
  if (string.IsNullOrEmpty(text))
  return;
  //Updates the search phrase count.
  SearchManager manager = SearchManager.GetManager();
  manager.UpdateSearchPhraseCount(text);
}

The SearchManager component makes a call to the data layer to perform the update. If the searched text already exists, then the number of occurrences is incremented by one; otherwise, a new entry is created. There is only one problem not yet discussed. Upon selecting an item in the auto complete popup, the text "(X occurrences)" would also be copied to the textbox. This is not very useful, and needs to be stripped out.

The solution to this is to attach to the itemSelected client event. Notice in the AutoCompleteExtender markup above, the OnClientItemSelected references the name of an event handler. This event handler performs the work of stripping out the "(X occurrences)" text from the selected entry. It does this with the following JavaScript.

Listing 9

function autoComplete_itemSelected(sender, e)
{
      var text = e.get_text();
      if (text.indexOf('(') > 0)
      {
            text = text.substring(0, text.indexOf('('));
            if (text != null && text.length > 0)
                  text = text.trimEnd();
      }
      var targetElement = sender.get_element();
      targetElement.value = text;
}

The event argument in this event is AutoCompleteItemEventArgs, which has an item, text, and value property. I am using the text property getter, and parsing it to look for the first parenthesis. If found, it is stripped out and assigned to the target element, and is accessible using the element property getter. Remember that extenders target another property and do not emit its own interface, so an extender's element property references the extended control.

The issue that most people will have with the solution above is that there is not any intellisense to find all this out, and there is not any MSDN documentation. I had to manually dig through the AJAX control toolkit source code to find all of this information.  I would highly recommend looking at the source code whenever using these extenders.


View Entire Article

User Comments

No comments posted yet.

Product Spotlight
Product Spotlight 





Community Advice: ASP | SQL | XML | Regular Expressions | Windows


©Copyright 1998-2024 ASPAlliance.com  |  Page Processed at 2024-04-19 2:10:07 PM  AspAlliance Recent Articles RSS Feed
About ASPAlliance | Newsgroups | Advertise | Authors | Email Lists | Feedback | Link To Us | Privacy | Search