Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Asp.NET MVC – JsonResult İle Veri Dönerken RecursionLimit Aşıldı(RecursionLimit Exceeded) Hatası

Bir proje üzerinde Ajax işlemleriyle oyalanırken almış olduğum “RecursionLimit aşıldı(RecursionLimit exceeded)” hatasının aldım.Lakin bu hatayı aldığımı fark etmeden önce allem edip gullem edip projede ilgili kısmın %80 alt yapısını değiştirdim yok.Olmuyor.Ajax işlemlerinde alınan hatalar bariz bir şekilde takip edilemediği için ya tarayıcıdan eklentilerle durumu takip edersiniz ya da Ajax ile hata kontrolü uygularsınız.Tabi ki de ben her birini denedim ama aldığım hatalar genellikle serverdan gelen derlenmiş kod çıktıları olduğu için üşendiğimden dolayı kodlara göz atmadım.Haliyle boş uğraşlar neticesinde bana gelen derleme kod satırları arasında(yazının devamında örnek ekran görüntüsü olarak göreceksiniz) “RecursionLimit aşıldı” hatasını gördüm.

Break – Point ile bakalım hatanın sebebi nedir derken en az yarım saatim gitti.Meğersem, belirli durumlar söz konusu olduğu zaman programın akışı bir döngüye girmekte ve bu böyle gitmekteymiş.Taaa ki, RecursionLimit aşılana kadar.

Şimdi RecursionLimit hatasını hangi durumda aldığımı, bu hataya sebep olan döngüye neden girildiğini ve sonuç olarak nasıl bir önlemle bu hatayı onardığımı irdeleyeceğiz.

Projemin veritabanında aralarında Foreign Key Constraint ile ilişki kurulmuş tablolarım mevcut.Haliyle bu diyagrama sahip bir veritabanı üzerinde çalışıyorum.

Şimdi bu duruma benzer bir senaryoda yaşadığımı özetleyeyim.
Bir “Okul” isminde veritabanı oluşturalım ve “Siniflar” ve “Ogrenciler” isminde iki tablomuz olsun.Tablolarımız kendi aralarında Foreign Key Constraint ile ilişkisel yapıda olsunlar.Bir sınıf birden fazla öğrenciyi barındırabilecek yapıda yani ve nihayetinde Linq To Sql ile veritabanımız ile proje arasında bağlantı kuralım.

Hemen “Siniflar.cs” isimli bir partial sınıf oluşturarak aşağıdaki property eklemesini gerçekleştirelim.

    partial class Siniflar
    {
        VeriTabaniDataContext Veri = new VeriTabaniDataContext();
        public List<Ogrenciler> SinifaBagliOgrenciler
        {
            get
            {
                return Veri.Ogrencilers.Where(o => o.SinifID == ID).ToList();
            }
        }
    }

Burada yaptığımız işlemin sebebini izah etmeye gerek yok.Şimdi siz, “ulan zaten ilişkili tablolar arasında LINQ esneklik sağlıyor.Sen neden böyle bir propertye ihtiyaç duyuyorsun?” diyebilirsiniz.Benim bunu açıklamam, şuanda elimdeki projeyi baştan sona size izah etmem demektir.Haliyle yazılımcının işi bazen hamallık olduğu için en pratik ve hızlı işlemleri sağlayan algoritmaları tercih edebilme yetkisine sahiptir.Bu yüzden gün gelir sizlerde böyle bir duruma ihtiyaç duyabilirsiniz.Ben benzer bir durumda ilgili hatayla karşılaştığım için mümkün mertebe yakın bir senaryo çizmeye çalışıyorum.

İlgili Controller’a ise aşağıdaki Action metodu oluşturalım.

        [HttpPost]
        public JsonResult Post(int id)
        {
            VeriTabaniDataContext Veri = new VeriTabaniDataContext();

            Siniflar Sinif = Veri.Siniflars.FirstOrDefault(s => s.ID == id);
            return Json(Sinif, JsonRequestBehavior.AllowGet);
        }

Şimdi yukarıdaki “Post” isimli Action metodunu Ajax ile tetikleyelim.

Ajax ile Post işlemi neticesinde id parametresinden gelen değere göre veritabanından ilgili sınıfı elde edip Json metoduyla geriye return yapalım.

Asp.NET MVC – JsonResult İle Veri Dönerken RecursionLimit Aşıldı(RecursionLimit Exceeded) Hatası

