In our C# application on .NET 4.8, we tried to use a PopulateObject
for deserializing data returned from an API. This API is not under our control.
Now the API developer added a new enum value and when we try to map it in our own Enum
it crashes with a message like
Error converting value 'x' to 'enum-y'
Now we COULD adjust our enum and go on, but that would only be a temporary fix until it happens again at another part of the code. We searched a little bit and found a specific solution. We added an 'Unknown' value to our enum and then added a converter like this:
public class AllowedMethodConverter : StringEnumConverter
{
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
if (Enum.TryParse(reader.Value.ToString(), out Method result)) // Here the Method has to be known
return result;
else
return Method.Unknown;
}
return base.ReadJson(reader, objectType, existingValue, serializer);
}
}
[JsonConverter(typeof(AllowedMethodConverter))]
public enum Method
{
Unknown,
Method1,
Method2
}
This is used in a very simple API method where we get the string from the API and afterwards:
JsonConvert.PopulateObject(response.Content, userSettings);
That works fine so far, but this would require one StringEnumConverter
per enum. With roughly 40 enums, it would be a little bit much to create 40 converters, just so I can ignore some values that do not exist.
Does anyone have a better idea how to handle this?
Instead of defining a custom converter for each enum, we can create a single, reusable JsonConverter
that works with any enum dynamically.
public class SafeEnumConverter<TEnum> : JsonConverter where TEnum : struct, Enum
{
public override bool CanConvert(Type objectType)
{
return objectType == typeof(TEnum);
}
public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
{
if (reader.TokenType == JsonToken.String)
{
string enumString = reader.Value.ToString();
if (Enum.TryParse(enumString, out TEnum result)) // Try to parse normally
return result;
return Enum.GetValues(typeof(TEnum)).Cast<TEnum>().First(); // Default to first value (e.g., Unknown)
}
return existingValue ?? Enum.GetValues(typeof(TEnum)).Cast<TEnum>().First();
}
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
{
writer.WriteValue(value.ToString());
}
}
Now, instead of defining a separate converter per enum, just use the same generic converter for all:
[JsonConverter(typeof(SafeEnumConverter<Method>))]
public enum Method
{
Unknown,
Method1,
Method2
}
[JsonConverter(typeof(SafeEnumConverter<AnotherEnum>))]
public enum AnotherEnum
{
Unknown,
Value1,
Value2
}
Now, when calling JsonConvert.PopulateObject()
, the converter will automatically handle unknown values and default to Unknown
:
JsonConvert.PopulateObject(response.Content, userSettings);
✅ Single Converter for All Enums – No need to create multiple converters
✅ Prevents Crashes – Unrecognized values are gracefully handled
✅ Scalable – Works with any enum
✅ Minimal Code Changes