Asp-Net-Core開發筆記:接口返回json對象出現套娃遞歸問題


前言

看了下推送記錄,一個月前,OK,我又變成月更了o(╯□╰)o,這絕對不行![○・`Д´・ ○]

所以今天來更新了

其實不是我懶得更新或者是太忙,其實是最近在寫一篇很長的博客,一直沒寫完( Ĭ ^ Ĭ )

好吧,先進入正題……

有一個關於WebApi序列化的問題,跟設計有關,但在涉及到關聯字段的時候經常會遇到。

實體類

先看看實體類定義,限於篇幅,只保留幾個關鍵字段。

public class CrawlTask : EntityBase {
    /// <summary>
    /// 爬蟲名稱
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 創建這個爬蟲的用戶
    /// </summary>
    public User User { get; set; }
    /// <summary>
    /// 用戶ID
    /// </summary>
    public string? UserId { get; set; }
}

用戶實體類:

public class User : EntityBase {
    /// <summary>
    /// 用戶名
    /// </summary>
    public string Name { get; set; }
    /// <summary>
    /// 用戶創建的爬蟲
    /// </summary>
    public List<CrawlTask> CrawlTasks { get; set; }
}

接口

然后接口這樣寫:

/// <summary>
/// 獲取用戶創建的全部爬蟲
/// </summary>
/// <returns></returns>
[HttpGet]
public ActionResult<List<CrawlTask>> GetAll() {
    var user = _authService.GetUser(User.Identity?.Name);
    return user.CrawlTasks;
}

然后請求這個接口,我們期望的數據是:

[
  {
    "name": "爬蟲名稱",
    "user": {
    	"name": "用戶名"
    },
    "userId": "0f3d4b2f-3b4e-4d08-8f4c-0009a316f041",
    "id": "4d52d83b-f3ec-47c6-ab26-e241c09c14d1"
  }
]

報錯

但事實是直接報錯:

System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.
Path: $.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.User.CrawlTasks.Name.

很明顯,返回的對象套娃遞歸了。

注意那個Path:$.User.CrawlTasks.User.CrawlTasks.User.Crawl... ,我們上面期望的json數據是:

{
    "name": "test crawl123",
    "user": {
        "name": "string"
    },
    "userId": "0f3d4b2f-3b4e-4d08-8f4c-0009a316f041",
    "id": "4d52d83b-f3ec-47c6-ab26-e241c09c14d1"
}

Crawl對象下的User只有Name屬性,不要把CrawlTasks列表也顯示出來,但程序它不知道啊,User里有CrawlTasks,然后CrawlTasks里面又有User,這就陷入一個套娃遞歸了……

初步解決

很明顯,這根設計和數據獲取方式有問題,可以通過換個查詢方式來避免,比如:

[HttpGet]
public ActionResult<List<CrawlTask>> GetAll() {
    return _crawlRepo
        .Where(a => a.UserId == User.Identity.Name)
        .ToList();
}

因為這里沒有請求Crawl的導航屬性User,所以不會讀取User對象的信息,出現的結果是這樣:

[
  {
    "name": "test crawl123",
    "user": null,
    "userId": "0f3d4b2f-3b4e-4d08-8f4c-0009a316f041",
    "id": "4d52d83b-f3ec-47c6-ab26-e241c09c14d1"
  }
]

可以看到User對象的值是null,對於接口來說已經夠用了,畢竟這是獲取當前用戶的所有爬蟲,所有爬蟲的user屬性都是同一個,沒必要重復啦。

不過即使把User對象加上也是完全沒問題的,這里改一下接口看一下效果:

[HttpGet]
public ActionResult<List<CrawlTask>> GetAll() {
    return _crawlRepo.Select
        .Where(a => a.UserId == User.Identity.Name)
        .Include(a => a.User)		// 添加了這行代碼,請求關聯對象
        .ToList();
}

返回的結果:

[
  {
    "name": "test crawl123",
    "user": {
      "name": "string",
      "crawlTasks": null,
      "id": "0f3d4b2f-3b4e-4d08-8f4c-0009a316f041"
    },
    "userId": "0f3d4b2f-3b4e-4d08-8f4c-0009a316f041",
    "id": "4d52d83b-f3ec-47c6-ab26-e241c09c14d1"
  }
]

可以看到,返回的Crawl對象中,User對象里的crawlTasks屬性是空的,因為我們前面加的那行代碼:.Include(a => a.User),FreeSQL還支持進一步查詢User的導航屬性crawlTasks,但需要置頂Includethen參數,配置套娃查詢……

繼續!

那有沒有什么辦法是不改動接口代碼的情況下,解決接口套娃的問題?

答案肯定有啦

這就要用NewtonsoftJson了~

首先安裝Microsoft.AspNetCore.Mvc.NewtonsoftJson這個nuget包

然后在服務配置里面添加代碼

services.AddControllersWithViews()
    .AddNewtonsoftJson(options => {
        options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
    });

然后再請求接口,返回的結果就跟上面的一樣啦~

會導致套娃遞歸的屬性直接變成null~

PS:這個代碼的作用就是把WebApi默認的json序列化器從System.Text.Json改成NewtonsoftJson,並且配置處理套娃遞歸的方式為忽略~

參考文檔


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM