ASP.NET Core操作MongoDB反序列化报JsonElement鉴别值未知错误
问题背景
正在开发集成MongoDB的ASP.NET Core项目,需要从HotelBookingDocument集合获取已预订酒店列表,相关实体定义如下:
public class HotelBookingDocument { public string Id { get; set; } public HotelDocument Hotel { get; set; } // 其余代码省略 } public class HotelDocument { public List<RoomDocument> Rooms { get; set; } // 其余代码省略 } public class RoomDocument { public object SupplierReference { get; set; } // 其余代码省略 } // 其余代码省略
已完成如下Bson序列化配置:
BsonClassMap.RegisterClassMap<HotelBookingDocument>(cm => { cm.AutoMap(); cm.SetIgnoreExtraElements(true); cm.MapIdMember(c => c.Id) .SetSerializer(new StringSerializer(BsonType.ObjectId)) .SetIgnoreIfDefault(true); }); BsonClassMap.RegisterClassMap<RoomDocument>(cm => { cm.AutoMap(); }); BsonClassMap.RegisterClassMap<HotelDocument>(cm => { cm.AutoMap(); });
查询方法代码如下:
public async Task<List<HotelBookingDocument>> GetHotelsList(string transactionId) { var hotels = await HotelBookingCollection.Find(x => x.TransactionId == transactionId).ToListAsync(); // 此处执行报错 return hotels; }
检查数据库存储时发现,部分文档的SupplierReference字段自动添加了"_t": "JsonElement"鉴别符,存储结构如下:
"SupplierReference": { "_t": "JsonElement" },
字段存储截图:
执行列表查询时抛出如下异常:
System.FormatException: An error occurred while deserializing the Hotel property of class HotelBookingDocument: An error occurred while deserializing the Rooms property of class HotelBookingDocument+HotelDocument: An error occurred while deserializing the SupplierReference property of class HotelBookingDocument+RoomDocument: Unknown discriminator value 'JsonElement'. ---> System.FormatException: An error occurred while deserializing the Rooms property of class HotelBookingDocument+HotelDocument: An error occurred while deserializing the SupplierReference property of class HotelBookingDocument+RoomDocument: Unknown discriminator value 'JsonElement'. ---> System.FormatException: An error occurred while deserializing the SupplierReference property of class HotelBookingDocument+RoomDocument: Unknown discriminator value 'JsonElement'. ---> MongoDB.Bson.BsonSerializationException: Unknown discriminator value 'JsonElement'. at MongoDB.Bson.Serialization.BsonSerializer.LookupActualType(Type nominalType, BsonValue discriminator) at MongoDB.Bson.Serialization.Conventions.ObjectDiscriminatorConvention.GetActualType(IBsonReader bsonReader, Type nominalType) at MongoDB.Bson.Serialization.Serializers.ObjectSerializer.DeserializeDiscriminatedValue(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.ObjectSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args) at MongoDB.Bson.Serialization.Serializers.SerializerBase`1.MongoDB.Bson.Serialization.IBsonSerializer.Deserialize(BsonDeserializationContext context, BsonDeserializationArgs args)...............
当前现象:按transactionId查询酒店预订列表时触发上述反序列化错误,但查询单条酒店预订文档时可正常返回第一条数据,无报错。
根因分析
_t是MongoDB C#驱动内置的类型鉴别符字段:当属性声明类型为object等非明确类型时,驱动序列化时会自动写入_t字段,存储值的实际运行时类型,用于反序列化时还原对应类型实例。- 数据库中出现
"_t": "JsonElement"的原因:写入对应文档时,SupplierReference属性被赋值为System.Text.Json.JsonElement类型的值(常见场景为接口直接接收Json请求未做强类型映射、处理动态Json节点时直接将JsonElement传入该object属性),驱动序列化时自动将运行时类型名JsonElement作为鉴别符写入存储。 - 反序列化报错原因:
JsonElement是System.Text.Json的专属结构体,MongoDB C#驱动默认没有注册该类型的序列化器,也没有对应鉴别符的类型映射规则。查询列表时驱动会遍历所有匹配条件的文档,一旦读取到带"_t": "JsonElement"的文档,尝试根据鉴别符查找对应类型失败就会抛出异常。而单条查询默认返回匹配结果的第一条,如果第一条文档不存在该异常鉴别符,就不会触发报错,和观测到的现象完全一致。
修复方案
- 优先方案:将
SupplierReference属性的声明类型从object改为业务对应的强类型,从根源上避免object类型序列化自动生成类型鉴别符的问题,同时减少后续运行时类型转换的异常风险。 - 动态类型适配方案:如果业务确实需要存储动态结构数据,给
SupplierReference属性显式指定序列化器,统一用BsonDocument处理动态值,避免写入JsonElement相关的无效鉴别符,示例配置:
BsonClassMap.RegisterClassMap<RoomDocument>(cm => { cm.AutoMap(); cm.MapMember(c => c.SupplierReference) .SetSerializer(new ObjectSerializer(BsonType.Document)); });
- 存量数据修复:清理数据库中已存在的带
"_t": "JsonElement"的脏数据,修正SupplierReference字段的存储结构,移除无效鉴别符,避免反序列化时匹配到未知类型。
内容的提问来源于stack exchange,提问作者hanushi-thana
相关产品推荐
相关产品推荐

