System.Text.Json Deserialize nested object from API call - Data is wrapped in parent JSON property
system.text.json deserialize dynamic
system text json custom converter attribute
jsonconverter attribute
system.text.json jsonconstructor
newtonsoft custom deserializer
deserialize json c# online
system.text.json referenceloophandling
I have an API JSON response that wraps the data content in a data
property, which looks like this:
{ "data":{ "email":"admin@example.com", "mobile":"+1555555123", "id":4, "first_name":"Merchant", "last_name":"Vendor", "role":"Merchant", } }
So when making request for a User Object with a Library like RequestSharp
, the response.Content
has the content for the User wrapped in the data
json property as it comes from the API. Code:
var request = RequestHelper.CreateTokenRequest(email, password); // Create the request from a helper var client = new RestClient(BaseUrl); // create new RestSharp Client IRestResponse response = client.Execute(request); // execute the request var content = response.Content; // raw content as string
This is fine, but when I go to deserialize the json to an Object with System.Text.Json
, like the following, will create the User
object but will not assign any of the attributes, although this is sort of expected because the serializer is looking for properties with first_name
and last_name
... not ['data']['first_name']
User account = JsonSerializer.Deserialize<User>(response.Content, options);
How can I get the JsonSerializer.Deserialize
to ignore the data
wrapper? In other API calls it may be the name of the Object such as transaction
or user
, either way, it wraps the data.
Other Notes:
I am targeting the latest .Net Core 3.1 and am migrating from Newtonsoft Json.Net
My User Object:
using System.ComponentModel; using System.Text.Json.Serialization; namespace MyApplication.Models { public interface IUser { string FirstName { get; set; } string LastName { get; set; } string Email { get; set; } string Mobile { get; set; } string Id { get; set; } string Role { get; set; } } public class User : IUser { [JsonPropertyName("first_name")] public string FirstName { get; set; } [JsonPropertyName("last_name")] public string LastName { get; set; } [JsonPropertyName("email")] public string Email { get; set; } [JsonPropertyName("mobile")] public string Mobile { get; set; } [JsonPropertyName("id")] public string Id { get; set; } [JsonPropertyName("role")] public string Role { get; set; } [JsonIgnore] public string Token { get; set; } } }
Update after resolution:
I selected the answer from u/Nikunj Kakadiya below as something that would work and was most similar to what I ended up doing.
I created a generic template based container class to handle the data
like this:
public class Container<T> { [JsonPropertyName("data")] public T Data { get; set; } }
I then used that container class to wrap the returned json contents from the API call, like this:
var options = new JsonSerializerOptions { AllowTrailingCommas = true }; Container<User> accountContainer = JsonSerializer.Deserialize<Container<User>>(response.Content, options); User account = accountContainer.Data;
Additionally, as u/Pavel Anikhouski noted, my serialization of the User
class led to an error that required me to create a custom converter for the id
field. The API returns the id
as an integer although it is a string in the User
class. This was the error I ran into which was initially confusing but I was able to figure out pretty quickly: ERROR: The JSON value could not be converted to System.String. Path: $.data.id | LineNumber: 0 | BytePositionInLine: 77.
Here is the custom converter IntToStringConverter
:
public class IntToStringConverter : JsonConverter<string> { public override string Read( ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) => reader.GetInt32().ToString(); public override void Write( Utf8JsonWriter writer, string value, JsonSerializerOptions options) => writer.WriteStringValue(value); }
and then changed the User
Class to use the customer converter:
... [JsonPropertyName("id")] [JsonConverter(typeof(IntToStringConverter))] public string Id { get; set; } ...
You need to make one another class. That is given below
Public class UserData { public User data { get; set; }; }
Now you can Deserialize data using new class called UserData like below
UserData account = JsonSerializer.Deserialize<UserData>(response.Content, options);
How to serialize and deserialize JSON using C#, System.Text.Json Deserialize nested object from API call - Data is wrapped in parent JSON property. 250 Views. 0. Votes. name fullName� This article shows how to use the System.Text.Json namespace to serialize and deserialize to and from JavaScript Object Notation (JSON). If you're porting existing code from Newtonsoft.Json, see How to migrate to System.Text.Json. The directions and sample code use the library directly, not through a framework such as ASP.NET Core.
It's possible to get a User
object using System.Text.Json
API without specifying a name of property data
from your JSON sample
{ "data":{ "email":"admin@example.com", "mobile":"+1555555123", "id":4, "first_name":"Merchant", "last_name":"Vendor", "role":"Merchant", } }
by the following code
var document = JsonDocument.Parse(json, new JsonDocumentOptions { AllowTrailingCommas = true }); var enumerator = document.RootElement.EnumerateObject(); if (enumerator.MoveNext()) { var userJson = enumerator.Current.Value.GetRawText(); var user = JsonSerializer.Deserialize<User>(userJson, new JsonSerializerOptions {AllowTrailingCommas = true}); }
In the sample above the JsonDocument
is loaded, than RootElement
is enumerated to get the first nested object as text to deserialize into User
instance.
It's more easier to get a property by name like document.RootElement.GetProperty("data");
, but the name can be different actually, according to your question. Accessing through indexer, like document.RootElement[0]
is also not possible, because it works only when ValueKind
of an element is Array
, not the Object
, like in your case
I've also changed the "id":4,
to "id":"4",
, because getting an error
Cannot get the value of a token type 'Number' as a string.
Writing raw property values when using System.Text.Json � Issue , Text.Json namespace to serialize to and deserialize from JSON in .NET. The System.Text.Json.Serialization namespace contains attributes and APIs for To write JSON to a string or to a file, call the JsonSerializer. Deserialization to immutable objects or read-only properties isn't supported. Text.Json API reference� Remarks. If the TokenType property of reader is JsonTokenType.PropertyName or JsonTokenType.None, the reader will be advanced by one call to Utf8JsonReader.Read() to determine the start of the value.
You can create an object like this:
public class Data { public string email { get; set; } public string mobile { get; set; } public int id { get; set; } public string first_name { get; set; } public string last_name { get; set; } public string role { get; set; } } public class RootObject { public Data data { get; set; } }
then
var data = JsonSerializer.Deserialize<RootObject>(JsonData);
then you can access the data like the following:
RootObject.Data.email ; RootObject.Data.first_name
Also, anytime you need to convert JSON string to C# POCO class you can use a tool like this : http://json2csharp.com/
System.Text.Json.JsonSerializer doesn't correctly serialize generic , Writing raw property values when using System.Text.Json #1784 ahsonkhan added tenet-performance api-suggestion and removed untriaged labels or request body stream directly to override standard deserialization behavior. or wrap existing JSON payloads (i.e. from external services) in a parent� How to write custom converters for JSON serialization (marshalling) in .NET. 01/10/2020; 17 minutes to read; In this article. This article shows how to create custom converters for the JSON serialization classes that are provided in the System.Text.Json namespace.
Either you get rid of the data object or you can write a custom json Converter. I suggest to change the sent data or just consume it as it is because what you are trying to do is not a best practice.
Serialization Guide, I'm currently trying to migrate from Newtonsoft.Json to System.Text.Json JsonSerializer doesn't correctly serialize generic super class when nested # 30425 The type is specified when serializing via the type argument when calling Serialize(. Do you need polymorphic serialization and deserialization? You could use Json.Parse so that you can query into the data -- and just use the single model.. private class Info { public string Prop1 { get; set; } public string Prop2 { get; set; } public int Prop3 { get; set; } public bool Prop4 { get; set; } } var result = JObject.Parse(resultContent); //parses entire stream into JObject, from which you can use to query the bits you need. var items
area-System.Text.Json, The Json.NET serializer can serialize a wide variety of .NET objects. NET will throw an error if it encounters incorrect JSON when deserializing a value. For example, if the serializer encounters a JSON property with an array of values JSON arrays on the serializer, then JSON arrays are wrapped in a containing object. Configure NamingStrategy property name serialization. Deserialize an Object This sample deserializes JSON to an object. Sample.
JSON Serialization - Unity, JsonElement get parent element or document I migrated an existing api project to aspnet3.1, and I prefere to use the new System. Unable to round-trip data. Json] make possible to deserialize objects from stream without always fully for path in JsonPropertyName to access nested property when deserializing json� System.Text.Json Deserialize nested object from API call - Data is wrapped in parent JSON property Hot Network Questions Ways/techniques to make things "fluffy/foamy" like whipped cream?
Jsonconverter nested objects, Use the JsonUtility class to convert Unity objects to and from the JSON format. marks it with the Serializable attribute, in order to work with the JSON serializer. You can also deserialize JSON data over an existing object, which overwrites any is a parallel API, EditorJsonUtility, which allows you to serialize any object � I try to convert my Newtonsoft.Json code to System.Text.Json and I came along a problem. I need to serialize/deserialize any object. I don't know the objects type at compile time. With Newtonso
Comments
- There is an error Cannot get the value of a token type 'Number' as a string. for
id
property - Do you still need an answer? There are several working answers below. If you really don't care about the root property name you could always deserialize to a dictionary and take the first value, i.e.
JsonSerializer.Deserialize<Dictionary<string, User>>(response.Content, options).Values.SingleOrDefault();
- But OP mentioned that In other API calls it may be the name of the Object such as
transaction
oruser
- This works although I ended up creating a template container class. Check out the solution above