.NET Aspire Azure AI Search integration

Includes: Hosting integration and Client integration

The .NET Aspire Azure AI Search Documents integration enables you to connect to Azure AI Search (formerly Azure Cognitive Search) services from your .NET applications. Azure AI Search is an enterprise-ready information retrieval system for your heterogeneous content that you ingest into a search index, and surface to users through queries and apps. It comes with a comprehensive set of advanced search technologies, built for high-performance applications at any scale.

Hosting integration

The .NET Aspire Azure AI Search hosting integration models the Azure AI Search resource as the AzureSearchResource type. To access this type and APIs for expressing them within your app host project, install the 📦 Aspire.Hosting.Azure.Search NuGet package:

dotnet add package Aspire.Hosting.Azure.Search

For more information, see dotnet add package or Manage package dependencies in .NET applications.

Add an Azure AI Search resource

To add an AzureSearchResource to your app host project, call the AddAzureSearch method providing a name:

var builder = DistributedApplication.CreateBuilder(args);

var search = builder.AddAzureSearch("search");

builder.AddProject<Projects.ExampleProject>()
       .WithReference(search);

// After adding all resources, run the app...

The preceding code adds an Azure AI Search resource named search to the app host project. The WithReference method passes the connection information to the ExampleProject project.

Important

When you call AddAzureSearch, it implicitly calls AddAzureProvisioning(IDistributedApplicationBuilder)—which adds support for generating Azure resources dynamically during app startup. The app must configure the appropriate subscription and location. For more information, see Local provisioning: Configuration

Generated provisioning Bicep

If you're new to Bicep, it's a domain-specific language for defining Azure resources. With .NET Aspire, you don't need to write Bicep by hand; instead, the provisioning APIs generate Bicep for you. When you publish your app, the generated Bicep is output alongside the manifest file. When you add an Azure AI Search resource, Bicep is generated to provision the search service with appropriate defaults.

@description('The location for the resource(s) to be deployed.')
param location string = resourceGroup().location

param principalType string

param principalId string

resource search 'Microsoft.Search/searchServices@2023-11-01' = {
  name: take('search-${uniqueString(resourceGroup().id)}', 60)
  location: location
  properties: {
    hostingMode: 'default'
    disableLocalAuth: true
    partitionCount: 1
    replicaCount: 1
  }
  sku: {
    name: 'basic'
  }
  tags: {
    'aspire-resource-name': 'search'
  }
}

resource search_SearchIndexDataContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(search.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '8ebe5a00-799e-43f5-93ac-243d3dce84a7')
    principalType: principalType
  }
  scope: search
}

resource search_SearchServiceContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
  name: guid(search.id, principalId, subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0'))
  properties: {
    principalId: principalId
    roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '7ca78c08-252a-4471-8644-bb5ff32d4ba0')
    principalType: principalType
  }
  scope: search
}

output connectionString string = 'Endpoint=https://${search.name}.search.windows.net'

The preceding Bicep is a module that provisions an Azure AI Search service resource with the following defaults:

  • location: The location parameter of the resource group, defaults to resourceGroup().location.
  • principalType: The principal type parameter of the Azure AI Search resource.
  • principalId: The principal ID parameter of the Azure AI Search resource.
  • search: The resource representing the Azure AI Search service.
    • properties: The properties of the Azure AI Search service:
      • hostingMode: Is set to default.
      • disableLocalAuth: Is set to true.
      • partitionCount: Is set to 1.
      • replicaCount: Is set to 1.
    • sku: Defaults to basic.
  • search_SearchIndexDataContributor: The role assignment for the Azure AI Search index data contributor role. For more information, see Search Index Data Contributor.
  • search_SearchServiceContributor: The role assignment for the Azure AI Search service contributor role. For more information, see Search Service Contributor.
  • connectionString: The connection string for the Azure AI Search service, which is used to connect to the service. The connection string is generated using the Endpoint property of the Azure AI Search service.

The generated Bicep is a starting point and can be customized to meet your specific requirements.

Customize provisioning infrastructure

