Resolving Object Cycle Serialization Errors in .NET Core

Nov 22, 2025 · Programming · 10 views · 7.8

Keywords: Object Cycle Reference | Serialization Error | .NET Core | System.Text.Json | Newtonsoft.Json | Entity Framework Core

Abstract: This article provides an in-depth analysis of System.Text.Json serialization errors caused by object cycle references in .NET Core 3.0 and later versions. By comparing different solutions using Newtonsoft.Json and System.Text.Json, it offers detailed configuration methods in Startup.cs, including the usage scenarios and implementation details of ReferenceHandler.IgnoreCycles and ReferenceLoopHandling.Ignore. The article also discusses the root causes of circular references and preventive measures to help developers completely resolve such issues.

Problem Background and Error Analysis

In ASP.NET Core application development, when loading entities with bidirectional navigation properties using Entity Framework Core, developers often encounter serialization errors caused by object cycle references. The specific error message is: System.Text.Json.JsonException: A possible object cycle was detected which is not supported. This error typically occurs when entities have one-to-many or many-to-many relationships with navigation properties defined on both sides.

Root Causes of Circular References

Taking a restaurant reservation system as an example, the entity classes are defined as follows:

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; }
}

When executing query operations:

var restaurants = await _dbContext.Restaurants
    .AsNoTracking()
    .Include(m => m.Reservations)
    .ToListAsync();

The serialization process enters an infinite loop: Restaurant → Reservations → Restaurant → Reservations... System.Text.Json does not support this type of circular reference by default, thus throwing an exception.

Solution 1: Using Newtonsoft.Json

For .NET Core 3.0 projects, circular reference handling can be achieved by installing the Microsoft.AspNetCore.Mvc.NewtonsoftJson package:

// Install NuGet package
Install-Package Microsoft.AspNetCore.Mvc.NewtonsoftJson -Version 3.0.0

// Configure in Startup.cs
services.AddControllersWithViews()
    .AddNewtonsoftJson(options =>
        options.SerializerSettings.ReferenceLoopHandling = 
            Newtonsoft.Json.ReferenceLoopHandling.Ignore
    );

This configuration ignores circular references and outputs null values when encountering duplicate objects, thereby avoiding serialization errors.

Solution 2: Using System.Text.Json New Features

In .NET 6 and later versions, System.Text.Json provides native circular reference handling capabilities:

// Method 1: Global configuration
services.AddControllers().AddJsonOptions(options =>
{
    options.JsonSerializerOptions.ReferenceHandler = 
        ReferenceHandler.IgnoreCycles;
    options.JsonSerializerOptions.WriteIndented = true;
});

// Method 2: Custom output formatter
services.AddControllers(options =>
{
    options.OutputFormatters.RemoveType<SystemTextJsonOutputFormatter>();
    options.OutputFormatters.Add(new SystemTextJsonOutputFormatter(
        new JsonSerializerOptions(JsonSerializerDefaults.Web)
        {
            ReferenceHandler = ReferenceHandler.Preserve,
        }));
});

Comparative Analysis of Both Solutions

Newtonsoft.Json Solution:

System.Text.Json Solution:

Practical Application Example

Here is a complete serialization example for an employee management system:

public class Employee
{
    public string Name { get; set; }
    public Employee Manager { get; set; }
    public List<Employee> DirectReports { get; set; }
}

// Create circular reference relationship
Employee tyler = new() { Name = "Tyler Stein" };
Employee adrian = new() { Name = "Adrian King" };

tyler.DirectReports = new List<Employee> { adrian };
adrian.Manager = tyler;

// Serialize using IgnoreCycles
JsonSerializerOptions options = new()
{
    ReferenceHandler = ReferenceHandler.IgnoreCycles,
    WriteIndented = true
};

string json = JsonSerializer.Serialize(tyler, options);
Console.WriteLine(json);

In the output result, circular reference parts will be set to null, avoiding serialization errors.

Best Practice Recommendations

1. Data Model Design: Consider serialization requirements during entity design phase, avoid unnecessary bidirectional navigation

2. DTO Pattern: For API return data, recommend using dedicated Data Transfer Objects instead of directly returning EF Core entities

3. Version Selection: New projects recommend using .NET 6+ and System.Text.Json, existing projects can choose migration strategies based on actual situation

4. Performance Considerations: IgnoreCycles loses some data, Preserve adds metadata, need to balance based on specific requirements

Conclusion

Object cycle references are common issues in .NET Core Web API development. By properly configuring serialization options, these problems can be effectively resolved. Developers are advised to choose appropriate solutions based on project requirements and version constraints, and consider the impact of data serialization during the design phase to build more robust applications.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.