Visual Studio veya Visual Web Developer ile ASP.NET sitesi geliştirilirken konu karşılaşılması muhtemel hatalar olduğunda akla hemen iki kavram gelmektedir:Hata Ayıklamak ve Hata Yakalamak. Visual Studio size yardım edip bir çok hatayı daha kodu yazarken ayıklamanızı sağlamaktadır. ASP.NET uygulamaları dahilinde karşılaşılar hatalar istenirse metot dahilinde yakalanabilir. Metot dahilinde yakalanmayan hataların sayfa bazında, olmadı site yani uygulama bazında tedbir alınıp yakalanması gerekir.
Bazen tek tek metotlarla ilgilenmek yerine hataları sayfa bazında yakalamak isteyebilirsiniz. Bu sayede bir sayfada meydana gelen bütün hatalar bir merkezden denetlenir. Sitedeki sayfalarla tek tek ilgilenmek istemeyenler hata yakalamayı uygulama bazında yapabilirler. Öncelikle metot dahilinde hataların nasıl yakalandığından söz edeceğiz. Bu bölümde öncelikle Try-Catch bloklarından söz edilecektir. Devamında Page sınıfının Error olayından ve Page sınıfının ErrorPage niteliğinden söz edilecektir. Bu nakale yakın bir zamanda yazımını tamamladığım ASP.NET kitabından aldığımı biliyorsunuz. Bu kitabın kapağında programlama dili olarak Visal Basic'in seçildiği işaret edildiği için bölümün orijinal halinde programlama dilinin Visual Basic olduğundan tekrar söz edilmedi. Bu nedenle bu makaleyi okuyacak arkadaşlar için açıklama yapmak gerekir: Bu uzun makalede kullanılan kodların dili Visual Basic'tir.
ASP.NET sitelerinde metot dahilinde hata yakalama işlemlerinin nasıl yapıldığını örnek bir olay üzerinde anlatmak istiyoruz. Kullanıcıdan bir işlem için TextBox aracılığıyla güncel tarihi istediğinizi varsayalım. TextBox’a tarih olarak değerlendirilemeyecek bilgi girilirse sayfanın sunucuda render edilmesi yani HTML kodu hazırlanması işlemi yarıda kalabilir. Aşağıda verilen metot işletildiğinde sayfadaki ilk TextBox’ın içeriği dönüştürülüp DateTime tipindeki değişkene aktarılır. Devamında bu tarih bilgisi gün, ay ve yıl olarak ayrıştırılıp sayfadaki diğer TextBox’lara aktarılır.
Protected Sub Ayristir_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Ayristir.Click
Dim Tarih As DateTime = DateValue(TextBox1.Text)
TextBox2.Text = Tarih.Day
TextBox3.Text = Tarih.Month
TextBox4.Text = Tarih.Year
End Sub
Bu kodda sayfadaki ilk TextBox’ın mevcut içeriği DateValue() fonksiyonu ile DateTime tipine dönüştürülüp “Tarih” adını verdiğimiz değişkene aktarılmaktadır. Tahmin edeceğiniz gibi TextBox’a tarih olarak değerlendirilmeyecek bilgi girilip bu kodun işletilmesi, daha doğrusu sayfanın postback olması sağlanırsa hata meydana gelir ve aşağıdakine benzer bir hata mesajı alınır.

Konu hataları metot dahilinde yakalamak olduğunda ilgili sayfanın Visual Studio ile gelen entegre debugger’ın denetiminde mi yoksa debugger’dan bağımsız mı test edildiği önemlidir. Bu hatayı üzerinde çalıştığımız siteyi entegre hata ayıklayıcısını devre dışı bırakarak test etmek isteyince aldık. Başka bir deyişle bu hatayı Ctrl+F5 tuşlarına basarak siteyi Visual Studio ile gelen web server ile test ederken aldık.
Şimdi konuyu baştan alalım:Bir sayfaya sahip web sitesi hazırlayıp bu sayfaya 4 TextBox ve bir Button yerleştirdik. Ardından Visual Studio’nun araç çubuğundaki Start Debugging düğmesini tıklayıp siteyi test etmek isteyince aşağıda verilen diyalog kutusu ekrana geldi.

Bu sırada siteye ait ana klasördeki Web.config dosyasındaki debug ayarı “false” idi. Debug ayarı true olsaydı bu diyalog kutusu ekrana gelmezdi. Bu diyalog kutusundaki ilk onay kutusu seçilip OK düğmesi tıklanırsa Web.config dosyasındaki debug ayarı True yapılır ve site entegre debugger’ın kontrolünde test edilmiş olunur. Geliştirme sırasında Debug ayarının True olması önerildiği için bu diyalog kutusundaki ilk radyo düğmesini seçip sitenin entegre hata ayıklayıcısının denetiminde test edilmesini sağladık.
Web.config dosyasındaki Debug ayarı True iken sayfadaki ilk TextBox’a tarih tipine dönüştürülemeyecek bilgi girilip yukarıda verilen kod işletilirse aşağıdaki gibi bir hata mesajı ile karşılaşılır. Yani Visual Studio yukarıdakinden farklı olarak ekrana bir hata sayfası getirmek yerine hataya neden olan kod satırını işaret eder. Bu sayede hataları ayıklamak kolaylaşmaktadır.

Geliştirme sürecinde Web.config dosyasındaki Debug ayarını True olarak ayarlamanız önerilir. Bu siteyi Visual Studio ile gelen gömülü web server ile test etmek yerine bu sayfayı başka bir bilgisayarın başına geçip IIS’ten talep etmiş olsaydık farklı bir hata mesajıyla karşılaşırdık. Aşağıda verilen ekran görüntüsünü incelediğinizde meydana gelen hata hakkında bilgi verilmediğini görürsünüz. Tabi bu sitenin ana sayfasını Intranet’e dahilindeki başka bir bilgisayardan talep edebilmek için bu web sitesinin IIS’in nazarından bir web sitesi veya sanal dizin olarak değerlendirilmiş olması gerekir. Aşağıda verilen ekran görüntüsündeki "bilgisayar1" sözkonusu web sitesinin bulunduğu ve IIS kurulu olan lokal bilgisayarın adıdır.

Bazen web siteleri birden fazla kişi tarafından geliştirilir ve geliştirme sürecinde uzak bir bilgisayarda sayfayı test eden programcı meydana gelen hataların ayrıntılarını görmek isteyebilir. Bu durumda Web.config dosyasında CustomError tagının mode niteliğini değiştirmeniz gerekir. Web.config dosyasının orijinal halinde CustomError ayarı aşağıdaki gibi olsa bile bu satırların açıklama satırı olması sağlandığı için devre dışıdır.
<customErrors mode="RemoteOnly" defaultRedirect="GenericErrorPage.htm">
<error statusCode="403" redirect="NoAccess.htm" />
<error statusCode="404" redirect="FileNotFound.htm" />
</customErrors>
CustomError konusu bu bölümün sonunda ele alınacaktır. Buna rağmen burada CustomError’dan söz etmemizin nedeni aynı web sitesi üzerinde birden fazla programcı çalıştığında karşılaşılan özel duruma işaret etmektir. Burada Web.config’deki CustomError ayarıyla ilgili olarak yazılanlara şimdilik kayıtsız kalabilirsiniz.
Şimdilik bu satırların mode’la ilgili olanıyla ilgilendiğimiz için Web.config dosyasındaki bu satırların açıklama satırı olmasını engelleyip özel hata sayfalarıyla ilgili kısmı sildik. Başka bir deyişle Web.config dosyasının hatalarla ilgili kısmını aşağıdaki gibi düzenledik. customErrors tagı Web.config’de system.web’in içinde yer almaktadır.
<system.web>
<customErrors mode="RemoteOnly">
</customErrors>
</system.web>
Her ne kadar bu ayarın varlığı ile yokluğu bir olsa bile konu hakkında bilgi vermek için bu düzenlemeyi yaptık. Bu şartlarda lokal bilgisayarda yani web sitesinin hazırlandığı bilgisayarda hataların ayrıntıları gösterilir ama uzak bilgisayarda bu hatalar görülemez. Yukarıdaki senaryoya göre yani geliştirme safhasında siteyi başka programcılar kendi bilgisayarlarında test etmek istiyorsa ve hataların ayrıntılarını görmelerine izin vermek istiyorsanız Web.config dosyasında mode niteliğini Off olarak ayarlamanız gerekir.
<customErrors mode="Off">
</customErrors>
Tabi sitenin geliştirilmesi tamamlanıp site yayınlandığında bu ayarın tekrar RemoteOnly yapılması gerekir. Web.config dosyasındaki mode niteliğini On yaparsanız sitenin geliştirildiği local bilgisayarda bile meydana gelen hataların ayrıntıları gösterilmez. Hemen eklemek gerekir; sitenin geliştirildiği bilgisayarda site entegre hata ayıklayıcının denetiminde test edilirken Web.config dosyasındaki customErrors tagındaki mode ayarının bir etkisi yoktur.
Bu ön bilgilerden sonra sırada meydana gelmesi muhtemel hataların metot dahilinde nasıl yakalandığını anlatmak var. Burada yapılması gereken şudur:Hataya neden olma ihtimali yüksek satırları try bloğuna almak ve meydana gelebilecek hataları catch bloğunda yakalamaktır. Bu amaçla yukarıda verilen metodu aşağıdaki gibi düzenledik.
Protected Sub Ayristir_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Ayristir.Click
Dim Tarih As DateTime
Try
Tarih = DateValue(TextBox1.Text)
TextBox2.Text = Tarih.Day
TextBox3.Text = Tarih.Month
TextBox4.Text = Tarih.Year
Catch
Response.Write("Girdiğiniz tarih veya saat geçersiz")
TextBox1.Focus()
End Try
End Sub
Bu kodda hataya neden olabilmesi muhtemel satırı try bloğuna aldık. Ardından catch bloğunda öngördüğümüz hata meydana geldiğinde yapılacak işlemler için kod yazdık. Catch bloğundaki Focus() metodu sayesinde kontrol tekrar ilgili TextBox’a geçer.
Kendimizi korumak için izninizle buraya ek bir cümle yazacağız:Yarın bir gün programcılık kitapları yazan birisi hata yakalarken string bilgiyi tarihsel bilgiye dönüştürmeyi ilk ben akıl ettim deyip bizi fikrisini izinsiz kullandığımızı şikayet ederse bu bizim için sürpriz olmayacaktır.
Şimdi metot dahilinde hata yakalama konusunda 2. bir örnek vereceğiz. Hazırlayacağımız örnekte 5 elemanlı bir dizi değişken tanımlayıp For döngüsü ile bu dizi değişkenin elemanlarına bilgi aktaracağız. Dizi değişkene aktaracağımız bilgileri ListBox’tan alacağız.
Protected Sub naklet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Aktar.Click
Dim takimlar(4) As String
Dim number_sayi As Integer = ListBox1.Items.Count
For i As Integer = 0 To number_sayi - 1
takimlar(i) = ListBox1.Items(i).ToString()
Next
End Sub
ListBox, 5 veya daha az elemana sahip iken bu kod sorunsuz olarak çalışır. Ancak ListBox 5’ten fazla elemana sahip iken bu kod işletildiğinde sunucuda sayfayı temsil eden HTML kodunun hazırlanıp istemciye gönderilmesi işlemi yarıda kalır ve aşağıdaki gibi bir hata mesajı alınır.

