The Windows Indexing Service is used to index files via the file
system and allow them to be searched through a set of APIs. One popular use of Indexing
Services is to provide a website search facility for websites hosted on Internet
Information Services (IIS).
This page describes how to use Windows Indexing Services from within ASP.NET using the
C# programming language. The article is "fully Dot Net friendly" - i.e. it
describes how search results can be retrieved as an ADO.NET DataTable and
displayed in a DataGrid (using a GridView would use near identical code
to that shown). This allows search results to be manipulated and presented in ways that
were not easily possible using classic ASP, such as by making use of the built in data
column sorting functionality, and the ability to use paging for the search results.
This article assumes that you know how to use Indexing Services and are familiar with
the concepts of creating search catalogs. The code sample assumes that an Indexing Service
search catalog called searchcatalog has previously been configured on your web
server.
The code samples will work with Index Server on Windows NT 4.0 systems and Indexing
Services on Windows Server 2000/2003/XP systems.
Using the C# code samples
There are two source code files shown. The ASP.NET file is called
IndexingServiceWithCSharp.aspx. It must be associated with a code behind page called
IndexingServiceWithCSharp.aspx.cs.
Note that if you want to use this sample source code to show users a graphical
representation of how relevant each search result is to their query then you will need to
create a set of images called 1bars.png to 10bars.png inclusive, then put them in an
images subfolder. Alternatively matches may be represented as percentages, or omitted
altogether.
How the C# code works
The ASP.NET page contains two web controls. A label control called LabelNumberOfResults
is used to display the number of search results. It is also used to display an errors
encountered during a search.
The page also contains a DataGrid control called DataGridSearchResults. This control is
used to display the search results. There are columns within this DataGrid for displaying
a document's rank, its title and the date the document was last updated. The title is a
hyperlink to the actual document itself.
Note that further columns can of course be added if other document properties need to
be displayed. Although a DataGrid is used in this example, other web controls can be
useful for displaying search results - in some cases it would be appropriate to use the
Repeater control for example.
The sample search doesn't contain a form for a user to enter a search query - for now
the query is held within the C#'s QueryText string variable. This value could of course be
assigned using the value of a textbox.
The name of the Indexing Service search catalog is contained in the CatalogName
variable.
The document rank returned by the Windows Indexing Service has a value of between 0 and
1000 (with 1000 being the most closely matching document). The sample C# code reduces this
to a figure between 0 and 10, which then allows the rank of each document to be shown
graphically through a set of images with the filenames 0bars.png to 10bars.png inclusive.
Ordering Search Results
It is useful to be able to order search results. One way of achieving this would be to
create a DataView from the search results data, and use that to populate the DataGrid:
//Create a DataView from the search results data
DataView SearchDataView = new
DataView(SearchResultsTable.Tables[0]);
//Sort the search results by rank
SearchDataView.Sort = "PageRank DESC";
DataGridSearchResults.DataSource = SearchDataView;
Finally, if you are interested in extending the functionality of Indexing Services to
allow content on any web server or ODBC database to be indexed and searchable, then take a
look at our Indexing Service Companion
product.
C# Example Source Code
The source code of the ASP.NET page IndexServer.aspx:
<%@ Page language="c#"
Codebehind="IndexServer.aspx.cs" AutoEventWireup="false"
Inherits=" BRETTB.IndexServer" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"
>
<HTML>
<HEAD>
<title>Indexing Service
Test</title>
<meta name="CODE_LANGUAGE"
Content="C#">
<meta
name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema"
content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="FlowLayout">
<form id="Form1"
method="post" runat="server">
<asp:Label id="LabelNumberOfResults"
runat="server"></asp:Label>
<p><asp:DataGrid id="DataGridSearchResults"
runat="server" HeaderStyle-Font-Bold="True"
AutoGenerateColumns="False"
BorderWidth="0"
AllowCustomPaging="True">
<Columns>
<asp:BoundColumn DataField="RankImageHTML"
HeaderText="Rank"></asp:BoundColumn>
<asp:HyperLinkColumn DataTextField="DocumentTitle"
DataNavigateUrlField="DocumentURL" HeaderText="Document
Title"></asp:HyperLinkColumn>
<asp:BoundColumn DataField="DocumentDate"
HeaderText="Last Updated"></asp:BoundColumn>
</Columns>
</asp:DataGrid></p>
</form>
</body>
</HTML>
The source code of the code behind page IndexServer.aspx.cs:
using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Data.OleDb;
using System.Data.SqlClient;
namespace BRETTB
{
/// <summary>
/// Summary description for IndexServer.
/// </summary>
public class IndexServer :
System.Web.UI.Page
{
protected
System.Web.UI.WebControls.DataGrid DataGridSearchResults;
protected
System.Web.UI.WebControls.Label LabelNumberOfResults;
private void Page_Load(object
sender, System.EventArgs e)
{
string
QueryText = "asp alliance"; //The search string
string
CatalogName = "searchcatalog"; //The name of your Index
Server catalog
int
NumberOfSearchResults = 0;
DataSet
SearchResults = new DataSet();
//Prevent
SQL injection attacks - further security measures are recommended
QueryText =
QueryText.Replace("'", "''");
//Build
the search query
string
SQL = "SELECT doctitle, vpath, Path, Write, Size, Rank ";
SQL += "FROM
\"" + CatalogName + "\"..SCOPE() ";
SQL +=
"WHERE";
SQL += "
CONTAINS(Contents, '" + QueryText + "') ";
SQL += "AND
NOT CONTAINS(Path, '\"_vti_\"') ";
SQL += "AND
NOT CONTAINS(FileName, '\".ascx\" OR \".config\" OR
\".css\"') ";
SQL += "ORDER
BY Rank DESC";
//Connect
to Index Server and perform search query
try
{
OleDbConnection
IndexServerConnection = new
OleDbConnection("Provider=msidxs;");
OleDbCommand
dbCommand = new OleDbCommand(SQL,
IndexServerConnection);
OleDbDataAdapter
IndexServerDataAdapter = new OleDbDataAdapter();
IndexServerDataAdapter.SelectCommand
= dbCommand;
IndexServerDataAdapter.Fill(SearchResults);
NumberOfSearchResults
= SearchResults.Tables[0].Rows.Count;
}
catch
(Exception ExceptionObject)
{
//Query
failed so display an error message
NumberOfSearchResults
= 0;
LabelNumberOfResults.Text
= "Problem with retrieving search results due to: " +
ExceptionObject.Message;
DataGridSearchResults.Visible
= false;
}
//Build
a datatable for search results
DataTable
SearchResultsTable = new
DataTable("SearchResults");
SearchResultsTable.Columns.Add(new DataColumn("DocumentRank", typeof(int)));
SearchResultsTable.Columns.Add(new DataColumn("RankPercentage", typeof(int)));
SearchResultsTable.Columns.Add(new DataColumn("RankNumber", typeof(int)));
SearchResultsTable.Columns.Add(new DataColumn("RankImageHTML", typeof(String)));
SearchResultsTable.Columns.Add(new DataColumn("DocumentURL", typeof(String)));
SearchResultsTable.Columns.Add(new DataColumn("DocumentTitle", typeof(String)));
SearchResultsTable.Columns.Add(new DataColumn("DocumentDate", typeof(String)));
if
(NumberOfSearchResults > 0)
{
LabelNumberOfResults.Text
= NumberOfSearchResults + " document(s) were found matching the query '" +
QueryText + "'";
foreach (DataRow SearchResultDataRow in
SearchResults.Tables[0].Rows)
{
//Determine
the document's date
DateTime
DocumentDate;
try
{
DocumentDate
= Convert.ToDateTime(SearchResultDataRow["Write"].ToString());
}
catch
{
DocumentDate
= DateTime.Now;
}
//Determine
the document's title
string DocumentTitle =
SearchResultDataRow["doctitle"].ToString();
if (DocumentTitle.Length < 2)
{
DocumentTitle
= "untitled document";
}
//Determine
the document's rank
int RankNumber = 0;
int DocumentRank =
Convert.ToInt32(SearchResultDataRow["Rank"].ToString());
int RankPercentage = DocumentRank;
RankPercentage
= Convert.ToInt32(Math.Round(Convert.ToDouble(RankPercentage / 10), 0));
if (DocumentRank > 900)
{
RankNumber
= 10;
}
else if (DocumentRank > 800)
{
RankNumber
= 9;
}
else if (DocumentRank > 700)
{
RankNumber
= 8;
}
else if (DocumentRank > 600)
{
RankNumber
= 7;
}
else if (DocumentRank > 500)
{
RankNumber
= 6;
}
else if (DocumentRank > 400)
{
RankNumber
= 5;
}
else if (DocumentRank > 300)
{
RankNumber
= 4;
}
else if (DocumentRank > 200)
{
RankNumber
= 3;
}
else if (DocumentRank > 100)
{
RankNumber
= 2;
}
else if (DocumentRank > 0)
{
RankNumber
= 1;
}
else
{
RankNumber
= 1;
}
string RankingAltTag = RankPercentage + " percent
match";
string RankImageHTML = "<img src=\"images/" +
RankNumber + "bars.png\" width=\"80\" height=\"17\"
alt=\"" + RankingAltTag + "\"> ";
//Populate
a DataRow for the current search result
DataRow
SearchResultsRow = SearchResultsTable.NewRow();
SearchResultsRow["DocumentRank"]
= SearchResultDataRow["Rank"].ToString();
SearchResultsRow["RankPercentage"]
= RankPercentage;
SearchResultsRow["RankNumber"]
= RankNumber;
SearchResultsRow["DocumentURL"]
= SearchResultDataRow["vpath"].ToString();
SearchResultsRow["DocumentTitle"]
= DocumentTitle;
SearchResultsRow["RankImageHTML"]
= RankImageHTML;
SearchResultsRow["DocumentDate"]
= DocumentDate.ToString("dd MMMM yyyy");
SearchResultsTable.Rows.Add(SearchResultsRow);
}
//Bind
DataTable to DataGrid
DataGridSearchResults.Visible
= true;
DataGridSearchResults.DataSource
= SearchResultsTable;
DataGridSearchResults.DataBind();
}
else
{
//No
search results were found for the query
DataGridSearchResults.Visible
= false;
LabelNumberOfResults.Text
= "No document(s) were found matching the query '" + QueryText +
"'";
}
}
#region Web Form Designer generated
code
override protected void OnInit(EventArgs
e)
{
//
//
CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}
/// <summary>
/// Required method
for Designer support - do not modify
/// the contents of
this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Load += new System.EventHandler(this.Page_Load);
}
#endregion
}
}
|