2012-04-26 14 views
9

JSON'a serileştirilmiş genel sözlük nesnelerini döndüren bir WCFservice oluşturmayı planlıyorum. Ne yazık ki, nesne potansiyel olarak her zaman farklı olduğu için serileştirme başarısız olur. KnownTypes, özellik türü Dictionary olduğundan ve sınıfın potansiyel olarak her zaman farklı olacağından, KnownType olduğunu söyleyemem için yardımcı olamaz.DataContract serializer kullanarak Dictionary <string, object> serileştirebilir miyim?

'Bilinmeyen tip' serileştirmek mümkün ise herhangi bir fikir var mı?

Sınıflarımın her biri için DataContract/DataMember belirtmem ama (en azından prototip sürümü için) Her yanıt için güçlü türlere sahip olmak istemiyorum. Javascript istemcisi sadece umursamıyor.

Adsız sınıflara ne dersiniz?

+0

Bundan çok memnun olduğum için memnunum. Lütfen, WCF'nin bu vb. Için nasıl yapılmadığı ile ilgili argümanlara cevap vermekten çekinmeyin. Bilinen bir yol varsa ya da orada olmanız ve geçerli nedenlerden (eğer ne olursa olsun) bize bildirin. nedenleri?). – tishma

cevap

7

NOT: Sadece orijinal soruda belirtilen bilinen tür sorununu çözmek istiyorsanız, cevabımın başında JavaScriptSerializer hakkında çok fazla ayrıntıya girdim, sonuna kadar atla cevabın

Performans koştum benchmarks dayanarak

, JavaScriptSerializer diğer alternatiflere göre çok daha yavaştır ve seri hale getirmek sürece 2x atabileceğiniz/DataContractSerializer kıyasla bir nesnedeki seriyi kaldırmak.

, JavaScriptSerializer o vaktinden 'bilinen türde' belirtmek için gerektirmez ve JSON en az temiz olmasını daha esnek olduğunu söyledi Bilinen Tip

gerek yok sözlükler durumu (bkz. örnekler here).

Bilinen tipler etrafında bu esnekliğin çevirme tarafı, aynı JSON dizesini orijinal türüne geri gönderemeyecektir.

public class Person 
{ 
    public string Name { get; set; } 

    public int Age { get; set; } 
} 

Ve Dictinoary<string, object> bir örneğini oluşturmak ve bunu seri hale önce kendisine Person sınıfının bir örneğini eklerseniz:

var dictionary = new Dictionary<string, object>(); 
dictionary.Add("me", new Person { Name = "Yan", Age = 30 }); 
var serializer = new new JavaScriptSerializer(); 
var json = serializer .Serialize(dictionary); 

Ben olacak Mesela ben basit Person sınıf var varsayalım Çok temiz, ancak herhangi bir tür bilgiden yoksun olan aşağıdaki JSON {"me":{"Name":"Yan","Age":30}} olsun.

public class Employee : Person 
{ 
} 

sonra basitçe serileştirici JSON {"Name":"Yan","Age":30} seriden çıkarılabilir garanti edebilmek için hiçbir yolu yoktur: Aynı üye tanımlarla iki sınıf varsa veya Person herhangi bir ek üyelerini tanıtan olmadan sınıflandırma ise Yani sözde doğru tipte. Eğer JavaScriptSerializer kullanarak {"me":{"Name":"Yan","Age":30}} serisini ise

, sözlükte siz "me" Person örneğidir ancak bunun yerine bir Dictionary<string, object>, basit bir mülkiyet torba değil ilişkilendirilmiş değeri geri almak. Eğer geri Person örneğini almak istiyorsanız

yaptığında (büyük olasılıkla asla istemem ama!) olabilir Dictionary<string, object>ConvertToType yardımcı yöntemi kullanarak bu dönüştürmek: eğer Öte yandan

var clone = serializer.Deserialize<Dictionary<string, object>>(json); 
var personClone = serializer.ConverToType<Person>(clone["me"]); 

JSON'un doğru tipte serileştirilmesi konusunda endişelenmenize gerek yok ve JSON serailizasyonu bir performans darboğazı değil (kodunuzu izleyin ve daha önce yapmadıysanız, ne kadar zaman harcayacağınızı serileştirmek için ne kadar zaman harcadığınızı öğrenin) sadece JavaScriptSerializer kullanın.

günün sonunda, hala DataContractSerializer kullanmak ve bu KnownTypes enjekte gerekir gerekiyor, EĞER burada deneyebileceğiniz iki şey vardır Bilinen Tip enjekte ediliyor.

1) Bilinen tür dizisini DataContractSerializer constructor'a aktarın.

