The main difficulty here is that Json.NET is a contract based serializer that creates a contract for each serializable type and then (de) serializes according to the contract. If the type is displayed in several places in the object hierarchy, the same contract applies. But you want to selectively include properties for this type depending on its location in the hierarchy, which contradicts the basic design of "one type one contract".
One quick way around this is to serialize in JObject and then use JToken.SelectTokens() to select only the JSON data that you want to return, deleting everything else. Because SelectTokens fully supports JSONPath query syntax , you can selectively enable the use of array wildcards and properties or other filters, for example:
"$.FirstLevel[*].Bar"
includes all properties with the name "Bar" in all elements of the property array named "FirstLevel" root object.
This should reduce the use of your network at will, but will not save processing time on the server.
Removal can be performed using the following extension methods:
public static partial class JsonExtensions { public static TJToken RemoveAllExcept<TJToken>(this TJToken obj, IEnumerable<string> paths) where TJToken : JToken { if (obj == null || paths == null) throw new NullReferenceException(); var keepers = new HashSet<JToken>(paths.SelectMany(path => obj.SelectTokens(path)), ObjectReferenceEqualityComparer<JToken>.Default); var keepersAndParents = new HashSet<JToken>(keepers.SelectMany(t => t.AncestorsAndSelf()), ObjectReferenceEqualityComparer<JToken>.Default);
And then use them like:
public class TestClass { public static void Test() { var root = new RootObject { FirstLevel1 = new FirstLevel { SecondLevel1 = new List<SecondLevel> { new SecondLevel { A = "a11", B = "b11", Third1 = new ThirdLevel { Foo = "Foos11", Bar = "Bars11" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList11", Bar = "BarList11" } } } }, SecondLevel2 = new List<SecondLevel> { new SecondLevel { A = "a12", B = "b12", Third1 = new ThirdLevel { Foo = "Foos12", Bar = "Bars12" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList12", Bar = "BarList12" } } } }, }, FirstLevel2 = new FirstLevel { SecondLevel1 = new List<SecondLevel> { new SecondLevel { A = "a21", B = "b21", Third1 = new ThirdLevel { Foo = "Foos21", Bar = "Bars21" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList21", Bar = "BarList21" } } } }, SecondLevel2 = new List<SecondLevel> { new SecondLevel { A = "a22", B = "b22", Third1 = new ThirdLevel { Foo = "Foos22", Bar = "Bars22" }, Third2 = new List<ThirdLevel> { new ThirdLevel { Foo = "FooList22", Bar = "BarList22" } } } }, } }; Assert.IsTrue(JObject.FromObject(root).DescendantsAndSelf().OfType<JValue>().Count() == 24);
Please note that there is a request to expand Feature Feature: ADD JsonProperty.ShouldSerialize (object target, line path) # 1857, which would simplify such functionality.
Demo violin here and here .