2008-11-05 12 views
7

Estoy tratando de implementar un diccionario para utilizarlo con WCF. Mis requisitos son:Cómo implementar un diccionario heredado sobre WCF

  • real (variable privada o base clase) de tipo equivalente a Diccionario
  • Comparer = método System.StringComparer.InvariantCultureIgnoreCase
  • personalizada (anulación/nuevo) Añadir (clave, valor) (a incluir validaciones ).
  • ToString Ignorar()
  • uso del mismo tipo tanto en el cliente y el host

He intentado utilizar esta clase en un proyecto común compartido por el anfitrión y el cliente WCF proyectos:

[Serializable] 
public class MyDictionary : Dictionary<string, object> 
{ 
    public MyDictionary() 
    : base(System.StringComparer.InvariantCultureIgnoreCase) 
    { } 

    public new void Add(string key, object value) 
    { /* blah */ } 

    public override string ToString() 
    { /* blah */ } 
} 

[DataContract] 
[KnownType(typeof(MyDictionary))] 
[KnownType(typeof(object[]))] 
[KnownType(typeof(double[]))] 
[KnownType(typeof(string[]))] 
[KnownType(typeof(DateTime[]))] 
public class ResultClass 
{ 
    public object Value{ get; set; } 
    /* More properties */ 
} 
public class ParmData 
{ 
    public object Value{ get; set; } 
    /* More properties */ 
} 
[DataContract] 
[KnownType(typeof(MyDictionary))] 
[KnownType(typeof(object[]))] 
[KnownType(typeof(double[]))] 
[KnownType(typeof(string[]))] 
[KnownType(typeof(DateTime[]))] 
public class ParameterClass 
{ 
    public List<ParmData> Data{ get; set; } 
    /* More properties */ 
} 

[OperationContract] 
ResultClass DoSomething(ParameterClass args); 

resultados:

  • Cuando paso MyDictionary como uno de los elementos ParameterClass.Data.Value, I ge t una excepción de KnownType faltante.
  • Puedo devolver MyDictionary de forma segura en la clase ResultClass, pero ya no es mi tipo. Es solo un diccionario, y no puede convertirse en MyDictionary. También comparer = System.Collections.Generic.GenericEqualityComparer<string>, no es el comparador insensible a mayúsculas y minúsculas que estoy buscando.

La ayuda que estoy solicitando es corregir mi intento fallido o una forma completamente diferente de cumplir mis requisitos establecidos. Cualquier solución no debería implicar copiar un diccionario a otro.

Gracias

+0

¿Es NetDataContractAttribute una opción viable? Es decir, ¿puede tener copias del mismo ensamblaje con su clase MyDictionary garantizada disponible tanto para el cliente como para el servidor? – cfeduke

+0

Gracias por responder a mi publicación, pero usted no ha respondido: ¿el código que publiqué funciona con su configuración? ¿O arroja una excepción (o no devuelve los datos)? –

+0

Marc - Solo hice 1 intento con tu prueba. clone.Data lanzó una excepción de valor nulo. Gracias por la ayuda, pero Jezell me indicó la dirección correcta. – chilltemp

Respuesta

1
  • Utilice CollectionDataContract atributo como jezell sugirió
  • Genere manualmente el código de referencia (proxy) con SvcUtil, utilizando el parámetro/collectionType. Este parámetro no es compatible con la GUI de referencia del servicio vs2008.

Fuente: WCF Collection Type Sharing

+2

¿Por qué acepta su propia respuesta si la solución fue proporcionada por otro usuario? –

1

Preámbulo: tenga en cuenta que la adición de un "nuevo" Add no impide que la gente llamando a la edad Add simplemente mediante fundición. Además, en términos de "mex", es un contrato de datos muy vago: ¿necesita ser tan abierto? (un montón de object etc ...)

Primero: ¿no has echado de menos algunos marcadores [DataContract]/[DataMember] allí? En particular:

  • ResultClass.Value
  • ParamData
  • ParamData.Value
  • ParameterClass.Data

Puede aclarar exactamente qué versión de .NET que está utilizando? DataContractSerializer etc. han sido modificados a través de service packs. Con 3.5 SP1 instalado (lo único que tengo a mano) al menos se serializa y deserializa a través de DataContractSerializer (sin pila WCF), y se llama al método Add correcto.

¿Puedes verificar si lo siguiente funciona con tu versión local? (Funciona para mí con 3.5 SP1 y con los atributos que faltan) [primera salida]:

