Пользовательский JsonConverter с вложенными интерфейсами - PullRequest
0 голосов
/ 01 ноября 2019

У меня есть собственный JsonConverter, который мне нужен для сериализации в моем контроллере ([FromBody]). Проблема в том, что когда у меня есть вложенные интерфейсы для этого свойства, сериализатор воссоздается, поэтому настройка конвертера теряется.

public class ItemController
{
    public async Task<IActionResult> PostItem([FromBody] Item item)
    {
        var itemDocument = await this.itemRepository.CreateItemAsync(item);
        return Ok(itemDocument);
    }
}


public class Item 
{
    [JsonProperty("itemComponent", NullValueHandling = NullValueHandling.Ignore)]
    **[JsonConverter(typeof(ItemComponentConverter))]**
    public IItemComponent ItemComponent { get; internal set; }
}


 public class ItemComponentConverter : JsonConverter
{
    public override bool CanWrite => false;

    public override bool CanConvert(Type objectType) => objectType == typeof(IItemComponent);

    public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer)
    {
        JObject parameters = JToken.ReadFrom(reader) as JObject;

        if (parameters?["$type"] == null)
        {
            return null;
        }

        string itemComponentName = parameters["$type"].Value<string>();

        if (!KnownItemComponents.TryGetKnownComponentType(itemComponentName, out Type itemComponentType))
        {
            return null;
        }

        return parameters.ToObject(itemComponentType, serializer);
    }

    public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer)
    {
        throw new NotSupportedException("Cannot write from " + nameof(ItemComponentConverter));
    }
}

Мое решение до сих пор заключается в добавлении сериализатора как поля в моем конвертере, где я создаю его с правильной сериализацией. Решение, если это вариант. Что касается моего поиска, единственным другим вариантом было перебирать все свойства объекта и иметь переключатель, который создает экземпляр объекта. Это решение не то, что я ищу. Есть ли способ установить или изменить сериализатор?

РЕДАКТИРОВАТЬ:

Это пример объекта, который также работает с первой реализацией:

{
    "key": "612f8544-8489-4571-86b4-118aedb95575",
    "name": "TestItem",
    "component": {
        "ContextKey": "TestKey1",
        "Lhs": "1234",
        "$type": "and"
    }
}

Это пример, где первая реализация не работает. Вот что я подразумеваю под вложенными интерфейсами:

{
    "key": "612f8544-8489-4571-86b4-118aedb95575",
    "name": "TestItem",
    "component": {
        "Left": {
            "ContextKey": "TestKey1",
            "Lhs": "1234",
            "$type": "equals"
        },
        "Right": {
            "ContextKey": "TestKey2",
            "Collection": ["joe", "mark"],
            "$type": "in"
        },
        "$type": "and"
    }
}

Что происходит со вторым примером, так это то, что когда сериализатор пытается определить тип «и», он будет вызывать второй раз, а затем третий разМетод ReadJson для десериализации типов «равно» и «в», которые являются частью одного и того же объекта. Все эти три типа IItemComponent . Вторая реализация решает эту проблему, используя статический сериализатор вместо параметра в параметрах ReadJson.

...