0

I have a data object that I've defined in my API using Newtonsoft decorators:

public class DataRequest
{
     [JsonProperty("Id")]
     public string id { get; set; }

     [JsonProperty("Action")]
     public ActionType Action { get; set; }
}

The property I have in my object is an enum:

public enum ActionType
{
    POST,
    DELETE
}

This works well when my API serializes this object when the request has the string "POST" or "DELETE". However, when my request has an unknown value, my DataRequest object is null. Is there a way I can handle this in case my API gets an unexpected value? I was thinking about excepting a string rather than an enum but I would imagine there is something where Newtonsoft or some other lib could do this for me

DannyD
  • 2,732
  • 16
  • 51
  • 73
  • 1
    Does this answer your question? [How can I ignore unknown enum values during json deserialization?](https://stackoverflow.com/questions/22752075/how-can-i-ignore-unknown-enum-values-during-json-deserialization) – quaabaam Apr 03 '21 at 00:31
  • The link I posted in my previous comment shows how to fall back through multiple options when a enum match is not found. With newtonsoft you would do this with a `JsonConverter`. – quaabaam Apr 03 '21 at 00:33
  • @quaabaam I had tried with newtonsoft by adding this JsonConverter to my ActionType property in the DataRequest: `[JsonConverter(typeof(StringEnumConverter))]` but I still got a null object when the enum is unknown. Is there a different way with newtonsoft that you know of? – DannyD Apr 03 '21 at 00:44
  • You would add that attribute to the enum itself (unless you don't have access to add the attribute to the object), see the last answer on this question... https://stackoverflow.com/questions/23366364/how-do-i-deserialize-an-array-of-enum-using-json-net. ... e.g. `[JsonConverter(typeof(StringEnumConverter))] public enum ActionType { POST, DELETE }` – quaabaam Apr 03 '21 at 00:52
  • Did you try the `TolerantEnumConverter` in the [answer](https://stackoverflow.com/a/22755077/10263) that @quaabaam linked to? You would use that in place of the `StringEnumConverter`. – Brian Rogers Apr 03 '21 at 01:29
  • See duplicate. If you can't get that to work, post a new question in which you provide a proper [mcve] that shows clearly what you tried, along with a detailed explanation of what _specifically_ you need help with. – Peter Duniho Apr 03 '21 at 07:04

2 Answers2

1

Do you want to access the invalid value you get sent in? If you don't care, you can look at the other answer linked in the comments. Here I assume that you want to see the weird value of ActionType, for logging or similar.

If the string you get is unknown, it can not be represented as an enum. You have to store the string somewhere.

The simplest solution seems to serialize/deserialize the string value directly, and provide a getter/setter that handles the enum. You can either use a nullable enum, or have a "special" value of UNKNOWN or something like that, when the string value is not a valid enum value.

public class DataRequest
{
    [JsonProperty("Id")]
    public string id { get; set; }

    [JsonProperty("Action")]
    public string RawActionValue { get; set; }

    [JsonIgnore]
    public ActionType? Action
    {
        get {
            if(Enum.TryParse<ActionType>(RawActionValue, out var res)) {
                return res;
            } else {
                return null;
            }
        }
        set {
            RawActionValue = value?.ToString();
        }
    }
}
gnud
  • 77,584
  • 5
  • 64
  • 78
0

If you don't need to store the original string then you can use a converter:

public class ActionTypeConverter : JsonConverter<ActionType>
{
    public override void WriteJson(JsonWriter writer, ActionType value, JsonSerializer serializer)
        => throw new NotImplementedException("Only for reading");   

    public override ActionType ReadJson(JsonReader reader, Type objectType, ActionType existingValue, bool hasExistingValue, JsonSerializer serializer)
    {
        if(Enum.TryParse((string)reader.Value, out ActionType a))
        {
           return a; 
        }
        
        //return / throw 
    }

There are a few ways to configure converters; here's one:

var o = JsonConvert.DeserializeObject<DataRequest>(json, new JsonSerializerSettings 
{ 
  Converters = { new ActionTypeConverter() } 
});
tymtam
  • 31,798
  • 8
  • 86
  • 126