JSON.NET kullanarak JSON verilerinin C # 'a serisini kaldırma


144

C # ve JSON verileri ile çalışmak için nispeten yeni ve rehberlik arıyorum. .NET3.5SP1 ve JSON.NET 3.5r6 ile C # 3.0 kullanıyorum.

Bir JSON yapısından doldurmak gerekir tanımlanmış bir C # sınıfı var. Ancak, web hizmetinden alınan bir girdinin her JSON yapısı, C # sınıfı içinde tanımlanan tüm olası öznitelikleri içermez.

Ne yanlış, zor bir yol gibi görünüyor yapıyorum ve sadece JObject her değeri tek tek toplama ve istenen sınıf özelliğine dize dönüştürme.

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

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

Bir JSON yapısını C # sınıfına serileştirmenin ve JSON kaynağından olası eksik verileri işlemenin en iyi yolu nedir?

Sınıfım şöyle tanımlanır:

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

  }

Ayrıştırılacak bir JSON örneği:

{
    "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"
    ]
}

Yanıtlar:



76

Genel DeserializeObject yöntemini kullanmayı denediniz mi?

JsonConvert.DeserializeObject<MyAccount>(myjsondata);

JSON verilerindeki eksik alanlar NULL olarak bırakılmalıdır.

GÜNCELLEME:

JSON dizesi bir diziyse şunu deneyin:

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

jarraysonra bir olmalıdır List<MyAccount>.

BAŞKA BİR GÜNCELLEME:

Aldığınız istisna bir nesne dizisi ile tutarlı değil - Bence serileştirici Sözlük türü accountstatusmodifiedbyözelliğinizde sorun yaşıyor .

accountstatusmodifiedby Özelliği serileştirmeden hariç tutmayı deneyin ve yardımcı olup olmadığına bakın. Varsa, bu özelliği farklı bir şekilde temsil etmeniz gerekebilir.

Belgeler: JSON'u Json.NET ile Serileştirme ve Diziselleştirme


Teşekkürler. Ancak "JS.S dizisi 'System.String' türüne serpiştirilemiyor" hatası alıyorum. JSON hediye adı dizisinin serisini GivenName dizesine serileştirmeye çalışırken (örneğin). C # sınıfında dize olarak tanımladığım JSON öznitelikleri yalnızca tek öğe dizileridir. Bu nedenle, serileştirme işlemi sırasında bu tür bir sorunla karşılaştığımda değerleri tek tek seçmeye başladım. Göz ardı ettiğim başka bir sihir mi?

Yani ... DateTime AccountStatusExpiration(örneğin) kodda tanımlandığı gibi boş bırakılamaz. Null edilebilir kılmak için ne gerekir? Basitçe değiştirmek DateTimeiçin DateTime??
Hamish Grubijan

50

Yanıt https://stackoverflow.com/a/10718128/776476 adresinden yeniden oluşturuldu

dynamicİşleri kolaylaştırmak için C # türünü kullanabilirsiniz. Bu teknik aynı zamanda, sihirli dizelere bağlı olmadığı için yeniden faktoringi de kolaylaştırır.

Json

Aşağıdaki jsondize bir http api çağrısından gelen basit bir yanıttır ve iki özelliği tanımlar: Idve Name.

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

C #

JsonConvert.DeserializeObject<dynamic>()Bu dizeyi dinamik bir türe dönüştürmek için kullanın ve daha sonra özelliklerine normal şekilde erişin.

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

Not : NewtonSoft montajı için NuGet bağlantısı http://nuget.org/packages/newtonsoft.json şeklindedir . Eklemeyi unutmayın: using Newtonsoft.Json;bu sınıflara erişmek için.


7
<dinamik> kullanımını seviyorum. Ancak, bu çalışma almak için bunu yapmak zorunda: sonucunu [ "Id"] Değer ve sonuç [ "Ad"] Değer..
fredw

