2010-01-29 17 views
6

He estado tratando de usar un cliente SilverLight para llamar a un servicio ASP.NET WCF que devolvería un Dictionary<string, object>. Eso funcionó bien cuando los valores en el diccionario eran tipos simples como int, string o Guid.servicio WCF que devuelve una matriz del diccionario <cadena, objeto>

Sin embargo, ahora tengo un escenario donde necesito que uno de los valores sea una matriz de Dictionary<string, object>! Todo compila bien y la firma del servicio no ha cambiado, pero la llamada de servicio ahora falla.

¿Alguna idea de cómo solucionarlo? Intenté anotar mi clase de servicio y mis métodos con los atributos KnownType y ServiceKnownType pero eso no funcionó.

Aquí es una pieza de código:

[ServiceContract(Namespace = "")] 
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Allowed)] 
public class Service1 
{ 
    [OperationContract] 
    [ServiceKnownType(typeof(Dictionary<string, object>))] 
    public Dictionary<string, object> GetObject() 
    { 
     return new Dictionary<string, object>() 
      { 
       { "pty1", 1 }, 
       { "pty2", Guid.NewGuid() }, 
       { "pty3", "blah" }, 
       { "pty4", new Dictionary<string, object>[] 
           { 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blah" }, 
             } 
            , 
            new Dictionary<string, object>() 
             { 
              { "pty1", 4 }, 
              { "pty2", Guid.NewGuid() }, 
              { "pty3", "blahblah" }, 
             } 
           } 
      } 
     }; 
    } 
} 

Gracias por sus respuestas. He activado el seguimiento WCF y, como se sospecha, hay un problema durante la serialización. El problema no es la serialización de Dictionary<string, object> sino la de Array de Dictionary<string, object>.

Aquí la excepción registrada por el servicio WCF.

Se produjo un error al intentar serializar el parámetro: GetObjectResult. El mensaje InnerException fue 'Tipo' System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089], [System.Object, mscorlib, Version = 2.0. 0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089]] [] 'con el nombre del contrato de datos' ArrayOfArrayOfKeyValueOfstringanyType: http://schemas.microsoft.com/2003/10/Serialization/Arrays 'no se espera. Agregue cualquier tipo no conocido de forma estática a la lista de tipos conocidos, por ejemplo, utilizando el atributo KnownTypeAttribute o agregándolos a la lista de tipos conocidos pasados ​​a DataContractSerializer. '. Por favor, consulte InnerException para más detalles.

También he trato de definir una nueva clase DataContract con un solo miembro de datos pero llevo hasta el mismo error.

Aquí está el código para eso, seguido de la excepción registrada por el registro de WCF.

[DataContract] 
[KnownType(typeof(ObjectHolder))] 
public class ObjectHolder 
{ 
    [DataMember] 
    public object Object { get; private set; } 

    public ObjectHolder(object obj) 
    { 
     this.Object = obj; 
    } 
} 

