2014-05-04 13 views
42

Bir WebAPI uygulama bu kodlanmış olan numunenin bakıyorum her seçilir nedenJson.NET içinde PreserveReferencesHandling ve ReferenceLoopHandling arasındaki fark nedir? Bu kodlanmış ile</p> <pre><code>json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; </code></pre> <p>ve başka:

json.SerializerSettings.ReferenceLoopHandling 
    = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

Ne açıklar. WebAPI için çok yeni biriyim, bu yüzden birileri bana, basitlik açısından, farklılıkların neler olduğunu ve neden diğerini kullanmam gerektiğini açıklayarak yardımcı olabilir.

+4

Dokümanlar ne dedi? Bunun hakkında ne belirsizdi? – nvoigt

cevap

98

Bu ayarlar en iyi örnek ile izah edilebilir. Şirketteki çalışanların hiyerarşisini temsil etmek istediğimizi varsayalım. Bu yüzden basit bir sınıf böyle yapmak: Angela Bob ve Charles:

class Employee 
{ 
    public string Name { get; set; } 
    public List<Employee> Subordinates { get; set; } 
} 

Bu şimdiye kadar sadece üç çalışanı olan küçük bir şirkettir. Angela patrondur, Bob ve Charles onun astlarıdır. en bu ilişkiyi açıklamak için verileri kuralım:

[ 
    { 
    "Name": "Angela Anderson", 
    "Subordinates": [ 
     { 
     "Name": "Bob Brown", 
     "Subordinates": null 
     }, 
     { 
     "Name": "Charles Cooper", 
     "Subordinates": null 
     } 
    ] 
    }, 
    { 
    "Name": "Bob Brown", 
    "Subordinates": null 
    }, 
    { 
    "Name": "Charles Cooper", 
    "Subordinates": null 
    } 
] 
: ... biz JSON çalışanların listesini seri halinde

Employee angela = new Employee { Name = "Angela Anderson" }; 
Employee bob = new Employee { Name = "Bob Brown" }; 
Employee charles = new Employee { Name = "Charles Cooper" }; 

angela.Subordinates = new List<Employee> { bob, charles }; 

List<Employee> employees = new List<Employee> { angela, bob, charles }; 

string json = JsonConvert.SerializeObject(employees, Formatting.Indented); 
Console.WriteLine(json); 

... bu çıktıyı almak

Şimdiye kadar çok iyi. Onları temsil eden nesneler ana çalışanların listesi ve astlarının Angela'nın listesiyle hem başvurulan çünkü Bob ve Charles için bilgi JSON tekrarlanır Ancak, fark edeceksiniz. Belki şu an için sorun değil.

Şimdi biz de kendi astlarına ilaveten her İşçinin amiri takip etmek için bir yol olsun isterim herhalde. Bu yüzden ... Bir Supervisor özellik eklemek için

class Employee 
{ 
    public string Name { get; set; } 
    public Employee Supervisor { get; set; } 
    public List<Employee> Subordinates { get; set; } 
} 

bizim Employee modelini değiştirmek ... ve göstermek için bizim kurulum koduna bir çift daha satırları ekleyin Angela Charles ve Bob raporu:

Employee angela = new Employee { Name = "Angela Anderson" }; 
Employee bob = new Employee { Name = "Bob Brown" }; 
Employee charles = new Employee { Name = "Charles Cooper" }; 

angela.Subordinates = new List<Employee> { bob, charles }; 
bob.Supervisor = angela;  // added this line 
charles.Supervisor = angela; // added this line 

List<Employee> employees = new List<Employee> { angela, bob, charles }; 

Ama şimdi biraz sorunumuz var. nesne grafiği içinde referans halka (ör angela referanslar bob ise bob referanslar angela) sahip olduğu için, biz çalışan listeyi seri deneyin zaman, bir JsonSerializationException olacaktır. Bu sorunu çözmek bir yolu böyle Ignore için ReferenceLoopHandling ayarlayarak geçerli: etapta bu ayarda

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    ReferenceLoopHandling = ReferenceLoopHandling.Ignore, 
    Formatting = Formatting.Indented 
}; 

string json = JsonConvert.SerializeObject(employees, settings); 

, aşağıdaki JSON olsun: Eğer JSON incelerseniz

