json.net – how to add property $type ONLY on root object

If you require the "$type" property on your root object and are OK with it appearing on nested polymorphic objects and arrays if required, use the following overload along with TypeNameHandling.Auto: JsonConvert.SerializeObject(Object, Type, JsonSerializerSettings).

From the docs:

public static string SerializeObject(
    Object value,
    Type type,
    JsonSerializerSettings settings
)

type
Type: System.Type
The type of the value being serialized. This parameter is used when TypeNameHandling is Auto to write out the type name if the type of the value does not match. Specifing the type is optional.

I.e., do:

var serializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.Auto,
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
    Formatting = Formatting.Indented
};

var event1Serialized = JsonConvert.SerializeObject(event1, typeof(IEvent), serializerSettings);

If you require "$type" on the root object and will not accept it on nested polymorphic objects and arrays even if otherwise required, you will need to use TypeNameHandling.All along with a custom contract resolver that sets JsonContainerContract.ItemTypeNameHandling = TypeNameHandling.None:

public class SuppressItemTypeNameContractResolver : DefaultContractResolver
{
    protected override JsonContract CreateContract(Type objectType)
    {
        var contract = base.CreateContract(objectType);
        var containerContract = contract as JsonContainerContract;
        if (containerContract != null)
        {
            if (containerContract.ItemTypeNameHandling == null)
                containerContract.ItemTypeNameHandling = TypeNameHandling.None; 
        }
        return contract;
    }
}

Then use it like:

static IContractResolver suppressItemTypeNameContractResolver = new SuppressItemTypeNameContractResolver();

var serializerSettings = new JsonSerializerSettings()
{
    TypeNameHandling = TypeNameHandling.All,
    ContractResolver = suppressItemTypeNameContractResolver,
    // Other settings as required.
    TypeNameAssemblyFormat = System.Runtime.Serialization.Formatters.FormatterAssemblyStyle.Simple,
    NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore,
    Formatting = Formatting.Indented
};
var event1Serialized = JsonConvert.SerializeObject(event1, serializerSettings);

Notes:

Leave a Comment