1 
MyDictionary 
abc=123 
def=ghi 

Código:

 // or long-hand in C# 2.0 
     ParameterClass pc = new ParameterClass { 
      Data = new List<ParmData> { new ParmData { 
       Value = new MyDictionary { 
        {"abc",123}, 
        {"def","ghi"} 
       }}}}; 
     DataContractSerializer dcs = new DataContractSerializer(pc.GetType()); 
     string xml; 
     using(StringWriter sw = new StringWriter()) 
     using(XmlWriter xw = XmlWriter.Create(sw)) { 
      dcs.WriteObject(xw, pc); 
      xw.Close(); 
      xml = sw.ToString(); 
     } 
     using(StringReader sr = new StringReader(xml)) { 
      ParameterClass clone = (ParameterClass)dcs.ReadObject(XmlReader.Create(sr)); 
      Console.WriteLine(clone.Data.Count); 
      Console.WriteLine(clone.Data[0].Value.GetType().Name); 
      MyDictionary d = (MyDictionary)clone.Data[0].Value; 
      foreach (KeyValuePair<string, object> pair in d) 
      { 
       Console.WriteLine("{0}={1}", pair.Key, pair.Value); 
      } 
     } 

Obviamente esto sólo pone a prueba DataContractSerializer (sin toda la pila WCF), pero parece que funciona ... Entonces, ¿funciona el mismo código con su versión local de .NET? De lo contrario, ¿es la instalación del último paquete de servicios 3.0 una opción? (idealmente mediante la instalación de 3.5 SP1).

Para información, consigo xml:

<?xml version="1.0" encoding="utf-16"?><ParameterClass xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/"><Data><ParmData><Value xmlns:d4p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays" i:type="d4p1:ArrayOfKeyValueOfstringanyType"><d4p1:KeyValueOfstringanyType><d4p1:Key>abc</d4p1:Key><d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:int">123</d4p1:Value></d4p1:KeyValueOfstringanyType><d4p1:KeyValueOfstringanyType><d4p1:Key>def</d4p1:Key><d4p1:Value xmlns:d6p1="http://www.w3.org/2001/XMLSchema" i:type="d6p1:string">ghi</d4p1:Value></d4p1:KeyValueOfstringanyType></Value></ParmData></Data></ParameterClass> 
+0

.Runtimes de .NET instalados: 1.0.3705.0 Versión 1.0 RTM; 1.1.4322.2407 Versión 1.1 Post-SP1 con KB928366; 2.0.50727.1433; 3.0.4506.648. Sí, el contrato debe ser abierto. Este es un contenedor para un sistema heredado. – chilltemp

+0

Pero, ¿funciona? –

+0

Hmmm ... que se parece a 3.0SP1 –

10

Añadir CollectionDataContract a la clase Dictionary:

Para obtener más información sobre el uso de contratos de datos recogida para poner en práctica los diccionarios, comprobar este enlace:

http://msdn.microsoft.com/en-us/library/aa347850.aspx

+0

Parece el enfoque correcto. El único problema es que termino con una nueva clase MyDictionary en un espacio de nombres secundario. Estoy investigando cómo convencerlo de usar el espacio de nombres correcto. (http://social.msdn.microsoft.com/forums/en-US/wcf/thread/8368d9c0-1048-43c5-85c1-bee1cdd25449/) – chilltemp

+0

El serializador admite colecciones basadas en diccionarios incluso sin el atributo; esto simplemente personaliza el esquema (nombres, etc.) –

1

que finalmente encontró una manera de hacer esto. Encontré this link que apuntó en la dirección correcta pero intentaré resumir.

  1. Asegúrese de que añade a su colección [CollectionDataContract] encargo
  2. Agregar referencia de servicio a través de VS como lo hace normalmente
  3. Expandir la referencia de servicio y buscar la Reference.svcmap presentar
  4. En el nodo de opciones de cliente verá

< CollectionMappings />

Reemplácela con el siguiente xml.

< CollectionMappings>
    < CollectionMapping TypeName = "Full.Namespace.Here" Categoría = "Lista" />
</CollectionMappings>

  1. Haga clic con el botón derecho en la Referencia del servicio y haga clic en actualizar. Ya no debería generar esa clase de "proxy" y le permitirá usar su clase compartida.
+0

La edición de un archivo generado automáticamente generalmente no es una buena idea. Es una forma fácil de sobrescribir accidentalmente sus cambios. – chilltemp

Cuestiones relacionadas