Se ha producido un error al intentar serializar parámetro: GetObjectResult. El mensaje InnerException fue 'Tipo' System.Collections.Generic.Dictionary`2 [[System.String, mscorlib, Version = 2.0.0.0, Culture = neutral, PublicKeyToken = b77a5c561934e089], [SilverlightApplication7.Web.ObjectHolder, SilverlightApplication7.Web, Versión = 1.0.0.0, Cultura = neutral, PublicKeyToken = null]] [] 'con el nombre del contrato de datos' ArrayOfArrayOfKeyValueOfstringObjectHolderWAwxSTlb: http://schemas.microsoft.com/2003/10/Serialization/Arrays 'no se espera. Agregue cualquier tipo no conocido de forma estática a la lista de tipos conocidos, por ejemplo, utilizando el atributo KnownTypeAttribute o agregándolos a la lista de tipos conocidos pasados ​​a DataContractSerializer. '. Por favor, consulte InnerException para más detalles.

Una vez más he jugado con ServiceKnownType para ObjectHolder, ObjectHolder[] e incluso ObjectHolder[][] desde la excepción menciona un "ArrayOfArrayOfKeyValueOfstringObjectHolder".

Todavía no hay solución.

+0

¿Qué error recibes? –

+0

Supongo que WCF podría tener problemas para serializar objetos. Podrías tratar de hacer tus diccionarios si eso es factible. – sipwiz

+0

Estoy de acuerdo con sipwiz, usted tendrá problemas para serializar el dictionario. Debe hacer que el diccionario contenga un objeto que sea serializable (lo que significa que necesita cambiar su Dictionary por Dictionary srodriguez

Respuesta

0

Intente definir una clase que tenga una sola propiedad. Esa propiedad es un Diccionario de cuerda, objeto.

Marque la clase con DataContract/DataMember. Luego define tu interfaz usando esa clase.

8

En primer lugar debe configure WCF tracing en el archivo de la aplicación de archivo que puede ayudarle a comprender lo que ocurre bajo el capó de las comunicaciones de servicio. En este caso, puede obtener fácilmente todos los errores que se producen durante el proceso de comunicación.

Ahora, intentemos resolver su problema. Estoy casi seguro de ese problema en tipos conocidos. En el mundo orientado a los servicios, debe definir manualmente todos los tipos concretos que pueden participar en el contrato de servicio, porque DataContractSerializer no proporciona dicha información en objetos serializados.

En este caso, quiere decir, que usted debe hacer lo siguiente:

[ServiceKnownType(typeof(string))] 
[ServiceKnownType(typeof(Guid))] 
[ServiceKnownType(typeof(int))] // but I think DataContractSerializer can deal himself with primitives 
[ServiceKnownType(typeof(YourClass))] //UserDefined types you should add manually 
public Dictionary<string, object> GetObject() 

También me recomendó que no se utiliza objeto de contrato de servicio, ya que el error muy propensos. Considérese, que luego usted o uno de sus colegas modifica una línea de código:

new Dictionary<string, object>() 
{ 
{ "pty1", 4 }, 
{ "pty2", Guid.NewGuid() }, 
{ "pty3", new SomeClass() }, //OOPS!!! 
} 

En este caso, cuando el servicio intenta devolver este diccionario se encuentra con la falta de tiempo de ejecución debido a DataContractSerializer no espera SomeClass en este contrato.

Una forma de resolver este problema es crear tipo separado:

[DataContract] 
[KnownType(typeof(Guid))] 
[KnownType(typeof(SomeClass1))] 
[KnownType(typeof(SomeClass2))] 
public class MyType 
{ 
    private MyType(object obj) { 
    Object = obj; 
    } 

    public static MyType FromSomeClass1(SomeClass1 c1) { 
    return new MyType(c1); 
    } 

    public static MyType FromSomeClass2(SomeClass2 c2) { 
    return new MyType(c2); 
    } 

    public static MyType FromGuid(Guid guid) { 
    return new MyType(guid); 
    } 

    [DataMember] 
    public object Object { get; private set; } 
} 

En este caso, si desea añadir un poco de nuevo tipo, se debe añadir método de fábrica y KnownTypeAttribute (este enfoque más detallado, pero menos propenso a errores).

Sin embargo, si su cliente y servicio están escritos en WCF, puede sacrificar los principios orientados a servicios principales y usar NetDataContractSerializer en su lugar DataContractSerializer. NetDataContractSerializer está diseñado para complementar DataContractSerializer. Puede serializar un tipo usando NetDataContractSerializer y deserializar con DataContractSerializer. Pero NetDataContractSerializer incluye información de tipo CLR en el XML serializado, mientras que DataContractSerializer no lo hace. Por lo tanto, el NetDataContractSerializer se puede usar en serialización y deserialización con cualquier tipo de CLR sin ningún tipo de KnownTypes.

+0

Esta es la mejor respuesta, puede mejorarla señalando que no es el Diccionario que es el tipo desconocido, sino los tipos de objetos contenidos en el diccionario. Es por eso que se agrega [ServiceKnownType (typeof (Dictionary ))] no ayuda, mientras que agrega [ServiceKnownType (typeof (types_which_the_object_might_be)]. –

0

Sin embargo, ahora tengo un escenario donde necesito que uno de los valores sea una matriz de diccionario.

El problema es que WCF no sabe cómo SERIALIZER/deserializar un conjunto de objetos que no está marcado con DataMember atributo y/o no se añade a ServiceKnownType s.

Por ejemplo, si hay algún método de servicio, que lleva un objeto arbitrario como parámetro

public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

y que desea pasar, dicen una matriz de enteros Integer(), debe agregar explícitamente esta matriz de enteros escriba para dar servicio a los tipos conocidos.

<ServiceKnownType(GetType(Integer()))> 
public interface IService 
    function DoSomething(Parameter as Object) as integer 
end interface 

Entonces método de servicio puede ser llamado

dim Service as IService 
dim Argument as Integer() 
Service.DoSomething(Argument) 

Alguna idea de cómo solucionarlo?

Probar agregando <ServiceKnownType(GetType(Dictionary(Of String, Object)()))> atributo.

Cuestiones relacionadas