Bu hatanın meydana gelme nedeni 5 elemanlı dizi değişkenin olmayan 6. elemanına bilgi aktarılmak istenmesidir. Bu gibi hataların önüne geçip sayfanın HTML karşılığının sunucuda hazırlanması işleminin yarım kalmasını önlemek için aşağıdaki gibi Try-Catch blokları hazırlanabilir.
Protected Sub naklet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Aktar.Click
Dim takimlar(4) As String
Dim number As Integer = ListBox1.Items.Count
Try
For indis As Integer = 0 To number - 1
takimlar(indis) = ListBox1.Items(indis).ToString()
Next
Catch
Response.Write("Dizi değişkenin sınırı aşıldı" + Chr(13) + _
Chr(10) + "Yalnızca ilk 5 eleman diziye aktarıldı")
End Try
For indis As Integer = 0 To takimlar.Length - 1
ListBox2.Items.Add(takimlar(indis))
Next
End Sub
Bu kodda hata meydana geleceğini düşündüğümüz satırları Try bloğuna aldık. Bu satırlarda hata meydana gelmezse kod sorunsuz çalışır ve kodun işletimi Catch bloğundan sonraki ilk satıra geçer. Hata meydana gelirse hatanın meydana geldiği noktada Catch bloğundaki satırlara geçilir. Bu şekilde düzenlenen kodun çalışmasının kırılmadığını göstermek için sayfaya 2. bir ListBox yerleştirdik ve dizi değişkenin elemanlarını 2. ListBox’a aktardık.
Şimdi yukarıda hazırladığımız koddaki Catch bloğunda değişiklik yapacağız. Hazırlamış olduğumuz örnekte Try bloğundaki satırlar nasıl bir hataya neden olurlarsa olsunlar Catch bloğu işletilir. Catch bloğundaki satırların yalnızca dizi değişkenlerle ilgili olarak indis sorunu yaşandığında işletilmesini isteseydik aşağıdaki gibi düzenleme yapardık. Try bloğundaki satırlarda çalışma anında yani sayfa sunucuda render edilip HTML kodu hazırlanırken dizi değişkenlerle ilgili hata meydana geldiğinde IndexOfRangeException sınıfının örneği otomatik olarak hazırlanıp Catch bloğuna gönderilir.
Protected Sub naklet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Aktar.Click
Dim takimlar(4) As String
Dim adet As Integer = ListBox1.Items.Count
Try
For indis As Integer = 0 To adet - 1
takimlar(i) = ListBox1.Items(indis).ToString()
Next
Catch Hata As IndexOutOfRangeException
Response.Write("Meydana gelen hatanın mesajı :" + _
Chr(13) + Chr(10) + Hata.Message)
End Try
End Sub
Bu örnekte sistem tarafından fırlatılan istisnanın yani hazırlanıp Catch bloğuna gönderilen IndexOutOfRangeException tipindeki nesnenin Message özelliğinin içeriğini sayfaya yazdık. Exception sınıfından türetilen IndexOutOfRangeException sınıfının Message özelliğinden başka Source, HelpLink, StackTrace, TargetSize ve InnerException gibi özellikleri bulunmaktadır. Bu kodu tekrar yorumlamak gerekirse şunlar söylenebilir:Try ve Catch blokları birlikte çalışmakta ve Try bloğundaki herhangi bir satırda hata meydana geldiğinde meydana gelen hataya göre bir Exception nesnesi hazırlanıp kodun işletimi Catch bloğuna geçmektedir.
Yukarıda verilen kodda Catch bloğuna gönderilen exception nesnesinin IndexOutOfRangeException tipinde olup olmadığını araştırdık. Bu sırada Catch bloğuna gönderilen hata nesnesi IndexOutOfRangeException sınıfının örneği ise Catch bloğuna yazılan satırlar işletilir. Try bloğunda meydana gelen hatadan dolayı Catch bloğuna gönderilen bütün nesneler System’de bulunan Exception sınıfından türetilen sınıfların örnekleridir. Bu kodda dizi değişkenin olmayan bir elemanı üzerinde işlem yapılmak istendiği için Catch bloğuna IndexOutOfRangeException tipinde bir nesne gönderilir. Konu üzerinde düşünmenizi sağlamak için yukarıda verilen ilk örneği aşağıdaki gibi düzenledik.
Protected Sub naklet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Aktar.Click
Dim Tarih As DateTime
Try
Tarih = Convert.ToDateTime(TextBox1.Text)
Catch Hata As IndexOutOfRangeException
Response.Write("Girdiğiniz tarih veya saat geçersiz")
TextBox1.Focus()
End Try
End Sub
Bu şartlarda TextBox’a DateTime tipine dönüştürülemeyecek bilgi girilip bu metot işletildiğinde Try bloğundaki satırlar hataya neden olur ve işletim Catch bloğunda geçer. Ne var ki Try bloğunda meydana gelen hata bu şatlarda Catch bloğunda yakalanamaz. Çünkü Catch deyiminin kullanıldığı satırda IndexOutOfRangeException tipinde değişken tanımlandığı için Catch bloğundaki satırlar işletilmeyip meydana gelen hatadan dolayı sayfanın görüntülenmesi işlemi durur. Başka bir deyişle Catch bloğunda gönderilecek hata nesnesi IndexOutOfRangeException tipinde olmadığı için bu hata yakalanamaz.
Şimdi ise hata yakalamanın nasıl yapıldığı anlatılırken ilk akla gelen hatalardan birisi olan sıfıra bölme hatasını yakalayan bir örnek vereceğiz. Bu amaçla sayfaya 3 TextBox ve 1 düğme yerleştirdik. İlk 2 TextBox’a bilgi girilip “Hesapla” adını verdiğimiz düğme tıklandığında 1. sayı ikinciye bölünüp sonuç 3. TextBox’a yazılacak.
Tam bu noktada 2004 yılında yayınlanan bir kitabımızda sıfıra bölme hatasından söz ederken aşağıdaki gibi sayi1 ve sayi2 adında 2 değişken tanımladığımız için değişken adı çalma suçlamasıyla dava edildiğimizi bilmenizi isteriz. Aman dikkat:Başkalarına ait değişken adlarını kullanmayınız. Aşağıda verilen kodda bu değişkenlerin tipini byte olarak seçme nedeni şudur:Aynı örnekte hem sıfıra bölme hem de sınır aşımı hatasından söz edebilmektir. Byte yerine Integer’ı tercih etseydik sınır aşımı hatasının meydana gelmesi için TextBox’lara 10 haneli büyük bir tam sayı girmek gerekecekti. Tabi yarın bir gün birileri bu örnekte Integer veri tipi dururken byte tipini tercih ettiğimiz için bizi suçlayabilir.
Protected Sub Hesapla_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Hesapla.Click
Dim sayi1, sayi2 As Byte
Dim Netice As Double
sayi1 = Convert.ToByte(TextBox1.Text)
sayi2 = Convert.ToByte(TextBox2.Text)
Netice = sayi1 / sayi2
TextBox3.Text = Netice.ToString()
End Sub
TextBox’lara girilecek sayılar Byte tipindeki değişkenlere aktarılacaktır. Sayfadaki ilk 2 TextBox’a 255’ten küçük bir sayı girilirse bu kod hatasızca çalışır. Kullanıcı 2. TextBox’a 0 yazarsa sıfıra bölme hatasının meydana geleceğini ve sayfanın sunucudan istemciye gönderilmeyeceğini düşünebilirsiniz. Ne var ki bu şartlarda sayfadaki 2. TextBox’a 0 girip bölen sayıyı 0 yapmanız halinde “Netice” değişkenin dolayısıyla 3. TextBox’ın içeriği Infinity olur. Visual Basic derleyicisinin varsayılan ayarlarında Byte bir sayıyı 0’a bölmek hataya neden olmuyor. Bölme işlemini normal bölü(/) yerine ters bölü(\) yani tam bölme operatörü ile yaparsanız 2. TextBox’a 0 yazmanız halinde sıfıra bölme hatası meydana gelir.
Netice = sayi1 \ sayi2
Aynı şekilde TextBox’lara 255’ten büyük bir değer yazılırsa değişken tipi byte olarak seçildiği için sınır aşımı hatası meydana gelir. Sayfadaki 2. TextBox’a 0 yazıp bu kodu işletmek isteyince sayfa sunucudan talep edilmeyip yapılan hata entegre debugger tarafından aşağıdaki gibi işaret edildi.

