liveBook · Manning

Circular reference

As explained in Pro ASP.NET Core 7, Tenth Edition

A circular reference is a chain of object references in which an object is eventually referenced again, forming a cycle.

A circular reference is a chain of object references that eventually points back to an earlier object. In ASP.NET Core web services, Entity Framework Core can create this cycle while loading related data: a Supplier contains Products, and each Product points back to its Supplier. JSON serialization then fails with an object-cycle exception. section 20.2

A related-data query that creates the cycle

A controller query such as context.Suppliers.Include(s => s.Products).FirstAsync(...) loads the supplier and its products. Entity Framework Core also populates each Product.Supplier navigation property, producing Supplier → Products → Supplier. Requesting /api/suppliers/1 can therefore fail during JSON serialization. section 20.2

Listing 20.4 Related data in the SuppliersController.cs file in the Controllers folder
using Microsoft.AspNetCore.Mvc;
using WebApp.Models;
using Microsoft.EntityFrameworkCore;

namespace WebApp.Controllers {

    [ApiController]
    [Route("api/[controller]")]
    public class SuppliersController : ControllerBase {
        private DataContext context;

        public SuppliersController(DataContext ctx) {
            context = ctx;
        }
                
        [HttpGet("{id}")]
        public async Task<Supplier?> GetSupplier(long id) {
            return await context.Suppliers
                .Include(s => s.Products)
                .FirstAsync(s => s.SupplierId == id);
        }
    }
}

Inspect the complete SuppliersController query and see where Include loads the related collection. section 20.2

Break the cycle before serialization rather than trying to prevent Entity Framework Core from creating it. After loading the supplier, set each product's Supplier property to null. The response can then contain the supplier and its products without recursively returning to the supplier. section 20.2.1

Listing 20.5 References in the SuppliersController.cs file in the Controllers folder
using Microsoft.AspNetCore.Mvc;
using WebApp.Models;
using Microsoft.EntityFrameworkCore;

namespace WebApp.Controllers {

    [ApiController]
    [Route("api/[controller]")]
    public class SuppliersController : ControllerBase {
        private DataContext context;
                
        public SuppliersController(DataContext ctx) {
            context = ctx;
        }
                
        [HttpGet("{id}")]
        public async Task<Supplier?> GetSupplier(long id) {
            Supplier supplier = await context.Suppliers
                .Include(s => s.Products)
                .FirstAsync(s => s.SupplierId == id);
            if (supplier.Products != null) {
                foreach (Product p in supplier.Products) {
                    p.Supplier = null;
                };
            }
            return supplier;
        }
    }
}

Inspect the foreach loop that removes each Product.Supplier back-reference before the controller returns the result. section 20.2.1

The problem is specific to serialized web-service results. Related objects used by MVC views or Razor Pages are not serialized, so their navigation-property cycles do not cause this JSON failure. section 27.4.3 section 20.6

How Pro ASP.NET Core 7, Tenth Edition covers it

How deep it goes
Explains navigation-property tracking, demonstrates the failing request, and shows manually nulling back-references before serialization.
Examples
Uses Supplier and Product entities, an Include query, the /api/suppliers/1 endpoint, and a foreach back-reference removal.
What it assumes
Assumes Entity Framework Core entities, navigation properties, ASP.NET Core controllers, and JSON responses.
What you can do after
Diagnose serialization failures and break response cycles by removing child-to-parent references before returning related data.
How it connects
Connects circular references to Entity Framework Core, related data, navigation properties, JSON serialization, and MVC view models.

Also explained in

Compare how 3 books explain circular reference →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Pro ASP.NET Core 7, Tenth Edition. The section links point to the parts of the book it draws on.