15

I have some JSON that has a variety of properties most of which are simple data types. However, I have one property in the JSON that when I deserialize it to a C# class I simply need it to be deserialized as a string.

Example JSON:

{"simpleProperty": "value1", "json":{"a":"a1", "b":"b1"}}

The "json" object has no set structure other than it will be a valid JSON object.

So in the above example the value of "json" is a JSON object -- but when it gets deserialized, I need it as a string.

So if my C# class is:

public class MyClass
{
    public string SimpleProperty { get; set; }
    public string Json { get; set; }
}

And then if I use:

var myClass = JsonConvert.DeserializeObject<MyClass>(jsonStr);

I would like myClass.Json to just be a simple string.

I have looked at creating a custom JsonConverter for this but that seems way too complex for something this simple. I must be be missing something here. Any direction would be greatly appreciated.

I also saw this post -- but it really doesn't answer the question: JSON.Net - How to deserialize JSON to object but treating a property as a string instead of JSON?

Community
  • 1
  • 1
csheets
  • 433
  • 2
  • 4
  • 14

2 Answers2

13

You can alternatively use the JToken type for the property, to indicate that any valid JSON can go there. Though it's not exactly what you asked for, it may be sufficient.

public class MyClass
{
    public string SimpleProperty { get; set; }
    public JToken Json { get; set; }
}

Doing myClass.Json.ToString() will then get you the JSON as a string.

Timothy Shields
  • 75,459
  • 18
  • 120
  • 173
  • Thanks but unfortunately that does not work for my use case because of how the class then needs to be used in the context of an existing framework that needs to consume that class and do stuff with it. – csheets May 01 '15 at 13:06
13

For my needs, I decided to go ahead and implement a custom JsonConverter as follows:

    class JsonConverterObjectToString : JsonConverter
    {
        public override bool CanConvert(Type objectType)
        {
            return (objectType == typeof(JTokenType));
        }

        public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
        {
            JToken token = JToken.Load(reader);
            if (token.Type == JTokenType.Object)
            {
                return token.ToString();
            }
            return null;
        }

        public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
        {
            //serializer.Serialize(writer, value);

            //serialize as actual JSON and not string data
            var token = JToken.Parse(value.ToString());
            writer.WriteToken(token.CreateReader());

        }
    }

I have not thoroughly tested the above implementation and I am not entirely sure about the Canconvert method as it never seemed to get invoked, but it seems to do the conversion and then allows me to then store the deserialized class into MongoDB and the JSON data is being stored a string. So all is good for now. I found the following helpful in the implementation: How to deserialize a JSON property that can be two different data types using Json.NET

UPDATE: modified WriteJson method to serialize back out as JSON object (not a string).

Community
  • 1
  • 1
csheets
  • 433
  • 2
  • 4
  • 14
  • 1
    The `CanConvert` method will not get invoked if you are using a `[JsonConverter]` attribute on a class or property, because Json.Net already knows your converter can handle that type. (You told it so by adding the attribute.) `CanConvert` is called if you do not use a `[JsonConverter]` attribute and instead pass a converter instance to the serializer via the settings. In that case, Json.Net has to ask the converter if it can handle each type it comes across. So you would want the `CanConvert` method to return true for the object type that your converter is designed to handle. – Brian Rogers May 01 '15 at 14:34
  • Great. That saved my day. In case the json is part of an array you can enhance ReadJson() by e.g. else if (token.Type == JTokenType.Array) { List objList = token.ToObject>(); return objList.Select(item => item.ToString()).ToList(); } – TomB Nov 04 '20 at 10:47