How to deserialize a read only List with Json.Net










3















I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.



I expose



AddItem(Item x) 


and a



IEnumerable<Item> Items

get // returns a projection of internal list



Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.



How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?










share|improve this question
























  • did you tried var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?

    – Kiquenet
    Feb 5 '15 at 8:11











  • @Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.

    – Neil N
    Feb 5 '15 at 16:58











  • @NeilN What worked for you?

    – Prakhar
    May 10 '16 at 9:34















3















I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.



I expose



AddItem(Item x) 


and a



IEnumerable<Item> Items

get // returns a projection of internal list



Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.



How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?










share|improve this question
























  • did you tried var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?

    – Kiquenet
    Feb 5 '15 at 8:11











  • @Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.

    – Neil N
    Feb 5 '15 at 16:58











  • @NeilN What worked for you?

    – Prakhar
    May 10 '16 at 9:34













3












3








3








I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.



I expose



AddItem(Item x) 


and a



IEnumerable<Item> Items

get // returns a projection of internal list



Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.



How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?










share|improve this question
















I have a class with an internal list. I don't want the user of this class to be able to interact with the list directly, since I want to both keep it sorted and to run a calculation (which depends on the order) before returning it.



I expose



AddItem(Item x) 


and a



IEnumerable<Item> Items

get // returns a projection of internal list



Serialization worked OK, but deserializing left the list empty. I figured it was because I didn't have a setter. So I added one that allowed you to set the list, but only if the internal list was empty. But this didn't solve the problem, turns out NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it, which, since my getter returns a projected list, those items get added to an object that is immediately disposed once deserialization is done.



How do I maintain a read-only access to my list, while at the same time allowing for somewhat straightforward deserialization?







c# serialization json.net deserialization






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Mar 22 '17 at 19:07







Neil N

















asked Dec 9 '14 at 19:20









Neil NNeil N

19.4k1474128




19.4k1474128












  • did you tried var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?

    – Kiquenet
    Feb 5 '15 at 8:11











  • @Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.

    – Neil N
    Feb 5 '15 at 16:58











  • @NeilN What worked for you?

    – Prakhar
    May 10 '16 at 9:34

















  • did you tried var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?

    – Kiquenet
    Feb 5 '15 at 8:11











  • @Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.

    – Neil N
    Feb 5 '15 at 16:58











  • @NeilN What worked for you?

    – Prakhar
    May 10 '16 at 9:34
















did you tried var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?

– Kiquenet
Feb 5 '15 at 8:11





did you tried var list = new object .... ; var ser = JsonConvert.SerializeObject(list, Formatting.Indented); ?

– Kiquenet
Feb 5 '15 at 8:11













@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.

– Neil N
Feb 5 '15 at 16:58





@Kiquenet: I'm not deserializing a list directly, I am deserializing an object that has a list as a read only property.

– Neil N
Feb 5 '15 at 16:58













@NeilN What worked for you?

– Prakhar
May 10 '16 at 9:34





@NeilN What worked for you?

– Prakhar
May 10 '16 at 9:34












5 Answers
5






active

oldest

votes


















2














What worked for me was the following:



[JsonProperty(PropertyName = "TargetName")]
private List<SomeClass> _SomeClassList get; set;
public IReadOnlyList<SomeClass> SomeClassList

get

return this._SomeClassList.AsReadOnly();




Then, make a function to prevent SomeClassList to be serialized:



public bool ShouldSerializeSomeClassList() return false; 





share|improve this answer


















  • 1





    I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

    – bazsibazsi
    Nov 14 '18 at 10:40



















1














It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:



void Main()

Poco p = new Poco();
p.Items.Add("foo");
p.Items.Add("bar");

p.Dump(); // Linqpad command to show a visual objet dump in the output pane

String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );

serialized.Dump();
// serialized == ""Items":["foo","bar"]"

Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );

p2.Dump();


class Poco

public List<String> Items get; = new List<String>();



When I run this, the dumps of p and p2 are identical.






