27 Şubat 2009 Cuma

Güle Güle İBB!!..

Öncelikle derin bir oh çekiyorum. Sonunda ibb'yi yendik. Ama nasıl yendik onu bize sorun. Kriz, ulusalcılığın tehdit edilmesi, Atatürkçülüğe zarar vermeye çalışanlar vs. hepsine karşı direnebiliyoruz da, bu Beşiktaş bir gün kalpten götürecek bizi. Berbat oybadık. Son 15 dk. hareketlendik biraz. 80'de attık golü. Tam maçı kopardık derken, 84'te yedik. 35 saniye sonra da tekrar öne geçtik. Son dakikalar geçmek bilmedi yaa.

Bu arada bu ibb bakalım gs maçında nasıl oynayacak. Abdullah Avcı'yı o maçta da merak ediyorum Böyle hırslı oynatacak mı takımını. Adamlar sanki şampiyonluğa oynuyorlar. Ne biçim koşuyorlar öyle. Neyse bir şekilde bitti maç. Hakemlerin gasbına, lig tv'nin o yorum yapamayan sözde yorumcularına, eyyamcılara rağmen şampiyon olacağız inşallah bu sene.

Görüşmek üzere..

25 Şubat 2009 Çarşamba

T-SQL - ANSI SQL 92 ve Saçmalıklar :)

Bugün belki işime yaramasa da bir şey öğrendim. :) Bir süredir kullanmadığım, daha önceleri sık sık kullandığım T-SQL, yani Microsoft'un SQL'i, ANSI standartlarından giriş seviye ANSI SQL 92 uyumluymuş. Giriş seviyesi olması da ANSI uyumluluğum ilk şartı imiş. Ve bir çok veri tabanı yönetim sistemleri (VTYS - RDBMS) genelde bu seviyede kalıyormuş. Ha peki, bunu öğrendin de ne oldu derseniz, bir şey olmadı sadece merakımı giderdim. :)

Bu yazı bu kadar yeter, televizyonu doğru dürüst izlediğim tek gün (Avrupa Yakası) bugün. Gidip dizinin yeni bölümünü izleyeceğim. :)

Görüşmek üzere..

23 Şubat 2009 Pazartesi

Yok Başlık Falan..

Bugün en nihayetinde ders kaydımı yaptırdım. Special Topics on Computer Networks, Bilgisayar Ağlarında Güvenlik, Advance Algorithm Analysis, System Modelling and Simulations derslerini seçtim. Tabi alttan Bilgisayar Mimarileri dersi de mevcut. :) Bu dönem okul ile ilişiğimi bitirme niyetindeyim, umarım başarabilirim. :)

2 gündür adeta inzivaya çekildim. Bilgisayarı sadece eğlence aracı olarak kullandım. Enrico Macias'ın L'Oriental albümünün tamamını dinledim. Bir kısmını dinlemiştim ama artık tüm albüm hakkında fikrim var. Bence dinlemelisiniz. Keza eski Türk şarkılarının orijinallerini de bu sanatçının seslendirdiğini de hatırlatırım. Onlar başlı başına bir şaheser. Benim favorilerim ve Adieu Mon Pays ve Aux talons de ses souliers.

Bir de Gökhan Kırdar'ın Go On My Heart albümünü dinleme fırsatım oldu. Herhalde yorum yapmaya gerek bile yoktur. Türkiye'de sanatçı diyebileceğim nadir insanlardan. Dayan Kalbim şarkısının farklı farklı versiyonlarını seslendirmiş. Tek tek çıkıyor şarkıları ama süperler. Ayrılık Neye Yarar parçası da muhteşemdi, bundan önce çıkan.

2 günde bir de kitap bitirme fırsatım oldu. Şu meşhur Olasılıksız (Adam Fawer) kitabını okudum. Fena bir kitap değildi, reklamı da iyi yapıldığı için tutmuş biraz. Daha önce bundan çok çok iyilerini okuduğum için "süperdi" diyemem. Hele benim gibi tarih kitaplarından hoşlanan birisi için bu normal bir durum olsa gerek. :)

Şu anda State Management - 4 makalesine ufaktan başladım Farid Farjad eşliğinde. :) Session hakkında yazıyorum ama hiç bir şeyi atlamamak için her noktayı açıklamaya çalışıyorum. Bu yüzden kağıt üzerinde kabataslak başladım. İnanıyorum ki, bu seri bittiğinde Türkçe State Management (Durum Yönetimi) makalesi açığı kalmayacak. Bu konuda cidden iddialıyım. :) Ancak haftasonundan önce bitmez çünkü SD kartlar için Güncelleme yapacak bir programa da başlayacağım yarın.

Yazı uzadı, burada sonlansın artık. Hoşça kalın..

21 Şubat 2009 Cumartesi

Türk Eğitim Sistemine Vurulan Kilit



Kurtuluş savaşının sona ermesiyle ülkenin tüm eksik yönlerini gören ve bunları yenilemek, değiştirmek için işe koyulan Ulu Önder Mustafa Kemal Atatürk, eğitime verdiği önemi birçok yerde dile getirmiştir. Bunlardan birkaçını paylaşmak istiyorum.

“Yetişecek çocuklarımıza ve gençlerimize, görecekleri öğrenimin sınırları ne olursa olsun, ilk önce ve her şeyden önce Türkiye’nin bağımsızlığına, kendi benliğine, milli geleneklerine düşman olan bütün unsurlarla mücadele etmek gereği öğretilmelidir. Dünyada uluslararası duruma göre böyle bir mücadelenin gerektirdiği manevi unsurlara sahip olmayan kişiler ve bu nitelikte kişilerden oluşan toplumlara yaşam ve bağımsızlık hakkı yoktur.”(1)

“İlk ve orta öğretim mutlaka insanlığın ve uygarlığın gerektirdiği bilimi ve tekniği versin, fakat o kadar pratik bir tarzda versin ki çocuk okuldan çıktığı zaman aç kalmaya mahkûm olmadığına emin olsun.”(2)

Kurtuluş savaşının en yoğun olduğu dönemde öğretmenler kurultayı yapılacakken ülkenin zor durumda olduğu düşünülerek, kurultayın ertelenmesi düşüncesi oluşur. Atatürk bu düşünceye karşı çıkarak: “Bu kurultayı ertelemeyin, ben de gelip konuşma yapacağım” der, kurultaya katılır ve özetle şunları söyler: Biz ülkeyi düşmandan kurtarmak için varımızla yoğumuzla savaşıyoruz, sizler yani öğretmenler asıl savaş sizin cehalete karşı yapacağınız savaştır. Asıl savaşımız, kurtuluş savaşımız bittikten sonra başlayacaktır. Cahillik yok edilmedikçe ancak yerimizde sayarız.

Atatürk, 20 yıla yakın sürede eğitimin en iyi duruma gelmesini sağlamış, canla başla bu uğurda savaşmıştır. Bu konuda çok çalışmıştır. Neden? Çünkü yukarıda yer verdiğim sözünde ne diyordu: “Asıl savaş cehalete karşı verilen savaştır. Cahillik yok edilmedikçe vermiş olduğumuz silahlı savaşın bir yararı olmayacaktır.” Bu yerine getirilmezse “Tarih tekerrürden ibarettir” savı da yeniden gerçekleşecektir. Atatürk döneminde en iyi duruma getirilen Türk eğitimi, ne yazık ki Ulu Önder’in yaşama gözlerini yummasıyla yeteneksiz, Türklükten uzak bireylerin yönetime gelmesi ve bunların yanlışları arkalığında gerilemiştir.

Bu söylemlerden anlaşılacağı üzere Türk çocuğunun 1938’den bu yana içi boşaltılan, dış güçlere teslim edilen eğitimle Osmanlının son 300 yılındaki duruma çekilmek istenmesi de acı bir gerçektir. Şimdi ulusal profesörümüz Oktay Sinanoğlu’nun da sıklıkla dile getirdiği 1949 yılında kurulan Türk-Abd eğitim komisyonundan söz etmek istiyorum. Öncelikle Oktay Sinanoğlu’nun söz ettiği bilgiyi aktarayım. “Küreselleşme olarak adlandırılan Yeni Dünya Düzeni, büyük bir aldatmacadır. Abd-İngiliz örgütleri, 1950’den bu yana Türkiye’de etkinlikte bulunmaktadırlar. Türkiye’de bu örgütün çalışmaları sonucu yabancı dilde eğitim ihaneti başlamış, kolejler açılmıştır. Bu yıllardan sonra Türkiye sömürge olmuş, üniversiteler bilim adamı yetiştiremez hale gelmiştir. İlk işgal ve ihanet Türkçeye saldırıyla başlamıştır.”(3)

Buradan sonra açılımını yapalım bu işgal meselesinin: 27 Aralık 1949 tarihinde Türkiye ve ABD hükümetleri arasında “Eğitim Komisyonu” kurulmuştur. Dört Türk, dört Amerikalı üyeden oluşan komisyon, ülkemizdeki eğitim kurumlarında yabancı dilde eğitim verilmesi kararını almıştır. Ayrıca komisyona ABD’li birisi başkanlık edecektir. Bu başkanın da oy kullanma hakkı olacaktır!.. Yani 5 ABD’liye karşılık 4 Türk üye. Komisyonun adı: Türkiye’de Birleşik Devletler Eğitim Komisyonu’dur.(Fulbright)

Bu komisyon Türkiye Cumhuriyeti’nin sağladığı parayla uygulamalarını yürütecektir. Komisyon, Türk eğitimini düzenlemek üzere Türkiye Cumhuriyeti ve Abd hükümeti tarafından tanınmıştır. Komisyon karar ve davranışlarında ABD Dışişleri Bakanına karşı sorumludur. Türk Hükümetinin himayesinde, her türlü Türk denetiminin dışındadır. Türk Eğitimi hakkında araştırma yapması, bilgi toplaması, gerekli Amerikan memurlarını uzman ve araştırmacı olarak okul, üniversite ve Bakanlıklara yerleştirmesi ve benzeri etkinliklerini kolaylaştırmak amacını sağlamak için bu komisyon kurdurulmuştur.

Türk Hükümetine bu komisyonun çalışmalarını kontrol ve denetleme hakkı dahi verilmemiştir. Bu özellik göz önüne alındığında Türk milletinin aile yapısı, Türk çocuğunun öğrenme yapısı, kültür yapımız, ilköğretim-lise müfredatından ağır ağır kısırlaştırma yöntemiyle çıkarılmış, yerine bizimle uyumlu olmayan, Batı’nın onlarca yıl önce vazgeçtiği yöntemler hiç denenmeden –kabaca- pat! diye çocuklarımızın önüne konulmuştur. Kendisine, kültürüne, yapısına uymayan bir eğitim-öğretim yöntemiyle karşılaşan Türk çocuğu, süreyle hedefsiz, bilinçsiz, özentili, işine yaramayan bir sürü yığınla kafası dolmuş olarak yaşama girmiştir. İşsizlik, beklentisizlik, ulusal varlığa düşmanlıkta bulunan ögelere kan uykusundaymış görünümünde ses çıkartamama durumları işte bu 50-60 yılda gerçekleşmiştir. Türk toplumu, yıllar geçtikçe ABD’nin istediği tüketim toplumuna dönüşmüştür. Atatürk ilkeleri başta olmak üzere tarihimiz, atalarımız, edebiyat alanındaki başyapıtlarımız bir bir eğitim müfredatımızdan çıkarılmıştır. Bunun sonucunda tarihini bilmeyen, atasını tanımayan, Atatürk’ü özümseyememiş, geleceğinden haberi olmayan, ulusal varlığa düşman olan ögelerle mücadelenin ne olduğunu bilmeyen bir millet ortaya çıkmıştır. Bunun yanında yukarıda sözünü ettiğimiz yabancı dille eğitim yöntemi ve bunun yanında açılan kolejler Türk eğitimine, Türk çocuğuna, Türkçeye balta vurmuş, üçünü de geleneklerinden, toplumundan, özünden uzaklaştırmıştır. Benliğinden uzaklaşan değerlerin yerini ise yabancılıkla doldurmuşlardır. En büyük ihanetlerden birisi de komisyonun almış olduğu yabancı dilde eğitim kararıdır. Yabancı dilde eğitim ihanetini ve yanlışlığını bir sonraki yazımda açıklamaya çalışacağım.

Sağlıcakla kalın.

Şahin Durmuş

En önemli ve verimli vazifelerimiz milli eğitim işleridir. Milli eğitim işlerinde kesinlikle zafere ulaşmak gerek. Bir milletin gerçek kurtuluşu ancak bu yolla olur.

Ulu Önder Gazi Mustafa Kemal Atatürk

(1)- (1922)- Atatürk’ün Söylev ve Demeçleri, Cilt:I, 1945
(2)- Gazi’nin Nutuklarından Alınmış Vecizeler, Muhit Mecmuası, No:32, 1931
(3)- SİNANOĞLU Oktay, Büyük Uyanış, Alfa Yayınevi, 13. Basım, Sayfa: 112, 113 (Haziran 2006)

16 Şubat 2009 Pazartesi

Uyku Molası

Yarın için uyumam lazım. Kendim için değil yani. :) Bu yüzden bu kadar girdi bu sayfaya çok bile. Ne de olsa Google'dan alan alıyoruz, çok fazla yazmamak gerek. :P

Mezun olur olmaz sayfamı açıyorum arkadaşlar. Uğraşacak vaktim bile yok inanın. Hem de arka planı gümüş gibi bir renk olacak gibi. :) Siyah iyi hoş ama uğraşı istiyor. Aksi taktirde beyazdan daha fazla göz yorabiliyor. :)

İlk fırsatta Session konusunu kapsayan State Management (Durum Yönetimi) serisinin 4. makalesini yazacağım. Ve belki ilk burada yayınlarım. :)

State Management - 3

Merhaba herkese. State Management makale dizimizin 3 bölümü ile birlikteyiz.

Çok kısa diğer makaleleri hatırlatacak olursak: 1. makalede State Management kavramını ve ViewState nesnesini; 2. makalede ise Cookie nesnesini incelemiştik. Şimdi de sırada QueryStrings var.

QueryStrings:

Query String dediğimiz şey, aslında çoğumuzun sürekli karşılaştığı bir nesnedir. Query Stringler, URL'lerin sonunda gördüğümüz bilgilerdir. URL'nin sonunda ne var, hangisi query string? Somut bir örnekle bu konuyu daha yakından inceleyelim.

Diyelim ki bir şeyler sipariş etmek için "Yemek Sepeti"ne girdiniz(www.yemeksepeti.com). Bu bir URL(Uniform Resource Locator)'dir. Sayfada İstanbul'u seçtiğinizde adres çubuğundaki URL http://www.yemeksepeti.com/index.asp?city=215 şekline dönüşüyor. Malumunuz index.aspx, default.asp vs. ana sayfayı gösterir. İşte ? işareti query stringimizi başlatmış oluyor. Bu yüzden yukarıda karşılaştığımız nesnedir diye bir ifade kullandım. City diye bir özellik var ve bu özelliğe 215 değeri verilmiş. Gördüğünüz gibi çok basit bir şekilde durum bilgisini tutmuş.

Son bir örnek daha, Google'da bir şey aratınız diyelim. Ben "Beşiktaş"ımı arattım. http://www.google.com.tr/search?hl=tr&q=Be%FEikta%FE&btnG=Google%27da+Ara&meta= şeklinde bir link yazıldı adres çubuğuna. Linkte geçen hl=tr yerine hl=en yazdığınızda Google'ın İngilizce sayfasına yönlendiğinizi göreceksiniz. q'nun(query; yani sorgulattığınız, arattığınız kelime) karşılığı olarak da başka bir şey yazıp aratabilirsiniz.

Query Stringlerde sayfa oluşurken dışarıden parametre yolluyoruz. URL yoluyla veriyi mevcut sayfaya veya başka bir sayfaya taşıyoruz.
Avantajları
1. Herhangi bir server kaynağına ihtiyaç yoktur. Direkt URL üzerinden taşıma yapılıyor.
2. Tüm tarayıcıların desteklemesi.
3. Kolay uygulanabilir olması.
Dezavantajları
1. Güvensiz olması. Gördüğünüz gibi açık seçik kullanıcının gözü önünde her şey. Ayrıca query stringe yazdığınız şey direkt sorguya gidiyor.
2. Kapasite sınırı. Bazı tarayıcıların, URL'lere 2083 karaktere kadar izin verdiği belirtiliyor.

Query Stringlerde, sayfa aynı ancak içerik query string değerine göre değişiyor. Bu sebepten aynı sayfadan istekte bulunurken kullanmak mantıklıdır. Bunun da iyice anlaşılması için örnek ile açıklayayım. Diyelim ki bir türlü yayınlamadığım sayfamı yayınladım ve resimler ekledim. :) www.gurkanalkan.com/galeri/sacmaresimler.aspx?resim=1 diye bir sayfada resim çıkmış olsun. Siz "ileri"ye bastığınızda bunun www.gurkanalkan.com/galeri/ sacmaresimler.aspx ?resim=2 haline geldiğini gördünüz. Burada resim değişti. Bakın sayfa aynı. Siz, "sonraki resim" seçeneğine tıklayarak bana dışarıdan parametre veriyorsunuz aslında. 2 numaralı resmi istediniz. Ben de size sadece oradaki resim yerine 2 numaralı resmi verdim. Yani değişen şey resimdir. Herhalde anlaşılmıştır bu nokta da.

Arkadaşlar biraz daha ilerlemeden önce bir şeyi belirtmek istiyorum. Verdiğim örnekler hep bir özellike ve değer içeriyordu. Böyle bir kısıtlama yok. Asıl kısıtlamanın tarayıcıdan kaynaklı 2083 karakter olduğunu belirtmiştik. Yani siz birden çok özellik ve değer kullanabilirsiniz. Örneğin; https://www.google.com/accounts/ServiceLogin?service=mail&passive=true&rm=false şeklinde devam eden google sayfası. Böyle birden çok özellik söz konusu olduğunda & ile ayırıyoruz.

İsterseniz küçük bir örnek yapalım. Bir web projesi açalım. Adı Default.aspx olarak kalsın. İşlemlerimizi hızlı yapmak için Design ekranına bir adet TextBox ve bir adet de Button koyalım. Ardından 2. bir sayfa ekleyelim projemize. Onun da adı Default2.aspx olarak kalsın.

İlk sayfamıza (Default.aspx) koyduğumuz Button'a basınca, TextBox'a yazmış olduğumuz değeri Default2.aspx saysına taşıyalım.

protected void Button1_Click(object sender, EventArgs e)
{
Response.Redirect("Default2.aspx?isim="+TextBox1.Text);
}

Yukarıda gördüğünüz gibi Button'a basınca sayfamızı Default2.aspx'e yönlendir dedik, ancak isim adlı özellik(query string'de özellik dediğimizi hatırlayın) ve değer olarak da TextBox'ta yazan değer ile birlikte gidecek.
Default2.aspx sayfasında da aşağıdaki gibi bir kod yazalım.
protected void Page_Load(object sender, EventArgs e)
{
Response.Write(Request.QueryString.Get("isim"));
}

Query String ile taşıdığımız değeri sayfaya yazdırmış olduk. Query Stringler kullanıcılar tarafından belirlenen ifadelerdir. Yani query stringleri kullanıcı gönderir. Bu yüzden query string okurken Request'i kullanıyoruz. Request.QueryString.Get deyip parametresine querystring'in özelliğinin adını geçiyoruz.

Msdn'den baktıysanız ya da QueryString'in açıklamasına göz attıysanız:

public NameValueCollection QueryString { get; }

gibi bir ifade görmüşsünüzdür. Bu QueryString'in NameValueCollection (2.makalemizde de sıkça geçmişti.) türünden bir "property" olduğunu söylemektedir.
Bunula ilgili bir örnek yapacak olursak:

int loop1, loop2;

NameValueCollection coll=Request.QueryString;
String[] arr1 = coll.AllKeys;
for (loop1 = 0; loop1 <>
{
Response.Write("Key: " + Server.HtmlEncode(arr1[loop1]) + "
");

String[] arr2 = coll.GetValues(arr1[loop1]);
for (loop2 = 0; loop2 <>
{
Response.Write("Value " + loop2 + ": " + Server.HtmlEncode(arr2[loop2]) + "
");

}
}

State Management-2'yi okuyanlar için herhalde gayet açık bir koddur. Hatırlarsanız NameValueCollection'ın bir key- value çifti olduğundan bahsetmiştik. AllKeys property'si cookie'de değindiğimiz gibi bize string dizisi dönen bir özellikti. Yukarıdaki örnek kodda da önce anahtarları (bizim özellik diye bahsettiğimiz şey), bir string diziye atmış. Daha sonra döngüde değerleriyle birlikte bu anahtarları da yazdırıyoruz.

Query String'e girmişken bir konuya daha değinmek istiyorum: Server.Transfer

Server.Transfer, Response.Redirect ile benzer işleve sahiptir. Karşılaştırmalı bakalım isterseniz.
Response.Redirect deyince siz browser'a verilerinizi gönderiyorsunuz ve server'dan "request"te bulunup diğer sayafaya verileri taşıyorsunuz. Server.Transfer ile bunu yaptığınızda göze çarpan ilk fark URL'nin sabit kalmasıdır. Buna mukabil Query String de görünmemektedir.

İlk yaptığımız örnekte ButtonClick'teki Response.Redirect kodu yerine aşağıdaki satırı yazın ve tekrar çalıştırın.
Server.Transfer("Default2.aspx?isim="+TextBox1.Text, true);
Buttona tıkladıktan sonra aşağıdaki sayfanın URL adresine dikkat buyurun.

Server.Transfer kullanımındaki bir diğer farklılık, bu yöntemle server'ın kaynaklarının korunmasıdır. Bu yöntemle tek bir request ile işlerinizi yapabilmektesiniz. Response.Redirect kullanırken iki request yapıyorduk. Dolayısıyla Server.Transfer kullanmak server'ın performansı arttırdığı gibi, uygulamamızı da hızlandıracaktır. Ancak buradaki önemli nokta, Server.Transfer'deki transfer olayı aynı site içerisinde çalışmaktadır. Farklı bir alan için Response.Redirect kullanmak durumundasınız.

Server.Transfer'in dikkat ettiyseniz 2. bir parametresi var. Yukarıda kasıtlı olarak değinmedim. Bu parametre bool preserverForm. Bunu true yaparsanız, transferi yaptığınız sayafan da query sring ve form değişkenlerine erişebilirsiniz. WebForm1.aspx diye bir sayfanızdan WebForm2'ye transfer yapacaksınız diyelim. Ve WebForm1 sayfanızda TextBox1 adında bir textbox var olsun. WebForm2'den buna Request.Form("TextBox1") diyerek erişebilirsiniz.

Server.Transfer'de çıkabilecek bir sorun var: "The View State is invalid for this page and might be corrupted" diye bir hata almanız mümkün. Asp.Net'te varsayılan olarak EnableViewStateMac true olarak ayarlanmıştır. Bu özelliği State Management-1 makalemizde hatırlarsanız incelemiştik. Çok fazla detaya girmeyeceğim o yüzden. Bu özellik true iken MAC doğrulama mekanizması çalışıyordu. Server.Transfer dediğinizde bu Mac mekanizması devre dışı kalabiliyor. ViewState'in sayfalar arasında transfer edilemeyeceğini burada da hatırlatalım. Dolayısıyla MAC çalışamaz. Bunu aşmak için bu özelliği false yapmalısınız. (Daha sonra tekrar true yapabilirsiniz.)

Kısaca Smart 404 diye bilinen hata sayfalarına da değineceğim arkadaşlar. Query Stringlerin URL'de göründüğünü ve dışarıdan müdaheleye açık olduğunu sanırım anladınız. Kullanıcıların sitelerin güvenliği konusunda çok meraklı olduğunu göz önüne alırsak bu kötü bir durum. :) Eğer Query String'e olmayan ya da alfanümerik karakterlerden oluşan bir değer girilmişse kullanıcıları 404 durum kodlu hata sayfalarına yönlendirebilirsiniz. Ya da.. İşte ya da deyince akla Smart 404 geliyor. :) Böyle adlandırıldığı için bu ismi kullanıyorum ama adı kimsenin gözünü korkutmasın. Bu sayfalar, doğru girilmeyen query stringlerde kullanıcıya daha düzgün bilgiler verirler. Hatta bazıları daha da ileri giderek, kullanıcının girdiği query string'e yakın sonucu açar veyahut sonuçları listeler. Bunu uygulayan en önemli sitelerden birisi de www.amazon.com . Yanlış bir query verirseniz URL'sine: "Looking for something?
We're sorry. The Web address you entered is not a functioning page on our site" diye bir sayfa ile sizi karşılar. Bir süre önce de "Sorry, you didn't find what you are looking for. Did you mean ........?" deyip size alternatiflerinizi sıralardı. Ki web uygulamalarında hata sayfalarını yönetmenin ne kadar önemli olduğunu takdir edersiniz.

Böylelikle "Client-Based State Manegement"ı bitirdik arkadaşlar. Bundan sonraki makale ya da makalelerimizde Session ve Application'ı inceleyeceğiz.
Görüşmek üzere..

Gürkan Alkan
İstanbul Üniversitesi Bilgisayar Mühendisliği

Kaynaklar:
1. http://support.microsoft.com/default.aspx?id=kb;en-us;Q316920
2. http://www.developer.com/net/asp/article.php/3299641
3. http://msdn.microsoft.com/en-us/library/system.web.httprequest.querystring.aspx
4. http://msdn.microsoft.com/en-us/library/z1hkazw7.aspx

State Management - 2

Merhaba bir kez daha herkese. State Management konulu makalemizin ikinci bölümü ile kaldığımız yerden devam edeceğiz.

İlk bölümde State Management'ın ne demek olduğunu, neden ihtiyaç duyulduğunu incelemiş, ViewState konusunu ele almıştık. Şimdi ise diğer nesnelerimize değineceğiz. Cookie ile başlayalım isterseniz.

Cookies: Cookie, kelime anlamı olarak çerez. :) Nedir bu cookieler? Cookieler, kullanıcılar hakkında bilgileri saklayan zararsız dosyalardır. Server tarafından kullanıcının bilgisayarına gönderilir. Aslında bu en basit haliyle böyle. Birazdan tüm detaylarına gireceğiz. Ancak bu kavramı anlamanız için somut bir kaç örnek vermek istiyorum.

Örneğin bir bir foruma üyesiniz. Foruma en son ne zaman geldiğiniz, siz yokken hangi mesajlar atılmış cookie ile görülebilir. Cookie'den geliş tarihiniz bulunur ve uygun işlem yapılır. Başka bir örnek verelim. E-Posta hesaplarında "Beni Hatırla" seçeneği var. Beni Hatırla seçeneğini aktifleştirirseniz, o da örneğin cookie yardımıyla sizi tanır. Arkadaşlar dikkatinizi çekerim, bu verdiğim örneklerde cookie kullanımı çok yaygın demiyorum. Sadece cookie ile de olur diyorum. Mesela online alışverişteki alışveriş sepeti uygulaması. Siz siteden çıksanız da sepetiniz bir sonraki açılışta hala orada durur. Cookie ile bunu yapmak pek akıllıca değil(sebebini makaleyi okudukça anlayacaksınız), genelde de yapılmaz ama mantığını anlamanız açısından size fikir verecektir.

Cookie hakkında kafanızda bir şeyler canlandıysa şayet şimdi bir adım öteye gidip, genel yapısını inceleyelim. Kullanıcı herhangi bir siteye girdi diyelim. Sizin sitenize girmiş olsun. Siz, sitenizden ona cookie'yi atarsınız(Response ile atabilirsiniz, çünkü hatırlarsanız ASP.Net'te server'dan dönen cevap response idi, bu yüzden cookie'yi yazarken response nesnesinden yardım alabiliriz.). Farzı misal kullanıcı sitenize tekrar girmeye karar verdi.URL'yi girdiği zaman, kullanıcının tarayıcısı(IE, Mozilla, Opera, Chrome vs.) da sitenize cookie'yi atar. Yani sizin kullanıcının bilgisayarına attığınız cookieyi, kullanıcının tarayıcısı yardımıyla geri alırsınız(Request ile alabilirsiniz, yine hatırlarsanız ASP.Net't client'tan giden istek Request idi, bu yüzden cookie'yi aldığımızda request nesnesinden yardım alabiliriz.). Yalnız tarayıcı URL ile ilgili cookie varsa, bulursa atar. Yoksa, atamaz. Böylelikle siz, sitenize gelen kullanıcı ile ilgili bazı bilgileri edinmiş olursunuz.
Kullanıcının siteden hangi sayfayı istediği normalde önemli değildir. Aslında önemli olduğu durumlar var ancak buna da makalemizin ilerleyen satırlarında değineceğiz. Standart olarak, cookie siteniz ile ilşkilidir, sitenizdeki bir sayfa ile değil(İsterseniz farklı ilişkiler de yaratabilirsiniz. Birazdan birlikte yaratacağız zaten.).

Çoğu tarayıcılar 4096 byte'a kadar cookie destekler. Bu küçük limit yüzünden, cookielerde küçük veriler saklamak uygundur. Tarayıcılar, bir siteden kullanıcının ne kadar cookie alacağını da belirlerler. Bir çok tarayıcı site başına 20 cookie'ye izin veriyor. Eğer siteniz daha fazlasını gönderirse eski cookieler sırasıyla silinmiş olur. Ancak bir kısım tarayıcılar da genel bir limit belirliyor, ki genelde 300 cookie oluyor bu limit, site bazında değil de tüm sitelerden gelen cookie sayısına göre saklıyorlar.

Cookie sınırlandırmalarında en büyük sorun ise kullanıcının tarayıcı ayarlarından cookie alımını engellemesidir. Gerçi bazı yazılımcılar, cookie'yi reddediyorsa siteme girmesin, de diyebilmekte. ? Dolayısıyla yararlı da olsa uygulamalarınız cookielere bağımlı olmamalıdır. Alternatif yollarınız mutlaka olmalıdır. Veyahut diğer yöntemlerle verilerini taşıyıp, saklarsınız. Kritik verilerde cookie kullanmamanız gerektiğini de herhalde fark etmişsinizdir. Bu konuya birazdan tekrar gireceğim. Tarayıcı ayarlarında yapılacak değişiklikler her zaman güçlük yaratır dedik. Bu sorunu aşabilmenin bir yolu da sitenizde P3P(Platform for Privacy Preferences Project) tanımlamaktır. Bu sayede, tarayıcılarında belli policy ayarları yapmış kullanıcılar, policy ihlallerinde derhal uyarılır ve siteye girmeyebilirler. Bu durumu sağladığınızda tarayıcılar sitenizden cookie alımı yapabilirler.

Cookie Yazma
İsterseniz şimdi cookie yazma olayına geçelim. Cookieler, kullanıcıların tarayıcılarına (yukarıda bahsettiğim sebeplerden dolayı) HttpResponse nesnesi ile yollanırlar, ki bu nesnenin de Cookies adında bir koleksiyonu vardır. HttpResponse nesnesine Page sınıfımızın(yani sayfamızın), Response property'si ile ulaşabiliriz. Sitenizden, kullanıcının harddiskinde depolanmak üzere, tarayıcıya gönderilen her cookie'yi Cookies koleksiyonuna eklemelisiniz.

Cookie yaratınca bir Name ve Value vermelisiniz. Mantıksal olarak anlamanız için ViewState'te bahsettiğim(State Management-1 Makalesi) HashTable yapısı gibi düşüneblirsiniz. Cookie'nin de "Name"i unique(eşsiz,tek) olmalı. Bu sayede direkt o isme tekabül eden değeri de bulabiliriz. Siz kazara aynı isimde 2 cookie yaratırsanız, birini diğerinin üstüne yazar. Bunlardan başka Cookie'nin yaşam süresini de belirleyebilirsiniz(expiration date and time). Mesela bir cookie'nin expiration date'ini 10 gün olarak ayarlarsanız, kullanıcı 10 gün boyunca o siteye girmezse cookie silinir. Kullanıcının siteye son girişinden itibaren 10 gün dikkate alınır çünkü. Şimdi diyebilirsiniz cookie'nin ömrünü uzun tutarım diye ama bunun da %100 garantisi yok çünkü kullanıcının canı sıkılır ve gider tüm cookieleri siler. :) Bu yüzden cookielerde öenmli şeyler taşınmamalı demiştik yukarıda.

Eğer cookie'nin expiration time'ını ayarlamazsanız, cookie yaratılır fakat kullanıcının bilgisayarında saklanmaz. Daha sonra göreceğimiz Session gibi varlığını sürdürür. Kullanıcı tarayıcısını kapatırsa cookie de gider. Bu yüzden expiration time'ını ayarlamayı unutmamalısınız. Ancak bu şekilde kullanılabilecek cookieler de işe yarayabilir; ya da kullanıcının bilgisyaraına cookie yazmayı güvenli bulmayabilirsiniz. Bu durumlarda Expiration Time değerine girmez ve kalıcı olmayan cookieler yaratırsınız. Örneğin ortak kullanılan bir bilgisayarınız vardır, girdiğiniz sitelerin cookiesini istemeyebilirsiniz.

Cookieleri eklemenin yollarından iki tanesine bakalım şimdi:
Response.Cookies["userName"].Value = "gurkan";
Response.Cookies["userName"].Expires = DateTime.Now.AddDays(1);

Yukarıdaki yol ile Cookilere direkt değer verebilirsiniz. Cookieler, NameObjectCollectionBase'den türedikleri için bu şekilde değer verilebilirler. UserName adında bir cookie yaratılıyor ve ona değer olarak gurkan veriliyor. Eğer o siteye 1 gün içinde tekrar girmezseniz cookie siliniyor.

HttpCookie cerez = new HttpCookie("lastVisit");
cerez.Value = DateTime.Now.ToString();
cerez.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cerez);

Yukarıdaki yol ile de cookie'yi yaratmak için HttpCookie sınıfını kullandık. Bu şekilde kullanmak için constructor içinde cookie adını belirtmek zorundayız. Dikkat edilmesi gereken nokta: tüm cookie değerleri string olmak zorundadır. Expiration ise DateTime türünde olmalıdır.

Birden Fazla Değeri Olan Cookie Olur mu?

Yukarıdaki örneklerde de gördüğünüz üzere her cookie'de bir değer sakladık. Ancak bir cookie'de birden fazla name-value çifti saklayabilirsiniz. Name-Value çiftleri subkeys olarak adlandırılırlar. Örneğin; "username" ve"lastvisit" adında 2 farklı cookie saklamak yerine, "userInfo" adında tek bir cookie yaratabiliriz. "username" ve"lastvisit" adında da subkey'leri olur.
Subkey kullanmanın birçok sebebi olabilir. Öncelikle birbiriyle ilişkili bilgileri tek bir cookie'ye koymak gayet güzel bir düşüncedir. Bunun dışında mesela hepsine birden expiration süresini atayabilirsiniz (Tersten düşünürsek, eğer hepsine farklı farklı süreler atayacaksak, ayrı ayrı cookieler kullanmak daha mantıklıdır). Ayrıca tarayıcıların limitlendirmelerini de bir nebze olsun aşabiliriz bu yolla.

Subkeys ile cookie yaratmak için yine 2 yolu da görelim:
Response.Cookies["userInfo"]["userName"] = "gurkan";
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);

Yukarıdaki örnekte önceki örnektekilerin aynısı yapılıyor ama gördüğünüz gibi userinfo'nun alt anahtarları olarak kullandık username ve lastvisit'i.

HttpCookie cerez = new HttpCookie("userInfo");
cerez.Values["userName"] = "gurkan";
cerez.Values["lastVisit"] = DateTime.Now.ToString();
cerez.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(cerez);

Yukarıdaki örnekte bir önceki örnekle aynı işi HttpCookie nesnesi yardımıyla yapmakta.

Cookie Faaliyet Alanları
Daha önce bahsettiğimiz bir konuya geri dönelim. Normalde tüm siteler kullanıcılarına cookie'yi atarlar. Kullanıcı da bu siteye request gönderirse, bu cookiler server'a gider. Siteye geri dönmüş olur. Yani başka bir deyişle: o sitedeki tüm sayfalar cookie'leri alır. Cookielerin faaliyet alanlarını 2 yolla ayarlayabilirsiniz.
1) Server'da bir klasöre erişim hakkı verirsiniz.
2) Domainlerin faaliyetlerini belirlersiniz.
Şimdi bu iki yaklaşımı da inceleyelim.

Server'da bir klasöre erişim hakkı vermek: Server'da bir klasör açarsınız ve cookie'leri alabilecek sayfaları o klasör altında tanımlarsınız. Bunu da Cookie'nin Path property'si ile ayarlarsınız.
HttpCookie cerez = new HttpCookie("AppCookie");
cerez.Value = "written " + DateTime.Now.ToString();
cerez.Expires = DateTime.Now.AddDays(1);
cerez.Path = "/Application1";
Response.Cookies.Add(cerez);
Buradaki Path, root'un altında fiziksel bir yol olabileceği gibi virtual path de olabilir. Yukarıdaki örnekte, Application1 klasörü içindeki tüm sayfalar cookielere erişebilmekte. Örneğin: www.gurkanalkan.com/Application1/... içindekiler cookileri alır. Ancak: www.gurkanalkan.com ya da www.gurkanalkan.com/Application2/... içindekiler cookilere erişemez.
(Yukarıdaki örneği diğer yol ile de yapabilirdik.)
Bazı tarayıcılarda path, büyük-küçük harfe karşı duyarlıdır. Buna dikkat edilmesi gerekir.

