Docs Menu
Docs Home
/ / /
C#/.NET

FAQ

On this page

  • Why Am I Getting Errors While Connecting to MongoDB?
  • How Does Connection Pooling Work in the .NET/C# Driver?
  • Why Does the Driver Throw a Timeout During Server Selection?
  • Should I Use LINQ or Builder Classes When Querying for Documents?
  • Why are Certain LINQ or Builder Expressions Unsupported?
  • What Object Types Can Be Serialized?

This page contains frequently asked questions and their corresponding answers.

Tip

If you can't find an answer to your problem on this page, see the Issues & Help page for next steps and more resources.

If you have trouble connecting to a MongoDB deployment, see the Connection Troubleshooting Guide for possible solutions.

Every MongoClient instance has a built-in connection pool for each server in your MongoDB topology. Connection pools open sockets on demand to support concurrent MongoDB operations in your multi-threaded application.

The maximum size of each connection pool is set by the MaxConnectionPoolSize option, which defaults to 100. If the number of in-use connections to a server reaches the value of MaxConnectionPoolSize, the next request to that server will wait until a connection becomes available. The following diagram illustrates a high-level view of how the MongoClient manages a connection pool:

CMAP diagram

In addition to the sockets needed to support your application's threads, each MongoClient instance opens two additional sockets per server in your MongoDB topology for monitoring the server's state. For example, a client connected to a three-node replica set opens six monitoring sockets. If the application uses the default setting for MaxConnectionPoolSize and only queries the primary (default) node, then there can be at most 106 total connections in use. If the application uses a read preference to query the secondary nodes, those connection pools grow and there can be 306 total connections.

To support high numbers of concurrent MongoDB threads within one process, you can increase MaxConnectionPoolSize.

The driver has a wait queue that limits the number of threads that can wait for a connection. The size of the wait queue is determined by the WaitQueueMultiple option, which defaults to 5. To calculate the maximum wait queue size, the driver multiplies WaitQueueMultiple by MaxConnectionPoolSize. If you use the default value for each option, the wait queue size will be 500. You can also set the wait queue size by specifying the WaitQueueSize option, which overrides the other settings. However, we do not recommend changing the wait queue size from the default.

Connection pools are rate-limited. The MaxConnecting setting determines the number of connections that the pool can create in parallel at any time. For example, if the value of MaxConnecting is 2, the third thread that attempts to concurrently check out a connection succeeds only in one of the following cases:

  • One of the first two threads finishes creating a connection.

  • An existing connection is checked back into the pool.

  • The driver's ability to reuse existing connections improves due to rate-limits on connection creation.

You can set the minimum number of concurrent connections to each server by using the MinConnectionPoolSize option, which defaults to 0. The connection pool will be initialized with this number of sockets. If errors cause any sockets to close and the total number of sockets (both in-use and idle) drops below the minimum, the driver opens more sockets until the number reaches the minimum.

You can set the maximum number of milliseconds that a connection can remain idle in the pool by using the MaxConnectionIdleTime option. Once a connection is idle for MaxConnectionIdleTime, the driver removes it. This option defaults to 10 minutes. If the pool size falls below MinConnectionPoolSize, the driver removes and replaces the idle connection.

MongoClient also has the MaxConnectionLifeTime option, which specifies the length of time, 30 minutes by default, that a connection can be pooled before expiring.

The following default configuration for a MongoClient works for most applications:

var client = new MongoClient("<connection string>");

Create a client once for each process, and reuse it for all operations. It is a common mistake to create a new client for each request, which is very inefficient.

There is no supported way to terminate a MongoClient in the driver.

Each driver operation requires that you choose a healthy server satisfying the server selection criteria. If you do not select an appropriate server within the server selection timeout, the driver throws a server selection timeout exception. The exception looks similar to the following:

A timeout occurred after 30000ms selecting a server using CompositeServerSelector{ Selectors = MongoDB.Driver.MongoClient+AreSessionsSupportedServerSelector, LatencyLimitingServerSelector{ AllowedLatencyRange = 00:00:00.0150000 }, OperationsCountServerSelector }.
Client view of cluster state is
{
ClusterId : "1",
Type : "Unknown",
State : "Disconnected",
Servers :
[{
ServerId: "{ ClusterId : 1, EndPoint : "Unspecified/localhost:27017" }",
EndPoint: "Unspecified/localhost:27017",
ReasonChanged: "Heartbeat",
State: "Disconnected",
ServerVersion: ,
TopologyVersion: ,
Type: "Unknown",
HeartbeatException: "<exception details>"
}]
}.

