I have an object that looks something like this (obviously simplified)
public class Person {
public string Name { get; set; }
public int Age { get; set; }
public string ETag { get { return ... } }
}
What I would like is for ETag to be a hash of the json serialization of the object omitting the ETag property (to prevent a recursive loop). However, I cannot just use a [JsonIgnore]
attribute since at other times I want to be able to json serialize the entire thing.
So what I want is something like this
public string ETag { get {
return Hash(JsonConvert.Serialize(this, p => p.Ignore(x=>x.ETag) ));
}}
which is unfortunately not an API that exists. How would I achieve something similar?
You can use a custom IContractResolver
to programmatically ignore properties on an object. So I think the approach I would take is to create a simple resolver that can specifically ignore a single property on a single type (obviously you could extend this if needed), then make a helper method that can serialize using that resolver. Use the helper method from within your ETag
property and you're good to go.
Here's the code for the resolver:
class IgnorePropertyResolver : DefaultContractResolver
{
Type targetType;
string targetPropertyName;
public IgnorePropertyResolver(Type targetType, string propertyName)
{
this.targetType = targetType;
this.targetPropertyName = propertyName;
}
protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
{
IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);
if (targetType == type)
{
props = props.Where(p => p.PropertyName != targetPropertyName).ToList();
}
return props;
}
}
Here's the helper method (I also threw a Hash helper method in there since you had not defined it in your question):
static class JsonHelper
{
public static string Serialize(object target, string propertyToIgnore)
{
JsonSerializerSettings settings = new JsonSerializerSettings();
settings.ContractResolver = new IgnorePropertyResolver(target.GetType(), propertyToIgnore);
return JsonConvert.SerializeObject(target, settings);
}
public static string Hash(string json)
{
using (var sha = new SHA1Managed())
{
return Convert.ToBase64String(sha.ComputeHash(Encoding.UTF8.GetBytes(json)));
}
}
}
And finally, here's a working demo:
class Program
{
static void Main(string[] args)
{
Person p = new Person { Name = "Joe", Age = 26 };
Console.WriteLine("Etag = " + p.ETag);
Console.WriteLine();
Console.WriteLine(JsonConvert.SerializeObject(p, Formatting.Indented));
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public string ETag
{
get { return JsonHelper.Hash(JsonHelper.Serialize(this, "ETag")); }
}
}
Output:
Etag = T99YVDlrbZ66YL2u5MYjyIyO4Qk=
{
"Name": "Joe",
"Age": 26,
"ETag": "T99YVDlrbZ66YL2u5MYjyIyO4Qk="
}
Fiddle: https://dotnetfiddle.net/YgVJ4K
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With