Json.NET - deserialize directly from a stream to a dynamic?
Solution 1
It turns out this had little to do with Json.NET and more to do with my understanding of dynamics (which I rarely use). Thanks to @Peter Richie, I found that GetJsonAsync<dynamic>
does work if I explicitly cast MyProperty to a string. But I'd rather not have to do that. Using my original method and a real working endpoint, here are 3 scenarios; only the last one works:
var url = "http://echo.jsontest.com/MyProperty/MyValue"; // great testing site!
var x1 = await GetJsonAsync<dynamic>(url);
Assert.AreEqual("MyValue", x1.MyProperty); // fail!
dynamic x2 = await GetJsonAsync<dynamic>(url);
Assert.AreEqual("MyValue", x2.MyProperty); // fail!
dynamic x3 = await GetJsonAsync<ExpandoObject>(url);
Assert.AreEqual("MyValue", x3.MyProperty); // pass!
Armed with that knowledge, the non-generic overload of my original method looks like this:
public async Task<dynamic> GetJsonAsync(string url) {
dynamic d = await GetJsonAsync<ExpandoObject>(url);
return d;
}
And users can do this:
var x = await GetJsonAsync(url);
Assert.AreEqual("MyValue", x.MyProperty); // pass!
Solution 2
It sounds like there's some information you haven't provided. The following works fine for me:
private T ReadJson<T>(Stream stream)
{
using (var reader = new StreamReader(stream))
{
using (var jr = new JsonTextReader(reader))
{
dynamic d = new JsonSerializer().Deserialize(jr);
return d;
}
}
}
//...
var d = ReadJson<dynamic>(new MemoryStream(Encoding.UTF8.GetBytes("{'MyProperty' : 'MyValue'}")));
Debug.WriteLine((String)d.MyProperty);
Todd Menier
OSS projects: Flurl - Fluent URL builder and wrist-friendly HTTP client library for .NET. AsyncPoco - Fully asynchronous fork of PetaPoco micro-ORM for .NET.
Updated on July 25, 2022Comments
-
Todd Menier almost 2 years
With a little help from the performance tips in the Json.NET docs, I put together a method for downloading/deserializing JSON from a remote resource:
public async Task<T> GetJsonAsync<T>(string url) { using (var stream = await new HttpClient().GetStreamAsync(url)) { using (var sr = new StreamReader(stream)) { using (var jr = new JsonTextReader(sr)) { return new JsonSerializer().Deserialize<T>(jr); } } } }
I'd like to have a non-generic version that returns a
dynamic
. Calling the above method withGetJsonAsync<dynamic>(url)
works, until you try to access a dynamic property on the result, at which point I get:'Newtonsoft.Json.Linq.JObject' does not contain a definition for '[MyProperty]'
I have seen how to deserialize to a dynamic from a string, but have not seen a working example of doing it directly from a stream, which would be preferable as it is more memory efficient. Is this possible?
-
Todd Menier about 10 yearsThanks, your explicit cast MyProperty to a string is what pointed me in the right direction.
-
Peter Ritchie about 10 yearsYes, technically the
MyProperty
property is a type ofJValue
--which doesn't have an implicit conversion tostring
.