Ответ на принятый ответ от CMS верен, я только что добавил некоторые функции:
// parse a date time that can contains spaces, dashes, slashes, colons
function parseDate(input) {
// trimes and remove multiple spaces and split by expected characters
var parts = input.trim().replace(/ +(?= )/g,'').split(/[\s-\/:]/)
// new Date(year, month [, day [, hours[, minutes[, seconds[, ms]]]]])
return new Date(parts[0], parts[1]-1, parts[2] || 1, parts[3] || 0, parts[4] || 0, parts[5] || 0); // Note: months are 0-based
}
Кажется, что в иерархии объектов есть циклические ссылки, которые не поддерживаются сериализатором JSON. Вам нужны все столбцы? Вы можете выбрать только те свойства, которые вам нужны в представлении:
return Json(new
{
PropertyINeed1 = data.PropertyINeed1,
PropertyINeed2 = data.PropertyINeed2
});
Это сделает ваш объект JSON более легким и понятным. Если у вас много свойств, AutoMapper может использоваться для автоматически карты между объектами DTO и объектами View.
Я использую исправление, потому что использование нокаута в представлениях MVC5.
В действии
return Json(ModelHelper.GetJsonModel<Core_User>(viewModel));
function
public static TEntity GetJsonModel<TEntity>(TEntity Entity) where TEntity : class
{
TEntity Entity_ = Activator.CreateInstance(typeof(TEntity)) as TEntity;
foreach (var item in Entity.GetType().GetProperties())
{
if (item.PropertyType.ToString().IndexOf("Generic.ICollection") == -1 && item.PropertyType.ToString().IndexOf("SaymenCore.DAL.") == -1)
item.SetValue(Entity_, Entity.GetPropValue(item.Name));
}
return Entity_;
}
Предоставленные ответы хороши, но я думаю, что их можно улучшить, добавив «архитектурную» перспективу.
Исследование
MVC's Controller.Json
выполняет работу, но это очень плохой при предоставлении соответствующей ошибки в этом случае. Используя Newtonsoft.Json.JsonConvert.SerializeObject
, ошибка указывает точно, что такое свойство, которое запускает циклическую ссылку. Это особенно полезно при сериализации более сложных иерархий объектов.
Надлежащая архитектура
Не следует пытаться сериализовать модели данных (например, модели EF), поскольку навигационные свойства ORM - это путь к гибели когда дело доходит до сериализации. Поток данных должен быть следующим:
Database -> data models -> service models -> JSON string
Сервисные модели могут быть получены из моделей данных с использованием автоматических карт (например, Automapper ). Хотя это не гарантирует отсутствие круговых ссылок, правильная конструкция должна это делать: модели обслуживания должны содержать именно то, что требует потребитель услуг (т. Е. Свойства).
В тех редких случаях, когда клиент запрашивает иерархию с использованием одного и того же типа объекта на разных уровнях, служба может создавать линейную структуру с родительскими и дочерними отношениями (используя только идентификаторы, а не ссылки).
Современные приложения стремятся избежать загрузки сложных структур данных одновременно и модели обслуживания должны быть тонкими. Например:
Чтобы подвести итог, есть 3 решения:
private DBEntities db = new DBEntities();//dbcontext
//Solution 1: turn off ProxyCreation for the DBContext and restore it in the end
public ActionResult Index()
{
bool proxyCreation = db.Configuration.ProxyCreationEnabled;
try
{
//set ProxyCreation to false
db.Configuration.ProxyCreationEnabled = false;
var data = db.Products.ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
finally
{
//restore ProxyCreation to its original state
db.Configuration.ProxyCreationEnabled = proxyCreation;
}
}
//Solution 2: Using JsonConvert by Setting ReferenceLoopHandling to ignore on the serializer settings.
//using using Newtonsoft.Json;
public ActionResult Index()
{
try
{
var data = db.Products.ToList();
JsonSerializerSettings jss = new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore };
var result = JsonConvert.SerializeObject(data, Formatting.Indented, jss);
return Json(result, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
//Solution 3: return a new dynamic object which includes only the needed properties.
public ActionResult Index()
{
try
{
var data = db.Products.Select(p => new
{
Product_ID = p.Product_ID,
Product_Name = p.Product_Name,
Product_Price = p.Product_Price
}).ToList();
return Json(data, JsonRequestBehavior.AllowGet);
}
catch (Exception ex)
{
Response.StatusCode = (int)HttpStatusCode.BadRequest;
return Json(ex.Message);
}
}
Вы можете заметить свойства, вызывающие циклическую ссылку. Затем вы можете сделать что-то вроде:
private Object DeCircular(Object object)
{
// Set properties that cause the circular reference to null
return object
}
Это на самом деле происходит потому, что сложные объекты - это то, что заставляет результирующий json-объект терпеть неудачу. И это терпит неудачу, потому что, когда объект отображается, он отображает детей, который отображает их родителей, делая круговую ссылку. Json потребовал бы бесконечного времени для его сериализации, поэтому он предотвращает проблему с исключением.
Отображение структуры Entity Framework также приводит к такому же поведению, и решение состоит в том, чтобы отбросить все нежелательные свойства.
Просто объясняя окончательный ответ, весь код будет выглядеть следующим образом:
public JsonResult getJson()
{
DataContext db = new DataContext ();
return this.Json(
new {
Result = (from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
}
, JsonRequestBehavior.AllowGet
);
}
Он также может быть следующим, если вы не хотите, чтобы объекты внутри свойства Result
:
public JsonResult getJson()
{
DataContext db = new DataContext ();
return this.Json(
(from obj in db.Things select new {Id = obj.Id, Name = obj.Name})
, JsonRequestBehavior.AllowGet
);
}
Из-за нового шаблона DbContext T4, который используется для создания сущностей EntityFramework. Чтобы иметь возможность выполнять отслеживание изменений, в этих шаблонах используется шаблон прокси, путем упаковки ваших хороших POCO с ними. Это приводит к проблемам при сериализации с помощью JavaScriptSerializer.
Итак, два решения:
Очень хорошо объяснено в следующей статье.
http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/
Использование Newtonsoft.Json: в вашем методе Global.asax Application_Start добавьте эту строку:
GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
JSON, например xml и другие форматы, представляет собой формат сериализации на основе дерева. Он не будет любить вас, если у вас есть круглые ссылки в ваших объектах, так как «дерево» будет:
root B => child A => parent B => child A => parent B => ...
Часто существуют способы отключения навигации по определенному пути; например, с XmlSerializer
вы можете пометить родительское свойство как XmlIgnore
. Я не знаю, возможно ли это с помощью json serializer, о котором идет речь, и не имеет ли DatabaseColumn
подходящих маркеров (очень маловероятно, поскольку это должно было бы ссылаться на каждый API сериализации)
Избегайте прямого преобразования объекта таблицы. Если отношения установлены между другими таблицами, это может вызвать эту ошибку. Скорее вы можете создать класс модели, присвоить значения объекту класса и затем сериализовать его.
У меня была та же проблема и решена с помощью using Newtonsoft.Json;
var list = JsonConvert.SerializeObject(model,
Formatting.None,
new JsonSerializerSettings() {
ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});
return Content(list, "application/json");
добавьте [JsonIgnore]
в свойства виртуальных объектов в вашей модели.
Более простой альтернативой для решения этой проблемы является возврат строки и форматирование этой строки в json с помощью JavaScriptSerializer.
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
return j.Serialize(entityList );
}
Важно, чтобы часть «Выбрать», которая выбирает нужные вам свойства на ваш взгляд. У некоторого объекта есть ссылка для родителя. Если вы не выбираете атрибуты, может появиться круговая ссылка, если вы просто возьмете таблицы в целом.
Не делайте этого:
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.toList();
return j.Serialize(entityList );
}
Сделайте это, если вам не нужна вся таблица:
public string GetEntityInJson()
{
JavaScriptSerializer j = new JavaScriptSerializer();
var entityList = dataContext.Entitites.Select(x => new { ID = x.ID, AnotherAttribute = x.AnotherAttribute });
return j.Serialize(entityList );
}
Это помогает визуализировать представление с меньшим количеством данных, только с необходимыми атрибутами, и делает ваш веб-сайт более быстрым.
//first: Create a class as your view model
public class EventViewModel
{
public int Id{get;set}
public string Property1{get;set;}
public string Property2{get;set;}
}
//then from your method
[HttpGet]
public async Task<ActionResult> GetEvent()
{
var events = await db.Event.Find(x => x.ID != 0);
List<EventViewModel> model = events.Select(event => new EventViewModel(){
Id = event.Id,
Property1 = event.Property1,
Property1 = event.Property2
}).ToList();
return Json(new{ data = model }, JsonRequestBehavior.AllowGet);
}