![](/img/trans.png)
[英]Error when deserialize Json .NET CORE 5 - JsonException: A possible object cycle was detected which is not supported
[英].Net Core 3.0 possible object cycle was detected which is not supported
我有 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();
.....
我收到錯誤響應,因為對象包含對彼此的引用。 有相關帖子建議單獨創建 model或者添加NewtonsoftJson 配置
問題是我不想創建單獨的 model 並且第二個建議沒有幫助。 有沒有辦法在沒有循環關系的情況下加載數據? *
System.Text.Json.JsonException:檢測到不支持的可能的 object 循環。 This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32. at System.Text.Json.ThrowHelper.ThrowInvalidOperationException_SerializerCycleDetected(Int32 maxDepth) at System.Text.Json.JsonSerializer.Write(Utf8JsonWriter writer , Int32 originalWriterDepth, Int32 flushThreshold, JsonSerializerOptions options, WriteStack& state) at System.Text.Json.JsonSerializer.WriteAsyncCore(Stream utf8Json, Object value, Type inputType, JsonSerializerOptions options, CancellationToken cancellationToken) at Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter. Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) 在麥克風的 WriteResponseBodyAsync(OutputFormatterWriteContext context, Encoding selectedEncoding) rosoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|29_0[TFilter,TFilterAsync](ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow( ResultExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext[TFilter,TFilterAsync](State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
*
我已經在一個新項目中嘗試過你的代碼,在首先為 3.0 安裝包Microsoft.AspNetCore.Mvc.NewtonsoftJson后,第二種方法似乎工作得很好
services.AddControllersWithViews()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
嘗試一個新項目並比較差異。
.NET Core 3.1安裝包 Microsoft.AspNetCore.Mvc.NewtonsoftJson(來自https://www.nuget.org/packages/Microsoft.AspNetCore.Mvc.NewtonsoftJson/ )
Startup.cs添加服務
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
誰仍然面臨這個問題:檢查您是否await
-ed 所有異步方法。
在啟動時設置 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;}
}
這使用 System.Text.Json
var options = new JsonSerializerOptions()
{
MaxDepth = 0,
IgnoreNullValues = true,
IgnoreReadOnlyProperties = true
};
使用選項進行序列化
objstr = JsonSerializer.Serialize(obj,options);
當我錯誤地返回Task<object>
而不是控制器方法中的object
時,我收到了這樣的錯誤。 任務導致循環。 檢查您要返回的內容。
經過幾個小時的調試,它確實有一個簡單的解決方案。 我發現這個鏈接很有幫助。
這個錯誤是因為:
ASP.NET Core 3.0 及以上版本中使用的默認 JSON 序列化程序。
ASP.NET Core 3.0 刪除了對 JSON.NET 的依賴,並使用它自己的 JSON 序列化程序,即“System.Text.Json”。
我能夠解決添加對 NewtonsoftJson Nuget 包的引用的問題,
PM> Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.1.2
並更新 Startup.cs 如下,
services.AddControllers().AddNewtonsoftJson(options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore );
System.Text.Json 序列化程序當前不支持 ReferenceLoopHandling
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
);
因為首先我們需要將屬性添加到我們可能有循環引用的所有模型中。
發生這種情況是因為當涉及到 JSON 序列化時,您的數據模型之間存在兩種方式的關系。
你不應該直接返回你的數據模型。 將它映射到一個新的響應模型,然后返回它。
對於其他沒有找到其他解決方案的人,您實際上需要分析您的完整調用堆棧,並查看是否有任何async
調用未在預期await
地方等待。 這是問題中提到的實際問題。
例如,考慮以下的方法中MyAppService
,它調用一個async Task<int>
的MyOtherService
:
public async Task<int> Create(InputModel input)
{
var id = _myOtherService.CreateAndGetIdAsync(input);
return Created("someUri", id);
}
如果CreateAndGetIdAsync
方法是async Task
,則對上述 Create 方法的調用將通過所提到的給定異常。 這是因為序列化會中斷,因為id
是Task<int>
但實際上不是int
。 因此,在返回響應之前必須await
。
附加說明:這里還需要注意一件事,即使認為出現此異常,它也不會影響 db 操作。 即,在我上面的示例中,db 操作將成功。 同樣,如 OP 中所述,我正在使用的 ORM 並未拋出異常,但此異常稍后會按調用堆棧的順序(在調用方之一中)拋出。
我知道這個問題是針對 .net Core 3.0 的,但是對於在 .net 5.0 中遇到相同問題的任何人,我在這里找到了解決方案。
總之,需要在您的 Startup class 的 ConfigureServices 方法中添加以下代碼:
services.AddControllers().AddJsonOptions(x =>
x.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve);
我從控制器中的默認 POST 方法中得到了這個錯誤,該方法是使用API Controller with actions, using entity framework
創建的API Controller with actions, using entity framework
。
return CreatedAtAction("GetLearningObjective", new { id = learningObjective.Id }, learningObjective);
System.Text.Json.JsonException: 檢測到可能的對象循環。 這可能是由於循環或對象深度大於最大允許深度 32。考慮在 JsonSerializerOptions 上使用 ReferenceHandler.Preserve 以支持循環。 在 System.Text.Json.ThrowHelper.ThrowJsonException_SerializerCycleDetected(Int32 maxDepth)
直接從 Postman 或瀏覽器調用HttpGet
,它可以正常工作。 通過像這樣編輯Startup.cs
- services.AddControllers()
解決:
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
});
你也可以這樣解決:
services.AddControllers(options =>
{
options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
options.OutputFormatters.Add(new SystemTextJsonOutputFormatter(new JsonSerializerOptions(JsonSerializerDefaults.Web)
{
ReferenceHandler = ReferenceHandler.Preserve,
}));
});
我遇到了這個問題,我很困惑,因為我有另一個應用程序運行相同的代碼,唯一的區別是這次我想使用 await,而在上一個應用程序中我使用了ConfigureAwait(false).GetAwaiter().GetResult();
因此,通過刪除 await 並在 Async 方法的末尾添加ConfigureAwait(false).GetAwaiter().GetResult()
我能夠解決這個問題。
將代碼添加到 Startup 類解決了我的錯誤,即包含語句。
services.AddControllersWithViews()
.AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
正如@Jozkee 在接受的答案中的評論中所述,.NET 6 在System.Text.Json
包含ReferenceHandler.IgnoreCycles
。
這就是我在不安裝 Newtonsoft.Json 並通過將以下內容添加到Program.cs
來利用 .NET 6 的新增功能的情況下解決此問題的方法。
builder.Services.AddControllersWithViews()
.AddJsonOptions(options => options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles);
我沒有使用 NewtonsoftJson,而是使用 System.Text.Json.Serialization
在 Startup.cs
public void ConfigureServices(IServiceCollection services)
{
..........
.......
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
options.JsonSerializerOptions.WriteIndented = true;
});
}
MinimalAPI 使用這個:
builder.Services.Configure<Microsoft.AspNetCore.Http.Json.JsonOptions>(options =>
{
options.SerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
});
我也有這個問題,根據答案,我向 Json 服務添加了如下選項:
builder.Services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
上面的代碼不起作用,我添加了下面的代碼,然后一起添加:
builder.Services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
}).AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
});
但是這些選項也沒有說明。 最后我嘗試將 MaxDepth 定義為 1 但再次發生此錯誤。
我們如何從這個錯誤中停止 Json 串行器或強制僅序列化接收數據的深度 1?
謝謝你們
我遇到了這個問題,我不得不通過將以下內容添加到我的數據庫上下文類中的OnModelCreating(ModelBuilder builder)方法來告訴應用程序/上下文忽略子實體上的父實體:
builder.Entity<ChildEntity>()
.HasOne(a => a.ParentEntity)
.WithMany(m => m.ChildEntities);
builder.Entity<ChildEntity>().Ignore(a => a.ParentEntity);
Ignore的最后一行是它為我所做的。
接受的答案將默認序列化程序從 System.Text.Json 更改為 Newtonsoft,並將通過從序列化中刪除導航屬性來解決循環!
訂單示例:
{
"id": "d310b004-79a2-4661-2f90-08d8d25fec03"
"orderItems": [
{
"orderId": "d310b004-79a2-4661-2f90-08d8d25fec03",
"orderItemId": "83d36eda-ba03-448c-e53c-08d8d25fec0b",
"orderItem": {
"id": "83d36eda-ba03-448c-e53c-08d8d25fec0b",
"name": "My order item"
}
// where is the reference to the order?!
}
]
}
如果您不想更改默認序列化程序或需要保留導航屬性,則可以配置 System.Text.Json 序列化程序以保留引用。 但要小心,因為它通過提供 $id、$ref 和$values屬性來改變輸出結構!
services.AddControllers().AddJsonOptions(options => options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve)
訂單示例:
{
"$id": "1",
"id": "d310b004-79a2-4661-2f90-08d8d25fec03"
"orderItems": {
$"id": "2",
$"values": [
{
$"id": "3",
"orderId": "d310b004-79a2-4661-2f90-08d8d25fec03",
"orderItemId": "83d36eda-ba03-448c-e53c-08d8d25fec0b",
"orderItem": {
"id": "83d36eda-ba03-448c-e53c-08d8d25fec0b",
"name": "My order item"
},
"order": {
"$ref": "1" // reference to the order
}
}
]
}
}
我有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(流utf8Json,對象值,類型inputType,JsonSerializerOptions選項,CancellationToken cancelTokens)位於Microsoft.AspNetFormat.System。 Microsoft.AspNetCore.Mvc.Formatters.SystemTextJsonOutputFormatter.WriteResponseBodyAsync(OutputFormatterWriteContext上下文,Encoding selectedEncoding)處的WriteResponseBodyAsync(OutputFormatterWriteContext上下文,對selectedEncoding進行編碼),Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker | T最后一個任務,狀態下一個,Sco 例如,Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.ResultNext [TFilter,TFilterAsync](狀態和下一個,范圍和范圍,對象和對象)在Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResultExecutedContextSealed上下文)狀態,布爾值和isCompleted),位於Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.InvokeResultFilters()
*
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.