diff --git a/_includes/code/connections/timeouts-custom.mdx b/_includes/code/connections/timeouts-custom.mdx
index a51bf15fc..c16868653 100644
--- a/_includes/code/connections/timeouts-custom.mdx
+++ b/_includes/code/connections/timeouts-custom.mdx
@@ -5,6 +5,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl
import PyV4Code from "!!raw-loader!/_includes/code/connections/connect-python-v4.py";
import TsV3Code from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts";
import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java";
+import CSharpCode from "!!raw-loader!/_includes/code/csharp/ConnectionTest.cs";
@@ -31,4 +32,12 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Conne
language="java"
/>
+
+
+
diff --git a/_includes/code/connections/timeouts-local.mdx b/_includes/code/connections/timeouts-local.mdx
index d17480b8e..3fdf82267 100644
--- a/_includes/code/connections/timeouts-local.mdx
+++ b/_includes/code/connections/timeouts-local.mdx
@@ -5,6 +5,7 @@ import FilteredTextBlock from "@site/src/components/Documentation/FilteredTextBl
import PyV4Code from "!!raw-loader!/_includes/code/connections/connect-python-v4.py";
import TsV3Code from "!!raw-loader!/_includes/code/connections/connect-ts-v3.ts";
import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/ConnectionTest.java";
+import CSharpCode from "!!raw-loader!/_includes/code/csharp/ConnectionTest.cs";
@@ -31,4 +32,12 @@ import JavaV6Code from "!!raw-loader!/_includes/code/java-v6/src/test/java/Conne
language="java"
/>
+
+
+
diff --git a/_includes/code/csharp/ConfigureBQTest.cs b/_includes/code/csharp/ConfigureBQTest.cs
new file mode 100644
index 000000000..ccb339633
--- /dev/null
+++ b/_includes/code/csharp/ConfigureBQTest.cs
@@ -0,0 +1,106 @@
+using Xunit;
+using Weaviate.Client;
+using Weaviate.Client.Models;
+using System;
+using System.Threading.Tasks;
+
+namespace WeaviateProject.Tests;
+
+public class ConfigureBQTest : IAsyncLifetime
+{
+ private WeaviateClient client;
+ private const string COLLECTION_NAME = "MyCollection";
+
+ // Runs before each test
+ public async Task InitializeAsync()
+ {
+ // START ConnectCode
+ // Note: The C# client doesn't support setting headers like 'X-OpenAI-Api-Key' via the constructor for local connections.
+ // This must be configured in Weaviate's environment variables.
+ client = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 });
+ // END ConnectCode
+
+ // Clean slate for each test
+ if (await client.Collections.Exists(COLLECTION_NAME))
+ {
+ await client.Collections.Delete(COLLECTION_NAME);
+ }
+ }
+
+ // Runs after each test
+ public Task DisposeAsync()
+ {
+ // No action needed here, as cleanup happens in InitializeAsync before the next test.
+ return Task.CompletedTask;
+ }
+
+ [Fact]
+ public async Task TestEnableBQ()
+ {
+ // START EnableBQ
+ await client.Collections.Create(new Collection
+ {
+ Name = "MyCollection",
+ Properties = [Property.Text("title")],
+ VectorConfig = new VectorConfig(
+ "default",
+ new Vectorizer.Text2VecContextionary(),
+ new VectorIndex.HNSW
+ {
+ // highlight-start
+ Quantizer = new VectorIndex.Quantizers.BQ()
+ // highlight-end
+ }
+ )
+ });
+ // END EnableBQ
+ }
+
+ [Fact]
+ public async Task TestUpdateSchema()
+ {
+ // Note: Updating quantization settings on an existing collection is not supported by Weaviate
+ // and will result in an error, as noted in the Java test. This test demonstrates the syntax for attempting the update.
+ var collection = await client.Collections.Create(new Collection
+ {
+ Name = "MyCollection",
+ Properties = [Property.Text("title")],
+ VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecContextionary())
+ });
+
+ // START UpdateSchema
+ await collection.Config.Update(c =>
+ {
+ var vectorConfig = c.VectorConfig["default"];
+ vectorConfig.VectorIndexConfig.UpdateHNSW(h => h.Quantizer = new VectorIndex.Quantizers.BQ());
+ });
+ // END UpdateSchema
+ }
+
+ [Fact]
+ public async Task TestBQWithOptions()
+ {
+ // START BQWithOptions
+ await client.Collections.Create(new Collection
+ {
+ Name = "MyCollection",
+ Properties = [Property.Text("title")],
+ VectorConfig = new VectorConfig(
+ "default",
+ new Vectorizer.Text2VecContextionary(),
+ // highlight-start
+ new VectorIndex.HNSW
+ {
+ VectorCacheMaxObjects = 100000,
+ Quantizer = new VectorIndex.Quantizers.BQ
+ {
+ Cache = true,
+ RescoreLimit = 200
+ }
+ }
+ // highlight-end
+ )
+ });
+ // END BQWithOptions
+ }
+}
\ No newline at end of file
diff --git a/_includes/code/csharp/ConfigurePQTest.cs b/_includes/code/csharp/ConfigurePQTest.cs
new file mode 100644
index 000000000..b85f234d1
--- /dev/null
+++ b/_includes/code/csharp/ConfigurePQTest.cs
@@ -0,0 +1,218 @@
+using Xunit;
+using Weaviate.Client;
+using Weaviate.Client.Models;
+using System;
+using System.Threading.Tasks;
+using System.Collections.Generic;
+using System.Text.Json;
+using System.Net.Http;
+using System.Linq;
+using System.Text.Json.Serialization;
+
+namespace WeaviateProject.Tests;
+
+public class ConfigurePQTest : IAsyncLifetime
+{
+ private static WeaviateClient client;
+ private static List data;
+ private const string COLLECTION_NAME = "Question";
+
+ // Runs once before any tests in the class
+ public async Task InitializeAsync()
+ {
+ // START DownloadData
+ using var httpClient = new HttpClient();
+ var responseBody = await httpClient.GetStringAsync(
+ "https://raw.githubusercontent.com/weaviate-tutorials/intro-workshop/main/data/jeopardy_1k.json");
+
+ data = JsonSerializer.Deserialize>(responseBody);
+
+ Console.WriteLine($"Data type: {data.GetType().Name}, Length: {data.Count}");
+ Console.WriteLine(JsonSerializer.Serialize(data[1], new JsonSerializerOptions { WriteIndented = true }));
+ // END DownloadData
+
+ // START ConnectCode
+ // Note: The C# client doesn't support setting headers like 'X-OpenAI-Api-Key' via the constructor for local connections.
+ // This must be configured in Weaviate's environment variables.
+ client = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 });
+
+ var meta = await client.GetMeta();
+ Console.WriteLine($"Weaviate info: {meta.Version}");
+ // END ConnectCode
+ }
+
+ // Runs once after all tests in the class
+ public async Task DisposeAsync()
+ {
+ if (await client.Collections.Exists(COLLECTION_NAME))
+ {
+ await client.Collections.Delete(COLLECTION_NAME);
+ }
+ }
+
+ // This helper runs before each test to ensure a clean collection state
+ private async Task BeforeEach()
+ {
+ if (await client.Collections.Exists(COLLECTION_NAME))
+ {
+ await client.Collections.Delete(COLLECTION_NAME);
+ }
+ }
+
+ // TODO[g-despot] Why is Encoder required?
+ // TODO[g-despot] Why are properties required? ERROR: didn't find a single property which is of type string or text and is not excluded from indexing
+ [Fact]
+ public async Task TestCollectionWithAutoPQ()
+ {
+ await BeforeEach();
+
+ // START CollectionWithAutoPQ
+ await client.Collections.Create(new Collection
+ {
+ Name = "Question",
+ VectorConfig = new VectorConfig(
+ "default",
+ new Vectorizer.Text2VecContextionary(),
+ new VectorIndex.HNSW
+ {
+ // highlight-start
+ Quantizer = new VectorIndex.Quantizers.PQ
+ {
+ TrainingLimit = 50000, // Set the threshold to begin training
+ Encoder = new VectorIndex.Quantizers.PQ.EncoderConfig
+ {
+ Type = VectorIndex.Quantizers.EncoderType.Tile,
+ Distribution = VectorIndex.Quantizers.DistributionType.Normal,
+ },
+ }
+ // highlight-end
+ }
+ ),
+ Properties =
+ [
+ Property.Text("question"),
+ Property.Text("answer"),
+ Property.Text("category")
+ ]
+ });
+ // END CollectionWithAutoPQ
+
+ // Confirm that the collection has been created with the right settings
+ var collection = client.Collections.Use(COLLECTION_NAME);
+ var config = await collection.Get();
+ Assert.NotNull(config);
+ var hnswConfig = config.VectorConfig["default"].VectorIndexConfig as VectorIndex.HNSW;
+ Assert.NotNull(hnswConfig?.Quantizer);
+ }
+
+ [Fact]
+ public async Task TestUpdateSchemaWithPQ()
+ {
+ await BeforeEach();
+
+ // START InitialSchema
+ await client.Collections.Create(new Collection
+ {
+ Name = "Question",
+ Description = "A Jeopardy! question",
+ VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecContextionary()),
+ Properties =
+ [
+ Property.Text("question"),
+ Property.Text("answer"),
+ Property.Text("category")
+ ]
+ });
+ // END InitialSchema
+
+ var collection = client.Collections.Use(COLLECTION_NAME);
+ var initialConfig = await collection.Get();
+ Assert.NotNull(initialConfig);
+
+ // START LoadData
+ var objectList = data.Select(obj => new
+ {
+ question = obj.GetProperty("Question").GetString(),
+ answer = obj.GetProperty("Answer").GetString()
+ }).ToArray();
+
+ await collection.Data.InsertMany(objectList);
+ // END LoadData
+
+ var aggregateResponse = await collection.Aggregate.OverAll(totalCount: true);
+ Assert.Equal(1000, aggregateResponse.TotalCount);
+
+ // START UpdateSchema
+ await collection.Config.Update(c =>
+ {
+ var vectorConfig = c.VectorConfig["default"];
+ vectorConfig.VectorIndexConfig.UpdateHNSW(h =>
+ h.Quantizer = new VectorIndex.Quantizers.PQ
+ {
+ TrainingLimit = 50000,
+ Encoder = new VectorIndex.Quantizers.PQ.EncoderConfig
+ {
+ Type = VectorIndex.Quantizers.EncoderType.Tile,
+ Distribution = VectorIndex.Quantizers.DistributionType.Normal,
+ },
+ });
+ });
+ // END UpdateSchema
+
+ var updatedConfig = await collection.Get();
+ Assert.NotNull(updatedConfig);
+ var hnswConfig = updatedConfig.VectorConfig["default"].VectorIndexConfig as VectorIndex.HNSW;
+ Assert.IsType(hnswConfig?.Quantizer);
+ }
+
+ [Fact]
+ public async Task TestGetSchema()
+ {
+ await BeforeEach();
+
+ // Create a collection with PQ enabled to inspect its schema
+ await client.Collections.Create(new Collection
+ {
+ Name = "Question",
+ VectorConfig = new VectorConfig(
+ "default",
+ new Vectorizer.Text2VecContextionary(),
+ new VectorIndex.HNSW
+ {
+ Quantizer = new VectorIndex.Quantizers.PQ
+ {
+ Encoder = new VectorIndex.Quantizers.PQ.EncoderConfig
+ {
+ Type = VectorIndex.Quantizers.EncoderType.Tile,
+ Distribution = VectorIndex.Quantizers.DistributionType.Normal,
+ },
+ TrainingLimit = 50000
+ }
+ }
+ ),
+ Properties =
+ [
+ Property.Text("question"),
+ Property.Text("answer"),
+ Property.Text("category")
+ ]
+ });
+
+ // START GetSchema
+ var jeopardy = client.Collections.Use("Question");
+ var config = await jeopardy.Get();
+
+ Console.WriteLine(JsonSerializer.Serialize(config, new JsonSerializerOptions { WriteIndented = true }));
+ // END GetSchema
+ Assert.NotNull(config);
+
+ var hnswConfig = config.VectorConfig["default"].VectorIndexConfig as VectorIndex.HNSW;
+ var pqConfig = hnswConfig?.Quantizer as VectorIndex.Quantizers.PQ;
+ Assert.NotNull(pqConfig);
+
+ // Print some of the config properties
+ Console.WriteLine($"Training: {pqConfig.TrainingLimit}");
+ Console.WriteLine($"Segments: {pqConfig.Segments}");
+ Console.WriteLine($"Centroids: {pqConfig.Centroids}");
+ }
+}
\ No newline at end of file
diff --git a/_includes/code/csharp/ConfigureRQTest.cs b/_includes/code/csharp/ConfigureRQTest.cs
new file mode 100644
index 000000000..f2bebf560
--- /dev/null
+++ b/_includes/code/csharp/ConfigureRQTest.cs
@@ -0,0 +1,166 @@
+// using Xunit;
+// using Weaviate.Client;
+// using Weaviate.Client.Models;
+// using System;
+// using System.Threading.Tasks;
+
+// namespace WeaviateProject.Tests;
+
+// public class ConfigureRQTest : IAsyncLifetime
+// {
+// private WeaviateClient client;
+// private const string COLLECTION_NAME = "MyCollection";
+
+// // Runs before each test
+// public async Task InitializeAsync()
+// {
+// // START ConnectCode
+// // Note: The C# client doesn't support setting headers like 'X-OpenAI-Api-Key' via the constructor for local connections.
+// // This must be configured in Weaviate's environment variables.
+// client = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 });
+// // END ConnectCode
+
+// // Clean slate for each test
+// if (await client.Collections.Exists(COLLECTION_NAME))
+// {
+// await client.Collections.Delete(COLLECTION_NAME);
+// }
+// }
+
+// // Runs after each test
+// public Task DisposeAsync()
+// {
+// // No action needed here, as cleanup happens in InitializeAsync before the next test.
+// return Task.CompletedTask;
+// }
+
+// [Fact]
+// public async Task TestEnableRQ()
+// {
+// // START EnableRQ
+// await client.Collections.Create(new Collection
+// {
+// Name = "MyCollection",
+// Properties = [Property.Text("title")],
+// VectorConfig = new VectorConfig(
+// "default",
+// new Vectorizer.Text2VecContextionary(),
+// new VectorIndex.HNSW
+// {
+// // highlight-start
+// Quantizer = new VectorIndex.Quantizers.RQ()
+// // highlight-end
+// }
+// )
+// });
+// // END EnableRQ
+// }
+
+// [Fact]
+// public async Task Test1BitEnableRQ()
+// {
+// // START 1BitEnableRQ
+// await client.Collections.Create(new Collection
+// {
+// Name = "MyCollection",
+// Properties = [Property.Text("title")],
+// VectorConfig = new VectorConfig(
+// "default",
+// new Vectorizer.Text2VecContextionary(),
+// new VectorIndex.HNSW
+// {
+// // highlight-start
+// Quantizer = new VectorIndex.Quantizers.RQ { Bits = 1 }
+// // highlight-end
+// }
+// )
+// });
+// // END 1BitEnableRQ
+// }
+
+// [Fact]
+// public async Task TestUncompressed()
+// {
+// // START Uncompressed
+// await client.Collections.Create(new Collection
+// {
+// Name = "MyCollection",
+// Properties = [Property.Text("title")],
+// VectorConfig = new VectorConfig(
+// "default",
+// new Vectorizer.Text2VecContextionary(),
+// // highlight-start
+// // Omitting the Quantizer property results in an uncompressed index.
+// new VectorIndex.HNSW()
+// // highlight-end
+// )
+// });
+// // END Uncompressed
+// }
+
+// [Fact]
+// public async Task TestRQWithOptions()
+// {
+// // START RQWithOptions
+// await client.Collections.Create(new Collection
+// {
+// Name = "MyCollection",
+// Properties = [Property.Text("title")],
+// VectorConfig = new VectorConfig(
+// "default",
+// new Vectorizer.Text2VecContextionary(),
+// new VectorIndex.HNSW
+// {
+// // highlight-start
+// Quantizer = new VectorIndex.Quantizers.RQ
+// {
+// Bits = 8, // Optional: Number of bits
+// RescoreLimit = 20 // Optional: Number of candidates to fetch before rescoring
+// }
+// // highlight-end
+// }
+// )
+// });
+// // END RQWithOptions
+// }
+
+// [Fact]
+// public async Task TestUpdateSchema()
+// {
+// // Note: Updating quantization settings on an existing collection is not supported by Weaviate
+// // and will result in an error, as noted in the Java test. This test demonstrates the syntax for attempting the update.
+// var collection = await client.Collections.Create(new Collection
+// {
+// Name = "MyCollection",
+// Properties = [Property.Text("title")],
+// VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecContextionary())
+// });
+
+// // START UpdateSchema
+// await collection.Config.Update(c =>
+// {
+// var vectorConfig = c.VectorConfig["default"];
+// vectorConfig.VectorIndexConfig.UpdateHNSW(h => h.Quantizer = new VectorIndex.Quantizers.RQ());
+// });
+// // END UpdateSchema
+// }
+
+// [Fact]
+// public async Task Test1BitUpdateSchema()
+// {
+// var collection = await client.Collections.Create(new Collection
+// {
+// Name = "MyCollection",
+// Properties = [Property.Text("title")],
+// VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecContextionary())
+// });
+
+// // START 1BitUpdateSchema
+// await collection.Config.Update(c =>
+// {
+// var vectorConfig = c.VectorConfig["default"];
+// vectorConfig.VectorIndexConfig.UpdateHNSW(h => h.Quantizer = new VectorIndex.Quantizers.RQ { Bits = 1 });
+// });
+// // END 1BitUpdateSchema
+// }
+// }
\ No newline at end of file
diff --git a/_includes/code/csharp/ConfigureSQTest.cs b/_includes/code/csharp/ConfigureSQTest.cs
new file mode 100644
index 000000000..9ee88c528
--- /dev/null
+++ b/_includes/code/csharp/ConfigureSQTest.cs
@@ -0,0 +1,108 @@
+using Xunit;
+using Weaviate.Client;
+using Weaviate.Client.Models;
+using System;
+using System.Threading.Tasks;
+
+namespace WeaviateProject.Tests;
+
+public class ConfigureSQTest : IAsyncLifetime
+{
+ private WeaviateClient client;
+ private const string COLLECTION_NAME = "MyCollection";
+
+ // Runs before each test
+ public async Task InitializeAsync()
+ {
+ // START ConnectCode
+ // Note: The C# client doesn't support setting headers like 'X-OpenAI-Api-Key' via the constructor for local connections.
+ // This must be configured in Weaviate's environment variables.
+ client = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 });
+ // END ConnectCode
+
+ // Clean slate for each test
+ if (await client.Collections.Exists(COLLECTION_NAME))
+ {
+ await client.Collections.Delete(COLLECTION_NAME);
+ }
+ }
+
+ // Runs after each test
+ public Task DisposeAsync()
+ {
+ // No action needed here, as cleanup happens in InitializeAsync before the next test.
+ return Task.CompletedTask;
+ }
+
+ [Fact]
+ public async Task TestEnableSQ()
+ {
+ // START EnableSQ
+ await client.Collections.Create(new Collection
+ {
+ Name = "MyCollection",
+ Properties = [Property.Text("title")],
+ VectorConfig = new VectorConfig(
+ "default",
+ new Vectorizer.Text2VecContextionary(),
+ new VectorIndex.HNSW
+ {
+ // highlight-start
+ Quantizer = new VectorIndex.Quantizers.SQ()
+ // highlight-end
+ }
+ )
+ });
+ // END EnableSQ
+ }
+
+ [Fact]
+ public async Task TestUpdateSchema()
+ {
+ // Note: Updating quantization settings on an existing collection is not supported by Weaviate
+ // and will result in an error, as noted in the Java test. This test demonstrates the syntax for attempting the update.
+ var collection = await client.Collections.Create(new Collection
+ {
+ Name = "MyCollection",
+ Properties = [Property.Text("title")],
+ VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecContextionary())
+ });
+
+ // START UpdateSchema
+ await collection.Config.Update(c =>
+ {
+ var vectorConfig = c.VectorConfig["default"];
+ vectorConfig.VectorIndexConfig.UpdateHNSW(h => h.Quantizer = new VectorIndex.Quantizers.SQ());
+ });
+ // END UpdateSchema
+ }
+
+ // TODO[g-despot] Missing cache
+ [Fact]
+ public async Task TestSQWithOptions()
+ {
+ // START SQWithOptions
+ await client.Collections.Create(new Collection
+ {
+ Name = "MyCollection",
+ Properties = [Property.Text("title")],
+ VectorConfig = new VectorConfig(
+ "default",
+ new Vectorizer.Text2VecContextionary(),
+ // highlight-start
+ new VectorIndex.HNSW
+ {
+ VectorCacheMaxObjects = 100000,
+ Quantizer = new VectorIndex.Quantizers.SQ
+ {
+ //Cache = true,
+ TrainingLimit = 50000,
+ RescoreLimit = 200
+ }
+ }
+ // highlight-end
+ )
+ });
+ // END SQWithOptions
+ }
+}
\ No newline at end of file
diff --git a/_includes/code/csharp/ConnectionTest.cs b/_includes/code/csharp/ConnectionTest.cs
new file mode 100644
index 000000000..67e59717b
--- /dev/null
+++ b/_includes/code/csharp/ConnectionTest.cs
@@ -0,0 +1,204 @@
+using Weaviate.Client;
+using System;
+using System.Threading.Tasks;
+using Xunit;
+
+namespace WeaviateProject.Examples;
+
+public class ConnectionTest
+{
+ //TODO[g-despot] Replace with readiness check
+ [Fact]
+ public async Task TestConnectLocalWithCustomUrl()
+ {
+ // START CustomURL
+ var config = new ClientConfiguration
+ {
+ RestAddress = "127.0.0.1",
+ RestPort = 8080,
+ GrpcAddress = "127.0.0.1",
+ GrpcPort = 50051 // Default gRPC port
+ };
+ using var client = new WeaviateClient(config);
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END CustomURL
+ }
+
+ // TODO[g-despot] How to add timeout
+ // START TimeoutLocal
+ // Coming soon
+ // END TimeoutLocal
+ // START TimeoutCustom
+ // Coming soon
+ // END TimeoutCustom
+
+ [Fact]
+ public async Task TestConnectWCDWithApiKey()
+ {
+ // START APIKeyWCD
+ // Best practice: store your credentials in environment variables
+ string weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL");
+ string weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY");
+
+ using var client = Connect.Cloud(
+ weaviateUrl, // Replace with your Weaviate Cloud URL
+ weaviateApiKey // Replace with your Weaviate Cloud key
+ );
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END APIKeyWCD
+ }
+
+ [Fact]
+ public async Task TestCustomConnection()
+ {
+ // START CustomConnect
+ // Best practice: store your credentials in environment variables
+ string httpHost = Environment.GetEnvironmentVariable("WEAVIATE_HTTP_HOST");
+ string grpcHost = Environment.GetEnvironmentVariable("WEAVIATE_GRPC_HOST");
+ string weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY");
+ string cohereApiKey = Environment.GetEnvironmentVariable("COHERE_API_KEY");
+
+ var config = new ClientConfiguration
+ {
+ UseSsl = true, // Corresponds to scheme("https")
+ RestAddress = httpHost,
+ RestPort = 443,
+ GrpcAddress = grpcHost,
+ GrpcPort = 443,
+ Credentials = Auth.ApiKey(weaviateApiKey),
+ // Headers = new Dictionary
+ // {
+ // { "X-Cohere-Api-Key", cohereApiKey }
+ // }
+ };
+ using var client = new WeaviateClient(config);
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END CustomConnect
+ }
+
+ [Fact]
+ public async Task TestCustomApiKeyConnection()
+ {
+ // START ConnectWithApiKeyExample
+ // Best practice: store your credentials in environment variables
+ string httpHost = Environment.GetEnvironmentVariable("WEAVIATE_HTTP_HOST");
+ string grpcHost = Environment.GetEnvironmentVariable("WEAVIATE_GRPC_HOST");
+ string weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY");
+ string cohereApiKey = Environment.GetEnvironmentVariable("COHERE_API_KEY");
+
+ var config = new ClientConfiguration
+ {
+ UseSsl = true, // Corresponds to scheme("https")
+ RestAddress = httpHost,
+ RestPort = 443,
+ GrpcAddress = grpcHost,
+ GrpcPort = 443,
+ Credentials = Auth.ApiKey(weaviateApiKey),
+ // Headers = new Dictionary
+ // {
+ // { "X-Cohere-Api-Key", cohereApiKey }
+ // }
+ };
+ using var client = new WeaviateClient(config);
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END ConnectWithApiKeyExample
+ }
+
+ [Fact]
+ public async Task TestConnectLocalNoAuth()
+ {
+ // START LocalNoAuth
+ using var client = Connect.Local();
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END LocalNoAuth
+ }
+
+ [Fact]
+ public async Task TestConnectLocalWithAuth()
+ {
+ // START LocalAuth
+ // Best practice: store your credentials in environment variables
+ string weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_LOCAL_API_KEY");
+
+ // The Connect.Local() helper doesn't support auth, so we must use a custom configuration.
+ var config = new ClientConfiguration
+ {
+ Credentials = Auth.ApiKey(weaviateApiKey)
+ };
+ using var client = new WeaviateClient(config);
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END LocalAuth
+ }
+
+ [Fact]
+ public async Task TestConnectLocalWithThirdPartyKeys()
+ {
+ // START LocalThirdPartyAPIKeys
+ // Best practice: store your credentials in environment variables
+ string cohereApiKey = Environment.GetEnvironmentVariable("COHERE_API_KEY");
+
+ var config = new ClientConfiguration
+ {
+ // Headers = new Dictionary
+ // {
+ // { "X-Cohere-Api-Key", cohereApiKey }
+ // }
+ };
+ using var client = new WeaviateClient(config);
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END LocalThirdPartyAPIKeys
+ }
+
+ [Fact]
+ public async Task TestConnectWCDWithThirdPartyKeys()
+ {
+ // START ThirdPartyAPIKeys
+ // Best practice: store your credentials in environment variables
+ string weaviateUrl = Environment.GetEnvironmentVariable("WEAVIATE_URL");
+ string weaviateApiKey = Environment.GetEnvironmentVariable("WEAVIATE_API_KEY");
+ string cohereApiKey = Environment.GetEnvironmentVariable("COHERE_API_KEY");
+
+ using var client = Connect.Cloud(
+ weaviateUrl, // Replace with your Weaviate Cloud URL
+ weaviateApiKey // Replace with your Weaviate Cloud key
+ // headers: new Dictionary
+ // {
+ // { "X-Cohere-Api-Key", cohereApiKey }
+ // }
+ );
+
+ var meta = await client.GetMeta();
+ Console.WriteLine(meta);
+
+ // The 'using' statement handles freeing up resources automatically.
+ // END ThirdPartyAPIKeys
+ }
+}
\ No newline at end of file
diff --git a/_includes/code/csharp/GetStartedTest.cs b/_includes/code/csharp/GetStartedTest.cs
new file mode 100644
index 000000000..f6e1deb91
--- /dev/null
+++ b/_includes/code/csharp/GetStartedTest.cs
@@ -0,0 +1,79 @@
+using Xunit;
+using Weaviate.Client;
+using Weaviate.Client.Models;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Text.Json;
+using System.Linq;
+using System.Threading.Tasks;
+// ... other usings
+
+// 1. Define your strongly-typed class
+public class JeopardyQuestion
+{
+ public string? question { get; set; }
+ public string? answer { get; set; }
+ public string? category { get; set; }
+}
+
+public class GetStartedTests
+{
+ [Fact]
+ public async Task GetStarted()
+ {
+ var client = Connect.Local();
+ const string collectionName = "Question";
+
+ try
+ {
+ if (await client.Collections.Exists(collectionName))
+ {
+ await client.Collections.Delete(collectionName);
+ }
+
+ var questions = await client.Collections.Create(new Collection()
+ {
+ Name = collectionName,
+ VectorConfig = new VectorConfig("default", new Vectorizer.Text2VecOllama()),
+ Properties = new List
+ {
+ Property.Text("answer"),
+ Property.Text("question"),
+ Property.Text("category"),
+ }
+ });
+
+ // Download and parse data as before...
+ using var httpClient = new HttpClient();
+ var resp = await httpClient.GetAsync(
+ "https://raw.githubusercontent.com/weaviate-tutorials/quickstart/main/data/jeopardy_tiny.json"
+ );
+ resp.EnsureSuccessStatusCode();
+ var jsonString = await resp.Content.ReadAsStringAsync();
+ var data = JsonSerializer.Deserialize>(jsonString);
+
+ // ============================= YOUR NEW, CLEAN CODE =============================
+ // 2. Prepare the data by mapping it to your new class
+ var dataObjects = data.Select(d => new JeopardyQuestion
+ {
+ answer = d.GetProperty("Answer").GetString(),
+ question = d.GetProperty("Question").GetString(),
+ category = d.GetProperty("Category").GetString()
+ }).ToList();
+ // ==============================================================================
+
+ var importResult = await questions.Data.InsertMany(dataObjects);
+
+ var response = await questions.Query.NearText("biology", limit: 2);
+ // ... rest of the test
+ Assert.Equal(2, response.Objects.Count());
+ }
+ finally
+ {
+ if (await client.Collections.Exists(collectionName))
+ {
+ await client.Collections.Delete(collectionName);
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/_includes/code/csharp/ManageCollectionsAliasTest.cs b/_includes/code/csharp/ManageCollectionsAliasTest.cs
new file mode 100644
index 000000000..e69de29bb
diff --git a/_includes/code/csharp/ManageCollectionsCrossReferencesTest.cs b/_includes/code/csharp/ManageCollectionsCrossReferencesTest.cs
new file mode 100644
index 000000000..975a0b509
--- /dev/null
+++ b/_includes/code/csharp/ManageCollectionsCrossReferencesTest.cs
@@ -0,0 +1,317 @@
+using Xunit;
+using Weaviate.Client;
+using Weaviate.Client.Models;
+using System;
+using System.Threading.Tasks;
+using System.Linq;
+using System.Collections.Generic;
+
+namespace WeaviateProject.Tests;
+
+public class ManageCollectionsCrossReferencesTest : IAsyncLifetime
+{
+ private WeaviateClient client;
+
+ // Runs before each test
+ public Task InitializeAsync()
+ {
+ // Note: The C# client doesn't support setting headers like 'X-OpenAI-Api-Key' via the constructor for local connections.
+ // This must be configured in Weaviate's environment variables.
+ client = new WeaviateClient(new ClientConfiguration { RestAddress = "localhost", RestPort = 8080 });
+ return Task.CompletedTask;
+ }
+
+ // Runs after each test
+ public async Task DisposeAsync()
+ {
+ // Clean up collections after each test
+ await client.Collections.Delete("JeopardyQuestion");
+ await client.Collections.Delete("JeopardyCategory");
+ }
+
+ [Fact]
+ public async Task TestCrossRefDefinition()
+ {
+ // START CrossRefDefinition
+ await client.Collections.Create(new Collection
+ {
+ Name = "JeopardyCategory",
+ Description = "A Jeopardy! category",
+ Properties = new() { Property.Text("title") }
+ });
+
+ await client.Collections.Create(new Collection
+ {
+ Name = "JeopardyQuestion",
+ Description = "A Jeopardy! question",
+ Properties = new()
+ {
+ Property.Text("question"),
+ Property.Text("answer")
+ },
+ // highlight-start
+ References = new()
+ {
+ new Reference("hasCategory", "JeopardyCategory")
+ }
+ // highlight-end
+ });
+ // END CrossRefDefinition
+
+ // Verify collections were created properly
+ var questionConfig = await client.Collections.Export("JeopardyQuestion");
+ Assert.Single(questionConfig.References);
+ Assert.Equal("hasCategory", questionConfig.References.First().Name);
+ }
+
+ [Fact]
+ public async Task TestObjectWithCrossRef()
+ {
+ await SetupCollections();
+ var categories = client.Collections.Use