前言
看了下推送记录,一个月前,OK,我又变成月更了o(╯□╰)o,这绝对不行![○・`Д´・ ○]
所以今天来更新了
其实不是我懒得更新或者是太忙,其实是最近在写一篇很长的博客,一直没写完( Ĭ ^ Ĭ )
另外快过年了,我领到了公众号作者的红包封面定制机会,接下来找时间设计(copy)一个好看的红包封面作为粉丝福利发给各位读者大大
好吧,先进入正题……
有一个关于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,并且配置处理套娃递归的方式为忽略~
参考文档
- https://stackoverflow.com/questions/59199593/net-core-3-0-possible-object-cycle-was-detected-which-is-not-supported 

代码使我头疼之React初学习

AspNetCore在docker部署时遇到一个小坑

Asp.Net Core部署:早知道,还是docker!以及一点碎碎念

纯前端实现词云展示+附微博热搜词云Demo代码

一个玄学的爬虫bug竟让我放弃Python语言!?背后的原因令人唏嘘~