I\'m working on an Entity Framework project. I want to serialize a bunch of entity class instances. I\'ve bound these together into a container class:
public
Also, if you are looking for a way to do this for all of your model classes with different member type names (for example, you have some models created by Entity Framework) this answer can help and you can ignore navigation properties in JSON serialization by it.
An easier method is to modify your model T4 template (.tt) to append [JsonIgnore]
attributes to your navigation properties, which will just leave the primitive types as serializable.
First, to address your issues with reference loops-- The PreserveReferencesHandling
setting controls whether Json.Net emits $id
and $ref
to track inter-object references. If you have this set to None
and your object graph contains loops, then you will also need to set ReferenceLoopHandling
to Ignore
to prevent errors.
Now, to get Json.Net to ignore all object references altogether and only serialize primitive properties (except in your Pseudocontext
class of course), you do need a custom Contract Resolver, as you suggested. But don't worry, it is not as hard as you think. The resolver has the capability to inject a ShouldSerialize
method for each property to control whether or not that property should be included in the output. So, all you need to do is derive your resolver from the default one, then override the CreateProperty
method such that it sets ShouldSerialize
appropriately. (You do not need a custom JsonConverter
here, although it is possible to solve this problem with that approach. It would require quite a bit more code, however.)
Here is the code for the resolver:
class CustomResolver : DefaultContractResolver
{
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty prop = base.CreateProperty(member, memberSerialization);
if (prop.DeclaringType != typeof(PseudoContext) &&
prop.PropertyType.IsClass &&
prop.PropertyType != typeof(string))
{
prop.ShouldSerialize = obj => false;
}
return prop;
}
}
Here is a full demo showing the resolver in action.
class Program
{
static void Main(string[] args)
{
// Set up some dummy data complete with reference loops
Thing t1 = new Thing { Id = 1, Name = "Flim" };
Thing t2 = new Thing { Id = 2, Name = "Flam" };
Widget w1 = new Widget
{
Id = 5,
Name = "Hammer",
IsActive = true,
Price = 13.99M,
Created = new DateTime(2013, 12, 29, 8, 16, 3),
Color = Color.Red,
};
w1.RelatedThings = new List<Thing> { t2 };
t2.RelatedWidgets = new List<Widget> { w1 };
Widget w2 = new Widget
{
Id = 6,
Name = "Drill",
IsActive = true,
Price = 45.89M,
Created = new DateTime(2014, 1, 22, 2, 29, 35),
Color = Color.Blue,
};
w2.RelatedThings = new List<Thing> { t1 };
t1.RelatedWidgets = new List<Widget> { w2 };
// Here is the container class we wish to serialize
PseudoContext pc = new PseudoContext
{
Things = new List<Thing> { t1, t2 },
Widgets = new List<Widget> { w1, w2 }
};
// Serializer settings
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new CustomResolver();
settings.PreserveReferencesHandling = PreserveReferencesHandling.None;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.Formatting = Formatting.Indented;
// Do the serialization and output to the console
string json = JsonConvert.SerializeObject(pc, settings);
Console.WriteLine(json);
}
class PseudoContext
{
public List<Thing> Things { get; set; }
public List<Widget> Widgets { get; set; }
}
class Thing
{
public int Id { get; set; }
public string Name { get; set; }
public List<Widget> RelatedWidgets { get; set; }
}
class Widget
{
public int Id { get; set; }
public string Name { get; set; }
public bool IsActive { get; set; }
public decimal Price { get; set; }
public DateTime Created { get; set; }
public Color Color { get; set; }
public List<Thing> RelatedThings { get; set; }
}
enum Color { Red, White, Blue }
}
Output:
{
"Things": [
{
"Id": 1,
"Name": "Flim"
},
{
"Id": 2,
"Name": "Flam"
}
],
"Widgets": [
{
"Id": 5,
"Name": "Hammer",
"IsActive": true,
"Price": 13.99,
"Created": "2013-12-29T08:16:03",
"Color": 0
},
{
"Id": 6,
"Name": "Drill",
"IsActive": true,
"Price": 45.89,
"Created": "2014-01-22T02:29:35",
"Color": 2
}
]
}
Hope this is in the ballpark of what you were looking for.