How to Integrate .NET Applications with a MongoDB Sharded Cluster
You can integrate .NET applications with a MongoDB sharded cluster by connecting to the mongos routers exposed on ports 27117 and 27118, using the standard MongoDB.Driver NuGet package with a connection string that lists both router endpoints.
The minhhungit/mongodb-cluster-docker-compose repository provides a complete Docker-based sharded cluster deployment that you can use to develop and test .NET applications locally. By leveraging the official MongoDB .NET driver, your applications can automatically discover the cluster topology, route queries to appropriate shards, and handle failover without custom logic.
Architecture Overview
The repository defines a production-style sharded cluster in [docker-compose.yml](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/docker-compose.yml) consisting of three distinct layers:
- Config Servers (
configsvr01,configsvr02,configsvr03): Store metadata and routing information for the cluster. - Shards (3 replica sets): Each shard is a 3-node replica set (
rs-shard-01,rs-shard-02,rs-shard-03) with members namedshard01-a/b/c,shard02-a/b/c, andshard03-a/b/c. - Routers (mongos) (
router01): The query router that exposes ports 27117 and 27118 to the host machine, forwarding operations to the appropriate shards.
The initialization logic in [scripts/entrypoint-route.sh](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/scripts/entrypoint-route.sh) waits for all replica sets to elect primaries, starts the mongos process, and registers each shard using sh.addShard().
Connecting .NET Applications to the Sharded Cluster
The MongoDB .NET driver treats a sharded cluster as a single logical database when you connect through the mongos routers. You do not need to specify individual shards or config servers in your connection string.
Connection String Configuration
Target the exposed router ports with a standard MongoDB URI:
var connectionString = "mongodb://127.0.0.1:27117,127.0.0.1:27118";
var client = new MongoClient(connectionString);
Listing both ports ensures the driver can fail over if one router becomes unavailable. The driver automatically discovers the full cluster topology from whichever router responds first.
Database and Collection Access
Once connected, interact with the cluster as you would with a standalone instance:
var database = client.GetDatabase("MyDatabase");
var collection = database.GetCollection<MyDocument>("MyCollection");
The mongos router transparently forwards write operations to the correct shard based on the collection's sharding key, and aggregates results from multiple shards for read operations.
Read and Write Configuration Best Practices
Sharded clusters require careful tuning of write concern and read preference to balance performance with consistency guarantees.
Write Concern for Durability
By default, the driver uses w:1, acknowledging writes when the primary shard member confirms the operation. For stronger durability across the replica set backing each shard, specify w:majority:
var settings = MongoClientSettings.FromConnectionString(connectionString);
settings.WriteConcern = WriteConcern.WMajority;
var client = new MongoClient(settings);
Read Preference for Load Distribution
The sample reader in [client/DemoMongoClusterReader/Program.cs](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/client/DemoMongoClusterReader/Program.cs) demonstrates using ReadPreference.SecondaryPreferred to offload read traffic from primary nodes:
var collection = database.GetCollection<MyDocument>("MyCollection",
new MongoCollectionSettings { ReadPreference = ReadPreference.SecondaryPreferred });
This setting routes queries to secondary members of the shard replica sets when available, falling back to primaries if necessary.
Querying by Sharding Key
For optimal performance, include the sharding key in your queries. The sample documents use oemNumber and zipCode as sharding keys. Queries filtering on these fields are routed directly to the relevant shard rather than broadcast to all shards:
var filter = Builders<MyDocument>.Filter.Eq(d => d.OemNumber, "ABCD");
var results = await collection.Find(filter).Limit(50).ToListAsync();
Complete .NET Implementation Examples
The repository includes two full .NET console applications in the client/ directory that demonstrate end-to-end integration.
Document Model
The shared document model in [client/MongoCluster.Messages/User.cs](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/client/MongoCluster.Messages/User.cs) maps C# properties to BSON elements:
using MongoDB.Bson;
using MongoDB.Bson.Serialization.Attributes;
namespace MongoCluster.Messages
{
public class MyDocument
{
[BsonId] public ObjectId Id { get; set; }
[BsonElement("name")] public string Name { get; set; }
[BsonElement("supplierId")] public string SupplierId { get; set; }
[BsonElement("oemNumber")] public string OemNumber { get; set; }
[BsonElement("blog")] public string Blog { get; set; }
[BsonElement("zipCode")] public string ZipCode { get; set; }
[BsonElement("location")] public string Location { get; set; }
}
}
Bulk Write Operations
The writer application in [client/DemoMongoClusterWriter/Program.cs](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/client/DemoMongoClusterWriter/Program.cs) generates test data and performs unordered bulk inserts for maximum throughput:
using MongoCluster.Messages;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Collections.Generic;
using System.Diagnostics;
var dbName = "MyDatabase";
var client = new MongoClient("mongodb://127.0.0.1:27117,127.0.0.1:27118");
var database = client.GetDatabase(dbName);
var collection = database.GetCollection<MyDocument>("MyCollection");
// Build a batch of 10,000 documents
var batch = new List<MyDocument>();
for (int i = 0; i < 10_000; i++)
{
batch.Add(new MyDocument
{
Id = ObjectId.GenerateNewId(),
SupplierId = Guid.NewGuid().ToString(),
OemNumber = RandomString(4),
ZipCode = new Random().Next(1, 1000).ToString("D4"),
Name = $"Demo {i}"
});
}
// Fire-and-forget bulk insert (unordered for speed)
collection.InsertManyAsync(batch, new InsertManyOptions { IsOrdered = false })
.GetAwaiter().GetResult();
Secondary-Preferred Reads
The reader application in [client/DemoMongoClusterReader/Program.cs](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/client/DemoMongoClusterReader/Program.cs) demonstrates querying with specific read preferences and filters:
using MongoCluster.Messages;
using MongoDB.Bson;
using MongoDB.Driver;
using System;
using System.Threading.Tasks;
var client = new MongoClient("mongodb://127.0.0.1:27117,127.0.0.1:27118");
var database = client.GetDatabase("MyDatabase");
// Read from a secondary when possible
var collection = database.GetCollection<MyDocument>("MyCollection",
new MongoCollectionSettings { ReadPreference = ReadPreference.SecondaryPreferred });
var filter = Builders<MyDocument>.Filter.Eq(d => d.OemNumber, "ABCD");
var results = await collection.Find(filter).Limit(50).ToListAsync();
Console.WriteLine($"Found {results.Count} documents");
Running the Complete Integration
Follow these steps to start the cluster and execute the .NET samples.
1. Start the MongoDB Cluster
Execute Docker Compose to initialize the config servers, shard replica sets, and mongos routers:
docker-compose up -d
The [scripts/entrypoint-route.sh](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/scripts/entrypoint-route.sh) script automatically waits for all replica sets to elect primaries, starts the mongos process, and registers each shard using sh.addShard().
2. Execute the Writer Application
Run the bulk insert sample to populate the cluster with test data:
dotnet run --project client/DemoMongoClusterWriter/DemoMongoClusterWriter.csproj
3. Execute the Reader Application
Query the data using secondary-preferred read preferences:
dotnet run --project client/DemoMongoClusterReader/DemoMongoClusterReader.csproj
The .NET driver automatically discovers the sharding topology via the mongos routers and distributes operations across the appropriate replica sets.
Summary
- Connection Method: Point your
MongoClientto the mongos routers exposed on ports 27117 and 27118 using a standard MongoDB connection string. - Automatic Topology Discovery: The .NET driver retrieves cluster metadata from the mongos and routes queries to the correct shards without manual configuration.
- Write Optimization: Use
InsertManyAsyncwithIsOrdered = falsefor high-throughput bulk writes across the sharded cluster. - Read Distribution: Configure
ReadPreference.SecondaryPreferredinMongoCollectionSettingsto offload read traffic from primary nodes. - Query Performance: Include the sharding key (e.g.,
oemNumberorzipCode) in your filters to enable targeted shard routing instead of cluster-wide broadcasts.
Frequently Asked Questions
What is the correct connection string for connecting .NET applications to this MongoDB sharded cluster?
Use a connection string that lists both mongos router endpoints exposed by the Docker Compose setup: mongodb://127.0.0.1:27117,127.0.0.1:27118. The .NET driver will automatically discover the full cluster topology from whichever router responds first, and will handle failover if one router becomes unavailable.
How does the .NET driver handle routing queries to specific shards?
The MongoDB .NET driver communicates with the mongos routers (configured in router01), which maintain metadata about which shard holds each document based on the sharding key. When you execute a query that includes the sharding key (such as oemNumber or zipCode in the sample documents), the mongos routes the operation directly to the relevant shard. For queries without the sharding key, mongos broadcasts to all shards and aggregates results.
Can I configure read preferences to reduce load on primary shard members?
Yes. You can specify ReadPreference.SecondaryPreferred when retrieving a collection, as demonstrated in [client/DemoMongoClusterReader/Program.cs](https://github.com/minhhungit/mongodb-cluster-docker-compose/blob/master/client/DemoMongoClusterReader/Program.cs). This setting directs the driver to read from secondary members of the shard replica sets when available, falling back to primaries only when necessary. This significantly reduces read load on primary nodes and improves overall cluster throughput.
What write concern should I use for a sharded cluster to ensure data durability?
While the default w:1 write concern acknowledges writes when the primary shard member confirms the operation, you should use WriteConcern.WMajority for production workloads. This ensures the write is acknowledged by a majority of nodes in the replica set backing the shard, guaranteeing durability even if the primary fails immediately after the write. You can configure this via MongoClientSettings before instantiating the MongoClient.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →