Search code examples
c#jsonjson.net

Newtonsoft Json Serialization just for specific property


I've two classes and they have an aggregation relationship from one to another

public class Issue
{
    //---
    //tons of other properties
    //---
    
    [JsonProperty("key")]
    public string Key { get; set; }

    [JsonProperty("fields")]
    public Fields Fields { get; set; }

}

public class Fields
{
     //---
     //tons of other properties
     //---
     
     [JsonProperty("customfield_10202")]
     public object Customfield10202 { get; set; }
}

taken a json result like this when I use json serializer with contract resolver

{
 "customfield_10202": "value"
}

Here are the contact resolver and operation of serialization

string json = JsonConvert.SerializeObject(fields, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new DynamicContractResolver("customfield_10202") });

public class DynamicContractResolver : DefaultContractResolver
{
    private readonly string _propertyName;

    public DynamicContractResolver(string propertyName)
    {
        _propertyName = propertyName;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
        
        properties =properties.Where(p => p.PropertyName == _propertyName ? true :false).ToList();

        return properties;
    }
}

but I expect result of json like this

{
    "fields": {
        "customfield_10202": "value"
    }
}

I can solve this situation easy way but it doesn't seem right. how can I take a result of json that I mentioned without using a string variable

string json_data = "{ \"fields\": " + json + "}";

Solution

  • Let's suppose you have the following Issue instance:

    var issue = new Issue
    {
        Key = "1",
        Fields = new Fields
        {
            Customfield10202 = "value"
        }
    };
    

    In order to be able to serialize

    • fields from the Issue class and
    • customfield_10202 from the Fields class

    you need to pass both names to the resolver.

    So, instead of receiving a single string in the ctor you should anticipate a collection of strings:

    public class DynamicContractResolver : DefaultContractResolver
    {
        private readonly string[] _properties;
    
        public DynamicContractResolver(string[] properties)
        {
            _properties = properties;
        }
    
        protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
        {
            IList<JsonProperty> properties = base.CreateProperties(type, memberSerialization);
            return properties.Where(p => _properties.Contains(p.PropertyName)).ToList();
        }
    }
    

    The usage would change like this:

    var properties = new[] {"fields", "customfield_10202"};
    string json = JsonConvert.SerializeObject(issue, Formatting.Indented, new JsonSerializerSettings { ContractResolver = new DynamicContractResolver(properties) });
    

    The generated output will be as desired:

    {
      "fields": {
        "customfield_10202": "value"
      }
    }