Domaine Scope Vermek: Bunda da domaininize göre erişim hakkı verirsiniz. Cookie'nin Domain property'si ile ayarlanır.

Response.Cookies["domain"].Value = DateTime.Now.ToString();
Response.Cookies["domain"].Expires = DateTime.Now.AddDays(1);
Response.Cookies["domain"].Domain = "support.gurkanalkan.com";

Yukarıdaki örnekte, cookielere sadece support.gurkanalkan.com subdomaini erişebilir. Diğer domainlerden erişilebilemez.
Son satırı:
Response.Cookies["domain"].Domain = "gurkanalkan.com";
şeklinde değiştirirseniz, tüm subdomainlerden erişilebilir bir hale gelmiş olur. Örneğin; "support.gurkanalkan.com", " forum.gurkanalkan.com", "thisishalloween.gurkanalkan.com" gibi tüm alt domainler erişir.


Cookie Okuma

Cookieleri HttpRequest nesnesi ile okuruz. Page sınıfımızın(sayfamız tabi ki) Request nesnesi ile de ulaşabiliriz o nesneye. Daha önce bu işlemin nasıl olduğuna değindiğim için direkt olarak kod üzerinde göstereceğim.

if(Request.Cookies["userName"] != null)
Label1.Text = Server.HtmlEncode(Request.Cookies["userName"].Value);

Yukarıdaki örnekte yine direkt işlem yapılmış. Eğer username isminde bir cookie varsa, bunun değerini label1'e yazdırıyor. HtmlEncode metodu da parametresindeki metni eğer html kodları varsa, değiştirerek komut olarak görünmemesini sağlar.

if(Request.Cookies["userName"] != null)
{
HttpCookie cerez= Request.Cookies["userName"];
Label1.Text = Server.HtmlEncode(cerez.Value);
}

Yukarıda da aynı işlemi diğer yolla yaptık.

Burada dikkat edilmesi gekeren, cookieyi okumadan önce, o cookienin var olduğundan emin olmaktır. Eğer bunu kontrol etmezsek ve okumaya çalıştığımız cookie yoksa(mesela anahtarını[ismini] yanlış yazmışızdır.) NullReferenceException alırız.
HtmlEncode ile de encode yaparak, kötü niyetli kullanıcıların cookie üzerinde oynama yapmamalarını sağlıyoruz.
Farklı tarayıcılar cookieleri farklı şekillerde saklarlar. Aynı makinadaki farklı tarayıcılar bile birbirlerinin cookielerini okuyamazlar. Örneğin IE'nin sakladığı cookielere Mozilla'dan erişemezsin.

Subkey'i olan bir cookiden okuma yapalım.

if(Request.Cookies["userInfo"] != null)
{
Label1.Text =
Server.HtmlEncode(Request.Cookies["userInfo"]["userName"]);

Label2.Text =
Server.HtmlEncode(Request.Cookies["userInfo"]["lastVisit"]);
}

Gördüğünüz gibi yine önce böyle bir cookienin var olup olmadığına bakıyoruz. Daha sonra da cookie yazma konusunda da gördüğümüz yöntemi kullanarak bu sefer okuma yapıyoruz.
"lastvisit"i daha önce DateTime türünde kullanmıştık. Ancak cookieler string değer tuttuklarından yukarıdaki gibi kullanılmış.

DateTime dt;
dt = DateTime.Parse(Request.Cookies["userInfo"]["lastVisit"]);
şeklinde de değiştirebiliriz.

Daha önce de bahsettiğim gibi subkey'ler NameValueCollection idi. Yani bir koleksiyon. Dolayısıyla bu koleksiyondan subkeyi farklı bir şekilde de alabiliriz. (Name'inden value'sini ayırırız)

if(Request.Cookies["userInfo"] != null)
{
System.Collections.Specialized.NameValueCollection
UserInfoCookieCollection;

UserInfoCookieCollection = Request.Cookies["userInfo"].Values;
Label1.Text =
Server.HtmlEncode(UserInfoCookieCollection["userName"]);
Label2.Text =
Server.HtmlEncode(UserInfoCookieCollection["lastVisit"]);
}


"Expiration Date"i Değiştirmek

Tarayıcıların cookieleri yönetmekten sorumlu olduğunu söylemiştik(Server ile cookile alışverişi, bilgisayara yerleştirmesine izin vermes, vermemesi, limitlendirmeleri). Cookienin expiration time ve date'i de tarayıcya bu konularda yardım eder(saklanmaları, silinmeleri vs.). Dolayısıyla siz cookienin Name ve Value'suna erişip okuyabilirken, expiration Time ve Date'ini okuyamazsınız.
Tarayıcı, server'a cookie'yi yollarken, expiration bilgisini göndermez(sıfır değeri döndürür). Eğer cookienin expiration date'i ile ilgili şüpheleriz varsa cookie'yi değiştirebilirsiniz. (Birazdan cookie değiştirme konusuna da değineceğiz.)


Cookie Koleksiyonunu Okumak

Bazen sayfanızda geçerli olan tüm cookieleri okumak durumunda kalabilirsiniz. Aşağıdaki kod örneği de bu durumlar içindir.

