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
相关产品推荐
相关产品推荐

