JsonException: 检测到不支持的可能的对象循环。这可能是由于循环或对象深度大于

sun*_*nny 25 c# api asp.net-core-mvc asp.net-core

在我的 web api 中,当我运行项目以从数据库获取数据时出现此错误 .net core 3.1

JsonException: 检测到不支持的可能的对象循环。这可能是由于循环或对象深度大于最大允许深度 32。

这些是我的代码我的模型

 public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ProductText { get; set; }
    public int ProductCategoryId { get; set; }
    [JsonIgnore]
    public virtual ProductCategory ProductCategory { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的 productCategory 类是:

 public class ProductCategory
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string CatText { get; set; }
    public string ImagePath { get; set; }
    public int Priority { get; set; }
    public int Viewd { get; set; }
    public string Description { get; set; }
    public bool Active { get; set; }
    public DateTime CreateDate { get; set; }
    public DateTime ModifyDate { get; set; }
    public virtual ICollection<Product> Products { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

我的回购是

public async Task<IList<Product>> GetAllProductAsync()
    {
        return await  _context.Products.Include(p => p.ProductCategory).ToListAsync(); 
    }
Run Code Online (Sandbox Code Playgroud)

我的界面

public interface IProductRepository
{
   ...
    Task<IList<Product>> GetAllProductAsync();
 ...
}
Run Code Online (Sandbox Code Playgroud)

这是我在 api 项目中的控制器

 [Route("api/[controller]")]
[ApiController]
public class ProductsController : ControllerBase
{
    private readonly IProductRepository _productRepository;

    public ProductsController(IProductRepository productRepository)
    {
        _productRepository = productRepository;
    }
    [HttpGet]
    public ActionResult Get()
    {
        return Ok(_productRepository.GetAllProduct());
    }
}
Run Code Online (Sandbox Code Playgroud)

当我运行 api 项目并输入这个 url: https://localhost:44397/api/products 我得到那个错误,我无法解决它

Ali*_*eza 41

发生这种情况是因为您的数据有一个参考循环。

例如

// this example creates a reference loop
var p = new Product()
     { 
        ProductCategory = new ProductCategory() 
           { products = new List<Product>() }
     };
    p.ProductCategory.products.Add(p); // <- this create the loop
    var x = JsonSerializer.Serialize(p); // A possible object cycle was detected ...
Run Code Online (Sandbox Code Playgroud)

您无法在新的System.Text.Json尚未(netcore 3.1.1)中处理引用循环情况,除非您完全忽略引用并且它始终不是一个好主意。(使用[JsonIgnore]属性)

但是你有两个选择来解决这个问题。

  1. 您可以Newtonsoft.Json在您的项目中使用而不是System.Text.Json(我为您链接了一篇文章)

  2. 从 dotnet5 库下载System.Text.Json预览包版本5.0.0-alpha.1.20071.1(通过 Visual Studio 的 NuGet 客户端):

选项 1 用法:

services.AddMvc()
     .AddNewtonsoftJson(
          options => {
           options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore; 
      });
// if you not using .AddMvc use these methods instead 
//services.AddControllers().AddNewtonsoftJson(...);
//services.AddControllersWithViews().AddNewtonsoftJson(...);
//services.AddRazorPages().AddNewtonsoftJson(...);
Run Code Online (Sandbox Code Playgroud)

选项 2 用法:

// for manual serializer
var options = new JsonSerializerOptions
{
    ReferenceHandling = ReferenceHandling.Preserve
};

string json = JsonSerializer.Serialize(objectWithLoops, options);

// -----------------------------------------
// for asp.net core 3.1 (globaly)
 services.AddMvc()
  .AddJsonOptions(o => {
     o.JsonSerializerOptions
       .ReferenceHandling = ReferenceHandling.Preserve  
            });
Run Code Online (Sandbox Code Playgroud)

这些序列化程序具有ReferenceLoopHandling功能。

  • 编辑 在 DotNet 5 中ReferenceHandling 改为ReferenceHandler

但是如果您决定忽略[JsonIgnore]这些属性之一的一个引用使用。但即使您没有引用循环,它也会导致该字段的 API 响应为空结果。

public class Product
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string ProductText { get; set; }
    
    public int ProductCategoryId { get; set; }
    // [JsonIgnore] HERE or
    public virtual ProductCategory ProductCategory { get; set; }
}

public class ProductCategory
{
    public int Id { get; set; }
    // [JsonIgnore] or HERE
    public ICollection<Product> products {get;set;}
}
Run Code Online (Sandbox Code Playgroud)

  • 从 `System.Text.Json` v5 Preview6 开始,`ReferenceHandling` 现在是 `ReferenceHandler`。请参阅:https://github.com/dotnet/runtime/pull/37296/files (8认同)

Erç*_*ğlu 18

.NET 5 Web API

    public static void ConfigureServices(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddControllers()
            .AddJsonOptions(o => o.JsonSerializerOptions
                .ReferenceHandler = ReferenceHandler.Preserve);
    }
Run Code Online (Sandbox Code Playgroud)


Che*_*Chu 8

在 .Net 6 中,您可以在 Program.cs 中使用以下方式System.Text.Json初始化启动操作:AddControllersWithViews

using System.Text.Json.Serialization;

builder.Services.AddControllersWithViews()
                .AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);
Run Code Online (Sandbox Code Playgroud)

AddMvc你也可以这样使用,

builder.Services.AddMvc()
                .AddJsonOptions(x => x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);
Run Code Online (Sandbox Code Playgroud)

但引用瑞安的话

asp.net core 3.0+ 模板使用这些新方法AddControllersWithViews、AddRazorPages、AddControllers 而不是AddMvc。

我建议使用第一个解决方案。


Wil*_* Jr 6

我有同样的问题,我的解决方法是添加 async 和 await 关键字,因为我在我的业务逻辑上调用 async 方法。

这是我的原始代码:

[HttpGet]
public IActionResult Get()
{
   //This is async method and I am not using await and async feature .NET which triggers the error
   var results = _repository.GetAllDataAsync(); 
   return Ok(results);
}
Run Code Online (Sandbox Code Playgroud)

对此:

HttpGet]
public async Task<IActionResult> Get()
{
   var results = await _repository.GetAllDataAsync();
   return Ok(results);
}
Run Code Online (Sandbox Code Playgroud)


小智 5

我修复了我的 API Core Net6.0 添加[JsonIgnore]

public class SubCategoryDto
{

    public int Id { get; set; }
    public string Name { get; set; }
    public string Image { get; set; }
    public int CategoryId { get; set; }
    [JsonIgnore]
    public Category Category { get; set; }
   
   
}
Run Code Online (Sandbox Code Playgroud)