0

this is my Calendar Model which has many to many relation with Category Model:

public class Calendar
{
    ...
    public ICollection<Category> Categories { get; set; } = new List<Category>();
    ...
}
public class Category
{
    ...
    public ICollection<Calendar> Calendars { get; set; } = new List<Calendar>();
    ...
}

and this is in my OnModelCreating method:

modelBuilder.Entity<Calendar>()
    .HasMany(c => c.Categories)
    .WithMany(cc => cc.Calendars);

And this is in my Controller

var query = _context.Calendars.AsNoTracking().AsQueryable();
var calendars = await query.Include(c => c.Categories).ToArrayAsync();
return ok(calendars);

The result errors when browser try parse it to json

2
  • 2
    What's the error? Commented Feb 17, 2024 at 20:53
  • 1
    Show full exception message with call stack. Commented Feb 17, 2024 at 21:03

2 Answers 2

1

The issue you're facing might be related to the circular reference between Calendar and Category entities. When these entities reference each other, serializing them to JSON can cause an infinite loop and result in a stack overflow error.

To solve this issue, you can use the [JsonIgnore] attribute on the navigation properties that cause the circular reference. This attribute tells the JSON serializer to ignore the specified property during serialization. In your case, you can add the attribute to either Categories in Calendar or Calendars in Category.

OR

you can configure the serialization settings to ignore circular references globally in your Startup.cs

services.AddControllers()
    .AddJsonOptions(options =>
    {
        options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.IgnoreCycles;
    });
Sign up to request clarification or add additional context in comments.

Comments

1

It looks like you have circular references between Calendar and Category, thus resulting JSON is infinite and that is why you are getting an error.

To resolve this issue you want to project database entities to a type that is not having circular references.

var calendars = await query
    .Select(cal => new {
        /// Here you put all properties except Categories
        Categories = cal.Categories.Select(cat => new {
            Id = cat.Id,
            Name = cat.Name,
            /// Here you can add more if you need
        }
    }
    .ToArrayAsync();

You can also use concrete types instead of anonymous one.

public class CalendarData {
    public IEnumerable<CategoryData> Categories { get; set; }
   /// Properties you need to pass down to browser
}

public class CategoryData {
   public int Id { get; set; }
   public string Name { get; set; }
   /// Properties you need to pass down to browser
}

Which will result in a code below.

var calendars = await query
    .Select(cal => new CalendarData {
        /// Here you put all properties except Categories
        Categories = cal.Categories.Select(cat => new CategoryData {
            Id = cat.Id,
            Name = cat.Name,
            /// Here you can add more if you need
        }
    }
    .ToArrayAsync();

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.