Giải nén dữ liệu JSON thành C # bằng JSON.NET


144

Tôi còn khá mới để làm việc với dữ liệu C # và JSON và đang tìm kiếm hướng dẫn. Tôi đang sử dụng C # 3.0, với .NET3.5SP1 và JSON.NET 3.5r6.

Tôi có một lớp C # được xác định mà tôi cần để tạo từ cấu trúc JSON. Tuy nhiên, không phải mọi cấu trúc JSON cho một mục được lấy từ dịch vụ web đều chứa tất cả các thuộc tính có thể được xác định trong lớp C #.

Tôi đã và đang làm những gì có vẻ là sai, một cách khó khăn và chỉ chọn ra từng giá trị một từ JObject và biến chuỗi thành thuộc tính lớp mong muốn.

JsonSerializer serializer = new JsonSerializer();
var o = (JObject)serializer.Deserialize(myjsondata);

MyAccount.EmployeeID = (string)o["employeeid"][0];

Cách tốt nhất để giải tuần tự hóa cấu trúc JSON vào lớp C # và xử lý dữ liệu bị thiếu có thể từ nguồn JSON là gì?

Lớp của tôi được định nghĩa là:

  public class MyAccount
  {

    [JsonProperty(PropertyName = "username")]
    public string UserID { get; set; }

    [JsonProperty(PropertyName = "givenname")]
    public string GivenName { get; set; }

    [JsonProperty(PropertyName = "sn")]
    public string Surname { get; set; }

    [JsonProperty(PropertyName = "passwordexpired")]
    public DateTime PasswordExpire { get; set; }

    [JsonProperty(PropertyName = "primaryaffiliation")]
    public string PrimaryAffiliation { get; set; }

    [JsonProperty(PropertyName = "affiliation")]
    public string[] Affiliation { get; set; }

    [JsonProperty(PropertyName = "affiliationstatus")]
    public string AffiliationStatus { get; set; }

    [JsonProperty(PropertyName = "affiliationmodifytimestamp")]
    public DateTime AffiliationLastModified { get; set; }

    [JsonProperty(PropertyName = "employeeid")]
    public string EmployeeID { get; set; }

    [JsonProperty(PropertyName = "accountstatus")]
    public string AccountStatus { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpiration")]
    public DateTime AccountStatusExpiration { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpmaxdate")]
    public DateTime AccountStatusExpirationMaxDate { get; set; }

    [JsonProperty(PropertyName = "accountstatusmodifytimestamp")]
    public DateTime AccountStatusModified { get; set; }

    [JsonProperty(PropertyName = "accountstatusexpnotice")]
    public string AccountStatusExpNotice { get; set; }

    [JsonProperty(PropertyName = "accountstatusmodifiedby")]
    public Dictionary<DateTime, string> AccountStatusModifiedBy { get; set; }

    [JsonProperty(PropertyName = "entrycreatedate")]
    public DateTime EntryCreatedate { get; set; }

    [JsonProperty(PropertyName = "entrydeactivationdate")]
    public DateTime EntryDeactivationDate { get; set; }

  }

Và một mẫu của JSON để phân tích là:

{
    "givenname": [
        "Robert"
    ],
    "passwordexpired": "20091031041550Z",
    "accountstatus": [
        "active"
    ],
    "accountstatusexpiration": [
        "20100612000000Z"
    ],
    "accountstatusexpmaxdate": [
        "20110410000000Z"
    ],
    "accountstatusmodifiedby": {
        "20100214173242Z": "tdecker",
        "20100304003242Z": "jsmith",
        "20100324103242Z": "jsmith",
        "20100325000005Z": "rjones",
        "20100326210634Z": "jsmith",
        "20100326211130Z": "jsmith"
    },
    "accountstatusmodifytimestamp": [
        "20100312001213Z"
    ],
    "affiliation": [
        "Employee",
        "Contractor",
        "Staff"
    ],
    "affiliationmodifytimestamp": [
        "20100312001213Z"
    ],
    "affiliationstatus": [
        "detached"
    ],
    "entrycreatedate": [
        "20000922072747Z"
    ],
    "username": [
        "rjohnson"
    ],
    "primaryaffiliation": [
        "Staff"
    ],
    "employeeid": [
        "999777666"
    ],
    "sn": [
        "Johnson"
    ]
}

Câu trả lời:



76

Bạn đã thử sử dụng phương pháp DeserializeObject chung chưa?

JsonConvert.DeserializeObject<MyAccount>(myjsondata);

Bất kỳ trường bị thiếu nào trong dữ liệu JSON chỉ cần để lại NULL.

CẬP NHẬT:

Nếu chuỗi JSON là một mảng, hãy thử điều này:

var jarray = JsonConvert.DeserializeObject<List<MyAccount>>(myjsondata);

jarraysau đó nên là a List<MyAccount>.

CẬP NHẬT KHÁC:

Ngoại lệ bạn nhận được không phù hợp với một loạt các đối tượng - Tôi nghĩ rằng trình tuần tự hóa có vấn đề với thuộc tính gõ từ điển của bạn accountstatusmodifiedby.

Hãy thử loại trừ accountstatusmodifiedby tài sản khỏi serialization và xem nếu điều đó giúp. Nếu có, bạn có thể cần phải đại diện cho tài sản đó khác nhau.

Tài liệu: Sắp xếp và khử tuần tự JSON bằng Json.NET


Cảm ơn. Tuy nhiên, tôi gặp lỗi "Không thể khử tuần tự mảng JSON thành loại 'System.String'." khi nó cố gắng giải tuần tự hóa (ví dụ) mảng tên được đặt JSON vào chuỗi lớp Tên. Các thuộc tính JSON mà tôi đã định nghĩa là chuỗi trong lớp C # chỉ là các mảng phần tử đơn lẻ. Đây là lý do tại sao tôi bắt đầu chọn ra từng giá trị một khi tôi gặp phải vấn đề này trong quá trình giải trừ. Phép thuật khác mà tôi đang xem?

Vì vậy, ... DateTime AccountStatusExpiration(ví dụ) không thể rỗng như được định nghĩa trong mã. Điều gì sẽ làm cho nó vô giá trị? Đơn giản chỉ cần đổi DateTimesang DateTime??
Hamish Grubijan

50

Trả lời được sao chép từ https://stackoverflow.com/a/10718128/776476

Bạn có thể sử dụng loại C # dynamicđể làm cho mọi thứ dễ dàng hơn. Kỹ thuật này cũng làm cho việc bao thanh toán trở nên đơn giản hơn vì nó không dựa vào chuỗi ma thuật.

Json

Các jsonchuỗi dưới đây là một phản ứng đơn giản từ một cuộc gọi http api và nó định nghĩa hai thuộc tính: IdName.

{"Id": 1, "Name": "biofractal"}

C #

Sử dụng JsonConvert.DeserializeObject<dynamic>()để giải tuần tự chuỗi này thành một kiểu động sau đó chỉ cần truy cập các thuộc tính của chuỗi theo cách thông thường.

var results = JsonConvert.DeserializeObject<dynamic>(json);
var id = results.Id;
var name= results.Name;

Lưu ý : Liên kết NuGet cho lắp ráp NewtonSoft là http://nuget.org/packages/newtonsoft.json . Đừng quên thêm: using Newtonsoft.Json;để truy cập các lớp đó.


7
Yêu việc sử dụng <động>. Tuy nhiên, tôi đã phải làm điều này để làm cho nó hoạt động: result ["Id"]. Giá trị và kết quả ["Tên"]. Giá trị
fredw

1
Mặc dù động là một lựa chọn tốt, nhưng các ví dụ trên không sử dụng 'chuỗi ma thuật' mà thay vào đó sử dụng các tổng quát được gõ mạnh được cập nhật trong các kỹ thuật tái cấu trúc VS thông thường (trừ khi bên trong View trong MVC nằm ngoài phạm vi của câu hỏi này).
gcoleman0828

4
Bạn vẫn có 'chuỗi ma thuật', giờ đây chúng chỉ bị ẩn đi bởi việc sử dụng năng động!
Ian Ringrose

Thật vậy, biofractal có nó ngược lại "chuỗi ma thuật", như @ IanRingrose chỉ ra. Đối tượng động được trả về bởi DeserializeObject<dynamic>theo định nghĩa không phải là "kiểm tra kiểu". Vì vậy, các dòng sau results.Idresults.Namekhông thể được xác minh tại thời gian biên dịch. Thay vào đó, bất kỳ lỗi nào sẽ xảy ra. Tương phản điều này với một cuộc gọi được gõ mạnh như DeserializeObject<List<MyAccount>>. Các tham chiếu đến các thuộc tính này có thể được xác nhận tại thời điểm biên dịch. Việc sử dụng dynamic, mặc dù có thể thuận tiện, giới thiệu "chuỗi ma thuật" làm tên thuộc tính; giảm sức mạnh IMHO.
ToolmakerSteve

8

Bạn có thể dùng:

JsonConvert.PopulateObject(json, obj);

ở đây: jsonlà chuỗi json, objlà đối tượng đích. Xem: ví dụ

Lưu ý: PopulateObject()sẽ không xóa dữ liệu danh sách của obj, sau đó Populate(), obj'sthành viên danh sách sẽ chứa dữ liệu gốc và dữ liệu từ chuỗi json


2
đó là PopulationObject - Popated không nằm trong mô hình đối tượng.
amok

1
Điều này làm việc HOÀN HẢO cho tôi! Tôi đã gặp vấn đề khi tôi có một chuỗi JSON khá phức tạp, khi tôi cố gắng chuyển nó thành các đối tượng C #, mọi thứ được đánh dấu là 'NotNull' sẽ bị thiếu khỏi đối tượng, mặc dù bắt đầu có trong chuỗi JSON. Rất lạ. Tôi đã sử dụng phương pháp này và nó hoạt động HOÀN HẢO!
jward01

3

Dựa trên câu trả lời của bbant, đây là giải pháp hoàn chỉnh của tôi để khử lưu lượng JSON từ một URL từ xa.

using Newtonsoft.Json;
using System.Net.Http;

namespace Base
{
    public class ApiConsumer<T>
    {
        public T data;
        private string url;

        public CalendarApiConsumer(string url)
        {
            this.url = url;
            this.data = getItems();
        }

        private T getItems()
        {
            T result = default(T);
            HttpClient client = new HttpClient();

            // This allows for debugging possible JSON issues
            var settings = new JsonSerializerSettings
            {
                Error = (sender, args) =>
                {
                    if (System.Diagnostics.Debugger.IsAttached)
                    {
                        System.Diagnostics.Debugger.Break();
                    }
                }
            };

            using (HttpResponseMessage response = client.GetAsync(this.url).Result)
            {
                if (response.IsSuccessStatusCode)
                {
                    result = JsonConvert.DeserializeObject<T>(response.Content.ReadAsStringAsync().Result, settings);
                }
            }
            return result;
        }
    }
}

Cách sử dụng sẽ như sau:

ApiConsumer<FeedResult> feed = new ApiConsumer<FeedResult>("http://example.info/feeds/feeds.aspx?alt=json-in-script");

Trong trường hợp FeedResultlà lớp được tạo ra bằng cách sử dụng Xamasoft JSON Lớp Generator

Dưới đây là ảnh chụp màn hình của các cài đặt tôi đã sử dụng, cho phép các tên thuộc tính lạ mà phiên bản web không thể chiếm được.

Trình tạo lớp JSON của Xamasoft


1

Tôi tìm thấy tôi đã xây dựng đối tượng của tôi không chính xác. Tôi đã sử dụng http://json2csharp.com/ để tạo cho tôi lớp đối tượng của mình từ JSON. Khi tôi đã có Oject chính xác, tôi có thể sử dụng mà không gặp vấn đề gì. Norbit, Noob sai lầm. Tôi nghĩ tôi sẽ thêm nó trong trường hợp bạn có cùng một vấn đề.


1

Bạn có thể thử kiểm tra một số trình tạo lớp trực tuyến để biết thêm thông tin. Tuy nhiên, tôi tin rằng một số câu trả lời đã có ích. Đây là cách tiếp cận của tôi có thể hữu ích.

Các mã sau đây đã được thực hiện với một phương pháp động trong tâm trí.

dynObj = (JArray) JsonConvert.DeserializeObject(nvm);

foreach(JObject item in dynObj) {
 foreach(JObject trend in item["trends"]) {
  Console.WriteLine("{0}-{1}-{2}", trend["query"], trend["name"], trend["url"]);
 }
}

Mã này về cơ bản cho phép bạn truy cập các thành viên có trong chuỗi Json. Chỉ là một cách khác nhau mà không cần các lớp học. query, trendurllà đối tượng chứa trong chuỗi Json.

Bạn cũng có thể sử dụng trang web này . Đừng tin tưởng các lớp học 100% nhưng bạn có ý tưởng.


0

Giả sử dữ liệu mẫu của bạn là chính xác, tên được đặt của bạn và các mục nhập khác được gói trong ngoặc là mảng trong JS ... bạn sẽ muốn sử dụng Danh sách cho các loại dữ liệu đó. và Danh sách cho biết accountstatusExmaxdate ... Tôi nghĩ rằng ví dụ của bạn có ngày được định dạng không chính xác, vì vậy không chắc chắn về những gì khác là không chính xác trong ví dụ của bạn.

Đây là một bài viết cũ, nhưng muốn lưu ý các vấn đề.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.