2009-06-02 26 views
5

Estoy tratando de serializar una NameValueCollection sobre WCF. Sigo recibiendo excepciones diciéndome que agregue un tipo después de otro. Después de la adición de ellos, por fin consigo 'System.Object []' no se puede añadir a la lista de tipos conocidos desde otro tipo 'System.Collections.ArrayList' con el mismo nombre de contrato de datos 'http://schemas.microsoft.com/2003/10/Serialization/Arrays:ArrayOfanyType'Problema de serialización de WCF con NameValueCollection

tipo es ya presente.

El contrato ahora se ve así:

[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(); 
} 

Realmente no sé qué hacer para ser capaz de serializar mi NameValueColletion.

Otra cosa extraña es que el compilador advierte que el CaseInsensitiveHashCodeProvider está en desuso.

Respuesta

9

La mejor idea sería dejar de usar tipos débiles como NameValueCollection y ArrayList. Use Dictionary<string,string> y List<T> en su lugar.

+0

NameValueCollection está débilmente tipado? – ironsam

+1

Utilicé el término "tipo débil", no "tipeado débilmente". Con esto, me refiero a incluir 'NameValueCollection' en el conjunto de tipos de colección presentados antes de los genéricos. –

+0

Cuando uso Dictionaries en WCF no se deserializan muy bien. O algo está apagado cuando lo deserializo. – micahhoover

1

NameValueCollection no implementa directamente la interfaz ICollection. En cambio, NameValueCollection extiende NameObjectCollectionBase. Esto implementa la interfaz ICollection y el método Add (system.string) sobrecargado no se implementa en la clase NameValueCollection. Cuando utiliza XMLSerializer, XmlSerializer intenta serializar o deserializar NameValueCollection como una ICollection genérica. Por lo tanto, busca el valor predeterminado Agregar (System.String). En ausencia del método Add (system.String), se lanza la excepción.

Utilice la clase SoapFormatter para la serialización en lugar de utilizar la serialización XML. Para usar la clase SoapFormatter, debe agregar una referencia 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

Gracias, he resuelto el problema utilizando el Diccionario en su lugar, que era mucho más fácil de usar para mí en este caso. – kaze

+0

ew, no, no use SoapFormatter. La interoperabilidad se romperá. – Cheeso

+1

@Kaze, entonces la solución que usaste es en realidad lo que Saunders propuso. Aunque marcó esta respuesta como "aceptada", en realidad usó una respuesta diferente. – Cheeso

3

Otro enfoque podría ser utilizar una clase contenedora para adaptar NameValueCollection a la serialización WCF. Aquí hay un ejemplo simple que serializa cada par nombre-valor como una cadena única delimitada por comas. A continuación, lee ese valor nuevo en el NameValueCollection sobre deserialización:

[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]); 
     } 
    } 
} 

Esto le permitiría utilizar el tipo como un estándar [DataMember] propiedad de sus DataContract s y también se utilizarían técnicas de serialización estándar WCF.

Cuestiones relacionadas