Home > Back-end >  Newtonsoft.Json serializing into static readonly class
Newtonsoft.Json serializing into static readonly class

Time:09-02

I have public class Result and object created from it:

public static readonly Result NotStarted = new Result(1, "", nameof(NotStarted));

This is realization of this pattern. In my case Result is based on TypesafeEnumBase:

public class TypesafeEnumBase : ITypesafeEnum
{
    [DefaultValue(typeof(string), "")]
    [JsonProperty("text", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
    public virtual string Description { get; protected set; }

    [DefaultValue(typeof(int), "1")]
    [JsonProperty("code", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
    public virtual int Id { get; protected set; }

    [DefaultValue(typeof(string), "")]
    [JsonProperty("name", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
    public virtual string Name { get; protected set; }
}

Now I'm receiving json object serialized from type containing Result property

[DataContract, Serializable]
public class IOResultBase : IIOResult
{
    [XmlIgnore]
    [JsonProperty("Result", NullValueHandling = NullValueHandling.Ignore, DefaultValueHandling = DefaultValueHandling.Ignore)]
    public virtual Result Result { get; set; }

    public IOResultBase()
    {
        this.Result = Result.NotStarted;
    }
}

You may notice that there is default value in constructor equals to Result.NotStarted static class.

I get json like this {"Result":{"text":"","code":0,"name":"Success"}} As you notice it has code of 0. And now IOResultBase foo = JsonConvert.DeserializeObject<IOResultBase>(json) is pushing this code 0 into foo.

But it turns out that 0 is being pushed in public static readonly Result NotStarted itself (even despite its readonly) instead of just creating new instance of foo.Result. So now 'code' of NotStarted (which is actually globally used constant) is changed from 1 to 0.

How should I force DeserializeObject to create new instance of public class Result instead of overriding public static readonly Result NotStarted?

CodePudding user response:

Pay utmost attention to the default (de)serialization settings of Newtonsoft.Json. Quite a few will not be what many would intuitvely expect them to be.

Such as, if there is an existing object instance in a property like the Result.NotStarted instance in the IOResultBase.Result property, Newtonsoft.Json will try to reuse the existing object instance provided by the property, meaning populating this existing instance with the values from the json.

Specifially, to solve your problem, you will have to set Newtonsoft.Json's setting ObjectCreationHandling to ObjectCreationHandling.Replace. So, perhaps something along the lines of:

var foo = JsonConvert.DeserializeObject<IOResultBase>(
    json,
    new JsonSerializerSettings() { ObjectCreationHandling = ObjectCreationHandling.Replace }
);
  • Related