88

When i serialize the following:

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

I get this disgusting mess:

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

What gives? How can i make this pretty? JSON responses also contain the k_BackingField

Micah
  • 10,295
  • 13
  • 66
  • 95
  • This helped me : http://stackoverflow.com/questions/15388452/access-the-default-json-net-serializer-in-asp-net-web-api – granadaCoder Jan 26 '16 at 21:26

4 Answers4

129

By default you don't need to use neither [Serializable] nor [DataContract] to work with Web API.

Just leave your model as is, and Web API would serialize all the public properties for you.

Only if you want to have more control about what's included, you then decorate your class with [DataContract] and the properties to be included with [DataMember] (because both DCS and JSON.NET respsect these attributes).

If for some reason, you need the [Serializable] on your class (i.e. you are serializing it into a memory stream for some reason, doing deep copies etc), then you have to use both attributes in conjunction to prevent the backing field names:

[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; }
}
mkchandler
  • 4,688
  • 3
  • 23
  • 25
Filip W
  • 27,097
  • 6
  • 95
  • 82
97

There is a more general solution: you can configure the Json Serializer to ignore the [Serializable] attribute, so that you don't have to change the attributes in your classes.

You should make this configuration change in the application start, i.e. in Global.asax Application_Start event:

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

You can also make other changes to the Json serialization, like specifying formats for serializing dates, and many other things.

This will only apply to the Web API JSON serialization. The other serializations in the app (Web API XML serialization, MVC JsonResult...) won't be affected by this setting.

JotaBe
  • 38,030
  • 8
  • 98
  • 117
  • 4
    I like this solution a lot better than adding [DataContract] and [DataMember] attributes everywhere. Thank you!! – Mark Good Jun 19 '14 at 14:09
  • 1
    Not something you should be using all the time, but this is a neat trick. Kind of a crowbar that helps you get around messy situations where you don't have the luxury of changing the models or refactoring the codebase in depth. – uygar.raf Apr 09 '15 at 07:43
  • You're right that this isn't the best way to do it. However, on some occasions refactoring it's not only a luxury, but it's not feasible at all. For example, if the codebase uses WCF, or XML Serialization, it does require Data Contract or XML serialization attributes. You cannot change that. Fortunately JSON.NET is very powerful: it does support Data Contract, XML serialization and its own attributes, and you can control how it uses them for serialization, or even to fully ignore them. And you can even add your own implementation. Of course, I prefere to keep clean clasess without attributes. – JotaBe Apr 09 '15 at 16:39
  • This is how it should work by default! Why do we wever wabt backingfield nonsense in our serialzed stream? – Byron Whitlock Apr 21 '15 at 01:16
  • This solution does remove the k_BackingField nastiness. However since we have [Serializable] declared for the class, the receiver on the other end would expect k_BackingField. And because we deliberately remove the backing, JSON.NET would fail to map the JSON data to class properties. As the result, we would get null for the properties. – Tony Apr 21 '15 at 19:29
  • 1
    If you are using web api and are targeting version 4 of the .net framework then you will need to update the Netwonsoft.Json package in order for this to work, ie `Update-Package Newtonsoft.Json`. – pblack Feb 01 '16 at 09:53
  • I'd give this a hundred votes if I could. When I saw "backingField" my first instance was I'll need a billion [Attributes] on my POCO's. Thanks!! – granadaCoder Nov 15 '18 at 21:51
  • This solution worked, thanks heaps. This solution is better because I have no control over attributes of the classes (DataMember, DataContract). All entities (model classes) are inside the DLL lib. – Malhaar Punjabi Oct 14 '19 at 00:52
2

Try using DataContract instead of Serializable for marking your class. For more detail on why, look at this good blog post on serializing automatic properties.

Sixto Saez
  • 12,610
  • 5
  • 43
  • 51
0

The [DataContract] attributes dosn't worked for me, so it was not an option.

XmlSerializer ignores [XmlAttribute] in WebApi

The above resolution solved it for me.

GlobalConfiguration.Configuration.Formatters.XmlFormatter.UseXmlSerializer = true;
JanBorup
  • 5,337
  • 1
  • 29
  • 17