[CSHARP-966] Saving a dynamic value causes stackoverflow Created: 07/May/14  Updated: 04/Apr/15  Resolved: 04/Apr/15

Status: Closed
Project: C# Driver
Component/s: Serialization
Affects Version/s: 2.0
Fix Version/s: None

Type: Bug Priority: Major - P3
Reporter: Austin McDaniel Assignee: Unassigned
Resolution: Done Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified


 Description   

I have a model that has a attribute like:

     public Dictionary<string, dynamic> Values { get; set; }

the Values attribute typically accepts objects like:

[ 
	    { "24352435234": 2343 }   // Number
	    { "24352435234": "Henry" } // Text
	    { "24352435234": DateTime }  // Date
	    { "23452435234": "23452345243" } // Single select box
	    { "23452435234": ["23452345243", "2345234234"] } // Multi-select box ---- this doesn't work currently
	    { "23452435234": "SW-132" } // Id
	 ]

all works fine until I do the Multi-Select case and then it does a stackoverflow and totally kills the .net process. Heres a quick video of the post/fail/errors http://www.screencast.com/t/MQG7hdvOcr

Using 1.9 driver, it saves fine but on de-serialization it fails.

  • Note: I'm using the nightly 3.0.0-build-0052 *


 Comments   
Comment by Craig Wilson [ 14/May/14 ]

Brant,
It serializes type information because, when using dynamic, that gets translated to object at runtime. Hence, we need to be able to read the data back in and therefore put some type information in there. In the 3.0.0 branch, instead of having the JsonConverter change it to a string[], have it change it to a List<object>. This is the currently recognized type for persisting arrays without type information. When it comes back, it will come back as a List<object>. Again, at compile time, this would be List<dynamic> to you, so the underlying List<object> is somewhat hidden. We are trying to balance the support for dynamic with the need to support round-trip fidelity of information.

Craig

Comment by Brant Wheeler [ 14/May/14 ]

We ended up working around this by creating a Json converter to convert the type from a JArray to a string[] before sending the data to Mongo, like this: https://gist.github.com/brantw/02cedc0c6ece275552da

The only oddity with this approach is that the C# driver will add some type metadata when saving to Mongo that the array type is System.String[], but everything serializes without error.

It would be awesome if the Mongo driver handled Json.NET types automatically since Json.NET has become the de-facto standard for Json serialization in the .NET world.

Comment by Robert Stam [ 13/May/14 ]

Oh.... the Json.NET classes don't serialize well with the BsonClassMapSerializer (we document the assumptions that BsonClassMapSerializer makes about classes that it is able to serialize automatically, and some of the Json.NET classes don't meet our requirements).

The stack overflow is actually related to JToken. Note that JToken is defined in Json.NET as:

public abstract class JToken : IEnumerable<JToken> ...

When we try to find a suitable serializer for JToken, we see that it implements IEnumerable<T>, so we conclude that we should serialize it as an array and we recursively look up the serializer for <T>, but since <T> happens to be JToken we end up with a stack overflow.

I don't know what it would take to succesfully serialize the full suite of Json.NET data objects to MongoDB, but it would require writing multiple custom serializers that work with the Json.NET data types.

Comment by Brant Wheeler [ 12/May/14 ]

Hi Robert,

Please see https://github.com/brantw/mongo-csharp-driver/commit/9885eb02e2bbf386b6850cca875c9254c898365d for an example of a failing test.

The stack overflow seems to be generated when serializing the Json.NET JArray class.

Comment by Robert Stam [ 07/May/14 ]

Thanks for reporting this. I am attempting to reproduce this, but am so far unable to.

Can you isolate this to a small sample class definition and a sample JSON document that fails to deserialize?

You can see my attempts so far to reproduce here:

https://github.com/rstam/mongo-csharp-driver/tree/csharp966

Here's a direct URL to the file with the tests:

https://github.com/rstam/mongo-csharp-driver/blob/csharp966/src/MongoDB.Bson.Tests/Jira/CSharp966Tests.cs

Generated at Wed Feb 07 21:38:19 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.