System.Text.Json Deserialize nested object from API call - Data is wrapped in parent JSON property

deserialize json c#
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&#39;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 or user
  • This works although I ended up creating a template container class. Check out the solution above