C# 在JSON.net中处理引用循环

C# 在JSON.net中处理引用循环,c#,json,json.net,C#,Json,Json.net,我希望将项目集合(列表)序列化为JSON 这些项目有一个连接集合,它提供了从一个项目到第二个项目的连接信息。由于连接对象有一个对项的引用,它使它成为一个无限循环 我的问题是,在第二次序列化对象时,是否有办法跳过连接集合的序列化。 我尝试过从JsonConverter继承和编写自定义WriteJson()方法,但从那里我没有意识到是否应该写出数组 我也尝试过使用定制的ContractResolver,但没有很好的效果 课程 public class Item { private stat

我希望将项目集合(
列表
)序列化为JSON

这些项目有一个
连接
集合,它提供了从一个
项目
到第二个
项目
的连接信息。由于连接对象有一个对项的引用,它使它成为一个无限循环

我的问题是,在第二次序列化对象时,是否有办法跳过连接集合的序列化。

我尝试过从
JsonConverter
继承和编写自定义
WriteJson()
方法,但从那里我没有意识到是否应该写出数组

我也尝试过使用定制的ContractResolver,但没有很好的效果


课程

public class Item
{
    private static int _lastID = 0;

    public Item()
    {
        ID = ++_lastID;
        Connections = new List<Connection>();
    }


    public int ID { get; set; }

    public string Name { get; set; }

    public string Prop1 { get; set; }

    public string Prop2 { get; set; }

    public List<Connection> Connections { get; set; }

}



public class Connection
{
    private Connection(ConnectionType type, Item source, Item target)
    {
        if (type == ConnectionType.None)
            throw new ArgumentException();
        if (source == null)
            throw new ArgumentNullException("source");
        if (target == null)
            throw new ArgumentNullException("target");

        Type = type;
        Source = source;
        Target = target;
    }


    public ConnectionType Type { get; set; }

    public Item Source { get; set; }

    public Item Target { get; set; }


    public static void Connect(ConnectionType type, Item source, Item target)
    {
        var conn = new Connection(type, source, target);
        source.Connections.Add(conn);
        target.Connections.Add(conn);
    }
}


编辑:

[
    {
        "id": 1,
        "name": "Item #1",
        "prop1": "val1",
        "prop2": "val2",
        "connections": {
            "type": "ConnType",
            "source": {
                "id": 1,
                "name": "Item #1",
                "prop1": "val1",
                "prop2": "val2"
                // no connections array
            },
            "target": {
                "id": 2,
                "name": "Item #2",
                "prop1": "val1",
                "prop2": "val2"
                // no connections array
            }
        }
    },
    {
        "id": 2,
        "name": "Item #2",
        "prop1": "val1",
        "prop2": "val2",
        "connections": {
            "type": "ConnType",
            "source": {
                "id": 1,
                "name": "Item #1",
                "prop1": "val1",
                "prop2": "val2"
                // no connections array
            },
            "target": {
                "id": 2,
                "name": "Item #2",
                "prop1": "val1",
                "prop2": "val2"
                // no connections array
            }
        }
    }
]
C#


有一个问题,因为Json中不能引用对象(请参阅)

这意味着每次引用中出现一个项目时,您都必须复制该项目,以便将所有连接带到客户端

我建议只使用ID将连接带到客户端,并将连接作为一个单独的对象

JsonIgnore
属性添加到
项上的
Connections
属性中

[JsonIgnore]
public List<Connection> Connections { get; set; }
[JsonIgnore]
公共列表连接{get;set;}
并使用类来发送到客户端,而不是直接发送项目列表

    class ConnectionContainer
    {
        private readonly List<Item> _items;
        private readonly List<ConnectionInfo> _connections;

        public ConnectionContainer(IEnumerable<Item> items)
        {
            _items = items.ToList();
            Connections = items.SelectMany(i => i.Connections).Distinct().Select(c => new ConnectionInfo
            {
                Type = c.Type,
                SourceId = c.Source.ID,
                TargetId = c.Target.ID
            }).ToList();
        }

        public List<Item> Items
        {
            get { return _items; }
        }

        public List<ConnectionInfo> Connections
        {
            get { return _connections; }
        }
    }

    class ConnectionInfo
    {
        private ConnectionType Type { get; set; }
        private int SourceId { get; set; }
        private int TargetId { get; set; }
    }
类连接容器
{
私有只读列表项;
专用只读列表\u连接;
公共连接容器(IEnumerable items)
{
_items=items.ToList();
Connections=items.SelectMany(i=>i.Connections).Distinct().Select(c=>newconnectioninfo
{
类型=c.类型,
SourceId=c.Source.ID,
TargetId=c.Target.ID
}).ToList();
}
公共清单项目
{
获取{return\u items;}
}
公共列表连接
{
获取{return\u connections;}
}
}
类连接信息
{
私有连接类型类型{get;set;}
private int SourceId{get;set;}
私有int TargetId{get;set;}
}

您可以引入一个新类,例如,
ItemClass
,该类将包含class
Item
的所有字段,但
Connections
属性除外,而不是从
Item
开始声明
目标
的类型

public class ItemClass
{
    public int ID { get; set; }

    public string Name { get; set; }

    public string Prop1 { get; set; }

    public string Prop2 { get; set; }
}

public class Connection
{
    // ...

    public ConnectionType Type { get; set; }

    public ItemClass Source { get; set; }

    public ItemClass Target { get; set; }

    // ...
}

现在,您将有相应地填充新的
ItemClass
类型实例的开销。

将其添加到Global.asax(或在WebApiConfig或任何其他配置类中)

var jsonFormatter=config.Formatters.OfType().First();
jsonFormatter.SerializerSettings.ReferenceLoopHandling=ReferenceLoopHandling.Ignore;

如果我没弄错,您只需要保留包含连接集合的第一个引用深度?如果是这种情况,请尝试使用:

settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.MaxDepth = 1;

如果我使用这个属性,我会丢失所有连接信息,我更希望它只包含第一个对象的信息,因为这些类在一个单独的项目中,我希望避免引用Newtonsoft。如果我以前尝试过混用
ReferenceLoopHandling
,但运气不好,但现在当我再次尝试时,它给了我我想要的。谢谢你给我指出了正确的方向。尽管我使用了
JsonConvert.SerializeObject(集合、设置)
现在我想起了为什么它不能与
ReferenceLoopHandling.Ignore
一起工作。连接对象只有一个引用(源引用或目标引用),这取决于它是从哪个对象序列化的。这对我来说不起作用,所以我会在allI喜欢这个解决方案之后使用@Wasif的解决方案,但由于它引入了更多的复杂性,我使用@Moeri解决方案
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.ReferenceLoopHandling = ReferenceLoopHandling.Serialize;
settings.MaxDepth = 1;