Не удалось сериализовать ответ в веб-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 ответов:
когда речь заходит о возврате данных обратно потребителю из веб-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; }
добавьте этот код в
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;
это сработало для меня
решение, которое сработало для меня:
используйте [DataContract] для атрибутов класса и [DataMember] для каждого свойства для сериализации.Этого достаточно, чтобы получить результат Json (например. от скрипача).
чтобы получить XML-сериализацию, напишите в Global.эйсакс этот код:
var xml = GlobalConfiguration.Конфигурация.Форматеры.XmlFormatter; XML.UseXmlSerializer = true;
- прочитайте эту статью, это помогло мне понять сериализация: 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