使用JsonConvert.DeserializeObject将Json反序列化为C#POCO类

时间:2012-06-20 18:52:19

标签: c# json serialization json.net poco

这是我简单的User POCO课程:

/// <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; }

}

我用来将JSON响应反序列化为User对象的方法(实际为JSON call is here):

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

这引发了一个例外:

  

无法反序列化当前的JSON对象(例如{“name”:“value”})   进入类型   'System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account]'   因为该类型需要一个JSON数组(例如[1,2,3])来反序列化   正确。

     

要修复此错误,请将JSON更改为JSON数组   (例如[1,2,3])或更改反序列化类型以使其正常   .NET类型(例如,不是整数的基本类型,不是集合   类似于数组或List的类型,可以从JSON反序列化   宾语。 JsonObjectAttribute也可以添加到类型中以强制它   从JSON对象反序列化。路径'accounts.github',第1行,   第129位。

之前从未使用过这种DeserializeObject方法,我有点被困在这里。

我确保POCO类中的属性名称与JSON响应中的名称相同。

我可以尝试将JSON反序列化为此POCO类吗?

7 个答案:

答案 0 :(得分:92)

这是一个工作示例。

关键点是:

  • Accounts
  • 的声明
  • 使用JsonProperty属性

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;
}

答案 1 :(得分:5)

将基于驼峰的JSON字符串反序列化为基于pascal的POCO对象的另一种更简化的方法是使用CamelCasePropertyNamesContractResolver

它是Newtonsoft.Json.Serialization命名空间的一部分。这种方法假设JSON对象和POCO之间的唯一区别在于属性名称的大小写。如果属性名拼写不同,那么您将需要使用JsonProperty属性来映射属性名称。

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; 
}

答案 2 :(得分:4)

accounts属性的定义如下:

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

你的POCO说明了这一点:

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

尝试使用这个Json:

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

项目数组(将映射到列表)始终用方括号括起来。

修改:帐户Poco将是这样的:

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

也许还有其他属性。

编辑2:要没有数组,请使用以下属性:

public Account Accounts { get; set; }

类似于我在第一次编辑中发布的示例类。

答案 3 :(得分:4)

您可以创建JsonConverter。有关与您的问题类似的示例,请参阅here

答案 4 :(得分:2)

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.`

整条消息表明可以序列化为List对象,但输入必须是JSON列表。 这意味着您的JSON必须包含

"accounts" : [{<AccountObjectData}, {<AccountObjectData>}...],

其中AccountObject数据是表示您的Account对象或徽章对象的JSON

目前看来是什么

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

其中account是JSON对象(用花括号表示),而不是JSON对象数组(数组用括号表示),这就是你想要的。尝试

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

答案 5 :(得分:1)

根据接受的答案,如果您有JSON文本示例,可以将其插入this converter,选择您的选项并生成C#代码。

如果您在运行时不知道类型,则此主题看起来很合适。

dynamically deserialize json into any object passed in. c#

答案 6 :(得分:0)

这不是我的想法。如果只有在运行时知道泛型类型,你会怎么做?

public MyDTO toObject() {
  try {
    var methodInfo = MethodBase.GetCurrentMethod();
    if (methodInfo.DeclaringType != null) {
      var fullName = methodInfo.DeclaringType.FullName + "." + this.dtoName;
      Type type = Type.GetType(fullName);
      if (type != null) {
        var obj = JsonConvert.DeserializeObject(payload);
      //var obj = JsonConvert.DeserializeObject<type.MemberType.GetType()>(payload);  // <--- type ?????
          ...
      }
    }

    // Example for java..   Convert this to C#
    return JSONUtil.fromJSON(payload, Class.forName(dtoName, false, getClass().getClassLoader()));
  } catch (Exception ex) {
    throw new ReflectInsightException(MethodBase.GetCurrentMethod().Name, ex);
  }
}