【问题标题】:ASP.NET API serialize entities with circular dependenciesASP.NET API 序列化具有循环依赖关系的实体
【发布时间】:2015-07-30 20:53:54
【问题描述】:

我有Test 实体和User 实体。

测试:

public class Test
{
  public int Id {get; set;}
  public string Title {get; set;}
  ...
  public virtual IList<User> Users {get; set;}
}

用户:

public class User
{
  public int Id {get; set;}
  public string Name {get; set;}
  ...
  public virtual IList<Test> Tests {get; set;}
}

在我的TestsApiController 中,我有以下操作:

public IQueryable<Test> GetTests()
{
    return db.Tests;
}

这会返回一个序列化异常,因为它尝试循环序列化 User 对象,然后是它们的 Test 对象,然后是它们的 User 对象,依此类推。

我目前的计划是创建一个TestDTO,其中包含一个IList&lt;int&gt; UserIds,而不是实际的对象。然后我必须在序列化之前将所有Test 对象转换为TestDTO 对象,这有点烦人。然后,如果我想序列化具有循环依赖关系的其他实体,我将不得不为它们创建更多的数据传输对象。

有没有办法创建或配置序列化程序以自动序列化此上下文中的 User(或任何其他)对象以简化其 Id 属性?

编辑例外: 无论使用XML 还是JSON,我都会遇到同样的异常

<Error>
<Message>An error has occurred.</Message>
<ExceptionMessage>
The 'ObjectContent`1' type failed to serialize the response body for content type 'application/xml; charset=utf-8'.
</ExceptionMessage>
<ExceptionType>System.InvalidOperationException</ExceptionType>
<StackTrace/>
<InnerException>
<Message>An error has occurred.</Message>
<ExceptionMessage>
Type 'System.Data.Entity.DynamicProxies.Test_6585C5F85A384907958ABA03B661933EF718BDEDE1513392E060DE06E80DB552' with data contract name 'Test_6585C5F85A384907958ABA03B661933EF718BDEDE1513392E060DE06E80DB552:http://schemas.datacontract.org/2004/07/System.Data.Entity.DynamicProxies' is not expected. Consider using a DataContractResolver or add any types not known statically to the list of known types - for example, by using the KnownTypeAttribute attribute or by adding them to the list of known types passed to DataContractSerializer.
</ExceptionMessage>
<ExceptionType>
System.Runtime.Serialization.SerializationException
</ExceptionType>
<StackTrace>...</StackTrace>
</InnerException>
</Error>

【问题讨论】:

  • 我想说这里的问题是设计,而不是序列化程序。考虑Tests 是否真的需要Users 的列表。如果是这样,我会存储一个 ID 列表而不是实际对象。
  • 这都是使用实体框架。它存储User 对象而不是它们的Ids 这一事实在我的应用程序的其他地方非常有用。

标签: c# asp.net serialization


【解决方案1】:

构建 json 结果的一种非常简单的方法是使用来自 NewtonSoft json 序列化程序的 JObject(这通常是 ASP.NET Web Api 中的默认值)。您要查找的内容类似于

public JObject GetTests()
{

    NewtonSoft.Json.Linq.JObject jsonResult = NewtonSoft.Json.Linq.JObject.FromObject(new 
    {
        Tests = from test in db.tests
                select new 
                {
                    Id = test.Id,
                    Title = test.Title,
                    Users = from user in test.Users
                            select new
                            {
                                Id = user.Id
                            }
                }
    });

    return jsonResult;
}

这使您可以更好地控制 json 结果,以便您可以选择要序列化的字段/属性,并避免创建大量数据传输对象。希望这会有所帮助。

干杯

【讨论】:

  • 我不会认为这比仅仅创建一个 TestDTO 更好,因为你基本上是在创建与匿名类型相同的东西。
  • 我认为这更方便,因为如果您创建一个 TestDTO,您将不得不在您的 POCO 和 DTO 之间进行某种映射。但是使用 JObject,您可以快速轻松地选择要序列化的属性。
【解决方案2】:

在您的 Web api 配置 (App_Start/WebApiConfig.cs) 中,添加以下内容:

    public static class WebApiConfig
    {
      public static void Register(HttpConfiguration config)
      {
        // Prevent "Self referencing loop detected" error occurring for recursive objects
        var serializerSettings = new JsonSerializerSettings()
        {
            ReferenceLoopHandling = ReferenceLoopHandling.Ignore
        };
        config.Formatters.JsonFormatter.SerializerSettings = serializerSettings;
      }
    }

这告诉 JSON.NET 忽略引用父对象的嵌套对象

【讨论】:

  • 我只是这样做了,但我仍然得到同样的异常。我编辑了我的问题以包含它。
猜你喜欢
  • 2012-04-21
  • 2014-09-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多