2009-06-02 18 views
5

Sto provando a serializzare un NameValueCollection su WCF. Continuo a ricevere eccezioni che mi dicono di aggiungere un tipo dopo l'altro. Dopo l'aggiunta di loro, ho finalmenteProblema di serializzazione WCF con NameValueCollection

Tipo 'System.Object []' non può essere aggiunto alla lista dei tipi conosciuti dal un altro tipo 'System.Collections.ArrayList' con lo stesso nome del contratto di dati 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfanyType' è già presente.

Il contratto ora assomiglia a questo:

[KnownType(typeof(NameValueCollection))] 
[KnownType(typeof(CaseInsensitiveHashCodeProvider))] 
[KnownType(typeof(CaseInsensitiveComparer))] 
[KnownType(typeof(string[]))] 
[KnownType(typeof(Object[]))] 
[KnownType(typeof(ArrayList))] 
[DataContract] 
public class MyClassDataBase 
{ 
    [DataMember] 
    public NameValueCollection DataCollection = new NameValueCollection(); 
} 

Io davvero non so cosa fare per essere in grado di serializzare la mia NameValueColletion.

Un'altra cosa strana è che il compilatore avverte che CaseInsensitiveHashCodeProvider è deprecato.

risposta

9

L'idea migliore sarebbe quella di smettere di usare i tipi deboli come NameValueCollection e ArrayList. Utilizzare invece Dictionary<string,string> e List<T>.

+0

NameValueCollection è debolmente digitato? – ironsam

+1

Ho usato il termine "tipo debole", non "debolmente digitato". Con questo intendo includere 'NameValueCollection' nell'insieme di tipi di raccolta presentati prima dei generici. –

+0

Quando uso i dizionari in WCF, non si esegue la de-serializzazione molto bene. O qualcosa è spento quando lo deserializzo. – micahhoover

1

NameValueCollection non implementa direttamente l'interfaccia ICollection. Invece, NameValueCollection estende NameObjectCollectionBase. Questo implementa l'interfaccia ICollection e il metodo Add (system.string) sovraccarico non è implementato nella classe NameValueCollection. Quando si utilizza XMLSerializer, XmlSerializer tenta di serializzare o deserializzare NameValueCollection come un ICollection generico. Pertanto, cerca l'aggiunta predefinita (System.String). In assenza del metodo Add (system.String), viene generata l'eccezione.

Utilizzare la classe SoapFormatter per la serializzazione anziché utilizzare la serializzazione XML. Per utilizzare la classe SoapFormatter, è necessario aggiungere un riferimento a System.Runtime.Serialization.Formatters.Soap.dll.

// Serializing NameValueCollection object by using SoapFormatter 
SoapFormatter sf = new SoapFormatter(); 
Stream strm1 = File.Open(@"C:\datasoap.xml", FileMode.OpenOrCreate,FileAccess.ReadWrite); 
sf.Serialize(strm1,namValColl); 
strm1.Close(); 

// Deserializing the XML file into NameValueCollection object 
// by using SoapFormatter 
SoapFormatter sf1 = new SoapFormatter(); 
Stream strm2 = File.Open(@"C:\datasoap.xml", FileMode.Open,FileAccess.Read); 
NameValueCollection namValColl1 = (NameValueCollection)sf1.Deserialize(strm2); 
strm2.Close(); 
+0

Grazie, ho risolto il problema utilizzando il dizionario , che è stato molto più facile da usare per me in questo caso. – kaze

+0

ew, no, non utilizzare SoapFormatter. Interoperabilità si romperà. – Cheeso

+1

@Kaze, quindi la soluzione che hai usato è in realtà ciò che Saunders ha proposto. Anche se hai contrassegnato questa risposta come "accettata", hai effettivamente utilizzato una risposta diversa. – Cheeso

3

Un altro approccio potrebbe essere l'utilizzo di una classe wrapper per adattare NameValueCollection alla serializzazione WCF. Ecco un semplice esempio che serializza ogni coppia nome-valore come una singola stringa delimitata da virgole. Si legge quindi che il valore di nuovo nel NameValueCollection su deserializzazione:

[CollectionDataContract] 
public class NameValueCollectionWrapper : IEnumerable 
{ 
    public NameValueCollectionWrapper() : this(new NameValueCollection()) { } 

    public NameValueCollectionWrapper(NameValueCollection nvc) 
    { 
     InnerCollection = nvc; 
    } 

    public NameValueCollection InnerCollection { get; private set; } 

    public void Add(object value) 
    { 
     var nvString = value as string; 
     if (nvString != null) 
     { 
      var nv = nvString.Split(','); 
      InnerCollection.Add(nv[0], nv[1]); 
     } 
    } 

    public IEnumerator GetEnumerator() 
    { 
     foreach (string key in InnerCollection) 
     { 
      yield return string.Format("{0},{1}", key, InnerCollection[key]); 
     } 
    } 
} 

Ciò consentirebbe di utilizzare il tipo come [DataMember] proprietà standard sui vostri DataContract s e si sarebbe anche utilizzare tecniche di serializzazione standard di WCF.

Problemi correlati