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

使用Microsoft.Azure.Cosmos 3.20.1调用ReadNextAsync抛出JSON序列化错误

Cosmos DB 3.20.1 查询大集合时反序列化Id冲突问题解决方案

根本原因

你遇到的错误和Cosmos DB内存储的文档id字段无关,是Newtonsoft.Json的引用跟踪机制和旧版Cosmos SDK内置序列化器的缓存复用逻辑冲突导致的:

  • 3.20.1版本的Cosmos SDK内置的Newtonsoft序列化器默认开启了引用跟踪,会在反序列化时把JSON里的$id标识符存入全局缓存
  • 大数据量查询需要多次调用ReadNextAsync拉取多页数据,同一序列化器实例会复用同一缓存
  • 不同分页的JSON返回结果中存在相同的$id值时,就会触发A different value already has the Id冲突,小数据量单页即可拉取完成时不会触发该问题

解决方案

方案1:自定义序列化器禁用引用跟踪(最稳定兼容)

自定义Cosmos序列化器,显式关闭Newtonsoft的引用跟踪配置,彻底避免跨分页的引用ID冲突:

public class CustomCosmosSerializer : CosmosSerializer
{
    private readonly JsonSerializer _jsonSerializer;

    public CustomCosmosSerializer()
    {
        _jsonSerializer = new JsonSerializer
        {
            // 核心配置:禁用引用跟踪
            PreserveReferencesHandling = PreserveReferencesHandling.None,
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
            // 可自行添加其他序列化配置,如命名策略、日期格式化规则等
        };
    }

    public override T FromStream<T>(Stream stream)
    {
        using (stream)
        using (var streamReader = new StreamReader(stream))
        using (var jsonReader = new JsonTextReader(streamReader))
        {
            return _jsonSerializer.Deserialize<T>(jsonReader);
        }
    }

    public override Stream ToStream<T>(T input)
    {
        var memoryStream = new MemoryStream();
        using (var streamWriter = new StreamWriter(memoryStream, leaveOpen: true))
        using (var jsonWriter = new JsonTextWriter(streamWriter))
        {
            _jsonSerializer.Serialize(jsonWriter, input);
            streamWriter.Flush();
        }
        memoryStream.Position = 0;
        return memoryStream;
    }
}

在你的GetCosmosClientOptionsClientOptions方法中注入自定义序列化器:

protected static CosmosClientOptions GetCosmosClientOptionsClientOptions(int maxRetryAttemptsOnThrottledRequests = 3, int maxRetryWaitTimeInSeconds = 180)
{
    return new CosmosClientOptions()
    {
        ConnectionMode = Microsoft.Azure.Cosmos.ConnectionMode.Direct,
        RequestTimeout = new TimeSpan(0, 1, 0),
        MaxTcpConnectionsPerEndpoint = 1000, 
        MaxRetryAttemptsOnRateLimitedRequests = maxRetryAttemptsOnThrottledRequests,
        MaxRetryWaitTimeOnRateLimitedRequests = TimeSpan.FromSeconds(maxRetryWaitTimeInSeconds),
        AllowBulkExecution = true,
        // 注入自定义序列化器
        Serializer = new CustomCosmosSerializer()
    };
}

方案2:升级Cosmos SDK版本

3.20.1之后的3.x稳定版已经修复了内置序列化器的缓存复用问题,你可以直接将Microsoft.Azure.Cosmos包升级到3.38.1及以上的最新3.x稳定版本,无需修改业务代码即可解决该问题。

临时规避方案

如果暂时无法做版本升级或序列化器修改,可以在QueryRequestOptions中调小单次拉取的条目数,降低冲突概率:

var requestOptions = new QueryRequestOptions
{
    MaxItemCount = 100
};

该方案仅为临时缓解,大数据量场景下仍有可能触发冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 06:51:03