-1

I have a use case to store dynamic properties of a class to a document in MongoDB.

Here is my Metadata class:

public class Metadata
{
    [JsonProperty("name")]
    [BsonElement("name")]
    public string Name { get; set; }

    /// <summary>
    /// Properties of element
    /// </summary>
    [JsonProperty("properties")]
    [BsonElement("properties")]
    public Dictionary<string, object> Properties { get; set; }
}

I want to read and format JSON correctly when the object for Properties is string/object/array. It is currently working with all types except for collections. Sample input:

"properties": {
        "description": "How many developers are in your team?",
        "questionType": "singleChoice",
        "choices": [
            {
                "label": "<50",
                "value": 0
            },
            {
                "label": ">=50",
                "value": 1
            }
        ]
    }

While deserializing the choices array, JSONConvert is considering it as an object as shown in the below image: enter image description here [Note the braces highlighted by the yellow lines]

This is causing a problem when storing the object in Mongo collection and retrieving.

How do I accept any type of value as value in my 'Properties' dictionary?

I am letting the controller do the de-serialization normally from the request body. I am guessing it is equivalent to:

JsonConvert.DeserializeObject<Dictionary<string, object>>(requestBody);
Ravi Kiran
  • 565
  • 1
  • 8
  • 22
  • so this? https://stackoverflow.com/questions/18994685/how-to-handle-both-a-single-item-and-an-array-for-the-same-property-using-json-n – Rand Random Jul 04 '22 at 10:50
  • Use generics maybe? – Charlieface Jul 04 '22 at 11:29
  • 1
    How exactly are you deserializing? Could you show us the JsonConvert call for that? – Good Night Nerd Pride Jul 04 '22 at 11:31
  • 1
    Best show us the full code that deserializes and fills the dictionary with data. – Good Night Nerd Pride Jul 04 '22 at 11:32
  • What data do you want to see after deserialization? You need to convert the array to something – Serge Jul 04 '22 at 12:31
  • It's probably deserializing it to `JArray` not *an object*. When you tell Json.NET to deserialize to type `object`, Json.NET will pick some type sufficient to capture the JSON in question. Specifically, it chooses the LINQ-to-JSON types `JArray` and `JObject` for JSON arrays and objects. If you don't want those types to be used, what do you want instead? – dbc Jul 04 '22 at 16:04

2 Answers2

0

try this

var metadata=JsonConvert.DeserializeObject<Metadata>(json);
metadata.Properties["choices"]=((JArray)metadata.Properties["choices"])
.ToObject<List<Choice>>();
    
public class Choice
{
    [JsonProperty("value")]
    public int Value { get; set; }

    [JsonProperty("label")]
    public string Label {get; set;}
}
Serge
  • 40,935
  • 4
  • 18
  • 45
0

Update: I wrote a helper to deserialize for anonymous types using BsonSerializer. The method serializes using JSON -> then deserializes as a BsonDocument -> then converts to the object.

public static class BsonAnonymousSerializer
    {
        /// <summary>
        /// Method to deserialize objects with dynamic types
        /// </summary>
        /// <typeparam name="T">Type of object</typeparam>
        /// <param name="entity">Object to deserialize</param>
        /// <returns>Deserialized object</returns>
        public static T Deserialize<T>(T entity)
        {
            string jsonString = JsonConvert.SerializeObject(entity);
            BsonDocument bsonDocument = BsonSerializer.Deserialize<BsonDocument>(jsonString);
            return BsonSerializer.Deserialize<T>(bsonDocument);
        }
    }

Usage:

var entity = BsonAnonymousSerializer.Deserialize(entity);
Ravi Kiran
  • 565
  • 1
  • 8
  • 22