【问题标题】:Exception problem following .NET 5 migration.NET 5 迁移后的异常问题
【发布时间】:2021-11-04 04:17:48
【问题描述】:

我刚刚将一个 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 和 C# 5 是不同的东西,特别是 .NET 5 是与 C# 9 一起发布的。
  • 要明确:你的意思是 - 它仍然抛出预期的异常,但消息现在更具体?听起来您只需更新单元测试即可处理新消息——也许使用StartsWith。抱歉,如果我误解了您的意思 - 如果是,请澄清。
  • 感谢我最初发布的修复和答案。我知道如何调整我的单元测试以使其工作,但我想了解为什么当我将项目迁移到 .NET 5 时,行为发生了变化。显然,.NET 5 JsonSerializer 从我的异常中引发了一个新异常。

标签: c# exception .net-core try-catch .net-5


【解决方案1】:

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

来自源代码的评论:

如果消息已经包含路径,只需重新抛出。这可能发生在序列化程序重新进入的情况下。 为了在重新进入的情况下获得正确的路径语义,需要使用带有“状态”的 API。

你可以找到源代码here

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

【讨论】:

  • 感谢您的回复。我将使用自定义异常而不是 NotSupportedException。
【解决方案2】:

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

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

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

【讨论】:

    猜你喜欢
    • 2018-11-30
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    • 2021-06-23
    • 2021-08-21
    • 1970-01-01
    • 2016-05-22
    • 2018-06-14
    相关资源
    最近更新 更多