1
Dinamik güzel bir alternatif olsa da, yukarıdaki örnekler 'sihirli dizeler' kullanmamakta, bunun yerine normal VS yeniden düzenleme teknikleri sırasında güncellenen güçlü tiplendirilmiş jenerikler kullanmaktadır (MVC'de bu sorunun kapsamı dışında kalan bir Görünüm içinde değilse).
gcoleman0828

4
Hala 'sihirli dizeleriniz' var, şimdi sadece dinamik kullanımıyla gizleniyorlar!
Ian Ringrose

Gerçekten de, biofraktal @ IanRingrose'un belirttiği gibi geriye doğru "sihirli telleri" geri almıştır. Tarafından döndürülen dinamik nesne DeserializeObject<dynamic>tanım gereği "tür denetlenmez". Yani aşağıdaki satırlar results.Idve results.Namederleme zamanında doğrulanamaz. Bunun yerine hatalar çalışma zamanında gerçekleşir. Bunu, güçlü bir şekilde yazılmış bir çağrı ile karşılaştırın DeserializeObject<List<MyAccount>>. Bu özelliklere referanslar derleme zamanında teyit edilebilir . Kullanılması dynamicuygun olsa da, özellik adları olarak "sihirli dizeler" i tanıtır; sağlamlık azalması.
ToolmakerSteve

8

Kullanabilirsiniz:

JsonConvert.PopulateObject(json, obj);

burada: jsonjson dizesi, objhedef nesnedir. Bakınız: örnek

Not: PopulateObject()listesi verileri, sonra en obj silmemesini Populate(), obj'sliste üyesi irade json dizesinden özgün veri ve veri içeren


2
it PopulateObject - Populate nesne modelinde değil.
amok

1
Bu benim için MÜKEMMEL çalıştı! Oldukça karmaşık bir JSON dizesi vardı sorunları yaşıyordum, C # nesnelerine yayınlamaya çalıştığımda, başlangıçta JSON dizesinde mevcut olsa bile 'NotNull' olarak işaretlenmiş herhangi bir şey nesneden eksik olurdu. Çok ilginç. Bu yöntemi kullandım ve MÜKEMMEL çalıştı!
jward01

3

BBant'ın cevabından yola çıkarak, JSON'u uzak bir URL'den serileştirmek için tam çözümüm.

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

Kullanımı şöyle olurdu:

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

Xamasoft JSON Sınıf ÜreticisiFeedResult kullanılarak sınıf nerede üretilir

Burada kullandığım ayarların ekran görüntüsü, web sürümünün hesaba katamadığı garip mülk adlarına izin veriyor .

Xamasoft JSON Sınıf Jeneratörü


1

Nesnemi yanlış inşa ettiğimi buldum. Bana JSON'dan nesne sınıfımı oluşturmak için http://json2csharp.com/ adresini kullandım . Doğru Oject'e sahip olduğumda, sorunsuz bir şekilde yayın yapabildim. Norbit, Noob hatası. Aynı sorunu yaşamanız durumunda ekleyeceğimi düşündüm.


1

Daha fazla bilgi için sınıf jeneratörlerinden bazılarını çevrimiçi kontrol etmeyi deneyebilirsiniz. Ancak, bazı cevapların yararlı olduğuna inanıyorum. İşte benim yararlı olabilecek yaklaşımım.

Aşağıdaki kod, dinamik bir yöntem düşünülerek yapılmıştır.

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

Bu kod temel olarak Json dizesinde yer alan üyelere erişmenizi sağlar. Sınıflara ihtiyaç duymadan sadece farklı bir yol. query, trendVe urlJson dizede yer alan nesnelerdir.

Bu web sitesini de kullanabilirsiniz . Sınıflara% 100 güvenmeyin ama siz anladınız.


0

Örnek verilerinizin doğru olduğunu, adınızın ve parantez içine alınmış diğer girdilerin JS'deki diziler olduğunu varsayarsak ... bu veri türleri için List'i kullanmak istersiniz. ve Say hesaplar için listtatusexpmaxdate ... Sanırım örnekte tarihler yanlış biçimlendirilmiş olsa da, örneğinizde başka neyin yanlış olduğu konusunda belirsiz.

Bu eski bir gönderi, ancak sorunları not etmek istedim.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.