Coding an AjaxPro.NET Based Search Engine for Your Website

In yesterday's article, we began building a search engine with AJAX functionality to be embedded into a .NET-based web site. We set up the frameworks we planned to use and designed the database. In this part, the conclusion to the tutorial, we will get into the client- and server-side design, add a couple of optimizations to the code, and then test out our new search engine.

Contributed by
Rating: 4 stars4 stars4 stars4 stars4 stars / 13
October 23, 2007
Rate this Article:
MEH MEH++


SEARCH ASP FREE
TOOLS YOU CAN USE

advertisement

A downloadable .rar file is available for this article.

The Server-side Design

Before putting the AjaxPro.NET framework into our application, we should get everything ready. Above all, we should add a reference to AjaxPro.2.dll to the project, which will result in generating a Bin folder. With this done, we will also have to modify the relevant part in the configure file-Web.config, as show in the following code snippet:


//......(omitted)

<system.web>

  <httpHandlers>

<add verb="POST,GET" path="ajaxpro/*.ashx" type="AjaxPro.AjaxHandlerFactory,
AjaxPro" />

  </httpHandlers>

......(omitted)

</system.web>;


Moreover, we should do something inside the "Search.aspx.cs" code file to register the current page class as the following:


[AjaxPro.AjaxNamespace("MySearchEngine")]

  public partial class Search : System.Web.UI.Page{

   private void Page_Load(object sender, System.EventArgs e){

    Utility.RegisterTypeForAjax(typeof(Search));

}


Note the first line of code is quite different from that provided by early versions of the framework. Be careful!

With the above steps prepared, we can now write the Ajax methods. Let's focus on the first one, GetResultXml:


[AjaxPro.AjaxMethod]

  public string GetResultXml(string strWord){

string strConnection = ConfigurationManager.ConnectionStrings
["MyConnectionString"].ConnectionString;

  SqlConnection conn = new SqlConnection(strConnection);

   SqlCommand cmd = conn.CreateCommand();

  cmd.CommandText = string.Format(

"SELECT id, title, author FROM Article WHERE title LIKE '%{0}%'",strWord );

  DataSet ds = new DataSet("ArticleDataSet");

   SqlDataAdapter da = new SqlDataAdapter(cmd);

try{

  da.Fill(ds);

}

  catch (SqlException) {}

finally{

  conn.Close();

}

  return ds.GetXml();

}


First, according to the downloaded materials, we have to put the attribute [AjaxPro.AjaxMethod] before every method that will be called via the AjaxPro.NET framework from the client side. The several steps that follow are the typical ASP.NET 2.0 database operation. The first point to notice is that we name the DataSet object "ArticleDataSet," so that will be conveniently used later. In the last step, we convert the record data in table form into a XML string by calling the GetXml method of our created DataSet instance.

Now let's turn our attention to the next Ajax method, namely GetXsl:


[AjaxPro.AjaxMethod]

  public string GetXsl(){

   XmlDocument doc = new XmlDocument();

  string strPath = Server.MapPath("../xsl/trans.xslt");

   doc.Load(strPath);

    return doc.InnerXml;

}


This method is relatively simple; its working relies on the XmlDocument class. We first get and load the required .xslt file, "trans.xslt," into the doc object. Then we directly return the XML-formatted string by returning the value of the InnerXml property of the doc object.

There is one final Ajax method: GetResultCount, which is responsible for returning the total number of the articles that satisfy the searching condition. Since it is also pretty simple, we will not dwell on it; please refer to the downloadable source code included at the beginning of this article.

The Client-side Design

On the client side, we first have to add references to the necessary JavaScript files that are required by Google's AJAXSLT framework at the <head> section of the "Search.aspx" (our search engine sample page) file:


<script src="javascript/misc.js" type="text/javascript"></script>

<script src="javascript/dom.js" type="text/javascript"></script>

<script src="javascript/xpath.js" type="text/javascript"></script>

<script src="javascript/xslt.js" type="text/javascript"></script>


Please note that we must follow the order specified above. This is because the programming logic of the latter .js files depends on the related parts that are coded inside the former. Here, however, we don't plan to dig into the inner workings.

Next, we follow the steps listed below to program the client side.

First, when the application starts up, we invoke the "MySearchEngine.GetXsl()" method to load the cascade style we are going to use to apply to the .xml files. This is the way specified by the AjaxPro.NET framework to call the server-side methods. Here the Ajax method GetXsl is prefixed by a particular namespace, MySearchEngine, that is defined above.

Then, inside the "onkeyup" event handler of the HTML <input> element (with the id being searchword), we invoke the GetResultXml client-side method, whose complete source code is listed below:


function GetResultXml(){

  var strWord = el("searchword").value;

   MySearchEngine.GetResultXml(strWord, GetResultXml_callback);

}

function GetResultXml_callback(response){

  var strXml = response.value;

   xml = xmlParse(strXml);

  el("result").innerHTML = xsltProcess(xml, xslt);

}


Here, with the help of a simple helper function named el we get the value of the HTML <input> control "searchword." Then we call the MySearchEngine.GetResultXml" server-side method, which is exposed via the AjaxPro.NET framework. Readers with more or less AJAX experience may be familiar with the followed code snippet; it is very similar to that used in invoking the general and original XMLHttpRequest with a typical callback function to deal with the returned result. Here, inside the GetResultXml_callback callback function we first invoke the xmlParse JavaScript helper function supplied by the AJAXSLT framework to convert the string formatted XML data into the formal XML format. Finally, by calling another AJAXSLT helper function, namely xsltProcess, we convert the above XML data into HTML format using the readily converted style data that is held in the xslt variable.

By now, we can come to the conclusion that with the XSLT light-weight language, the XML data can be converted into client-side HTML format without any complexity.

Let's take a quick look at the .xslt file we have just used, namely trans.xslt:


<?xml version="1.0" encoding="gb2312"?>

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:output method="html" encoding="gb2312" indent="yes"/>

<xsl:template match="/">

<table cellspacing="0" cellpadding="4" rules="cols" bordercolor="#DEDFDE"
border="1" id="dgResult" style="color:Black;background-color:White;border-
color:#DEDFDE;border-width:1px;border-style:None;width:100%;border-
collapse:collapse;">

  <tr style="color:White;background-color:#6B696B;font-weight:bold;">

  <td style="width:10%;">ID</td>

  <td style="width:70%;">Title</td>

  <td style="width:20%;">Author</td>

  </tr>

<xsl:for-each select="/ArticleDataSet/Table">

<tr style="background-color:#F7F7DE;">

<xsl:attribute name="style"><xsl:if test="position() mod 2 = 0">background-
color:#F7F7DE;

</xsl:if><xsl:if test="position() mod 2 = 1">background-color:white;


</xsl:if></xsl:attribute>

  <td>

   <xsl:value-of select="id"/>

  </td>

  <td>

   <xsl:value-of select="title"/>

  </td>

  <td>

   <xsl:value-of select="author"/>

  </td>

</tr>

</xsl:for-each>

</table>

</xsl:template>

</xsl:stylesheet>


Here, we have utilized some skills. First, we select a HTML <table> element to render the final XML data. Second, with the lines of code that lie below the for-each clause that judges whether the current line number is odd, we have achieved the effect of rendering the background color of the table rows alternately.

Optimization

At this point, we have accomplished our original target-building an AjaxPro.NET based search engine inside our own website. However, there is at least one aspect that deserved to be optimized. In the above solution, we, through the "onkeyup" event of an HTML <input> element, trigger the background searching operation. Is this reasonable?

Let's take the example of a user who wants to search for "ajax" in a real scenario. It may take him one to two seconds to enter four letters, and the final results before him are all related to "ajax." Nevertheless, according to the solution introduced above, the background will execute an inquiry four times. This is because the "onkeyup" related event handler will be triggered four times when the user enters "ajax." Obviously, this is unreasonable; it puts a leaden burden on the server side which quite contradicts the original intention of AJAX.

In fact, during the course of the user quickly entering the search words it's unnecessary to send out the search request when the user does not care about the results. It's only when the user finishes entering the search words that it makes sense to send out a request to the server side. Thus, we can do some optimization: instead of using the "onkeyup" event handler to trigger the background search action, we can adopt the more active solution of making a comparison every x seconds (say the time interval is set to 100 ms). If the system sees that within 500 milliseconds the value within the HTML <input> element does not change and that the value differs from the search key word associated with the current retrieved results, then the system draws the conclusion that the user has altered the search key words and the new ones have been completely entered. At this point, it starts to send out a request to the background server side.

Now, let's delve into the process of optimization.

First, we add three global variables: curWord, lastValue, and diffCount, whose functions are detailed and explained in the following code:

// global variable, used to remember the retrieved words related to the current searched result

  var curWord = "";

// global variable, used to remember the last time checked result

// we set this variable to prevent it from sending out much too frequent requests during the course of the user entering a string of words

  var lastValue = "";

// global variable, used to remember the comparison result between the current entered value and current retrieved value

// add 1 if different, or else set to 0

  var diffCount = 0;


Next, we define a checkInput function. This function is responsible for checking out the value of the <input> element. If the current value of this <input> element differs from that retrieved currently and is identical with the one checked last time, then the value of the diffCount variable is added to 1. If the value of the  diffCount variable is added to 1 for 5 continuous times then its value must be greater than 5, when a request will be sent out to the server side-perform the inquiry and finally show the results. The following gives the complete source code associated with the checkInput function:


function checkInput(){

  var val = el("searchword").value;

   if (val != curWord && lastValue == val){

    diffCount++;

}

  else

{

   diffCount = 0;

}

  if (diffCount > 5) {

   diffCount = 0;

    curWord = val;

    GetResultXml();

}

 lastValue = val;

  setTimeout("checkInput()", 100);

}


Moreover, there is also one point that needs to be optimized. In the above solution, up to now, we have not added a hint message to show the number of the articles that meet the search condition. So, we work out another helper function, named GetResultCount, and also its server-side counterpart, the Ajax method "MySearchEngine.GetResultCount" which was mentioned before. Thus, here we only list the client-side function:


function GetResultCount(){

  var strWord = el("searchword").value;

  var count = MySearchEngine.GetResultCount(strWord).value;

  el("resultcount").innerHTML ="There are totally " + count + "articles that meet
the searching condition.";

}


Here, we first get the value of the <input> element. Then we invoke the server-side function "MySearchEngine.GetResultCount" synchronously to get the number of articles that meet the search condition. At last, we display the matching number-related message to the users.

Finishing Up

Finally, you can press F5 to appreciate your work. The following Figure 2 shows one of the run-time snapshots.

Figure 2-one of the run-time snapshots of our search engine sample application.

In Figure 2, when the user enters some key words and waits for a very short amount of time (measured in milliseconds) a table will appear before him, displaying the data that meet the specified search condition. Additionally, a friendly "hint" message appears above the table to tell him how many items of data meet the search condition.

What's more, from the above Figure 2, clever readers may want to add a "Search" like button. That's a pretty good idea! But forgive me for leaving that as your homework.

Summary

In this article, with the help of the AjaxPro.NET server-side AJAX framework, we built a simple search engine which is based on the server-side database. Since XML is a standard format for transferring data and XSLT is a standard language for formatting and decorating XML data, we converted the original data persisted in the database (the XSLT data simply stored under a sub folder of the web site) into XML-formatted strings and passed them back via AjaxPro.NET.

Then, on the client side, with the help of  AJAXSLT, the Google client-side AJAX framework, we reverted the XML-formatted strings to original XML/XSLT data. And further, by using AJAXSLT we turned the XML data into an HTML format that could finally be rendered on the browser.

Since this is just a demo for exploring local search engine techniques, the example in this article can be further enhanced and optimized in many aspects. We've only worked out two means of optimization for it. However, the optimization of this search engine is only limited by your imagination.

Have fun ajaxifying your web applications!

blog comments powered by Disqus
.NET ARTICLES

- .Net 4.5 Brings Changes
- Understanding Events in VB.NET
- Objects, Properties, Events and Methods in V...
- Install Visual Web Developer Express 2010
- Microsoft Gadgeteer an Open Source Alternati...
- Best DotNetNuke Modules
- Facebook Image Viewer in Visual Basic
- Murach`s ADO.NET 4 Database Programming with...
- 5 Must Have Visual Studio 2010 Extensions
- Dynamic Web Applications with ASP.NET Mono u...
- PDFSharp: HTML to PDF in ASP.NET 3.5 using V...
- Using the PDFSharp Library in ASP.NET 3.5 wi...
- Sending Email in ASP.NET 3.5 using VB.NET wi...
- ASP.NET 3.5 Role Based Security and User Aut...
- Creating ASP.NET Login Web Pages and Basic C...

ASP Web Hosting ASP.Net Web Hosting Windows Web Hosting
 
 
 

ASP Free Forums 
 RSS  Tutorials RSS
 RSS  Forums RSS
 RSS  All Feeds
Site Map 
Request Media Kit
Write For Us Get Paid 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Privacy Policy 
Support 


© 2003-2012 by Developer Shed. All rights reserved. DS Cluster 6 - Follow our Sitemap
Most Popular Topics
All ASP.Net Tutorials