Docs 菜单
Docs 主页
/ / /
C#/.NET

FAQ

在此页面上

  • 为什么连接 MongoDB 时会出错?
  • 连接池化在 .NET/C# 驱动程序中是如何工作的?
  • 为什么驱动程序在选择服务器时会抛出超时错误?
  • 查询文档时应该使用 LINQ 还是构建器类?
  • 某些 LINQ 或生成器表达式为何不受支持?
  • 哪些对象类型可以序列化?
  • .NET/ C#驱动程序和MongoDB实体框架核心提供程序之间有什么区别?

本页包含常见问题及其相应解答。

提示

如果在此页面上找不到问题的回答,请参阅问题和帮助页面,了解后续步骤和更多资源。

如果在连接到 MongoDB 部署时出现问题,请参阅连接故障排除指南,了解潜在的解决方案。

对于 MongoDB 拓扑结构中的每个服务器,每个 MongoClient 实例都有一个内置连接池。连接池按需打开套接字以支持多线程应用程序中的并发 MongoDB 操作。

每个连接池的最大大小由MaxConnectionPoolSize选项设置,默认为100 。 如果正在使用的服务器连接数达到MaxConnectionPoolSize值,则对该服务器的下一个请求将等待,直到出现可用连接。 下图概括地说明了MongoClient如何管理连接池:

CMAP 图

除了支持应用程序线程所需的套接字之外,每个MongoClient实例还为 MongoDB 拓扑结构中的每个服务器再打开两个套接字,用于监控服务器的状态。 例如,连接到三节点副本集的客户端会打开六个监控套接字。 如果应用程序使用MaxConnectionPoolSize的默认设置,并且仅查询主(默认)节点,则在使用的总连接数最多可以为106 。 如果应用程序使用读取偏好来查询从节点,则这些连接池会增长,总连接数可能为306

要在一个进程中支持大量并发 MongoDB 线程,可以增加 MaxConnectionPoolSize

驱动程序有一个等待队列,用于限制可以等待连接的线程数。等待队列的大小由 WaitQueueMultiple 选项决定,默认为 5。计算等待队列大小的最大值时,驱动程序将 WaitQueueMultiple 乘以 MaxConnectionPoolSize。如果对每个选项使用默认值,则等待队列大小为 500。还可以通过指定 WaitQueueSize 选项来设置等待队列大小,该选项会覆盖其他设置。但是,我们不建议更改默认等待队列大小。

连接池的速率受到了限制。MaxConnecting 设置将决定连接池在任何时候可以并行创建的连接数量。例如,如果 MaxConnecting的值为 2,尝试同时签出连接的第三个线程只在下面的其中一种情况下才会成功:

  • 前两个线程之一完成了连接创建操作。

  • 现有连接会重新检入池中。

  • 由于对创建连接的速率有限制,驱动程序重用现有连接的能力得到了提高。

您可以使用 MinConnectionPoolSize 选项设置每个服务器的最小并发连接数量,此值默认为 0。系统将使用这一数量的套接字对连接池进行初始化。如果错误导致任何套接字关闭,而且(使用中和空闲的)套接字总数低于最小值,驱动程序将打开更多的套接字,直到此数量达到最小值。

您可以使用 MaxConnectionIdleTime 选项设置一个连接在连接池中保持空闲状态的最大毫秒数。当一个连接的空闲时间达到 MaxConnectionIdleTime 之后,驱动程序就会将其删除。此选项的默认值为 10 分钟。如果池大小低于 MinConnectionPoolSize,驱动程序将删除替换空闲连接。

MongoClient 还具有 MaxConnectionLifeTime 选项,此选项将指定一个连接在过期之前可以池化的时间长度(默认值为 30 分钟)。

以下 MongoClient 的默认配置适用于大多数应用程序:

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

为每个进程创建一个客户端,并在所有操作中重复使用。为每个请求创建一个新客户端是个常见的错误,效率非常低。

不支持在驱动程序中终止 MongoClient 方法。

每个驾驶员操作都要求您选择满足服务器选择条件的正常服务器。如果未在服务器选择超时 内选择适当的服务器,驾驶员将引发服务器选择超时异常。该异常看起来类似于以下内容:

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>"
}]
}.

