首页 > 解决方案 > 类型未知时反序列化 JSON - .NET Core

问题描述

我试图了解反序列化来自 REST API 的 Json 数据的最佳方法。

我正在使用的 API 上的端点之一将返回一个User对象或一个ApiException对象。

所以我必须做

var user = JsonConverter.Deserialize<User>(json);
if(user.UserId == 0)
{
    var error = JsonConverter.Deserialize<ApiException>(json);
}

或者

if(!json.Contains("error"))
{
    var user = JsonConverter.Deserialize<User>(json);
}
else
{
    var error = JsonConverter.Deserialize<ApiException>(json);  
}

有没有更清洁的方法来实现这一点?

编辑:我想另一种方法是如果 api 返回一个包装类,该包装类包含包含类型的响应,但由于某种原因这仍然感觉很笨重。

标签: asp.net-core.net-core

解决方案


一个想法是使用 System.Text.Json 中的JsonDocument类在反序列化为任何一种可能的类型之前查看原始数据。例如,如果“userId”键的存在是识别为用户对象的可靠方法,您可以在 JsonDocument 中以高性能方式对此进行测试,而无需对错误类型进行不必要的反序列化。它看起来像:

using JsonDocument document = JsonDocument.Parse(json);
if (document.RootElement.TryGetProperty("userId", out _))
{
    var user = JsonSerializer.Deserialize<User>(json);
    // Do stuff with user
}
else
{
    var error = JsonSerializer.Deserialize<ApiException>(json);
    // Do stuff with error
}

要知道这实际上是否比两种类型的盲目反序列化更好,我会将其放入基准测试中,看看哪种情况会胜出。我使用从 UTF8 字节数组中解析的相对较小的“用户”进行了快速测试。我的基准测试结果:

|           Method |     Mean |     Error |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|----------------- |---------:|----------:|----------:|-------:|------:|------:|----------:|
|     JSONDocument | 2.500 us | 0.0193 us | 0.0181 us | 0.1297 |     - |     - |     824 B |
|      StringParse | 1.360 us | 0.0096 us | 0.0090 us | 0.2460 |     - |     - |    1544 B |
| BlindDeserialize | 2.084 us | 0.0132 us | 0.0123 us | 0.1335 |     - |     - |     840 B |

在此示例中,搜索“UserId:”的原始字符串似乎比使用 JSONDocument 更快,但会消耗更多内存。“BlindDeserialize”正在反序列化两者并检查结果。当然,这至少不科学,但给人一种替代品的味道。


推荐阅读