System.Text.StringBuilder output = new System.Text.StringBuilder();
HttpCookie cerez;
for(int i=0; i
{
cerez = Request.Cookies[i];
output.Append("Cookie name = " + Server.HtmlEncode(cerez.Name)
+ "
");

output.Append("Cookie value = " + Server.HtmlEncode(cerez.Value)
+ "

");

}
Label1.Text = output.ToString();


Yukarıdaki örneğin bir problemi var. Eğer cookielerin subkeyleri varsa, subkeyler tek bir name/value stringi şeklinde görünecektir.

Subkey'in olup olmadığını anlamak için HasKeys property'si kullanılır. Eğer varsa; subkey koleksiyonunu, ayrı ayrı subkey name ve value'ları şeklinde okuyabilirsiniz. Subkey value'larını Values koleksiyonundan indeks ile direkt okuyabilirsiniz.Value'ların isimlerine de Values koleksiyonunun AllKeys property'si ile okuyabilirsiniz. Bu size bir string dizisi dönecektir. Aynı şekilde Name'leri Keys property'si ile de okuyabilirsiniz. Bu da size bir string dizisi döner. Ancak aralarında bir fark var. AllKeys ile isimler siteye ilk erişimden sonra cachelenir(önbellekleme) . Keys ile isimler siteye her erişimde tekrar tekrar bulunur. Bu yüzden şartlara göre her ikisini de kullanmak avantajlı olabilir.

Şimdi bir önceki örneği subkey durumunu kontrol edecek şekilde değiştirelim.

System.Text.StringBuilder output = new System.Text.StringBuilder();
HttpCookie cerez;
string subkeyName,subkeyValue;
for(int i=0; i
{
cerez = Request.Cookies[i];
output.Append("Name = " + cerez.Name + "
");

if(cerez.HasKeys)
{
for(int j=0; j
{
subkeyName = Server.HtmlEncode(cerez.Values.AllKeys[j]);
subkeyValue = Server.HtmlEncode(cerez.Values[j]);
output.Append("Subkey name = " + subkeyName + "
");

output.Append("Subkey value = " + subkeyValue +
"

");

}
}
else
{
output.Append("Value = " + Server.HtmlEncode(cerez.Value) +
"

");

}
}
Label1.Text = output.ToString();


Yukarıdaki kodu NameValueCollection nesnesi yardımıyla da yapabilirdik.

System.Text.StringBuilder output = new System.Text.StringBuilder();
HttpCookie cerez;
string subkeyName,subkeyValue;
for(int i=0; i
{
cerez = Request.Cookies[i];
output.Append("Name = " + cerez.Name + "
");

if (cerez.HasKeys)
{
System.Collections.Specialized.NameValueCollection CookieValues =
cerez.Values;
string[] CookieValueNames = CookieValues.AllKeys;
for (int j = 0; j <>
{
subkeyName = Server.HtmlEncode(CookieValueNames[j]);
subkeyValue = Server.HtmlEncode(CookieValues[j]);
output.Append("Subkey name = " + subkeyName + "
");

output.Append("Subkey value = " + subkeyValue +
"

");

}
}
else
{
output.Append("Value = " + Server.HtmlEncode(cerez.Value) +
"

");

}
}
Label1.Text = output.ToString();


Cookieleri Değiştirme ve Silme

Bir cookieyi direkt değiştiremezsiniz. Bunun yerine, yeni bir değer verip tekrar cookieyi yaratırsınız ve onu tarayıcıya gönderirsiniz. Eskisinin üzerine yazdırmış olursunuz.
Aşağıda da örnek olarak ziyaretçi sayısını tutan bir kod mevcuttur.
int sayac;
if (Request.Cookies["counter"] == null)
sayac = 0;
else
{
sayac = int.Parse(Request.Cookies["counter"].Value);
}
sayac++;

Response.Cookies["counter"].Value = sayac.ToString();
Response.Cookies["counter"].Expires = DateTime.Now.AddDays(1);

Silme işlemine geçelim isterseniz. Silme de bir nevi değiştirme işlemidir. Cookieyi sizin direkt silmeniz mümkün değil çünkü cookie kullanıcının bilgisayarında saklı. Cookieyi siz değil, kullanıcının tarayıcısı silecek. Ama bunu siz sağlayacaksınız. Silmek istediğiniz cookie ile aynı isimde bir cookie oluşturun; ama expiration time'ını geçmiş bir tarih olarak ayarlayın. Bunu gönderin. Tarayıcı da bunu diğerinin üstüne yazacak haliyle aynı isimde olduğundan. Daha sonra da expiration time'ı dolduğu için de silecek. :)
Aşağıda örnek bir kod yer almaktadır.

HttpCookie cerez;
string cookieName;
int limit = Request.Cookies.Count;
for (int i=0; i
{
cookieName = Request.Cookies[i].Name;
cerez = new HttpCookie(cookieName);
cerez.Expires = DateTime.Now.AddDays(-1);
Response.Cookies.Add(cerez);
}

Şimdi de değiştirme ve silme işlemlerini subkeyi olan cookieler için yapalım.
Herhalde genel mantığı anlamışsınızdır. Bu yüzden değiştirme işlemini direkt kod üzerinden gösereceğim.
Response.Cookies["userInfo"]["lastVisit"] = DateTime.Now.ToString();
Response.Cookies["userInfo"].Expires = DateTime.Now.AddDays(1);


Subkeyleri silmek içinse,subkeyleri tutan Values koleksiyonunu kontrol etmelisiniz. Önce Cookies nesnesi yardımıyla yeniden oluşturmalısınız. Daha sonra Values koleksiyonunun Remove metodunu çağırmalısınız (Parametresine de silinecek subkeyin adını geçmelisiniz.). Sonra da bunu tarayıcıya yollarsanız işlem tamamlanmış olur.

string subkeyName;
subkeyName = "userName";
HttpCookie aCookie = Request.Cookies["userInfo"];
aCookie.Values.Remove(subkeyName);
aCookie.Expires = DateTime.Now.AddDays(1);
Response.Cookies.Add(aCookie);

Kısaca güvenliğine değinelim. Gerçi yazı içinde fark ettiyseniz bir-iki yerde biraz girdik bu konuya. Örneğin, kullanıcı bilgisayarından cookie'yi değiştirip size geri gönderebilir. Cookie üzerinde oynamalar olmuş olabilir. Çok fazla güvenli olmadığı için önemli bilgileri de tutmamanız gerektiğini bir kez daha hatırlatalım. Bahsedilen HtmlEncoding metodu da güvenlik konusu kapsamında düşünülebilir. Cookieler plaintext olarak gidip geldiğinden yolda(server-tarayıcı arasında) da değiştirilmiş olabilir. Bunun için SSL(Secure Sockets Layer) kullanılabilir. Kullanıcının makinasındayken SSL herhangi bir koruma sağlamaz ancak tarayıcı ile server arasında cookieyi şifreler ve cookie bu arada artık plaintext olarak değil, ciphertext olarak gidip gelir.

Son bir hususa daha değinmek istiyorum. Tarayıcılar cookieleri kabul etmeyebilirler. Eğer kullanıcı böyle bir düzenleme yaptıysa. Bu işlem sonrası, tarayıcıdan server'a herhangi bir bilgi de gitmez. Cookie yazdırılamayınca hata falan da almazsınız zaten. Ancak bunu anlamak için tek yol bir cookie yazıp okumaya çalışmak olacaktır. Son bir not: Cookies property'si size tarayıcının cookie alımına açık ya da kapalı olduğunu bildirmez. Sadece tarayıcının yapısında cookie alım özelliğinin bulunup bulunmadığını söyler.

Cookie konusu da kısaca böyle arkadaşlar. Maalesef yine State Management konusunu bitiremedim. :) Böylelikle ViewState ve Cookie'yi görmüş olduk. Diğer nesnelere de en yakın zamanda gireceğiz.

Görüşmek üzere..

Gürkan Alkan
İstanbul Üniversitesi Bilgisayar Mühendisliği

State Management - 1

Selam herkese. Aslında kafamı dağıtmaktan başka bir şey yapmadığım bu blogda, makale yayınlamak istemiyordum ancak bloga fazla ilgi gösteremeyince bari yazdıklarımı buraya da taşıyayım dedim :) Geçenlerde biri kendi yazısı gibi göstermiş bu Durum Yönetimi serimi. Okunması, paylaşılması hoş bir şey aa uğraşınızı kendi uğraşı gibi göstermesi cidden saygısızca olmuş. Neyse uyardım zaten kendisini. İyi okumalar, siyah zeminde gözleriniz daha iyi okuyacaktır. :D
----

Merhaba arkadaşlar. Bir makalemiz ile daha birlikteyiz.
Bu makalemizin konusu: State Management, yani Durum Yönetimi. Peki nedir bu Durum Yönetimi dediğimiz şey?
Siz web ortamında birer istemcisiniz(client). Siz bir web sayfasına girdiğinizde onu sunucudan istemiş oluyorsunuz. Bunu HTTP protokolü ile yaparsınız. HTTP inetinfo.exe'ye sizin çağırdığınız sayfayı söyler. Inetinfo.exe de uzantıya bakar. Uzantı aspx ise aspnet_isapi.dll'e gider ve sayfayı hazırlamasını söyler, aspnet_isapi.dll de aspnet_wp.exe'ye gider. Tüm bu işlemlerden sonra size bir cevap(response) döner. Ancak yine HTTP protokolü aracılığıyla(HTTPResponse). HTTP'nin önemini herhalde kavramışsınızdır. Ancak HTTP'nin öyle bir özelliği var ki bizleri durum yönetimi kavramına yönlendirmekte. HTTP stateless'tır. Yani önceki durumlar hakkında bilgisi yok, hiç birşeyin durumunu tutmaz. Hatırlarsanız ASP.Net server-side bir yaklaşımdı, yani değişken vs. gibi değerlerini sunucuda oluşturuyordu. ASP.NET'te bir sayfa sunucuda render edildikten sonra, yani HTML'e çevrildikten sonra, kullanıcıya gönderilir ve sunucu belleğinden silinir. Yani eski değerlere tekrar erişme gibi bir durum mümkün olmuyor. Dolayısıyla birazdan inceleyeceğimiz kavramlar ile sayfanın durumunu tutabileceğiz(yani verileri kalıcı olarak saklayabileceğiz).
En çok karşılaşacağınız 5 tanesini inceleyeceğiz.
1. ViewState
2. Cookie
3. QueryString
4. Application State
5. Session State
Yukarıdakilerden ilk 3 tanesi, bilgileri kullanıcının bilgisayarında saklamalarından mütevellit "Client-Based State Manegement" olarak isimlendirilirler. Diğer iki tanesi de bilgileri sunucuda sakladığından, "Server-Based State Management" şeklinde bilinirler.
İsterseniz bu kavramların neler olduklarını inceleyelim.
ViewState: Sayfa postback olduğunda değişen kontrol değerlerinin taşınmasını, bunların kaybolmamasını sağlar(ki hepsinin mantığı aynı sayılır). Yukarıda da değinildiği üzere bilgileri client tarafında tutuyor. Bir örnekle açıklayalım: Diyelim ki 4 tane button var. 1 milyon kişi sayfaya bağlanmış. Herkes farklı bir düğmeye basar. Biz 1. düğmeye bastık. Sonra da gidip 2. düğmeye bastık. Ancak sayfaya daha önce de 1. düğmeye bastığımızı söylemeliyiz. Evet arkadaşlar, işte tüm bu bilgileri sayfa içinde tutarız. Buradaki kilit nokta bilgilerin sayfa içinde tutulduğudur. Dolayısıyla sayfa sunucuya gidip gelirken bunları taşır. Buradan çıkarılacak önemli sonuç nedir? Sayfanızda viewstate kullanacaksanız çok büyük verileri viewstate ile tutmamalısınız. Aksi taktirde büyük performans kayıpları yaşayabilirsiniz.
ViewState'i ASP.NET otomatik olarak kontrol ediyor. Aslına bakarsanız biz pek karışmıyoruz. Ancak gerekli durumlarda müdahele ederiz. Örneğin sık sık güncellenen bir veriniz varsa bu yapıyı kullanmamanız daha iyidir.
Sayfanın kaynağını görüntülediğinizde hidden diye bir alan görebilirsiniz. gibi bir satır görürsünüz. Değeri Base64 formatında string olarak sakladığı için anlamsız gelen bazı karakterler görmektesiniz. Yalnız burada bir ayrımın altını çizeyim. Bazı yerlerde şifreli diye ifadeler geçiyor. Bu değer şifrelenmemiştir, kodlanmıştır sadece. Zaten encoded diye geçiyor, encrypt diye değil.
ViewState ile ilgili diğer önemli nokta da, ViewState'in her sayfaya özel olmasıdır. Bir sayfa diğer sayfanın viewstate'ini bilemez.
Bir diğer önemli husus da ViewState'in sayfa üzerinde yer alan kontrollerin sırasını, dizimini tutmasıdır. Bunu gözlemlemenin en güzel yolu hidden alanına bakmaktır. Visual Studio'yu açın ve design ekranına sırayla bir button, bir textbox, bir label ve bir hyperlink koyun. Bunları çalıştırın ve sayfanın kaynağına bakın.

Şimdi de bu kontrollere bazı değişiklikler yapalım ve çalıştırıp tekrar kaynağı görüntüleyelim.

Gördüğünüz gibi değer değişmedi. Her ikisinde de value aynıdır. Bizim design kısmında yaptığımız değişikler ViewState'te tutulmaz. Takdir edersiniz ki, bu tür değişiklikler zaten source içerisinde tutulmakta olduğundan bunları saklamanın da pek bir mantığı yoktur.
Şimdi biraz kafa karıştırıcı detaya girelim. ViewState başlığının ilk cümlesini tekrar buraya taşıyorum: " Sayfa postback olduğunda değişen kontrol değerlerinin taşınmasını, bunların kaybolmamasını sağlar". Postback olduğunda değişen kontrol değerlerinden bahsetmişiz. Şimdi sayfanın postback olmasını sağlayalım. Mesela buttona tıklayalım. ButtonClick eventinin içine istediğiniz kodu yazabilirsiniz. Önemli olan sayfamızı postback ettirmektir.

Gördüğünüz gibi value değişti. Yani, postback sonucunda kontrollerin değişen özellikleri de ViewState'te tutulmaktadır. Ancak msdn'de belirtildiği üzere tüm kontrollerde bu geçerli olmuyormuş. Detaylı bilgi için : http://msdn.microsoft.com/en-us/library/ms972976.aspx

ViewState varsayılan olarak aktiftir. Sayfanızın source kısmında EnableViewState özelliğini ayarlayabilirsiniz. <%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs" Inherits="_Default" EnableViewState="false" %> derseniz, sayfada ViewState kullanımını engellemiş olursunuz. Bunu sayfa genelinde değil de kontrol bazında da ayarlayabilirsiniz.


şeklinde. Bu şekilde yapmanın olumlu yanı sayfanın yükünü azaltmaktır. Böylelikle ViewState'in tutacağı değer küçülür. Ancak ViewStae'i sıkıştıradabilirsiniz. Bu konu hakkında bağlantıyı incelerseniz daha iyi fikir sahibi olacaksınız: http://www.codeproject.com/KB/viewstate/ViewStateCompression.aspx

ViewState, HashTable mantığında çalışır. Yani anahtar,veri çifti vardır. Anahtar ile veri çekilir. Object türünde veriler tutar. Ancak alışılan yöntemle, yani indekslerle değil de, anahtar vasıtasıyla verilere erişiyor. İndekste verilere tek tek bakarsınız ancak HashTable yapısında direkt olarak "şu anahtara sahip olan veriyi getir" diyorsunuz. Dolayısıyla çok daha hızlıdır. Örneğin:
ViewState["gurkan"]=1986;
şeklinde bir ifade kullanırsanız, gurkan anahtarına sahip bir veriye 1986 değerini atamış olursunuz. Her anahtar bir veriye verilmelidir. Var olan bir key'i tekrar vermek isterseniz Exception alırsınız.
Aynı şekilde:
int deger=(int)ViewState["gurkan"];
diyerek de ViewState'deki değeri bir değişkene atayabilirsiniz.

Şimdi de ViewState'in nasıl daha güvenilir bir hale getirilebileceğini inceleyelim. Daha önce de değindiğim üzere ViewState kodlanmıştı, şifrelenmemişti. Şifrelenmesini de az sonra ele alacağız ancak öncelikle kodlanmasından bahsedelim. Bu kodlamanın(Base64) uzunluğu hep 4'ün katları şeklindedir. Eğer 4'ün katı değilse, sonuna 4'ün katı olana kadar = konur. Bizim örneklerimizde de dikkat ettiyseniz sonunda = vardı, ViewState'in value'sunda. ASCII ile ilşkili bir kodlamadır ancak fazla detayına inmeyeceğim. Bu kodlama, değerlerin direkt görülebilmesini engeller. Bu yönü güzel çünkü ileride inceleyeceğimiz bazı nesnelerde direkt kullanıcının görebileceği şekilde değerler vardır. Ancak sık sık tekrarladığımız üzere bu bir şifreleme değildir ve encode edilmiş her şey, pek tabidir ki decode edilebilmektedir(Lojik devrelerdeki mantık aynen bunda da geçerlidir). Dolayısıyla pek de güvenli bir şey değildir. Eğer önemli bilgiler taşıyacaksak bu büyük bir risktir.
Daha önce Hash Fonksiyonlarını kullanan olduysa, orada Message Authentication Codes vardı. Mesajın içeriğinin yolda değiştirilmediğini ve belli bir kaynaktan çıktığını doğrulamaya yarıyordu. Hemen hemen aynı yapı burada da var: MAC. Sunucudaki ViewState değeri ile kullanıcıya gelen ViewState değerini karşılaştırıp, değişiklik yapılıp yapılmadığını kontrol eder. Eğer değişiklik varsa uyarır. Tüm bu işlemler yine otomatik olarak yapılmakta. Eğer siz gidip de EnableViewStateMac="false" demezseniz tabi. :) (EnableViewState'teki gibi yazdığınız yeri siz seçersiniz.)
Artık nasıl şifreleme yapılacağına değinme vakti geldi sanırım. Öncelikle, şifrelemek için EnableViewStateMac="true" olmalıdır. Ardından machine.config dosyanıza gibi bir ifade ile şifreleme yapabilirsiniz. Ancak şifrelemeler de %100 güvenlik anlamına gelmiyor şimdilik. Örnek olarak kullandığımız 3DES algoritması, simetrik bir algoritmadır. Dolayısıyla şifreleme için ve şifreyi çözme için aynı anahtar kullanılır. Dolayısıyla bu da güvenlik açığıdır. Herhalde tam anlamıyla güvenlikten söz edebilmek için bir kaç yıl daha bekleyeceğiz ki Quantum Kriptografi iyice gelişsin. :)
Arkadaşlar, makaleyi çok fazla uzatıp da okunurluğunu düşürmek istemiyorum. O yüzden bu yazıyı burada sonlandırıyorum. Bir sonraki makalede kaldığımız yerden devam edeceğiz.
Hoşça kalın..

Gürkan Alkan
İstanbul Üniversitesi Bilgisayar Mühendisliği

Not: Son 1 ayda e-postaların ulaşımında sorunlar yaşanıyordu ancak sorun tamamen çözülmüştür. Bilginize.
Referanslar: http://aspalliance.com/articleViewer.aspx?aId=135&pId=
http://msdn.microsoft.com/en-us/library/ms972976.aspx

15 Şubat 2009 Pazar

1 - 1 :(

4 gündür bloga girmedim. Bu süre zarfında ne oldu diye yazmadan önce az önce biten maçımızı izlemeyenlere haber ereyim: Beşiktaşımız: 1 - 1 : Ts

Tek kale maç oynadık, adamlar 1 pozisyonla golü aldılar. Yattara'nın pozisyonu dışında başka atakları yok neredeyse. Kısmetsiziz resmen. Tuhaf tuhaf goller kaçırdık. 1 golümüz sayılmadı. 26. hafta da yaklaştı Denizli Efendi. Sanırım Demirören sana da yol verecek. :)

Neyse maç dışında 12 Şubat'ta sunumu yaptım ve yaklaşık 3.5 saat sürdü. Cuma günü de YolBil için bir güvenlik modülü hazırladım.

Cumartesi gününü bilgisayarımı temizleyerek geçirdim. Sevgililer Günü hediyesi verdim bir nevi kendisine. :D

Ha unutmadan, State Management makale dizimin 3. versiyonunu yazdım. Yazılım Günlüğü'nden okuyabilirsiniz. YazGeliştir'e koydum ama sanırım orada editörler pek ilgilenemiyor, yayınlanma süresi bazen uzuyor böyle. Bir hatırlatma: 1 ve 2 no'lu makaleleri okursanız 3. makaleyi okumak bir eğlence olur size. :) Gerçi birbirlerinden bağımsız ama okumanızda fayda var.

Görüşmek üzere..

11 Şubat 2009 Çarşamba

PES Zaferi :)

Makineyi kapatacaktım ama yorgun da olsam şu zaferimi yazayım dedim. :D

Malumunuz, Beşiktaşımız Liverpool ile yaptığı bir maçı kazandı, diğerini ise farklı kaybetti. İnsanlar sadece kaybedilene odaklandı. İlk maçtaki zaferimizi görmezlikten geldiler. Yazacakların ne alaka diyeceksiniz. :)

Geçenlerde 3 arkadaş PES oynamaya gittik. Sınav vesilesiyle okula uğradım ve çıkışında müthiş bir oyun oldu. Ben Beşiktaşlıyım, diğer ikisi(Ziya-İbrahim:deşifre ettim ikinizi de, insan içine çıkamazsınız artık (: ) Fenerli.

Bunlar Liverpool'u aldı, ben Beşiktaş'ı. :) 3 net pozisyona girdim ve onların tek pozisyonu vardı. 68. dakikada İbrahim Üzülmez kırmızı gördü. :) O çıkınca kazanma ümidim arttı doğal olarak. :D Neyse efendim, 90+3'te korner kazandım ve sert ortaya Liverpool'lu oyuncu kendi kalesine gönderdi topu, 0-1 ile maçı kazandım. O anki yüz ifadelerini ve maçtaki ezikliklerini o günün anısı olarak saklayacağım. :D

Yalnız şunu da fark ettim o gün. Beşiktaşı alınca daha bir duygusal oynuyorum. :D
Kazanma hırsım 2 katına çıkıyor. Beşiktaş ile yenilmez olacağız inşallah. :D

Bu yazıyı Zico&Abr. Lİncoln ikilisine armağan ediyorum. :D

Hoşça kalın..

7 Şubat 2009 Cumartesi

Alakasız..

Yatmadan buraya yazı yazayım da iyice uykum gelsin dedim. :S

En nihayetinde Kerberos ile sistem güvenliğine kadar geldim çalışmamda. Herhalde 1-1.5 güne sunum hazır olacak gibi.

Az önce Kayserispor gs'ye çelmeyi taktı: 1-1 :)

Haberlerine kısaca göz atayım dedim, HaberTürk sitesi yine berbat Türkçesi ile yazılar yazmış. Doğrusunu atıyorum, ayıp değil ki, değiştirmiyorlar bile. Bazı yazarları sanki Beyoğlu'nda yürürken almışlar gibi. Tabirimi bağışlayın ama sizler okurlarınıza değer verip yazılarınızda özen göstermezseniz, bizler de sizi protesto ederiz. Şikayet mesajları bırakıyorum sitelerine sürekli. Bir de bunların yorum onaylamaları var. Hoşlarına gidenlerinigösteriyorlar sitede. Çok güzel bir siteydi ama artık bana itici gelmeye başladı. Zaten Erol Bey ayrıldıktan sonra kanallarını da izlemiyorum.

Unutmadan, statlarında ırkçılık yapan gs'li holiganlar, bir de çArşı'ya hakarette bulunmuşlar bugün pankartlarla. çArşı cevap bile vermemeli bence. Kimin ne olduğu ortada. Biz duyarlı bir topluluğuz, onlar ise.. Neyse yazmıyorum. Kahrolsun ırkçılık!!..

Herkese iyi geceler..

6 Şubat 2009 Cuma

Dikkat "Odun" Çıkabilir!

Tam çıkıyordum ki bu konu hakkında yazmaya karar verdim. Herhalde hepimiz bir çok insanla gün boyu etkileşim içindeyizdir. Açıkçası bu etkileşimden hiç hoşlanmamaya başladım. Özellikle yolda, otobüs gibi toplu taşıma araçlarında insanlarla ister istemez etkileşim içine giriyorsunuz. Böyle yerler erkeklerin, tabirim için affedin, öküzlüklerine alışkınım da, bayanlarınki de çok fazla olmaya başladı.

Her gün en az 1 tanesi de denk mi gelir yahu. :@ Ya ayağınıza basar hiç birşey yokmuş gibi devam eder; kocaman bavul gibi çantasını(içine kendisi bile sığar vallahi) size çarpar, bir de ters ters bakar, sanki orası çantasına tahsis edilmiştir de siz bir ihlalde bulunmuşsunuzdur; araçlara sığma problemimden ötürü çok az yer versem de, arada iyi tarafıma denk gelip yer verdiğimde hanım(!)efendiler bir dirsek atar, sanki yer vermekten vazgeçebilirmişsiniz gibi. Bu düşünceyi taşıma ihtimalinizi düşünüp size pis pis de bakarlar. :) Aslında gözle görülmese de ince ve herkesin fark edemeyeceği detay diyebileceğiniz nezaketleri ise sakın yapmayın derim. Zaten kimseden teşekkür beklemiyoruz ama karşıdan başka "odunluklar" gelebiliyor. :)

Rahatladım yaaa. :D İyi geceler herkese. :)

Gurkan.Sleep(5000);

Buraya yazmayalı çok uzun zaman olmuş. Hiç bir derse katılmadan tüm dersleri vermemim mutluluğunu hala yaşamaktayım. :) 2. dönem "Bilgisayar Mimarisi"ni verirsem sanırım sonunda mezun oluyorum. :)

Beklediğim boşluk oluşmadı maalesef. GSM tabanlı projemiz sessizce devam ederken, aldığım projelerle iyice sıkıştım diyebilirim. Bugün bir de ".Net Security" konusunda sunum yapmam istendi. Sanırım buraya düzenli yazma işi başka bahara kalacak. :)

En kısa sürede görüşmek üzere..