Tekrar hatırlatmak gerekirse bu kodun olduğu sayfayı localhost olarak kullandığımız bilgisayarda entegre hata ayıklayıcısından bağımsız çalıştırmış olsaydık ekrana aşağıdaki gibi hata sayfası getirilirdi. Tabi bu sayfa yayınlanıp başka bir bilgisayardan talep edilmiş olunsaydı hataya neden olan satır bu şekilde kullanıcıya gösterilmezdi. 
Böyle bir hata meydana geldiği zaman sayfanın görüntülenmesinin durmasını engellemek için Try-Catch bloğu hazırladık. Gerçekte bu kod değişik nedenlerden dolayı değişik hatalara neden olabilir ama öncelikle sıfıra bölme ve taşma hataları ile ilgilenmek istiyoruz.
Protected Sub Hesapla_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Hesapla.Click
Dim number1, number2 As Byte
Dim Netice As Double
Try
number1 = Convert.ToByte(TextBox1.Text)
number2 = Convert.ToByte(TextBox2.Text)
Netice = number1 \ number2
TextBox3.Text = Netice.ToString()
Catch
Response.Write("Hata meydana geldi")
TextBox2.Focus()
End Try
End Sub
Bu kodla ilgili olarak ek açıklama yapacağız: Bu koddaki Try bloğundaki satırlar işletilirken ister taşma hatası ister sıfıra bölme hatası meydana gelsin her şartta kullanıcıya Catch bloğundaki mesaj verilip tekrar ilk TextBox’ın üzerine gidilir. Konu üzerinde düşünmenizi sağlamak için bu kodun Catch bloğunu aşağıdaki gibi düzenledik.
Catch Hata As System.Exception
Dim tip As Object = Hata.GetType()
Response.Write("Hata meydana geldi" +Chr(13) + Chr(10) + "Meydana gelen hata : " + tip.ToString())
TextBox2.Focus()
End Try
Burada yapılan şudur: Catch anahtar kelimesinin bulunduğu satırda Exception tipinde bir değişken tanımladık. Catch deyimi, Try bloğundan gönderilen nesnenin tipinin burada tanımlanan değişkenle aynı tipte olup olmadığına bakar. Gönderilen Exception nesnesi System.Exception tipinde ise Catch bloğundaki satırlar işletilir. Hata nedeniyle Try bloğundan catch bloğuna gönderilen hata nesnesinin tipi ister IndexOutOfRangeException olsun ister OverflowExceptionher şartta catch bloğundaki bu satırlar işletilir. Çünkü IndexOutOfRangeException ve OverflowExceptionsınıfları System.Exception sınıfından türetilmiş sınıflardır.
Bu kodda bloğun içinde object tipinde bir değişken tanımlayıp catch bloğuna gönderilen nesnenin tipini GetType() metodu ile öğrendik. Catch bloğundaki satırların işletilmesinin nedeni sıfıra bölme iken aşağıdaki gibi bir mesaj alınır.

Gördüğünüz gibi bu sırada meydana gelen hata sıfıra bölme işlemi kaynaklı olduğu için Catch bloğuna DivideByZeroException sınıfının örneği gönderilmiş. TextBox’lardan birisine Convert sınıfının ToByte() metodu ile byte tipine dönüştürülemeyecek bilgi girip ondan sonra bu kodu işletseydik farklı gibi hata mesajı alırdık. İlk 2 TextBox’tan birisine 255’ten daha büyük bir sayı girilirse taşma hatası meydana gelir(OverflowException).
When Deyimi
Visual Basic kodu içinde Catch bloğunda meydana gelen hatalar yakalarken When deyimi ile bu hataları kategorize edebilirsiniz. Bu konuda bilgi vermek için aşağıda verilen kodu hazırladık.
Protected Sub islem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles islem.Click
Dim Number As Byte
Try
Number = Convert.ToByte(TextBox1.Text)
Catch hata As OverflowException
Response.Write("Hata meydana geldi")
End Try
End Sub
Tahmin edeceğiniz gibi TextBox’a 255’ten büyük bir değer girilip bu kod işletilirse ToByte() metodunun kullanıldığı satır hataya neden olur ve Catch bloğuna OverflowException sınıfının örneği gönderilir. Buraya kadar sizin için yeni bir şey yoktur. When deyiminin nasıl kullanıldığını anlatmak için bu kodu aşağıdaki gibi değiştirdik.
Protected Sub islem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles islem.Click
Dim Number As Byte
Try
Number = Convert.ToByte(TextBox1.Text)
Catch hata As OverflowException When Convert.ToInt16(TextBox1.Text)> 300
Response.Write("Girdiğiniz sayı çok büyük")
End Try
End Sub
Tahmin edeceğiniz gibi Catch bloğundaki satırın işletilmesi veya meydana gelmesi muhtemel olan OverflowException hatasını yakalamak için TextBox’a 300’den büyük bir sayı girilmelidir. Bu şartlarda TextBox’a 300 ile 256 arası bir değer girilirse meydana gelecek hata yakalanmaz ve sayfanın HTML karşılığının sunucuda hazırlanması işlemi yarım kalır. OverflowException hatasını her şartta yakalamak için bu koda ekleme yaptık.
Protected Sub islem_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles islem.Click
Dim Number As Byte
Try
Number = Convert.ToByte(TextBox1.Text)
Catch hata As OverflowException When Convert.ToInt16(TextBox1.Text)> 300
Response.Write("Girdiğiniz sayı çok büyük")
Catch hata As OverflowException
Response.Write("Hata meydana geldi")
End Try
End Sub
Hata Yakalama Sınıfları
ASP.NET sitelerinde hataları yakalarken kullanabileceğiniz çok sayıda sınıf bulunmaktadır. Yukarıda Exception, OverflowException, DivideByZeroException ve IndexOutOfRangeException sınıflarından kısaca söz edildi. Hata yakalama sınıflarının işlevleri biraz zor anlaşıldığı için yukarıda sözünü ettiğimiz konulardan tekrar söz edeceğiz. Öncelikle aşağıda verilen kodu incelemenizi istiyoruz.
Protected Sub Hesapla_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Hesapla.Click
Dim Number, Number2 As Byte
Dim Netice As Double
Try
Number1 = Convert.ToByte(TextBox1.Text)
Number2 = Convert.ToByte(TextBox2.Text)
Netice = Number1 \ Number2
TextBox3.Text = Netice.ToString()
Catch Hata As System.Exception
Response.Write("Hata meydana geldi" + Chr(13) + Chr(10) + Hata.ToString())
TextBox2.Focus()
End Try
End Sub
2. TextBox’a sıfır(0) girilip bu kod işletilirse sıfıra bölme hatası meydana gelir(yani Catch bloğuna DivideByZeroException nesnesi gönderilir) ve meydana gelen hata ile ilgili olarak sayfaya hata mesajı yazılır.
Bu kodda yukarıdaki sayfalarda verilen örneklerden farklı olarak “Hata” adını verdiğimiz bir nesne var. Bildiğiniz gibi nesneleri New anahtar kelimesini kullanıp ilgili sınıfın yapıcı metodundan yararlanarak hazırlanıyorduk. Ancak burada “Hata” adını verdiğimiz System’deki Exception tipindeki nesne otomatik olarak hazırlandı. Bu kodda Catch bloğuna DivideByZeroException nesnesi gönderilmesine ve Catch deyiminin olduğu satırda Exception tipinde değişken tanımlanmasına rağmen hata yakalandı.
Nasıl ki Object tipindeki değişkenlere istenen tipteki bilgiler aktarılabiliniyorsa bütün hata sınıflarının türetildiği Exception sınıfı tipindeki değişkene istenen hata sınıfının örneği aktarılabilinmektedir. Try bloğundan Catch bloğuna gönderilen DivideByZeroException nesnesi hatasızca dönüştürülüp System.Exception tipindeki değişkene aktarılabildiği için hata yakalanıp Catch bloğundaki satırlar işletilebilmektedir.
Bu sırada sıfıra bölme dışında başka bir hata meydana gelirse ekrana getirilen hata mesajı farklı olur. Sayfa sunucudan talep edilip TextBox’lardan birisine 255’ten büyük bir değer yazılıp bu kod işletilmiş olsaydı aşağıdaki gibi hata mesajı sayfaya yazılırdı.

