Search code examples
c#jsonrestjson.net

Serialize custom list to json c#


I have a custom Collection to control the changes made to it, and revert changes if I need to, similar to the implementation of the IEditableObject

public class CollectionBO<TEntity> : Collection<TEntity> where TEntity : BOBase
{
    public List<TEntity> AddedEntities { get; set; }
    public List<TEntity> RemovedEntities { get; set; }

   
    public CollectionBO()
    {
        AddedEntities = new List<TEntity>();
        RemovedEntities = new List<TEntity>();
    }

}

I want to use that list also in the DTO of a rest api, to access the information of the records to be removed or added easily, but the problem I have is that it does not serialize the internal lists (AddedEntities, RemovedEntities), when they arrive to the server, those lists are always empty, the question is it possible to serialize a list and even its IList properties

 await (serverUrl).AppendPathSegment(endPoit)
                            .WithOAuthBearerToken(token)
                            .PutJsonAsync(CollectionBO);

Solution

  • The issue is caused by a mismatch between your inheritance structure and your desired output structure.

    By inheriting from Collection<T>, Newtonsoft invokes the JsonArrayContract due to your type implementing ICollection<>. As a result, when it attempts to serialize, it outputs an array: "[]".

    That said, your object structure is an object with containing arrays. In order to force the serializer to treat your CollectionBO<TEntity> as an object, you need to decorate it with the [JsonObject] attribute.

    [JsonObject]
    public class CollectionBO<TEntity> : System.Collections.ObjectModel.Collection<TEntity> 
        where TEntity : BOBase
    {
          public List<TEntity> AddedEntities { get; set; }
          public List<TEntity> RemovedEntities { get; set; }
    
    
          public CollectionBO()
          {
                AddedEntities = new List<TEntity>();
                RemovedEntities = new List<TEntity>();
          }
    }
    

    This allows the serializer to treat it correctly:

    {"AddedEntities":[{"Id":1},{"Id":2}],"RemovedEntities":[{"Id":3},{"Id":4}],"Count":0}

    As a word of caution, extending collection types is rarely advisable since you can create all sorts of odd behaviors, such as the behavior with the Newtonsoft serializer. In addition, note that the Count property is serialized to 0, even though you have underlying objects. While you can certainly make this work, be advised that you will continue to run into unexpected behavior when extending a collection type but not treating it as a collection.