Json.Net: Serialize / Deserialize property as value, not as object
How can I achieve the following JSON representation of class Id when used in another class?
class Car
{
public StringId Id { get; set; }
public string Name { get; set; }
}
class StringId
{
public string Value { get; set; }
}
// ---------------------------------------------
// Desired representation
{ "Id": "someId", "Name": "Ford" }
// Default (undesired) representation
{ "Id" : { "Value": "someId" }, "Name": "Ford" }
source to share
You can add TypeConverter
for StringId
. Json.NET will pick up a type converter and use it to convert from string to string:
[TypeConverter(typeof(StringIdConverter))]
class StringId
{
public string Value { get; set; }
}
class StringIdConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
return true;
return base.CanConvertFrom(context, sourceType);
}
public override bool CanConvertTo(ITypeDescriptorContext context, Type destinationType)
{
if (destinationType == typeof(StringId))
return true;
return base.CanConvertTo(context, destinationType);
}
public override object ConvertFrom(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value)
{
if (value is string)
{
return new StringId { Value = (string)value };
}
return base.ConvertFrom(context, culture, value);
}
public override object ConvertTo(ITypeDescriptorContext context, System.Globalization.CultureInfo culture, object value, Type destinationType)
{
if (destinationType == typeof(string) && value is StringId)
{
return ((StringId)value).Value;
}
return base.ConvertTo(context, culture, value, destinationType);
}
}
If your string representation contains inline numeric or date / time data, be sure to convert that data with culture
, not the default, the current culture. Json.NET will invoke the converter with the correct culture, which is invariant culture by default , thus ensuring that the generated JSON files are portable across cultures.
Example fiddle .
Note that if you are using .Net Core, support for type converters was only added as of Json.NET 10.0.1 , and support for type converters in Json.NET Portable builds is not available as of 10.0.3.
Alternatively, if you don't mind adding Json.NET specific attributes for your type, you can use customJsonConverter
[JsonConverter(typeof(StringIdConverter))]
class StringId
{
public string Value { get; set; }
}
class StringIdConverter : JsonConverter
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(StringId);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.Null)
return null;
var token = JToken.Load(reader);
return new StringId { Value = (string)token };
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
var id = (StringId)value;
writer.WriteValue(id.Value);
}
}
You can also configure the converter in the global settings .
Example fiddle .
source to share
You can override a ToString
class method StringId
to return a value
public override string ToString()
{
return this.Value;
}
You will need TypeConverter
to deserialize from string toStringId
public class StringIdConverter : TypeConverter
{
public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
{
if (sourceType == typeof(string))
{
return true;
}
return base.CanConvertFrom(context, sourceType);
}
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
{
if (value is string)
{
return new StringId(value.ToString());
}
return base.ConvertFrom(context, culture, value);
}
}
And decorate your class with StringId
this attribute
[TypeConverter(typeof(StringIdConverter))]
public class StringId{
...
}
source to share