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

反序列化带$id的Cosmos DB对象时出现JsonSerializationException如何解决?

错误根因

你配置的MetadataPropertyHandling.Ignore会让Newtonsoft.Json将$id、$ref这类JSON元数据字段识别为普通业务字段,而非引用处理标记。当PreserveReferencesHandling.All序列化集合类型时,会生成{"$id":"xxx","$values":[实际集合内容]}的结构,反序列化时元数据处理被关闭,Json.NET会将该结构识别为普通对象,自然无法转换为List<T>/数组类型,触发类型不匹配错误。

解决方案

方案1:保留引用处理能力(无需修改存量数据)

如果你的业务需要用到PreserveReferencesHandling提供的循环引用处理、引用复用能力,只需要将MetadataPropertyHandling从Ignore修改为Default即可,Json.NET会自动识别$开头的元数据字段,正确解析带$id的集合:

var cosmosClientOptions = new CosmosClientOptions()
{
    ConnectionMode = ConnectionMode.Direct,
    Serializer = new CosmosJsonNetSerializer(new JsonSerializerSettings()
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Default, // 仅修改这一行
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        PreserveReferencesHandling = PreserveReferencesHandling.All,
        NullValueHandling = NullValueHandling.Include,
        TypeNameHandling = TypeNameHandling.None,
    })
};

该方案修改成本极低,不需要调整存量数据,新写入的数据仍会保留$id字段实现引用处理逻辑。

方案2:彻底移除$id字段(兼容存量数据+新数据无冗余字段)

如果你不需要引用处理能力,希望存量和新数据都不带额外的$id元数据字段,按以下步骤配置:

  1. 新增自定义Json转换器,处理存量数据中带$id的集合解析:
public class IgnoreReferenceMetadataConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        // 适配所有集合、数组类型
        return objectType.IsArray || 
               (objectType.IsGenericType && typeof(IEnumerable).IsAssignableFrom(objectType) && objectType != typeof(string));
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JToken token = JToken.Load(reader);
        // 处理带$id元数据的集合结构
        if (token.Type == JTokenType.Object && ((JObject)token).TryGetValue("$values", out JToken collectionValue))
        {
            return collectionValue.ToObject(objectType, serializer);
        }
        return token.ToObject(objectType, serializer);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        serializer.Serialize(writer, value);
    }
}
  1. 调整序列化配置,关闭引用处理并注册转换器:
var cosmosClientOptions = new CosmosClientOptions()
{
    ConnectionMode = ConnectionMode.Direct,
    Serializer = new CosmosJsonNetSerializer(new JsonSerializerSettings()
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Ignore,
        ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
        PreserveReferencesHandling = PreserveReferencesHandling.None, // 关闭引用处理
        NullValueHandling = NullValueHandling.Include,
        TypeNameHandling = TypeNameHandling.None,
        Converters = new List<JsonConverter> { new IgnoreReferenceMetadataConverter() } // 注册转换器
    })
};

该方案可直接兼容存量带$id的文档,新写入的文档不会再生成冗余的元数据字段。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 06:48:01