Serialização do .NET WebAPI k_BackingField Nastiness

86

Quando eu serializo o seguinte:

[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; }
}

Eu fico com essa bagunça nojenta:

<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>

O que da? Como posso deixar isso bonito? As respostas JSON também contêm o k_BackingField

Micah
fonte
Isso me ajudou: stackoverflow.com/questions/15388452/…
granadaCoder

Respostas:

126

Por padrão, você não precisa usar [Serializable]nem [DataContract]trabalhar com Web API.

Basta deixar seu modelo como está, e a API da Web serializará todas as propriedades públicas para você.

Apenas se quiser ter mais controle sobre o que está incluído, você então decora sua classe com [DataContract]e as propriedades a serem incluídas [DataMember](porque DCS e JSON.NET refletem esses atributos).

Se, por algum motivo, você precisar do [Serializable]em sua classe (ou seja, você está serializando-o em um fluxo de memória por algum motivo, fazendo cópias profundas etc.), você deve usar os dois atributos em conjunto para evitar os nomes dos campos de apoio:

[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
fonte
6
Era isso - eu só precisava remover o [Serializável]. Obrigado.
Micah
Obrigado Filip, tenho que manter os atributos por causa do cache .. BTW, sou um ávido fã do seu blog .. continue assim!
Stephen Patten
20
Isso é simplesmente terrível. Por que a Microsoft NUNCA pode fazer nada correto quando se trata de serialização?
Chris Marisic de
Existe uma solução mais geral, como mostro na minha própria resposta abaixo.
JotaBe
Talvez o problema com a serialização seja a definição de "correto", todos precisam de dados em seu caminho.
Luiz Felipe
94

Existe uma solução mais geral: você pode configurar o Json Serializer para ignorar o [Serializable]atributo, de forma que você não precise alterar os atributos em suas classes.

Você deve fazer essa alteração de configuração no início do aplicativo, ou seja, no Application_Startevento Global.asax :

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

Você também pode fazer outras alterações na serialização Json, como especificar formatos para serializar datas e muitas outras coisas.

Isso se aplica apenas à serialização JSON da API da Web. As outras serializações no aplicativo (serialização XML da API da Web, MVC JsonResult ...) não serão afetadas por esta configuração.

JotaBe
fonte
4
Gosto muito mais dessa solução do que adicionar atributos [DataContract] e [DataMember] em todos os lugares. Obrigado!!
Mark Good
1
Não é algo que você deveria usar o tempo todo, mas é um truque interessante. Uma espécie de alavanca que o ajuda a contornar situações complicadas nas quais você não tem o luxo de alterar os modelos ou refatorar a base de código em profundidade.
uygar.raf
Você está certo de que esta não é a melhor maneira de fazer isso. No entanto, em algumas ocasiões, refatorar não é apenas um luxo, mas também não é viável. Por exemplo, se a base de código usa WCF ou XML Serialization, ela exige um contrato de dados ou atributos de serialização XML. Você não pode mudar isso. Felizmente, o JSON.NET é muito poderoso: ele suporta contrato de dados, serialização XML e seus próprios atributos, e você pode controlar como ele os usa para serialização ou até mesmo ignorá-los totalmente. E você pode até adicionar sua própria implementação. Claro, prefiro manter uma classe limpa, sem atributos.
JotaBe
É assim que deve funcionar por padrão! Por que sempre usamos um absurdo de backingfield em nosso stream serializado?
Byron Whitlock,
1
Se você estiver usando api web e são dirigidas a versão 4 do .NET Framework, então você vai precisar atualizar o pacote Netwonsoft.Json para que isso funcione, ou seja Update-Package Newtonsoft.Json.
pblack 01 de
0

Os atributos [DataContract] não funcionavam para mim, então não era uma opção.

XmlSerializer ignora [XmlAttribute] em WebApi

A resolução acima resolveu para mim.

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