簡體   English   中英

System.Text.Json.JsonException:檢測到可能的 object 循環

[英]System.Text.Json.JsonException: A possible object cycle was detected

我正在開發一個.Net 博客風格 API 作為一個練習項目,並且遇到了這個錯誤。 我有一個用戶 class,發布 class 和評論 class。 Comment 引用 Post 和 User,每個都是一對多的。

這是我的用戶 class:

 public class User
    {
        //Other properties..
        public List<Post> Posts { get; set; }
        public List<Comment> Comments { get; set; }
    }

我的帖子 class:

public class Post
    {
        //Other properties..
        public List<Comment> Comments { get; set; }
        [Required]
        public User CreatedBy { get; set; }
    }

和我的評論 class:

  public class Comment
    {
        //Other properties..
        [Required]
        public User CreatedBy { get; set; }
        [Required]
        public Post Post { get; set; }
    }

我正在嘗試保存這樣的評論(我從以前的方法中填充了 Post.Id 和 CreatedBy.Id)。 這就像它按預期插入數據庫一樣工作,但是我得到了 JsonException。

comment.Post = await _context.Posts.SingleOrDefaultAsync(p => p.Id == comment.Post.Id);
comment.CreatedBy = await _context.Users.FindAsync(comment.CreatedBy.Id);

await _context.Comments.AddAsync(comment);

await _context.SaveChangesAsync();

return comment;

我可以通過添加 Microsoft.AspNetCore.Mvc.NewtonsoftJson 並將其添加到我的啟動 class 來解決這個問題

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

但我想知道我是否應該在我的代碼中做些什么來避免這種情況,而不是僅僅提供一個選項來說明它沒關系。

Post 的一個實例包含一個 Comments 列表。 每個評論實例都包含一個帖子。 Post 的一個實例包含一個 Comments 列表。 每個 Comment 實例都包含一個 Post.... 等等。

雖然這樣做並不違反 C# 的規則,但我更願意避免這樣做,因為它會給數據集合帶來未知的復雜性。 文本序列化是您在執行此操作時會遇到的最大痛點之一。 盡管有一些方法可以處理這些痛點(ReferenceLoopHandling 和 Ignore 屬性標簽等等),但我發現從我的 class 定義中盡可能多地省略引用循環要容易得多,即使這意味着定義兩個不同命名的類相同的屬性,例如 Comment 和 PostComment(其中 PostComment 將是包含在帖子下的評論)。

例如,像下面這樣的結構會破壞循環引用,並使其易於序列化並持久化到數據庫中。 注意 Post 的 Comment 屬性的類型更改以及 PostComment 中相關的 Post 省略,從而打破了循環。

public class User
{
    //Other properties..
    public List<Post> Posts { get; set; }
    public List<Comment> Comments { get; set; }
}

public class Post
{
    //Other properties..
    public List<PostComment> Comments { get; set; }
    [Required]
    public User CreatedBy { get; set; }
}

public class Comment
{
    //Other properties..
    [Required]
    public User CreatedBy { get; set; }
    [Required]
    public Post Post { get; set; }
}

public class PostComment
{
    //Other properties..
    [Required]
    public User CreatedBy { get; set; }
}

我的 api (.net 5) 也有類似的問題。 拋出的異常 500 無法被 API 捕獲。 要查看實際問題,我必須從 go 到 windows “事件記錄器”。

為了解決我在配置(startup.cs)中添加的問題:

   services.AddMvc()
                .AddJsonOptions(opt =>
                 {
                     opt.JsonSerializerOptions.ReferenceHandler = System.Text.Json.Serialization.ReferenceHandler.Preserve;
                 });

文檔位於: https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-migrate-from-newtonsoft-how-to?pivots=dotnet-5-0

為避免循環,您可以嘗試使用急切加載並添加IgnoreAutoIncludes()擴展方法。 通過使用Include()擴展方法的這種方式,您可以指定要使用查詢拉回的導航屬性(但在您的特定情況下,您不需要包含任何內容,因為您只對 Post 實體感興趣):

 comment.Post = await _context.Posts.IgnoreAutoIncludes()
        .SingleOrDefaultAsync(p => p.Id == comment.Post.Id);

此外,如果您使用的是 Fluent API,您可以通過在OnModelCreating()方法中添加Ignore從映射中排除屬性:

modelBuilder.Entity<Post>().Ignore(c => c.Comments);

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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