33

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?

3
  • 2
    Net yet. Anonymous type objects lack a parameterless constructor, and so attempting to deserialize to an anonymous type throws an exception. Demo: dotnetfiddle.net/BLsmwg. Commented Dec 12, 2019 at 22:08
  • Relevant enhancement (open): JsonSerializer support for immutable classes and structs. #38569, tagged milestones: Future, 5.0. Commented Dec 12, 2019 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. Commented Dec 12, 2019 at 22:17

4 Answers 4

48

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.

Sign up to request clarification or add additional context in comments.

Comments

3

You can also deserialize to System.Text.Json.Nodes.JsonObject which supports indexers, allowing you to access any property:

var json = """{ "token": "ab123" }"""; var jsonObj = JsonSerializer.Deserialize<JsonObject>(json); var token = jsonObj["token"].GetValue<string>(); 

Comments

1

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; 

4 Comments

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
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
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.
Yes you can but we are not talking anymore about an anonymous type. You can use JsonObject which works like a DOM object.
-2

If you insist on using only what is already provided in System.Text.Json, you could use a tuple, but its restriction makes it almost useless: the JSON items must be named Item1, Item2, and so on, and you cannot have only one item.

var json = @"{""Item1"": ""abc"", ""Item2"": 123}"; var tuple = JsonSerializer.Deserialize<(string, int)>(json, new JsonSerializerOptions { IncludeFields = true }); 

You could give the elements names, but that only changes the output, you cannot change the JSON naming. Names are just syntactic sugar for tuples and are not available at runtime.

1 Comment

I understand that this is not a complete answer to the question. However, it is something that people might think of and even try when looking for a solution. Posting it here adds interesting information and could save time for some users.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.