Good day, I run into the problem then returning DTO object. I have these classes
public class ProductBase
{
public int Id { get; set; }
public string Name { get; set; }
public string Description { get; set; }
public IEnumerable<ProductVariant> Variants { get; set; }
public int BaseImageId { get; set; } = 0;
}
public class ProductVariant
{
public int Id { get; set; }
public int Quantity { get; set; }
public int ProductBaseId { get; set; }
public ProductBase productBase { get; set; }
public int ProductSizeId { get; set; }
public ProductSize ProductSize { get; set; }
public int ProductColorId { get; set; }
public ProductColor ProductColor { get; set; }
public IEnumerable<ImageVariant> imageVariants { get; set; }
}
public class ProductColor
{
public int Id { get; set; }
public string Color { get; set; }
public IEnumerable<ProductVariant> productVariant { get; set; }
}
public class ProductSize
{
public int Id { get; set; }
public string Size { get; set; }
public IEnumerable<ProductVariant> productVariant { get; set; }
}
In productBaseRepository I have this call
public async Task<IEnumerable<Models.ProductBase>> GetAllWithVariantsAsync()
{
var result = await _dataContext.ProductBases
.Include(pb => pb.Variants)
.ThenInclude(v => v.ProductSize)
.Include(pb => pb.Variants)
.ThenInclude(v => v.ProductColor)
.ToListAsync();
return result;
}
I have created DTO convertion function
public static IEnumerable<ProductBaseDTO> ConvertToDto(this IEnumerable<ProductBase> productBases)
{
var returnProductBaseDto = (from product in productBases
select new ProductBaseDTO
{
Id = product.Id,
Name = product.Name,
Variants = product.Variants.ToList(),
Description = product.Description,
BaseImageId = product.BaseImageId,
}).ToList();
return returnProductBaseDto;
}
But then I call this function from swagger
[HttpGet]
public async Task<ActionResult<List<ProductBaseDTO>>> GetAllProductsWithVariants()
{
var baseProductDomain = await _productBaseRepository.GetAllWithVariantsAsync();
var baseProduct = baseProductDomain.ConvertToDto();
return Ok(baseProduct);
}
I get that System.Text.Json.JsonException: A possible object cycle was detected. This can either be due to a cycle or if the object depth is larger than the maximum allowed depth of 32
If I remove variants from call it works, so I need to some how remove Unecessry values from Variants
CodePudding user response:
The problem happens because your ProductVariant
references ProductSize
and ProductColor
and ProductSize
and ProductColor
reference a list of ProductVariant
objects. And ProductVariant
has a reference to its BaseProduct
. This creates a cycle, two objects referencing each other.
In order to solve this issue, remove productVariant
List from ProductSize
and ProductColor
or remove the ProductSize
and ProductColor
references from ProductVariant
. Also remove the productBase
reference from ProductVariant
.
Use the IDs to find object references if required instead of having circular object references.
See prevent property from being serialized in web API on how to prevent properties from being serialized without removing the property declaration from the class.
CodePudding user response:
This is because Variants
has a reference to its parents type,
You could simply set this to null, e.g.
foreach(var x in baseProduct.SelectMany(c => c.Variants) { x.ProductBase = null }
We ussually have different viewmodels to stop these cycles, e.g:
public class Order {
public List<OrderLine> OrderLines {get;set}
}
public class OrderLine {
public Order Order {get;set}
}
// Gets mapped to the following viewmodels:
public class OrderViewModel {
public List<OrderOrderLineViewModel > OrderLines {get;set}
}
public class OrderOrderLineViewModel {
public Order Order => null; // Stop object cycling
}
Note that the exception message should tell you where the issue is for example $.Variants.productBase.variants.productBase.variants
or something similar.