Upgrade to Azure Cognitive Search .NET SDK version 11

If your search solution is built on the Azure SDK for .NET, this article will help you migrate your code from earlier versions of Microsoft.Azure.Search to version 11, the new Azure.Search.Documents client library. Version 11 is a fully redesigned client library, released by the Azure SDK development team (previous versions were produced by the Azure Cognitive Search development team).

With one exception, all features from version 10 are implemented in version 11. Key differences include:

  • One package (Azure.Search.Documents) instead of four
  • Three clients instead of two: SearchClient, SearchIndexClient, SearchIndexerClient
  • Naming differences across a range of APIs and small structural differences that simplify some tasks

The client library's Change Log has an itemized list of updates.

All C# code samples and snippets in the Cognitive Search product documentation have been revised to use the new Azure.Search.Documents client library.

Why upgrade?

The benefits of upgrading are summarized as follows:

  • New features will be added to Azure.Search.Documents only. The previous version, Microsoft.Azure.Search, is now a legacy client. Updates to legacy libraries are limited to high priority bug fixes only.

  • Consistency with other Azure client libraries. Azure.Search.Documents takes a dependency on Azure.Core and System.Text.Json, and follows conventional approaches for common tasks such as client connections and authorization.

Package comparison

Version 11 consolidates and simplifies package management so that there are fewer to manage.

Version 10 and earlier Version 11
Microsoft.Azure.Search
Microsoft.Azure.Search.Service
Microsoft.Azure.Search.Data
Microsoft.Azure.Search.Common
Azure.Search.Documents package

Client comparison

Where applicable, the following table maps the client libraries between the two versions.