2) DataContractSerializer için sizi ilgilendiren türleri) bulmak için araçlarla DataContractResolver bir alt sınıfı (geçirin constructor

Sen türlerinden izler türlü bir 'bilinen tip kayıt' oluşturabilir

o sözlüğe eklenebilir ve size DataContractSerializer için enjekte etmek gerekir tüm türlerini kontrol ederseniz, en basit şeyi deneyebilirsiniz:

  1. bir türü ekleme statik yöntemlerle bir KnownTypeRegister sınıf oluşturun bilinen türler listesine:

var serializer = new DataContractSerializer(typeof(Dictionary<string, object>), KnownTypeRegister.Get());: Eğer seri hale oluşturmak zaman

[DataContract] 
public class Person 
{ 
    static Person() 
    { 
     KnownTypeRegister.Add(typeof(Person)); 
    } 
    [DataMember] 
    public string Name { get; set; } 
    [DataMember] 
    public int Age { get; set; } 
}
  • kasadan bilinen türlerinden dizisini alın:

    public static class KnownTypeRegister 
    { 
        private static readonly ConcurrentBag _knownTypes = new ConcurrentBag(); 
        public static void Add(Type type) 
        { 
         _knownTypes.Add(type); 
        } 
        public static IEnumerable Get() 
        { 
         return _knownTypes.ToArray(); 
        } 
    }
  • sicil ile türleri kaydeden statik kurucu ekleyin

    Daha fazla dinamik/daha iyi seçenek olabilir Ayrıca, dinamik olarak bilinen tip çözünürlük hakkında daha fazla bilgi edinmek isterseniz, uygulamak daha da zordur, Juhson Lowy'nin here konusundaki MSDN makalesine bir göz atın. Ayrıca, Carlos Figueira tarafından this blog post da konuyla ilgili bir okumaya değer, türleri dinamik olarak oluşturma gibi daha ileri teknikler hakkında ayrıntılı bilgi!

  • +0

    Her şeyden önce, detaylı yanıt için teşekkürler. Çizgiler boyunca araştırmaya değer gibi gözüküyor. Ayrıca, blogunuzda ServiceStack'ı da öğrendim ve kesinlikle bir REST JSON hizmeti oluşturmak için diğerlerinden çok daha kolay geliyor. – tishma

    1

    sorumluluk reddi Bir WCF uç noktasında object ortaya çıkarmanızı önermem; alto bu 'esnek' görünür, hizmetiniz tarafından hangi tür bilgilerin sunulacağını belirtmediğinizden bu iyi bir fikir değildir.

    ve şimdi bir cevap

    için WCF çağrısı ajax çağrısı tarafından tüketilen ediliyorsa ve bunu Javascript client just doesn't care. sonra neden olmasın WCF çağrısı basitçe bir dize döndürür yapmak dediği gibi? Sonra WCF çağrısı internal'leri Bu (eğer soru soruldu beri) ucuna bir araçtır

    public string MyServiceMethod() 
    { 
        var hash = new Dictionary<string, object>(); 
        hash.Add("key1", "val1"); 
        hash.Add("key2", new { Field1 = "field1", Field2 = 42}); 
        var serialized = new JavaScriptSerializer().Serialize(hash); 
        return serialized; 
    } 
    

    disclaimer2 JavaScriptSerializer kullanarak Dictionary<string, object> serialize - Ben iyi tanımlanmış olurdu bir üretim kalite uygulama için Arabirim, neyin talep edildiğini ve tel üzerinden geri gönderildiğini açıktı.

    +0

    Evet, bir dizgeyi döndürmek geçerli bir noktadır. Her yöntemde manuel olarak serileştirilmek zorunda kalmak kabul edilemez. Aslında bunun için bir çeşit sarmalayıcı düşünüyorum. DataContract serileştirme kullanarak çerçevenin bir parçası olarak daha hızlı olacağını düşündüm. Bu mu? – tishma

    +0

    Ancak, Javascript kodu tam olarak bir prototipten üretime kadar olan bir istekte ne döndüğünü bilmek zorundadır ve .NET'de yazımın ne kadar katı bir şekilde yardımcı olabileceğini göremiyorum. Olabilir mi? – tishma

    +1

    tishma, 'DataContract''un daha hızlı olacağı konusunda hiç bir ölçümüm yok. Ancak bir üçüncü parti JSON seri hale getirici (örneğin Json.NET) kullanarak serileştirilmesi ve bir dizgenin döndürülmesi, WCF'nin serileştirilmesinden daha hızlı olabilir. Ve hayır, katı yazım şeyler javascript tarafı ile yardımcı olmaz ama katı yazarak 'public API' bakmak ve tam olarak ne bir 'Sözlük ' i açığa çıkmasına karşıt olarak görün ne olduğunu biliyor. – wal

    İlgili konular