diff --git a/src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringOptions.cs b/src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringOptions.cs
deleted file mode 100644
index 0398c7fce8..0000000000
--- a/src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringOptions.cs
+++ /dev/null
@@ -1,17 +0,0 @@
-namespace Orleans.Clustering.Cosmos;
-
-///
-/// Options for configuring Azure Cosmos DB clustering.
-///
-public class CosmosClusteringOptions : CosmosOptions
-{
- private const string ORLEANS_CLUSTER_CONTAINER = "OrleansCluster";
-
- ///
- /// Initializes a new instance.
- ///
- public CosmosClusteringOptions()
- {
- ContainerName = ORLEANS_CLUSTER_CONTAINER;
- }
-}
diff --git a/src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringProviderBuilder.cs b/src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringProviderBuilder.cs
new file mode 100644
index 0000000000..87d343474f
--- /dev/null
+++ b/src/Azure/Orleans.Clustering.Cosmos/CosmosClusteringProviderBuilder.cs
@@ -0,0 +1,115 @@
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Orleans;
+using Orleans.Clustering.Cosmos;
+using Orleans.Hosting;
+using Orleans.Providers;
+
+[assembly: RegisterProvider("Cosmos", "Clustering", "Silo", typeof(CosmosClusteringProviderBuilder))]
+[assembly: RegisterProvider("Cosmos", "Clustering", "Client", typeof(CosmosClusteringProviderBuilder))]
+
+namespace Orleans.Hosting;
+
+internal sealed class CosmosClusteringProviderBuilder : IProviderBuilder, IProviderBuilder
+{
+ public void Configure(ISiloBuilder builder, string name, IConfigurationSection configurationSection) =>
+ builder.UseCosmosClustering(optionsBuilder =>
+ optionsBuilder.Configure((options, services) =>
+ {
+ var databaseName = configurationSection[nameof(options.DatabaseName)];
+ if (!string.IsNullOrEmpty(databaseName))
+ {
+ options.DatabaseName = databaseName;
+ }
+ var containerName = configurationSection[nameof(options.ContainerName)];
+ if (!string.IsNullOrEmpty(containerName))
+ {
+ options.ContainerName = containerName;
+ }
+ if (bool.TryParse(configurationSection[nameof(options.IsResourceCreationEnabled)], out var irce))
+ {
+ options.IsResourceCreationEnabled = irce;
+ }
+ if(int.TryParse(configurationSection[nameof(options.DatabaseThroughput)], out var dt))
+ {
+ options.DatabaseThroughput = dt;
+ }
+ if(bool.TryParse(configurationSection[nameof(options.CleanResourcesOnInitialization)], out var croi))
+ {
+ options.CleanResourcesOnInitialization = croi;
+ }
+
+ var serviceKey = configurationSection["ServiceKey"];
+ if(!string.IsNullOrEmpty(serviceKey))
+ {
+ options.ConfigureCosmosClient(sp=>
+ new ValueTask(sp.GetRequiredKeyedService(serviceKey)));
+ }
+ else
+ {
+ var connectionName = configurationSection["ConnectionName"];
+ var connectionString = configurationSection["ConnectionString"];
+ if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))
+ {
+ var rootConfiguration = services.GetRequiredService();
+ connectionString = rootConfiguration.GetConnectionString(connectionName);
+ }
+
+ if (!string.IsNullOrEmpty(connectionString))
+ {
+ options.ConfigureCosmosClient(connectionString);
+ }
+ }
+ }));
+
+ public void Configure(IClientBuilder builder, string name, IConfigurationSection configurationSection) =>
+ builder.UseCosmosGatewayListProvider(optionsBuilder =>
+ optionsBuilder.Configure((options, services) =>
+ {
+ var databaseName = configurationSection[nameof(options.DatabaseName)];
+ if (!string.IsNullOrEmpty(databaseName))
+ {
+ options.DatabaseName = databaseName;
+ }
+ var containerName = configurationSection[nameof(options.ContainerName)];
+ if (!string.IsNullOrEmpty(containerName))
+ {
+ options.ContainerName = containerName;
+ }
+ if (bool.TryParse(configurationSection[nameof(options.IsResourceCreationEnabled)], out var irce))
+ {
+ options.IsResourceCreationEnabled = irce;
+ }
+ if (int.TryParse(configurationSection[nameof(options.DatabaseThroughput)], out var dt))
+ {
+ options.DatabaseThroughput = dt;
+ }
+ if (bool.TryParse(configurationSection[nameof(options.CleanResourcesOnInitialization)], out var croi))
+ {
+ options.CleanResourcesOnInitialization = croi;
+ }
+
+ var serviceKey = configurationSection["ServiceKey"];
+ if (!string.IsNullOrEmpty(serviceKey))
+ {
+ options.ConfigureCosmosClient(sp =>
+ new ValueTask(sp.GetRequiredKeyedService(serviceKey)));
+ }
+ else
+ {
+ // Construct a connection multiplexer from a connection string.
+ var connectionName = configurationSection["ConnectionName"];
+ var connectionString = configurationSection["ConnectionString"];
+ if (!string.IsNullOrEmpty(connectionName) && string.IsNullOrEmpty(connectionString))
+ {
+ var rootConfiguration = services.GetRequiredService();
+ connectionString = rootConfiguration.GetConnectionString(connectionName);
+ }
+
+ if (!string.IsNullOrEmpty(connectionString))
+ {
+ options.ConfigureCosmosClient(connectionString);
+ }
+ }
+ }));
+}
\ No newline at end of file
diff --git a/src/Azure/Orleans.Clustering.Cosmos/CosmosGatewayListProvider.cs b/src/Azure/Orleans.Clustering.Cosmos/Membership/CosmosGatewayListProvider.cs
similarity index 100%
rename from src/Azure/Orleans.Clustering.Cosmos/CosmosGatewayListProvider.cs
rename to src/Azure/Orleans.Clustering.Cosmos/Membership/CosmosGatewayListProvider.cs
diff --git a/src/Azure/Orleans.Clustering.Cosmos/CosmosMembershipTable.cs b/src/Azure/Orleans.Clustering.Cosmos/Membership/CosmosMembershipTable.cs
similarity index 100%
rename from src/Azure/Orleans.Clustering.Cosmos/CosmosMembershipTable.cs
rename to src/Azure/Orleans.Clustering.Cosmos/Membership/CosmosMembershipTable.cs
diff --git a/src/Azure/Orleans.Clustering.Cosmos/Options/CosmosClusteringOptions.cs b/src/Azure/Orleans.Clustering.Cosmos/Options/CosmosClusteringOptions.cs
new file mode 100644
index 0000000000..5ffc7419f5
--- /dev/null
+++ b/src/Azure/Orleans.Clustering.Cosmos/Options/CosmosClusteringOptions.cs
@@ -0,0 +1,32 @@
+namespace Orleans.Clustering.Cosmos;
+
+///
+/// Options for configuring Azure Cosmos DB clustering.
+///
+public class CosmosClusteringOptions : CosmosOptions
+{
+ private const string ORLEANS_CLUSTER_CONTAINER = "OrleansCluster";
+
+ ///
+ /// Initializes a new instance.
+ ///
+ public CosmosClusteringOptions()
+ {
+ ContainerName = ORLEANS_CLUSTER_CONTAINER;
+ }
+}
+
+///
+/// Configuration validator for .
+///
+public class CosmosClusteringOptionsValidator : CosmosOptionsValidator
+{
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The option to be validated.
+ /// The option name to be validated.
+ public CosmosClusteringOptionsValidator(CosmosClusteringOptions options, string name) : base(options, name)
+ {
+ }
+}
\ No newline at end of file
diff --git a/src/Azure/Orleans.Clustering.Cosmos/Properties/AssemblyInfo.cs b/src/Azure/Orleans.Clustering.Cosmos/Properties/AssemblyInfo.cs
new file mode 100644
index 0000000000..3a3d99f3cc
--- /dev/null
+++ b/src/Azure/Orleans.Clustering.Cosmos/Properties/AssemblyInfo.cs
@@ -0,0 +1,3 @@
+using System.Runtime.CompilerServices;
+
+[assembly: InternalsVisibleTo("Tester.AzureUtils")]