0

I want to serialize objects using json.net and C# .Also I want only selected properties to be inside the final JSON object returned. I have two classes

public class Class {
 
   [JsonProperty("className")]
   public string Name{ get; set;}
   
   [JsonProperty("tierUnitId")]
   public int? TierUnitId { get; set; }
   
   [JsonProperty("options")]
   public List<Options> Options{get; set;}
 
}

public class Options{

     [JsonProperty("idNum")]
     public int? idNum {get; set;}

     [JsonProperty("options")]
     public string Options {get; set;}

 }    

Now I have an Class object which I want to serialize.

{   
   "className" : "Class",
   "tierUnitId" : 101,
   "options" : [
            { "idNum" : 10 , "options" : "00010011" } ,
            { "idNum" : 11 , "options" : "11110011" }
    ]

}

For that i have override the CreateProperties method of the DefaultContractResolver class for including only selected properties.Also i'm passing the list of properties to be included to the constructor of my CustomRetrieveResponseResolver class which is extending DefaultContractResolver.

private readonly IList<string> _propertiesToInclude;
public CustomRetrieveResponseResolver(IList<string> propertiesToInclude)
{
    _propertiesToInclude = propertiesToInclude;
}

I have a list of strings propertiesToInclude which have the name of properties to be included.

For ex:
propertiesToInclude = { "Name" , "options.idNum" }

Now the problem is that in the list propertiesToInclude i have the relative names of the nested properties. I know that CreateProperties is going to be called twice one for Class and then for options Class ( due to the List<Options> Options inside Class ). Is there any way of serializing in this manner ? Like the output for the above object will be

{   
       "className" : "Class",
       "options" : [
                { "idNum" : 10 } ,
                { "idNum" : 11  }
        ]
    
}    

Can Someone help me in this i.e serializing selected values with the using path of nested properties?

Pulkit Sharma
  • 390
  • 2
  • 14
  • Json.NET is a contract-based serializer. It defines a contract for a type, then serializes according to the contract. So there's no (straightforward) way to use a different contract for the ***same type*** at different locations in the serialization graph. See: [How to perform partial object serialization providing "paths" using Newtonsoft JSON.NET](https://stackoverflow.com/q/30304128/3744182) for a discussion and workaround. In fact that may be a duplicate, agree? – dbc Jan 25 '22 at 15:00
  • That being said, in your example you don't really need to filter properties by path, do you? Filtering by a `IList> propertiesByTypeToInclude` should be good enough, shouldn't it? – dbc Jan 25 '22 at 15:35

1 Answers1

0

Use [JsonIgnore] attribute if you want to ignore properties when serializing/reserializing.

For dynamic exclusion on properties:

public class CustomPropertiesContractResolver : DefaultContractResolver
{
    private HashSet<string> _propertySet;
    
    public CustomPropertiesContractResolver(IEnumerable<string> propertyNames)
    {
        if (propertyNames != null)
        {
            _propertySet = new HashSet<string>(propertyNames, StringComparer.OrdinalIgnoreCase);
        }
    }
    
    protected override List<MemberInfo> GetSerializableMembers(Type objectType)
    {
        List<MemberInfo> serializableMembers = null;
        var allMembers = base.GetSerializableMembers(objectType);
   
        if (_propertySet != null && _propertySet.Count > 0)
        {
            serializableMembers = allMembers.Where(m => !_propertySet.Contains(m.Name)).ToList();
        }
        return serializableMembers != null && serializableMembers.Count > 0 ? serializableMembers : allMembers;
    }
}

Usage

var serializedStr = JsonConvert.SerializeObject(employeeObj, new JsonSerializerSettings()
{
    ContractResolver = new CustomPropertiesContractResolver(new List<string>{"options"})
};);
     

To provide depth and be able to track contracts of nested properties, check this answer: Json.NET serialize by depth and attribute

Indrit Kello
  • 1,293
  • 8
  • 19
  • This will not work as I have to ignore properties dynamically. I have to include properties that are in the listpropertiesToInclude. – Pulkit Sharma Jan 25 '22 at 10:17
  • I was updating my answer. Take a look and let me know. – Indrit Kello Jan 25 '22 at 10:23
  • this will work but not for the nested properties like the example i have given. Like for "RvcOperatorOptions.RvcObjNum" your solution will not work. – Pulkit Sharma Jan 25 '22 at 10:24
  • I updated the answer creating a custom `ContractResolver` and overriding `GetSerializableMembers`. I haven't fully tested it yet but you can give it a try. If it doesn't work, I will create a solution and work on top of this. – Indrit Kello Jan 25 '22 at 10:38
  • Same thing this is also not working as i have used CreateProperties which also internally calls GetSerializableMembers so it is the same things. This will also not going to work for nested one's. – Pulkit Sharma Jan 25 '22 at 10:47
  • I think what you want to do it's tricky. I would suggest to find the properties more like to change (even all) and make them virtual. Then you can override only the ones you want on a model that will be used for serialization. This could add some more complexity to your code but it's a cleaner solution. – Indrit Kello Jan 25 '22 at 11:16
  • However, I updated my answer with a potential solution to ignore in depth by combining the current solution with another answer. Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/241382/discussion-between-indrit-kello-and-pulkit-sharma). – Indrit Kello Jan 25 '22 at 11:20