错误信息由多个部分组成:

  1. 服务器选择超时(30000 毫秒)。

  2. 考虑的服务器选择器(CompositeServerSelector,包含 AreSessionsSupportedServerSelectorLatencyLimitingServerSelectorOperationsCountServerSelector)。

  3. 驱动程序对集群拓扑的当前视图。驱动程序感知到的服务器列表是该视图的关键部分。每个服务器描述都包含其当前状态的详尽描述,包括端点信息、服务器版本、服务器类型及其当前健康状态。如果服务器在报告健康状况时遇到问题,HeartbeatException 包含自上次失败的心跳以来的异常。分析每个集群节点上的 HeartbeatException 可以帮助诊断大多数服务器选择问题。以下是常见的心跳异常:

    • No connection could be made because the target machine actively refused it:驱动程序看不到此群集节点。这可能是因为集群节点已崩溃、防火墙导致网络流量无法到达集群节点或端口,或者其他网络错误导致流量无法成功路由到集群节点。

    • Attempted to read past the end of the stream:由于网络错误、防火墙配置错误或其他网络问题,导致驱动程序无法连接到集群节点时,会出现此错误。如需解决此异常,请确保所有集群节点都可以连接。当客户端机器的 IP 地址未配置在 Atlas IP 访问列表中时,通常会出现此错误,该列表可在 Atlas 项目的 Network Access 标签页下找到。

    • The remote certificate is invalid according to the validation procedure:该错误通常表示 TLS/SSL 相关问题,如证书过期/无效或根 CA 不可信。您可以使用 openssl s_client 等工具来调试与 TLS/SSL 相关的证书问题。

如果您习惯于使用 C# 进行编程,请考虑使用 LINQ,因为它与原生 C# 编程的感觉相似。如果您以前有使用其他 MongoDB 驱动程序的经验,请考虑使用构建者类,因为它们与其他驱动程序保持一致。

我们鼓励尝试这两种方法,以确定最适合您目的的机制。

每个 LINQ 或“生成器”表达式都必须在“查询 API”中可用。由于以下原因,这种操作并不总是可行的:

  1. 您尝试使用的 .NET/C# 功能没有与 MongoDB 对应的表示。例如,.NET/C# 和 MongoDB 在排序规则方面有不同的语义。

  2. 驱动程序不支持从 LINQ 或 Builder 表达式到 MQL(MongoDB 查询语言)的特定转换。发生这种情况的原因可能是所提供的查询没有 MQL 转换,或者驱动程序中尚未实现某项功能。

如果收到 Unsupported filter ...(不支持的筛选器...)或 Expression not supported ...(表达式不受支持...)异常消息,请尝试以下步骤:

  1. 尝试配置新的 LINQ3 提供商。与3 LINQ 提供程序相比,LINQ2 提供程序包含许多修复和新功能。

  2. 使用MongoDB C# 分析器分析表达式。

  3. 尽可能简化查询。

  4. BsonDocument 或 JSON 字符串形式提供查询。所有驱动程序定义类(例如 FilterDefinitionProjectionDefinitionPipelineDefinition 都支持从 BsonDocument 或 JSON 字符串进行隐式转换。例如,以下过滤器在查询或聚合中使用时是等效的:

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

注意

如果使用BsonDocument 或JSONstring ,则 BsonClassMap 、BSON 序列化属性和序列化约定不会在 QueryAPI 中考虑。字段名称必须与服务器存储的名称和大小写一致。 例如,引用 _id 字段时,必须使用 BsonDocument 中的 _id 或JSON string定义来引用它。 同样,如果文档具有用 [BsonElement("first_name")] 注释的字段 FirstName,则必须在 BsonDocument 或JSON string定义中将其引用为 first_name

您可以在同一查询中将原始和键入形式结合起来,如下代码所示:

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

ObjectSerializer 只允许对被视为安全的类型进行序列化和反序列化。当构造 ObjectSerializer 时,您可以传入类型为 Func<Type, bool> 的委托。此委托接受一个对象类型并返回一个布尔值,以表明是否可以安全地对此类型进行序列化。

在大多数情况下,应传入 ObjectSerializer.DefaultAllowedTypes() 委托。对于我们认为安全的许多知名框架类型,此方法会返回 true。要序列化自定义类型,请为要包含的类型创建一个值为 true 的布尔表达式。然后,将此表达式添加到传递给 ObjectSerializer 构造函数的委托的末尾。

在以下示例中,ObjectSerializer 会序列化和反序列化ObjectSerializer.DefaultAllowedTypes() 允许的或其全名以 "MyNamespace" 开头的任何类型:

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

要允许序列化匿名类型,请将布尔表达式 type.FullName.StartsWith("<>f__AnonymousType")) 添加到委托中,如如下示例所示:

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

您应在程序启动时创建并注册 ObjectSerializer,然后再执行任何其他操作。

.NET/ C#驱动程序是一个直接公开MongoDB功能的库,包括具有投影、群组操作和灵活映射功能的 LINQ提供商。 该驾驶员包含以下功能:

  • 事务

  • 批量操作

  • LINQ 查询

  • 直接修改数据库的操作

  • 聚合操作

  • 自定义映射

Entity Framework Core 提供程序允许您在.NET/ C#应用程序中将 Microsoft 的 Entity Framework Core 与MongoDB结合使用。 实体框架核心提供程序支持变更跟踪、基于实体的 LINQ 操作以及实体框架核心用户熟悉的建模。 该提供商包括以下功能:

  • 智能对象跟踪

  • 基于实体的 LINQ 操作

  • 使用 Fluent API进行实体框架建模和映射

  • 通过变更跟踪自动更新数据库

后退

监控