2

Sometimes I need to suppress output of "$type" properties by Json.NET even when specified by JsonPropertyAttribute.ItemTypeNameHandling. How can this be done?

My root class looks like below:

public class DomainResource
{
    [JsonProperty(ItemTypeNameHandling = TypeNameHandling.Auto)]
    public List<Extension> Extensions { get; set; }
}

And in addition I have a class hierarchy for Extension such as the following:

public class Extension
{
    readonly string url;

    public string Url { get { return url; } }

    public Extension(string url)
    {
        this.url = url;
    }
}

public class IntegerExtension : Extension
{
    public IntegerExtension(string url) : base(url) { }

    [JsonProperty("ValueInteger")]
    public int Value { get; set; }
}

I want to ignore ItemTypeNameHandling in certain scenarios during serialization, but I am not able to find a way to do that. I tried setting JsonSerializerSettings with TypeNameHandling.None as input for jsonconvert when I do not want "$type" properties using the code below:

public static string SerializeObject(object value)
{
    JsonSerializerSettings jsonSettings = new JsonSerializerSettings
    {
        ContractResolver = new CamelCasePropertyNamesContractResolver(),
        NullValueHandling = NullValueHandling.Ignore,
        TypeNameHandling = TypeNameHandling.None,

    };
    jsonSettings.Converters.Add(new StringEnumConverter
    {
        CamelCaseText = true
    });
    return JsonConvert.SerializeObject(value, Formatting.None, jsonSettings);
}

And then use it as follows:

var res = new DomainResource();
res.Extensions = new List<Extension>();
res.Extensions.Add(new IntegerExtension("ewwer"){Value = 3});

var x = CustomJsonConvert.SerializeObject(res);

My desired JSON is:

{"extensions":[{"valueInteger":3,"url":"ewwer"}]}

But instead it contains "$type" properties as shown below:

{"extensions":[{"$type":"DicomtoJsonConverter.IntegerExtension, DicomtoJsonConverter","valueInteger":3,"url":"ewwer"}]}

How can I suppress output of "$type" properties without changing DomainResource class?

dbc
  • 104,963
  • 20
  • 228
  • 340
ankush
  • 949
  • 2
  • 14
  • 33

1 Answers1

1

You can use a custom ContractResolver to suppress output of type information even when specified by JsonPropertyAttribute.TypeNameHandling, JsonPropertyAttribute.ItemTypeNameHandling or JsonContainerAttribute.ItemTypeNameHandling. First, define the following contract resolver:

public class NoTypeNameHandlingContractResolver : DefaultContractResolver
{
    protected override JsonProperty CreateProperty(MemberInfo member, MemberSerialization memberSerialization)
    {
        var property = base.CreateProperty(member, memberSerialization);
        // Suppress JsonPropertyAttribute.TypeNameHandling
        property.TypeNameHandling = null;
        // Suppress JsonPropertyAttribute.ItemTypeNameHandling
        property.ItemTypeNameHandling = null;
        return property;
    }

    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        if (contract is JsonContainerContract)
        {
            // Suppress JsonContainerAttribute.ItemTypeNameHandling
            ((JsonContainerContract)contract).ItemTypeNameHandling = null;
        }
        return contract;
    }
}

Then, modify CustomJsonConvert.SerializeObject() as follows:

public static class CustomJsonConvert
{
    // You may want to cache the contract resolver for best performance, see
    // https://stackoverflow.com/questions/33557737/does-json-net-cache-types-serialization-information
    static readonly JsonSerializerSettings jsonSettings;
    static CustomJsonConvert()
    {
        jsonSettings = new JsonSerializerSettings
        {
            ContractResolver = new NoTypeNameHandlingContractResolver
            {
                NamingStrategy = new CamelCaseNamingStrategy
                {
                    // These are the settings used by CamelCasePropertyNamesContractResolver by default.
                    // Change them if this is not what you want.
                    OverrideSpecifiedNames = true,
                    ProcessDictionaryKeys = true,
                },
            },
            NullValueHandling = NullValueHandling.Ignore,
            TypeNameHandling = TypeNameHandling.None,
            Converters = { new StringEnumConverter { CamelCaseText = true } },
        };
    }

    public static string SerializeObject(object value)
    {
        return JsonConvert.SerializeObject(value, Formatting.None, jsonSettings);
    }
}

If you are using a version of Json.NET that predates 9.0.1 you will need to subclass CamelCasePropertyNamesContractResolver rather than subclassing DefaultContractResolver since NamingStrategy was introduced in that release.

dbc
  • 104,963
  • 20
  • 228
  • 340