JSON.Net: Force serialization of all private fields and all fields in sub-classes

C#json.net

C# Problem Overview


I have a class with several different classes and I send the information in these classes out to clients but I don't want to send them all out so some are private, some have the [JsonObject(MemberSerialization.OptIn)] flag etc.

However, now I want to do a backup of all these objects when I need to shutdown the server and every 12 hours (I don't want to use a database) so what I want to do (if possible) is to force the JSON.Net Serializer to convert the object and all the object belonging to that object.

For example:

class Foo
{
  public int Number;
  private string name;
  private PrivateObject po = new PrivateObject();
 
  public string ToJSON()
  { /* Serialize my public field, my property and the object PrivateObject */ }
}

I tried this code (even though it's obsolete) but it doesn't Serialize the objects related to my object:

Newtonsoft.Json.JsonSerializerSettings jss = new Newtonsoft.Json.JsonSerializerSettings();

Newtonsoft.Json.Serialization.DefaultContractResolver dcr = new Newtonsoft.Json.Serialization.DefaultContractResolver();
dcr.DefaultMembersSearchFlags |= System.Reflection.BindingFlags.NonPublic;
jss.ContractResolver = dcr;

return Newtonsoft.Json.JsonConvert.SerializeObject(this, jss);

C# Solutions


Solution 1 - C#

This should work:

var settings = new JsonSerializerSettings() { ContractResolver = new MyContractResolver() };
var json = JsonConvert.SerializeObject(obj, settings);

public class MyContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        var props = type.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                        .Select(p => base.CreateProperty(p, memberSerialization))
                    .Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
                               .Select(f => base.CreateProperty(f, memberSerialization)))
                    .ToList();
        props.ForEach(p => { p.Writable = true; p.Readable = true; });
        return props;
    }
}

Solution 2 - C#

@L.B's answer is great. But ... it requires .NET 3.5 or above.

For those of us stuck with 2.0 ...

public class ForceJSONSerializePrivatesResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
	protected override IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(System.Type type, MemberSerialization memberSerialization)
	{
		var props = type.GetProperties(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
		
		List<Newtonsoft.Json.Serialization.JsonProperty> jsonProps = new List<Newtonsoft.Json.Serialization.JsonProperty>();
		
		foreach( var prop in props )
		{
		jsonProps.Add( base.CreateProperty(prop, memberSerialization));
		}
		
		foreach( var field in type.GetFields(System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance) )
		{
		jsonProps.Add ( base.CreateProperty( field, memberSerialization ) );
		}
				       
		jsonProps.ForEach(p => { p.Writable = true; p.Readable = true; });
		return jsonProps;
	}
}

...seems to work.

Solution 3 - C#

Awesome thanks @L.B. Here's a full implementation in a .linq script in case anyone wants to test with private subclasses - e.g. See A has private subclass B.

void Main()
{
	var a = A.Test();
	SerialiseAllFields.Dump(a);
}

class A
{
	private int PrivField1;
	private int PrivProp1 { get; set; }
	private B PrivSubClassField1;

	public static A Test()
	{
		return new A { PrivField1 = 1, PrivProp1 = 2, PrivSubClassField1 = B.Test() };
	}
}

class B
{
	private int PrivField1;
	private int PrivProp1 { get; set; }

	public static B Test()
	{
		return new B { PrivField1 = 3, PrivProp1 = 4 };
	}
}

// Define other methods and classes here
public static class SerialiseAllFields
{
	public static void Dump(object o, bool indented = true)
	{
		var settings = new Newtonsoft.Json.JsonSerializerSettings() { ContractResolver = new AllFieldsContractResolver() };
		if (indented)
		{
			settings.Formatting = Newtonsoft.Json.Formatting.Indented;
		}
		Newtonsoft.Json.JsonConvert.SerializeObject(o, settings).Dump();
	}
}

public class AllFieldsContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
	protected override IList<Newtonsoft.Json.Serialization.JsonProperty> CreateProperties(Type type, Newtonsoft.Json.MemberSerialization memberSerialization)
	{
		var props = type
			.GetProperties(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
			.Select(p => base.CreateProperty(p, memberSerialization))
			.Union(type.GetFields(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance)
			.Select(f => base.CreateProperty(f, memberSerialization)))
			.ToList();
		props.ForEach(p => { p.Writable = true; p.Readable = true; });
		return props;
	}
}

The interesting thing is that the backing fields for the properties are also serialized i.e. output is:

{
  "PrivProp1": 2,
  "PrivField1": 1,
  "<PrivProp1>k__BackingField": 2,
  "PrivSubClassField1": {
    "PrivProp1": 4,
    "PrivField1": 3,
    "<PrivProp1>k__BackingField": 4
  }
}

Solution 4 - C#

this is modified version of the previous accepted answer, this will also serialize private fields/properties. performance a bit increased. (serialization without BinaryFormatter a bit slower)

public class CloneContractResolver : Newtonsoft.Json.Serialization.DefaultContractResolver
{
    protected override IList<JsonProperty> CreateProperties(Type type,
                                MemberSerialization memberSerialization)
    {
        List<MemberInfo> members = GetSerializableMembers(type);
        if (members == null)
         throw new JsonSerializationException("Null collection of serializable members returned.");

        members.AddRange(type.GetProperties(BindingFlags.NonPublic | BindingFlags.Instance)
            .Where(f => !f.CustomAttributes.Any(x => x.AttributeType
                == typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))));

        members.AddRange(type.GetFields(BindingFlags.NonPublic | BindingFlags.Instance)
            .Where(f => !f.CustomAttributes.Any(x => x.AttributeType
                == typeof(System.Runtime.CompilerServices.CompilerGeneratedAttribute))));

        JsonPropertyCollection properties = new JsonPropertyCollection(type);
        members.ForEach(member =>
        {
            JsonProperty property = CreateProperty(member, memberSerialization);
            property.Writable = true;
            property.Readable = true;
            properties.AddProperty(property);
        });
        return properties;
    }
}

in my opinion, this method will use a bit more memory

public static class CloneHelper
{
    private readonly static JsonSerializerSettings clone_settings = new JsonSerializerSettings() { ContractResolver = new CloneContractResolver() };
    public static T Clone<T>(this object source)
    {
        T entity = JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source, clone_settings), clone_settings);
        return entity;
    }
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionWesterlund.ioView Question on Stackoverflow
Solution 1 - C#L.BView Answer on Stackoverflow
Solution 2 - C#AdamView Answer on Stackoverflow
Solution 3 - C#IlanView Answer on Stackoverflow
Solution 4 - C#Mustafa Salih ASLIMView Answer on Stackoverflow