Reputation:
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 (in the middleware)
private Image _image = new Image();
ImagesManager.cs (in the middleware)
private Employee _employee = new Employee();
Here is more code:
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; }
}
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();
}
}
}
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.
I use Newtonsoft Json.NET, Entity Framework 6, NSwag 6, Xamarin.Forms v2.3.2.127.
Upvotes: 3
Views: 2294
Reputation:
I followed the answers of Oxidda, David and 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). 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: Eliminated the possibility for circular reference at the source. 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.
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.
Upvotes: 1
Reputation: 33
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.
Try putting a [JsonIgnore]
above the Employee property in Image the image class.
Upvotes: 2