Is it possible to shorten the type discriminator property name and value during serialization/deserialization? I don't have access to the types itself so in my case it should be done by configuring serializer itself. I need the property name to be "__type"
and the property value to be some custom name.
I know that in System.Web.Script.Serialization
JavaScriptTypeResolver
could be used but I need to implement in .NET Core System.Text.Json.
Here is an example how it can be done using JavaScriptTypeResolver
(the example is based on this MS example):
var people = new Person[] { new Person { Name = "AbcPerson" } };
var serialized = new JavaScriptSerializer(new CustomTypeResolver()).Serialize(people);
Console.WriteLine(serialized);
...
public class Person
{
public string Name { get; set; }
}
public class CustomTypeResolver : JavaScriptTypeResolver
{
private readonly IDictionary<string, Type> _typeIds
= new Dictionary<string, Type> { { "P", typeof(Person) } };
public override Type ResolveType(string id)
{
_typeIds.TryGetValue(id, out var result);
return result;
}
public override string ResolveTypeId(Type type)
{
return _typeIds.SingleOrDefault(x => x.Value == type).Key;
}
}
The output is:
[{"__type":"P","Name":"AbcPerson"}]
EDIT: Partial solution is to use attributes like this [JsonDerivedType(typeof(Person), typeDiscriminator: "P")]
. But then output is like this
[{"$type":"P","Name":"AbcPerson"}]
And I'm left with a problem of changing $type
to __type
.
To change the type discriminator property name to "__type"
(which is the discriminator name that was used by JavaScriptSerializer
and DataContractJsonSerializer
), you need to set [JsonPolymorphic(TypeDiscriminatorPropertyName = "__type")]
on every type for which you want to emit a type discriminator. For instance, if your data model has a base type Person
and a derived type Adult
, you would need to modify them as follows:
[JsonPolymorphic(TypeDiscriminatorPropertyName = "__type")] // Add this here
[JsonDerivedType(typeof(Person), typeDiscriminator: "P")]
[JsonDerivedType(typeof(Adult), typeDiscriminator: "A")]
public class Person
{
public string Name { get; set; }
}
[JsonPolymorphic(TypeDiscriminatorPropertyName = "__type")] // And also here
[JsonDerivedType(typeof(Adult), typeDiscriminator: "A")]
public class Adult : Person;
Demo fiddle #1 here.
Alternatively, if you cannot modify your data models easily, you can change the discriminator name via a JsonTypeInfo
modifier:
public static partial class JsonExtensions
{
public const string MyTypeDiscriminatorPropertyName = "__type";
public static Action<JsonTypeInfo> SetupMyTypeDiscriminatorPropertyName() =>
SetupTypeDiscriminatorPropertyName(MyTypeDiscriminatorPropertyName);
public static Action<JsonTypeInfo> SetupTypeDiscriminatorPropertyName(string name) =>
(JsonTypeInfo typeInfo) =>
{
if (typeInfo.PolymorphismOptions != null)
typeInfo.PolymorphismOptions.TypeDiscriminatorPropertyName = name;
};
}
Then use it in options e.g. as follows:
var options = new JsonSerializerOptions
{
TypeInfoResolver = new DefaultJsonTypeInfoResolver()
.WithAddedModifier(JsonExtensions.SetupMyTypeDiscriminatorPropertyName()),
// Add other options as required.
};
var json = JsonSerializer.Serialize(people, options);
var people2 = JsonSerializer.Deserialize<Person []>(json, options);
Demo fiddle #2 here.
See also: