Administrate Indexing Server from Within Your Application

Introduction

You can leverage Microsoft Indexing Server to provide powerful search capabilities within your application. Indexing Server can be used to index files on your local or network file system as well as files of your local Web site. You then can query the Indexing catalog by using a standard SQL syntax. The following article describes in detail how you can create and configure your own Indexing catalog and then search it from within your application. This article concentrates on how you can programmatically administrate Indexing Server; for example, create a new Indexing catalog and then add folders to be indexed by this catalog.

The Indexing Service Administration API

Current versions of the .NET framework do not provide any types to programmatically administrate the Indexing Server. But Indexing Server provides a COM-based API you can use. Add a reference to the “Indexing Service Administration Type Library 1.0” that you find under the COM tab of the “Add Reference” dialog. This references the “ciodm.dll” in the windowssystem32 folder. Next, import the namespace “CIODMLib”; it will give you access to three types:

  • AdminIndexServerClass—This type is used to administrate the Indexing Server itself. It allows to create or remove catalogs, start or stop the Indexing service, etc.
  • CatAdmClass—This type provides access to an existing Indexing catalog. You can add or remove search scopes, start or stop the catalog, etc.
  • ScopeAdm—This type provides access to a search scope. You can set logon information for the scope, start a full or incremental scan, etc.

How to Retrieve the List of Indexing Catalogs

Indexing Server can have many Indexing catalogs and your application always tells Indexing Server which catalog to search. You can use the AdminIndexServerClass type to enumerate all defined Indexing catalogs. First, you need to create an instance of the AdminIndexServerClass type. Then, you call FindFirstCatalog() to find the first catalog in the list. It returns true if it finds a catalog; otherwise, false. To find the next catalog, you call FindNextCatalog() that again returns true when it finds another catalog, or false otherwise. As the example below shows, you first call FindFirstCatalog() and then in a loop FindNextCatalog() until one of them returns false. Each time, you then call GetCatalog() to get a reference to the current catalog in the list. This returns an object of the type object and you need to query for the appropriate interface on that object. Simple type casting will not work because you are working with COM objects. You need to use the “as” keyword followed by the interface you are looking for. Underneath, this will query for the appropriate interface on that COM object and return null if not present or a reference to the interface. The interface you are looking for is the ICatAdm interface that provides you access to the catalog itself. The CatAdm type itself implements also the ICatAdm interface.

protected void FillCatalogList(ListView ListOfCatalogs)
{
   AdminIndexServerClass Admin = new AdminIndexServerClass();

   // remove any existing item in the catalog list
   ListOfCatalogs.Items.Clear();

   // finds the first catalog in the list
   bool FoundCatalog = Admin.FindFirstCatalog();

   // loop through all catalogs present
   while (FoundCatalog)
   {
      // gets the object representing the current catalog
      ICatAdm Catalog = Admin.GetCatalog() as ICatAdm;

      // adds the catalog details to the list view
      ListViewItem Item =
         ListOfCatalogs.Items.Add(Catalog.CatalogName);
      Item.SubItems.Add(Catalog.CatalogLocation);
      Item.SubItems.Add(Catalog.IsUpToDate.ToString());
      Item.SubItems.Add(Catalog.DocumentsToFilter.ToString());
      Item.SubItems.Add(Catalog.FilteredDocumentCount.ToString());
      Item.SubItems.Add(Catalog.DelayedFilterCount.ToString());
      Item.SubItems.Add(Catalog.FreshTestCount.ToString());
      Item.SubItems.Add(Catalog.IndexSize.ToString());
      Item.SubItems.Add(Catalog.PctMergeComplete.ToString());
      Item.SubItems.Add(Catalog.PendingScanCount.ToString());
      Item.SubItems.Add(Catalog.PersistentIndexCount.ToString());
      Item.SubItems.Add(Catalog.QueryCount.ToString());
      Item.SubItems.Add(Catalog.StateInfo.ToString());
      Item.SubItems.Add(Catalog.TotalDocumentCount.ToString());
      Item.SubItems.Add(Catalog.UniqueKeyCount.ToString());
      Item.SubItems.Add(Catalog.WordListCount.ToString());

      // finds the next catalog in the list
      FoundCatalog = Admin.FindNextCatalog();
   }

   // select the first catalog in the list
   if (ListOfCatalogs.Items.Count > 0)
      ListOfCatalogs.SelectedIndices.Add(0);
}

As the example above shows, the ICatAdm interface provides a number of properties about the catalog. You can obtain the name, the location, whether the catalog is up to date or not, and so forth. The example above adds each found catalog to a list view.

How to Start, Stop, Pause, or Continue Indexing Server

The AdminIndexServerClass provides four methods to start, stop, pause, and continue the Indexing service. It also provides methods to find out whether the service is running or paused:

  • Start()—Starts the Indexing service
  • Stop()—Stops the Indexing service
  • Pause()—Pauses the Indexing service
  • Continue()—Continues a paused Indexing service
  • IsRunning()—Returns true if the Indexing service is running
  • IsPaused()—Returns true if the Indexing service is paused

How to Add or Remove an Indexing Catalog

You can add a new catalog with the AddCatalog() method. You need to pass along the name of the new catalog as well as the folder location where the catalog will be created. You need to restart the Indexing service before you can use a newly created catalog. The following example shows a dialog so the user can enter the name and location of a new catalog. Next, it calls AddCatalog and then asks the user whether to restart the Indexing service so the catalog becomes usable. Finally, it calls the method shown above to re-query the list of defined catalogs—FillCatalogList().

private void AddCatalog_Click(object sender, EventArgs e)
{
   // the dialog to create a new catalog
   AddNewCatalog AddNew = new AddNewCatalog();

   // we want to create the catalog
   if (AddNew.ShowDialog(this) == DialogResult.OK)
   {
      AdminIndexServerClass Admin = new AdminIndexServerClass();

      // create the new catalog
      Admin.AddCatalog(AddNew.NewCatalogName,
                       AddNew.NewCatalogLocation);

      // restart the service for the new catalog to function
      if (MessageBox.Show(this, RestartService, this.Text,
         MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
            DialogResult.Yes)
      {
         Admin.Stop();
         Admin.Start();
      }

      // refresh the list of catalogs
      FillCatalogList(ListOfCatalogs);
   }
}

You can call RemoveCatalog() to remove an existing catalog. You need to pass along the name of the catalog. You also need to first stop the Indexing service to be able to remove any catalog. The example below asks whether the user wants to delete the currently selected catalog. If the user confirms, it stops the Indexing services, deletes the catalog, and then starts the Indexing service again. Afterwards, it calls FillCatalogList() again to refresh the list of catalogs in the list view.

private void RemoveCatalog_Click(object sender, EventArgs e)
{
   string CatalogName = ListOfCatalogs.SelectedItems[0].Text;

   // ask the user to confirm the deletion of the catalog
   if (MessageBox.Show(this, ConfirmDeleteCatalog, CatalogName,
      MessageBoxButtons.YesNo, MessageBoxIcon.Question) ==
         DialogResult.Yes)
   {
      AdminIndexServerClass Admin = new AdminIndexServerClass();

      Admin.Stop();
      Admin.RemoveCatalog(CatalogName, true);
      Admin.Start();

      // refresh the list of catalogs
      FillCatalogList(ListOfCatalogs);
   }
}

More by Author

Must Read