我正在编写一个包含ASP.NET Web API(.NET 4.6.2)(即后端),Web API客户端实现PCL(即中间件)和Xamarin.Forms项目(即前端)的解决方案。在我的web api最近更改后,当我尝试在前端反序列化JSON响应时,我现在总是得到StackOverflowException。具体的一行是:
result_ = JsonConvert.DeserializeObject<ObservableCollection<Employee>>(Encoding.UTF8.GetString(responseData_, 0, responseData_.Length));
当我在这里调试时,我看到程序在两行之间跳转,直到发生溢出:
EmployeesManager.cs(在中间件中)
private Image _image = new Image();
ImagesManager.cs(在中间件中)
private Employee _employee = new Employee();
这是更多代码:
模型(在Web API中):
public class Employee
{
public int Id { get; set; }
// OMITTED PROPS
public int? ImageId { get; set; }
public Image Image { get; set; }
public ICollection<Device> Devices { get; set; }
public int? TeamId { get; set; }
public Team Team { get; set; }
}
public class Image
{
[Key]
public int Id { get; set; }
[Required]
public byte[] Data { get; set; }
public int EmployeeId { get; set; }
public Employee Employee { get; set; }
}
客户端实现中的模型(中间件)。它们是使用Nswag:
生成的public partial class Employee : INotifyPropertyChanged
{
private int _id;
private int? _imageId;
private Image _image = new Image(); // THIS LINE IS PART OF THE OVERFLOW
private ObservableCollection<Device> _devices;
private int? _teamId;
private Team _team = new Team();
// OMITTED PROPS
[JsonProperty("image", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
public Image Image
{
get { return _image; }
set
{
if (_image != value)
{
_image = value;
RaisePropertyChanged();
}
}
}
public partial class Image : INotifyPropertyChanged
{
private int _id;
private int _employeeId;
private Employee _employee = new Employee(); // THIS LINE IS PART OF THE STACK OVERFLOW
private byte[] _data;
// OMITTED PROPS
[JsonProperty("employee", Required = Required.Default, NullValueHandling = NullValueHandling.Ignore)]
public Employee Employee
{
get { return _employee; }
set
{
if (_employee != value)
{
_employee = value;
RaisePropertyChanged();
}
}
}
我通过Xamarin.Forms项目使用Web API客户端实现。所有平台上的行为都是相同的。但是,只有iOS和UWP识别Stack Overflow。在Android上,当我从Web API读取数据时,应用程序只会在没有异常的情况下关闭。
如果有人想要查看更多代码,我可以准备一个包含所请求代码的小包。将它们全部发布在这里会完全破坏可读性。
我使用Newtonsoft Json.NET,Entity Framework 6,NSwag 6,Xamarin.Forms v2.3.2.127。
答案 0 :(得分:1)
我之前发生过这件事;这是由于对象之间的循环引用。您有一个Employee引用Image和Image引用Employee。
尝试将[JsonIgnore]
放在Image图像类的Employee属性上方。
答案 1 :(得分:1)
我按照Oxidda,David和EJoshuaS的回答。
以下是完整文档的完整解决方案:
我尝试将JsonIgnore放在中间件(Web API客户端PCL)内的Image类的Employee属性上。奇怪的是,没有解决问题。我仍然使用属性后面的私有变量获得Stack Overflow。 现在我将JsonIgnore放在Web API(后端)中的Image类的Employee导航属性上,也放在Device类的Employee导航属性上。然后我完全从API客户端(中间件)中删除了导航属性(图像类中的Employee和设备类中的Employee),因为现在永远不会收到这些属性的JSON,因为API已经忽略了这些属性。 错误现在已经消失,最重要的是我对请求和响应的速度提升了很快。看起来虽然Web API(后端)工作正常并且关系没有问题,但可选模型上的那些导航属性引入了大量开销。这些类非常小,数据库的表几乎是空的,但影响似乎很大。
TL; DR:消除源头循环引用的可能性。对客户端进行镜像更改。问题解决了,也获得了巨大的速度提升。
如果有人对我的解决方案的完整设计感兴趣,这里有一个小小的总结。我很喜欢。
基本上你可以在Web API中编写一些属性(+配置JSon Serializer和DbContext),然后生成整个后端和中间件的其余部分。我喜欢它。