检测到不支持的.Net Core 3.0可能的对象周期


22

我有2个实体与一对多相关

public class Restaurant {
   public int RestaurantId {get;set;}
   public string Name {get;set;}
   public List<Reservation> Reservations {get;set;}
   ...
}
public class Reservation{
   public int ReservationId {get;set;}
   public int RestaurantId {get;set;}
   public Restaurant Restaurant {get;set;}
}

如果我尝试使用我的API预订餐厅

   var restaurants =  await _dbContext.Restaurants
                .AsNoTracking()
                .AsQueryable()
                .Include(m => m.Reservations).ToListAsync();
    .....

我收到错误消息,因为对象包含彼此的引用。有相关的文章建议创建单独的模型 或添加NewtonsoftJson配置

问题是我不想创建单独的模型,第二个建议没有帮助。有没有没有循环关系的加载数据的方法吗?*

System.Text.Json.JsonException:检测到不支持的可能的对象循环。这可能是由于循环造成的,或者是对象深度大于System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth)处System.Text.Json.Json.JsonSerializer.Write(Utf8JsonWriter writer)处的最大深度。 ,Int32 originalWriterDepth,Int32 flushThreshold,JsonSerializerOptions选项,WriteStack和状态)位于System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json,对象值,类型inputType,JsonSerializerOptions选项,CancellationToken cancelTokens)在Microsoft.AspNetFormat.System。 Microsoft.AspNetCore.Mvc上的WriteResponseBodyAsync(OutputFormatterWriteContext上下文,对selectedEncoding进行编码)。

*


要求它忽略Reservation类的Restaurant属性。
Lasse V. Karlsen

6
确实,您不应该直接从API返回数据库实体。我建议创建特定于API的DTO并进行相应的映射。当然,您说过您不想这样做,但我认为将API和持久性内部结构分开是一种很好的做法。
mackie

“和第二条建议没有帮助”需要详细信息。
Henk Holterman

“问题是我不想创建单独的模型”。除非您这样做,否则您的设计从根本上是有缺陷的。API是一种类似于接口的协定(实际上是一个应用程序编程接口)。它永远都不应更改,一旦发布,任何更改都需要一个新版本,该版本将需要与旧版本同时运行(不推荐使用,并最终在将来删除)。这使客户有时间更新其实现。如果直接返回一个实体,那么您将紧密耦合数据层。
克里斯·普拉特

对该数据层的任何更改都必须立即对API进行不可更改的更改,立即中断所有客户端,直到他们更新其实现。以防万一,这是一件坏事。简而言之:切勿接受或返回API中的实体。您应该始终使用DTO。
克里斯·普拉特

Answers:


32

我已经在一个新项目中尝试过您的代码,并且首先为3.0 安装软件包Microsoft.AspNetCore.Mvc.NewtonsoftJson后,第二种方法似乎运行良好

services.AddControllerWithViews()
    .AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

尝试一个新项目并比较差异。


1
关键时刻是重新安装Microsoft.AspNetCore.Mvc.NewtonsoftJson的正确版本,我没有关注该版本,因为该软件包位于包装盒下,没有任何错误和警告!感谢您的回答!一切都按我的预期工作!
纳扎尔·皮利普

1
为了提高系统json的性能,我们必须使用NewtonsoftJson是不是错了?:/
Marek Urbanowicz

40

.NET Core 3.1 安装软件包Microsoft.AspNetCore.Mvc.NewtonsoftJson

Startup.cs 添加服务

services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

1
您可以格式化回复并添加一些详细信息吗?这是不可读的。
Sid

欲了解更多详情,请查看:thecodebuzz.com/...
迭戈贝南西奥

4

最好在启动时使设置的JSON序列化选项起作用,因为将来您可能会遇到类似的情况。但是,与此同时,您可以尝试将数据属性添加到模型中,这样就不会序列化:https : //www.newtonsoft.com/json/help/html/PropertyJsonIgnore.htm

public class Reservation{ 
    public int ReservationId {get;set;} 
    public int RestaurantId {get;set;} 
    [JsonIgnore]
    public Restaurant Restaurant {get;set;} 
}

这也可以。但是正如您提到的那样,您必须更新所有模型,我更喜欢services.AddControllers()。AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
Nantharupan

1
public class Reservation{ 
public int ReservationId {get;set;} 
public int RestaurantId {get;set;} 
[JsonIgnore]
public Restaurant Restaurant {get;set;} 

以上工作也。但我更喜欢以下

services.AddControllers().AddNewtonsoftJson(options =>
    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);

因为首先我们需要将属性添加到所有模型中,所以我们可能需要循环引用。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.