developer tip

JsonConvert.DeserializeObject를 사용하여 Json을 C # POCO 클래스로 deserialize

optionbox 2020. 12. 4. 08:08
반응형

JsonConvert.DeserializeObject를 사용하여 Json을 C # POCO 클래스로 deserialize


다음은 내 간단한 UserPOCO 클래스입니다.

/// <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 호출은 여기에 있음 ) :

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 유형이되도록 변경하십시오 (예 : 정수와 같은 기본 유형이 아니라 다음과 같은 컬렉션 유형이 아님). JSON 개체에서 역 직렬화 할 수있는 배열 또는 목록)입니다. JsonObjectAttribute를 유형에 추가하여 JSON 객체에서 강제로 역 직렬화 할 수도 있습니다. 경로 'accounts.github', 1 행, 위치 129.

이전에이 DeserializeObject 메서드로 작업 한 적이 없어서 여기에 갇혀 있습니다.

POCO 클래스의 속성 이름이 JSON 응답의 이름과 동일한 지 확인했습니다.

이 POCO 클래스로 JSON을 역 직렬화하려면 어떻게해야합니까?


다음은 작동하는 예입니다.

요점은 다음과 같습니다.

  • 선언 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;
}

계정 속성은 다음과 같이 정의됩니다.

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

귀하의 POCO는 다음과 같이 말합니다.

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

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


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


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

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

The whole message indicates that it is possible to serialize to a List object, but the input must be a JSON list. This means that your JSON must contain

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

Where AccountObject data is JSON representing your Account object or your Badge object

What it seems to be getting currently is

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

Where accounts is a JSON object (denoted by curly braces), not an array of JSON objects (arrays are denoted by brackets), which is what you want. Try

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

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#


That's not exactly what I had in mind. What do you do if you have a generic type to only be known at runtime?

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

참고URL : https://stackoverflow.com/questions/11126242/using-jsonconvert-deserializeobject-to-deserialize-json-to-a-c-sharp-poco-class

반응형