28

I am updating some apps for .NET Core 3.x, and as part of that I'm trying to move from Json.NET to the new System.Text.Json classes. With Json.NET, I could deserialize an anonymous type like so:

var token = JsonConvert.DeserializeAnonymousType(jsonStr, new { token = "" }).token;

Is there an equivalent method in the new namespace?

dbc
  • 104,963
  • 20
  • 228
  • 340
superstator
  • 3,005
  • 1
  • 33
  • 43
  • 2
    Net yet. Anonymous type objects lack a parameterless constructor, and so attempting to deserialize to an anonymous type throws an exception. Demo: https://dotnetfiddle.net/BLsmwg. – dbc Dec 12 '19 at 22:08
  • Relevant enhancement (open): [JsonSerializer support for immutable classes and structs. #38569](https://github.com/dotnet/corefx/issues/38569), tagged *milestones: Future, 5.0*. – dbc Dec 12 '19 at 22:11
  • Well you could do it with a custom `JsonConverter` but it would be tricky and involved to do so in a generic manner. – dbc Dec 12 '19 at 22:17

2 Answers2

30

As of .Net 5.0, deserialization of immutable types -- and thus anonymous types -- is supported by System.Text.Json. From How to use immutable types and non-public accessors with System.Text.Json:

System.Text.Json can use a parameterized constructor, which makes it possible to deserialize an immutable class or struct. For a class, if the only constructor is a parameterized one, that constructor will be used.

As anonymous types have exactly one constructor, they can now be deserialized successfully. To do so, define a helper method like so:

public static partial class JsonSerializerExtensions
{
    public static T? DeserializeAnonymousType<T>(string json, T anonymousTypeObject, JsonSerializerOptions? options = default)
        => JsonSerializer.Deserialize<T>(json, options);

    public static ValueTask<TValue?> DeserializeAnonymousTypeAsync<TValue>(Stream stream, TValue anonymousTypeObject, JsonSerializerOptions? options = default, CancellationToken cancellationToken = default)
        => JsonSerializer.DeserializeAsync<TValue>(stream, options, cancellationToken); // Method to deserialize from a stream added for completeness
}

And now you can do:

var token = JsonSerializerExtensions.DeserializeAnonymousType(jsonStr, new { token = "" }).token;

Demo fiddle here.

t3chb0t
  • 16,340
  • 13
  • 78
  • 118
dbc
  • 104,963
  • 20
  • 228
  • 340
2

Please try this library I wrote as an extension to System.Text.Json to offer missing features: https://github.com/dahomey-technologies/Dahomey.Json.

You will find support for anonymous types.

Setup json extensions by calling on JsonSerializerOptions the extension method SetupExtensions defined in the namespace Dahomey.Json:

JsonSerializerOptions options = new JsonSerializerOptions();
options.SetupExtensions();

Then serialize your class with the JsonSerializerExtensions static type:

var token = JsonSerializerExtensions.DeserializeAnonymousType(jsonStr, new { token = "" }, options).token;
  • 9
    Very nice, but the attraction for us of System.Text.Json was to eliminate another 3rd party dependency. If we have to add a library to make it work, might as well stick with Newtonsoft – superstator Dec 18 '19 at 18:32
  • 3
    I totally understand your point. The reason why I wrote this library instead of keeping on using Newtonsoft is because System.Text.Json is much faster and because Newtonsoft is less flexible for one specific topic: polymorphism support – Michaël Catanzariti Dec 18 '19 at 22:06
  • Anyway to do it without the prototype? I have a situation where I need to process a json feed of unknown structure entered by the user. I cant do a prototype because I dont know what their json will look like. I am planning on processing it as an assumed flat array containing objects whose fields I will enumerate. – computrius Oct 15 '20 at 20:38
  • Yes you can but we are not talking anymore about an anonymous type. You can use JsonObject which works like a DOM object. – Michaël Catanzariti Oct 16 '20 at 21:03