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


Я работаю с ASP.NET MVC 5 Web Api. Я хочу проконсультироваться со всеми моими пользователями.

я писал api/users и я получаю это:

"типу' ObjectContent ' 1 'не удалось сериализовать тело ответа для типа контента' application / json; charset=utf-8'"

В WebApiConfig, уже я добавил Эти строки:

HttpConfiguration config = new HttpConfiguration();
config.Formatters.XmlFormatter.SupportedMediaTypes.Remove(appXmlType);
config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore; 

но это все равно не сработает.

моя функция для возврата данных это:

public IEnumerable<User> GetAll()
{
    using (Database db = new Database())
    {
        return db.Users.ToList();
    }
}
18 81

18 ответов:

когда речь заходит о возврате данных обратно потребителю из веб-Api (или любой другой веб-службы в этом отношении), я настоятельно рекомендую не передавать обратно объекты, которые поступают из базы данных. Гораздо надежнее и ремонтопригоднее использовать модели, в которых вы управляете тем, как выглядят данные, а не базой данных. Таким образом, вам не придется возиться с форматерами так много в WebApiConfig. Вы можете просто создать пользовательскую модель, которая имеет дочерние модели в качестве свойств и избавиться от них ссылочные циклы в возвращаемых объектах. Это делает сериализатор намного счастливее.

кроме того, обычно нет необходимости удалять формататоры или поддерживаемые типы носителей, если вы просто указываете заголовок "Accepts" в запросе. Игра с этим материалом иногда может сделать вещи более запутанными.

пример:

public class UserModel {
    public string Name {get;set;}
    public string Age {get;set;}
    // Other properties here that do not reference another UserModel class.
}

Если вы работаете с EF, помимо добавления кода ниже на Global.асакс

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

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

using System.Data.Entity;

тогда вы можете вернуть свои собственные модели EF

просто!

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

лучше использовать его в конструкторе dbcontext

public DbContext() // dbcontext constructor
            : base("name=ConnectionStringNameFromWebConfig")
{
     this.Configuration.LazyLoadingEnabled = false;
     this.Configuration.ProxyCreationEnabled = false;
}

Asp.Net ошибка веб-API: тип 'ObjectContent' 1 'не удалось сериализовать тело ответа для типа контента' application / xml; charset=utf-8'

добавьте этот код в global.asax ниже Application_Start:

обновление от .Ignore до .Serialize . Это должно сработать.

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
            GlobalConfiguration.Configuration.Formatters.Remove(GlobalConfiguration.Configuration.Formatters.XmlFormatter);
public class UserController : ApiController
{

   Database db = new Database();

   // construction
   public UserController()
   {
      // Add the following code
      // problem will be solved
      db.Configuration.ProxyCreationEnabled = false;
   }

   public IEnumerable<User> GetAll()
    {
            return db.Users.ToList();
    }
}

мне не нравится этот код:

foreach(var user in db.Users)

в качестве альтернативы можно было бы сделать что-то вроде этого, что сработало для меня:

var listOfUsers = db.Users.Select(r => new UserModel
                         {
                             userModel.FirstName = r.FirstName;
                             userModel.LastName = r.LastName;

                         });

return listOfUsers.ToList();

тем не менее, я в конечном итоге использовал решение Лукаса Роселли.

обновление: упрощено путем возврата анонимного объекта:

var listOfUsers = db.Users.Select(r => new 
                         {
                             FirstName = r.FirstName;
                             LastName = r.LastName;
                         });

return listOfUsers.ToList();

есть также этот сценарий, который генерирует ту же ошибку:

В случае возврата являясь List<dynamic> к методу web api

пример:

public HttpResponseMessage Get()
{
    var item = new List<dynamic> { new TestClass { Name = "Ale", Age = 30 } };

    return Request.CreateResponse(HttpStatusCode.OK, item);
}

public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

Итак, для этого сценария используйте [KnownTypeAttribute] в возвращаемом классе (все они) следующим образом:

