JsonConvert.DeserializeObject

时间:2016-10-11 14:52:05

标签: c# asp.net json asp.net-web-api

我正在编写一个包含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。

2 个答案:

答案 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:消除源头循环引用的可能性。对客户端进行镜像更改。问题解决了,也获得了巨大的速度提升。

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

  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轻松获取数据。
  5. 基本上你可以在Web API中编写一些属性(+配置JSon Serializer和DbContext),然后生成整个后端和中间件的其余部分。我喜欢它。