using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Converters;
using Newtonsoft.Json.Serialization;
using static System.Net.Mime.MediaTypeNames;
public class ProtoBufInput
public string Id { get; set; }
public Building BuildingObj { get; set; }
public byte[] Payload { get; set; }
public ProtoBufInput(string id, Building buildingObj, byte[] payload)
BuildingObj = buildingObj;
public class ProtoBufResult
public int RandomNumber { get; set; }
public bool RandomBool { get; set; }
public IList<string> ErrorMessages { get; set; }
public Building BuildingObj { get; set; }
public string RandomString { get; set; }
public class Building : Component<BuildingMetadata>
public string Id { get; set; }
public string tag { get; set; }
public class BuildingMetadata : ComponentMetadata
public BuildingType Type { get; set; }
public bool IsAttached { get; set; }
public override object Clone()
var baseClone = base.Clone() as ComponentMetadata;
return new BuildingMetadata()
PropertyMetadata = baseClone.PropertyMetadata,
public class ComponentMetadata : ICloneable
public string Model { get; set; }
public IDictionary<string, PropertyMetadata> PropertyMetadata { get; set; } = new Dictionary<string, PropertyMetadata>();
public virtual object Clone()
return new ComponentMetadata()
PropertyMetadata = PropertyMetadata.ToDictionary(kvp => kvp.Key, kvp => kvp.Value.Clone() as PropertyMetadata),
public class PropertyMetadata : ICloneable
string SerializedValue { get => Value == null ? null : JsonConvert.SerializeObject(Value); set => Value = (value == null ? null : JsonConvert.DeserializeObject<JToken>(value)); }
public JToken Value { get; set; }
[JsonProperty("Version")]
public int Version { get; set; }
[JsonProperty("backVersion")]
public int BackVersion { get; set; }
[JsonProperty("backCode")]
public int BackCode { get; set; }
[JsonProperty("Description")]
public string Description { get; set; }
[JsonProperty("createTime")]
public string CreateTime { get; set; }
return new PropertyMetadata()
CreateTime = CreateTime ?? DateTime.UtcNow.ToString("o"),
public interface IComponent
ComponentMetadata GetMetadata();
IEnumerable<(string name, IComponent component)> ListComponents();
IEnumerable<(string name, JToken property)> ListProperties();
bool TryGetProperty(string name, out JToken property);
bool TryGetComponent(string name, out IComponent component);
public class Component<TMetadataType> : ComponentBase, IComponent where TMetadataType : ComponentMetadata, new()
public TMetadataType Metadata { get; set; } = new TMetadataType();
public string Model => Metadata.Model;
public IEnumerable<(string, IComponent)> ListComponents() => Components.Select(x => (x.Key, x.Value as IComponent));
public IEnumerable<(string, JToken)> ListProperties() => Properties.Select(x => (x.Key, x.Value));
public ComponentMetadata GetMetadata() => Metadata;
public bool TryGetComponent(string name, out IComponent component)
if (!Components.TryGetValue(name, out var innerComponent))
component = innerComponent as IComponent;
public bool TryGetProperty(string name, out JToken property) => Properties.TryGetValue(name, out property);
public class ComponentBase
string SerializedProperties { get => Properties == null ? null : JsonConvert.SerializeObject(Properties); set => Properties = (value == null ? null : JsonConvert.DeserializeObject<Dictionary<string, JToken>>(value)); }
public IDictionary<string, JToken> Properties { get; set; } = new Dictionary<string, JToken>();
public IDictionary<string, InnerComponent> Components { get; set; } = new Dictionary<string, InnerComponent>();
public class InnerComponent : Component<ComponentMetadata>
public string tag { get; set; }
public static void Test()
static void TestBuilding()
PropertyMetadata propertyMetaData = new()
Value = JToken.Parse(GetJson()),
Description = "description",
CreateTime = "9/19/2022",
Metadata = new BuildingMetadata()
PropertyMetadata = new Dictionary<string, PropertyMetadata>()
{ "propKey1", propertyMetaData },
["foo"] = JToken.Parse(GetJson()),
using var stream = new MemoryStream();
Serializer.Serialize(stream, test1);
var test2 = Serializer.Deserialize<Building>(stream);
Assert.That(test1.Id.Equals(test2.Id));
Assert.That(test1.tag.Equals(test2.tag));
Assert.That(JToken.DeepEquals(test1.Metadata.PropertyMetadata["propKey1"].Value, test1.Metadata.PropertyMetadata["propKey1"].Value));
Assert.That(test1.Properties.Values.Zip(test2.Properties.Values).All(p => JToken.DeepEquals(p.Item1, p.Item2)));
static void TestPropertyMetadata()
PropertyMetadata test1 = new()
Value = JToken.Parse(GetJson()),
Description = "description",
CreateTime = "9/19/2022",
using var stream = new MemoryStream();
Serializer.Serialize(stream, test1);
var test2 = Serializer.Deserialize<PropertyMetadata>(stream);
Assert.AreEqual(JsonConvert.SerializeObject(test1), JsonConvert.SerializeObject(test2));
Assert.That(JToken.DeepEquals(test1.Value, test2.Value));
static void TestComponentBase()
ComponentBase test1 = new()
["foo"] = JToken.Parse(GetJson()),
using var stream = new MemoryStream();
Serializer.Serialize(stream, test1);
var test2 = Serializer.Deserialize<ComponentBase>(stream);
Assert.That(test1.Properties.Keys.SequenceEqual(test2.Properties.Keys));
Assert.That(test1.Properties.Values.Zip(test2.Properties.Values).All(p => JToken.DeepEquals(p.Item1, p.Item2)));
Assert.AreEqual(JsonConvert.SerializeObject(test1), JsonConvert.SerializeObject(test2));
public static string GetJson() => @"{""ccc"":"""",""ccc_file_name"":"""",""consent_id"":""120266"",""council_code"":""DEMO"",""date_cccissued"":null,""date_granted"":null,""date_issued"":null,""date_lodged"":""2012-05-03T00:00:00"",""days_inactive"":null,""days_live"":null,""days_suspended"":null,""form6_received"":null,""inspections"":""In Progress"",""issued"":"""",""last_updated"":null,""lodged"":""Accepted"",""processing"":"""",""rfis"":""Pending""}";
public static void Main()
Console.WriteLine("Environment version: {0} ({1}), {2}", System.Runtime.InteropServices.RuntimeInformation.FrameworkDescription, Environment.Version, Environment.OSVersion);
Console.WriteLine("{0} version: {1}", typeof(JsonSerializer).Namespace, typeof(JsonSerializer).Assembly.FullName);
Console.WriteLine("Failed with unhandled exception: ");