1

I have a specific situation where I need to include the class name as property in JSON when classes are serialized. The tricky parts is I need to do this dynamically. I can't just create an anonymous class before calling serialization.

I have decorated my class with a custom attribute as below:

 [OntologyArea("con", " http://someurl/area/DomicileAddress")]
    public class DomicileAddress : IContactPoint
    {

        [JsonProperty(PropertyName = "con:hasAddressPoint")]
        public IAddressPoint AddressPoint
        {
            get; set;
        }
    }

In the above example the OntologyArea attribute should be read and included as a Property. The propery name should be the first argument of OntologyArea + the class name (i.e con:DomicileAddress) and the value should be the concrete class of IAddressPoint.

The tricky part is that the concrete class of IAddressPoint might need to do the same as shown here:

[OntologyArea("geo", "http://someurl.net/geolocation")]
    public class StreetAddress : IAddressPoint
    {
        [JsonProperty("geo:hasStartingStreetNumber")]
        public string StartingStreetNumber
        {
            get; set;
        }
    }

an example of JSON:

"con:DomicileAddress" : {
    "con:hasAddressPoint" : {
        "geo:StreetAddress" : {
            "geo:hasEndingStreetNumber" : ""
        }
    }
}

So if any object does have a OntologyArea attribute I need to add a parent level. If it does not contain this attribute normal serilization should continue.

Please let me know If I need to explain more.

JohnJackson
  • 95
  • 3
  • 9
  • Possible duplicate of [Json.NET serialize object with root name](https://stackoverflow.com/questions/16294963/json-net-serialize-object-with-root-name) – MX D Feb 14 '18 at 09:19
  • I can't use a dynamic object as this must done on runtime. But thanks for suggestion. – JohnJackson Feb 14 '18 at 09:33

2 Answers2

1

Is this solution for specifying the concrete type is a must or is it just your proposed solution?

Because Json.NET has a built-in support for encoding the actual types for properties of interface types or base classes:

var json = JsonConvert.SerializeObject(myContract, new JsonSerializerSettings { TypeNameHandling = TypeNameHandling.Auto });

If you really need a completely custom logic you have to implement a converter, which also can be passed to the JsonSerializerSettings. It must be derived from JsonConverter and you have to implement the WriteJson method to emit your desired json sting using low level tokens just like in case of an XmlWriter:

private class MyConverter : JsonConverter
{
    public override bool CanConvert(Type objectType)
    {
        return typeof(IAddressPoint).IsAssignableFrom(objectType);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        var address = (IAddressPoint)value;

        writer.WriteStartObject(); // {
        writer.WritePropertyName($"geo:{address.GetType().Name}"); // "geo:StreetAddress"
        // ... etc.
        writer.WriteEndObject(); // }

        // or you can just emit raw string:
        writer.WriteRaw(myJsonBody);
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, 
    {
        // todo: and the deserialization part goes here
    }
}
György Kőszeg
  • 17,093
  • 6
  • 37
  • 65
  • I must support concrete types. Where do I put this JsonConverter attribute? On the Interface of IAddressPoint? And If I have another Interface I will create a custom converter for that interface as well? Thanks. – JohnJackson Feb 14 '18 at 10:43
  • You can put that above the property but it is not needed. You can pass a collection of converters to the serializer settings and then `CanConvert` will be called for each property. By returning `true` for multiple types you can use a single converter for all of the custom types. But then in `WriteJson` the `value` can have any of these types and you must handle all of them. – György Kőszeg Feb 14 '18 at 11:16
  • Is it possible for you to make a more detailed example? That will be very great.. – JohnJackson Feb 14 '18 at 12:10
0

This pointed me in the correct direction. I have an attribute that is read in this class and appended to the writer object.

JohnJackson
  • 95
  • 3
  • 9