Skip to content

Instantly share code, notes, and snippets.

@CallumWatkins
Last active March 3, 2018 17:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save CallumWatkins/2ca41e12b86eb5710af8cccc1cd63857 to your computer and use it in GitHub Desktop.
Save CallumWatkins/2ca41e12b86eb5710af8cccc1cd63857 to your computer and use it in GitHub Desktop.
A Json.NET serialization binder to allow providing a custom type name using an attribute. License: MIT
// ==========
// Usage:
[JsonTypeName("CustomNameHere")]
public class Usage
{
public string Example { get; set; } = "Hello World";
}
// Serialize:
JsonConvert.SerializeObject(new Usage(),
new JsonSerializerSettings()
{
SerializationBinder = new JsonTypeNameSerializationBinder(),
TypeNameHandling = TypeNameHandling.All,
Formatting = Formatting.Indented
});
// Generates:
{
"$type": "CustomNameHere",
"Example": "Hello World"
}
// ==========
/// <summary>
/// Set a custom type name for use during serialization and deserialization with Json.NET.
/// </summary>
[AttributeUsage(AttributeTargets.Class)]
public class JsonTypeNameAttribute : Attribute
{
public string TypeName { get; }
public JsonTypeNameAttribute(string typeName)
{
TypeName = typeName;
}
}
/// <summary>
/// A serialization binder for use with the <see cref="JsonTypeNameAttribute"/> on classes in the declared or specified assembly.
/// </summary>
public class JsonTypeNameSerializationBinder : DefaultSerializationBinder
{
private readonly Dictionary<string, Type> _nameToType;
private readonly Dictionary<Type, string> _typeToName;
public JsonTypeNameSerializationBinder(Assembly assembly = null)
{
(Type type, string name)[] customNames = GetCustomTypeNames().ToArray();
_nameToType = customNames.ToDictionary(t => t.name, t => t.type);
_typeToName = customNames.ToDictionary(t => t.type, t => t.name);
IEnumerable<(Type type, string name)> GetCustomTypeNames()
{
foreach (Type type in assembly?.GetTypes() ?? this.GetType().Assembly.GetTypes())
{
foreach (object customAttribute in type.GetCustomAttributes(false))
{
if (customAttribute is JsonTypeNameAttribute jsonTypeNameAttribute)
{
yield return (type, jsonTypeNameAttribute.TypeName);
break;
}
}
}
}
}
public override void BindToName(Type serializedType, out string assemblyName, out string typeName)
{
if (_typeToName.TryGetValue(serializedType, out string name))
{
assemblyName = null;
typeName = name;
}
else
{
base.BindToName(serializedType, out assemblyName, out typeName);
}
}
public override Type BindToType(string assemblyName, string typeName)
{
if (_nameToType.TryGetValue(typeName, out Type type))
{
return type;
}
else
{
return base.BindToType(assemblyName, typeName);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment