Десериализация типов интерфейсов, не поддерживаемых в запросе API

#c# #.net #api #.net-core #interface

Вопрос:

Я получаю эту систему сообщений об ошибках.Исключение NotSupportedException: Десериализация типов интерфейсов не поддерживается.

при вызове API, который принял запрос, как указано ниже.

пример

 [HttpPost]  public IActionResult AddSomeData(MyClass MyClass)  {  return Ok();  }    public class MyClass : MyInterface  {  return Ok();  }    public interface MyInterface   {  public string SomeOtherProperties { get; set; }   public MyInterface Property { get; set; } //Or reference of any other interface  }  

Я пробовал примеры, приведенные в Интернете, такие как создание конкретного класса и добавление атрибута поверх свойства. Но это не помогает.

В качестве обходного пути я удалил общедоступное свойство MyInterface { get; set; } и добавил общедоступное свойство MyClass { get; set; }

Есть ли лучшее решение для этого?

Комментарии:

1. Вы используете что-то вроде ASP.NET или ASP.NET Ядро? Я предполагаю, что это так, [HttpPost] но, с другой стороны, другие библиотеки могли бы следовать аналогичной схеме.

2. На очень наивном уровне десериализатору придется new() обновить ваш экземпляр, а затем установить значения для каждого свойства в этом экземпляре, как десериализатор обновит интерфейс?

3. Привязка MVC требует, чтобы все типы можно было обнаружить с помощью отражения во время запуска (единственным реальным исключением являются общие коллекции). Хотя вы можете написать свой собственный поставщик привязки для создания подтипов, я бы не рекомендовал этого делать. Можете ли вы использовать универсальные средства для определения типа Property ?

Ответ №1:

Проблема с десериализацией в интерфейс заключается в том, что вы теряете информацию

 public class MyClass : MyInterface {  public string SomeOtherProperties { get; set; }  public MyInterface Property { get; set; }  public string importantString { get; set; } = "Don't lose me please"; }  public interface MyInterface {  string SomeOtherProperties { get; set; }  MyInterface Property { get; set; } }  

Возьмем приведенный выше пример, попытка десериализации в интерфейс потребует указания десериализатору знать только о свойствах интерфейса, а любые другие поля, которые предоставляет ваш конечный пользователь, будут полностью удалены. Кроме того, у вас могут быть методы в конкретном классе, которые поддерживают свойства интерфейса, которые должны существовать.

Есть несколько вариантов, связанных с отражением, которые вы могли бы использовать, если вам нужен API для поддержки нескольких реализаций интерфейса, но вопрос в том, зачем вам нужен интерфейс в первую очередь? Предполагается, что API должен четко определять, что должно быть предоставлено пользователем, абстрагирование этого с помощью интерфейса, который должен быть реализован каким-то конкретным классом, кажется плохой идеей.

Редактировать: если все, что вам нужно, — это общая информация, и в ней нет ничего необычного, вы можете просто использовать MyInterface в качестве стандартного класса

 public class MyClass : MyInterface {  public string nonImportantString { get; set; } = "lose me"; } public class MyInterface {  public string SomeOtherProperties { get; set; }  public MyInterface Property { get; set; } }  

При этом ваш api чист, и вы можете десериализоваться нормально