.NET7 Web API 中的 JSON 多态序列化

Mok*_*oki 5 c# json asp.net-core system.text.json .net-7.0

.NET7 包括对序列化器的许多改进System.Text.Json,其中之一是使用新[JsonPolymorphic]属性的类型的多态序列化。我正在尝试在我的 Asp.Net Web API 中使用它,但是尽管模型已正确设置,但它似乎并未序列化类型鉴别器。

仅当尝试通过网络发送对象时才会发生这种情况,当使用 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;
Run Code Online (Sandbox Code Playgroud)
// 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);
Run Code Online (Sandbox Code Playgroud)
// 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...");
Run Code Online (Sandbox Code Playgroud)

这些响应都没有使用类型鉴别器进行注释,并且我的强类型客户端无法将结果反序列化为正确的层次结构。

GET /api/ok HTTP/1.1
# =>
# ACTUAL: {}
# EXPECTED: { "$type": "ok" }
Run Code Online (Sandbox Code Playgroud)
GET /api/fail HTTP/1.1
# =>
# ACTUAL: { "error": "Whoops..." }
# EXPECTED: { "$type": "fail", "error": "Whoops..." }
Run Code Online (Sandbox Code Playgroud)

我是否缺少某种 API 配置,使控制器以多态方式序列化结果?

Mok*_*oki 9

指定[JsonDerivedType(...)]各个子类基本类型似乎可以解决问题,但似乎并不是故意的。这可能会在未来的版本中得到修复。

[JsonPolymorphic]
[JsonDerivedType(typeof(SuccesfulResult), typeDiscriminator: "ok")]
[JsonDerivedType(typeof(ErrorResult), typeDiscriminator: "fail")]
public abstract record Result;

[JsonDerivedType(typeof(SuccesfulResult), typeDiscriminator: "ok")]
public record SuccesfulResult : Result;

[JsonDerivedType(typeof(ErrorResult), typeDiscriminator: "fail")]
public record ErrorResult(string Error) : Result;
Run Code Online (Sandbox Code Playgroud)