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

MongoDB插入时抛出BsonSerializationException异常的解决咨询

解决MongoDB存储含URL键的字典时的序列化异常问题

这个问题本质是MongoDB的BSON文档字段名有严格规则:不能包含/、.、$这些特殊字符,而你的Metadata字典用了带/和:的URL作为键,默认序列化会把字典键直接转成BSON字段名,所以触发了BsonSerializationException。下面给你几个可行的解决方案:

方案1:使用特性指定字典的序列化方式(最简单)

直接给Metadata属性添加BsonDictionaryOptions特性,指定字典序列化为数组形式的文档,而不是嵌入式的键值对。这样MongoDB会把字典存储为包含k(键)和v(值)的对象数组,完全避开非法字段名的问题。

修改你的模型:

using MongoDB.Bson.Serialization.Attributes;

public class UserInfo{
    public string Id{get;}
    [BsonDictionaryOptions(DictionaryRepresentation.ArrayOfDocuments)]
    public Dictionary<string, string> Metadata{ get; }
}

这样插入数据时,Metadata会被序列化成类似这样的BSON结构:

"Metadata": [
    { "k": "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name", "v": "your-value" },
    { "k": "other-key", "v": "other-value" }
]

读取数据时,MongoDB驱动会自动把这个数组反序列回Dictionary<string, string>,完全不影响你的业务逻辑。

方案2:自定义字典键的序列化器(保持嵌入式结构)

如果你希望保持字典的嵌入式结构(即键直接作为BSON字段名),可以自定义一个序列化器,把非法的键字符替换成合法字符,反序列化时再还原。

示例代码:

using MongoDB.Bson.Serialization;
using MongoDB.Bson.Serialization.Serializers;

public class SafeDictionarySerializer : DictionarySerializerBase<Dictionary<string, string>, string, string>
{
    protected override Dictionary<string, string> CreateInstance() => new();

    protected override string DeserializeKey(BsonDeserializationContext context)
    {
        // 反序列化时把替换的字符还原回原URL
        var key = base.DeserializeKey(context);
        return key.Replace("_slash_", "/").Replace("_colon_", ":");
    }

    protected override void SerializeKey(BsonSerializationContext context, string key)
    {
        // 序列化时把URL中的非法字符替换成合法的
        var safeKey = key.Replace("/", "_slash_").Replace(":", "_colon_");
        base.SerializeKey(context, safeKey);
    }
}

然后在模型上指定使用这个序列化器:

[BsonSerializer(typeof(SafeDictionarySerializer))]
public Dictionary<string, string> Metadata{ get; }

这样存储时,URL键会被转换成http__slash__schemas.xmlsoap.org_slash_ws_slash_2005_slash_05_slash_identity_slash_claims_slash_name这种合法的字段名,读取时自动还原成原URL。

方案3:修改模型结构为键值对列表

如果可以接受修改模型的存储结构,把Dictionary<string, string>改成List<KeyValuePair<string, string>>,这样存储时每个键值对都是独立的对象,不存在非法字段名的问题:

public class UserInfo{
    public string Id{get;}
    public List<KeyValuePair<string, string>> Metadata{ get; }
}

这种方式的优点是完全不需要处理序列化逻辑,缺点是你在业务代码中需要把字典转换成列表,或者直接用列表来操作数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:02:18