You are on page 1of 159

ASP.

NET
ASP.NET AJAX
ADO.NET
Makaleleri

Uğur UMUTLUOĞLU
www ww
w..uum muuttlluuoogglluu..ccoomm
hhttttpp::////uum
muuttlluuoogglluu..bbllooggssppoott..ccoom
m
uugguurr..uum muuttlluuoogglluu@
@nneettrroonn..ccoom m..ttrr

Son Güncelleme: 18 Mayõs 2008

Bu materyali istediğiniz şekilde dağõtabilir ve sitenizde yayõnlayabilirsiniz.

1
İçindekiler

Önsöz ................................................................................................................................... 3

ASP.NET............................................................................................................................... 4
ASP.NET Web Site Administration Tool ............................................................................ 5
HttpBrowserCapabilities ile Tarayõcõ Bilgilerine Ulaşmak ................................................... 8
AdRotator ile Reklam Yönetim Sistemi Geliştirmek.......................................................... 12
View State ile Durum Yönetimi ........................................................................................ 19
ASP.NET 2.0 - Sayfa Direktifleri (Page Directives) .......................................................... 29
ASP.NET 2.0 - Performans Yönetimindeki Yenilikler ....................................................... 38
GridView'e Programatik Veri Bağlamada Sayfalama ve Sõralama İşlemleri..................... 49
GridView Kayõtlarõnõ Okumak ve Metin Dosyasõna Aktarmak........................................... 54
GridView'deki Kayõtlarõ Excel Dosyasõna Aktarmak.......................................................... 61
ASP.NET 3.5 ile Gelen Yenilikler..................................................................................... 67
TreeView'da Veritabanõyla ve XML Dosyalarla Çalõşmak................................................. 74
Site Navigasyonu Hakkõnda Bilinmeyenler....................................................................... 84
TreeView Kontrolüne Kullanõcõ İsteğine Göre Veri Ekleme .............................................. 97

ASP.NET AJAX .................................................................................................................107


ASP.NET ATLAS............................................................................................................108
AJAX: Asenkron JavaScript ve XML ...............................................................................115
ASP.NET AJAX Uygulamalarõ ile İlgili Sorunlar ve Çözümleri .........................................122
AJAX Uygulamalarõnda UpdatePanel Kullanõmõ..............................................................126
ASP.NET AJAX’a Giriş ...................................................................................................133

Diğer Konular....................................................................................................................140
Excel Dosyasõndaki Bilgilere Ulaşmak ............................................................................141
Datatable ile Sõralama ve Filtreleme İşlemleri .................................................................145
Adõm Adõm Team Foundation Server Single-Server Kurulumu .......................................154

2
Önsöz
Bu e-kitapta ASP.NET, ASP.NET AJAX ve ADO.NET gibi .NET teknolojileri ile ilgili yazmõş
olduğum makaleleri topluca bulabilirsiniz. Şimdilik üç ayrõ kategoride yer alan makaleler,
İçindekiler kõsmõnda yazõm tarihlerine göre sõralanmõştõr. Yine her kategorinin başlangõcõnda,
o kategoride yer alan makaleler ile ilgili anahtar kelimeler yer almaktadõr.

Kitapta görmüş olduğunuz makalelerin çevrimiçi versiyonlarõnõ yazgelistir.com ve


msakademik.net adreslerinden de takip edebilirsiniz. Şimdilik yirminin üzerindeki teknik
içerikli makalenin yer aldõğõ bu kitabõ yeni makaleler yazdõkça güncellemeye çalõşacağõm. E-
kitap’õn güncel versiyonu için www.umutluoglu.com adresini takip edebilirsiniz.

Bu kitabõ sitenizden veya forumlardan paylaşabilirsiniz.

Uğur UMUTLUOĞLU

3
ASP.NET

Anahtar kelimeler

AdRotator ASP.NET 2.0 ASP.NET 3.5 ASP.NET AJAX

Caching Excel GridView HttpBrowserCapabilities LINQ


Performans Sayfa DirektifleriSite Navigasyonu SiteMap
SqlCacheDependency TreeView Veritabanõ Örnekleri
ViewState Website Administration Tool Xml

4
ASP.NET Web Site Administration Tool
16 Mart 2006

Bu makalede sizlere Visual Studio 2005 ile gelen ve ASP .NET uygulamalarõnda
kullanabileceğimiz yeniliklerden birisi olan Web Site Administration Tool'u anlatmaya
çalõşacağõm.

Web Site Administration Tool'un aslõnda bize çok büyük yenilikler getirmediğini, ancak
uygulamamõzda yapacağõmõz bazõ işlemleri hõzlõ, pratik ve derli toplu yapmamõzõ sağlayan bir
araç olduğunu söyleyerek başlayalõm. Bildiğiniz gibi ASP .NET ile birlikte gelen web.config
dosyasõnda yaptõğõmõz ayarlarõ uygulamamõzõn genelinde kullanarak işimizi bir noktadan,
daha az kod yazarak, hõzlõ ve güvenli bir şekilde yapabiliyorduk. web.config ile birlikte daha
hõzlõ yaptõğõmõz bu işlemleri, Web Site Administration Tool ile hiç kod yazmadan, özel
dizinlerde elle web.config dosyalarõ oluşturmadan çok daha hõzlõ bir şekilde yapabiliyoruz.
Aslõnda bu aracõn temel mantõğõ da bu. Sizin web.config dosyalarõnda XML tabanlõ kodlarõ
yazarak yapmanõz gereken ayarlarõ, bir web arayüzüyle kolay ve pratik bir şekilde yapmanõzõ
sağlamak.

Web Site Administration Tool'u açmadan önce önemli sayõlabilecek bir noktayõ belirtmek
istiyorum. Solution Explorer'dan uygulamamõzõn içerisinde yer alan App_Data klasörüne
bakacak olursak, bu klasörün altõnda herhangi bir dosya olmadõğõnõ göreceğiz. Tabii ki az
sonra buraya bazõ dosyalar gelecek. Web Site Administration Tool'a Visual Studio 2005'e
yeni eklenen bir menü olan Website menüsünün altõndaki ASP .NET Configuration'dan
ulaşabildiğimiz gibi Solution Explorer penceresinin en sağõndaki ASP .NET Configuration
kutucuğuna tõklayarakta ulaşabiliyoruz. ASP .NET Development Server aktif hale geliyor,
tarayõcõmõzda yeni bir pencere açõlõyor ve resimdeki gibi bir sayfayla karşõlaşõyoruz.

Sayfadan yapabileceğimiz işlemlere özetle bakacak olursak;

Security linkinden
- Authentication modunu değiştirebilir

5
- Kullanõcõ oluşturabilir ve yönetebilir
- Rol oluşturabilir ve yönetebilir
- Kullanõcõlarõ rollerle ilişkilendirebilir
- Rollerin dizinlere erişim haklarõnõ yönetebilirsiniz.

Application linkinden
- Uygulama genelinde kullanõlabilecek (web.config de tutulacak) değerleri oluşturabilir ve
yönetebilir
- Uygulamada e-posta göndermek için gerekli olan SMTP ayarlarõnõ yönetebilir
- Hata sayfalarõ ayarlarõ yapõlabilir
- Debugging ve tracing işlemleri ile ilgili ayarlarõ yapabilirsiniz.

Provider linkinden
- Uygulamanõzda kullanacağõnõz data sağlayõcõsõ ile ilgili ayarlarõ yapabilir
- Membership ve role sağlayõcõlar için farklõ data sağlayõcõsõ belirleyebilirsiniz.

Kullanõmõnda çok zorluk çekilmeyecek, basit ve kullanõşlõ bir araç. İsterseniz bu aracõ
kullanarak sitemizde kullanõcõlar ve roller oluşturalõm, bunlarõ aralarõnda ilişkilendirelim ve
rollerin dizine erişim haklarõnõ ayarlayõp web.config dosyalarõnda ne gibi değişiklikler
olduğunu gözlemleyelim.

Security sayfasõna geldiğimizde buradan Users, Rules, Access Rules kõsõmlarõnõ ve


bunlarõn üzerinde yine bu 3 kõsõmla ilgili ayarlarõ aşama aşama yapabileceğimiz bir link
görüyoruz. Ben örneğimizi alt taraftaki Users, Rules, Access Rules kõsõmlarõnõ kullanarak
yapacağõm. Users kõsmõna baktõğõmõzda bizim şu anda Windows authentication tipini
kullandõğõmõzõ ve dolayõsõyla kullanõcõ yönetiminin aktif olmadõğõnõ söylüyor. Alt kõsõmdaki
select authentication type linkine tõklayarak buradan from the internet seçeneğini
seçiyoruz ve sağ alttaki Done linkine tõklõyoruz. web.config dosyamõza bakacak olursak
authentication modunun artõk Forms olduğunu görüyoruz. Böylece kullanõcõ yönetimi artõk
aktif hale geldi. Users kõsmõnda Create user, Manage users linklerinden artõk kullanõcõ
oluşturabilir ve kullanõcõlarõ yönetebiliriz. Birkaç kullanõcõ hesabõ oluşturduktan sonra Roles
kõsmõndan rolleri aktif hale getirip bir rol oluşturalõm ve kullanõcõlarõn bazõlarõnõ bu rol ile
ilişkilendirelim.

Son olarakta oluşturduğumuz bir rolün yada kullanõcõnõn uygulamamõzdaki bir dizine erişim
haklarõnõ yapõlandõralõm. Örneğin ben uygulamamda varolan Editor klasörüne sadece editor
olarak tanõmladõğõm kullanõcõlarõn erişebilmesini istiyorum. Access Rules'tan Create access
rules seçeneğini tõklõyorum. Sol kõsõmdaki dosya yapõsõndan Editor klasörünü seçip,

6
rollerden editorü seçiyorum ve izinlerden de Allow seçeneğini seçiyorum ve OK diyorum.
Daha sonradan da diğer kullanõcõlarõn bu dizine erişimini engellemek için yine aynõ sayfadan
Anonymous users'a Deny iznini veriyorum. Artõk Editor klasörüme sadece editor rolünü
almõş kullanõcõlarõm erişebilecekler.

Şimdi uygulamamõza dönüp web.config dosyalarõna ve App_Data klasörünün içeriğine


bakalõm. Solution Explorer'dan Refresh butonuna tõkladõğõmõzda App_Data klasörünün
içerisinde bir SQL Server 2005 veritabanõ dosyasõ oluştuğunu göreceğiz. Bu veritabanõndaki
ilgili tablolarda oluşturduğumuz kullanõcõlarla ve rollerle ilgili bilgilerin tutulduğunu görebiliriz.
(Aslõnda bu veritabanõnõ dosyasõnõn bir çok işlevi ve getirdiği birçok kolaylõk var, ama onu ayrõ
bir konu olarak yazmak gerekir.) web.config dosyalarõnda da daha önceden belirttiğimiz gibi
bazõ değişikliklerin olduğunu göreceğiz. Örneğin Editor klasörüne bakacak olursak, burada
önceden bulunmayan ancak yaptõğõmõz işlemlerden sonra oluşan ve bu dizinle ilgili erişim
bilgilerini tutan web.config dosyasõnõ görebiliriz. Dosyanõn içerisindeki kodlar ise aslõnda
çokta yabancõ olmadõğõmõz kodlar.

<?xml version="1.0" encoding="utf-8"?>


<configuration xmlns="http://schemas.microsoft.com/.NetConfiguration/v2.0">
<system.web>
<authorization>
<allow roles="editor" />
<deny users="?" />
</authorization>
</system.web>
</configuration>

7
HttpBrowserCapabilities ile Tarayõcõ Bilgilerine
Ulaşmak

25 Nisan 2007

Web sayfamõza bağlanan istemcilerin kullandõklarõ tarayõcõlarõn (web browser) tipi, versiyonu,
eklentileri, özellikleri farklõ olabilmekte ve bu farklõlõklar bazõ durumlarda sorunlar
oluşturabilmektedir. Örneğin bir tarayõcõda düzgün ve sorunsuz görüntülenen bir sayfa, başka
bir tarayõcõda hatalõ olarak görüntülenebilmektedir. Bu noktada uygulama geliştirilirken
tarayõcõ bazlõ olarak bazõ kontrollerin yapõlmasõ ve buna göre de istemciye uygun içeriklerin
gönderilmesi gerekebilir.

Bir web uygulamasõ geliştirilirken, bazõ durumlarda istemcinin tarayõcõsõ hakkõnda bilgiler elde
etmek ve bu bilgiler doğrultusunda işlemler yapõlmak istenilebilir. ASP.NET web
uygulamalarõnda bu tip işlemleri kolay bir şekilde yapmamõzõ sağlayan
HttpBrowserCapabilities sõnõfõ bulunmaktadõr. HttpBrowserCapabilities sõnõfõndan
oluşturacağõmõz bir nesne örneği ile sayfamõza bağlanan ziyaretçinin kullandõğõ tarayõcõ ile
ilgili bilgilere erişebilir ve bu bilgilere göre farklõ sayfalara yönlendirme yapmak, farklõ içerikler
görüntülemek gibi işlemler yapabiliriz. Yine sitemize bağlanan ziyaretçilerin tarayõcõlarõnõn
istatistiklerini veritabanõnda tutmak için de bu sõnõfõ etkili bir şekilde kullanabiliriz.

HttpBrowserCapabilities sõnõfõ, HttpCapabilitiesBase sõnõfõndan türetilmiştir ve System.Web


isim alanõ (namespace) altõnda yer almaktadõr. Oluşturulacak nesne örneği ile
Request.Browser özelliği üzerinden işlemler yapõlabilmektedir. Nesne üzerinden
erişeceğimiz özellik (property) ve metotlar aracõlõğõyla tarayõcõya ait bilgileri alabilir, bu
bilgilere göre işlemler yapabiliriz.

Nesne örneği oluştururken kullanõcõnõn tarayõcõ bilgilerini elde edebilmek için;

HttpBrowserCapabilities tarayici = Request.Browser;

şeklinde bir tanõmlama yapõlmalõdõr. Oluşturulan HttpBrowserCapabilities nesne örneği


üzerinden erişebileceğimiz bazõ önemli üyeler şunlardõr:

Özellik Adõ İşlevi


Tarayõcõnõn ActiveX desteği olup olmadõğõ hakkõnda bilgi verir. (bool
ActiveXControls
tipinde değer döndürür)
Tarayõcõnõn beta sürümü olup olmadõğõ hakkõnda bilgi verir. (bool tipinde
Beta
değer döndürür)
Browser Varolan tarayõcõ bilgilerini verir. (string tipinde değer döndürür)

8
İstemcide kurulu olan .NET Framework sürümünü getirir. (string değere
ClrVersion
dönüştürülerek kullanõlabilir)
Tarayõcõnõn cookie desteği olup olmadõğõnõ verir. (bool tipinde değer
Cookies
döndürür)
Bağlanan tarayõcõnõn crawler (Google, Yahoo gibi site indeksleyicileri)
Crawler
olup olmadõğõnõ verir. (bool tipinde değer döndürür)
Tarayõcõnõn desteklediği ECMA script versiyonunu verir. (string değere
EcmaScriptVersion
dönüştürülerek kullanõlabilir)
Tarayõcõnõn HTML frame desteği olup olmadõğõnõ verir. (bool tipinde
Frames
değer döndürür)
Tarayõcõnõn mobil bir cihaz üzerinde çalõşan tarayõcõ olup olmadõğõnõ
IsMobileDevice
verir. (bool tipinde değer döndürür)
JavaScript JavaScript özelliği JavaScript desteğinin olup olmadõğõnõ, VBScript ise
VBScript VBScript desteği olup olmadõğõnõ verir. (bool tipinde değer döndürür)
Tarayõcõnõn desteklediği Jscript versiyonunu verir. (string değere
JScriptVersion
dönüştürülerek kullanõlabilir)
Ziyaretçinin bulunduğu platform ile ilgili bilgileri verir. (string tipinde
Platform
değer döndürür)
Tarayõcõnõn Client Script CallBack desteği olup olmadõğõnõ verir. (bool
SupportsCallback
tipinde değer döndürür)
Type Tarayõcõnõn ismini ve tipini verir. IE7 gibi. (string tipinde değer döndürür)
Version Tarayõcõnõn versiyon numarasõnõ verir. (bool tipinde değer döndürür)
İstemcinin Win16 tabanlõ bir bilgisayarda çalõşõp çalõşmadõğõnõ verir.
Win16
(bool tipinde değer döndürür)
İstemcinin Win32 tabanlõ bir bilgisayarda çalõşõp çalõşmadõğõnõ verir.
Win32
(bool tipinde değer döndürür)

HttpBrowserCapabilities'in özelliklerini daha yakõndan inceleyebilmek için örnek bir uygulama


geliştirelim. Açacağõmõz ASP.NET web uygulamasõnda sayfamõzõn Page_Load olayõ için
aşağõdaki kodlarõ Default.aspx.cs dosyasõna ekleyelim.

protected void Page_Load(object sender, EventArgs e)


{
// İstemcinin tarayõcõsõ ile ilgili bilgilere ulaşabilmek için HttpBrowserCapabilities nesnesini
// aynõ tipten değer getiren Request.Browser özelliği aracõlõğõyla oluşturmalõyõz.
HttpBrowserCapabilities tarayici = Request.Browser;

Response.Write("Tarayõcõ beta sürüm mü? : " + tarayici.Beta + "<br>");


Response.Write("Tarayõcõnõn cookie desteği var mõ? : " + tarayici.Cookies + "<br>");

9
Response.Write("Tarayõcõ mõbil bir cihazda mõ çalõşõyor? : " + tarayici.IsMobileDevice +
"<br>");
Response.Write("Tarayõcõnõn Ecma script versiyon numarasõ : " +
tarayici.EcmaScriptVersion + "<br>");
Response.Write("Tarayõcõnõn çalõştõğõ işletim sistemi : " + tarayici.Platform + "<br>");
Response.Write("Tarayõcõnõn tipi: " + tarayici.Type + "<br>");
}

Uygulamayõ çalõştõrdõğõmõzda kendi tarayõcõlarõmõz ve çalõştõğõmõz sistem ile ilgili olarak


aşağõdaki gibi bir sonuç elde edeceğiz.

Tarayõcõ ile ilgili bilgilere ulaşmak

NOT: Tarayõcõ ile ilgili bilgilere erişmek için HttpBrowserCapabilities sõnõfõndan bir nesne
örneği oluşturmak zorunlu değildir. tarayici isimli nesne örneği üzerinden noktaya basarak
sõnõf üyelerine ulaşabildiğimiz gibi Request.Browser özelliği aracõlõğõ ile de aynõ üyelere erişip
işlemler yapabiliriz.

Nesne örneği veya Request.Browser özelliği üzerinden tarayõcõ özelliklerine ulaşabiliriz

Günümüzde üçüncü parti yazõlõm olarak bir çok site web sayfalarõnõ ziyaret eden kullanõcõlar
ile ilgili bazõ bilgileri yukarõda kullandõğõmõz gibi farklõ yöntemlerle tutmaktadõr. Kendi web
uygulamamõzda da HttpBrowserCapabilities sõnõfõnõ kullanarak site ziyaretçilerinin tarayõcõlarõ
ile ilgili istatistikleri tutabiliriz. Yine bu özellikleri kullanarak tarayõcõnõn tipine göre farklõ

10
içerikler sunabilir, farklõ sayfalara yönlendirme işlemleri yapabilir. Örneğin, sitemiz ziyaret
edecek kullanõcõlarõn masaüstü bilgisayarlardaki tarayõcõlarõ kullanabilecekleri gibi, mobil bir
bilgisayardan da erişebilecekleri olasõ bir durumdur. Mobil tarayõcõlar ise normal bir tarayõcõ
kadar işlevsel olmadõklarõ için sayfalarõmõzdaki içeriklerin bazõlarõnõ görüntüleyemez veya
hatalõ görüntüler. Böyle bir durum karşõsõnda mobil bir tarayõcõ için farklõ sayfalar tasarlamak
ve gelen kullanõcõlarõ bu sayfalara yönlendirmek isteyebiliriz. Aşağõdaki gibi hazõrlanan bir
projenin anasayfasõ içerisinde gerekli kontroller ve yönlendirmeler yapõlõrsa istenildiği gibi
kullanõcõnõn doğru içeriğe erişmesi sağlanabilir. Yine kullanõcõnõn tarayõcõsõnõn Cookie,
JavaScript gibi sitenin işleyişi açõsõndan önem taşõyan bileşenleri desteklememesi
durumunda, site düzgün bir şekilde kullanõlamayacağõ için kullanõcõya bilgilendirici mesajlar
verilebilir.

Tarayõcõnõn özelliklerine göre kullanõcõya farklõ içerikler sunabiliriz.

11
AdRotator ile Reklam Yönetim Sistemi Geliştirmek
12 Mayõs 2007

AdRotator, ASP.NET uygulamalarõnda dönüşümlü olarak reklamlarõ veya tanõtõcõ resim


dosyalarõnõ görüntülenmesini sağlayan kontroldür. Resim dosyalarõnõ görüntülemenin
yanõnda, hangi resim dosyasõnõn ne sõklõkla görüntüleceği gibi bir işlevselliği de yapõsõ
itibariyle sağlamaktadõr. Yine anahtar kelime tanõmlamalarõ (keyword) ile yayõnlacak
reklamlarõ sahip olduklarõ kelimelere göre süzülmesi ve buna göre yayõnlanmasõnõ otomatik
olarak sağlamaktadõr. Bu işlemleri yapabilmek için temel olarak uygulama içerisindeki bir
XML dosyasõ kullanõlmaktadõr. Belirli bir formatta yazõlan reklam bilgileri, XML dosyasõ
içerisine kaydedilerek AdRotator kontrolüne bağlanõp reklamlarõn kolay bir biçimde site
içerisinde dönüşümlü şekilde görüntülenmesi sağlanõr. Aşağõdaki 3 tane reklam içeren ve
AdRotator için kullanõlabilecek özelliklere sahip bir XML dosyasõ örneği bulunmaktadõr.

<?xml version="1.0" encoding="utf-8" ?>


<Advertisements>
<Ad>
<AlternateText>NedirTV</AlternateText>
<ImageUrl>images/nedirtv.jpg</ImageUrl>
<NavigateUrl>http://www.nedirtv.com</NavigateUrl>
<Impression>5</Impression>
<Keyword>video</Keyword>
</Ad>
<Ad>
<AlternateText>MS Akademik</AlternateText>
<ImageUrl>images/msakademik.gif</ImageUrl>
<NavigateUrl>http://www.msakademik.net</NavigateUrl>
<Impression>3</Impression>
<Keyword>makale</Keyword>
</Ad>
<Ad>
<AlternateText>Yazgeliştir</AlternateText>
<ImageUrl>images/yazgelistir.gif</ImageUrl>
<NavigateUrl>http://www.yazgelistir.com</NavigateUrl>
<Impression>5</Impression>
<Keyword>makale</Keyword>
</Ad>
</Advertisements>

Bu şekilde hazõrlanan bir XML dosyasõ AdRotator kontrolünün AdvertisementFile özelliğine


dosya yolu belirtilerek bağlanõp kullanõlabilir. Dosyadaki her <ad> boğumu bir reklamõ
tanõmlar. Buradaki <AlternateText> resmin alt metnini, <ImageUrl> resim dosyasõnõn yolunu
ve adõnõ, <NavigateUrl> ise resme tõklandõğõnda hangi URL'ye gidileceğini belirler. XML

12
dosyasõ içerisinde tanõmlõ olan <Impression> boğumundaki değer ise, o reklamõn gösterilme
sõklõğõnõ belirlemektedir. Bu sõklõk herhangi bir yüzdesel oran değil, diğer reklamlara göre ne
kadar sõklõkta görüntüleneceğidir. (Örneğin Impression değeri 10 olan bir reklam, Impression
değeri 5 olan bir reklama göre yaklaşõk 2 kat fazla gösterilecektir.) <Keyword> alanõnda ise
o reklama ait anahtar kelime veya kelimelerin tanõmlamasõ yapõlõr. AdRotator kontrolünün
KeywordFilter özelliğine verilecek anahtar kelime ile XML dosyasõndaki <Keyword>
alanõndaki kelimenin eşleşmesi durumunda, reklamõn/reklamlarõn seçilmesi ve
görüntülenmesi sağlanõr. Bu şekilde basit bir XML dosyasõna tanõmlanan reklam bilgileri ile
site içerisinde kullanõlabilecek reklam dönüşüm sistemi oluşturabiliriz.

XML ile AdRotator kullanõm oldukça pratik ve kolaydõr. Fakat burada bizleri kõsõtlayõcõ bazõ
özellikler olduğu gibi, yine yapõlmasõnõ isteyebileceğimiz bazõ ek işlemleri de
gerçekleştirmekte de bazõ sõkõntõlarla karşõlaşabiliriz. Reklamlarõ dinamik şekilde değiştirme
işlemi gerçekleştirmek için her seferinde XML dosyasõnõ açõp değişiklikler yapmak, aslõnda bir
programcõ için kõsõtlayõcõ bir unsurdur. Bu noktada reklamlarõ XML dosyasõnda saklamak
yerine veritabanõnda tutmak, özellikle sõklõkla güncellenecek reklam bilgileri için programcõya
veya site yöneticisine dinamik bir yapõ ve dolayõsõyle kolaylõk sağlayacaktõr. Yine reklamlarla
ilgili olarak; bir reklamõn kaç kez görüntülendiği, o reklama kaç kez tõklandõğõ gibi istatistiklerin
tutmakta böyle bir sistemde oldukça zengin bir işleyiş sunacaktõr.

Yukarõda bahsedilen sorunlarõ XML dosyasõnõ kullanarak gerçekleştirmek zahmetli ve zor


işlemler gerektirecektir. AdRotator ile ilgili olarak bu sorunlarõ aşmak için, öncelikli olarak
AdRotator kontrolüne bağlanacak olan verileri bir XML dosyasõndan getirmek yerine,
veritabanõndaki bir tablodan getirmek gerekecektir. Bu bize reklamlarõn değiştirilmesini, yeni
reklamlarõn eklenmesini sağlamak ve reklamlar hakkõnda istatistikler tutmak için oldukça
esnek ve kolay bir yapõ sağlayacaktõr. Bunun için öncelikli olarak kendimize bir tablo
oluşturup, reklamlar ile ilgili yukarõdaki XML dosyasõndaki bilgileri bu tablo içerisinde
taşõyalõm. Tablomuzu oluşturmaya geçmeden önce tablomuzda başka ne gibi bilgileri de
tutabileceğimizi düşünelim. XML dosyasõndaki bilgilerin dõşõnda yine yukarõda bahsettiğimiz
reklam görüntüleme sayõsõ, reklama tõklama sayõsõ, hatta reklamõn o an güncel olup
olmadõğõ gibi bilgileri de aynõ tablo içerisinde tutmak yapacağõmõz işlemleri oldukça
kolaylaştõracaktõr. Gelin bu şekilde kendimize Reklamlar adõnda bir tablo oluşturalõm.
Aşağõdaki şekilde, SQL Server üzerinde kurulmuş bir tablonun kolon isimleri ve taşõyacağõ
değerler görünmektedir.

13
Resim: Reklamlar Tablosu

Tablomuzdaki alanlarõ isimlendirirken AdRotator'a alanlarõ kolay bir şekilde tanõtabilmek için
AlternateText, ImageUrl, NavigateUrl, Impression ve Keyword kõsõmlarõnõ XML
dosyasõndaki aynõ isimlerle adlandõrmamõz gerekecektir. Bu şekilde tablo verileri AdRotator'a
bağlandõğõnde alanlar otomatik olarak algõlanacaktõr. ID tablonun primary key'i, Link reklam
URL'si, Durum reklamõn aktif olup olmadõğõ, Goruntuleme reklamõn görüntülenme sayõsõnõ
ve Tiklama reklama kaç kez tõklanõldõğõ bilgilerini taşõyacak alanlardõr. Bu şekilde
tasarladõğõmõz tablo içerisine artõk verilerimizi ekleyerek, AdRotator kontrolüne bu verileri
nasõl bağlayabileceğimizi görelim.

Resim: Reklamlar tablosu içerisine dört tane reklam eklendi

Burada sistemimizin kolay şekilde işleyebilmesi için NavigateUrl alanõ içerisine direk olarak
reklamõn URL'si yerine, sitemiz içerisinde hangi reklama tõklandõğõnõ yakalamamõzõ
sağlayacak bir sayfayõ eklememiz gerekecektir. (reklam.aspx) Yine bu sayfaya parametre
olarak yollayacağõmõz bilginin reklamõn ID kolonundaki değer olmasõ da işlemlerimizi
kolaylaştõracaktõr. Bu nedenle NavigateUrl alanõna ID değeri 1 olan reklam dosyasõ için
reklam.aspx?ID=1 gibi bir değer vermeliyiz.

Artõk tablodan alõnan verilerin AdRotator'a bağlanmasõ işlemini gerçekleştirebiliriz. Bunun için
öncelikli olarak AdRotator bulunan sayfamõzõn Page_Load kõsmõnda tablomuza bağlanõp,
reklam bilgilerini çekerek bir veri nesnesine bağlamak ve bu nesneyi de AdRotator'õn
DataSource özelliğine atamamõz gerekecektir. Aşağõda bu işlemin gerçekleşmesini sağlayan
kodlar bulunmaktadõr.

protected void Page_Load(object sender, EventArgs e)


{
// Ornek isimli veritabanina baglanti cumlesi olusturuluyor.
SqlConnection conn = new SqlConnection("data source=.; initial catalog=Ornek;

14
integrated security=true"))
// Tablodan reklam bilgilerini getirecek sorgu cumlesi hazirlaniyor
SqlCommand comm = new SqlCommand("SELECT AlternateText, ImageUrl,
NavigateUrl, Impression FROM Reklamlar WHERE Durum='True'", conn);
DataTable dt = new DataTable();
SqlDataAdapter da = new SqlDataAdapter(comm);
da.Fill(dt); // DataTable nesnesine eklenen veriler, AdRotator'a veri kaynagi olarak
gosteriliyor ve veriler yukleniyor

AdRotator1.DataSource = dt;
AdRotator1.DataBind();
}

Böylece sayfa çalõştõrõldõğõnda tabloda o an aktif olan reklamlarõn bilgileri AdRotator'a


bağlanacak ve AdRotator dönüşümlü bir şekilde reklamlarõn görüntülenmesini sağlayacak.
Peki reklam bilgilerini sayfamõzda görüntüledik, ama şu anda sayfamõzda hangi reklam yer
alõyor? Yukarõdaki işlemler tablodan tüm reklam bilgilerini getirdi. Bir DataTable nesnesine
atõlan reklamlar kontrolümüzün DataSource özelliğine bağlandõ. AdRotator ise bu
reklamlardan bir tanesini kendi içerisindeki algoritma ile seçti ve sayfada görüntüledi. İşte bu
noktada AdRotator'un hangi reklamõ seçtiğini yakalamamõz ve buna göre de sayfada
görüntülenen reklamõn tablodaki Goruntuleme alanõnõ 1 arttõrmamõz gerekecek. Böylece
reklam yönetim sistemimizdeki en önemli işlemlerden biri olan reklam görüntüleme sayõsõnõ
tutmayõ başaracağõz.

AdRotator kontrolünün olaylarõ (event) içerisinde yer alan Ad_Created event'i, kontrolün
reklam kaynağõndan bilgiler aldõğõnda tetiklenen event'idir. Ad_Created event'ini bir metoda
bağlayacak olursak, metodun parametrelerinden ikincisinin AdCreatedEventArgs sõnõfõndan
(class) e adõnda bir değer taşõdõğõnõ göreceğiz. İşte buradaki e değeri, o an sayfaya eklenen
reklam hakkõnda bazõ bilgileri elde etmemizi sağlayacaktõr.

Resim: e nesnesi üzerinden o an sayfaya eklenen reklam hakkõnda bilgiler elde


edilebilir

Burada karşõmõza çõkan NavigateUrl adresi içerisinde reklamõn ID değerini de taşõdõğõ için
bizim reklamõn bulunduğu satõrõ ele alabilmemizi sağlayacaktõr. AdRotator1_AdCreated

15
metodu içerisinde yapacağõmõz işlemlerle tablodaki Goruntuleme alanõndaki değerin
güncellenmesini ve 1 arttõrõlmasõnõ sağlayabiliriz. Aşağõdaki tabloda bu işlemler için gerekli
kodlar yer almaktadõr.

protected void AdRotator1_AdCreated(object sender, AdCreatedEventArgs e)


{
SqlConnection conn = new SqlConnection("data source=.; initial catalog=Ornek;
integrated security=true");
string id = e.NavigateUrl;
// 15. karakterden sonraki deger bize reklamin ID degerini verecektir. reklam.aspx?ID=3
icerisinden 3 degeri gibi...
id = id.Substring(15);

// id degeri alinan reklamin bulundugu satirda Goruntuleme alanini 1 arttirarak


guncelliyoruz
SqlCommand comm = new SqlCommand("UPDATE Reklamlar SET
Goruntuleme=Goruntuleme+1 WHERE ID=@ID", conn);
comm.Parameters.AddWithValue("@ID", id);
conn.Open();
comm.ExecuteNonQuery();
conn.Close();
}

! NOT: Buradaki id.SubString(15) ifadesi reklam.aspx?ID=1 gibi bir linkteki 1 değerini


alabilmek için yapõlan string bölme işlemidir. Dosya adõnõn ve parametre adõnõn farklõ olmasõ
durumunda bu ifadede değişiklik yapmak gerekecektir.

Böylece sayfaya getirilen reklamõ AdCreated event'i içerisinde yakaladõk ve görüntülenme


sayõsõnõ tablo içerisinde güncelleme işlemi yaparak arttõrdõk. Şimdi sõra reklama tõklanmasõ
durumunda tablodaki ilgili reklamõn Tiklanma alanõnõn 1 arttõrõlarak, reklamlarõn tõklanma
sayõlarõnõn tutulmasõnda. Dikkat edeceğiniz gibi reklam bilgilerini sakladõğõmõ tabloda
reklamõn adresinin Link alanõnda tuttuk. NavigateUrl alanõnda ise sitemizin içerisindeki bir
dosyanõn linkini verdik. Az sonra hazõrlayacağõmõz bu sayfada tõklanan reklamõn Tiklanma
alanõnõn arttõrõlmasõ işlemini gerçekleştirerek, sayfanõn asõl reklam linkine yönlendirilmesini
sağlayacağõz.

reklam.aspx.cs sayfasõnõn Page_Load metodu içerisinde öncelikli olarak QueryString'den


ID bilgisini almak, ID'ye sahip reklamõn Tiklanma alanõnõ güncellemek ve reklamõn asõl
adresine yönlendirme yapmak gerekiyor. Aşağõda bu işlemleri gerçekleştirmek için gerekli
kodlar yer almaktadõr.

reklam.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
if (Request.QueryString["ID"] != null)

16
{
string reklamID = Request.QueryString["ID"];

SqlConnection conn = new SqlConnection("data source=.; initial catalog=Ornek;


integrated security=true");

// Reklamõn tõklanma sayõsõ güncelleniyor


SqlCommand comm = new SqlCommand("UPDATE Reklamlar SET
Tiklama=Tiklama+1 WHERE ID=@ID", conn);
comm.Parameters.AddWithValue("@ID", reklamID);
conn.Open();
comm.ExecuteNonQuery();
conn.Close();

// Reklamõn URL adresi alõnõyor


SqlCommand selectComm = new SqlCommand("SELECT Link FROM Reklamlar
WHERE ID=@ID",conn);
selectComm.Parameters.AddWithValue("@ID", reklamID);
conn.Open();
string url = selectComm.ExecuteScalar().ToString(); // Reklamõn URL'si alõnda
conn.Close();

// Reklamõn adresine yönlendirme yapõlõyor


Response.Redirect(url);
}
}

Artõk sayfamõzõ çalõşõtõrõp görüntülenen reklama tõklama zamanõ! Birden fazla reklam
gösterimi yaparak ve bu reklamlarõn bazõlarõna tõklayarak Reklamlar tablosundaki
değişiklikleri gözlemleyebiliriz.

17
Resim: Gösterilen reklama tõklandõğõnda, o reklamõn tõklanma sayõsõnõ arttõrõldõ ve
reklamõn sitesine yönlendirme yapõldõ

Bu makalemizde AdRotator kontrolüne bağlanacak reklam verilerini veritabanõnda bir tablo


içerisinde nasõl tutabileceğimizi gördük. Yine tabloda tutulan reklamlarda ilgili olarak reklamõn
aktif olup olmadõğõ, reklamõn gösterim sayõsõ ve reklama tõklama sayõsõnõ da tutarak sitemiz
için komple reklam yönetim sistemi geliştirmiş olduk. Umarõm projelerinizde
kullanabileceğimiz faydalõ bir sistem geliştirmişizdir.

18
View State ile Durum Yönetimi
08 Ağustos 2007

ASP.NET uygulamalarõnda durum yönetiminde (state management) veri taşõma işleminde


kullanõlan nesnelerden biri de View State'dir. View State, bir ASP.NET sayfasõ içerisinde
bulunan kontrollerin özelliklerinin ve programcõnõn istediği verilerin saklanmasõnõ sağlar.
Varsayõlan olarak biz belirtmesek bile, sayfada Postback işlemi gerçekleştiğinde kontrollere
ait bilgiler sunucu tarafõnda HTML kodlarõ üretilirken şifrelenmiş bir şekilde View State
içerisine yazõlõr. Sayfa tekrar yüklendiğinde ise kontrollerin özellikleri bu nesneden okunur.
Böylece Postback işlemi sonucunda kontroller üzerinde yapõlan değişiklikler sayfa tekrar
yüklendiğinde kaybedilmeden elde edilebilir.

ViewState Olmasaydõ?
Çoğumuzun hatõrlayacağõ gibi, ASP veya PHP ile geliştirilen uygulamalarda bir sayfa
içerisindeki kontrollerin değerleri, sayfa post edildiğinde kaybolurdu ve tekrar elde etmek için
ekstra işlemler yapmamõz gerekirdi. ASP.NET'e geçiş yaptõğõmõz ilk zamanlarda en çok
dikkatimizi çeken durumlardan birisi de bir formu post ettiğimizde form üzerindeki verilerin
kaybolmamasõydõ. İşte ASP.NET uygulamalarõnda bizi bu sõkõntõdan kurtaran ve post
işleminden sonra da verilerin form üzerinde saklanmasõnõ sağlayan View State nesnesidir.
Dilerseniz View State nesnesinin uygulamalarda bize ne gibi bir kolaylõk sağladõğõnõ daha net
bir şekilde görebilmek için şu basit örneği gerçekleştirelim. Açtõğõmõz bir sayfaya iki tane
Label kontrolü ve iki tane Button kontrolü ekleyelim. Label kontrollerinden bir tanesinin
EnableViewState özelliğini true, diğerinin ise bu özelliğini false olarak ayarlayalõm.
(EnableViewState özelliği bir kontrolün özelliklerinin ViewState içerisinde taşõnõp
taşõnmamasõ durumunu belirler. Makalemizin ilerleyen kõsõmlarõnda EnableViewState
özelliğini tekrar inceliyor olacağõz.) Butonlardan bir tanesinin Click eventi içerisine aşağõdaki
ifadeleri ekleyelim. Diğer butonda ise herhangi bir değişiklik yapmayacağõz, sadece postback
yapmak amaçlõ kullanacağõz.

protected void Button1_Click(object sender, EventArgs e)


{
Label1.Text = "EnableViewState'i kapalõ olan label";
Label2.Text = "EnableViewState'i açõk olan label";
}

19
Resim: EnableViewState özelliği açõk olan kontrolün ve kapalõ olan kontrolün postback
işlemleri sonucundaki davranõşlarõ

Görüldüğü gibi ilk postback işlemi sonucunda butonun Click eventi aracõlõğõyla her iki labela
da değerler yazõldõ. Fakat sayfa üzerinde farklõ bir postback işlemi (labellarõn durumunu
değiştirmeyen bir postback işlemi) gerçekleştiğinde EnableViewState özelliği false olan label
kontrolü (Label1), bir önceki postbackten kazandõğõ değerini kaybetti. Diğer yandan,
ViewState nesnesi içerisinde değeri saklanan label (Label2) farklõ postback işlemlerinden
geçmesine rağmen önceki sayfadaki değerini kaybetmedi.

ViewState Hangi Durumlarda, Hangi Kontrollerin Değerlerini Saklar?


View State içerisinde sadece formda bulunan input elementleri değil, GridView, DetailsView
ve Calendar diğer ASP.NET sunucu kontrollerinin özellikleri de saklanmaktadõr. HTML
kodlarõ içerisinde taşõnan View State nesnesini gözlemlemek için isterseniz basit bir web
uygulamasõ açalõm. Bu noktada View State içerisinde kontrollerin değerlerinin saklanmasõ ile
ilgili önemli birkaç hususa değinebilmek için dilerseniz uygulamanõn gidişatõnõ aşağõdaki gibi
takip edelim.

Adõm-1: Sayfamõza btnTikla adõnda bir button ve lblIcerik adõnda bir label kontrolü
ekleyelim. Button'un Text özelliğini Tõkla, label'õn Text özelliğini Merhaba olarak değiştirelim.
Sayfayõ çalõştõrdõktan sonra tarayõcõ üzerinde boş bir alana fare ile sağ tõklayõp Kaynağõ
Görüntüle (View Source) seçeneğinden oluşan sayfanõn HTML kodlarõna göz atalõm.

20
Resim: Kontrolleri ekledikten sonra __VIEWSTATE nesnesinin içeriği

Görüldüğü gibi bilgiler HTML kodlarõ içerisinde __VIEWSTATE adõ verilen hidden bir input
elementi bulunmaktadõr. Bir ASP.NET sayfasõnda varsayõlan olarak her zaman
__VIEWSTATE değeri saklanmaktadõr. Base64 formatõ kullanarak şifrelenen veriler sayfa
içerisinde saklanõr ve sayfanõn postback ile tekrar yüklenmesi durumunda gerekli bilgiler
çözümlenerek sayfa içerisinde kullanõlõr. Yukarõdaki resimde seçili olarak tutulan View State
değerine dikkat edelim.

Adõm-2: Sayfamõzdaki button'un Text özelliğini Click, label'õn Text özelliğini de Hello olarak
değiştirelim. Sayfayõ çalõştõrdõktan sonra tekrar HTML kodlarõ içerisindeki __VIEWSTATE
değerini kontrol edelim.

Resim: Button ve label içeriğinin değiştirilmesinden sonra __VIEWSTATE'in sakladõğõ


değer

21
İki resimdeki seçili __VIEWSTATE alanlarõna dikkat edecek olursanõz, button ve label
kontrollerinin içeriğini değiştirmemize rağmen View State içerisinde saklanan değerin aynõ
şekilde kaldõğõnõ görebilirisiniz. Bunun sebebi şu anda View State içerisinde sadece
sayfamõzdaki kontrollerin hiyerarşik olarak diziliminin tutulmasõ ve bizim Design aşamasõnda
yapmõş olduğumuz değişikliklerin tutulmamasõdõr . Yani kontrolün özelliklerinde belirlediğimiz
atamalar direkt olarak HTML kodlarõ içerisinde <input type="submit" name="Button1"
value="Click" ... şeklinde tutulacağõ için bu bilgilerin __VIEWSTATE'e yazõlmasõna gerek
yoktur. Zaten View State'in en temel kullanõm amaçlarõndan biri de Design aşamasõnda
belirlenen kontrol özelliklerini saklamasõ değil, form üzerinde Postback işlemi yapõldõktan
sonra değişen kontrol değerlerinin taşõnmasõnõ ve sayfa tekrar yüklendiğinde bu verilerin
kaybolmamasõnõ sağlamaktõr. Dilerseniz son cümlede bahsettiğimiz olayõ Adõm-3'te görelim.

Adõm-3: Aşağõdaki kod örneğinde görüldüğü gibi, Button'un Click olayõ (event)
gerçekleştiğinde lblIcerik'in Text özelliğini ASP.NET olarak değiştirelim. Sayfayõ çalõştõrdõktan
sonra buttona tõklayarak Click eventini gerçekleştirelim ve Postback ile sayfayõ tekrar elde
edelim. Yeniden oluşan sayfanõn kodlarõna bakacak olursak aşağõdaki gibi __VIEWSTATE'in
içeriğinin değiştiğini görebiliriz.

protected void Button1_Click(object sender, EventArgs e)


{
lblIcerik.Text = "ASP.NET";
}

Resim: Button'un Click eventinde label'in değeri değiştiği için bu değişiklik Postback
işlemi sonunda __VIEWSTATE'e yansõtõlmõştõr

Bu sonuç, __VIEWSTATE içerisinde formdaki kontrollerin dizilimi dõşõnda Postback işlemi


sonucunda kontrollerin özelliklerinde yapõlan değişikliklerin de tutulduğunun bir göstergesidir.
Kontrol üzerinde sadece değişen Text özelliği değil, değişen diğer tüm özellikler de

22
(BackColor, Width, Height, ... gibi diğer özellikler) View State içerisinde saklanõr. Burada
kontroller ile ilgili söyleyebileceğimiz önemli ve ilginç bir hususta şudur ki; TextBox,
CheckBox ve RadioButton gibi kontrollerin postback esnasõnda değişen özellikleri View State
içerisinde taşõnmaz!

Hangi Durumlarda Verilerin ViewState İçerisinde Taşõnmasõ


Engellenmeli?
Kontrollerin değerlerinin ne gibi durumlarda View State içerisinde saklanõp saklanmayacağõ
konusunda genel bir fikre sahip olduğumuzu düşünüyorum. Yukarõda yapõlan Adõm-3
işleminden sonra eğer dikkatinizi çektiyse label kontrolü üzerinde yaptõğõmõz değişiklikten
dolayõ __VIEWSTATE içerisindeki verinin boyutu arttõ. Peki sayfamõzda büyük miktarda veri
saklayan bir kontrol (örneğin GridView gibi) kullansak ve bu kontrolün içeriğini Postback
işlemi sonucunda değiştirsek, __VIEWSTATE'in boyutu ne şekilde değişir? Gelin sayfamõza
bir GridView nesnesi ekleyerek ne gibi değişiklikler olduğunu gözlemleyelim. Bu örneği
sayfaya eklediğim GridView'i AdventureWorks veritabanõ altõnda yer alan
Production.Product tablosuna bağlayarak gerçekleştirdim.

Resim: GridView'e doldurulan veriler ve HTML kõsmõnda yer alan __VIEWSTATE


nesnesinin içeriği

Her ne kadar resmin boyutunu küçültmüş olsamda, __VIEWSTATE'in oldukça fazla yer
kapladõğõ aşina bir şekilde görünmektedir. Yine sayfanõn HTML kodlarõnõ ayrõ bir dosyaya,
__VIEWSTATE içerisindeki metinsel kõsmõ da farklõ bir dosyada kaydedip aralarõndaki farkõ
kõyaslayacak olursak __VIEWSTATE değerinin sayfa içerisinde oldukça fazla yer kapladõğõnõ
göreceksiniz. Örneğin benim hazõrladõğõm bu örnekte sayfanõn tamamõ 6.66 KB, sadece

23
__VIEWSTATE içerisindeki değer ise 2.85 KB yer kaplamaktadõr. Yani View State'de
saklanan veri, boyut olarak sayfanõn neredeyse yarõsõnõ kaplamaktadõr. Burada oluşturulan
View State değeri her Postback işlemi gerçekleştiğinde sunucuya gönderileceği ve her sayfa
oluşumunda da istemciye getirileceği için sürekli olarak sunucu-istemci arasõnda fazladan
veri transferi söz konusu olacaktõr. İşte bu noktada uygulamayõ geliştiren kişi olarak bize
önemli bir performans ayarlamasõ görevi düşmektedir. GridView vb. bir kontrolün View State
içerisinde saklanmasõ, sayfanõn düzgün bir biçimde çalõşmasõ için gerekli midir, yoksa
gereksiz midir? Bir başka söylemle; sayfa, Postback olduğunda önceki halinde bulunan
verileri hatõrlamaya ihtiyacõ var mõdõr, yok mudur? Eğer cevabõmõz "Hayõr, bu sayfanõn tekrar
oluşturulmasõ esnasõnda, önceki halindeki GridView vb. bir nesnenin verisinin taşõnmasõna
gerek yok" ise, bu noktada sayfanõn sunucu-istemci arasõnda daha hõzlõ şekilde çalõşabilmesi
bu değerlerin View State içerisinde saklanmasõnõ engellememiz gerekmektedir. ASP.NET
sunucu kontrollerinin tamamõnda EnableViewState adõnda bir özellik bulunmaktadõr. Bu
özellik kontrolün postback işlemi sonucunda değişen değerlerinin View State içerisinde
saklanõp saklanmayacağõnõ belirler. bool tipinden bir değer alabilen EnableViewState
özelliğinin varsayõlan değeri true'dur. EnableViewState değerinin true olmasõ, kontrolün
özelliklerinin View State içerisinde saklanõr, false olmasõ durumunda ise saklanmaz. Eğer bir
kontrolün özelliklerinin View State içerisinde taşõnmasõnõ istemiyorsanõz, o kontrolün
EnableViewState özelliğini false olarak ayarlamanõz gerekecektir. Aşağõdaki örnek kod
parçasõnda bir GridView kontrolünün EnableViewState özelliğinin kapatõlmõştõr.

<asp:GridView ID="GridView1" runat="server" EnableViewState="False"></asp:GridView>

24
Resim: EnableViewState özelliğinin false olmasõ durumunda değişen değerler
ViewState'de taşõnmaz ve sayfanõn boyutu azalõr.

Yukarõdaki resimde gördüğünüz gibi __VIEWSTATE nesnesinin içeriği ciddi anlamda


azalmõştõr. Benim yaptõğõm testte, sayfanõn boyutu 6.66 KB'dan 3.96 KB gibi bir değere
düştü.

NOT: ViewState değerinin bazõ durumlarda çok ciddi boyutlara ulaşmasõ uygulamanõn
performansõ açõsõndan ciddi sorunlara yol açabilir. ViewState nesnesi içerisinde saklanan
değerlerin sõkõştõrõlarak daha küçük boyutlara ulaşõlmasõnõ sağlayan bazõ teknikler
bulunmaktadõr. Fakat bu konu başlõ başõna bir makale anlamõna geleceği için bu yazõmõzda,
bu detaya gimeyeceğiz. Arama motorlarõnda ViewState compression veya ViewState
sõkõştõrma şeklinde aramalar yapacak olursanõz çok sayõda kaynağa erişebilirsiniz.

Bir kontrolün ViewState özelliğini kapatma işlemini kontrolün EnableViewState özelliği


üzerinden gerçekleştirebileceğimiz gibi, bir sayfa içerisindeki tüm kontrollerin ViewState
özelliğini de sayfamõzõn Page direktifi içerisinden veya Page nesnesi üzerinden yine
EnableViewState özelliği ile kapatabiliriz. Aşağõdaki örnek kodlarda bu işlemlerin nasõl
gerçekleştirileceği gösterilmiştir.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"


Inherits="_Default" EnableViewState="false" %>

25
protected void Page_Load(object sender, EventArgs e)
{
Page.EnableViewState = false;
}

Sayfamõzõn EnableViewState özelliğini kapatmamõz durumunda artõk kontrollerin postback


sonrasõnda değişen özellikleri ViewState içerisinde tutulmayacaktõr. Fakat böyle bir durumda
oluşan HTML kodlarõ içerisine bakacak olursanõz, __VIEWSTATE alanõnda hala bazõ bilgiler
olacağõnõ görebilirsiniz. Her ne kadar kontrollerin değişen özellikleri artõk bu nesnede
saklanmasa da, sayfaya eklene kontrollerin hiyerarşik yapõsõ burada tutulmaya devam
edilecektir.

ViewState Nesnesi İçerisinde Kendi Verilerimizi Saklamak


View State ile sayfa içerisindeki kontrollerin özellikleri dõşõnda kendi istediğimiz verileri de
taşõyabilmekteyiz. View State ile aynõ adõ taşõyan ViewState isimli nesne aracõlõğõyla istenilen
verileri saklayabilir ve aynõ sayfa üzerinde gerçekleşen Postback işlemlerinden sonra bu
verileri okuyabiliriz. ViewState nesnesinin yapõsõnõ inceleyecek olursak geriye StateBag
adõnda bir nesne örneği döndürdüğünü ve içerisindeki nesneleri IDictionary tipinde bir
kolleksiyonda sakladõğõnõ görebiliriz. Indeksleyiciler aracõlõğõyla içerisinde key-value çiftleri
taşõyabilmektedir. Burada key değerimiz string, value değerimiz ise object tipinden olmalõdõr.
Yine saklanacak olan object tipindeki değer serileştirilebilir (serializable) olmak zorundadõr.
Yani .NET ortamõnda kendi yazdõğõmõz serileştirilebilir tipleri de ViewState içerisinde
saklayabiliriz. Aşağõdaki kod örneğinde ViewState nesnesine int ve DataTable tipinden
değerlerin atanmasõ gösterilmiştir.

ViewState["miktar"] = 128535;
ViewState["tablo"] = new DataTable("TestTable");

İndeksleyiciler aracõlõğõyla ViewState'e ekleme yapõlabileceği gibi, Add metodunu


kullanarakta ViewState.Add("KeyAdõ", value) şeklinde bir nesne eklenebilir. Bu şekilde
ViewState'e atõlan değerler Postback işlemi sonunda sayfanõn HTML kodlarõ içerisinde
saklanacaktõr. Postback işlemleri sonucunda hala aynõ sayfa üzerindeysek bu verilere
aşağõdaki şekilde erişebiliriz.

int sayi = (int)ViewState["miktar"];


DataTable dtTest = (DataTable)ViewState["tablo"];

Görüldüğü gibi, ViewState içerisinde sakladõğõmõz değerler object tipinde saklanacağõ için
sayfa içerisinde bu verilere erişirken gerekli dönüşüm (cast) işlemlerini de gerçekleştirmek
gerekecektir. ViewState içerisinden saklanan bir değeri çõkarmak için Remove metodu,
programatik yollarla eklenen tüm verileri çõkarmak ise Clear metodu kullanõlabilir. Aşağõda bu
iki metodun kullanõmõ gösterilmiştir.

ViewState.Remove("tablo"); // tablo isimli nesne ViewState'den çõkarõlõr

26
ViewState.Clear(); // ViewState'e eklenen tüm kayõtlar silinir. (Kontrol bilgileri silinmez!)

ViewState Güvenliği
ViewState istemci tarafõnda HTML kodlarõ içerisinde Base64 encoding formatõnda
şifrelenerek saklandõğõndan bahsetmiştik. Bildiğiniz gibi istemcinin bilgisayarõnda veri
saklamamõzõ sağlayan durum yönetim nesneleri arasõnda, ViewState dõşõnda QueryString ve
Cookie nesneleri de bulunmaktadõr. QueryString ve Cookie içerisinde taşõnan verilere
kullanõcõ kolay bir şekilde erişebilmekte ve değişiklikler yapabilmektedir. ViewState
nesnesinde taşõnan veriler ise şifrelenmiş bir şekilde taşõnacağõ için okunabilir olmayacaktõr
ve diğer nesnelere göre daha güvenli bir veri taşõma yöntemi sunacaktõr diyebiliriz. Fakat
burada unutmamamõz gereken bir nokta var ki; verilerin saklandõğõ Base64 encoding formatõ
acemi bir programcõ tarafõndan dahi çok kolay bir şekilde çözümlenebilir. Base64 encoding
formatõnda saklanan verilerin geriye dönüştürülmesi kolay bir şekilde gerçekleştirilebileceği
için, ViewState nesnesinin çözümlenmesi ve içerisinde saklanan değerlerin görüntülenmesi
de çok kolay olacaktõr. (Internette ViewState Decoder şeklinde bir arama yapacak olursanõz
ViewState değerlerini çözümleyen çok sayõda araç ile karşõlaşabilirsiniz.) Eğer ViewState
içerisinde gizli bir bir güvenlik açõğõna sebebiyet verebilir. Bundan dolayõ ViewState'in
şifrelenmiş bir şekilde veri saklamasõna güvenerek, bir kullanõcõ veya site için güvenlik
sorununa yol açabilecek verileri taşõmamalõyõz. Peki ViewState'de şifrelenerek taşõnan bu
verileri biraz daha güvenli bir biçimde saklamak mümkün olabilir mi? MAC (Machine
Authentication Check) adõ verilen bir yapõ aracõlõğõyla ViewState nesnesinin kullanõcõ
tarafõndan değiştirilip değiştirilmediği ASP.NET sayfasõ tarafõndan algõlanabilmekte ve
kullanõcõya hata gönderilebilmektedir. Bir ASP.NET sayfasõnõn MAC mekanizmasõ bu tip
güvenlik nedenleriyle varsayõlan olarak açõk tutulmakta ve sayfa postback işlemine tabi
tutulduğunda sunucu tarafõnda sayfanõn asõl ViewState değeri ile o an kendisine gelen
ViewState değerlerini karşõlaştõrõp eğer farklõlõk varsa; yani ViewState nesnesi değiştirilmiş
ise kullanõcõya hata gönderilecektir. Bu ayarõn açõk bõrakõlmasõ bahsettiğimiz gibi güvenlik
açõsõndan gereklidir. Fakat bu durumda sayfa üzerinde postback işlemi yapõldõğõnda sunucu
tarafõnda ekstra kontrol işlemleri yapõlacağõnõ ve performans açõsõndan bazõ kayõplarõmõz
olacağõnõ da unutmamak gerekir. Eğer sayfada ViewState'de taşõnan değerlerin kullanõcõ
tarafõndan değiştirilmesinin güvenlik açõsõndan bir sakõncasõ yok ise, bu özelliği kapatmak
isteyebiliriz. Sayfa bazõnda bu özelliği kapatmak istiyorsak Page direktifini, site genelinde
kapatmak istiyorsak web.config dosyasõnõ kullanabiliriz. Aşağõdaki örneklerde sadece bir
sayfa içerisinde ve web.config dosyasõ içerisinde eklenecek kodlar görülmektedir.

<%@ Page Language="C#" AutoEventWireup="true" EnableViewStateMac="true"


CodeFile="Default.aspx.cs" Inherits="_Default" %>

<system.web>
.....
.....
<pages enableViewStateMac="false"></pages>

27
.....
</system.web>

Bu yazõmõzda, durum yönetiminde sõklõkla kullandõğõmõz ViewState nesnesinin davranõşlarõnõ,


nerelerde ne şekilde verileri sakladõğõnõ, bu nesne içerisinde ne şekilde nesneler
saklayabileceğimizi, performans ve güvenlik açõsõndan dikkat etmemiz gereken noktalarõ
incelemeye çalõştõk.

28
ASP.NET 2.0 - Sayfa Direktifleri (Page Directives)
26 Ağustos 2007

Sayfa direktifleri, ASP.NET uygulamalarõnda bir sayfanõn temel anlamdaki özelliklerini,


davranõşlarõnõ, kullanacağõ bazõ dõş kaynaklarõn tanõmlamalarõnõn yapõlmasõnõ sağlayan ve
ASP.NET sayfalarõnõn Source kõsmõnda (HTML kodlarõnõn olduğu kõsõmda) en üste
yerleştirilen kod parçalarõdõr. Sayfa direktifleri ile yapõlan ayarlamalar sayfanõn derleyici
tarafõndan nasõl çalõşacağõnõ, nasõl ele alõnacağõnõ ve hangi kaynaklarõ kullanacağõnõ belirler.
Bu anlamda bir ASP.NET sayfasõ ile çalõşõrken bu tip ayarlamalarõ yapmamõzõ sağlayan sayfa
direktifleri yakõndan tanõmak, kullanõmõna hakim olmak, biz ASP.NET programcõlarõ için
önemli olacaktõr.

Sayfa direktifleri ASP.NET'in 1.0 sürümünden beri tüm sayfalarda kullanõlmaktadõr. ASP.NET
2.0 ile birlikte gelen bazõ yeni dosya tipleri (Master Sayfalar gibi) ve çalõşma mekanizmalarõ
(CrossPage Postback gibi) ile birlikte, yeni sayfa direktifleri de ASP.NET'in yapõsõna
eklenmiştir. Bu makalemizde bir sayfada kullanõlabilecek tüm direktifleri detaylõ bir şekilde ele
alõyor olacağõz. Aşağõdaki listede ASP.NET sayfalarõnda kullanõlabilecek sayfa direktiflerinin
listesi bulunmaktadõr.

1. Page
2. Assembly
3. Control
4. Implements
5. Import
6. Master
7. MasterType
8. OutputCache
9. PreviousPageType
10. Reference
11. Register

Aslõnda listenin ilk sõrasõnda gördüğümüz Page direktifi bize oldukça tanõdõk gelecektir. Zira
her .aspx uzantõlõ sayfanõn HTML kodlarõnõn en üst kõsmõnda bulunan Page direktifi üzerinde
değişiklik yapmasak dahi ne amaçla kullanõldõğõnõ az-çok bilmekteyiz. Page direktifinin
kullanõmõnõ şöyle bir bakacak olursak;
<% @Page ...... %>
şeklinde bir tanõmlamaya sahip olduğunu görürüz. Aslõnda bu tanõmlama tüm sayfa direktifleri
için geçerli bir tanõmlama şeklidir. Yukarõdaki listede gördüğünüz 11 sayfa direktifi <%
@DirektifAdõ şeklinde başlar, devamõnda gerekli niteliklerine (attribute) atamalar yapõlarak
ayarlamalar yapõlõr ve %> ifadesi ile de direktifin sonlandõrõldõğõ derleyiciye bildirilir. Burada
görülen <% %> ifadeleri asp söz diziminde, sunucu tarafõnda çalõştõrõlacak etiket anlamõna
gelmekte, @ işareti ise çalõştõrõlacak ifadenin bir sayfa direftifi ifadesi olduğunu belirtir. Direktif
içerisinde ise gerekli tanõmlamalar NitelikAdõ="Değeri" şeklinde yapõlacaktõr.

29
Dilerseniz sayfa direktiflerinin kullanõmõnõ, gerekli ve önemli nitelikleri ile birlikte tek tek ele
alalõm.

1. Page Direktifi
Page direktifi ASP.NET sayfalarõnda kullanõlan en temel ve önemli direktiftir. İçerisinde
yapõlan tanõmlamalar ile bulunduğu sayfanõn derleyici tarafõndan nasõl, ne şekilde ele
alõnacağõnõ ve hangi özelliklerle birlikte derlenip çalõştõrõlacağõnõ belirler. Page direktifi zorunlu
olmamakla birlikte, tüm .aspx sayfalarõnda bulunmaktadõr. Page direktifi ile birlikte
kullanõlacak önemli nitelikler (attribute) aşağõda bulunmaktadõr.

- Async: Sayfanõn asenkron şekilde çalõşmasõnõ belirler. true değeri alõrsa sayfa asenkron
şekilde çalõşabilir hale gelir, false değer aldõğõnda senkron şekilde çalõşõr.
- AutoEventWireup: Sayfanõn yaşam döngüsü içerisinde olaylarõ (event) için tanõmlanmõş
olan metot isimlerinin kullanõlõp kullanõlmayacağõnõ belirler. Eğer true değeri alõrsa Page_Init,
Page_Load, Page_PreRender gibi önceden tanõmlanmõş metot isimleri olaylara bağlanarak
kullanõlõr. Eğer false değeri alõrsa kullanõcõ kendisi olaylara farklõ metot isimleri bağlayabilir.
Varsayõlan değeri true'dur.
- CodeFile: Sayfanõn code-behind dosyasõnõ belirler. Yani aspx sayfasõ çalõştõrõldõğõnda hangi
kod sayfasõ ile birlikte derleneceği bu nitelik ile belirlenir. Default.asp.cs gibi.
- Culture: Sayfanõn para birimi, tarih ve ölçü birimleri gibi kültür (culture) bilgilerinin hangi dile
göre getirileceğini belirler.
- UICulture: Sayfanõn görsel arayüzündeki dile göre değişebilen içeriklerin sayfa
oluşturulduğunda hangi dil kullanõlarak üretileceğini belirler.
- EnableTheming: Site genelinde tema ayarlamalarõ açõk ise, temalandõrma işleminin
sayfaya uygulanõp uygulanmayacağõnõ belirler. Eğer web.config'den uygulama için bir tema
ayarlamasõ yapõlmõş ise ve bu nitelik true değerini taşõrsa tema sayfaya uygulanõr, false
değerini taşõrsa tema sayfaya uygulanmaz.
- EnableViewState: Sayfa içerisindeki kontrollerin PostBack işlemi sonucunda değişen
özelliklerinin ViewState nesnesi içerisinde taşõnõp taşõnmayacağõnõ belirler. true değeri alõrsa
sayfadaki bütün kontrollerin özellikleri ViewState'de taşõnõr, false değeri alõrsa taşõnmaz.
Varsayõlan değeri true'dur.
- ErrorPage: Sayfada hata oluşmasõ durumunda, sayfanõn hangi hata sayfasõna
yönlendirileceğini belirler.
- Inherits: Sayfanõn compile işlemi yapõlõrken hangi sõnõftan (class) kalõtõlacağõnõ ve hangi
sõnõfõn örnekleneceğini belirler. Varsayõlan olarak sayfanõn code-behind dosyasõnda yazõlan
sõnõf adõ, yani dosya ile aynõ ismi taşõyan sõnõf adõ bu değere atanõr. Default2.aspx sayfasõnda
Default2 gibi.
- Language: Sayfanõn hangi .NET destekli dil ile yazõldõğõnõ belirler. C# dilinde yazõlmõş ise
C#, VB.NET dilinde yazõlmõş ise VB gibi.
- MasterPageFile: Sayfa eğer bir master sayfadan türetilmiş ise, türetilen master sayfanõn
adõ atanõr. SiteMaster.master isimli master sayfadan türetilen sayfa için SiteMaster.master
bilgisini taşõr.
- MaintainScrollPositionOnPostback: Sayfanõn PostBack işlemi sonucunda yenilenmesi
durumunda, sayfanõn otomatik olarak kullanõcõnõn son olarak konumlandõğõ yere getirilmesi
işlemini yapar. Yani kullanõcõ scroll bar ile sayfayõ aşağõya doğru hareket ettirip, ardõndan da
sayfayõ yenilerse, yenileme işlemi sonrasõnda tarayõcõ sayfanõn en üstüne değil de

30
kullanõcõnõn son olarak kaldõğõ kõsma konumlanõr. true değeri alõrsa burada bahsedildiği gibi
davranõr. false değeri almasõ durumunda ise yenileme işlemi sonunda sayfanõn en üstüne
gelinir.
- Theme: Sayfanõn App_Themes klasöründe oluşturulmuş site şemalarõndan birini
uygulamasõnõ sağlar.
- Title: Sayfanõn tarayõcõdaki başlõk bilgisini belirler.
- Trace: Sayfada trace (izleme) işlemlerinin yapõlõp yapõlmayacağõnõ belirler. Varsayõlan
değeri false'dur ve trace işlemi yapõlmaz. true değeri atandõğõnda sayfada trace işlemi yapõlõr.
- ValidateRequest: Sayfadaki bilgilerin sunucuya gönderilmesi esnasõnda, form içerisinde
taşõnan bilgilerde güvenlik açõsõndan sorun çõkarabilecek içerikler var ise (örneğin kullanõcõ
bir TextBox içerisinde <span> <b> <script>....</script> gibi ifadeler yazdõysa) sayfanõn hata
vermesini ve bilgilerin gönderiminin iptal edilmesini sağlar. Güvenlik açõsõndan önemli bir
niteliktir. Varsayõlan değeri true'dur ve yukarõda bahsedildiği gibi bir işlem gerçekleşirse işlemi
iptal eder ve hata verir. false ise tehlikeli bir içerik bulunsa bile gönderilen bilgileri kabul
edecektir.

Aşağõdaki kod örnekğinde bir ASP.NET sayfasõna uygulanabilecek Page direktifi


görülmektedir.

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Default.aspx.cs"


Inherits="_Default"
Culture="tr-TR" UICulture="tr-TR" EnableViewState="false"
ErrorPage="Hata.aspx" %>

Yukarõdaki örnekte sayfanõn C# dili ile kodlandõğõ, sayfa olaylarõnõn varsayõlan metotlara
bağlandõğõ, sayfanõn C# kodlarõnõn Default.aspx.cs dosyasõnda bulunduğu, sayfanõn _Default
adõnda bir sõnõftan türetildiği, sayfanõn kültür (culture) bilgisinin tr-TR yani Türkçe dili olduğu,
sayfa içerisindeki kontrollerin değerlerinin ViewState içerisinde saklanmayacağõ ve sayfada
bir hata oluşursa sayfanõn otomatik olarak Hata.aspx isimli sayfaya yönlendirileceği
belirtilmiştir.

2. Assembly Direktifi
İlgili sayfaya kullanõcõnõn oluşturmuş olduğu bir assembly'nin eklenmesini sağlar. Böylece
sayfa içerisinde ilgili assembly'de bulunan tipler (class, struct gibi) kullanabilmektedir.
web.config dosyasõ içerisinde <assembly> düğümüne add etiketi ile uygulamaya assembly
ekleme işleminin sayfa bazõnda yapõlmasõnõ sağlar. Assembly direktifinin alabileceği iki nitelik
vardõr:

- Name: İlgili assembly'nin adõnõn verilmesi gereklidir. Burada assembly dosyasõnõn


uzantõsõnõ yazmaya gerek yoktur.
- Src: İlgili assembly dosyasõnõn bulunduğu yer ve dosya adõnõn verilmesi gereklidir.

Assembly direktifinin örnek kullanõmlarõ aşağõda görülmektedir.

31
<%@ Assembly Name="AssemblyIsmi" %>

Assembly direktifinin iki niteliği de aynõ işlemi yapmakta ve bir Assembly direktifi içerisinde
aynõ anda bunlardan sadece bir tanesi kullanõlabilmektedir.

3.Control Direktifi
Bir user control'ünün (kullanõcõ kontrolü) özelliklerinin belirlenmesini sağlar. Böylece
ASP.NET'in bu user control'ünü ne şekilde ele alacağõ ve nasõl derleyeceği belirlenir.
Bildiğiniz gibi user control'ler ascx uzantõsõ ile saklanan, içerisinde ASP.NET kontrolleri ve
HTML kodlarõ bulundurabilen ve ASP.NET web sayfalarõnõn belirli parçalarõnõ oluşturan
dosya tipleridir. Bir aspx sayfasõ içerisindeki Page direktifi ile ascx kontrolünde kullanõlan
Control direktifinin hemen hemen aynõ işlevleri olduğunu söyleyebiliriz. Control direktifi
sadece user control'lerinde kullanõlabilmektedir.

Control direktifinin nitelikleri, Page direktifinin niteliklerine göre az sayõda olmakla beraber,
niteliklerin kullanõmõ ve yaptõklarõ işlemler hemen hemen aynõdõr. Yukarõda, Page direktifi
kõsmõndaki niteliklere ve açõklamalarõna göz atmak, Control direktifinin kullanõmõ ile ilgili bize
yeterli bilgi verecektir. Aşağõda Control direktifinin bir user control'ünde kullanõmõ ile ilgili bir
örnek yer almaktadõr.

<%@ Control Language="C#" AutoEventWireup="true" CodeFile="Login.ascx.cs"


Inherits="Login" EnableViewState="false" %>

4. Implements Direktifi
.NET Framework'te tanõmlõ olan bir interface'i (arayüz) sayfaya uygulamak için kullanõlan
direktiftir. Uygulanan interface'e ait metotlar ve property'ler (özellik) aspx dosyasõ içerisinde
açõlacak <script> etiketinde yazõlarak sayfaya uygulanabilir. Implements direktifi sadece
Interface niteliğini kullanmaktadõr.

- Interface: Sayfaya uygulanacak .NET interface'inin belirtilmesi gereklidir.

Aşağõdaki örnekte, System.Web.UI namespace'i (isim alanõ) altõnda yer alan IValidator isimli
interface'in bir sayfaya Implements direktifi ile uygulanõşõ görülmektedir.

<%@ Implements Interface="System.Web.UI.IValidator" %>

5. Import Direktifi
Sayfaya bir namespace'in eklenmesi için kullanõlan direktiftir. .NET Framework yapõsõnda
bulunan veya projede tanõmlanmõş olan herhangi bir namespace Import direktifi ile sayfaya
eklenebilir. web.config dosyasõ içerisinde uygulama genelinde kullanõlabilecek
namespace'lerin eklenmesi gibi, sadece bir sayfaya namespace'lerin eklenmesi işlemi için de

32
Import direktifi kullanõlabilir. Import direktifi ile sadece Namepace niteliği kullnõlõr.

- Namespace: Sayfaya eklenecek namespace'in belirtilmesi gerekir.

Aşağõdaki örnekte Import direktifi ile bir sayfaya namespace eklemeleri yapõlmõştõr.

<%@ Import Namespace="System.Data.SqlClient" %>


<%@ Import Namespace="KendiIsimAlanim" %>

6. Master Direktifi
Bir Master page'in özelliklerinin belirlenmesini sağlayan direktiftir. Page direktifi web form
sayfalarõnda(aspx), Control direktifi user control'lerde(ascx) olduğu gibi, Master direktifi de
master page'lerin ASP.NET derleyicisi tarafõndan ne şekilde ele alõnacağõnõ belirler.
Kullanõlan nitelikler ve niteliklerin kullanõm amaçlarõ Page ve Control direktifleri ile hemen
hemen aynõdõr. Bu nitelikler için Page direktifi kõsmõndaki nitelik açõklamalarõna göz
atabilirsiniz. Aşağõda bir master page dosyasõnda kullanõlabilecek Master direktifi
görülmektedir.

<%@ Master Language="C#" AutoEventWireup="true"


CodeFile="SiteSablonu.master.cs" Inherits="SiteSablonu" %>

7. MasterType Direktifi
Master page'den türetilen bir ASP.NET sayfasõndaki Page.Master property'si MasterPage
tipinden bir değer döndürmekte ve böylece master page ile ilgili işlemler yapõlabilmektedir.
Bazõ durumlarda master page sõnõfõ içerisinde tanõmlanmõş özel bir property (özellik) veya
metoda Page.Master özelliği ile direkt olarak erişilmek istenilebilir. Böyle bir durumda
Page.Master özelliğini ilgili master page'in tipine cast (dönüştürme) işlemi yapmak
gerekecektir. İlgili sayfadan master page'in nesne örneğine cast işlemi yapõlmadan erişilmek
istenilirse, bu sayfaya MasterType direktifi eklenmesi gerekecektir. MasterType direktifi
içerisinde tanõmlanan master page'in otomatik olarak Page.Master özelliğinin geri dönüş tipi
olmasõnõ sağlar ve böylece master page'deki özel property veya metoda direkt olarak erişme
işlemi gerçekleştirilebilir. Aşağõda MasterType direktifinin alabileceği nitelikler ve bu
niteliklerin açõklamalarõ yer almaktadõr.

- TypeName: Content page'de Master özelliğinin geri dönüş tipi olmasõ istenilen master
page'in tip adõnõ alõr.
- VirtualPath: Content page'de Master özelliğinin geri dönüş tipi olmasõ istenilen master
page dosyasõnõn dosya yolunu ve ismini alõr.

Örnekteki MasterType direktifi, content page içerisindeki Master özelliğinin geri dönüş tipinin
SiteSablonu.master isimli master page dosyasõ olduğunu belirler.

33
<%@ MasterType VirtualPath="~/SiteSablonu.master" %>

Resim-1: MasterType direktifi eklenilmediğinde Page.Master property'si MasterPage


nesne örneğini getirir ve master page'deki üyelere erişmek için cast işlemi gerekir

Resim-2: MasterType direktifi eklendiğinde artõk Page.Master property'si master


page'in nesne örneğini getirir

Resim-3: Master property'si master page'in nesne örneğini getirdiği için content
page'den direkt olarak master page üyelerine erişebiliriz

8. OutputCache Direktifi
ASP.NET uygulamalarõnda sayfanõn çõktõsõnõ önbelleğe alma işlemlerinde (Caching)
kullanõlan direktiftir. Sayfaya OutputCache direktifini eklediğimizde ve gerekli nitelikleri
tanõmladõğõmõzda, sayfanõn HTML çõktõsõ bellekte saklanõr, sayfa belirli bir süre boyunca
tekrar çalõştõrõlmaz ve bellekten okunur. OutputCache direktifi ile yapõlan önbellekleme
işlemleri sayfanõn daha hõzlõ şekilde istemciye gönderilmesini sağlar.

- CacheProfile: web.config içerisinde tanõmlõ olan Cache profillerinden birinin sayfaya


uygulanõlmasõ istenilen durumda kullanõlan niteliktir.
- DiskCacheable: Verilerin disk ve benzeri bir depolama cihazõna alõnõp alõnamayacağõnõ
belirler.
- Duration: Önbelleğe alõnacak sayfanõn ne kadar süre ile bellekten okunacağõnõ belirler.
Saniye cinsinden rakamsal değer almaktadõr.
- Location: Önbelleklenen verilerin nereye kaydedileceğini belirler. Varsayõlan olarak Any
değerini taşõr. Bu değer verilerin istemci, proxy ve sunucuda taşõnabildiğini belirtir. İstenirse

34
sadece sunucuda, istemcide veya proxy'de saklanmasõ sağlanabilir. Alabileceği diğer
değerler; Client, Server, Downstream, ServerAndClient ve None'dir.
- NoStore: Sayfanõn header (başlõk) bilgilerinde "no cache" bilgisinin gönderilip
gönderilmeyeceğini belirler.
- SqlDependency: Sayfanõn SQL Server veritabanõndaki bir tablonun değişimine bağõmlõ
olarak önbelleklenmesi durumunda kullanõlacak niteliktir. Bu özelliğe değer atayabilmek için,
web.config dosyasõndaki caching düğümünde bulunan sqlCacheDependency içerisine bir
veritabanõ tanõmlamasõ yapõlmalõdõr.
- VaryByControl: Sayfadaki bir kontrolün değişimine göre önbellekleme işleminin
yapõlmasõnõ sağlar. Değer olarak önbellekleme işleminin yapõlmasõnõ sağlayacak kontrolün ID
değerini almalõdõr.
- VaryByCustom: Farklõ değerlere ve kriterlere göre önbellekleme işlemlerinin yapõlmasõ
durumunda kullanõlacak niteliktir. Bu niteliğin alacağõ değerin yakalanõp ele alõnabilmesi için
Global.asax dosyasõ içerisindeki GetVaryByCustomString isimli metodun ezilmesi (override
edilmesi) gerekmektedir.
- VaryByHeader: Sayfanõn HTML kõsmõnda yer alan header (başlõk) bilgilerine göre
önbellekleme işlemlerinin yapõlmasõnõ sağlar.
- VaryByParam: Sayfanõn Url'den gelen QueryString parametrelerine göre önbelleğe alõnõp
alõnmayacağõnõ belirler. Varsayõlan değeri None'dir ve parametreleri dikkate almaksõzõn
sayfanõn belleğe alõnmasõnõ sağlar. QueryString'deki herhangi bir parametrenin adõnõ alarakta
bu değere göre sayfanõn farklõ kopyalarõnõn önbellekleğe alõnabilmesini sağlar. Bu niteliğin
her OutputCache direktifi içerisinde yazõlmasõ zorunludur.

Aşağõda bir sayfanõn HTML çõktõsõnõ QueryString bilgisine bakmaksõnõz 30 saniye süre ile
istemcinin bilgisayarõnda önbelleğe atan OutputCache direktifi bulunmaktadõr.

<%@ OutputCache Duration="30" Location="Client" VaryByParam="None" %>

9. PreviousPageType Direktifi
Cross-Page PostBack işlemlerinde hedef sayfaya gelinen kaynak sayfanõn nesne örneğini
elde etmek için kullanõlan direktiftir. Normal koşullarda sayfanõn code-behind kõsmõnda elde
ettiğimiz PreviousPage nesnesi Page tipinden nesne örneği döndürmektedir. Eğer
PreviousPage nesnesin üzerinden önceki sayfanõn nesne örneğini elde etmek istiyorsak
sayfa içerisine PreviousPageType direktifi eklemek gerekecektir. PreviousPageType
direktifinin alabileceği nitelikler ve açõklamalarõ aşağõdadõr.

- TagName: PreviousPage nesnesinin hangi sõnõfõn nesne örneğini oluşturacağõnõ belirler.


- VirtualPath: PreviousPage nesnesinin hangi sayfayõnõn nesne örneğini oluşturacağõnõ
belirler.

Aşağõdaki PreviousPageType direktifi eklendiği sayfada PreviousPage nesnesinin


Source.aspx sayfasõnõn nesne örneğini dönmesini sağlar.

<%@ PreviousPageType VirtualPath="~/Source.aspx" %>

35
Dilerseniz PreviousPageType direktifinin sayfaya ne gibi bir etkisi olduğunu daha iyi
anlayabilmek için aşağõdaki resimleri inceleyelim. Resim-4'te PreviousPageType direktifi
eklenmemiş bir sayfada PreviousPage nesnesinin geri dönüş tipinin Page class'õ olduğunu
görebilirsiniz. Resim-5'te ise sayfaya PreviousPageType direktifi eklendiğinde sayfanõn
PreviousPage nesnesinin Source.aspx sayfasõnõn nesne örneğinin döndürdüğü
görülmektedir. Böylece artõk PreviousPage'den önceki sayfanõn nesne örneğine ulaşõlabilir ve
önceki sayfanõn class'õ içerisinde metot, property gibi üyeler çağrõlabilir.

Resim-4: PreviousPageType direktifi eklenmemiş bir sayfada PreviousPage


nesnesinin geri dönüş tipinin Page class'õdõr

Resim-5: PreviousPageType direktifi eklendiğinde PreviousPage nesnesinin geri


dönüş tipi Source.aspx sayfasõnõn nesne örneğidir

10. Reference Direktifi


Uygulamada bulunan bir ASP.NET sayfasõnõn veya ASP.NET user control'ün sayfaya
referans olarak eklenmesi ve sayfa ile birlikte derlenmesini sağlar. Böylece eklenen sayfanõn
veya user control'ün class'õna sayfa içerisinden erişilebilir.

- Control: Sayfaya referansõ eklenecek kontrol dosyasõnõn adõ.


- Page: Sayfaya eklenecek olan aspx sayfasõnõn dosya adõ.
- VirtualPath: Projede bulunan bir dosyanõn yolu ve dosya adõ. Page ve Control niteliklerinin
yerine de kullanõlabilir.

Aşağõdaki Reference direktifi ile sayfaya referansõ eklenen Default2.aspx sayfasõnõn class'õna
erişilebilir.

<%@ Reference VirtualPath="~/Default2.aspx" %>

11. Register Direktifi


Register direktifi projede veya bir assembly dosyada bulunan user control'ün sayfaya kayõt
edilmesi işleminde kullanõlmaktadõr. Hazõrlanan bir user control'ün sayfadaki HTML etiketleri
içerisine ASP.NET sunucu kontrolü gibi eklenebilmesi için öncelikli olarak sayfada kayõtlõ
olmasõ; yani Register direktifi ile eklenmesi gerekecektir. Aşağõda Register direktifi ile
kullanõlabilecek nitelikler ve açõklamalarõ yer almaktadõr.

36
- Assembly: Eklenecek user control'ün assembly'si. Eğer user control aynõ projede ise
kullanmaya gerek yoktur.
- Namespace: Eklenecek user control'ün hangi namespace içerisinde bulunduğunu belirler.
User control aynõ projede ise kullanmaya gerek yoktur.
- Src: User control'ün uygulamada bulunduğu yer ve dosya adõ.
- TagName: Kullanõlacak user control'ün adõ
- TagPrefix: HTML kodlarõ içerisinde user control ekleneceği zaman hangi etiket adõ ile
çağrõlacağõ bilgisidir. (TagName ve TagPrefix niteliklerinin kullanõmõ için aşağõdaki kod
örneklerine bakmakta fayda var)

Aşağõdaki Register direktifi ile sayfaya LoginKontrolum adõndaki bir user control'ü eklenmiştir.
Böylece sayfaya TagName ve TagPrefix bilgileri ile ilgili dosyadaki user control eklenebilir.

<%@ Register Src="Login.ascx" TagName="LoginKontrolum"


TagPrefix="myControls" %>

<myControls:LoginKontrolum ID="LoginKontrolum1" runat="server" />

Böylece ASP.NET uygulamalarõnda kullanabileceğimiz 11 sayfa direktifini detaylõ bir şekilde


incelemiş olduk.

37
ASP.NET 2.0 - Performans Yönetimindeki Yenilikler
02 Eylül 2007

Bir web uygulamasõ geliştirilirken göz önüne alõnacak en önemli unsurlardan birisi de
uygulamanõn performansõdõr. ASP.NET'in ilk sürümleri ile birlikte gelen yeniliklerde özellikle
uygulamanõn performansõnõ arttõrma işlemlerini oldukça kolay, pratik ve gerçekten etkili bir
şekilde gerçekleştirebilmekteydik. En temel performans bakõmõ tekniklerimiz olan
OutputCache ile sayfa çõktõsõnõ, Cache nesnesi ile de sayfa içerisindeki bir nesneyi belirli bir
süre bellekte saklayabilmekte ve sonraki erişimlerde sayfanõn çok daha hõzlõ bir şekilde
çalõşabilmesini sağlayabilmekteyiz. ASP.NET 2.0 ile birlikte birçok alanda gelen yenilikler
arasõnda performans yönetimi konusunda da bazõ yeni teknikler ve kullanõm kolaylõklarõ
getirilmiştir. Bu yazõmõzda da ASP.NET 2.0 ile birlikte gelen bu yenilikleri inceliyor olacağõz.

ASP.NET 2.0 ile gelen yenilikleri şu başlõklar altõnda toplayabiliriz:

1. Cache Profilleri (Cache Profiles) ile OutputCache mekanizmasõnõn daha kolay şekilde
yönetilebilmesi
2. Post-Caching ve Substitution kontrolü önbelleklenen sayfada dinamik alanlar
kullanabilme
3. SqlCacheDependency ile veritabanõndaki değişikliklere göre veri önbellekleme
4. DataSource kontrolleri ile önbellekteki veriler ile çalõşmak
5. Custom Dependency'ler oluşturabilme

Dilerseniz yukarõdaki başlõklarõ bizlere ne gibi yenilikler getirdiği ve uygulamalarda nasõl


kullanacabileceğimiz hususunda detaylõ bir şekilde ele alalõm.

1. Cache Profilleri (Cache Profiles)

ASP.NET'in ilk sürümünden beri bir sayfanõn tamamõnõn veya belirli bir kõsmõnõn HTML
çõktõsõnõn önbelleğe alõnmasõnõ ve sayfanõn çok daha hõzlõ bir şekilde çalõşmasõnõ
sağlayabilmekteyiz. Sayfa veya user control içerisine ekleyeceğimiz <%@ OutputCache ...
%> direktifi ile sayfanõn önbelleğe alõnma şeklini belirleyebiliyorduk. ASP.NET 2.0 ile birlikte
gelen Cache Profilleri ile birlikte sayfalarõmõzda ortak olarak kullanabileceğimiz OutputCache
ayarlamalarõnõ artõk web.config içerisinde düzenli bir şekilde saklayabilmekte ve sayfa
içerisinde OutputCache direktifinin bu profillerden birini kullanabilmesini sağlayabilmekteyiz.
Dilerseniz önce OutputCache direktifini sayfa içerisinde nasõl kullanabiliyorduk bir
hatõrlayalõm. Aşağõdaki kod parçasõnõ bir .aspx sayfasõndaki Page direktifinin alt kõsmõna
ekleyecek olursak; sayfa QueryString bilgisini dikkate almaksõzõn 60 saniye süre ile
önbelleğe alõnacaktõr.

<%@ OutputCache Duration="60" VaryByParam="None" %>

38
Cache profillerin bize ne gibi bir noktada fayda sağladõğõnõ görebilmek için şöyle bir senaryo
üzerinde duralõm. Varsayalõm ki uygulamamõz çok sayõda sayfadan oluşuyor ve bu sayfalarõn
bir grubunu farklõ şekilde, diğer grubunu farklõ şekilde önbelleğe alma işlemini
gerçekleştirmek istiyoruz. Şöyle ki;

Grup 1: A, B, C, D, E, F ve G sayfalarõnõ 600 saniye süre ile, QueryString verilerini


dikkate almadan
Grup 2: K, L, M, N, O ve P sayfalarõnõda 300 saniye süre ile UrunID QueryString değerine
göre

önbellekte saklama işlemi gerçekleştirelim. Böyle bir durumda yukarõdaki Grup 1 sayfalarõna
<%@ OutputCache Duration="600" VaryByParam="None" %> ifadesini, Grup 2
sayfalarõna da <%@ OutputCache Duration="300" VaryByParam="UrunID" %>
ifadelerini eklememiz gerekecekti. Varsayalõm ki belirli bir süre sonra Grup 1'deki sayfalarõn
çok uzun süre ile önbellekte tutulduğunu ve kullanõcõnõn güncel bilgiye erişemediğini gördük.
Yine Grup 2'deki sayfalarõnda sadece UrunID QueryString bilgilesine göre değil de, UrunID
ve Renk QueryString bilgilerine göre önbellekte saklanmasõnõ istiyoruz; yani sayfalardaki
OutputCache direktiflerini değiştirme ihtiyacõmõz var. Bu durum yukarõdaki 12-13 tane
sayfanõn tek tek açõlarak kod kõsõmlarõnda değişiklik yapõlmasõ anlamõna geliyor. Sayfa
sayõsõnõn 30-40 olduğunu düşünürsek durum biraz daha vahim hale geliyor:) İşte bu noktada
gruplanan iki OutputCache niteliğini web.config içerisinde saklayacak ve sayfalarõmõzda da
web.config'deki bu ayarlarõ kullanacak olursak artõk bilgileri tek bir noktada toplamõş ve
dolayõsõyla da bu değişiklikleri de çok basit bir şekilde sayfalara uygulamõş olacağõz. Peki
Cache profillerini web.config içerisinde ne şekilde saklayacağõz. Aşağõdaki kod parçalarõ ile
birlikte web uygulamasõna CacheProfil_A ve CacheProfil_B adõnda iki tane Cache profili
eklemiş oluyoruz.

<system.web>
.....
.....
<caching>
<outputCacheSettings>
<outputCacheProfiles>
<add name="CacheProfil_A" duration="600" varyByParam="None" />
<add name="CacheProfil_B" duration="300" varyByControl="UrunID"/>
</outputCacheProfiles>
</outputCacheSettings>
</caching>
</system.web>

Oluşturulan bu profilleri sayfalarda kullanabilmek için yapmamõz gereken OutputCache


direktifi içerisindeki CacheProfile özelliğini uygun profile name değerine atamak olacaktõr.
Aşağõda CacheProfile_B profilini kullanan bir sayfaya yazõlacak OutputCache direktifi
görülmektedir.

39
<%@ OutputCache CacheProfile="CacheProfil_B" %>

Böylece Cache profillerini kullanarak sayfalar içerisinde kullandõğõmõz OutputCache direktifi


bilgilerini web.config dosyasõndan okuyor ve daha yönetilebilir hale getirmiş oluyoruz.

2. Post-Caching ve Substitution Kontrolü Önbelleklenen Sayfada


Dinamik Alanlar Kullanabilme

ASP.NET'in önceki sürümlerinde sayfanõn tamamõnõ veya sadece belirli bir alanõnõ önbelleğe
alabiliyorduk. Fragment Caching adõ verilen bir teknikte sayfa içerisinde bir user-control
(ascx) dosyasõ ekleyerek sadece bu alanõn HTML çõktõsõnõ önbelleğe saklayabiliyor ve
sayfanõn diğer alanlarõnõn dinamik oluşmasõnõ sağlayabiliyorduk. Fakat sayfanõn tamamõnõ
önbellekten getirilirken sadece belirli bir alanõnõ dinamik oluşturma işlemini
gerçekleştiremiyorduk. ASP.NET 2.0 ile birlikte gelen yeniliklerle birlikte artõk bu tip bir
önbellekleme işlemini de gerçekleştirebilmekteyiz.

Resim: Substitution kontrolü ile önbelleklenen sayfadaki parçalarõn işleyişi

Fragment caching ile sayfanõn belirli bir alanõnõ önbelleğe alma işlemi oldukça pratik bir
işlemdi. Fakat burada yapõlacak işlemin biraz daha zor olacağõnõ söyleyebiliriz. Zira sayfanõn
dinamik olarak oluşturulacak kõsmõnõ her ne kadar bir kontrol aracõlõğõyla hazõrlõyor olsakta,
bu kontrolün içerisinde yazdõrõlacak HTML kodlarõnõ tamamen bizlerin yazmasõ gerekecek.
Post-Cache Substitution ile yapõlacak işlemde Response.WriteSubstitution metodu ile
HttpResponseSubstitutionCallback delegate'i (temsilci) aracõlõğõyla static bir metodu
işaretlememiz gerekir. Substitution kontrolü ile yapõlacak işlemde ise bu kontrolün
MethodName isimli özelliğin yine static olarak yazõlmõş özel bir metodun adõnõ vermeliyiz.
Tahmin edeceğiniz üzere sayfaya dinamik olarak gelecek HTML içerikler burada bahsetmiş
olduğumuz metotlardan getirilecektir. Dilerseniz bahsettiğimiz iki yolu sayfamõza nasõl
uygulayabileceğimiz bir bakalõm.

- Post-Cache Substitution

40
Bu yolu seçtiğimizde sayfamõzõn source kõsmõnda dinamik içeriğin geleceği kõsma
Response.WriteSubstitution metodu ile static metot çağrõmõnda bulunmamõz gerekir.
İsterseniz öncelikle burada bize gerekli olan metodu yazarak üzerinde biraz konuşalõm. Zira
bu metot ile ilgili konuşulmasõ gereken birkaç noktamõz var.

protected static string DinamikIcerik(HttpContext ctx)


{
return "<b>" + DateTime.Now.ToLongTimeString() + "</b>";
}

Yazacağõmõz metot dinamik içeriğimizi oluşturacak; yani HTML kodlarõmõzõ bize getirecek bir
metot olmalõdõr. Bundan dolayõ metodumuzun geri dönüş tipi string'dir ve return edilen HTML
kodlarõ dinamik içeriğimizi oluşturacaktõr. Bu sayfamõza bir istek geldiğinde sayfa içeriği
(dinamik alan dõşõndaki içerikler) önbellekten getirilecektir; yani sayfamõzõn tekrar
çalõştõrõlmasõna, dolayõsõyla da nesne örneğini oluşturulmasõna gerek yoktur. Bundan dolayõ
static bir metot yazacak olursak uygulamamõz sayfanõn nesne örneğine ihtiyaç duymadan bu
metodu çağõrabilecektir. Metodumuz HttpResponseSubstitutionCallback delegate'inin
işaretleyebileceği bir metot olmak zorunda olduğu için burada bir de HttpContext tipinden bir
metot parametresine ihtiyacõmõz vardõr. Bu parametre gelen istek ile ilgili bilgilerin
taşõnmasõnõ sağlar fakat pek kullanmaz. Böylece yazõlacak metodun detaylarõnõ irdelemiş
olduk. Peki metodu nasõl çağõracağõz. Aşağõdaki kodlarda görüldüğü gibi bir sayfa
tasarlayalõm.

......
<%@ OutputCache Duration="30" VaryByParam="none" %>
......
......
<form id="form1" runat="server">
<div>
Önbellekten gelen zaman: <%= DateTime.Now.ToLongTimeString() %>
<br /><br />
Dinamik zaman:
<% Response.WriteSubstitution(new
HttpResponseSubstitutionCallback(DinamikIcerik)); %>
</div>
</form>
.....

41
Resim: Post-Cache Substitution yolunu kullandõğõmõzda sadece belirli bir alanõn
dinamik oluşmasõnõ sağlayabiliriz.

Response.WriteSubstitution metodu ile sayfanõn HTML kõsmõna DinamikIcerik isimli


metodun geriye döndürdüğü string ifade yazõlmõştõr. Burada çalõşma zamanõ esnasõnda bir
metodu işaretlemek söz konusu olduğu için new
HttpResponseSubstitutionCallback(DinamikIcerik) şeklinde delegate nesnesi oluşturup
DinamikIcerik isimli metodu işaretlememiz gerekir. Bu teknikte gerek metodun yazõmõnda
gerekse metodun çağrõmõnda biraz zorlukla karşõlaşabileceğizi söyleyebiliriz.

- Substitution Kontrolü
Post-Cache Substitution yolu yazõlan metodu işaretlemede biraz zorlayõcõ olduğu için bu tip
durumlarda Substitution kontrolünü kullanmak daha kolay bir çözüm olabilir. Aslõnda bu iki
yolda da yapõlan işlemler aynõdõr, sadece kontrol üzerinde çalõştõğõmõzda metodu
işaretlememiz daha pratik olacaktõr. Aşağõdaki kodlarda Substitution kontrolünün sayfaya
nasõl uygulanabileceğini görebiliriz.

......
<%@ OutputCache Duration="30" VaryByParam="none" %>
......
......
<form id="form1" runat="server">
<div>
Önbellekten gelen zaman: <%= DateTime.Now.ToLongTimeString() %>
<br /><br />
Dinamik zaman:
<asp:Substitution ID="Substitution1" runat="server" MethodName="DinamikIcerik" />
</div>
</form>
.....

Görüldüğü gibi Substitution kontrolünin MethodName özelliğini metodun adõ olarak

42
belirlemek yeterli olacaktõr. Böylece sayfadaki Substitution kontrolünün içeriği dinamik şekilde
oluşturulacaktõr. Substitution kontrolünün içeriği dõşõnda kalan bölgelerin içerikleri ise
önbellekten getirilecektir.

3. SqlCacheDependency ile Veritabanõndaki Değişikliklere Göre Veri


Önbellekleme

ASP.NET 2.0'dan önceki sürümlerde önbellekleme işlemleri CacheDependency sõnõfõ ile


zamana bağõmlõ kalmadan, bir dosyanõn veya klasörün değişim durumuna göre
gerçekleştirilebilmekteydi. Yine bu sõnõf aracõlõğõyla veritabanõnda bir tablodaki değişimlere
bağõmlõ kalarak önbellekleme işlemleri yapõlabilmekteydi. Fakat bu işlemleri yapabilmek için
gerek vertiabanõnda oluşturulacak nesneler(tablo, trigger ve stored procedure gibi) gerekse
uygulamada yapõlacak işlemler programcõ için oldukça zor işlemlerdi. ASP.NET 2.0'da gelen
yeni SqlCacheDependency class'õ ve aspnet_regsql.exe aracõnõn SqlCacheDependency
seçenekleri ile gerek veritabanõnda oluşturulacak nesneler, gerekse uygulama içerisinde
yapõlacak işlemler artõk çok daha kolay bir hale geldi.

SqlCacheDependency çok detaylõ bir mevzu olduğu için başlõ başõna bir makale olarak ele
almakta fayda olabilir. Biz burada olabildiğince kõsa bir şekilde bu mekanizmayõ incelemeye
ve uygulamalarda nasõl kullanabileceğimizi göreceğiz. Öncelikli olarak
SqlCacheDependency'nin uygulama ve veritabanõ tarafõndaki bileşenlerini inceleyelim.
Veritabanõndaki bir tablonun değişimine göre önbellekleme işlemleri yapabilmek için mutlaka
veritabanõ ile bütünleşik şekilde çalõşmak, yani veritabanõ içerisinde bazõ nesneleri kullanmak
gerekecektir. Burada esas alõnacak durum verilerin asõl getirildiği tablonun verilerini kontrol
etmek yerine bizim aracõ bir tablo üzerinden asõl verilerin saklandõğõ tablonun kontrolünü
yapmaktõr. Zira verilerin saklandõğõ tablomuzda binlerce kayõt bile olabilir. Böyle bir tablonun
değişip değişmediğini trigger'lar aracõlõğõyla başka bir tabloya aktarmak ve kontrollerin bu
tablo üzerinden gerçekleştirmek çok daha hõzlõ olacaktõr. Uygulama içerisinde kullanacağõmõz
SqlCacheDependency tipindeki nesnemiz tablonun değişip değişmediğini belirli aralõklarla
veritabanõndan kontrolünü yapacak ve eğer tabloda değişiklik olmuşsa Cache'de saklanacak
verinin değiştirilmesini sağlayacak. Bu işleyişi daha iyi anlamak için aşağõdaki şekil üzerinden
konuşmaya devam edelim.

43
Resim: SqlCacheDependency mekanizmasõnõn çalõşma şekli

Görüldüğü gibi Cache nesnesinde saklanan veriler SqlCacheDependency nesnesi ile


bütünleşik şekilde veritabanõndaki tabloya bağõmlõ bir biçimde tutulmaktadõr. Cache'de
saklanan veriler istenildiğinde SqlCacheDependency nesnesi veritabanõndaki değişim olup
olmadõğõnõ kontrol etmek için haber veren tabloya (notification table) bakacak ve değişim
yoksa Cache'de saklanan veri aynen kullanõlacaktõr. Eğer SqlCacheDependency nesnesi
notification table'da ilgili kaydõn değiştiğini görürse (ki bu Urunler tablosunda bir değişiklik
yapõldõğõ anlamõna gelir) Cache'deki nesnenin kaldõrõlmasõnõ sağlar. Bu noktadan sonra
programcõ uygulamada yazdõğõ kodlar ile Cache'den kaldõrõlmõş nesneyi tekrar doldurarak
uygulamaya güncel verilerin aktarõlmasõnõ sağlayacaktõr.

Bir projede SqlCacheDependency tekniğini uygulamak biraz zor bir yoldur. Gelin adõm adõm
bu işlemi nasõl gerçekleştirebileceğimize bakalõm.

Adõm-1
SQL Server'da ilgili notification table, trigger ve stored procedure'larõn kurulmasõ gereklidir.
aspnet_regsql.exe aracõ ile bu işlemi kolay bir şekilde gerçekleştirebileceğiz.
aspnet_regsql.exe .NET Framework SDK v2.0 ile birlikte gelen araçlardan biridir. SDK
Command Prompt'ta yazõlacak komutlarla önce ilgili tablonun bulunduğu veritabanõna ilgili
notification table, trigger ve stored procedure'larõn kurulmasõ gerekecektir. Başlat >
Programlar > Microsoft .NET Framework SDK v2.0 > SDK Command Prompt
seçeneğinden komut satõrõnõ açtõktan sonra aşağõdaki resimlerde görülen komutlarõ yazarak
bu işlemi gerçekleştirelim.

Not: Komutlarda yazõlan parametrelerden


-S localhost: localhost isimli sunucu

44
-E: Windows Authentication ile bağlan
-d AdventureWorks -ed: AdventureWorks veritabanõnõ aktif hale getir
-t Urunler -et: Urunler isimli tabloyu aktif hale getir
anlamõna gelmektedir. Farklõ durumlarda kullanõlabilecek parametreler için Command
Prompt'ta aspnet_regsql -? komutunu yazarak yardõm alabilirsiniz.

Resim: AdventureWorks veritabanõnda SqlCacheDependency nesneleri kuruldu ve


veritabanõ aktif hale geldi

Veritabanõ aktif hale geldi. Bu işlem sonunda AdventureWorks veritabanõna notification table
ve stored procedure'lar kuruldu. Bir sonraki adõmda ise artõk ilgili tabloyu aktif hale
getirmemiz gerekecek. Aşağõdaki resimde gördüğümüz komutla da Urunler adõndaki tabloyu
aktif hale getireceğiz.

Resim: Urunler isimli tablo veritabanõnda aktif hale geldi

Bu komut ile de Urunler adõndaki tabloya gerekli trigger ve notification table'a da Urunler
tablosunun kaydõ yeni bir satõr olarak eklendi. Artõk bu tablo üzerinde gerçekleşen
değişiklikleri SqlCacheDependency nesnesi ile takibini yapabilecek ve Cache nesnesinde
saklanan verileri bu değişime göre güncelleyebileceğiz.

Adõm-2
Uygulamanõn SqlCacheDependency nesnesi ile veritabanõna bağõmlõ işlemleri sağlõklõ bir
şekilde gerçekleştirebilmek için web.config dosyasõnda bu işlemi uygulama bazõnda aktif hale
getirmek gerekecektir. Bu işlem için öncelikli olarak web.config dosyasõ içerisine bir
connectionString eklemek, ardõndan da SqlCacheDependency tanõmlamasõnõ yapmak
gerekecektir. Aşağõdaki kodlarda yapõlmasõ gereken tanõmlamalar görülmektedir.

45
Resim: web.config dosyasõna connectionString ekleme ve SqlCacheDependency
ayarlamalarõnõ yapmak

<system.web> düğümü içerisine eklenen <sqlCacheDependency> düğümünün


niteliklerinden enabled="true" ifadesi SqlCacheDependency'i uygulamada aktif hale getirir.
poolTime="3000" ise notification table'a ne kadarlõk sürede bir bakõlacağõnõ; yani tablonun
güncellenip güncellenmediğinin ne kadar sürede bir kontrol edileceğini belirler. (3000 değeri
3 saniye anlamõna gelir) <databases> alt düğümünde ise hangi veritabanlarõnõn
kaydedileceği belirlenir. <add> ile eklenen veritabanõnda name="advConnDepend" ifadesi
kaydedilen veritabanõnõn adõnõ, connectionStringName="advConn" ise hangi bağlantõ
cümlesinin kullanõlacağõnõ belirler. Buradaki advConn isimli bağlantõ cümlesinin
<connectionStrings> düğümünde olmasõ gereklidir.

Adõm-3
Uygulamada SqlCacheDependency ile veritabanõna bağõmlõ şekilde Cache'de veri saklama
işlemlerini gerçekleştirmeden önce gerekli altyapõyõ hazõrladõk. Şimdi ise uygulamada
Cache'e atacağõmõz nesnenin SqlCacheDependency ile tablodaki değişimlere göre nasõl
güncellenebileceğine bakalõm. Bu işlem için Cache.Insert metodunun aşõrõ yüklenmiş
versiyonlarõndan birini kullanmamõz gerekecek.

public void Insert(string key, object value, CacheDependency dependencies);

Metodun parametrelerine bakacak olursak ilk parametre Cache'de saklanacak verinin


çağrõlacak adõ, ikinci parametre Cache'de saklanacak veri, üçüncü parametre ise
CacheDependency tipinden saklanacak verinin dosya veya veritabanõna bağõmlõ kalmasõnõ
sağlayan nesnemiz olacaktõr. Bizim üçüncü parametre olarak kullanacağõmõz
CacheDependency sõnõfõndan kalõtõlan SqlCacheDependency sõnõfõndan bir nesne olacaktõr.
İsterseniz şöyle bir senaryo üzerinden SqlCacheDependency nesnesinin kullanõmõna
bakalõm. Bir sayfada bulunan GridView kontrolünde veritabanõndan getirilen ürünleri
listeleyelim. Burada getirilen veriler performans açõsõndan her defasõndan veritabanõnda değil
de Cache'den getirilsin istiyoruz. Yine SqlCacheDependency ile Cache'de sakladõğõmõz
verileri tabloda güncelleme olduğu sürece güncellenmesini istiyoruz. Aşağõdaki kodlar böyle
bir işlemi nasõl gerçekleştirebileceğimizi göstermektedir.

46
protected void Page_Load(object sender, EventArgs e)
{
// Cache'de saklanan nesnenin null olup olmadõğõnõ kontrol ediyoruz. Eğer veritabanõnda
// değişim olursa nesne bellekten kaldõrõlõr; yani null olur. Böylece if bloğu çalõşõr
// ve güncel veriler tekrar alõnõp Cache'e aktarõlabilir.
if (Cache["veriler"] == null)
{
string baglanti = "data source=.; initial catalog=AdventureWorks; integrated
security=true";
string sorgu = "SELECT * FROM Urunler";
SqlDataAdapter da = new SqlDataAdapter(sorgu, baglanti);
DataTable dt = new DataTable();
da.Fill(dt);

// SqlCacheDependency nesnesini oluşturuyoruz. İlk parametre web.config'de


tanõmlanan
// SqlCacheDependency database'i. İkinci parametre ise veritabanõnda kontrol edilecek
// olan tablonun adõ olacaktõr.
SqlCacheDependency tabloyaBaglan = new
SqlCacheDependency("advConnDepend", "Urunler");

// dt isimli DataTable nesnesini Cache'e atõyoruz. İlk parametremiz Cache nesnesinin


adõ,
// ikinci parametre Cache'de saklanacak nesne; yani DataTable nesnesi, üçücü
parametre
// ise tabloyaBaglan isimli SqlCacheDependency nesnesi olacaktõr. Artõk Cache'de
saklanan
// veri Urunler tablosundaki değişimlere bağõmlõ olacaktõr. Değişim olmadõğõ sürece
// değerler şu an oluşturulan nesneden alõnacaktõr. Tabloda değişim olduğunda bu kod
bloğu
// tekrar çalõşacağõ için Cache'de saklanan verileri güncellenmesi otomatikmen
gerçekleşir.
Cache.Insert("veriler", dt, tabloyaBaglan);
}

// GridView kontrolünün DataSource değeri Cache'den getiriliyor. Gelen değer object


tipinde olduğu
// için DataTable'a cast işlemi gerçekleştiriyoruz.
GridView1.DataSource = (DataTable)Cache["veriler"];
GridView1.DataBind();
}

Böylece DataTable nesnesini artõk Urunler tablosundaki değişimlere bağõmlõ kõlarak


Cache'de saklayabiliriz. Urunler tablosunda değişiklik olmadõğõ sürece veriler aynen
Cache'de saklanacak, ne zaman ki tabloda değişiklik olursa o zaman veriler Cache'den

47
kaldõrõlacak ve sayfanõn bu esnadan sonraki ilk çalõşmasõnda da Cache'e güncel veriler
atõlacaktõr. Böylece zamana bağõmlõ bir kontrol söz konusu olmadan verinin değişimine
bağõmlõ bir işlem gerçekleştirilebilecektir.

4. DataSource Kontrolleri ile Önbellekteki Verilerle Çalõşmak

ASP.NET 2.0 öncesinde bir sayfada bulunan veri kontrollerini DataSet vb. veri kontrollerine
bağlayarak veri işlemleri gerçekleştiriyorduk. ASP.NET 2.0 ile birlikte gelen SqlDataSource,
AccessDataSource, ObjectDataSource gibi DataSource kontrolleri ile birlikte veri bağlama
işlemlerini artõk daha kolay ve pratik bir şekilde gerçekleştirebilmekteyiz. Bu yeni ASP.NET
kontrollerinin önbellekleme işlemlerini kolay bir şekilde gerçekleştirmemizi sağlayan
özelliklerinden biri de önbellekteki verilerle çalõşabilmesidir.. EnableCaching özelliğinin true
olarak ayarlanmasõ ve CacheDuration özelliğinin saniye cinsinden bir değere atanmasõ
durumunda bağlanan veriler belirli bir süre boyunca önbelleğe alõnacak ve buradan
okunacaktõr. Yine SqlCacheDependency özelliği ile bir SqlDataSource veri kaynağõnõn SQL
Server'daki tablonun değişim durumuna göre önbellekte saklanmasõ sağlanabilmektedir.
Aşağõdaki örnek kodlarda SqlDataSource kontrolünün SqlCacheDependency özelliği ile
veriyi önbellekte saklayabilmesi sağlanmaktadõr. Burada SqlCacheDependency özelliğinin
aldõğõ değer advConnDepend:Urunler şeklindedir. advConnDepend web.config dosyasõnda
tanõmlanan SqlCacheDependecy veritabanõnõn adõ, Urunler ise tablonun adõdõr.

<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$


ConnectionStrings:advConn %>"
SelectCommand="SELECT * FROM [Urunler]" EnableCaching="true"
SqlCacheDependency="advConnDepend:Urunler">
</asp:SqlDataSource>

5. Custom Dependency'ler Oluşturabilme

Cache işlemlerinde kullanõlan CacheDependency sõnõfõ ASP.NET 1.1 sürümünde sealded bir
sõnõftõ ve kalõtõmda kullanõlamõyordu. ASP.NET 2.0 ile birlikte artõk normal bir sõnõf olarak
tanõmlanan CacheDependency sõnõfõ sayesinde kendi sõnõflarõmõzõ CacheDependency
sõnõfõndan kalõtabilir ve Cache'de veri saklama işlemlerinde kullanabiliriz. Böylece sadece
dosya ve klasör değişimlerine bağõmlõ olmaksõzõn, kendi özel durumlarõmõza göre sõnõfõmõzõ
düzenleyip Cache'de saklanacak verilerin bağõmlõlõk durumlarõnõ belirleyebiliriz.

48
GridView'e Programatik Veri Bağlamada Sayfalama
ve Sõralama İşlemleri

31 Ekim 2007

Gridview kontrolü ile web uygulamalarõnda kompleks veri işlemlerini dahi çok kolay bir
şekilde gerçekleştirebildiğimizi eminim ki çoğumuz oldukça iyi biliyoruz. Özellikle tasarõm
aşamasõnda Visual Studio 2005 arayüzünün sunduğu olanaklar ile (Wizard'lar, properties
penceresi, vb.) neredeyse kod yazmadan dahi bu işlemleri yürütebilmekteyiz. Fakat
profesyonel bir uygulama geliştirirken gridview kontrolünü bu araçlarõ kullanmadan
programatik yollarla kullanma ihtiyacõmõz olabilir. Böyle bir durumda da klasik
alõşkanlõklarõmõz DataTable ve DataSet nesneleri ile çalõşmamõz gerekecektir. Tabii ki bu tip
nesnelerle gridview kontrolüne programatik olarak veri bağlama işlemleri az önce
bahsettiğimiz araçlarla yapõlan işlemlere göre biraz daha uzun ve zor olacaktõr. Bu makalede
gridviewe programatik olarak veri bağlama işlemlerinde verileri sayfalama ve sõralama
işlemlerini ne şekilde yürütebileceğimizi ele alacağõz.

Eğer daha önceden gridviewi sadece tasarõm aşamasõnda SqlDataSource veya


AccessDataSource gibi bir datasource kontrolüne bağlayarak kullandõysanõz, sayfalama
işlemi için gridviewin AllowPaging özelliğini, sõralama işlemi için de AllowSorting özelliğini
true olarak ayarlamanõz gerektiğini hatõrlayacaksõnõzdõr. Bu iki özellik gridviewe otomatik
olarak verileri sayfalama ve sõralama özelliği kazandõrõr. Yine sayfalama işlemi ile ilgili olarak
gridview'in PageSize özelliği sayfalama yapõldõğõnda her sayfada kaç tane kayõt
görüntüleneceğini belirler. Tasarõm aşamasõnda bu üç özellik bizim tüm sõralama ve
sayfalama işlemlerimiz için yeterli olacaktõr; ancak gridviewe programatik yollarla veri
bağlayacağõmõz zaman AllowPaging ve AllowSorting özelliklerini true olarak ayarlamak
yeterli olmayacaktõr. Zira gridview kendisine bağlanan verilerin ne şekilde sayfalanacağõnõ ve
sõralanacağõnõ bizim belirlememizi bekleyecektir. Dilerseniz boş bir ASP.NET sayfasõna
gridview kontrolü ekleyerek üzerinde çalõşmaya başlayalõm. Eklenecek gridview kontrolünün
adõna gvUrunler diyelim. Aşağõdaki kodlarda gvUrunler kontrolü ve sayfanõn code-behind
kõsmõndaki veri bağlama işlemlerimiz görülmektedir.

Default.aspx

<form id="form1" runat="server">


<asp:GridView ID="gvUrunler" runat="server"> </asp:GridView>
</form>

Default.aspx.cs

protected void Page_Load(object sender, EventArgs e)


{

49
SqlConnection conn = new SqlConnection("data source=.; database=AdventureWorks;
integrated security=true");
SqlCommand cmd = new SqlCommand("Select ProductID,Name,Color From
Production.Product Where ListPrice > 1500", conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dt = new DataTable();
da.Fill(dt);

// GridView kontrolünün özelliklerini ve veri bağlama işlemlerini gerçekleştiriyoruz.


// Sayfalama ve sõralama işlemlerini aktif hale getirdik.
gvUrunler.AllowSorting = true;
gvUrunler.AllowPaging = true;
gvUrunler.PageSize = 10;
gvUrunler.DataSource = dt;
gvUrunler.DataBind();
}

Sayfamõzõ çalõştõrdõğõmõzda herhangi bir sorunun olmadõğõnõ ve verilerin düzgün bir şekilde
listelendiğini görebiliriz. Fakat başka bir sayfadaki verileri görüntülemek istediğimizde veya
herhangi bir kolona göre sõralama yapmaya çalõştõğõmõzda aşağõdaki resimlerde görülecek
şekilde hatalarla karşõlaşõrõz.

Resim: Sayfalama işlemi yapõldõğõ esnada hata alõrõz

50
Resim: Sõralama işlemi yapõldõğõ esnada hata alõrõz

Bu hatalarõ almamõzõn sebebi gridviewi programatik olarak veriye bağladõğõmõz için ilgili
sayfalama ve sõralama işlemlerini de bizim belirlememiz gerektiğidir. Aldõğõmõz hatalar "The
GridView 'gvUrunler' fired event XXX which wasn't handled." şeklindeydi ki XXX
kõsmõndaki kelimeler de aslõnda ilgili event'lerin isimleridir. Burada bahsedilen hata gridview
ile ilgili daha önceden ele alõnmamõş belirli bir event'in fõrlatõlmasõdõr. Zira gridview birçok
işlemde olduğu gibi sayfalama ve sõralama işlemlerinde de arka planda ilgili eventleri
gerçekleştirmektedir. Bizim programcõ olarak burada ilgili eventleri yakalayacak olan
metotlarõ oluşturmamõz ve kodlamamõz gerekecektir. Sayfalama işlemi için ele alõnacak event
PageIndexChanging, sõralama işlemlerinde ise Sorting'dir. Öncelikli olarak gerekli
delegate'ler aracõlõğõyla bu eventleri birer metoda bağlõyor ve metotlarõn içerisini
dolduruyoruz. Aşağõdaki kodlarda bu işlemlerin ne şekilde yapõldõğõ görülmektedir. Burada
ilgili metotlara aktarõlan ikinci event parametresi bizim açõmõzdan oldukça önemlidir. Zira
sayfalama esnasõnda çalõşacak GridView1_SelectedIndexChanging metodundaki
GridViewSelectEventArgs tipindeki e parametresi ve sõralama işlemi esnasõnda çalõşacak
olan GridView1_Sorting metodundaki GridViewSortEventArgs tipinden e parametresi
buradaki eventler gerçekleşirken önemli bilgileri taşõmaktadõr.

Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
........
gvUrunler.AllowSorting = true;
gvUrunler.AllowPaging = true;
gvUrunler.PageSize = 10;
// Sayfalama ve sõralama event'lerini metotlara bağlõyoruz
gvUrunler.PageIndexChanging += new
GridViewPageEventHandler(gvUrunler_PageIndexChanging);
gvUrunler.Sorting += new GridViewSortEventHandler(gvUrunler_Sorting);
gvUrunler.DataSource = dt;
gvUrunler.DataBind();
}

51
// Sayfalama işleminde; yani PageIndexChanging event'i tetiklendiğinde çalõşacak metot
void GridView1_SelectedIndexChanging(object sender, GridViewSelectEventArgs e)
{
gvUrunler.PageIndex = e.NewSelectedIndex;
gvUrunler.DataBind();
}

// Sõralama işlemi yapõldõğõnda; yani Sorting event'i tetiklendiğinde çalõşacak metot


void GridView1_Sorting(object sender, GridViewSortEventArgs e)
{
// İlk sort işlemi yapõldõğõnda çalõşõr
if (ViewState["siralananKolon"] == null)
{
ViewState.Add("siralananKolon", e.SortExpression);
ViewState.Add("siralamaYonu", "ASC");
}
else
{
// Aynõ kolon 2. kez sõralandõğõnda çalõşõr
if (ViewState["siralananKolon"].ToString() == e.SortExpression)
{
if (ViewState["siralamaYonu"].ToString() == "ASC")
ViewState["siralamaYonu"] = "DESC";
else
ViewState["siralamaYonu"] = "ASC";
}
// Farklõ bir kolon sõralandõğõnda çalõşõr
else
{
ViewState["siralananKolon"] = e.SortExpression;
ViewState["siralamaYonu"] = "ASC";
}
}

// Veriyi tekrar yüklemeden önce sõralanacak alanõ ve sõralama kriterini belirlemek gerekir.
// DataTable nesnesini tekrar elde edip, görünümünü(DataView) değiştiriyoruz
DataTable dt = (DataTable)gvUrunler.DataSource;
dt.DefaultView.Sort = ViewState["siralananKolon"].ToString() + " " +
ViewState["siralamaYonu"].ToString();
gvUrunler.DataBind();
}

Yukarõda yapõlan işlemlere biraz daha detaylõ şekilde bakalõm.

52
- PageIndexChanging event'i için yazõlan metotta: e parametresi çalõşma zamanõ esnasõnda
gridview ile ilgili bilgileri taşõr. e nesnesinden erişeceğimiz NewSelectedIndex isimli özelliği
bize o an istenen sayfa indeks numarasõnõ getirir. Burada yapacağõmõz işlem bu indeks
numarasõnõ elde edip gridviewin o anki PageIndex özelliğine eşitlemek. Ardõndan da
gridviewin görünümünü güncellemek için yeni verilerle yüklenmesini sağlamak
gerekecektir(DataBind metodu ile)

- Sorting event'i için yazõlan metotta: Burada ele alacağõmõz işlemler biraz daha karmaşõk
olacaktõr. Zira PageIndexChanging eventinde ihtiyacõmõz olan sayfanõn indeks numarasõnõ e
parametresinden elde edebiliyoruz. Sorting eventinde, yani sõralama işleminde ise iki bilgiye
ihtiyacõmõz olacaktõr; birincisi sõralama yapõlacak kolonun adõ, ikincisi ise sõralamanõn yönü
(Ascending, Descending). Yine metotla birlikte gelen e parametresi bize önemli bilgileri
taşõmaktadõr. Fakat e parametresi sõralanacak kolonun adõnõ doğru olarak getirse bile
sõralama yönünü her defasõnda Ascending olarak getirecektir. Bundan dolayõ ihtiyacõmõz olan
iki değerden birisine erişebilmek için ekstra çaba sarfetmemiz gerekecek. Burada sõralama
işlemi yapõlan kolona bir kez tõklanõrsa sõralama işlemini Ascending(ASC), ardõndan bir kez
daha aynõ kolona tõklanõrsa da Descending(DESC) yapmamõz gerekecektir. Özetle, her
zaman bir kolona ilk tõklandõğõnda ASC, ikinci tõklamada DESC, üçüncü tõklamada ASC...
şeklinde devam edecektir. Yine sayfa postback işlemini yaptõğõnda bir önceki sõralama
işleminin yönünü bilmemiz ve değiştirmemiz gerekecektir. Bu nedenle ViewState nesnesi
içerisinde bu değeri saklayarak her postback işleminde o anki sõralanacak kolonun durumuna
göre sõralama yönünü değiştirmemiz gerekecek. Örneğin Name kolonunu ilk sõralamamda
SQL cümlesinin sonuna Name ASC, Name kolonuna ikinci kez tõklandõğõnda Name DESC
şeklinde bir sõralama yapmamõz gerekecek. Bu esnada eğer ki Color sütununa tõklanõrsa
Color ASC şeklinde işleme devam etmemiz gerekecektir. Bu durumlarõ ele alabilmemiz için
gerekli koşullarõ bu metot içerisinde oluşturuyoruz. Son işlem olarakta DataTable
nesnesindeki verileri tekrar sõralayarak gridviewe yeniden bağlamamõz gerekecektir.
Gridviewin DataSource özelliğinden object tipinde elde ettiğimiz nesneyi önce DataTable
tipine cast ediyoruz. Ardõndan da datatable'õn görünümünü DataView nesnesi olarak elde
etmemizi sağlayan DefaultView özelliğine ait Sort özelliğine de sõralama cümlemizi
belirmemiz gerekecektir. Son olarakta gridview nesnesini DataBind metodu ile tekrar
yükleyecek olursak artõk verilerimiz düzgün bir şekilde sõralanarak görüntülecektir.

Böylece gridview kontrolüne programatik yollarla veri bağlamada sayfalama ve sõralama


işlemlerini nasõl gerçekleştirebileceğimizi görmüş olduk. Özellikle karmaşõk sorgulamalarda
gridview kontrolüne bu şekilde veri bağlayabilir ve dolayõsõyla da sayfalama-sõralama
işlemlerini ele almamõz gerekebilir. Ele aldõğõmõz işlemler özellikle bu tip durumlarda oldukça
işinize yarayacaktõr.

53
GridView Kayõtlarõnõ Okumak ve Metin Dosyasõna
Aktarmak
01 Kasõm 2007

ASP.NET 2.0 ile gelen yeni veri kontrollerinden GridView web uygulamalarõnda kullandõğõmõz
en zengin veri kontrolüdür. Bir programcõnõn birçok ihtiyacõnõ karşõlayabilecek gelişmiş
özelliklere sahip olan bu kontrolle tek satõr kod yazmadan dahi veriye bağlanabilmekte,
getirilen verileri sayfalayõp sõralayabilmekte, hatta yine kod yazmadan otomatik güncelleme
ve silme işlemlerini de gerçekleştirebilmekteyiz. Bu kontrol ile ilgili olarak programcõya düşen
görev ise kontrolün varolmayan özelliklerini çalõştõrabilecek işlemleri yapmak kalõyor. Bu
işlemlerden birisi de GridView'deki verilerin farklõ bir ortama aktarõlmasõ olacaktõr. Farklõ
ortamdan kastõmõz farklõ bir tabloya, farklõ bir nesneye veya bir dosyaya olabilir. Bu
makalemizde GridView kontrolünde bulunan verilere programatik yollarla nasõl
erişebileceğimize ve bu verileri txt uzantõlõ olarak bir metin dosyasõna nasõl
dönüştürebileceğimizi göreceğiz.

GridView veriyi tutuş şekli açõsõndan DataTable nesnesinde benzetilebilir. GridView'da


saklanan kayõtlar satõrlar ve sütunlar halinde tutulmaktadõr. Gridview'deki satõrlar
GridViewRow, sütunlarda DataControlField tipinden birer nesne olarak saklanõr. Satõrlara
Rows kolleksiyonundan(collection), sütunlara ise Colums kolleksiyonunda erişebilmekteyiz.
Bir satõrda bulunan bir sütunun değerine elde etmek için ise GridViewRow nesnesinin Cells
kolleksiyonunu kullanarak ilgili hücredeki bilgilere erişebiliriz. Aslõnda ASP.NET'te dosya
download işlemini biliyorsak, bu bilgiler bile bizim bir gridview içerisindeki kayõtlarõ metinsel
bir dosyaya aktarmamõz için yeterli olacaktõr. Kolleksiyonu ve kolleksiyonda saklanan verinin
tipini bildiğimize göre bir foreach döngüsü içerisinde bu değerlere erişebilmemiz mümkündür.
Bir sayfaya ekleyeceğimiz GridView'a gvUrunler adõnõ verip, gerekli ayarlamalarõ yapõp bir
SqlDataSource kontrolüne bağlayalõm. Yapacağõm örnekte AdventureWorks veritabanõnda
yer alan Production.Product tablosunu kullanacağõm(Sorgu: SELECT ProductID, Name,
Color, ListPrice, ModifiedDate FROM Production.Product). Sayfaya eklenen bir buton
kontrolünün Click event'inde grid kontrolünün içerisindeki verilere aşağõdaki örnek kodlar ile
erişebiliriz. Kodlara bakõlacak olursa; bir foreach döngüsü ile griddeki satõrlar içerisinde adõm
adõm ilerlenmiş ve elde edilen satõrõn Cells kolleksiyonundan 1 numaralõ indeksteki değeri
istenilmiş(yani Name sütunu).

protected void Button1_Click(object sender, EventArgs e)


{
Response.Write("GridView'daki ürünlerin isimleri:");
foreach (GridViewRow row in gvUrunler.Rows)
Response.Write(row.Cells[1].Text + "<br>");
}

54
Şekil: Butona tõklandõğõnda o an gridviewde bulunan satõrlarõn Name alanlarõ sayfaya
yazdõrõldõ

Buradaki okuma işlemi belirli bir hücre üzerinden gerçekleştirildi. Eğer tüm hücreleri okumak
istersek sütun sayõsõnõ bilmek ve ona göre de foreach döngüsünün içerisine bir for döngüsü
açmak gerekecektir. Gridviewdaki sütunlar Columns kolleksiyonunda saklandõğõ için bu
kolleksiyonun Count özelliği bize toplam sütun sayõsõnõ getirecektir. Aşağõdaki kodlar ile de
griddeki tüm ve satõrlarõn tüm hücrelerini okuyabiliriz.

protected void Button1_Click(object sender, EventArgs e)


{
Response.Write("GridView'daki ürünler:");
foreach (GridViewRow gvr in gvUrunler.Rows)
{
for(int i=0; i < gvUrunler.Columns.Count; i++)
Response.Write(gvr.Cells[i].Text + " ");
Response.Write("<br>");
}
}

Şekil: Gridviewdaki o an bulunan bütün veriler getirildi

55
Gridview'õn Rows kolleksiyonu, sadece sayfa çalõştõrõldõğõ anda görüntülenen kayõtlarõ
içerisinde saklayacaktõr. Eğer grid kontrolünü sayfalandõrõlmõş şekilde kullanõyorsak ve birden
fazla sayfada veriler tutuluyorsa yukarõdaki kodlar çalõştõrõldõğõnda sadece o an üretilen
sayfada grid içerisine hangi satõrlar geliyorsa o satõrlarõn bilgilerine erişebiliriz. Eğer
amacõmõz griddeki bilgileri bir dosyaya aktarmak ise olaya farklõ yaklaşõmlarõmõz olabilir.
Sadece o an gridde görüntülenen satõrlarõ dosyaya kaydetmek isteyebileceğimiz gibi, belirli
sayõdaki satõrõ veya gride bağlanan tüm kayõtlarõda dosyaya kaydetmek isteyebiliriz.
Dilerseniz gridviewdaki kayõtlarõ metinsel bir dosyaya kaydetme işlemini gerçekleştiren ve bu
üç farklõ durumu gözönüne alan küçük bir uygulama yazalõm. Sayfaya ekleyeceğimiz
gridview kontrolünü bir SqlDataSuorce kontrolüne bağlayalõm. Sorgu olarak yukarõdaki
sorguyu aynen kullanabiliriz. Yine Update,Delete işlemleri içinde gerekli sorgularõ oluşturalõm.
Burada her ne kadar Update-Delete işlemi yapmayacak olsakta gride eklenecek Update-
Delete butonlarõnõn metinsel dosyamõza eklenmesini de nasõl engelleyebileceğimizi ele
alacağõz. GridView dõşõnda sayfaya bir RadioButtonList kontrolü ve bir de Button kontrolü
ekleyelim. RadioButtonList kontrolü ile sadece bu sayfadaki verileri kaydetme, ilk 50 veriyi
kaydetme ve tüm verileri kaydetme seçeneklerini ele alacağõz. Sayfamõzõn tasarõmõ ve
kodlarõ aşağõdaki gibi olacaktõr.

Şekil: Oluşturduğumuz sayfanõn Design kõsmõ

<asp:GridView ID="gvUrunler" runat="server" AllowPaging="True"


AutoGenerateColumns="False" DataKeyNames="ProductID"
DataSourceID="SqlDataSource1" PageSize="5">
<Columns>
<asp:BoundField DataField="ProductID" HeaderText="ProductID" InsertVisible="False"
ReadOnly="True" SortExpression="ProductID" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:BoundField DataField="Color" HeaderText="Color" SortExpression="Color" />
<asp:BoundField DataField="ListPrice" HeaderText="ListPrice"
SortExpression="ListPrice" />
<asp:BoundField DataField="ModifiedDate" HeaderText="ModifiedDate"

56
SortExpression="ModifiedDate" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="SqlDataSource1" runat="server" ConnectionString="<%$
ConnectionStrings:AdventureWorksConnectionString %>"
SelectCommand="SELECT [ProductID], [Name], [Color], [ListPrice], [ModifiedDate] FROM
[Production].[Product]"
DeleteCommand="DELETE FROM [Production].[Product] WHERE [ProductID] =
@ProductID"
UpdateCommand="UPDATE [Production].[Product] SET [Name] = @Name, [Color] =
@Color, [ListPrice] = @ListPrice, [ModifiedDate] = @ModifiedDate WHERE [ProductID] =
@ProductID">
<DeleteParameters>
<asp:Parameter Name="ProductID" Type="Int32" />
</DeleteParameters>
<UpdateParameters>
<asp:Parameter Name="Name" Type="String" />
<asp:Parameter Name="Color" Type="String" />
<asp:Parameter Name="ListPrice" Type="Decimal" />
<asp:Parameter Name="ModifiedDate" Type="DateTime" />
<asp:Parameter Name="ProductID" Type="Int32" />
</UpdateParameters>
</asp:SqlDataSource>
<asp:RadioButtonList ID="rblSecim" runat="server">
<asp:ListItem Value="0">Sadece bu kayõtlar</asp:ListItem>
<asp:ListItem Value="1">İlk 50 kayõt</asp:ListItem>
<asp:ListItem Value="2">Tüm kayõtlar</asp:ListItem>
</asp:RadioButtonList>
<asp:Button ID="Button1" runat="server" OnClick="Button1_Click" Text="Kayõtlarõ Kaydet"
Width="153px" />

Sayfanõn tasarõmõnõ ve gridviewa bağlanacak verinin ayarlanmasõndan sonra adõm adõm


yapõlacak işlemleri kodlamaya başlayalõm. Öncelikli olarak gridde bulunan Edit ve Delete
butonlarõnõn oluşturulacak txt dosyasõnda bulunmasõnõ istemeyeceğimiz için bu link
butonlarõnõ yazdõrma işleminde çõkarmamõz gerekecek. Update ve Delete gibi komut
çalõştõran butonlar gridview içerisinde CommandField olarak tutulduğu için gridviewdaki
CommandField kõsmõnõ programatik olarak gridden çõkarmamõz yeterli olacaktõr. Bu işlemi
gerçekleştirmek için GereksizKolonlariSil adõnda bir metot yazalõm. Bu işlemin ardõndan da
kullanõcõnõn radiobuttonlistten işaretleyeceği seçeneğe göre gridden farklõ sayõda veri
okunacağõ için bu kõsmõ çözümleyelim. Burada;
- Sadece bu kayõtlar seçeneğini seçilirse direkt olarak grid içerisindeki satõrlarõ okuma ve
download işlemi yaptõrmamõz gerekecek.
- İlk 50 kayõt seçeneği seçilirse grid kontrolünün PageSize özelliğini 50 yapmak gerekecek.
Yine ilk 50 kaydõn getirilebilmesi için de PageIndex özelliğinin 0 olarak ayarlanmasõ
gerekecek. Ardõndan grid kontolünün DataBind metodunu çağõracak olursak ilk sayfaya

57
gidilecek ve ilk 50 kayõt yüklenecektir. Böylece ilk 50 kaydõn txt formatõnda download
edilmesini sağlayabileceğiz.
- Tüm kayõtlar seçeneği seçilirse gridview kontrolünün AllowPaging özelliğini false
yapmamõz ardõndan DataBind metodunu çağõrmamõz gerekecek. Böylece yapõlacak
postback işleminin sonucunda gridde sayfalama yapõlmayacağõ için tüm kayõtlar yüklenecek,
dolayõsõyla da download işleminde tüm kayõtlar dosyaya yazdõrõlabilecek.
Sayfaya eklediğimiz butonun click eventine aşağõdaki kodlar eklendiğinde grid kontrolündeki
verileri istenilen şekilde download işlemine hazõrlamõş oluruz. Kodlarõn en alt kõsmõnda da az
sonra yazacağõmõz ve metinsel dosyaya kaydetme işlemini üstlenecek olan metodu
çağõrõyoruz.

private void GereksizKolonlariSil()


{
// Eğer Select, Edit ve Delete gibi CommandFieldlar aktif ise bu butonlarõn bulunduğu
sütunu gridden kaldõrõyoruz.
for (int i = 0; i < gvUrunler.Columns.Count; i++)
{
if (gvUrunler.Columns[i] is CommandField)
gvUrunler.Columns.RemoveAt(i);
}
}

protected void Button1_Click(object sender, EventArgs e)


{
GereksizKolonlariSil();

// Sadece bu kayõtlar şõkkõ seçilirse ek bir işlem yapmaya gerek yoktur. Diğer iki şõkkõ ele
alõyoruz.
if (rblSecim.SelectedIndex == 1) // İlk 50 kayõt
{
gvUrunler.PageIndex = 0;
gvUrunler.PageSize = 50;
}
else if (rblSecim.SelectedIndex == 2) // Tüm kayõtlar
{
gvUrunler.AllowPaging = false;
}

gvUrunler.DataBind();
TextKaydet(); // Bu metot az sonra yazacağõmõz ve kayõtlarõ metinsel dosyaya aktaracak
olan metot
}

Bu şekilde gridview kontrolünün içeriğini yazdõrõlacak hale geldik. Butona tõklandõğõnda


postback işlemi gerçekleşeceği için gridview kontrolünü yeniden düzenliyoruz; fakat az
sonraki yapõlacak işlemlerde postback sonrasõ dosya download edileceği için sayfa

58
yenilenmeyecektir, dolayõsõyla da bizim design kõsmõnda yaptõğõmõz ayarlamalar geçerli
kalacaktõr. Aşağõdaki kodlarda da grid içerisindeki verileri metinsel dosyaya kaydetme
işlemini üstlenecek TextKaydet metodu bulunmaktadõr.

protected void TextKaydet()


{
// string birleştirme işleminin daha performanslõ olmasõ için System.Text isim alanõ
// altõnda yer alan StringBuilder ile string birleştirme işlemi yapacağõz
StringBuilder sb = new StringBuilder();

// Öncelikli olarak gridviewdaki sütunlarõn başlõklarõnõ okuyor ve değişkenimize ekliyoruz


foreach (DataControlField cell in gvUrunler.Columns)
{
sb.Append(cell.HeaderText + " "); // HeaderText property'si hücrenin başlõk bilgisini
getirir
}
sb.Append(Environment.NewLine); // Yeni bir satõr açõyoruz

// Artõk kayõtlarõ tek tek okuyup değişkenimize ekliyoruz


foreach (GridViewRow gvr in gvUrunler.Rows)
{
for (int i = 0; i < gvUrunler.Columns.Count; i++)
{
// Eğer hücrede boş değer varsa &nbsp; karakterinin yazõlmasõnõ engellemek için
kontrol yapõyoruz
if (gvr.Cells[i].Text == " " || gvr.Cells[i].Text == "")
sb.Append(" - ");
else
sb.Append(gvr.Cells[i].Text + " ");
}

sb.Append(Environment.NewLine); // Satõr bittiğinde bir alt satõra geç


}

// Okuma işlemi bitti ve değişken hazõr. Artõk metinsel dosyanõn oluşturulmasõ ve kullanõcõ
tarafõndan
// yüklenmesi için gerekli işlemleri gerçekleştiriyoruz
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=Urunler.txt");
Response.ContentType = "application/vnd.text";
Response.Write(sb.ToString());
Response.End();
}

59
Şekil: Sayfayõ çalõştõrdõğõmõzda işaretlediğimiz seçeneğe göre txt uzantõlõ dosyayõ
bilgisayarõmõza indirebiliriz

Böylece gridview içerisindeki kayõtlarõ okuma işlemini gerçekleştirerek alõnan bilgileri txt
uzantõlõ olarak metinsel bir dosya içerisinde sunmuş olduk. Özellikle basit anlamda kullanõcõ
arayüzlerinde yapõlan listeleme ve raporlama işlemlerinde işimizi görebilecek tarzda küçük bir
web uygulamasõ geliştirmiş olduk. Benzer yollarla okunan verileri başka bir kaynağa (farklõ bir
sunucudaki tabloya veya bir Excel dosyasõna gibi) aktarabiliriz.

60
GridView'deki Kayõtlarõ Excel Dosyasõna Aktarmak
02 Kasõm 2007

Bir önceki makalemizde GridView nesnesinin satõr-sütun (row-column) ilişkisinin ne şekilde


olduğuna, GridView kontrolünün içerisindeki kayõtlarõ nasõl okuyabileceğimize ve okunan
satõrlarõ metinsel bir dosyaya nasõl aktarabileceğimize değinmiştik. Bu makalemizde de
okunan verileri bir Excel dosyasõna nasõl aktarabileceğimizi inceleyeceğiz. İlk bakõşta
aklõmõza şu gelebilir: "GridView'in içeriği DataTable veya SqlDataSource gibi bir veri
kaynağõndan geliyor. Zaten o nesneleri kullanarak veri aktarma işlemini yürütebiliriz". Evet,
kesinlikle:) Fakat özellikle web sayfalarõnda GridView ile yapõlan raporlama işlemlerinde
sayfayõ kullanan kişi yapmõş olduğu sõralamaya veya sayfalamaya göre o an görünen
kayõtlarõ bir dökümana aktarmak ve kendi bilgisayarõna saklamak isteyebilir. Örneğin kullanõcõ
gridview'da listelenen ürünleri fiyatõna göre sõralatõp gelen ilk 50 tane kaydõ bir Excel
dökümanõna aktarmak isteyebilir. İşte bu noktada veriyi sõralanmõş, sayfalanmõş şekilde
zaten hali hazõrda tutan gridviewden okuma ve aktarma işlemi yapmak programcõ ve kullanõcõ
açõsõndan oldukça önemli bir işlem olacaktõr.

Önceki makalemizde gridviewdeki satõrlarõ okuma işlemini detaylõ şekilde ele aldõğõmõz için
bu konulara değinmeden griddeki verileri Excel dosyasõna nasõl aktarabileceğimize
geçiyorum. Öncelikli olarak burada yapõlan işlemde veriler Excel gibi bir dökümana
aktarõlacaktõr; yani içerisinde verileri çok daha farklõ bir formatta tutan bir dosya tipi. İşin en
güzel ve kolay tarafõ şu ki; kullanacağõmõz gridview nesnesi içerisindeki kayõtlarõ çok fazla
işlem yapmamõza gerek kalmadan kolay bir şekilde Excel dosyasõna aktarabileceğiz. Bu
işlemi yaparken iki farklõ yolu seçebiliriz:

1. GridView kontrolündeki satõrlarõ direkt olarak Excel dosyasõna aktarmak


2. GridView kontrolündeki satõrlarõ okuyarak Table nesnesine aktarmak ve ardõndan Table
nesnesinin içeriğini Excel dosyasõna aktarmak

Buradaki ilk yolu gördükten sonra "Neden Table nesnesi üzerinden bu işlemi yürütelim ki?"
gibi bir soru işareti aklõmõza gelebilir. Fakat gridview'daki kayõtlarõ direkt olarak bir Excel
dökümanõna aktarma işleminde bazõ sõkõntõlarla ve hatalarla karşõlaşõlabilmektedir. Açõkcasõ
internetten yapmõş olduğum araştõrmalarda bu işlemi gridviewdaki satõrlar üzerinden direkt
Excel'e aktarma yolunu seçersek hesapta olmayan hatalarla karşõlaşabilme durumumuz
olabiliyor. Bu nedenle 2. yolu kullanarak bu işlemi yürütmek daha sağlõklõ olabilir. Yine Table
nesnesi kullanõldõğõnda elde edilen veriler üzerinde değişiklik yapma gibi bir avantajõmõzda
olabildiği için bu yol biraz daha esnektir diyebiliriz. Dilerseniz ilk yolu kullanarak gridviewin
satõrlarõnõ Excel dosyasõna nasõl aktaracağõmõza bakalõm. Sayfamõza bir gridview kontrolü, bir
radiobuttonlist kontrolü ve buton kontrolü ekleyerek sayfamõzõ tasarlayalõm. Aşağõda
sayfamõzõn görünümü bulunmaktadõr.

61
Şekil: Kullanacağõmõz sayfanõn tasarõmõ ve kontrol isimleri

RadioButtonList'ten yapõlan seçim işlemine göre farklõ şekilde verileri Excel'e aktarmamõz
gerekecek. Yine gridviewde Edit-Delete-Select gibi command butonlarõ içeren bir kõsõm
olursa bu kõsmõ dosyaya yazdõrmak istemeyebiliriz. Bu işlem için GereksizKolonlariSil
adõnda bir metot oluşturup, gridview kontrolünün dosyaya yazõlmaya hazõr hale getirilmesi
işlemini aşağõdaki kodlarda görüldüğü gibi butonun click eventinde gerçekleştiriyoruz.
Yapõlan işlemlerle ilgili bilgiler yorum satõrlarõnda bulunmaktadõr.

protected void Button1_Click(object sender, EventArgs e)


{
// GridView'in footer kõsmõnõn Excel dosyasõnda görüntülenmesini istemiyorsak
PagerSettings'i saklamamõz gerekli
gvUrunler.PagerSettings.Visible = false;

GereksizKolonlariSil();

if (rblSecim.SelectedIndex == 1) // İlk 50 kayõt


{
gvUrunler.PageIndex = 0;
gvUrunler.PageSize = 50;
}
else if (rblSecim.SelectedIndex == 2) // Tüm kayõtlar
gvUrunler.AllowPaging = false;

gvUrunler.DataBind(); // Yapõlan değişikliklerin geçerli olmasõ için verileri tekrar


yüklüyoruz
GridiExceleKaydet(); // Gridviewdeki kayõtlarõ direkt olarak Excel'e yazacak metot
}

private void GereksizKolonlariSil()

62
{
// Eğer Select, Edit ve Delete gibi CommandFieldlar aktif ise bu butonlarõn bulunduğu
sütunu gridden çõkarõyoruz
for (int i = 0; i < gvUrunler.Columns.Count; i++)
{
if (gvUrunler.Columns[i] is CommandField)
gvUrunler.Columns.RemoveAt(i);
}
}

Böylece gridview kontrolünün içeriğini dosyaya yazdõrõlacak şekle getirildi. Butona


tõklandõğõnda postback işlemi gerçekleşeceği için gridview kontrolü yeniden düzenlenecek,
ardõndan da GridiExceleKaydet metodunda okunan kayõtlarõ dosyaya aktaracağõz. Aşağõda
bu metot ve yapõlan işlemlerin açõklamalarõ bulunmaktadõr.

protected void GridiExceleKaydet()


{
// Oluşacak dosyaya gridview aynen aktarõlacağõ için hücrelerin çevrelerinin çizilmesini
sağlõyoruz
gvUrunler.GridLines = GridLines.Both;
// Gönderilecek cevaba gridin içeriğini yazdõrmak için gvUrunler kontrolünü render etmek
gerekli. Bu işlemleri
// StringWriter ve HtmlTextWriter nesnelerini ile yürütüyoruz. StringWriter, System.IO isim
alanõ altõnda yer alõr
StringWriter stringYaz = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(stringYaz);
gvUrunler.RenderControl(htw);

// İstemciye gönderilecek cevabõ oluşturuyoruz. Öncelikli olarak cevapta(response'da) şu


ana kadar oluşan
// bilgileri silip, cevabõn başlõk bilgisine gönderilecek dosya ile ilgili bilgileri ekliyoruz. Dosya
tipini belirttikten
// sonra yukarõda oluşturulan StringWriter nesnesini ToString metodu ile cevaba
yazdõrõyoruz
Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=Urunler.xls");
Response.ContentType = "application/ms-excel";
Response.Write(stringYaz.ToString());
Response.End();
}

Bu işlemlerle birlikte gridview kontrolünün içeriğini Urunler.xls olarak bir Excel dosyasõna
yazdõrabiliriz. Fakat sayfayõ çalõştõrõp dosyaya aktarma işlemini yaptõğõmõz esnada bir hata
almamõz gerekecektir. Zira yukarõda gvUrunler isimli gridviewõn RenderControl metodunu
çalõştõrmamõz çalõşma zamanõ esnasõnda HttpException istisnasõna sebep olacaktõr.

63
Şekil: gvUrunler'in RenderControl metodunu kullanarak yaptõğõmõz işlem başarõsõz
olacak ve çalõşma zamanõnda HttpException istisnasõ alacağõz

Buradaki hatanõn sebebi ASP.NET sayfasõnõn yapõsõ itibariyle çalõşma zamanõ esnasõnda
içerisinde bulunan bir kontrolü RenderControl metodu ile çözümlememize izin
vermemesidir. Bu hatayõ düzeltebilmek için Page class'õ içerisinde virtual olarak tanõmlanmõş
olan VerifyRenderingInServerForm isimli metodu ezmek(override işlemi) gerekecektir. Bu
işlemi Visual Studio 2005 editöründe gerçekleştirdiğimizde metodun gövdesinde otomatik
olarak base class'taki metodu çağõran base.VerifyRenderingInServerForm(control);
ifadesi bulunacaktõr. Bu metot parametre olarak Control tipinden nesneler almaktadõr ki; bu
nesneler sayfamõz içerisinde bulunan runat="server" tanõmlamasõ içeren sunucu
kontrollerimizdir. Bizim burada yapmamõz gereken işlem metot içerisinde gelen kontrole
bakmak ve eğer gridview kontrolü ise bu metodun çağrõlmasõnõ engellemek olacaktõr.
Aşağõdaki kodlarda bu işlemi nasõl yapacağõmõz görülmektedir.

public override void VerifyRenderingInServerForm(Control control)


{
// Oluşan hata gvUrunler isimli kontrolün render edilmesi esnasõnda alõndõğõ için, render
edilen
// kontrolün gvUrunler olmadõğõ durumda base class'taki metodunu çağõrõyoruz
if(control.ID != "gvUrunler")
base.VerifyRenderingInServerForm(control);
}

Böylece gridviewin RenderControl metodu ile çözümlenmesi işleminde yaşanan sorunun


üstesinden gelebileceğiz. Sayfayõ çalõştõrdõğõmõzda seçim işlemini yaparak kayõtlarõ dosyaya
aktarabiliriz.

64
Şekil: Seçime göre oluşan Urunler.xls dosyamõz

Bu şekilde 1. yolumuz olan gridviewden direkt okuma ve Excel'e yazma işlemini


gerçekleştirdik. Buradaki en büyük avantajõmõz satõr okuma işlemleriyle uğraşmadan sadece
render edilme işlemi ile bu işlemi yürütebilmek olacaktõr. Dezavantajõmõz ise sayfamõzõn
yapõsõ ile ilgili olan bir metodu override ederek gridview kontrolünün render edilmesini
engellemek gibi bir işlemle uğraşmamõz gerekeceğidir.

Gridviewdeki kayõtlarõ Excel dosyasõna aktarmamõzõn bir diğer yolu ise


System.Web.UI.WebControls isim alanõ altõnda yer alan Table isimli bir class'tan
faydalanarak bu işlemi yürütmektir. Table class'õ aslõnda HTML <table> etiketinin sunucu
tarafõnda oluşturulmasõnõ sağlayan, içinde satõr ve hücreler bulundurabilen nesne yapõsõ
sunan bir kontroldür. Burada ise Table nesnesini Excel dosyasõndaki satõr ve sütunlarõ
oluşturmasõ amacõyla kullanacağõz. Aşağõda, gridview içerisindeki satõrlarõ Table nesnesine
aktarma ve ardõndan da gridview yerine Table nesnesini render ederek içeriğini dosyaya
aktarma işlemlerini içeren TabloyuExceleKaydet metodu bulunmaktadõr.

protected void TabloyuExceleKaydet()


{
// Yeni bir tablo oluşturuyoruz. Bu tablo griddeki satõrlarõ içerisinde barõndõracak.
// Oluşan Excel dosyasõnda hücreler arasõnda çizgiler ekliyoruz
Table tablo = new Table();
tablo.GridLines = GridLines.Both;

// Tablonun ilk satõrõ sütun başlõklarõ olacak


tablo.Rows.Add(gvUrunler.HeaderRow);

65
// Gridview'daki satõrlarõ döngü ile Rows kolleksiyonundan alõyor ve tabloya ekliyoruz
foreach (GridViewRow row in gvUrunler.Rows)
{
// GridViewRow class'õ TableRow class'õndan kalõtõldõğõ için Add metoduna parametre
olarak verilebilir
tablo.Rows.Add(row);
}

// Burada gridview yerine tablo nesnesini render ediyoruz


StringWriter stringYaz = new StringWriter();
HtmlTextWriter htw = new HtmlTextWriter(stringYaz);
tablo.RenderControl(htw); // Render edilen bilgileri htw nesnesine yaz

Response.Clear();
Response.AddHeader("content-disposition", "attachment;filename=Urunler.xls");
Response.ContentType = "application/ms-excel";
Response.Write(stringYaz.ToString());
Response.End();
}

Butonun click eventinde çağõrdõğõmõz GridiExceleKaydet metodu yerine


TabloyuExceleKaydet metodunu çağõracak olursak artõk griddeki veriler önce Table
nesnesine, ardõndan Excel dosyasõna aktarõlacaktõr. Bu yolu seçtiğimizde
VerifyRenderingInServerForm metodunu override etmemize gerek kalmayacaktõr.

Böylece gridview içerisinde yer alan kayõtlarõ bir Excel dökümanõna nasõl aktarabileceğimizi
iki farklõ yolu kullanarak görmüş olduk.

66
ASP.NET 3.5 ile Gelen Yenilikler
11 Aralõk 2007

.NET Framework 3.5 sürümünün resmen duyurulmasõyla ASP.NET'te 3.5 sürümüne ulaşmõş
oldu. Bildiğimiz gibi .NET Framework 3.0 ile önceki mimaride değişiklik olmamõştõ ama
Windows Presentation Foundation, Windows Communication Foundation, Workflow
Foundation ve Cardspace gibi yeni teknolojiler mimariye eklenmişti. 3.5 sürümüyle birlikte
ise önceki mimaride bazõ değişiklikler, yeni eklentiler ve yeni tipler getirildi. Özellikle Linq
(Language Integrated Query) adõndaki Dil ile Bütünleşik Sorgulama modeli bu sürümdeki
en göze çarpan yenilik oldu. Bu yazõmõzda Framework'ün ASP.NET kõsmõnda bizi ne gibi
yeniliklerin beklediğini incelemeye çalõşacağõz.

Aslõnda ASP.NET'i .NET Framework'ün 1.0 sürümünden beri takip edenler 1.1 sürümünden
2.0 sürümüne geçişteki köklü ve önemli yenilikleri hatõrlayacaktõr. Yazõmõza giriş yaparken
hemen şunu belirtelim ki 2.0 sürümünden 3.5 sürümüne geçişte bu denli büyük ve köklü
yeniliklerimiz olmayacak. Fakat AJAX ve Linq temelli olarak ta iki köklü yeniliğin geldiğini de
belirtmekte fayda var. Bir diğer konu da ASP.NET 3.5'in ardõndan yakõnda resmen
duyurulmasõ beklenen ASP.NET 3.5 Extension paketi. (Belki de yazõyõ okuduğunuzda bu
paket resmen duyrulmuş olacaktõr) ASP.NET MVC (Model View Controller) Framework, yeni
AJAX ve veri kontrolleri ile SilverLight kontrollerinin ekleneceği bu paketinde mimariye dahil
olmasõyla birlikte aslõnda daha da önemli yeniliklerin bizi beklediğini söyleyebiliriz.
Makalemizin son kõsmõnda bu paket ile ilgili de önemli bilgileri sizlerle paylaşmaya
çalõşacağõm.

ASP.NET 3.5 ile gelen en önemli ve köklü iki yenilik AJAX Extension entegrasyonu ve Linq
desteğidir. Aslõnda Linq C# 3.0 ile birlikte gelen bir yenilik ve platformdaki tüm uygulamalarda
kullanabileceğimiz gibi ASP.NET uygulamalarõnda da kullanabileceğiz. Aşağõdaki başlõklarda
gelen yenilikleri inceliyoruz.

1. ASP.NET AJAX Entegrasyonu


ASP.NET AJAX, ASP.NET ortamõnda hõzlõ ve kolay bir şekilde AJAX uygulamalarõ
geliştirmemizi sağlayan ücretsiz bir AJAX framework'üdür. ASP.NET 2.0'õn ardõndan
duyurulan ve bu yõlõn (2007) başõnda resmi sürümü çõkarõlan AJAX Extension'larõ ASP.NET
3.5 ile mimariyle bütünleşik şekilde geliyor. Artõk temel sõnõf kütüphanelerimiz içerisinde
AJAX kontrolleri ve tipleri de bulunmaktadõr. Bir başka deyişle AJAX web uygulamalarõ
geliştirmek için ASP.NET'in sitesinden ASP.NET AJAX paketini indirmeye ve kurulum
yapmaya gerek kalmayacak.

.NET Framework 3.5 ile birlikte duyurulan yeni uygulama geliştirme ortamõmõz Visual Studio
2008'de açõlan her ASP.NET 3.5 artõk AJAX destekli olarak oluşturuluyor. Yani AJAX
Extension kontrollerini kullanarak hõzlõ şekilde AJAX uygulamalarõ geliştirebiliyoruz.
Yapõlacak tek işlem sayfaya gerekli AJAX Extension kontrollerini eklemek ve gerekli işlemleri

67
yapmak. Kurulum yapmaya, kontrolleri ToolBox'a eklemeye ve proje oluştururken ayrõ bir
proje şablonu seçmeye gerek yok. Bu sürümü ile birlikte bazõ eksiklikler ve sorunlar
giderilerek artõk ASP.NET AJAX'õn sunucu kontrolleriyle tam uyumlu şekilde çalõşmasõ da
sağlanõyor. Visual Studio 2008 ile birlikte Control Toolkit'te yer alan kontrollerin varolan
sunucu kontrollerine çok kolay şekilde entegre edilebilmesi de işimizi kolaylaştõracak bir
yenilik olarak göze çarpõyor. Önceki sürümde olduğu gibi AJAX kontrollerimiz
System.Web.UI isim alanõna eklenmiş durumda. Aşağõda Microsoft'un sunduğu .NET
Framework 3.5 isim alanlarõ ve sõnõflarõ posterinden System.Web.UI kesiti bulunmaktadõr.
(ScriptManagerProxy ve Timer kontrolleri nedendir bilinmez bu postere eklenmemiş ama
aşağõda güncellediğim posterin ilgili kesitini görebilirsiniz.)

Şekil: System.Web.UI isim alanõna AJAX kontrolleri eklendi

2. LINQ (Language Integrated Query)


.NET Framewrok 3.5 ile birlikte artõk web uygulamalarõnda da Linq hayatõmõza girecek. Linq
C# 3.0 ile birlikte geliyor ve dil ile bütünleşik olarak sorgulamalar yapõlabilmesini sağlõyor.
Veritabanõnda SQL query'leri kullanarak nasõl tablolar üzerinde sorgulamalar yapõyor ve
sorgu sonucunu elde edebiliyorsak, artõk C# veya VB.NET gibi bir dil ile de uygulama
içerisindeki bir nesnenin içeriği ile ilgili SQL sorgu cümlelerine benzer şekilde sorgulamalar
gerçekleştirebileceğiz. Bir dizi, bir koleksiyon nesnesi, XML dosyadan alõnan veriler veya
DataTable gibi veri taşõyan bir nesne üzerinde Select, Where, Order By, Join... gibi
tanõdõğõmõz ifadeleri kullanarak sorgulamalar gerçekleştirebiliyoruz. Aslõnda Linq böyle 3-4
cümle ile anlatõlacak kadar da basit bir yenilik değil. Aksine arka planda sadece Linq'i
desteklemek için bile birçok önemli yenilik C# diline kazandõrõlõyor. Linq ile birlikte gelen var
tipi, nesne ve koleksiyonlara ilk değer atõcõlar, extension metotlarõ ile varolan bir sõnõfa ek
metotlar eklemek gibi birçok yeniliği de C# veya VB.NET gibi bir dil ile dolayõsõyla ASP.NET
ile bütünleşik şekilde kullanabiliyoruz.. Linq ve gelen diğer yeniliklerle ilgili olarak aşağõdaki
blog yazõlarõnõ ve makaleleri okumanõzõ tavsiye ederim.

- C# 3.0 Ne Getiriyor ve LINQ PROJESİ Nedir?


- Bilinçsizce Türlendirilmiş Lokal Değişken (Implicitly Typed Local Variable): var
- Nesne ve Koleksiyonlara İlk Değer Atayõcõ (Object and Collection Initializer)
- Genişletme Metotlarõ (Extension Methods)
- LINQ: Daha Fazla Sorgu

68
3. Yeni Veri Kontrolleri
ASP.NET 3.5 ile gelen AJAX kontrolleri dõşõnda kontrol kütüphanemizde üç yeni kontrol daha
ekleniyor: ListView, DataPager ve LinqDataSource. ListView ve DataPager kontrolleri ile artõk
daha esnek veri görüntüleme işlemleri yapabiliyorken, LinqDataSource kontrolü ile de tüm
veri kontrollerini Linq sorgularõnõn sonucuna bağlayabiliyoruz.

- ListView
ListView veri görüntüleme, veri seçme-ekleme-güncelleme-silme gibi işlemleri
yapabileceğimiz bir kontrol. İlk bakõşta GridView kontrolüne benzetebileceğimiz bu kontrolün
GridView'den üç temel farklõlõğõ bulunmaktadõr. Bildiğimiz gibi GridView ile veri seçme-
güncelleme-silme gibi işlemleri otomatik olarak yapabiliyorken veri ekleme işlemini bu şekilde
gerçekleştiremiyorduk; ancak oluşturulacak bir template içerisinde ekstra işlemler yaparak bu
işlemi yapabiliyorduk. ListView ile artõk veri ekleme işlemlerini de otomatik olarak
gerçekleştirebileğiz (1. farklõlõk). ListView ile sayfalama işlemleri yaparken artõk DataPager
(bu yeni kontrole az sonra değineceğiz) gibi özel bir kontrol ile sayfalama template'ini de
özelleştirebiliyoruz (2. farklõlõk). Yine tasarõm aşamasõnda ListView kontrolü ile daha
özelleştirilebilir veri görüntüleme işlemleri yapabiliyoruz ki bu belki de ListView'in
GridView'dan en önemli farklõlõğõ (3. farklõlõk). ListView kontrolünü aslõnda GridView ve
DataList kontrolünün harmanlaşmõş versiyonu gibi düşünebiliriz. Tõpkõ GridView'deki gibi
kolay şekilde tüm veri işlemlerimizi çözebilirken, DataList'te olduğu gibi de arka planda HTML
kodlarõnõ kullanarak kontrolün görünümünü çok kolay şekilde istediğimiz gibi
değiştirebiliyoruz. ToolBox'ta Data Controls kõsmõnda yer alan bu kontrolü basit bir şekilde
nasõl kullanabileceğimizi görelim. Bu örnekte ListView'i bir SqlDataSource kontrolü ile SQL
Server veritabanõndaki bir tabloya bağlõyoruz. Bu kõsõm aslõnda önceki veri kontrollerinde
olduğu gibi, fakat bağlama işleminin ardõndan verilerin nasõl görüntüleceğini belirlememiz
gerekecektir. ListView'in sağ üst köşesindeki Smart-tag ikonuna tõklayarak açõlan pencereden
Configure ListView linkini seçiyoruz. Açõlan pencereden verilerin nasõl listeleneceğini, stil
ayarlarõnõ ve veri ekleme, güncelleme, silme, sayfalama işlemlerini aktif hale getirip
getiremeceğimizi belirliyoruz. Aşağõdaki resimde karşõmõza çõkacak pencere ve
yapabileceğimiz seçimler görünmektedir.

69
Resim: ListView'in "Configure ListView" penceresinden yapõlacak seçimler ve
açõklamalarõ

Aslõnda yukarõdaki resimde ilk ilgimizi çekecek durumlardan birisi verileri artõk yan yana da
dizebildiğimiz olabilir. ListView tõpkõ DataList kontrolü gibi arka planda HTML kodlarõ ile
özelleştirilebildiği için artõk görüntülenecek verileri esnek şekilde kullanõcõlara
görüntületebiliriz. Bu şekilde yine görsel kõsõmdan yapacağõmõz işlemlerle veriye çok kolay
erişebiliriz. ListView ile ilgili olarak kullanabileceğimiz bazõ önemli özellikler (property) ve
açõklamalarõnõ aşağõda bulabilirsiniz.

DataSourceID: Bağlanacak DataSource kontrolünün ID bilgisi


EditIndex: Güncelleme işleminin yapõlacağõ kayõt numarasõ. Varsayõlan değeri -1'dir ve hiçbir
kayõtõ güncelleme modunda açma anlamõna gelir
GroupItemCount: Gruplanacak kayõt sayõsõnõ belirler. Bu sayõ tek satõrda kaç kayõt
bulunacağõnõ belirler ve 1 dõşõnda bir değer verildiğinde GroupTemplate tanõmlamasõ da
yapõlmasõ gerekecektir.
InsertItemPosition: Insert şablonunun bulunacağõ yeri belirler. InsertItemPosition enum
sabiti tipinden değer alõr ve alabileceği değerler None, FirstItem ve LastItem'dõr.
ItemContainerID: Görüntülenecek verilerin bulunacağõ HTML elementin ID bilgisini taşõr.

LayoutTemplate, ItemTemplate, AlternatingItemTemplate, SelectedItemTemplate,


InsertItemTemplate, EmptyDataTemplate, EditItemTemplate, GroupTemplate gibi görünüm
şablonlarõ içerisine yazõlacak uygun HTML elementleri ile verinin her türlü görünümünü
belirleyebiliriz. Aşağõda ListView ile oluşturulmuş bir sayfanõn çõktõsõnõ görebilirsiniz.

70
Resim: ListView ile görüntülenen veriler

- DataPager
ListView ile bütünleşik şekilde kullanabileceğimiz bu kontrol ile ListView'in veri sayfalama
template'ini şekillendirebilmekteyiz. ListView'in TemplateLayout şablonu içerisine eklenir.
Temel olarak esnek sayfalama template hazõrlamamõzõ sağlayan bu kontrolde ToolBox'õn
Data Controls grubunda yer alõyor. İki farklõ görünüm şekli bulunan bu kontrole eğer
istenilirse TextBox, DropDownList gibi kontroller eklenerek özelleştirebiliriz. Örneğin toplam
20 sayfadan oluşan verilerimizde bir TextBox'a 15 yazarak 15 numaralõ sayfaya gidilmesini
sağlayabiliriz. Burada akla gelen sorulardan birisi şu olabilir DataPager gibi etkin sayfalama
işlemleri yapabilen bu kontrolü sadece ListView kontrolü ile birlikte kullanõlabiliyor.

- LinqDataSourceaSource
LinQ ile yapõlan sorgu sonuçlarõnõ veri kontrollerine bağlanmasõnõ sağlayan kontroldür.
Aslõnda bu kontrolle birlikte .NET Framework 3.5 ve Visual Studio 2008 ile gelen yeni bir
dosya tipinden bahsetmekte fayda olacaktõr: yeni bir dosya eklerken karşõnõza LINQ to SQL
Classes tipi olarak gelen DataBase Markup Language (dbml) dosyalarõ. Gelişmiş bir
projedeki en büyük ihtiyaçlarõmõzdan birisi de veritabanõndaki tablolarõn class olarak
karşõlõklarõnõ uygulamamõzda oluşturmak olacaktõr. Aslõnda entity katmanõ oluşturarak daha
kolay şekilde veri ile çalõşmaktan bahsediyoruz. dbml dosyalarõ veritabanõndaki bir tablonun
tüm özelliklerini taşõyan class'õnõ oluşturmamõzõ sağlar. DataContext tipindeki nesneler
üzerinde Linq sorgularõ çalõştõrabiliriz. LinqDataSource kontrolümüzde bu amaca yönelik
kullanõlabilecek bir kontroldür.

4. Web Servislerinde WCF Desteği


Web servisleri artõk .NET Framework 3.0 ile gelen WCF (Windows Communication
Foundation) desteği ile geliştirilebiliyor. JSON kullanõlan AJAX uygulamalarõnda ve RSS
kaynaklarõndan veri sağlanmasõ gibi işlemler artõk WCF ile daha da kolay şekilde

71
gerçekleştirilebilecek. Yine Visual Studio 2008'de yeni bir web projesi oluştururken WCF
Service proje şablonu, projemize yeni bir dosya eklerken WCF Service dosyasõ (.svc)
karşõmõza çõkan yeniliklerden bazõlarõ.

ASP.NET 3.5 ile birlite gelen temel yenilikler bunlar. Gözümüze biraz az gelmiş olabilir ama
Microsoft geçtiğimiz günlerde çõkardõğõ ASP.NET 3.5 Extensions paketi ile artõk ASP.NET
3.5'i daha da güçlü hale getirdi. Bu yeni paket ile gelen yeni kontroller ve MVC Framework ile
artõk daha güçlü ve zengin web uygulamalarõ geliştirebiliyor olacağõz. Aşağõdaki kõsa yazõda
ASP.NET 3.5 Extensions paketini tanõmaya çalõşõyoruz.

ASP.NET 3.5 EXTENSIONS

Aslõnda Microsoft bunun bir benzerini ASP.NET 2.0'õn ardõndan ASP.NET AJAX Extension'õ
duyurarak yapmõştõ. Şimdi de benzeri bir strateji ile geliyorlar. AJAX ancak 3.5 sürümünde
mimariyle bütünleşti, belki 3.5 Extensions ile gelen yenilikler de ASP.NET 4.0 (böyle bir
sürüm olur mu bilinmez) ile bütünleşik gelecektir. Aslõnda ASP.NET 3.5 Extensions içerisinde
daha önceden duyurulan ASP.NET Futures paketindeki kontroller ile ASP.NET MVC
Framework'ün olduğunu söylesek pek te yanlõş olmaz. Aşağõda bizleri bekleyen yenilikleri
hakkõnda kõsa bilgileri bulabilirsiniz.

1. ASP.NET MVC Framework: MVC yani Model View Controller. MVC mimarisi aslõnda
daha önceden de duyulan bir tasarõm deseniydi (design pattern) programlama dünyasõnda.
Bu yaklaşõmdaki temel mantõk bir web projesini üç temel parçaya bölmek ve yapõlacak işleri
bu parçalar üzerinden yürütmektir. Hazõrladõğõmõz projelerde sõklõkla kullandõğõmõz
uygulamayõ iş katmanõ ile veri katmanõ olarak ayrõ parçalara bölmeyi buradaki yaklaşõm ile
benzeştirebiliriz. Aslõnda temel amaç uygulamayõ işe yarar belirli amaçlarõ olan parçalara
bölmek ve bir parçanõn değişiminden diğer parçalarõn etkilenmesini engellemektir. MVC
uygulamanõn Model, View ve Controller olarak üçe ayrõlmasõnõ benimseyen bir tasarõm
desenidir.
- Model veri ve durum bilgilerini taşõr. Burasõ DataTable, DataSet ve entity katmanõmõzdaki
sõnõflarõn bulunduğu bileşendir.
- View uygulamanõn arayüzlerinin bulunduğu bileşendir. Master sayfalar, aspx ve ascx gibi
kullanõcõnõn görüntüleyeceği dosyalar bu kõsõmda yer alõr.
- Controller ise arayüzler arasõndaki etkileşimi sağlayan, veri nesneleri üzerinde değişiklik
yapõlmasõnõ sağlayan bileşenlerdir. Örneğin, Controller katmanõndaki sõnõflar aracõlõğõyla etkin
URL Mapping işlemi yaparak artõk tarayõcõ üzerinden sayfalara istek yapmak yerine
nesnelere istekte bulunabiliyoruz. Yani URL üzerinden tarayõcõda görüntülenecek nesnenin
render edilmesi sağlanabiliyor.

2. ASP.NET AJAX Tarafõndaki Geliştirmeler: Futures paketinden tanõdõğõmõz History


kontrolü bu paketin içerisinde olacak. AJAX sayfalarõnda tarayõcõdaki ileri-geri gitme
problemini çözecek olan bu kontrol asenkron postbackler esnasõnda sayfanõn URL kõsmõnõ
değiştirerek tarayõcõnõn değişen sayfa içeriklerini geçmişine kaydetmesini sağlõyor.

72
3. Dinamik Veri (Dynamic Data) Desteği: Yine Futures paketinden tanõdõğõmõz bir özellik.
DynamicAutoData, DynamicList, DynamicNavigator, DynamicRssLink gibi bazõ veri
kontrolleri ile bir veritabanõnda yapacağõmõz Select, Insert, Update, Delete gibi işlemleri
neredeyse kod yazmadan gerçekleştirebilmemizi sağlõyor. .NET Framework 3.5 ile gelen
Database Markup Language (dbml) dosyalarõ ile dinamik veri kontrollerini birlikte
düşününce ve üstüne MVC Framework'ü de katõnca bu yeniliklerin MVC'nin Model katmanõnõ
oluşturacağõnõ söyleyebiliriz.

4. SilverLight Desteği: SilverLight artõk ASP.NET ile giderek bütünleşiyor. Tahminen yine
Futures paketindeki Media ve XAML kontrollerinin ekleneceği bu pakette ASP.NET ile
SilverLight'õn entegrasyonunun daha da kolaylaşacak. Yani daha interaktif daha zengin
içerikli sayfalar geliyor.

5. ADO.NET Veri Servisleri (Data Services): ADO.NET Entity Framework adõ verilen bu
pakette ASP.NET 3.5 Extensions ile birlikte duyurulacak. Object Relation Mapping (ORM)
desteği ile daha da güçlenen .NET Framework 3.5'teki veri işlemleri aslõnda bu framework
altõnda toplanõyor gibi. Artõk veri ile ilgili her türlü işlemi oluşturacağõmõz veya SqlMetal.exe
aracõ ile oluşturulacak class'lar ile gerçekleştireceğiz gibi.

ASP.NET 3.5 Futures paketiyle ilgili daha detaylõ bilgi edinmek, bilgisayarõnõza yüklemek ve
kullanmak için http://asp.net/downloads/3.5-extensions/ adresine göz atabilirsiniz.

73
TreeView'da Veritabanõyla ve XML Dosyalarla
Çalõşmak
05 Şubat 2008

ASP.NET 2.0 ile birlikte gelen site navigasyonu kontrolleri ile site haritalarõnõn kullanõcõlara
dinamik menülerle görüntülenmesi sağlanabilmekte ve daha profesyonel görünümler elde
edilebilmektedir. Bu kontrollerden biri olan TreeView’da ağaç görünümünde menüler
oluşturmamõzõ sağlamaktadõr. Genellikle proje içerisinde XML tabanlõ oluşturulan bir
.sitemap dosyasõ ile birlikte kullanõlõr. Sitemap dosyalarõ gerek oluşturulmasõ gerekse site
navigasyon kontrolleri ile kolay ve uyumlu çalõşmasõ açõsõndan biz yazõlõm geliştiricilere
büyük kolaylõklar sağlamaktadõr.

Sitemap dosyasõ belirli standartlar dahilinde yazõlmakta ve genellikle site içerisindeki linklerin
hiyerarşik yapõsõnõ saklamaktadõr. TreeView kontrolü site haritasõnõ taşõmak amacõyla
kullanõlabileceği gibi farklõ içerikleri de ilişkisel şekilde kullanõcõlara sunulmasõnõ da
sağlayabilecek bir yapõya sahiptir. Örneğin kendi hazõrladõğõmõz XML dokümanõndaki verilerin
süzülerek üst düğüm – alt düğüm ilişkisi ile bu kontrole yüklenmesini isteyebiliriz. Böyle bir
durumda akla gelen soru TreeView kontrolünü farklõ yapõdaki XML dosyalarõ ile nasõl
konuşturabileceğimizdir. Makalemizin ilk kõsmõnda bu sorunun çözümünü inceleyeceğiz.

Site haritasõnõn sitemap dosyasõnda saklanmasõnõn bazõ dezavantajlarõ olduğunu da


söyleyebiliriz. Zira XML tabanlõ bir doküman olduğu için gerek yapõsõnõ çözümlemek gerekse
güncellemeler yapmak sõkõntõ doğurabilmektedir. Özellikle kategori-alt kategori yapõsõ geniş
olan ve sõklõkla güncellenen sitelerde (örneğin alõşveriş sitelerinde) verileri XML
dokümanõnda saklamak yerine veritabanõnda saklamak daha sõk tercih edilmektedir. Peki
sitemizin haritasõnõ veritabanõndaki tablolarda saklõyorsak bu verileri TreeView kontrolünde
nasõl görüntüleriz? Makalemizin ikinci kõsmõnda da bu sorunun çözümünü adõm adõm
inceleyeceğiz.

Dilerseniz bu iki işlemin detaylarõnõ incelemeden önce TreeView kontrolünün yapõsõ hakkõnda
önemli bir noktaya değinelim. TreeView kontrolü Nodes koleksiyonu içerisinde TreeNode
tipiden nesneler saklayarak linklerin oluşturulmasõnõ sağlar. Aslõnda sayfa çalõştõrõldõğõnda
TreeView’da görünen tüm linkler birer TreeNode nesnesidir. TreeNode nesnesi de kendi
içerisindeki ChildNodes koleksiyonu içerisinde yine kendi tipinden yani TreeNode nesneleri
taşõyabildiği için iç içe linkler oluşturulabilmektedir. Sitemap dosyasõnõ TreeView kontrolüne
kaynak olarak gösterdiğimizde kullanõlan SiteMapDataSource kontrolünün yapmõş olduğu
işlem .sitemap dosyasõnõn içerisindeki yapõyõ çözümlemek ve bunlarõ TreeNode nesneleri
olarak TreeView kontrolüne bağlamaktõr. Aşağõdaki şekil TreeView kontrolüne bağlanan
TreeNode’larõn yapõsõnõ simgelemektedir.

74
Şekil: TreeView kontrolüne eklenen TreeNode nesnelerinin hiyerarşik yapõsõ

TreeNode sõnõfõnõn (class) yapõcõ metotlarõ (constructor) aracõlõğõ ile farklõ şekilde nesneler
oluşturulabilir. Burada oluşturulan nesneler TreeView kontrolündeki linkler olacağõ için sayfa
yüklendiğinde LinkButton veya HyperLink olarak getirilecektir. Dolayõsõyla oluşturulan link ya
aynõ sayfa üzerinde postback işlemi yapacak ya da başka bir sayfaya link verecektir. Aşağõda
bir TreeNode nesnesinin farklõ oluşturulma şekilleri bulunmaktadõr.

// Oluşan linkin metnini ilk parametre belirler. Bu linke tõklandõğõnda Deger1 değeri ile
postback işlemi yapar
TreeNode anaMenu1 = new TreeNode("Postback Link", "Deger1");

// Bir önceki link gibi çalõşõr. Linkin sol kõsmõnda son parametrede yer alan resim görüntülenir
TreeNode anaMenu2 = new TreeNode("Resimli Link", "Deger2", "menu.jpg");

// Oluşan link 4. parametrede belirlenen sayfaya gider. Son parametre ise hedef sayfanõn
açõlma şeklini belirler (“_blank” yeni bir pencerede açõlmasõnõ sağlar). 3. parametre burada
boş bõrakõlmõştõr fakat geçerli bir resim adresi verilerek linkin solunda resim görüntülenebilir
TreeNode anaMenu3 = new TreeNode("Sayfaya Link", "", "", "Sayfa.aspx", "_blank");

Bir TreeNode nesnesi ChildNodes koleksiyonunda kendi tipinden nesneler taşõyabilir ve


bunlarda o nesnenin alt linklerini oluşturur. Oluşan ana menü de TreeView kontrolünün
Nodes koleksiyonuna eklenerek menü içerisinde görüntülenmesi sağlanõr. Aşağõda
oluşturulan iki alt menü bir ana menüye bağlanmakta ve ana menüde TreeView kontrolüne
bağlanmaktadõr.

Default.aspx
<form id="form1" method="post" runat="server">
<asp:TreeView ID="agacMenu" runat="server" />
</form>

Default.aspx.cs
// Ana düğüm oluşturuluyor
TreeNode anaMenu1 = new TreeNode("Ana menü - 1", "", "", "AnaMenu1.aspx", "");

75
// Alt düğümleri oluşturmasõ için iki TreeNode nesnesi oluşturuluyor
TreeNode altMenu1 = new TreeNode("Alt menü - 1", "", "", "AltMenu1.aspx", "");
TreeNode altMenu2 = new TreeNode("Alt menü - 2", "", "", "AltMenu2.aspx", "");

// Alt düğümler ana menü nesnesine ekleniyor


anaMenu1.ChildNodes.Add(altMenu1);
anaMenu1.ChildNodes.Add(altMenu2);

// Oluşan ana menü sayfadaki agacMenu kontrolüne ekleniyor


agacMenu.Nodes.Add(anaMenu1);

Sayfa çalõştõrõldõğõnda oluşan basit menü aşağõdaki şekilde görülmektedir.

Resim: Programatik şekilde oluşturulan TreeView kontrolü

Bu şekilde menülerin TreeView içerisinde programatik olarak nasõl yerleştirileceğini görmüş


olduk. Dilerseniz XML dosyadan ve veritabanõnda getirilen verileri nasõl TreeView’a
aktarabileceğimizi inceleyelim

Veri Kaynağõ Olarak XML Dosyalarõnõ Kullanmak


Sitemap dosyalarõ ASP.NET 2.0 ile birlikte gelen yeni bir dosya tipidir. XML tabanlõ olan bu
dosya SiteMapDataSource ile navigasyon kontrollerine veri kaynağõ oluşturmaktadõr. Bazõ
durumlarda kendi hazõrladõğõmõz özel yapõdaki bir XML dosyasõndaki verileri de TreeView
kontrolü ile kullanmak isteyebiliriz. Böyle bir durumda XML dosyasõnõ XmlDataSource
kontrolü ile TreeView’a bağlamamõz gerekecektir. Tabii ki dosyamõzdaki yapõyõ
çözümleyebilmesi için de TreeView kontrolünde bazõ özel ayarlamalar yapmamõz gerekir. Bir
askeri birlikteki askerlerin listesini içeren XML dosyasõnõ TreeView kontrolüne yükleyelim.
Öncelikli olarak işe bir XML dosyasõ oluşturarak başlayalõm.

Askerler.xml

<?xml version="1.0" encoding="windows-1254" ?>

<KarargahDestekGrubu>

<Birim Ad="Karargah Bölüğü">


<Asker Id="109" Ad="Ahmet YÜKSEL" />
<Asker Id="186" Ad="Metin DİLEK" />
<Asker Id="214" Ad="Umut NACAK" />

76
<Asker Id="304" Ad="Onb. Eyüp ERDEM" />
<Asker Id="319" Ad="Çvş. Uğur UMUTLUOĞLU" />
<Asker Id="341" Ad="Çvş. Muhammet KURT" />
</Birim>
<Birim Ad="Muhafõz Bölüğü">
<Asker Id="177" Ad="Bahadõr ARSLAN" />
<Asker Id="192" Ad="Emrah USLU" />
<Asker Id="265" Ad="Çvş. Burak BATUR" />
<Asker Id="329" Ad="Onb. Osman ÇOKAKOĞLU" />
</Birim>
<Birim Ad="Lojistik Destek">
<Asker Id="155" Ad="Onb. Bülent SÖZGE" />
<Asker Id="281" Ad="Çvş. Özgür ALTUNTAŞ" />
<Asker Id="299" Ad="Burak Selim ŞENYURT" />
</Birim>

</KarargahDestekGrubu>

Bu noktadan sonra XMLDataSource kontrolü ile dosyayõ TreeView'a bağlamamõz ve gerekli


ayarlarõ yapmamõz gerekecektir. TreeView kontrolünün DataBindings koleksiyonuna
eklenecek TreeNodeBinding nesneleri ile bu işlemi gerçekleştirebiliriz. Bu işlemi
programatik yollarla gerçekleştirebileceğimiz gibi dekleratif şekilde de yapabiliriz. Aşağõdaki
kodlarda sayfamõza eklenen TreeView ve XmlDataSource kontrolleri ile TreeView'in
DataBindings koleksiyonuna eklenen TreeNodeBindings nesneleri görülmektedir.

Default.aspx

<asp:TreeView ID="AskerListe" runat="server" DataSourceID="XmlDSAskerListe">


<DataBindings>
<asp:TreeNodeBinding DataMember="KarargahDestekGrubu" Text="Karargah Destek
Grubu"></asp:TreeNodeBinding>
<asp:TreeNodeBinding DataMember="Birim" TextField="Ad"></asp:TreeNodeBinding>
<asp:TreeNodeBinding DataMember="Asker" TextField="Ad"
ValueField="Id"></asp:TreeNodeBinding>
</DataBindings>
</asp:TreeView>

<asp:XmlDataSource ID="XmlDSAskerListe" Runat="server" DataFile="Askerler.xml" />

TreeNodeBinding tanõmlamalarõnda bulunan DataMember özelliği XML'den okunacak etiket


ismini, TextField ise görüntülenecek verinin bulunduğu niteliği belirlemektedir. Sayfa
çalõştõrõldõğõnda okunan verilerin TreeView'a hiyerarşik şekilde doldurulduğu görülecektir.
TreeView kontrolünün önemli özelliklerinden biri de listelenen linklere resim eklenebileceği
gibi CheckBox gibi bir kontrolde eklenmesini sağlayabilmesidir. Yaptõğõmõz örnekte belirli bir
bölükte bulunan askerlerden bazõlarõnõn seçilmesi ve sayfa postback edildiğinde seçili

77
elemanlarõ okunmasõ isteniliyorsa bu işlem kolay bir şekilde yapõlabilir. Amaç askerlerin
seçim işleminin yapõlmasõ olacağõ için asker isimlerinin eklendiği TreeNodeBinding
elementinin ShowCheckBox niteliği true olarak ayarlanõrsa listelenen asker isimlerinin sol
kõsmõna birer CheckBox kontrolü eklenecektir. Aşağõda bu değişikliğin nasõl yapõlacağõ,
CheckBox'lar olmadan TreeView'in görünümü ve CheckBox kontrolleri eklendiğinde
TreeView kontrolünün görünümü bulunmaktadõr.

Default.aspx

<asp:TreeNodeBinding DataMember="Asker" TextField="Ad" ValueField="Id"


ShowCheckBox="true"></asp:TreeNodeBinding>

Resim: XML dosyasõnõ kaynak olarak kullanan TreeView'õn a) normal şekilde


oluşturulmasõ, b) linklerinin CheckBox ile birlikte oluşturulmasõ

Bu şekilde TreeView kontrolünü kendi oluşturacağõmõz bir XML dosyasõ ile nasõl
besleyebileceğimizi görmüş olduk. Burada kilit noktamõz XmlDataSource kontrolü ile veri
kaynağõnõ belirlememiz ve TreeView'in DataBindings özelliğine ekleyeceğimiz
TreeNodeBinding nesneleri ile XML dosyadaki hangi etiketleri ve nitelikleri süzeceğimizi
belirlemektir. Son kõsõmda menümüzdeki asker isimlerine eklediğimiz CheckBox'larõ seçim
durumlarõna göre bir liste elde etme işlemini de aşağõdaki kodlarda gördüğünüz şekilde
gerçekleştirebiliriz. Öncelikli olarak sayfamõzõn HTML kõsmõnda bir Button nesnesi ekleyerek
bu butona tõklanmasõ durumunda listedeki seçili elemanlarõ ekrana yazdõralõm.

Default.aspx

<asp:Button ID="btnSec" runat="server" Text="Çarşõ İznine Çõkacak Askerleri Seç"


OnClick="btnSec_Click" />

78
Default.aspx.cs

protected void btnSec_Click(object sender, EventArgs e)


{
// En üstte tek node olduğu için bu node'un içerisindeki kõsõmlarõ tek tek ele alõyoruz
foreach(TreeNode node in AskerListe.Nodes[0].ChildNodes)
{
Response.Write(node.Value + " kõsmõndaki askerler:<br>");
// Her kõsõmda bulunan askerleri ele alõyoruz
foreach(TreeNode altNode in node.ChildNodes)
{
if(altNode.Checked) // Eğer seçilmiş ise
Response.Write(" - " + altNode.Text + "<br>");
}
}
}

Seçim işlemi yapõldõktan sonra aşağõdaki şekilde görüleceği gibi seçim listesini elde
edebiliyoruz.

Resim: 1) Listeden seçim yapõlmasõ, 2) Seçilen askerlerin listesinin ve bağlõ olduğu


kõsõmlarõn elde edilmesi

Veri Kaynağõ Olarak Veritabanõ Kullanmak


Geldik makalemizin belki de en can alõcõ kõsmõna! Zira veritabanõnda saklanan site
haritalarõnõ TreeView veya Menu gibi kontrollere aktarabilmek biz programcõlar için oldukça

79
kolaylaştõrõcõ bir işlem olacaktõr. Veritabanõndaki tablolarda saklanan kategori-alt kategori
tarzõndaki ilişkili verileri TreeView'e aktarmak için dilerseniz alõşveriş sitelerindeki gibi bir yapõ
üzerinden hareket edelim. Ürünlerimizin bulunduğu ana kategorilerimiz olsun; Elektronik
Eşya, Bilgisayar gibi... Yine bu ana kategorilerin altõnda da ürünlerimizi ayrõştõrmak için alt
kategorilerimiz olsun; Bilgisayar kategorisinin altõnda Dizüstü Bilgisayar ve Masaüstü
Bilgisayar gibi... Bu kategorilere aitte ürünlerimiz olsun. Yani 3 tane ana tablomuz içerisinde
bu bilgiler saklansõn: Kategoriler, AltKategoriler ve Urunler. Aşağõdaki şekillerde örnekte
kullanacağõm tablolarõn alan isimleri ve veri tipleri bulunmaktadõr.

Şekil: Kategoriler tablosu

Şekil: Alt Kategoriler tablosu

Şekil: Ürünler tablosu

Tablolarõ verilerle doldurduktan sonra öncelikli olarak normal bir veri işlemi ile üç tablodaki
verileri seçerek bir DataSet nesnesi içerisine dolduralõm. Burada işimizi kolaylaştõrmak için
DataSet içerisinde 3 farklõ DataTable içerisinde saklayacağõmõz bu verileri DataRelation
nesnesi ile ilişkili şekilde tutmak mantõklõ olacaktõr. Zira bir sonraki adõmda ilişkili kayõtlarõ
okurken elde edilen DataRow nesnelerinin GetChildRows() metodu ilişkili alt tablodaki
kayõtlara kolayca erişmemizi sağlayacaktõr. Tablo yapõlarõ incelenecek olunursa, Kategoriler
> AltKategoriler > Urunler şeklinde bir ilişkinin olduğu görülecektir. DataSet'e ekleyeceğimiz
DataRelation nesneleri de bu düzende belirlenecektir.

Default.aspx.cs

protected DataSet MenuListe()


{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OleDB.4.0; Data
Source=C:\\Inetpub\\wwwroot\\TreeView_test\\Veriler.mdb");

80
OleDbDataAdapter daKat = new OleDbDataAdapter("Select * From Kategoriler", con);
OleDbDataAdapter daAltKat = new OleDbDataAdapter("Select * From AltKategoriler",
con);
OleDbDataAdapter daUrunler = new OleDbDataAdapter("Select * From Urunler", con);

// Tablolardan gelen verileri DataSet içerisine tablolar halinde dolduruyoruz


DataSet ds = new DataSet();
daKat.Fill(ds, "Kategoriler");
daAltKat.Fill(ds, "AltKategoriler");
daUrunler.Fill(ds, "Urunler");

// Tablolar arasõnda ilişkili kolonlar üzerinden ilişkileri belirliyoruz


ds.Relations.Add("Kat_AltKat", ds.Tables["Kategoriler"].Columns["KategoriID"],
ds.Tables["AltKategoriler"].Columns["KategoriID"]);
ds.Relations.Add("AltKat_Urun", ds.Tables["AltKategoriler"].Columns["AltKategoriID"],
ds.Tables["Urunler"].Columns["AltKategoriID"]);
return ds;
}

Makalemizin ilk kõsõmlarõna dönecek olursak TreeView kontrolünün TreeNode nesnelerinde


oluştuğundan bahsetmiştik. Programatik olarak TreeView'e düğümler (node) ekleyip,
düğümler altõna da alt düğümler (child node) oluşturarak menüler elde edebilmiştik. Bu
noktadan sonra yapacağõmõz işlem döngüler içerisinde önce kategorilere erişmek ve kategori
için TreeNode nesneleri oluşturmak. Oluşan kategori düğümüne alt kategorileri, alt
kategorilere de kendilerine ait ürünlerin eklenmesini sağlamamõz gerekiyor. Oluşan tüm
kategori nesnelerini de TreeView'in Nodes koleksiyonuna ekleyecek olursak menümüzü
oluşturabileceğiz.

Default.aspx

<form id="form1" method="post" runat="server">


<asp:TreeView ID="tvMenu" runat="server" />
</form>

Default.aspx.cs

private void Page_Load(object sender, EventArgs e)


{
DataSet dsMenu = MenuListe();

// Kategorileri oku
foreach(DataRow dr in dsMenu.Tables["Kategoriler"].Rows)

81
{
TreeNode anaMenu = new TreeNode(dr["Ad"].ToString(), "", "",
"Kategori.aspx?Id=" + dr["KategoriID"].ToString(), "");
// Alt kategorileri oku
foreach(DataRow drAlt in dr.GetChildRows("Kat_AltKat"))
{
TreeNode altMenu = new TreeNode(drAlt["Ad"].ToString(), "", "",
"AltKategori.aspx?Id=" + drAlt["AltKategoriID"].ToString(), "");
// Ürünleri oku
foreach(DataRow drUrun in drAlt.GetChildRows("AltKat_Urun"))
{
TreeNode urunMenu = new TreeNode(drUrun["Ad"].ToString(), "", "",
"Urun.aspx?Id=" + drUrun["UrunId"].ToString(), "");
altMenu.ChildNodes.Add(urunMenu);
}
anaMenu.ChildNodes.Add(altMenu);
}
tvMenu.Nodes.Add(anaMenu);
}
}

Sayfayõ çalõştõrdõğõmõzda veritabanõndaki 3 tablodan getirilen verilerin hiyerarşik şekilde


TreeView kontrolüne yüklendiğini görebiliriz. Aşağõdaki resimde sayfamõzõn çõktõsõnõ
görebilirsiniz.

82
Resim: Veritabanõndan getirilen veriler TreeView kontrolüne yüklendi

Görüldüğü gibi veritabanõndaki kayõtlarõ TreeView kontrolüne yükleme işlemi oldukça pratik
halde gerçekleştirilebiliyor. Burada bizim için en önemli noktalardan biri tabii ki veritabanõnda
saklanan kayõtlarõn tablolarda ilişkisel bir şekilde saklanmasõdõr. Bu tip bir işlemi yukarõdaki
şekilde gerçekleştirebileceğimiz gibi kendi Kategori, AltKategori ve Urun sõnõflarõmõzõ
oluşturup her bir sõnõf içerisinde bir alt birimindeki nesnelere ait liste koleksiyonlarõnõ
taşõyarak ta gerçekleştirebilirdik.

Bu makalemizde TreeView kontrolünün nesneleri taşõyõş şekline değinerek XML veri


kaynaklarõndan veya bir veritabanõnda okunan verileri TreeView kontrolüne nasõl
aktarabileceğimizi inceledik. Sitemap dosyalarõ kullanmaksõzõn da TreeView kontrolünü etkin
şekilde uygulamalarõmõzda kullanabiliriz. Burada anlatõlan bir çok konu aslõnda bir diğer
navigasyon kontrolü olan Menu kontrolü için de geçerli olduğunu söyleyebiliriz.

83
Site Navigasyonu Hakkõnda Bilinmeyenler
01 Mart 2008

ASP.NET 2.0 ile birlikte gelen site navigasyonu yapõsõ ve kontrolleri ziyaretçilerin site
içerisinde kolay şekilde gezinmelerini sağlayacak menüler oluşturabilmemizi sağlamaktadõr.
Projelerimizde pratik şekilde kullanabileceğimiz bu yapõlar birçok ihtiyacõmõzõ karşõlayacak
özelliklere sahiptir. Fakat bazen kendi özel durumlarõmõza göre bu kontrolleri değiştirmek
veya varolan yapõya ek nitelikler kazandõrmak isteyebiliriz. Aslõnda site navigasyonu
hakkõnda birçoğumuzun bilmediği özellikler belki de bizim projelerdeki bu tip ihtiyaçlarõmõzõ
karşõlayabilecektir. İşte bu makalede ASP.NET'te site navigasyonu hakkõnda bilinmeyen
yönleri keşfetmeye çalõşacağõz. Aşağõda beş başlõkta bu konularõn detaylarõnõ inceleyoruz.

Site Haritasõnõn Belirli Kõsõmlarõnõ Görüntüleme


Site navigasyonu işlemlerinde kullandõğõmõz sitemap dosyasõnõn belirli standartlarõ
bulunmaktadõr. En dõşta sadece bir SiteMapNode düğümünün olmasõ, aynõ linki birden fazla
kez kullanamamak (bu kõsõtlamayõ nasõl aşabileceğimizi bir sonraki başlõkta göreceğiz) gibi
standartlar bazen karşõmõza birer kõsõtlama olarak çõkmakta ve yapmak istediğimiz işlemleri
engelleyebilmektedir. Yine bazõ durumlarda içerisinde onlarca düğüm (node) bulunduran bir
site haritasõnõn sadece belirli bir kõsmõnõ görüntülemek isteyebiliriz. SiteMapDataSource
kontrolünün bazõ özelliklerini kullanarak site haritasõnõn belirli kõsõmlarõnõn görüntülenmemesi
veya sadece belirli kõsõmlarõndan sonraki düğümlerin görüntülenmesi gerçekleştirilebilir.
Dilerseniz standart bir sitemap dosyasõ hazõrlayarak ne gibi işlemleri yapabileceğimizi
inceleyelim.

Web.sitemap

<?xml version="1.0" encoding="windows-1254" ?>

<siteMap>
<siteMapNode url="Default.aspx" title="Anasayfa">
<siteMapNode url="Makale.aspx" title="Makaleler">
<siteMapNode url="Aspnet.aspx" title="ASP.NET" description="ASP.NET konusunda
makaleler" />
<siteMapNode url="Adonet.aspx" title="ADO.NET" description="ADO.NET konusunda
makaleler" />
<siteMapNode url="Cs.aspx" title="C#" description="C# konusunda makaleler" />
<siteMapNode url="SqlServer.aspx" title="SQL Server" description="SQL Server ile ilgili
makaleler" />
</siteMapNode>
<siteMapNode url="Videolar.aspx" title="Videolar" description="Teknik içerikli videolar">
<siteMapNode url="KonuAnlatimi.aspx" title="Konu Anlatõmõ" description=".NET içerikli
görsel videolar" />
<siteMapNode url="Webiner.aspx" title="Webiner" description="Web seminerlerinin

84
videolarõ" />
</siteMapNode>
<siteMapNode url="Forum.aspx" title="Forum" />
<siteMapNode url="Iletisim.aspx" title="İletişim" />
</siteMapNode>
</siteMap>

Sitenin genelinde şablon olarak kullanõlacak olan bir master sayfaya SiteMapPath,
TreeView ve SiteMapDataSource kontrollerini ekleyerek sitemap dosyasõndan getirilen
verileri sayfamõza yükleyelim. Sayfayõ çalõştõrõp sonucunu görerek neler yapabileceğimiz
üzerinde yazõmõza devam edelim. Aşağõda sayfamõzõn kodlarõ ve çõktõsõ bulunmaktadõr.

Sablon.master

<form id="form1" method="post" runat="server">


<asp:SiteMapPath ID="SiteMapPath1" runat="server" /><br><br>
<asp:TreeView ID="TreeView1" runat="server" DataSourceID="SiteMapDataSource1"
/>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
</form>

Resim: Sitemap dosyasõndaki veriler SiteMapPath ve TreeView kontrolüne eklendi

web.sitemap dosyasõnda oluşturulan site haritasõnda hiyerarşik olarak en üstte Anasayfa


bulunmaktadõr. Bu link sayfamõzda da aynõ şekilde tutuluyor. Fakat TreeView kontrolünde
anasayfa linkinin görülmesi çoğu zaman istenilmeyen bir durumdur. Özellikle SiteMapPath ile

85
birlikte TreeView kullanõldõğõnda zaten Anasayfa linki sürekli olarak SiteMapPath'de yer
alacağõ için TreeView'da en dõşta tüm node'larõ kapsayan Anasayfa node'unu göstermek
istemeyebiliriz. Fakat sitemap dosyasõnda da en dõşta bir SiteMapNode bulundurmak gibi bir
zorunluluğumuz olduğunu da belirtmiştik; yani web.sitemap'te bu linki bulundurmak
zorunludur. Peki TreeView'dan bu linki nasõl kaldõrabiliriz?

SiteMapDataSource kontrolüne ait ShowStartingNode özelliği (property) bu işlemi


gerçekleştirmemizi sağlar. bool tipinden değer alan bu özellik varsayõlan olarak true değerini
taşõr ve başlangõç node'unun gösterilmesini sağlar. Eğer bu özelliğe false değeri atanõrsa
sitemap dosyasõnõ veri kaynağõ olarak kullanan kontrolde en dõştaki node okunmaz. Aşağõda
değişen kod kõsmõ ve sayfanõn yeni çõktõsõ görülmektedir.

Sablon.master

...
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server"
ShowStartingNode="false" />
...

Resim: ShowStartingNode özelliği false değeri olarak ayarlandõğõnda en dõştaki node


listelenmez

Bu şekilde en dõştaki node'un görüntülenmesi engellendi ve artõk Anasayfa linki


görüntülenmiyor. SiteMapPath kontrolü SiteMapDataSource kontrolüne bağõmlõ çalõşmadõğõ
için bu değişiklikten etkilenmez ve Anasayfa linkini görüntüler.

Bazõ durumlarda da site haritasõndaki içeriklerin belirli kõsmõnõ görüntülemek isteyebiliriz.


Örneğin yukarõ kullandõğõmõz senaryoda ziyaretçi Makaleler kategorisi içerisinde gezerse
TreeView'da sadece Makaleler kategorisinin alt linklerini görüntülemek isteyebiliriz. Sitemap

86
içeriğinin sadece belirli bir kõsmõnõ görüntülemek istediğimiz durumlarda kullanabileceğmiz
birden fazla özellik bulunmaktadõr. Aşağõda bu özellikler ve açõklamalarõ bulunmaktadõr.

- StartFromCurrentNode: O an bulunulan sayfanõn node ve alt node'larõnõn getirilmesini


sağlar. bool tipinde değer alõr ve true değeri aldõğõnda sadece bulunulan sayfanõn node ve
alt node'larõnõ getirir. Özellikle karmaşõk site haritalarõnda ziyaretçiye sadece o an ziyaret
ettiği kategorinin alt kategorilerini görüntülemek istendiğinde kullanõlabilir. Örneğin kullanõcõ
Makale.aspx sayfasõnda bulunduğunda TreeView veya Menu kontrolü sadece Makaleler
kategorisindeki linkleri görüntüler.

- StartingNodeUrl: Belirtilen adresin bulunduğu node'u ve alt node'larõnõ getirir. Değer olarak
string tipinden sayfanõn adurl bilgisini almaktadõr. Belirli sayfalarda sadece belirli bir
kategorinin ve alt kategorilerinin görüntülenmesi istenildiğinde kullanõlabilir. Örneğin sitede
editör olan bir kişi siteye giriş yaptõğõnda menü kõsmõnda sadece Editorler.aspx sayfasõ ve bu
sayfanõn altõnda kalan sayfalarõn görüntülenmesi istenildiğinde bu özellik "Editorler.aspx"
değerine ayarlanabilir.

Aşağõdaki kod örneklerinde yukarõda bahsedilen özelliklerin kullanõmõ görülmektedir. Kodlarõn


hemen altõnda ise sayfanõn çõktõsõ bulunmaktadõr.

Sablon.master (StartFromCurrentNode kullanõmõ)

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server"


StartFromCurrentNode="true" />

Resim: StartFromCurrentNode true değeri aldõğõ için o an bulunulan kategori ve alt


kategorileri getirildi

Sablon.master (StartingNodeUrl kullanõmõ)

<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server"

87
StartingNodeUrl="Videolar.aspx" />

Resim: StartingNodeUrl özelliği Videolar.aspx değerini aldõğõ için sitemap dosyasõnda


bu sayfa ve altõnda yer alan node'lar getirildi

Site Haritasõnda Aynõ Linki Birden Fazla Kullanmak


Sitemap dosyasõndaki siteMapNode'larõn url bilgilerinin tekil (unique) değerler olmasõ
gerekmektedir. Site haritasõ oluşturulurken XmlSiteMapProvider tarafõndan url bilgileri tekil
değer olarak alõnõr ve birbirini tekrar eden url bilgilerinin olmasõna izin verilmez. Önceki
örnekte kullandõğõmõz web.sitemap dosyasõndaki Makale.aspx url bilgisini Default.aspx bilgisi
ile değiştirelim. Sayfayõ çalõştõrdõğõmõzda aşağõdaki gibi bir hata sayfasõ ile karşõlaşõrõz.

Web.sitemap

<siteMap>
<siteMapNode url="Default.aspx" title="Anasayfa">
<siteMapNode url="Default.aspx" title="Makaleler">
...

88
Resim: Sitemap dosyasõnda aynõ URL bilgisini taşõyan iki node bulunduğu için hata
oluştu

Görüldüğü gibi web.sitemap dosyasõnda birden fazla URL kullanõmõna izin verilmez. Fakat
bazõ durumlarda site haritasõnda aynõ linki birden kez fazla kullanma ihtiyacõ hissedebiliriz.
Böyle bir durumda maalesef aynõ linkleri kullanma şansõmõz olmayacaktõr. Ancak kendi özel
SiteMapProvider'larõmõzõ oluşturarak bu tip bir işlemi gerçekleştirebiliriz. Peki varolan yapõyõ
kullanarak bu işlemi nasõl gerçekleştirebiliriz? Bu işlem için iki yol seçilebilir. Bunlardan ilki
URL ReWriting ile farklõ url'leri aynõ sayfaya yönlendirme yapmak olabilir, fakat bu pek etkili
bir yöntem olmayacaktõr. Zira aynõ linki 3-4 yerde kullanmak için farklõ URL ReWriting
tanõmlamalarõ yapmak gerekebilir. Bir diğer yol ise asõl sayfa adresinin sonuna geçersiz
QueryString'ler yazmak olacaktõr. Her ne kadar etkili ve tavsiye edilecek bir yol olmasa da
böyle bir durumda kullanõlabilecek en kolay çözüm bu olacaktõr. Örneğin aynõ sayfayõ üç
farklõ yerde kullanmak istersek Sayfa.aspx, Sayfa.aspx?1 ve Sayfa.aspx?2 gibi üç farklõ url
kullanõp aynõ sayfaya link verebiliriz. Aşağõda web.sitemap dosyasõndaki url'lerin değiştirildiği
ve sayfanõn düzgün şekilde çalõştõğõ görülebilir.

Web.sitemap

<siteMap>
<siteMapNode url="Default.aspx" title="Anasayfa">
<siteMapNode url="Default.aspx?1" title="Makaleler">
...

89
Resim: Sitemap dosyasõnda aynõ olan URL bilgilerinin sonuna geçersiz QueryString'ler
eklendiğinde farklõ anahtar değerleri taşõndõğõ için aynõ sayfalar link verilebilir

SiteMap Nesnesi ile Çalõşmak


Sitemap dosyalarõnda taşõnan bilgileri uygulama içerisinden okuma olanağõmõz
bulunmaktadõr. Sonuçta XML olarak taşõnan bu verileri programatik yollarla elde etme
şansõmõz olacaktõr. .NET Framework gibi güçlü bir altyapõya sahip ortamda bu dosyayõ XML
olarak okuma işlemi yapmak yerine elbetteki daha kolay bir yolumuz da olacaktõr! SiteMap
adõndaki nesne ile bu dosya içerisindeki belirli bilgileri kolay ve etkili şekilde
okuyabilmekteyiz. Özellikle o an bulunduğumuz sayfa ile ilgili bilgileri site haritasõ
dosyasõndan okuyabilmek bizim için önemli olacaktõr. SiteMap.CurrentNode özelliği o an
bulunulan sayfanõn siteMapNode düğümünün SiteMapNode sõnõfõ tipinden değerini
getirecektir. Bu özellik üzerinden erişebileceğimiz önemli bilgileri aşağõda listesini
gördüğünüz özelliklerden (property) elde edebiliriz.
Description: Bulunulan sayfanõn description kõsmõndaki bilgi
Title: Bulunulan sayfanõn title kõsmõndaki bilgi
Url: Bulunulan sayfanõn url kõsmõndaki bilgisi
Bulunulan sayfa node'unun altõnda alt node (child node) olup olmadõğõ
HasChildNodes:
bilgisi. bool değer getirir ve true alt node'larõn olduğunu belirtir
Eğer alt node'lara sahip ise bu node'larõn SiteMapNodeCollection tipinden
ChildNodes:
listesinin getirir
Bulunulan sayfa node'unun üst kõsmõnda yer alan sayfa node'unun
ParentNode:
SiteMapNode tipinden değerini getirir
NextSibling: Aynõ seviyede bir sonraki kõsõmda bulunulan sayfa node'unun

90
SiteMapNode tipinden değerini getirir
Aynõ seviyede bir önceki kõsõmda bulunulan sayfa node'unun
PreviousSibling:
SiteMapNode tipinden değerini getirir

SiteMap nesnesini kullanabilmek için sayfamõzda SiteMapDataSource veya diğer


site navigasyonu kontrollerinin bulunmasõ zorunlu değildir. Eğer o an görüntülenen
sayfa projemizdeki web.sitemap dosyasõnda bulunuyor ise SiteMap.CurrentNode
özelliği bize o sayfanõn SiteMapNode tipinden değerini otomatik olarak getirecektir.

Özellikle sitemap dosyasõndaki title ve description nitelikleri sayfamõzda sõklõkla


kullanabileceğimiz özellikler olabilir. Örneğin ADO.NET kategorisindeyken sayfamõzõn başlõk
bilgisini title kõsmõndan alõp ADO.NET olarak belirlemek ve sayfanõn belirli bir kõsmõndaki bir
etikete de description kõsmõndan alõnan bilgiyi yazdõrmak kulağa oldukça hoş gelen
kolaylõklar gibi geliyor. Aşağõda bu özelliklerin bazõlarõnõ kullanarak sayfamõzda değişiklikler
yapõyoruz.

Sablon.master

...
<br><asp:Label ID="lblSayfaBilgi" runat="server" ForeColor="Red"/>
<br><asp:HyperLink ID="hlOnceki" runat="server" ForeColor="Blue"/>
<asp:HyperLink ID="hlSonraki" runat="server" ForeColor="Blue"/>
...

Sablon.master.cs

protected void Page_Load(object sender, EventArgs e)


{
this.Title = SiteMap.CurrentNode.Title;

if(!String.IsNullOrEmpty(SiteMap.CurrentNode.Description))
lblSayfaBilgi.Text = "<br>Bu sayfada " + SiteMap.CurrentNode.Description + "
bulabilirsiniz.";

if(SiteMap.CurrentNode.PreviousSibling != null)
{
hlOnceki.Text = SiteMap.CurrentNode.PreviousSibling.Title + " <<";
hlOnceki.NavigateUrl = SiteMap.CurrentNode.PreviousSibling.Url;
}
if(SiteMap.CurrentNode.NextSibling != null)
{
hlSonraki.Text = ">> " + SiteMap.CurrentNode.NextSibling.Title;

91
hlSonraki.NavigateUrl = SiteMap.CurrentNode.NextSibling.Url;
}
}

SiteMap.CurrentNode özelliği kullanõlarak sayfa hakkõndaki bilgileri elde ettik

Site Haritasõna Ek Bilgiler Ekleme


Sitemap dosyasõnda saklanan standart sayfa bilgileri url, title ve description niteliklerinde
tutulmaktadõr. Bu niteliklerde sayfa ile ilgili istenilen en temel bilgiler saklamaktadõr. Fakat
bazõ durumlarda site haritasõ dosyasõnda bir sayfa ile ilgili farklõ bilgileri de saklamak
isteyebiliriz. Bu tip bilgileri elbetteki farklõ veri kaynaklarõndan (XML dosyasõ, veritabanõ gibi)
elde ederek kullanõcõlara sunabiliriz. Fakat bir sayfanõn bazõ bilgilerini sitemap dosyasõndan,
bazõ bilgilerini de farklõ bir kaynaktan elde etmek kötü bir pratik olacaktõr. Peki sayfa ile ilgili
saklamak istediğimiz bu tip bilgileri yine sitemap dosyasõ içerisinde saklamamõz mümkün
müdür? Sitemap dosyasõnõn yapõsõ buna uygun mudur ve saklanan bilgileri sayfa içerisinden
elde etmek için ekstra işlemler yapmak gerekir mi?

Sitemap dosyalarõ içerisinde ek bilgileri kolay şekilde taşõyabilmektedir. Böyle bir durumda
uygulama içerisinden bu bilgilere ulaşmak ise beklediğimizden daha kolay olacaktõr. Ek
bilgileri saklamak için daha önceden bir yerlerde (SiteMap sağlayõcõsõ gibi) tanõmlama
yapmaya gerek yoktur. Nasõl ki bir sayfanõn url bilgisini siteMapNode içerisinde
tanõmlayabiliyorsak, bu bilgileri de aynõ şekilde tanõmlayabiliriz. Sayfa içerisinden okuma
işlemini ise biraz farklõ bir yoldan ama oldukça basit bir şekilde gerçekleştirilebilir. Dilerseniz
daha önceki örneklerde kullandõğõmõz sitemap dosyamõz üzerinde bir örnek yaparak bu

92
işlemleri nasõl gerçekleştirebileceğimizi görelim. Sitemizdeki kategorilerin her birisinde
bulunacak editör bilgilerini sitemap dosyasõnda ilgili sayfanõn node'unda saklayõp, ziyaretçi bir
kategoriyi gezdiğinde ilgili kategorinin editörünü sayfada görüntüleyeceğiz. Öncelikli olarak
sitemap dosyasõndaki her bir kategori node'una Editor adõnda bir nitelik tanõmlõyor ve ilgili
editörlerin isimlerini belirtiyoruz. Aşağõda web.sitemap dosyamõzõn bir kõsmõnda yapõlan
değişiklikler görülmektedir.

Web.sitemap

...
<siteMapNode url="Makale.aspx" title="Makaleler">
<siteMapNode url="Aspnet.aspx" title="ASP.NET" description="ASP.NET konusunda
makaleler" Editor="Uğur UMUTLUOĞLU" />
<siteMapNode url="Adonet.aspx" title="ADO.NET" description="ADO.NET konusunda
makaleler" Editor="Burak BATUR" />
<siteMapNode url="Cs.aspx" title="C#" description="C# konusunda makaleler"
Editor="Emrah USLU" />
<siteMapNode url="SqlServer.aspx" title="SQL Server" description="SQL Server ile ilgili
makaleler" Editor="Bülent SÖZGE" />
</siteMapNode>
...

Her bir node içerisinde Editor="Uğur UMUTLUOĞLU" şeklinde nitelik tanõmlamalarõ


yapmak yeterli olacaktõr. Gelelim sayfa içerisinden bu bilgiyi nasõl elde edebileceğimize.
Makalemizin önceki kõsõmlarõnda bulunduğumuz sayfanõn varolan bilgilerini Sitemap
nesnesinin CurrentNode özelliği üzerinden okuyabildiğimizi görmüştük. Örneğin title bilgisini
SiteMap.CurrentNode.Title ifadesi ile elde edebilmiştik. Title ve diğer özellikler
SiteMapNode sõnõfõ içerisinde daha önceden tanõmlõ olduklarõ için sõnõfõn nesne örneği
üzerinden erişebiliriz. Fakat sonradan tanõmladõğõmõz Editor bilgisini özellik (property)
üzerinden değil de CurrentNode özelliğinin indeksleyicisi (indexer) üzerinden erişebiliriz.
Aşağõdaki tek satõrlõk ifade bu bilgiyi sayfamõza eklediğimiz lblEditor adõndaki bir etikete
aktarmamõzõ sağlayacaktõr.

Sablon.master.cs

protected void Page_Load(object sender, EventArgs e)


{
...
lblEditor.Text = "Bölüm Editörü: " + SiteMap.CurrentNode["Editor"];
...
}

Sayfayõ çalõştõrdõğõmõzda o an bulunduğumuz kategorinin siteMapNode düğümünden okunan


Editor bilgisinin elde edildiğini görebiliriz. SiteMap.CurrentNode özelliği o anki sayfanõn
siteMapNode düğümünün nesne örneğini getirmekte ve içerisinde taşõnan Editor bilgisini de

93
indeksleyici üzerinden SiteMap.CurrentNode["Editor"] şeklinde okuyabilmekteyiz. Bu
şekilde sitemap dosyasõnda farklõ nitelikler tanõmlayõp sayfa içerisinden kolay şekilde
okunmasõnõ sağlayabiliriz. Aşağõda sayfamõzõn çõktõsõ görülmektedir.

Resim: web.sitemap dosyasõndan okunan Editor bilgisi sayfada görülmektedir

Birden Fazla Sitemap Dosyasõ Kullanabilmek


ASP.NET uygulamalarõnda bazõ durumlarda birden fazla site haritasõ dosyasõ kullanmak
isteyebiliriz. Farklõ içerikleri olan linkleri ayrõ iki dosyada toplayarak sayfamõzõn farklõ
kõsõmlarõnda görüntülemek kullanõcõlarõn site içerisinde gezinmelerini kolaylaştõracaktõr. Fakat
site navigasyon kontrollerini SiteMapDataSource kontrolü ile beslediğimizde sadece bir tane
sitemap dosyasõ kullanabilmekteyiz. Bu durumun sebebi ise site haritasõ sağlayõcõlarõnda
(SiteMap Provider) sadece web.sitemap dosyasõ için bir tanõmlama yapõlmasõdõr. Web
uygulamalarõnda kullandõğõmõz web.config dosyalarõ bildiğimiz gibi .NET Framework'ün
kurulu olduğu dizinde bulunan bazõ konfigürasyon dosyalarõndan kalõtõm yoluyla elde edilerek
kullanõlõr. Yani bir sunucuda çalõşan tüm web uygulamalarõ bu dizindeki .config dosyalarõnda
yapõlan ayarlara göre çalõşmaktadõr. Windows XP işletim sistemi ile .NET Framework 2.0
kurulu olan bir bilgisayarda C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFIG
dizininde bulunan web.config dosyasõna bakõlacak olunursa <siteMap> düğümünde sadece
bir sağlayõcõ tanõmlamasõ olduğu görülür. Yine bu tanõmlamada göreceğimiz siteMapFile
niteliği aslõnda SiteMapDataSource kontrolünün verileri hangi dosyadan okuduğunun
göstergesidir. Aslõnda buradaki tanõmlamalardan yola çõkarak uygulamadaki web.config
dosyasõna birden fazla sağlayõcõ tanõmlamasõ yapõp farklõ isimdeki .sitemap dosyalarõnõn
projemizde kullanõlabilmesini sağlayabiliriz. Öncelikli olarak web.config dosyamõza
web2.sitemap isimli bir dosyayõ da kullanabilmemizi sağlayan tanõmlamayõ ekleyelim.
<system.web> düğümü içerisine açacağõmõz <siteMap> düğümüne ekleyeceğimiz kodlar
aşağõda görülmektedir.

web.config
<system.web>
...
<siteMap>
<providers>

94
<add name="SiteMapProvider2" siteMapFile="web2.sitemap"
type="System.Web.XmlSiteMapProvider, System.Web, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a"/>
</providers>
</siteMap>
</system.web>

Bu şekilde artõk uygulamamõzda web.sitemap dosyasõ dõşõnda web2.sitemap dosyasõnõ da


kullanabiliriz. Öncelikli olarak projemize web2.sitemap adõnda bir site haritasõ dosyasõ
ekleyelim. Ardõndan da sayfamõza bir Menu kontrolü ile bir SiteMapDataSource kontrolü
ekleyelim. SiteMapDataSource kontrolünün SiteMapProvider özelliği az önce web.config
dosyasõna eklediğimiz SiteMapProvider2 sağlayõcõsõ olarak belirlenirse Menu kontrolüne
web2.sitemap dosyasõndaki veriler aktarõlacaktõr. Aşağõda web2.sitemap ve Sablon.master
dosyalarõna eklenen kodlar görülmektedir.

web.sitemap

<?xml version="1.0" encoding="windows-1254" ?>


<siteMap>
<siteMapNode url="Default.aspx" title="Anasayfa">
<siteMapNode url="" title="Üyelik İşlemleri">
<siteMapNode url="SifreDegistir.aspx" title="Şifre Değiştir" description="" />
<siteMapNode url="Profil.aspx" title="Profil Bilgileri" description="" />
</siteMapNode>
<siteMapNode url="Haberler.aspx" title="Haberler" description="">
<siteMapNode url="YazilimHaberleri.aspx" title="Yazõlõm Dünyasõndan Haberler"
description="" />
<siteMapNode url="SeminerHaberleri.aspx" title="Seminer Haberleri" description="" />
<siteMapNode url="Duyurular.aspx" title="Duyurular" description="" />
</siteMapNode>
<siteMapNode url="KitapOneri.aspx" title="Kitap Önerileri" />
</siteMapNode>
</siteMap>

Sablon.master

...
<asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource2" Font-
Names="Verdana" Font-Size="12px"></asp:Menu>
<asp:SiteMapDataSource ID="SiteMapDataSource2" runat="server"
ShowStartingNode="False" SiteMapProvider="SiteMapProvider2" />
...

95
Sayfayõ çalõştõrdõğõmõzda daha önceden hazõrladõğõmõz TreeView kontrolünün
SiteMapDataSource1 kontrolü ile web.sitemap dosyasõndan, Menu kontrolünün ise
SiteMapDataSource2 kontrolü ile web2.sitemap dosyasõndan getirilen verilerle
doldurulduğunu görebiliriz. Aşağõda sayfamõzõn çõktõsõ bulunmaktadõr.

Resim: Birden fazla sitemap dosyasõndan alõnan veriler TreeView ve Menu


kontrollerine yüklendi

Bu makalemizde site navigasyon işlemlerinin bilinmeyen yönlerini incelemeye çalõştõk.


ASP.NET 2.0 ile birlikte gelen sitemap dosyalarõ ve site navigasyon kontrolleri birçok işlemin
kolay şekilde yapõlmasõnõ sağlamaktadõr. Bu yapõlarõ detaylõ şekilde bilmemiz durumunda
karşõmõza çõkabilecek farklõ senaryolarõ kolay şekilde çözebiliriz.

96
TreeView Kontrolüne Kullanõcõ İsteğine Göre Veri
Ekleme
04 Mart 2008

TreeView kontrolü ASP.NET uygulamalarõnda site gezinme işlemlerinde sõklõkla kullanõlan


kontrollerden biridir. Ağaç görünümünde linkler ve alt linkleri hiyerarşik biçimde listeleyen bu
kontrol açõlõr kapanõr bir yapõ sunduğu için özellikle karmaşõk ve çok sayõdaki içerikleri
listelerken oldukça kullanõşlõ olmaktadõr. TreeView kontrolünün içeriğini sitemap dosyasõndan
okuyabildiğimiz gibi veritabanõ vb. bir veri kaynağõndan da okuyabilmekteyiz. TreeView
kontrolünün farklõ veri kaynaklarõyla kullanõmõ ile ilgili bilgi edinmek için daha önceden yazmõş
olduğum makaleye bu linkten göz atabilirsiniz. Veritabanõndan getirilen bu veriler eğer çok
fazla ise tüm verileri bir defada getirmek performans açõsõndan olumsuz olabilir. Kullanõcõnõn
sadece görüntülemek istediği içerikleri yüklemek sayfanõn daha hõzlõ çalõşmasõnõ
sağlayacaktõr. Bu konuyla ilgili olarak oldukça somut bir örnek üzerinde durabiliriz. Eminim ki
hepimiz MSDN sitesini gezmişiz ve araştõrma yaparken sol kõsõmdaki menüyü kullanarak
birçok konuya göz atmõşõzdõr. Eğer dikkat ettiyseniz buradaki ağaç görünümlü kontrolün tüm
içeriği ilk başta yüklenmemektedir. Kullanõcõ bir linke tõkladõğõnda o konuya ait alt linkler bir
veri kaynağõndan dinamik şekilde getirilerek yüklenir. Zira oldukça geniş konu ve alt konuyu
saklayan bu menünün bir defada yüklenmesi sayfanõn ilk yüklenmesi esnasõnda oldukça
uzun sürecektir.

Çok sayõda içeriği bulunan veritabanlarõnda bu bilgileri TreeView kontrolüne yüklemek


istediğimizde verilerin isteğe göre yüklenmesi bizim için önemli olabilmektedir. Yazõmõzda bu
işlemi nasõl gerçekleştirebileceğimizi inceliyor olacağõz. TreeView kontrolüne başlangõçta
belirli verileri yüklemek ve bir linke tõklandõğõnda alt linklerini yükleme işlemi bu kontrolün
TreeNodePopulate olayõ (event) ile gerçekleşmektedir. TreeView kontrolü üzerinde
yapõlacak işlemleri ve gerekli ayarlarõ makalenin ilerleyen kõsõmlarõnda göreceğiz. Bir örnek
üzerinden konuyu incelemeye başlayalõm. Spor kulüpleri ile bilgileri sunan bir web portalõmõz
olduğunu düşünelim. Avrupa ve dünya liglerindeki futbol kulüplerini ve her futbol kulübünde
bulunan oyuncularõ bir TreeView kontrolünde listelemek istiyoruz. Ziyaretçinin seçtiği futbolcu
ile ilgili bilgileri ise sayfamõzda listeleyeceğiz. Veritabanõmõzda yaklaşõk 20 tane ligi
saklayacak olursak, her ligde ortalama 18 futbol takõmõnõ ve her futbol takõmõnda ortalama 25
futbolcu olduğunu da düşünürsek TreeView kontrolüne 3 ayrõ tablodan yaklaşõk 9000 satõrlõk
bilgiyi yüklememiz gerekecektir. Farklõ tablolardan bu kadar veriyi kontrole yüklemek elbetteki
uzun zaman alacaktõr ve tüm verilerin getirilmesi de böyle bir senaryoda gereksiz olacaktõr.
Bu işlem yerine sayfa ilk yüklendiğinde sadece liglerin listesini getirilecek olursak, bir lige
tõklandõğõnda o ligin futbol kulüplerini, bir kulübe tõklandõğõnda da o kulübün oyuncularõ listeye
eklenecektir. Böylece her tõklamada istenilen verilerin getirilmesi işlemini gerçekleştirmek
gerekecektir. Ziyaretçi sayfa ile etkileşime geçtiğinde veritabanõndan veriler getirileceği için
çalõşma esnasõnda biraz yavaş işleyiş olsa da sayfa ilk çalõştõğõnda daha hõzlõ yüklenecektir.
Microsoft Access'te oluşturacağõmõz bir veritabanõ üzerinden örneğimizi gerçekleştirelim. Bu
veritabanõnda Ligler, Kulupler ve Oyuncular adõnda verilerin saklandõğõ tablolarõmõz
olacaktõr. Aşağõdaki resimde bu tablolarõn bilgileri görülmektedir.

97
Resim: Spor.mdb isimli veritabanõ dosyamõzda bulunan tablolarõn yapõlarõ

Az öncede bahsettiğimiz gibi sayfa ilk yüklendiğinde TreeView'a sadece liglerin listesi
getirilecektir. Ne zaman ki kullanõcõ bir lige tõklarsa veritabanõndan sadece o ligin kulüpleri
getirilecektir. Kullanõcõ bir kulübe tõkladõğõnda da TreeView'õn node'larõna o kulübün
oyuncularõnõn listesi eklenecektir. Bu işlemi gerçekleştirmek için boş bir ASP.NET sayfasõna
bir TreeView kontrolü ve bir Label kontrolü ekleyelim. TreeView kontrolüne yüklenen bir lige
tõklandõğõnda o ligin kulüplerinin getirilmesi için sunucu tarafõnda bir metot çalõştõrõp lige ait
kulüpleri çekmemiz ve listeye eklememiz gerekecektir. Getirilen liglerden birine tõklanmasõ
durumunda TreeView kontrolünün TreeNodePopulate olayõ gerçekleşecektir. Bu olay
sunucu getirilen yeni verilerin o an tõklanan node'a eklenmesini sağlayacaktõr. Bu olayõn
tetiklenebilmesi için TreeView kontrolüne ait ExpandDepth özelliğinin (property) değerini "0"
olarak belirlememiz ve sadece en üstteki node'larõn yükleneceğini belirtmemiz
gerekmektedir. Aşağõda TreeView kontrolünde yapõlan değişiklikler ve sayfamõzõn kodlarõ
bulunmaktadõr.

Default.aspx

<form id="form1" runat="server">


<div>
<table border="0" cellpadding="4" style="width: 100%">
<tr>
<td width="250">
<asp:TreeView ID="tvLig" runat="server" ExpandDepth="0"
OnTreeNodePopulate="tvMenu_TreeNodePopulate" ImageSet="Simple">
<NodeStyle Font-Names="Tahoma" Font-Size="10pt" ForeColor="Black"
HorizontalPadding="0px" NodeSpacing="0px" VerticalPadding="0px" />
</asp:TreeView>
</td>
<td valign="top">

98
<asp:Label ID="lblOyuncuBilgiler" runat="server"></asp:Label>
</td>
</tr>
</table>
</div>
</form>

TreeView kontrolü ilk yüklendiğinde sadece en üst seviyedeki node'lar gelecektir. Sayfamõzõn
code-behind dosyasõnda yazacağõmõz kodlarla TreeView'a liglerin yüklenmesini sağlõyoruz.

Default.aspx.cs

public partial class _Default : System.Web.UI.Page


{
string yol;
protected void Page_Load(object sender, EventArgs e)
{
yol = Server.MapPath("~/App_Data") + "/Spor.mdb";
if(!IsPostBack)
LigleriYukle();
}

private void LigleriYukle()


{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OleDB.4.0; Data
Source=" + yol);
OleDbCommand cmd = new OleDbCommand("Select LigID, Ad From Ligler", con);
con.Open();

OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
TreeNode kategori = new TreeNode(dr["Ad"].ToString(), dr["LigID"].ToString());
kategori.PopulateOnDemand = true;
tvLig.Nodes.Add(kategori);
}
con.Close();
}

protected void tvMenu_TreeNodePopulate(object sender, TreeNodeEventArgs e)


{
// Bu metot az sonra doldurulacak
}
}

99
Bağlanõlan veritabanõnnda çalõştõrõlan sorgu sonucu sadece ligler getirildi ve tvLig adõndaki
TreeView kontrolüne veriler eklendi. Buradaki en önemli noktalardan bir tanesi de eklenen
TreeNode nesnelerine ait PopulateOnDemand ("isteğe göre besle" diyebiliriz) özelliğidir.
bool tipinden değer alan bu özelliği true belirlememiz durumunda eklenen ligler istek
geldikçe alt node'larõnõ getirecektir. Oluşturulan lig node'larõna text olarak Ad, value olarak
LigID değerlerini atayõp PopulateOnDemand özelliğine true değerini verdikten sonra tvLig
adõndaki TreeView kontrolüne ekledik. Sayfanõn sorunsuz şekilde çalõşmasõ için
TreeNodePopulate olayõnõ bağladõğõmõz tvMenu_TreeNodePopulate metodunu şimdilik içi
boş bir şekilde tanõmladõk. Sayfa çalõştõrõldõğõnda sadece liglerin TreeView'a eklendiğini
göreceğiz.

Resim: Sadece ligler TreeView kontrolüne eklendi

Bir sonraki adõmda kullanõcõ herhangi bir linke tõklayarak o ligin altõndaki kulüpleri listelemek
isteyecektir. Bu noktada TreeNodePopulate olayõ tetiklenecek ve code-behind sayfamõzda
yazdõğõmõz tvMenu_TreeNodePopulate metodu çağrõlacaktõr. Bu metodun parametrelerine
bakacak olursak ikinci parametrenin TreeNodeEventArgs tipinden e adõnda bir nesne
olduğunu görürüz. e nesnesine ait Node özelliği tõklanõlan node'un nesne örneğini
getirecektir. Örneğin Türkiye Süper Lig'e tõklanmasõ durumunda bu node'un nesne örneğine
TreeNode tipinden erişebiliriz. Lige ait kulüpleri veritabanõndan çekerek ChildNodes
koleksiyonuna eklememiz durumunda artõk kulüpler ligin alt node'larõ olarak eklenecektir. Bir
sonraki adõmda da bir kulübe tõklandõğõnda oyuncular listeleneceği için burada tõklanõlan
linkin lig mi olduğu yoksa kulüp mü olduğunun ayõrt edilmesi gerekecektir. Eğer bir lige
tõklanmõşsa Kulupler tablosundan, bir kulübe tõklanmõşsa da Oyuncular tablosundan veriler
getirilecektir. TreeNode nesnesine ait Depth özelliği elde edilen node'un hiyerarşik olarak
hangi derinlikte olduğunu belirtmektedir. Ligler TreeView'da 0. derinlikte, kulüpler ise 1.
derinliktedir. Bu durumu da göze alarak aşağõdaki şekilde sayfamõzõn kodlarõna eklemeler
yapõyoruz.

100
Default.aspx.cs

protected void tvMenu_TreeNodePopulate(object sender, TreeNodeEventArgs e)


{
if (e.Node.Depth == 0) // Lige tõklanmõş ise
KulupleriYukle(e.Node);

else if (e.Node.Depth == 1) // Kulübe tõklanmõş ise


OyunculariYukle(e.Node);
}

private void KulupleriYukle(TreeNode ligNode)


{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OleDB.4.0; Data
Source=" + yol);
OleDbCommand cmd = new OleDbCommand("Select KulupID, Ad From Kulupler Where
LigID=@id", con);
cmd.Parameters.AddWithValue("@id", ligNode.Value);
con.Open();

OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{
TreeNode kategori = new TreeNode(dr["Ad"].ToString(),
dr["KulupID"].ToString());
kategori.PopulateOnDemand = true;
kategori.SelectAction = TreeNodeSelectAction.Expand;
ligNode.ChildNodes.Add(kategori);
}
con.Close();
}

private void OyunculariYukle(TreeNode kulupNode)


{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OleDB.4.0; Data
Source=" + yol);
OleDbCommand cmd = new OleDbCommand("Select OyuncuID, Ad From Oyuncular
Where KulupID=@id", con);
cmd.Parameters.AddWithValue("@id", kulupNode.Value);
con.Open();

OleDbDataReader dr = cmd.ExecuteReader();
while (dr.Read())
{

101
string navigateUrl = "Default.aspx?OyuncuID=" + dr["OyuncuID"].ToString();
TreeNode kategori = new TreeNode(dr["Ad"].ToString(), "", "", navigateUrl, "");
kulupNode.ChildNodes.Add(kategori);
}
con.Close();
}

Görüldüğü gibi kulüplerin getirilmesi KulupleriYukle, oyuncularõn getirilmesi


OyunculariYukle adõndaki iki metot ile gerçekleştiriliyor. Her iki metoda da parametre olarak
tõklanõlan TreeNode nesnesi gönderiliyor. Value özelliğinden erişilen ID bilgisine göre alt
node'larõn kayõtlarõ getirilerek tõklanan TreeNode nesnesinin ChildNodes koleksiyonuna
ekleniyor. OyunculariYukle metodunda TreeNode nesnesinin PopulateOnDemand ve
SelectAction özelliklerine herhangi bir atama yapõlmadõğõnõ görülmektedir; çünkü
oyuncularõn altõnda herhangi bir alt node yer almayacağõ için beslenmesine gerek yoktur. Bu
metotla ilgili bir diğer farkta oyuncu ismine tõklandõğõnda sayfamõza QueryString ile
oyuncunun ID bilgisi taşõnacağõ için TreeNode nesnesinin farklõ şekilde
oluşturulmasõdõr. Sayfayõ çalõştõrdõğõmõzda aşağõdaki gibi bir sonuç alabiliriz.

Resim: Kullanõcõdan gelen isteklere göre TreeView içeriği dinamik şekilde dolduruldu

Tüm verilerin bir defada gelmediğini görebilmek için sayfa götürülendikten sonra Kaynağõ
Görüntüle seçeneğinden sayfanõn HTML kodlarõ kontrol edilebilir. Yine linklere tõklandõğõnda
TreeNodePopulate olayõnõn tetiklenmesini de tvMenu_TreeNodePopulate metoduna bir

102
breakpoint ekleyerek görebiliriz.

Resim: "İspanya La Liga" linkine tõklandõğõnda breakpoint eklediğimiz noktada seçilen


node'un bilgilerini görebiliriz

Breakpoint'i kaldõrarak sayfanõn çalõşma şeklini tekrar gözlemleyelim. Liglere ve kulüplere


tõklandõğõnda veritabanõndan verilerin getirilmesine rağmen sayfada herhangi bir postback
işlemi olmadõğõnõ göreceğiz. Aslõnda TreeView kontrolü varsayõlan davranõş şekline göre
TreeNodePopulate olayõ tetiklendiğinde callback tekniğini kullanarak sunucu ile asenkron
şekilde iletişime geçmektedir. Böylece getirilen veriler hem daha hõzlõ şekilde kontrole
eklenmektedir, hem de postback işlemi gerçekleşmediği için sayfa kaybolmadan yenilenir.
TreeView kontrolüne bu davranõşõ kazandõran PopulateNodesFromClient özelliğidir. bool
tipinden değer alan bu özelliğin varsayõlan değeri true'dur ve node'larõn istemci (client)
tarafõnda asenkron şekilde güncellenmesini sağlar. Bu özellik false değerine atanõr ve sayfa
tekrar çalõştõrõlõrsa liglere ve kulüplere tõklandõğõnda sayfada postback işleminin yapõldõğõ
görülecektir.

Son olarakta QueryString ile taşõnan bilgileri alarak lblOyuncuBilgiler etiketine yazdõrabiliriz.
Bu işlemi Page_Load metodu içerisinde gerçekleştiriyoruz. Aşağõda sayfaya eklenen kodlar
ve sayfanõn çõktõsõ yer almaktadõr.

Default.aspx.cs

protected void Page_Load(object sender, EventArgs e)


{
...
if (Request.QueryString["OyuncuID"] != null)
OyuncuBilgileriniGetir(Request.QueryString["OyuncuID"].ToString());
}

private void OyuncuBilgileriniGetir(string oyuncuID)


{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OleDB.4.0; Data
Source=" + yol);

103
OleDbCommand cmd = new OleDbCommand("Select Ad, DogumTarih, Mevki From
Oyuncular Where OyuncuID=@id", con);
cmd.Parameters.AddWithValue("@id", oyuncuID);
con.Open();

OleDbDataReader dr = cmd.ExecuteReader(CommandBehavior.SingleRow);
dr.Read();
lblOyuncuBilgiler.Text = "Ad-Soyad: " + dr["Ad"].ToString() +
"<br>Doğum Tarihi: " + dr["DogumTarih"].ToString() +
"<br>Oynadõğõ Mevki: " + dr["Mevki"].ToString();
con.Close();
}

Resim: Seçilen oyuncunun bilgileri getirildi

ASP.NET AJAX Kontrolleri ile TreeView Kontrolüne Dinamik Veri


Ekleme
TreeView kontrolüne veri eklenirken kullanõcõyõ bilgilendirmek için işlem yapõldõğõ esnada bir
metin görüntülemek istenilebilir. Bu tip bir işlemi ASP.NET AJAX kontrolleri ile kolay şekilde
gerçekleştirebiliriz. ScriptManager, UpdatePanel ve UpdateProgress kontrolü ile yapõlacak
bu işlemde dikkat etmemiz gereken nokta TreeView kontrolünün
PopulateNodesFromClient özelliğidir. Bu özelliğin true olmasõ durumunda TreeView
callback yöntemiyle sunucuyla iletişime geçecek ve kullandõğõmõz AJAX kontrolleri etkin
olmayacaktõr. Bundan dolayõ da UpdateProgress kontrolü ile kullanõcõyõ haberdar edemeyiz.
Eğer TreeView kontrolü UpdatePanel içerisinde atõlõrsa ve PopulateNodesFromClient
özelliğine de false değeri atanõrsa, kontrol normal bir postback işlemi yapmak isteyecek fakat
UpdatePanel'e bağlõ çalõştõğõ içinde kõsmi postback (partial postback) işlemi gerçekleşecektir.

104
Böylece sayfa yukarõda anlattõğõmõz şekilde çalõşacaktõr. Visual Studio 2005'te yeni açtõğõmõz
bir ASP.NET AJAX-Enabled Web Site projesine (veya Visual Studio 2008'de .NET
Framework 3.5 ile açõlan normal bir ASP.NET projesine) önceki projedeki kodlarõmõzõ aynen
taşõyalõm. Yapacağõmõz tek değişiklik Default.aspx sayfasõnda TreeView kontrolünü bir
UpdatePanel içerisine bõrakmak olacaktõr. Tabii ki TreeView kontrolünün
PopulateNodesFromClient özelliğini false yapmamõz da gerekecektir. Aşağõda
oluşturduğumuz AJAX sayfasõndaki kodlar ve sayfanõn çõktõsõ yer almaktadõr.

Default.aspx
...
<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:TreeView ID="tvLig" runat="server"
OnTreeNodePopulate="tvMenu_TreeNodePopulate" ImageSet="Simple" ExpandDepth="0"
PopulateNodesFromClient="False">
<NodeStyle Font-Names="Tahoma" Font-Size="10pt" ForeColor="Black"
HorizontalPadding="0px" NodeSpacing="0px" VerticalPadding="0px" />
</asp:TreeView>
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="0">
<ProgressTemplate>
Veriler yükleniyor. Bekleyiniz...
</ProgressTemplate>
</asp:UpdateProgress>
...

105
Resim: Dinamik yükleme işleminin UpdatePanel ve UpdateProgress ile
gerçekleştirilmesi

TreeView kontrolüne dinamik veri ekleme işlemini ASP.NET AJAX kontrolleri ile
gerçekleştirmeyi de görmüş olduk. Bu makalemizde TreeView kontrolüne kullanõcõdan gelen
isteklere göre dinamik şekilde veri ekleme işlemini inceledik. Özellikle çok sayõda node'lardan
oluşan yapõlarda TreeView kontrolünün içeriğini dinamik şekilde oluşturmak uygulamanõn
performansõ açõsõndan oldukça önemli olabilmektedir.

106
ASP.NET AJAX

Anahtar kelimeler

AJAX Mimarisi ASP.NET AJAX Mimarisi Atlas JavaScript

ScriptManager ScriptManagerProxy Timer UpdatePanel


UpdateProgress XMLHTTPRequest

107
ASP.NET ATLAS
29 Mart 2006

Not: Bu makale Microsoft’un ASP.NET AJAX’õ duyurmasõndan önce yayõnlanmõştõr.


ASP.NET ATLAS, ASP.NET AJAX’õn release olmadan önceki adõdõr ve bu makalede
bahsedilen konularõn hemen hemen tamamõ ürünün tam sürümü için de geçerlidir.

Tarayõcõlarõn son yõllarda çõkardõklarõ yeni sürümleriyle birlikte yeni bir tanõmlama ile
karşõlaşmõş olduk: XMLHTTPRequest. Bu nesne sayesinde tarayõcõ ile sunucu asenkron (eş
zamanlõ olmayan) şekilde iletişime geçebiliyor ve XML tabanlõ bilgileri alma, gönderme gibi
işlemler yapõlabiliyordu. AJAX (Asynchornous JavaScript and XML) adõ verilen bu teknoloji
sayesinde, JavaScript dili aracõlõğõ ile bir sayfayõ tamamen sunucuya göndermeden
(postback atmadan) ya da yeni bir URL çağõrmadan sadece sayfamõzõn gerekli olan
kõsmõnda değişiklikler yapabiliyorduk. Son zamanlarda www.start.com, www.virtualearth.com
ve Google Suggest gibi birçok sitede bu teknolojinin örneklerini sõkça görüyoruz. Bu sitelerde
ortak olan nokta, sayfalarõn çoğunun server tarafõna tamamen gönderilmeden, sadece
güncellenecek olan kõsmõnõn server tarafõndan gelen bilgi ile yenilenmesidir. Bu teknolojiyi
ASP .NET ile geliştirdiğimiz sayfalara kolay şekilde entegre edebileceğimiz bir teknoloji var
mõ diye sorarsanõz, cevabõ; artõk evet:)

Microsoft’un Visual Studio 2005 ve ASP .NET 2.0 ile gelen yeni vizyonunda artõk yazõlõm
geliştirme kõsmõnda programcõnõn yükünün olabildiğince azaltõlmasõ, hazõrlanan projenin
daha etkili ve daha hõzlõ şekilde geliştirilmesi amaçlanõyordu. İşte bu doğrultuda ASP .NET
ekibi, ASP .NET 2.0’õn resmi olarak duyurulmasõnõn hemen ardõndan ATLAS’õn beta
sürümünü de duyurdu. ATLAS adõ verilen bu eklenti, ASP .NET 2.0 Web Uygulamalarõnda
AJAX teknolojisini çok kolay bir şekilde ve neredeyse hiç kod yazmaksõzõn kullanõlabilir hale
getirdi. Web 2.0 sürümünün dillerden düşmediği son zamanlarda web dünyasõna yeni bir
heyecan ve soluk getiren AJAX teknolojisi, ASP .NET - ATLAS sayesinde artõk çok kolay
şekilde uygulamalara eklenebilir oldu.

AJAX web uygulama geliştiriciler için çok önemli ve heyecan verici bir gelişme olmasõna
rağmen getirdiği bazõ sõnõrlamalarõ ve zorluklarõ da vardõ. Tarayõcõ tipine göre farklõ DOM
objeleri tanõmlamak, uygulamayõ geliştirebilmek için ileri sayõlabilecek düzeyde JavaScript
kodu yazmak gibi... ATLAS bu kõsõtlamalarõ ve zorluklarõ ortadan kaldõrdõğõ gibi, aynõ
zamanda nesne tabanlõ bir ortam olan .NET Framework'ün nimetlerinden de faydalanmamõzõ
sağladõ.

ATLAS'õn genel yapõsõna bakacak olursak; ATLAS kullanõcõ tarafõndaki Framework ve


Servisler ile sunucu tarafõnda yer alan Framework olmak üzere iki kõsõmdan oluşuyor.
(ATLAS'õn genel mimarisini sşağõdaki resimden görebilirsiniz) Bu yapõ sayesinde Atlas .js
dosyalarõndan oluşan Sunucu Script Kütüphaneleri ve Uygulama Servisleri kullanõcõ tarafõnda
çalõşarak kontrollerdeki ve bileşenlerdeki verileri sunucu tarafõna gönderebiliyor ve aynõ
zamanda server-controller aracõlõğõ sunucu tarafõnda çalõşan ASP .NET sayfalarõyla ve web
servisleri ile haberleşebiliyor. Uygulamayõ geliştiriciler olarak ise bizler ASP .NET'e eklenen

108
ATLAS kontrolleri sayesinde AJAX'ta yapabildiğimiz birçok şeyi kod yazmadan yapabiliyoruz.
Bu sayede artõk web uygulamalarõ daha etkileşimli ve daha zengin hale getirilebiliyor, sayfa
tamamen sunucuya gönderilmeyip, tekrar tamamen geri alõnmadõğõ için de sayfalarõmõz artõk
çok daha hõzlõ çalõşabilir hale geliyor.

Resim: ATLAS'õn Genel Mimari Yapõsõ

Makalenin son kõsmõnda ASP .NET - ATLAS'a nasõl ulaşabileceğimizi ve nasõl kurup
kullanabileceğimizi anlatmaya çalõşacağõm. Daha önceden de bahsettiğim gibi ATLAS şu an
hala geliştirme aşamasõnda olan ve tam sürüm olarak henüz piyasaya sürülmemiş olan bir
ürün. Ürünü geliştiren ekip genellikle her ay içerisinde yenilenmiş sürümünü ATLAS'õn resmi
sitesi olan http://atlas.asp.net adresinden ücretsiz olarak download edilebilir halde
duyuruyorlar. Yine bu adresten bu ürün ile ilgili bir çok demo videoya ve yazõlõ kaynağa
ulaşabilirsiniz. Download bölümünden ATLAS Setup linkinden ASP.NET “Atlas” March
Community Technology Preview (CTP) dosyasõnõ ücretsiz olarak indirip bilgisayarõnõza
kurabilirsiniz. Visual Basic .NET ve C# .NET dilleri ile uygulama geliştirmenizi sağlayan bu
kurulumu tamamladõktan sonra, Visual Studio 2005'te yeni bir Web Site Projesi açacak
olursanõz, önceki ekranlardan farklõ olarak My Templates'in altõnda Atlas Web Site adõnda
bir template olduğunu göreceksiniz. Bu seçeneği seçerek yeni bir ATLAS uygulamasõ
açabilir, kontroller ve uygulama üzerinde ekli olarak gelen dosyalar sayesinde sayfalarõnõzda
ATLAS'õ kullanabilirsiniz.

109
Resim: Atlas Web Site Template'in seçilmesi

ATLAS önümüzdeki günlerde adõndan daha çok bahsedilecek, üzerinde durulmasõ gereken
ve önümüzdeki yõllarda uygulamalarõmõzda sõk sõk kullanacağõmõz çok yeni bir teknoloji.
Umarõm bu yeni teknolojiyi genel olarak sizlere iyi ve anlaşõlõr bir şekilde aktarabilmişimdir.

ATLAS'õn en son çõkan sürümünde (şu an için Mart ayõnda çõkan sürümü) birkaç yeni kontrol
daha eklendi. Bu yazõda ATLAS kontrollerinden en çok kullanõlanlarõ olan ScriptManager,
UpdatePanel, UpdateProgress ve TimerControl kontrollerine göz atacağõz.

ScriptManager
Sayfalarõmõzda ATLAS'õ kullanmamõzõ sağlayan ve her sayfaya mutlaka eklenmesi gereken
kontroldür. Sayfamõzdaki ATLAS kontrollerinin doğru olarak çalõştõrõlabilmesi için bu
kontrolümüzü sayfamõzõn en üst kõsmõna eklemiş olmamõz gerekmektedir.

<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="True"


>

Kullanõmõna bakacak olursak; buradaki en önemli özellik EnablePartialRendering özelliğidir.


Bu özellik sayesinde sayfamõzda oluşturacağõmõz kõsõmlar, tüm sayfa tekrar yüklenmeksizin
parça halinde yüklenecektir. "Partial Page Rendering" (Türkçe olarak parçalõ sayfa
düzenlemesi diyebiliriz) modelini sayfamõzda çalõşõr hale getirebilmemiz için bu özelliğin True
olarak ayarlanmasõ gerekiyor, aksi durumda sayfamõz ATLAS'õn nimetlerinden
faydalanamayacaktõr. Yine <atlas:ScriptManager> kontrolü sayesinde sayfamõzõ bir web
servisine bağlayabilir ve uygulamalarda sayfamõzõ bu web servisi ile konuşturabiliriz.

<atlas:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="True"


>
<Services>
<atlas:ServiceReference path="MyWebService.asmx" type="text/javascript" />

110
</Services>
</atlas:ScriptManager>

UpdatePanel
Sadece kendi içerisindeki alanõn güncellenmesini sağlar. İçerisine eklenmiş olan HTML
kodlarõ ve ASP .NET kontrolleri dahil olmak üzere herşeyi, bir olay tetiklendiği anda ya da bir
değişiklik olduğu anda tekrar güncellemektedir. UpdatePanel içerisinden güncellenen bir
sayfa tamamen sunucu tarafõna gönderilmez (post-back olmaz) ve bu olay esnasõnda
UpdatePanel'in dõşõndaki hiçbir alan güncellenmez.

.... Güncellenmeyecek içerikler .....

<atlas:UpdatePanel ID="UpdatePanel1" runat="server">


<ContentTemplate>
<asp:Label ID="lblZaman" runat="server"></asp:Label>
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger ControlID="Button2" EventName="Click" />
</Triggers>
</atlas:UpdatePanel>

.... Güncellenmeyecek içerikler .....

UpdatePanel alt elementi olan <ContentTemplate> ile birlikte kullanõlmaktadõr.


UpdatePanel'de güncellenecek olan kõsõm sadece <ContentTemplate> içerisinde
tutulmaktadõr. Yani değiştirilecek bilgilerimizin, kodlarõmõzõn ve kontrollerimizin tamamen bu
elementin içerisinde tutulmasõ gerekmektedir. <Triggers> ise, UpdatePanel'in dõşarõsõnda
bulunan bir kontrolün değerinin değişmesi ya da kontrolde bir olayõn gerçekleşmesi
durumunda UpdatePanel'in güncellenmesini sağlar. Yukarõdaki kodlara bakacak olursak,
UpdatePanel dõşõnda bulunan Button2 adlõ bir butonun Click olayõ UpdatePanel'e trigger
olarak eklenmiş. Yani Button2'ye tõkladõğõmõzda UpdatePanel güncellenebilecek. Eğer
Button2'nin Click olayõnõ UpdatePanel'e eklemezsek, bu butona tõkladõğõmõzda tüm sayfa
yeniden yüklenecektir. (Button2'yi <ContentTemplate> 'in içerisine koymuş olsaydõk, trigger
eklememize gerek kalmayacaktõ ) Örnek bir uygulama yapacak olursak;

- New Web Site menüsünden yeni bir "ATLAS" Web Site projesi açalõm. Uygulamaya
başlamadan önce Solution Explorer'dan uygulama dosyalarõna bakacak olursanõz bin
dizininin altõnda uygulamamõzda ATLAS'õ kullanmamõzõ sağlayan Microsoft.Web.Atlas.dll
adlõ dosyanõn bulunduğunu görebileceksiniz. Yine web.config dosyasõnda ATLAS'õ bu
projedeki tüm sayfalarõmõzda kolayca kullanmamõzõ sağlayan gerekli ayarlamalarõn yapõlmõş
olduğunu görebilirsiniz.

- Uygulamaya geçecek olursak, Default.aspx dosyasõnõn en üst kõsmõna öncelikle bir

111
<atlas:ScriptManager> kontrolü ekleyelim ve bu kontrolün EnablePartialRendering
özelliğini True yapalõm.

- Daha sonra sayfamõza bir <atlas:UpdatePanel> kontrolü ekleyelim. <ContentTemplate>


in içerisine lblZaman adõnda bir label ve Button1 adõnda bir buton ekleyelim.

- Sayfamõzõn Page_Load olayõna lblZaman.Text = "Zaman: " + Date.Now() yazalõm.

- UpdatePanel'imizin içerisindeki butonun Click olayõna yine aynõ kodu yazalõm:


lblZaman.Text = "Zaman: " + Date.Now()

- UpdatePanel'in dõşõna Button2 adõnda bir buton daha ekleyelim. Bu butonun Click olayõnõ
UpdatePanel'in içerisindeki <Triggers> alt elementine ControlEventTrigger olarak ekleyelim.
(Aşağõdaki örnekteki gibi)

<atlas:UpdatePanel ID="UpdatePanel1" runat="server">


<ContentTemplate>
<asp:Label ID="lblZaman" runat="server"></asp:Label><br />
<asp:Button ID="Button1" runat="server" Text="Zamanõ Güncelle" />
</ContentTemplate>
<Triggers>
<atlas:ControlEventTrigger ControlID="Button2" EventName="Click" />
</Triggers>
</atlas:UpdatePanel>

- Uygulamamõzõ çalõştõrdõğõmõzda butonlarõmõza tõkladõğõmõzda tarayõcõmõzõn hareketlerine


dikkat edecek olursak, progress barda (tarayõcõnõn sağ alt köşesinde) sayfanõn yüklendiğini
gösteren mavi şeritin hiç çõkmadõğõnõ ve sayfamõzda değişen zaman bilgisi dõşõnda hiçbir
hareketlilik veya değişiklik olmadõğõnõ göreceğiz.

Basit bir örnek ile UpdatePanel'i anladõğõmõzõ umuyorum. UpdatePanel'in içerisine farklõ
kontroller (Calendar, Gridview, vb.) ekleyerek sayfanõn çalõşmasõnõ tekrar
gözlemleyebilirsiniz.

UpdateProgress
Bu kontrol ise UpdatePanel'de güncelleme işlemi yapõldõğõnda ziyaretçiye güncelleme
işleminin yapõldõğõnõ gösteren kontroldür. Örneğin bir güncelleme işlemi yapõldõğõnda
"Yükleniyor" "Güncelleniyor" şeklinde bir yazõnõn ya da benzer bir resim dosyasõnõn
görünmesini istiyorsanõz bu kontrol sayesinde bu işlemi yapabilirsiniz.

112
<atlas:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img src="images/indicator.gif" /><br />
Bilgiler güncelleniyor.....<br />
</ProgressTemplate>
</atlas:UpdateProgress>

Örnek koda bakacak olursak, UpdateProgress kontrolünün alt elementi olan


ProgressTemplate'in içerisine yazmõş olduğumuz kodlar ziyaretçiye güncelleme yapõldõğõ
bilgisini vermeye yöneliktir. Sayfa ilk yüklendiğinde ya da yükleme işlemleri bittiğinde bu
kõsõm görünmez (display:none) Bu kõsõm sadece UpdatePanel'de bir güncelleme olayõ
olduğunda, güncelleme işlemi bitene kadar sayfamõzda görüntülenir.

TimerControl
TimerControl adõndan ve konumuzun gidişatõndan da tahmin edebileceğimiz üzere,
sayfamõzõn post-back atmaksõzõn, belirli aralõklarla UpdatePanel kontrolündeki bilgilerin
güncellenmesini sağlayan kontroldür. Belirttiğimiz zaman aralõklarõnda sayfamõzdaki
UpdatePanel'in içerisindeki bilgileri güncellenmesini sağlar.

<atlas:TimerControl runat="server" Interval="5000" ID="TimeControl1">

<Triggers>
<atlas:ControlEventTrigger ControlID="Button2" EventName="Click" />
<atlas:ControlEventTrigger ControlID="TimerControl1" EventName="Tick" />
</Triggers>

Yukarõdaki kodlardan ilkine bakacak olursak, burada sayfamõza bir ATLAS TimerControl
kontrolü eklemiş bulunuyoruz. Interval değeri ile Timer'õmõzõn ne kadar sürede bir
tetikleneceğini belirtiyoruz. Interval="5000" tanõmlamasõndaki 5000 aslõnda 5 saniyeye eşit.
Yani her saniye için değerimizi 1000 değer arttõrmamõz gerekecek. Bu sayede
UpdateControl'ümüzü timer aracalõğõ ile tetikleyebiliyoruz. Yalnõz az önce de bahsetmiş
olduğum gibi, UpdateControl'ün dõşarõdaki bir değişiklikle güncellenmesi için UpdatePanel
kontrolümüze trigger eklememiz gerekiyordu. Burada da Timer kontrolümüz için
UpdatePanel'imizin <Triggers> elementine gerekli kodlarõ eklememiz gerekecek. (Alt

113
kõsõmdaki kodlardan görebilirsiniz.) Buradaki EventName değerine dikkat edecek olursak
Tick değerini görüyoruz. Tick TimerControl1 kontrolümüzün bir eventi. Buradaki örnekte
Timer kontrolümüzün her 5 saniyede bir Tick eventi çalõşacak ve UpdatePanel'imizdeki
değerler tüm sayfa post-back olmadan, ya da biz buton vb. bir kontrole müdahale etmeden
güncellenecektir.

114
AJAX: Asenkron JavaScript ve XML
18 Ocak 2007

Son zamanlarda özellikle web programcõlõğõ ile ilgilenenlerin sõklõkla duyduğu bir terim AJAX.
Microsoft’un tam sürümünü çõkarmaya hazõrlandõğõ ve yeni nesil web sayfalarõnda sõklõkla
kullanacağõmõz ASP .NET AJAX’a geçiş yapmadan önce AJAX adõ verilen uygulama
geliştirme yaklaşõmõnõ ele almamõz, temellerini öğrenmemiz iyi olacaktõr. Peki nedir AJAX?
Bizlere nasõl bir teknoloji ve ne gibi yenilikler sunuyor?

AJAX aslõnda yeni bir programlama dili ya da programlama aracõ değildir. Daha önceden de
var olan bazõ teknolojileri kullanarak bize nasõl uygulama geliştireceğimizi gösteren yeni bir
programlama modelidir. AJAX yani Asenkron JAvascript ve XML, temel olarak JavaScript
dilindeki XMLHTTPRequest nesnesini kullanarak web sayfalarõ üzerinde asenkron bir şekilde
veri iletişimini sağlayan programlama modelidir. Yani bir web sayfasõ yüklendikten sonra,
aynõ sayfa üzerinde iken arka tarafta sunucu ile iletişime geçmeyi ve veri transferi
yapmamõza olanak sağlar. Dilerseniz bu kõsmõ biraz daha açmak için klasik modelde
programlanan bir web sayfasõnõn ve AJAX modelinde programlanan bir web sayfasõnõn nasõl
çalõştõğõnõ inceleyelim.

Klasik Çalõşma Modeli


Klasik model kullanõlan bir web sayfasõnda, istemci web tarayõcõsõndan aldõğõ isteği sunucuya
gönderir(1) ve sunucu bu isteğe göre oluşturduğu içeriği tarayõcõya gönderir(2). Böylece web
sayfasõ istemci tarafõndan görüntülenir. İstemci aynõ sayfa üzerinde yeni bir istekte
bulunduğunda ise istek sunucuya tekrar gönderilir(3) ve üretilen içerik tamamen yenilenmiş
bir sayfa olarak tarayõcõya gönderilir(4). Bu aslõnda bugüne kadar gördüğümüz, alõşõlagelmiş
çalõşma modelidir. Bir sayfa üzerinden başka bir sayfaya veya içeriğe istekte bulunur ve
PostBack işlemi ile sayfa tamamen yenilenir. (Aşağõdaki şekilde klasik çalõşma modeli
anlatõlmõştõr.)

AJAX Çalõşma Modeli


AJAX mimarisini kullanan bir web sayfasõnda ise ilk işlemler klasik çalõşma modeldeki gibi
olur. Yani istemci isteğini sunucuya gönderir(1) ve oluşturulan içerik alõnarak tarayõcõ

115
üzerinde görüntülenir(2). AJAX’õn getirdiği yenilik işin bundan sonraki kõsõmlarõnda karşõmõza
çõkacaktõr. Yüklenen web sayfasõ üzerinde yeni bir istekte bulunacağõmõz zaman, istemci
tarafõnda çalõşacak olan bir Javascript kodu, arka planda asenkron bir şekilde sunucuya
istekte bulunur(3). Sunucudan alõnan bilgi yine asenkron bir şekilde getirilir ve gelen yeni
içerik ile birlikte sayfamõzda ilgili kõsõmlar güncellenir(4). Bu sayede yeni bir istek durumunda
web sayfamõz sadece güncelleyeceğimiz verileri alacaktõr. Sayfa tamamen PostBack işlemi
tabi tutulmayacaktõr, kõsmi bir PostBack işlemi gerçekleşecektir ve sayfanõn tamamen
yenilenmesine gerek kalmayacaktõr. Bu işlem süresinde sayfa tamamen PostBack
edilmeyeceği için farklõ bir sayfa beklemesi olmayacak ve aynõ sayfa üzerinde kalõnacaktõr.
(Aşağõdaki şekilde AJAX çalõşma modeli anlatõlmõştõr.)

İki çalõşma modelini ele alõrsak AJAX bizlere klasik çalõşma modeline göre daha hõzlõ ve
verimli bir çalõşma ortamõ sunmaktadõr. İstemciye sadece sayfanõn güncelleyeceğimiz kõsmõnõ
getirildiğimiz için daha küçük veri parçalarõnõn transfer edilmesiyle sunucu ve istemci
arasõndaki trafik azalmakta ve sayfalar daha hõzlõ bir şekilde yenilenmektir. Yine sayfamõzõ
ziyaret eden kullanõcõlar aynõ sayfa üzerinde kalacaklarõ için site ile etkileşimleri artacaktõr. Bu
sayede artõk web uygulamalarõ masaüstü uygulamalarõn sağladõğõ hõza ve zenginliğe giderek
yaklaşmaktadõr.

Dünü, bugünü, yarõnõ…


AJAX’a bu kadar övgünün yeterli olduğunu düşünüyorum. AJAX’õn tarihçesine bakacak
olursak aslõnda birçoğumuzun sandõğõ gibi AJAX’õn son 1-2 yõl içinde çõkan bir model
olmadõğõnõ görüyoruz. AJAX’õ uygulamamõzõ sağlayan XMLHTTPRequest nesnesi ilk olarak
Microsoft tarafõndan Internet Explorer 5.0’õn yapõsõna eklenmişti. Birçoğumuzun kullanmõş
olduğu Outlook Web Access aracõ AJAX’õ kullanan ilk örneklerden biriydi. Ancak ilk
zamanlarda XMLHTTPRequest nesnesinin sadece Internet Explorer’da bulunmasõ ve diğer
tarayõcõlarõn bu nesneyi yapõsõnda bulundurmamasõ nedeniyle AJAX neredeyse hiç
kullanõlmamõştõ. Son zamanlarda ise popüler tüm tarayõcõlar artõk yapõlarõnda bu nesneyi
bulundurmaya başladõlar. AJAX’a asõl popülaritesini kazandõran ise Google’õn son birkaç
yõlda hazõrladõğõ uygulamalar oldu. Google Suggest, Google Earth, Gmail gibi uygulamalar
kullanõcõlarõ ve geliştiricilere yepyeni bir web dünyasõnõn haberlerini vermiş oldu. Yine
PageFlakes, Microsoft’un Start.com ve VirtualEarth uygulamalarõ son yõllarda AJAX’õ
kullanan ve çok ses getiren sitelerden sadece birkaçõ. Şu an kullanõlan popüler tarayõcõlarõn
neredeyse tamamõ (Internet Explorer 5.0+, Firefox 1.0+, Opera 8+, Safari 1.2 ve Netscape 7

116
sürümleri) XMLHTTPRequest nesnesini bulundurduğu için uygulama geliştiriciler olarak
bizlerin bu modeli kullanmasõnda da herhangi bir sakõncasõ kalmamõştõr. Şu anda giderek
yaygõnlaşmakta olan AJAX uygulamalarõ şüphesiz ki giderek artarak gelecekte karşõmõza çok
daha sõk çõkacaktõr. Gelişen teknolojilerle paralel olarak internet hõzlarõnõn artõşõnõ da göze
alõrsak, gelecekte web uygulamalarõnõn neredeyse masaüstü uygulamalar kadar hõzlõ ve
verimli çalõşabileceğini düşünebiliriz.

Nasõl Çalõşõr?
Peki, AJAX mimarisi nasõl çalõşõyor ve bir web sayfasõnõn asenkron bir şekilde sunucuyla
iletişime geçmesini nasõl sağlõyor? Yazõmõzõn başõnda da bahsettiğim gibi AJAX mimarisi
temel olarak XMLHTTPRequest nesnesini kullanõr. XMLHTTPRequest web tarayõcõsõ
üzerinde bulunan bir bileşendir. JavaScript dilindeki XMLHTTPRequest nesnesi aracõlõğõ ile
bu bileşeni kullanabilmekteyiz. Bu nesne sayfa yüklendikten sonra istemci ve sunucunun
asenkron şekilde haberleşmesini sağlar. İstemci tarafõndaki web tarayõcõsõ, sunucudan
asenkron şekilde veri isteğinde bulunur.(Request) Sunucu tarafõnda ise alõnan isteğe göre bir
çõktõ üretilir ve veriler yine asenkron şekilde istemcinin web tarayõcõsõna gönderilir.(Response)
Alõnan veriler DOM(Document Object Model) ve Javascript sayesinde dinamik bir şekilde
sayfaya yüklenmesi sağlanõr. Bu esnada sayfada kõsmi PostBack işlemi olmakta ve yapõlan
işlemler sayfanõn arka tarafõnda yapõlmaktadõr. İşlem süresince tarayõcõdaki sayfa aynen
kalmakta ve sadece güncellenen alanlarda değişiklikler olmaktadõr.

XMLHTTPRequest Nesnesini İnceleyelim


XMLHTTPRequest nesnesi JavaScript’in içerisinde bulunan bir yapõdõr. Bu nesne içerisindeki
metotlar, eventhandler ve özellikler sayesinde bir web sayfasõnõn yüklendikten sonra
asenkron şekilde sunucu ile haberleşmesini sağlamaktadõr. Bu işlemi yaparken kullandõğõ 2
temel metot vardõr. Bunlar open ve send metotlarõdõr. Yine asenkron haberleşmenin hangi
safhada olduğunu, sunucudan bize bir bilgi dönüp dönmediğini kontrol edebilmemizi
sağlayan bir olay ve bir özellik bulunmaktadõr. Bunlar da onreadystatechange eventhandler’õ
ve readystate özelliği. Gelin isterseniz XMLHTTPRequest nesnesinin üyelerinin kullanõmõnõ
ve AJAX modelini bir web sayfasõna nasõl uygulayabileceğimizi daha iyi anlamak için ilk
AJAX örneğimizi hazõrlayalõm. Öncelikle sayfamõzõn HTML içeriğini hazõrlayalõm. HTML

117
sayfamõzda <body> içerisine bir tane span elementi ve tipi buton olan bir input elementi
ekleyelim.

<span id="lblGuncelle"></span>
<input type="button" value="Güncelle" onclick="AsenkronCagriYap()" />

Buradaki buton yapacağõmõz asenkron çağrõyõ tetikleyecek olan elementimizdir. Bu butona


tõkladõğõmõzda az sonra yazacağõmõz ve adõ AsenkronCagriYap() olan JavaScript
fonksiyonumuzu çağõrõp, çağrõ sonucunda dönecek olan bilgileride yine JavaScript
içerisinden dinamik bir şekilde id bilgisi lblGuncelle olan span elementimizin içerisine
yazdõracağõz. JavaScript’teki fonksiyonlarõmõzõ yazmadan önce isterseniz bu bölümün
başõnda anlattõğõmõz XMLHTTPRequest nesnesini nasõl oluşturacağõmõzõ ve bu nesnenin
yapõsõnda bulunan üyelerini inceleyelim.

Yeni bir XMLHTTPRequest nesnesi oluşturmak için bilmemiz gereken 3 farklõ isimlendirme
vardõr. Tarayõcõnõn içerisinde bulunan bileşene göre ActiveXObject(“Msxml2.XMLHTTP”),
ActiveXObject(“Microsoft.XMLHTTP”) ve XMLHTTPRequest() ile nesne oluşturabiliriz.

IE 6.0+ tarayõcõlar için aşağõdaki tanõmlama yapõlõr.


var nesne = new ActiveXObject("Msxml2.XMLHTTP");

IE 5.5 sürümleri için ise aşağõdaki tanõmlama yapõlõr.


var nesne = new ActiveXObject("Microsoft.XMLHTTP");

Mozilla, Opera, Safari gibi tarayõcõlar için ise aşağõdaki tanõmlama yapõlõr.
var nesne = new XMLHTTPRequest();

Buradan şöyle bir sonuç çõkõyor. İstemci tarafõnda farklõ tarayõcõlar olabileceği için bizim bu
ihtimali düşünüp yazacağõmõz fonksiyonda yukarõdaki tüm ihtimalleri denemeliyiz. Bunun için
JavaScript içerisinde try-catch bloklarõ yazarak tarayõcõya göre yeni bir nesne oluşturmalõyõz.
(Aşağõdaki kod üzerinde çok fazla dõrmaya gerek yok. Zira buradaki try-catch yapõsõ C# .NET
ve VB .NET’teki yapõyla hemen hemen aynõdõr.)

function NesneOlustur()
{
var nesne;
try
{
nesne = new ActiveXObject("Msxml2.XMLHTTP"); // IE 6.0+ tarayõcõlar için
}
catch(e)
{
try
{

118
nesne = new ActiveXObject("Microsoft.XMLHTTP"); // IE 5.5 tarayõcõlarõ için
}
catch(e)
{
try
{
nesne = new XMLHTTPRequest(); // Firefox, Opera 8.0+ ve Safari tarayõcõlarõ için
}
catch(e)
{
alert("Tarayõcõnõz AJAX'õ desteklemiyor!!!");
return null;
}
}
}
return nesne;
}

Yukarõdaki JavaScript fonksiyonu bize istemcinin kullandõğõ tarayõcõya göre oluşturacağõ


XMLHTTPRequest nesnesini döndürecektir. Bu nesne üzerinden artõk asenkron işlemlere
başlayabiliriz. open ve send metotlarõ sunucuya asenkron istekte bulunmamõzõ
sağlamaktadõr.

open metodu 3 parametre almaktadõr. İlk parametre; isteği hangi metodu kullanarak
yapacağõmõzdõr. (GET veya POST) İkinci parametre hangi adrese istekte bulunacağõmõzdõr.
(Örneğin sonuc.aspx) Son parametre ise isteğin asenkron bir şekilde gerçekleşip
gerçekleşmeyeceğidir. (true değeri asenkron şekilde olacağõ anlamõna gelir.)

nesne.open(“GET”, “sonuc.aspx”, true);

open nesnesinin 2 ve 5 parametre almõş aşõrõ yüklenmiş halleri de vardõr. Yukarõdaki kullanõm
genel olduğu için bu bize yetecektir.

send metodu ise open ile hazõrladõğõmõz isteği sunucuya gönderir. Eğer open ile açacağõmõz
istek POST metodunu kullanõyorsa, send metodu parametre olarak gönderilecek veriyi
taşõyabilir. Send metodunu parametresiz veya null parametresi ile de kullanabilmekteyiz.

nesne.send(); veya nesne.send(null);

İsteğimiz sunucuya gönderildi. Artõk sunucudan gelecek olan cevabõ bekleyip eğer sonuç
dönerse bu sonucu HTML kõsmõnda yazmamõz kaldõ. Bu işlemi yapabilmemiz için yine
XMLHTTPRequest içerisinde bulunan onreadystatechange eventhandler’õ ve readystate
özelliğini kullanmamõz gerekiyor.

119
onreadystatechange eventhandler’õ sunucuya istekte bulunduktan sonraki durum
değişikliklerini yakalar. Burada bahsettiğimiz durumlar ise 5 tanedir ve bu durumlarõ
readystate özelliğini kullanarak elde edebiliriz. Bu durumlar;

0 = İstek hazõrlanmadõ
1 = İstek hazõrlandõ
2 = İstek gönderildi
3 = İstek değerlendiriliyor ve sonuç bekleniyor
4 = İstek tamamlandõ ve sonuç geldi

onreadystatechange olayõnõ atacağõmõz bir fonksiyon içerisinde readystate değerini kontrol


edersek, readystate bize 4 değerini getirdiğinde artõk isteğimiz tamamlanmõş ve bize bir
sonuç getirilmiş demektir.

nesne.onreadystatechange = function
{
if (nesne.readystate == 4)
{
// sonucu HTML’e yazdõr
}
}

Artõk HTML kodumuzdaki buton içerisinden çağõracağõmõz AsenkronCagriYap() fonksiyonunu


oluşturabiliriz.
function AsenkronCagriYap()
{
var yeniNesne = NesneOlustur(); // XMLHTTPRequest nesnemizi oluşturduk

// Bulunacağõmõz isteği açõyor ve sunucuya gönderiyoruz. İsteğimiz aynõ dizinde bulunan


Ogrenciler.htm adresine, GET metodunu kullanarak gerçekleşiyor.
yeniNesne.open("GET","Ogrenciler.htm",true);
yeniNesne.send(null);

// Yeni bir fonksiyon yazmamõza gerek kalmadan onreadystatechange olayõnõ isimsiz bir
fonksiyona bağlõyoruz
yeniNesne.onreadystatechange = function()
{
// Eğer readystate 4 değerine sahipse asenkron işlem bitmiş ve veriler getirilmiş demektir
if(yeniNesne.readystate == 4)
{
// Getirilen veriyi HTML kõsmõndaki lblGuncelle içerisine dinamik bir şekilde yazdõrõyoruz
document.getElementById('lblGuncelle').innerHTML = yeniNesne.responseText;
}
}
}

120
Son olarak belirtmemiz gereken nokta ise document.getElementById('lblGuncelle').
innerHTML şeklinde HTML kõsmõndaki lblGuncelle span elementine ulaşõyor ve bu elementin
içerisine istek sonucunda gelecek olan bilgiyi yazdõrõyoruz. yeniNesne.responseText ise Text
formatõnda gelecek olan veriyi almamõzõ sağşõyor. (responseXML ise DOM’a uygun XML
formatõnda gelen veriyi almamõzõ sağlar) Sayfamõzõ çalõştõracak olursak sadece butonu
bulunan bir sayfamõz olacak. Burada span elementi ile belirttiğimiz boş bir alan daha var.
Uygulamamõzõn doğru çalõşõp çalõşmadõğõnõ görebilmemiz için sayfamõzõn bulunduğu dizine
Ogranciler.htm adõnda bir dosya oluşturmamõz gerekiyor. Bu dosyanõn içerisine örnek
olmasõ açõsõndan birkaç satõrlõk yazõ ekleyebiliriz. Sayfamõzda bulunan butona tõkladõğõmõzda
butonun onclick olayõ çalõşacak ve AsenkronCagriYap() isimli JavaScript fonksiyonumuz
çağõrõlacaktõr. Bu fonksiyon asenkron çağrõ işlemini gerçekleştirecek ve getirilen bilgiyi
lblGuncelle adõnõ verdiğimiz span elementinin içerisine yazacaktõr.

Yukarõdaki örneğimizde kullandõklarõmõz dõşõnda XMLHTTPRequest’in aşağõdaki üyeleri de


bulunmaktadõr.

Metotlar:
abort() = nesne üzerinden yapõlan isteği durdurur.
getAllResponseHeaders() = Gelen cevabõn başlõk bilgilerini getirir.
getResponseHeader("headerLabel") = Parametre olarak verilen başlõk bilgisini getirir.
setRequestHeader("headerLabel", "value") = Gönderilen başlõk bilgisine istenilen değeri
atar.

Özellikler:
status = Sunucudan dönen cevabõn numarasal kodudur. Örneğin 404 kodu “Not Found” yani
istekte bulunduğumuz sayfa bulunamadõ anlamõna gelir. 200 ise “OK” değeri dönderir ve
işlemin tamamlandõğõnõ belirtir.
statusText = status özelliğinin metin karşõlõğõnõ verir.

Son kõsõmda belirtilen metot ve özellikler üzerinde fazla durmamõza gerek olmadõğõnõ
düşünüyorum. AJAX’õ kullanarak asenkron veri alõş-verişini yapabilmek için örneğimizde
kullandõğõmõz open ve send metotlarõ, onreadystatechange eventhandler’õ ile readystate
özelliği bizim için yeterli olacaktõr.

Bu yazõmõzda AJAX modelini inceleyip web uygulamalarõmõzda nasõl kullanabileceğmizi ele


aldõk. AJAX web üzerinde uygulama geliştiriciler için gerçekten köklü ve önemli bir gelişme.
ASP .NET geliştiricileri için hazõrlanan ve kullanõmõ giderek yaygõnlaşan ASP .NET AJAX
aracõnõ kullanmak için AJAX’õ veya JavaScript’i iyi bilmemize gerek olmamasõna rağmen
temel olarak AJAX modelini nasõl uygulayabileceğimizi öğrenmek bizler için oldukça yararlõ
olacaktõr.

121
ASP.NET AJAX Uygulamalarõ ile İlgili Sorunlar ve
Çözümleri
13 Mart 2007

AJAX uygulama modeli, her geçen gün uygulamalarda daha da sõk kullanõlõr hale geliyor.
ASP.NET uygulama geliştiricileri olarak bizler de Microsoft’un ücretsiz sunmuş olduğu AJAX
kütüphanesi olan ASP.NET AJAX’õ projelerimizde kullanarak, daha persormanslõ ve zengin
uygulamalar geliştirebiliyoruz. ASP.NET AJAX uygulamalarõ geliştirirken elbetteki bazõ
durumlarda sõkõntõlar, sorunlar yaşanabilecektir. Bu yazõda bu nitelikteki bazõ sorunlarõ ve
hatalarõ ele alarak bu durumlarda ne gibi çõkõş yollarõna başvurabileceğimize değineceğiz.

ASP.NET AJAX uygulamalarõnõn sunucuya taşõnmasõnda, klasik uygulamalarõn ASP.NET


AJAX uygulamasõ haline getirilmesinde ve bazõ ASP.NET kontrollerinin UpdatePanel
içerisinde kullanõlmasõnda çõkabilecek sorunlar ve bu sorunlar halinde ne gibi işlemler
yapmamõz gerekeceğini aşağõda detaylõ şekilde ele alacağõz.

ASP.NET AJAX desteği olmayan (AJAX Extension kurulu olmayan)


bir sunucuda ASP.NET AJAX’õ nasõl çalõştõrabilirim?
ASP.NET AJAX ile ilgili belki de en sõk karşõlaşõlan sorulardan biri de şu: “Kendi
bilgisayarõmda ASP.NET AJAX projemi geliştirdim. Herşey gayet güzel çalõşõyordu. Fakat
sitemin bulunduğu sunucuya dosyalarõ yüklediğimde ‘Configuration Error’ vb. bazõ hatalar
alõyorum ve sayfalarõmõ çalõştõramõyorum”. Bu hatanõn temel sebebi, sunucuda ASP.NET
AJAX Extension v1.0’õn kurulu olmamasõdõr.

ASP.NET AJAX’õn ATLAS sürümlerinde yapõlan bir projenin kullanacağõ assembly dosyalarõ
projenin Bin dizinine atõlõyor ve assembly dosyalarõ ile birlikte taşõnan proje, bulunduğu tüm
bilgisayarda sorunsuz bir şekilde çalõşabiliyordu. ASP.NET AJAX v1.0 ile artõk bir AJAX
projesinin kullanacağõ assembly dosyalarõ GAC(Global Assembly Cache) içerisine atõldõğõ
için, projeye referans dosyasõ olarak eklemeler yapõlmõyor ve projeniz GAC’daki dosyalarõ
kullanõyor. Bu nedenle hazõrlamõş olduğunuz bir ASP.NET AJAX projesinin sunucuda veya
başka bir bilgisayarda çalõşabilmesi için, o bilgisayara ASP.NET AJAX Extension 1.0’õn
kurulu olmasõ gerekecektir. Sunucuda AJAX projelerini çalõştõramama gibi bir durumda
yapõlmasõ gereken işlemler, projenize gerekli dll dosyalarõnõ eklemek ve web.config
dosyasõnda bazõ değişiklikleri yapmak olacaktõr.

- Öncelikli olarak projenize gerekli dll dosyalarõnõ eklemeniz gerekecektir. ASP.NET AJAX
dosyalarõnõn kullandõğõ assembly dosyalarõ System.Web.Extension ve
System.Web.Extension.Design dll dosyalarõdõr. Bu dosyalarõ AJAX Extension kurulu
bilgisayarõnõzdaki C:\Program Files\Microsoft ASP.NET\ASP.NET 2.0 AJAX
Extensions\v1.0.61025 dizininde bulabilirsiniz. Projenize Bin isimli bir dizin oluşturmanõz ve
dll dosyalarõnõ bu dizine eklemeniz gerekecektir.

122
- Daha sonra uygulamanõzdaki web.config dosyasõnda bazõ değişiklikler yapmanõz
gerekecek. web.config içerisindeki tanõmlamalarõ dikkatli şekilde inceleyecek olursanõz,
tanõmlamalarõn type özelliği içerisinde ...System.Web.Extensions, Version=1.0.61025.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35 şeklinde ifadeler bulunur. Bu
ifadeler yapõlacak olan işlemlerde kullanõlacak assembly dosyasõnõn GAC içerisinden
okunacağõnõ belirten ifadelerdir. web.config’deki bu ifadelerde yer alan Version=1.0.61025.0,
Culture=neutral, PublicKeyToken=31bf3856ad364e35 kõsõmlarõnõ çõkarmanõz gerekecektir.
Aşağõdaki şekilde değişiklik yapõlacak alanlar gri zemin üzerinde gösterilmiştir. Web.config
içerisindeki bu alanlar ve aynõ tanõmlamalarõn geçtiği diğer alanlarda değişiklik yapmak
gerekecektir.

web.config dosyasõnda gerekli değişikliklerin yapõlmasõ

type kõsõmlarõnda yapacağõnõz bu değişikliklerden sonra artõk projeniz Bin dizinindeki dll
dosyalarõnõ kullanacaktõr. Projenizle birlikte bu dll dosyalarõnõ da sunucuya attõktan sonra, son
işlem olarak uygulamanõn bulunduğu dizini sitenizde virtual directory (sanal dizin) olarak
tanõmlayacak olursanõz, artõk projeniz sorunsuz bir şekilde çalõşacaktõr.

Daha önceden geliştirilmiş ASP.NET 2.0 uygulamasõnda nasõl


ASP.NET AJAX kullanabilirim?
Daha önceden geliştirilmiş bir ASP.NET 2.0 projesini AJAX’a geçirmek karşõmõza çõkabilecek
ihtiyaçlardan biridir. Böyle bir durumda yapõlmasõ gereken iki işlem var. Birincisi web.config
dosyasõ içerisindeki gerekli değişiklikleri yapmak, ikincisi ise uygulama içerisinde AJAX
kullanõlacak sayfalara ScriptManager ve UpdatePanel gibi AJAX kontrollerin eklenmesi
olacaktõr.

123
- web.config dosyasõnda değişiklik yapabilmek için öncelikle bir ASP.NET AJAX
uygulamasõndaki web.config dosyasõna ihtiyacõmõz olacaktõr. Eğer klasik uygulamanõzdaki
web.config dosyasõ içerisinde hiç değişiklik yapmadõysanõz (yani uygulama ilk açõldõktan
sonra web.config dosyasõna herhangi bir ekleme-çõkarma veya değişiklik yapmadõysanõz),
yapõlacak işlem oldukça basit olacaktõr: ASP.NET AJAX uygulamanõzdan aldõğõnõz
web.config dosyasõnõ aynen klasik uygulamanõza eklemek. Eğer klasik uygulamnõzdaki
web.config dosyasõnda değişiklikler yaptõysanõz, ASP.NET AJAX projesindeki web.config’den

- <configSections></configSections>
- <pages></pages> kõsmõ içerisindeki <controls></controls>
- <compilation></compilation> kõsmõ içerisindeki <assemblies></assemblies>
- <httpHandlers></httpHandlers>
- <httpModules></httpModules>
- <system.web.extensions></system.web.extensions>
- <system.webServer></system.webServer>

kõsõmlarõnõ uygulamanõzõn web.config dosyasõ içerisindeki uygun alanlara eklemeniz


gerekecektir. Buradaki kõsõmlarõn hiyerarşik olarak belirli bir düzene sahip olmasõ gerekeceği
için bazõ düzenlemeler yapmak gerekebilir. Örneğin <configSections> düğümünün,
<configuration> kõsmõndaki ilk düğüm olmasõ zorunlu olacaktõr. Bu tip hatalarõ derleme
zamanõnda veya ilk çalõştõrma anõnda alacağõmõz için kolayca düzeltebiliriz. Böylece
uygulamanõzda ASP.NET AJAX ile ilgili ayarlamalarõ gerçekleştirmiş olacaksõnõz.

- ASP.NET AJAX Extension’larõnõ kullanmak istediğiniz sayfalara ScriptManager,


UpdatePanel, UpdateProgress gibi kontrolleri ekleyerek sayfalarõnõzda artõk AJAX’õ sorunsuz
bir şekilde kullanabilirsiniz.

Daha önceden geliştirdiğim bir ASP.NET 1.0 veya 1.1


uygulamasõnda ASP.NET AJAX’õ kullanabilir miyim?
ASP.NET AJAX Extension, ASP.NET’in sadece 2.0 versiyonu ile kullanõlabilir bir yapõ olduğu
için, önceki ASP.NET sürümlerinde ASP.NET AJAX’õn kullanõlmasõ mümkün değildir. 1.0 ve
1.1 sürümleri ile geliştirilmiş projelerde .NET Framework için hazõrlanmõş olan AJAX.NET
isimli ücretsiz AJAX kütüphanesini kullanabilirsiniz. (AJAX.NET için http://ajax.schwarz-
interactive.de adresinden bilgi alabilirsiniz)

ASP.NET AJAX uygulamalarõnda FileUpload ve WebParts kontrolleri


gibi kontrolleri çalõştõramadõm? Sorun neden kaynaklanõyor?
ASP.NET AJAX, ASP.NET kontrolleri ile uyumlu bir şekilde çalõşsa da desteklemediği bazõ
kontroller de vardõr. Bu kontroller asenkron mimari ile uyumlu çalõşamayacağõ için, bir
UpdatePanel içerisinde de düzgün şekilde kullanõlamayacaktõr. FileUpload, TreeView,
Menu kontrolleri, Login kontrolleri ve Web Part kontrolleri AJAX uygulamalarõnda
düzgün bir şekilde kullanõlamamaktadõr. Yine GridView ve DetailsView kontrolleri de bazõ
durumlarda UpdatePanel içerisinde düzgün şekilde kullanõlamayacaktõr. GridView

124
kontrolünün EnableSortingAndPagingCallbacks değerini True ve DetailsView kontrolünün
EnablePagingCallbacks değerini True olarak değiştirmeniz durumunda bu kontroller kendi
Callback özelliklerini kullanarak güncellenecek ve UpdatePanel içerisinde kõsmi güncelleme
gerçekleşmeyecektir. Bu değerleri değiştirmezseniz, yani varsayõlan değerleri olan False
değerlerini taşõrlarsa UpdatePanel’iniz düzgün bir şekilde çalõşacaktõr.

125
AJAX Uygulamalarõnda UpdatePanel Kullanõmõ
24 Nisan 2007

UpdatePanel kontrolü, ASP.NET AJAX uygulamalarõnda, bir web sayfasõ içerisinde kõsõmlar
oluşturulmasõnõ ve bu kõsõmlarõn asenkron şekilde güncellenmesini sağlayan kontroldür.
ASP.NET AJAX uygulamalarõnda, bir sayfa PostBack işlemine tabi tutulmadan, sadece
UpdatePanel içerisi güncellenebilir. Bu şekilde web sayfalarõ daha hõzlõ çalõşõr hale geldiği
gibi, sunucu ile istemci arasõndaki veri trafiği de önemli derecede azalõr.

UpdatePanel kontrolü, sayfa içerisinde bir alan oluşturarak, (HTML kõsmõnda <div> veya
<span> etiketi ile oluşan bir alan) içerisine eklenen kontrollerin görüntülenmesini ve asenkron
bir şekilde bu kontrollerin içeriklerinin güncellenmesini sağlar.
<ContentTemplate></ContentTemplate> ve <Triggers></Triggers> kõsõmlarõ olmak üzere
iki kõsõmdan oluşmaktadõr. <ContentTemplate> kõsmõnda, UpdatePanel içerisinde yer alacak
içerikler bulunur.(ASP.NET kontrolleri, HTML kontrolleri, resim dosyalarõ, metinler vb.)
Sadece bu kõsõmda yer alan bileşenler, kõsmi güncelleme işleminden etkilenir. <Triggers>
kõsmõnda ise UpdatePanel'in çalõşmasõnõ; yani güncelleme işleminin gerçekleşmesini
sağlayacak olaylarõn bağlanmasõ işlemi gerçekleştirilir. (Bir Button kontrolünün Click olayõ
veya DropDownList kontrolünün SelectedIndexChanged olayõ gibi durumlarõn panele
bağlanmasõ) ContentTemplate ve Triggers kõsõmlarõ UpdatePanel içerisinde şu şekilde
kullanõlmaktadõr.

<asp:UpdatePanel ID="updatePanel1" runat="server">


<ContentTemplate>
<!-- Buraya gerekli içerikler eklenecek -->
</ContentTemplate>
<Triggers>
<!-- Bu kõsõmda UpdatePanel'e olaylar bağlanõr -->
</Triggers>
</asp:UpdatePanel>

UpdatePanel’in ContentTemplate’i içerisine bileşenleri eklemek, kõsmi güncelleme işleminin


yapõlmasõ için yeterli olmayacaktõr. UpdatePanel içerisindeki kõsmõn güncellenmesi için,
sayfada bulunan herhangi bir kontrol üzerinde gerçekleşecek bir olayõn paneli tetiklemesi
gerekecektir. Örneğin, bir butonun tõklanmasõ; yani Button kontrolünün Click olayõnõn
gerçekleşmesi UpdatePanel’in güncellenmesini sağlayabilir. UpdatePanel, kendisini
güncelleyecek olaya bağlanõr ve böylece olay gerçekleştiğinde UpdatePanel içerisi asenkron
bir şekilde güncellenebilir. Burada UpdatePanel’in içerisini güncelleyecek kontrolün
bulunacağõ konuma göre iki farklõ durum sözkonusu olacaktõr; kontrolün UpdatePanel
içerisinde veya dõşarõsõnda olmasõ. Gelin bu iki durumda UpdatePanel'in nasõl çalõştõğõnõ ele
alalõm. Öncelikle File > New > Web Site menüsünden ASP.NET AJAX Enabled Web Site
seçeneğini seçerek açtõğõmõz yeni projenin Default.aspx sayfasõna bir UpdatePanel kontrolü
ekleyelim.

126
Durum-1: Kontrol UpdatePanel içerisinde ise:
UpdatePanel’i güncelleyecek kontrol UpdatePanel’in içerisinde yer alõyorsa, bu kontrolün
varsayõlan olayõnõn gerçekleşmesi UpdatePanel’i otomatik olarak tetikleyecektir. Yani biz
herhangi bir ayarlama veya atama yapmasak dahi, UpdatePanel içerisinde yer alan Button
gibi bir kontrole tõklandõğõnda panelin içerisindeki veriler güncellenecektir. Default.aspx ve
Default.aspx.cs dosyalarõnda aşağõ değişiklikleri yapõp, uygulamayõ çalõştõralõm.

Default.aspx
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Label ID="Label1" runat="server" Text=""></asp:Label> <br />
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>

Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
}

Resim: UpdatePanel içerisindeki kontrolün paneli tetiklemesi

Açõlan sayfada butona tõklandõğõnda Label1 üzerindeki tarih bilgisinin asenkron bir şekilde
güncellendiğini görebiliriz. Burada dikkat edeceğiniz gibi panele herhangi bir trigger bağlama
işlemi yapmamamõza rağmen güncelleme işlemi otomatik olarak yapõldõ. UpdatePanel’in
içerisine eklenen kontrolün otomatik olarak paneli güncellemesini sağlayan UpdatePanel
kontrolünün ChildrensAsTrigger isimli özelliğidir. ChildrensAsTrigger özelliği varsayõlan
olarak True değeri taşõdõğõ için UpdatePanel içerisine eklenen bir kontrolün olayõ, biz
belirtmesek bile panele trigger olarak eklenecektir. Eğer ChildrensAsTrigger özelliği False
olarak değiştirilirse, panel içerisine eklenen bir kontrol otomatik olarak paneli güncellemez.

Durum-2: Kontrol UpdatePanel’in dõşõnda ise:


Güncelleme işlemini yapacak kontrol bazõ durumlarda tasarõm gereği UpdatePanel’in
dõşarõsõnda da bulunabilir. Böyle bir durumda bu kontrolün paneli otomatik olarak
güncelleyebilmesi mümkün olmayacaktõr. Kontrol ancak trigger olarak panele bağlanõrsa,
kontrol üzerinde gerçekleşecek olay panelin içerisini güncelleyecektir. Bu durumda kontrolü
UpdatePanel içerisinde bulunan <Triggers> kõsmõna AsyncPostBackTrigger trigger olarak

127
eklemek gerekecektir. Örneğin UpdatePanel dõşõnda kalan btnDisari isimli bir butonu panele
trigger olarak bağlamak için aşağõdaki ifadeleri UpdatePanel’e eklemek gerekecektir.

<asp:UpdatePanel ID="UpdatePanel1" runat="server">


<ContentTemplate>
<table style="background-color:#DDDDDD; width:200px">
<tr>
<td>
<asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> <br />
<asp:Button ID="Button1" runat="server" Text="Button" />
</td>
</tr>
</table>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnDisari" EventName="Click" />
</Triggers>
</asp:UpdatePanel>
<br /><br />
<asp:Button ID="btnDisari" runat="server" Text="Panel dõşõndan güncelle" />

Resim: UpdatePanel dõşõndaki bir kontrolün paneli tetiklemesi

Bu işlem HTML kodlarõ içerisinden gerçekleştirilebileceği gibi, sayfanõn Design kõsmõnda iken
UpdatePanel seçilip Properties penceresinden Triggers özelliğine tõklanõrsa, açõlan
pencereden de istenilen kontrol ve kontrolün olayõnõ seçmek trigger eklemek için yeterli
olacaktõr.

128
Resim: UpdatePanel'e AsyncPostBackTrigger eklenmesi

AsyncPostBackTrigger, panele asenkron postback işlemi yapmasõ istenilen kontrolün


eklenmesi için kullanõlacak seçenektir. ControlID, paneli tetikleyecek kontrolün adõ,
EventName ise bu kontrol üzerinde gerçekleşecek olaydõr. Bu şekilde UpdatePanel
dõşõndaki bir kontrolün paneli asenkron bir şekilde güncellemesi sağlanabilir. Eğer tasarõm
gereği UpdatePanel içerisinde bulunan bir kontrolün panelin içerisinde değilde, sayfanõn
tamamõnda postback işlemi gerçekleştirmesi istenirse, bu kontrolün panele
PostBackTrigger olarak eklenmesi gerekecektir.

Bir Sayfada Birden Fazla UpdatePanel Kullanõmõ


Bir sayfa içerisinde bir tane UpdatePanel kullanõlabileceği gibi birden fazla UpdatePanel de
kullanõlabilir. Böyle bir durumda da karşõmõza bazõ karõşõklõklar çõkabilecektir. Gelin şimdi de
bir sayfa içerisinde birden fazla UpdatePanel bulunduğunda panellerin ne şekilde
çalõşacağõnõ, birbirlerinin güncellemelerinden nasõl etkileneceklerini ele alalõm. Bu işlem için
öncelikli olarak sayfamõza UpdatePanel2 adõnda ikinci bir panel ekleyelim. Bu panelin
ContentTemplate’i içerisine de aşağõda görüldüğü şekilde Label2 adõnda bir Label kontrolü
ve Button2 adõnda bir Button kontrolü ekleyelim.

Default.aspx
<asp:UpdatePanel ID="UpdatePanel2" runat="server">
<ContentTemplate>
<table style="background-color:#B5DDDD; width:200px">
<tr><td>
<asp:Label ID="Label2" runat="server"></asp:Label> <br />
<asp:Button ID="Button2" runat="server" Text="Button-2" />
</td></tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>

129
Label2 kontrolünün de asenkron şekilde güncellenmesi için Default.aspx.cs dosyasõndaki
Page_Load kõsmõnõ şu şekilde değiştirelim:

Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
Label2.Text = DateTime.Now.ToLongTimeString();
}

Artõk UpdatePanel2 kontrolü içerisindeki Button2’ye tõklandõğõnda Label2 üzerine güncel


zaman bilgisinin asenkron bir şekilde güncellenerek gelmesini bekliyoruz. Uygulamayõ
çalõşõtõrõp değişiklikleri gözlemleyelim. Burada istenilenin dõşõnda bir durum gözünüze
çarpacaktõr. Herhangi bir paneldeki butona tõklanõlmasõ durumunda her iki panelin de
güncelleneceğini göreceksiniz.

Resim: Bir sayfada birden fazla UpdatePanel kullanõmõ

Bu işleyiş aslõnda normal şartlarda pekte istenilen bir durum olmayacaktõr. Zira birbirinden
ayrõlmõş iki farklõ panelin sadece kendi triggerlarõ tarafõndan tetiklenmesi istenilebilir. Fakat
burada ise UpdatePanel1 içerisindeki bir kontrol tetiklendiğinde UpdatePanel2 içerisi de
güncellenmektedir. UpdatePanel'lerin bu şekilde çalõşmalarõnõ sağlayan UpdateMode
özellikleridir. Sayfamõza eklediğimiz bir UpdatePanel'in UpdateMode özelliği varsayõlan
olarak Always değerini taşõmaktadõr. UpdateMode özelliğinin Always olmasõ durumunda
sayfa içerisindeki herhangi bir UpdatePanel'in tetiklenmesi panelinde tetiklenmesini
sağlayacaktõr. Eğer UpdateMode özelliği Conditional değerini alõrsa, panel sadece kendi
triggerlarõ aracõlõğõyla tetiklenecektir. Bu noktada UpdatePanel1'in UpdateMode özelliğini
Conditional yapacak olursanõz, sayfayõ çalõştõrdõğõnõzda UpdatePanel1'in sadece kendi
triggerlarõ tarafõndan tetiklenebileceğini göreceksiniz. Fakat UpdatePanel2'nin UpdateMode
özelliği hala Always olduğu için UpdatePanel1'deki bir güncelleme, UpdatePanel2'yi de
tetikleyecektir.

Aşağõdaki tabloda iki UpdatePanel'in UpdateMode özelliklerine göre ne şekilde


tetiklenecekleri listelenmiştir.

130
UpdatePanel1'in UpdatePanel2'in UpdatePanel1 UpdatePanel2
UpdateMode UpdateMode triggerõ triggerõ
özelliği özelliği tetiklenirse tetiklenirse
Her iki panelde Her iki panelde
Always Always
güncellenir. güncellenir.
UpdatePanel2
Her iki panelde güncellenir,
Conditional Always
güncellenir. UpdatePanel1
güncellenmez.
UpdatePanel1
güncellenir, Her iki panelde
Always Conditional
UpdatePanel2 güncellenir.
güncellenmez.
UpdatePanel1 UpdatePanel2
güncellenir, güncellenir,
Conditional Conditional
UpdatePanel2 UpdatePanel1
güncellenmez. güncellenmez.

İç İçe UpdatePanel Kullanõmõ


ASP.NET AJAX ile hazõrlanan bir sayfa içerisinde iç içe UpdatePanel'ler de
kullanõlabilmektedir. Hazõrlanan web sayfasõ içerisinde UpdatePanel sayfanõn büyük bir
kõsmõnõ kaplõyor ve içerisinde çok sayõda kontrol bulunduruyorsa, içerisindeki tüm kontrollerin
beraber güncellenmesinin dõşõnda bazõ kontrol gruplarõnõn da ayrõ olarak güncellenmesi
istenilebilir. Böyle bir durumda, ana UpdatePanel'in ContentTemplate kõsmõnda yerleştirilecek
ikinci bir UpdatePanel, dõştaki UpdatePanel ile uyumlu bir şekilde çalõşabilecektir. Aşağõdaki
örnekte sayfaya eklenen bir UpdatePanel içerisine ikinci bir UpdatePanel eklenmiştir. Burada
iç kõsõmdaki UpdatePanel'in dõştaki panelden ayrõ olarak çalõşabilmesi için dõştaki
UpdatePanel'in (UpdatePanel3) UpdateMode özelliği Conditional, içteki UpdatePanel'in
(UpdatePanel4) UpdateMode özelliği ise Always olarak tanõmlanmalõdõr.

Default.aspx
<asp:UpdatePanel ID="UpdatePanel3" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<table style="width: 300px; background-color: #9999ff">
<tr><td>
<asp:Label ID="lblDisKisim" runat="server"></asp:Label><br />
<asp:Button ID="Button3" runat="server" Text="Ana Panel" /><br />
<br />
<asp:UpdatePanel ID="UpdatePanel4" runat="server">
<ContentTemplate>
<table style="width: 200px; background-color: #99ccff">
<tr><td>

131
<br />
<asp:Label ID="lblIcKisim" runat="server"></asp:Label><br />
<asp:Button ID="Button4" runat="server" Text="İç Panel" />
</td></tr>
</table>
</ContentTemplate>
</asp:UpdatePanel>

</td></tr> </table>
</ContentTemplate>
</asp:UpdatePanel>

Default.aspx.cs
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = DateTime.Now.ToLongTimeString();
Label2.Text = DateTime.Now.ToLongTimeString();

lblDisKisim.Text = DateTime.Now.ToLongTimeString();
lblIcKisim.Text = DateTime.Now.ToLongTimeString();
}

Resim: Bir UpdatePanel içerisinde başka bir UpdatePanel kullanõlabilir.

Ana panelde bulunan butona tõklanmasõ durumunda panelin tamamõ (iç panel de dahil)
güncellenecektir. İç panelde bulunan butona tõklandõğõnda ise sadece iç panel
güncellenecektir. Bazõ durumlarda, özellikle sayfanõn tasarõmõ gereği bir UpdatePanel
içerisinde başka bir UpdatePanel kullanõlmasõ durumu ile karşõlaşabiliriz.

132
ASP.NET AJAX’a Giriş
09 Eylül 2007

Merhabalar. Bu yazõmõzda web dünyasõnda son yõllara damgasõnõ vuran AJAX uygulama
tekniğini kõsaca ele alõp Microsoft’un ASP.NET uygulama geliştiricilere ücretsiz olarak
sunmuş olduğu ASP.NET AJAX isimli ücretsiz AJAX kod kütüphanesini uygulamalarõmõzda
nasõl kullanabileceğimizi inceleyeceğiz.

AJAX; yani Asenkron JavaScript ve XML adõ verilen uygulama modelini kullanarak istemci
ile sunucu arasõnda asenkron şekilde işlemler yapabilmekteyiz. Temel olarak bu işlemler
JavaScript dilini kullanarak tarayõcõnõn yapõsõndaki XmlHttpRequest bileşeni üzerinden
yürütülmektedir. Böylece web sayfalarõnõn tamamen güncellenmesine gerek kalmadan,
sadece belirli alanlarõnõ yenileyebilir ve böylece daha hõzlõ çalõşan web sayfalarõ
geliştirebiliriz. Burada bahsettiğimiz işlem aslõnda web dünyasõnda devrim niteliğinde bir
yenilikti. Google ve Microsoft gibi şirketlerin gerçekleştirdiği projelerle son iki yõl içerisinde
giderek duyulan AJAX ismi, artõk günümüz web projelerinin vazgeçilmez bir parçasõ olmuştur.
Yeni yapõlan birçok web projesi AJAX destekli olarak geliştirildiği gibi, eski web projelerinin
birçoğu da AJAX destekli hale getirilmektedir. Bu nedenle AJAX artõk biz web uygulama
geliştiricileri için oldukça önemli hale gelmiştir.

AJAX ile geliştirilmiş popüler uygulamalara


örnekler
http://www.pageflakes.com
http://local.live.com
http://www.gmail.com
http://www.netvibes.com

AJAX temel olarak istemci-sunucu (client-server) arasõnda asenkron işlemler yürütülmesini


sağladõğõ için, uygulamanõn en önemli kõsmõ belki de istemci tarafõnda çalõştõrmamõz gereken
JavaScript kodlarõ olacaktõr. Zira istemciden sunucuya asenkron bir şekilde gidebilmek için
istemci tarafõnda kodlar çalõştõrmak gerekecektir. Bir AJAX uygulamasõ geliştirebilmek için iyi
seviyede JavaScript dili bilmemiz gerekir diyebiliriz. JavaScript dilini iyi bilmeyen kullanõcõlar
için ise kolay bir şekilde AJAX uygulamalarõ geliştirebilmeleri için AJAX kod kütüphaneleri
hazõrlanmõş ve geliştiricilerin kullanõmõna sunulmuştur. Microsoft ise ASP.NET
programcõlarõnõn uygulamalarõnõ kolay bir şekilde AJAX destekli hale getirmeleri için
ASP.NET AJAX adõ verilen ücretsiz bir kod kütüphanesi duyurmuştur. ASP.NET AJAX temel
olarak istemci ve sunucu tarafõnda çalõştõrõlacak bileşenlerden oluşmakta ve tam anlamõyla
sunucu taraflõ yürütülebilecek AJAX uygulamalarõ geliştirmemizi sağlamaktadõr. ASP.NET
AJAX framework’ünün istemci tarafõnda gerekli JavaScript kod kütüphaneleri ve servisleri,
sunucu tarafõnda ise .NET Framework ve ASP.NET kontrolleri ile uyumlu bir şekilde
çalõşmamõzõ sağlayan AJAX kontrolleri, sõnõf kütüphaneleri ve servisler bulunmaktadõr.

Peki, bir ASP.NET uygulamasõnda ASP.NET AJAX’õ nasõl kullanabiliriz? Öncelikle Visual
Studio 2005 veya Visual Web Developer 2005 gibi bir araçta bu kütüphaneyi kullanabilmek

133
için ASP.NET AJAX’õn resmi web sitesinden 1.3 MB’lõk küçük bir dosyayõ bilgisayarõmõza
indirmek ve kurulum gerçekleştirmek gerekecektir. http://www.asp.net/ajax/downloads/
adresindeki Download ASP.NET Extensions v1.0 linkinden indireceğimiz dosyayõ
bilgisayarõmõza kurduğumuzda Visual Studio 2005’e gerekli proje şablonu ve AJAX kontrolleri
eklenecektir. Böylece artõk yeni bir AJAX web projesi oluşturabileceğiz. Dilerseniz artõk böyle
bir projeyi nasõl geliştirebileceğimize bakalõm.

Bu örneği Visual Studio 2005 uygulama arayüzünde geliştireceğim. Yeni bir proje açmak
için File > New > Web Site seçeneğini seçiyoruz. Açõlan pencereden ASP.NET AJAX-
Enabled Web Site şablonunu seçerek projemizi oluşturuyoruz. Ben projenin dili olarak C#’õ
seçiyorum.

Resim: Visual Studio 2005’te yeni bir AJAX projesi açmak

Böylece yeni bir ASP.NET AJAX projesi oluşturduk. ASP.NET AJAX Extensions kurulumunu
gerçekleştirdiğimizde Visual Studio 2005 Toolbox’õna AJAX Extensions isminde yeni bir
kontrol grubu açõlõr ve buraya AJAX uygulamalarõna özel beş tane kontrol eklenir:
ScriptManager, UpdatePanel, UpdateProgress, Timer ve ScriptManagerProxy. Bu
kontrollerin görevlerine kõsaca inceleyelim.

134
Resim: Visual Studio 2005 Toolbox’õna eklenen AJAX Extensions kontrolleri

ScriptManager:
Sayfanõn AJAX destekli çalõşmasõnõ sağlayan en temel kontroldür. İstemci için gerekli
JavaScript kodlarõnõn üretilmesi ve sayfadaki diğer AJAX kontrollerinin uyumlu bir şekilde
çalõşmasõnõ sağlar. Diğer AJAX kontrollerini kullanabilmek için sayfamõzda mutlaka bir tane
ScriptManager kontrolü bulunmalõdõr.

UpdatePanel:
Sayfa içerisinde asenkron şekilde güncellenebilir alanlar oluşturulmasõnõ sağlayan kontroldür.
Böylece sayfada sadece bu alanlarõn içeriğinin asenkron şekilde güncellenerek sayfanõn
daha hõzlõ çalõşmasõ sağlanabilir.

UpdateProgress:
Asenkron güncelleme işlemi gerçekleşirken kullanõcõyõ güncelleme işleminden haberdar
edebilmek için kullanabileceğimiz kontroldür. Kontrolün içeriği sadece güncelleme
yapõldõğõnda sayfada görüntülenir, güncelleme işlemi bittiğinde ise kaybolur.

Timer:
UpdatePanel kontrolünün içeriği kullanõcõnõn isteği ile güncellenebileceği gibi bazõ
durumlarda belirli zaman aralõklarõyla da güncellenebilir. Timer kontrolü ile UpdatePanel
içeriğinin belirli zaman aralõklarõnda güncellenmesi sağlanabilir.

ScriptManagerProxy:
Bazõ durumlarda bir master sayfanõn (master page) içerik sayfasõnda ScriptManager kontrolü
kullanma ihtiyacõ olabilir. Eğer master sayfada ScriptManager var ise, içerik sayfasõna ikinci
bir ScriptManager kontrolü eklemek soruna yol açacaktõr. İşte böyle bir durumda içerik
sayfasõna ScriptManager yerine ScriptManagerProxy kontrolü ekleyerek işlemleri
yürütebiliriz. ScriptManagerProxy bu tip bir sayfada ScriptManager kontrolüne servis ve script
ekleme işlemlerini gerçekleştirir.

Projeyi açtõğõmõzda dikkatimizi çeken ilk şeylerden birisi aspx sayfamõzdaki ScriptManager
kontrolü olacaktõr. Hali hazõrda gelen ScriptManager kontrolü dõşõnda sayfamõza
UpdatePanel kontrolünü de ekleyecek olursak asenkron işlemler yürütebiliriz. Web
sayfalarõnda gezinirken çoğumuz bir kayõt formundan il bilgisini seçtiğimizde sayfanõn
yenilenmeden ile ait ilçeleri listelediğini görmüşüzdür. Dilerseniz bu şekilde bir uygulamayõ

135
gerçekleştirmeye çalõşalõm. İl ve ilçe bilgilerini saklamak için iller ve ilceler olmak üzere
Microsoft Office Access’te iki tablo oluşturalõm.

Resim: Access’te oluşturduğumuz iller ve ilceler tablolarõ

Bu tablolarõn içeriğini test amaçlõ olmak üzere birkaç il ve ilçe ile dolduralõm. Uygulama
tarafõnda ekleyeceğimiz kontroller ve yapacağõmõz işlemlere gelecek olursak; sayfaya
eklediğimiz UpdatePanel kontrolünün içeriğine iki tane DropDownList kontrolü ekleyelim.
Bunlardan ilkinin adõ ddlIller, diğerinin adõ ise ddlIlceler olsun. ddlIller’in DropDownList
Tasks penceresinden Enable AutoPostBack seçeneği aktif hale getirelim. İlk olarak ddlIller
kontrolünü iller tablosuna bağlayalõm. Bu işlemi pratik bir şekilde yine DropDownList Tasks
penceresindeki Choose Data Source seçeneğinden gerçekleştirebiliriz.

Resim: DropDownList Tasks penceresinden gerekli işlemleri yapõyoruz

Açõlan pencereden adõm adõm ilerleyecek olursak;

- Select a data source seçeneğinden New Data Source seçerek açõlan pencereden
Access Database ikonunu seçip OK diyelim.
- Açõlan pencereden Access dosyamõzõ seçelim ve Next diyelim.
- Karşõmõza çõkan pencereden ise tablo isimleri kõsmõndan iller tablosunu ve alt kõsõmdaki
sütun listesinden il_kod ve il_ad alanlarõnõ seçelim ve Next diyelim. Ardõndan da Finish
butonuna tõklayõp ana menümüze dönelim.
- Ana ekrandan ise ikinci açõlõr menüde il_ad, üçüncü açõlõr menüde ise il_kod
seçeneklerini aktif yapalõm. Böylece ilk açõlõr menü kontrolüne illeri bağlamõş olduk.

Şimdi yapõlacak işlem ise ilçeler açõlõr menüsüne seçilen ilin ilçelerini getirebilmek. ddlIlceler
kontrolü için de yukarõdaki ilk iki adõmõ aynen gerçekleştirdikten sonra;

- Karşõmõza çõkan pencereden ilceler tablosunu seçelim. Sütunlar listesinden ise sadece
ilce_kod ve ilce_ad sütunlarõnõ seçelim.
- Aynõ pencerede sağ kõsõmda bulunan WHERE butonuna tõklayalõm. Açõlan pencerede
Column kõsmõndan ilce_il_kod, Operator kõsmõndan =, Source kõsmõndan Control’ü

136
seçelim. Sağ kõsõmdaki ControlID kõsmõndan ise ddlIller’i seçelim. Sağ kõsõmda yer alan
Add butonu ile yaptõğõmõz seçimleri parametre olarak SQL cümlemize ekleyelim ve OK
butonuna tõklayalõm.
- Son ekranda Finish’i seçip ana ekranõmõza dönelim. Burada da ikinci açõlõr menüden
ilce_ad sütununu, üçüncü açõlõr menüden ilce_kod sütununu seçelim ve OK diyelim.

Resim: İlçeler menüsüne seçilen ilin ilçelerinin getirilebilmesi için SQL cümlemize
gerekli parametre ekleme işlemini gerçekleştiriyoruz

Artõk sayfamõz yenilenmeden iller seçeneğinden seçilen şehre ait ilçeleri diğer menümüze
ekleyecektir. Hiç JavaScript kodu yazmadan nasõl oldu bu iş diyecek olursanõz burada
ASP.NET AJAX’õn ne denli önemli bir araç olduğunu görüyoruz. Normal bir web sayfasõnda
kullandõğõmõz içeriklerimizi UpdatePanel içerisine ekleyecek olursak artõk panel içerisindeki
bileşenler otomatik olarak asenkron güncellenebilir hale gelecektir. Artõk sayfamõzõ çalõştõrõp
sonuçlarõ görelim.

137
Resim: İl menüsünden seçilen ile ait ilçeler sayfanõn yenilenmesine gerek kalmadan
alttaki menüye doldurulur

UpdatePanel kontrolü ContentTemplate ve Triggers olmak üzere iki kõsõmdan oluşur.


Oluşturduğumuz sayfanõn kodlarõna bakacak olursak DropDownList kontrollerinin
UpdatePanel içerisindeki <ContentTemplate> kõsmõna eklendiğini görebiliriz.
UpdatePanel'de asenkron olarak güncellenecek kõsõmlar sadece ContentTemplate içerisinde
tutulmaktadõr. Triggers kõsmõnda ise UpdatePanel’in içeriğinin asenkron olarak
güncellenmesini sağlayacak kontrollerin tanõmlamasõ yapõlõr. Örneğin bir Button’a
tõklandõğõnda veya DropDownList’ten bir seçim yapõldõğõnda UpdatePanel’in içeriğinin
güncellenmesi isteniliyorsa bu kontrollerin UpdatePanel’e trigger (tetikleyici) olarak
bağlanmasõ gerekir.

<asp:UpdatePanel ID="UpdatePanel1" runat="server">


<ContentTemplate>
<!-- Buraya güncellenecek içerikler gelecek... -->
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Button1" EventName="Click" />
</Triggers>
</asp:UpdatePanel>

Trigger kõsmõna eklenen Button1 isimli kontrolün Click event’i (olayõ) gerçekleştiğinde, yani
butona tõklandõğõnda UpdatePanel içeriği güncellenecektir. Fakat dikkat ettiyseniz biz
yaptõğõmõz örnekte yukarõdaki gibi bir trigger eklemesi yapmadõk. Bu UpdatePanel
kontrolümüzün varsayõlan davranõşlarõndan birisidir. UpdatePanel içerisinde bulunan bir
kontrolün panele trigger olarak bağlamasõna gerek yoktur. Bu kontrol üzerinde gerçekleşecek
bir olay otomatik olarak paneli güncelleyecektir. Paneli güncelleyecek kontrol eğer tasarõm
gereği UpdatePanel dõşõnda yer alõyorsa, bu kontrolün yukarõdaki kodlarda görüldüğü gibi
Triggers kõsmõna eklenmesi gerekir.

Böylece UpdatePanel kontrolümüzü nasõl kullanabileceğimizi incelemiş olduk. Dilerseniz


uygulamamõzõ görsel olarak daha zengin hale getirelim. Örneğin iller menüsünden bir il
seçtiğimizde ilçelerin güncellenmesi esnasõnda UpdateProgress kontrolü ile sayfanõn bir

138
köşesine güncelleme işlemi yapõldõğõnõ belirten bir yazõ veya resim ekleyelim.
UpdateProgress kontrolüne eklediğimiz içerik sayfa yüklendiğinde kullanõcõya
görüntülenmez. Güncelleme işlemi başladõğõnda bu kontrolün içeriği görünür hale gelir ve
güncelleme işlemi bittiğinde ise kaybolur. Sayfaya eklediğimiz UpdateProgress kontrolünün
DisplayAfter özelliği güncelleme işleminden kaç milisaniye sonra UpdateProgress’in
görüntüleneceğini belirler. Bu özelliği 0 olarak belirleyelim ve kontrolün içerisine güncelleme
işlemini belirten bir resim dosyasõ ve metin ifade ekleyelim.

<asp:UpdateProgress ID="UpdateProgress1" runat="server" DisplayAfter="0">


<ProgressTemplate>
<div style="background-color: #ff3333; color:White; font-size:14px; width:120px">
<img src="yukleniyor.gif" /><br />
<b>Yükleniyor...</b>
</div>
</ProgressTemplate>
</asp:UpdateProgress>

Sayfayõ çalõştõrõp il menüsünden farklõ illeri seçecek olursak UpdateProgress’in çalõşma


şeklini gözlemleyebiliriz.

Resim: UpdatePanel’in içeriği güncellendiği esnada UpdateProgress kontrolü


görüntülenir

Eğer yapõlacak güncelleme işlemi zamana bağõmlõ olacaksa AJAX kontrollerinden olan
Timer’i UpdatePanel’e ekleyerek panel içeriğinin belirli zaman aralõklarõyla güncellenmesini
sağlayabiliriz. Timer kontrolünün Interval özelliği kaç milisaniyede bir panelin
güncelleneceğini belirler. Örneğin Interval özelliği 30000 olursa panel içeriği 30 saniyede bir
otomatik olarak güncellenir.

Bu yazõmõzda Microsoft’un ASP.NET uygulamalarõnda hõzlõ ve çok kolay bir şekilde AJAX’õ
uygulamamõzõ sağlayan ASP.NET AJAX isimli kütüphanesi ile nasõl uygulama
geliştirebileceğimizi gördük. ASP.NET AJAX ile ilgili olarak www.nedirtv.com sitesindeki
ASP.NET AJAX isimli videolarõ inceleyebilirsiniz. Bir sonraki yazõmõzda görüşmek dileğiyle…

139
Diğer Konular

Anahtar kelimeler

DataRow DataTable Excel Filtreleme OleDb Sõralama


Team Foundation Server

140
Excel Dosyasõndaki Bilgilere Ulaşmak
27 Kasõm 2005

Bildiğimiz gibi MS Excel, .xls tipi dosyalarda verileri saklamamõzõ ve bu veriler üzerinde
işlemler yapabilmemizi sağlamaktadõr. Peki bu verilere .NET ortamõnda nasõl ulaşabiliriz? Bu
aşamaya geçmeden, öncelikle bu işlemi yapabilmemiz için Excel’de dosyamõzõ ne şekilde
hazõrlamamõz gerektiğini anlatacağõm.
Hazõrlayacağõm örnekte bir sõnõftaki öğrencilerin isimlerinin ve 3 tane sõnav notlarõnõn
bilgilerini Excel dosyamõzda tutalõm. Açtõğõmõz Excel dosyasõnda 4 adet sütunumuz olsun.
“AdSoyad”, “Sinav1”, “Sinav2” ve “Final” sütunlarõ. Daha sonra bu sütunlarõn altlarõnõ gerekli
bilgilerle dolduralõm.

Bilgilerin olduğu alanõ seçerek bu alana bir ad veriyoruz, böylece seçili alanõmõz tanõmlõ bir
hale geliyor. Bunun için Ekle > Ad > Tanõmla menüsünü seçiyoruz ve buradan bu alana
vereceğimiz ismi yazõp (Bu uygulamada ben NotTablosu adõnõ verdim) önce “Ekle” diyor ve
daha sonra eklenen bu isim seçili iken “Tamam” diyoruz.

Artõk Excel dosyasõ ADO.NET tarafõndan kullanõlabilecek formattadõr. Bu haliyle Excel


dosyasõnõ bir Access veritabanõ dosyasõ gibi düşünebiliriz. Burada; NotTablosu tablo adõ,
AdSoyad, Sõnav1, Sõnav2 ve Final ise alan adlarõdõr. Dosyayõ Notlar_1.xls olarak kaydedelim
ve dosyayõ kapatalõm. (Zaten dosya açõkken uygulamamõzõ çalõştõrõrsak hata verecektir.)
Burada dikkat etmemiz gereken önemli bir nokta var. İlk satõrõmõzda yer alan AdSoyad,
Sinav1, Sinav2 ve Final bilgileri alan adõ olarak algõlanacaktõr ve veritabanõna eklemeye
çalõştõğõmõzda ilk satõrõmõzdaki bu bilgiler alõnmayacaktõr. Dosyadaki bilgileri SQL komutuyla
filtreleyerek, istediğimiz satõrlarõ ve bilgileri çekebileceğiz. Örnek olarak “SELECT * FROM

141
NotTablosu WHERE Final=80” şeklindeki bir komut, bize bu tabloda Final notunun 80’e eşit
olduğu satõrlarõ getirecektir.
Şimdi sõra geldi ADO.NET ile Excel dosyamõza bağlanmaya ve verileri almaya. Bunun için bir
uygulama oluşturuyoruz. Ben örnek olarak bir ASP.NET Web Uygulamasõ oluşturuyorum.
Uygulamamõzdaki WebFrom1.aspx dosyasõna bir buton ve 1 datagrid nesnesi ekliyorum.
Butona tõkladõğõmda Excel dosyasõndaki veriler alõnarak datagride yüklenecek. Uygulamanõn
kodlarõna gelince; öncelikle veritabanõ ile ilgili işlemler için System.Data.OleDb (Excel
dosyasõna bağlanmamõz için gerekli) ve System.Data.SqlClient isim alanlarõnõ uygulama
kodlarõnõn başlangõcõna ekleyip butonun Click Event’ ine aşağõdaki kodlarõ yazõyoruz.

' Dosyaya bağlanmak için gerekli olan bağlantõ stringini


Dim ConnStr As String = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=" &
Server.MapPath("Notlar_1.xls") & ";" & "Extended Properties=Excel 8.0;"

Dim Conn As New OleDbConnection(ConnStr)


Conn.Open()

Dim MyCommand As New OleDbCommand("SELECT * FROM NotTablosu", Conn)

Dim da As New OleDbDataAdapter


da.SelectCommand = MyCommand

da.Fill(dt)

' Verileri daha sonra da kullanabilmek için session içerisinde tutuyoruz


Session("Veriler") = dt

' Verinin görüntüleneceği DataGrid in DataTable a bağlanmasõ ve verinin yüklenmesi


DataGrid1.DataSource = dt.DefaultView
DataGrid1.DataBind()
Label1.Text = "Excel dosyasõndan veri alõndõ"

Conn.Close()

Kodlardan da anlayacağõnõz gibi genel yapõ bir Access veritabanõndan veri almakla hemen
hemen aynõ. Tek farklõlõk Excel dosyasõna bağlandõğõmõzõ belirten ConnStr değişkenindeki
Extended Properties=Excel 8.0 bilgisi. Sonraki aşamada projemizi çalõştõrõp açõlan formdaki
Veriyi Yükle butonuna tõkladõğõmõzda datagrid Notlar_1.xls dosyasõndaki tanõmlõ alandaki
verilerle dolacaktõr. (Önemli bir not: Notlar_1.xls dosyasõnõn uygulamamõzla aynõ yerde
bulunmasõ gerekmektedir.)

142
Bu kõsma kadar bir xls dosyasõnda tanõmladõğõmõz alandaki bilgileri ADO.NET nesnelerii ile
nasõl alabileceğimizi anlatmaya çalõştõm. Şimdi elimizdeki bu verileri basit bir örnekle
veritabanõna kaydetmeye çalõşalõm. WebForm1.aspx dosyasõna Veritabanõna Kaydet adõnda
bir buton ekliyorum ve butonun Click Event’ ine aşağõdaki kodlarõ yazõyorum.

Dim ConnStr As String = "data source=.;persist security info=False;initial


catalog=Deneme;user id=UserDeneme;pwd=123"

Dim Conn As New SqlConnection(ConnStr)


Conn.Open()

Dim sayi As Integer

' Session içerisinde tutulan verilerin alõnmasõ


dt = Session("Veriler")

For sayi = 0 To dt.Rows.Count - 1

Dim SqlStr As String = "INSERT INTO Notlar (AdSoyad, Sinav1, Sinav2, Final) " & _
"VALUES ('" & dt.Rows(sayi)(0) & "', " & dt.Rows(sayi)(1) & ", " & dt.Rows(sayi)(2) & ", " &
dt.Rows(sayi)(3) & ")"

Dim MyCommand As New SqlCommand(SqlStr, Conn)


Dim da As New SqlDataAdapter

da.SelectCommand = MyCommand
da.Fill(dt)

Next

Label1.Text = "Veriler veritabanõna yazõldõ"


Conn.Close()

143
Kodlardan ve açõklama satõrlarõndan da anlayacağõnõz gibi dt adlõ DataTable içerisindeki
verileri bir for döngüsü içerisinde satõr satõr çekerek döngünün her dönmesinde bir satõrõ MS
SQL Server içerisinde varolan “Deneme” veritabanõndaki “Notlar” tablosuna ekledik. Bu
tabloyu kendi veritabanõnõza kolayca eklemek için aşağõdaki kodlarõ kullanabilirsiniz.

CREATE TABLE [dbo].[Notlar] (


[AdSoyad] [varchar] (50) NOT NULL ,
[Sinav1] [int] NULL ,
[Sinav2] [int] NULL ,
[Final] [int] NULL
) ON [PRIMARY]

Oluşturduğumuz bir Excel dosyasõndaki tanõmlanmõş verileri ADO.NET aracõlõğõyla alarak


kullanõcõnõn görebileceği formda bir datagrid nesnesine yazdõrdõk. Daha sonra da yine bu
verileri ADO.NET nesneleri aracõlõğõyla SQL Server’daki tablomuza yazdõrdõk. Anlatmaya
çalõştõğõm konuda bu özelliği basit yönüyle inceledik. Buradaki örnek kodlardan yola çõkarak
sizde uygulamalarõnõzda bir Excel dosyasõndaki verileri alõp üzerinde işlemler yapabilir ve
varolan başka bir veritabanõ dosyasõna yazdõrabilirsiniz.

144
Datatable ile Sõralama ve Filtreleme İşlemleri
11 Temmuz 2007

Geliştirdiğimiz uygulamalarda veritabanõ ile ilgili işlemleri sõklõkla yapmaktayõz. Veritabanõna


bağlanmak, verileri seçip uygulama ortamõnda aktarmak ve bu verileri uygulamayõ kullanacak
kişilerin istediğine göre sunmak, programcõ olarak bizlerin en rutin işlemlerinden biridir. Tabi
ki bu tip işlemleri yaparken esas alacağõmõz kurallardan biri de uygulamanõn performanslõ bir
şekilde çalõşmasõnõ sağlamaktõr. Bu yazõmõzda da veritabanõndan çektiğimiz verileri
uygulama ortamõnda sakladõğõmõz DataTable nesnesi üzerinde verileri filtreleme ve sõralama
işlemlerini yapmamõzõ sağlayan Find ve Select isimli iki metodu detaylõ bir şekilde
irdeleyeceğiz.
Dilerseniz şöyle bir senaryo ile konumuza giriş yapalõm. Veritabanõnda ürünlerimizin
bulunduğu tablodan verileri getirerek uygulama içerisinde kullanõyoruz. Kullanõcõ, form
üzerinde bulunan kontroller aracõlõğõyla aynõ veri üzerinde özel kriterler belirterek veri seçme
işlemleri gerçekleştiriyor. (Sadece istenilen kriterdeki kayõtlarõ getir, istenilen kriterdeki verileri
istenilen sõrada getir... gibi) Eğer kullanõcõ form üzerinde bu tip işlemleri sõklõkla yapacak ise,
her seferinde veritabanõna bağlantõ açmak, sorgu çalõştõrmak ve sorgu sonuçlarõnõ
uygulamaya aktarmak elbetteki hem uygulamanõn performansõnõ azaltacaktõr, hem de
veritabanõnda daha fazla işlem yapõlacağõ için sunucuda yavaşlõğa sebep olacaktõr. İşte böyle
bir senaryoda tablodan istenilen tüm verileri alarak uygulamada (yani DataTable nesnesi
içerisinde) saklamak, daha sonra da bu veriler üzerinde filtreleme ve sõralama işlemleri
yapmak uygulamamõzõn performansõnõ olumlu yönde arttõracaktõr.
ADO.NET içerisinde bu tip işlemleri yapmamõzõ sağlayan bazõ yapõlar mevcuttur. Bu
yazõmõzda ise DataTable sõnõfõ içerisinde bulunan bazõ metotlarõ kullanarak bu işlemleri nasõl
gerçekleştireceğimizi göreceğiz. Yine DataTable nesnesi içerisindeki verileri okuyarak, bu
verilerin farklõ görünümlerini sunan DataView isimli bir nesne ile de bu tip işlemler yapõlabilir.
DataView nesnesini ilerleyen zamanlarda fõrsat olursa bir makale ile sizlere sunmaya
çalõşacağõm. Dilerseniz DataTable sõnõfõ içerisinde yer alan bu metotlarõn kullanõmõnõ örnek
bir uygulama ile inceleyelim. Bunun için bir Windows Application açarak aşağõdaki şekilde bir
form tasarlayalõm.

145
Şekil: Formumuzun tasarõmõ ve kontrollerin isimleri
Yine uygulamamõzda kullanõlacak verileri tutacağõmõz Urunler isimli tablonun tasarõmõnõ da şu
şekilde gerçekleştirelim:

Şekil: MS Access'te hazõrlayacağõmõz Urunler tablosu

İlerleyen kõsõmlarda daha düzgün bir şekilde ilerleyebilmek için gerekli olan nesnelerin
tanõmlamalarõnõ ve Form_Load'da yapõlacak işlemleri hazõrlayalõm.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Data.OleDb; // Veritabanõ işlemleri için gerekli isim alanõnõ ekliyoruz.

namespace DataTable_SortFilter
{
public partial class Form1 : Form

146
{
// Connection, DataAdapter ve DataTable nesnelerini field olarak tanõmlõyoruz.
OleDbConnection con;
OleDbDataAdapter da;
DataTable dtUrunler;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
// Gerekli bağlantõ ve sorgu cümleleri ile nesneleri oluşturuyoruz.
// DataAdapter'õn Fill metodu ile getirilen verileri DataTable nesnesine yüklüyoruz.
con = new OleDbConnection("Provider=Microsoft.Jet.OleDb.4.0; Data
Source=Sirket.mdb");
da = new OleDbDataAdapter("SELECT * FROM Urunler", con);
dtUrunler = new DataTable("Urunler");
da.Fill(dtUrunler);
}

private void btnDoldur_Click(object sender, EventArgs e)


{
// btnDoldur isimli butona tõklandõğõnda dgvUrunler isimli gridimizi verilerle
dolduruyoruz.
dgvUrunler.DataSource = dtUrunler;
}
}
}

DataTable nesnemizi verilerle doldurduk. Şimdi yavaş yavaş sõralama ve filtreleme işlemlerini
nasõl gerçekleştirebileceğimize bakalõm.

Find metodu ile Satõr (DataRow) Arama


Bildiğiniz gibi, DataTable nesneleri veritabanõndaki tablolara oldukça benzer nesnelerdir.
Tõpkõ tablolarda olduğu gibi DataTable nesnesinde tutulan sütunlardan (DataColumn) birini
veya birden fazlasõnõ, DataTable'õn PrimaryKey property'si ile primary key (birincil anahtar)
olarak tanõmlayabiliriz. Primary key olarak tanõmlanan sütunda taşõnan kayõtlar tek olmalõ,
yani birbirini tekrar etmemelidir. Bu aşamadan sonra artõk Find metodunu kullanarak tablo
içerisinde primary key sütundaki kayõtlar üzerinde arama yapõlabilir. Find metodu parametre
olarak object tipinden bir değer alõr ki; bu değer primary key alanda taşõnan değerlerden biri
olmalõdõr. dtUrunler adõndaki DataTable nesnemizin primary key sütunu int tipinden değer

147
alan UrunID sütunu olacaktõr. UrunID'si 5 olan bir kaydõn DataRow tipinden bilgilerine şu
şekilde ulaşabiliriz.

DataRow satir = dtUrunler.Sort(5); // UrunID'si 5 olan kaydõn bilgilerini DataRow tipinden


getirecektir.

Hazõrlamõş olduğumuz Windows uygulamasõndaki btnFind isimli butonun vazifesi txtID isimli
textbox'a girilen rakamsal değerin bulunduğu kaydõn bilgilerini getirmek olacaktõr. btnFind
isimli butonumuzun Click event'inde çalõşacak olan metodu aşağõdaki gibi dolduralõm.

private void btnFind_Click(object sender, EventArgs e)


{
// Arama işlemlerini yapabilmek için DataTable nesnesinin Primary Key alanõnõ
// belirlememiz gereklidir. dtUrunler nesnesinin PrimaryKey property'si DataColumn
tipinden
// bir dizi isteyeceği için öncelikli olarak bu diziyi tanõmlõyoruz. Burada unique kayõt
// saklayan herhangi bir alan tablonun Primary key'i olarak belirlenip Find metodu ile bu
// alan üzerinde arama yapõlabilir.
DataColumn[] dcPK = { dtUrunler.Columns["UrunID"] };
dtUrunler.PrimaryKey = dcPK;

// Hatalõ bilgi veya olmayan bir ID girildiğinde uygulamanõn düzgün çalõşmasõ için
// işlemleri try-catch içerisinde ele alõyoruz.
try
{
int urunID = Convert.ToInt32(txtID.Text);
// Kullanõcõdan ID değerini aldõk. Rows kolleksiyonunun Find metodu parametre olarak
// verilen değeri satõrlar içerisinde arar ve bulduğu satõrõ DataRow tipinde geriye
// döndürür. Böylece satir isimli DataRow nesnemizin indekleyicileri ([]) aracõlõğõyla
// sütun isimlerini vererek kaydõn bilgilerine ulaşabiliriz.
DataRow satir = dtUrunler.Rows.Find(urunID);
string satirBilgileri = satir["UrunID"].ToString() + " - " + satir["Ad"].ToString() +
" - " + satir["Fiyat"].ToString() + " YTL";
MessageBox.Show(satirBilgileri, urunID + " ID'li ürünün bilgileri");
}
catch (Exception ex)
{
MessageBox.Show("Satõr bulunamadõ!");
}
}

Uygulamayõ çalõştõrdõğõmõzda gridi doldurup varolan bir kaydõn UrunID bilgisini txtID isimli
textboxa yazõp butona tõklatõrsak o ürün ile ilgili UrunID, Ad ve Fiyat gibi bilgileri mesaj kutusu
içerisinde görebiliriz.

148
Şekil: Find metodu ile ID bilgisi verilen kaydõn bilgilerine ulaşmak

Böylece Find metodunu kullanarak primary key sütunumuzdaki bir bilgiye göre ilgili kaydõn
değerlerine nasõl ulaşabileceğimizi görmüş olduk. Find metodunun kullanõmõnõ inceleyecek
olursak bir de aşõrõ yüklenmiş halinin olduğunu görebiliriz. Metodun ikinci versiyonu ise object
tipinden bir dizi ister. Eğer tablomuzun primary key alanõnõ birden fazla sütun oluşturuyorsa,
Find metodunun bu versiyonunu kullanarak birden fazla kriter belirterek arama işlemi
yapabiliriz. Örneğin dtUrunler tablomuzun primary key alanõnõn sadece UrunID sütunundan
değilde, UrunID ve Ad sütunlarõnõn birleşiminden oluştuğunu varsayalõm. Böyle bir durumda
arama kriterini sadece UrunID alanõ üzerinden değil, hem UrunID hem de Ad alanõ üzerinden
verebiliriz. Aslõnda Find(object key) versiyonu primary key alan üzerinden WHERE UrunID=5
gibi bir arama yaparken, Find(object[] keys) versiyonu ise UrunID ve Ad sütunlarõnõn primary
key olduğu bir durumda WHERE UrunID=5 AND Ad='Çikolata-Fõndõklõ' şeklinde bir arama
yaparak sonucu getirir. Find metonun aşõrõ yüklenmiş halinin kullanõmõnõ aşağõdaki örnekte
görebilirsiniz.

// UrunID ve Ad sütunlarõnõ bir DataColumn dizisi içerisinde primary key olarak


// tanõmlõyor ve dtUrunler tablomuzun PrimaryKey property'sine set ediyoruz.
DataColumn[] dcPK = { dtUrunler.Columns["UrunID"], dtUrunler.Columns["Ad"] };
dtUrunler.PrimaryKey = dcPK;

// Object tipindeki dizimizin ilk değer UrunID, ikinci değeri Ad sütunu için.
object[] urunID_Ad = {5, "Çikolata-Fõndõklõ"};
DataRow satir = dtUrunler.Rows.Find(urunID_Ad);

Select Metodu ile Filtreleme ve Sõralama İşlemleri


Find metodu primary key alan üzerinden tek bir satõr ile bilgi getirir, yani bir nevi SELECT *
FROM Urunler WHERE UrunID=5 gibi bir sorgu çalõştõrmamõzõ sağlar. Bazõ durumlarda ise
sadece bir kaydõn değilde belirli kriterlere uyan kayõtlarõn bulunmasõnõ isteyebiliriz.(SELECT *
FROM Urunler WHERE Fiyat>1 AND Fiyat<2 gibi) Dikkat edecek olursanõz Find metodunda
yapacağõmõz aramalar sadece primary key alanõ ile kõsõtlõ idi. Burada bahsettiğimiz sorguda
ise sadece primary key alan üzerinden değil de, tüm alanlarla ilgili kriterler belirtme
isteğinden söz ediyoruz. Yine verdiğimiz kriterler sonucunda getirilen kayõtlarõn belirli bir
alana göre sõralanmasõnõ da isteyebiliriz. (SELECT * FROM Urunler WHERE Fiyat>1 AND

149
Fiyat<2 ORDER BY Ad gibi) Bu tip durumlarda veritabanõna tekrar SELECT sorgularõ
göndermeden DataTable nesnesi üzerinden de sorgulama işlemleri gerçekleştirebiliriz.
DataTable sõnõfõ içerisinde yer alan Select metodu bu görevi üstlenmektedir. Verilen krtier ve
sõralama ifadesine göre DataTable içerisindeki veriler üzerinde kriterlere uyan karakterleri
DataRow dizisi olarak geriye döndürür. Select metodunun versiyonlarõnõ inceleyecek olursak;

public DataRow[] Select();


DataTable içerisindeki tüm satõrlarõ getirir.

public DataRow[] Select(string filterExpression);


DataTable içerisinden sadece filtrelenen kayõtlarõ getirir.

public DataRow[] Select(string filterExpression, string sort);


DataTable içerisinden sadece filtrelenen kayõtlarõ, belirtilen sõralamada getirir.

public DataRow[] Select(string filterExpression, string sort, DataViewRowState


recordStates);
DataTable içerisinden DataRowViewState'i belirtilen kayõtlar içerisinden filtrelenen kayõtlarõ,
belirtilen sõralamada getirir.
Metot içerisinde kullanõlan parametreler ile ilgili olarak;

- filterExpression: Filtreleme ifadesi. WHERE ile kullanõlacak ifade. Örneğin; "Fiyat>1 AND
Fiyat<5" gibi.
- sort: Sõralama ifadesi. ORDER BY ile kullanõlacak ifade. Örneğin Fiyat DESC gibi.
- recordStates: Bildiğiniz gibi DataTable içerisindeki veriler üzerinde çalõşma zamanõnda
değişiklikler yapabiliyoruz. recordStates parametresi DataTable içerisindeki kayõtlarõn
durumuna göre seçme işleminin hangi kayõtlar arasõndan yapõlacağõnõ belirler. Silinmiş
kayõtlar arasõndan seç, değiştirilmeyen kayõtlar arasõndan seç gibi... DataViewRowState
enum'õ (numaralandõrõcõ) tipinden değer alõr. Bu değerler ve anlamlarõnõ aşağõdaki listede
bulabilirsiniz.

Added: Sadece eklenen kayõtlarda


CurrentRows: Tabloda o an varolan kayõtlarda
Deleted: Sadece silinen kayõtlarda
ModifiedCurrent: Değişen kayõtlarda (o an varolan
değerleri ile birlikte)
ModifiedOriginal: Değişen kayõtlarda (orjinal
değerleri ile birlikte)
None: Hiçbir kayõtta
OriginalRows: Orjinal kayõtlarda (silinen ve
değişen kayõtlar dahil)
Unchanged: Değişmeyen kayõtlarda
Tablo: DataViewRowState enum tipinin alabileceği değerler ve anlamlarõ

Select metodunun örnek kullanõmlarõnõ aşağõda bulabilirsiniz.

150
// Tablodaki tüm kayõtlarõ getirir.
DataRow[] satirlar = dtUrunler.Select();

// Tablodaki kayõtlarda UrunID bilgisi 5 ve 10 arasõnda olanlarõ getirir.


DataRow[] satirlar = dtUrunler.Select("UrunID>5 AND UrunID<10");

// Tablodaki kayõtlarda UrunID bilgisi 5 ve 10 arasõndaki kayõtlarõ Fiyat değerleri azalan


şekilde getirir.
DataRow[] satirlar = dtUrunler.Select("UrunID>5 AND UrunID<10", "Fiyat DESC");

// Tabloda o an varolan kayõtlar içerisinde, UrunID bilgisi 5 ve 10 arasõndaki kayõtlarõ, Fiyat


değerleri azalan şekilde getirir.
DataRow[] satirlar = dtUrunler.Select("UrunID>5 AND UrunID<10", "Fiyat DESC",
DataViewRowState.CurrentRows);

Yukarõdaki ifadelerin tamamõndan dönen sonuç DataRow dizisi şeklindedir. Dizi olarak gelen
bu kayõtlarõ bir foreach döngüsü içerisinde uygulama ortamõna aktarabiliriz. Getirilen
sonuçlarõn label1 isimli bir Label kontrolüne yazõmõnõn örnek kodlarõ aşağõda yer almaktadõr.

foreach (DataRow dr in satirlar)


{
label1.Text += dr["UrunID"] + " - " + dr["Ad"] + " - " + dr["Fiyat"] + "\n";
}

Uygulamamõzõn btnSelect butonuna tõklandõğõnda txtWhereCumle textbox'õndan,


cmdOrderBy combobox'õndan ve cbDesc checkbox'õndan alacağõ değerlere göre filtrelenen
ve sõralanan kayõtlarõ DataGridView kontrolüne aşağõdaki gibi doldurabiliriz.

private void btnSelect_Click(object sender, EventArgs e)


{
string whereIfade, orderByIfade;
whereIfade = txtWhereCumle.Text; // WHERE'den sonra gelecek ifade
orderByIfade = cmbOrderBy.SelectedItem.ToString(); // ORDER BY'dan sonra gelecek
ifade
if (cbDesc.Checked)
orderByIfade += " DESC"; // Tersten sõralama yapõlacaksa ifademize DESC ekliyoruz

DataRow[] satirlar = dtUrunler.Select(whereIfade, orderByIfade);

// Seçilen satõrlar dtUrunler isimli tabloya ait olduğu için başka yapõya sahip
// bir DataTable nesnesine yüklenemez! Buradaki sorunu aşabilmek için yeni
// bir DataTable nesnesini dtUrunler isimli tablonun Copy metodu ile oluşturuyoruz.
// Yani dtGecici isimli tablomuz dtUrunler tablosu ile aynõ yapõya sahip oluyor.

151
// Fakat bize sadece o an seçilen veriler gerekli(satirlar dizisi). Bu nedenle de
// dtGecici'deki row'larõ Clear metodu ile siliyoruz. Select metodunun kullanõmõnda
// benzer durumlarda sõkõntõ çõkabilmektedir. Burada ele almadõğõmõz DataView nesnesi
// bu problemleri çözebilecek şekilde dizayn edilmiştir.
DataTable dtGecici = dtUrunler.Copy();
dtGecici.Clear();

foreach (DataRow dr in satirlar)


{
// satirlar nesnesindeki row'lar hala dtUrunler tablosuna ait olduğu için
// ImportRow metodu ile satõrlarõ kopyalõyoruz
dtGecici.ImportRow(dr);
}
dgvUrunler.DataSource = dtGecici; // Verileri gride yüklüyoruz.
}

txtWhereCumle isimli textbox'a arama kriterlerimizi, cmbOrderBy combobox'õna sõralanacak


alanõn girişini yaparak, sõralamayõ tersten yapmak istiyorsak cbDesc checkbox'õnõ seçerek
istenilen verileri grid içerisine doldurabiliriz.

Şekil: Filtreleme ve Sõralama işlemlerinin yapõlmasõ ve sonuçlarõn elde edilmesi

Bu yazõmõzda DataTable üzerinde filtreleme ve sõralama işlemlerini gerçekleştirmemizi


sağlayan Find ve Select metotlarõnõ derinlemesine incelemeye çalõştõk. Veritabanõndan
getirilen aynõ veriler üzerinde sõklõkla sorgulama yapacağõmõz durumlarda (özellikle
raporlama, listeleme vb. işlemlerde) veritabanõna sürekli bağlanarak aynõ veriler üzerinde
sorgu çalõştõrmak performans ve zaman açõsõndan olumsuz sonuçlar doğurabilir. Bu tip

152
durumlarda DataTable sõnõfõ içerisinde yer alan Select metodu ile birden fazla satõr üzerinde
seçme işlemleri, yine DataTable içerisinde bulunanan Rows kolleksiyonuna ait Find metodu
ile de tek kaydõ seçme işlemlerini gerçekleştirebiliriz. Bu işlemleri yaparken sorgulamalar
veritabanõ üzerinde değil de, DataTable nesnemiz üzerinde gerçekleşeceği için bilgisayarõn
belleğinde tutulan bir veri üzerinde gerçekleşen bu işlemler daha hõzlõ olacaktõr. Bu noktada
bu işlemler yapõlõrken veritabanõ üzerinde yapõlacak değişikliklerin uygulamaya
yansõmayacağõnõ da unutmamamõz gerekir.

153
Adõm Adõm Team Foundation Server Single-Server
Kurulumu

07 Mart 2007

Bu yazõda Team Foundation Server kullanabilmemiz için gerekli olan araçlarõn kurulumunu
adõm adõm inceleyeceğiz. Yine Visual Studio 2005 üzerinde takõm projesi oluşturup bu
projede çalõşabilmek için gerekli olan Team Explorer kurulumunu ve Visual Studio 2005'te
yeni bir takõm projesini nasõl oluşturabileceğimizi göreceğiz. Bu dökümanda anlatõlan kurulum
Team Foundation Server Single-Server Deployment kurulumudur. Kurulum Windows
Server 2003 - Standart Edition üzerinde yapõlmõştõr.

TEAM FOUNDATION SERVER KURULUMU (I) bölümünde anlatõlan aşamalar sunucu


olarak kullanõlacak bilgisayarda, TEAM EXPLORER KURULUMU (II) bölümündeki aşamalar
ise Team Foundation Server'a bağlanarak, bu ortak alan üzerinde proje geliştirecek
bilgisayarlarda gerçekleşmelidir. Team Foundation Server ile ilgili olarak daha detaylõ bilgileri
daha önceden yazgelistir.com'da yayõnlanmõş olan şu makalelerden elde edebilirsiniz:

Team Foundation Server Nasõl Kurulur 1


Team Foundation Server Nasõl Kurulur 2

I. Team Foundation Server Kurulumu

Bu kuruluma geçmeden önce, Windows Update sitesinden son güncellemeler yapõlmalõdõr.


(http://windowsupdate.microsoft.com)

Not: Kurulum boyunca sõklõkla güncelleme işlemleri yapõlacaktõr. Bu nedenle kurulum


esnasõnda internete bağlõ olmanõz gerekecektir. Güncelleme işlemleri, zorunlu olmamakla
beraber, kurulumun doğru şekilde sonlanabilmesi ve TFS'õn (Team Foundation Server)
düzgün şekilde çalõşabilmesi için tavsiye edilmektedir.

Kuruluma geçmeden önce, sunucu olarak kullanacağõmõz (TFS kurulumu yapacağõmõz


bilgisayar) sistem üzerinde gerekli kullanõcõlarõ oluşturmamõz gerekecektir. Bu kullanõcõlar,
kurulum işlemi sõrasõnda ve kurulum sonrasõnda bazõ işlemleri yapabilmemiz için gerekli
olacaktõr. Oluşturulacak kullanõcõlar ve özellikleri aşağõdaki gibi olacaktõr:

- TFSSETUP: Kurulum işlemini yapacak olan kullanõcõdõr. Kullanõcõ olarak, Administrator


grubunda yer almalõdõr.
- TFSSERVICE: SharePoint Services ile ilgili işlemlerde kullanõlacak olan kullanõcõdõr.
Güvenlik açõsõndan Administrator grubunda yer almamalõ ve Log on locally yetkisine sahip
olmalõdõr.
- TFSREPORTS: SQL Server Reporting Services tarafõndan kullanõlacak olan kullanõcõdõr.

154
TFSSERVICE kullanõcõsõ ile aynõ yetkilere sahip olmasõ yeterli olacaktõr.
- TFSPROXY: Team Foundation Server Proxy tarafõndan kullanõlacak olan kullanõcõdõr.
Remote bilgisayarlarda administrator kullanõcõsõ olmasõ gereklidir. Bu kullanõcõ kurulum
işlemlerinde kullanõlmayacaktõr.

Aşağõdaki kurulumlar yapõlõrken sisteme TFSSETUP kullanõcõsõ ile login olunmasõ


gerekmektedir. Önemli başka bir husus ta; kurulumlarõ aşağõdaki sõraya göre yapmamõz,
kurulumun başarõlõ bir şekilde bitmesi için gerekli olacaktõr. Şimdi adõm adõm kurulum
işlemlerini yapmaya başlayalõm.

I.a. IIS Kurulumu

- Control Panel > Administrative Tools kõsmõndan Configure Your Server Wizard’a girin.
- İlk iki ekranõ Next’i seçerek geçin. Ekrana gelen Server Role penceresinden Application
Server (IIS, ASP.NET) seçip Next’e tõklayõn.
- Gelen ekrandan sadece Enable ASP.NET seçeneğini seçin ve kurulumu tamamlayõn.
(Frontpage Server Extensions seçilmemelidir)
- Kurulum bittikten sonra http://windowsupdate.microsoft.com adresinden son güncellemeleri
yapõn.

Not: IIS krulumunu, benzer şekilde Control Panel > Add/Remove Programs kõsmõndaki
Windows Components seçeneğinden de gerçekleştirebilirsiniz.

I.b. SQL Server Kurulumu

- TFS için kurulacak olan SQL Server 2005 sürümü Standart Edition veya Enterprise
Edition olmalõdõr.
- Kurulum CD'lerinden CD-1’i açõn. Start ekranõndan Install’õn altõndaki Server components,
tools, Books Online, and samples seçeneğini seçin. Bir sonraki aşamada Prerequestlerin
kurulumu yapõlacaktõr.
- Sonraki kõsõmda sistem ve donanõm gereksinimleri test edilecektir.
- Registration kõsmõnda gerekli Key'i girip Next’i seçin.
- Componenets to Install ekranõndan sadece aşağõdaki bileşenleri seçiniz:
* SQL Server Database Services
* Analysis Services
* Integration Services
* Reporting Services
* Workstation components, Books Online, and development tools
- Components to Install penceresindeki Advanced seçeneğinden açõlan penceredeki ağaç
yapõsõnõ açõnõz ve;
* Database Services’in altõndaki Replication’a tõklayõn. Buradan Entire feature will be
unavailable seçeneğini seçiniz.
* Client Components’in altõndan Management Tools dõşõndaki tüm bileşenlerde Feature
will be unavailable seçeneğini seçiniz.
* Documentation, Samples, and Sample Databases’in altõndaki SQL Server Books
Online seçeneğinden Feature will be unavailable seçeneğini seçiniz.

155
- Instance penceresinden Default Instance seçin. (Kurulumun başarõlõ bir şekilde
yapõlabilmesi için Default Instance seçilmelidir. Named Instance'õn seçilmesi durumunda TFS
kurulumu başarõsõz olacaktõr.)
- Service Account ekranõndan Use the built-in System Account’u seçip listeden Local
System’i seçin.
- Start services at the end of the setup seçeneğinden tüm servisleri seçin.
- Authentication Mode kõsmõndan Windows Authentication seçeneğini seçin.
- Collocation Settings kõsmõndan dili Latin1_General seçin ve aşağõdaki kõsõmdan Accent–
sensetive seçeneğini seçin.
- Report Server Installation Options penceresinde Install the default configuration’õ
seçin.
- Error and Usage Report Settings penceresindeki iki seçeneği isteğinize göre
seçebilirsiniz.
- Son aşamada yapõlacak olan kurulumun özeti görüntülenir. Install seçeneğine tõklayarak
kuruluma başlayõn.

I.c. SQL SERVER 2005 Hotfix Kurulumu

- Bu kurulumdan önce SQL Server 2005 – Service Pack 1’in yüklenmesi sağlõklõ olacaktõr.
http://go.microsoft.com/fwlink/?LinkId=65988 adresinden SQL Server 2005 – Service Pack 1
‘i yükleyin ve kurulumu yapõn.
- Hotfix kurulumu için öncelikle SQL Server Configuration Manager’i açõn ve SQL Server
2005 Services’in altõndaki SQL Server Browser’õ Stop seçeneğinden durdurunuz.
- Team Foundation Server DVD'si içerisindeki SQLServerKB klasörünü açõn ve AS2005-
KB914595-x86-ENU.exe isimli hotfix installer dosyasõnõ çalõştõrõn. (Eğer 64 bit sistem
üzerinde çalõşõyorsanõz diğer dosyalardan uygun olanõnõ seçin)
- Kurulum bittikten sonra SQL Server Configuration Manager’da SQL Server Browser’õ
Automatic konumda ve çalõşõr durumda olduğunu kontrol edin. Çalõşmõyorsa çalõşõr hale
getirmeniz gerekmektedir.
- SQL Server 2005 Network Configuration’da Protocols for MSSQLServer’a tõklayarak
TCP/IP‘nin enabled olduğuna emin olun.

I.d. .NET Framework 2.0 Hotfix Kurulumu

- Team Foundation Server DVD’sinden KB913393 dizinindeki NDP20-KB913393-X86.exe


dosyasõnõ çalõştõrõnõz. Bu şekilde .NET Framework 2.0 Hotfix kurulumunu da tamamlamõş
olacaksõnõz.

I.e. SharePoint Services Kurulumu

- SharePoint Services Service Pack 2 ile kurulumu yapmak için


http://go.microsoft.com/fwlink/?linkid=55087 adresindeki dosyayõ indiriniz.
- Kurulum dosyasõnõ çalõşõtõrõnõz ve Type of Installation sayfasõnda Server Farm seçeneğini
seçiniz. Summary ekranõndan Install seçeneğine tõklayarak kurulumu başlatõnõz.
- Kurulum tamamlandõğõnda Configure Administrative Virtual Server başlõğõnda bir web
sayfasõ açõlacaktõr. Bu pencere çõktõğõnda üzerinde hiçbir değişiklik yapmadan kapatõnõz. (Bu

156
sayfa üzerinde hiçbir ayar değişikliliğinin yapõlmamasõ gerekmektedir. SharePoint üzerindeki
gerekli ayarlarõ daha sonradan Team Foundation Server yapacaktõr. Bu sayfanõn açõlmamasõ
durumunda http://go.microsoft.com/fwlink/?LinkId=52668 adresini ziyaret ederek sorunun
olasõ sebebini ve çözümünü araştõrõnõz.)

Team Foundation Server kurulumuna geçmeden önce yapõlan kurulumlar ile ilgili güncelleme
işlemlerinin yapõlabilmesi için Windows Update sitesini ziyaret ediniz ve varsa gerekli
güncelleme işlemlerini yapõnõz. (Adres: http://windowsupdate.microsoft.com)

I.f. Team Foundation Server Kurulumu

- TFS kurulan sisteme TFSSETUP ile login olun.


- TFS kurulum DVD’sini takõnõz ve açõlan autorun ekranõndan Install Team Foundation
Server ve daha sonra da Single-Server Installation seçeneğini seçin.
- Welcome ekranõnda Next’i, sonraki ekrandan I accept the terms of.... seçeneğini seçerek
Next seçeneğine tõklayõn.
- Kurulum bilgisayarõnõzõn donanõmsal ve yazõlõmsal gereksinimlerini kontrol edip eğer sorun
varsa size bildirecektir. Sorun olmamasõ durumunda Next’e tõklayarak devam edin.
- Destination Folder ekranõnda görünen klasörü değiştirmeyin ve Next’i seçin.
- Service Account penceresinde domain\TFSSERVICE ile login olun.
- Reporting Account sayfasõnda domain\TFSREPORTS ile login olun.
- SMTP ve e-posta bilgilerini doldurunuz ve Next’i seçerek kurulum ekranõna geçiniz.
- Install’a tõklayarak kuruluma başlayõnõz.
- Kurulum boyunca TFS sizden bilgisayarõnõzõ yeniden başlatmanõzõ isteyebilir. Böyle bir
durumda bilgisayarõnõzõ yeniden başlatõnõz. Sisteme TFSSETUP ile login olmayõ
unutmayõnõz! TFS kuruluma kaldõğõ yerden devam edecektir.

I.g. Team Foundation Server Kurulumundan Sonra Yapõlacak İşlemler

- Kurulum tamamlandõktan sonra All Programs > Microsoft SQL Server > Configuration
Tools kõsmõndan Reporting Services Configuration’õ açõnõz. TFS’in kurulu olduğu
makinanõn adõnõ (yani bulunduğunuz makina) ve database instance adõnõ yazõn. (Bu isimlerin
otomatik olarak gelmesi gerekiyor)
- Sol kõsõmdaki butonlardan Encryption Keys seçeneğine tõklayõnõz. Gelen ekrandan
Backup’a tõklayõnõz. Çõkan ekrana bir şifre ile şifrenin tutulacağõ dosyanõn kaydedileceği yeri
ve dosya adõnõ belirleyiniz. (Bu işlem Reporting Services Encryption Key’in yedeklenmesi
amacõyla yapõlmaktadõr. Zorunlu bir işlem değildir.)
- Internet Explorer’da adres kõsmõna
http://localhost:8080/services/v1.0/Registration.asmx adresini yazõn ve açõlan sayfadan
GetRegistrationEntries linkine tõklayõn. Açõlan sayfadaki Invoke butonuna tõklayõnõz. (Metin
kutusuna herhangi bir değer girmenize gerek yok.) Karşõnõza gelen XML metinde
<Type>vstfs</Type> şeklinde bir kõsõm var ise herhangi problem yok demektir.

II. Team Explorer Kurulumu

157
Team Foundation Server'a bağlanarak proje içerisinde çalõşabilmek için farklõ yazõlõmlar
kullanõlabilir. Yazõlõm geliştirici veya programcõ olarak TFS üzerindeki projelerle çalõşabilmek
için Visual Studio 2005'i kullanmamõz gerekecektir. Bu kõsõmda da Visual Studio 2005 ile TFS
sunucusuna bağlanabilmek için gerekli olan Team Explorer'õn kurulumunu göreceğiz. Bu
kurulum TFS'e bağlanacak bilgisayarlara yapõlacaktõr. TFS kurulu olan makinada da Visual
Studio 2005 kullanõlacaksa, aynõ şekilde bu makinaya da kurulumu gerçekleştirebiliriz.
Kurulum için şu adõmlarõ takip etmemiz gerekecektir:

- Microsoft Office Excel 2003'ü Complete Install seçeneğini seçerek kurunuz.


- Microsoft Office Project Professional 2003'ü Complete Install seçeneğini seçerek
kurunuz.
- Windows Update sitesini ziyaret ederek gerekli güncellemeleri yükleyin. (Adres:
http://windowsupdate.microsoft.com)
- Office Update sitesini ziyaret ederek gerekli güncellemeleri yükleyin.
(http://office.microsoft.com/officeupdate)
- Control Panel > Add/Remove Programs > Add/Remove Windows Components
seçeneğinden Internet Explorer Enhanced Security Configuration (Internet Explorer
Arttõrõlmõş Güvenlik Yapõlandõrõlmasõ) seçeneği eğer seçili ise seçimi Next’i seçin ve bu
işlemi tamamlayõn.
- Team Foundation Server kurulum DVD’sini Team Explorer kurulacak olan bilgisayara
takõn ve çalõşan autorun ekranõndan Install Team Explorer’õ seçin. Setup Wizard’da gerekli
seçenekleri seçip Next ile ilerleyerek kurulumu tamamlayõnõz.

III. Visual Studio 2005’ten TFS'a Bağlanma Ve Takõm Projesi


Oluşturma

III.a. Visual Studio 2005'ten Team Foundation Server’a Bağlanma

Team Explorer kurulumunu yaptõktan sonra, Visual Studio 2005’te TFS sunucusuna
bağlanabilmek için Tools menüsünden Connect to Team Foundation Server seçeneğine
tõklayõn. Açõlan pencereden Servers butonuna tõklayõn. Açõlan pencereden Add butonuna
tõklayõn ve Team Foundation Server Name kõsmõnda bağlanacağõnõz sunucunun adõnõ veya
IP numarasõnõ girin. Daha sonra Close butonuna tõklayõn ve OK seçeneğini seçin. (Listede
bağlanabileceğiniz proje var ise bu projeyi seçerek OK butonuna tõklayabilir ve projeye
bağlanabilirsiniz) Bağlanma esnasõnda sizden TFS sunucusuna bağlanma yetkisi olan
kullanõcõ adõ ve şifresi istenecektir. Sunucuda bulunan ve TFS’e bağlanma yetkisi olan bir
kullanõcõ hesabõnõ kullanmanõz gerekmektedir. Bu şekilde TFS sunucuna bağlanabilir ve
yetkileriniz çerçevesinde bir projeye dahil olabilir veya yeni bir proje oluşturabilirsiniz.

III.b. Takõm Projesi Oluşturma

Visual Studio 2005’te yeni bir takõm projesi oluşturmak için File > New > Team Project’i
seçin ve açõlan pencereden bağlanacağõnõz TFS sunucusunu seçin. Gelen ekranda
oluşturulacak projenin adõnõ belirterek ve sonraki aşamada projenizde kullanacağõnõz şablonu

158
seçin. MSF for Agile ve MSF for CMMI şablonlarõndan birini seçebilir veya kendi
oluşturduğunuz proje şablonlarõnõ kullanabilirsiniz. MSF for CMMI, CMMI proje süreçlerini
takip edebilmek için kullanõlabilecek bir şablon olduğu için küçük ve orta büyüklüklerdeki
projelerde pek tercih edilmez. MSF for Agile veya kendi oluşturduğunuz proje şablonlarõ
yeterli olacaktõr. Proje şablonu seçildikten sonra. sõradaki ekranda eğer proje ile ilgili
açõklamalar varsa yazõn ve Next’i tõklayõn. Projenin kaynak kodlarõnõn tutulacağõ yeri seçin.
Ekrana, oluşturacağõnõz proje ile ilgili bilgiler getirilir. Son kõsõmda Finish’e tõklayarak projeyi
oluşturun.

159

You might also like