我有2个课程:
public class A
{
public int Id { get; set; }
public string Name { get; set; }
public B myB { get; set; }
}
public class B
{
public int Id { get; set; }
public string Name { get; set; }
public ICollection<A> myAs { get; set; }
}
我正在使用Postman测试Api呼叫。
public IEnumerable<B> GetBs()
{
return _context.Bs.Include(b => b.myAs).ToList();
}
按预期返回B对象及其关联的A对象的列表:
{
"Id": 1,
"Name": "B2",
"myAs": [
{
"Id": 1,
"Name": "A1"
},
{
"Id": 2,
"Name": "A2"
}
]
},
{
"Id": 2,
"Name": "B3",
"myAs": [
{
"Id": 3,
"Name": "A3"
},
{
"Id": 4,
"Name": "A4"
},
{
"Id": 5,
"Name": "A5"
}
]
}
相反,返回一个奇怪的层次结构:
public IEnumerable<A> GetAs()
{
return _context.As.Include(a => a.myB).ToList();
}
返回:
[
{
"Id": 1,
"Name": "A1",
"myB": {
"Id": 1,
"Name": "B2",
"myAs": [
{
"Id": 2,
"Name": "A2"
}
]
}
},
{
"Id": 2,
"Name": "A2",
"myB": {
"Id": 1,
"Name": "B2",
"myAs": [
{
"Id": 1,
"Name": "A1"
}
]
}
},
{
"Id": 3,
"Name": "A3",
"myB": {
"Id": 2,
"Name": "B3",
"myAs": [
{
"Id": 4,
"Name": "A4"
},
{
"Id": 5,
"Name": "A5"
}
]
}
}
]
GetAs方法返回A对象,其中B对象具有嵌套的A对象。
经过一番研究(我在这里可能是非常错误的)后,我的理解是,由于A对B(myB)具有导航属性,而B对A对象(myAs)列表具有导航属性,这导致了一种循环。
我的问题是
注释A和B实际上不是我的域模型。我只是想让示例尽可能简单。
谢谢。
答案 0 :(得分:1)
这里有几件事:
输出具有预期的形状。您可能怀疑,串行化器正在扩展双向引用。想想如果您递归地手动序列化每个对象的每个属性会发生什么。就是这样。
要解决眼前的问题,请配置默认的序列化器设置,如下所示:
jsonFormatter.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.Serialization.ReferenceLoopHandling.Ignore;
上面的内容在制作原型时很有用,但是当您的应用程序更加形式化时,您应该从Web API端点创建并返回专用的视图模型类型。
public class AViewModel
{
public int Id { get; set; }
public string Name { get; set; }
}
public class BViewModel
{
public int Id { get; set; }
public string Name { get; set; }
public IEnumerable<AViewModel> myAs { get; set; }
}
public IEnumerable<BViewModel> GetBs()
{
return _context.Bs.Include(b => b.myAs)
.Select(b => new BViewModel
{
Id = b.Id,
Name = b.Name,
As = b.As.Select(a => new AViewModel
{
Id = a.Id,
Name = a.Name
})
})
.ToList();
}
值得注意的是,有一些库,例如备受赞誉的AutoMapper,可以为您在模型类型之间执行这些转换,并使用反射通过名称自动分配相应的属性。
就个人而言,我尽量避免使用基于反射的方法,因为它们会使代码难以静态地推理。这既阻碍了我们自己这样的人类读者,也阻碍了C#语言这样的工具。
也就是说,根据手头的任务进行权衡是值得的。我希望最终能看到语言级别的支持,从而消除此类样板作业,而不必进入严格的领域,但是我有很长的等待时间。