0

I have a MyParameters object that has a "auto reset" feature that will initialize some of its child object values to the default value. In this case it seems like all the values are getting over written from the Json object that user sends in except the Filters list. See below..

MyController.cs:

namespace xx.Controllers
{
    [Authorize("xx")]
    [Route("api/[controller]")]
    public class MyController : Controller
    {
        public async Task<ActionResult> Post([FromBody]MyParameters parameters)
        {    
            //at this point parameters.Filters include the following:
            //[1,2,3,4,5,6,7,1,3,4,5]
            ...
        }
    }

    public class MyParameters
    {
        public Options Options { get; set; } = new Options ();

        ....            
    }

    public class Options 
    {
        public Options () => Reset();
        public List<int> Filters { get; set; }
        ...

        public void Reset()
        {
            this.Filters = new List<int> { 1, 2, 3, 4, 5, 6, 7 };
            ...
        }
    }
}

the request that is coming in from the UI looks like the following:

{  
   "Options":{  
      "Filters":[  
         1,
         3,
         4,
         5
      ],
      ...
}

How can I force the Filters to be over written instead of appended to the default values on the object.

EDIT:

I combined the comments and the answer agnelsix put and got it working by adding

services.AddMvc()
        .AddJsonOptions(options => options.SerializerSettings.ObjectCreationHandling = Newtonsoft.Json.ObjectCreationHandling.Replace);

in the Startup.cs.

scorpion5211
  • 1,020
  • 2
  • 13
  • 33
  • Related or duplicate: [Json.Net PopulateObject Appending list rather than setting value](https://stackoverflow.com/q/20270266/3744182) and [How to apply ObjectCreationHandling.Replace to selected properties when deserializing JSON?](https://stackoverflow.com/q/33744236/3744182) and [Repeated serialization and deserialization creates duplicate items](https://stackoverflow.com/q/24835262/3744182) and [Clear collections before adding items when populating existing objects](https://stackoverflow.com/q/35482896/3744182). – dbc Apr 07 '18 at 18:29
  • What version of MVC are you using? Depending on the version, you will be using either [tag:javascriptserializer] or [tag:json.net] to deserialize JSON. See https://techblog.dorogin.com/json-serializers-in-asp-net-and-other-e12d3d62933f – dbc Apr 07 '18 at 18:34

2 Answers2

2

That is how JSON works with lists.

You can change this behaviour with ObjectCreationHandling options:

var settings = new JsonSerializerSettings
{
    ObjectCreationHandling = ObjectCreationHandling.Replace
};

var jsonString = "{\"Options\":{\"Filters\":[1,2,3,4,5]}}";
var deserialize = JsonConvert.DeserializeObject<MyParameters>(jsonString, settings);
angelsix
  • 392
  • 1
  • 7
  • But my object is already deserialized by the time it enters the Post function, where would I even set the serializer settings ? – scorpion5211 Apr 07 '18 at 15:59
  • You are relying on the MVC seralizer to do that. You have many options. Here are some https://stackoverflow.com/questions/44828302/asp-net-core-api-json-serializersettings-per-request?utm_medium=organic&utm_source=google_rich_qa&utm_campaign=google_rich_qa – angelsix Apr 07 '18 at 16:05
  • Hah! I knew there was a way to customize these globally!! I’ll try it out soon and update you. Thank you – scorpion5211 Apr 07 '18 at 16:07
0

In deserialization, the constructor is not called, only all the properties are initialized. So whatever you initialize in the constructor is going to be overwritten. If you still want to keep the constructor values intact then call the Reset() method after serialization is completed like using OnDeserializedAttribute

Anup Sharma
  • 2,053
  • 20
  • 30
  • *In deserialization, the constructor is not called* - this is only true with `BinaryFormatter`; data contract serialization when data contract attributes are applied; and under very rare circumstances by Json.NET as explained [here](https://stackoverflow.com/a/41871975/3744182). And in fact in this question the constructor is getting called which explains the bug the OP is seeing. – dbc Apr 07 '18 at 18:39