Deserializar JSON del servicio web ASP.net en un objeto C#

Después de pasar un día leyendo las publicaciones aquí, todavía no puedo hacer que esto funcione, así que espero que esto tenga sentido para alguien aquí.

El servicio web devuelve este JSON simple

{"d":{"__type":"TestWebServices.Person","Name":"Bob","FavoriteColor":"Green","ID":0}}

Entonces estoy usando código C# para deserializar

DataContractJsonSerializer jsonSerializer = new DataContractJsonSerializer(typeof(Person));
Person someone = (Person)jsonSerializer.ReadObject(responseStream);

Cuando uso este modelo, alguien se crea pero todas las propiedades son nulas.

[DataContract]
public class Person {
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string FavoriteColor { get; set; }
    [DataMember]
    public int ID { get; set; }
}

Traté de ser más literal y usé este modelo.

[DataContract]
public class Person {
    [DataMember]
    public PersonItem d { get; set; }
}
[DataContract]
public class PersonItem {
    [DataMember]
    public string __Type { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string FavoriteColor { get; set; }
    [DataMember]
    public int ID { get; set; }
}

Y obtuve este error, que ni siquiera sé por dónde empezar

El elemento ':d' contiene datos de un tipo que se asigna al nombre ':GEMiniWebServices.Person'. El deserializador no tiene conocimiento de ningún tipo que se asigne a este nombre. Considere usar un DataContractResolver o agregue el tipo correspondiente a 'TestWebServices.Person' a la lista de tipos conocidos, por ejemplo, usando el atributo KnownTypeAttribute o agregándolo a la lista de tipos conocidos pasados ​​a DataContractSerializer.

¿Alguna idea? Gracias

preguntado el 03 de mayo de 12 a las 16:05

Si agrega un Service Reference, el cliente generado deserializará la respuesta por usted. -

2 Respuestas

__El tipo nunca debe ser parte de su objeto. Es una pista para el serializador. Además, la sugerencia de tipo que tiene en su objeto JSON es mala. Serialización JSON independiente dice:

Para preservar la identidad del tipo, al serializar tipos complejos en JSON se puede agregar una "sugerencia de tipo" y el deserializador reconoce la sugerencia y actúa de manera adecuada. La "sugerencia de tipo" es un par clave/valor JSON con el nombre de clave "__tipo" (dos guiones bajos seguidos de la palabra "tipo"). El valor es una cadena JSON con el formato "DataContractName:DataContractNamespace" (cualquier cosa hasta los primeros dos puntos es el nombre).

La sugerencia de tipo es muy similar al atributo xsi:type definido por el estándar de instancia de esquema XML y utilizado al serializar/deserializar XML.

Los miembros de datos llamados "__type" están prohibidos debido a un posible conflicto con la sugerencia de tipo.

Funciona con lo siguiente si reescribe el __type declaración como Person:#TestWebServices o eliminarlo:

namespace TestWebServices
{
    [KnownType(typeof(Person))]
    [DataContract]
    public class PersonWrapper
    {
        [DataMember]
        public Person d { get; set; }
    }
    [DataContract]
    public class Person
    {
        [DataMember]
        public string Name { get; set; }
        [DataMember]
        public string FavoriteColor { get; set; }
        [DataMember]
        public int ID { get; set; }
    }
}

contestado el 04 de mayo de 12 a las 16:05

Gracias por la información JamieSee. También lo probé sin el "__tipo" y obtuve el mismo error. El servicio web está creando esa sugerencia de tipo, no estoy seguro de qué puedo hacer al respecto. - desnudar

Comentario agregado: si elimino la "d":{"__type":"GEMiniWebServices.Person" del JSON, tanto DataContractJsonSerializer como JavaScriptSerializer no tienen problemas para analizar los datos en el objeto PersonItem. Ese es el propósito de "d":{ "__type":"? Obviamente está haciendo que algo simple sea complicado. ¿Pensamientos? - desnudar

Este problema se describe aquí codeproject.com/Artículos/72443/… El artículo sugiere eliminar el json que está causando el problema. - desnudar

Funciona si reescribes el __type declaración a Person:#TestWebServices o eliminarlo. - JamieVer

aquí está una pregunta relacionado con el "propósito" de "d": {. - joe enzminger

Intente agregar (y estoy haciendo un poco de apuñalamiento aquí, por lo que el espacio de nombres exacto puede ser incorrecto)

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/TestWebServices.Person")]

a su DataContractAttribute en Person.

[DataContract(Namespace = "http://schemas.datacontract.org/2004/07/TestWebServices.Person")]
public class Person {
    [DataMember]
    public PersonItem d { get; set; }
}
[DataContract]
public class PersonItem {
    [DataMember]
    public string __Type { get; set; }
    [DataMember]
    public string Name { get; set; }
    [DataMember]
    public string FavoriteColor { get; set; }
    [DataMember]
    public int ID { get; set; }
}

contestado el 03 de mayo de 12 a las 16:05

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.