Круговая ссылка была обнаружена при сериализации объекта (ASP.NET) [дубликат]

Twilio developer evangelist здесь.

Похоже, вы обновили версию с версии 4 до версии 5 библиотеки Twilio C # . Это было обновление с нарушением изменений, и здесь доступен полный файл обновления . .

Для отправки сообщений вам необходимо обновить, чтобы использовать новый MessageResource . Вот пример:

using System;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using Twilio.Types;
using System.Collections.Generic;

class Example
{
   static void Main(string[] args)
   {
        // Find your Account Sid and Auth Token at twilio.com/console
        const string accountSid = "your_account_sid";
        const string authToken = "your_auth_token";
        TwilioClient.Init(accountSid, authToken);

        var to = new PhoneNumber("+15017250604");
        var message = MessageResource.Create(
            to,
            from: new PhoneNumber("+15558675309"),
            body: "This is the ship that made the Kessel Run in fourteen parsecs?");
        Console.WriteLine(message.Sid);
   }
}

Дайте мне знать, если это поможет.

156
задан Glauco Vinicius 21 February 2013 в 15:02
поделиться

14 ответов

Кажется, что в иерархии объектов есть циклические ссылки, которые не поддерживаются сериализатором JSON. Вам нужны все столбцы? Вы можете выбрать только те свойства, которые вам нужны в представлении:

return Json(new 
{  
    PropertyINeed1 = data.PropertyINeed1,
    PropertyINeed2 = data.PropertyINeed2
});

Это сделает ваш объект JSON более легким и понятным. Если у вас много свойств, AutoMapper может использоваться для автоматически карты между объектами DTO и объектами View.

163
ответ дан Darin Dimitrov 22 August 2018 в 20:09
поделиться
  • 1
    Я думаю, что, возможно, выбор тех, которые я хочу, может работать. Думаю, круговая ссылка заключается в том, что в Event I есть IQueryable & lt; Category & gt; который, в свою очередь, будет иметь IQueryable & lt; Event & gt; – Jon 20 July 2009 в 14:06
  • 2
    Automapper не гарантирует, что вы не получите эту проблему. Я пришел сюда, чтобы найти ответ, и я фактически использую automapper. – Captain Kenpachi 14 August 2013 в 11:43
  • 3
    Посмотрите ответ от @ClayKaboom, так как он объясняет, почему он может быть круговым – PandaWood 4 March 2014 в 01:15

Я использую исправление, потому что использование нокаута в представлениях 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_;  
    }
1
ответ дан A.Kosecik 22 August 2018 в 20:09
поделиться

Предоставленные ответы хороши, но я думаю, что их можно улучшить, добавив «архитектурную» перспективу.

Исследование

MVC's Controller.Json выполняет работу, но это очень плохой при предоставлении соответствующей ошибки в этом случае. Используя Newtonsoft.Json.JsonConvert.SerializeObject, ошибка указывает точно, что такое свойство, которое запускает циклическую ссылку. Это особенно полезно при сериализации более сложных иерархий объектов.

Надлежащая архитектура

Не следует пытаться сериализовать модели данных (например, модели EF), поскольку навигационные свойства ORM - это путь к гибели когда дело доходит до сериализации. Поток данных должен быть следующим:

Database -> data models -> service models -> JSON string 

Сервисные модели могут быть получены из моделей данных с использованием автоматических карт (например, Automapper ). Хотя это не гарантирует отсутствие круговых ссылок, правильная конструкция должна это делать: модели обслуживания должны содержать именно то, что требует потребитель услуг (т. Е. Свойства).

В тех редких случаях, когда клиент запрашивает иерархию с использованием одного и того же типа объекта на разных уровнях, служба может создавать линейную структуру с родительскими и дочерними отношениями (используя только идентификаторы, а не ссылки).

Современные приложения стремятся избежать загрузки сложных структур данных одновременно и модели обслуживания должны быть тонкими. Например:

  1. загружается только данные заголовка события (идентификатор, имя, дата и т. Д.) -> модель обслуживания (JSON), содержащая только данные заголовка
  2. управляемых посетителей list - доступ к всплывающей и ленивой загрузке списка -> сервисная модель (JSON), содержащая только список участников
2
ответ дан Alexei 22 August 2018 в 20:09
поделиться

Чтобы подвести итог, есть 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);
        }
    }
