ASP 101 - Active Server Pages 101 - Web04
The Place ASP Developers Go!

Please visit our partners


Windows Technology Windows Technology
15 Seconds
4GuysFromRolla.com
ASP 101
ASP Wire
VB Forums
VB Wire
WinDrivers.com
internet.commerce internet.commerce
Partners & Affiliates














ASP 101 is an
internet.com site
ASP 101 is an internet.com site
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

ASP 101 News Flash ASP 101 News Flash



 Top ASP 101 Stories Top ASP 101 Stories
Migrating to ASP.NET
Getting Scripts to Run on a Schedule
The Top 10 ASP Links @ Microsoft.com

QUICK TIP:
Close and free up object references
Show All Tips >>
ASP 101 RSS Feed ASP 101 Updates


Query Index Server with IXSSO in .NET

by Lance Bailles

There are many articles on the internet about querying Index Server using MSIDXS but few concerning IXSSO in .Net. It is my hope that this article will help more developers to return to the more efficient IXSSO when developing Index Server solutions in the .Net framework. The complete code with explanation is available in a .zip file by clicking here. The coding represented here won't be to the liking of all, but it will get you started. It is presumed that you understand .Net controls and Index Server commands.

Let's make a user interface. We will create a GUI that will allow the users to select areas of the website they are interested in, and to ignore other areas. We also want to ensure that the user isn't overwhelmed with the number of returns on each page so we will create a pageable datagrid to house the results of their query.


Figure 1. User Interface on Page Load

The code for the controls in Figure 1 is as follows:

<asp:textbox id="txtSearch" Runat="Server" Columns="40"></asp:textbox>
<asp:button id="Button1" onClick="doSubmit" Runat="Server" Text="Search!"></asp:button>
<h4>Optional - Select areas to be searched</h4>
<asp:CheckBoxList ID="chkListFolders" Runat="Server" RepeatColumns="4" RepeatDirection="Vertical"></asp:CheckBoxList>
<hr>

Notice that the check box is not populated on the client-side. The name and values of the folders represented in the check box are bound on the code behind page in the Page_Load Subroutine. In addition to the visible controls in Figure 1, we also want to include a label and a datagrid.

<asp:label id="lblResults" Runat="Server" Width="400px" EnableViewState="False"></asp:label><BR>
<br>
<!-- dg here -->
<asp:DataGrid id="dgResults" runat="server" AutoGenerateColumns="False" BorderColor="#DEDFDE" BorderStyle="None" BackColor="White"
CellPadding="4" GridLines="Vertical" BorderWidth="1px" ForeColor="Black" AllowPaging="True" PageSize="10" OnPageIndexChanged="getResults_PageIndexChanged">
<FooterStyle BackColor="#CCCC99"></FooterStyle>
<SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#CE5D5A"></SelectedItemStyle>
<AlternatingItemStyle BackColor="White"></AlternatingItemStyle>
<ItemStyle BackColor="#F7F7DE"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#6B696B"></HeaderStyle>
<PagerStyle HorizontalAlign="Right" ForeColor="Black" BackColor="#F7F7DE" Mode="NumericPages"></PagerStyle>
<Columns>
<asp:BoundColumn DataField="RANK" HeaderText="Rank"></asp:BoundColumn>
<asp:BoundColumn DataField="VPATH" HeaderText="Vert Path"></asp:BoundColumn>
<asp:BoundColumn DataField="DocTitle" HeaderText="Title"></asp:BoundColumn>
</Columns>
</asp:DataGrid>

Finally, we need to add one line so that the .aspx page can access its code behind page:

<%@ Page Inherits="IndexControls_main" src="IndexServer_dotnet.vb"%>
<HTML>
<HEAD>
<title>Search The Website</title>
</HEAD>
<body>

Now, we will move on to create the code behind page that contains the functionality for the query and all the controls. We'll start from the top and work our way down.

Imports System
Imports System.Data
Imports System.Data.Oledb ' for DA and DS
Imports System.Web.UI
Imports System.Web.UI.WebControls ' for Datagrid
Imports System.Text ' for stringbuilder

Public Class IndexControls_main
    Inherits Page

    Protected WithEvents lblResults As Label
    Protected WithEvents chkListFolders As CheckBoxList
    Protected WithEvents txtSearch As TextBox
    Protected WithEvents dgResults As DataGrid

The namespaces must be imported to provide definitions and framework for the objects created in the code. After the imports, we create a class called "IndexControls_main" which we referred to on the top of the IndexServer_dotNet.aspx page. The class inherits the page, and on that page are four web controls which we will protect.

Private Sub Page_Load()
If Not IsPostBack Then
    ' CREATE THE CHECK BOX LIST: text,value
    chkListFolders.Items.Add(New ListItem("Journal", "Journal" ))
    chkListFolders.Items.Add(New ListItem("Newsletter", "newsletter" ))
    chkListFolders.Items.Add(New ListItem("Calendar", "calendar" ))
    chkListFolders.Items.Add(New ListItem("Meetings", "meetings" ))
    chkListFolders.Items.Add(New ListItem("Membership", "membership" ))
    chkListFolders.Items.Add(New ListItem("Careers", "placement" ))
    chkListFolders.Items.Add(New ListItem("Check Sample", "checksample" ))
    chkListFolders.Items.Add(New ListItem("Foundation", "foundation" ))
    chkListFolders.Items.Add(New ListItem("Press Center", "media" ))

    ' PRE-SELECT ALL CHECK BOXES
    ' The check boxes control which folders are searched in the
    ' the query. For convenience, all boxes are pre-checked and
    ' if the user wants to narrow their search, they may uncheck them.


    Dim itmFold As ListItem
        For each itmFold in chkListFolders.Items
            itmFold.selected=true
        Next
