当Newtonsoft.JSON反序列化失败时,有没有办法返回自定义错误?

问题描述

当由于对Enum的反序列化失败而导致请求失败时,我想更改ResponseBody。该应用程序是.NET Core 3 API。

我在一个实体上拥有以下属性

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

其中Attribute是以下枚举:

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

当我尝试发布具有错误枚举值的正文时:

{
  "attribute": "wrong-value"
}

我的端点返回一个带有Newtonsoft错误的400,我想返回一个由我创建的ResponseBody。

{
    "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."
}

是否可以通过中间件拦截此类错误并返回自定义ResponseBody?

解决方法

我要做的是创建一个StringEnumConverter类:

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;
    }
}

然后尝试反序列化我的JSON字符串时,我会捕获到任何异常,例如:

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

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

这样,我的异常将具有适当的消息。当然,您必须记住,这仅是为了将字符串反序列化为Attribute类型(也许名称应更改为StringToAttributeConverter以提高可读性)。如果可能的话,您将必须找到一种针对所有不同类型的枚举的通用方法(也许使用通用...)。