文档菜单
文档首页
/ / /
C#/.NET

常见问题解答

本页内容

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

本页包含常见问题及其答案。

提示

如果您在本页找不到解决问题的答案,请参阅问题与帮助页面以获取下一步操作和更多资源。

如果您在连接到MongoDB部署时遇到麻烦,请参阅连接故障排除指南以获取可能的解决方案。

每个MongoClient实例为其MongoDB拓扑中的每个服务器都有一个内置的连接池。连接池根据需要打开套接字以支持多线程应用程序中的并发MongoDB操作。

每个连接池的最大大小由MaxConnectionPoolSize选项设置,默认为100。如果连接到服务器的使用中连接数达到MaxConnectionPoolSize的值,则对该服务器的下一个请求将等待,直到有连接可用。以下图展示了MongoClient如何管理连接池的高级视图

CMAP diagram

除了支持应用程序线程所需的套接字之外,每个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将包含最后一次失败的 heartbeat 异常。分析每个集群节点的HeartbeatException可以帮助诊断大多数服务器选择问题。以下 heartbeat 异常是常见的

    • 无法建立连接,因为目标机器主动拒绝:驱动程序看不到此集群节点。这可能是由于集群节点已崩溃,防火墙阻止网络流量到达集群节点或端口,或某些其他网络错误阻止流量成功路由到集群节点。

    • 尝试读取流末尾之后的内容:此错误发生在由于网络错误、配置不当的防火墙或其他网络问题导致驱动程序无法连接到集群节点时。要解决此异常,请确保所有集群节点可访问。此错误通常发生在客户端机器的IP地址未配置在Atlas IP访问列表中,该列表位于网络访问选项卡下,用于您的Atlas项目。

    • 远程证书根据验证程序无效:此错误通常指示与TLS/SSL相关的问题,例如过期的/无效的证书或不受信任的根CA。您可以使用类似openssl s_client的工具来调试TLS/SSL相关的证书问题。

如果您习惯于使用C#编程,请考虑使用LINQ,因为它与原生C#编程的感觉相似。如果您有其他MongoDB驱动程序的使用经验,请考虑使用Builder类,因为它们与其他驱动程序的一致性更高。

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

每个LINQ或Builder表达式都必须在查询API中可用。以下原因可能导致此情况

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

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

如果您收到“不支持的过滤器 ...”或“表达式不受支持 ...”异常消息,请尝试以下步骤

  1. 使用MongoDB C# Analyzer分析您的表达式。

  2. 尽可能简化您的查询。

  3. 将查询作为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或JSON字符串,则在查询API中不考虑BsonClassMap、BSON序列化属性和序列化约定。字段名必须与服务器存储的名称和大小写匹配。例如,当引用_id字段时,您必须在BsonDocument或JSON字符串定义中使用_id。同样,如果一个文档有一个字段FirstName被注释为[BsonElement("first_name")],您必须在BsonDocument或JSON字符串定义中将其称为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。Entity Framework Core 提供程序支持智能对象跟踪、基于实体的 LINQ 操作以及 Entity Framework Core 用户熟悉的建模。该提供程序包括以下功能:

  • 智能对象跟踪

  • 基于实体的 LINQ 操作

  • 使用流畅 API 进行 Entity Framework 建模和映射

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

返回

OData