All .NET Aspire Azure resources are subclasses of the AzureProvisioningResource type. This type enables the customization of the generated Bicep by providing a fluent API to configure the Azure resources—using the ConfigureInfrastructure<T>(IResourceBuilder<T>, Action<AzureResourceInfrastructure>) API. For example, you can configure the search service partitions, replicas, and more:

builder.AddAzureSearch("search")
    .ConfigureInfrastructure(infra =>
    {
        var searchService = infra.GetProvisionableResources()
                                 .OfType<SearchService>()
                                 .Single();

        searchService.PartitionCount = 6;
        searchService.ReplicaCount = 3;
        searchService.SearchSkuName = SearchServiceSkuName.Standard3;
        searchService.Tags.Add("ExampleKey", "Example value");
    });

The preceding code:

There are many more configuration options available to customize the Azure AI Search resource. For more information, see Azure.Provisioning customization.

Connect to an existing Azure AI Search service

You might have an existing Azure AI Search service that you want to connect to. You can chain a call to annotate that your AzureSearchResource is an existing resource:

var builder = DistributedApplication.CreateBuilder(args);

var existingSearchName = builder.AddParameter("existingSearchName");
var existingSearchResourceGroup = builder.AddParameter("existingSearchResourceGroup");

var search = builder.AddAzureSearch("search")
                    .AsExisting(existingSearchName, existingSearchResourceGroup);

builder.AddProject<Projects.ExampleProject>()
       .WithReference(search);

// After adding all resources, run the app...

For more information on treating Azure AI Search resources as existing resources, see Use existing Azure resources.

Alternatively, instead of representing an Azure AI Search resource, you can add a connection string to the app host. Which is a weakly-typed approach that's based solely on a string value. To add a connection to an existing Azure AI Search service, call the AddConnectionString method:

var builder = DistributedApplication.CreateBuilder(args);

var search = builder.ExecutionContext.IsPublishMode
    ? builder.AddAzureSearch("search")
    : builder.AddConnectionString("search");

builder.AddProject<Projects.ExampleProject>()
       .WithReference(search);

// After adding all resources, run the app...

Note

Connection strings are used to represent a wide range of connection information, including database connections, message brokers, endpoint URIs, and other services. In .NET Aspire nomenclature, the term "connection string" is used to represent any kind of connection information.

The connection string is configured in the app host's configuration, typically under User Secrets, under the ConnectionStrings section:

{
  "ConnectionStrings": {
    "search": "https://{account_name}.search.azure.com/"
  }
}

For more information, see Add existing Azure resources with connection strings.

Hosting integration health checks

The Azure AI Search hosting integration doesn't currently implement any health checks. This limitation is subject to change in future releases. As always, feel free to open an issue if you have any suggestions or feedback.

Client integration

To get started with the .NET Aspire Azure AI Search Documents client integration, install the 📦 Aspire.Azure.Search.Documents NuGet package in the client-consuming project, that is, the project for the application that uses the Azure AI Search Documents client.

dotnet add package Aspire.Azure.Search.Documents

Add an Azure AI Search index client

In the Program.cs file of your client-consuming project, call the AddAzureSearchClient extension method on any IHostApplicationBuilder to register a SearchIndexClient for use via the dependency injection container. The method takes a connection name parameter.

builder.AddAzureSearchClient(connectionName: "search");

Tip

The connectionName parameter must match the name used when adding the Azure AI Search resource in the app host project. For more information, see Add an Azure AI Search resource.

After adding the SearchIndexClient, you can retrieve the client instance using dependency injection. For example, to retrieve the client instance from an example service:

public class ExampleService(SearchIndexClient indexClient)
{
    // Use indexClient
}

You can also retrieve a SearchClient which can be used for querying, by calling the GetSearchClient(String) method:

public class ExampleService(SearchIndexClient indexClient)
{
    public async Task<long> GetDocumentCountAsync(
        string indexName,
        CancellationToken cancellationToken)
    {
        var searchClient = indexClient.GetSearchClient(indexName);

        var documentCountResponse = await searchClient.GetDocumentCountAsync(
            cancellationToken);

        return documentCountResponse.Value;
    }
}

