.net - JsonConverter 在集成测试中不起作用
问题描述
我已启用我的 API 以使用字符串值对枚举进行序列化/反序列化。为此,我已将 JsonStringEnumConverter 添加到我的 API 的 Startup 类中支持的 JsonConverters 列表中:
.AddJsonOptions(opts =>
{
var enumConverter = new JsonStringEnumConverter();
opts.JsonSerializerOptions.Converters.Add(enumConverter);
});
它工作正常——我的 API 成功地将枚举序列化和反序列化为字符串。
现在-我正在尝试为我的 API 构建集成测试并遇到一些问题。我HttpContentJsonExtensions.ReadFromJsonAsync
用于反序列化 API 响应,但枚举属性引发了异常。
问题很HttpContentJsonExtensions.ReadFromJsonAsync
明显 - 不知道 API 使用的转换器列表(因为,正如我之前提到的,我已将其添加JsonStringEnumConverter
到支持的转换器列表中并且它工作正常)。
如果我在我的测试功能中这样做:
var options = new System.Text.Json.JsonSerializerOptions();
options.Converters.Add(new JsonStringEnumConverter());
SomeClass result= await response.Content.ReadFromJsonAsync<SomeClass>(options);
然后对 enum 属性进行反序列化,不抛出异常。但是现在,ReadFromJsonAsync
只知道JsonStringEnumConverter
API 使用的其他 JSON 转换器(如 Guid 转换器),而不知道
如何确保HttpContentJsonExtensions.ReadFromJsonAsync
能够使用 API 使用的所有 JSON 转换器?
谢谢!
解决方案
不幸的是,没有办法开箱即用地实现这一目标。原因是 System.Text.Json API 的“设计者”以令人难以置信的莫名其妙的举动决定将所述 API 设为静态 - 可能是为了模仿众所周知的 Newtonsoft.Json - 但静态 API 当然不能携带和他们一起陈述。有关更多上下文,请参阅修复此糟糕设计的功能请求。
实际上,我在该 FR 中提出了一个解决方案,自从我炮制它以来,我已经对其进行了一些调整:
public interface IJsonSerializer
{
JsonSerializerOptions Options { get; }
Task<T> DeserializeAsync<T>(Stream utf8Json, CancellationToken cancellationToken);
// other methods elided for brevity
}
public class DefaultJsonSerializer : IJsonSerializer
{
private JsonSerializerOptions _options;
public JsonSerializerOptions Options
=> new JsonSerializerOptions(_options); // copy constructor so that callers cannot mutate the options
public DefaultJsonSerializer(IOptions<JsonSerializerOptions> options)
=> _options = options.Value;
public async Task<T> DeserializeAsync<T>(Stream utf8Json, CancellationToken cancellationToken = default)
=> await JsonSerializer.DeserializeAsync<T>(utf8Json, Options, cancellationToken);
// other methods elided for brevity
}
本质上,您定义了一个包装器接口,其方法签名与静态方法签名相同JsonSerializer
(减去JsonSerializerOptions
参数,因为您想使用在类上定义的那些),然后是委托给静态JsonSerializer
方法的所述接口的默认实现。将接口映射到实现中Startup.ConfigureServices
,而不是调用JsonSerializer
需要处理 JSON 的类中的静态方法,而是将 JSON 接口注入这些类并使用它。
鉴于您正在使用HttpContentJsonExtensions
,您还需要定义您自己的该扩展类的包装器版本,该扩展类复制其方法签名但将其JsonSerializerOptions
参数替换为您的 JSON 序列化接口的实例,然后将所述接口的选项传递给底层HttpContentJsonExtensions
实现:
public static class IJsonSerializerHttpContentJsonExtensions
{
public static Task<object?> ReadFromJsonAsync(this HttpContent content, Type type, IJsonSerializer serializer, CancellationToken cancellationToken = default)
=> HttpContentJsonExtensions.ReadFromJsonAsync(content, type, serializer.Options, cancellationToken);
// other methods elided for brevity
}
痛吗?是的。这是不必要的吗?也是的。傻吗?第三次,是的。但微软就是这样。
推荐阅读
- jenkins - Jenkins 管道中的 curl 错误 - 找不到 URL
- javascript - 如何将 csv 数据导入 javascript 以创建搜索器?
- java - @PreUpdate、@PostUpdate、@PrePersist、@PostPersist、@PreRemove 和 @PostRemove 不适用于带有 OpenXava 的 @ElementCollection 的 @Embeddable
- asp.net - System.Net.Sockets.Socket:同时读写?
- pyspark - 如何使用 Apache PySpark 中的 roc_curve 生成的阈值计算精确召回率
- wpf - Powershell 和 WinAPI。FindWindowEx 在 Windows 10 中找不到开始按钮的句柄
- java - Maven 没有使用 mvn clean verify 运行黄瓜测试
- php - EasyAdmin3 / Symfony / Twig - 在 Twig 模板中带有路由名称和参数的 url 生成器
- java - 我如何将所有不同的警报框组合成一个警报框,一起显示所有结果?
- crash - 为什么我在尝试设置浮点数时会崩溃?