diff --git a/dotnet/Directory.Packages.props b/dotnet/Directory.Packages.props
index f4a51a045a48..82fe6178c515 100644
--- a/dotnet/Directory.Packages.props
+++ b/dotnet/Directory.Packages.props
@@ -189,6 +189,7 @@
+
diff --git a/dotnet/samples/Concepts/Concepts.csproj b/dotnet/samples/Concepts/Concepts.csproj
index 9633d7893ff9..c9535ba8898d 100644
--- a/dotnet/samples/Concepts/Concepts.csproj
+++ b/dotnet/samples/Concepts/Concepts.csproj
@@ -53,6 +53,7 @@
+
diff --git a/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs
new file mode 100644
index 000000000000..feb195663838
--- /dev/null
+++ b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreChromaContainerFixture.cs
@@ -0,0 +1,56 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using ChromaDB.Client;
+using Docker.DotNet;
+
+namespace Memory.VectorStoreFixtures;
+
+///
+/// Fixture to use for creating a Chroma container before tests and delete it after tests.
+///
+public class VectorStoreChromaContainerFixture : IAsyncLifetime
+{
+ private DockerClient? _dockerClient;
+ private string? _chromaContainerId;
+
+ public async Task InitializeAsync()
+ {
+ }
+
+ public async Task ManualInitializeAsync()
+ {
+ if (this._chromaContainerId == null)
+ {
+ // Connect to docker and start the docker container.
+ using var dockerClientConfiguration = new DockerClientConfiguration();
+ this._dockerClient = dockerClientConfiguration.CreateClient();
+ this._chromaContainerId = await VectorStoreInfra.SetupChromaContainerAsync(this._dockerClient);
+
+ // Delay until the Chroma server is ready.
+ var chromaClient = new ChromaClient("http://localhost:8000");
+ var succeeded = false;
+ var attemptCount = 0;
+ while (!succeeded && attemptCount++ < 10)
+ {
+ try
+ {
+ await chromaClient.ListCollectionsAsync();
+ succeeded = true;
+ }
+ catch (Exception)
+ {
+ await Task.Delay(1000);
+ }
+ }
+ }
+ }
+
+ public async Task DisposeAsync()
+ {
+ if (this._dockerClient != null && this._chromaContainerId != null)
+ {
+ // Delete docker container.
+ await VectorStoreInfra.DeleteContainerAsync(this._dockerClient, this._chromaContainerId);
+ }
+ }
+}
diff --git a/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs
index 77c5e8a55db9..767e7d2de956 100644
--- a/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStoreFixtures/VectorStoreInfra.cs
@@ -10,6 +10,46 @@ namespace Memory.VectorStoreFixtures;
///
internal static class VectorStoreInfra
{
+ ///
+ /// Setup the chroma container by pulling the image and running it.
+ ///
+ /// The docker client to create the container with.
+ /// The id of the container.
+ public static async Task SetupChromaContainerAsync(DockerClient client)
+ {
+ await client.Images.CreateImageAsync(
+ new ImagesCreateParameters
+ {
+ FromImage = "chromadb/chroma",
+ Tag = "latest",
+ },
+ null,
+ new Progress());
+
+ var container = await client.Containers.CreateContainerAsync(new CreateContainerParameters()
+ {
+ Image = "chromadb/chroma",
+ HostConfig = new HostConfig()
+ {
+ PortBindings = new Dictionary>
+ {
+ {"8000", new List {new() {HostPort = "8000" } }},
+ },
+ PublishAllPorts = true
+ },
+ ExposedPorts = new Dictionary
+ {
+ { "8000", default },
+ },
+ });
+
+ await client.Containers.StartContainerAsync(
+ container.ID,
+ new ContainerStartParameters());
+
+ return container.ID;
+ }
+
///
/// Setup the postgres pgvector container by pulling the image and running it.
///
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs
index 81cd303017d6..fe565d333a5b 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_AzureAISearch.cs
@@ -22,6 +22,7 @@ namespace Memory;
///
///
///
+///
///
/// To run this sample, you need an already existing Azure AI Search instance.
/// To set your secrets use:
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs
new file mode 100644
index 000000000000..826b63230d8b
--- /dev/null
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Chroma.cs
@@ -0,0 +1,86 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using Azure.AI.OpenAI;
+using Azure.Identity;
+using ChromaDB.Client;
+using CommunityToolkit.VectorData.Chroma;
+using Memory.VectorStoreFixtures;
+using Microsoft.Extensions.AI;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.SemanticKernel;
+
+namespace Memory;
+
+///
+/// An example showing how to use common code, that can work with any vector database, with a Chroma database.
+/// The common code is in the class.
+/// The common code ingests data into the vector store and then searches over that data.
+/// This example is part of a set of examples each showing a different vector database.
+///
+/// For other databases, see the following classes:
+///
+///
+///
+///
+///
+///
+/// To run this sample, you need a local instance of Docker running, since the associated fixture will try and start a Chroma container in the local docker instance.
+///
+public class VectorStore_VectorSearch_MultiStore_Chroma(ITestOutputHelper output, VectorStoreChromaContainerFixture chromaFixture) : BaseTest(output), IClassFixture
+{
+ [Fact]
+ public async Task ExampleWithDIAsync()
+ {
+ // Use the kernel for DI purposes.
+ var kernelBuilder = Kernel
+ .CreateBuilder();
+
+ // Register an embedding generation service with the DI container.
+ kernelBuilder.AddAzureOpenAIEmbeddingGenerator(
+ deploymentName: TestConfiguration.AzureOpenAIEmbeddings.DeploymentName,
+ endpoint: TestConfiguration.AzureOpenAIEmbeddings.Endpoint,
+ credential: new AzureCliCredential(),
+ dimensions: 1536);
+
+ // Initialize the Chroma docker container via the fixtures and register the Chroma VectorStore.
+ await chromaFixture.ManualInitializeAsync();
+ kernelBuilder.Services.AddChromaVectorStore("http://localhost:8000");
+
+ // Register the test output helper common processor with the DI container.
+ kernelBuilder.Services.AddSingleton(this.Output);
+ kernelBuilder.Services.AddTransient();
+
+ // Build the kernel.
+ var kernel = kernelBuilder.Build();
+
+ // Build a common processor object using the DI container.
+ var processor = kernel.GetRequiredService();
+
+ // Run the process and pass a key generator function to it, to generate unique record keys.
+ // The key generator function is required, since different vector stores may require different key types.
+ // E.g. Chroma supports Guid and string keys, but others may not support Guid.
+ await processor.IngestDataAndSearchAsync("skglossaryWithDI", () => Guid.NewGuid());
+ }
+
+ [Fact]
+ public async Task ExampleWithoutDIAsync()
+ {
+ // Create an embedding generation service.
+ var embeddingGenerator = new AzureOpenAIClient(new Uri(TestConfiguration.AzureOpenAIEmbeddings.Endpoint), new AzureCliCredential())
+ .GetEmbeddingClient(TestConfiguration.AzureOpenAIEmbeddings.DeploymentName)
+ .AsIEmbeddingGenerator(1536);
+
+ // Initialize the Chroma docker container via the fixtures and construct the Chroma VectorStore.
+ await chromaFixture.ManualInitializeAsync();
+ var chromaClient = new ChromaClient("http://localhost:8000");
+ var vectorStore = new ChromaVectorStore(chromaClient, ownsClient: true);
+
+ // Create the common processor that works for any vector store.
+ var processor = new VectorStore_VectorSearch_MultiStore_Common(vectorStore, embeddingGenerator, this.Output);
+
+ // Run the process and pass a key generator function to it, to generate unique record keys.
+ // The key generator function is required, since different vector stores may require different key types.
+ // E.g. Chroma supports Guid and string keys, but others may not support Guid.
+ await processor.IngestDataAndSearchAsync("skglossaryWithoutDI", () => Guid.NewGuid());
+ }
+}
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs
index cf92aa577e3d..54d9be374856 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Common.cs
@@ -16,6 +16,7 @@ namespace Memory;
///
///
///
+///
///
/// The vector store to ingest data into.
/// The service to use for generating embeddings.
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs
index f88f893c489d..116dbb29c505 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_InMemory.cs
@@ -20,6 +20,7 @@ namespace Memory;
///
///
///
+///
///
public class VectorStore_VectorSearch_MultiStore_InMemory(ITestOutputHelper output) : BaseTest(output)
{
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs
index 3995ba486c87..0b6377fa6bde 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Postgres.cs
@@ -21,6 +21,7 @@ namespace Memory;
///
///
///
+///
///
/// To run this sample, you need a local instance of Docker running, since the associated fixture will try and start a Postgres container in the local docker instance.
///
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs
index 3640c4ba7330..e97fe9a11534 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Qdrant.cs
@@ -22,6 +22,7 @@ namespace Memory;
///
///
///
+///
///
/// To run this sample, you need a local instance of Docker running, since the associated fixture will try and start a Qdrant container in the local docker instance.
///
diff --git a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs
index ae8e2e1d2bab..ab2f42c12819 100644
--- a/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs
+++ b/dotnet/samples/Concepts/Memory/VectorStore_VectorSearch_MultiStore_Redis.cs
@@ -22,6 +22,7 @@ namespace Memory;
///
///
///
+///
///
/// Redis supports two record storage types: Json and HashSet.
/// Note the use of the enum to specify the preferred storage type.
diff --git a/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs b/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs
index 3b9658419ecd..f3ad10e9a7b1 100644
--- a/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs
+++ b/dotnet/samples/Demos/VectorStoreRAG/Options/ApplicationConfig.cs
@@ -16,6 +16,7 @@ internal sealed class ApplicationConfig
private readonly RagConfig _ragConfig = new();
private readonly AzureAISearchConfig _azureAISearchConfig = new();
private readonly CosmosConfig _azureDocumentDBConfig = new();
+ private readonly ChromaConfig _chromaConfig = new();
private readonly CosmosConfig _cosmosNoSqlConfig = new();
private readonly QdrantConfig _qdrantConfig = new();
private readonly RedisConfig _redisConfig = new();
@@ -45,6 +46,9 @@ public ApplicationConfig(ConfigurationManager configurationManager)
configurationManager
.GetRequiredSection($"VectorStores:{CosmosConfig.DocumentDBConfigSectionName}")
.Bind(this._azureDocumentDBConfig);
+ configurationManager
+ .GetRequiredSection($"VectorStores:{ChromaConfig.ConfigSectionName}")
+ .Bind(this._chromaConfig);
configurationManager
.GetRequiredSection($"VectorStores:{CosmosConfig.NoSqlConfigSectionName}")
.Bind(this._cosmosNoSqlConfig);
@@ -73,6 +77,8 @@ public ApplicationConfig(ConfigurationManager configurationManager)
public CosmosConfig AzureDocumentDBConfig => this._azureDocumentDBConfig;
+ public ChromaConfig ChromaConfig => this._chromaConfig;
+
public CosmosConfig CosmosNoSqlConfig => this._cosmosNoSqlConfig;
public QdrantConfig QdrantConfig => this._qdrantConfig;
diff --git a/dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs b/dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs
new file mode 100644
index 000000000000..6e1f45cbe07e
--- /dev/null
+++ b/dotnet/samples/Demos/VectorStoreRAG/Options/ChromaConfig.cs
@@ -0,0 +1,16 @@
+// Copyright (c) Microsoft. All rights reserved.
+
+using System.ComponentModel.DataAnnotations;
+
+namespace VectorStoreRAG.Options;
+
+///
+/// Chroma service settings.
+///
+internal sealed class ChromaConfig
+{
+ public const string ConfigSectionName = "Chroma";
+
+ [Required]
+ public string ConnectionString { get; set; } = string.Empty;
+}
diff --git a/dotnet/samples/Demos/VectorStoreRAG/Program.cs b/dotnet/samples/Demos/VectorStoreRAG/Program.cs
index e7382eb9e71e..2f092dd3f122 100644
--- a/dotnet/samples/Demos/VectorStoreRAG/Program.cs
+++ b/dotnet/samples/Demos/VectorStoreRAG/Program.cs
@@ -82,6 +82,11 @@
appConfig.AzureDocumentDBConfig.ConnectionString,
appConfig.AzureDocumentDBConfig.DatabaseName);
break;
+ case "Chroma":
+ kernelBuilder.Services.AddChromaCollection>(
+ appConfig.RagConfig.CollectionName,
+ appConfig.ChromaConfig.ConnectionString);
+ break;
case "CosmosNoSql":
kernelBuilder.Services.AddCosmosCollection>(
appConfig.RagConfig.CollectionName,
@@ -121,6 +126,7 @@
{
case "AzureAISearch":
case "AzureDocumentDB":
+ case "Chroma":
case "CosmosNoSql":
case "InMemory":
case "Redis":
diff --git a/dotnet/samples/Demos/VectorStoreRAG/README.md b/dotnet/samples/Demos/VectorStoreRAG/README.md
index 95f4b1909318..57bee44dfd44 100644
--- a/dotnet/samples/Demos/VectorStoreRAG/README.md
+++ b/dotnet/samples/Demos/VectorStoreRAG/README.md
@@ -10,6 +10,7 @@ The sample can be configured in various ways:
1. You can choose your preferred vector store by setting the `Rag:VectorStoreType` configuration setting in the `appsettings.json` file to one of the following values:
1. AzureAISearch
1. AzureDocumentDB
+ 1. Chroma
1. CosmosNoSql
1. InMemory
1. Qdrant
@@ -130,6 +131,22 @@ dotnet user-secrets set "VectorStores:CosmosNoSql:ConnectionString" ""
```
+### Chroma
+
+If you want to use Chroma as your vector store, you will need to have an instance of Chroma available.
+
+You can use the following command to start a Chroma instance in docker, and this will work with the default configured settings:
+
+```cli
+docker run -d --name chroma -p 8000:8000 chromadb/chroma:latest
+```
+
+If you want to use a different instance of Chroma, you can update the appsettings.json file or add the following secret to reconfigure:
+
+```cli
+dotnet user-secrets set "VectorStores:Chroma:ConnectionString" ""
+```
+
### Qdrant
If you want to use Qdrant as your vector store, you will need to have an instance of Qdrant available.
diff --git a/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj b/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj
index 6e9d9f62fc7b..099e745caac9 100644
--- a/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj
+++ b/dotnet/samples/Demos/VectorStoreRAG/VectorStoreRAG.csproj
@@ -20,6 +20,7 @@
+
diff --git a/dotnet/samples/Demos/VectorStoreRAG/appsettings.json b/dotnet/samples/Demos/VectorStoreRAG/appsettings.json
index 8ba1a6952153..981bfb86c31a 100644
--- a/dotnet/samples/Demos/VectorStoreRAG/appsettings.json
+++ b/dotnet/samples/Demos/VectorStoreRAG/appsettings.json
@@ -33,6 +33,9 @@
"ConnectionString": "",
"DatabaseName": ""
},
+ "Chroma": {
+ "ConnectionString": "http://localhost:8000"
+ },
"CosmosNoSql": {
"ConnectionString": "",
"DatabaseName": ""
diff --git a/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs b/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs
index e64e97904a35..6d908cafa445 100644
--- a/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs
+++ b/dotnet/src/InternalUtilities/samples/InternalUtilities/TestConfiguration.cs
@@ -41,7 +41,6 @@ public static void Initialize(IConfigurationRoot configRoot)
public static PostgresConfig Postgres => LoadSection();
public static RedisConfig Redis => LoadSection();
public static JiraConfig Jira => LoadSection();
- public static ChromaConfig Chroma => LoadSection();
public static MongoDBConfig MongoDB => LoadSection();
public static ChatGPTRetrievalPluginConfig ChatGPTRetrievalPlugin => LoadSection();
public static MsGraphConfiguration MSGraph => LoadSection();
@@ -219,11 +218,6 @@ public class JiraConfig
public string Domain { get; set; }
}
- public class ChromaConfig
- {
- public string Endpoint { get; set; }
- }
-
public class MongoDBConfig
{
public string ConnectionString { get; set; }
diff --git a/dotnet/src/VectorData/Chroma/README.md b/dotnet/src/VectorData/Chroma/README.md
index 2e862fa4adff..62029d71137e 100644
--- a/dotnet/src/VectorData/Chroma/README.md
+++ b/dotnet/src/VectorData/Chroma/README.md
@@ -1 +1 @@
-Microsoft.SemanticKernel.Connectors.Chroma and the MemoryStore abstraction has been deprecated. Please use the new Microsoft.Extensions.VectorData abstractions with the Chroma implementation that can be found in the [CommunityToolkit/AI repository](https://github.com/CommunityToolkit/AI/tree/main/MEVD/src/Chroma)
+Microsoft.SemanticKernel.Connectors.Chroma and the MemoryStore abstraction have been deprecated. Please use the new Microsoft.Extensions.VectorData abstractions with the Chroma implementation that can be found in the [CommunityToolkit/AI repository](https://github.com/CommunityToolkit/AI/tree/main/MEVD/src/Chroma), published as [CommunityToolkit.VectorData.Chroma](https://www.nuget.org/packages/CommunityToolkit.VectorData.Chroma).
diff --git a/dotnet/test/VectorData/Chroma.UnitTests/.editorconfig b/dotnet/test/VectorData/Chroma.UnitTests/.editorconfig
deleted file mode 100644
index 394eef685f21..000000000000
--- a/dotnet/test/VectorData/Chroma.UnitTests/.editorconfig
+++ /dev/null
@@ -1,6 +0,0 @@
-# Suppressing errors for Test projects under dotnet folder
-[*.cs]
-dotnet_diagnostic.CA2007.severity = none # Do not directly await a Task
-dotnet_diagnostic.VSTHRD111.severity = none # Use .ConfigureAwait(bool) is hidden by default, set to none to prevent IDE from changing on autosave
-dotnet_diagnostic.CS1591.severity = none # Missing XML comment for publicly visible type or member
-dotnet_diagnostic.IDE1006.severity = warning # Naming rule violations