Adding a custom type name to all classes when serialized using Json.NET

I have a requirement to add a type property for each serialization of an I object using Json.Net. I understand that Json.Net already supports this out of the box, but in my case the type name should exclude the assembly, and the property name should be customizable (none of them are supported).

I currently have this:

public class TypeConverter : JsonConverter
{
    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serialiser)
    {
        JObject jObject = JObject.FromObject(value, serializer);
        jObject.AddFirst(new JProperty("myCustomTypePropertyName"), value.GetType().Name);
        jObject.WriteTo(writer);
    }

    public override void ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serialiser)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return objectType.IsClass;
    }
}

This works for an external type that is serialized, but unfortunately the converter is not called for nested objects. If I add a serializer to the JObject.FromObject call, I get a self-regulation loop exception when it tries to re-enter the converter for the external type.

, , - serializer, , .

; , - .

(: .NET 3.5, SerializationBinders .)

+4
1

, . JsonConverter, , , . JsonConverters ; . , , , IContractResolver.

. , "type name" ( , , ) IValueProvider, , . ( , , .)

- DefaultContractResolver, Json.Net. CreateProperties() , .

:

class CustomResolver : DefaultContractResolver
{
    private string customTypePropertyName;
    private IValueProvider valueProvider = new SimpleTypeNameProvider();

    public CustomResolver(string customTypePropertyName)
    {
        this.customTypePropertyName = customTypePropertyName;
    }

    protected override IList<JsonProperty> CreateProperties(Type type, MemberSerialization memberSerialization)
    {
        IList<JsonProperty> props = base.CreateProperties(type, memberSerialization);

        if (type.IsClass && type != typeof(string))
        {
            // Add a phantom string property to every class which will resolve 
            // to the simple type name of the class (via the value provider)
            // during serialization.
            props.Insert(0, new JsonProperty
            {
                DeclaringType = type,
                PropertyType = typeof(string),
                PropertyName = customTypePropertyName,
                ValueProvider = valueProvider,
                Readable = true,
                Writable = false
            });
        }

        return props;
    }

    class SimpleTypeNameProvider : IValueProvider
    {
        public object GetValue(object target)
        {
            return target.GetType().Name;
        }

        public void SetValue(object target, object value)
        {
            return;
        }
    }
}

, JsonSerializerSettings. :

class Program
{
    static void Main(string[] args)
    {
        Person p = new Person
        {
            Id = 2,
            Name = "Peter",
            Employer = new Company
            {
                Id = 5,
                Name = "Initech"
            }
        };

        JsonSerializerSettings settings = new JsonSerializerSettings
        {
            ContractResolver = new CustomResolver("MyTypeName"),
            Formatting = Formatting.Indented
        };

        string json = JsonConvert.SerializeObject(p, settings);

        Console.WriteLine(json);
    }
}

class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public Company Employer { get; set; }
}

class Company
{
    public int Id { get; set; }
    public string Name { get; set; }
}

:

{
  "MyTypeName": "Person",
  "Id": 2,
  "Name": "Peter",
  "Employer": {
    "MyTypeName": "Company",
    "Id": 5,
    "Name": "Initech"
  }
}
+5

Source: https://habr.com/ru/post/1544222/


All Articles