2012-06-20 37 views
41

Đây là đơn giản lớp User POCO tôi:Sử dụng JsonConvert.DeserializeObject để deserialize JSON để một lớp C# 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; } 

} 

Và phương pháp tôi đang sử dụng để deserialize một phản ứng JSON thành đối tượng User (thực tế JSON call is here này):

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

này bắn một ngoại lệ:

Không thể deserialize đối tượng JSON hiện tại (ví dụ: {"name": "value"}) thành loại 'System.Collections.Generic.List`1 [CoderwallDotNet.Api.Models.Account]' vì loại yêu cầu mảng JSON (ví dụ: [1,2,3 ]) để deserialize chính xác.

Để khắc phục lỗi này, hãy thay đổi JSON thành một mảng JSON (ví dụ [1,2,3]) hoặc thay đổi loại được loại bỏ để nó là loại thông thường .NET (ví dụ: không phải kiểu nguyên thủy như số nguyên , không phải bộ sưu tập loại như một mảng hoặc Danh sách) có thể được deserialized từ một đối tượng JSON . JsonObjectAttribute cũng có thể được thêm vào kiểu để buộc nó để deserialize từ một đối tượng JSON. Đường dẫn 'accounts.github', dòng 1, vị trí 129.

Chưa bao giờ làm việc với phương pháp DeserializeObject này trước đây, tôi bị kẹt ở đây.

Tôi đã đảm bảo rằng tên thuộc tính trong lớp POCO giống với tên trong phản hồi JSON.

Tôi có thể cố gắng deserialize JSON vào lớp POCO này như thế nào?

+0

Dường như tôi đến trễ, nhưng hãy xem câu trả lời của tôi. sử dụng 'JsonProperty' dễ dàng hơn nhiều (và có thể đọc được) hơn là viết' JsonConverter' –

+0

Có thể bạn đang xem xét một thứ như thế này. http://stackoverflow.com/questions/25672338/dynamically-deserialize-json-into-any-object-passed-in-c-sharp – Jim

Trả lời

69

Đây là ví dụ hoạt động.

keypoint là:

  • Tuyên bố của Accounts
  • Sử dụng JsonProperty thuộc tính

.

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

Điều đó dẫn đến nhiều, nhiều mã sạch hơn. Tôi đã thực hiện một Serializer tùy chỉnh, nhưng tôi thích cách tiếp cận này tốt hơn vì nó gọn gàng hơn. Cảm ơn một lần nữa! –

+8

Bạn đã quên Danh sách <> trên Tài khoản hay tôi thiếu một cái gì đó? Dường như với tôi rằng câu hỏi ban đầu có Tài khoản dưới dạng danh sách, nhưng giải pháp này có Tài khoản dưới dạng một đối tượng Tài khoản đơn lẻ ... không phải là mảng, không phải danh sách. – huntharo

+2

@huntharo Hình như khai báo 'Tài khoản' đã thay đổi - từ' Danh sách 'thành 'Tài khoản' - là vì ví dụ JSON (được liên kết trong câu hỏi) có một đối tượng JSON riêng lẻ - không phải mảng - cho' tài khoản ':' "tài khoản": {"github": "sergiotapia"} ' –

2

Thuộc tính tài khoản được định nghĩa như thế này:

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

POCO tiểu bang của bạn này:

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

Hãy thử sử dụng Json này:

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

Một mảng các mặt hàng (đó là sẽ được ánh xạ tới danh sách) luôn được đặt trong dấu ngoặc vuông.

Edit: Các Poco tài khoản sẽ được một cái gì đó như thế này:

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

và có thể các tài sản khác.

Chỉnh sửa 2: Để không có một mảng sử dụng tài sản như sau:

public Account Accounts { get; set; } 

với một cái gì đó giống như lớp mẫu tôi đã đăng trong chỉnh sửa đầu tiên.

+0

Chỉ cần xác định thuộc tính không phải là danh sách.Tôi đang chỉnh sửa câu trả lời của mình (Edit2) – Sascha

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

Toàn bộ thông báo cho biết có thể tuần tự hóa đối tượng Danh sách, nhưng đầu vào phải là danh sách JSON. Điều này có nghĩa rằng JSON của bạn cần phải chứa

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

đâu AccountObject dữ liệu JSON đại diện cho đối tượng tài khoản của bạn hoặc đối tượng Huy hiệu của bạn

gì nó có vẻ là đang nhận được là

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

đâu chiếm là một đối tượng JSON (được biểu thị bằng dấu ngoặc nhọn), không phải là một mảng các đối tượng JSON (các mảng được biểu thị bằng dấu ngoặc đơn), đó là những gì bạn muốn. Hãy thử

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

JSON thực tế nằm trong câu hỏi. –

+0

Rất tiếc, chỉnh sửa hiện chỉnh sửa: Xong. Xin lỗi vì không nhận thấy điều đó; lướt qua không phải lúc nào cũng tối ưu, P –

4

Bạn có thể tạo JsonConverter. Xem here để biết ví dụ tương tự như câu hỏi của bạn.

+0

** Chính xác ** những gì tôi đã hy vọng tồn tại. Tôi chắc chắn sẽ xem xét điều này. Cảm ơn bạn! –

+0

Không sao, tôi rất vui được giúp đỡ. – SwDevMan81

4

khác, và sắp xếp hợp lý hơn, cách tiếp cận để deserializing một JSON chuỗi lạc đà-cased đến một đối tượng POCO pascal-cased là sử dụng CamelCasePropertyNamesContractResolver.

Đó là một phần của không gian tên Newtonsoft.Json.Serialization. Cách tiếp cận này giả định rằng sự khác biệt duy nhất giữa đối tượng JSON và POCO nằm trong vỏ của các tên thuộc tính. Nếu tên thuộc tính được viết khác nhau, thì bạn sẽ cần phải sử dụng thuộc tính JsonProperty để ánh xạ các tên thuộc tính.

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

Đó không phải chính xác những gì tôi có trong đầu. Bạn sẽ làm gì nếu bạn có một loại chung để chỉ được biết trong thời gian chạy?

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