I’m developing a CBLite datalayer within a Xamarin (C# ofc) project and I’ve encountered an odd problem.
Our data can be highly nested/embedded with rules based on the type that it describes, so some properties can be arrays of json objects, or just value arrays, or just json objects.
However, much in the same way I noticed this problem in our webAPI layer, Newtonsoft Json does not recursively deserialise nested structures. So when I’m in my map function trying to map against properties nested at ‘n’ depth, my application crashes because I’m no longer working with IDictionaries, but JObjects.
For my web layer I ended up implementing a recursive deserialiser, but my question is if there’s a more elegant solution with CBLite?
I can happily have my top level map function ensure it does a recursive deserialise, but I was hoping that I might be able to inject this behaviour into the CouchbaseDatabase object?
Any ideas for a neater solution would be very much welcomed!
This is a topic that has bothered me for a long time. There is not currently a better solution than what you are doing. There is a lot of interest in changing the API to deserialize directly into defined structures instead of dictionaries and lists as we are currently doing and this is something that we are actively researching! I started to implement a recursive deserializer for the library but I worried about the performance loss for people who didn’t care to go that deep. I toyed around with the idea of making the way we handle de/serialization public but decided against it for now (who knows if we will use JSON to store our data to disk in the future or not, etc, it’s best left inside the implementation).
The way I deal with this inside the library is with an
AsList<> extension that tries to convert via Newtonsoft and then simply does a cast. That way I can just get everything on demand instead of deserializing everything up front.
Thanks for the quick response, I’ve chosen to go with the crowd favourite deserialiser which I call if the document passes my top level type checks (there’s an outer overload that takes the root Dictionary):
private object RecursivelyDeserialiseDocument(JToken valueAsToken)
.ToDictionary(prop => prop.Name,
prop => RecursivelyDeserialiseDocument(prop.Value));
This has done the trick for me, but like I say I was hoping for a more elegant solution.
That being said, I’m unsure why Newton hasn’t just incorporated this into his base JSON deserialiser, seeing as I’ve never known anyone to only wanted to do a root level deserialisation.
I guess the answer would be
A) Just because you don’t know them doesn’t mean they don’t exist (I’m constantly surprised at how often this argument is true).
B) The extra deserialization will add overhead in a library that is almost entirely focused on performance. With direct use of Newtonsoft, you could accomplish this in a number of ways (overloading the deserialization class, etc).
These problems will become redundant, though, if we can switch the library to use actual classes instead of abstract collections (I made a POC, but with sweeping API changes it will need to wait for 2.0).
Both are valid points, and ultimately using the library to do it recursively generates the exact same result, if at a slight cost.
I could imagine the overhead would be acceptable if there was a serialisation enum or flag to denote if you wanted the functionality. But now we’re off the beaten track and discussing a 3rd party lib!
CB retrieval to POCO’s would be nice for more standard projects :D, would be extremely cool if one could turn on the JSON type serialisation and have it be able to resolve on both sides, given a common data model library. My current app actually relies on retrieving data as abstract dictionaries however as it passes this information onto other aspects of the project that have knowledge of the strongly typed model.