Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Administrate Indexing Server from within your application

0.00/5 (No votes)
1 Jul 2005 1  
Describes in detail how you can programmatically administrate Indexing Server, for example create a new Indexing catalog and then add folders to be indexed by this catalog.

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 can then query the Indexing catalog 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 that you can use. Add a reference to the �Indexing Service Administration Type Library 1.0� which you can find under the COM tab of the "Add Reference" dialog. This references the �ciodm.dll� in the windows\system32 folder. Next import the namespace �CIODMLib� which will give you access to the 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 the Indexing Server which catalog to search for. You can use the AdminIndexServerClass type to enumerate all the defined Indexing catalogs. First you need to create an instance of the type AdminIndexServerClass. Then you can 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 can call FindNextCatalog() which again returns true if it finds another catalog otherwise false. As the example below shows you first call FindFirstCatalog() and then in a loop FindNextCatalog() till 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 as 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 which provides you access to the catalog itself. The CatAdm type itself implements 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, if the catalog is up to date or not, etc. 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 if 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 method AddCatalog(). 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 if 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 again calls FillCatalogList() 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);
    }
}

How to retrieve the list of search scopes of a catalog?

Each catalog has search scopes, the folders which are included in the catalog. A search scope can be inclusive (by default) or exclusive, meaning this folder will not be included in the catalog. With exclusive you can define sub-folders which should be excluded by this catalog. Listing all the search scopes of the catalog works very similar to the listing of all catalogs of the Indexing Server. First obtain a reference to the catalog by calling the method GetCatalogByName() on an instance of type AdminIndexServerClass. This returns an object of type object and you need to query for the ICatAdm interface using the �as� keyword.

private ICatAdm GetCatalog(string CatalogName)
{
    AdminIndexServerClass Admin = new AdminIndexServerClass();
    
    // find the catalog by name

    return Admin.GetCatalogByName(CatalogName) as ICatAdm;
}

Next you call FindFirstScope() on ICatAdm interface to get the first search scope which returns true if one is found otherwise false. You call FindNextScope() on ICatAdm interface to find subsequent search scopes which again returns true when one is found otherwise false. You do this again in a loop till it returns false. Each time you call GetScope()to obtain a reference to the current search scope. This again returns an object of the type object and you query for the IScopeAdm interface via the �as� keyword. That interface then provides a list of properties about the search scope itself:

private void FillScopeList(string CatalogName)
{
    // remove any existing item in the scope list

    ListOfScopes.Items.Clear();
    
    // get a handle to the newly selected catalog

    ICatAdm Catalog = GetCatalog(CatalogName);
    
    // search for the first scope item

    bool FoundScope = Catalog.FindFirstScope();
    
    // loop through all the scope items

    while (FoundScope)
    {
        // get a handle to the current scope item

        IScopeAdm Scope = Catalog.GetScope() as IScopeAdm;
        
        // create a new list view item and set its values

        ListViewItem Item = ListOfScopes.Items.Add(Scope.Alias);
        Item.SubItems.Add(Scope.ExcludeScope.ToString());
        Item.SubItems.Add(Scope.Logon);
        Item.SubItems.Add(Scope.Path);
        Item.SubItems.Add(Scope.VirtualScope.ToString());
        
        // search for the next scope item

        FoundScope = Catalog.FindNextScope();
    }
    
    // select the first scope in the list

    if (ListOfScopes.Items.Count > 0)
        ListOfScopes.SelectedIndices.Add(0);
}

The example above adds all search scopes of a catalog to a list view. This includes the path of the search scope and whether it is exclusive. The VirtualScope is only set if this catalog indexes a web site.

How to start, stop, pause or continue a catalog?

You can start, stop, pause or continue an individual catalog. First you need to get a reference to the catalog by calling GetCatalogByName on an instance of the type AdminIndexServerClass. Then you query again for the ICatAdm interface. The ICatAdm interface also provides methods to find out if the catalog is running or paused:

  • StartCatalog()- starts the Indexing catalog.
  • StopCatalog()- stops the Indexing catalog.
  • PauseCatalog()- pauses the Indexing catalog.
  • ContinueCatlog()- continues a paused Indexing catalog.
  • IsCatalogRunning()- returns true if the Indexing catalog is running.
  • IsCatalogPaused()- returns true if the Indexing catalog is paused.

