2011-02-02 23 views
21

Tôi có đoạn mã sau:DataContract serialization ngoại lệ (tên hợp đồng dữ liệu không mong đợi)

[DataContract] 
class TestContract { 
    private String _Name; 
    private Int32 _Age; 

    [DataMember(Name = "Name")] 
    public String Name { 
     get { return _Name; } 
     set { _Name = value; } 
    } 

    [DataMember(Name = "Age")] 
    public Int32 Age { 
     get { return _Age; } 
     set { _Age = value; } 
    } 
} 

[Serializable] 
public class DNCJsonDictionary<K, V> : ISerializable { 
    Dictionary<K, V> dict = new Dictionary<K, V>(); 

    public DNCJsonDictionary() { } 

    protected DNCJsonDictionary(SerializationInfo info, StreamingContext context) { 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext context) { 
     foreach(K key in dict.Keys) { 
      info.AddValue(key.ToString(), dict[ key ]); 
     } 
    } 

    public void Add(K key, V value) { 
     dict.Add(key, value); 
    } 

    public V this[ K index ] { 
     set { dict[ index ] = value; } 
     get { return dict[ index ]; } 
    } 
} 

public class MainClass { 
    public static String Serialize(Object data) { 
     var serializer = new DataContractJsonSerializer(data.GetType()); 
     var ms = new MemoryStream(); 
     serializer.WriteObject(ms, data); 

     return Encoding.UTF8.GetString(ms.ToArray()); 
    } 

    public static void Main() { 
     DNCJsonDictionary<String, Object> address = new DNCJsonDictionary<String, Object>(); 
     address[ "Street" ] = "30 Rockefeller Plaza"; 
     address[ "City" ] = "New York City"; 
     address[ "State" ] = "NY"; 

     TestContract test = new TestContract(); 
     test.Name = "CsDJ"; 
     test.Age = 28; 

     DNCJsonDictionary<String, Object> result = new DNCJsonDictionary<String, Object>(); 
     result[ "foo" ] = "bar"; 
     result[ "Name" ] = "John Doe"; 
     result[ "Age" ] = 32; 

     result[ "Address" ] = address; 

      // ** --- THIS THROWS AN EXCEPTION!!! --- **    
     result[ "test" ] = test; 

     Console.WriteLine(Serialize(result)); 

     Console.ReadLine(); 
    } 
} 

Khi tôi chạy, tôi nhận được ngoại lệ này:

Loại 'Json_Dictionary_Test.TestContract' với dữ liệu tên hợp đồng 'TestContract: http://schemas.datacontract.org/2004/07/Json_Dictionary_Test' không được mong đợi. Thêm bất kỳ loại nào không được biết đến tĩnh vào danh sách các kiểu đã biết - ví dụ, bằng cách sử dụng thuộc tính KnownTypeAttribute hoặc bằng cách thêm chúng vào danh sách các kiểu đã biết được truyền cho DataContractSerializer.

Nhưng tôi không hiểu điều đó! Như tôi biết, KnownTypeAttribute được sử dụng chỉ trong deserialization, và nếu có thừa kế, phải không? Nhưng đây chỉ là serialization. Và không có thành viên datacontract hoạt động tốt.

Bất kỳ ý tưởng nào?


Tôi đã tìm ra điều gì đó hiệu quả! Có một lớp cha với một danh sách KnownTypes, mà tôi điền vào với mọi tầng lớp trẻ và điều đó sẽ được sử dụng trong serialization:

[DataContract] 
[KnownType("GetKnownTypes")] // for serialization 
class ResultContract { 
    private static List<Type> KnownTypes { get; set; } 

    public static List<Type> GetKnownTypes() { 
     return KnownTypes; 
    } 

    static ResultContract() { 
     KnownTypes = new List<Type>(); 
     try { 
      foreach(Type type in Assembly.GetExecutingAssembly().GetTypes()) { 
       if(!type.IsAbstract && type.IsSubclassOf(typeof(ResultContract))) { 
        KnownTypes.Add(type); 
       } 
      } 
     } catch(Exception ex) { 
      Console.WriteLine("Fatal error!"); 
     } 
    } 
} 

[DataContract] 
class TestContract : *ResultContract* { 
    ... 
} 
... 
+0

Giải pháp tốt! Điều này sẽ giúp tôi tiết kiệm rất nhiều thời gian. Thay vì làm cho tất cả các lớp serializable một lớp con tôi chỉ kiểm tra xem chúng có thuộc tính DataContract hoạt động tốt hơn cho tôi không: if (! Type.IsAbstract && type.IsDefined (typeof (DataContractAttribute), true)) { knownTypes. Thêm (loại); } – rob

Trả lời

20

Thêm dòng này:

[KnownType(typeof(TestContract))] 

Vì vậy mà

[Serializable] 
[KnownType(typeof(TestContract))] 
public class DNCJsonDictionary<K, V> : ... 

Đây là sự cố đã biết. Đó là lý do tại sao generics không hoàn toàn tương thích với WCF.

Nhưng lý do rất dễ, WCF được cho là tạo WSDL và có thể xuất bản hợp đồng của bạn. Đó là tất cả tốt và tốt để sử dụng Generics để xác định hợp đồng của bạn nhưng WSDL cần phải trỏ đến một số lớp cụ thể do đó bạn cần KnownType.

+0

Thaks, nó hoạt động, nhưng ... DNCJsonDictionary chỉ là một container, nó có thể không biết về "KnownTypes", nó không phải là công việc của mình. Và nếu tôi sử dụng Danh sách thay vì "từ điển" của tôi, nó hoạt động. – Aaaaaaaa

+0

Nếu nó đã được tiếp xúc trong một hợp đồng sau đó nó nên biết về KnownTypes vì ​​nó sẽ cho khuôn khổ làm thế nào để serialize. Tôi không bảo vệ WCF, tôi đã không thiết kế nó! Trong thực tế, tôi không thích nó: http://stackoverflow.com/questions/3710635/succinct-and-light-weight-api-restjson-in-net – Aliostad

+0

Được rồi, nhưng câu hỏi của tôi vẫn là: ví dụ Danh sách > T < cũng là một loại chung, và tôi điều, nó đã không có một thuộc tính [KnownType (typeof (TestContract))]. Nhưng nó hoạt động tốt: List ltc = new List (); ltc.Add (kiểm tra); Console.WriteLine (Serialize (ltc)); Tại sao? Làm sao? – Aaaaaaaa

Các vấn đề liên quan