Else
' do nothing - check boxes will retain their
' checked or unchecked values

End If
End Sub

On Page_Load, if the page has not been posted back (default page view when user loads the page for the very first time), we bind an arraylist to a checkbox list. The first value is the name to be displayed beside the check box, and the second value is the actual name of the folder that will be searched. Next, we use a FOR loop to loop through all the items in the array in order to provide pre-checked check boxes. This way, the users get the widest possible scope of returns if they don't want to fuss check boxes.

Sub doSubmit(ByVal s As Object, ByVal e As EventArgs)
    ' SEARCH BUTTON EXECUTES THIS SUB
    ' Set the datagrid to page zero so when the search
    ' query is changed, new results start at page zero

    dgResults.CurrentPageIndex = 0
    getResults()
End Sub

The search button shown in Figure 1 executes the doSubmit routine. While the routine may not seem necessary at first glance, it becomes an extremely efficient way of dealing with new searches that are executed after another dataset has been opened and paged. The datagrid is set to page zero so that new searches begin where they are supposed to, not at whatever page you were at on your previous search. The routine also triggers getResults.

Sub getResults()
    ' triggered by doSubmit and getResults_PageIndexChanged
    Dim SearchString As String = txtSearch.Text

    Dim DA As New OleDbDataAdapter
    Dim DS As New DataSet("IndexServerResults") ' give the dataset a name
    Dim Q As Object = Server.CreateObject("ixsso.Query")
    Dim Util As Object = Server.CreateObject("ixsso.Util")

This creates a few necessary objects. In object DS, we give a name to the dataset. We could just as well have called it "Thingmabob" as the name is just a name, but once made it is treated as the name of a table holding the dataset. The query object and the utility are made as they always have been in classic .asp.

    Dim strbldSearch As New StringBuilder(SearchString)

    ' EXLUDE FOLDERS AND FILES FROM SEARCH
    ' Anything that you don't want people to find in their
    ' search results should go here.

    strbldSearch.Append(" and not #vpath = *\_vti_cnf*")
    strbldSearch.Append(" and not #vpath = *\_mmServerScripts*")
    strbldSearch.Append(" and not #vpath = *\YourFolderName*")
    strbldSearch.Append(" and not #vpath = *\images*")
    strbldSearch.Append(" and not #filename *.inc")
    strbldSearch.Append(" and not #filename *.vb")

    Q.Query = strbldSearch.ToString()
    Q.Catalog = "YourCatalogName" ' name of your IndexServer Catalog
    Q.SortBy = "rank[a]" ' a-ascending, d-descending
    Q.Columns = "Rank, DocTitle, vpath, filename"
    Q.MaxRecords = 250

I have chosen to use StringBuilder to add parameters to the query. We begin by excluding certain files and folders from the scope of our search. The query (Q) also allows you to select columns from the Index Server engine and to limit the number of possible returns given to the user. Sure, you may have 10,000 files referencing amylase, but will they page through so large a record set? Better to keep the number low and the quality high. More than 500 is generally taxing on both the system's memory and the user's patience.

     ' INCLUDE FOLDERS IN SEARCH
    ' (1) Always include root directory, but not sub folders
   
Util.AddScopeToQuery(Q, "/", "shallow")
    ' (2) Include folders selected in check box list AND their
    ' their sub folders. See sub Page_Load check list array

    Dim itmFolder As ListItem
    For each itmFolder in chkListFolders.Items
        If itmFolder.Selected Then
            Util.AddScopeToQuery(Q, "/" & itmFolder.Value, "deep")
        End If
    Next

In this sample, we always wish to include the homepage in the scope of the search. This is performed by selecting the base of the website "/" and using "shallow" to indicate that we do not include sub folders in this one parameter. Since we are also allowing the users to use a check box list to select which areas of the website they wish to search, we use a FOR loop to loop through the selected items in the check box list and add these to the parameters of the search. We use "deep" to indicate that we wish to have sub folders included in these instances.

    Try
        DA.Fill(DS, Q.CreateRecordset("nonsequential"), "IndexServerResults")
        Dim intRowCount AS Integer
        intRowCount = DS.Tables("IndexServerResults").Rows.Count
        lblResults.Text = "There are " & intRowCount & " records."
        dgResults.DataSource = DS
        dgResults.DataBind()

        Q = Nothing
        util = Nothing

    Catch exc As Exception
        lblResults.Text = "There were no search results. Please rephrase your query"
        'lblResults.Text = exc.Message
    End Try
End Sub

It's time to execute the code! We use a TRY statement to catch exceptions and assist with debugging. We populate the data adapter with the dataset, count the rows, and bind the results to the datagrid. If there is an exception, we may have the exception message written out or on production, tell us that there are no available results. All that is left now is the routine for paging:

' handles dataset paging
Sub getResults_PageIndexChanged(ByVal sender As Object, ByVal e As DataGridPageChangedEventArgs)
    dgResults.CurrentPageIndex = e.NewPageIndex
    getResults()
End Sub
End Class

The dataset paging performs exactly like any other datagrid event. The final results should look like Figure 2:


Figure 2. Dataset bound to pageable datagrid

In Summary, IXSSO has always offered an effective means of querying Index Server. By adapting this time tested technology to the new ways of .Net, we will help users to find what they need, quickly, on our websites. We also provide them with the option of narrowing their search, and reward them with the convenience of pageable results.

Code Download

You can download the code in zip file format from here: indexserver_dotnet.zip (3.1 KB).

Related Articles


Home |  News |  Samples |  Articles |  Lessons |  Resources |  Forum |  Links |  Search |  Feedback

Internet.com
The Network for Technology Professionals

Search:

About Internet.com

Legal Notices, Licensing, Permissions, Privacy Policy.
Advertise | Newsletters | E-mail Offers