WebApi Json Self ссылочный цикл

У меня есть ужасное время, решая эту ошибку в моем проекте ASP.NET WebApi (полный DotNet, а не Core):

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>Self referencing loop detected for property 'Server' with type 'System.Data.Entity.DynamicProxies.Server_8AB873452FD27AADAE6B91C89AF500FFD407544E56422B394D3E2B8AC1524157'. Path 'Server_Hardware_Current[0]'.</ExceptionMessage>
<ExceptionType>Newtonsoft.Json.JsonSerializationException</ExceptionType>
     <StackTrace>   at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CheckForCircularReference(JsonWriter writer, Object value, JsonProperty property, JsonContract contract, JsonContainerContract containerContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.CalculatePropertyValues(JsonWriter writer, Object value, JsonContainerContract contract, JsonProperty member, JsonProperty property, JsonContract& memberContract, Object& memberValue)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeList(JsonWriter writer, IEnumerable values, JsonArrayContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeObject(JsonWriter writer, Object value, JsonObjectContract contract, JsonProperty member, JsonContainerContract collectionContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.SerializeValue(JsonWriter writer, Object value, JsonContract valueContract, JsonProperty member, JsonContainerContract containerContract, JsonProperty containerProperty)
               at Newtonsoft.Json.Serialization.JsonSerializerInternalWriter.Serialize(JsonWriter jsonWriter, Object value, Type objectType)
               at Newtonsoft.Json.JsonSerializer.SerializeInternal(JsonWriter jsonWriter, Object value, Type objectType)
               at System.Web.Http.Results.JsonResult'1.Serialize()
               at System.Web.Http.Results.JsonResult'1.Execute()
               at System.Web.Http.Results.JsonResult'1.ExecuteAsync(CancellationToken cancellationToken)
               at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
               at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
               at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
               at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()
            --- End of stack trace from previous location where exception was thrown ---
               at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
               at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)  at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
     </StackTrace>
</Error>

Я должен добавить и сильно подчеркнуть, что я ноб в С#. Если вам нужна дополнительная информация, сообщите мне, что именно вам нужно, и если вы хотите, чтобы я поместил ядро в файл, скажите мне имя файла;)

О моем проекте:

Я пытаюсь создать клиент/серверное решение, которое будет развертывать агент на целевом сервере/клиенте, и его аппаратное и программное обеспечение отправляется в центральную базу данных, как это делается в каждом программном обеспечении для развертывания программного обеспечения. Сам агент может считывать нужную информацию из системы, поэтому теперь я пытаюсь создать WebApi, который будет принимать результат и обеспечить конечную точку связи для агента, а также какую-то консоль, чтобы видеть информацию и делать разные виды оценка (обновлены ли мои системы, какое программное обеспечение установлено там и т.д.).

Программное обеспечение и пакеты

Я запускаю сообщество Visual Studio 2017

Пакеты Nuget:

  • По умолчанию пакеты WebApi (Inclused Newtonsoft.Json)
  • Entity Framework 6 также создал модель EDMX файла, которая выглядит совершенно корректно для меня
  • Корпоративная библиотека для ведения журнала

Часть кода контроллера

        public IHttpActionResult GetSingleServer(int id)
    {

        // using (KysoHostDbContext ServersDbContext = new KysoHostDbContext())
        // {
            KysoHostDbContext ServersDbContext = new KysoHostDbContext();
        //ServersDbContext.Configuration.ProxyCreationEnabled = false;
        //ServersDbContext.Configuration.LazyLoadingEnabled = false;


        var returnobject = ServersDbContext.Servers.FirstOrDefault(a => a.ServerId == id);
           // .Include(ServersDbContext.Servers.FirstOrDefault().Server_OS_Current.ToString());


            if ((returnobject.Equals(null)))
            {
                return NotFound();
            }
            else
            {
                return Json(returnobject);
            }
        // }

    }

Модель

using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;

namespace KysoWebApi.Models
{
public partial class Servers
{
    public Servers()
    {
        ServerHardwareCurrent = new HashSet<ServerHardwareCurrent>();
        ServerHardwareHistory = new HashSet<ServerHardwareHistory>();
        ServerOsCurrent = new HashSet<ServerOsCurrent>();
        ServerOsHistory = new HashSet<ServerOsHistory>();
        ServerWinFeaturesCurrent = new HashSet<ServerWinFeaturesCurrent>();
        ServerWinFeaturesHistory = new HashSet<ServerWinFeaturesHistory>();
        ServerWinInstalledSoftwareCurrent = new HashSet<ServerWinInstalledSoftwareCurrent>();
        ServerWinInstalledSoftwareHistory = new HashSet<ServerWinInstalledSoftwareHistory>();
        ServerWinRolesCurrent = new HashSet<ServerWinRolesCurrent>();
        ServerWinRolesHistory = new HashSet<ServerWinRolesHistory>();
    }

    [Key]
    public int ServerId { get; set; }
    [Required]
    [Column(TypeName = "varchar(50)")]
    public string AgentGuid { get; set; }

    [InverseProperty("Server")]
    public ICollection<ServerHardwareCurrent> ServerHardwareCurrent { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerHardwareHistory> ServerHardwareHistory { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerOsCurrent> ServerOsCurrent { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerOsHistory> ServerOsHistory { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerWinFeaturesCurrent> ServerWinFeaturesCurrent { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerWinFeaturesHistory> ServerWinFeaturesHistory { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerWinInstalledSoftwareCurrent> ServerWinInstalledSoftwareCurrent { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerWinInstalledSoftwareHistory> ServerWinInstalledSoftwareHistory { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerWinRolesCurrent> ServerWinRolesCurrent { get; set; }
    [InverseProperty("Server")]
    public ICollection<ServerWinRolesHistory> ServerWinRolesHistory { get; set; }
   }
}

То, что я уже пробовал

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

  • Global.asax

            /*
        var json = GlobalConfiguration.Configuration.Formatters.JsonFormatter;
        json.SerializerSettings.PreserveReferencesHandling =
            Newtonsoft.Json.PreserveReferencesHandling.All;
            */
    
    
    
        /*
        HttpConfiguration config = GlobalConfiguration.Configuration;
    
        config.Formatters.JsonFormatter
                    .SerializerSettings
                    .ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        */
    
        /*
        JsonConvert.DefaultSettings = () => new JsonSerializerSettings
        {
            Formatting = Newtonsoft.Json.Formatting.Indented,
            ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        };
        */
    
  • WebApiConfig.cs

        /*
        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
        = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        */
    
    
        /*
        config.Formatters.JsonFormatter.SerializerSettings.ReferenceLoopHandling
        = Newtonsoft.Json.ReferenceLoopHandling.Serialize;
        config.Formatters.JsonFormatter.SerializerSettings.PreserveReferencesHandling
        = Newtonsoft.Json.PreserveReferencesHandling.Objects;
        */
    
        /*
         * var json = config.Formatters.JsonFormatter;
        json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
        */
    
  • ServerController.cs

Как вы, вероятно, видели в коде контроллера, я попытался отключить ленивую загрузку явно, так как моя модель включала виртуальную директиву. Поскольку удаление этого не помогло, я попытался отключить ленивую загрузку, что по-прежнему приводило к той же ошибке. Только когда я отключу ProxyCreation, я получаю результат, но это включает только данные SQL из таблицы Servers, а не все дочерние объекты, которые я хочу иметь. Это может быть не обязательно все время, но, пожалуйста, несите меня, так как мне это понадобится позже.

Я также пытался использовать что-то вроде использования.Include, но мне не удалось заставить его работать. Я чувствую, что:

public IHttpActionResult GetSingleServer(int id) 

может быть проблемой, но тогда я не могу использовать

return NotFound();

или же:

return Json(returnobject);

Любая помощь будет принята с благодарностью. Кроме того, заранее заблаговременно, чтобы кто-то нашел время, чтобы прочитать все это :)


Обновление 1

Я попытался: 'public IHttpActionResult GetSingleServer (int id) {

        // using (KysoHostDbContext ServersDbContext = new KysoHostDbContext())
        // {
            KysoHostDbContext ServersDbContext = new KysoHostDbContext();
        // ServersDbContext.Configuration.ProxyCreationEnabled = false;
        ServersDbContext.Configuration.LazyLoadingEnabled = false;


        var returnobject = ServersDbContext.Servers.Include("ServerHardwareCurrent")
                .Where(a => a.ServerId == id);
           // .Include(ServersDbContext.Servers.FirstOrDefault().Server_OS_Current.ToString());


            if ((returnobject.Equals(null)))
            {
                ServersDbContext.Dispose();
                return NotFound();
            }
            else
            {
            ServersDbContext.Dispose();
            return Json(returnobject);
            }
        // }

    }'

Что дает мне:

<ExceptionMessage>The operation cannot be completed because the DbContext has been disposed.</ExceptionMessage><ExceptionType>System.InvalidOperationException</ExceptionType><StackTrace>   at System.Data.Entity.Internal.LazyInternalContext.InitializeContext()   at System.Data.Entity.Internal.Linq.InternalQuery'1

У меня явно отключена ленивая загрузка, но она по-прежнему пытается лениться?

Тот же результат, если я попытаюсь переместить его: var returnobject = ServersDbContext.Servers.Where(a => a.ServerId == id).Include("ServerHardwareCurrent");

Это сводит меня с ума. почему он ленив нагрузку все время, даже когда я говорю это не так? :/

0
источник поделиться
1 ответ

Поскольку комментариев больше нет, это было моим решением. Пожалуйста, возьмите его с солью:

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

0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос