shuhelohelo’s blog

Xamarin.Forms多めです.

webapiでentityframeworkの結果を返すときに循環エラーとなるのを防ぐ方法

https://youtu.be/eNScZiYuVCU

43分辺り。

相互に参照する以下のような2つのモデルがある.

    public class Author
    {
        public int ID { get; set; }
        [Required]
        public string FirstName { get; set; }
        [Required]
        public string LastName { get; set; }
        public string Nationality { get; set; }

        public List<Book> Books { get; set; }
    }

    public class Book
    {
        public int ID { get; set; }

        [Required]
        public string Title { get; set; }
        public DateTime PublishDate { get; set; }

        [Required]
        public int AuthorID { get; set; }

        public Author Author { get; set; }
    }

このとき,これらのモデルのデータをEntityFramework Coreで取得してJSONで返すWebAPIをASP.NET Coreで作成する.

このAPIはすべてのBookの情報を返すシンプルなメソッド.

        // GET: api/Books
        [HttpGet]
        public async Task<ActionResult<IEnumerable<Book>>> GetBooks()
        {
            return await _context.Books.Include(b=>b.Author).ToListAsync();
        }

このときIncludeメソッドを使用してBookが持つAuthorの情報も取得するようにする.

ここで,クライアントからこのAPIを利用すると,以下のような循環参照エラーが発生する.

System.Text.Json.JsonException: A possible object cycle was detected which is not supported. 
This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32.

JSONに変換する際にこの循環参照によって際限なく深くなってしまうために生じる.

EFの処理自体は問題なく,あくまでJSONに変換するときの問題.

解決方法

NewtonsoftJsonは.NETにとりこまれたけれど,これの解決は.NET Core 3.1ではできず,Microsoft.AspNetCore.Mvc.NewtonsoftJasonパッケージを使用する必要がある.

Nugetからインストールする.

次に,Startup.csに以下を追加する.

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

オプションでReferenceLoopHandlingIgnoreに設定することで,このエラーを回避することができる.

サンプルコード:

github.com