簡體   English   中英

.Net Core 3.0 可能的 object 周期被檢測到不支持

[英].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 方法的調用將通過所提到的給定異常。 這是因為序列化會中斷,因為idTask<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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM