ho il seguente codice:eccezione serializzazione DataContract (nome del contratto dati non è prevista)
[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();
}
}
Quando eseguo, ottengo questa eccezione:
Tipo 'Json_Dictionary_Test.TestContract' con i dati il nome del contratto 'TestContract: http://schemas.datacontract.org/2004/07/Json_Dictionary_Test' non è previsto. Aggiungi qualsiasi tipo non noto staticamente all'elenco dei tipi noti, ad esempio utilizzando l'attributo KnownTypeAttribute o aggiungendoli all'elenco dei tipi noti passati a DataContractSerializer.
Ma non lo capisco! Come so, KnownTypeAttribute viene utilizzato solo per la deserializzazione e, se esiste un'eredità, non è vero? Ma qui è solo la serializzazione. E senza il membro datacontract funziona bene.
Qualche idea?
Ho capito qualcosa che funziona! C'è una classe genitore con una lista KnownTypes, che riempio con tutte le classi dei bambini e che sarà utilizzato in serializzazione:
[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* {
...
}
...
Bella soluzione! Questo mi farà risparmiare un sacco di tempo. Invece di trasformare tutte le classi serializzabili in una sottoclasse, controllo se hanno l'attributo DataContract che funziona meglio per me: if (! Type.IsAbstract && type.IsDefined (typeof (DataContractAttribute), true)) { knownTypes. Aggiungere (tipo); } – rob