Workspace indexing

In a solution, project systems are responsible for providing functionality for build, debug, GoTo symbol searching, and more. Project systems can do this work because they understand the relation and capabilities of files within a project. An Open Folder workspace needs the same insight to provide rich IDE features as well. The collection and persistent storage of this data is a process called workspace indexing. This indexed data can be queried through a set of asynchronous APIs. Extenders can participate in the indexing process by providing IFileScanners that know how to handle certain types of files.

Types of indexed data

There are three kinds of data that are indexed. Note the type expected from file scanners differs from the type deserialized from the index.

Data File scanner type Index query result type Related types
References FileReferenceInfo FileReferenceResult FileReferenceInfoType
Symbols SymbolDefinition SymbolDefinitionSearchResult ISymbolService should be used instead of IIndexWorkspaceService for queries
Data values FileDataValue FileDataResult<T>

Querying for indexed data

There are two asynchronous types available to access persisted data. The first is through IIndexWorkspaceData. It provides basic access to a single file's FileReferenceResult and FileDataResult data, and it caches results. The second is the IIndexWorkspaceService which doesn't use caching, but allows for more querying capabilities.

using Microsoft.VisualStudio.Workspace;
using Microsoft.VisualStudio.Workspace.Indexing;

private static IIndexWorkspaceData GetCachedIndexedData(IWorkspace workspace)
{
    // Gets access to indexed data wrapped in a cache.
    return workspace?.GetIndexWorkspaceDataService()?.CreateIndexWorkspaceData();
}

private static IIndexWorkspaceService GetDirectIndexedData(IWorkspace workspace)
{
    // Gets direct access to indexed data.
    // Can also be casted to IIndexWorkspaceService2.
    return workspace?.GetIndexWorkspaceService();
}

Participating in indexing

Workspace indexing roughly follows the following sequence:

  1. Discovery and persistence of file system entities in the workspace (only on initial opening scan).
  2. Per file, the matching provider with the highest priority is asked to scan for FileReferenceInfos.
  3. Per file, the matching provider with the highest priority is asked to scan for SymbolDefinitions.
  4. Per file, all providers are asked for FileDataValues.

Extensions can export a scanner by implementing IWorkspaceProviderFactory<IFileScanner> and exporting the type with ExportFileScannerAttribute. The SupportedTypes attribute argument should be one or more values from FileScannerTypeConstants. For an example scanner, see the VS SDK sample.

Warning

Do not export a file scanner that supports the FileScannerTypeConstants.FileScannerContentType type. It is used for Microsoft internal purposes, only.

In advanced situations, an extension might dynamically support an arbitrary set of file types. Rather than MEF exporting IWorkspaceProviderFactory<IFileScanner>, an extension can export IWorkspaceProviderFactory<IFileScannerProvider>. When indexing begins, this factory type will be imported, instantiated, and have its GetSymbolScannersAsync method invoked. IFileScanner instances supporting any value from FileScannerTpeConstants will be honored, not just symbols.