WebApi Json Self引用循环

时间:2017-08-06 13:55:26

标签: c# entity-framework json.net

我在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>

我必须补充并强调我是c#中的菜鸟。 如果您需要更多信息,请告诉我您的具体需求,如果您希望我将核心放入文件中,请告诉我文件名;)

关于我的项目:

我正在尝试创建一个客户端/服务器解决方案,该解决方案将在目标服务器/客户端上部署代理,并将其硬件和软件发送到中央数据库,就像每个软件部署软件一样。 代理本身可以从系统中读取所需的信息,所以我现在正在尝试创建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时,我才会得到一个结果,但是它只包含Servers表中的SQL数据,而不是我想要的所有子对象。 这可能不是一直都是必要的,但请耐心等待,因为我以后无论如何都需要它。

我也试过使用像.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 =&gt; a.ServerId == id).Include(“ServerHardwareCurrent”);

这让我疯了。为什么它总是懒得加载,即使我不告诉它? :/

1 个答案:

答案 0 :(得分:0)

由于没有其他评论,这是我的解决方案。请带上一粒盐:

关于我的关系循环问题,我发现如果我删除与servers表相关的所有表的导航属性,它就可以了。不过,我必须将它们留在服务器表中。这实际上并没有解决Json不关心我告诉它忽略循环的问题,但它删除了循环,至少我的代码工作。