Генерация VS Swagger с двойным наследием и дискриминатором
Замечание: VS использует для генерации кода NSwag библиотеки
Есть сваггер:
{
"openapi": "3.0.1",
"info": {...},
"servers": [...],
"paths": {...},
"components": {
"schemas": {
"Interface": {
"type": "object",
"properties": {...},
"discriminator": {
"propertyName": "ByClass",
"mapping": {
"1_1": "#/components/schemas/Class1_1",
"1_2": "#/components/schemas/Class1_2"
}
}
},
"Class1_1": {
"allOf": [
{"$ref": "#/components/schemas/Interface"},
{
"type": "object",
"properties": {...}
}
],
"discriminator": {
"propertyName": "BySubClass",
"mapping": {
"2_1": "#/components/schemas/Class2_1",
"2_2": "#/components/schemas/Class2_2"
}
}
}
"Class1_2": {
"allOf": [
{"$ref": "#/components/schemas/Interface"},
{
"type": "object",
"properties": {...}
}
]
}
"Class2_1": {
"allOf": [
{"$ref": "#/components/schemas/Class1_1"},
{
"type": "object",
"properties": {...}
}
]
}
"Class2_2": {
"allOf": [
{"$ref": "#/components/schemas/Class1_1"},
{
"type": "object",
"properties": {...}
}
]
}
}
}
}
По факту описывает наследование классов
Interface ┬-> Class1_1 ┬-> Class2_1
│ └-> Class2_2
└-> Class1_2
И дискриминаторы.
Таким образом если у ресурса есть 2 поля
{
"ByClass": "1_1",
"BySubClass": "2_1",
...
}
то код, сгенереный в VS должен при десериализации сделать класс Class2_1
Но сделает он класс Class1_1
, и вот почему, при генерации будет следующий код:
[Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), "ByClass")]
[JsonInheritanceAttribute("1_1", typeof(Class1_1))]
[JsonInheritanceAttribute("1_2", typeof(Class1_2))]
[JsonInheritanceAttribute("2_1", typeof(Class2_1))]
[JsonInheritanceAttribute("2_2", typeof(Class2_1))]
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.0.22.0 (Newtonsoft.Json v11.0.0.0)")]
public partial class Interface
{
...
}
Таким образом теряется дискриминатор BySubClass
и поэтому вернётся экземпляр Class1_1
и даже если явно перенести в Class1_1
[JsonInheritanceAttribute("2_1", typeof(Class2_1))]
[JsonInheritanceAttribute("2_2", typeof(Class2_1))]
и добавить
[Newtonsoft.Json.JsonConverter(typeof(JsonInheritanceConverter), "BySubClass")]
то всё равно вернётся класс Class1_1
и вот почему:
[System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.0.22.0 (Newtonsoft.Json v11.0.0.0)")]
internal class JsonInheritanceConverter : Newtonsoft.Json.JsonConverter
{
...
public override bool CanRead
{
get
{
if (_isReading)
{
_isReading = false;
return false;
}
return true;
}
}
...
}
при двойной сериализации класса, второй раз подряд этот конвертер не отработает.
Я пошёл дальше и изменил строчку в этом сериализаторе:
public override object ReadJson(Newtonsoft.Json.JsonReader reader, System.Type objectType, object existingValue, Newtonsoft.Json.JsonSerializer serializer)
{
...
try
{
_isReading = subtype == objectType;// Была добавлена эта строчка
return serializer.Deserialize(jObject.CreateReader(), subtype);
}
finally
{
_isReading = false;
}
}
и всё заработало, но теперь вопрос, как без этих танцев сделать чтобы сгенеренный код верно парсил ресурс?