3

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.

3
  • 3
    The objects mutually reference each other, causing an infinite recursion. You may need to decorate one or more navigation properties with [JsonIgnore] or something of that nature so the serializer doesn't attempt to follow those properties. Commented Oct 11, 2016 at 14:55
  • @zuckerthoben, how did you generate your template? T4? I'm sure you can help me, please take a look at this. Commented Jan 31, 2017 at 20:12
  • @Shimmy I saw that your problem is solved. Couldn't really help anyway, because I don't have automatic integration. I don't need it because my Web API is not changing that much. Commented Feb 1, 2017 at 7:44

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

4 Comments

I agree, I think that this is the correct solution.
Circular Reference is not a problem in the web api. The web api would not return valid json if there would be circular reference. I have wireshark running on my webserver, validating that requests and responses are valid, which they are. I guess the client implementation has issues with circular reference, thus this issue. So I will try to put JsonIgnore on the navigation property in the image class of the api client.
@zuckerthoben From a Web API perspective the circular reference may not be a problem but it's definitely a problem for many serialization libraries.
@Oxidda damn, very nice solution! Thank you so much!
1

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.

  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.

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.