For more information, see:

Add keyed Azure AI Search index client

There might be situations where you want to register multiple SearchIndexClient instances with different connection names. To register keyed Azure AI Search clients, call the AddKeyedAzureSearchClient method:

builder.AddKeyedAzureSearchClient(name: "images");
builder.AddKeyedAzureSearchClient(name: "documents");

Important

When using keyed services, it's expected that your Azure AI Search resource configured two named connections, one for the images and one for the documents.

Then you can retrieve the client instances using dependency injection. For example, to retrieve the clients from a service:

public class ExampleService(
    [KeyedService("images")] SearchIndexClient imagesClient,
    [KeyedService("documents")] SearchIndexClient documentsClient)
{
    // Use clients...
}

For more information, see Keyed services in .NET.

Configuration

The .NET Aspire Azure AI Search Documents library provides multiple options to configure the Azure AI Search connection based on the requirements and conventions of your project. Either an Endpoint or a ConnectionString is required to be supplied.

Use a connection string

A connection can be constructed from the Keys and Endpoint tab with the format Endpoint={endpoint};Key={key};. You can provide the name of the connection string when calling builder.AddAzureSearchClient():

builder.AddAzureSearchClient("searchConnectionName");

The connection string is retrieved from the ConnectionStrings configuration section. Two connection formats are supported:

Account endpoint

The recommended approach is to use an Endpoint, which works with the AzureSearchSettings.Credential property to establish a connection. If no credential is configured, the DefaultAzureCredential is used.

{
  "ConnectionStrings": {
    "search": "https://{search_service}.search.windows.net/"
  }
}
Connection string

Alternatively, a connection string with key can be used, however; it's not the recommended approach:

{
  "ConnectionStrings": {
    "search": "Endpoint=https://{search_service}.search.windows.net/;Key={account_key};"
  }
}

Use configuration providers

The .NET Aspire Azure AI Search library supports Microsoft.Extensions.Configuration. It loads the AzureSearchSettings and SearchClientOptions from configuration by using the Aspire:Azure:Search:Documents key. Example appsettings.json that configures some of the options:

{
  "Aspire": {
    "Azure": {
      "Search": {
        "Documents": {
          "DisableTracing": false
        }
      }
    }
  }
}

For the complete Azure AI Search Documents client integration JSON schema, see Aspire.Azure.Search.Documents/ConfigurationSchema.json.

Use inline delegates

You can also pass the Action<AzureSearchSettings> configureSettings delegate to set up some or all the options inline, for example to disable tracing from code:

builder.AddAzureSearchClient(
    "searchConnectionName",
    static settings => settings.DisableTracing = true);

You can also set up the SearchClientOptions using the optional Action<IAzureClientBuilder<SearchIndexClient, SearchClientOptions>> configureClientBuilder parameter of the AddAzureSearchClient method. For example, to set the client ID for this client:

builder.AddAzureSearchClient(
    "searchConnectionName",
    configureClientBuilder: builder => builder.ConfigureOptions(
        static options => options.Diagnostics.ApplicationId = "CLIENT_ID"));

Client integration health checks

By default, .NET Aspire client integrations have health checks enabled for all services. Similarly, many .NET Aspire hosting integrations also enable health check endpoints. For more information, see:

The .NET Aspire Azure AI Search Documents integration implements a single health check that calls the GetServiceStatisticsAsync method on the SearchIndexClient to verify that the service is available.

Observability and telemetry

.NET Aspire integrations automatically set up Logging, Tracing, and Metrics configurations, which are sometimes known as the pillars of observability. For more information about integration observability and telemetry, see .NET Aspire integrations overview. Depending on the backing service, some integrations may only support some of these features. For example, some integrations support logging and tracing, but not metrics. Telemetry features can also be disabled using the techniques presented in the Configuration section.

Logging

The .NET Aspire Azure AI Search Documents integration uses the following log categories:

  • Azure
  • Azure.Core
  • Azure.Identity

Tracing

The .NET Aspire Azure AI Search Documents integration emits tracing activities using OpenTelemetry when interacting with the search service.

See also