1

I have REST API and Blazor application. I have following Model logic:

public class Offer
{
    [Required] 
    public int OfferId { get; set; }

    public string OfferName { get; set; }
    public ICollection<Item> Items { get; set; }
}


public class Item
{
    public int ItemId { get; set; }
    public string PartNo { get; set; }
    ....
    public int OfferId { get; set; }
    public Offer Offer { get; set; }

    public Nullable<int> ParentId { get; set; }
    public Item Parent { get; set; }
    public IEnumerable<Item> Children { get; set; }

}

Offer can have more items, every item can have children items. Let's assume that there can be only one level of children.

I wanted to ask rest API for list of items with their children. So I created controller like this:

[HttpGet("offer/{offerId}/{parentId}")]
    public IActionResult GetItemsForOffer(int offerId, Nullable<int> parentId, [FromQuery] ItemParameters parameters)
    {
        if (parentId == 0) parentId = null;
        var items = _repository.Item.GetItemsByOffer(offerId, parentId, parameters);
        
        

        Response.Headers.Add("X-Pagination", JsonConvert.SerializeObject(items.MetaData));

        
        return Ok(items);
    }

And Repisotory looks like this:

public PagedList<Item> GetItemsByOffer(int offerId, Nullable<int> parentId, ItemParameters parameters)
    {
        var items = FindByCondition(a => a.OfferId.Equals(offerId) && a.ParentId == parentId )
            .Include(item => item.Children)
            .Sort(parameters.OrderBy);
        
        return PagedList<Item>.ToPagedList(items,
            parameters.PageNumber,
            parameters.PageSize);
    }

The code was working before I added .Include(item => item.Children)

PagedList (but this is not important for this case I think):

public class PagedList<T> : List<T>
{
    public MetaData MetaData { get; set; }
    public PagedList(List<T> items, int count, int pageNumber, int pageSize)
    {
        MetaData = new MetaData
        {
            TotalCount = count,
            PageSize = pageSize,
            CurrentPage = pageNumber,
            TotalPages = (int)Math.Ceiling(count / (double)pageSize)
        };
        AddRange(items);
    }
    public static PagedList<T> ToPagedList(IQueryable<T> source, int pageNumber, int pageSize)
    {
        var count = source.Count();
        var items = source.Skip((pageNumber - 1) * pageSize).Take(pageSize).ToList();
        return new PagedList<T>(items, count, pageNumber, pageSize);
    }
}

My idea of response is this:

[
{
    "itemId": 1,
    "partNo": "ABC",
    ...
    "parentId": null,
    "parent": null,
    "children": [
    {
        "itemId": 2,
        "partNo": "DEF",
        "children": []
    }
]
},
{
    "itemId": 3,
    "partNo": "GHI",
    ...
    "parentId": null,
    "parent": null,
    "children": null
}

]

But I get this error instead: 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.

I googled it and found similiar topic: .Net Core 3.0 possible object cycle was detected which is not supported

Best answer (I think) is "This happens because of the 2 way relationship between your data model when it comes to be JSON serialized.

You should not return your data model diectly. Map it to a new response model then return it."

So it seems my idea of using REST API is wrong. I thought that REST API should handle all joining and including. But maybe I should do it in a Blazor http repository? Or where is a proper place to do joining?

And while I am writing this, I realized that I actually dont need Children, I just need information that Children exists. But I dont know how to write it.

  • Does this answer your question? [.Net Core 3.0 possible object cycle was detected which is not supported](https://stackoverflow.com/questions/59199593/net-core-3-0-possible-object-cycle-was-detected-which-is-not-supported) – IbraHim M. Nada Mar 18 '21 at 11:54
  • 1
    Technically, yes, I solved it by installing package Microsoft.AspNetCore.Mvc.NewtonsoftJson. But I still would like to know if my approach is right. – Petr Jankovský Mar 18 '21 at 13:17
  • 1
    yes it is, this approach is the standard one. you can make a DTO and map into it without the many children – IbraHim M. Nada Mar 18 '21 at 13:22

0 Answers0