Serialization stuff

Topics: ASP.NET Web API
May 8, 2013 at 10:33 AM
I'm bumping into a few odd things with serialization. Maybe I'm just missing something.

1. Default values are serialized.
Setting the following SerializerSettings still causes default and null values to be included in serialized results. I also attempted using the DataContract/DataMember attributes with EmitDefaultValue=false and using the JsonProperty attribute directly on properties (using the same values as in the SerializerSettings).
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
            {
                NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
                DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.IgnoreAndPopulate
            };
I'd like to know why it isn't working as (I) expected.

2. Public properties with { get; private set; } in the entity framework don't get serialized.
When setting the setter of a property to private, the whole field is no longer serialized. I need it to still be serialized so you can read the data.
Jun 13, 2013 at 12:44 PM
Still have these problems. Any suggestions are welcome.
Coordinator
Jun 13, 2013 at 4:25 PM
Both of these scenarios should work with Json.NET so we would have to see your code to understand what is going on.

Daniel Roth
Jun 18, 2013 at 8:48 AM
1. Each code block represents an object setup attempt to get it to work. None did.
Both properties should not serialize with a value of 'null'.
Using DataContract.
[DataContract]
public class TestObject
{
    [DataMember(EmitDefaultValue = false)]
    public int? IntValue { get; set; }

    [DataMember(EmitDefaultValue = false)]
    public string StringValue { get; set; }
}
Using JsonObject.
[JsonObject]
public class TestObject
{
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)]
    public int? IntValue { get; set; }

    [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate)]
    public string StringValue { get; set; }
}
[JsonObject]
public class TestObject
{
    [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore)]
    public int? IntValue { get; set; }

    [JsonProperty(DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate, NullValueHandling = NullValueHandling.Ignore)]
    public string StringValue { get; set; }
}
Setting Json SerializerSettings globally.
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings = new Newtonsoft.Json.JsonSerializerSettings()
    {
        NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
        DefaultValueHandling = Newtonsoft.Json.DefaultValueHandling.IgnoreAndPopulate
    };
Using no attributes at all
public class TestObject
{
    public int? IntValue { get; set; }
    public string StringValue { get; set; }
}
Response in all cases:
{
    /*Other properties*/,
    "IntValue": null,
    "StringValue": null
}
2. Private set, public get properties
EDMX code result
public int PublicValue { get; set; }
Results in the following after serialization
{
    /*Other properties*/,
    PublicValue: 500
}
Now setting the setter to private in the Model Browser / EDMX viewer creates the following code output.
public int PublicValue { get; private set; }
Which results in the following after serialization
{
    /*Other properties*/,
    //< It should be here but isn't.
}
Jun 24, 2013 at 7:31 AM
Hi Omar,

This is the issue happening to me after I upgraded to Json.NET 4.5 or later, It was working fine earlier.

I used RickStrahl JsonNetFormatter & that one works fine.

using System.IO;
using System.Net;
using System.Net.Http;
using System.Net.Http.Formatting;

using Framework.Converters.Json;

using Newtonsoft.Json;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Linq;

public class JsonNetFormatter : MediaTypeFormatter
{
    private static readonly JsonSerializerSettings Settings = CreateSerializerSettings();

    private static JsonSerializerSettings CreateSerializerSettings()
    {
        var settings = new JsonSerializerSettings()
            {
                ReferenceLoopHandling = ReferenceLoopHandling.Ignore,
                NullValueHandling = NullValueHandling.Ignore,
            };

            settings.Converters.Add(new GuidConverter());

        return settings;
    }

    public JsonNetFormatter()
    {
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("application/json"));
        SupportedMediaTypes.Add(new System.Net.Http.Headers.MediaTypeHeaderValue("text/json"));
    }

    public override bool CanWriteType(Type type)
    {
        // don't serialize JsonValue structure use default for that
        if (type == typeof(JValue) || type == typeof(JObject) || type == typeof(JArray))
            return false;

        return true;
    }

    public override bool CanReadType(Type type)
    {
        return true;
    }

    public override System.Threading.Tasks.Task<object> ReadFromStreamAsync(Type type,
                                                        Stream stream,
                                                        HttpContent content,
                                                        IFormatterLogger formatterLogger)
    {
        var task = Task<object>.Factory.StartNew(() =>
        {
            var sr = new StreamReader(stream);
            var jreader = new JsonTextReader(sr);

            var ser = new JsonSerializer();
            ser.Converters.Add(new IsoDateTimeConverter());

            object val = ser.Deserialize(jreader, type);
            return val;
        });

        return task;
    }

    public override Task WriteToStreamAsync(Type type, object value,
                                            Stream stream,
                                            HttpContent content,
                                            TransportContext transportContext)
    {
        var task = Task.Factory.StartNew(() =>
        {
            string json = JsonConvert.SerializeObject(value, Settings);

            byte[] buf = System.Text.Encoding.Default.GetBytes(json);
            stream.Write(buf, 0, buf.Length);
            stream.Flush();
        });

        return task;
    }
}
Just insert the above formatter to Global Formatters Collection.

GlobalConfiguration.Configuration.Formatters.Insert(0, new JsonNetFormatter());

Serialization will work properly after that.
Coordinator
Jun 29, 2013 at 4:07 AM
I just tried returning all of these types from a Web API built with ASP.NET Web API 2 and Json.NET 4.5.11 they all returned empty JSON objects for me.

Daniel Roth
Jul 3, 2013 at 11:50 PM
Hmm in that case I'll have to try and see if using the 4.5 version may solve this. I'll post an update again once I've done so.