I'm currently having some issues with Newtonsoft Json.
What I want is simple: Compare the Object which will be serialized with all Properties and Subproperties for Equality.
I tried now to Create my own EqualityComparer but it only compared with the Properties of the Parent Object.
Also, I tried to write my own ReferenceResolver but had no luck with it.
Let's talk with an Example:
public class EntityA
{
int Foo {get; set;}
public override bool Equals(object obj)
{
return (obj is EntityA other) && other.Foo == this.Foo;
}
}
public class EntityB
{
int Bar {get; set;}
EntityA Parent {get; set;}
public override bool Equals(object obj)
{
return (obj is EntityB other) && other.Bar == this.Bar;
}
}
public class InnerWrapper
{
public string FooBar {get; set;}
public EntityB BEntity {get; set;}
}
public class OuterClass
{
public EntityA AEntity { get; set;}
List<InnerWrapper> InnerElements {get; set;}
}
Now what I want is to have the References from EntityB to EntityA. They are in my case always the same. So what I expect is, that in the JSON in every EntityB the reference to EntityA is written as ref. The Equal of the Entities overwrites the Equals to check if they are the same. They are Database Objects, so that they are equals as soon as their ID is the same. In this case I've called them Foo
and Bar
.
What I've tried is as following:
public class MyEqualComparer : IEqualityComparer
{
public bool Equals(object x, object y)
{
return x.Equals(y);
}
public int GetHashCode(object obj)
{
return obj.GetHashCode();
}
}
with the following JSON Settings
public static readonly JsonSerializerSettings JsonSerializerSettings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All,
NullValueHandling = NullValueHandling.Ignore,
FloatParseHandling = FloatParseHandling.Decimal,
Formatting = Formatting.Indented,
PreserveReferencesHandling = PreserveReferencesHandling.Objects,
EqualityComparer = new MyEqualComparer(),
ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
Error = (sender, args) => Log.Error(args.ErrorContext.Error, $"Error while (de)serializing: {args.ErrorContext}; object: {args.CurrentObject}")
};
But it doesn't work. It compares totally wrong values. For example the EntityA from the OuterClass
with each of the InnerWrapper
. But not with the Properties or even Subproperties (in this case the Properties of the EntityB
of the InnerWrapper
).
With a custom ReferenceResolver, I've also no luck, because the settings above are really generic and I don't have any idea how to write a generic one.
Do you have any idea how to get this work?
// Edit:
Below an example what I expect:
{
"$id" : "1",
"AEntity": {
"$id": "2",
"Foo": 200
},
"InnerElements": [
{
"$id": "3",
"Bar": 20,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "4",
"Bar": 21,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "5",
"Bar": 23,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "6",
"Bar": 24,
"Parent": {
"$ref" : "2"
}
},
{
"$id": "7",
"Bar": 25,
"Parent": {
"$ref" : "2"
}
}
]
}
And this is what I get:
{
"$id" : "1",
"AEntity": {
"$id": "2",
"Foo": 200
},
"InnerElements": [
{
"$id": "3",
"Bar": 20,
"Parent": {
"$id": "8",
"Foo": 200
}
},
{
"$id": "4",
"Bar": 21,
"Parent": {
"$id": "9",
"Foo": 200
}
},
{
"$id": "5",
"Bar": 23,
"Parent": {
"$id": "10",
"Foo": 200
}
},
{
"$id": "6",
"Bar": 24,
"Parent": {
"$id": "11",
"Foo": 200
}
},
{
"$id": "7",
"Bar": 25,
"Parent": {
"$id": "12",
"Foo": 200
}
}
]
}
Of course, in this case, the impact is low. But my real scenario is much bigger.