JohnJackson
JohnJackson

Reputation: 87

Include Class name as part of the serialization in JSON C#

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.

Upvotes: 1

Views: 6837

Answers (2)

JohnJackson
JohnJackson

Reputation: 87

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

Upvotes: 0

György Kőszeg
György Kőszeg

Reputation: 18013

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
    }
}

Upvotes: 1

Related Questions