How to serialize everything except a specific property in one specific serialization

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 ... } } } 

I would like ETag to be a serialization hash of a json object that does not have an ETag property (to prevent a recursive loop). However, I cannot just use the [JsonIgnore] attribute, as in other cases I want json to serialize the whole thing.

So I want something like this

 public string ETag { get { return Hash(JsonConvert.Serialize(this, p => p.Ignore(x=>x.ETag) )); }} 

which, unfortunately, is not an API that exists. How can I achieve something like this?

+6
source share
2 answers

You can use a custom IContractResolver to programmatically ignore object properties. Therefore, I think the approach I would like to take is to create a simple resolver that can specifically ignore one property for one type (obviously, you could extend it if necessary), and then create a helper method that can serialize using this resolver. Use the helper method from your ETag property, and you're good to go.

Here is the code for the recognizer:

 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 a helper method (I also threw a Hash hash method there, since you did not define 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

+5
source

This is not very good, but you can use string replacement after JSON serialization. You can set the ETag to a marker value so that after serialization you can replace / remove this element.

0
source

Source: https://habr.com/ru/post/976077/


All Articles