From 162b8a95f09ba60d556759d9687893068a458cbb Mon Sep 17 00:00:00 2001 From: Shay Rojansky Date: Thu, 13 Mar 2025 13:50:57 +0100 Subject: [PATCH] First round of MEVD DI changes Contributes to #10549 --- .../AzureAISearchKernelBuilderExtensions.cs | 13 +- ...zureAISearchServiceCollectionExtensions.cs | 414 ++++++++++++------ ...eCosmosDBMongoDBKernelBuilderExtensions.cs | 10 +- ...mosDBMongoDBServiceCollectionExtensions.cs | 269 ++++++++---- ...ureCosmosDBNoSQLKernelBuilderExtensions.cs | 14 +- ...osmosDBNoSQLServiceCollectionExtensions.cs | 268 ++++++++---- .../InMemoryKernelBuilderExtensions.cs | 6 +- .../InMemoryServiceCollectionExtensions.cs | 100 +++-- .../MongoDBServiceCollectionExtensions.cs | 273 +++++++----- .../PineconeKernelBuilderExtensions.cs | 10 +- .../PineconeServiceCollectionExtensions.cs | 251 +++++++---- .../PostgresServiceCollectionExtensions.cs | 294 ++++++++----- .../QdrantKernelBuilderExtensions.cs | 10 +- .../QdrantServiceCollectionExtensions.cs | 260 +++++++---- .../RedisKernelBuilderExtensions.cs | 14 +- .../RedisServiceCollectionExtensions.cs | 363 +++++++++------ .../SqliteServiceCollectionExtensions.cs | 279 +++++++----- .../WeaviateKernelBuilderExtensions.cs | 6 +- .../WeaviateServiceCollectionExtensions.cs | 128 ++++-- 19 files changed, 1921 insertions(+), 1061 deletions(-) diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchKernelBuilderExtensions.cs index 5096c1486f1f..9b4c6818fb03 100644 --- a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchKernelBuilderExtensions.cs @@ -12,6 +12,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Azure AI Search instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class AzureAISearchKernelBuilderExtensions { /// @@ -23,7 +24,7 @@ public static class AzureAISearchKernelBuilderExtensions /// The kernel builder. public static IKernelBuilder AddAzureAISearchVectorStore(this IKernelBuilder builder, AzureAISearchVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureAISearchVectorStore(options, serviceId); + builder.Services.AddKeyedAzureAISearchVectorStore(serviceId, options); return builder; } @@ -38,7 +39,7 @@ public static IKernelBuilder AddAzureAISearchVectorStore(this IKernelBuilder bui /// The kernel builder. public static IKernelBuilder AddAzureAISearchVectorStore(this IKernelBuilder builder, Uri endpoint, TokenCredential tokenCredential, AzureAISearchVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureAISearchVectorStore(endpoint, tokenCredential, options, serviceId); + builder.Services.AddKeyedAzureAISearchVectorStore(serviceId, endpoint, tokenCredential, options); return builder; } @@ -53,7 +54,7 @@ public static IKernelBuilder AddAzureAISearchVectorStore(this IKernelBuilder bui /// The kernel builder. public static IKernelBuilder AddAzureAISearchVectorStore(this IKernelBuilder builder, Uri endpoint, AzureKeyCredential credential, AzureAISearchVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureAISearchVectorStore(endpoint, credential, options, serviceId); + builder.Services.AddKeyedAzureAISearchVectorStore(serviceId, endpoint, credential, options); return builder; } @@ -73,7 +74,7 @@ public static IKernelBuilder AddAzureAISearchVectorStoreRecordCollection? options = default, string? serviceId = default) { - builder.Services.AddAzureAISearchVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedAzureAISearchVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -97,7 +98,7 @@ public static IKernelBuilder AddAzureAISearchVectorStoreRecordCollection? options = default, string? serviceId = default) { - builder.Services.AddAzureAISearchVectorStoreRecordCollection(collectionName, endpoint, tokenCredential, options, serviceId); + builder.Services.AddKeyedAzureAISearchVectorStoreRecordCollection(serviceId, collectionName, endpoint, tokenCredential, options); return builder; } @@ -121,7 +122,7 @@ public static IKernelBuilder AddAzureAISearchVectorStoreRecordCollection? options = default, string? serviceId = default) { - builder.Services.AddAzureAISearchVectorStoreRecordCollection(collectionName, endpoint, credential, options, serviceId); + builder.Services.AddKeyedAzureAISearchVectorStoreRecordCollection(serviceId, collectionName, endpoint, credential, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchServiceCollectionExtensions.cs index 0daa73595cbd..52be400d1c92 100644 --- a/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.AzureAISearch/AzureAISearchServiceCollectionExtensions.cs @@ -20,229 +20,358 @@ namespace Microsoft.SemanticKernel; public static class AzureAISearchServiceCollectionExtensions { /// - /// Register an Azure AI Search with the specified service ID and where is retrieved from the dependency injection container. + /// Registers an Azure AI Search in the , retrieving the from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . /// The service collection. - public static IServiceCollection AddAzureAISearchVectorStore(this IServiceCollection services, AzureAISearchVectorStoreOptions? options = default, string? serviceId = default) - { + public static IServiceCollection AddAzureAISearchVectorStore( + this IServiceCollection serviceCollection, + AzureAISearchVectorStoreOptions? options = default, // If we are not constructing the SearchIndexClient, add the IVectorStore as transient, since we // cannot make assumptions about how SearchIndexClient is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var searchIndexClient = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new AzureAISearchVectorStore( - searchIndexClient, - selectedOptions); - }); - - return services; + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureAISearchVectorStore(serviceCollection, serviceKey: null, options, lifetime); + + /// + /// Registers a keyed Azure AI Search in the , retrieving the from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedAzureAISearchVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + AzureAISearchVectorStoreOptions? options = default, + // If we are not constructing the SearchIndexClient, add the IVectorStore as transient, since we + // cannot make assumptions about how SearchIndexClient is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new AzureAISearchVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register an Azure AI Search with the provided and and the specified service ID. + /// Registers an Azure AI Search in the , using the provided and . /// - /// The to register the on. + /// The to which the vector store should be added. /// The service endpoint for Azure AI Search. /// The credential to authenticate to Azure AI Search with. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . /// The service collection. - public static IServiceCollection AddAzureAISearchVectorStore(this IServiceCollection services, Uri endpoint, TokenCredential tokenCredential, AzureAISearchVectorStoreOptions? options = default, string? serviceId = default) + public static IServiceCollection AddAzureAISearchVectorStore( + this IServiceCollection serviceCollection, + Uri endpoint, + TokenCredential tokenCredential, + AzureAISearchVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedAzureAISearchVectorStore(serviceCollection, serviceKey: null, endpoint, tokenCredential, options, lifetime); + + /// + /// Registers a keyed Azure AI Search in the , using the provided and . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The service endpoint for Azure AI Search. + /// The credential to authenticate to Azure AI Search with. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedAzureAISearchVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + Uri endpoint, + TokenCredential tokenCredential, + AzureAISearchVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { Verify.NotNull(endpoint); Verify.NotNull(tokenCredential); - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var selectedOptions = options ?? sp.GetService(); - var searchClientOptions = BuildSearchClientOptions(selectedOptions?.JsonSerializerOptions); - var searchIndexClient = new SearchIndexClient(endpoint, tokenCredential, searchClientOptions); - - // Construct the vector store. - return new AzureAISearchVectorStore( - searchIndexClient, - selectedOptions); - }); - - return services; + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => + { + options ??= serviceProvider.GetService(); + var searchClientOptions = BuildSearchClientOptions(options?.JsonSerializerOptions); + var searchIndexClient = new SearchIndexClient(endpoint, tokenCredential, searchClientOptions); + + // Construct the vector store. + return new AzureAISearchVectorStore(searchIndexClient, options); + }, + lifetime)); + + return serviceCollection; } /// - /// Register an Azure AI Search with the provided and and the specified service ID. + /// Registers an Azure AI Search in the , using the provided and . /// - /// The to register the on. + /// The to which the vector store should be added. /// The service endpoint for Azure AI Search. /// The credential to authenticate to Azure AI Search with. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . /// The service collection. - public static IServiceCollection AddAzureAISearchVectorStore(this IServiceCollection services, Uri endpoint, AzureKeyCredential credential, AzureAISearchVectorStoreOptions? options = default, string? serviceId = default) + public static IServiceCollection AddAzureAISearchVectorStore( + this IServiceCollection serviceCollection, + Uri endpoint, + AzureKeyCredential credential, + AzureAISearchVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedAzureAISearchVectorStore(serviceCollection, serviceKey: null, endpoint, credential, options, lifetime); + + /// + /// Registers a keyed Azure AI Search in the , using the provided and . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The service endpoint for Azure AI Search. + /// The credential to authenticate to Azure AI Search with. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedAzureAISearchVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + Uri endpoint, + AzureKeyCredential credential, + AzureAISearchVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) { Verify.NotNull(endpoint); Verify.NotNull(credential); - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var selectedOptions = options ?? sp.GetService(); - var searchClientOptions = BuildSearchClientOptions(selectedOptions?.JsonSerializerOptions); - var searchIndexClient = new SearchIndexClient(endpoint, credential, searchClientOptions); - - // Construct the vector store. - return new AzureAISearchVectorStore( - searchIndexClient, - selectedOptions); - }); - - return services; + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => + { + options ??= serviceProvider.GetService(); + var searchClientOptions = BuildSearchClientOptions(options?.JsonSerializerOptions); + var searchIndexClient = new SearchIndexClient(endpoint, credential, searchClientOptions); + + // Construct the vector store. + return new AzureAISearchVectorStore(searchIndexClient, options); + }, + lifetime)); + + return serviceCollection; } /// - /// Register an Azure AI Search , and with the - /// specified service ID and where is retrieved from the dependency injection container. + /// Registers an Azure AI Search , and , + /// retrieving the from the dependency injection container. /// /// The type of the data model that the collection should contain. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection that this will access. - /// Optional configuration options to pass to the . - /// An optional service id to use as the service key. + /// Configuration options to pass to the . + /// The service lifetime for the collection. Defaults to . /// The service collection. public static IServiceCollection AddAzureAISearchVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, + string collectionName, + AzureAISearchVectorStoreRecordCollectionOptions? options = default, + // If we are not constructing the SearchIndexClient, add the IVectorStore as transient, since we + // cannot make assumptions about how SearchIndexClient is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureAISearchVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); + + /// + /// Registers a keyed Azure AI Search , and , + /// retrieving the from the dependency injection container. + /// + /// The type of the data model that the collection should contain. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection that this will access. + /// Configuration options to pass to the . + /// The service lifetime for the collection. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedAzureAISearchVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, string collectionName, AzureAISearchVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { // If we are not constructing the SearchIndexClient, add the IVectorStore as transient, since we // cannot make assumptions about how SearchIndexClient is being managed. - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var searchIndexClient = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return new AzureAISearchVectorStoreRecordCollection( - searchIndexClient, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new AzureAISearchVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), collectionName, - selectedOptions); - }); + options ?? serviceProvider.GetService>()), + lifetime)); - AddVectorizedSearch(services, serviceId); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - return services; + return serviceCollection; } /// - /// Register an Azure AI Search , and with the - /// provided and and the specified service ID. + /// Registers an Azure AI Search , and with the + /// provided and . /// /// The type of the data model that the collection should contain. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection that this will access. /// The service endpoint for Azure AI Search. /// The credential to authenticate to Azure AI Search with. /// Optional configuration options to pass to the . - /// An optional service id to use as the service key. + /// The service lifetime for the collection. Defaults to . /// The service collection. public static IServiceCollection AddAzureAISearchVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, Uri endpoint, TokenCredential tokenCredential, AzureAISearchVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedAzureAISearchVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, endpoint, tokenCredential, options, lifetime); + + /// + /// Registers a keyed Azure AI Search , and with the + /// provided and . + /// + /// The type of the data model that the collection should contain. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection that this will access. + /// The service endpoint for Azure AI Search. + /// The credential to authenticate to Azure AI Search with. + /// Optional configuration options to pass to the . + /// The service lifetime for the collection. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedAzureAISearchVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + Uri endpoint, + TokenCredential tokenCredential, + AzureAISearchVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { Verify.NotNull(endpoint); Verify.NotNull(tokenCredential); - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var selectedOptions = options ?? sp.GetService>(); - var searchClientOptions = BuildSearchClientOptions(selectedOptions?.JsonSerializerOptions); - var searchIndexClient = new SearchIndexClient(endpoint, tokenCredential, searchClientOptions); - - // Construct the vector store. - return new AzureAISearchVectorStoreRecordCollection( - searchIndexClient, - collectionName, - selectedOptions); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => + { + options ??= serviceProvider.GetService>(); + var searchClientOptions = BuildSearchClientOptions(options?.JsonSerializerOptions); + var searchIndexClient = new SearchIndexClient(endpoint, tokenCredential, searchClientOptions); - AddVectorizedSearch(services, serviceId); + // Construct the vector store. + return new AzureAISearchVectorStoreRecordCollection(searchIndexClient, collectionName, options); + }, + lifetime)); - return services; + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } /// - /// Register an Azure AI Search , and with the - /// provided and and the specified service ID. + /// Registers an Azure AI Search , and with the + /// provided and . /// /// The type of the data model that the collection should contain. - /// The to register the on. + /// The to register the on. /// The name of the collection that this will access. /// The service endpoint for Azure AI Search. /// The credential to authenticate to Azure AI Search with. /// Optional configuration options to pass to the . - /// An optional service id to use as the service key. + /// The service lifetime for the collection. Defaults to . /// The service collection. public static IServiceCollection AddAzureAISearchVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, Uri endpoint, AzureKeyCredential credential, AzureAISearchVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedAzureAISearchVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, endpoint, credential, options, lifetime); + + /// + /// Registers a keyed Azure AI Search , and with the + /// provided and . + /// + /// The type of the data model that the collection should contain. + /// The to register the on. + /// The key with which to associate the vector store. + /// The name of the collection that this will access. + /// The service endpoint for Azure AI Search. + /// The credential to authenticate to Azure AI Search with. + /// Optional configuration options to pass to the . + /// The service lifetime for the collection. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedAzureAISearchVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + Uri endpoint, + AzureKeyCredential credential, + AzureAISearchVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { Verify.NotNull(endpoint); Verify.NotNull(credential); - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var selectedOptions = options ?? sp.GetService>(); - var searchClientOptions = BuildSearchClientOptions(selectedOptions?.JsonSerializerOptions); - var searchIndexClient = new SearchIndexClient(endpoint, credential, searchClientOptions); - - // Construct the vector store. - return new AzureAISearchVectorStoreRecordCollection( - searchIndexClient, - collectionName, - selectedOptions); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => + { + var selectedOptions = options ?? serviceProvider.GetService>(); + var searchClientOptions = BuildSearchClientOptions(selectedOptions?.JsonSerializerOptions); + var searchIndexClient = new SearchIndexClient(endpoint, credential, searchClientOptions); - AddVectorizedSearch(services, serviceId); + // Construct the vector store. + return new AzureAISearchVectorStoreRecordCollection(searchIndexClient, collectionName, selectedOptions); + }, + lifetime)); - return services; - } + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - /// - /// Also register the with the given as a . - /// - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + return serviceCollection; } /// @@ -252,8 +381,11 @@ private static void AddVectorizedSearch(IServiceCollection services, st /// The . private static SearchClientOptions BuildSearchClientOptions(JsonSerializerOptions? jsonSerializerOptions) { - var searchClientOptions = new SearchClientOptions(); - searchClientOptions.Diagnostics.ApplicationId = HttpHeaderConstant.Values.UserAgent; + var searchClientOptions = new SearchClientOptions + { + Diagnostics = { ApplicationId = HttpHeaderConstant.Values.UserAgent } + }; + if (jsonSerializerOptions != null) { searchClientOptions.Serializer = new JsonObjectSerializer(jsonSerializerOptions); diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBKernelBuilderExtensions.cs index af73629568ec..150ea19c26f9 100644 --- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.AzureCosmosDBMongoDB; using MongoDB.Driver; @@ -9,6 +10,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Azure CosmosDB MongoDB instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class AzureCosmosDBMongoDBKernelBuilderExtensions { /// @@ -24,7 +26,7 @@ public static IKernelBuilder AddAzureCosmosDBMongoDBVectorStore( AzureCosmosDBMongoDBVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBMongoDBVectorStore(options, serviceId); + builder.Services.AddKeyedAzureCosmosDBMongoDBVectorStore(serviceId, options); return builder; } @@ -45,7 +47,7 @@ public static IKernelBuilder AddAzureCosmosDBMongoDBVectorStore( AzureCosmosDBMongoDBVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBMongoDBVectorStore(connectionString, databaseName, options, serviceId); + builder.Services.AddKeyedAzureCosmosDBMongoDBVectorStore(serviceId, connectionString, databaseName, options); return builder; } @@ -65,7 +67,7 @@ public static IKernelBuilder AddAzureCosmosDBMongoDBVectorStoreRecordCollection< AzureCosmosDBMongoDBVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBMongoDBVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedAzureCosmosDBMongoDBVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -89,7 +91,7 @@ public static IKernelBuilder AddAzureCosmosDBMongoDBVectorStoreRecordCollection< AzureCosmosDBMongoDBVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBMongoDBVectorStoreRecordCollection(collectionName, connectionString, databaseName, options, serviceId); + builder.Services.AddKeyedAzureCosmosDBMongoDBVectorStoreRecordCollection(serviceId, collectionName, connectionString, databaseName, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBServiceCollectionExtensions.cs index f4f77082a271..25f8db3263b9 100644 --- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBMongoDB/AzureCosmosDBMongoDBServiceCollectionExtensions.cs @@ -14,154 +14,231 @@ namespace Microsoft.SemanticKernel; public static class AzureCosmosDBMongoDBServiceCollectionExtensions { /// - /// Register a Azure CosmosDB MongoDB with the specified service ID - /// and where the Azure CosmosDB MongoDB is retrieved from the dependency injection container. + /// Registers an Azure CosmosDB MongoDB , retrieving the from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBMongoDBVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, AzureCosmosDBMongoDBVectorStoreOptions? options = default, - string? serviceId = default) - { // If we are not constructing MongoDatabase, add the IVectorStore as transient, since we // cannot make assumptions about how MongoDatabase is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new AzureCosmosDBMongoDBVectorStore(database, options); - }); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureCosmosDBMongoDBVectorStore(serviceCollection, serviceKey: null, options, lifetime); - return services; + /// + /// Registers a keyed Azure CosmosDB MongoDB , retrieving the from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the store. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBMongoDBVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + AzureCosmosDBMongoDBVectorStoreOptions? options = default, + // If we are not constructing MongoDatabase, add the IVectorStore as transient, since we + // cannot make assumptions about how MongoDatabase is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new AzureCosmosDBMongoDBVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Azure CosmosDB MongoDB with the specified service ID - /// and where the Azure CosmosDB MongoDB is constructed using the provided and . + /// Registers an Azure CosmosDB MongoDB , using the provided and . /// - /// The to register the on. + /// The to which the vector store should be added. /// Connection string required to connect to Azure CosmosDB MongoDB. /// Database name for Azure CosmosDB MongoDB. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBMongoDBVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, string connectionString, string databaseName, AzureCosmosDBMongoDBVectorStoreOptions? options = default, - string? serviceId = default) - { // If we are constructing IMongoDatabase, add the IVectorStore as singleton, since we are managing the lifetime of it, // and the recommendation from Mongo is to register it with a singleton lifetime. - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var settings = MongoClientSettings.FromConnectionString(connectionString); - settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedAzureCosmosDBMongoDBVectorStore(serviceCollection, serviceKey: null, connectionString, databaseName, options, lifetime); - var mongoClient = new MongoClient(settings); - var database = mongoClient.GetDatabase(databaseName); + /// + /// Registers a keyed Azure CosmosDB MongoDB , using the provided and . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Connection string required to connect to Azure CosmosDB MongoDB. + /// Database name for Azure CosmosDB MongoDB. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBMongoDBVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string connectionString, + string databaseName, + AzureCosmosDBMongoDBVectorStoreOptions? options = default, + // If we are constructing IMongoDatabase, add the IVectorStore as singleton, since we are managing the lifetime of it, + // and the recommendation from Mongo is to register it with a singleton lifetime. + ServiceLifetime lifetime = ServiceLifetime.Singleton) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => + { + var settings = MongoClientSettings.FromConnectionString(connectionString); + settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; + + var mongoClient = new MongoClient(settings); + var database = mongoClient.GetDatabase(databaseName); - var selectedOptions = options ?? sp.GetService(); + options ??= serviceProvider.GetService(); - return new AzureCosmosDBMongoDBVectorStore(database, options); - }); + return new AzureCosmosDBMongoDBVectorStore(database, options); + }, + lifetime)); - return services; + return serviceCollection; } /// - /// Register an Azure CosmosDB MongoDB and with the specified service ID - /// and where the Azure CosmosDB MongoDB is retrieved from the dependency injection container. + /// Registers an Azure CosmosDB MongoDB and , + /// retrieving the is retrieved from the dependency injection container. /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBMongoDBVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, AzureCosmosDBMongoDBVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return new AzureCosmosDBMongoDBVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureCosmosDBMongoDBVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - return services; + /// + /// Registers a keyed Azure CosmosDB MongoDB and , + /// retrieving the is retrieved from the dependency injection container. + /// + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBMongoDBVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + AzureCosmosDBMongoDBVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new AzureCosmosDBMongoDBVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } /// - /// Register an Azure CosmosDB MongoDB and with the specified service ID - /// and where the Azure CosmosDB MongoDB is constructed using the provided and . + /// Registers an Azure CosmosDB MongoDB and + /// using the provided and . /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Connection string required to connect to Azure CosmosDB MongoDB. /// Database name for Azure CosmosDB MongoDB. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBMongoDBVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string connectionString, string databaseName, AzureCosmosDBMongoDBVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var settings = MongoClientSettings.FromConnectionString(connectionString); - settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; - - var mongoClient = new MongoClient(settings); - var database = mongoClient.GetDatabase(databaseName); - - var selectedOptions = options ?? sp.GetService>(); - - return new AzureCosmosDBMongoDBVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureCosmosDBMongoDBVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, connectionString, databaseName, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed Azure CosmosDB MongoDB and + /// using the provided and . /// - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Connection string required to connect to Azure CosmosDB MongoDB. + /// Database name for Azure CosmosDB MongoDB. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBMongoDBVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string connectionString, + string databaseName, + AzureCosmosDBMongoDBVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => + { + var settings = MongoClientSettings.FromConnectionString(connectionString); + settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; + + var mongoClient = new MongoClient(settings); + var database = mongoClient.GetDatabase(databaseName); + + options ??= serviceProvider.GetService>(); + + return new AzureCosmosDBMongoDBVectorStoreRecordCollection(database, collectionName, options); + }, + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKernelBuilderExtensions.cs index 12f7c0118538..3143d53acda9 100644 --- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using Microsoft.Azure.Cosmos; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.AzureCosmosDBNoSQL; @@ -9,6 +10,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Azure CosmosDB NoSQL instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class AzureCosmosDBNoSQLKernelBuilderExtensions { /// @@ -24,7 +26,7 @@ public static IKernelBuilder AddAzureCosmosDBNoSQLVectorStore( AzureCosmosDBNoSQLVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBNoSQLVectorStore(options, serviceId); + builder.Services.AddKeyedAzureCosmosDBNoSQLVectorStore(serviceId, options); return builder; } @@ -45,11 +47,11 @@ public static IKernelBuilder AddAzureCosmosDBNoSQLVectorStore( AzureCosmosDBNoSQLVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBNoSQLVectorStore( + builder.Services.AddKeyedAzureCosmosDBNoSQLVectorStore( + serviceId, connectionString, databaseName, - options, - serviceId); + options); return builder; } @@ -70,7 +72,7 @@ public static IKernelBuilder AddAzureCosmosDBNoSQLVectorStoreRecordCollection? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBNoSQLVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedAzureCosmosDBNoSQLVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -94,7 +96,7 @@ public static IKernelBuilder AddAzureCosmosDBNoSQLVectorStoreRecordCollection? options = default, string? serviceId = default) { - builder.Services.AddAzureCosmosDBNoSQLVectorStoreRecordCollection(collectionName, connectionString, databaseName, options, serviceId); + builder.Services.AddKeyedAzureCosmosDBNoSQLVectorStoreRecordCollection(serviceId, collectionName, connectionString, databaseName, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLServiceCollectionExtensions.cs index 1c70d360ee62..2e93943d6347 100644 --- a/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.AzureCosmosDBNoSQL/AzureCosmosDBNoSQLServiceCollectionExtensions.cs @@ -15,155 +15,231 @@ namespace Microsoft.SemanticKernel; public static class AzureCosmosDBNoSQLServiceCollectionExtensions { /// - /// Register an Azure CosmosDB NoSQL with the specified service ID - /// and where the Azure CosmosDB NoSQL is retrieved from the dependency injection container. + /// Registers an Azure CosmosDB NoSQL , retrieving the is retrieved from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBNoSQLVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, AzureCosmosDBNoSQLVectorStoreOptions? options = default, - string? serviceId = default) - { // If we are not constructing Database, add the IVectorStore as transient, since we // cannot make assumptions about how Database is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new AzureCosmosDBNoSQLVectorStore(database, options); - }); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureCosmosDBNoSQLVectorStore(serviceCollection, serviceKey: null, options, lifetime); - return services; + /// + /// Registers a keyed Azure CosmosDB NoSQL , retrieving the is retrieved from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBNoSQLVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + AzureCosmosDBNoSQLVectorStoreOptions? options = default, + // If we are not constructing Database, add the IVectorStore as transient, since we + // cannot make assumptions about how Database is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new AzureCosmosDBNoSQLVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register an Azure CosmosDB NoSQL with the specified service ID - /// and where the Azure CosmosDB NoSQL is constructed using the provided and . + /// Registers an Azure CosmosDB NoSQL , using the provided and . /// - /// The to register the on. + /// The to which the vector store should be added. /// Connection string required to connect to Azure CosmosDB NoSQL. /// Database name for Azure CosmosDB NoSQL. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBNoSQLVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, + string connectionString, + string databaseName, + AzureCosmosDBNoSQLVectorStoreOptions? options = default, + // If we are constructing Database, add the IVectorStore as singleton. + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureCosmosDBNoSQLVectorStore(serviceCollection, serviceKey: null, connectionString, databaseName, options, lifetime); + + /// + /// Registers a keyed Azure CosmosDB NoSQL , using the provided and . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Connection string required to connect to Azure CosmosDB NoSQL. + /// Database name for Azure CosmosDB NoSQL. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBNoSQLVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, string connectionString, string databaseName, AzureCosmosDBNoSQLVectorStoreOptions? options = default, - string? serviceId = default) - { // If we are constructing Database, add the IVectorStore as singleton. - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var cosmosClient = new CosmosClient(connectionString, new() + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => { - ApplicationName = HttpHeaderConstant.Values.UserAgent, - UseSystemTextJsonSerializerWithOptions = options?.JsonSerializerOptions ?? JsonSerializerOptions.Default, - }); + var cosmosClient = new CosmosClient(connectionString, new() + { + ApplicationName = HttpHeaderConstant.Values.UserAgent, + UseSystemTextJsonSerializerWithOptions = options?.JsonSerializerOptions ?? JsonSerializerOptions.Default, + }); - var database = cosmosClient.GetDatabase(databaseName); - var selectedOptions = options ?? sp.GetService(); + var database = cosmosClient.GetDatabase(databaseName); + options ??= serviceProvider.GetService(); - return new AzureCosmosDBNoSQLVectorStore(database, options); - }); + return new AzureCosmosDBNoSQLVectorStore(database, options); + }, + lifetime)); - return services; + return serviceCollection; } /// - /// Register an Azure CosmosDB NoSQL and with the specified service ID - /// and where the Azure CosmosDB NoSQL is retrieved from the dependency injection container. + /// Registers an Azure CosmosDB NoSQL and , + /// retrieving the from the dependency injection container. /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBNoSQLVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, AzureCosmosDBNoSQLVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return new AzureCosmosDBNoSQLVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedAzureCosmosDBNoSQLVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - AddVectorizedSearch(services, serviceId); - - return services; + /// + /// Registers a keyed Azure CosmosDB NoSQL and , + /// retrieving the from the dependency injection container. + /// + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Optional options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBNoSQLVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + AzureCosmosDBNoSQLVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new AzureCosmosDBNoSQLVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } /// - /// Register an Azure CosmosDB NoSQL and with the specified service ID - /// and where the Azure CosmosDB NoSQL is constructed using the provided and . + /// Register an Azure CosmosDB NoSQL and , + /// using the provided and . /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Connection string required to connect to Azure CosmosDB NoSQL. /// Database name for Azure CosmosDB NoSQL. /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddAzureCosmosDBNoSQLVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string connectionString, string databaseName, AzureCosmosDBNoSQLVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var cosmosClient = new CosmosClient(connectionString, new() - { - ApplicationName = HttpHeaderConstant.Values.UserAgent, - UseSystemTextJsonSerializerWithOptions = options?.JsonSerializerOptions ?? JsonSerializerOptions.Default, - }); - - var database = cosmosClient.GetDatabase(databaseName); - var selectedOptions = options ?? sp.GetService>(); - - return new AzureCosmosDBNoSQLVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedAzureCosmosDBNoSQLVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, connectionString, databaseName, options, lifetime); /// - /// Also register the with the given as a . + /// Register a keyed Azure CosmosDB NoSQL and , + /// using the provided and . /// - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Connection string required to connect to Azure CosmosDB NoSQL. + /// Database name for Azure CosmosDB NoSQL. + /// Optional options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedAzureCosmosDBNoSQLVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string connectionString, + string databaseName, + AzureCosmosDBNoSQLVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => + { + var cosmosClient = new CosmosClient(connectionString, new() + { + ApplicationName = HttpHeaderConstant.Values.UserAgent, + UseSystemTextJsonSerializerWithOptions = options?.JsonSerializerOptions ?? JsonSerializerOptions.Default, + }); + + var database = cosmosClient.GetDatabase(databaseName); + options ??= serviceProvider.GetService>(); + + return new AzureCosmosDBNoSQLVectorStoreRecordCollection(database, collectionName, options); + }, + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryKernelBuilderExtensions.cs index 85311ceba4fb..2dd1bf01ca40 100644 --- a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.InMemory; @@ -8,6 +9,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Data services on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class InMemoryKernelBuilderExtensions { /// @@ -18,7 +20,7 @@ public static class InMemoryKernelBuilderExtensions /// The kernel builder. public static IKernelBuilder AddInMemoryVectorStore(this IKernelBuilder builder, string? serviceId = default) { - builder.Services.AddInMemoryVectorStore(serviceId); + builder.Services.AddKeyedInMemoryVectorStore(serviceId); return builder; } @@ -39,7 +41,7 @@ public static IKernelBuilder AddInMemoryVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedInMemoryVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryServiceCollectionExtensions.cs index b541aad65b98..c98cb459275f 100644 --- a/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.InMemory/InMemoryServiceCollectionExtensions.cs @@ -14,50 +14,92 @@ namespace Microsoft.SemanticKernel; public static class InMemoryServiceCollectionExtensions { /// - /// Register an InMemory with the specified service ID. + /// Registers an InMemory . /// - /// The to register the on. - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddInMemoryVectorStore(this IServiceCollection services, string? serviceId = default) + public static IServiceCollection AddInMemoryVectorStore( + this IServiceCollection serviceCollection, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedInMemoryVectorStore(serviceCollection, serviceKey: null, lifetime); + + /// + /// Registers an InMemory . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedInMemoryVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddKeyedSingleton(serviceId); - services.AddKeyedSingleton(serviceId, (sp, obj) => sp.GetRequiredKeyedService(serviceId)); - return services; + serviceCollection.Add(new ServiceDescriptor(typeof(InMemoryVectorStore), serviceKey, typeof(InMemoryVectorStore), lifetime)); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService(serviceKey), + lifetime)); + + return serviceCollection; } /// - /// Register an InMemory and with the specified service ID. + /// Register an InMemory and . /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. public static IServiceCollection AddInMemoryVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, InMemoryVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Singleton) + where TKey : notnull + => AddKeyedInMemoryVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); + + /// + /// Register a keyed InMemory and . + /// + /// The type of the key. + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedInMemoryVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + InMemoryVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) where TKey : notnull { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var selectedOptions = options ?? sp.GetService>(); - return (new InMemoryVectorStoreRecordCollection(collectionName, selectedOptions) as IVectorStoreRecordCollection)!; - }); - - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); - - return services; + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new InMemoryVectorStoreRecordCollection( + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBServiceCollectionExtensions.cs index b8e89aab82da..d86c92b10609 100644 --- a/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.MongoDB/MongoDBServiceCollectionExtensions.cs @@ -14,154 +14,229 @@ namespace Microsoft.SemanticKernel; public static class MongoDBServiceCollectionExtensions { /// - /// Register a MongoDB with the specified service ID - /// and where the MongoDB is retrieved from the dependency injection container. + /// Registers a MongoDB , retrieving the from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to register the on. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddMongoDBVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, MongoDBVectorStoreOptions? options = default, - string? serviceId = default) - { // If we are not constructing MongoDatabase, add the IVectorStore as transient, since we // cannot make assumptions about how MongoDatabase is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new MongoDBVectorStore(database, options); - }); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedMongoDBVectorStore(serviceCollection, serviceKey: null, options, lifetime); - return services; + /// + /// Registers a keyed MongoDB , retrieving the from the dependency injection container. + /// + /// The to register the on. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedMongoDBVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + MongoDBVectorStoreOptions? options = default, + // If we are not constructing MongoDatabase, add the IVectorStore as transient, since we + // cannot make assumptions about how MongoDatabase is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new MongoDBVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a MongoDB with the specified service ID - /// and where the MongoDB is constructed using the provided and . + /// Registers a MongoDB , using the provided and . /// - /// The to register the on. + /// The to register the on. /// Connection string required to connect to MongoDB. /// Database name for MongoDB. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddMongoDBVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, string connectionString, string databaseName, MongoDBVectorStoreOptions? options = default, - string? serviceId = default) - { // If we are constructing IMongoDatabase, add the IVectorStore as singleton, since we are managing the lifetime of it, // and the recommendation from Mongo is to register it with a singleton lifetime. - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var settings = MongoClientSettings.FromConnectionString(connectionString); - settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; - - var mongoClient = new MongoClient(settings); - var database = mongoClient.GetDatabase(databaseName); - - var selectedOptions = options ?? sp.GetService(); - - return new MongoDBVectorStore(database, options); - }); + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedMongoDBVectorStore(serviceCollection, serviceKey: null, connectionString, databaseName, options, lifetime); - return services; + /// + /// Registers a keyed MongoDB , using the provided and . + /// + /// The to register the on. + /// The key with which to associate the vector store. + /// Connection string required to connect to MongoDB. + /// Database name for MongoDB. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedMongoDBVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string connectionString, + string databaseName, + MongoDBVectorStoreOptions? options = default, + // If we are constructing IMongoDatabase, add the IVectorStore as singleton, since we are managing the lifetime of it, + // and the recommendation from Mongo is to register it with a singleton lifetime. + ServiceLifetime lifetime = ServiceLifetime.Singleton) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => + { + var settings = MongoClientSettings.FromConnectionString(connectionString); + settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; + + var mongoClient = new MongoClient(settings); + var database = mongoClient.GetDatabase(databaseName); + + return new MongoDBVectorStore(database, options ?? serviceProvider.GetService()); + }, + lifetime)); + + return serviceCollection; } /// - /// Register a MongoDB and with the specified service ID - /// and where the MongoDB is retrieved from the dependency injection container. + /// Registers a MongoDB and , + /// retrieving the from the dependency injection container. /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddMongoDBVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, MongoDBVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return new MongoDBVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedMongoDBVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - AddVectorizedSearch(services, serviceId); - - return services; + /// + /// Registers a keyed MongoDB and , + /// retrieving the from the dependency injection container. + /// + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedMongoDBVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + MongoDBVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new MongoDBVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } /// - /// Register a MongoDB and with the specified service ID - /// and where the MongoDB is constructed using the provided and . + /// Registers a MongoDB and , + /// using the provided and . /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Connection string required to connect to MongoDB. /// Database name for MongoDB. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddMongoDBVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string connectionString, string databaseName, MongoDBVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var settings = MongoClientSettings.FromConnectionString(connectionString); - settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; - - var mongoClient = new MongoClient(settings); - var database = mongoClient.GetDatabase(databaseName); - - var selectedOptions = options ?? sp.GetService>(); - - return new MongoDBVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedMongoDBVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, connectionString, databaseName, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed MongoDB and , + /// using the provided and . /// - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Connection string required to connect to MongoDB. + /// Database name for MongoDB. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedMongoDBVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string connectionString, + string databaseName, + MongoDBVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => + { + var settings = MongoClientSettings.FromConnectionString(connectionString); + settings.ApplicationName = HttpHeaderConstant.Values.UserAgent; + + var mongoClient = new MongoClient(settings); + var database = mongoClient.GetDatabase(databaseName); + + var selectedOptions = options ?? serviceProvider.GetService>(); + + return new MongoDBVectorStoreRecordCollection(database, collectionName, selectedOptions); + }, + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeKernelBuilderExtensions.cs index 50048c8dfa6f..9410c1ef9c15 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.Pinecone; using Sdk = Pinecone; @@ -9,6 +10,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Pinecone instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class PineconeKernelBuilderExtensions { /// @@ -20,7 +22,7 @@ public static class PineconeKernelBuilderExtensions /// The kernel builder. public static IKernelBuilder AddPineconeVectorStore(this IKernelBuilder builder, PineconeVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddPineconeVectorStore(options, serviceId); + builder.Services.AddKeyedPineconeVectorStore(serviceId, options); return builder; } @@ -34,7 +36,7 @@ public static IKernelBuilder AddPineconeVectorStore(this IKernelBuilder builder, /// The kernel builder. public static IKernelBuilder AddPineconeVectorStore(this IKernelBuilder builder, string apiKey, PineconeVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddPineconeVectorStore(apiKey, options, serviceId); + builder.Services.AddKeyedPineconeVectorStore(serviceId, apiKey, options); return builder; } @@ -54,7 +56,7 @@ public static IKernelBuilder AddPineconeVectorStoreRecordCollection( PineconeVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddPineconeVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedPineconeVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -76,7 +78,7 @@ public static IKernelBuilder AddPineconeVectorStoreRecordCollection( PineconeVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddPineconeVectorStoreRecordCollection(collectionName, apiKey, options, serviceId); + builder.Services.AddKeyedPineconeVectorStoreRecordCollection(serviceId, collectionName, apiKey, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeServiceCollectionExtensions.cs index 5e7658eb923f..123522892291 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Pinecone/PineconeServiceCollectionExtensions.cs @@ -13,141 +13,206 @@ namespace Microsoft.SemanticKernel; public static class PineconeServiceCollectionExtensions { /// - /// Register a Pinecone with the specified service ID and where is retrieved from the dependency injection container. + /// Registers a Pinecone , retrieving from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddPineconeVectorStore(this IServiceCollection services, PineconeVectorStoreOptions? options = default, string? serviceId = default) - { + public static IServiceCollection AddPineconeVectorStore( + this IServiceCollection serviceCollection, + PineconeVectorStoreOptions? options = default, // If we are not constructing the PineconeClient, add the IVectorStore as transient, since we // cannot make assumptions about how PineconeClient is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var pineconeClient = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new PineconeVectorStore( - pineconeClient, - selectedOptions); - }); - - return services; + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedPineconeVectorStore(serviceCollection, serviceKey: null, options, lifetime); + + /// + /// Registers a keyed Pinecone , retrieving from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedPineconeVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + PineconeVectorStoreOptions? options = default, + // If we are not constructing the PineconeClient, add the IVectorStore as transient, since we + // cannot make assumptions about how PineconeClient is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new PineconeVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Pinecone with the specified service ID and where is constructed using the provided apikey. + /// Registers a Pinecone using the provided apikey. /// - /// The to register the on. + /// The to which the vector store should be added. /// The api key for Pinecone. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddPineconeVectorStore(this IServiceCollection services, string apiKey, PineconeVectorStoreOptions? options = default, string? serviceId = default) + public static IServiceCollection AddPineconeVectorStore( + this IServiceCollection serviceCollection, + string apiKey, + PineconeVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedPineconeVectorStore(serviceCollection, serviceKey: null, apiKey, options, lifetime); + + /// + /// Registers a keyed Pinecone using the provided apikey. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The api key for Pinecone. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedPineconeVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string apiKey, + PineconeVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var pineconeClient = new Sdk.PineconeClient(apiKey); - var selectedOptions = options ?? sp.GetService(); - - return new PineconeVectorStore( - pineconeClient, - selectedOptions); - }); - - return services; + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new PineconeVectorStore( + new Sdk.PineconeClient(apiKey), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Pinecone and with the - /// specified service ID and where is retrieved from the dependency injection container. + /// Registers a Pinecone and , + /// retrieving from the dependency injection container. /// /// The type of the data model that the collection should contain. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection that this will access. - /// Optional configuration options to pass to the . - /// An optional service id to use as the service key. + /// Configuration options to pass to the . + /// The service lifetime for the client. Defaults to . /// The service collection. public static IServiceCollection AddPineconeVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, PineconeVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { // If we are not constructing the PineconeClient, add the IVectorStore as transient, since we // cannot make assumptions about how PineconeClient is being managed. - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var pineconeClient = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return new PineconeVectorStoreRecordCollection( - pineconeClient, + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedPineconeVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); + + /// + /// Registers a keyed Pinecone and , + /// retrieving from the dependency injection container. + /// + /// The type of the data model that the collection should contain. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection that this will access. + /// Configuration options to pass to the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedPineconeVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + PineconeVectorStoreRecordCollectionOptions? options = default, + // If we are not constructing the PineconeClient, add the IVectorStore as transient, since we + // cannot make assumptions about how PineconeClient is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new PineconeVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), collectionName, - selectedOptions); - }); + options ?? serviceProvider.GetService>()), + lifetime)); - AddVectorizedSearch(services, serviceId); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - return services; + return serviceCollection; } /// - /// Register a Pinecone and with the - /// provided and the specified service ID. + /// Registers a Pinecone and , + /// using the provided apikey. /// /// The type of the data model that the collection should contain. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection that this will access. /// The api key for Pinecone. - /// Optional configuration options to pass to the . - /// An optional service id to use as the service key. + /// Configuration options to pass to the . + /// The service lifetime for the client. Defaults to . /// The service collection. public static IServiceCollection AddPineconeVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string apiKey, PineconeVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var pineconeClient = new Sdk.PineconeClient(apiKey); - var selectedOptions = options ?? sp.GetService>(); - - return new PineconeVectorStoreRecordCollection( - pineconeClient, - collectionName, - selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedPineconeVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, apiKey, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed Pinecone and , + /// using the provided apikey. /// /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection that this will access. + /// The api key for Pinecone. + /// Configuration options to pass to the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedPineconeVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string apiKey, + PineconeVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new PineconeVectorStoreRecordCollection( + new Sdk.PineconeClient(apiKey), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresServiceCollectionExtensions.cs index 983b8e7db443..236dcc698761 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Postgres/PostgresServiceCollectionExtensions.cs @@ -13,160 +13,234 @@ namespace Microsoft.SemanticKernel; public static class PostgresServiceCollectionExtensions { /// - /// Register a Postgres with the specified service ID and where the NpgsqlDataSource is retrieved from the dependency injection container. + /// Registers a Postgres , retrieving the from the dependency injection container. /// - /// The to register the on. + /// The to which the vector store should be added. /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddPostgresVectorStore(this IServiceCollection services, PostgresVectorStoreOptions? options = default, string? serviceId = default) - { + public static IServiceCollection AddPostgresVectorStore( + this IServiceCollection serviceCollection, + PostgresVectorStoreOptions? options = default, // Since we are not constructing the data source, add the IVectorStore as transient, since we // cannot make assumptions about how data source is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var dataSource = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new PostgresVectorStore( - dataSource, - selectedOptions); - }); - - return services; + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedPostgresVectorStore(serviceCollection, serviceKey: null, options, lifetime); + + /// + /// Register a keyed Postgres , retrieving the from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Optional options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedPostgresVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + PostgresVectorStoreOptions? options = default, + // Since we are not constructing the data source, add the IVectorStore as transient, since we + // cannot make assumptions about how data source is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new PostgresVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Postgres with the specified service ID and where an NpgsqlDataSource is constructed using the provided parameters. + /// Registers a Postgres using the provided parameters. + /// + /// The to which the vector store should be added. + /// Postgres database connection string. + /// Optional options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddPostgresVectorStore( + this IServiceCollection serviceCollection, + string connectionString, + PostgresVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedPostgresVectorStore(serviceCollection, serviceKey: null, connectionString, options, lifetime); + + /// + /// Registers a keyed Postgres using the provided parameters. /// - /// The to register the on. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. /// Postgres database connection string. /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddPostgresVectorStore(this IServiceCollection services, string connectionString, PostgresVectorStoreOptions? options = default, string? serviceId = default) + public static IServiceCollection AddKeyedPostgresVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string connectionString, + PostgresVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - string? npgsqlServiceId = serviceId == null ? default : $"{serviceId}_NpgsqlDataSource"; // Register NpgsqlDataSource to ensure proper disposal. - services.AddKeyedSingleton( - npgsqlServiceId, - (sp, obj) => - { - NpgsqlDataSourceBuilder dataSourceBuilder = new(connectionString); - dataSourceBuilder.UseVector(); - return dataSourceBuilder.Build(); - }); - - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var dataSource = sp.GetRequiredKeyedService(npgsqlServiceId); - var selectedOptions = options ?? sp.GetService(); - - return new PostgresVectorStore( - dataSource, - selectedOptions); - }); - - return services; + serviceCollection.Add( + new ServiceDescriptor( + typeof(NpgsqlDataSource), + serviceKey, + (_, _) => + { + NpgsqlDataSourceBuilder dataSourceBuilder = new(connectionString); + dataSourceBuilder.UseVector(); + return dataSourceBuilder.Build(); + }, + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new PostgresVectorStore( + serviceProvider.GetRequiredKeyedService(serviceKey), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Postgres and with the specified service ID - /// and where the NpgsqlDataSource is retrieved from the dependency injection container. + /// Register a Postgres and , + /// retrieving the from the dependency injection container. /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddPostgresVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, PostgresVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Transient) where TKey : notnull - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var dataSource = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return (new PostgresVectorStoreRecordCollection(dataSource, collectionName, selectedOptions) as IVectorStoreRecordCollection)!; - }); - - AddVectorizedSearch(services, serviceId); + => AddKeyedPostgresVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - return services; + /// + /// Register a keyed Postgres and , + /// retrieving the from the dependency injection container. + /// + /// The type of the key. + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedPostgresVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + PostgresVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + where TKey : notnull + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new PostgresVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } /// - /// Register a Postgres and with the specified service ID - /// and where the NpgsqlDataSource is constructed using the provided parameters. + /// Registers a Postgres and , + /// using the provided parameters. /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Postgres database connection string. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddPostgresVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string connectionString, PostgresVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - where TKey : notnull - { - string? npgsqlServiceId = serviceId == null ? default : $"{serviceId}_NpgsqlDataSource"; - // Register NpgsqlDataSource to ensure proper disposal. - services.AddKeyedSingleton( - npgsqlServiceId, - (sp, obj) => - { - NpgsqlDataSourceBuilder dataSourceBuilder = new(connectionString); - dataSourceBuilder.UseVector(); - return dataSourceBuilder.Build(); - }); - - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var dataSource = sp.GetRequiredKeyedService(npgsqlServiceId); - - return (new PostgresVectorStoreRecordCollection(dataSource, collectionName, options) as IVectorStoreRecordCollection)!; - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Singleton) where TKey : notnull + => AddKeyedPostgresVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, connectionString, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed Postgres and , + /// using the provided parameters. /// /// The type of the key. - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) - where TKey : notnull + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Postgres database connection string. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedPostgresVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string connectionString, + PostgresVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) where TKey : notnull { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + // Register NpgsqlDataSource to ensure proper disposal. + serviceCollection.Add( + new ServiceDescriptor( + typeof(NpgsqlDataSource), + serviceKey, + (_, _) => + { + NpgsqlDataSourceBuilder dataSourceBuilder = new(connectionString); + dataSourceBuilder.UseVector(); + return dataSourceBuilder.Build(); + }, + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new PostgresVectorStoreRecordCollection( + serviceProvider.GetRequiredKeyedService(serviceKey), + collectionName, + options), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantKernelBuilderExtensions.cs index c8dd0b6070b9..d5b176c46a77 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.Qdrant; using Qdrant.Client; @@ -9,6 +10,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Qdrant instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class QdrantKernelBuilderExtensions { /// @@ -20,7 +22,7 @@ public static class QdrantKernelBuilderExtensions /// The kernel builder. public static IKernelBuilder AddQdrantVectorStore(this IKernelBuilder builder, QdrantVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddQdrantVectorStore(options, serviceId); + builder.Services.AddKeyedQdrantVectorStore(serviceId, options); return builder; } /// @@ -36,7 +38,7 @@ public static IKernelBuilder AddQdrantVectorStore(this IKernelBuilder builder, Q /// The kernel builder. public static IKernelBuilder AddQdrantVectorStore(this IKernelBuilder builder, string host, int port = 6334, bool https = false, string? apiKey = default, QdrantVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddQdrantVectorStore(host, port, https, apiKey, options, serviceId); + builder.Services.AddKeyedQdrantVectorStore(serviceId, host, port, https, apiKey, options); return builder; } @@ -58,7 +60,7 @@ public static IKernelBuilder AddQdrantVectorStoreRecordCollection string? serviceId = default) where TKey : notnull { - builder.Services.AddQdrantVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedQdrantVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -88,7 +90,7 @@ public static IKernelBuilder AddQdrantVectorStoreRecordCollection string? serviceId = default) where TKey : notnull { - builder.Services.AddQdrantVectorStoreRecordCollection(collectionName, host, port, https, apiKey, options, serviceId); + builder.Services.AddKeyedQdrantVectorStoreRecordCollection(serviceId, collectionName, host, port, https, apiKey, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantServiceCollectionExtensions.cs index 693d8d94fc3b..a4b084b515d0 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Qdrant/QdrantServiceCollectionExtensions.cs @@ -13,147 +13,231 @@ namespace Microsoft.SemanticKernel; public static class QdrantServiceCollectionExtensions { /// - /// Register a Qdrant with the specified service ID and where is retrieved from the dependency injection container. + /// Registers a Qdrant , retrieving the from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddQdrantVectorStore(this IServiceCollection services, QdrantVectorStoreOptions? options = default, string? serviceId = default) - { + public static IServiceCollection AddQdrantVectorStore( + this IServiceCollection serviceCollection, + QdrantVectorStoreOptions? options = default, // If we are not constructing the QdrantClient, add the IVectorStore as transient, since we // cannot make assumptions about how QdrantClient is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var qdrantClient = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new QdrantVectorStore( - qdrantClient, - selectedOptions); - }); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedQdrantVectorStore(serviceCollection, serviceKey: null, options, lifetime); - return services; + /// + /// Registers a keyed Qdrant , retrieving the from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedQdrantVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + QdrantVectorStoreOptions? options = default, + // If we are not constructing the QdrantClient, add the IVectorStore as transient, since we + // cannot make assumptions about how QdrantClient is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new QdrantVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } + /// - /// Register a Qdrant with the specified service ID and where is constructed using the provided parameters. + /// Registers a Qdrant using the provided parameters. /// - /// The to register the on. + /// The to which the vector store should be added. /// The Qdrant service host name. /// The Qdrant service port. /// A value indicating whether to use HTTPS for communicating with Qdrant. /// The Qdrant service API key. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddQdrantVectorStore(this IServiceCollection services, string host, int port = 6334, bool https = false, string? apiKey = default, QdrantVectorStoreOptions? options = default, string? serviceId = default) - { - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var qdrantClient = new QdrantClient(host, port, https, apiKey); - var selectedOptions = options ?? sp.GetService(); - - return new QdrantVectorStore( - qdrantClient, - selectedOptions); - }); + public static IServiceCollection AddQdrantVectorStore( + this IServiceCollection serviceCollection, + string host, + int port = 6334, + bool https = false, + string? apiKey = default, + QdrantVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedQdrantVectorStore(serviceCollection, serviceKey: null, host, port, https, apiKey, options, lifetime); - return services; + /// + /// Registers a keyed Qdrant using the provided parameters. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The Qdrant service host name. + /// The Qdrant service port. + /// A value indicating whether to use HTTPS for communicating with Qdrant. + /// The Qdrant service API key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedQdrantVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string host, + int port = 6334, + bool https = false, + string? apiKey = default, + QdrantVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new QdrantVectorStore( + new QdrantClient(host, port, https, apiKey), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Qdrant and with the specified service ID - /// and where the Qdrant is retrieved from the dependency injection container. + /// Registers a Qdrant and , + /// retrieving the from the dependency injection container. /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddQdrantVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, QdrantVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Transient) where TKey : notnull - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var qdrantClient = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); - - return (new QdrantVectorStoreRecordCollection(qdrantClient, collectionName, selectedOptions) as IVectorStoreRecordCollection)!; - }); - - AddVectorizedSearch(services, serviceId); + => AddKeyedQdrantVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - return services; + /// + /// Registers a keyed Qdrant and , + /// retrieving the from the dependency injection container. + /// + /// The type of the key. + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Optional options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedQdrantVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + QdrantVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + where TKey : notnull + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new QdrantVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + return serviceCollection; } /// - /// Register a Qdrant and with the specified service ID - /// and where the Qdrant is constructed using the provided parameters. + /// Registers a Qdrant and , using the provided parameters. /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// The Qdrant service host name. /// The Qdrant service port. /// A value indicating whether to use HTTPS for communicating with Qdrant. /// The Qdrant service API key. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddQdrantVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string host, int port = 6334, bool https = false, string? apiKey = default, QdrantVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Singleton) where TKey : notnull - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var qdrantClient = new QdrantClient(host, port, https, apiKey); - var selectedOptions = options ?? sp.GetService>(); - - return (new QdrantVectorStoreRecordCollection(qdrantClient, collectionName, selectedOptions) as IVectorStoreRecordCollection)!; - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + => AddKeyedQdrantVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, host, port, https, apiKey, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed Qdrant and , using the provided parameters. /// /// The type of the key. - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// The Qdrant service host name. + /// The Qdrant service port. + /// A value indicating whether to use HTTPS for communicating with Qdrant. + /// The Qdrant service API key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedQdrantVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string host, + int port = 6334, + bool https = false, + string? apiKey = default, + QdrantVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) where TKey : notnull { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new QdrantVectorStoreRecordCollection( + new QdrantClient(host, port, https, apiKey), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisKernelBuilderExtensions.cs index 1f7ed194856f..b57ad737ec8a 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.Redis; using StackExchange.Redis; @@ -9,6 +10,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Redis instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class RedisKernelBuilderExtensions { /// @@ -20,7 +22,7 @@ public static class RedisKernelBuilderExtensions /// The kernel builder. public static IKernelBuilder AddRedisVectorStore(this IKernelBuilder builder, RedisVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddRedisVectorStore(options, serviceId); + builder.Services.AddKeyedRedisVectorStore(serviceId, options); return builder; } @@ -34,7 +36,7 @@ public static IKernelBuilder AddRedisVectorStore(this IKernelBuilder builder, Re /// The kernel builder. public static IKernelBuilder AddRedisVectorStore(this IKernelBuilder builder, string redisConnectionConfiguration, RedisVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddRedisVectorStore(redisConnectionConfiguration, options, serviceId); + builder.Services.AddKeyedRedisVectorStore(serviceId, redisConnectionConfiguration, options); return builder; } @@ -54,7 +56,7 @@ public static IKernelBuilder AddRedisHashSetVectorStoreRecordCollection RedisHashSetVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddRedisHashSetVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedRedisHashSetVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -76,7 +78,7 @@ public static IKernelBuilder AddRedisHashSetVectorStoreRecordCollection RedisHashSetVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddRedisHashSetVectorStoreRecordCollection(collectionName, redisConnectionConfiguration, options, serviceId); + builder.Services.AddKeyedRedisHashSetVectorStoreRecordCollection(serviceId, collectionName, redisConnectionConfiguration, options); return builder; } @@ -96,7 +98,7 @@ public static IKernelBuilder AddRedisJsonVectorStoreRecordCollection( RedisJsonVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddRedisJsonVectorStoreRecordCollection(collectionName, options, serviceId); + builder.Services.AddKeyedRedisJsonVectorStoreRecordCollection(serviceId, collectionName, options); return builder; } @@ -118,7 +120,7 @@ public static IKernelBuilder AddRedisJsonVectorStoreRecordCollection( RedisJsonVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddRedisJsonVectorStoreRecordCollection(collectionName, redisConnectionConfiguration, options, serviceId); + builder.Services.AddKeyedRedisJsonVectorStoreRecordCollection(serviceId, collectionName, redisConnectionConfiguration, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisServiceCollectionExtensions.cs index 778c1e75a88a..89861562cdbf 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Redis/RedisServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Redis/RedisServiceCollectionExtensions.cs @@ -13,199 +13,312 @@ namespace Microsoft.SemanticKernel; public static class RedisServiceCollectionExtensions { /// - /// Register a Redis with the specified service ID and where the Redis is retrieved from the dependency injection container. + /// Registers a Redis , retrieving the Redis from the dependency injection container. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddRedisVectorStore(this IServiceCollection services, RedisVectorStoreOptions? options = default, string? serviceId = default) - { + public static IServiceCollection AddRedisVectorStore( + this IServiceCollection serviceCollection, + RedisVectorStoreOptions? options = default, + // If we are not constructing the ConnectionMultiplexer, add the IVectorStore as transient, since we + // cannot make assumptions about how IDatabase is being managed. + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedRedisVectorStore(serviceCollection, serviceKey: null, options, lifetime); + + /// + /// Registers a keyed Redis , retrieving the Redis from the dependency injection container. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedRedisVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + RedisVectorStoreOptions? options = default, // If we are not constructing the ConnectionMultiplexer, add the IVectorStore as transient, since we // cannot make assumptions about how IDatabase is being managed. - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); - - return new RedisVectorStore( - database, - selectedOptions); - }); - - return services; + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new RedisVectorStore( + serviceProvider.GetRequiredService(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Redis with the specified service ID and where the Redis is constructed using the provided . + /// Registers a Redis , using the provided . /// - /// The to register the on. + /// The to which the vector store should be added. /// The Redis connection configuration string. If not provided, an instance will be requested from the dependency injection container. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// The service collection. - public static IServiceCollection AddRedisVectorStore(this IServiceCollection services, string redisConnectionConfiguration, RedisVectorStoreOptions? options = default, string? serviceId = default) - { + public static IServiceCollection AddRedisVectorStore( + this IServiceCollection serviceCollection, + string redisConnectionConfiguration, + RedisVectorStoreOptions? options = default, + // If we are constructing the ConnectionMultiplexer, add the IVectorStore as singleton, since we are managing the lifetime + // of the ConnectionMultiplexer, and the recommendation from StackExchange.Redis is to share the ConnectionMultiplexer. + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedRedisVectorStore(serviceCollection, serviceKey: null, redisConnectionConfiguration, options, lifetime); + + /// + /// Registers a keyed Redis , using the provided . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The Redis connection configuration string. If not provided, an instance will be requested from the dependency injection container. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// The service collection. + public static IServiceCollection AddKeyedRedisVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string redisConnectionConfiguration, + RedisVectorStoreOptions? options = default, // If we are constructing the ConnectionMultiplexer, add the IVectorStore as singleton, since we are managing the lifetime // of the ConnectionMultiplexer, and the recommendation from StackExchange.Redis is to share the ConnectionMultiplexer. - services.AddKeyedSingleton( - serviceId, - (sp, obj) => - { - var database = ConnectionMultiplexer.Connect(redisConnectionConfiguration).GetDatabase(); - var selectedOptions = options ?? sp.GetService(); - - return new RedisVectorStore( - database, - selectedOptions); - }); - - return services; + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new RedisVectorStore( + ConnectionMultiplexer.Connect(redisConnectionConfiguration).GetDatabase(), + options ?? serviceProvider.GetService()), + lifetime)); + + return serviceCollection; } /// - /// Register a Redis with the specified service ID - /// and where the Redis is retrieved from the dependency injection container. + /// Registers a Redis , retrieving the Redis is retrieved from the dependency injection container. /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddRedisHashSetVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, RedisHashSetVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedRedisHashSetVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - return new RedisHashSetVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); + /// + /// Registers a keyed Redis , retrieving the Redis is retrieved from the dependency injection container. + /// + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedRedisHashSetVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + RedisHashSetVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new RedisHashSetVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); - AddVectorizedSearch(services, serviceId); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - return services; + return serviceCollection; } /// - /// Register a Redis with the specified service ID - /// and where the Redis is constructed using the provided . + /// Registers a Redis , using the provided . /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// The Redis connection configuration string. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddRedisHashSetVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string redisConnectionConfiguration, RedisHashSetVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var database = ConnectionMultiplexer.Connect(redisConnectionConfiguration).GetDatabase(); - var selectedOptions = options ?? sp.GetService>(); + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedRedisHashSetVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, redisConnectionConfiguration, options, lifetime); - return new RedisHashSetVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); + /// + /// Registers a keyed Redis , using the provided . + /// + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// The Redis connection configuration string. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedRedisHashSetVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string redisConnectionConfiguration, + RedisHashSetVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new RedisHashSetVectorStoreRecordCollection( + ConnectionMultiplexer.Connect(redisConnectionConfiguration).GetDatabase(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); - AddVectorizedSearch(services, serviceId); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - return services; + return serviceCollection; } /// - /// Register a Redis with the specified service ID - /// and where the Redis is retrieved from the dependency injection container. + /// Registers a Redis , retrieving the Redis is retrieved from the dependency injection container. /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddRedisJsonVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, RedisJsonVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var database = sp.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedRedisJsonVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - return new RedisJsonVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); + /// + /// Registers a keyed Redis , retrieving the Redis is retrieved from the dependency injection container. + /// + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedRedisJsonVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + RedisJsonVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new RedisJsonVectorStoreRecordCollection( + serviceProvider.GetRequiredService(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); - AddVectorizedSearch(services, serviceId); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - return services; + return serviceCollection; } /// - /// Register a Redis with the specified service ID - /// and where the Redis is constructed using the provided . + /// Registers a Redis using the provided . /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// The Redis connection configuration string. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddRedisJsonVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string redisConnectionConfiguration, RedisJsonVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedSingleton>( - serviceId, - (sp, obj) => - { - var database = ConnectionMultiplexer.Connect(redisConnectionConfiguration).GetDatabase(); - var selectedOptions = options ?? sp.GetService>(); - - return new RedisJsonVectorStoreRecordCollection(database, collectionName, selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Singleton) + => AddKeyedRedisJsonVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, redisConnectionConfiguration, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed Redis using the provided . /// - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// The Redis connection configuration string. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedRedisJsonVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string redisConnectionConfiguration, + RedisJsonVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Singleton) { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new RedisJsonVectorStoreRecordCollection( + ConnectionMultiplexer.Connect(redisConnectionConfiguration).GetDatabase(), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteServiceCollectionExtensions.cs index 9c962c0786d5..7df7591bd38d 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Sqlite/SqliteServiceCollectionExtensions.cs @@ -14,175 +14,248 @@ namespace Microsoft.SemanticKernel; public static class SqliteServiceCollectionExtensions { /// - /// Register a SQLite with the specified service ID - /// and where the SQLite is retrieved from the dependency injection container. + /// Registers a SQLite , retrieving the SQLite from the dependency injection container. /// In this case vector search extension loading should be handled manually. /// - /// The to register the on. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// The to which the vector store should be added. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddSqliteVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, SqliteVectorStoreOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var connection = sp.GetRequiredService(); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedSqliteVectorStore(serviceCollection, serviceKey: null, options, lifetime); - if (connection.State != ConnectionState.Open) + /// + /// Registers a keyed SQLite , retrieving the SQLite from the dependency injection container. + /// In this case vector search extension loading should be handled manually. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedSqliteVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + SqliteVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => { - connection.Open(); - } + var connection = serviceProvider.GetRequiredService(); - var selectedOptions = options ?? sp.GetService(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } - return new SqliteVectorStore(connection, options); - }); + return new SqliteVectorStore(connection, options ?? serviceProvider.GetService()); + }, + lifetime)); - return services; + return serviceCollection; } /// - /// Register a SQLite with the specified service ID. - /// instance will be initialized, connection will be opened and vector search extension with be loaded. + /// Registers a SQLite , using the specified connection string. /// - /// The to register the on. + /// The to which the vector store should be added. /// Connection string for . - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddSqliteVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, string connectionString, SqliteVectorStoreOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var connection = new SqliteConnection(connectionString); - var extensionName = GetExtensionName(options?.VectorSearchExtensionName); + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedSqliteVectorStore(serviceCollection, serviceKey: null, connectionString, options, lifetime); - connection.Open(); + /// + /// Registers a keyed SQLite , using the specified connection string. + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// Connection string for . + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedSqliteVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + string connectionString, + SqliteVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => + { + var connection = new SqliteConnection(connectionString); + var extensionName = GetExtensionName(options?.VectorSearchExtensionName); - connection.LoadExtension(extensionName); + connection.Open(); + connection.LoadExtension(extensionName); - var selectedOptions = options ?? sp.GetService(); - return new SqliteVectorStore(connection, options); - }); + return new SqliteVectorStore(connection, options ?? serviceProvider.GetService()); + }, + lifetime)); - return services; + return serviceCollection; } /// - /// Register a SQLite and with the specified service ID - /// and where the SQLite is retrieved from the dependency injection container. + /// Registers a SQLite and , + /// retrieving the from the dependency injection container. /// In this case vector search extension loading should be handled manually. /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddSqliteVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, SqliteVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Transient) where TKey : notnull - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var connection = sp.GetRequiredService(); + => AddKeyedSqliteVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, options, lifetime); - if (connection.State != ConnectionState.Open) + /// + /// Registers a keyed SQLite and , + /// retrieving the from the dependency injection container. + /// In this case vector search extension loading should be handled manually. + /// + /// The type of the key. + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedSqliteVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + SqliteVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) + where TKey : notnull + { + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => { - connection.Open(); - } + var connection = serviceProvider.GetRequiredService(); - var selectedOptions = options ?? sp.GetService>(); + if (connection.State != ConnectionState.Open) + { + connection.Open(); + } - return (new SqliteVectorStoreRecordCollection(connection, collectionName, selectedOptions) as IVectorStoreRecordCollection)!; - }); + return new SqliteVectorStoreRecordCollection( + connection, + collectionName, + options ?? serviceProvider.GetService>()); + }, + lifetime)); - AddVectorizedSearch(services, serviceId); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); - return services; + return serviceCollection; } /// - /// Register a SQLite and with the specified service ID. - /// instance will be initialized, connection will be opened and vector search extension with be loaded. + /// Registers a SQLite and usihng the provided connection string/ /// /// The type of the key. /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// Connection string for . - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddSqliteVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, string connectionString, SqliteVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Transient) where TKey : notnull - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var connection = new SqliteConnection(connectionString); - var extensionName = GetExtensionName(options?.VectorSearchExtensionName); - - connection.Open(); - - connection.LoadExtension(extensionName); - - var selectedOptions = options ?? sp.GetService>(); - - return (new SqliteVectorStoreRecordCollection(connection, collectionName, selectedOptions) as IVectorStoreRecordCollection)!; - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + => AddKeyedSqliteVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, connectionString, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed SQLite and usihng the provided connection string/ /// /// The type of the key. - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// Connection string for . + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedSqliteVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + string connectionString, + SqliteVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) where TKey : notnull { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => + { + var connection = new SqliteConnection(connectionString); + var extensionName = GetExtensionName(options?.VectorSearchExtensionName); + + connection.Open(); + connection.LoadExtension(extensionName); + + return new SqliteVectorStoreRecordCollection( + connection, + collectionName, + options ?? serviceProvider.GetService>()); + }, + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } /// /// Returns extension name for vector search. /// private static string GetExtensionName(string? extensionName) - { - return !string.IsNullOrWhiteSpace(extensionName) ? extensionName! : SqliteConstants.VectorSearchExtensionName; - } + => !string.IsNullOrWhiteSpace(extensionName) ? extensionName! : SqliteConstants.VectorSearchExtensionName; } diff --git a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateKernelBuilderExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateKernelBuilderExtensions.cs index 45c320df959c..6183455d358a 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateKernelBuilderExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateKernelBuilderExtensions.cs @@ -1,5 +1,6 @@ // Copyright (c) Microsoft. All rights reserved. +using System; using System.Net.Http; using Microsoft.Extensions.VectorData; using Microsoft.SemanticKernel.Connectors.Weaviate; @@ -9,6 +10,7 @@ namespace Microsoft.SemanticKernel; /// /// Extension methods to register Weaviate instances on the . /// +[Obsolete("Call the corresponding method on the Services property of your IKernelBuilder instance.")] public static class WeaviateKernelBuilderExtensions { /// @@ -29,7 +31,7 @@ public static IKernelBuilder AddWeaviateVectorStore( WeaviateVectorStoreOptions? options = default, string? serviceId = default) { - builder.Services.AddWeaviateVectorStore(httpClient, options, serviceId); + builder.Services.AddKeyedWeaviateVectorStore(serviceId, httpClient, options); return builder; } @@ -54,7 +56,7 @@ public static IKernelBuilder AddWeaviateVectorStoreRecordCollection( WeaviateVectorStoreRecordCollectionOptions? options = default, string? serviceId = default) { - builder.Services.AddWeaviateVectorStoreRecordCollection(collectionName, httpClient, options, serviceId); + builder.Services.AddKeyedWeaviateVectorStoreRecordCollection(serviceId, collectionName, httpClient, options); return builder; } } diff --git a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateServiceCollectionExtensions.cs b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateServiceCollectionExtensions.cs index 7f6dfe48a404..9d080a183775 100644 --- a/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateServiceCollectionExtensions.cs +++ b/dotnet/src/Connectors/Connectors.Memory.Weaviate/WeaviateServiceCollectionExtensions.cs @@ -15,84 +15,118 @@ namespace Microsoft.SemanticKernel; public static class WeaviateServiceCollectionExtensions { /// - /// Register a Weaviate with the specified service ID. + /// Registers a Weaviate . /// - /// The to register the on. + /// The to which the vector store should be added. /// /// that is used to interact with Weaviate API. /// should point to remote or local cluster and API key can be configured via . /// It's also possible to provide these parameters via . /// - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddWeaviateVectorStore( - this IServiceCollection services, + this IServiceCollection serviceCollection, HttpClient? httpClient = default, WeaviateVectorStoreOptions? options = default, - string? serviceId = default) + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedWeaviateVectorStore(serviceCollection, serviceKey: null, httpClient, options, lifetime); + + /// + /// Registers a keyed Weaviate . + /// + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// + /// that is used to interact with Weaviate API. + /// should point to remote or local cluster and API key can be configured via . + /// It's also possible to provide these parameters via . + /// + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedWeaviateVectorStore( + this IServiceCollection serviceCollection, + object? serviceKey, + HttpClient? httpClient = default, + WeaviateVectorStoreOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) { - services.AddKeyedTransient( - serviceId, - (sp, obj) => - { - var selectedHttpClient = HttpClientProvider.GetHttpClient(httpClient, sp); - var selectedOptions = options ?? sp.GetService(); - return new WeaviateVectorStore(selectedHttpClient, options); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStore), + serviceKey, + (serviceProvider, _) => new WeaviateVectorStore( + HttpClientProvider.GetHttpClient(httpClient, serviceProvider), + options ?? serviceProvider.GetService()), + lifetime)); - return services; + return serviceCollection; } /// - /// Register a Weaviate and with the specified service ID. + /// Registers a Weaviate and . /// /// The type of the record. - /// The to register the on. + /// The to which the vector store should be added. /// The name of the collection. /// /// that is used to interact with Weaviate API. /// should point to remote or local cluster and API key can be configured via . /// It's also possible to provide these parameters via . /// - /// Optional options to further configure the . - /// An optional service id to use as the service key. + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . /// Service collection. public static IServiceCollection AddWeaviateVectorStoreRecordCollection( - this IServiceCollection services, + this IServiceCollection serviceCollection, string collectionName, HttpClient? httpClient = default, WeaviateVectorStoreRecordCollectionOptions? options = default, - string? serviceId = default) - { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - var selectedHttpClient = HttpClientProvider.GetHttpClient(httpClient, sp); - var selectedOptions = options ?? sp.GetService>(); - - return new WeaviateVectorStoreRecordCollection(selectedHttpClient, collectionName, selectedOptions); - }); - - AddVectorizedSearch(services, serviceId); - - return services; - } + ServiceLifetime lifetime = ServiceLifetime.Transient) + => AddKeyedWeaviateVectorStoreRecordCollection(serviceCollection, serviceKey: null, collectionName, httpClient, options, lifetime); /// - /// Also register the with the given as a . + /// Registers a keyed Weaviate and . /// - /// The type of the data model that the collection should contain. - /// The service collection to register on. - /// The service id that the registrations should use. - private static void AddVectorizedSearch(IServiceCollection services, string? serviceId) + /// The type of the record. + /// The to which the vector store should be added. + /// The key with which to associate the vector store. + /// The name of the collection. + /// + /// that is used to interact with Weaviate API. + /// should point to remote or local cluster and API key can be configured via . + /// It's also possible to provide these parameters via . + /// + /// Options to further configure the . + /// The service lifetime for the client. Defaults to . + /// Service collection. + public static IServiceCollection AddKeyedWeaviateVectorStoreRecordCollection( + this IServiceCollection serviceCollection, + object? serviceKey, + string collectionName, + HttpClient? httpClient = default, + WeaviateVectorStoreRecordCollectionOptions? options = default, + ServiceLifetime lifetime = ServiceLifetime.Transient) { - services.AddKeyedTransient>( - serviceId, - (sp, obj) => - { - return sp.GetRequiredKeyedService>(serviceId); - }); + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorStoreRecordCollection), + serviceKey, + (serviceProvider, _) => new WeaviateVectorStoreRecordCollection( + HttpClientProvider.GetHttpClient(httpClient, serviceProvider), + collectionName, + options ?? serviceProvider.GetService>()), + lifetime)); + + serviceCollection.Add( + new ServiceDescriptor( + typeof(IVectorizedSearch), + serviceKey, + static (serviceProvider, serviceKey) => serviceProvider.GetRequiredKeyedService>(serviceKey), + lifetime)); + + return serviceCollection; } }