2016-10-11 37 views
2

我正在編寫一個包含ASP.NET Web API(.NET 4.6.2)(即後端),Web API客戶端實現PCL(即中間件)和Xamarin.Forms項目(也稱爲前端)的解決方案。在我的web api最近發生的變化之後,當我嘗試反序列化我前端的JSON響應時,我總是得到一個StackOverflowException。具體線路爲:JsonConvert.DeserializeObject上的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認識到堆棧溢出。在Android上,當我從Web API讀取數據時,應用程序僅關閉而沒有異常。

如果有人想看更多的代碼,我可以準備一個包含所需代碼的小包。在這裏發佈它們會完全破壞可讀性。

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

+3

對象相互引用,導致無限遞歸。您可能需要使用'[JsonIgnore]'或某種特性修飾一個或多個導航屬性,以便序列化程序不會嘗試遵循這些屬性。 – David

+0

@zuckerthoben,你是如何生成你的模板? T4?我相信你可以幫助我,請看看[this](https://github.com/NSwag/NSwag/issues/553)。 – Shimmy

+0

@Shimmy我看到你的問題解決了。無論如何不能真正幫助,因爲我沒有自動集成。我不需要它,因爲我的Web API沒有那麼多改變。 – zuckerthoben

回答

1

我跟着Oxidda,David和EJoshuaS的回答。

下面是完整文檔的目的,完整的解決方案:

我試圖把JsonIgnore對員工財產上的Image類的中間件(在Web API客戶端PCL)內。奇怪的是,這並沒有解決問題。我仍然使用屬性後面的私有變量進行堆棧溢出。 現在我將JsonIgnore放在Web API(後端)中的Image類的Employee導航屬性上以及Device類的Employee導航屬性中。然後,我完全從API客戶端(中間件)中刪除了導航屬性(圖像類中的Employee和設備類中的Employee),因爲這些屬性的JSON現在不會被接收,因爲API已經忽略了這些屬性。 現在錯誤消失了,最重要的是我對請求和響應速度有了明顯的提升。似乎雖然Web API(後端)工作正常,並且與關係沒有任何問題,但可選模型上的導航屬性引入了大量開銷。這些類非常小,數據庫的表幾乎是空的,但影響似乎很大。

TL; DR:消除了在源處循環引用的可能性。對客戶進行鏡像更改。問題解決了,也獲得了巨大的速度提升。

如果有人對我的解決方案的完整設計感興趣,下面是一個小小的總結。我很喜歡。

  1. 使用實體框架6創建ASP.NET Web API(.NET 4.6.2)項目6.添加了具有關係的模型,添加了DbContext。腳手架的異步控制器。 Web API已完成。請注意,在JSon中使用實體框架時,不應該使用延遲加載。相反,我使用控制器中的急切加載。
  2. 創建一個與Xamarin PCL使用的配置文件相同的PCL。因此它與Xamarin解決方案兼容,也適用於所有其他標準.NET解決方案。
  3. 基於Web API生成中間件API,其中NSwag。您基本上將API.dll加載到程序中,選擇您的設置,然後在C#中收到完整的與PCL兼容的Web API客戶端實現。 API是非常高級別和異步的,因此您可以在任何.NET前端輕鬆使用API​​。
  4. 添加您選擇的前端解決方案。通過客戶端API輕鬆獲取數據。

基本上你可以在Web API中編寫一些屬性(+配置JSon串行器和DbContext),並生成整個後端和中間件的其餘部分。我喜歡它。

1

我以前曾發生過這種事;這是由於對象之間的循環引用。你有一個Employee引用Image和Image引用Employee。

試着把[JsonIgnore]放在Image Image類的Employee屬性上面。

+0

我同意,我認爲這是正確的解決方案。 – EJoshuaS

+0

循環引用在web api中不是問題。如果有循環引用,web API將不會返回有效的json。我的網絡服務器上運行wireshark,驗證請求和響應是有效的,它們是。 我猜客戶端實現有循環引用的問題,因此這個問題。所以我會嘗試將JsonIgnore放在api客戶端的圖像類的導航屬性中。 – zuckerthoben

+1

@zuckerthoben從Web API的角度來看,循環引用可能不是問題,但對於很多序列化庫來說,這絕對是一個問題。 – EJoshuaS