.NET 3.1 MVC序列化菜单项出现对象循环JsonException如何解决
问题核心原因
你在Startup中配置的JSON序列化规则仅作用于Controller接口返回值的自动序列化流程,Razor视图中手动调用JsonSerializer.Serialize()静态方法时不会继承这些全局配置,因此循环引用处理逻辑未生效。同时你的Startup配置存在两处不合理的地方:
- 重复调用
AddControllers会覆盖之前的注册配置 - MVC项目应该使用
AddControllersWithViews而非AddControllers,后者不会注册视图相关服务
解决方案
你可以根据自己的业务场景选择以下任意一种方案处理:
方案1:视图序列化时手动传入配置(最快修复)
如果不需要修改现有实体结构,直接在视图序列化时指定循环引用处理规则即可:
用System.Text.Json序列化:
@inject ICategoryService _categoryService; @inject IMenuItemService _menuItemService; @using System.Text.Json; @{ var allMenuItems = _menuItemService.GetAllMenuItems(); var jsonOptions = new JsonSerializerOptions { ReferenceHandler = ReferenceHandler.Preserve, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; string json = JsonSerializer.Serialize(allMenuItems, jsonOptions); }
用Newtonsoft.Json序列化(更推荐,避免Preserve生成的额外$id字段影响前端使用):
@inject ICategoryService _categoryService; @inject IMenuItemService _menuItemService; @using Newtonsoft.Json; @{ var allMenuItems = _menuItemService.GetAllMenuItems(); string json = JsonConvert.SerializeObject(allMenuItems, new JsonSerializerSettings { ReferenceLoopHandling = ReferenceLoopHandling.Ignore }); }
方案2:添加DTO消除循环引用(长期最优方案)
出现循环引用通常是因为你的MenuItem实体类和关联导航属性(比如Category)互相持有对方的引用,单独创建仅包含前端所需字段的DTO(数据传输对象),序列化DTO即可从根源避免问题,同时还能精简序列化后的JSON体积:
- 定义DTO类
public class MenuItemDto { public int Id { get; set; } public string Name { get; set; } public string NavUrl { get; set; } // 仅保留需要的关联字段,不要引入完整的关联实体对象 public string CategoryName { get; set; } }
- 查询后映射到DTO再序列化即可。
方案3:实体类添加序列化忽略特性
如果不想新增DTO,可以在实体类的循环导航属性上添加序列化忽略特性:
public class MenuItem { public int Id { get; set; } public string Name { get; set; } // 序列化时忽略该关联属性,注意匹配你使用的序列化库对应的特性 [System.Text.Json.Serialization.JsonIgnore] // 用Newtonsoft的话换成 [Newtonsoft.Json.JsonIgnore] public Category Category { get; set; } }
内容的提问来源于stack exchange,提问作者peter
相关产品推荐
相关产品推荐

