[英]JSON Polymorphic serialization in .NET7 Web API
.NET7 对System.Text.Json
序列化程序进行了大量改进,其中之一是使用新的[JsonPolymorphic]
属性对类型进行多态序列化。 我试图在我的 Asp.Net web API 中使用它,但它似乎没有序列化类型鉴别器,尽管 model 已正确设置。
它仅在尝试通过网络发送对象时发生,在使用 JsonSerializer 时,一切似乎都运行良好。 例如:
// This is my data model
[JsonPolymorphic]
[JsonDerivedType(typeof(SuccesfulResult), typeDiscriminator: "ok")]
[JsonDerivedType(typeof(ErrorResult), typeDiscriminator: "fail")]
public abstract record Result;
public record SuccesfulResult : Result;
public record ErrorResult(string Error) : Result;
// Some test code that actually works
var testData = new Result[]
{
new SuccesfulResult(),
new ErrorResult("Whoops...")
};
var serialized = JsonSerializer.SerializeToDocument(testData);
// Serialized string looks like this:
// [{ "$type": "ok" }, { "$type": "fail", "error": "Whoops..." }]
// So type discriminators are in place and all is well
var deserialized = serialized.Deserialize<IEnumerable<Result>>()!;
// This assertion passes succesfully!
// We deserialized a collection polymorphically and didn't lose any type information.
testData.ShouldDeepEqual(deserialized);
// However, when sending the object as a response in an API, the AspNet serializer
// seems to be ignoring the attributes:
[HttpGet("ok")]
public Result GetSuccesfulResult() => new SuccesfulResult();
[HttpGet("fail")]
public Result GetFailResult() => new ErrorResult("Whoops...");
这些响应都没有使用类型鉴别器进行注释,而且我的强类型客户端无法将结果反序列化为适当的层次结构。
GET /api/ok HTTP/1.1
# =>
# ACTUAL: {}
# EXPECTED: { "$type": "ok" }
GET /api/fail HTTP/1.1
# =>
# ACTUAL: { "error": "Whoops..." }
# EXPECTED: { "$type": "fail", "error": "Whoops..." }
我是否缺少某种 API 配置,它会使控制器以多态方式序列化结果?
在各个子类和基类型上指定[JsonDerivedType(...)]
似乎可以解决问题,但似乎不是故意的。 这可能会在未来的版本中得到修复。
您必须在序列化时指定基类型才能工作,而无需使用[JsonDerivedType(...)]
注释每个派生类型
var serialized = JsonSerializer.SerializeToDocument<Result[]>(testData);
更新:
这是在此处和此处跟踪的 ASP.NET Core 中的一个已知错误。 (不影响 IEnumerable 结果)
该链接有一个 .NET 团队成员在此评论中使用自定义解析器的解决方法,如下所示
var options = new JsonSerializerOptions { TypeInfoResolver = new InheritedPolymorphismResolver() };
JsonSerializer.Serialize(new Derived(), options); // {"$type":"derived","Y":0,"X":0}
[JsonDerivedType(typeof(Base), typeDiscriminator: "base")]
[JsonDerivedType(typeof(Derived), typeDiscriminator: "derived")]
public class Base
{
public int X { get; set; }
}
public class Derived : Base
{
public int Y { get; set; }
}
public class InheritedPolymorphismResolver : DefaultJsonTypeInfoResolver
{
public override JsonTypeInfo GetTypeInfo(Type type, JsonSerializerOptions options)
{
JsonTypeInfo typeInfo = base.GetTypeInfo(type, options);
// Only handles class hierarchies -- interface hierarchies left out intentionally here
if (!type.IsSealed && typeInfo.PolymorphismOptions is null && type.BaseType != null)
{
// recursively resolve metadata for the base type and extract any derived type declarations that overlap with the current type
JsonPolymorphismOptions? basePolymorphismOptions = GetTypeInfo(type.BaseType, options).PolymorphismOptions;
if (basePolymorphismOptions != null)
{
foreach (JsonDerivedType derivedType in basePolymorphismOptions.DerivedTypes)
{
if (type.IsAssignableFrom(derivedType.DerivedType))
{
typeInfo.PolymorphismOptions ??= new()
{
IgnoreUnrecognizedTypeDiscriminators = basePolymorphismOptions.IgnoreUnrecognizedTypeDiscriminators,
TypeDiscriminatorPropertyName = basePolymorphismOptions.TypeDiscriminatorPropertyName,
UnknownDerivedTypeHandling = basePolymorphismOptions.UnknownDerivedTypeHandling,
};
typeInfo.PolymorphismOptions.DerivedTypes.Add(derivedType);
}
}
}
}
return typeInfo;
}
}
应该固定在.NET 8
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.