не удалось сериализовать ответ в веб-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свойство исключения сериализации, чтобы узнать, что именно привело к сбою сериализации.
Отображаемое имя

Можете ли вы поделиться кодом для вашего типа сотрудника? Это может быть потому, что тип Employee не сериализуем ...
Мэгги Ин

Также взгляните на этот 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, я получаю эту ошибку. в любом случае ваше решение
устранило

Этот ответ не дает решения использовать xml, и это то, что он просил.
честное слово, 06

У меня работает, когда я перешел на 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
Извините, но что означает это утверждение?
Blaise

5
Строка добавлена ​​к Global.asaxs 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 03

На самом деле это должен быть выбранный ответ, поскольку он не делает никаких предположений о типах возвращаемых значений, которые вам нужны. Это будет работать как для XML, так и для JSON. Спасибо, что разместили это.
Аллен Андервуд,

22

Поместите это в конструктор. Надеюсь, это решит проблему:

    public MyController()
    {

        db.Configuration.ProxyCreationEnabled = false;
    }

Отличное решение. Мне нужно поместить его в конструктор, и он сработал.
InsParbo

У меня это сработало в сочетании с настройками GlobalConfiguration. Но почему это работает? Любое объяснение того, как это решает проблему? А в чем собственно была проблема?
Кьяран Галлахер

Чтобы понять, что такое прокси сущностей: 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 и запустить это переопределение в методе Register в WebApi Config:

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

1
При переходе на List у меня сработало добавление конструктора без параметров, и я мог продолжать возвращать IEnumerable <Widget>
Майк Чил

8

Решение простое.

После запроса LINQ добавьте .ToList () (или ToDictionary, если необходимо).

Он будет загружать быстрее, чем ленивую загрузку данных


1
Для меня сработало изменение типа возврата действия IENumerableи добавление .TiList()к нему.
Рикардо Соуза

5

** эта ошибка возникает при вызове из веб-запроса 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 для API. Найдите в своем проекте файл "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 Entity:

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 умирал в поисках таблицы, которой не было в моей базе данных !!

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.