Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Json.net how to serialize object as value

Tags:

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

like image 788
androticus Avatar asked Jun 29 '14 01:06

androticus


People also ask

How do you serialize and deserialize an object in C# using JSON?

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.

Is JSON object serializable?

JSON-Java is a Java serialization/deserialization library. It parses JSON documents into Java objects and generates new JSON documents from the Java classes.

How do I deserialize JSON?

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.


2 Answers

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"} 
like image 188
Brian Rogers Avatar answered Oct 02 '22 04:10

Brian Rogers


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);         }     } } 
like image 25
Lejdholt Avatar answered Oct 02 '22 05:10

Lejdholt