не вдалося серіалізувати відповідь у веб-API


86

Я працював над веб-API ASP.NET MVC, у мене виникла така помилка:

Тип 'ObjectContent`1' не зміг серіалізувати тіло відповіді для типу вмісту 'application / xml; charset = utf-8 '.

Мій контролер:

public Employee GetEmployees()
{
    Employee employees = db.Employees.First();
    return employees;
}

чому я отримую цю помилку?


6
Виняток, який ви бачите, - загальний виняток, який може бути спричинений будь-якою кількістю факторів. Перевірте InnerExceptionвластивість виключення серіалізації, щоб з’ясувати, що саме спричинило помилку серіалізації.
— Відображуване ім’я

Чи можете ви поділитися кодом для вашого працівника? Можливо, це пов’язано з тим, що тип Службовець не піддається серіалізації ...
— Меггі Ін

Крім того , подивіться на цю stackoverflow.com/questions/8173524 / ...
— sttaq

Відповіді:


121

Для мене це була проблема з круговим посиланням.

Прийнята відповідь не спрацювала для мене, оскільки вона лише змінює поведінку форматора JSON, але я отримував XML, коли зателефонував до служби з браузера.

Щоб виправити це, я вимкнув XML і змусив повернути лише JSON.

У файлі Global.asax поставте такі рядки у верхній частині методу Application_Start:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Тепер будуть повернуті лише результати JSON. Якщо вам потрібні результати XML, вам потрібно буде знайти інше рішення.


працював у мене. але справа в тому, що я використовую POSTMAN. це хромоване розширення. коли я публікую дані за допомогою POSTMAN, це працює нормально. але коли я використовую restsharp, це видає мені цю помилку. у будь-якому разі ваше рішення виправило мою проблему
— ArgeKumandan

Ця відповідь не пропонує рішення щодо використання xml, і саме про це він просив.
— fairduane

Працює для мене, коли я перейшов на json з xml.
— Sike12

Насправді ця відповідь сягає кореня проблеми. Першою помилкою, яку я отримав, була кругова помилка посилання (спроба повернути JSON з контролера MVC). Коли я перейшов на контролер, успадкований API, я натомість почав отримувати цю помилку. Коли я додав наведений вище код до Global.asax, помилка зникла.
— Метью Піттс,

43

у вашому файлі global.asax у метод Application_start () додайте такий рядок:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;

Сподіваюся, це вам допоможе!


3
Що таке application_start і де його можна знайти? А де саме слід розмістити цей рядок?
— Ciaran Gallagher

4
Вибачте, але що означає це твердження?
— Блез

5
Рядок додано до Global.asax"" Application_Start, але без змін.
— cheesus

8
Це все ще не працювало для мене. Однак я додав ще один рядок після рядка у цій відповіді, і він спрацював: GlobalConfiguration.Configuration.Formatters.Remove (GlobalConfiguration.Configuration.Formatters.XmlFormatter); Я створив більш повну відповідь нижче
— Зейн

2
Цю відповідь не слід приймати, оскільки вона дійсно видаляє XmlSerializer, а не вирішує проблему кругового посилання за допомогою XmlSerializer.
— Believe2014

29

У мене така сама проблема. І я це вирішив. Я помістив конструктор за замовчуванням у клас DTO.

Приклад:

public class User
{
    public User()
    {
    }
}

Сподіваюся, це спрацює з вами!


Дякую за пропозицію, це допомогло мені з відповіддю xml, але хтось знає, навіщо йому потрібен конструктор за замовчуванням? Дані ми вже маємо ...
— Ілля Чорномордик

Я думаю, коли об'єкт серіалізується з відповіді, спочатку конструктор був викликаний для створення екземпляра об'єкта, після цього метод set використовується для встановлення даних на екземпляр об'єкта. Це моє припущення.
— taynguyen

Це насправді повинна бути обрана відповідь, оскільки вона не робить жодних припущень щодо типів повернення, які вам потрібні. Це буде працювати як для XML, так і для JSON. Дякуємо, що розмістили це.
— Аллен Андервуд

22

Помістіть це в конструктор. Сподіваюся, це вирішить проблему:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }

Відмінне рішення. Мені потрібно помістити його в конструктор, і він спрацював.
— InsParbo

Це працювало у мене в поєднанні з налаштуваннями GlobalConfiguration. Але чому це працює? Будь-яке пояснення щодо того, як це вирішує проблему? І в чому була проблема насправді?
— Ciaran Gallagher

Щоб зрозуміти , що об'єктні проксі: msdn.microsoft.com/en-us/library/jj592886(v=vs.113).aspx щоб зрозуміти , що ProxyCreationEnabled є: stackoverflow.com/questions/7111109 / ...
— Sadjad Khazaie

16

Я знайшов два рішення цього. Першим і найпростішим у реалізації є зміна будь-яких IEnumerables, ICollections на тип List. WebAPI може серіалізувати ці об'єкти, однак не може серіалізувати типи інтерфейсу.

public class Store
{

  [StringLength(5)]
    public string Zip5 { get; set; }

    public virtual List<StoreReport> StoreReports { get; set; }  //use a list here
 }

Інший варіант - не використовувати власний серіалізатор JSON і запустити це перевизначення в методі Реєстрації WebApi Config:

        var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        config.Formatters.Remove(config.Formatters.XmlFormatter);

1
Поки зміна на List працювала для мене, додавання
— безпараметричного

8

Рішення просте.

Після запиту LINQ додайте .ToList () (або ToDictionary, якщо потрібно).

Це зробить бажання завантаження, ніж ліниве завантаження даних


1
Зміна типу повернення дії на IENumerableта додавання .TiList()до повернення спрацювало для мене.
— Рікардо Соуза,

5

** ця помилка виникає при виклику із веб-запиту web api / wcf / ... з боку клієнта, але як побічний ефект вам потрібно буде включити залежні відносини за ключовим словом include. **

public CustomerPortalContext()
            : base("Name=CustomerPortalContext")
        {
            base.Configuration.ProxyCreationEnabled = false;
        }

4

Якщо ви працюєте з EF, окрім додавання коду нижче на Global.asax

            GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);          

Не забудьте імпортувати

using System.Data.Entity;

Тоді ви можете повернути свої власні моделі EF



3

Якщо ви використовуєте веб-api з Entity Framework, рішення може бути серіалізувати відповідь у веб-API за допомогою Json

В основному, вам потрібно створити модель, що відповідає кожній моделі EF, це видаляє залежності між класами і дозволяє легку серіалізацію.

Код: (взято з посилання)

Створіть UserModel

public class UserModel
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

Змінити мій метод GetAll ()

public IEnumerable<UserModel> GetAll()
{
    using (Database db = new Database ())
    {
        List<UserModel> listOfUsers = new List<UserModel>();
        UserModel userModel = new UserModel();
        foreach(var user in db.Users)
        {
           userModel.FirstName = user.FirstName;
           userModel.LastName = user.LastName;
           listOfUsers.Add(userModel);
        }
        IEnumerable<UserModel> users = listOfUsers;

        return users;
    }
}

2

Entity 6 за замовчуванням використовує XML для apis, у вашому проекті знайдіть файл "Global.asax" і додайте цей рядок:

GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);

Цей рядок видаляє формат XML.


Привіт, веб-API серіалізує відповідь у XML та JSON, якщо ви додаєте заголовок Content-Type: application / json, відповідь у JSON, вам потрібно визначити цей заголовок, у браузері ви завжди зможете побачити його як формат XML
— Роберт Соліс

1

але якщо ви виявили цю проблему з іншими сутностями / класами, вам доведеться створити новий DTO для кожного класу, і якщо їх у вас багато, ви можете знайти проблему, також я думаю, що створити DTO лише для вирішення цієї проблеми це не найкращий спосіб ...

Ви спробували це?

var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
json.SerializerSettings.PreserveReferencesHandling = 
Newtonsoft.Json.PreserveReferencesHandling.All;

З повагою


1

мммм, наступне може допомогти.

Я отримував той самий виняток, і в моєму випадку спочатку передавав фактичну сутність poco, створену для коду сутності. Оскільки він містить зв'язок з іншими сутностями, я щойно створив сутність viewmapper / dto поверх нього для повернення.

Зараз це чудово працює.

Суб'єкт Poco:

public class Tag
{
public int Id{get;set;}
public string Title{get;set;}
public IList<Location> Locations{get;set;}
}

ViewMapper / Dto

public class TagResultsViewMapper
{
public int Id{get;set;}
public string Title{get;set;}
//just remove the following relationship 
//public IList<Location> Locations{get;set;}
}

0

Ваше запитання дуже схоже на моє. Ви не повинні повертати дані з бази даних безпосередньо. Для цього потрібно створити модель та пов’язати дані, які ви хочете показати.

У моєму прикладі є дані про Користувача, які Json не міг серіалізувати, я створив userModel, і в своєму API я повертаю userModel замість User з бази даних.

Логіка перетворення або асоціювання даних між User і UserModel повинна бути в API.

Не вдалося серіалізувати відповідь у веб-API за допомогою Json


0

Це була конкретна помилка, яку я отримував від мого виклику веб-API odata:

The 'ObjectContent`1' type failed to serialize the response 
body for content type 'application/json; odata.metadata=minimal'.

Нарешті я зрозумів, що в моєму класі dbContext є файл відформатоване ім'я таблиці , призначене в onModelCreating .., тож SqlClient вмирав, шукаючи таблицю, якої не було в моєму db !!

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.