How do I change property names based on type when serializing with Json.net?

I have a type property object

and I need to change the name depending on what type it is. Should be very similar [XmlElement("PropertyName", typeof(PropertyType))]

to XML.

For example, I have a property public object Item { get; set; }

If my property is of a type at run time Vehicle

, I want to change the name of my property to Vehicle; if it has a type Profile

, I want to change the name of my property to "Profile".

+3


source to share


1 answer


There is no built-in way to dynamically change a property name based on its runtime type, but you can create your own JsonConverter

in conjunction with a custom class Attribute

to do what you want. The transformer must be created to work at the class level in order to be able to manipulate the names of properties written in JSON. It can iterate over the properties of the target class using reflection and check if any property declared as has a object

custom attribute in use. If so, and the runtime type of the object matches the type specified in the attribute, use the property name from the attribute, otherwise just use the original property name.

The custom attribute would look like this:

[AttributeUsage(AttributeTargets.Property, AllowMultiple = true)]
class JsonPropertyNameByTypeAttribute : Attribute
{
    public string PropertyName { get; set; }
    public Type ObjectType { get; set; }

    public JsonPropertyNameByTypeAttribute(string propertyName, Type objectType)
    {
        PropertyName = propertyName;
        ObjectType = objectType;
    }
}

      

And here is the code for the converter:

public class DynamicPropertyNameConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        Type type = value.GetType();
        JObject jo = new JObject();

        foreach (PropertyInfo prop in type.GetProperties().Where(p => p.CanRead))
        {
            string propName = prop.Name;
            object propValue = prop.GetValue(value, null);
            JToken token = (propValue != null) ? JToken.FromObject(propValue, serializer) : JValue.CreateNull();

            if (propValue != null && prop.PropertyType == typeof(object))
            {
                JsonPropertyNameByTypeAttribute att = prop.GetCustomAttributes<JsonPropertyNameByTypeAttribute>()
                    .FirstOrDefault(a => a.ObjectType.IsAssignableFrom(propValue.GetType()));

                if (att != null)
                    propName = att.PropertyName;
            }

            jo.Add(propName, token);
        }

        jo.WriteTo(writer);
    }

    public override bool CanRead
    {
        get { return false; }
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        // ReadJson is not called if CanRead returns false.
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        // CanConvert is not called if a [JsonConverter] attribute is used
        return false;
    }
}

      

To use the converter, first add the attribute [JsonConverter]

to the target class that contains the property (or properties) you want to name dynamically. Then add your custom attribute to the target property (s) of that class. You can add as many attributes as needed to cover the range of types that you expect.



For example:

[JsonConverter(typeof(DynamicPropertyNameConverter))]
class Foo
{
    public int Id { get; set; }
    public string Name { get; set; }

    [JsonPropertyNameByType("Vehicle", typeof(Vehicle))]
    [JsonPropertyNameByType("Profile", typeof(Profile))]
    public object Item { get; set; }
}

      

Then serialize as usual:

string json = JsonConvert.SerializeObject(foo, Formatting.Indented);

      

Here is a working demo: https://dotnetfiddle.net/75HwrV

+5


source







All Articles