Val
Val

Reputation: 1822

Converting List<MyClass> to JSON fails

I'm trying to convert a list of my objects to a JSON array (wrapped in a JSON object) but keep getting an error that I have no idea what is being caused by.

My class for objects on the list:

public class BriefResponseTestingDto
{
    public Guid GrantId { get; set; }
    public string GrantName { get; set; }
}

My code serializing the list to JSON:

List<BriefResponseTestingDto> list = new List<BriefResponseTestingDto>();
list.Add(new BriefResponseTestingDto() { GrantId = new Guid(), GrantName = "Name1"});
list.Add(new BriefResponseTestingDto() { GrantId = new Guid(), GrantName = "Name2"});
list.Add(new BriefResponseTestingDto() { GrantId = new Guid(), GrantName = "Name3"});

dataAsJobject = new JObject(JsonConvert.SerializeObject(list));

After serializing, I try to convert the string to JObject and I get an exception thrown with the message: Can not add Newtonsoft.Json.Linq.JValue to Newtonsoft.Json.Linq.JObject.

What am I doing wrong?

Upvotes: 0

Views: 1777

Answers (2)

Brian Rogers
Brian Rogers

Reputation: 129667

You can't put a JValue, JArray or another JObject into a JObject directly; you need to put it into a JProperty (which has a name) and add that to the JObject. That is why you are getting the error you are seeing. Also, you should use JArray.FromObject to convert your list to a JArray before adding it to the JProperty. If you use SerializeObject() you will wind up with a string value instead, which is not what you want here. See Can Json.Net handle a List<object>? for more explanation on that.

So you would have:

var dataAsJobject = new JObject(new JProperty("data", JArray.FromObject(list)));
var json = dataAsJobject.ToString();

Fiddle: https://dotnetfiddle.net/eYMLVV

You could also get your desired output using an anonymous object instead:

var anon = new { data = list };
var json = JsonConvert.SerializeObject(anon, Formatting.Indented);

Fiddle: https://dotnetfiddle.net/BGxvwf

Upvotes: 0

Andy
Andy

Reputation: 13527

When you want to serialize to string do this:

var jsonString = JsonConvert.SerializeObject(list);

To convert back, do this:

var myList = JsonConvert.DeserializeObject<List<BriefResponseTestingDto>>(jsonString);

Since you serialized a List, that is an array and it won't work with JObject. I would suggest an even more generic JToken that handles all cases. If you must work with it in it's current form, use JArray.

var myjObj = JsonConvert.DeserializeObject<JArray>(jsonString);

Based on my conversion with OP, the want to be able to add an array to an existing object. There are a couple ways to do this, but I tend to always fall back to the dynamic route.

Let's say we have an object that looks like this:

{
    "hello":"world"
}

and we want to add an array as a sibling to the property hello so it looks like this:

{
    "hello":"world",
    "myArray":[1,2,3,4,5]
}

We can accomplish this by taking the original model and converting it to dynamic. Since we are tightly coupled to Newtonsoft, I am going to take advantage of that by letting that library do the heavy lifting.

Here is a method to convert an object to an ExpandoObject type dynamic that allows you to some pretty neat things:

public static dynamic ConvertObjectToExpandoObject(object obj)
{
    using (var ms = new MemoryStream())
    {
        using (var sw = new StreamWriter(ms, Encoding.UTF8, 1024, leaveOpen: true))
        using (var jtw = new JsonTextWriter(sw))
        {
            new JsonSerializer().Serialize(jtw, obj);
        }
        ms.Position = 0;
        using (var sr = new StreamReader(ms))
        using (var jtr = new JsonTextReader(sr))
        {
            return JsonSerializer.CreateDefault(new JsonSerializerSettings
            {
                Converters = { new ExpandoObjectConverter() }
            }).Deserialize<ExpandoObject>(jtr);
        }
    }
}

Now that it is dynamic and it understands ExpandoObject semantics, we can add any property as any type to it:

var myDynamic = ConvertObjectToExpandoObject(new { hello = "world" });
myDynamic.myArray = new int[] { 1, 2, 3, 4, 5 };
var jsonString = JsonConvert.SerializeObject(myDynamic);

You could use any model you want here, even concrete models (not just anonymous object). We added an array to it, then serialized it back. It will now look like the result from above that we wanted.

Upvotes: 1

Related Questions