简体   繁体   English

JsonConvert.DeserializeObject上的StackOverflowException

[英]StackOverflowException on JsonConvert.DeserializeObject

I am writing a solution that contains an ASP.NET Web API (.NET 4.6.2) aka the backend, a Web API Client Implementation PCL aka the middleware and Xamarin.Forms projects aka the frontend. 我正在编写一个包含ASP.NET Web API(.NET 4.6.2)(即后端),Web API客户端实现PCL(即中间件)和Xamarin.Forms项目(即前端)的解决方案。 After recent changes to my web api I now always get a StackOverflowException when I try to deserialize the JSON response in my frontend. 在我的web api最近更改后,当我尝试在前端反序列化JSON响应时,我现在总是得到StackOverflowException。 The specific line is: 具体路线是:

result_ = JsonConvert.DeserializeObject<ObservableCollection<Employee>>(Encoding.UTF8.GetString(responseData_, 0, responseData_.Length));

When I am debugging here, I see that the program is jumping between two lines until the overflow occurs: 当我在这里调试时,我看到程序在两行之间跳转,直到发生溢出:

EmployeesManager.cs (in the middleware) EmployeesManager.cs(在中间件中)

private Image _image = new Image();

ImagesManager.cs (in the middleware) ImagesManager.cs(在中间件中)

private Employee _employee = new Employee();

Here is more code: 这是更多的代码:

The models (in the Web API): 模型(在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; }
}

The models in the client implementation (middleware). 客户端实现中的模型(中间件)。 They are generated with Nswag : 它们是用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();
            }
        }
    }

I use the Web API client implementation via Xamarin.Forms projects. 我通过Xamarin.Forms项目使用Web API客户端实现。 The behavior is the same on all platforms. 所有平台上的行为都是相同的。 Only iOS and UWP recognize the Stack Overflow, though. 但是,只有iOS和UWP识别Stack Overflow。 On Android the app just closes without an Exception when I am reading data from the Web API. 在Android上,当我从Web API读取数据时,应用程序只关闭而没有异常。

If somebody wants to see more code, I can prepare a small package containing the requested code. 如果有人想要查看更多代码,我可以准备一个包含所请求代码的小包。 Posting them all here would break readability completely. 将它们全部发布在这里会完全破坏可读性。

I use Newtonsoft Json.NET, Entity Framework 6, NSwag 6, Xamarin.Forms v2.3.2.127. 我使用Newtonsoft Json.NET,Entity Framework 6,NSwag 6,Xamarin.Forms v2.3.2.127。

I had this happen to me before; 我之前发生过这件事; it was due to a circular reference between the objects. 这是由于对象之间的循环引用。 You have an Employee references Image and Image referencing Employee. 您有一个Employee引用Image和Image引用Employee。

Try putting a [JsonIgnore] above the Employee property in Image the image class. 尝试将[JsonIgnore]放在Image的[JsonIgnore]属性上面。

I followed the answers of Oxidda, David and EJoshuaS. 我按照Oxidda,David和EJoshuaS的回答。

Here is the complete solution for the purpose of full documentation: 以下是完整文档的完整解决方案:

I tried putting JsonIgnore on the Employee property on the Image class inside the middleware (the Web API client PCL). 我尝试将JsonIgnore放在中间件(Web API客户端PCL)内的Image类的Employee属性上。 Strangely enough that did not fix the problem. 奇怪的是,没有解决问题。 I still got the Stack Overflow with the private variables behind the properties. 我仍然使用属性后面的私有变量获得Stack Overflow。 Now I put JsonIgnore on the Employee navigation property of the Image class in the Web API (the backend) and also on the Employee navigation property of the Device class. 现在我将JsonIgnore放在Web API(后端)中的Image类的Employee导航属性上,也放在Device类的Employee导航属性上。 Then I removed the navigation properties (Employee in the image class, and Employee in the device class) completely from the API client (middleware), because JSON for those properties now will never be received, since the API will already ignore those. 然后我完全从API客户端(中间件)中删除了导航属性(图像类中的Employee和设备类中的Employee),因为现在永远不会收到这些属性的JSON,因为API已经忽略了这些属性。 The error is away now and on top I got a significant speed boost to requests and responses. 错误现在已经消失,最重要的是我对请求和响应的速度提升了很快。 Seems like although the Web API (backend) was working fine and had no issues with the relations, those navigation properties on the optional models introduced a high amount of overhead. 看起来虽然Web API(后端)工作正常并且关系没有问题,但可选模型上的那些导航属性引入了大量开销。 The classes are really small and the tables of the database are almost empty but the impact seems to be huge. 这些类非常小,数据库的表几乎是空的,但影响似乎很大。

TL;DR: Eliminated the possibility for circular reference at the source. TL; DR:消除源头循环引用的可能性。 Mirrored changes to the client. 对客户端进行镜像更改。 Problem solved and also received a huge speed boost. 问题解决了,也获得了巨大的速度提升。

If somebody is interested in the complete design of my solution, here is a small summary. 如果有人对我的解决方案的完整设计感兴趣,这里有一个小小的总结。 I like it a lot. 我很喜欢。

  1. Created a ASP.NET Web API (.NET 4.6.2) project with Entity Framework 6. Added models with relations, added DbContext. 使用Entity Framework 6创建了一个ASP.NET Web API(.NET 4.6.2)项目。添加了带关系的模型,添加了DbContext。 Scaffolded Async Controllers. 脚手架异步控制器。 Web API is done. Web API已完成。 Note that you should not use lazy loading when using entity framework with JSon. 请注意,在将实体框架与JSon一起使用时,不应使用延迟加载。 Instead I use eager loading in the controllers. 相反,我在控制器中使用急切加载。
  2. Created a PCL with the same profile that Xamarin PCLs are using. 使用与Xamarin PCL正在使用的相同的配置文件创建PCL。 Thus it is compatible to Xamarin solutions, but also to all other standard .NET solutions. 因此,它与Xamarin解决方案兼容,但也与所有其他标准.NET解决方案兼容。
  3. Generated the middleware API with NSwag , based on the Web API. 使用NSwag生成基于Web API的中间件API。 You basically load your API.dll into the program, select your settings and you receive a complete PCL-compatible client implementation of your Web API in C#. 您基本上将API.dll加载到程序中,选择您的设置,并在C#中获得与Web API完全兼容的PCL客户端实现。 The API is quite high level and async so you can consume your API easily in any .NET frontend. API具有相当高的级别和异步性,因此您可以在任何.NET前端轻松使用API​​。
  4. Add frontend solutions of your choice. 添加您选择的前端解决方案。 Consume your data easily through the client API. 通过客户端API轻松获取数据。

Basically you can just write some properties in the Web API (+ configure the JSon Serializer and the DbContext) and the rest of the whole backend and middleware is generated. 基本上你可以在Web API中编写一些属性(+配置JSon Serializer和DbContext),然后生成整个后端和中间件的其余部分。 I love it. 我喜欢它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM