.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 的格式是否正确。
我刚刚将一个 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 的格式是否正确。