Out Of Memory exception when deserializing with JSON.net – Use Streams instead

O

Calling an api and deserializing the returned json into a type is something I have to do quite often.

I used to use the following:

//assume client is an instance of HttpClient - this part isn't important
var response = await client.PostAsync(url, content);

//read the response as a string
var responseString = await response.Content.ReadAsStringAsync();

//use json.net to deserialize this into a JObject
var json = (JObject)JsonConvert.DeserializeObject(responseString);

//typically, my json is wrapped up in a 'result' element
var result = JsonConvert.DeserializeObject<IEnumerable<TKeenResult>>(json["result"].ToString());

//now we can deserialize
return JsonConvert.DeserializeObject<IEnumerable<MyResult>>(json["result"].ToString());


If the JSON returned is large, we’ll often get an Out Of Memory Exception

From the docs

To minimize memory usage and the number of objects allocated, Json.NET supports serializing and deserializing directly to a stream.

To rectify this, we can instead use Streams

//again, assume client is an instance of HttpClient - this part isn't important
var response = await client.PostAsync(url, content);

using (var stream = await response.Content.ReadAsStreamAsync())
{
    using (var streamReader = new StreamReader(stream))
    {
        using (var reader = new JsonTextReader(streamReader))
        {
            var serializer = new JsonSerializer();

            var responseFromKeen = serializer.Deserialize<TypeContainingMyResult>(reader);
            return responseFromKeen.Result;
        }
    }
}

 

In my example, where the JSON has a nested ‘result’ element, you’ll also need a class to represent this (see `TypeContainingMyResult` above)

public class TypeContainingMyResult
{
	public IEnumerable<MyType> Result {get; set}
}