如何解决JsonConverter 在集成测试中不起作用
我已启用我的 API 以使用字符串值序列化/反序列化枚举。为此,我已将 JsonStringEnumConverter 添加到我的 API 启动类中受支持的 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 当然不能承载与他们一起陈述。有关更多上下文,我refer you to the feature request to fix this poor design。
实际上,我在那个 FR 中想出了 a solution,自从我编造它以来,我已经对其进行了一些调整:
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
中的实现,而不是在需要处理 JSON 的类中调用静态 JsonSerializer
方法,而是将 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
}
疼吗?是的。没有必要吗?也是。傻吗?第三次,是的。但这就是微软。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。