The error message consists of multiple parts:

  1. The server selection timeout (30000 ms).

  2. The server selectors considered (CompositeServerSelector containing AreSessionsSupportedServerSelector, LatencyLimitingServerSelector, and OperationsCountServerSelector).

  3. The driver’s current view of the cluster topology. The list of servers that the driver is aware of is a key part of this view. Each server description contains an exhaustive description of its current state including information about an endpoint, a server version, a server type, and its current health state. If the server encounters issues in reporting its health, HeartbeatException contains the exception from the last failed heartbeat. Analyzing the HeartbeatException on each cluster node can assist in diagnosing most server selection issues. The following heartbeat exceptions are common:

    • No connection could be made because the target machine actively refused it: The driver cannot see this cluster node. This can be because the cluster node has crashed, a firewall is preventing network traffic from reaching the cluster node or port, or some other network error is preventing traffic from being successfully routed to the cluster node.

    • Attempted to read past the end of the stream: This error happens when the driver cannot connect to the cluster nodes due to a network error, misconfigured firewall, or other network issue. To address this exception, ensure that all cluster nodes are reachable. This error commonly occurs when the client machine’s IP address is not configured in the Atlas IPs Access List, which can be found under the Network Access tab for your Atlas Project.

    • The remote certificate is invalid according to the validation procedure: This error typically indicates a TLS/SSL-related problem such as an expired/invalid certificate or an untrusted root CA. You can use tools like openssl s_client to debug TLS/SSL-related certificate problems.

If you're used to programming in C#, consider using LINQ because of its similar feel to programming in native C#. If you have prior experience with other MongoDB drivers, consider using Builder classes because of their consistency with other drivers.

We encourage experimenting with both approaches to determine the most suitable mechanism for your purposes.

Each LINQ or Builder expression must be available in the Query API. This is not always possible for the following reasons:

  1. You are attempting to use a .NET/C# feature that does not have an equivalent MongoDB representation. For example, .NET/C# and MongoDB have different semantics around collations.

  2. The driver does not support a particular transformation from LINQ or Builder expression into MQL (MongoDB Query Language). This may happen because the provided query has no MQL translation or because a feature has not been implemented yet in the driver.

If you receive an Unsupported filter ... or Expression not supported ... exception message, try the following steps:

  1. Try configuring the new LINQ3 provider. The LINQ3 provider contains many fixes and new features over the LINQ2 provider.

  2. Use the MongoDB C# Analyzer to analyze your expressions.

  3. Try to simplify your query where possible.

  4. Provide a query as a BsonDocument or JSON string. All driver definition classes such as FilterDefinition, ProjectionDefinition, and PipelineDefinition support implicit conversion from BsonDocument or JSON string. For example, the following filters are equivalent when used in a query or aggregation:

FilterDefinition<Entity> typedFilter = Builders<Entity>.Filter.Eq(e => e.A, 1);
FilterDefinition<Entity> bsonFilter = new BsonDocument {{ "a", 1 }};
FilterDefinition<Entity> jsonFilter = "{ a : 1 }";

Note

If you use BsonDocument or JSON string, then BsonClassMap, BSON serialization attributes, and serialization conventions are not taken into account in the Query API. Field names must match the names and casing as stored by the server. For example, when referencing the _id field, you must refer to it using _id in BsonDocument or JSON string definitions. Similarly, if a document has a field FirstName annotated with [BsonElement("first_name")], you must refer to it as first_name in BsonDocument or JSON string definitions.

You can combine the raw and typed forms in the same query, as the following code demonstrates:

FilterDefinition<Entity> filter = Builders<Entity>.Filter
.And(Builders<Entity>.Filter
.Eq(e => e.A, 1), BsonDocument
.Parse("{ b : 2 }"));

The ObjectSerializer allows serialization and deserialization only of types that are considered safe. When you construct an ObjectSerializer, you can pass in a delegate of type Func<Type, bool>. This delegate accepts an object type and returns a boolean value indicating whether the type is safe for serialization.

In most cases, you should pass in the ObjectSerializer.DefaultAllowedTypes() delegate. This method returns true for a number of well-known framework types that we have deemed safe. To serialize custom types, create a boolean expression that evaluates to true for the types you want to include. Then, add this expression to the end of the delegate you pass to the ObjectSerializer constructor.

In the following example, the ObjectSerializer will serialize and deserialize any type that is allowed by ObjectSerializer.DefaultAllowedTypes() or whose full name begins with "MyNamespace":

var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type)
|| type.FullName.StartsWith("MyNamespace"));
BsonSerializer.RegisterSerializer(objectSerializer);

To allow anonymous types to be serialized, add the boolean expression type.FullName.StartsWith("<>f__AnonymousType")) to your delegate, as shown in the following example:

var objectSerializer = new ObjectSerializer(type => ObjectSerializer.DefaultAllowedTypes(type)
|| type.FullName.StartsWith("<>f__AnonymousType"));
BsonSerializer.RegisterSerializer(objectSerializer);

You should create and register your ObjectSerializer at the start of your program, before doing anything else.

← In-Use Encryption