Details
-
Bug
-
Status: Closed
-
Major
-
Resolution: Not A Bug
-
3.5.0
-
None
-
None
-
Azure CosmosDB graph
Description
We use Gremlin.NET against a CosmosDB graph and have upgraded our projects from 3.4.10 to 3.5.0 which I understand changed serialization to use System.Text.Json.
We discovered that many of our queries that ended up retrieving edges were failing with the following ArgumentOutOfRangeException exception:
JSON type not supported.Parameter name: ValueKindActual value was Number.
We determined this happens for queries retrieving edges that have Number type JSON properties, most likely because Number is not considered in the ToObject method:
A workaround that seems to work is instantiate our Gremlin.NET client with a subclass of GraphSON2Reader that accounts for this, but for the time being we've decided to rollback the update instead.
Here's some code that triggers the issue, at least when using the CosmosDB backend which is what we use:
using Gremlin.Net.Driver; using Gremlin.Net.Structure.IO.GraphSON; using System; using System.Text.Json; using System.Threading.Tasks;namespace GremlinNetTest { class Program { static async Task Main(string[] _) { var (hostname, port, username, password) = ( "<redacted>", 443, "<redacted>", "<redacted>" ); var server = new GremlinServer(hostname, port, enableSsl: true, username, password); var client = new GremlinClient(server, new GraphSON2MessageSerializer(new GraphSON2Reader(), new GraphSON2Writer())); // Create vertexes. var (v1Id, v2Id) = (Guid.NewGuid().ToString(), Guid.NewGuid().ToString()); await client.SubmitAsync<dynamic>($"g.addV('item').property('id','{v1Id}').property('pk','0')"); await client.SubmitAsync<dynamic>($"g.addV('item').property('id','{v2Id}').property('pk','0')"); // Create edge with string property works. await client.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('works').to(g.V(['0','{v2Id}'])).property('hello','world')"); // Create edge with number property fails to deserialize result. // ** FAILS ** await client.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('fails').to(g.V(['0','{v2Id}'])).property('number', 1)"); await client.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('fails').to(g.V(['0','{v2Id}'])).property('long', 3147483647)"); await client.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('fails').to(g.V(['0','{v2Id}'])).property('decimal', 1.5)"); // ** /FAILS ** // Create edge with number property works to deserialize result with custom reader. var clientWithCustomReader = new GremlinClient(server, new GraphSON2MessageSerializer(new CustomReader(), new GraphSON2Writer())); await clientWithCustomReader.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('works').to(g.V(['0','{v2Id}'])).property('number', 1)"); await clientWithCustomReader.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('works').to(g.V(['0','{v2Id}'])).property('long', 3147483647)"); await clientWithCustomReader.SubmitAsync<dynamic>($"g.V(['0','{v1Id}']).addE('works').to(g.V(['0','{v2Id}'])).property('decimal', 1.5)"); } } public class CustomReader : GraphSON2Reader { public override dynamic ToObject(JsonElement graphSon) { if (graphSon.ValueKind == JsonValueKind.Number) { if (graphSon.TryGetInt32(out int intValue)) return intValue; if (graphSon.TryGetInt64(out long longValue)) return longValue; if (graphSon.TryGetDecimal(out decimal decimalValue)) return decimalValue; } return base.ToObject(graphSon); } } }