someone
someone

Reputation: 575

How we can handle deserializing error of Enum when there is no equivalent value in C# side?

In my C# code, I have an enum type that is going to be stored in MongoDB as string. In my C# code I have this type:

public enum Color
{
    Unknown =0,
    Red =1,
    Blue =2,
    Brown =3,
}

When in MongoDB string value is Red, Blue or Brown there is no problem but sometimes in DB there are other colours that are not included in my enum type like black, in this case, I expect the Color deserialized to Unknown but I get deserializing error indicates that black is not defined. Is there any way to handle this? I can not add every colour on my side and I can not change the enum type to any other type. I'm wondering how can I deserialize it to Unknown?

Upvotes: 3

Views: 1110

Answers (3)

McKnight
McKnight

Reputation: 131

Another option is a custom generic enum serializer for the MongoDB driver (BSON), this will allow you to define a default value when registering the serializer

public class EnumSerializer<T> : SerializerBase<T> where T : struct
{
    public T DefaultValue { get; }

    public EnumSerializer(T defaultValue)
    {
        DefaultValue = defaultValue;
    }

    public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, T value)
    {
        ctx.Writer.WriteString(value.ToString());
    }

    public override T Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
    {
        if (ctx.Reader.CurrentBsonType == MongoDB.Bson.BsonType.Null)
        {
            ctx.Reader.ReadNull();
            return DefaultValue;
        }
        if (ctx.Reader.CurrentBsonType == MongoDB.Bson.BsonType.String)
        {
            var value = ctx.Reader.ReadString();
            if (Enum.TryParse<T>(value, true, out var res))
                return res;
        }
        return DefaultValue;
    }
}

You can use it like so

BsonSerializer.RegisterSerializer(typeof(CurrancyCode), new EnumSerializer<CurrancyCode>(CurrancyCode.GBP));

Upvotes: 0

Dĵ ΝιΓΞΗΛψΚ
Dĵ ΝιΓΞΗΛψΚ

Reputation: 5679

you will need a custom serializer like so:

public class ColorSerializer : SerializerBase<Color>
{
    public override void Serialize(BsonSerializationContext ctx, BsonSerializationArgs args, Color value)
    {
        ctx.Writer.WriteString(value.ToString());
    }

    public override Color Deserialize(BsonDeserializationContext ctx, BsonDeserializationArgs args)
    {
        return
            ctx.Reader.CurrentBsonType switch
            {
                MongoDB.Bson.BsonType.String => ctx.Reader.ReadString() switch
                {
                    "Red" => Color.Red,
                    "Blue" => Color.Blue,
                    "Brown" => Color.Brown,
                    _ => Color.Unknown,
                },
                _ => Color.Unknown,
            };
    }
}

register it with the serializer registry during app startup like so:

BsonSerializer.RegisterSerializer(typeof(Color), new ColorSerializer());

done!

Upvotes: 1

Amit Kotha
Amit Kotha

Reputation: 2019

You can use a custom StringEnumConverter. This will return you default enum value

public class SafeStringEnumConverter : StringEnumConverter
{
    public object DefaultValue { get; }

    public SafeStringEnumConverter(object defaultValue)
    {
        DefaultValue = defaultValue;
    }

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        try
        {
            return base.ReadJson(reader, objectType, existingValue, serializer);
        }
        catch
        {      
            return DefaultValue;
        }
    }
}

You can use this in your enum like this

Then you can use it as follows:

[JsonConverter(typeof(SafeStringEnumConverter), Unknown)]

    public enum Colors
    {
        Unknown=0,
        Red =1,
        Blue =2,
        Brown =3
    }

Upvotes: 1

Related Questions