9
ответ дан Amro 22 August 2018 в 20:09
поделиться

Вы можете заметить свойства, вызывающие циклическую ссылку. Затем вы можете сделать что-то вроде:

private Object DeCircular(Object object)
{
   // Set properties that cause the circular reference to null

   return object
}
0
ответ дан Bassil 22 August 2018 в 20:09
поделиться

Это на самом деле происходит потому, что сложные объекты - это то, что заставляет результирующий 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
           );
}
51
ответ дан ClayKaboom 22 August 2018 в 20:09
поделиться
  • 1
    +1 для четких и понятных вещей, спасибо @ Clay. Мне нравится ваше объяснение относительно концепций ошибки. – Ajay2707 26 July 2017 в 13:28

Из-за нового шаблона DbContext T4, который используется для создания сущностей EntityFramework. Чтобы иметь возможность выполнять отслеживание изменений, в этих шаблонах используется шаблон прокси, путем упаковки ваших хороших POCO с ними. Это приводит к проблемам при сериализации с помощью JavaScriptSerializer.

Итак, два решения:

  1. Либо вы просто сериализуете и возвращаете нужные свойства на клиенте
  2. Вы можете отключить автоматическую генерацию прокси, установив ее в контекст конфигурации контекста. Configuration.ProxyCreationEnabled = false;

Очень хорошо объяснено в следующей статье.

http://juristr.com/blog/2011/08/javascriptserializer-circular-reference/

4
ответ дан Juri 22 August 2018 в 20:09
поделиться

Использование Newtonsoft.Json: в вашем методе Global.asax Application_Start добавьте эту строку:

GlobalConfiguration.Configuration.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
4
ответ дан kravits88 22 August 2018 в 20:09
поделиться

JSON, например xml и другие форматы, представляет собой формат сериализации на основе дерева. Он не будет любить вас, если у вас есть круглые ссылки в ваших объектах, так как «дерево» будет:

root B => child A => parent B => child A => parent B => ...

Часто существуют способы отключения навигации по определенному пути; например, с XmlSerializer вы можете пометить родительское свойство как XmlIgnore. Я не знаю, возможно ли это с помощью json serializer, о котором идет речь, и не имеет ли DatabaseColumn подходящих маркеров (очень маловероятно, поскольку это должно было бы ссылаться на каждый API сериализации)

7
ответ дан Marc Gravell 22 August 2018 в 20:09
поделиться

Избегайте прямого преобразования объекта таблицы. Если отношения установлены между другими таблицами, это может вызвать эту ошибку. Скорее вы можете создать класс модели, присвоить значения объекту класса и затем сериализовать его.

4
ответ дан Mathemats 22 August 2018 в 20:09
поделиться

У меня была та же проблема и решена с помощью using Newtonsoft.Json;

var list = JsonConvert.SerializeObject(model,
    Formatting.None,
    new JsonSerializerSettings() {
        ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
});

return Content(list, "application/json");
82
ответ дан Rob Church 22 August 2018 в 20:09
поделиться
  • 1
    Этот встроенный код работал отлично для меня. Тот же материал в глобальной конфигурации, о котором упоминал kravits88, не работает для меня. ТАКЖЕ, подпись метода должна быть обновлена, чтобы возвращать ContentResult для этого кода. – BiLaL 23 April 2015 в 09:51
  • 2
    отличное решение .. спасибо – Anupam Singh 15 June 2015 в 11:34
  • 3
    Это должно быть отмечено как лучший ответ, поскольку оно охватывает случаи, когда вы не можете тратить часы на преобразование ваших объектов в другие представления, как в ответе, отмеченном как принятое. – Renan 27 March 2017 в 19:58
  • 4
    Хороший ответ, решил мою проблему – Shah NIral 3 August 2017 в 09:07

добавьте [JsonIgnore] в свойства виртуальных объектов в вашей модели.

4
ответ дан Roman Marusyk 22 August 2018 в 20:09
поделиться

Более простой альтернативой для решения этой проблемы является возврат строки и форматирование этой строки в 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 );
}

Это помогает визуализировать представление с меньшим количеством данных, только с необходимыми атрибутами, и делает ваш веб-сайт более быстрым.

-1
ответ дан Sterling Diaz 22 August 2018 в 20:09
поделиться
//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);
}
-1
ответ дан Ynnoboy 22 August 2018 в 20:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: