I've pored through the docs, StackOverflow, etc., can't seem to find this...
What I want to do is serialize/deserialize a simple value-type of object as a value, not an object, as so:
public class IPAddress { byte[] bytes; public override string ToString() {... etc. } public class SomeOuterObject { string stringValue; IPAddress ipValue; } IPAddress ip = new IPAddress("192.168.1.2"); var obj = new SomeOuterObject() {stringValue = "Some String", ipValue = ip}; string json = JsonConverter.SerializeObject(obj);
What I want is for the json to serialize like this:
// json = {"someString":"Some String","ipValue":"192.168.1.2"} <- value serialized as value, not subobject
Not where the ip becomes a nested object, ex:
// json = {"someString":"Some String","ipValue":{"value":"192.168.1.2"}}
Does anyone know how to do this? Thanks! (P.S. I am bolting Json serialization on a large hairy legacy .NET codebase, so I can't really change any existing types, but I can augment/factor/decorate them to facilitate Json serialization.)
In Deserialization, it does the opposite of Serialization which means it converts JSON string to custom . Net object. In the following code, it calls the static method DeserializeObject() of the JsonConvert class by passing JSON data. It returns a custom object (BlogSites) from JSON data.
JSON-Java is a Java serialization/deserialization library. It parses JSON documents into Java objects and generates new JSON documents from the Java classes.
A common way to deserialize JSON is to first create a class with properties and fields that represent one or more of the JSON properties. Then, to deserialize from a string or a file, call the JsonSerializer. Deserialize method.
You can handle this using a custom JsonConverter
for the IPAddress
class. Here is the code you would need:
public class IPAddressConverter : JsonConverter { public override bool CanConvert(Type objectType) { return (objectType == typeof(IPAddress)); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { return new IPAddress(JToken.Load(reader).ToString()); } public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { JToken.FromObject(value.ToString()).WriteTo(writer); } }
Then, add a [JsonConverter]
attribute to your IPAddress
class and you're ready to go:
[JsonConverter(typeof(IPAddressConverter))] public class IPAddress { byte[] bytes; public IPAddress(string address) { bytes = address.Split('.').Select(s => byte.Parse(s)).ToArray(); } public override string ToString() { return string.Join(".", bytes.Select(b => b.ToString()).ToArray()); } }
Here is a working demo:
class Program { static void Main(string[] args) { IPAddress ip = new IPAddress("192.168.1.2"); var obj = new SomeOuterObject() { stringValue = "Some String", ipValue = ip }; string json = JsonConvert.SerializeObject(obj); Console.WriteLine(json); } } public class SomeOuterObject { public string stringValue { get; set; } public IPAddress ipValue { get; set; } }
Output:
{"stringValue":"Some String","ipValue":"192.168.1.2"}
This is a answer to Customise NewtonSoft.Json for Value Object serialisation, in regards to value objects in DDD. But that question is marked as duplicate to this one, which i don't think is completely true.
I borrowed the code for the ValueObjectConverter from https://github.com/eventflow/EventFlow, I have only done minor changes.
using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using FluentAssertions; using Newtonsoft.Json; using Xunit; namespace Serialization { public class ValueObjectSerializationTests { class SomeClass { public IPAddress IPAddress { get; set; } } [Fact] public void FactMethodName() { var given = new SomeClass { IPAddress = new IPAddress("192.168.1.2") }; var jsonSerializerSettings = new JsonSerializerSettings() { Converters = new List<JsonConverter> { new ValueObjectConverter() } }; var json = JsonConvert.SerializeObject(given, jsonSerializerSettings); var result = JsonConvert.DeserializeObject<SomeClass>(json, jsonSerializerSettings); var expected = new SomeClass { IPAddress = new IPAddress("192.168.1.2") }; json.Should().Be("{\"IPAddress\":\"192.168.1.2\"}"); expected.ShouldBeEquivalentTo(result); } } public class IPAddress:IValueObject { public IPAddress(string value) { Value = value; } public object GetValue() { return Value; } public string Value { get; private set; } } public interface IValueObject { object GetValue(); } public class ValueObjectConverter : JsonConverter { private static readonly ConcurrentDictionary<Type, Type> ConstructorArgumenTypes = new ConcurrentDictionary<Type, Type>(); public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) { if (!(value is IValueObject valueObject)) { return; } serializer.Serialize(writer, valueObject.GetValue()); } public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) { var parameterType = ConstructorArgumenTypes.GetOrAdd( objectType, t => { var constructorInfo = objectType.GetConstructors(BindingFlags.Public | BindingFlags.Instance).First(); var parameterInfo = constructorInfo.GetParameters().Single(); return parameterInfo.ParameterType; }); var value = serializer.Deserialize(reader, parameterType); return Activator.CreateInstance(objectType, new[] { value }); } public override bool CanConvert(Type objectType) { return typeof(IValueObject).IsAssignableFrom(objectType); } } }
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