[ 
    { 
    "Name": "Angela Anderson", 
    "Supervisor": null, 
    "Subordinates": [ 
     { 
     "Name": "Bob Brown", 
     "Subordinates": null 
     }, 
     { 
     "Name": "Charles Cooper", 
     "Subordinates": null 
     } 
    ] 
    }, 
    { 
    "Name": "Bob Brown", 
    "Supervisor": { 
     "Name": "Angela Anderson", 
     "Supervisor": null, 
     "Subordinates": [ 
     { 
      "Name": "Charles Cooper", 
      "Subordinates": null 
     } 
     ] 
    }, 
    "Subordinates": null 
    }, 
    { 
    "Name": "Charles Cooper", 
    "Supervisor": { 
     "Name": "Angela Anderson", 
     "Supervisor": null, 
     "Subordinates": [ 
     { 
      "Name": "Bob Brown", 
      "Subordinates": null 
     } 
     ] 
    }, 
    "Subordinates": null 
    } 
] 

, bu Bu ayarın ne olduğu açık olmalıdır: serializer, serileştirme işleminde olan bir nesneye bir referansla karşılaştığı her zaman, sadece o üyeyi atlar. (Bu sonsuz bir döngüye girmesini seri hale engeller.) JSON üst kısmında astlarının Angela'nın listesinde Bob ne de Charles de bir danışman gösterdiğini görebilirsiniz. JSON'un alt kısmında, Bob ve Charles her ikisi de Angela'yı amir olarak gösterir, ancak bu noktada astlarının listesinin hem Bob hem de Charles'ı içermediğine dikkat edin.

Bu JSON ile çalışmak ve hatta bazı nesnelerle orijinal nesne hiyerarşisini yeniden yapılandırmak mümkün olsa da, açıkça optimal değildir. Hala yerine ayarlayarak PreserveReferencesHandling kullanarak nesne referanslarını korurken Biz JSON tekrarlanan bilgileri ortadan kaldırabilir:

JsonSerializerSettings settings = new JsonSerializerSettings 
{ 
    PreserveReferencesHandling = PreserveReferencesHandling.Objects, 
    Formatting = Formatting.Indented 
}; 

string json = JsonConvert.SerializeObject(employees, settings); 

Şimdi aşağıdaki JSON olsun:

[ 
    { 
    "$id": "1", 
    "Name": "Angela Anderson", 
    "Supervisor": null, 
    "Subordinates": [ 
     { 
     "$id": "2", 
     "Name": "Bob Brown", 
     "Supervisor": { 
      "$ref": "1" 
     }, 
     "Subordinates": null 
     }, 
     { 
     "$id": "3", 
     "Name": "Charles Cooper", 
     "Supervisor": { 
      "$ref": "1" 
     }, 
     "Subordinates": null 
     } 
    ] 
    }, 
    { 
    "$ref": "2" 
    }, 
    { 
    "$ref": "3" 
    } 
] 

Bildirimi şimdi her nesne olmuştur JSON'da bir sıralı $id değeri atandı. Bir nesnenin ilk göründüğü zaman, tam olarak serileştirilirken, sonraki referanslar, orijinal nesneyi karşılık gelen $id ile yeniden gönderen özel bir $ref özelliğiyle değiştirilir. Bu ayar geçerli olduğunda, JSON çok daha özlüdür ve Json.Net/Web API tarafından üretilen $id ve $ref notasyonunu anlayan bir kitaplık kullandığınızı varsayarak, hiçbir ek iş gerekmeden orijinal nesne hiyerarşisine geri gönderilebilir.

Peki neden bir ayar veya diğerini seçmelisiniz? Bu sizin ihtiyaçlarınız doğrultusunda. JSON, $id/$ref biçimini anlamayan bir istemci tarafından tüketilecek ve bu, eksik veri içeren yerlerde tolere edebilirse, ReferenceLoopHandling.Ignore kullanmayı tercih edersiniz. Daha kompakt JSON arıyorsanız ve verileri serileştirmek için Json.Net veya Web API'sini (veya başka bir uyumlu kütüphane) kullanacaksanız, PreserveReferencesHandling.Objects'u kullanmayı tercih edersiniz. Verileriniz, yinelenen referans içermeyen yönlendirilmiş bir asiklik grafikse, o zaman ayarlara da ihtiyacınız yoktur.

+9

Mükemmel cevap. Son yöntemi kullanırken ('PreserveReferencesHandling.Objects') [JsonNetDecycle] (https://bitbucket.org/smithkl42/jsonnetdecycle) nesne başvuruları istemci tarafında yeniden birleştirmek için harika bir kütüphanedir. – WimpyProgrammer

+0

Gerçekten iyi bir cevap. Ben aydınlandım. –

İlgili konular