我正在尝试使用一些优美的异常处理来包装我的应用程序。当我的应用程序无法反序列化JSON时,我得到一个JsonSerializationException
,其消息如下所示:
将值“ [IncorrectDataType]”转换为类型“ ApexFramework.Enums + DataTypes”时出错。路径“布局[0] .ElementContainer [0] .ContainerDatatype”,第12行,位置58。
通过此异常消息,我有兴趣以干净的方式捕获和呈现以下内容:
我浏览了
JsonSerializationException
对象,我没有什么可以轻松抓住的,所以:
任何人都可以确认没有办法与JsonSerializationException
一起以干净的方式获取我需要的信息吗?
如果没有,谁能帮助我想出最优雅,最有效的方法来从异常堆栈中获取我需要的信息?
答案 0 :(得分:0)
我不确定这是否是您所需要的,但是您可以使用Json.NET Schema来验证json字符串并获得更多体面的验证错误消息。
您可以使用DataAnnotations创建json模式(字符串)或验证对象。
您可以在Nuget中找到这两个软件包:
安装软件包Newtonsoft.Json.Schema -Version 3.0.10
安装包System.ComponentModel.Annotations-版本4.5.0
请考虑以下模型:
public class Album
{
[DisplayName("Album Id")]
[Description("Album Id must be a positive integer")]
[Range(1, Int32.MaxValue)]
public int AlbumId { get; set; }
[DisplayName("Artist Id")]
[Description("Artist Id must be a positive integer")]
[Range(1, Int32.MaxValue)]
public int ArtistId { get; set; }
[DisplayName("Title")]
[Description("An Album Title is required")]
[Required()]
[StringLength(160)]
public string Title { get; set; }
[DisplayName("Album Price")]
[Description("Album Price must be between 0.01 and 100.00")]
[Range(0.01, 100.00)]
public decimal Price { get; set; }
}
下面的类将包含有关验证错误的信息:
public class ValidationError
{
public string Property { get; set; }
public string Message { get; set; }
public object CurrentValue { get; set; }
}
反序列化和验证json字符串:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.IO;
using Newtonsoft.Json;
using Newtonsoft.Json.Schema;
using Newtonsoft.Json.Schema.Generation;
// json that contains properties with invalid values
string json = @"{
""AlbumId"": -10,
""ArtistId"": 1,
""Title"": null,
""Price"": 200.0
}";
JsonTextReader reader = new JsonTextReader(new StringReader(json));
JSchemaValidatingReader validatingReader = new JSchemaValidatingReader(reader)
{
Schema = new JSchemaGenerator().Generate(typeof(Album))
};
var errors = new List<ValidationError>();
validatingReader.ValidationEventHandler += (o, a) => errors.Add(new ValidationError
{
Property = a.ValidationError.Schema.Title,
Message = a.ValidationError.Schema.Description,
CurrentValue = a.ValidationError.Value
});
JsonSerializer serializer = new JsonSerializer();
Album album = serializer.Deserialize<Album>(validatingReader);
foreach (ValidationError error in errors)
{
Debug.WriteLine($"Property: {error.Property}, Message: {error.Message}");
}
输出:
属性:相册ID,消息:相册ID必须为正整数
属性:标题,消息:需要相册标题
属性:相册价格,消息:相册价格必须在0.01到100.00之间
答案 1 :(得分:0)
您可以使用Json.NET的serialization error event handling功能以更有用的格式获取有关异常的信息。
反序列化期间发生异常时,Json.NET会在对象层次结构的每个级别上捕获并重新抛出该异常,从而使每个对象都有机会使用OnError
方法处理该异常。当您不想处理异常时,可以利用此优势,通过传递给ErrorEventArgs
事件处理程序的JsonSerializerSettings.Error
中提供的信息,记录有关异常发生的位置的详细信息。例如,以下代码捕获并报告发生异常的path,引起异常的member,并在遇到错误时对objects的堆栈进行反序列化:< / p>
static bool TryDeserialize<TRootObject>(string jsonString, out TRootObject root)
{
var errorStack = new Stack<Newtonsoft.Json.Serialization.ErrorEventArgs>();
var settings = new JsonSerializerSettings
{
Converters = { new StringEnumConverter() },
Error = (o, e) => errorStack.Push(e)
};
try
{
root = JsonConvert.DeserializeObject<TRootObject>(jsonString, settings);
return true;
}
catch (JsonException ex)
{
var last = errorStack.Last();
var member = last.ErrorContext.Member;
var path = last.ErrorContext.Path;
var objectsStack = String.Join(", ", errorStack
.Where(e => e.CurrentObject != null)
.Select(e => e.CurrentObject.ToString()));
Console.WriteLine("Exception parsing JSON: ");
Console.WriteLine(ex.Message);
Console.WriteLine("Error context details: ");
Console.WriteLine(" Path: {0}\n Member: {1}\n Object stack = {{{2}}}",
path, member, ObjectsStack);
root = default(TRootObject);
return false;
}
}
然后,如果我尝试将JSON反序列化为您的问题所隐含的数据模型,则会收到以下错误消息:
Exception parsing JSON:
Error converting value "[IncorrectDataType]" to type 'DataTypes'. Path 'Layout[0].ElementContainer[0].ContainerDatatype', line 6, position 56.
Error context details:
Path: Layout[0].ElementContainer[0].ContainerDatatype
Member: ContainerDatatype
Object stack = {RootObject, System.Collections.Generic.List`1[Layout], Layout, System.Collections.Generic.List`1[ElementContainer], ElementContainer}
如您所见,您所需的信息更加清晰可用,因此您不再需要解析异常消息。您仍然需要解析异常路径以提取索引,但是路径语法是标准的JSONPath syntax,因此定义明确。您可以在任何先前存在的JSONPath解析器(包括Json.NET自己的JPath
)上对路径解析代码进行建模。
注意:
.net小提琴here的工作示例。