как исправить внутреннюю ошибку сервера 500 на ajax-обратном вызове в asp.net mvc [duplicate]

Упрощенный ярлык, который я пробовал, это:

    int x[] = {1,2,3};
    String printableText = Arrays.toString(x).replaceAll("[\\[\\]]", "").replaceAll(", ", "\n");
    System.out.println(printableText);

Он будет печатать

1
2
3

В этом подходе нет циклов, и это лучше всего для небольших массивов

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

14 ответов

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

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

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

164
ответ дан Darin Dimitrov 31 August 2018 в 19:40
поделиться

Я использую исправление, потому что использование нокаута в представлениях 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 31 August 2018 в 19:40
поделиться

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

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

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 31 August 2018 в 19:40
поделиться

Чтобы подвести итог, есть 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 31 August 2018 в 19:40
поделиться

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

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

   return object
}
0
ответ дан Bassil 31 August 2018 в 19:40
поделиться

Это на самом деле происходит потому, что сложные объекты - это то, что заставляет результирующий 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 31 August 2018 в 19:40
поделиться

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

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

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

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

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

4
ответ дан Juri 31 August 2018 в 19:40
поделиться

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

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

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

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

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

7
ответ дан Marc Gravell 31 August 2018 в 19:40
поделиться

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

4
ответ дан Mathemats 31 August 2018 в 19:40
поделиться

У меня была та же проблема и решена с помощью 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 31 August 2018 в 19:40
поделиться

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

4
ответ дан Roman Marusyk 31 August 2018 в 19:40
поделиться

Более простой альтернативой для решения этой проблемы является возврат строки и форматирование этой строки в 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 31 August 2018 в 19:40
поделиться
//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 31 August 2018 в 19:40
поделиться
Другие вопросы по тегам:

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