не вдалося серіалізувати відповідь у веб-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.