JsonConvert.DeserializeObject上的StackOverflowException [英] StackOverflowException on JsonConvert.DeserializeObject

查看:69
本文介绍了JsonConvert.DeserializeObject上的StackOverflowException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在编写一个包含ASP.NET Web API(.NET 4.6.2)(又称为后端),Web API客户端实现PCL(又称为中间件)和Xamarin.Forms项目(又称为前端)的解决方案.在对Web api进行最新更改之后,当我尝试在前端反序列化JSON响应时,我现在总是会得到一个StackOverflowException.具体行是:

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. After recent changes to my web api I now always get a StackOverflowException when I try to deserialize the JSON response in my frontend. 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(在中间件中)

private Image _image = new Image();

ImagesManager.cs(在中间件中)

private Employee _employee = new Employee();

这里有更多代码:

模型(在Web API中):

The models (in the 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 :

The models in the client implementation (middleware). They are generated with 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可以识别堆栈溢出.在Android上,当我从Web API读取数据时,该应用程序会关闭且无异常.

I use the Web API client implementation via Xamarin.Forms projects. The behavior is the same on all platforms. Only iOS and UWP recognize the Stack Overflow, though. On Android the app just closes without an Exception when I am reading data from the 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.

我使用Newtonsoft Json.NET,实体框架6,NSwag 6,Xamarin.Forms v2.3.2.127.

I use Newtonsoft Json.NET, Entity Framework 6, NSwag 6, Xamarin.Forms v2.3.2.127.

推荐答案

我遵循了Oxidda,David和EJoshuaS的回答.

I followed the answers of Oxidda, David and EJoshuaS.

以下是完整文档的完整解决方案:

Here is the complete solution for the purpose of full documentation:

我尝试将JsonIgnore放在中间件(Web API客户端PCL)内部Image类的Employee属性上.奇怪的是,这不能解决问题.我仍然在属性后面有私有变量的堆栈溢出. 现在,我将JsonIgnore放在Web API(后端)中Image类的Employee导航属性以及Device类的Employee导航属性上.然后,我从API客户端(中间件)中完全删除了导航属性(图像类中的Employee和设备类中的Employee),因为这些属性的JSON现在将不再被接收,因为API已经忽略了它们. 现在,错误消失了,最重要的是,我极大地提高了请求和响应的速度.似乎尽管Web API(后端)运行良好且关系没有问题,但可选模型上的导航属性带来了大量的开销.这些类很小,数据库的表几乎是空的,但影响似乎很大.

I tried putting JsonIgnore on the Employee property on the Image class inside the middleware (the Web API client PCL). Strangely enough that did not fix the problem. I still got the Stack Overflow with the private variables behind the properties. 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. 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. 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. The classes are really small and the tables of the database are almost empty but the impact seems to be huge.

TL; DR:从源头消除了进行循环引用的可能性.反映到客户端的更改.问题解决了,速度也大大提高了.

如果有人对我的解决方案的完整设计感兴趣,这里有一个小总结.我很喜欢.

If somebody is interested in the complete design of my solution, here is a small summary. I like it a lot.

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

基本上,您可以只在Web API中编写一些属性(+配置JSon Serializer和DbContext),然后将生成整个后端和中间件的其余部分.我喜欢它.

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. I love it.

这篇关于JsonConvert.DeserializeObject上的StackOverflowException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