.NET 5 迁移后的异常问题

Exception problem following .NET 5 migration

我刚刚将一个 dotnet core 3.1 项目迁移到 dotnet 5.0,此后我的单元测试遇到了问题。我的单元测试之一是测试反序列化 AccountDto 对象时返回的错误(转换器测试)。

在迁移 dotnet 5.0 之前,我在单元测试捕获中收到以下错误消息:“不支持记录类型 ID“”。自迁移以来,捕获的异常已更改:“不支持记录类型 id ''。不受支持的成员类型位于类型 'System.String' 上。路径:$.RecordTypeId | LineNumber:0 | BytePositionInLine: 64."

通过分析异常的内容,我注意到我在 RecordTypeConverter.Read() 中抛出的异常确实存在,但在内部异常中。

单元测试:

[Theory]
[InlineData("", null, "The record type id '' is not supported.")]
protected void MapAccountRecordTypeTest(string recordTypeId, string recordTypeExpected, string errorExpected)
{
    var account = new AccountDto();
    var error = string.Empty;

    var accountDto = new AccountDto
    {
        RecordType = recordTypeId
    };
    var myjson = JsonSerializer.Serialize(accountDto);

    try
    {
        account = JsonSerializer.Deserialize<AccountDto>(myjson);
    }
    catch (Exception ex)
    {
        error = ex.Message;
    }

    Assert.Equal(errorExpected, error);
}

单元测试调用的代码并抛出我想捕获的异常:

public class RecordTypeConverter : JsonConverter<string>
{
    private readonly Dictionary<string, string> _accountStatus = new()
    {
        { Constant.ENTERPRISE_RECORD_TYPE_ID, Constant.ENTERPRISE_RECORD_TYPE },
        { Constant.INDIVIDUAL_RECORD_TYPE_ID, Constant.INDIVIDUAL_RECORD_TYPE }
    };

    public override string Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
    {
        string value = reader.GetString();
        if (value != null)
        {
            string key = value.ToUpper();
            if (!_accountStatus.ContainsKey(key))
            {
                throw new NotSupportedException($"The record type id '{key}' is not supported.");
            }

            return _accountStatus[key];
        }

        return null;
    }

    public override void Write(Utf8JsonWriter writer, string value, JsonSerializerOptions options)
        => writer.WriteStringValue(value);
}

捕获异常:

à System.Text.Json.ThrowHelper.ThrowNotSupportedException(ReadStack& state, Utf8JsonReader& reader, NotSupportedException ex)
   à System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   à System.Text.Json.JsonSerializer.ReadCore[TValue](JsonConverter jsonConverter, Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)
   à System.Text.Json.JsonSerializer.ReadCore[TValue](Utf8JsonReader& reader, Type returnType, JsonSerializerOptions options)
   à System.Text.Json.JsonSerializer.Deserialize[TValue](String json, Type returnType, JsonSerializerOptions options)
   à System.Text.Json.JsonSerializer.Deserialize[TValue](String json, JsonSerializerOptions options)
   à tests.AccountTests.MapAccountRecordTypeTest(String recordTypeId, String recordTypeExpected, String errorExpected) dans D:\XXXXX\AccountTests.cs :ligne 72

异常出现在上述异常的内部异常中。我应该检索的是这个异常:

à SlxConnector.Helpers.Converters.RecordTypeConverter.Read(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options) dans d:\XXXXXXX\src\Helpers\Converters\RecordTypeConverter.cs :ligne 27
   à System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   à System.Text.Json.JsonPropertyInfo`1.ReadJsonAndSetMember(Object obj, ReadStack& state, Utf8JsonReader& reader)
   à System.Text.Json.Serialization.Converters.ObjectDefaultConverter`1.OnTryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   à System.Text.Json.Serialization.JsonConverter`1.TryRead(Utf8JsonReader& reader, Type typeToConvert, JsonSerializerOptions options, ReadStack& state, T& value)
   à System.Text.Json.Serialization.JsonConverter`1.ReadCore(Utf8JsonReader& reader, JsonSerializerOptions options, ReadStack& state)

我知道如何调整我的单元测试以使其工作,但我想了解为什么当我将我的项目迁移到 .NET 5 时,行为发生了变化。显然,.NET 5 JsonSerializer 从我的异常中引发了一个新异常 ???

迁移到 .NET 5 后,您的代码将使用新版本的 .NET 运行时。这个新版本提供相同的 public 接口来访问功能(“您的代码如何请求反序列化”),但内部实现(“如何完成反序列化”)不一样。
API 和运行时的构建者尽量保持 public 接口不变,但内部实现发生变化并不罕见。这样做是为了合并错误修复、改进或安全补丁。

在您的具体案例中,您获得了比以前更多的信息——我认为这也很好。正如您已经建议的那样,调整单元测试是处理此问题的首选方法。

如果你想分析.NET运行时的变化,你可以看看code for JSON serialization

我没有检查具体是哪个版本对此进行了更改,但更改是在 2020 年 3 月 6 日进行的。现在,当您在 Message 中抛出没有“路径:”的 NotSupportedException 时,它将使用 ThrowHelper class 重新抛出。

来自源代码的评论:

If the message already contains Path, just re-throw. This could occur in serializer re-entry cases. To get proper Path semantics in re-entry cases, APIs that take 'state' need to be used.

您可以找到源代码here

要解决您的问题,您应该在异常消息中添加“路径:”,或使用自定义 Exception。您还应该验证 JsonException 不仅仅是最合适的解决方案,因为您在反序列化之前检查 JSON 的格式是否正确。