Selam arkadaşlar,
Bir proje üzerinde çalışırken aşağıdaki hata ile karşılaştım. Size de yardımcı olabilmek adına aşağıda paylaşıyorum. Aldığım hata şu şekilde;
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. Consider using ReferenceHandler.Preserve on JsonSerializerOptions to support cycles.
Bu hatanın sebebi JSON olarak serialize etmeye çalışılan bir nesnenin derinliğinin “serialize edilebilen maksimum derinlik” değerinin üzerinde olmasıdır. Json objesini ağaç yapısı görünümünde ele alırsanız açabileceğiniz toplam düğüm sayısı 32’den yüksektir.
Serileştirme hatasının detayına geleceğim fakat bu hatayla karşılaşmamızın en sık sebeplerinden biri çağırdığımız async bir metodu await etmeden geriye döndürüyor olmamızdır. Küçük bir kod parçasıyla açıklayayım;
public IActionResult Get(int id){
var item = _service.GetItemByIdAsync(id);
return item;
}
Yukarıdaki kod bloğunda dikkatinizi çekmek istediğim bir nokta var. _service içerisinde çağırılan GetItemById metodumuz asenkron fakat biz bu metodu çağırırken await etmemişiz, .Result diyerek sonucunu da istememişiz. Hal böyle olunca item değeri içerisine Task tipinde bir değer almaktadır ve biz bir alt satırda bu Task değerini döndürmekteyiz.
public async Task<IActionResult> Get(int id){
var item = await _service.GetItemByIdAsync(id);
return item;
}
Kodun düzeltimiş hali bu şekildedir.
Bu sorunun ikinci en sık yaşandığı durum Entity framework ve navigation propertylerinin kullanılması durumudur. Örneğin User ve UserDetail isminde iki entitiymiz olduğunu düşünelim. User modelimiz virtual olarak UserDetail tutmakta, UserDetail modelimiz ise virtual olarak User tutmaktadır. Bu durum serialization sırasında circular dependency(dairesel bağımlılık) sebebiyle aynı objeleri iç içe eklemekte ve Json objemizin derinliğini sonsuza götürmektedir.
Hatanın en yaygın çözümü serializer olarak System.Text.Json yerine Newtonsof.Json kullanılması oluyor. System.Text.Json .NET 6 versiyonunda bu desteği getirdi fakat .NET 5 ve önceki sürümlerde Newtonsof.Json’un içerdiği bazı özellikleri içermiyor ve bu sebeple bize ayak bağı olabiliyor.
Newtonsoft.Json çözümü
services.AddControllers().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
);
System.Text.Json 5 Çözümü
services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.ReferenceHandler = ReferenceHandler.Preserve;
});
System.Text.Json 6 Çözümü
JsonSerializerOptions options = new()
{
ReferenceHandler = ReferenceHandler.IgnoreCycles,
WriteIndented = true
};
objstr = JsonSerializer.Serialize(obj,options);
Kaynaklar:
https://docs.microsoft.com/en-us/dotnet/standard/serialization/system-text-json-preserve-references?pivots=dotnet-6-0
https://stackoverflow.com/questions/38704025/cannot-access-a-disposed-object-in-asp-net-core-when-injecting-dbcontext
Bir yanıt yazın