46

Estoy refacturando mi serialización XML, y pensé que probaría el DataContractSerializer. todo funciona sin problemas, hasta que se necesita para serializar esta clase:"Escriba no esperado", usando DataContractSerializer, pero es solo una clase simple, ¿no hay cosas divertidas?

using System; 
using System.Runtime.Serialization; 

namespace VDB_Sync.Model 
{ 
[DataContract(Name="Konstant")] 
public class Konstant : DataFelt 
{ 
    [DataMember] 
    private MySqlDbType mydataType; 
    [DataMember] 
    private object value; 

    public Konstant(string navn, MySqlDbType dataType, object value) 
     : base(navn, dataType, "*Konstant", false, false) 
    { 
     //this.navn = navn; 
     this.mydataType = dataType; 
     this.value = value; 

     if (navn.Contains("*Løbenummer")) 
     { 
      navn = "*Konstant: " + Convert.ToString(value); 
     } 
    } 

    public object Value 
    { 
     get 
     { 
      return value; 
     } 
    } 

} 
} 

Es me dan esto:

Tipo 'VDB_Sync.Model.Konstant' con el nombre de contrato de datos 'Konstant: http://schemas.datacontract.org/2004/07/VDB_Sync.Model 'no se espera. Considere el uso de un DataContractResolver o 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.

* La ayuda que he encontrado hasta ahora apunta a colecciones y tipos. Tengo una enumeración (MySqlDbType) en mi clase, pero entérate: incluso recibo el mismo error cuando no tengo ningún DataMembers declarado: -x Entonces, ¿qué está pasando aquí? ¿Qué me estoy perdiendo?

de remisión, así es como me serializado que, VDB_SessionController siendo la raíz: *

public void GemKonfig(VDB_SessionController session) 
    { 
     var settings = new XmlWriterSettings() 
     { 
      Indent = true, 
      IndentChars = "\t" 
     }; 

     var writer = XmlWriter.Create(defaultFile, settings); 
     DataContractSerializer ser = 
      new DataContractSerializer(typeof(VDB_SessionController)); 

     ser.WriteObject(writer, session); 
     writer.Close(); 
    } 

Respuesta

50

La excepción que se está informando es para VDB_Sync.Model.Konstant. Esto significa que en algún lugar más arriba de la cadena, esta clase está siendo arrastrada a otra clase y esa clase es la que está siendo serializada.

El problema es que, dependiendo de cómo esté integrado Konstant en esta clase (por ejemplo, si está en una colección o en una lista genérica), el DataContractSerializer puede no estar preparado para su aparición durante la deserialización.

Para resolver esto, debe aplicar el atributo de tipo conocido a la clase que contiene Konstant. De acuerdo con su código de serialización, sospecho que esto es VDB_SessionController.

lo tanto, tratar de decorar esta clase con el atributo KnownType:

[KnownType(typeof(VDB_Sync.Model.Konstant)] 
public class VDB_SessionController 
+0

Impresionante - ¡funciona! Parece que necesito hacer esto con muchas clases, ¡gracias! – Julian

+2

¿Cómo podría agregar esta decoración si la clase fue generada por el marco de la entidad? –

+0

¡Genial! ¡Ahora también entiendo el propósito de la decoración de "KnownType"! ¡Gracias! – Homer1982

0

cambiar esta situación:

[DataContract(Name="Konstant")] 
public class Konstant : DataFelt 

a esto:

[DataContract(Name="Konstant")] 
[KnownTypes(typeof(somenamespace.DataFelt))] 
public class Konstant : DataFelt 
+0

cerca, pero no dice:/ – Julian

+0

El KnownTypeAttribute tiene que ir en la clase base. – Bryan

+0

¿Qué sucede si no tiene acceso al tipo de base? – Choco

8

También se pueden combinar [KnownType] y reflexión para que el código sea más resistente a los cambios futuros.

[DataContract] 
[KnownType("GetKnownPersonTypes")] 
internal class Person 
{ 
    private static IEnumerable<Type> _personTypes; 

    private static IEnumerable<Type> GetKnownTypes() 
    { 
     if (_personTypes == null) 
      _personTypes = Assembly.GetExecutingAssembly() 
            .GetTypes() 
            .Where(t => typeof (Person).IsAssignableFrom(t)) 
            .ToList(); 
     return _personTypes; 
    } 
} 

Ahora un DataContractSerializer/DataContractJsonSerializer/XmlSerializer configurado para trabajar con Person, también funcionará con cualquier tipo derivado de Person (siempre que se declaró en el mismo conjunto).

15

Agregue esto a WebApiConfig.cs

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

var json = config.Formatters.JsonFormatter; 

json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects; 
config.Formatters.Remove(config.Formatters.XmlFormatter); 

Referencia: http://www.datazx.cn/Forums/en-US/a5adf07b-e622-4a12-872d-40c753417645/action?threadDisplayName=web-api-error-the-objectcontent1-type-failed-to-serialize-the-response-body-for-content&forum=wcf

+8

Todo lo que hace es deshabilitar la serialización de XML, es por eso que esta excepción desaparece. Sin embargo, si necesita serialización XML, esta respuesta no ayudará. Además, solo necesita la última línea: 'config.Formatters.Remove (config.Formatters.XmlFormatter);' Todo lo que está sobre esa línea es irrelevante. – niaher

2

Es como lo sugirió @Leon pero con el arreglo de @Bryan, el 'KnownTypeAttribute' debe estar en la clase base, por lo que debe ser como este:

[DataContract(Name="DataFelt")] 
[KnownType(typeof(somenamespace.Konstant))] 
public class DataFelt 

y en el Subclase:

[DataContract(Name="Konstant")] 
public class Konstant : DataFelt 
3

el problema para mí es que yo era r generando la interfaz (IIindividual) desde mi controlador WebAPI. Cuando cambié ese tipo de devolución al tipo Clase (Individual), este error desapareció.

No trabaja:

[HttpGet] 
    [Route("api/v1/Individual/Get/{id}")] 
    public IIndividual Get([FromUri]int id) 
    { 
     return _individualService.Get(id); 
    } 

de Trabajo:

[HttpGet] 
    [Route("api/v1/Individual/Get/{id}")] 
    public Individual Get([FromUri]int id) 
    { 
     IIndividual individual = _individualService.Get(id); 
     return individual as Individual; 
    } 
Cuestiones relacionadas