Şimdi yukarıda verilen kodun Try bloğunda değişiklik yapıp sıfıra bölme hatası meydana geldiğinde başka mesaj, TextBox’a byte tipindeki değişkene sığamayacak büyüklükte bir değer girildiğinde sayfaya başka bir mesajın yazılmasını sağlayacağız.
Protected Sub Hesapla_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Hesapla.Click
Dim Number1, Number2 As Byte
Dim Netice As Double
Try
Number1 = Convert.ToByte(TextBox1.Text)
Number2 = Convert.ToByte(TextBox2.Text)
Netice = Number1 \ Number2
TextBox3.Text = Netice.ToString()
Catch Hata As System.DivideByZeroException
Response.Write("Sıfıra bölme hatası meydana geldi")
TextBox2.Focus()
Catch Hata As System.OverflowException
Response.Write("Büyük sayı girdiniz")
TextBox2.Focus()
End Try
End Sub
Bu kodu dikkatle incelerseniz Try bloğundan sonra birden fazla Catch bloğunun olduğunu görürsünüz. Hazırladığımız kodun Catch bloklarını bu şekilde değiştirip TextBox’ların birisine karaktersel bilgi girip bu kodu işletirsek meydana gelecek hata yakalanamaz ve sayfanın HTML karşılığı hazırlanmaz. Çünkü TextBox’a karaktersel bilgi girilip bu kod işletilirse Convert sınıfının ToByte() metodunun kullanıldığı satırlar hataya neden olur.
Number1 = Convert.ToByte(TextBox1.Text)
Number2 = Convert.ToByte(TextBox2.Text)
Convert sınıfının bu metodu ile string bilgiler byte tipine dönüştürülmeye çalışılırken meydana gelecek hataları yakalamak istiyorsanız 3. bir Catch bloğu hazırlayabilirsiniz. Convert sınıfının herhangi bir metodu ile dönüştürme yapılırken hata meydana geldiğinde Catch bloğuna FormatException sınıfının örneği gönderilmektedir.
Aşağıdaki gibi 3 catch bloğu hazırlayıp hem ilk TextBox’a byte tipindeki değişkene aktarılamayacak büyüklükte bir sayı girip hem de 2. TextBox’a 0 yazıp sıfıra bölme hatasının meydana gelmesini sağlarsanız ilk TextBox’ın içeriği byte değişkene aktarılırken hata meydana geleceği için Catch bloğuna OverflowException nesnesi gönderilir ve 2. Catch bloğu işletilir.
Catch Hata As System.DivideByZeroException
Response.Write("Sıfıra bölme hatası meydana geldi")
Catch Hata As System.OverflowException
Response.Write("Büyük sayı girdiniz")
Catch Hata As System.FormatException
Response.Write("Yanlış türde bilgi girdiniz")
End Try
InvalidCastException ve NullReferenceException Sınıfı
Değişik tipteki bilgileri başka bir tipe dönüştürmek mümkündür. DirectCast veTryCast operatörlerinden yararlanıp tip dönüşümleri yapılabilmektedir. Tip dönüştürme işlemleri sırasında sorun olduğunda InvalidCastException hatası meydana gelmektedir. InvalidCastException sınıfını anlatmak için aşağıda verilen kodu hazırladık.
Dim Nesne As Object = 2008
Try
Dim Yil As Integer
Yil = DirectCast(Nesne, Integer)
Me.Title = Yil.ToString()
Catch Hata As System.InvalidCastException
Response.Write("Dönüştürme hatası meydana geldi")
End Try
Bu kodda “Nesne” adını verdiğimiz object tipindeki değişkenin içeriği rakamlardan meydana geldiği için Unboxing işlemi yapılıp sorunsuz bir şekilde integer tipindeki değişkene aktarılır. Object tipindeki değişkenin içeriği integer tipindeki değişkene aktarılırken Unboxing işlemi başarısız olsaydı InvalidCastException hatası ile karşılaşılırdı. Örneğin burada “Nesne” adını verdiğimiz Object tipindeki değişken Integer değişkenlerin kapasitelerini aşan büyüklükte bir sayı aktarsaydık Catch bloğuna InvalidCastException tipinde bir nesne gönderilirdi.
Nothingyapılmış bir nesnenin özelliklerini kullanmak isterseniz NullReferenceException hatası ile karşılaşılır. Bu hata ile nasıl karşılaşıldığını göstermek için bir Bitmap nesnesi hazırlayıp Nothing yaptıktan sonra Width ve Height özelliklerini kullanmayı denedik.
Dim Resim As System.Drawing.Bitmap
Dim dosya As String = Server.MapPath("jazz.jpg")
Try
Resim = New System.Drawing.Bitmap(dosya)
Resim = Nothing
Dim i As Integer = Resim.Width
Dim j As Integer = Resim.Height
Catch Hata As NullReferenceException
Response.Write("Nesne Nothing yapılmış")
End Try
Throw Deyimi İle Exception Nesnesi Hazırlamak
Şimdiye kadar anlatılanlardan çıkarmış olabileceğiniz gibi herhangi bir nedenden dolayı bir metot dahilinde hata meydana geldiğinde karşılaşılan hataya uygun olarak ilgili hata sınıfının örneği hazırlanıp gönderilmektedir. Bizim yaptığımız, fırlatılan nesnenin hangi sınıfın örneği olduğunu öğrenip ona göre kullanıcıya mesaj verip tedbir almaktı. Burada asıl vurgulamak istediğimiz konu, sistem bir exception fırlattığında bu Exception’a kaynaklık edecek sınıfı kendisinin seçtiğidir.
Şimdi Throw deyiminden yararlanıp kendimiz bir Exception nesnesi hazırlayıp Catch bloğuna göndereceğiz. Bu amaçla kullanıcıdan gün, ay ve yıl bilgilerini isteyip bunları birleştirip tarih bilgisi elde edeceğiz. Bu amaçla sayfaya 4 TextBox yerleştirip aşağıda verilen kodu hazırladık.
Protected Sub Birleştir_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Birleştir.Click
Dim Tarih As DateTime
Dim gun As Integer = Convert.ToInt16(TextBox1.Text)
Dim ay As Integer = Convert.ToInt16(TextBox2.Text)
Dim yil As Integer = Convert.ToInt16(TextBox3.Text)
Tarih = DateSerial(yil, ay, gun)
TextBox4.Text = Tarih.ToShortDateString()
End Sub
Kullanıcı TextBox’lara uygun değerler girdiğinde bu kod sorunsuz çalışır. Ancak gün bilgisi olarak 31’den, ay bilgisi olarak 12’den büyük bir değer girdiğinde gün, ay ve yıl bilgileri birleştirilip tarih elde edilmek istendiğinde hata meydana gelir.
Yanlış bilgi girişinden dolayı sayfadaki kırılmayı önlemek için yukarıda yapıldığı gibi Try-Catch bloğu hazırlayabilir veya kullanıcının girdiği bilgileri DateSerial() metoduna parametre olarak vermeden önce kontrol edebilirsiniz. Pratik değeri olmasa bile aşağıda verilen kod hatasız çalışır ve DateSerial() metoduna parametre olarak verilecek ay ve gün bilgilerinin yanlış olması engellenir.
Protected Sub Birleştir_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Birleştir.Click
Dim Tarih As DateTime
Dim gun As Integer = Convert.ToInt16(TextBox1.Text)
Dim ay As Integer = Convert.ToInt16(TextBox2.Text)
Dim yil As Integer = Convert.ToInt16(TextBox3.Text)
If gun > 31 Or ay > 12 Then
Try
Throw New OverflowException("Yanlış bilgi girdiniz")
Catch Hata As Exception
Response.Write(Hata.Message)
TextBox1.Focus()
End Try
End If
Tarih = DateSerial(yil, ay, gun)
TextBox4.Text = Tarih.ToShortDateString()
End Sub
Kullanıcı ay veya gün bilgilerinde sınırı aştığında catch bloğu işletilir. try bloğunda şimdiye kadar yapılanlardan farklı olarak throw deyimi ile OverflowException nesnesi hazırlanmaktadır. Burada throw deyimi ile Exception nesnesi hazırlandığı için sıra catch bloğunu işletmeye gelir.
Catch bloğunda ise kullanıcıya mesaj verildikten sonra imleç ilk TextBox’a alınıp kullanıcıya girdiği bilgileri düzeltme şansı verilir. Throw deyimi ile OverflowException nesnesi yerine başka bir Exception nesnesi hazırlayabilirdik. Hemen hatırlatmak gerekirse, throw deyimi ilgili exception sınıfının örneğini alma işlemi daha çok kendi özel hata sınıflarını hazırlayan programcılar gerek duymaktadır.
Finally Bloğu
Bazen herhangi bir nedenden dolayı yarı yolda vazgeçilen bir işlemden dolayı geride bazı kalıntılar kalır. Bu gibi durumlar kaynak israfına neden olur. Bu konuda bilgi vermek için aşağıda verilen sayfayı hazırladık.

