Reputation: 156
I have a question concerning NewtonSoft Json.Net Serialization. I have searched around but have not been able to find a solution. There are some question in SO that resemble this one by the title, but none present this scenario.
What i need is to prevent certain objects from being serialized under certain conditions.
Example: Given this class:
class A
{
B b;
}
We can prevent B from being serialized by writing:
class A
{
B b;
public bool ShouldSerializeb()
{
return false; //validate the condition you want.
}
}
But if we have multiple Bs, we end up having to write a function for each one:
class A
{
B b;
B bb;
B bbb;
public bool ShouldSerializeb()
{
return false; //validate the condition you want.
}
public bool ShouldSerializebb()
{
return false; //validate the condition you want.
}
public bool ShouldSerializebbb()
{
return false; //validate the condition you want.
}
}
There is another way: Use a Contract resolver
public class ShouldSerializeContractResolver : DefaultContractResolver
{
public new static readonly ShouldSerializeContractResolver Instance
= new ShouldSerializeContractResolver();
protected override JsonProperty CreateProperty(MemberInfo member,
MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType == typeof(B))
{
property.ShouldSerialize =
instance =>
{
if (instance == null)
return false;
// The problem is that "instance" here is A and not B
// preventing the necessary validation
return false; //validate the condition you want.
};
}
return property;
}
}
Questions:
Is there a way to have "instance be "B" in order to validate its internals?
Is there a way to write the function to validate the object itself and not the member? Something like this:
class B { public bool ShouldSerialize() { return false; //validate the condition you want. } }
Thank you (I probably should post this on github, but we are so used to concentrate question in SO)
Upvotes: 2
Views: 1940
Reputation: 129787
Yes, you can do this in the ContractResolver
. You have the instance
(of A
), and you have the property (of type B
), so you just need to ask the ValueProvider
on the property to give you the value from the instance. That is the B
that you seek. Then you can inspect the B
to decide whether or not to serialize the property.
So, for example, if class B
looked like this:
class B
{
public string Name { get; set; }
[JsonIgnore]
public bool IsHidden { get; set; }
}
You could decide in the resolver that you only want to serialize B
if IsHidden
is false:
protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
{
JsonProperty property = base.CreateProperty(member, memberSerialization);
if (property.PropertyType == typeof(B))
{
property.ShouldSerialize = instance =>
{
if (instance == null) return false;
B b = (B)property.ValueProvider.GetValue(instance);
// validate the condition you want, for example:
return b != null && !b.IsHidden;
};
}
return property;
}
Here is a working demo: https://dotnetfiddle.net/4MbQ0q
By the way, I'm fairly certain that the instance
passed to ShouldSerialize
will never be null, because it doesn't make sense to ask whether a property of A
should be serialized if there is no A
in the first place. It doesn't hurt to have the check in there, but I don't think you need it.
Upvotes: 1
Reputation: 9
Could you write two methods for ShouldSerialize?
public bool ShouldSerialize(typeof(B))
{
return false;
}
or write an overide within class B and call it as class B : A and then
Class B : A {
public overide bool ShouldSerialize()
{
return false;
}
}
Class A {
public bool ShouldSerialize(){
return true;
}
}
then call b.ShouldSerialize(); or bb.ShouldSerialize();
Worth a try, may have misunderstood the question but hey oh someone else will know in time.
Upvotes: 0