share|improve this answer


















  • 3





    Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

    – Jamey
    Oct 24 '17 at 9:24


















1














With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.



The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.



Any custom logic can be implemented inside AddItem.



The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings



public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>

public override bool CanConvert(Type objectType)

return typeof(ItemsHolder).IsAssignableFrom(objectType);


public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)


JObject jObject = JObject.Load(reader);

ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;

var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
foreach (var jItem in jItems)

var childReader = CreateReaderFromToken(reader, jItem);
var item = serializer.Deserialize<Item>(childReader);
holder.AddItem(item);


return holder;


public override ItemsHolder Create(Type objectType)

return new ItemsHolder();


public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)

JsonReader jObjectReader = token.CreateReader();
jObjectReader.Culture = reader.Culture;
jObjectReader.DateFormatString = reader.DateFormatString;
jObjectReader.DateParseHandling = reader.DateParseHandling;
jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
jObjectReader.FloatParseHandling = reader.FloatParseHandling;
jObjectReader.MaxDepth = reader.MaxDepth;
jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
return jObjectReader;







share|improve this answer






























    1














    Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.



    One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.



    Here's my class that I'd like to Serialize/Deserialize



    public class CannotDeserializeThis

    private readonly IList<User> _users = new List<User>();
    public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();

    public void AddUser(User user)

    _users.Add(user);




    I could serialize this to:
    "Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]



    But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:



    public class ReadonlyJsonDefaultContractResolver : DefaultContractResolver

    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

    var prop = base.CreateProperty(member, memberSerialization);
    if (!prop.Writable)

    var property = member as PropertyInfo;
    if (property != null)

    var hasPrivateSetter = property.GetSetMethod(true) != null;
    prop.Writable = hasPrivateSetter;

    if (!prop.Writable)

    var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));

    if (privateField != null)

    var originalPropertyName = prop.PropertyName;
    prop = base.CreateProperty(privateField, memberSerialization);
    prop.Writable = true;
    prop.PropertyName = originalPropertyName;
    prop.UnderlyingName = originalPropertyName;
    prop.Readable = true;





    return prop;




    The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.



    This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')






    share|improve this answer
































      0














      I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:



      public class State

      [Newtonsoft.Json.JsonProperty]
      public double Citizens get; private set;

      [Newtonsoft.Json.JsonProperty]
      public float Value get return pValue;
      private float pValue = 450000.0f;

      public List<string> BeachList get; = new List<string>();

      public State()



      public State(double _Citizens)

      this.Citizens = _Citizens;



      ...

      State croatia = new State(30.0D);
      croatia.BeachList.Add("Bol na Braču");
      croatia.BeachList.Add("Zrće");

      string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);

      State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);


      So, croatia and, slovenia now both have the same property values.
      I added Citizens and, Value properties to see if you want to work with one or the other way.



      Thanks to Saeb Amini (Private setters in Json.Net)






      share|improve this answer























      • My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

        – Neil N
        Jul 5 '17 at 14:00











      • You're right about that. I will get to bottom of this. I will get back here @NeilN.

        – MaGnumX
        Jul 5 '17 at 18:38










      Your Answer






      StackExchange.ifUsing("editor", function ()
      StackExchange.using("externalEditor", function ()
      StackExchange.using("snippets", function ()
      StackExchange.snippets.init();
      );
      );
      , "code-snippets");

      StackExchange.ready(function()
      var channelOptions =
      tags: "".split(" "),
      id: "1"
      ;
      initTagRenderer("".split(" "), "".split(" "), channelOptions);

      StackExchange.using("externalEditor", function()
      // Have to fire editor after snippets, if snippets enabled
      if (StackExchange.settings.snippets.snippetsEnabled)
      StackExchange.using("snippets", function()
      createEditor();
      );

      else
      createEditor();

      );

      function createEditor()
      StackExchange.prepareEditor(
      heartbeatType: 'answer',
      autoActivateHeartbeat: false,
      convertImagesToLinks: true,
      noModals: true,
      showLowRepImageUploadWarning: true,
      reputationToPostImages: 10,
      bindNavPrevention: true,
      postfix: "",
      imageUploader:
      brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
      contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
      allowUrls: true
      ,
      onDemand: true,
      discardSelector: ".discard-answer"
      ,immediatelyShowMarkdownHelp:true
      );



      );













      draft saved

      draft discarded


















      StackExchange.ready(
      function ()
      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f27387085%2fhow-to-deserialize-a-read-only-list-with-json-net%23new-answer', 'question_page');

      );

      Post as a guest















      Required, but never shown

























      5 Answers
      5






      active

      oldest

      votes








      5 Answers
      5






      active

      oldest

      votes









      active

      oldest

      votes






      active

      oldest

      votes









      2














      What worked for me was the following:



      [JsonProperty(PropertyName = "TargetName")]
      private List<SomeClass> _SomeClassList get; set;
      public IReadOnlyList<SomeClass> SomeClassList

      get

      return this._SomeClassList.AsReadOnly();




      Then, make a function to prevent SomeClassList to be serialized:



      public bool ShouldSerializeSomeClassList() return false; 





      share|improve this answer


















      • 1





        I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

        – bazsibazsi
        Nov 14 '18 at 10:40
















      2














      What worked for me was the following:



      [JsonProperty(PropertyName = "TargetName")]
      private List<SomeClass> _SomeClassList get; set;
      public IReadOnlyList<SomeClass> SomeClassList

      get

      return this._SomeClassList.AsReadOnly();




      Then, make a function to prevent SomeClassList to be serialized:



      public bool ShouldSerializeSomeClassList() return false; 





      share|improve this answer


















      • 1





        I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

        – bazsibazsi
        Nov 14 '18 at 10:40














      2












      2








      2







      What worked for me was the following:



      [JsonProperty(PropertyName = "TargetName")]
      private List<SomeClass> _SomeClassList get; set;
      public IReadOnlyList<SomeClass> SomeClassList

      get

      return this._SomeClassList.AsReadOnly();




      Then, make a function to prevent SomeClassList to be serialized:



      public bool ShouldSerializeSomeClassList() return false; 





      share|improve this answer













      What worked for me was the following:



      [JsonProperty(PropertyName = "TargetName")]
      private List<SomeClass> _SomeClassList get; set;
      public IReadOnlyList<SomeClass> SomeClassList

      get

      return this._SomeClassList.AsReadOnly();




      Then, make a function to prevent SomeClassList to be serialized:



      public bool ShouldSerializeSomeClassList() return false; 






      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered Apr 28 '15 at 11:46









      WotuuWotuu

      5421517




      5421517







      • 1





        I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

        – bazsibazsi
        Nov 14 '18 at 10:40













      • 1





        I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

        – bazsibazsi
        Nov 14 '18 at 10:40








      1




      1





      I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

      – bazsibazsi
      Nov 14 '18 at 10:40






      I think this should be the accepted answer. Also, you can simply use [JsonIgnore] attribute on the public collection to prevent Json.NET to deserialize the ReadOnlyCollection.

      – bazsibazsi
      Nov 14 '18 at 10:40














      1














      It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:



      void Main()

      Poco p = new Poco();
      p.Items.Add("foo");
      p.Items.Add("bar");

      p.Dump(); // Linqpad command to show a visual objet dump in the output pane

      String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );

      serialized.Dump();
      // serialized == ""Items":["foo","bar"]"

      Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );

      p2.Dump();


      class Poco

      public List<String> Items get; = new List<String>();



      When I run this, the dumps of p and p2 are identical.






      share|improve this answer


















      • 3





        Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

        – Jamey
        Oct 24 '17 at 9:24















      1














      It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:



      void Main()

      Poco p = new Poco();
      p.Items.Add("foo");
      p.Items.Add("bar");

      p.Dump(); // Linqpad command to show a visual objet dump in the output pane

      String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );

      serialized.Dump();
      // serialized == ""Items":["foo","bar"]"

      Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );

      p2.Dump();


      class Poco

      public List<String> Items get; = new List<String>();



      When I run this, the dumps of p and p2 are identical.






      share|improve this answer


















      • 3





        Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

        – Jamey
        Oct 24 '17 at 9:24













      1












      1








      1







      It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:



      void Main()

      Poco p = new Poco();
      p.Items.Add("foo");
      p.Items.Add("bar");

      p.Dump(); // Linqpad command to show a visual objet dump in the output pane

      String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );

      serialized.Dump();
      // serialized == ""Items":["foo","bar"]"

      Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );

      p2.Dump();


      class Poco

      public List<String> Items get; = new List<String>();



      When I run this, the dumps of p and p2 are identical.






      share|improve this answer













      It's 2017 now, and I can report that Json.NET 10.x seems to get this right. Here's my test-case:



      void Main()

      Poco p = new Poco();
      p.Items.Add("foo");
      p.Items.Add("bar");

      p.Dump(); // Linqpad command to show a visual objet dump in the output pane

      String serialized = Newtonsoft.Json.JsonConvert.SerializeObject( p );

      serialized.Dump();
      // serialized == ""Items":["foo","bar"]"

      Poco p2 = (Poco)Newtonsoft.Json.JsonConvert.DeserializeObject( serialized, typeof(Poco) );

      p2.Dump();


      class Poco

      public List<String> Items get; = new List<String>();



      When I run this, the dumps of p and p2 are identical.







      share|improve this answer












      share|improve this answer



      share|improve this answer










      answered May 22 '17 at 5:44









      DaiDai

      72.5k13115201




      72.5k13115201







      • 3





        Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

        – Jamey
        Oct 24 '17 at 9:24












      • 3





        Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

        – Jamey
        Oct 24 '17 at 9:24







      3




      3





      Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

      – Jamey
      Oct 24 '17 at 9:24





      Poco doesn't contain a read-only list. OP wanted a list which the user couldn't modify. With this code I can write p2.Items.Add("foobar"); after deserialisation..

      – Jamey
      Oct 24 '17 at 9:24











      1














      With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.



      The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.



      Any custom logic can be implemented inside AddItem.



      The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings



      public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>

      public override bool CanConvert(Type objectType)

      return typeof(ItemsHolder).IsAssignableFrom(objectType);


      public override object ReadJson(JsonReader reader,
      Type objectType,
      object existingValue,
      JsonSerializer serializer)


      JObject jObject = JObject.Load(reader);

      ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;

      var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
      foreach (var jItem in jItems)

      var childReader = CreateReaderFromToken(reader, jItem);
      var item = serializer.Deserialize<Item>(childReader);
      holder.AddItem(item);


      return holder;


      public override ItemsHolder Create(Type objectType)

      return new ItemsHolder();


      public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)

      JsonReader jObjectReader = token.CreateReader();
      jObjectReader.Culture = reader.Culture;
      jObjectReader.DateFormatString = reader.DateFormatString;
      jObjectReader.DateParseHandling = reader.DateParseHandling;
      jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
      jObjectReader.FloatParseHandling = reader.FloatParseHandling;
      jObjectReader.MaxDepth = reader.MaxDepth;
      jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
      return jObjectReader;







      share|improve this answer



























        1














        With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.



        The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.



        Any custom logic can be implemented inside AddItem.



        The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings



        public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>

        public override bool CanConvert(Type objectType)

        return typeof(ItemsHolder).IsAssignableFrom(objectType);


        public override object ReadJson(JsonReader reader,
        Type objectType,
        object existingValue,
        JsonSerializer serializer)


        JObject jObject = JObject.Load(reader);

        ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;

        var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
        foreach (var jItem in jItems)

        var childReader = CreateReaderFromToken(reader, jItem);
        var item = serializer.Deserialize<Item>(childReader);
        holder.AddItem(item);


        return holder;


        public override ItemsHolder Create(Type objectType)

        return new ItemsHolder();


        public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)

        JsonReader jObjectReader = token.CreateReader();
        jObjectReader.Culture = reader.Culture;
        jObjectReader.DateFormatString = reader.DateFormatString;
        jObjectReader.DateParseHandling = reader.DateParseHandling;
        jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
        jObjectReader.FloatParseHandling = reader.FloatParseHandling;
        jObjectReader.MaxDepth = reader.MaxDepth;
        jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
        return jObjectReader;







        share|improve this answer

























          1












          1








          1







          With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.



          The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.



          Any custom logic can be implemented inside AddItem.



          The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings



          public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>

          public override bool CanConvert(Type objectType)

          return typeof(ItemsHolder).IsAssignableFrom(objectType);


          public override object ReadJson(JsonReader reader,
          Type objectType,
          object existingValue,
          JsonSerializer serializer)


          JObject jObject = JObject.Load(reader);

          ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;

          var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
          foreach (var jItem in jItems)

          var childReader = CreateReaderFromToken(reader, jItem);
          var item = serializer.Deserialize<Item>(childReader);
          holder.AddItem(item);


          return holder;


          public override ItemsHolder Create(Type objectType)

          return new ItemsHolder();


          public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)

          JsonReader jObjectReader = token.CreateReader();
          jObjectReader.Culture = reader.Culture;
          jObjectReader.DateFormatString = reader.DateFormatString;
          jObjectReader.DateParseHandling = reader.DateParseHandling;
          jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
          jObjectReader.FloatParseHandling = reader.FloatParseHandling;
          jObjectReader.MaxDepth = reader.MaxDepth;
          jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
          return jObjectReader;







          share|improve this answer













          With Newtonsoft you can use a CustomCreationConverter<T> or the abstract JsonConverter, you have to implement the Create method and ReadJson.



          The ReadJson method is where the converter will do the default deserialization calling the base method, from there, each item inside the readonly collection can be deserialized and added with the AddItem method.



          Any custom logic can be implemented inside AddItem.



          The last step is configuring this new converter for deserialization with an attribute [JsonConverter(typeof(NavigationTreeJsonConverter))] or within the JsonSerializerSettings



          public class ItemsHolderJsonConverter : CustomCreationConverter<ItemsHolder>

          public override bool CanConvert(Type objectType)

          return typeof(ItemsHolder).IsAssignableFrom(objectType);


          public override object ReadJson(JsonReader reader,
          Type objectType,
          object existingValue,
          JsonSerializer serializer)


          JObject jObject = JObject.Load(reader);

          ItemsHolder holder = base.ReadJson(CreateReaderFromToken(reader,jObject), objectType, existingValue, serializer) as ItemsHolder;

          var jItems = jObject[nameof(ItemsHolder.Items)] as JArray ?? new JArray();
          foreach (var jItem in jItems)

          var childReader = CreateReaderFromToken(reader, jItem);
          var item = serializer.Deserialize<Item>(childReader);
          holder.AddItem(item);


          return holder;


          public override ItemsHolder Create(Type objectType)

          return new ItemsHolder();


          public static JsonReader CreateReaderFromToken(JsonReader reader, JToken token)

          JsonReader jObjectReader = token.CreateReader();
          jObjectReader.Culture = reader.Culture;
          jObjectReader.DateFormatString = reader.DateFormatString;
          jObjectReader.DateParseHandling = reader.DateParseHandling;
          jObjectReader.DateTimeZoneHandling = reader.DateTimeZoneHandling;
          jObjectReader.FloatParseHandling = reader.FloatParseHandling;
          jObjectReader.MaxDepth = reader.MaxDepth;
          jObjectReader.SupportMultipleContent = reader.SupportMultipleContent;
          return jObjectReader;








          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Jul 20 '17 at 10:23









          animalito maquinaanimalito maquina

          1,16011126




          1,16011126





















              1














              Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.



              One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.



              Here's my class that I'd like to Serialize/Deserialize



              public class CannotDeserializeThis

              private readonly IList<User> _users = new List<User>();
              public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();

              public void AddUser(User user)

              _users.Add(user);




              I could serialize this to:
              "Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]



              But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:



              public class ReadonlyJsonDefaultContractResolver : DefaultContractResolver

              protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

              var prop = base.CreateProperty(member, memberSerialization);
              if (!prop.Writable)

              var property = member as PropertyInfo;
              if (property != null)

              var hasPrivateSetter = property.GetSetMethod(true) != null;
              prop.Writable = hasPrivateSetter;

              if (!prop.Writable)

              var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));

              if (privateField != null)

              var originalPropertyName = prop.PropertyName;
              prop = base.CreateProperty(privateField, memberSerialization);
              prop.Writable = true;
              prop.PropertyName = originalPropertyName;
              prop.UnderlyingName = originalPropertyName;
              prop.Readable = true;





              return prop;




              The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.



              This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')






              share|improve this answer





























                1














                Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.



                One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.



                Here's my class that I'd like to Serialize/Deserialize



                public class CannotDeserializeThis

                private readonly IList<User> _users = new List<User>();
                public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();

                public void AddUser(User user)

                _users.Add(user);




                I could serialize this to:
                "Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]



                But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:



                public class ReadonlyJsonDefaultContractResolver : DefaultContractResolver

                protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

                var prop = base.CreateProperty(member, memberSerialization);
                if (!prop.Writable)

                var property = member as PropertyInfo;
                if (property != null)

                var hasPrivateSetter = property.GetSetMethod(true) != null;
                prop.Writable = hasPrivateSetter;

                if (!prop.Writable)

                var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));

                if (privateField != null)

                var originalPropertyName = prop.PropertyName;
                prop = base.CreateProperty(privateField, memberSerialization);
                prop.Writable = true;
                prop.PropertyName = originalPropertyName;
                prop.UnderlyingName = originalPropertyName;
                prop.Readable = true;





                return prop;




                The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.



                This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')






                share|improve this answer



























                  1












                  1








                  1







                  Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.



                  One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.



                  Here's my class that I'd like to Serialize/Deserialize



                  public class CannotDeserializeThis

                  private readonly IList<User> _users = new List<User>();
                  public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();

                  public void AddUser(User user)

                  _users.Add(user);




                  I could serialize this to:
                  "Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]



                  But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:



                  public class ReadonlyJsonDefaultContractResolver : DefaultContractResolver

                  protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

                  var prop = base.CreateProperty(member, memberSerialization);
                  if (!prop.Writable)

                  var property = member as PropertyInfo;
                  if (property != null)

                  var hasPrivateSetter = property.GetSetMethod(true) != null;
                  prop.Writable = hasPrivateSetter;

                  if (!prop.Writable)

                  var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));

                  if (privateField != null)

                  var originalPropertyName = prop.PropertyName;
                  prop = base.CreateProperty(privateField, memberSerialization);
                  prop.Writable = true;
                  prop.PropertyName = originalPropertyName;
                  prop.UnderlyingName = originalPropertyName;
                  prop.Readable = true;





                  return prop;




                  The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.



                  This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')






                  share|improve this answer















                  Looks like there's a number of ways to do it, but one thing I did not want to do was to have to modify all of my data objects to be aware of how they should be serialized/deserialized.



                  One way to do this was to take some examples of DefaultContractResolver's others had done (but still didn't do what I needed to do) and modify them to populate readonly fields.



                  Here's my class that I'd like to Serialize/Deserialize



                  public class CannotDeserializeThis

                  private readonly IList<User> _users = new List<User>();
                  public virtual IEnumerable<User> Users => _users.ToList().AsReadOnly();

                  public void AddUser(User user)

                  _users.Add(user);




                  I could serialize this to:
                  "Users":["Name":"First Guy","Name":"Second Guy","Name":"Third Guy"]



                  But Deserializing this would leave the Users IEnumerable empty. The only way, I could find, around this was to either remove the '.ToList.AsReadonly' on the Users property or implement a DefaultContractResolver as such:



                  public class ReadonlyJsonDefaultContractResolver : DefaultContractResolver

                  protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)

                  var prop = base.CreateProperty(member, memberSerialization);
                  if (!prop.Writable)

                  var property = member as PropertyInfo;
                  if (property != null)

                  var hasPrivateSetter = property.GetSetMethod(true) != null;
                  prop.Writable = hasPrivateSetter;

                  if (!prop.Writable)

                  var privateField = member.DeclaringType.GetRuntimeFields().FirstOrDefault(x => x.Name.Equals("_" + Char.ToLowerInvariant(prop.PropertyName[0]) + prop.PropertyName.Substring(1)));

                  if (privateField != null)

                  var originalPropertyName = prop.PropertyName;
                  prop = base.CreateProperty(privateField, memberSerialization);
                  prop.Writable = true;
                  prop.PropertyName = originalPropertyName;
                  prop.UnderlyingName = originalPropertyName;
                  prop.Readable = true;





                  return prop;




                  The DefaultContractResolver is finding the corresponding private backing field, creating a property out of that, and renaming it to the public readonly property.



                  This assumes a convention, though. That your backing field starts with an underscore and is a lowercase version of your public property. For most of the code we were working with, this was a safe assumption. (e.g. 'Users' -> '_users', or 'AnotherPropertyName' -> '_anotherPropertyName')







                  share|improve this answer














                  share|improve this answer



                  share|improve this answer








                  edited Nov 29 '18 at 18:00

























                  answered Nov 28 '18 at 16:50









                  Jay DubyaJay Dubya

                  114




                  114





















                      0














                      I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:



                      public class State

                      [Newtonsoft.Json.JsonProperty]
                      public double Citizens get; private set;

                      [Newtonsoft.Json.JsonProperty]
                      public float Value get return pValue;
                      private float pValue = 450000.0f;

                      public List<string> BeachList get; = new List<string>();

                      public State()



                      public State(double _Citizens)

                      this.Citizens = _Citizens;



                      ...

                      State croatia = new State(30.0D);
                      croatia.BeachList.Add("Bol na Braču");
                      croatia.BeachList.Add("Zrće");

                      string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);

                      State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);


                      So, croatia and, slovenia now both have the same property values.
                      I added Citizens and, Value properties to see if you want to work with one or the other way.



                      Thanks to Saeb Amini (Private setters in Json.Net)






                      share|improve this answer























                      • My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

                        – Neil N
                        Jul 5 '17 at 14:00











                      • You're right about that. I will get to bottom of this. I will get back here @NeilN.

                        – MaGnumX
                        Jul 5 '17 at 18:38















                      0














                      I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:



                      public class State

                      [Newtonsoft.Json.JsonProperty]
                      public double Citizens get; private set;

                      [Newtonsoft.Json.JsonProperty]
                      public float Value get return pValue;
                      private float pValue = 450000.0f;

                      public List<string> BeachList get; = new List<string>();

                      public State()



                      public State(double _Citizens)

                      this.Citizens = _Citizens;



                      ...

                      State croatia = new State(30.0D);
                      croatia.BeachList.Add("Bol na Braču");
                      croatia.BeachList.Add("Zrće");

                      string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);

                      State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);


                      So, croatia and, slovenia now both have the same property values.
                      I added Citizens and, Value properties to see if you want to work with one or the other way.



                      Thanks to Saeb Amini (Private setters in Json.Net)






                      share|improve this answer























                      • My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

                        – Neil N
                        Jul 5 '17 at 14:00











                      • You're right about that. I will get to bottom of this. I will get back here @NeilN.

                        – MaGnumX
                        Jul 5 '17 at 18:38













                      0












                      0








                      0







                      I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:



                      public class State

                      [Newtonsoft.Json.JsonProperty]
                      public double Citizens get; private set;

                      [Newtonsoft.Json.JsonProperty]
                      public float Value get return pValue;
                      private float pValue = 450000.0f;

                      public List<string> BeachList get; = new List<string>();

                      public State()



                      public State(double _Citizens)

                      this.Citizens = _Citizens;



                      ...

                      State croatia = new State(30.0D);
                      croatia.BeachList.Add("Bol na Braču");
                      croatia.BeachList.Add("Zrće");

                      string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);

                      State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);


                      So, croatia and, slovenia now both have the same property values.
                      I added Citizens and, Value properties to see if you want to work with one or the other way.



                      Thanks to Saeb Amini (Private setters in Json.Net)






                      share|improve this answer













                      I stumbled upon the answer on Stackoverflow in the comment section but, it wasn't voted. And, I give you more detailed answer here:



                      public class State

                      [Newtonsoft.Json.JsonProperty]
                      public double Citizens get; private set;

                      [Newtonsoft.Json.JsonProperty]
                      public float Value get return pValue;
                      private float pValue = 450000.0f;

                      public List<string> BeachList get; = new List<string>();

                      public State()



                      public State(double _Citizens)

                      this.Citizens = _Citizens;



                      ...

                      State croatia = new State(30.0D);
                      croatia.BeachList.Add("Bol na Braču");
                      croatia.BeachList.Add("Zrće");

                      string croatiaSerialized = Newtonsoft.Json.JsonConvert.SerializeObject(croatia);

                      State slovenia = Newtonsoft.Json.JsonConvert.DeserializeObject<State>(croatiaSerialized);


                      So, croatia and, slovenia now both have the same property values.
                      I added Citizens and, Value properties to see if you want to work with one or the other way.



                      Thanks to Saeb Amini (Private setters in Json.Net)







                      share|improve this answer












                      share|improve this answer



                      share|improve this answer










                      answered Jul 3 '17 at 9:00









                      MaGnumXMaGnumX

                      30026




                      30026












                      • My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

                        – Neil N
                        Jul 5 '17 at 14:00











                      • You're right about that. I will get to bottom of this. I will get back here @NeilN.

                        – MaGnumX
                        Jul 5 '17 at 18:38

















                      • My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

                        – Neil N
                        Jul 5 '17 at 14:00











                      • You're right about that. I will get to bottom of this. I will get back here @NeilN.

                        – MaGnumX
                        Jul 5 '17 at 18:38
















                      My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

                      – Neil N
                      Jul 5 '17 at 14:00





                      My problem goes beyond just being able to set something via a private setter. While your solution will work for primitive types like float or double, it wont work for IEnumerables, like in my question. From above: "NewtonSoft does not call the setter, it only calls the getter to get the list, and then adds each item to it"

                      – Neil N
                      Jul 5 '17 at 14:00













                      You're right about that. I will get to bottom of this. I will get back here @NeilN.

                      – MaGnumX
                      Jul 5 '17 at 18:38





                      You're right about that. I will get to bottom of this. I will get back here @NeilN.

                      – MaGnumX
                      Jul 5 '17 at 18:38

















                      draft saved

                      draft discarded
















































                      Thanks for contributing an answer to Stack Overflow!


                      • Please be sure to answer the question. Provide details and share your research!

                      But avoid


                      • Asking for help, clarification, or responding to other answers.

                      • Making statements based on opinion; back them up with references or personal experience.

                      To learn more, see our tips on writing great answers.




                      draft saved


                      draft discarded














                      StackExchange.ready(
                      function ()
                      StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f27387085%2fhow-to-deserialize-a-read-only-list-with-json-net%23new-answer', 'question_page');

                      );

                      Post as a guest















                      Required, but never shown





















































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown

































                      Required, but never shown














                      Required, but never shown












                      Required, but never shown







                      Required, but never shown







                      Popular posts from this blog

                      27

                      Top Tejano songwriter Luis Silva dead of heart attack at 64

                      Category:Rhetoric