daily pastebin goal
19%
SHARE
TWEET

Untitled

a guest Dec 10th, 2018 60 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. public abstract class ReferenceHandlingCustomCreationConverter<T> : JsonConverter where T : class
  2. {
  3.     const string refProperty = "$ref";
  4.     const string idProperty = "$id";
  5.  
  6.     public override bool CanConvert(Type objectType)
  7.     {
  8.         return typeof(T).IsAssignableFrom(objectType);
  9.     }
  10.  
  11.     protected virtual T Create(Type objectType, T existingValue, JsonSerializer serializer, JObject obj)
  12.     {
  13.         return existingValue ?? (T)serializer.ContractResolver.ResolveContract(objectType).DefaultCreator();
  14.     }
  15.  
  16.     protected abstract void Populate(JObject obj, T value, JsonSerializer serializer);
  17.  
  18.     protected abstract void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract);
  19.  
  20.     public override sealed object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
  21.     {
  22.         var contract = serializer.ContractResolver.ResolveContract(objectType);
  23.         if (!(contract is JsonObjectContract))
  24.         {
  25.             throw new JsonSerializationException(string.Format("Invalid non-object contract type {0}", contract));
  26.         }
  27.         if (!(existingValue == null || existingValue is T))
  28.         {
  29.             throw new JsonSerializationException(string.Format("Converter cannot read JSON with the specified existing value. {0} is required.", typeof(T)));
  30.         }
  31.  
  32.         if (reader.MoveToContent().TokenType == JsonToken.Null)
  33.             return null;
  34.         var obj = JObject.Load(reader);
  35.  
  36.         var refId = (string)obj[refProperty].RemoveFromLowestPossibleParent();
  37.         var objId = (string)obj[idProperty].RemoveFromLowestPossibleParent();
  38.         if (refId != null)
  39.         {
  40.             var reference = serializer.ReferenceResolver.ResolveReference(serializer, refId);
  41.             if (reference != null)
  42.                 return reference;
  43.         }
  44.  
  45.         var value = Create(objectType, (T)existingValue, serializer, obj);
  46.  
  47.         if (objId != null)
  48.         {
  49.             // Add the empty array into the reference table BEFORE poppulating it, to handle recursive references.
  50.             serializer.ReferenceResolver.AddReference(serializer, objId, value);
  51.         }
  52.  
  53.         Populate(obj, value, serializer);
  54.  
  55.         return value;
  56.     }
  57.  
  58.     public override sealed void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
  59.     {
  60.         var contract = serializer.ContractResolver.ResolveContract(value.GetType());
  61.         if (!(contract is JsonObjectContract))
  62.         {
  63.             throw new JsonSerializationException(string.Format("Invalid non-object contract type {0}", contract));
  64.         }
  65.         if (!(value is T))
  66.         {
  67.             throw new JsonSerializationException(string.Format("Converter cannot read JSON with the specified existing value. {0} is required.", typeof(T)));
  68.         }
  69.  
  70.         writer.WriteStartObject();
  71.  
  72.         if (serializer.ReferenceResolver.IsReferenced(serializer, value))
  73.         {
  74.             writer.WritePropertyName(refProperty);
  75.             writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
  76.         }
  77.         else
  78.         {
  79.             writer.WritePropertyName(idProperty);
  80.             writer.WriteValue(serializer.ReferenceResolver.GetReference(serializer, value));
  81.  
  82.             WriteProperties(writer, (T)value, serializer, (JsonObjectContract)contract);
  83.         }
  84.  
  85.         writer.WriteEndObject();
  86.     }
  87. }
  88.  
  89. public static partial class JsonExtensions
  90. {
  91.     public static JsonReader MoveToContent(this JsonReader reader)
  92.     {
  93.         if (reader.TokenType == JsonToken.None)
  94.             reader.Read();
  95.         while (reader.TokenType == JsonToken.Comment && reader.Read())
  96.             ;
  97.         return reader;
  98.     }
  99.  
  100.     public static JToken RemoveFromLowestPossibleParent(this JToken node)
  101.     {
  102.         if (node == null)
  103.             return null;
  104.         var contained = node.AncestorsAndSelf().Where(t => t.Parent is JContainer && t.Parent.Type != JTokenType.Property).FirstOrDefault();
  105.         if (contained != null)
  106.             contained.Remove();
  107.         // Also detach the node from its immediate containing property -- Remove() does not do this even though it seems like it should
  108.         if (node.Parent is JProperty)
  109.             ((JProperty)node.Parent).Value = null;
  110.         return node;
  111.     }
  112. }
  113.    
  114. protected abstract void Populate(JObject obj, T value, JsonSerializer serializer);
  115.  
  116. protected abstract void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract);
  117.    
  118. public class DefaultReferenceHandlingCustomCreationConverter<T> : ReferenceHandlingCustomCreationConverter<T> where T : class
  119. {
  120.     protected override void Populate(JObject obj, T value, JsonSerializer serializer)
  121.     {
  122.         using (var reader = obj.CreateReader())
  123.             serializer.Populate(reader, value);
  124.     }
  125.  
  126.     protected override void WriteProperties(JsonWriter writer, T value, JsonSerializer serializer, JsonObjectContract contract)
  127.     {
  128.         foreach (var property in contract.Properties.Where(p => p.Writable && !p.Ignored))
  129.         {
  130.             // TODO: handle JsonProperty attributes including
  131.             // property.Converter, property.IsReference, property.ItemConverter, property.ItemReferenceLoopHandling,
  132.             // property.ItemReferenceLoopHandling, property.ObjectCreationHandling, property.ReferenceLoopHandling, property.Required                            
  133.             var itemValue = property.ValueProvider.GetValue(value);
  134.             writer.WritePropertyName(property.PropertyName);
  135.             serializer.Serialize(writer, itemValue);
  136.         }
  137.     }
  138. }
  139.    
  140. var settings = new JsonSerializerSettings
  141. {
  142.     Converters = { new DefaultReferenceHandlingCustomCreationConverter<RootObject>() },
  143.     ReferenceLoopHandling = ReferenceLoopHandling.Serialize,
  144. };
  145. var json = JsonConvert.SerializeObject(parent, Formatting.Indented, settings);
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top