简体   繁体   中英

Is there a way to return a custom error when Newtonsoft.JSON deserialization fails?

I want to change the ResponseBody when a request fails because deserialization to an Enum wasn't successful. The application is a .NET Core 3 API.

I've got the following property on one of my entities:

[JsonConverter(typeof(StringEnumConverter))]
public Attribute Attribute { get; set; }

where Attribute is the following Enum:

public enum Attribute
    {
        [EnumMember(Value = "value-1")]
        value1,
        [EnumMember(Value = "value-2")]
        value2,
        [EnumMember(Value = "some-value")]
        somevalue
    }

When I try to POST a body with a wrong value for the Enum:

{
  "attribute": "wrong-value"
}

My endpoint returns a 400 with a Newtonsoft error and I'd like to return a ResponseBody created by me instead.

{
    "errors": {
        "attribute": [
            "Error converting value \"wrong-value\" to type 'Project.Attribute'. Path 'attribute', line 10, position 24."
        ]
    },
    "type": "https://tools.ietf.org/html/rfc7231#section-6.5.1",
    "title": "One or more validation errors occurred.",
    "status": 400,
    "traceId": "|1cf19d18-4577510ef4de1g923."
}

Is there a way to intercept such error with a middleware and return a custom ResponseBody?

What I would do is to create a StringEnumConverter class:

internal class StringEnumConverter : JsonConverter
{
    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        if (reader.TokenType == JsonToken.String)
            try
            {
                return JsonConvert.DeserializeObject<Attribute>("'" + reader.Value.ToString() + "'");
            }
            catch
            {
                var tr = reader as JsonTextReader;
                throw new Exception($"Error converting value \"{reader.Value.ToString()}\" to type \"{objectType.ToString()}\". Path \"{tr.Path}\", line {tr.LineNumber}, position {tr.LinePosition}.");
            }
        throw new NotImplementedException();
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotImplementedException();
    }

    public override bool CanConvert(Type objectType)
    {
        return true;
    }
}

And then while trying to deserialize my JSON string I would catch any exception like:

string json = "{'attribute': 'value1x'}";

try
{
    MyClass r = JsonConvert.DeserializeObject<MyClass>(json);
}
catch (Exception e)
{
    Console.WriteLine(e.Message);
}

That way my Exception would have the appropriate message. Of course, you have to keep in mind that this is only for deserializing strings to the Attribute type (perhaps the name should be changed to StringToAttributeConverter for more readability). You will have to find a slightly more generic way of doing it for all different types of enums (maybe by using a generic...) if possible.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM