When using Json.Net, I understand how to get the $type property into the rendered json, but is there a way to change that field name? I need to use "__type" instead of "$type".
-
I need this too, for example [JSON-LD](http://json-ld.org) uses `@type` – Hendy Irawan Jan 09 '15 at 04:02
8 Answers
http://json.codeplex.com/workitem/22429
"I would rather keep $type hard coded and consistent."
Consistent with what I wonder?
http://json.codeplex.com/workitem/21989
I would rather not - I think this is too specific to me and I don't want to go overboard with settings. At some point I will probably implement this - http://json.codeplex.com/workitem/21856 - allowing people to read/write there own meta properties in the JSON and you could reimplement type name handling with a new property name. The other option is just to modify the source code for yourself to have that property name.
And more recently, Issue #36: Customizable $type property name feature:
I'd rather not
This is my solution...
json.Replace("\"$type\": \"", "\"type\": \"");

- 104,963
- 20
- 228
- 340

- 15,170
- 23
- 107
- 189
-
1
-
And still more recently (JamesNK closed this Jun 11, 2017): [Be able to support custom inheritance discriminator field #1331](https://github.com/JamesNK/Newtonsoft.Json/issues/1331). – dbc Jun 11 '21 at 14:02
Looks like this is hardcoded as public const string TypePropertyName = "$type";
in Newtonsoft.Json.Serialization.JsonTypeReflector
which is internal static class unfortunately.
I needed this myself, and the only thing I can think of is having custom modified version of json.net itself. Which is of course is a major pita.

- 3,531
- 1
- 24
- 25
-
4Unfortunately, I have pretty much had to completely abandon the path I was headed down because of how hard Json.Net is to use in many cases. This is just one example. – Brian McCord Feb 29 '12 at 19:24
-
I am myself looking of how I on the server-side, that is written i C# and uses Json.NET, can deserialize JSON sent from an Android app using Jackson. In Jackson I can setup to use "$type", but it doesnt work anyway. – Ted Jan 06 '13 at 22:59
I had to do this for my UI REST API as Angular.js disregards fields names starting with a dollar sign ($).
So here's a solution that renames $type
to __type
for the whole Web API and works both for serialization and deserialization.
In order to be able to use a custom JsonWriter
and a custom JsonReader
(as proposed in the other answers to this question), we have to inherit the JsonMediaTypeFormatter
and override the corresponding methods:
internal class CustomJsonNetFormatter : JsonMediaTypeFormatter
{
public override JsonReader CreateJsonReader(Type type, Stream readStream, Encoding effectiveEncoding)
{
return new CustomJsonReader(readStream, effectiveEncoding);
}
public override JsonWriter CreateJsonWriter(Type type, Stream writeStream, Encoding effectiveEncoding)
{
return new CustomJsonWriter(writeStream, effectiveEncoding);
}
private class CustomJsonWriter : JsonTextWriter
{
public CustomJsonWriter(Stream writeStream, Encoding effectiveEncoding)
: base(new StreamWriter(writeStream, effectiveEncoding))
{
}
public override void WritePropertyName(string name, bool escape)
{
if (name == "$type") name = "__type";
base.WritePropertyName(name, escape);
}
}
private class CustomJsonReader : JsonTextReader
{
public CustomJsonReader(Stream readStream, Encoding effectiveEncoding)
: base(new StreamReader(readStream, effectiveEncoding))
{
}
public override bool Read()
{
var hasToken = base.Read();
if (hasToken && TokenType == JsonToken.PropertyName && Value != null && Value.Equals("__type"))
{
SetToken(JsonToken.PropertyName, "$type");
}
return hasToken;
}
}
}
Of course you need to register the custom formatter in your WebApiConfig
. So we replace the default Json.NET formatter with our custom one:
config.Formatters.Remove(config.Formatters.JsonFormatter);
config.Formatters.Add(new CustomJsonNetFormatter());
Done.
-
I like this solution! With a small customization I no longer have to use the lengthy types names _Namespace.Type, AssemblyName_ but can also rewrite this ;-) – t3chb0t Jun 30 '18 at 07:44
when serializing, there is a nice way to override the property name:
public class CustomJsonWriter : JsonTextWriter
{
public CustomJsonWriter(TextWriter writer) : base(writer)
{
}
public override void WritePropertyName(string name, bool escape)
{
if (name == "$type") name = "__type";
base.WritePropertyName(name, escape);
}
}
var serializer = new JsonSerializer();
var writer = new StreamWriter(stream) { AutoFlush = true };
serializer.Serialize(new CustomJsonWriter(writer), objectToSerialize);
I haven't tried deserialization yet, but in worst case I could use:
json.Replace("\"__type": \"", "\"type\": \"$type\");

- 25,216
- 29
- 151
- 297
-
Do you have a similar solution for the reader? I am trying to deserialise objects, but the $types in my Json are pretty uggly/complicated and would like to rename them. Thanks :-) – toughQuestions Sep 11 '20 at 14:09
We had a need for this so I created a custom JsonReader. We're are using rest in our MS web services with complex data models and needed to replace the "__type" property with "$type."
class MSJsonReader : JsonTextReader
{
public MSJsonTextReader(TextReader reader) : base(reader) { }
public override bool Read()
{
var hasToken = base.Read();
if (hasToken && base.TokenType == JsonToken.PropertyName && base.Value != null && base.Value.Equals("__type"))
base.SetToken(JsonToken.PropertyName, "$type");
return hasToken;
}
}
Here is how we use it.
using(JsonReader jr = new MSJsonTextReader(sr))
{
JsonSerializer s = new JsonSerializer();
s.DateFormatHandling = DateFormatHandling.MicrosoftDateFormat;
s.NullValueHandling = NullValueHandling.Ignore;
s.TypeNameHandling = TypeNameHandling.Auto; // Important!
s.Binder = new MSRestToJsonDotNetSerializationBinder("Server.DataModelsNamespace", "Client.GeneratedModelsNamespace");
T deserialized = s.Deserialize<T>(jr);
return deserialized;
}
Here is our MSRestToJsonDotNetSerializationBinder that completes the compatibility between MS rest and Json.Net.
class MSRestToJsonDotNetSerializationBinder : System.Runtime.Serialization.SerializationBinder
{
public string ServiceNamespace { get; set; }
public string LocalNamespace { get; set; }
public MSRestToJsonDotNetSerializationBinder(string serviceNamespace, string localNamespace)
{
if (serviceNamespace.EndsWith("."))
serviceNamespace = serviceNamespace.Substring(0, -1);
if(localNamespace.EndsWith("."))
localNamespace = localNamespace.Substring(0, -1);
ServiceNamespace = serviceNamespace;
LocalNamespace = localNamespace;
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
assemblyName = null;
typeName = string.Format("{0}:#{1}", serializedType.Name, ServiceNamespace); // MS format
}
public override Type BindToType(string assemblyName, string typeName)
{
string jsonDotNetType = string.Format("{0}.{1}", LocalNamespace, typeName.Substring(0, typeName.IndexOf(":#")));
return Type.GetType(jsonDotNetType);
}
}

- 41
- 1
You could also do it this way:
[JsonConverter(typeof(JsonSubtypes), "ClassName")]
public class Annimal
{
public virtual string ClassName { get; }
public string Color { get; set; }
}
You will need the JsonSubtypes
converter that is not part of Newtonsoft.Json
project.

- 2,701
- 29
- 28
There is another option that allows to serialize custom type property name in Json.NET
. The idea is do not write default $type
property, but introduce type name as property of class itself.
Suppose we have a Location
class:
public class Location
{
public double Latitude { get; set; }
public double Longitude { get; set; }
}
First, we need to introduce type property name and modify the class as demonstrated below:
public class Location
{
[JsonProperty("__type")]
public string EntityTypeName
{
get
{
var typeName = string.Format("{0}, {1}", GetType().FullName, GetType().Namespace);
return typeName;
}
}
public double Latitude { get; set; }
public double Longitude { get; set; }
}
Then, set JsonSerializerSettings.TypeNameHandling
to TypeNameHandling.None
in order the deserializer to skip the rendering of default $type
attribute.
That's it.
Example
var point = new Location() { Latitude = 51.5033630, Longitude = -0.1276250 };
var jsonLocation = JsonConvert.SerializeObject(point, new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.None, //do not write type property(!)
});
Console.WriteLine(jsonLocation);
Result
{"__type":"Namespace.Location, Namespace","Latitude":51.503363,"Longitude":-0.127625}

- 57,952
- 20
- 129
- 193
-
I don't see how deserializing will determine the correct type with your solution. Can you explain? – Dio F May 31 '15 at 15:06
-
To deserialize, try `JsonCreationConverter`, e.g. see http://stackoverflow.com/questions/8030538 – xmedeko Mar 04 '16 at 08:58
Using a custom converter should get the job done.
public CustomConverter : JsonConverter
{
public override bool CanWrite => true;
public override bool CanRead => true;
public override object ReadJson(JsonReader reader,
Type objectType,
object existingValue,
JsonSerializer serializer)
=> throw new NotImplementedException();
public override void WriteJson(JsonWriter writer,
object value,
JsonSerializer serializer)
{
var jOjbect = (JObject)JToken.FromObject(value);
jOjbect.Add(new JProperty("type", value.GetType().Name));
jOjbect.WriteTo(writer);
}
}

- 1,005
- 11
- 22