Serialización de .NET WebAPI k_BackingField Maldad

86

Cuando serializo lo siguiente:

[Serializable]
public class Error
{

    public string Status { get; set; }
    public string Message { get; set; }
    public string ErrorReferenceCode { get; set; }
    public List<FriendlyError> Errors { get; set; }
}

Me sale este desastre repugnante:

<ErrorRootOfstring xmlns:i="http://www.w3.org/2001/XMLSchema-instance"   xmlns="http://schemas.datacontract.org/2004/07/Printmee.Api">
<_x003C_Errors_x003E_k__BackingField>
An exception has occurred. Please contact printmee support
</_x003C_Errors_x003E_k__BackingField>
<_x003C_LookupCode_x003E_k__BackingField>988232ec-6bc9-48f3-8116-7ff7c71302dd</_x003C_LookupCode_x003E_k__BackingField>
</ErrorRootOfstring>

¿Lo que da? ¿Cómo puedo hacer esto bonito? Las respuestas JSON también contienen k_BackingField

Miqueas
fuente
Esto me ayudó: stackoverflow.com/questions/15388452/…
granadaCoder

Respuestas:

126

De forma predeterminada, no es necesario utilizar [Serializable]ni [DataContract]trabajar con Web API.

Simplemente deje su modelo como está y la API web serializará todas las propiedades públicas por usted.

Solo si desea tener más control sobre lo que se incluye, luego decorará su clase [DataContract]y las propiedades con las que se incluirá [DataMember](porque tanto DCS como JSON.NET respetan estos atributos).

Si por alguna razón, necesita el [Serializable]en su clase (es decir, lo está serializando en un flujo de memoria por alguna razón, haciendo copias profundas, etc.), entonces debe usar ambos atributos en conjunto para evitar los nombres de los campos de respaldo:

[Serializable]
[DataContract]
public class Error
{
    [DataMember]
    public string Status { get; set; }
    [DataMember]
    public string Message { get; set; }
    [DataMember]
    public string ErrorReferenceCode { get; set; }
    [DataMember]
    public List<FriendlyError> Errors { get; set; }
}
Filip W
fuente
6
Eso fue todo, solo necesitaba quitar el [Serializable]. Gracias.
Micah
Gracias Filip, tengo que conservar los atributos debido a la caché ... Por cierto, soy un ávido fan de tu blog ... ¡sigue viniendo!
Stephen Patten
20
Esto es simplemente terrible. ¿Por qué Microsoft NUNCA puede hacer nada correcto cuando se trata de serialización?
Chris Marisic
Hay una solución más general, como muestro en mi propia respuesta a continuación.
JotaBe
Quizás el problema con la serialización es la definición de "correcto", todos necesitan datos a su manera.
Luiz Felipe
94

Hay una solución más general: puede configurar el serializador Json para ignorar el [Serializable]atributo, de modo que no tenga que cambiar los atributos en sus clases.

Debe realizar este cambio de configuración en el inicio de la aplicación, es decir, en el Application_Startevento Global.asax :

var serializerSettings =
  GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings;
var contractResolver =
  (DefaultContractResolver)serializerSettings.ContractResolver;
contractResolver.IgnoreSerializableAttribute = true;

También puede realizar otros cambios en la serialización de Json, como especificar formatos para serializar fechas y muchas otras cosas.

Esto solo se aplicará a la serialización JSON de la API web. Las otras serializaciones en la aplicación (serialización XML de API web, MVC JsonResult ...) no se verán afectadas por esta configuración.

JotaBe
fuente
4
Me gusta mucho más esta solución que agregar atributos [DataContract] y [DataMember] en todas partes. ¡¡Gracias!!
Mark Good
1
No es algo que debas usar todo el tiempo, pero es un buen truco. Una especie de palanca que te ayuda a sortear situaciones complicadas en las que no tienes el lujo de cambiar los modelos o refactorizar el código base en profundidad.
uygar.raf
Tienes razón en que esta no es la mejor manera de hacerlo. Sin embargo, en algunas ocasiones la refactorización no solo es un lujo, sino que no es factible en absoluto. Por ejemplo, si el código base usa WCF o serialización XML, requiere atributos de serialización XML o contrato de datos. No puedes cambiar eso. Afortunadamente, JSON.NET es muy poderoso: admite contratos de datos, serialización XML y sus propios atributos, y puede controlar cómo los usa para la serialización, o incluso ignorarlos por completo. E incluso puede agregar su propia implementación. Por supuesto, prefiero mantener las clases limpias y sin atributos.
JotaBe
¡Así es como debería funcionar por defecto! ¿Por qué siempre hacemos tonterías de backingfield en nuestro flujo serializado?
Byron Whitlock
1
Si está utilizando una API web y tiene como objetivo la versión 4 del marco .net, deberá actualizar el paquete Netwonsoft.Json para que esto funcione, es decir Update-Package Newtonsoft.Json.
pblack
0

Los atributos de [DataContract] no funcionaron para mí, por lo que no era una opción.

XmlSerializer ignora [XmlAttribute] en WebApi

La resolución anterior me lo resolvió.

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
JanBorup
fuente