Client operations Microsoft.Azure.Search (v10) Azure.Search.Documents (v11)
Targets the documents collection of an index (queries and data import) SearchIndexClient SearchClient
Targets index-related objects (indexes, analyzers, synonym maps SearchServiceClient SearchIndexClient
Targets indexer-related objects (indexers, data sources, skillsets) SearchServiceClient SearchIndexerClient (new)

Caution

Notice that SearchIndexClient exists in both versions, but targets different operations. In version 10, SearchIndexClient creates indexes and other objects. In version 11, SearchIndexClient works with existing indexes, targeting the documents collection with query and data ingestion APIs. To avoid confusion when updating code, be mindful of the order in which client references are updated. Following the sequence in Steps to upgrade should help mitigate any string replacement issues.

Naming and other API differences

Besides the client differences (noted previously and thus omitted here), multiple other APIs have been renamed and in some cases redesigned. Class name differences are summarized below. This list is not exhaustive but it does group API changes by task, which can be helpful for revisions on specific code blocks. For an itemized list of API updates, see the change log for Azure.Search.Documents on GitHub.

Authentication and encryption

Version 10 Version 11 equivalent
SearchCredentials AzureKeyCredential
EncryptionKey (Undocumented in API reference. Support for this API transitioned to generally available in v10, but was only available in the preview SDK) SearchResourceEncryptionKey

Indexes, analyzers, synonym maps

Version 10 Version 11 equivalent
Index SearchIndex
Field SearchField
DataType SearchFieldDataType
ItemError SearchIndexerError
Analyzer LexicalAnalyzer (also, AnalyzerName to LexicalAnalyzerName)
AnalyzeRequest AnalyzeTextOptions
StandardAnalyzer LuceneStandardAnalyzer
StandardTokenizer LuceneStandardTokenizer (also, StandardTokenizerV2 to LuceneStandardTokenizerV2)
TokenInfo AnalyzedTokenInfo
Tokenizer LexicalTokenizer (also, TokenizerName to LexicalTokenizerName)
SynonymMap.Format None. Remove references to Format.

Field definitions are streamlined: SearchableField, SimpleField, ComplexField are new APIs for creating field definitions.

Indexers, datasources, skillsets

Version 10 Version 11 equivalent
Indexer SearchIndexer
DataSource SearchIndexerDataSourceConnection
Skill SearchIndexerSkill
Skillset SearchIndexerSkillset
DataSourceType SearchIndexerDataSourceType

Data import

Version 10 Version 11 equivalent
IndexAction IndexDocumentsAction
IndexBatch IndexDocumentsBatch

Query requests and responses

Version 10 Version 11 equivalent
DocumentsOperationsExtensions.SearchAsync SearchClient.SearchAsync
DocumentSearchResult SearchResult or SearchResults, depending on whether the result is a single document or multiple.
DocumentSuggestResult SuggestResults
SearchParameters SearchOptions
SuggestParameters SuggestOptions
SearchParameters.Filter SearchFilter (a new class for constructing OData filter expressions)

JSON serialization

By default, the Azure SDK uses System.Text.Json for JSON serialization, relying on the capabilities of those APIs to handle text transformations previously implemented through a native SerializePropertyNamesAsCamelCaseAttribute class, which has no counterpart in the new library.

To serialize property names into camelCase, you can use the JsonPropertyNameAttribute (similar to this example).

Alternatively, you can set a JsonNamingPolicy provided in JsonSerializerOptions. The following System.Text.Json code example, taken from the Microsoft.Azure.Core.Spatial readme demonstrates the use of camelCase without having to attribute every property:

// Get the Azure Cognitive Search endpoint and read-only API key.
Uri endpoint = new Uri(Environment.GetEnvironmentVariable("SEARCH_ENDPOINT"));
AzureKeyCredential credential = new AzureKeyCredential(Environment.GetEnvironmentVariable("SEARCH_API_KEY"));

// Create serializer options with our converter to deserialize geographic points.
JsonSerializerOptions serializerOptions = new JsonSerializerOptions
{
    Converters =
    {
        new MicrosoftSpatialGeoJsonConverter()
    },
    PropertyNamingPolicy = JsonNamingPolicy.CamelCase
};

SearchClientOptions clientOptions = new SearchClientOptions
{
    Serializer = new JsonObjectSerializer(serializerOptions)
};

SearchClient client = new SearchClient(endpoint, "mountains", credential, clientOptions);
Response<SearchResults<Mountain>> results = client.Search<Mountain>("Rainier");

If you are using Newtonsoft.Json for JSON serialization, you can pass in global naming policies using similar attributes, or by using properties on JsonSerializerSettings. For an example equivalent to the one above, see the Deserializing documents example in the Newtonsoft.Json readme.

Inside v11

Each version of an Azure Cognitive Search client library targets a corresponding version of the REST API. The REST API is considered foundational to the service, with individual SDKs wrapping a version of the REST API. As a .NET developer, it can be helpful to review the more verbose REST API documentation for more in depth coverage of specific objects or operations. Version 11 targets the 2020-06-30 search service.

Version 11.0 fully supports the following objects and operations:

  • Index creation and management
  • Synonym map creation and management
  • Indexer creation and management
  • Indexer data source creation and management
  • Skillset creation and management
  • All query types and syntax

Version 11.1 additions (change log details):

Version 11.2 additions (change log details):

Currently unsupported in any version of Azure.Search.Documents:

Before upgrading

  • Quickstarts, tutorials, and C# samples have been updated to use the Azure.Search.Documents package. We recommend reviewing existing samples and walkthroughs to learn about the new APIs before embarking on a migration exercise.

  • How to use Azure.Search.Documents introduces the most commonly used APIs. Even knowledgeable users of Cognitive Search might want to review this introduction to the new library as a precursor to migration.

Steps to upgrade

The following steps get you started on a code migration by walking through the first set of required tasks, especially with regard to client references.

  1. Install the Azure.Search.Documents package by right-clicking on your project references and selecting "Manage NuGet Packages..." in Visual Studio.

  2. Replace using directives for Microsoft.Azure.Search with the following:

    using Azure;
    using Azure.Search.Documents;
    using Azure.Search.Documents.Indexes;
    using Azure.Search.Documents.Indexes.Models;
    using Azure.Search.Documents.Models;
    
  3. For classes that require JSON serialization, replace using Newtonsoft.Json with using System.Text.Json.Serialization.

  4. Revise client authentication code. In previous versions, you would use properties on the client object to set the API key (for example, the SearchServiceClient.Credentials property). In the current version, use the AzureKeyCredential class to pass the key as a credential, so that if needed, you can update the API key without creating new client objects.

    Client properties have been streamlined to just Endpoint, ServiceName, and IndexName (where appropriate). The following example uses the system Uri class to provide the endpoint and the Environment class to read in the key value:

    Uri endpoint = new Uri(Environment.GetEnvironmentVariable("SEARCH_ENDPOINT"));
    AzureKeyCredential credential = new AzureKeyCredential(
       Environment.GetEnvironmentVariable("SEARCH_API_KEY"));
    SearchIndexClient indexClient = new SearchIndexClient(endpoint, credential);
    
  5. Add new client references for indexer-related objects. If you are using indexers, datasources, or skillsets, change the client references to SearchIndexerClient. This client is new in version 11 and has no antecedent.

  6. Revise collections and lists. In the new SDK, all lists are read-only to avoid downstream issues if the list happens to contain null values. The code change is to add items to a list. For example, instead of assigning strings to a Select property, you would add them as follows:

    var options = new SearchOptions
     {
        SearchMode = SearchMode.All,
        IncludeTotalCount = true
     };
    
     // Select fields to return in results.
     options.Select.Add("HotelName");
     options.Select.Add("Description");
     options.Select.Add("Tags");
     options.Select.Add("Rooms");
     options.Select.Add("Rating");
     options.Select.Add("LastRenovationDate");
    

    Select, Facets, SearchFields, SourceFields, ScoringParameters, and OrderBy are all lists that now need to be reconstructed.

  7. Update client references for queries and data import. Instances of SearchIndexClient should be changed to SearchClient. To avoid name confusion, make sure you catch all instances before proceeding to the next step.

  8. Update client references for index, synonym map, and analyzer objects. Instances of SearchServiceClient should be changed to SearchIndexClient.

  9. For the remainder of your code, update classes, methods, and properties to use the APIs of the new library. The naming differences section is a place to start but you can also review the change log.

    If you have trouble finding equivalent APIs, we suggest logging an issue on https://github.com/MicrosoftDocs/azure-docs/issues so that we can improve the documentation or investigate the problem.

  10. Rebuild the solution. After fixing any build errors or warnings, you can make additional changes to your application to take advantage of new functionality.

Breaking changes

Given the sweeping changes to libraries and APIs, an upgrade to version 11 is non-trivial and constitutes a breaking change in the sense that your code will no longer be backward compatible with version 10 and earlier. For a thorough review of the differences, see the change log for Azure.Search.Documents.

In terms of service version updates, where code changes in version 11 relate to existing functionality (and not just a refactoring of the APIs), you will find the following behavior changes:

  • BM25 ranking algorithm replaces the previous ranking algorithm with newer technology. New services will use this algorithm automatically. For existing services, you must set parameters to use the new algorithm.

  • Ordered results for null values have changed in this version, with null values appearing first if the sort is asc and last if the sort is desc. If you wrote code to handle how null values are sorted, you should review and potentially remove that code if it's no longer necessary.

Next steps