返回文章列表文章索引阅读全文
STARBLOG / 阅读手记
Asp-Net-Core开发笔记

Asp-Net-Core开发笔记:接口返回json对象出现套娃递归问题

前言 看了下推送记录,一个月前,OK,我又变成月更了o(╯□╰)o,这绝对不行![○・`Д´・ ○] 所以今天来更新了 其实不是我懒得更新或者是太忙,其实是最近在写一篇很长的博客,一直没写完( Ĭ ^ Ĭ ) 好吧,先进入正题…… 有一个关于WebApi序列化的问题,跟设计有关,但在涉及到关联字段的时候经常会遇到。 实体类 先看看实体类定义,限于篇幅,只保留几个关键字段。 public class

曦远 (DealiAxy)约 10 分钟
目录7 个章节

前言

看了下推送记录,一个月前,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,但需要置顶Include的then参数,配置套娃查询……

继续!

那有没有什么办法是不改动接口代码的情况下,解决接口套娃的问题?

答案肯定有啦

这就要用NewtonsoftJson了~

首先安装Microsoft.AspNetCore.Mvc.NewtonsoftJson这个nuget包

然后在服务配置里面添加代码

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

然后再请求接口,返回的结果就跟上面的一样啦~

会导致套娃递归的属性直接变成null~

PS:这个代码的作用就是把WebApi默认的json序列化器从System.Text.Json改成NewtonsoftJson,并且配置处理套娃递归的方式为忽略~

参考文档

_EOF_

Asp-Net-Core开发笔记:接口返回json对象出现套娃递归问题

本文作者:
程序设计实验室
版权声明:
本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!

相关文章

Asp-Net-Core开发笔记:在docker部署时遇到一个小坑

哦吼 之前刚说了尝试了使用docker来部署AspNetCore应用,结果这才刚上班就遇到问题了= =… 我这项目用的数据库是Oracle,之前直接运行没啥问题,但放在docker里运行就报了这个错误: ORA-01882: timezone region not found 看这错误信息是在说时区不对,分别在服务器和docker里看一下时间: [root@localhost ~]# date -

2022-02-16 · Asp-Net-Core开发笔记 · 约 1 分钟

Asp-Net-Core开发笔记:FrameworkDependent搭配docker部署

之前我写过一篇使用 docker 部署 AspNetCore 应用的文章,这种方式搭配 CICD 非常方便, build 之后 push 到私有的 dockerhub ,在生产服务器上 pull 下来镜像就可以直接运行了。 然而,有时需要一种更传统的部署方式,比如在本地打包可执行文件之后直接放到服务器上执行。 这种方式配置完成之后,每次更新只需要重新本地重新 publish 后把可执行文件上传

2023-09-08 · Asp-Net-Core开发笔记 · 约 1 分钟

讨论

共 0 条

良言一句三冬暖,恶语伤人六月寒。

加载评论中…