System.Json.Net — десериализация Task‹T› не удалась (нет конструктора без параметров)

У меня возникла проблема, когда я не могу десериализовать строку в задачу, используя System.Text.Json (.Net 5).

JsonSerializer.Deserialize<Task<TItem>>(serializedItem)

Фон

У меня есть локализованный кеш и я храню в нем элементы, полученные из БД.

Я не могу сохранить фактический элемент в кеше, потому что любое последующее манипулирование объектом приводит к тому, что кешированный элемент становится манипулятивным, что влияет на все дальнейшие использования. Поэтому я храню сериализованную копию объекта.

По поводу производительности...

Я использую шаблон async/await для вызова БД (все приложение асинхронно).

Я прочитал статью (возможно, это было видео), в которой Стивен Тауб описал преимущество кэширования задачи в производительности. В этой статье SO Когда кэшировать задачи? подробно рассказывается. Во всяком случае, я подумал, что попытаюсь воспользоваться этим (он отлично работает без сериализации), используя следующее в моем локальном слое кеша:

  1. Если Task находится в моем кеше, дождитесь его и верните результат.
  2. В противном случае вызовите метод БД, не дожидаясь его, и добавьте результирующую задачу в кеш.

Когда я добавляю сериализацию, то десериализация задачи:

Task<TItem>? cachedItem = JsonSerializer.Deserialize<Task<TItem>>(serializedItem);

приводит к

Десериализация типов без конструктора без параметров, отдельного параметризованного конструктора или параметризованного конструктора с аннотацией JsonConstructorAttribute не поддерживается.


person DrGriff    schedule 25.09.2020    source источник
comment
Как это связано с async-await? Это работает, если это синхронно?   -  person Paulo Morgado    schedule 25.09.2020
comment
Вы не можете сериализовать или десериализовать Task<T>, это операция, которая асинхронно возвращает свой результат, а не объект данных, из которого можно получить осмысленный контракт. Он обертывает Action<T> или другой делегат, и вы не можете сериализовать делегата. См.: почему BinaryFormatter может сериализовать действие‹›, а Json.net не может. Конечно, этот ответ предназначен для json.net, но system.text.json еще более ограничен и даже не пытается поддерживать [Serializable] сериализацию, поскольку сериализует не элементы, а только свойства.   -  person dbc    schedule 25.09.2020
comment
И хотя Action<T> технически помечен как [Serializable], Task<T> не, поэтому нет причин думать, что его можно сериализовать.   -  person dbc    schedule 25.09.2020
comment
Этого достаточно для ответа?   -  person dbc    schedule 26.09.2020


Ответы (1)


Ответ здесь относительно прост — сериализуйте данные внутри результата задачи, а не саму задачу.

Если вы не используете что-то вроде memcached, а используете что-то вроде простого Dictionary внутрипроцессного кэша объектов, то сериализация и десериализация кажутся довольно сложным подходом к клонированию объектов.

person Mike Marynowski    schedule 02.12.2020