How to add or remove a search scope to a catalog?

First you need to obtain a reference to the catalog and then call the method AddScope(). You pass along the folder to index and true if the search scope is exclusive or false if it is inclusive. The example below shows a dialog so the user can enter the folder of the search scope and select if it is exclusive or inclusive. Next it gets the name of the currently selected catalog, obtains the catalog object for it and then adds the search scope by calling AddScope() on the Catalog object. It then asks the user if a full scan for it should be performed. In that case it gets a reference to the newly created search scope by calling GetScopeByPath() on the Catalog object and then calls Rescan() on it passing along true for a full scan. Finally it calls the method FillScopeList() to refresh the list of search scopes in the list view.

private void AddScope_Click(object sender, EventArgs e)
{
    string CatalogName = ListOfCatalogs.SelectedItems[0].Text;
    
    // the dialog to create a new scope

    AddNewScope AddNew = new AddNewScope();
    
    // we want to create the scope

    if (AddNew.ShowDialog(this) == DialogResult.OK)
    {
        // get the catalog handle

        ICatAdm Catalog = GetCatalog(CatalogName);
        
        // create the new scope

        Catalog.AddScope(AddNew.Path, AddNew.ExcludeFolder, 
                                                 null, null);
        
        // ask the user if we want to scan the new search scope

        if (MessageBox.Show(this, PerformFullScan, this.Text,
                    MessageBoxButtons.YesNo, 
                    MessageBoxIcon.Question) == DialogResult.Yes)
        {
            // get a reference to the search scope we just added

            IScopeAdm Scope = 
                Catalog.GetScopeByPath(AddNew.Path) as IScopeAdm;
            
            // to a full scan

            Scope.Rescan(true);
        }
        
        // refresh the list of scopes

        FillScopeList(ListOfCatalogs.SelectedItems[0].Text);
    }
}

Adding or removing search scopes does not require stopping or restarting the catalog service. To remove a search scope you call the method RemoveScope() on the Catalog object and pass along the path of the search scope. The example below asks if the user wants to delete the currently selected search scope. If the user confirms it deletes the search scope and afterwards it again calls FillScopeList() to refresh the list of search scopes in the list view.

private void RemoveScope_Click(object sender, EventArgs e)
{
    string CatalogName = ListOfCatalogs.SelectedItems[0].Text;
    string ScopePath = 
         ListOfScopes.SelectedItems[0].SubItems[3].Text
    
    // ask the user to confirm the deletion of the search scope

    if (MessageBox.Show(this, ConfirmDeleteScope, ScopePath,
                 MessageBoxButtons.YesNo, 
                 MessageBoxIcon.Question) == DialogResult.Yes)
    {
        // get the catalog handle

        ICatAdm Catalog = GetCatalog(CatalogName);
        
        // delete the selected scope

        Catalog.RemoveScope(ScopePath);
        
        // refresh the list of scopes

        FillScopeList(ListOfCatalogs.SelectedItems[0].Text);
    }
}

Summary

The administrative API of Indexing Server is very simple. The AdminIndexServerClass type gives you full control over the Indexing Server itself. The ICatAdm interface and CatAdm type provide full control over each catalog. The IScopeAdm interface and ScopeAdm type provide full control over each search scope. This makes it very easy for you to add new catalogs and search scopes or remove existing catalogs and search scopes programmatically. You also have the ability to force a full or partial scan of search scopes so that additions or changes are available to your application instantly. Refer to the MSDN help for more details about the Indexing Server API. The enclosed sample application provides a sample administrative interface to Indexing Server using the very same API. If you have comments on this article or this topic, please contact me @ klaus_salchner@hotmail.com. I want to hear if you have learned something new. Contact me if you have questions about this topic or article.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here