Azure-cosmos-dotnet-v3: ItemQuery does not appear to use custom serializer

Created on 20 Dec 2018  路  10Comments  路  Source: Azure/azure-cosmos-dotnet-v3

I've created a custom JSON serializer and am able to get it to work when inserting data using UpsertItemsAsync. However, when I retrieve data back using CreateItemQuery and FetchNextSetAsync the custom serializer does not appear to get called.

As you can see from this stack trace, it looks like it's calling Newtonsoft.Json even though I've plugged a custom serializer in.

System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> Newtonsoft.Json.JsonSerializationException: Unexpected property '_rid' found when reading union. Path '_rid', line 1, position 12715.
   at Newtonsoft.Json.Converters.DiscriminatedUnionConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
   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.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Microsoft.Azure.Cosmos.Internal.QueryResult.Convert(Type type)
   at Microsoft.Azure.Cosmos.Internal.QueryResult.AsType[T]()
   at Microsoft.Azure.Cosmos.FeedResponseBinder.Convert[T](FeedResponse`1 dynamicFeed)
   at Microsoft.Azure.Cosmos.Linq.DocumentQuery`1.<ExecuteNextPrivateAsync>d__36`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.CosmosItems.<NextResultSetAsync>d__29`1.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at Microsoft.Azure.Cosmos.CosmosDefaultResultSetIterator`1.<FetchNextSetAsync>b__7_0(Task`1 task)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at <StartupCode$FSI_0015>.$FSI_0015.main@()
---> (Inner Exception #0) System.AggregateException: One or more errors occurred. ---> Newtonsoft.Json.JsonSerializationException: Unexpected property '_rid' found when reading union. Path '_rid', line 1, position 12715.
   at Newtonsoft.Json.Converters.DiscriminatedUnionConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
   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.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Microsoft.Azure.Cosmos.Internal.QueryResult.Convert(Type type)
   at Microsoft.Azure.Cosmos.Internal.QueryResult.AsType[T]()
   at Microsoft.Azure.Cosmos.FeedResponseBinder.Convert[T](FeedResponse`1 dynamicFeed)
   at Microsoft.Azure.Cosmos.Linq.DocumentQuery`1.<ExecuteNextPrivateAsync>d__36`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.CosmosItems.<NextResultSetAsync>d__29`1.MoveNext()
   --- End of inner exception stack trace ---
   at System.Threading.Tasks.Task.ThrowIfExceptional(Boolean includeTaskCanceledExceptions)
   at System.Threading.Tasks.Task`1.GetResultCore(Boolean waitCompletionNotification)
   at System.Threading.Tasks.Task`1.get_Result()
   at Microsoft.Azure.Cosmos.CosmosDefaultResultSetIterator`1.<FetchNextSetAsync>b__7_0(Task`1 task)
   at System.Threading.Tasks.ContinuationResultTaskFromResultTask`2.InnerInvoke()
   at System.Threading.Tasks.Task.Execute()
---> (Inner Exception #0) Newtonsoft.Json.JsonSerializationException: Unexpected property '_rid' found when reading union. Path '_rid', line 1, position 12715.
   at Newtonsoft.Json.Converters.DiscriminatedUnionConverter.ReadJson(JsonReader reader, Type objectType, Object existingValue, JsonSerializer serializer)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.DeserializeConvertable(JsonConverter converter, JsonReader reader, Type objectType, Object existingValue)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.ResolvePropertyAndCreatorValues(JsonObjectContract contract, JsonProperty containerProperty, JsonReader reader, Type objectType)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateObjectUsingCreatorWithParameters(JsonReader reader, JsonObjectContract contract, JsonProperty containerProperty, ObjectConstructor`1 creator, String id)
   at Newtonsoft.Json.Serialization.JsonSerializerInternalReader.CreateNewObject(JsonReader reader, JsonObjectContract objectContract, JsonProperty containerMember, JsonProperty containerProperty, String id, Boolean& createdFromNonDefaultCreator)
   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.Deserialize(JsonReader reader, Type objectType, Boolean checkAdditionalContent)
   at Newtonsoft.Json.JsonSerializer.DeserializeInternal(JsonReader reader, Type objectType)
   at Newtonsoft.Json.Linq.JToken.ToObject(Type objectType, JsonSerializer jsonSerializer)
   at Microsoft.Azure.Cosmos.Internal.QueryResult.Convert(Type type)
   at Microsoft.Azure.Cosmos.Internal.QueryResult.AsType[T]()
   at Microsoft.Azure.Cosmos.FeedResponseBinder.Convert[T](FeedResponse`1 dynamicFeed)
   at Microsoft.Azure.Cosmos.Linq.DocumentQuery`1.<ExecuteNextPrivateAsync>d__36`1.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at Microsoft.Azure.Cosmos.CosmosItems.<NextResultSetAsync>d__29`1.MoveNext()<---
bug

Most helpful comment

I was able to repro @isaacabraham, thanks for the details. We'll work on it.

All 10 comments

@isaacabraham Have you tried using the Stream version of the methods and applying your own custom deserializer? Does that work correctly?

I'm applying my own serializer but haven't used the Stream version of the methods. Is there any way to perform custom deserialization without using the Stream version of methods - is there any reason why they would work and the other one wouldn't?

Could you share the code snippet for the CreateItemQuery call with the custom deserializer parameter? Trying to repro that on my side (Or if you have a repro repo that would help too).

@ealsur there is no custom deserializer parameter on the CreateItemQuery call that I could see. But here's repository that demonstrates the issue: https://github.com/isaacabraham/cosmosdbtest. It should just build and run out of the box as a console application.

The key point is that the custom serialization gets called on the upsert call (indeed, it also seems to immediately deserialize the object again - which seems inefficient to me), but when you call the query, the custom serializer is not called. Instead it seems to go straight back to Newtonsoft which can't deserialize the object and pops.

I've also included it as a script which shows the same issue.

I was able to repro @isaacabraham, thanks for the details. We'll work on it.

How is this going please? This is a blocking issue for me.

@j82w @kirankumarkolli When do the streaming support wire up through the pipeline we should add tests for this API.

@kentcb I'm currently working on supporting this. I'm hoping to have a PR out by next week, but the time frame may change if I hit any major issues.

Here is the PR to update query to go to the handler pipeline.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

darthmolen picture darthmolen  路  4Comments

kirankumarkolli picture kirankumarkolli  路  5Comments

gegoodwin picture gegoodwin  路  7Comments

ealsur picture ealsur  路  6Comments

wahyuen picture wahyuen  路  4Comments