[KnownTypeAttribute(typeof(TestClass))]
public class TestClass
{
    public string Name { get; set; }
    public int Age { get; set; }
}

это работает для меня!

Я решил его с помощью этого кода для WebApiConfig.cs file

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

мой личный фаворит: просто добавьте код ниже, чтобы App_Start/WebApiConfig.cs. Это вернет json вместо XML по умолчанию, а также предотвратит ошибку, которую вы имели. Нет необходимости редактировать Global.asax удалить XmlFormatter etc.

типу 'ObjectContent' 1 'не удалось сериализовать тело ответа для типа контента' application / xml; charset=utf-8

config.Formatters.JsonFormatter.SupportedMediaTypes.Add(new MediaTypeHeaderValue("text/html"));

Использовать AutoMapper...

public IEnumerable<User> GetAll()
    {
        using (Database db = new Database())
        {
            var users = AutoMapper.Mapper.DynamicMap<List<User>>(db.Users);
            return users;
        }
    }

используйте следующее пространство имен:

using System.Web.OData;

вместо :

using System.Web.Http.OData;

это сработало для меня

решение, которое сработало для меня:

  1. используйте [DataContract] для атрибутов класса и [DataMember] для каждого свойства для сериализации.Этого достаточно, чтобы получить результат Json (например. от скрипача).

  2. чтобы получить XML-сериализацию, напишите в Global.эйсакс этот код:

    var xml = GlobalConfiguration.Конфигурация.Форматеры.XmlFormatter; XML.UseXmlSerializer = true;

  3. прочитайте эту статью, это помогло мне понять сериализация: https://www.asp.net/web-api/overview/formats-and-model-binding/json-and-xml-serialization

чтобы добавить к ответу йенсендпа:

Я бы передал сущность созданной пользователем модели и использовал значения из этой сущности для установки значений в вашей вновь созданной модели. Например:

public class UserInformation {
   public string Name { get; set; }
   public int Age { get; set; }

   public UserInformation(UserEntity user) {
      this.Name = user.name;
      this.Age = user.age;
   }
}

затем измените тип возврата на:IEnumerable<UserInformation>

Если вы работаете с EntityFramework, вы должны отключить прокси в конструкторе класса DbContext как,

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.ProxyCreationEnabled = false;
  }
}

другой случай, когда я получил эту ошибку, был, когда мой запрос базы данных вернул нулевое значение, но мой тип модели пользователя/представления был установлен как ненулевой. Например, изменение поля UserModel из int до int? решены.

Это также происходит, когда тип ответа не является общедоступным! Я вернул внутренний класс, как я использовал Visual Studio, чтобы создать мне тип.

internal class --> public class

хотя все эти ответы выше верны, можно проверить InnerException > ExceptionMessage.

если он говорит что-то вроде этого "Tэкземпляр ObjectContext был удален и больше не может использоваться для операций, требующих подключения.". Это может быть проблемой из-за поведения EF по умолчанию.

с присвоением LazyLoadingEnabled = false в вашем конструкторе DbContext будет делать уловка.

public class MyDbContext : DbContext
{
  public MyDbContext()
  {
    this.Configuration.LazyLoadingEnabled = false;
  }
}

для более подробного чтения о EagerLoading и LazyLoading поведении EF обратитесь к этому статья MSDN.

в моем случае у меня было подобное сообщение об ошибке:

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

но когда я копаю глубже в нем, проблема была:

тип 'имя.SomeSubRootType' с именем контракта данных 'SomeSubRootType: / / schemas. datacontract. org/2004/07/WhatEverService' не ожидается. Рассмотрите возможность использования DataContractResolver если вы использование DataContractSerializer или добавление любых типов, не известных статически список известных типов, например, с помощью KnownTypeAttribute атрибут или путем добавления их к списку известных типов переданных к сериализатор.

Как я решил, добавив KnownType.

[KnownType(typeof(SomeSubRootType))]
public partial class SomeRootStructureType

Это было решено вдохновленный от этого ответ.

ссылка:https://msdn.microsoft.com/en-us/library/ms730167 (v=vs. 100). aspx