Bu sayfadaki “Kaydet” başlıklı düğme için aşağıda verilen kodu hazırladık. Bu sayfa görüntülenip TextBox’lara uygun bilgi girildiği sürece bu kod hatasız çalışır ve metodun sonunda Stream kapatıldığı için text dosyası serbest bırakılır. Dolayısıyla başka bir ziyaretçi bu sayfa aracılığıyla dosyaya bilgi yazabilir.
Protected Sub Kaydet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Kaydet.Click
Dim akis As System.IO.FileStream
akis=New System.IO.FileStream(Server.MapPath("dosya.txt"), IO.FileMode.Append)
Dim yazici As System.IO.StreamWriter
yazici = New System.IO.StreamWriter(akis)
Dim sira_no As Integer = Convert.ToInt16(TextBox1.Text)
Dim Tarih As DateTime = Convert.ToDateTime(TextBox2.Text)
Dim aciklama As String = TextBox3.Text
yazici.WriteLine(sira_no.ToString())
yazici.WriteLine(Tarih.ToString())
yazici.WriteLine(aciklama)
yazici.Close()
akis.Close()
End Sub
Ancak kullanıcı TextBox’lara uygun olmayan yani Integer ve DateTime tipine dönüştürülmeyecek bilgi girerse hata meydana gelir. Hata meydana geldiğinde sayfanın görüntülenmesine devam edilmesi için bu kodu aşağıda gibi düzenledik.
Protected Sub Kaydet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Kaydet.Click
Dim akis As System.IO.FileStream
akis = New System.IO.FileStream(Server.MapPath(|
"dosya.txt"), IO.FileMode.Append)
Dim yazici As System.IO.StreamWriter
yazici = New System.IO.StreamWriter(akis)
Try
Dim sira_no As Integer = Convert.ToInt16(TextBox1.Text)
Dim Tarih As DateTime = Convert.ToDateTime(TextBox2.Text)
Dim aciklama As String = TextBox3.Text
yazici.WriteLine(sira_no.ToString())
yazici.WriteLine(Tarih.ToString())
yazici.WriteLine(aciklama)
yazici.Close()
akis.Close()
Catch
Response.Write("Hatalı bilgi girdiğiniz")
End Try
End Sub
Kullanıcı uygun olmayan bilgi girerse catch bloğundaki satır işletilir ve kullanıcıya bu konuda bilgi verilir. Ancak bu durumda “yazici” ve “akis” adını verdiğimiz stream nesneleri ilgili text dosyasını tutmaya devam ederler. Çünkü bu stream nesnelerini kapatan satırları try bloğuna yazmıştık.
Hata meydana gelsin veya gelmesin mutlaka işletilmesini istediğiniz satırlar varsa bu satırları Finally bloğuna yazmalısınız. Finally bloğunun nasıl kullanıldığını anlatmak için yukarıda verilen kodu aşağıdaki gibi değiştirdik.
Protected Sub Kaydet_Click(ByVal sender As Object, ByVal e As EventArgs) Handles Kaydet.Click
Dim akis As System.IO.FileStream
akis=New System.IO.FileStream(Server.MapPath("dosya.txt"), IO.FileMode.Append)
Dim yazici As System.IO.StreamWriter
yazici = New System.IO.StreamWriter(akis)
Try
Dim sira_no As Integer = Convert.ToInt16(TextBox1.Text)
Dim Tarih As DateTime = Convert.ToDateTime(TextBox2.Text)
Dim aciklama As String = TextBox3.Text
yazici.WriteLine(sira_no.ToString())
yazici.WriteLine(Tarih.ToString())
yazici.WriteLine(aciklama)
Catch
Response.Write("Hatalı bilgi girdiğiniz")
Finally
yazici.Close()
akis.Close()
End Try
End Sub
Gerek duyarsanız birden fazla Catch bloğu ve/veya iç-içe Try-Catch bloğu hazırlayabilirsiniz. Söz konusu hatanın birden fazla nedenden kaynaklanması ihtimali varsa try bloğu için birden fazla catch hazırlanabilir.
Entegre Hata Ayıklayıcısı ve Exception Sınıfları
Çok kullanılan hata yakalama sınıflarından biraz söz ettikten sonra mevcut hata sınıflarıyla entegre hata ayıklayıcının ilişkisinden söz edeceğiz. Bu amaçla Visual Studio'nun Debug menüsünden komut verip ekrana Exceptions diyalog kutusunu getirdik.

Bu diyalog kutusunda Visual Studio ile hazırlanan web uygulamaları dahilinde yararlanabileceğiniz Exception sınıflarıyla, entegre hata ayıklayıcısı arasındaki ilişki ayarlanmaktadır. Bu konuda bilgi vermek için sayfaya bir TextBox ve düğme yerleştirip düğmenin Click olayı için aşağıda verilen kodu hazırladık.
Private Sub islem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles islem.Click
Dim number As Byte
Try
number = Convert.ToByte(TextBox1.Text)
Catch hata As OverflowException
Response.Write("Hata meydana geldi")
End Try
End Sub
Tahmin edeceğiniz gibi Start Debugging komutu verilip sayfa sunucudan talep edilip TextBox’a 255’ten büyük bir sayı girilmesi halinde hata meydana gelir. Bu hatadan dolayı OverflowException tipinde nesne hazırlanıp catch bloğuna gönderilir.
Şimdi öyle bir ayarlama yapacağız ki site Start Debbuging komutu verilip Visual Studio ile gelen web server ile test edilirken Catch bloğundaki satırların işletilmesi yerine uygulamanın çalışmasının kırılmasını sağlayacağız. Bu amaçla Exceptions diyalog kutusunda önce Common Language Runtime Exceptions adlı exception sınıfı grubuna ait namespace’lerin listelenmesini sağladık. Ardından System adlı namespace’te yer alan OverflowException hata sınıfını bulduk.

