You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MongoDB C#驱动配置MapCreator后仍序列化Position类报错

问题解决:GeoJSON.Net Position类与MongoDB C#驱动序列化冲突

错误原因

你遇到的Creator map for class GeoJSON.Text.Geometry.Position has 3 arguments, but none are configured错误,本质是MongoDB C#驱动无法自动匹配Position类构造函数的参数与BSON文档字段的对应关系。原配置中AutoMap()与MapCreator的组合没有明确绑定构造参数和属性,导致驱动无法完成序列化/反序列化。

另外需要注意:GeoJSON.Net的Position类默认会序列化为带Longitude/Latitude属性的对象,但MongoDB要求GeoJSON坐标是数组格式([经度, 纬度, 海拔]),这也是后续需要修正的核心点,否则MongoDB无法识别为合法的地理空间类型。

解决方案

1. 替换Position类的BSON映射配置

放弃AutoMap(),手动绑定构造参数与属性,确保驱动能正确解析构造函数:

BsonClassMap.RegisterClassMap<Position>(cm =>
{
    // 手动映射属性到BSON字段名(符合GeoJSON标准)
    cm.MapProperty(p => p.Longitude).SetElementName("longitude");
    cm.MapProperty(p => p.Latitude).SetElementName("latitude");
    cm.MapProperty(p => p.Altitude).SetElementName("altitude");

    // 绑定构造函数参数与对应属性
    var constructor = typeof(Position).GetConstructor(new[] { typeof(double), typeof(double), typeof(double) });
    if (constructor != null)
    {
        cm.MapConstructor(constructor)
          .SetParameter(0, cm.GetMemberMap(p => p.Longitude))
          .SetParameter(1, cm.GetMemberMap(p => p.Latitude))
          .SetParameter(2, cm.GetMemberMap(p => p.Altitude));
    }
});

2. 添加自定义序列化器(关键:适配MongoDB GeoJSON数组格式)

为Position类编写自定义序列化器,将其序列化为MongoDB期望的数组格式:

public class PositionSerializer : IBsonSerializer<Position>
{
    public Type ValueType => typeof(Position);

    public Position Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
    {
        var bsonArray = context.Reader.ReadBsonArray();
        var longitude = bsonArray[0].AsDouble;
        var latitude = bsonArray[1].AsDouble;
        var altitude = bsonArray.Count > 2 ? bsonArray[2].AsDouble : null;
        return new Position(longitude, latitude, altitude);
    }

    public void Serialize(BsonSerializationContext context, BsonSerializationArgs args, Position value)
    {
        var array = new BsonArray();
        array.Add(value.Longitude);
        array.Add(value.Latitude);
        if (value.Altitude.HasValue)
        {
            array.Add(value.Altitude.Value);
        }
        context.Writer.WriteBsonArray(array);
    }

    // 实现IBsonSerializer的非泛型接口方法
    object IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)
        => Deserialize(context, args);

    void IBsonSerializer.Serialize(BsonSerializationContext context, BsonSerializationArgs args, object value)
        => Serialize(context, args, (Position)value);
}

3. 注册序列化器与映射

在MongoDB初始化代码中,先注册序列化器,再注册类映射:

// 先注册Position自定义序列化器
BsonSerializer.RegisterSerializer(new PositionSerializer());

// 再注册Position类映射
BsonClassMap.RegisterClassMap<Position>(cm =>
{
    cm.MapProperty(p => p.Longitude).SetElementName("longitude");
    cm.MapProperty(p => p.Latitude).SetElementName("latitude");
    cm.MapProperty(p => p.Altitude).SetElementName("altitude");

    var constructor = typeof(Position).GetConstructor(new[] { typeof(double), typeof(double), typeof(double) });
    if (constructor != null)
    {
        cm.MapConstructor(constructor)
          .SetParameter(0, cm.GetMemberMap(p => p.Longitude))
          .SetParameter(1, cm.GetMemberMap(p => p.Latitude))
          .SetParameter(2, cm.GetMemberMap(p => p.Altitude));
    }
});

// 其余初始化代码保持不变
var objectSerializer = new ObjectSerializer(ObjectSerializer.AllAllowedTypes);
BsonSerializer.TryRegisterSerializer(objectSerializer);
BsonSerializer.TryRegisterSerializer(new GuidSerializer(GuidRepresentation.Standard));  

var mongoUrl = MongoUrl.Create(connectionString);
var client = new MongoClient(mongoUrl);
var db = client.GetDatabase(mongoUrl.DatabaseName);

为什么原配置无效?

原配置中AutoMap()会自动扫描类的构造函数和属性,但没有明确告诉驱动构造参数对应的BSON字段。MapCreator仅指定了构造函数的调用方式,却未绑定参数与属性的关联,导致驱动无法在序列化/反序列化时匹配数据。

内容的提问来源于stack exchange,提问作者Juzzbott

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 20:03:17