从 Json.Net 中的 JsonReaderException 中查找无效值

Find invalid values from JsonReaderException in Json.Net

我运行下面的代码故意抛出JsonReaderException。它正确地给出了 "Could not convert string to boolean: aaa. Path 'Active', line 3, position 17."

的异常消息

有没有办法直接从 JsonReaderException 中获取验证失败的值,这样我就不必解析异常消息了?

string json = @"{
  'Email': 'james@example.com',
  'Active': 'aaa',
  'CreatedDate': '2013-01-20T00:00:00Z',
  'Roles': [
    'User',
    'Admin'
  ]
}";

try
{
  Account account = JsonConvert.DeserializeObject<Account>(json);
  Console.WriteLine(account.Email);
}
catch (JsonReaderException exc)
{
  // Do Something
}

似乎违规值未在 JsonReaderException. The only possible location for this value would be the Exception.Data 字典中保存为 属性,但是 Json.NET 未在此处添加任何内容。

但是,通过一些工作,您可以利用 Json.NET 的 serialization error event handling functionality to directly access the bad value at the time the exception is thrown. First, define the following helper method and ErrorEventArgs 子类型:

public class ErrorAndValueEventArgs : Newtonsoft.Json.Serialization.ErrorEventArgs 
{
    public object ReaderValue { get; } = null;

    public ErrorAndValueEventArgs(object readerValue, object currentObject, ErrorContext errorContext) : base(currentObject, errorContext)
    {
        this.ReaderValue = readerValue;
    }
}

public static partial class JsonExtensions
{
    public static TRootObject Deserialize<TRootObject>(string json, EventHandler<ErrorAndValueEventArgs> error, JsonSerializerSettings settings = null)
    {
        using (var sr = new StringReader(json))
        using (var jsonReader = new JsonTextReader(sr))
        {
            var serializer = JsonSerializer.CreateDefault(settings);
            serializer.Error += (o, e) => error(o, new ErrorAndValueEventArgs(jsonReader.Value, e.CurrentObject, e.ErrorContext));
            return serializer.Deserialize<TRootObject>(jsonReader);
        }
    }
}

现在您将能够在抛出异常时访问 JsonReader.Value 的值:

object errorValue = null;
try
{
    Account account = JsonExtensions.Deserialize<Account>(json, (o, e) => errorValue = e.ReaderValue);
    Console.WriteLine(account.Email);
}
catch (JsonException exc)
{
    // Do Something
    Console.WriteLine("Value at time of {0} = {1}, Data.Count = {2}.", exc.GetType().Name, errorValue, exc.Data.Count);
    // Prints Value at time of JsonReaderException = aaa, Data.Count = 0.
}

备注:

  • 由于您必须手动创建自己的 JsonTextReader,因此您需要能够访问 JSON 字符串(或 Stream)才能使此方法生效. (在您的问题中显示的示例中是这样。)

  • JsonSerializationException Parsing.

  • 中显示了一种类似的捕获附加错误信息的技术
  • 您可能想要增强 ErrorAndValueEventArgs 以同时记录 JsonReader.TokenType。如果在抛出异常时 reader 位于容器(对象或数组)的开头,则 JsonReader.Value 将为空。

演示 fiddle here.