Verilen ekran görüntüsünde tespit edebileceğiniz gibi bu hata sınıfı için Thrown özelliği pasif iken User-unchandled özelliği aktif durumdadır. Başka bir deyişle kodun herhangi bir yerinde meydana gelebilecek ve OverflowException sınıfının örneğinin fırlatılmasına neden olacak hata yakalanmazsa sayfanın sunucuda hazırlanıp istemciye gönderilmesi işlemi tamamlanmaz.
Yukarıda verilen kodda TextBox’a 255’ten büyük bir değer girilirse, dolayısıyla byte değişkene 255’ten büyük bir sayı aktarılmak istenirse meydana gelebilecek hata yakalandığı için sayfanın render edilmesi işlemi yarım kalmaz. Başka bir deyişle mevcut ayarlarda Byte tipindeki değişkene 255’ten büyük bir değer aktarılmak istenirse ve OverflowException hatasını yakalayan bir Catch bloğu yoksa talep edilen veya PostBack olan sayfa istemciye gönderilmez. Benzer şekilde .NET Framework ile gelen sınıfların hemen hepsi için User-unhanded sütunundaki onay kutusu seçili durumda olduğu için yakalanmayan bütün hatalar Debug modda uygulamanın kırılmasına neden olurlar.
Bu diyalog kutusunda System’de yer alan OverflowException sınıfının User-unchandled özelliği aktif durumda iken ayrıca Thrown sütunundaki onay kutusunu aktif duruma getirdikten sonra OK düğmesi ile bu diyalog kutusunu kapattık. Ardından yukarıda verilen kodu aşağıdaki gibi düzenledik.
Private Sub islem_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles islem.Click
Dim number As Byte
Try
number = Convert.ToByte(TextBox1.Text)
If number = 100 Then
Throw New OverflowException
End If
Catch hata As OverflowException
Response.Write("Hata meydana geldi veya 100 girdiniz")
End Try
End Sub
Önce bu kodu biraz yorumlayalım: TextBox’a 255’ten büyük bir değer girilip bu kod işletilirse ToByte() metodunun kullanıldığı satır hataya neden olur ve Catch bloğuna OverflowException sınıfının örneği gönderilir. TextBox’a 100 sayısı girilip bu kod işletildiğinde ise Try bloğundaki karşılaştırma True olacağı için Catch bloğuna yine OverflowException sınıfının örneği gönderilir.
Tekrar etmek gerekirse ister TextBox’a 100 ister 255’ten büyük bir sayı yazılsın OverflowException sınıfının örneği Catch bloğuna fırlatılır. Bu şartlarda yani Exceptions diyalog kutusunda OverflowException sınıfının Thrown özelliği seçili durumda iken site Start Debugging komutu ile test edildiğinde TextBox’a ister 100 girilsin ister 255’ten büyük sayı uygulamanın çalışması kırılır. Çünkü Exceptions diyalog kutusunda yaptığımız ayarlamanın anlamı şudur: Her ne nedenden olursa olsun ister direk Throw deyimi kullanılsın ister yapılmak istenen işlem sonucu OverflowException hatası üretilirse ilgili sayfanın HTML kodunun hazırlanıp istemciye gönderilmesi işlemi yarıda kalır. Tabi siteyi yayınlayıp başka bir bilgisayarda test ederseniz TextBox’a ister 255’ten büyük sayı girilsin ister 100 girilsin Catch bloğundaki satırlar işletilir ve uygulamanın çalışması kırılmaz.
Sayfa Seviyesinde Hata Yakalamak
Bu bölümde şimdiye kadar Page sınıfının mirasçısı sayfalarda ve kendi yazacağınız class’larda metotlar dahilinde meydana gelmesi muhtemel hataları nasıl yakalayabileceğinizden söz ettik. Şimdi gelelim sayfa bazında hataların nasıl yakalandığını anlatmaya. ASP.NET sitesini hazırlayan programcı sayfa ve sınıflarda hazırladığı metotlarda meydana gelmesi muhtemel hataları öngörüp her metot için hata yakalama konusunda tedbir almış olsa bile bazı öngörülemeyen hatalar olabilir.
Bu konuda bilgi vermek için yukarıdaki sayfalarda sözünü ettiğimiz sıfıra bölme hatasından tekrar söz edeceğiz. Her ne kadar sıfıra bölme hatasından söz etme hakkı(!) yerli bir yazara ait olsa bile bu yasağı burada bir süreliğine deleceğiz.
Protected Sub hesapla_Click(ByVal sender As Object, ByVal e As EventArgs) Handles hesapla.Click
Dim Number, Number2 As Byte
Dim Netice As Double
Number1 = Convert.ToByte(TextBox1.Text)
Number2 = Convert.ToByte(TextBox2.Text)
Netice = Number1 \ Number2
TextBox3.Text = Netice.ToString()
End Sub
Bu metotta meydana gelmesi muhtemel hatalardan birisi olan sıfıra bölme hatasını metot dahilinde Try-Catch bloğuyla yakalamadığımız için bu kod işletilmek üzere sayfa PostBack edildiğinde sayfanın HTML karşılığı hazırlanmaz. Bu hatanın önüne nasıl geçildiğinden söz etmek için hataya neden olan metodun bulunduğu sayfanın(yani Page sınıfının mirasçısı sınıf) Error olayını temsil edecek metodu aşağıdaki gibi düzenledik. Bu metotta text dosyasına hata meydana geldiği bilgisi yazılmaktadır. Başka bir deyişle karşılaşılan hata log’lanmaktadır. Kod uzamasın diye text dosyasına meydana gelen hatayla ilgili açıklayıcı bilgi yazmadık.
Protected Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Dim akis As System.IO.FileStream
akis=New System.IO.FileStream(Server.MapPath("hatalar.txt"), IO.FileMode.Append)
Dim yazici As System.IO.StreamWriter
yazici = New System.IO.StreamWriter(akis)
Dim Tarih As DateTime = Now
yazici.WriteLine(Tarih.ToString())
yazici.WriteLine("Hata meydana geldi")
yazici.Close()
End Sub
Her ne kadar bu metoda Page_Error() adını vermiş olsak bile sizler istediğiniz adı verebilirsiniz. İleriki günlerde bu kitap yayınlandığında programcılık kitapları yazan birisi “Page_Error” metodunu kullanmayı ilk ben akıl ettim, dolayısıyla çalıntı yapılmıştır diye bizi suçlamasını engellemek için bu metoda bir de aşağıdaki gibi farklı bir ad verdik.
Protected Sub Hatalarimla_Sev_Beni(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Dim akis As System.IO.FileStream
akis=New System.IO.FileStream(Server.MapPath("hatalar.txt"), IO.FileMode.Append)
Dim yazici As System.IO.StreamWriter
yazici = New System.IO.StreamWriter(akis)
Dim Tarih As DateTime = Now
yazici.WriteLine(Tarih.ToString())
yazici.WriteLine("Hata meydana geldi")
yazici.Close()
End Sub
Bu metoda ait ilk satırda Handles deyimi ile metodun hangi nesnenin hangi olayını temsil ettiği işaret edildiği için metoda verilen adın önemi yoktur. Ancak Error olayını temsilen hazırlanan metodun Object ve EventArgs tipinde iki parametreye sahip olması ve geriye bilgi göndermemesi yani Sub tipi metot olması şarttır.
Üzerinde çalıştığınız sayfanın olaylarını temsil edecek metotlar hazırlarken kod penceresindeki Class Name liste kutusunda Page Events seçili iken Method Name liste kutusunda ilgilendiğiniz olayı seçerseniz Visual Studio’nun sizin için metodu hazırlayacağını biliyorsunuz.

Yukarıda verilen yani sayfanın Error olayını temsil eden metot, sayfa dahilinde programcı tarafından hazırlanan metotlarda yakalanmayan herhangi bir hata meydana geldiğinde işletilir. Örnek olması için sayfanın Error olayını temsilen hazırladığımız bu metotta StreamWriter sınıfıyla text dosyasına mesaj yazıldıktan klasik hata sayfası ekrana getirilir. Sayfa entegre hata ayıklayıcının eşliğinde test ediliyorsa Error olayını temsil eden bu metot işletildikten sonra sayfanın görüntülenmesi işlemi yarım kalır ve hataya neden satır işaret edilir.
Bu şartlarda yani sayfanın Error olayını temsil eden böyle bir metot varken, sayfa yayınlanıp herhangi bir istemciden görüntülenirse neler olur ona bakmak gerekir. Bu sırada bu sayfa dahilinde bir hata meydana gelir ve bu hata ilgili metot dahilinde yakalanmazsa Error olayı meydana gelir. Bu sınıfın yani sayfanın bu olayla ilgili mevcut Page_Error() metodu işletilip text dosyasına hatayla ilgili bilgi yazılır. Devamında yine ekrana klasik hata raporu getirilir ki bu raporda kullanıcı için anlaşılır özel bilgi yoktur. Konunun diğer ayrıntılarını ortaya çıkarmak için yukarıda verilen Page_Error() adlı metotta bazı değişiklikler yaptık.
Protected Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Dim akis As System.IO.FileStream
akis=New System.IO.FileStream(Server.MapPath("hatalar.txt"), IO.FileMode.Append)
Dim yazici As System.IO.StreamWriter
yazici = New System.IO.StreamWriter(akis)
Dim son_hata As System.Exception
son_hata = Server.GetLastError()
Dim Tarih As DateTime = Now
yazici.WriteLine(Tarih.ToString())
yazici.WriteLine(son_hata.ToString())
yazici.Close()
End Sub
Metoda sonradan eklediğimiz 2 satırda önce Exception tipinde bir değişken tanımladık. Devamında HttpServerUtility sınıfının örneği olan Server nesnesinin GetLastError() metoduyla web sitesiyle ilgili olarak meydana gelen son hatadan dolayı hazırlanan Exception nesnesini bu değişkene aktardık. En son olarak bu nesnenin içeriğini text dosyasına yazdık. Aşağıda verilen ekran görüntüsü sayfada sıfıra bölme hatasının meydana gelmesini sağlayıp Page_Error() metodunun işletilmesine neden olduktan sonra aldık.

Tabi burada yapıldığı gibi meydana gelen en son hatayla ilgili bilgilerin tümü yerine Message özelliğinin içeriğiyle ilgilenebilirdik. Sayfanın Error olayını temsil eden metodun bu şekilde düzenlenmesinin kullanıcıya bir yararı yoktur. Çünkü burada meydana gelen hata loglanmakla yani hatayla ilgili bilgiler text dosyasına yazılmakla birlikte kullanıcı yine klasik hata mesajıyla karşılaşmaktadır.
Meydana gelen hatayla ilgili bilgileri sayfaya yazıp kullanıcıya bilgi vermek istiyorsanız meydana gelen en son hatayı HttpServerUtility tipindeki Server nesnesinin ClearError() metoduyla silmeniz gerekir. Bu metodu nasıl kullandığımızı aşağıda görebilirsiniz.
Protected Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Dim son_hata As System.Exception
son_hata = Server.GetLastError()
Server.ClearError()
Response.Write("Hata meydana geldi" + "<br/>")
Response.Write("Meydana gelen hata :" + son_hata.Message)
End Sub
Kodu kısaltmak için meydana gelen hatayla ilgili olarak text dosyasına bilgi yazan satırları kaldırdık. Bu kodda GetLastError() metoduyla meydana gelen en son hata nesnesini elde ettikten sonra ClearError() metoduyla bu hatanın Server nesnesinden silinmesini sağladık. Hata ClearError() metoduyla silindikten sonra tarayıcı penceresine klasik hata sayfası gelmez. Aşağıda verilen ekran görüntüsü sıfıra bölme hatasının meydana gelmesini sağlanıp Page_Error() adlı metot işletildikten sonra alındı.

Programcılar genellikle Page_Error() metodunda yakaladıkları hatanın etkisini ortadan kaldırırken özel bir hata sayfası hazırlıyorlar. Bu düşünceyle sitede “hata.aspx” adında kısıtlı özelliklere sahip bir sayfa hazırlayıp bu sayfanın Load olayını temsil eden metodu aşağıdaki gibi düzenledik.

Şimdi öyle bir ayarlama yapmalıyız ki ana sayfasındaki metotlar dahilinde yakalanmayan herhangi bir hata meydana geldiğinde “hata.aspx” adını verdiğimiz sayfa görüntülensin. Bu ayarlama yukarıda verilen Page_Error() metodunda yapılabilir. Bu düşünceyle sitenin ana sayfasının bu metodunu aşağıdaki gibi düzenledik. Hataya neden olan kodları kısaltmak için hata fırlatma işlemini Throw deyimiyle yaptık.
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub islem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles islem.Click
Throw New DivideByZeroException()
End Sub
Protected Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Response.Redirect("hata.aspx")
End Sub
End Class
Bu şartlarda sitenin ana sayfasındaki “islem” adlı düğme tıklandığında Throw deyimiyle yani anahtar kelimesiyle DivideByZeroException sınıfının örneği alınıp ortama fırlatılır. Bu hatayı yakalayan bir catch bloğu olmadığına göre sitenin ana sayfasıyla ilgili olarak Error olayı meydana gelir. Bu sırada Error olayını temsil eden metot olduğu için işletilir. Bu metotta yani Error olayını temsil eden metotta Response nesnesinin Redirect() metoduyla “hata.aspx” adını verdiğimiz sayfaya geçildiği için sitenin ana sayfası görüntülenip bu sayfadaki “islem” düğmesi tıklanırsa aşağıdaki gibi bir sonuç alınır. Aşağıda verilen ekran görüntüsü alındığı sırada “hata.aspx” adını verdiğimiz sayfa görüntüleniyordu.

Şimdi “hata.aspx” adını verdiğimiz bu sayfanın Load olayını temsil eden metodu geliştirip sitenin ana sayfasında meydana gelen hata hakkında kullanıcıya bilgi vermeyi deneyeceğiz. Tekrar etmek gerekirse; yukarıda sitenin ana sayfasında sayfanın Error olayıyla ilgili Page_Error() metodunda Redirect() metoduyla “hata.aspx” adını verdiğimiz sayfayı talep ettik. Bu durumda hata.aspx sayfasında bir önceki sayfada karşılaşılan hatayla ilgili bilgi artık yoktur. Bu nedenle kullanıcıya sunulmak istenen bilgiler bir şekilde burada “hata.aspx” adını verdiğimiz sayfaya ulaştırılmalıdır. Bu amaçla ana sayfanın yukarıda verdiğimiz Error_Page() metodunu aşağıdaki gibi düzenledik.
Partial Class _Default
Inherits System.Web.UI.Page
Protected Sub islem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles hesapla.Click
Throw New DivideByZeroException()
End Sub
Protected Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Dim hata_nesnesi As New Exception()
hata_nesnesi = Server.GetLastError()
Dim orijinal_mesaj As String
orijinal_mesaj = hata_nesnesi.Message
Response.Redirect("hata.aspx?mesaj=" + orijinal_mesaj)
End Sub
End Class
Page_Error() metodunun bu yeni halinde kullanıcıya verilmek istenen bilgiyi yani ana sayfaya karşılaşılan hatanın orijinal mesajını “hata.aspx” adlı sayfaya QueryString’le gönderdik. Ortama fırlatılan hatanın yakalandığı metodu bu şekilde düzenledikten sonra kullanıcıya bilgi verilen “hata.aspx” adlı sayfanın Load olayıyla ilgili metodu aşağıdaki gibi düzenledik. Tabi sizler içinde bulunulan şartlara göre kullanıcıyı yönlendiren ve ayrıntılı bilgi veren bir sayfa hazırlayabilirsiniz.
Partial Class hata
Inherits System.Web.UI.Page
Protected Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
Response.Write("Hata meydana geldi" + "<br>")
Response.Write(Request.QueryString("mesaj"))
End Sub
End Class
Hata Yakalama Noktalarının Öncelik Sıraları
Konunun kolay kavranmasını sağlamak için yukarıda sayfa seviyesinde yapılan hata yakalamayla ilgili olarak anlatılanları özetleyeceğiz. Ancak bu kez hazırlayacağımız sayfayı IIS’ten yararlanarak test edeceğiz. Bu sayede hata yakalama noktalarının öncelik sıralarını net olarak görmüş olacağız. Bu amaçla yeni bir site hazırlayıp ana sayfasına Button nesnesi yerleştirip bu button nesnesinin Click olayını temsilen aşağıdaki gibi bir metot hazırladık.
Protected Sub islem_Click(ByVal sender As Object, ByVal e As EventArgs) Handles islem.Click
Throw New DivideByZeroException()
End Sub
Bu metotta Throw anahtar kelimesiyle DivideByZeroException nesnesi hazırlanıp ortama fırlatılmaktadır. Bu metodu hazırladıktan sonra Visual Studio’nun Build menüsünden komut verip aşağıda verilen Publish Web Site diyalog kutusunu ekrana getirdik.

Bu diyalog kutusundan yararlanarak üzerinde çalıştığımız siteyi kullandığımız bilgisayarda “\InetPub\wwwroot” klasörüne aktardık. Başka bir deyişle sadece ana sayfasına bir Button nesnesi yerleştirdiğimiz sitenin IIS’in nazarında Default Web Site olarak değerlendirilmesini sağladık. Bu web sitesini hazırlayıp yayınladığımız bilgisayarın adı SERVER’dı. Siteyi yayınlama işleminden sonra başka bir bilgisayarın başına geçilip bu sırada sunucu görevi yapan IIS’ten bu sitenin ana sayfası talep edilip sayfadaki düğme tıklandığında aşağıdaki gibi bir hata sayfası ile karşılaşılır.

Hata yakalama konusunu özetlemek amacıyla hazırladığımız bu web sitesinin ana sayfasındaki düğme tıklandığında ortama sıfıra bölme hatası fırlatılıp sunucunun browser penceresine bu sayfayı göndermesi sağlanmaktadır. Bu hata sayfası IIS ile birlikte gelen standart sayfalardan birisidir. Bu sayfada kullanıcıya karşılaştığı hata hakkında açıklayıcı bilgi verilmemektedir. Throw deyimi ile sıfıra bölme hatasını meydana getirmek yerine olmayan bir sayfaya gitmek istemiş olsaydık sunucu başka bir hata sayfasını istemciye gönderirdi.
Bu hatayı yani Throw deyimi ile ürettiğimiz hatayı try-catch blokları ile yakalamadığımız için öncelikle sayfanın Error olayını temsil eden bir metodunun olup olmadığı araştırılır. Bu sayfayla ilgili olarak Error olayı meydana geldiğinde işletilecek bir metot henüz olmadığı için bu kez Application nesnesinin Error olayıyla ilgili bir metodun olup olmadığı araştırılır. Üzerinde çalıştığımız sitede Application_Error adında ve uygulamanın Error olayını temsil eden bir metot henüz olmadığı için son çare olarak IIS ile gelen standart hata sayfası istemciye gönderildi.
Bu anlatılanları bir cümle ile özetlemek gerekirse; ASP.NET sitelerinde hata yakalama konusunda herhangi bir hazırlık yapılmadığında hatalı bir durumla karşılaşıldığında IIS ile gelen standart hata sayfalarından birisi istemciye gönderilmektedir.
Bu bölümün ilk sayfalarında hata yakalama konusunu try-catch bloklarından itibaren anlatmaya başladık. Sitedeki sayfalarda meydana gelen hataları birden fazla yerde yakalamak mümkün olduğu için henüz yolun başındakiler için bu çeşitlilik kafa karıştırmaktadır. Herhangi bir sayfada herhangi bir hata meydana geldiğinde gelişen olayları anlatmak için Throw deyimi ile Exception nesnesi ürettikten sonra aşağıdaki gibi bir Global.asax dosyası hazırladık. Bu dosyanın nasıl hazırlandığını önceki konulardan biliyorsunuz.

Visual Studio bu dosyada çok kullanılan 5 olay için 5 metodu otomatik olarak hazırladığı ve bu metotlardan birisi uygulamanın Error olayını temsil eden metot olduğu için Application_Error() metoduna sonradan 2 satır yazdık. Bu metoda sonradan eklediğimiz ilk satırda web sitesi dahilinde meydana gelen en son hatayı temizledik. Çünkü bu metotta en son meydana gelen hata devreden çıkarılmazsa hata yakalanmamış gibi browser penceresine standart hata sayfalarından birisi getirilir. Bu sırada yani hatayı devre dışı yaptıktan sonra meydana gelen en son hatayla ilgili bilgileri loglayabilir yani bir dosyaya yazabilirsiniz.
Global.asax dosyası aracılığı ile uygulama dahilinde en son meydana gelen hatayı yakalayıp silmekten söz ettikten sonra şimdi sırada Web.config dosyasıyla uygulamadaki herhangi bir sayfada meydana gelen hataların nasıl yakaladığı konusu var. Bu amaçla Web.config dosyasında CustomErrors tagına yer verip uygulamadaki herhangi bir sayfada herhangi bir hata meydana geldiğinde “genel_hata.aspx” adlı sayfaya geçilmesini istediğimizi belirttik. Bu bölümün ileriki sayfalarında CustomErrors tagı hakkında bilgi verilecektir.

Web.config dosyasında customErrors tagını bu şekilde düzenledikten sitenin ana klasörüne “genel_hata.aspx” adında bir sayfa yerleştirdik. Bu sayfanın Load olayını temsil eden metodu aşağıdaki gibi düzenledik.

Bu şartlarda sitenin ana sayfası sunucudan talep edilip ana sayfadaki düğme tıklanıp Throw düğmesiyle hata üretilirse öncelik Global.aspx dosyasındaki Application_Error() metodunda olduğu için Web.config dosyası aracılığıyla işaret edilen bu sayfaya geçilemez. Çünkü Global.aspx’deki Application_Error() metodu dahilinde ClearError() metoduyla uygulamanın herhangi bir sayfasında meydana gelen en son hatayı sildik. Eğer hem Global.asax dosyasında dahilinde Application_Error() metoduna yer veriyor hem de Web.config dosyası dahilinde CustomErrors tagıyla mevcut bir sayfayı işaret ediyorsanız, bu sayfanın işletilme şansı bulabilmesi için Application_Error() metodunda ClearError() ile hatayı silmemeniz gerekir. Bu nedenle Application_Error() metodundaki satırlardan birisini sildik.
SubApplication_Error(ByVal sender As Object, ByVal e As EventArgs)
Response.Write("Hata meydana geldi")
EndSub
Bu şartlarda yani Web.config dosyasında CustomErrors ile bir sayfa işaret edilmiş iken Application_Error() metodunu hazırlama amacı olsa olsa meydana gelen hataları loglamak olur. Öncelikli amacımız hata yakalama süreci hakkında bilgi vermek olduğu için yukarıdaki gibi kısıtlı özelliklere sahip bir metot hazırladık. Özetlemek gerekirse, hem Application_Error metodu hem de Web.config dosyasında customErrors tagıyla yapılan ayarlama sitedeki bütün sayfalar üzerinde etkilidir.
Bu şartlarda yani hem Global.asax dosyasında Application_Error() metodu hazırlanmış hem de Web.config dosyasında özel bir hata sayfası işaret edilmiş iken ilgili sayfanın ErrorPage niteliğiyle bir hata sayfasını işaret etmeniz halinde hem Global.asax dosyasındaki Application_Error() metodu işletilme şansı bulamaz hem de Web.config dosyası aracılığıyla işaret edilen özel hata sayfasına geçilmez. Bu işlemin nasıl yapıldığını anlatmak için sitenin ana sayfasının Page yönergesini aşağıdaki gibi ayarladık.
<%@ Page Language="VB" AutoEventWireup="false"
ErrorPage ="~/error_page_hata.aspx"
CodeFile="Default.aspx.vb" Inherits="_Default" %>
Bu ayar sayesinde sayfadaki herhangi bir metotta hata meydana gelir ve bu hata try-catch bloklarıyla yakalanmazsa sayfayla ilgili Error olayını temsil eden metot var mı yok mu ona bakılır. Programcı böyle bir metodu hazırlamadıysa istemciye yani ziyaretçiye, sayfanın ErrorPage niteliğine adı aktarılmış sayfa gönderilir. Bu nedenle adını ErrorPage niteliğine aktardığımız sayfayı hazırladık.

Bu konuyu anlatmak üzere hazırladığımız sitedeki ana sayfanın Error olayı için henüz herhangi bir metot hazırlamadığımız için ortama fırlatılan hata, adı ErrorPage niteliğine aktarılan bu sayfa tarafından yakalanır. Şimdi bir adım daha geriye gidip sayfanın Error olayını temsil eden metot bir hazırlayacağız.
Protected Sub Page_Error(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Error
Response.Write("Error olayını temsil eden metot işletildi" + "<br>")
End Sub
Bu şartlarda yani Global.asax dosyasında Application_Error() metodu hazırlanmış, sayfanın ErrorPage niteliğine sitedeki mevcut bir sayfanın adı aktarılmış iken ve sayfanın Error olayını temsil eden bir metot var iken sayfa dahilinde bir hata meydana geldiğinde önce Error olayıyla ilgili metot işletilir. Error olayını temsil eden metotta ClearError() metodu ile son hata silinmediyse veya Redirect() metoduyla başka bir sayfaya geçilmediyse ErrorPage niteliğiyle işaret edilen sayfaya geçilir. Aşağıda verilen ekran görüntüsünü bu şartlarda uzak bir bilgisayarın başında iken sitedeki ana sayfadaki düğmeyi tıklayıp hata oluşmasını sağladıktan sonra aldık.

Tekrar etmek gerekirse, sayfanın Error olayını temsil eden metotta Server nesnesine ClearError() metodunu uygulamış olsaydık adı geçerli sayfanın ErrorPage niteliğine aktarılan bu sayfaya geçilmezdi.
Şimdiye kadar hata yakalama işlemiyle ilgili olarak yazılanlara bakılırsa ASP.NET sitesindeki herhangi bir metotta meydana gelen hatayı değişik yerlerde yakalamak mümkündür. Hataların ilk yakalanabilineceği yer hata üretmesi muhtemel ilgili metot dahilinde try-catch bloklarıdır. Try-catch bloklarından sonra sıra söz konusu sayfanın Error olayını temsil eden metodundur.
Sayfanın Error olayını temsil eden metotta da yakalanmayan hatalar sayfanın Page yönergesinin ErrorPage niteliğine adı aktarılan sayfada oluşan hata yakalanabilir. ErrorPage niteliğinden yararlanıp meydana gelen hata henüz yakalanmadıysa en son olarak Global.asax dosyası dahilinde hazırlanan ve uygulamanın Error olayını temsil eden metotta hata yakalanabilir. Web.config dosyasında CustomErrors tagı ve Global.asax’deki Application_Error() metodu sayesinde ancak sayfa dahilinde yakalanmayan hatalar yakalanıp gereği yapılabilinir.
Şimdi web.config dosyası aracılığıyla CustomErrors tagıyla meydana gelen hataların nasıl özel hata sayfalarına yöneltildiğinden söz edeceğiz. Bu amaçla üzerinde çalıştığımız sayfaya bir düğme yerleştirip bu düğmenin Click olayını temsil eden metodu aşağıdaki gibi düzenledik.
ProtectedSub btnGit_Click(ByVal sender As Object, ByVale As EventArgs) Handles btnGit.Click
Response.Redirect("Defualt2.aspx")
EndSub
Bu metot sayesinde sunucudan sitedeki Defualt2.aspx sayfası istenir. Ancak bu sırada sitede böyle sayfa olmadığı için ünlü HTTP 404 nolu hata meydana gelir ve IIS bu hatayla ilgili olarak istemciye aşağıdaki gibi sayfayı gönderir.

Şimdi Web.config dosyası aracılığıyla CustomErrors tagıyla http 404 hatası meydana geldiği zaman istemciye bu klasik sayfa yerine özel bir sayfasının gönderilmesini sağlayacağız. Bu amaçla Web.config dosyasında system.web tagı içinde yer alan customErrors tagını aşağıdaki gibi düzenledik.
<customErrors mode="RemoteOnly">
<error statusCode="404" redirect="hata404.aspx" />
</customErrors>
http 404 hatası meydana geldiğinde istemciye hata404.aspx adını verdiğimiz sayfanın gönderilmesi için sayfanın uzak bir bilgisayardan talep edilmesi veya mode niteliğinin On olarak ayarlanması gerekir. Bu şartlarda yani sitenin ana klasöründeki Web.config dosyasının customErrors tagı bu şekilde düzenlenmiş iken olmayan bir sayfa talep edildiğinde sunucu istemciye “hata404.aspx” sayfasını gönderir.
Bu sırada kullanıcı yetkisi olmadığı bir sayfayı talep ederse yine IIS standart hata sayfalarından birisini gönderir. Bunun önüne geçmek için customErrors tagı içinde ikinci veya üçüncü error tagına yer verip ikinci bir özel hata sayfası hazırlayabilirsiniz. Ancak öngörülüp kendisi için özel hata sayfası hazırlamadığınız hatalara özel genel bir hata sayfası hazırlayabilirsiniz. Bu amaçla customErrors tagının defaultRedirect niteliği aşağıdaki gibi düzenlenebilir.
<customErrors mode="RemoteOnly" defaultRedirect ="genel_hata.aspx">
<error statusCode="403" redirect="yetki_hatasi.aspx" />
<error statusCode="404" redirect="hata404.aspx" />
</customErrors>