Ben Ajax ile hata kontrol mekanizmasını kullanarak ilgili hatayı görüntüledim.Hata derlenmiş kaynak kodu olarak gelmektedir ve içeriğinde ki hatayı haber veren ilgili satırı vurgulayarak görüntüyü yukarıda paylaşıyorum.

Evet, buraya kadar bu hatayı nasıl bir durumda aldığımı sizlere örnek bir senaryoyla göstermiş oldum.Gördüğünüz gibi ilişkisel tablolar arasında yukarıdaki gibi bir property kullanırsanız yazılım akışı sonsuz bir döngüye girmekte ve buda RecursionLimit sınırını aşmaktadır.Haliyle bu durum bize RecursionLimit aşıldı hatası olarak geri dönmektedir.

Tabi ki de bu hatayla, bu ya da benzeri durumlarda da karşılaşabilirsiniz.O yüzde kesinlikle Ajax ya da Json veri yapılarıyla çalışıyorsanız hata durumlarında elinizdeki tek veri kaynak kod dahi olsa detaylıca değerlendirmenizi tavsiye ederim.

Şimdi, kısaca hatanın neden meydana geldiği üzerine pratik bir açıdan istişare ettikten sonra “bu hata nasıl atlatılır?” sorusuna değineceğiz.

JsonResult ile geriye Json metoduyla bir model gönderdiğimizde, Json metodu o modeli Json veri yapısına çevirmekte ve öyle döndürmektedir.İlgili modelin property isimlerini çevireceği Json veri yapısındaki node isimlerine karşılık getirmekte ve verileri de ona göre dizayn etmektedir.Böyle bir senaryoda verilen modelin propertyleri kompleks bir yapıya sahip olduğu için çevirme işlemi esnasında durmadan sonsuz bir döngüye girilmekte ve nihayetinde aynı nesne içerisinde sonsuz bir Json veri tipine çevirme işlemi gerçekleştirilmeye zorlanmaktadır.Haliyle bu hatanın temel sebebi bu mantıksal paradokstan kaynaklanmaktadır.

Peki bu hatadan nasıl kurtulacağız?

Şimdi aşağıdaki kod bloğunu inceleyiniz.

        [HttpPost]
        public JsonResult Post(int id)
        {
            VeriTabaniDataContext Veri = new VeriTabaniDataContext();

            Siniflar Sinif = Veri.Siniflars.FirstOrDefault(s => s.ID == id);
            var JsonModel = new
            {
                SinifAdi = Sinif.SinifAdi,
                ID = Sinif.ID,
                Ogrenciler = from o in Sinif.SinifaBagliOgrenciler
                             select new
                             {
                                 Adi = o.Adi,
                                 SoyAdi = o.SoyAdi,
                                 ID = o.ID
                             }
            };
            return Json(JsonModel, JsonRequestBehavior.AllowGet);
        }

Yukarıdaki kod bloğunda da gördüğünüz gibi geriye göndereceğimiz modeli Anonymous Types şeklinde tekrardan tertipleyip gönderiyoruz ve hatta dikkat ederseniz eğer model içinde RecursionLimit hatasına düşürebilecek propertydeki elemanları tekrardan LINQ sorgusuyla Anonymous Types’a çeviriyoruz.

İşte RecursionLimit hatası bu şekilde düzeltilebiliyor…

Biliyorum, anlaşılması zor bir yazı oldu.Ama bu hatanın çözümü için en azında makalenin sonundaki çözüm size yol gösterecektir.Anlayacağınızı umuyorum ki karışık algoritmalar içindeki kompleks hatalar üzerine senaryo oluşturup okuyucuya aktarmak oldukça zor.

Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar dilerim…

Bunlar da hoşunuza gidebilir...

4 Cevaplar

  1. Ömer Şerif dedi ki:

    “Sinif.Ogrenciler.ForEach(x=>x.Sinif=null);” şeklinde yaparsanız Json için kısır döngüden kurtarırsınız.

  2. Sefa can dedi ki:

    Bu işlemlerde gelen nesneleri modele aktarmak ve ilişkili tabloları json olarak dönerken relation alanları JsonIgnore olarak işaretlemek en kesin ve doğru çözümdür.

    İyi çalışmalar

    • Gençay dedi ki:

      Merhaba Sefa Bey,

      Verdiğiniz bilgi için teşekkür ederim lakin bilginize dair sorum olacaktı. Alanları JsonIgnore ile işlemekten kastınız attribute ile işaretlemek olsa gerek? Mutabık mıyız?

      Sevgiler.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir

*