Using JsonConvert.DeserializeObject to deserialize Json to a C# POCO class

374,138

Solution 1

Here is a working example.

Keypoints are:

  • Declaration of Accounts
  • Use of JsonProperty attribute

.

using (WebClient wc = new WebClient())
{
    var json = wc.DownloadString("http://coderwall.com/mdeiters.json");
    var user = JsonConvert.DeserializeObject<User>(json);
}

-

public class User
{
    /// <summary>
    /// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
    /// </summary>
    [JsonProperty("username")]
    public string Username { get; set; }

    /// <summary>
    /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
    /// </summary>
    [JsonProperty("name")]
    public string Name { get; set; }

    /// <summary>
    /// A User's location. eh: "Bolivia, USA, France, Italy"
    /// </summary>
    [JsonProperty("location")]
    public string Location { get; set; }

    [JsonProperty("endorsements")]
    public int Endorsements { get; set; } //Todo.

    [JsonProperty("team")]
    public string Team { get; set; } //Todo.

    /// <summary>
    /// A collection of the User's linked accounts.
    /// </summary>
    [JsonProperty("accounts")]
    public Account Accounts { get; set; }

    /// <summary>
    /// A collection of the User's awarded badges.
    /// </summary>
    [JsonProperty("badges")]
    public List<Badge> Badges { get; set; }
}

public class Account
{
    public string github;
}

public class Badge
{
    [JsonProperty("name")]
    public string Name;
    [JsonProperty("description")]
    public string Description;
    [JsonProperty("created")]
    public string Created;
    [JsonProperty("badge")]
    public string BadgeUrl;
}

Solution 2

Another, and more streamlined, approach to deserializing a camel-cased JSON string to a pascal-cased POCO object is to use the CamelCasePropertyNamesContractResolver.

It's part of the Newtonsoft.Json.Serialization namespace. This approach assumes that the only difference between the JSON object and the POCO lies in the casing of the property names. If the property names are spelled differently, then you'll need to resort to using JsonProperty attributes to map property names.

using Newtonsoft.Json; 
using Newtonsoft.Json.Serialization;

. . .

private User LoadUserFromJson(string response) 
{
    JsonSerializerSettings serSettings = new JsonSerializerSettings();
    serSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
    User outObject = JsonConvert.DeserializeObject<User>(jsonValue, serSettings);

    return outObject; 
}

Solution 3

You could create a JsonConverter. See here for an example thats similar to your question.

Solution 4

The accounts property is defined like this:

"accounts":{"github":"sergiotapia"}

Your POCO states this:

public List<Account> Accounts { get; set; }

Try using this Json:

"accounts":[{"github":"sergiotapia"}]

An array of items (which is going to be mapped to the list) is always enclosed in square brackets.

Edit: The Account Poco will be something like this:

class Account {
    public string github { get; set; }
}

and maybe other properties.

Edit 2: To not have an array use the property as follows:

public Account Accounts { get; set; }

with something like the sample class I've posted in the first edit.

Solution 5

Along the lines of the accepted answer, if you have a JSON text sample you can plug it in to this converter, select your options and generate the C# code.

If you don't know the type at runtime, this topic looks like it would fit.

dynamically deserialize json into any object passed in. c#

Share:
374,138
Only Bolivian Here
Author by

Only Bolivian Here

Updated on November 24, 2021

Comments

  • Only Bolivian Here
    Only Bolivian Here over 2 years

    Here is my simple User POCO class:

    /// <summary>
    /// The User class represents a Coderwall User.
    /// </summary>
    public class User
    {
        /// <summary>
        /// A User's username. eg: "sergiotapia, mrkibbles, matumbo"
        /// </summary>
        public string Username { get; set; }
    
        /// <summary>
        /// A User's name. eg: "Sergio Tapia, John Cosack, Lucy McMillan"
        /// </summary>
        public string Name { get; set; }
    
        /// <summary>
        /// A User's location. eh: "Bolivia, USA, France, Italy"
        /// </summary>
        public string Location { get; set; }
    
        public int Endorsements { get; set; } //Todo.
        public string Team { get; set; } //Todo.
    
        /// <summary>
        /// A collection of the User's linked accounts.
        /// </summary>
        public List<Account> Accounts { get; set; }
    
        /// <summary>
        /// A collection of the User's awarded badges.
        /// </summary>
        public List<Badge> Badges { get; set; }
    
    }
    

    And the method I'm using to deserialize a JSON response into a User object (this actual JSON call is here):

    private User LoadUserFromJson(string response)
    {
        var outObject = JsonConvert.DeserializeObject<User>(response);
        return outObject;
    }
    

    This fires an exception:

    Cannot deserialize the current JSON object (e.g. {"name":"value"}) into type 'System.Collections.Generic.List`1[CoderwallDotNet.Api.Models.Account]' because the type requires a JSON array (e.g. [1,2,3]) to deserialize correctly.

    To fix this error either change the JSON to a JSON array (e.g. [1,2,3]) or change the deserialized type so that it is a normal .NET type (e.g. not a primitive type like integer, not a collection type like an array or List) that can be deserialized from a JSON object. JsonObjectAttribute can also be added to the type to force it to deserialize from a JSON object. Path 'accounts.github', line 1, position 129.

    Having never worked with this DeserializeObject method before, I'm kind of stuck here.

    I've made sure that the property names in the POCO class are the same as the names in the JSON response.

    What can I try to deserialize JSON into this POCO class?

  • Samyeak Maharjan
    Samyeak Maharjan almost 12 years
    Just define the property not as a list. I'm editing my answer (Edit2)
  • Only Bolivian Here
    Only Bolivian Here almost 12 years
    The actual JSON is in the question.
  • dmi_
    dmi_ almost 12 years
    Oops, editing now edit: Done. Sorry for not noticing that; skimming is not always optimal ;P
  • Only Bolivian Here
    Only Bolivian Here almost 12 years
    Exactly what I was hoping existed. I'll definitely take a look at this. Thank you!
  • SwDevMan81
    SwDevMan81 almost 12 years
    No problem, glad I could help.
  • Only Bolivian Here
    Only Bolivian Here almost 12 years
    That resulted in much, much cleaner code. I had already implemented a custom Serializer, but I like this approach better as it's leaner. Thanks again!
  • huntharo
    huntharo almost 11 years
    Did you forget the List<> on Account, or am I missing something? It seems to me that the original question had Accounts as a list, but this solution has Accounts as a single Account object... not an array, not a list.
  • Rick Haffey
    Rick Haffey about 9 years
    @huntharo Looks like the changed Accounts declaration -- from List<Account> to Account -- is because the example JSON (linked in the question) has an individual JSON object -- not an array -- for accounts: "accounts": {"github": "sergiotapia"}
  • Emil
    Emil over 6 years
    how is that a valid answer without any explanation? why should we use JsonProperty if name is the same. JsonProperty is used if returned object has name like badges instead of Badges. Making account not list is not a solution either. because accounts are supposed to be list but it throws exception some cases.
  • Vanquished Wombat
    Vanquished Wombat almost 3 years
    Update July 2021 - the converter is still present on the web and works well.
  • Admin
    Admin over 2 years
    Your answer could be improved with additional supporting information. Please edit to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers in the help center.
  • Asad Naeem
    Asad Naeem over 2 years
    but we can write [JsonProperty("Username")]