SauravBhattacharya
SauravBhattacharya

Reputation: 643

Cosmos DB ReadNextAsync throwing JSON Serialization error

I am using Microsoft.Azure.Cosmos 3.20.1. I am creating a cosmos client with managed identity,

using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Azure.Identity;
using Business.CosmosDB;
using Microsoft.Azure.Cosmos;
using Microsoft.Azure.Cosmos.Linq;
using Newtonsoft.Json;

namespace ConsoleApp2
{
    public class FlattenedProduct
    {
        [JsonProperty(PropertyName = "id")]
        public string id
        {
            get;
            set;
        }
        public string userType_language { get; set; } // partition Key
        public string Name { get; set; }
        public string Description { get; set; }
        public bool IsEnabled { get; set; }
        public bool IsFeatured { get; set; }

        [JsonProperty(PropertyName = "PartitionKey")]
        public string PartitionKey
        {
            get
            {
                return userType_language;
            }
        }
    }

    public class GridResults<T>
    {
        public int Total { get; set; }
        public List<T> Data { get; set; } = new List<T>();

        public long QueryDuration { get; set; }
    }
    class Program
    {
        static async Task Main(string[] args)
        {
            string endpoint = "https://xxx.documents.azure.com:443/";
            CosmosClient client = new CosmosClient(endpoint, new DefaultAzureCredential(), GetCosmosClientOptionsClientOptions());
            string databaseId = "xxx";
            var database = client.GetDatabase(databaseId);
            string collectionId = "FlattenedProduct";
            var container = database.GetContainer(collectionId);
            
            GridResults<FlattenedProduct> results = new GridResults<FlattenedProduct>();

            var requestOptions = new QueryRequestOptions();
            using (var setIterator = container.GetItemLinqQueryable<FlattenedProduct>(requestOptions: requestOptions).Where( x => x.IsEnabled).ToFeedIterator())
            {
                Microsoft.Azure.Cosmos.FeedResponse<FlattenedProduct> items = null;
                while (setIterator.HasMoreResults)
                {
                    try
                    {
                        items = await setIterator.ReadNextAsync();
                        foreach (var item in items)
                        {
                            results.Data.Add(item);
                        }

                        items = null;
                    }
                    catch (Exception e)
                    {
                    }
                }
            }
        }

        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
            };
        }
    }
}

I am getting the following exception on ReadNextAsync:

{"A different value already has the Id '1'."}
{"Error reading object reference '1'. Path '[37].userType_language (this is the partition key)', line 1, position 53422."}

I have checked that none of the records have id = 1.

Full stack trace

   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.AddReference(JsonReader reader, String id, Object value)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateObject(Object newObject, JsonReader reader, JsonObjectContract contract, JsonProperty member, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObject(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.PopulateList(IList list, JsonReader reader, JsonArrayContract contract, JsonProperty containerProperty, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateList(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, Object existingValue, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateValueInternal(JsonReader reader, Type objectType, JsonContract contract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerMember, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.JsonSerializer.Deserialize[T](JsonReader reader)
   at Microsoft.Azure.Cosmos.CosmosJsonDotNetSerializer.FromStream[T](Stream stream)
   at Microsoft.Azure.Cosmos.CosmosJsonSerializerWrapper.FromStream[T](Stream stream)
   at Microsoft.Azure.Cosmos.CosmosSerializerCore.FromFeedStream[T](Stream stream)
   at Microsoft.Azure.Cosmos.Serializer.CosmosElementSerializer.GetResourcesHelper[T](IReadOnlyList`1 cosmosElements, CosmosSerializerCore serializerCore, CosmosSerializationFormatOptions cosmosSerializationOptions)
   at Microsoft.Azure.Cosmos.Serializer.CosmosElementSerializer.GetResources[T](IReadOnlyList`1 cosmosArray, CosmosSerializerCore serializerCore)
   at Microsoft.Azure.Cosmos.QueryResponse`1..ctor(HttpStatusCode httpStatusCode, IReadOnlyList`1 cosmosElements, CosmosQueryResponseMessageHeaders responseMessageHeaders, CosmosDiagnostics diagnostics, CosmosSerializerCore serializerCore, CosmosSerializationFormatOptions serializationOptions)
   at Microsoft.Azure.Cosmos.QueryResponse`1.CreateResponse[TInput](QueryResponse cosmosQueryResponse, CosmosSerializerCore serializerCore)
   at Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.CreateQueryFeedResponseHelper[T](ResponseMessage cosmosResponseMessage)
   at Microsoft.Azure.Cosmos.CosmosResponseFactoryCore.CreateQueryFeedUserTypeResponse[T](ResponseMessage responseMessage)
   at Microsoft.Azure.Cosmos.FeedIteratorCore`1.<ReadNextAsync>d__8.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.ClientContextCore.<RunWithDiagnosticsHelperAsync>d__38`1.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.ClientContextCore.<OperationHelperWithRootTraceAsync>d__29`1.MoveNext()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at ConsoleApp2.Program.<Main>d__0.MoveNext() in C:\Users\...\ConsoleApp2\ConsoleApp2\Program.cs:line 65

Only caveat is, it runs for a long time (> 1min) before throwing exception, so maybe we require a large collection.

Upvotes: 0

Views: 1043

Answers (1)

SauravBhattacharya
SauravBhattacharya

Reputation: 643

The data had some $id's that I didn't see before. I fixed it by setting the metadata property handling to ignore:

new CosmosClientOptions()
{
    Serializer = new CosmosJsonNetSerializer(new JsonSerializerSettings()
    {
        MetadataPropertyHandling = MetadataPropertyHandling.Ignore
    })
}

CosmosJsonNetSerializer source can be found here: https://github.com/Azure/azure-cosmos-dotnet-v3/blob/master/Microsoft.Azure.Cosmos/src/Serializer/CosmosJsonDotNetSerializer.cs

Upvotes: 2

Related Questions