You are on page 1of 2713

Oldies

Goldies
Gemi Makaleler

Burak Selim enyurt


Table of Contents
WF 4.0 - WCF Servislerini Kullanmak ( 01.04.2009 ) - WF 4.0 .................................................................................... 9
Windows Workflow Foundation 4.0 - lk zlenimler ( 26.03.2009 ) - WF 4.0 ...........................................................23
SQL Persistence Hizmeti ( 06.03.2009 ) - WWF .......................................................................................................37
Mesaj Szlemeleri(Message Contracts) ( 09.02.2009 ) - WCF ...............................................................................54
Ado.Net Data Services Ders Notlar - 7 (Security) ( 02.02.2009 ) - WCF ..................................................................75
Dayankl WCF Servisleri(Custom Persistence Providers) ( 23.01.2009 ) - WCF.......................................................91
Dayankl WCF Servisleri (Durable WCF Services) ( 16.01.2009 ) - WCF ................................................................108
Ado.Net Senkronizasyon Servisleri(Sync Services for Ado.Net) ( 03.01.2009 ) - Ado.Net .....................................124
Client Application Services (stemci Uygulama Servisleri) ( 16.12.2008 ) - Web Services .....................................141
Ado.Net Data Services Ders Notlar - 6 (Optimistic Concurrency) ( 30.10.2008 ) - WCF .......................................157
Ado.Net Data Services Ders Notlar - 5 (Custom LINQ Provider-CUD) ( 24.10.2008 ) - WCF .................................168
Ado.Net Data Services Ders Notlar - 4 (CUD Operasyonlar) ( 16.10.2008 ) - WCF ..............................................182
Ado.Net Data Services Ders Notlar - 3 (stemci Gelitirmek) ( 06.10.2008 ) - WCF ..............................................195
Ado.Net Data Services Ders Notlar - 2 (Custom LINQ Providers) ( 24.09.2008 ) - WCF ........................................206
Ado.Net Data Services Ders Notlar - 1 (Merhaba) ( 22.09.2008 ) - WCF ..............................................................220
WPF Temeller : Layout Kavram ( 11.08.2008 ) - WPF ...........................................................................................239
Seriletirme lemlerinde Vekil(Surrogate) Kullanmak ( 03.07.2008 ) - WCF ........................................................250
Seriletirme lemlerinde Versiyonlama(Versioning) Vakalar ( 22.06.2008 ) - WCF .............................................267
WCF Seriletirme(Serialization) ( 16.06.2008 ) - WCF ............................................................................................283
ServiceHost Snfndan Geniletmek ( 05.06.2008 ) - WCF ....................................................................................299
WCF - P2P(Peer-to-peer) Programlamaya Giri ( 25.05.2008 ) - WCF ...................................................................318
WCF - Performans ( 20.05.2008 ) - WCF ................................................................................................................331
WCF ile WF Entegrasyonu - 2 ( 23.04.2008 ) - WCF ...............................................................................................342
WCF ile WF Entegrasyonu - 1 ( 17.04.2008 ) - WCF ...............................................................................................357
LINQ Maceralarm ( 10.04.2008 ) - C# 3.0 ..............................................................................................................371
C# 3.0 : Derinlemesine Lambda fadeleri ( 31.03.2008 ) - C# 3.0 ...........................................................................385
C# 3.0: Derinlemesine Extension Method Kavram ( 21.03.2008 ) - C# 3.0 ...........................................................404
WCF - Visual Studio 2008 ile Gelen Yenilikler ( 14.03.2008 ) - WCF ......................................................................418
Kod Tarafndan Ynetmek ( 07.03.2008 ) - WCF ....................................................................................................435
AJAX ve JSON Destei ( 25.02.2008 ) - WCF ...........................................................................................................449
Web Bazl Programlama Modeli ( 14.02.2008 ) - WCF...........................................................................................469
Mesaj Szlemeleri(Message Contracts) ( 09.02.2008 ) - WCF .............................................................................484
RSS, Atom Formatl erik Paylam(Syndication) ( 08.02.2008 ) - WCF................................................................505

www.bsenyurt.com Page 1
Front-End Service Gelitirmek ( 30.01.2008 ) - WCF ..............................................................................................523
Adm Adm State Machine Workflow Gelitirmek ( 15.01.2008 ) - WWF ..............................................................538
WWF : alma Zaman Motoru, Singleton ve Factory Desenleri ( 04.01.2008 ) - WWF .......................................562
lk Bakta Windows Workflow Foundation ( 01.01.2008 ) - WWF........................................................................575
Linq To Sql : Arka Planda Neler Oluyor? ( 19.12.2007 ) - LINQ ..............................................................................596
LINQ to SQL ile CRUD lemleri ( 15.12.2007 ) - LINQ ............................................................................................621
Nasl Yaplr? Adm Adm zel HttpHandler ( 10.12.2007 ) - Asp.Net 2 .................................................................637
.Net Remoting Dnyasndan WCF'e Gemek ( 03.12.2007 ) - WCF .......................................................................655
WCF - MTOM ve Stream Kullanarak Veri Aktarm ( 26.11.2007 ) - WCF ..............................................................672
WCF - MSMQ(MicroSoft Message Queue) ile Entegrasyon ( 13.11.2007 ) - WCF .................................................690
WCF - Replay Attack Etkisini Hafifletmek ( 07.11.2007 ) - WCF .............................................................................705
WCF - Gvenilir Oturumlar(Reliable Sessions) ( 01.11.2007 ) - WCF .....................................................................720
WCF - Windows CardSpace ile Gvenlik ( 25.10.2007 ) - WCF ..............................................................................742
Daha Etkili Profil(Profile) Ynetimi ( 17.10.2007 ) - Asp.Net 2.0 ...........................................................................760
WPF - Sayfa(Page) Kavram, Navigasyon lemleri ve XBAP ( 04.10.2007 ) - WPF .................................................789
WPF - Temel Animasyon lemleri - 2 ( 01.10.2007 ) - WPF...................................................................................812
WPF - Temel Animasyon lemleri ( 26.09.2007 ) - WPF ........................................................................................835
WPF - Grafik lemlerinde ekillerin(Shapes) Kullanm ( 18.09.2007 ) - WPF .......................................................849
WPF - Grafik lemlerinde Fralarn(Brushes) Kullanm ( 11.09.2007 ) - WPF......................................................866
WPF - Veriye Balanmak (Data Binding) ( 03.09.2007 ) - WPF ..............................................................................880
WPF-Uygulama Nesnesi (Application Object) ( 30.08.2007 ) - WPF ......................................................................898
WCF - Client Callback (stemci Tarafl Geri Bildirim) ( 23.08.2007 ) - WCF ............................................................916
Asp.Net Temelleri : Derinlemesine Download/Upload lemleri ( 15.08.2007 ) - Asp.Net 2 .................................932
Asp.Net 2.0 URL Rewriting Hakknda Gerekler ( 07.08.2007 ) - Asp.Net 2 ..........................................................949
Asp.Net Temelleri : Etkili Trace Kullanm ( 02.08.2007 ) - Asp.Net .......................................................................961
Asp.Net Temelleri : Tablo Bazl Resimleri Ele Almak ( 26.07.2007 ) - Asp.Net ......................................................982
Asp.Net Temelleri - Etkin Hata Ynetimi (Error Management) ( 18.07.2007 ) - Asp.Net ......................................994
WCF - Windows Tabanl Dorulama ve Yetkilendirme ( 12.07.2007 ) - WCF ......................................................1006
WCF - Internet zerinden Gvenlii Salamak - 2 ( 05.07.2007 ) - WCF .............................................................1018
WCF - Internet zerinden Gvenlii Salamak - 1 ( 03.07.2007 ) - WCF .............................................................1030
WCF - Transaction Yonetimi (Transaction Management) - 2 ( 28.06.2007 ) - WCF .............................................1042
WCF - Transaction Yonetimi (Transaction Management) - 1 ( 19.06.2007 ) - WCF .............................................1056
WCF - Istemci Tarafl Asenkron arma (Client Side Asynchronous Invoking) ( 13.06.2007 ) - WCF .................1062
C# Temelleri - Olaylar(Events) Kavramak ( 06.06.2007 ) - C# 2.0........................................................................1073

www.bsenyurt.com Page 2
WCF - One Way Ticket ( 31.05.2007 ) - WCF ........................................................................................................1085
WCF - InstanceContextMode ( 24.05.2007 ) - WCF .............................................................................................1095
WCF - Mesaj Seviyesinde Gvenlik ( 16.05.2007 ) - WCF ....................................................................................1106
WCF - Hata Ynetimi (Fault Management) ( 09.05.2007 ) - WCF ........................................................................1118
WCF-Windows ve Windows Service Hosting ( 04.05.2007 ) - WCF .....................................................................1131
WCF - Adm Adm IIS Hosting ( 28.04.2007 ) - WCF .............................................................................................1142
Kendi Web Part Bilesenlerimizi Gelistirmek - 2 ( 20.04.2007 ) - Asp.Net 2 .........................................................1157
C# Temelleri : Nitelikleri(Attributes) Kavramak ( 11.04.2007 ) - C# .....................................................................1168
Balantsz Katmanda LINQ ( 02.04.2007 ) - C# 3.0 ..............................................................................................1180
Kendi Web Part Bileenlerimizi Gelitirmek ( 28.03.2007 ) - Asp.Net 2 ..............................................................1190
WPF, Xaml, Baml ve Dahas ( 21.03.2007 ) - WPF ................................................................................................1201
Profesyonelce Master Pages ( 13.03.2007 ) - Asp.Net 2 ......................................................................................1212
.Net Tarafnda Xml ile Oynamak-2 ( 08.03.2007 ) - Xml.......................................................................................1227
.Net Tarafnda Xml ile Oynamak-1 ( 28.02.2007 ) - Xml.......................................................................................1243
LINQ: Daha Fazla Sorgu ( 21.02.2007 ) - C# 3.0....................................................................................................1254
lk Bakta WCF ( 14.02.2007 ) - WCF ...................................................................................................................1267
Web Server Control Yazmak - 3 ( 05.02.2007 ) - Asp.Net 2 .................................................................................1281
Web Server Control Yazmak - 2 ( 23.01.2007 ) - Asp.Net 2 .................................................................................1290
Web Server Control Yazmak - 1 ( 17.01.2007 ) - Asp.Net 2 .................................................................................1301
Web Servislerinde SoapHeader ile zelletirilmi Dorulama ( 10.01.2007 ) - Web Service ..............................1309
Nasl Yaplr : zelletirilmi SiteMapProvider Yazmak ( 29.12.2006 ) - Asp.Net 2..............................................1318
Nasl Yaplr : Connected(Bal) Web Parts ( 26.12.2006 ) - Asp.Net 2 ................................................................1327
Asp.Net 2.0 ve Client Script Callback ( 17.12.2006 ) - Asp.Net 2 .........................................................................1337
HTTPHandler ve HttpModule Kavramlar ( 08.12.2006 ) - Asp.Net .....................................................................1343
Asp.Net 2.0 Temelleri : Bir Web Sayfasnn Anatomisi ( 30.11.2006 ) - Asp.Net .................................................1357
Kullanc Web Kontrollerini Daha Etkin Kullanmak ( 21.11.2006 ) - Asp.Net .......................................................1370
SqlCommandBuilder iin 4 Tavsiye ( 13.11.2006 ) - Ado.Net ..............................................................................1383
C# Temelleri : Enum Sabitinin Bilinmeyen Ynleri ( 30.10.2006 ) - C# ................................................................1394
C# 3.0 - lk Bakta XLINQ ( 22.10.2006 ) - C# 3.0 .................................................................................................1407
C# Temelleri: 1!=1 Eitsizliinden GetHashCode' a Uzun nce Bir Yol ( 11.10.2006 ) - C# ...................................1416
C# Temelleri : Referans Tipi Olmak ( 02.10.2006 ) - C#........................................................................................1426
C# 3.0 - lk Bakta DLINQ ( 25.09.2006 ) - C# 3.0.................................................................................................1437
C# Temelleri : Static Olmak ( 14.09.2006 ) - C# 2.0 ..............................................................................................1444
XML Verilerini XSD ile Ynetimli Kod zerinden Dorulamak ( 01.09.2006 ) - Xml .............................................1454

www.bsenyurt.com Page 3
lk Bakta .Net Resource Ynetimi ( 19.08.2006 ) - C# 2.0 ..................................................................................1462
Cross-Page Postback Paradigmas ( 04.08.2006 ) - Asp.Net 2..............................................................................1468
Xml Web Servislerinde Etkili Caching Kullanm ( 28.07.2006 ) - Web Servisleri .................................................1480
Asp.Net 2.0 zerinde Xslt Kullanm ( 20.07.2006 ) - Asp.Net 2 ..........................................................................1485
Byk Nesneler(Large Objects) ile almak ( 11.07.2006 ) - Ado.Net 2 .............................................................1497
lk Bakta .Net Process Ynetimi ( 07.07.2006 ) - Framework ............................................................................1505
Asp.Net 2.0 ile Configuration Management (Konfigurasyon Ynetimi) ( 26.06.2006 ) - Asp.Net 2 ....................1513
.Net Remoting - SoapSuds ( 21.06.2006 ) - Remoting..........................................................................................1527
Profile API ile Personalization ( 02.06.2006 ) - Asp.Net 2 ....................................................................................1539
Native Web Services ( 22.05.2006 ) - Sql 2005 ....................................................................................................1547
Custom Serialization ( 14.05.2006 ) - C# 2.0 ........................................................................................................1554
Data Access Application Block Nedir? (.Net 2.0 iin) ( 05.05.2006 ) - EA ............................................................1565
Sql 2005 XML Veri Tipini XSD ile Dorulamak ( 21.04.2006 ) - Sql 2005 ..............................................................1573
Server Side SponsorShip ( 19.04.2006 ) - Remoting ............................................................................................1579
Client Side SponshorShip ( 12.04.2006 ) - Remoting ...........................................................................................1588
.Net Remoting - Lease Time (Kiralk Sre) Ynetimi ( 06.04.2006 ) - Remoting ..................................................1595
.Net Remoting - Synchronous, Asynchronous, OneWay ( 31.03.2006 ) - Remoting............................................1601
.Net Remoting ve Event Mimarisi ( 26.03.2006 ) - Remoting ..............................................................................1610
.Net Remoting ve Factory Design Pattern ( 18.03.2006 ) - Remoting ..................................................................1618
Web Servisleri in Drt Pf Nokta ( 14.03.2006 ) - Web Servis ..........................................................................1626
XPath ve .Net ( 04.03.2006 ) - Xml .......................................................................................................................1633
Connection Pooling' in nemi ( 27.02.2006 ) - Ado.Net 2 ...................................................................................1640
Mobil Uygulamalarda Http zerinden Download ve Upload ( 21.02.2006 ) - Mobile.Net..................................1648
Sabit Deer Tipleri (Immutable Value Types) Analizi ( 08.02.2006 ) - C# ............................................................1653
Seriletirme (Serialization) in Pf Noktalar ( 02.02.2006 ) - C# .........................................................................1660
Compact Framework zerinde RDA ile Senkronizasyon ( 24.01.2006 ) - Mobile ................................................1672
Web Uygulamalarnda zel Dorulama lemleri ( 14.01.2006 ) - Asp.Net .........................................................1681
Windows Uygulamalarnda Daha Kolay Thread Ynetimi ( 05.01.2006 ) - .Net 2.0 ............................................1689
Generic Mimaride Kstlamalarn(Costraints) Kullanm ( 31.12.2005 ) - C# 2.0 ..................................................1694
C# 2.0 ile Generic Delegates ( 21.11.2005 ) - C# 2.0 ............................................................................................1706
Kendi Referans Tiplerimizi Klonlamak ( 14.11.2005 ) - C# 2.0 .............................................................................1712
Ado.Net 2.0(Beta 2) - Connection String Security (Balant Katar iin Gvenlik) ( 17.10.2005 ) - Ado.Net 2.....1719
Constructor Initializers (Yapc Metod Balatclar) Deyip Gemeyin ( 03.10.2005 ) - C# ...................................1725
Boxing ve Unboxing Performans Kritii ( 26.09.2005 ) - C# .................................................................................1732

www.bsenyurt.com Page 4
Using fadesi ile Garanti Dispose ( 20.09.2005 ) - C# ...........................................................................................1740
CallBack Teknii ile Asenkron Metod Yrtmek ( 09.09.2005 ) - C# ....................................................................1749
Web Uygulamalarnda Custom Paging ( 03.09.2005 ) - Asp.Net .........................................................................1756
Numaralandrclar Kullanmak in Bir Sebep ( 28.08.2005 ) - C# ..........................................1762
SortedList ve Hashtable in 2 Basit neri ( 06.08.2005 ) - C# .............................................................................1774
Tip Gvenli (Type Safety ) Koleksiyonlar Oluturmak - 2 ( 31.07.2005 ) - C#.......................................................1780
Tip Gvenli (Type Safety ) Koleksiyonlar Oluturmak - 1 ( 23.07.2005 ) - C#.......................................................1786
Dizilere(Arrays) likin Basit neri ( 14.07.2005 ) - C# ....................................................................................1794
C# 2.0 in terasyon Yenilikleri ( 05.07.2005 ) - C# 2 ...........................................................................................1801
C# 2.0 Covariance ve Contravariance Delegates ( 30.06.2005 ) - C# 2 ................................................................1810
C# 2.0 ile Partial Types (Ksmi Tipler) ( 27.06.2005 ) - C# 2 ..................................................................................1817
C# 2.0 ve Nullable Deer Tipleri ( 22.06.2005 ) - C# 2 .........................................................................................1826
C# 2.0 ve Static Snflar ( 20.06.2005 ) - C# 2 .......................................................................................................1835
C# 2.0 ve Anonymous (simsiz) Metodlar ( 16.06.2005 ) - C# 2 ...........................................................................1845
Operator Overloading (Operatrlerin Ar Yklenmesi) ( 03.06.2005 ) - C# .......................................................1850
Kendi stina Nesnelerimizi Kullanmak (ApplicationException) ( 23.05.2005 ) - C# ..............................................1863
Ado.Net 2.0 ve Data Provider-Independent Mimari ( 24.04.2005 ) - Ado.Net 2 .................................................1873
Ado.Net 2.0' da Transaction Kavram ( 17.04.2005 ) - Ado.Net 2 ........................................................................1886
DataReader Nesnelerini Kullanrken ( 04.04.2005 ) - Ado.Net ............................................................................1895
Command Nesnelerine Dikkat! ( 27.03.2005 ) - Ado.Net ....................................................................................1904
Self Referencing Relations ve Recursive(Yinelemeli) Metodlar ( 14.03.2005 ) - Ado.Net ...................................1909
Balantsz Katmanda Concurrency Violation Durumu ( 06.03.2005 ) - Ado.Net ................................................1914
RijndaelManaged Vastasyla Encryption(ifreleme) ve Decryption(Deifre) ( 23.02.2005 ) - Framework .........1924
Caching Mekanizmasn Anlamak - 2 ( 07.02.2005 ) - Asp.Net ............................................................................1932
Caching Mekanizmasn Anlamak - 1 ( 21.01.2005 ) - Asp.Net ............................................................................1942
Derinlemesine Session Kullanm - 2 ( 08.01.2005 ) - Asp.Net .............................................................................1948
Derinlemesine Session Kullanm - 1 ( 31.12.2004 ) - Asp.Net .............................................................................1959
Ado.Net ile Sql Server Full-Text Searching (Tm Metinde Arama) Kullanm ( 18.12.2004 ) - Ado.Net ..............1967
Oyun Programlamaya Giri (Matrisler Yardmyla arpma Kontrol) ( 04.12.2004 ) - C# .................................1978
Oyun Programlamaya Giri (arpma Teknikleri - 3) ( 19.11.2004 ) - C# ............................................................1988
Oyun Programlamaya Giri (arpma Teknikleri - 2) ( 12.11.2004 ) - C# ............................................................1997
Oyun Programlamaya Giri (arpma Teknikleri - 1) ( 06.11.2004 ) - C# ............................................................2002
Ado.Net 2.0 ve SqlDependency Snf Yardmyla Query Notification ( 26.10.2004 ) - Ado.Net 2 .......................2009
Ado.Net 2.0 ve Sql Komutlarn Asenkron Olarak Yrtmek - 3 ( 22.10.2004 ) - Ado.Net 2 ................................2015

www.bsenyurt.com Page 5
Xml Web Servisleri - 5 (Mimarinin Temelleri - DISCO) ( 07.10.2004 ) - Web Servis.............................................2020
Xml Web Servisleri - 4 ( Mimarinin Temelleri - WSDL) ( 02.10.2004 ) - Web Servis ............................................2024
Xml Web Servisleri - 3 ( Mimarinin Temelleri - SOAP) ( 01.10.2004 ) - Web Servis .............................................2039
Xml Web Servislerine Giri - 2 ( 30.09.2004 ) - Web Servis..................................................................................2049
Xml Web Servislerine Giri - 1 ( 29.09.2004 ) - Web Servis..................................................................................2057
Ado.Net 2.0 ve Sql Komutlarn Asenkron Olarak Yrtmek - 2 ( 25.09.2004 ) - Ado.Net 2 ................................2067
Ado.Net 2.0 ve Sql Komutlarn Asenkron Olarak Yrtmek - 1 ( 23.09.2004 ) - Ado.Net 2 ................................2071
Ado.Net 2.0 ile Mars' a Ayak Basyoruz ( 20.09.2004 ) - Ado.Net 2 .....................................................................2079
Ado.Net 2.0 ve Toplu Gncelleme lemleri (Batch-Updates) ( 18.09.2004 ) - Ado.Net 2...................................2086
Ado.Net 2.0 ve Bulk-Data Kopyalama Mekanizmas ( 17.09.2004 ) - Ado.Net 2 .................................................2091
Asp.Net 2.0 ve ObjectDataSource Kontrol ( 14.09.2004 ) - Asp.Net 2 ...............................................................2103
Asp.Net 2.0 ve Master Page Kavram ( 10.09.2004 ) - Asp.Net 2.........................................................................2110
Asp.Net 2.0 DetailsView Kontrol ile Insert,Update,Delete ( 08.09.2004 ) - Asp.Net 2 ......................................2119
Asp.Net 2.0 GridView Kontrolnde Update,Delete lemleri ( 07.09.2004 ) - Asp.Net 2 ....................................2125
Asp.Net 2.0 ve TreeView Kontrol ( 06.09.2004 ) - Asp.Net 2 .............................................................................2134
Asp.Net 2.0 ve Temalar (Themes) ( 03.09.2004 ) - Asp.Net 2 ..............................................................................2141
Asp.Net 2.0 iin Site Map Kullanm ( 03.09.2004 ) - Asp.Net 2 ...........................................................................2148
Asp.Net 2.0 ile Veri Kmelerinde Sayfalama lemleri ( 01.09.2004 ) - Asp.Net 2...............................................2154
Asp.Net 2.0 ve Code Klasr ( 01.09.2004 ) - Asp.Net 2 ......................................................................................2158
Asp.Net 2.0 ile Cross-Page Posting ( 31.08.2004 ) - Asp.Net 2 .................................................2164
Localization (Yerelletirme) 2 - Dil Destei ( 07.08.2004 ) - C# ............................................................................2170
Localization (Yerelletirme) - 1 ( 05.08.2004 ) - C# ..............................................................................................2176
Identity Deerlerinin alma Zamannda Elde Edilmesi ( 29.07.2004 ) - Ado.Net ..............................................2183
CurrencyManager ile Navigasyon ve Temel Satr lemleri ( 27.07.2004 ) - Ado.Net ..........................................2190
NET Remoting' i Kavramak - 3 ( 22.07.2004 ) - Remoting ....................................................................................2196
Transaction' larda DeadLock Kavram ( 07.07.2004 ) - Ado.Net ..........................................................................2202
NET Remoting' i Kavramak - 2 ( 03.07.2004 ) - Remoting ....................................................................................2207
Transaction' larda Izolasyon Seviyeleri -2 (IsolationLevel Numaralandrcs) ( 28.06.2004 ) - Ado.Net .............2213
Transaction' larda Izolasyon Seviyeleri (Isolation Level) - 1 ( 19.06.2004 ) - Ado.Net .........................................2224
Transaction' larda SavePoint Kullanm ( 15.06.2004 ) - Ado.Net ........................................................................2231
XML Rapor Web Servisleri ( 10.06.2004 ) - Web Servis .......................................................................................2238
.NET Remoting'i Kavramak ( 22.05.2004 ) - Remoting .........................................................................................2243
Windows Servislerinin Kontrol - 2 ( Sistemdeki Servislerin Kontrol Edilmesi ) ( 12.05.2004 ) - Win Servis.......2249
Windows Servislerinin Kontrol -1 ( 05.05.2004 ) - Win Servis ...........................................................................2258

www.bsenyurt.com Page 6
Windows Servislerine Giri ( 29.04.2004 ) - Win Servis .......................................................................................2269
Single File Assembly ve Multiple-File Assembly Kavramlar ( 27.04.2004 ) - Framework....................................2281
Private Assembly ve Shared Assembly Kavram ( 22.04.2004 ) - Framework ......................................................2292
likiler ve Hesaplanm Alanlarn Bir Arada Kulllanlmas ( 08.04.2004 ) - Ado.Net ............................................2299
DataRelation Snf ve oa-ok (Many-to-many) likiler ( 01.04.2004 ) - Ado.Net ...........................................2302
DataTable.Compute Metodu ( 29.03.2004 ) - Ado.Net .......................................................................................2311
OleDbDataAdapter Snf Olaylar ( 18.03.2004 ) - Ado.Net .................................................................................2316
OleDbDataAdapter Snf ve Update Metodu. ( 14.03.2004 ) - Ado.Net ..............................................................2327
OleDbDataAdapter Snf - 2 ( 02.03.2004 ) - Ado.Net .........................................................................................2333
DataAdapter Kavram ve OleDbDataAdapter Snfna Giri ( 27.02.2004 ) - Ado.Net..........................................2348
Command Kavram ve OleDbCommand Snf ( 23.02.2004 ) - Ado.Net ..............................................................2362
Batch Queries (Toplu Sorgular) ve SqlDataReader ( 17.02.2004 ) - Ado.Net .......................................................2380
Connection (Balant) Kavram ve OleDbConnection Snf ( 13.02.2004 ) - Ado.Net ..........................................2384
GetOleDbSchemaTable Metodu le Veritabanmzda Ne Var Ne Yok ( 12.02.2004 ) - Ado.Net ..........................2397
Data Form Wizard Yardmyla likili Tablo Uygulamalarnn Hazrlanmas ( 09.02.2004 ) - Ado.Net ..................2402
Strongly Typed DataSet - 2 (Kuvvetle Trlendirilmi Veri Kmeleri) ( 05.02.2004 ) - Ado.Net............................2418
Strongly Typed DataSet - 1 (Kuvvetle Trlendirilmi Veri Kmeleri) ( 04.02.2004 ) - Ado.Net............................2426
Stored Procedureler ve ParameterDirection Numaralandrcs ( 31.01.2004 ) - Ado.Net ..................................2434
Tablo Deiikliklerini GetChanges ile zlemek ( 29.01.2004 ) - Ado.Net ..............................................................2441
Indeksleyiciler (Indexers) ( 27.01.2004 ) - C# .......................................................................................................2447
Sql Tablolarndaki Binary Resimlere Bakmak ve Dosya Olarak Kaydetmek ( 24.01.2004 ) - Ado.Net .................2453
Sql Tablolarna Resim Eklemek ( 23.01.2004 ) - Ado.Net .....................................................................................2458
Net Data Providers(Veri Salayclar) ( 22.01.2004 ) - Ado.Net ..........................................................................2462
Temsilciler (Delegates) Kavramna Giri ( 20.01.2004 ) - C# ................................................................................2465
Checked, Unchecked Anahtar Kelimeleri ve OverFlow Hatas ( 15.01.2004 ) - C# ..............................................2471
Bir Arayz, Bir Snf ve Bir Tablo ( 14.01.2004 ) - C# ............................................................................................2476
Arayzler'de is ve as Anahtar Szcklerinin Kullanm ( 12.01.2004 ) - C# ..........................................................2483
Arayz(Interface), Snf(Class) ve oklu Kaltm ( 09.01.2004 ) - C# .....................................................................2487
Interface (Arayz) Kullanmna Giri ( 08.01.2004 ) - C# ......................................................................................2491
ArrayList Koleksiyonu ve DataGrid ( 07.01.2004 ) - C# ........................................................................................2496
e Yarar Bir MultiThreading(ok Kanall) Uygulama rnei ( 06.01.2004 ) - C# .................................................2504
Thread'lerde ncelik(Priority) Durumlar ( 05.01.2004 ) - C# ..............................................................................2509
Thread'leri Belli Sreler Boyunca Uyutmak ve Yoketmek ( 02.01.2004 ) - C# .....................................................2516
StreamReader Snf Yardmyla Dosya Okumak ( 01.01.2004 ) - Ado.Net ...........................................................2522

www.bsenyurt.com Page 7
ok Kanall(Multithread) Uygulamalar ( 01.01.2004 ) - C# ..................................................................................2525
Boxing (Kutulamak) ve Unboxing (Kutuyu Kaldrmak) ( 30.12.2003 ) - Ado.Net .................................................2530
SqlDataReader Snf 2 ( 29.12.2003 ) - Ado.Net ..................................................................................................2535
SqlDataReader Snf 1 ( 28.12.2003 ) - Ado.Net ..................................................................................................2541
Kaltm (Inheritance) Kavramna Ksa Bir Bak ( 25.12.2003 ) - C# ......................................................................2546
Virtual(Sanal) Metodlar ( 25.12.2003 ) - C# .........................................................................................................2556
Bir Snf Yazalm ( 23.12.2003 ) - C# .....................................................................................................................2560
Reflection Snf le Tiplerin Srr Ortaya kyor ( 22.12.2003 ) - C# .....................................................................2567
Stack ve Queue Koleksiyon Snf ( 19.12.2003 ) - C# ...........................................................................................2578
HashTable Koleksiyon Snf ( 18.12.2003 ) - C# ...................................................................................................2582
DataGrid Denetimi zerinde Sralama(Sorting) lemi ( 17.12.2003 ) - C# ..........................................................2585
DataGrid Denetimi zerinde Sayfalama(Paging) lemi ( 16.12.2003 ) - Ado.Net ...............................................2589
DataView Snf ve Faydalar ( 15.12.2003 ) - Ado.Net ................................................................................2593
SQL_DMO lemleri ( 12.12.2003 ) - Ado.Net .....................................................................................................2599
likili Tablolar DataSet le Kullanmak - 2 ( 10.12.2003 ) - Ado.Net....................................................................2605
likili Tablolar DataSet le Kullanmak - 1 ( 09.12.2003 ) - Ado.Net....................................................................2610
DataColumn.Expression zellii le Hesaplanm Alanlarn Oluturulmas ( 06.12.2003 ) - Ado.Net.................2614
DataTable Snfn Kullanarak Programatik Olarak Tablolar Oluturmak-2 ( 05.12.2003 ) - Ado.Net .................2617
Struct (Yap) Kavram ve Class (Snf) ile Struct (Yap) Arasndaki Farklar ( 04.12.2003 ) - C# .............................2621
DataTable Snfn Kullanarak Programatik Olarak Tablolar Oluturmak-1 ( 04.12.2003 ) - Ado.Net ..................2627
Basit Bir Web Service Uygulamas ( 01.12.2003 ) - Web Servis ...........................................................................2633
Enumerators ( 01.12.2003 ) - C# ..........................................................................................................................2646
DataSet ve WriteXml Metodunun Kullanm ( 30.11.2003 ) - Ado.Net ................................................................2650
Params Anahtar Szcnn Kullanm ( 30.11.2003 ) - C# .................................................................................2653
Bir Form ve Kontrollerinin Elle Programlanmas ( 21.11.2003 ) - C# ..................................................................2659
Distributed Transactions ( 19.11.2003 ) - Ado.Net .............................................................................................2665
Transaction Kavram ( 17.11.2003 ) - Ado.Net ....................................................................................................2678
Overload Metodlarn Gc ( 13.11.2003 ) - C# ...................................................................................................2686
Stored Procedure Yardmyla Tablodan Kayt Silmek ( 12.11.2003 ) - Ado.Net ..................................................2693
Web Sayfalarnda Stored Procedure Kullanm ( 12.11.2003 ) - Asp.Net ............................................................2701
Stored Procedure Yardmyla Yeni Bir Kayt Eklemek ( 08.11.2003 ) - Ado.Net ...................................................2707

www.bsenyurt.com Page 8
WF 4.0 - WCF Servislerini Kullanmak (
01.04.2009 ) - WF 4.0
Deerli Okurlarm Merhabalar,

Bir nceki yazmzda Windows Workflow Foundation 4.0 (WF 4.0) ile birlikte gelmesi
muhtemel(yksek bir olaslkla ok az deiikle gelecekler) kavramlar incelemeye almtk ve
pek ok yeni aktivite tipinin alt yapya dahil edilmi olduunu grdk. WF rnekleri bilindii zere
ou zaman servisler ile haberlemek durumundadr. Bu zellikle gerek hayat senaryolarnda ok
sk karlana ve ihtiya duyulan bir durumdur. Nitekim WF ierisinde yer alan aklarn d
ortamlara olan bir bamll sz konusu olabilir. Bir Bankaclk sisteminde yer alan aklarda,
servisler yardmyla ulalabilen baz operasyonlar bu bamlla rnek gsterilebilir
rnein. WF alt yaps bu anlamda WCF(Windows Communication Foundation) servisleri ile
haberleilebilmesini kolaylatrmak amacyla .Net Framework 3.5 ile birlikte yeni aktivite
bileenlerine sahip olmutur. SendActivity ve ReceiveActivity isimli bu tipler temel olarak
servislere ait operayonlarn arlmas veya WF ierisinde servis bazl operasyonlarn d dnyaya
sunulmasnda etkin olarak kullanlmaktadr. Ancak WF 4.0 ile birlikte servisler ile olan iletiimde
daha yetenekli aktivite tipleri yer almaktadr. zellikle grsel adan gelitiriciye kolaylklar
salayan ama asl etkisini XAML bazl servis tanmlamalarnn yaplabilmesinde gsteren aktiviteler
sz konusudur. Zaten WF ve WCF 4.0 ierisinde XAML tabanl deklerafit tanmlamalarn son
derece etkin bir ekilde kullanld bir gerektir. WF 4.0 asnda bakldnda bir WCF operasyonu
ile salanan istek/cevap(Request/Response)odakl iletiim temel olarak aadaki ekilde
grld gibidir.

Buna gre WF ierisinde herhangibir noktada servis operasyonlarn armak


iin ClientOperation isimli aktivite kullanlmaktadr. Bu operasyonun yer ald WCF servisi bir
veya daha fazla EndPoint zerinden istemcilere hizmet verebilir. WF rnekleri kendi ierisinde,
bu EndPoint' in belirttii Address, Binding ve Contract tipine gre uygun bir mesajlama trafii
balatabilir. Buna gre servis operasyonlar arabilir ve sonularn ele
alabilir. ClientOperation, Workflow Foundation 4.0 ile birlikte gelen yeni aktivite tiplerinden
birisidir. Peki bu yeni tipin .Net Framework 3.5 srm ile gelen ve ayn amala
kullanlan SendActivity tipine gre farkllklar, zellikle avantaklar neler olabilir? te bu
yazmzda ksaca bu sorulara cevap bulmaya alacak ve ayn zamanda bizleri bekleyen yenilikleri
greceiz. Bu nedenle bir rnek zerinden adm adm ilerleyerek devam etememizde yarar olaca
kansndaym.

www.bsenyurt.com Page 9
Senaryomuza gre basit ve herzamanki gibi gerek hayatta kullanlmayacak bir Sequential
Workflow uygulamas gelitireceiz. Akmz yine gelitirici tarafndan tasarlanm zel bir aktivite
tipini kullanarak istemciden iki saysal deer alacaktr. Bu deerler bir servise gnderilerek
ilenecek ve sonular yine ak ierisine ynlendirilerek dier bir zel aktivite tipi yardmyla ekrana
yazdrlacaktr. lk olarak servis uygulamasnn tasarlanmasnda yarar vardr.

Yazmzda gelitirmekte olduumuz rnek henz Relase olmam .Net Framework


4.0 srm zerinde gelitirilmekte ve bu amala Visual Studio 2010' un PDC 2008'
de yaymlanan Virtual PC versiyonu kullanlmaktadr. Dolaysyla yazlan ve ilenen
kavramlarda veya Visual Studio 2010 srmnde kkl deiiklikler olabilir, olmas
muhtemeldir.

CalculusService isimli WCF uygulamamz WCF Service Application tipinde gelitirilmektedir.

Serviste kullanlan szleme ierii ise aadaki kod parasnda grld gibidir.

using System.ServiceModel;

namespace CalculusService
{
[ServiceContract]
public interface IMatService
{
[OperationContract]
double Sum(double x, double y);
}

www.bsenyurt.com Page 10
}

Servis szlemesinde(Service Contract), ok basit olarak double tipinden iki saysal deerin
toplamn alarak geriye sonucunu dndren Sum isimli bir operasyon yer
almaktadr.IMatService isimli servis arayz tipini(Interface) uygulayan snfa ait kod ierii ise
aadaki gibidir.

namespace CalculusService
{
public class MatService
: IMatService
{
public double Sum(double x, double y)
{
return x + y;
}
}
}

Servis zerinde tanmlanm olan operasyonlar basit HTTP protokolne gre sunulmaktadr. Bu
nedenle balayc tip olarak BasicHttpBinding kullanlmaktadr. Servis iin
birdeHTTP zerinden metadata bilgisinin verilebilmesi amacyla MexHttpBinding bazl
bir EndPoint daha sz konusudur.(Geri biraz sonra grebileceimiz gibi, WF rneinin servise ait
birMetadata indirmesine gerek kalmayacaktr :) ) rnek WCF servis
uygulamamza EndPoint ayarlar aadaki Web.config dosyasnn ieriinde olduu gibi
tanmlanabilir.

<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true"></compilation>
<authentication mode="Windows"/>
</system.web>
<system.serviceModel>
<services>
<service behaviorConfiguration="CalculusService.MatServiceBehavior"
name="CalculusService.MatService">
<endpoint address="" binding="basicHttpBinding" bindingConfiguration=""
contract="CalculusService.IMatService">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CalculusService.MatServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>

www.bsenyurt.com Page 11
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

WCF servis uygulamamz test amacyla gelitirildiinden IIS(Internet Information


Services) zerine atlmamtr. Bu nedenle Solution ierisinde yer alan istemci uygulamalar ile
haberlemesi srasndaki gelitirme srecini kolaylatrmak adna, sabit bir HTTP portu kullanmas
salanabilir. Sabit port ayarlamas iin WCF projesinin zelliklerinden(Properties) aadaki
ekran grntsnde olduu gibi Specific Port zelliine bir deer atamak yeterli
olacaktr. (Elbetteki bu WCF uygulamasn, IIS altna atmak kolay bir ekilde zellikler
penceresinde yer alan Use Local IIS Web server seenei ile mmkn olabilir. Yada bu
amala Publish ilemlerinden yararlanlabilir.)

Bu aamada ilerlemeden nce servisin HTTP zerinden arlabildiinden emin olmak gerekir. Bu
amala, MatService.svc dosyasnn bir tarayc ierisinde almas yeterlidir. Eer aadaki ekran
grntsnde yer alan sonular elde edilebiliyorsa WCF servisinin arlabilir olduu sonucuna
varlabilir.

www.bsenyurt.com Page 12
Gelelim WF tarafna. Her zamanki gibi basit
bir Sequential Workflow Console Application zerinden ilerliyor olacaz. Servise gnderilecek
parametreleri ekrandan almak ve yazdrmak iinse bir nceki yaz dizimizdekilere benzer iki basit
aktivite tipi kullanyor olacaz. Console ekranndan bilgi okumak iin kullanlan Read aktivitesine
ait kod ierii aadaki gibi gelitirilebilir.

using System;
using System.WorkflowModel;

namespace CalculusWF
{
public class Read
:WorkflowElement
{
public OutArgument<double> Value1 { get; set; }
public OutArgument<double> Value2 { get; set; }

protected override void Execute(ActivityExecutionContext context)


{
Console.WriteLine("Value 1 ?");
Value1.Set(context, Convert.ToDouble(Console.ReadLine()));
Console.WriteLine("Value 2 ?");
Value2.Set(context, Convert.ToDouble(Console.ReadLine()));
}
}
}

Read aktivitesi grld zere iki adet OutArgument<T> tipinden zellik kullanmakta
ve override ettii Execute metodu ierisinde ekrandan ald deerleri d ortama sunmaktadr.
Yine dikkat edilmesi gereken noktalardan birisi, aktivitenin WF Base Library ierisindeki yeni ata
snf olan WorkflowElement tipinden tremi olmasdr. Write aktivitesideRead aktivitesi
gibi WorkflowElement trevlidir ve WF ieriinden(ActivityExecutionContext yardmyla) gelen
sonu deerini ekrana yazdrmak iin kullanlmaktadr. Writeaktivitesine ait kod ierii aada
grld gibidir.

using System;

www.bsenyurt.com Page 13
using System.WorkflowModel;

namespace CalculusWF
{
class Write
:WorkflowElement
{
public InArgument<double> Result { get; set; }

protected override void Execute(ActivityExecutionContext context)


{
double r=Result.Get(context);
Console.WriteLine("lem sonucu {0} dr",r.ToString());
}
}
}

Workflow ierisinde toplama ilemi iin kullanlacak deerler ile ilem sonucuna tm aktivite
boyunca ulalmas istendiinden aadaki ekran grntsnde yer ald gibi
adet Variable tanmlamas yaplmaktadr. Bu
tanmlamalar Matflow.xaml isimli Sequential Activity tipinin tamam iin geerlidir.

A, B ve Total isimli deikenler double tipinden tanmlanmtr. Bu


deerler Read, Write aktiviteleri ile ClientOperation tarafndan kullanlabilecektir. Bu ilemin
ardndan artk aktivite dizisinin oluturulmasna balanabilir. lk olarak Read aktivitesi srklenir.
Sz konusu aktivitenin zellikleri aadaki gibi ayarlanabilir.

www.bsenyurt.com Page 14
Dikkat edilecei zere Read aktivitesi ierisinde tanmlanm olan Value1 ve Value2 isimli
zelliklere, Sequence aktivitesi ierisinde tanmlanan A ve B deikenleri atanmtr. Bir baka
deyile Read aktivitesi ile komut satrndan okunup set edilen Value1 ve Value2 deerleri dier
aktiviteler tarafndan kolayca ele alnabileceklerdir. Nitekim A ve B isimliglobal deikenleri
tanmaktadrlar. Read ve Write aktiviteleri arasna ClientOperation aktivitesini eklemeden
nce, Write aktivitesi iinde aada grlen zellik ayarlamalarn yapmamz yeterli olacaktr.

Dikkat edilecei zere Write aktivitesi ierisinde tanmlanm olan Result isimli
zellie global deikenlerden Total atanmtr. Artk Write aktivitesi ile okunarak global
seviyedeki A ve B deikenlerine atanan deerleri, kullanlmak zere ele alacak ve toplam
sonucunu Total isimli deikene verecek olan ClientOperation aktivitesini gelitirmeye
balayabiliriz.

www.bsenyurt.com Page 15
ClientOperation aktivitesini Read ve Write aktiviteleri arasna srkleyip braktmzda ilk
etapta aadaki ekran grnts ile karlarz. Dikkat edilecei
zere Operation Contract, Binding ve EndPoint Address isimli 3 nemli zellik gze
arpmaktadr.

Tahmin edilecei zere bu zelliklerin deerleri ile istemci iin gerekli bir EndPoint bilgisi
oluturulabilir. Bir baka deyile bir EndPoint tanmn oluturan adresleme(Address), balayc
tip(Binding Type) ve szleme(Contract) bilgilerinin tamam bu aktivite tipi ierisinde
belirlenmektedir. lk olarak aadaki ekran grntsnde yer alan admlar takip edilerekten servis
szlemesinin(Service Contract) ad girilir.

Visual Studio 2010 rn olarak sunulduunda servis szlemesi gibi ksmlarn elle deil otomatik
olarak girilebilecek ekilde ayarlanabileceini dnmekteyim. imdilik servis tarafndaki szleme
arayz tipinin adn elle(byk kk harf duyarllna da dikkat ederekten) yazmamz
gerekmektedir. Servis szlemesinin belirlenmesi tek bana yeterli
deildir. ClientOperation aktivitesinin bu servis operasyonu zerinde hangi operasyonu

www.bsenyurt.com Page 16
aracannda belirlenmesi gerekmektedir. Burada New ServiceContractdmesi yardmyla
szleme tanmlandnda, baln New OperationContract olarak deitii gzlemlenir. Tahmin
edilecei gibi New OperationContractdmesi ve takip eden admlar ile Sum operasyonuna ait
tanmlamalar grsel olarak yaplabilmektedir. Aynen aadaki ekran grntsnde yer ald gibi.

Burada ok detayl operasyon ayarlamalar yaplabilmektedir. Gvenlik ile ilikili


ilemler(Protection Level), Transaction aktarma opsiyonlar, operasyonun tek ynl(One-
Way)olup olmad, operasyondan dnebilecek Fault tipleri vb... Gelitirdiimiz rnekte sadece
operasyon parametrelerinin girilmesi yeterlidir. x ve y isimli argmanlar, Sum operasyonuna ait
girdi parametreleri olduklarndan Direction zellikleri In olarak belirlenmitir. Dier
taraftan SumResult isimli argman, operasyonun dn deerini iaret etmekte
olduundan,Direction zelliine Out deeri verilmitir. u anda arlacak servis operasyonu ile
ilikili tanmlamalar yaplmtr. Artk bu servis ile hangi balayc tip ve adres ile iletiime
geileceine dair zelliklerin belirlenmesi gerekmektedir. Bu amala aadaki ekran grntsnde
yer alan atamalarn yaplmas yeterlidir.

www.bsenyurt.com Page 17
Unutulmamas gereken noktalardan biriside WCF servisleri ile haberleecek olan istemci
uygulamalarn, servis tarafnda belirtilen EndPoint ieriine uygun EndPoint bildirimlerine sahip
olmas zorunluluudur. Gelitirilen rnekte servis tarafnda BasicHttpBinding tipi kullanldndan
istemci tarafndaki EndPoint iinde ayn tipte bir balaycnn kullanlmas gerekmektedir. Benzer
olarak servis tarafndaki operasyon HTTP bazl olaraktan localhost isimli makineden
ve 49100 nolu port zerinden sunulmaktadr. Bu nedenle istemci tarafndan bu kritere uygun
bir adres iin talepte bulunulmaldr. Dikkat ekici noktalardan biriside adres
ksmnda C# notasyonuna pek uymayan bir ekilde byk harfle balayan bir New anahtar
kelimesi olmasdr. (WF 4.0 ile ilikili yenilikleri rendiim Microsoft LAB dkmanlarnda bu
durumun final srmnde deieceine dair bir bilgi yer almaktadr. Tabi final srmnde bizleri
neler bekliyor neler...) Artk istemci tarafndaki EndPoint iin
gerekli ABC(AddressBindingContract) bilgileri tanmlanm durumdadr.

Yaplmas gereken nemli ilemlerden biriside WF ierisindeki deikenleri ClientOperation ile


servise aktarmak ve servisten dnen deeride tekrardan WF ierisine ynlendirmektir. Bunun
iin ClientOperation elementinin zelliklerinde aadaki ekran grntsnde yer alan
ayarlamalarn yaplmas yeterli olacaktr.

www.bsenyurt.com Page 18
Grld zere SumResult isimli servis operasyon
argman Total isimli WF deikenine, x isimli servis operasyon argman A isimli WF deikenine
ve son olarak y isimli servis operasyonu argman B isimli WF deikenine set edilmitir. te bu
kadar. Grld zere grsel olarak pek ok ayarlama yaplmtr. Sonu
olarakMatFlow.xaml adl Workflow rneimiz iin aadaki XAML(eXtensible Application
Markup Language) ierii retilmektedir.

<p:Activity x:Class="CalculusWF.MatFlow" xmlns:c="clr-


namespace:CalculusWF;assembly=CalculusWF"
xmlns:p="http://schemas.microsoft.com/netfx/2009/xaml/workflowmodel"
xmlns:p1="http://schemas.microsoft.com/netfx/2008/xaml/schema"
xmlns:p2="http://schemas.microsoft.com/netfx/2009/xaml/servicemodel" xmlns:s="clr-
namespace:System;assembly=System" xmlns:swd="clr-
namespace:System.WorkflowModel.Debugger;assembly=System.WorkflowModel"
xmlns:swdx="clr-
namespace:System.WorkflowModel.Design.Xaml;assembly=System.WorkflowModel.Design"
xmlns:sx="clr-namespace:System.Xml;assembly=System.Runtime.Serialization"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<p:Sequence
swd:XamlDebuggerXmlReader.FileName="C:\Orneklerim\CalculusService\CalculusWF\MatFlow.xa
ml">
<p:Sequence.Variables>
<p:Variable x:TypeArguments="p1:Double" Name="A" />
<p:Variable x:TypeArguments="p1:Double" Name="Total" />

www.bsenyurt.com Page 19
<p:Variable x:TypeArguments="p1:Double" Name="B" />
</p:Sequence.Variables>
<c:Read DisplayName="Read Parameters" Value1="[A]" Value2="[B]" />
<p2:ClientOperation EndpointAddress="[New
s:Uri(&quot;http://localhost:49100/MatService.svc&quot;)]" OperationName="Sum">
<p2:ClientOperation.Endpoint>
<p2:Endpoint Name="ClientOperationEndpoint">
<p2:Endpoint.Binding>
<p2:BasicHttpBinding TextEncoding="utf-8">
<p2:BasicHttpBinding.ReaderQuotas>
<sx:XmlDictionaryReaderQuotas />
</p2:BasicHttpBinding.ReaderQuotas>
<p2:BasicHttpBinding.Security>
<p2:BasicHttpSecurity Mode="None">
<p2:BasicHttpSecurity.Message>
<p2:BasicHttpMessageSecurity AlgorithmSuite="Default"
ClientCredentialType="UserName" />
</p2:BasicHttpSecurity.Message>
<p2:BasicHttpSecurity.Transport>
<p2:HttpTransportSecurity />
</p2:BasicHttpSecurity.Transport>
</p2:BasicHttpSecurity>
</p2:BasicHttpBinding.Security>
</p2:BasicHttpBinding>
</p2:Endpoint.Binding>
<p2:Endpoint.ContractProjection>
<p2:SoapContractProjection>
<p2:SoapContractProjection.Contract>
<p2:ServiceContract Name="IMatService">
<p2:OperationContract Name="Sum">
<p2:OperationArgument Name="x" Type="p1:Double" />
<p2:OperationArgument Name="y" Type="p1:Double" />
<p2:OperationArgument Direction="Out" Name="SumResult"
Type="p1:Double" />
</p2:OperationContract>
</p2:ServiceContract>
</p2:SoapContractProjection.Contract>
</p2:SoapContractProjection>
</p2:Endpoint.ContractProjection>
</p2:Endpoint>
</p2:ClientOperation.Endpoint>
<p2:ClientOperation.OperationArguments>
<p:OutArgument x:Key="SumResult"
x:TypeArguments="p1:Double">[Total]</p:OutArgument>
<p:InArgument x:Key="x"
x:TypeArguments="p1:Double">[A]</p:InArgument>
<p:InArgument x:Key="y"
x:TypeArguments="p1:Double">[B]</p:InArgument>
</p2:ClientOperation.OperationArguments>
</p2:ClientOperation>
<c:Write DisplayName="Write Result" Result="[Total]" />
</p:Sequence>
</p:Activity>

Burada durup aslnda biraz soluklanmak belki bir yudum kahve imek ve
sonrasnda XAML ieriine younlaarak dnmek gerekmektedir. Dikkat edilecei zere WF' in

www.bsenyurt.com Page 20
tm ierii, Write, Read, ClientOperation aktiviteleri, global WF deikenleri
bu XAML ieriinde bildirilmektedir. Tabiki bu XAML ierii alma zaman tarafnda
deerlendirilmektedir. Dekleratif(Declerative) bir yaklamdan
ziyade ClientOperation aktivitesinin XAML ierisine nasl gmldne dikkat etmemizde yarar
vardr. ylekiEndPoint ve buna ait AddressBindingContract bilgilerinin
tamam XAML elementleri ierisinde oluturulmutur. Buna gre XAML ierii basit bir editor
yardmyla deitirildii takdirde Workflow rneinin yeni ortam artlarna gre adapte edilmesi
kolayca salanabilir. Sz gelimi, servis adresinin deimesi veya operasyon adnda yada parametrik
yapsnda oluabilecek deiiklikleri koda girmeden dzenleyebilir ve WF' in gncellenmesini
salayabiliriz. Bunun salanmasnn en byk etkenlerinden
birisi Workflow bazl WCF servislerinin kod yazmadan XAML tabanl gelitirilip kullanlabiliyor
olmasdr. (Bu alt yapy ve Workflow bazl bir WCF servisinin XAML ile dekleratif olarak nasl
tanmlanabileceini ilerleyen makalelerimizde veya grsel derslerimizde incelemeye
alacaz.) Artk rneimizi test etmeye balayabiliriz. Bundan nce Solution' mzn son halinin
aadaki ekran grntsne benzer olacan dnebiliriz.

Programn almasnn sonucu aadakine benzer bir ekran kts oluacaktr.

Dikkat edilmesi ve unutulmamas gereken noktalardan biriside programn almas iin servisinde
alyor olmas gerekliliidir. Nitekim servisin ayakta olmamas halinde istemcilerin taleplerine
karlk alma zaman istisnalar(Runtime Exception) almas sz konusudur.

Peki ClientOperation kullandmzda .Net 3.5 srm ile Workflow Foundation alt yapsna
kazandrlan SendActivity tipine gre en byk farkllk(farkllklar) nedir?

www.bsenyurt.com Page 21
Aadaki ekran grnts 17.4.2008 tarihinde yaynlanan WCF ile WF Entegrasyonu
-1 makalesine aittir. Bu makaleden hatrlanaca zere SendActivity tarafndan
kullanlan WCF servisinin Host uygulama zerinde ela alnabilmesi iin Add Service
Reference(veya svcutil ile komut satrndan) ile proxy retiminin yaplmas
gerekmektedir.

Hereyden nce servis kullanan bir istemci gelitirilirken, Add Service Reference seenei
ile proxy tiplerinin eklenmesi gerekmektedir. Oysaki gelitirdiimiz rnekte byle bir ileme
bavurulmamtr. Bunun yerine ClientOperation elementi iin XAML tabanl tanmlamalar
yaplmtr. Dolaysyla yeni alma zaman motorunun bu ierie bakaraktan servis ile iletiime
getiini ve fiziki bir proxy' ye ihtiya duymadn syleyebiliriz. Bir baka deyile rnein servis
tarafnda oluabilecek baz deiikliklerin WFtarafna bildirilmesi iin bir referans gncellemesi
yaplmasna gerek kalmamaktadr. Buda nemli bir avantajdr.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde yeni WF 4.0 ve WCF
4.0 kabiliyetlerinin rnek bir sonucunu deerlendirmeye altk. Bu amala yeni gelen aktivite
tiplerindenClientOperation tipini ele aldk ve bir servis operasyonunun referansn eklemeden,
dekleratif olarak tanmlanp XAML ile oluturulmasn ve kullanlmasn grdk. Tabi bu konuda
konuulabilecek farkl vakalarda vardr. En nemli sorunlardan biriside servis operasyonlarnn uzun
sreli(Long Running Workflows) olabileceidir. Bu durumda WF'
in kalcolarak saklanmas(Persistence) gibi durumlar sz konusudur ki bunu WF 4.0 zerinde
kurmak ve ynetmek(Management) son derece kolaydr. zellikle ynetim ve izleme safhasnda
devreye giren Dublin kod adl Windows Application Server' n yeteneklerini en ksa srede
sizinle paylamaya alyor olacam. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

www.bsenyurt.com Page 22
Windows Workflow Foundation 4.0 - lk
zlenimler ( 26.03.2009 ) - WF 4.0
Deerli Okurlarm Merhabalar,

Bundan sadece bir ka sene nce .Net Framework 3.0 versiyonu ile birlikte i
aklarnn(Workflows) kod ierisinde modellenerek farkl uygulamalarda kullanlabilmesini
salamak amacyla Windows Workflow Foundation(WWF) alt yaps duyurulmutu. Paralelinde
ise, Servis Odakl Mimarilere(Service Oriented Architecture) yeni bir yaklam, Windows
Communication Foundation(WCF) ile birlikte getirilmiti. Workflow Foundation her ne kadar
i aklarnn(ou zaman kod aklarnn) kendi iinde modellenmesini salasa da, zaman ierisinde
d ortamlar ile olan haberlemesinde WCF ile birlikte hareket etmeye balamtr. Bu nedenle .Net
Framework 3.5 ile birlikte her iki alt yapnnda birbirleriyle daha kolay haberleebilmesi iin baz
eklentiler yaplmtr. Bu geniletmelerden en nemlileri Workflow Activity Library ierisine
eklenen SendActivity ve ReceiveActivity aktivite tipleridir. Bylece bir Workflow uygulamasnn
servisler yardmyla d dnya ile tek ynl(One-Way) mesajlaabilmesi yada kendi ierisinden
d dnyaya servis bazl operasyonlar sunabilmesi mmkn hale gelmitir. Ama belkide en nemli
geniletme WorkflowServiceHost snfdr. Bu snf sayesinde, WF uygulamalarnn servis olarak
host edilebilmesi, bir baka deyile IIS/WAS(Internet Information Services/Windows
Process Activation Service) ierisinde sunulmas mmkn klnmaktadr. Sonu olarak artk
gnmzde, Workflow Tabanl Servisler(Workflow Based Services) kavram hayatmzn bir
paras haline gelmeye balamtr. Yinede zellikle gelitirici asndan bakldnda halen daha
eksiklikler bulunmaktadr. zellikle WF ile WCF entegrasyonunda karlalan bu zorluklarn
stesinden gelebilmek iin .Net Framework 4.0ierisinde nemli yenilikler bulunmaktadr. te bu
yazmzda halen son srm ile yaynlanmam olsada WF 4.0 ile gelmesi muhtemel yeniliklere
deinilmeye allacaktr.

Yazmzda yer alan rnekler ve teknik terimlerin ou PDC 2008' de yaymlanan Virtual
PC imaj zerinde gerekletirilmektedir. Mays aynda beta srmnn yaymlanmas
planlanan Visual Studio 2010' un ilk grnts ele alnmaktadr. Bu nedenle son
srmler yaymlandktan sonra makalede yer alan kavramlarn bir ksmnn deitii
grlebilir ve muhtemeldir.

WF uygulamalar 3.5 srmnde XAML(eXtensible Application Markup Language) yardmyla


yaplabilsede yinede gelitirici asndan tam anlamyla oturmu bir yap deildi. rnein debug
edilmelerinde sorundu. Ancak 4.0 srmnde sadece XAML bazl Workflow rneklerinin
gelitirilmesi ok daha kolay bir hale getirilmektedir. Aslnda buradaki en byk amalardan
biriside, Workflow tabanl WCF servislerinin, XAML bazl
olaraktan dekleratif(Declerative) tanmlanabilmesinin salanmasdr. Dekleratif ekilde yaplan
tanmlamalar, kodlamaya girmeden alma zamannda baz deiikliklerin kolayca yaplabilmesini
salamaktadr. Dolaysyla 4.0 srmnde WF tarafnda ve WCF tarafndaXAML yapsn ok daha
yaygn bir ekilde gryor ve kullanyor olacaz. XAML tabanl bu ierikler herhangibir depolama
alannda(Muhtemelen Oslo kod adl yapnn deerlendirecei saklama-
Repository alanlarnda) saklanabilecei gibi, alma zamanna devredilerek yrtlebileceklerde.
Yani bir WF uygulamasnn(hatta bir WCF servisinin ve ok doal olarak bir Workflow
servisinin) bulunduu ortamdan Export edilerek baka bir platforma tanmas ve
orada Import edilerek yrtlmeye balanmas mmkn olabilecek. Dier taraftan depolanarak
saklanan bu Workflow Servislerinin veya dier WCF servislerinin
kolayca ynetilebilmesi(Management) iinde Dublin(Windows Application Server)kod adl
bir alma yrtlmektedir. Bu sunucu ve IIS' e gelen eklentiler sayesinde, servislerin kolay bir

www.bsenyurt.com Page 23
ekilde Import/ Export edilmesi, izlenebilmesi(Tracking), durumlarnn
denetlenmesi(Monitoring) gibi Admin seviyesindeki ilemler kolaylkla gerekletirilebilecektir.
Tabiki bu konular ile ilikili detaylar nmzdeki zamanlarda ilemeye alyor
olacaz. XAML tabanl WF rnekleri, 4.0 ile gelen yeniliklerden sadece bir tanesi. Bunun dnda
aadaki ekildende grebileceiniz gibi pek ok yeni aktivite tipi ile kar karyayz.

Grld zere pek ok farkl aktivite tipi yer almakta. Bu ekilde alt mavi izgi ile iaretlenmi
olan aktiviteler(veya Workflow elementleri) WCF odakl bileenlerdir.
rnein ClientOperation bileeni ile,
bir WCF operasyonunu SendMessage/ReceiveMessage yapsna uygun olacak ekilde armak
mmkn olmaktadr. ServiceOperationbileeni ile WF ierisinden dary
bir WCF operasyonu(Operation) yine SendMessage/ReceiveMessage yapsna uygun olaraktan
sunulabilmektedir. SendMessage aynen 3.5' tekiSendActivity aktivitesine benzer olacak
ekilde tek ynl mesaj(One Way Message) gnderilmesinde kullanlr. Tahmin edilecei
zere ReceiveMessage bileenide tek ynl olaraktan WCF mesajlarnn alnmasnda
kullanlmaktadr.

WCF tabanl rnek bu bileenler dnda dikkat ekici noktalardan biriside FlowChart aktivite
tipidir. Bu bileen yardmyla ak diagram mantnda basit karar yaplar ve anahtar admlar ile
srelerin kolayca tasarlanmas mmkndr. Gelitiriciler asndan ok yaygn olarak
kullanlabilecek bir ak tipidir. Bu ak tipi Sequential veState Machine aktivite tiplerinin baz
yanlarn kendi ierisinde barndrmaktadr. Buna ek olarak rnein Assign bileeni
ile workflow seviyesindeki bir deikene deer atanmas salanabilir. lgi ekici dier aktiviteler
ise DbQuery'1, DbUpdate ve Persist bileenleridir. Aslnda DbQuery'1 bileeni
yardmyla SQL sorgularnn altrlmas veDbUpdate ile veri kaynana doru gncelletirmelerin
yaplmas mmkndr. Bu belki ok ekstra bir zellikmi gibi gelmeyebilir ama nemli olan nokta
sz konusu aktivitelere ait ayarlamalarn dekleratif olarak(yani XAML
bazl) yaplabilmesidir. Persist bileeni ise, Workflow' un herhangibir
noktasnda persistence hizmetinin devreye alnarak akn uzun sreliine korunabilmesini

www.bsenyurt.com Page 24
salamaktadr ki Long Running Workflow Service tipleri iin nemli bir zelliktir. Bunu 3.5
versiyonunda kod yardmyla yaptmz dnlrse bir aktivite bileeninin olmas gelitirime
safhasn kolaylatrmakta ve ynetimi dahada glendirmektedir. (Bu aktivite tiplerini ve nasl
kullanldklarn ilerleyen grsel derslerimizde ele almaya alyor olacam)

Gelelim aktivite ktphanesine. Artk aktivitelerimiz WorkflowElement isimli yeni bir tipten
tretilmektedir. Bir baka deyile Base Activity Library' de yer WF elementlerin ata
snfWorkflowElement tipi olmaktadr. Yine Visual Studio 2010 Object Browser' dan alnan
ekran grntsnde bu durum aadaki ekildende grld gibi tespit edilebilir.

Dikkat edilecei zere DbQuery aktivitesi, Activity tipinden tremi olmasna


ramen, Activity tipinin kendisi WorkflowElement tipinden tredii iin dolayl olarak
birWorkflowElement' tir. Assign bileeni ise dorudan WorkflowElement tipinden
tremektedir. Burada aslnda nemli bir noktay daha vurgulamak gerekiyor. Eer var olan bir
aktivite trnden geniletme yaplarak yeni bir bileen retilecekse, Activity tipinden tretilme
yaplmas ve bu yeni snf ierisinde, geriye WorkflowElement referans
dndrenCreateBody metodunun ezilmesi(override) nerilmektedir. Aynen aadaki ekran
grntsnde olduu gibi.

www.bsenyurt.com Page 25
Dier taraftan eer sfrdan bir aktivite tipi tasarlanacaksa WorkflowElement tipinden
tretip Execute metodunun override edilmesi
gerekmektedir. WorkflowElement aslnda abstractbir snf ve Execute metodu abstract olarak
tanmlanmtr. Bu nedenle implemente eden tip ierisinde Execute metodunun mutlaka ezilmesi
arttr.(C# Object Oriented kurallarn hatrlayalm)

www.bsenyurt.com Page 26
Execute metodu parametre olarak ActivityExecutionContext tipinden bir referans deeri
almaktadr. Bu sayede sz konusu aktivitenin alma zamannda iinde bulunduu Activite ile
konuabilmesi mmkn olmaktadr. Aktivite tasarlanmas ile ilikili nemli noktalardan biriside d
ortama deiken aktarm veya tam tersidir. Bu
noktada InArgument<T> veOutArgument<T> tiplerinden yararlanlarak, aktivite ierisine veri
girii veya aktiviteden d ortama veri k salanabilmektedir. Biraz sonra gelitireceimiz
rneimizde iki zel aktivite tipi yazarken bu generic snflardan yararlanlacaktr.

WF 4.0 aklarnn kolay bir ekilde tasarlanabilmesi iin Visual Studio


2010 ierisinde WPF(Windows Presentation Foundation) tabanl bir arayz sunulmaktadr. Bu
arayz sayesinde aklarn daha zengin bir grsellikle hazrlanmas mmkndr. Sz
gelimi zoom zellii ile byk aklarn ekran ierisinde daha verimli ekilde grlebilmesi
salanmaktadr. Zannediyorum aadaki ekran grntsnde bu durumun kafamzda biraz daha
netlemesi iin yeterlidir.

www.bsenyurt.com Page 27
Dikkat ekici noktalardan bir dieride rnekte yer alan ProductActivity bileeni yannda
bir Breakpoint yer almasdr. Dolaysyla debug ilemleri iin Workflow elementlerinin
kendisinin designer ierisinde dorudan iaretlenebildiini syleyebiliriz. Dier dikkat ekici
ksmda sol alt tarafta yer alan Arguments ve Variables blmleridir. Bugn
yazmzda Variables ksmn kullanarak Sequence aktivitesinin tamamn ilgilendiren deikenlerin
nasl tanmlanabileceini ve kullanlabileceinide grm olacaz. nemli noktalarda biriside
Arguments veya Variables gibi blmler ile Workflow ierisinde eitli tanmlamalarn koda girmeye
gerek duymadan kolay bir ekilde grsel olarak yaplabilmesidir.(Designer tarafnn kullanmn
daha kolay kavramak iin yaynlanacak grsel derslerimizi takip etmenizi neririm.)

Variables ve Arguments;

WF 4.0' da Variables kavram verinin depolanmasn ifade eder.


Deikenler(Variables) Workflow' un(yada Activity bileeninin) alma zaman rnei
boyunca veri depolamak amacyla kullanlrlar. Tanmlanrken adlar ve tipleri belirtilir.
Yaamlar, Workflow veya Activity rneinin bellekte kald sre boyunca geerlidir.
Yani Workflow sonlandnda veya Activity bileeni almasn tamamladnda
referanslar bellekten kaldrlmaktadr.

Arguments kavram ise verinin aktivite ierisine veya aktivite ierisinden darya
aktarlmas anlamnda kullanlmaktadr. Her argmann bir
yn(Direction)vardr.(Input, Output, Input/Output) Argmanlar aktivite ierisinde
tanmlanrken InArgument<T>,

www.bsenyurt.com Page 28
OutArgument<T> veya InOutArgument<T> tipinden tanmlanrlar. Tile kullanlacak
verinin tipi belirtlir.

Dilerseniz basit bir rnek gelitirerek yenilikleri daha yakndan tanmaya alalm. ncelikle Visual
Studio 2010 ortamnda .Net Framework 4.0 ablonunda bir Activity Librarygelitirerel ie
balayacaz. Bu ktphane rneimizde kullanacamz zel aktivite tiplerini barndryor olacak.

Bu ilemin ardndan projemize bir adet snf ekleyerek devam edebiliriz. Snfmz ierii ise
aadaki gibidir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.WorkflowModel;

namespace SampleActiviyLibrary
{
public class ProductActivity
:WorkflowElement
{
public OutArgument<int> ProductId { get; set; }
public OutArgument<int> Count { get; set; }

protected override void Execute(ActivityExecutionContext context)


{
Console.WriteLine("ProductId ?");
ProductId.Set(context, Convert.ToInt32(Console.ReadLine()));
Console.WriteLine("Requested count ?");
Count.Set(context, Convert.ToInt32(Console.ReadLine()));
}
}
}

Burada dikkat edeceiniz zere kod yardmyla zel bir aktivite tipi(Custom
Activity) gelitirilmektedir. ProductActivity snf WorkflowElement tipinden tremektedir ve

www.bsenyurt.com Page 29
ierisinde OutArgument<int> tipinden ProductId ve Count isimli zellikler(Properties) yer
almaktadr. Override edilen Execute metodu
ierisinde, OutArgument<T> tipinin Setmetodundan yararlanlarak, Console penceresinden
okunan deerlerin ProductId ve Count zelliklerine aktarlmas
salanr. OutArgument<T> kullanlmas nedeniyle, zelliklerin
deerleri ProductActivity aktivitesinin kullanldn Workflow ortamna aktarlabilmektedir. Yani
bu aktivite ierisinde Console penceresinden alnan bir takm deerler(ki bu sadece rnek olarak
verilmitir, gerek hayat senaryolarnda bu deerlerin farkl kaynaklardan gelmesi muhtemeldir.),
aktivitenin kullanld Workflow ieriine ProductId ve Countisimleriyle tanabilir. Gelelim ikinci
zel aktivitemize.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.WorkflowModel;

namespace SampleActiviyLibrary
{
public class OrderInformationActivity
:WorkflowElement
{
public InArgument<int> OrderedProductId { get; set; }
public InArgument<int> OrderedProductCount { get; set; }

protected override void Execute(ActivityExecutionContext context)


{
int orderedId=OrderedProductId.Get<int>(context);
int orderedCount = OrderedProductCount.Get<int>(context);

// TODO: Mail gnderme ilemleri.


Console.WriteLine("{0} numaral rnden {1} adet siparis
edilmistir",orderedId,orderedCount);
}
}
}

OrderInformationActivity bileenide ProductActivity snf gibi WorkflowElement tipinden


tremektedir. Ancak bu
kez InArgument<int> tipinden OrderedProductId veOrderedProductCount isimli zellikler
kullanlmaktadr. Yani, Workflow ierisinden bu aktiviteye, InArgument<T> tipinden tanmlanan
zellikler zerinden veri tanabilir. Girilen deerlerin Execute metodu ierisinde elde edilii
srasnda InArgument<T> tipinin generic Get<T> metodu kullanlr. Dikkat edilecei zere
metodlar parametre olarakActivityExecutionContext tipinden referans almaktadr. Yani,
aktivitenin kullanld Workflow ortamna ait bir takm
bilgiler(rnein InstanceId gibi) Execute metodu ierisinde tanabilmektedir. Bu aktivite ilede,
sembolik olarak Console penceresine sipari edilen rn numaras ve miktar bilgileri yazdrlmakta
ve belkide mail gnderme ilemleri gerekletirilmektedir. Workflow rneimizi tasarlamadan
nce arada XAML bazl bir aktivite tipinin nasl gelitirileceine de deinmek isterim. Bu
amala Visual Studio 2010 ortamnda, projeye Add New Item ile bir Activity esi aadaki
ekilde grld gibi eklenir.

www.bsenyurt.com Page 30
Dikkat edilecei zere aktivitenin uzants XAML' dr. Bununla birlikte alan pencereden grlecei
gibi Activity tipi grsel olarak tasarlanabilir. Buradaki aktivitede aslnda birde zellik
tanmlanmaktadr. DiscountRate isimli bu zellik Argument penceresi kullanlaraktan aadaki
gibi oluturulmutur! Sper.

www.bsenyurt.com Page 31
Grld gibi herhangibir ekilde kod yazlmamtr. Ardndan tasarm ortamnda basit
bir Assign bileeni srklenerek, Discount aktivitemizde aada grld gibi kullanlmas
salanmaktadr.

Assign aktivitesinin yapt tek ey DiscountRate isimli zellie sabit bir deerin atanmasnn
salanmasdr. Ancak burada nemli olan noktalar Discount bileeninin tamamen grsel olarak
tasarlanmas ve sonucun XAML olarak aadaki gibi retilmesidir.

<p1:Activity x:Class="SampleActiviyLibrary.Discount" xmlns:p="http://schemas.microsoft.c


om/netfx/2008/xaml/schema"

www.bsenyurt.com Page 32
xmlns:p1="http://schemas.microsoft.com/netfx/2009/xaml/workflowmodel" xmlns:s="clr-
namespace:System;assembly=mscorlib" xmlns:swdx="clr-
namespace:System.WorkflowModel.Design.Xaml;assembly=System.WorkflowModel.Design"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<p:SchemaType.Members>
<p:SchemaProperty Name="DiscountRate" Type="s:Decimal" />
</p:SchemaType.Members>
<p1:Assign>
<p1:Assign.To>
<p1:OutArgument
x:TypeArguments="s:Decimal">[DiscountRate]</p1:OutArgument>
</p1:Assign.To>
<p1:Assign.Value>
<p1:InArgument x:TypeArguments="p:Double">[1.12R]</p1:InArgument>
</p1:Assign.Value>
</p1:Assign>
</p1:Activity>

Grld gibi, tasarm zamannda gelitirdiimiz bu aktivite tipi sadece XAML(Only


XAML) ierikli olacak ekilde retilmitir. te dekleratif tanmla dediimizde tam olarak budur.
retilen bu XAML ierii herhangibir ortamda depolanabilir ve dahada
nemlisi WF alma zaman tarafndan yrtlerek baka Workflow' lar tarafndan ele alnp
kullanlabilir.

Bu ksa bilgilerden sonra tekrar rneimize dnebiliriz. Artk


gelitirdiimiz Workflow ktphanesini basit
bir Sequential Workflow Console Application projesinde referans ederek
kullanacaz. Console uygulamasna ekleyeceimiz ProductOrderFlow.xaml isimli aktivite
ierisinde bir Sequence bileeni bulunmaktadr. Bu bileen iinde ise rn numaras ve sipari
adedi bilgileri iin iki deiken tanmlanmaktadr. Bu sefer Variables ksmn kullanaraktan
aadaki ekran grntsnde olduu gibi gerekli deikenleri kolayca belirleyebiliriz.

www.bsenyurt.com Page 33
UrunNo ve SiparisAdedi isimli Int32 tipinden olan deikenler Sequence aktivitesi ierisinde
tanmlandklarndan, alt aktiviteler tarafndanda eriilip kullanlabilmektedirler. imdi Sequence
aktivitesi ierisine nce ProductActivity sonrada OrderInformationActivity bileenlerini
ekleyeceiz. ProductActivity bileeni hatrlayacanz gibi Console penceresinden okuduu
deerleri ProductId ve Count isimli output zelliklerine aktarmaktayd. Dolaysyla bu
deerleri Sequence ierisinde tanmlanan UrunNo ve SiparisAdedi isimli deikenler ile
eletirmemiz mmkndr. Bunun iin tek yaplmas gereken, ProductActivity bileeninin
zelliklerinden ilgili atamalarn aadaki ekran grntsnde olduu gibi yaplmasdr.

www.bsenyurt.com Page 34
ProductActivity bileeninin hemen arkasna OrderInformationActivity bileenini ekleyerek
devam edebiliriz. Bu bileende hatrlayacanz gibi kullanld ortamdan girdi(Input)deerleri
almak zere iki zellie sahiptir. Bu nedenle sz konusu aktivitenin zelliklerinde aadaki ekran
grntsnde yer alan ayarlar yapmamz yeterlidir.

Bylece bir nceki aktivite ile, Sequence aktivitesindeki SiparisAdedi ve UrunNo isimli
deikenlere tanan deerler, OrderInformationActivity ierisinden elde edilebilirler. te bu
kadar. Tabi imdilik :) Tm bu ilemlerin arndan ProductOrderFlow.xaml aktivitesine
ait XAML ieriine bakldnda, aadaki kod parasnda yer alan ktnn elde edildii grlebilir.

<p:Activity x:Class="HostWFApplication.ProductOrderFlow" xmlns:p="http://schemas.micr


osoft.com/netfx/2009/xaml/workflowmodel"xmlns:p1="http://schemas.microsoft.com/netfx
/2008/xaml/schema" xmlns:s="clr-namespace:SampleActiviyLibrary;assembly=
SampleActiviyLibrary" xmlns:swd="clr-namespace:System.WorkflowModel.Debugger;assembly=
System.WorkflowModel" xmlns:swdx="clr-
namespace:System.WorkflowModel.Design.Xaml;assembly= System.WorkflowModel.Design"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<p:Sequence swd:XamlDebuggerXmlReader.FileName="C:\Orneklerim\SampleActiviyLibrary
\HostWFApplication\ProductOrderFlow.xaml">
<p:Sequence.Variables>
<p:Variable x:TypeArguments="p1:Int32" Name="UrunNo" />
<p:Variable x:TypeArguments="p1:Int32" Name="SiparisAdedi" />
</p:Sequence.Variables>
<s:ProductActivity Count="[SiparisAdedi]" ProductId="[UrunNo]" />
<s:OrderInformationActivity OrderedProductCount="[SiparisAdedi]"
OrderedProductId="[UrunNo]" />
</p:Sequence>
</p:Activity>

www.bsenyurt.com Page 35
Harika deil mi? Tm ak ierii XAML bazl olacak ekilde tanmlanm durumda. Burada durup
bu XAML ieriini yorumlayacak programlar dnmek gerekiyor. Daha karmak aklara ait bu
ierikler eitli aralar yardmyla ynetilebilir ve aklarn deitirilerek yeni halleriyle devreye
alnmas salanabilir.

Peki ak devreye sokacak olan alma zaman ortamnn hazrlayacs nerededir? Sonu itibariyle
yazlan Workflow rneklerinin mutlaka bir Host uygulama ierisinde ele alnyor olmas arttr.
rneimiz Visual Studio 2010 ierisine gmlm hazr bir Console ablonu olduundan, .Net
3.0 ve .Net 3.5' teki WF projelerinde olduu gibi tm gerekli kodlar otomatik olarak
retilmektedir. Gelitirdiimiz rnekte bu kodlar Program.cs dosyasnn bir paras olarak aadaki
gibi retilir.

namespace HostWFApplication
{
using System;
using System.Linq;
using System.Threading;
using System.WorkflowModel;
using System.WorkflowModel.Activities;

class Program
{
static void Main(string[] args)
{
Sequence s;
AutoResetEvent syncEvent = new AutoResetEvent(false);

WorkflowInstance myInstance = WorkflowInstance.Create(new


ProductOrderFlow());
myInstance.Completed += delegate(object sender, WorkflowCompletedEventArgs e)
{
syncEvent.Set();
};
myInstance.Resume();

syncEvent.WaitOne();

}
}
}

Grld gibi ilk olarak ProductOrderFlow tipinden bir WorkflowInstance referans


retilmektedir. Workflow tamamlandnda Completed olay metodu devreye girer. Her zamanki
gibi WorkflowCompletedEventArgs parametresinden yararlanarak rnein WF tarafndan
retilen Output deerleri ele alnabilir. (Bu arada s isimli Sequence tipinden bir deiken yer ald
grlmektedir. Hi kullanlmayan bu deikenin final srmnde zaten ortadan kaldrlaca
syleniyor. Burada kazayla kaldn sanyorz ;) ) Uygulamamz bu son haliyle altrdmzda
aadaki ekran grnts ile karlarz.

www.bsenyurt.com Page 36
Dikkat edilecei zere kullancdan rn numaras ve sipari adedi istenmi sonrasnda ise buna
uygun bir ilem yrtlm ve tasarlanm olan ak baarl bir ekilde tamamlanmtr.

Buraya kadar anlattklarmz ile aslnda Workflow Foundation 4.0 ile gelen yeniliklerin sadece bir
ksmn inceleme ansn bulduk. Durumu deerlendirdiimizde aadaki maddeler ile ksa bir zet
geebiliriz;

WF 4.0 ierisinde XAML kullanm daha etkili ve yaygn hale getirilmi, bu


sayede Workflow Based Service' lerin dekleratif olarak gelitirilmesinin yolu tam olarak
almtr. Bu konuyu bir sonraki makalemizde(veya grsel dersimizde) incelemeye alyor
olacam.
WF 4.0 ierisinde WCF 4.0 ile daha iyi anlalmasn salayacak yeni aktiviteler eklenmitir.
Saysz pek ok yeni aktivite dnda FlowChart tipide gz ard edilmemelidir. Bu tip
zellikle gelitiricilerin bildii ak emalar mantna uygun olacak ekilde sre
tasarlanmasn olanakl klmaktadr.
Activity Base Library ierisinde yer alan ata aktivite tipi artk WorkflowElement olarak
tasarlanmtr. Buna gre sfrdan tasarlanacak
aktivitelerin WorkflowElement abstractsnfndan tremesi, var olanlar geniletecek
olanlarn ise Activity snfndan treyerek CreatBody metodunu ezmesi nerilir.
Gelitirici tanml bir aktivite, istenirse kod yerine tasarm arac yardmyla da retilebilir. Bu
durumda bir XAML ierii oluturulmaktadr.
Visual Studio 2010 tarafnda WPF tabanl yeni tasarm arac sayesinde, WF gelitirilmesi
son derece kolay ve zevkli bir hal almaktadr. zellikle
aktivitelerin arguman(Argument)veya deikenlerinin(Variables) grsel olarak
belirlenebilmesi nemli noktalardan birisidir.
XAML tabanl WF yaplar, Oslo gibi modellerin salad depolama
alanlarnda(Repositories) saklanabilir, baka uygulamalar
tarafndan(Quadrant gibi) ynetilip deitirilebilir, dier WF alma zaman
motorlarna aktarlabilmeleri(Import) iin bulunduklar ortamlardan kt(Export) olarak
verilebilirler.

Elbette bahsettiimiz konularn tamamnda deiiklikler olabilir, olmas muhtemeldir. Kesinlik ancak
son srmler ile ortaya kacaktr. Bylece geldik bir makalemizin daha sonuna. Bu makalemizde
ilk bakta WF 4.0 ile gelen yeniliklerin bir ksmna deinmeye altk ve konuyu pekitirmek
amacyla bir rnek gelitirdik. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

SQL Persistence Hizmeti ( 06.03.2009 ) - WWF


Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 37
Workflow Foundation yardmyla kod aklarnn modellenebilmesi ve herhangibir .Net
uygulamas ierisinden host edilerek altrlabilmesi mmkndr. Bu kavram iin ierisine
servisler girdiinde ok daha genilemektedir. Nitekim servisler
yardmyla Workflow rneklerinin host edildikleri uygulama dndaki ortamlar ile
haberleebilmeleri mmkn olmaktadr. Hatta servislerin kendi ilerinde Workflow aktivitilerini
kullanabilmeleri ve bylece belirli kod aklarn yrtebilmeleride mmkndr. Bu cmleden sonra
durup dnldnde Workflow Foundation kavramnn aklar, platform bamsz ortamlara
tayabilecei sonucuda ortaya kmaktadr. Dier taraftan Workflow uygulamalar sadece d
ortamlar ile haberlemek iin servislerden yararlanmazlar. laveten, Workflow alma
zamann(Runtime) ilgilendiren ve zellikle aktivitilerin dayankl olarak saklanmasn(Durable
Persistence), alma hayatlarnn izlenmesini(Tracking), admlar aras geilerin zel olarak
planlanmasn(Scheduling) salayan ve.Net Framework ierisinde nceden tanmlanm
servislerde sz konusudur.

Workflow servisleri, alma zamanna eklenerek workflow rneklerine yeni kabiliyetler


kazandrlmasn salamak amacyla kullanlrlar.
rneinPersistenceServices ve TrackingServices, SQL veritabanlarn varsaylan
olarak kullanan alma zaman servisleridir. PersistenceServices ile workflow' larn
kalc olarak saklanabilmesi salanabilir. TrackingServices yardmylada alma zaman
workflow rneklerinin izlenebilmesi mmkndr. Bir baka rnek olarak workflow alma
zaman davranlarn deitirmemizi salayan Manual Scheduler servisi gz nne
alnabilir. Bu servislerin bir ksmnn kullanlabilmesi iin, alma zamanna bilinli olarak
eklenmeleri gerekmektedir. Bir baka deyile etkinletirilmeleri gerekir.

te bu yazmzdaki konumuz, uzun sreli alma ihtimali olan bir Workflow' un belirli koullarda
kalc olarak fiziki bir ortamda saklanmasnn, SQL Persistence Service yardmyla nasl
gerekletirilebileceidir. SQL Persistence Service sayesinde, bir Workflow' un faaliyetsiz
kalmas(Idle) halinde bellek yerine, tablo bazl bir ortamda saklanabilmesi ve bu durum sona
erdiinde sz konusu depolama alanndan tekrar ayaa kaldrlarak almaya devam etmesi
mmkn olmaktadr. Konuyu daha kolay kavrayabilmek adna ilk
nceWorkflow alma zamannn kendi ve ynettii WF rnekleri ile ilikili yaam dngsn
incelemekte yarar vardr. Bu yaam dngsnn kolayca ele alnabilmesi
iin WorkflowRuntime snf ierisine eitli olaylar eklenmitir.

Bilindii zere WorkflowRuntime snf alma zamannda WF rneklerinin ynetiminden


sorumludur. Bu ynetim ilemi srasnda WorkflowRuntime snf zerinden ele
alnabilecek 14 farkl olay metodu vardr. Sz konusu olaylarn bir ksm sadece alma zamann
ilgilendirirken, bir ksmda WF rneklerinin yaam dnglerine(LifeCycle) adanmtr. Buna
gre ServicesExceptionNotHandled, Started ve Stopped olaylar Workflow alma zaman
olaylar olarak dnlebilir.

Workflow alma Zaman Olaylar

Workflow alma zaman servislerinden herhangibirinde kontrol


ServicesExceptionNotHandled altna alnmam bir istisna(Exception) olutuunda devreye
giren olaydr.

Workflow alma zaman motoru, zerine eklenmi servisler


ile baarl bir ekilde balatldnda devreye girer. Burada
Started
alma zamanna eklenen servislerin baarl bir ekilde
balatldklarna dair bir bilgilendirme yapmas sz konusudur.

Started olayna benzer olaraktan, WF alma zaman


motorunun, kendi zerinde yer alan ve almakta olan tm
Stopped
servislerin baarl bir ekilde durdurulmas sonrasnda tetiklenir.
Servisler baarl bir ekilde durdurulduklarna dair WF alma

www.bsenyurt.com Page 38
zaman motoruna bilgilendirmede bulunurlar.

Aadaki tabloda aklamalar verilmi olan olaylar ise, WF alma zamannn


ynettii Workflow rneklerinin durumlarnn(State) deitii hallerde tetiklenmektedir.

Workflow rneine Adanm Olaylar

Workflow rnei devre d brakldnda tetiklenir.


zellikle Persistence servisi kullanldnda nem kaznr. Nitekim devre
WorkflowAborted
d braklan servisin kalc olarak saklanmas ve tekrar kald
yerden ayaa kaldrlmas(Resume) mmkn olabilmektedir.

Bir Workflow rnei tamamlanp bellekten henz kaldrlmadan nce


devreye giren olaydr. Bu olaya ait metod yardmyla host uygulamaya,
WorkflowCompleted
tamamlanan Workflow rneinin output parametrelerini dndrmek
mmkndr.

Workflow rnei oluturulduunda ancak Start metodu ile altrlmadan


WorkflowCreated
az nce tetiklenir.

Bir workflow rnei dardan bekledii bir etki veya Delay aktivitesi
nedeni ile ierisinde yer alan herhangibir aktiviteyi iletmedii durumlarda
WorkflowIdled
tetiklenir. zellikle Idle olma durumunda Persistence hizmetlerinin
kullanm nem kazanr.

Persistence servisi kullanld durumlarda, Workflow rneinin


WorkflowLoaded herhangibir aktivitesi altrlmadan nce ve bellee yklenmesi
sonrasnda devreye giren olaydr.

Persistence servisin kullanlmas halinde bir workflow rneinin


saklanmak zere kaydedilmesi sonrasnda tetiklenir. Workflow persistence
WorkflowPersisted
servisi varsaylan olarakSQL veritabann kullandndan, sz konusu
kaydetme ilemi tablo zerinde gerekletirilmektedir.

Bir erteleme nedeni ile Suspended moda geen bir rnein tekrar ayaa
WorkflowResumed kalkmas sonrasnda ve kald yerden devam ederken herhangibir aktivite
altrlmadan nce devreye giren olaydr.

Workflow rnei yrtlmeye balatldnda tetiklenir. Bu balang kk


WorkflowStarted aktivitenin(Root Activity) altrlmas sonrasnda meydana
gelmektedir.

Workflow rnei, Suspend metoduna yaplan ar


WorkflowSuspended veya Suspend aktivitesine gelinmesi nedeniyle Suspended moduna
getiinde tetiklenen olaydr.

Workflow rnei yok edildikten ama bellekten atlmadan az nce alan


olaydr. Workflow, Terminate metodu
yardmyla, Terminate aktivitesine gelinmesi nedeniyle veya
ele alnmam bir istisna(Unhandled Exception) yznden Terminated
WorkflowTerminated
durumuna geebilir. Eer persistence servis kullanlyorsa, Terminate
edilen workflow rneine ait tm kaytlar ilgili depolama alanndan
kaldrlr. SQL tabanl persistence servisi gz nne alndnda bu, tablolar
zerinde gerekli silme ilemlerinin yaplmas anlamna gelmektedir.

Persistence servisleri kullanldnda, Workflow rnei depolama alanna


WorkflowUnloaded kaydedildikten sonra ama bellekten kaldrlmadan az nce tetiklenen
olaydr.

www.bsenyurt.com Page 39
Aslnda WF alma Zaman Motorunun(WF Runtime Engine) kendisinin bir State
Machine olduu rahatlkla dnlebilir. Nitekim, ynetmekte olduu rneklerin durumlar
arasndaki geileri kontrol altna almakta ve bununla ilikili olaylar ynetmektedir. Temel olarak
workflow rnekleri Created, Running, Suspended, Completed ve Terminated olmak zere 5
farkl duruma sahip olabilir. Bu durum aadaki diyagram ile zetlenebilir.

lk etapta, Persistence servisinin devrede olmad durumlarda standart olarak alan olay
metodlarn ele alacamz bir rnek gelitirerek devam edebiliriz. Bu amala rnek
bir Sequential Workflow Console Application oluturarak baladmz dnebiliriz. Sz
konusu rnek ierisinde Costflow isimli bir Sequential Activity kullanlmakta olup admlar
aadaki ekilde grld gibidir.

Sz konusu aktivite ayn zamanda dardan parametre alp, bir sonu retmektedir.
Aktivitenin faaliyetsiz(Idle) moda getiini grmek iin sembolik olarak Delay aktivitesinden
yararlanlmaktadr. Sz konusu aktivititede sadece duraksama sresi zellii 10 saniye olarak set
edilmitir.

www.bsenyurt.com Page 40
Costflow aktivitesine ait kod ierii aadaki gibi tasarlanabilir.

using System;
using System.Workflow.Activities;

namespace WFCostFactory
{
public enum WorkType
{
Consumer,
Corporate
}
public sealed partial class Costflow
: SequentialWorkflowActivity
{
#region Workflow zellikleri(Properties)

// D ortamdan gelen parametreler


public int TotalDays { get; set; }
public decimal CostValue { get; set; }
public WorkType WorkT { get; set; } // D ortama sonu olarak dndrlen parametre

#endregion

public Costflow()
{
InitializeComponent();
}

// CodeActivity tarafndan altrlan rnek fonksiyonellik


private void Calculate(object sender, EventArgs e)
{
Console.WriteLine("Calculate Metodu. Maliyet hesaplama ilemleri yaplr");
switch (WorkT)
{
case WorkType.Consumer:
CostValue = TotalDays * 1.10M;
break;
case WorkType.Corporate:
CostValue = TotalDays * 1.15M;
break;
default:
CostValue = 1;
break;
}

www.bsenyurt.com Page 41
}
}
}

Sz konusu aktiviteyi host eden Console uygulamasna ait kod ierii ise aadaki gibidir. Burada
dikkat edilmesi gereken nokta WorkflowRuntime rneine ait tm olaylarn yklenmi olmasdr.
Bu olaylarn ou rneimizde devreye girmeyecektir. Ancak hangi durumlarda devreye girecei
yukardaki tablolarda belirtilmitir.

using System;
using System.Collections.Generic;
using System.Threading;
using System.Workflow.Runtime;

namespace WFCostFactory
{
class Program
{
static WorkflowRuntime wfRuntime = null;
static AutoResetEvent wHandle = null;

static void Main(string[] args)


{
// Workflow Runtime nesnesi rneklenir
using(wfRuntime = new WorkflowRuntime())
{
wHandle = new AutoResetEvent(false);

#region Event Tanmlamalar

wfRuntime.Started += new
EventHandler<WorkflowRuntimeEventArgs>(wfRuntime_Started);
wfRuntime.ServicesExceptionNotHandled += new
EventHandler<ServicesExceptionNotHandledEventArgs>(wfRuntime_ServicesExceptionNotHandled)
;
wfRuntime.Stopped += new
EventHandler<WorkflowRuntimeEventArgs>(wfRuntime_Stopped);
wfRuntime.WorkflowAborted += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowAborted);
wfRuntime.WorkflowCreated += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowCreated);
wfRuntime.WorkflowIdled += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowIdled);
wfRuntime.WorkflowLoaded += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowLoaded);
wfRuntime.WorkflowPersisted += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowPersisted);
wfRuntime.WorkflowResumed += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowResumed);
wfRuntime.WorkflowStarted += new
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowStarted);
wfRuntime.WorkflowSuspended += new
EventHandler<WorkflowSuspendedEventArgs>(wfRuntime_WorkflowSuspended);
wfRuntime.WorkflowTerminated += new
EventHandler<WorkflowTerminatedEventArgs>(wfRuntime_WorkflowTerminated);
wfRuntime.WorkflowUnloaded += new

www.bsenyurt.com Page 42
EventHandler<WorkflowEventArgs>(wfRuntime_WorkflowUnloaded);
wfRuntime.WorkflowCompleted+=new
EventHandler<WorkflowCompletedEventArgs>(wfRuntime_WorkflowCompleted);

#endregion

// Workflow nesne rnei oluturulur


// TotalDays ve WorkT zellikleri iin ilk deerler set edilir
WorkflowInstance instance = wfRuntime.CreateWorkflow(
typeof(WFCostFactory.Costflow)
, new Dictionary<string,object>
{
{"TotalDays",20}
,{"WorkT",WorkType.Corporate}
}
);
// Workflow rnei balatlr
instance.Start();
// lemler tamamlana kadar bekle
wHandle.WaitOne();
}
}

static void wfRuntime_WorkflowUnloaded(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowUnloaded", e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowTerminated(object sender,


WorkflowTerminatedEventArgs e)
{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2} Exception Message : {3}",
DateTime.Now, "WorkflowTerminated", e.WorkflowInstance.InstanceId.ToString(),
e.Exception.Message);
wHandle.Set();
}

static void wfRuntime_WorkflowSuspended(object sender, WorkflowSuspendedEventArgs


e)
{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowSuspended", e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowStarted(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowStarted", e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowResumed(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowResumed", e.WorkflowInstance.InstanceId.ToString());
}

www.bsenyurt.com Page 43
static void wfRuntime_WorkflowPersisted(object sender, WorkflowEventArgs e)
{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowPersisted", e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowLoaded(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowLoaded", e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowIdled(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now, "WorkflowIdled",
e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowCreated(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowCreated", e.WorkflowInstance.InstanceId.ToString());
}

static void wfRuntime_WorkflowCompleted(object sender, WorkflowCompletedEventArgs


e)
{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowCompleted", e.WorkflowInstance.InstanceId.ToString());
Console.WriteLine("Maliyet : {0}", e.OutputParameters["CostValue"].ToString());
wHandle.Set();
}

static void wfRuntime_WorkflowAborted(object sender, WorkflowEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, InstanceId : {2}", DateTime.Now,
"WorkflowAborted", e.WorkflowInstance.InstanceId);
}

static void wfRuntime_Stopped(object sender, WorkflowRuntimeEventArgs e)


{
Console.WriteLine("{0} : Event : {1}, IsStarted : {2}", DateTime.Now,
"WFRuntime_Stopped", e.IsStarted.ToString());
}

static void wfRuntime_ServicesExceptionNotHandled(object sender,


ServicesExceptionNotHandledEventArgs e)
{
Console.WriteLine("{0} : InstanceId : {1} Event : {2}, Exception Message : {3}",
DateTime.Now,
e.WorkflowInstanceId.ToString(),"WF Runtime_ServicesExceptionNotHandled",e.Exception.Me
ssage);
}

static void wfRuntime_Started(object sender, WorkflowRuntimeEventArgs e)

www.bsenyurt.com Page 44
{
Console.WriteLine("{0} : Event : {1}, IsStarted : {2}", DateTime.Now,
"WFRuntime_Started", e.IsStarted.ToString());
}
}
}

rnei ilk etapta bu haliye altrdmzda aadaki ekran kts ile karlarz.

lk analizimi yapabiliriz artk. Dikkat edilecei zere ilk olarak Workflow alma zamanna
ait Started olay tetiklenmi ve IsStarted deeri true olarak set edilmitir. Hatrlanaca zere
Workflow motorunun kulland veya balatt tm servislerin IsStarted zelliine etkisi vardr ve
bu zelliin deeri true kalmad srece alma zaman balatlamayacaktr. Bu ilemin
arkasndan Workflow nesnesi rneklendii iin WorkflowCreated ve WorkflowStared olaylar
srasyla almaktadr. Sre devam etmekteyken Delay aktivitesi devreye girmitir. te bu
noktada Workflow rnei faaliyetsiz kalarak, alma zaman moturu tarafndan bellekte tutulmaya
devam edilmektedir. Bu anda WorkflowIdled olay tetiklenmitir.

zellikle olay metodlarnn bazlar ierisindeden GUID tipinden InstanceId deerlerinin


elde edilebiliyor olmas nemlidir ki bu sayede hangi WF rneinin faaliyetsiz kald
kolayca anlalabilmektedir. Tahmin edeceiniz zere bu Id deeri persistence ortamlar
iinde benzersilii salamak asndan nemlidir.

Faaliyetsiz kalma durumu Delay aktitivitesinde belirtilen sre sonlanncaya kadar devam eder.
Sre sonunda ise Workflow rnei almasna kald yerden tekrar balayacaktr. te bizim en
byk amacmz bu faaliyetsiz kalma annda sz
konusu WF rneini SQL Persistence Service yardmyla fiziki bir ortama kaydetmektir.

Varsaylan olarak WF rneklerinin durumu bellekte saklanr. Bir baka


deyile, workflow herhangibir sebeple faaliyetsiz duruma getiinde sz konusu rnek bellekte
asl olarak kalr ve beklemeye balar. Ancak gerek hayat senaryolarnda almakta
olan Workflow rneklerinin uzun sre asl kalmasda sz konusu olabilir. Bu, zellikle faaliyetine
devam etmesi iin onu bekleten operasyona baldr. Dolaysyla bu tip vakalarda Workflow
rneklerinin kalc olarak saklanmalar tercih edilebilir. Kalclkta esas olan Workflowrneinin o
anki durumu ve deerleri ile fiziki bir depolama alanna atlmasdr. Bu noktada ounlukla SQL gibi
veritaban kaynaklarnn kullanlmas tercih edilir. Dier taraftan elbetteki Persistence servisleri
zelletirilebilir ve farkl veri kaynaklarna kaydetme ilemleri gerekletirilebilir.

Workflow Foundation, alma zamanndaki WF rneklerinin bellekten kaldrlp almasnn


durdurulmas sonrasnda, kalc olarak saklanabilmeleri iin nceden gelitirilmi
bir Persistence servisi sunmaktadr. Hangi tip Persistence kullanlrsa kullanlsn, Workflow alma
zaman, kalc olarak saklanan Workflow rneine(rneklerine) gelen mesajlar takip de eder. Bu
sayede gerektii anda, zerinde yer alan Persistence servisi devreye alarak, ilgili WF rneinin
tekrardan bellee yklenmesini salayabilir. Workflow alma zaman, Persistence servisini belirli
durumlar gerekletirildiinde armaktadr. Bu durumlar;

www.bsenyurt.com Page 45
WF rnei belirli bir nedenden askya alndnda yani faaliyetsiz hale getiinde(Idle).
WF rnei yok edilmeden(Terminate) nce.
WF rnei tamamlanmadan(Complete) nce.
Workflow rnei zerinde Unload, TryUnload metodlar arldnda.
PersistOnCloseAttribute nitelii ile imzalanm olan bir aktivitenin tamamlanmas
sonrasnda. zellikle transaction kullanan aktivitiler bu nitelie sahiptir. Dier taraftan
ierisinde transaction kullanlacak olan aktivitilerinde bu nitlei uygulamas gerekir.

WorkflowPersistenceService abstract snfndan tretme yaplarak istenirse zel persistence


snflarda yazlabilmektedir. Biz rneimizde SqlWorkflowPersistenceServicetipinden
yararlanarak WF rneklerini SQL veritaban zerinde saklamaya alacaz. imdi bu durumu
incelememiz gerekiyor. Ancak depolama alan iin SQL tarafnda gerekli hazrlklarn yaplmas
gerekmektedir. Bu noktada .Net Framework ile birlikte hazr olarak gelen WF SQL
betikleri(Scripts) kullanlabilir. Sz konusu SQL betikleri varsaylan olarak rnein Windows
XP iletim sisteminin kurulu olduu bir
makinede C:\WINDOWS\Microsoft.NET\Framework\v3.0\Windows Workflow
Foundation\SQL\EN klasrnde yer almaktadr.

Burada yer
alan SqlPersistenceService_Logic ile SqlPersistenceService_Schema betikleri, Persistence
depolama alan iin gerekli tablo(Table), sakl yordam(Stored Procedure) gibi veritaban
nesnelerini oluturmakla grevlidir. Sz konusu betikler, bir SQL sunucusu zerinde altrlp
kullanlabilecei gibi, istenirse ilgili Workflow alma zamannHost eden uygulamann eriebilecei
dosya bazl bir veritaban zerindende altrlabilir. Biz rneimizde ikinci seenei kullanacaz.
Yani, sz konusu depolama alan iin SQL Express Edition temelli bir veritaban dosyasn ele
alacaz. Bu amala ilk olarak Solution' mza bir Database Project ekleyerek devam edebiliriz.
Proje eklenmesi srasnda bize aadaki ekran grntsnde olduu gibi kullanmak istediimiz
veritaban sorulacaktr.

www.bsenyurt.com Page 46
Elimizde byle bir veritaban olmadn gz nne alaraktan Add New Reference seeneine
tklayalm. Srekli kullandmz standart balant ekleme iletiim kutusu ile karlacaz. Burada
nemli olan veri kayna olarak Microsoft SQL Server Database File (SqlClient) tipinin
seilmesidir. Sonrasnda ise veritabanmza bir isim vererek devam edebiliriz.

Ok dmesine bastmzda sz konusu veritaban yoksa eer, oluturmak isteyip istemediimize


dair bir soru sorulacaktr. Bu oluturma ilemi srasnda unutulmamas gereken noktalardan
biriside SQL Express servisinin alyor olmas zorunluluudur. Eer servis almyorsa tahmin
edilecei zere sz konusu veritaban oluturulamayacaktr. Database projesi oluturulduktan

www.bsenyurt.com Page 47
sonra yukarda deindiimiz SQL betiklerini Create Scripts klasr altna ekleyerek devam
edebiliriz. Bu ilemler sonrasnda proje ierii aadakine benzer olacaktr.

(Buradaki gibi bir veritaban projesinin oluturulmas aslnda art deildir. Bu sadece sz konusu
veritabannn ynetimin kolaylatrlmasn salayan ve belirli bir dzeni tesis eden bir opsiyon
olarak grlmelidir. Genel olarak gerek hayat uygulamalarnda depolama alan olarak sunucu bazl
veritabanlar tercih edilir. Sizlere tavsiyem ayn rnei SQL sunucusu zerinde gerekletirmeye
almanzdr.)

Sradaki ilem, sz konusu SQL betiklerinin altrlmasdr. Bu betikler altrldktan


sonra CostFactoryPersistenceDb isimli veritabannn ierii aadaki ekilde grld gibi
oluturulacaktr.

www.bsenyurt.com Page 48
Burada temel
olarak Workflow rneklerinin saklanmas(Insert), kilitlenmesi(lock), elde edilmesi(retrieve
) veya silinmesi(delete) ile ilikili gerekli Stored Procedure' ler ve tablolar yer almaktadr.
Artk depolama alanda tanmlandna gre, Workflow uygulamamz iin gerekli kod
deiikliklerini yapabiliriz. Bu amala host uygulama zerindeSqlWorkflowPersistenceService' in
oluturulmas ve alma zamanna eklenmesi gerekmektedir. te rnek kodlarmz;

using System;
using System.Collections.Generic;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;

namespace WFCostFactory
{
class Program
{
static WorkflowRuntime wfRuntime = null;
static AutoResetEvent wHandle = null;

www.bsenyurt.com Page 49
static void Main(string[] args)
{
// Workflow Runtime nesnesi rneklenir
using(wfRuntime = new WorkflowRuntime())
{
// Varsaylan ayarlar ile persistence servisi rneklenir
SqlWorkflowPersistenceService persistenceService = new
SqlWorkflowPersistenceService
(
@"Data Source=.\SQLEXPRESS;AttachDbFilename=C:\Documents and
Settings\Burak Selim Senyurt\My Documents\CostFactoryPersistenceDb.mdf;Integrated
Security=True;Connect Timeout=30;User Instance=True"
);
// Oluturulan servis alma zamanna bildirilir.
wfRuntime.AddService(persistenceService);
//Dier kod satrlar...

lk olarak System.Workflow.Runtime.Hosting isim alannda(namespace) yer


alan SqlWorkflowPersistence hizmetine ait bir nesne rnei oluturulur. Nesne
rneklenirken yapcmetod(Constructor) ierisinde persistence iin kullanlacak veri depolama
alann balant bilgisi verilmektedir. Bu en basit yapc metodu versiyonudur. Dier versiyonlarn
kullanarak farkl balang ayarlamalar yaplabilir. Sz gelimi Workflow rneklerinin Idle moda
getiklerinde bellekten kaldrlp kaldrlmayacaklar, birden fazla Workflow alma zaman
moturunun ayn WF rneklerini kullanmalar halinde, birbirlerini kesmemeleri iin kilit
srelerinin(Lock Time) ne olaca gibi kriterlerde yapc metod parametreleri ile belirlenebilir.

Servis tanmlamas ile ilgili ayarlar istenirse konfigurasyon dosyasnda da yaplabilir.


Bunun iin host uygulamaya ait konfigurasyon dosyasnda rnein aadaki
tanmlamalarn yaplmas yeterlidir.

www.bsenyurt.com Page 50
Tabi host uygulama ierisinde WorkflowRuntime nesne rnei
oluturulurken wfRuntime=new WorkflowRuntime("WorkflowRuntime"); eklinde
bir kullanm sz konusudur. Burada parametre
olarak app.config dosyasndaki section ad verilmektedir. Bu ad benzersizdir. Yani farkl
bir isim olamaz. Dier taraftan yapc metodun bu versiyonunun altrlabilmesi
iin(rnein gelitirdiimiz Console uygulamasnda) mutlaka System.Configuration
assembly' nn projeye referans edilmesi gerekmektedir.

Artk uygulamamz test etmeye balayabiliriz. Konuyu kolay takip edebilmek amacyla
gelitirdiiniz rnei Debug ederken adm adm ilerlemenizi neririm. ncelikle programn
almas sonrasndaki ekran grntsne bakalm.

Dikkat edilecei zere Workflow rnei faaliyetsiz hale getikten sonra(WorkflowIdled olaynn
tetiklenmesi sonras) srasyla WorkflowPersisted, WorkflowUnloaded olaylar almtr. Bir
baka deyile faaliyetsiz kalan Workflow rnei veritabanndaki ilgili tablolara yazlmtr. Dier
taraftan faaliyetsiz kalma sresi dolduunda ve Workflow ak tekrar devam etmek istediinde
srasyla WorkflowLoaded ve WorkflowPersisted olaylar tetiklenmitir. Yani WF rnei

www.bsenyurt.com Page 51
tablodan tekrar yklenerek yrtlmeye devam etmi ve son olarakta tamamlanmtr. zellikle
Workflow faaliyetsiz hale geldiinde InstanceState isimli tabloda aadaki ekran grntsne
benzer olacak ekilde bir satr ald ve Delay sresi sona erdikten sonra ise WF rneinin tekrar
ayaa kaldrlmasyla birlikte sz konusu satrn silindii grlr.

Tahmin edilecei zere bu satr saklanan WF rneine ait bilgileri seriletirerek tutmaktadr. Bu
nedenle zellikle WF ierisinde kullanlan tiplerin, eer SQL Persistence hizmeti kullanlyorsa
seriletirilebilir olmalarna dikkat etmek gerekmektedir. Bu durumu analiz etmek
iin Costflow aktivitesine Customer isimli tipten bir zellik eklenmitir.

using System;
using System.Workflow.Activities;

namespace WFCostFactory
{
public enum WorkType
{
Consumer,
Corporate
}
public class Customer
{
public string Name { get; set; }
public int Id { get; set; }
}
public sealed partial class Costflow : SequentialWorkflowActivity
{
#region Workflow zellikleri(Properties)

// D ortamdan gelen parametreler


public int TotalDays { get; set; }
public decimal CostValue { get; set; }
public WorkType WorkT { get; set; } // D ortama sonu olarak dndrlen parametre
public Customer Owner { get; set; }

#endregion

public Costflow()
{
InitializeComponent();
}
// Dier kod satrlar

Burada hemen bir noktay vurgulamak isterim. Sz konusu rnek bu haliyle altrldnda
seriletirme ile ilikili herhangibir hata mesajnn alnmad grlecektir. Bunun
nedeni Customer tipine ait nesne rneinin WF ierisinde kullanlmam olmasdr. Bu nedenle
Workflow nesnesi host uygulamada rneklenirken aadaki kod deiikliini yapmamz alma
zamannda seriletirme hatasn almamz iin gerekli ve yeterlidir.

WorkflowInstance instance = wfRuntime.CreateWorkflow(

www.bsenyurt.com Page 52
typeof(WFCostFactory.Costflow)
, new Dictionary<string,object>
{
{"TotalDays",20}
,{"WorkT",WorkType.Corporate}
,{"Owner",new Customer{ Id=1000, Name="Burak Selim enyurt"}}
}
);

rnek bu haliyle altrldnda aadaki grnt ile karlalr.

Dikkat edilecei zere, WorkflowPersisted olay metodunun hemen


arkasndan WorkflowTerminated olay tetiklenmi ve oluan istisna(Exception) mesaj ekrana
yazdrlmtr. Bir baka deyile Workflow rnei tabloya yazdrlamam ve istisna frlatarak
sonlanmtr. te bu durumun sebebi Owner isimli Customer tipinin binary formatta
seriletirilebilir tanmlanmamasdr. Bu nedenle Customer
tipinin Serializable nitelii(Attribute) ile aadaki kod parasnda grld gibi iaretlenmesi
gerekir.

[Serializable]
public class Customer
{
public string Name { get; set; }
public int Id { get; set; }
}

Uygulama tekrar denendiinde sorunsuz olarak alt hatta WF rnei oluturulurken parametre
olarak verilen Customer nesnesinin, WorkflowCompleted olaynda (tabloda saklanp tekrar elde
edilmesi ile birlikte) tedarik edilebildii grlebilir.

Grld zere Workflow rneklerinin, alma zamannda belirli koullarn salanmas artyla
bir depolama alannda saklanmas ve sonradan tekrardan ayaa kaldrlp yrtlmesi SQL
Persistence Service yardmyla son derece kolay bir ekilde gerekletirilebilmektedir. Elbetteki
gerek hayat koullarnda SQL d kaynaklarn kullanlmasda istenebilir. Bu gibi vakalarda sz

www.bsenyurt.com Page 53
konusu hizmet iin zel bir gelitirme yaplmas gerekmektedir. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnei ndirmek in Tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Mesaj Szlemeleri(Message Contracts) (


09.02.2009 ) - WCF
Deerli Okurlarm Merhabalar,

Servis tabanl uygulamalarda en nemli noktalardan biriside aradaki bilgi transferlerinin nasl ve ne
ekilde gerekletirildiidir. Gerek uki, bu bilgi transferinin oluma ekli ou zaman gelitiricinin
gznden kaan yada ok fazla ilgilenmedii bir konu olmaktadr. Nitekim ou servis gelitirme
arac buradaki sz konusu ieriin hazrlanmasn , gnderilmesini veya alnmasn
otomatikletirmektedir. zellikle Windows Communication Foundation tarafnda, bilginin
istemci ve servis arasndaki dolamnda balayc tiplerin(Binding Type) seilmesi ile zaten
arka tarafta ne ekilde bir haberleme olaca ve paketlerin nasl hazrlanaca belirlenmi olur.
Aslnda servis ve istemci tarafnda mesaj bazl bir iletiim olduu son derece aktr. Farkl
platformlar zerinde koan servislerin haberlemeleri yada farkl tipteki istemci uygulamalarn
servisleri kullanabilmeleri gerektiinde ise, aradaki haberlemenin bir standart zerinde ve esnek
olmas beklenir. Bu nedenle zellikle SOAP bazl web servisleri gz nne alndnda mesajn tipi
ve ieriide bellidir. te burada SOAP(Simpe Object Access Protocol) tarz mesajlardan sz
edilebilir. Tipik olarak SOAP mesajlar bir zarf olarak temsil edilmekte(SOAP
Envelope) veHeader, Body isimli iki paradan olumaktadr. Aadaki ekilde bu ierik temsil
edilmeye allmtr.

Peki bu mesajlarn makalemize konu olmasnn sebebi nedir? Bilindii zere WCF mimarisinde
eitli tipte szlemeler(Contracts) sz konusudur. rnein servislerin ne i yaptnn, nasl
fonksiyonellikler sunduunun ifade edilmesinde Sevis Szlemeleri(Service
Contracts) kullanlmaktadr. Benzer ekilde istemci tarafna
aktarlacakseriletirilebilir(Serializable) tipler sz konusu ise Veri Szlemeleri(Data
Contracts) tanmlanr. Yine istemci tarafna aktarlacak istisna mesajlarnn eitli durumlar iin
zelletirilmesi dnldnde Hata Szlemeleri(Fault Contracts) kullanlr. Ancak bu

www.bsenyurt.com Page 54
szleme eitleri dnda birde Mesaj Szlemeleri(Message Contracts) bulunmaktadr. te bu
yazmzn konusuda budur.

Yazmza servis odakl uygulamalarda mesajlarn yerini konumlandrmaya alarak baladk.


zellikle SOAP tabanl bu mesajlar gerektiinde zel olarak tasarlanabilirler. WCFtarafnda bunu
gerekletirebilmek iin Mesaj Szlemelerinden yararlanlr. Mesaj szlemelerinin ne zaman
kullanlacana karar verilmesi genellikle zordur. Farkl platformlar iin destek verebilme
imkan(Interoperability) ve mesaj kontrol ounlukla karar vermeyi kolaylatrmaktadr.
Gerektende servis tarafndan istemciye gnderilecek veya alnacak mesajlarn farkl platformlara
destek verebilecek ekilde tasarlanmas gerektii durumlarda zel Mesaj Szlemeleri gz nne
alnabilir. Dier taraftan Mesaj Szlemeleriile tanacak bilginin deiik
paralarnn SOAP paketinin Header veya Body ksmna ayrtrlmas ve bu sayede de, gerekli
olmayan paralarn mesaj ile birlikte tanmamas salanabilmektedir. Bu tam anlamyla aradaki
mesajlamann kontrol altna alnmas anlamna gelmektedir. Hatta, istemci ve servislerin belirli
olduu vakalarda, arada zel bir mesaj formatna gre veri ieriinin tanmasda mmkn olabilir.
Dier taraftan gz ard edilmemesi gereken bir noktada, mesaj seviyesinde gvenliktir. Mesaj
Szlemeleri kullanlrken bir tipin SOAP zarfnn ierisindeki yaylm belirlenebildii gibi(hangi
ksmlar Header' da olacak vb...) verinin ifrelenmeside(Encryption) zelletirilebilir. Bylece
vakaya gre bir mesaj deseninin oluturulmas ve kullanlmas mmkn olabilmektedir.

ou durumda Mesaj Szlemeleri yerine Veri Szlemelerininde ayn ii yapyor


olduu grlr. Ancak genel kanya gre, eer bir tip n sayda mesaj ierisinde
kullanlacaksa(yani reusable type olarak dnlebilirse) Veri Szlemesi olarak
tanmlanmas nerilmektedir.
Ancak tip(type) sadeceistek/cevap(Request/Respone) modeline gre bir kereliine
kullanlyorsa, Mesaj Szlemesi olacak ekilde tanmlanr.

Mesaj szlemelerinin uygulanmas son derece kolaydr. Ancak dikkat edilmesi gereken noktalar
vardr. Hereyden
nce MessageContract, MessageHeader, MessageBodyMember,MessageHeaderArray gibi n
iteliklerinden(attributes) yararlanlarak Mesaj Szlemesi tanmlanabilmektedir. Bununla
birlikte servis operasyonlarnda Mesaj Szlemelerinin kullanlmas sz konusu ise metod
yapsnda uyulmas gereken kurallar vardr. Buna gre metod desenleri aadaki rnekler olduu
gibi olmaldr. Bu tablodaki rnek kullanmlarda yer
alan ProductOrderResponse ve ProductOrderRequest isimli tipler rnek Mesaj Szlemesi
snflardr.

Geerli Mesaj Szleme Kullanmlar


[OperationContract] Operasyonun dn tipi
ProductOrderResponse CompleteOrderProcess(ProductOrderReques ve parametresi Mesaj
trequest); Szlemesi tipindendir.
Operasyon parametre
almamakta ve Mesaj
[OperationContract]
Szlemesi tipinden
ProductOrderResponse CompleteOrderProcess();
referans
dndrmektedir.
Operasyon Mesaj
Szlemesi tipinden
[OperationContract]
parametre almakta ama
void CompleteOrderPrococes2(ProductOrderRequest request);
deer
dndrmemektedir.
Geersiz Mesaj Szleme Kullanmlar
[OperationContract] Parametrenin Mesaj

www.bsenyurt.com Page 55
int CompleteOrderProcess(ProductOrderRequest request); Szlemesi olduu
durumlarda dn tipi
olarak Mesaj Szlemesi
harici bir tip
kullanlamaz. Exception
retir.
Birden fazla Mesaj
[OperationContract]
Szlemesi parametre
void
olarak
ComplteOrderProcess(ProductOrderRequest request1,ProductOrderR
kullanlamaz. Exception
equest request2);
retir.

Bu ksa teorik bilgileri devam ettireceiz ancak dilerseniz basit bir rnek zerinden ilerleyerek
devam edelim. ncelikli olarak bir WCF Snf Ktphanesi projesi oluturduumuzu dnelim.
Bu projemizde yer alacak olan tiplerin snf diygramndaki grnts aadaki gibi tasarlanabilir.

Snf diyagram(Class Diagram) gzmz korkutmasn. Senaryomuz aslnda


sadece Mesaj Szlemelerinin nasl kullanlacan gstermeye ynelik olduundan ok anlaml
olmayan operasyonlar iermekte. Bu yzden rnek olarak bir sipari srecine zel mesajlar
tasarladmz bir durum sz konusu. Kullanlan tiplerin ierikleri srasyla aadaki gibidir;

Product Snf. (Veri Szlemesi-Data Contract olarak tanmlanmtr)

www.bsenyurt.com Page 56
using System;
using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace = "http://Northwind/ProductTransferService/Product")]
public class Product
{
[DataMember(Order=0)]
public int ProductId { get; set; }
[DataMember(Order=1)]
public string Name { get; set; }
[DataMember(Order=2)]
public double ListPrice { get; set; }
[DataMember(Order=3)]
public DateTime OrderDate { get; set; }
}
}

CustomerNumber yaps-struct.(Veri Szlemesi-Data Contract olarak tanmlanmtr)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace =
"http://Northwind/ProductTransferService/CustomerNumber")]
public struct CustomerNumber
{
[DataMember]
public char Region { get; set; }
[DataMember]
public int Number { get; set; }
[DataMember]
public string LastName { get; set; }
}
}

Receiver Snf(Veri Szlemesi olarak tanmlanmtr)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace="http://Northwind/ProductTransferService/Receiver")]
public class Receiver
{
[DataMember]
public int ReceiverId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public CustomerNumber Number { get; set; }
[DataMember]
public int RequestedProductCount { get; set; }

www.bsenyurt.com Page 57
}
}

Sender Snf.(Veri Szlemesi olarak tanmlanmtr)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace = "http://Northwind/ProductTransferService/Sender")]
public class Sender
{
[DataMember]
public int SenderId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public CustomerNumber SenderNumber { get; set; }
}
}

RequestStatus Enum sabiti.(Veri Szlemesi olarak tanmlanmtr. Enum sabiti sz konusu


olduu iin deerler DataMember yerine EnumMember isimli nitelik ile iaretlenmitir.)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace =
"http://Northwind/ProductTransferService/RequestStatus")]
public enum RequestStatus
{
[EnumMember]
Ok,
[EnumMember]
Error,
[EnumMember]
Waiting
}
}

Buraya kadar tanmladmz tipler ierisinde snf, yap ve enum sabiti tipleri sz konusudur. Bu
tipler birer Veri Szlemesi olarak tanmlanmtr ve MesajSzlemeleri ierisinde ele
alnmaktadr. Yazmzn konusu olan Mesaj Szlemelerinden iki adet tanmlanmaldr. Bu
tanmlamalardan birisi istek(Request) dier isecevap(Response) ieriklerinin yapsn iaret
etmektedir. Bir baka deyile, istemciden servise gelecek veya geriye dndrlecek
olan SOAP zarflarnn ierikleri kod yardmyla belirlenmektedir. stemci tarafndan gelecek olan
taleplere ait Mesaj Szlemesi aadaki kod parasnda olduu gibi tanmlanmtr.

using System;
using System.ServiceModel;

namespace ProductTransferLib
{

www.bsenyurt.com Page 58
[MessageContract]
public class ProductOrderRequest
{
#region Header Ksmna yazlacak zellikler

[MessageHeader]
public Guid OrderNumber { get; set; }
[MessageHeader]
public DateTime OrderDate { get; set; }
[MessageHeader]
public Product OrderedProduct { get; set; }

#endregion

#region Body ksmna yazlacak zellikler

[MessageBodyMember(ProtectionLevel=System.Net.Security.ProtectionLevel.None)
] // ProtectionLevel iin varsaylan dere None' dur.
public Sender OrderSender { get; set; }
[MessageBodyMember]
public Receiver[] Receivers { get; set; }

#endregion
}
}

ProductOrderRequest isimli snf bir Mesaj Szlemesi olacak ekilde tanmlanmtr. Bu


nedenle MessageContract nitelii ile imzalanmtr. Bu nitelik
sadece snf(Class) veya yaplara(Structs) uygulanabilir. Yazmzn banda
mesajn Header ve Body ksmlarndan bahsetmitik. Header ksmnda tanacak
olan alan(Field)veya zellikleri(Property) belirtmek iin MessageHeader nitelii
kullanlmaktadr. rnektende grld gibi, Header ksmnda Guid, DateTime gibi bilinen tipler
dndaProduct isimli gelitirici tanml bir snfada yer verilmitir. Sz konusu tipler mesaj ierisine
alnrken seriletirilmektedir. Bu nedenle Product snf ve dier gelitirici tanml tipler
birer Veri Szlemesi olarak tanmlanmtr. Body ksmnda yer alacak zellik veya alanlar
ise MessageBodyMember nitelii ile tanmlanrlar.
Yine Body ksmndada, Sender ve Receiver isimli gelitirici tanml Veri Szlemelerine yer
verilmektedir. zellikle Receiver tipinden bir Array kullanldnada dikkat edilmelidir.

Header veya Body ksmlarnda Array' ler


kullanlyorsa MessageHeader ve MessageBodyMember nitelikleri bu dizilerin
elemanlarn bir elementin alt elementleri(Child Element) olacak ekilde
konumlandrr. rnein;

<diziAdi>
<diziElemanTipiAdi>ierii</diziElemanTipiAdi>
<diziElemanTipiAdi>ierii</diziElemanTipiAdi>
</diziAdi>

Ancak istenirse her bir dizi elemannn ayr birer boum olarak ele alnmas salanabilir.
Bunun iin MessageHeaderArray nitelii kullanlr.

<diziAdi>ierii</diziAdi>
<diziAdi>ierii</diziAdi>

www.bsenyurt.com Page 59
Yanlz bu nitelik sadece dizilere uygulanabilir. Bir baka
deyile koleksiyonlara uygulanamamaktadr.

Eer SOAP ieriinde byte tipinden bir diziye yer


verilmise MessageHeader veya MessageBodyMember niteliklerinin kullanlmas
halinde bunlar dorudan Base64 tipine dntrlrler. Ancak,
eer MessageHeaderArray nitelii kullanlyorsa, ele alnan seriletirme tipine
gre(DataContractSerializer, XmlSerializer gibi) bir aktarm gerekletirilir.

MessageHeader ve MessageBodyMember niteliklerinde yer alan ProtectionLevel zellii


kullanlarak dijital olarak
imzalama(Sign) veya ifreleme(Encryption) salanabilir.ProtectionLevel zellii System.Net
.Security.ProtectionLevel enum sabiti tipinden bir deer alabilir. Bu
deerler None, EncryptAndSign, Sign olabilir. Varsaylan deeri None' dur. Signseilirse dijital
imzalama sz konusudur. EncryptAndSign seilirsede ifreleme ve dijital imzalama sz
konusudur. Elbette None dndaki deerlerin ie yaramas iin WCF alma ortamna ynelik
olaraktan gerekli Binding ve Behavior ayarlamalarnn yaplmas gerekir. Aksi durumda alma
zamannda dorulama ilemi srasnda bir istisnas alnr. ProtectionLevel, Header ksmnda her
bir eleman iin ayr ayr uygulanmaktadr. Body ksm sz konusu olduunda ise ka eleman olursa
olsun hepsi iin aynProtectionLevel seviyesi sz konusudur. Buna
gre MessageBodyMember nitelii iinde seviyesi yksek olan ProtectionLevel deeri, dierleri
iinde uygulanr. Sz gelimi 3 farklMessageBodyMember iin
srasyla None, EncryptAndSign, Sign deerleri belirlenmise, tm mesaj gvdesi
iin EncrptyAndSign seenei gz nne alnmaktadr.

SOAP ile ilikili web servisi standartlarnda 1.1 versiyonu iin Actor ve 1.2 iin Role ad
verilen bir zellik yer almaktadr. Bu zelliin deerini WCF tarafnda ele almak
iin MessageHeader niteliinin Actor zellii kullanlr. Bunun
dnda MustUnderstand ve Relay zelliklerindende yararlanlarak, SOAP standarlarna
gre baz niteliklerin mesajlama srelerine kazandrlmas da salanabilir.

stemciye gnderilecek cevap mesajnn ierii ise ProductOrderResponse isimli Mesaj Szlemesi
ile tanmlanmaktadr.

using System.ServiceModel;
using System;

namespace ProductTransferLib
{
[MessageContract]
public class ProductOrderResponse
{
[MessageBodyMember]
public RequestStatus Status { get; set; }

[MessageBodyMember]
public DateTime ProcessDate{ get; set; }

[MessageBodyMember]
public byte[] OrderPicture { get; set; } // Burada byte[] tipinden bir dizi sz konusu olduu
iin SOAP body' si ierisinde Base64 tipinden bir kodlama(encoding) sz konusu olacaktr

[MessageHeader]
public int OrderdProductCount { get; set; }

www.bsenyurt.com Page 60
}
}

ProductOrderResponse tipi Mesaj Szlemesi olarak tanmlanrken ama istemci tarafna


gnderilecek olan SOAP mesajnn Header ve Body ksmlarnda neler olacana karar
verilmesidir. Dikkat edilecei
zere Body ksmnda RequestStatus enum sabiti, DateTime ve byte[] dizisi tipinden bir ierik
yer almaktadr. Dier taraftan Header ksmnda ise rnek olarak int veri tipinden bir deer
dndrlmektedir.

Bir tipin hem MessageContract hemde DataContract olacak ekilde tanmlanmas da


mmkndr. Byle bir vakada, WCF alma zamannda servis operasyonlar
uygulanrken, sz konusu tip iin Mesaj Szlemesi kriterleri gz nne alnmaktadr.

Artk istemci ve servis arasnda dolaacak olan SOAP mesajlarna ait ierikler tanmlanmtr.
Dolaysyla bu mesajlama modelini kullanacak bir Servis Szlemesi ve uygulayc snf
tasarlanabilir. Dikkat edilecei zere Servis Szlemesinde yer
alan CompleteOrderProcess isimli operasyonun dn tipi ve parametresi
birer MesajSzlemesidir.

using System.ServiceModel;

namespace ProductTransferLib
{
[ServiceContract(
Name="ProductTransferService"
,Namespace="http://Northwind/ProductTransferService")]
public interface IProductTransferService
{
[OperationContract]
ProductOrderResponse CompleteOrderProcess(ProductOrderRequest request);
}
}

Operasyonun uygulan iinse aadaki gibi bir kod rnei gelitirilebilir.

using System;
using System.IO;

namespace ProductTransferLib
{
public class ProductTransferService
:IProductTransferService
{
#region IProductTransferService Members

public ProductOrderResponse CompleteOrderProcess(ProductOrderRequest request)


{
DateTime requestDate = request.OrderDate;
Guid requestOrderNumber = request.OrderNumber;
Sender requestSender = request.OrderSender;
Receiver[] requestReceivers = request.Receivers;

www.bsenyurt.com Page 61
int orderedProductCount = 0;
foreach (Receiver receiver in requestReceivers)
{
orderedProductCount += receiver.RequestedProductCount;
}

// Not : XP_HDD.gif resminin byte ieriinin dizi boyutu istemci tarafna gnderilebilecek
varsaylan dizi limini aabilir. Bu nedenle istemci tarafndaki konfigurasyon ayarlarnda
maxArrayLength deerinin bilinli olarak arttrlmas gerekebilir.
return new ProductOrderResponse
{
ProcessDate=DateTime.Now,
Status= RequestStatus.Ok,
OrderPicture=File.ReadAllBytes(System.Environment.CurrentDirectory
+ "\\XP_HDD.gif"),
OrderdProductCount=orderedProductCount
};
}

#endregion
}
}

Burada request deikeninden yararlanlarak istemci tarafndan gelen SOAP paketindeki mesaj
ierii ele alnmakta ve kullanlmaktadr. Sembolik olarak paket ierisinde
gelenReceivers dizisindeki her bir Receiver nesne rneinin sipari saysnn toplam tespit
edilmektedir. Ayrca rnek byte[] ierii dndrlmesi iin kk bir resim
dosyasndan(XP_HDD.gif) yararlanlmaktadr. lemin tarihi, durumu, sipari ile ilikili resim ve
toplam sipari says bilgileri kullanlaraktanda bir cevap mesaj oluturulmakta ve istemci tarafna
gnderilmektedir.

SOAP mesajlarnn ierikleri aslnda XML tabanldr. Bu ierii


ynetirken Mesaj Szlemeleri, nesne tabanl bir modeli ele alabilmemizi
salamaktadr. Bir baka deyile, kod tarafnda XML yaps ile uramak yerine, nesne
tabanl bir modeli kullanarak mesaj ieriini kolayca oluturabilmemiz olanakl hale
gelmektedir ki bu gelitirme sreci iin nemli bir avantajdr.

Bu ilemlerin tamamlanmasnn ardndan servis ktphanesini Host edecek basit bir uygulama
gelitirilebilir. Biz rneimizde her zaman olduu gibi, sunucu ve istemci taraflar iin
birer Console uygulamas gelitiriyor olacaz. Sunucu uygulama kodlar ve konfigurasyon ierii
aadaki kod paralarnda olduu gibi tanmlanabilirler.

Sunucu uygulama kodlar;

using System;
using System.ServiceModel;
using ProductTransferLib;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{

www.bsenyurt.com Page 62
ServiceHost host = new ServiceHost(typeof(ProductTransferService));
host.Open();
Console.WriteLine("Servis dinlemede.\nKapatmak iin bir tua basnz.");
Console.ReadLine();
host.Close();
}
}
}

Sunucu taraf konfigurasyon ierii;

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ProductTransferServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ProductTransferServiceBehavior"
name="ProductTransferLib.ProductTransferService">
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="" name="ProductTransferServiceHttpEndPoint"contract="Produc
tTransferLib.IProductTransferService" />
<endpoint address="Mex" binding="mexHttpBinding"
bindingConfiguration="" name="ProductTransferServiceMexEndPoint" contract="IMeta
dataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://buraksenyurt:1000/ProductTransferService"
/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

Sunucu uygulama basit olarak HTTP tabanl bir sunum yapmakta ve BasicHttpBinding balayc
tipini ele almaktadr. Bununla birlikte istemci tarafnn, servise ait Metadata bilgisini ekebilmesi
iin IMetadataExchange arayzn kullanan bir MexHttpBinding EndPoint' ide
kullanlmaktadr.

stemci uygulamamz kullanrken yine Add Service Reference seenei ile


ayn solution ierisinde yer alan rnek servise ait referans retimini gerekletirebiliriz. stemci
tarafna ait konfigurasyon ierii aadaki gibidir(Bu ierik Add Service Reference seeneinin
kullanlmas sonucunda otomatik olarak retilmektedir.)

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


<configuration>
<system.serviceModel>

www.bsenyurt.com Page 63
<bindings>
<basicHttpBinding>
<binding name="ProductTransferServiceHttpEndPoint" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="163840" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""
/>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://buraksenyurt:1000/ProductTransferService"
binding="basicHttpBinding" bindingConfiguration="ProductTransferServiceHttpEndPoint
"
contract="ProductTransferServiceReference.ProductTransferService"
name="ProductTransferServiceHttpEndPoint" />
</client>
</system.serviceModel>
</configuration>

stemci tarafndaki rnek kod ierii ise aadaki gibidir.

using System;
using System.IO;
using ClientApp.ProductTransferServiceReference;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
ProductTransferServiceClient client = new
ProductTransferServiceClient("ProductTransferServiceHttpEndPoint");

Sender sndr = new Sender


{
Name="Burak Selim",
SenderId=10001,
SenderNumber=new CustomerNumber{ Number=1, Region='A',
LastName="SENYURT"}
};

Receiver[] receivers = {
new Receiver{ Name="Bil", Number=new CustomerNumber{ LastName="Geyts",
Region='B', Number=1}, ReceiverId=10002, RequestedProductCount=100},
new Receiver{ Name="Deyv", Number=new CustomerNumber{ LastName="Masteyn",
Region='C', Number=2}, ReceiverId=10003, RequestedProductCount=150},

www.bsenyurt.com Page 64
new Receiver{ Name="Co", Number=new CustomerNumber{ LastName="Satriyani",
Region='C', Number=3}, ReceiverId=10055, RequestedProductCount=75}
};

RequestStatus requestStatus;
DateTime processDate;
byte[] orderPicture;

Console.WriteLine("Sipari iin bir tua basnz.");


Console.ReadLine();

int result=client.CompleteOrderProcess(
DateTime.Now,
Guid.NewGuid(),
new Product{ ProductId=1, Name="Her
Ynyle WCF", ListPrice=10, OrderDate=DateTime.Now},
sndr,
receivers,
out orderPicture,
out processDate,
out requestStatus);

Console.WriteLine("result {0}",result.ToString());
File.WriteAllBytes(System.Environment.CurrentDirectory + "\\ResponsePicture.gif",
orderPicture);

Console.WriteLine("lemler tamamland. kmak iin bir tua basnz.");


Console.ReadLine();
}
}
}

stemci uygulamada servise ait proxy nesnesi rneklendikten


sonra CompleteOrderProcess metodunun ihtiyac olan parametreler
hazrlanmaktadr. CompleteOrderProcess metodu
aslnda ProcessOrderResponse Mesaj Szlemesi tipinden bir parametre almaktadr. Ne varki
istemci tarafnda metodun uygulan ekli biraz farkldr. Hereyden nce, servise
gnderilecek SOAP paketi ierisinde yer alacak Header ve Body elementlerinin her biri, istemci
tarafnda ayr birer metod parametresi ekline ele alnmaktadr. Metodun arlmas sonucu
istemciye dnecek olan SOAP mesajndaki Header ksmnda yer alan int deer aslnda istemci
tarafnda, CompleteOrderProcess' in dn deeridir. Yine istemciye dndrlen
ve Body ksmnda yer alan orderPicture,processDate ve requestStatus deikenleri
ise, CompleteOrderProcess metodunun out tipinden parametreleri olarak ele
alnmaktadr. orderPicture deikeni bir byte[] dizisi olarak mesaj ieriinden toparlanmakta ve
fiziki olarak istemci tarafndaki bir dosyaya yazdrlmaktadr. Bu tahmin edilecei zere servis
tarafndan gnderilen resimdir. Projemizde hem sunucu hemde istemci uygulamamz
altrdmzda aadaki ekran grntsnde yer alan sonular elde ederiz.

www.bsenyurt.com Page 65
Aslnda burada artc bir sonu yoktur. Nesne tabanl olacak ekilde istemci ve servis arasndaki
tipler kolay bir ekilde kullanlmtr. Ancak bizim iin nemli olan arka planda hareket
eden SOAP mesajlarnn ieriklerinin ne hale geldiidir. Bu
amala Fiddler isimli HTTP Debugging aracndan yararlanrsak, rnein altrlmas sonrasnda
a trafiinde, aadaki ekran grntsnde yer alan mesajlamann olutuunu grrz.

Dikkat edilecei zere, Mesaj Szlemelerinde Header ve Body ksmlarnda hangi bilgilerin yer
almasn istiyorsak buna gre bir aa yaps olumutur. Request ksmna ait
olan SOAP zarfnn XML ierii tam olarak aadaki gibidir.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>

www.bsenyurt.com Page 66
<h:OrderDate xmlns:h="http://Northwind/ProductTransferService">2009-02-
08T01:53:03+02:00</h:OrderDate>
<h:OrderNumber xmlns:h="http://Northwind/ProductTransferService">9476df3d-0f74-4643-
9fcf-b7344d5da37d</h:OrderNumber>
<h:OrderedProduct xmlns:h="http://Northwind/ProductTransferService"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ProductId xmlns="http://Northwind/ProductTransferService/Product">1</ProductId>
<Name xmlns="http://Northwind/ProductTransferService/Product">Her Ynyle
WCF</Name>
<ListPrice xmlns="http://Northwind/ProductTransferService/Product">10</ListPrice>
<OrderDate xmlns="http://Northwind/ProductTransferService/Product">2009-02-
08T01:53:03+02:00</OrderDate>
</h:OrderedProduct>
</s:Header>
<s:Body>
<ProductOrderRequest xmlns="http://Northwind/ProductTransferService">
<OrderSender xmlns:a="http://Northwind/ProductTransferService/Sender"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Name>Burak Selim</a:Name>
<a:SenderId>10001</a:SenderId>
<a:SenderNumber
xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>SENYURT</b:LastName>
<b:Number>1</b:Number>
<b:Region>65</b:Region>
</a:SenderNumber>
</OrderSender>
<Receivers xmlns:a="http://Northwind/ProductTransferService/Receiver"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Receiver>
<a:Name>Bil</a:Name>
<a:Number xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>Geyts</b:LastName>
<b:Number>1</b:Number>
<b:Region>66</b:Region>
</a:Number>
<a:ReceiverId>10002</a:ReceiverId>
<a:RequestedProductCount>100</a:RequestedProductCount>
</a:Receiver>
<a:Receiver>
<a:Name>Deyv</a:Name>
<a:Number xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>Masteyn</b:LastName>
<b:Number>2</b:Number>
<b:Region>67</b:Region>
</a:Number>
<a:ReceiverId>10003</a:ReceiverId>
<a:RequestedProductCount>150</a:RequestedProductCount>
</a:Receiver>
<a:Receiver>
<a:Name>Co</a:Name>
<a:Number xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>Satriyani</b:LastName>
<b:Number>3</b:Number>
<b:Region>67</b:Region>
</a:Number>

www.bsenyurt.com Page 67
<a:ReceiverId>10055</a:ReceiverId>
<a:RequestedProductCount>75</a:RequestedProductCount>
</a:Receiver>
</Receivers>
</ProductOrderRequest>
</s:Body>
</s:Envelope>

Bu XML ierii incelendiinde tam olarak Mesaj Szlemesinde belirttiimiz kriterlere uyulduu
grlmektedir. Sz
gelimi Header ksmnda OrderDate, OrderNumber veOrderProduct elementleri yer
almaktayken, Body ksmnda ProductOrderRequest elementi tarafndan sarmalanm
olan, OrderSender ve Receivers elementleri
bulunmaktadr.Receivers aslnda Receiver[] dizisinin kullanlmas nedeni ile kendi ierisinde
birden fazla Receiver alt elementi iermektedir. Burada gelitirici tanml
tiplerin(Product,Receiver,Sender gibi) Veri Szlemesi olarak tanmlanmalar
nedeniyle XML elemetleri ierisine aktarlm olmalarda gzden karlmamaldr. Yine
istemciye dnen mesajn(Response)tam ieriine bakldnda aadakine benzer
bir SOAP kts ile karlalmaktadr.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:OrderdProductCount
xmlns:h="http://Northwind/ProductTransferService">325</h:OrderdProductCount>
</s:Header>
<s:Body>
<ProductOrderResponse xmlns="http://Northwind/ProductTransferService">
<OrderPicture>R0lGODlhIAAgAPcAAAAAAB8hNR4hODMpHCQgLiIkNyYqRysvUC4wQy
0wTi0xUzU3SzE1VjE1WzU5Xjs
+VDw/WDU6Yzk+ZTk/bDg5dTFILDl0FzpGRz5BXD5CYz1CbD5EdVYzLXI/SF9OMF1
WP05tK0JoN0pxNVF5JVR1M2lfPn
FHKn5GP3VpL31vN31wL3d0OEZIVkZUSUFFY0FGbURIZEZKaklLYExPaEJIek1SaEx
Td1VWalNXd1prWFp1Rl96bWRcS
2JNYGtrRnhuRGdlaGNkdmh5eTc3mDxDxT5P2Dxdxj5d3T9g1z9r40VMg0pRiVZbhFR
bl1hkilljl0Nxr0h2t1tlqFVzqGFmjW
ZpgWtthGlti2Npl25xiGd6l25xkG1ym3ByhnN0inl2h3N2kXF2m3R4lnR5mXp8lWNqq2p
zp2xzsXN5q3l+pXp/qnR7tEFW0E
Jt0EN85l+fGkmLJ0mSIVOKJFWJNVeXJFqpH1y2GFqiJGOWKWK3Hm2oIV6KVFnFGGn
NF3POGnrSGWHJIHbNInvQIHiDiH
qAonyCuH6Qr0qK3kOF7EeP8EqU8Vua6lWb8miW1XGYzWWk8XSq73et8H+x8YM2N
5oxJ7MsG4pfPIN4K5J7LpR0OKFV
KaB2HbB+FYNtQpp8eKRNR7JyRtAqE+UsEfg+D/Q2ENRNE9dyH8F0NuxHD/pJDfxWDO
1+HP1lDv12EbeDC7OaFKmUIqm
XNruDK72nEKyMfoHSHYTRJMeKCMiRCN+GH9WWBc2xDNqjA8GnIv2GE/uaF/CGIf2W
IOCrBOS1BfqlHPq0HfysIfu3I+vG
A/fXBPrcFvzeKfzeOP3gOIKDj4yDlZCCkYaKrYGHs4CGu4SJtYWLvYqPtIiNuo6TvJWXp
pGVu5+ivoiOwIySwpGWxJSZxJ
ecyJmdxJmeyJ2hw52iy4i28JK88aGlxqGmzKSpzqmsyaar0Kmt0a6xzK2x07a4zbG11bS4
17a52Lq907m92ZzC8b7B3K3J
7aXH8MTG3MjL4c7R5dHT5gAAAAAAAAAAACH5BAEAAP8ALAAAAAAgACAAAAj/AP8JH
EiwoMGDCNvNsCcvHjx37tixW
5cuHTpy5MSB++atW7UM2BDaszduGxkyXrp0AWMFTBYrYqpY+8bxmxpu0xDSs5eGTIIX
DjRIcCBBgoYAWxCE4ditG45
q1Q7mo0ePEJkFCAoM8GCCA4ECBWAsCAOuo1OPB/nJgzdP3z5auY4Ra6UK1ad3+aaKa1r
NBreoBvM5hLf21K9jv+iOCu
VlkLhv1TxWe1ponsF58DK707bKWDFfrFKRopRDzpwdY8II2QMHS2WD9B5C9BRMri9Vojvo

www.bsenyurt.com Page 68
oGOnT58/f/pYoFLonMF0E
CeCClZsLm5RN0bw/g2cTwUsa74ZRAdP4jhTxIr9/2KlalSlG3Tq8KHeh88DJ2uobU+QThw0YLI
yWdJUitSk0nX4VosgfcT
BhAsNoGHQQ9es8wwLNzjhhA01nNADCXTk0YcftgQCSAhmwGeGQe6MQ006UjhyTzmPJGLEEl
yAcIeGgXTIBwtrPLHGG
QXls04Y6URziDn4lMMIIkcM8cUNLcjxhh54iHABE2tg8QSPBOmDDhbsmPFIPfVEwogbR1CQyS2Y
8LAACx9ckoIZa5SBA
5YDtUMOF+JAAQk+5jyiSBJEBMEJL8Mko0wzyiRTghlnYNFEGe0Q5A453VATRTlFPoLkEEDowgsyh
jKTDDIxnHHGE2WU
oQ5BF4lDyCL14P8jphtsUNCJLsIkY+gyybzChKlnpGoNQdpoNEUjhmjxBBRtEPHCJroUmswyia5wJTep
SiHfQN885gQLz4
BBhRMwUHDDLZ/q2oyuLEgjTqplSFEGQeBsRA013dCTDzloUBGEK8KAqgyvu1hRDbxSSPEEQZA11c01
3HTjDj/6qNPFD
7DM0kssKDzwaLwJN9HEQO9QY8A13fxVzTTTFFJIN95EcwUONdCwBKogS6GEAiMPhFxEE1Fk0UXhFB
0
OTdqEow022i
zN9IgDMbCBEgUYoEADEUQwAQ00NKCAAgd8DfbUSpQ9NQ4EZUCDElZnPcEGG3DttQNifz01EzgoYfM
VB
ME9sLYBAhj
QgAZxr+2113XH7cMKeivhBUHZxBADBA9U/gAGGLjgAgYZYO555pprHgMNCJVu+umop6766gcFBAA7
</OrderPicture>
<ProcessDate>2009-02-08T01:53:03.46875+02:00</ProcessDate>
<Status>Ok</Status>
</ProductOrderResponse>
</s:Body>
</s:Envelope>

Gzden kamayacak olan nokta OrderPicture elementinin ieriidir :) Tahmin edilecei zere bu
elementin ierii, servis tarafndaki resmimizin byte[] dizisi haline geldikten sonra, SOAPmesaj
ieriine Base64 kodlamasna gre seriletirilmi halidir. Bu ierik, istemci tarafnda ters
seriletirilme ileminden sonra yine byte[] dizisi olacak ekilde ele alnabilmektedir. Bunlarn
haricinde Header ksmnda OrderProductCount elementinin, Body ksmnda
ise ProductOrderResponse elementi ile sarmalanm
olan OrderPicture, ProcessDate ve Statusalt elementlerinin olduu grlmektedir.

Mesaj Szlemelerinde ele alnan bir dier durumda trlendirilmemi versiyonlarn


kullanlmasdr(Untyped Message Contracts). Burada System.ServiceModel.Channels isim
alannda yer alan Message snf ele alnmaktadr. SOAP 1.1 ve SOAP 1.2 uyumlu mesajlar iaret
edebilen bu snf yardmyla, istemciden gelen talepler ele alnabilir ve cevaplar
oluturularak Message tipinden rnekler zerinden kar tarafa gnderilebilir. Son olarak bu
durumu deerlendirip makalemizi tamamlayalm. Bu amala Servis Szlememizeaadaki
ekran grntsnde yer alan yeni bir operasyon ilave ettiimizi dnelim.

www.bsenyurt.com Page 69
RunProcess isimli operasyon parametre ve dn deeri olarak Message tipini kullanmaktadr. Sz
konusu operasyon metodunun ProductTransferService ierisindeki uyarlamas ise aadaki gibi
yaplabilir.

// Untyped Message alp veren rnek servis operasyonu metodu.


public Message RunProcess(Message request)
{
// Servise gelen Untyped Message ' n Body ksmnda yer alan Product dizi ieriini elde etmek
iin GetBody metodunun generic versiyonundan yararlanlr.
Product[] products = request.GetBody<Product[]>();

// stemciye dndrelecek Untyped Message' n Body ksmnda yer alacak rnek Product ierii
iin dizi oluturulur.
Product[] resultSet=new Product[products.Length];

// Gelen mesajn Body ksmndan elde edilen dizi zerinde rnek ilemler yaplr.
// rnekte ListPrice bilgisi 1 birim arttrlmtr.
for (int i = 0; i < products.Length; i++)
{
products[i].ListPrice += 1;
resultSet[i] = products[i];
}

// Operasyondan dndrelecek olan Untyped Message oluturulur.


// lk parametre SOAP versiyonunu belirtir. rnein "SOAP 1.1".
// kinci parametre servis operasyonunda ReplyAction zelliine atanan deerdir.
// nc parametre ise Body ksmnda yer alacak olan nesne rneidir.
Message response = Message.CreateMessage(request.Version,
"ReplyAction",resultSet);

// Untyped Message geriye dndrlr.


return response;
}

RunProcess isimli servis operasyonu, istemciden gelen mesajn Body ksmnda yer
alan Product nesne verilerini ele almakta ve rnek olarak ListPrice deerlerini 1 birim arttrarak
geriye dndrmektedir. Metoda gelen trlendirilmemi mesajn gvdesindeki veri ieriini ele
alabilmek iin GetBody<T> metodundan yararlanlr. Tahmin edilecei zere metodun kulland

www.bsenyurt.com Page 70
generic tip zerinden bir XML ters seriletirme ilemi sz konusudur. Nitekim istemciden gelen
mesaj XML tipindedir ve kod ierisinde nesnel olarak kullanlmas gerekmektedir. Bunlara ek
olaraktan, servisin istemciye gnderecei trlendirilmemi mesajn retimi
iin, Message snfnn static CreateMessage fonksiyonundan yararlanlr. Metodun ar
yklenmi(overload) 11 farkl versiyonu bulunmaktadr. rneimizde kullandmz halinde, ilk
parametre ile SOAP versiyonu, ikinci parametre ile SOAP Action ad ve son olarak nc
parametre ilede Body ksmna gelecek olan nesne rnei belirtilmitir. Eklenen bu yeni
fonksiyonellik nedeniyle istemci tarafnda yer alan servis referansnnda gncellenmesi
gerekmektedir. Bu gncelleme ileminin ardndan RunProcess isimli operasyon istemci tarafnda
rnek olarak aadaki kod parasnda grld gibi kullanlabilir.

Console.WriteLine("\nUntyped Message\n");

// Gncel kanal implementasyonundan yararlanarak OperationContextScope nesnesi rneklenir.


// OperationContextScope nesnesinden yararlanarak gelen ve giden mesajlarn ierikleri
ynetilebilir, Header, Body gibi ksmlarna mdahale edilebilir.
using (new OperationContextScope(client.InnerChannel))
{
// Untyped mesaj ierisinde gnderilecek olan Product nesneleri iin bir dizi hazrlanr.
Product[] products =
{
new Product{ Name="Programming WCF", ListPrice=12, OrderDate=DateTime.Now,
ProductId=19},
new Product{ Name="Programming C# 3.0", ListPrice=16, OrderDate=DateTime.Now,
ProductId=21}
};

// stemciden servise gnderilecek olan Untyped Message hazrlanr.


// lk parametre mesaj versiyonudur. (SOAP 1.1 gibi).
// kinci parametre servis szlemesinde RunProcess operasyonunda belirtilen Action zelliinin
deeridir.
// nc parametre ise mesaj ieriinde gnderilecek olan seriletirilebilir nesne rneidir. Bu
rnekte Product tipinden bir dizi kullanlmaktadr.
Message request =
Message.CreateMessage(OperationContext.Current.OutgoingMessageHeaders.MessageV
ersion, "RequestAction", products);

// Operasyon ars yaplr ve parametre olarak hazrlanan Untyped Message rnei gnderilir.
// ar sonucu yine bir Untyped Message rneidir.
Message reply = client.RunProcess(request);

// Servisten gelen Untyped Message ierisindeki Body ksmnda tutulan Product topluluunu dizi
olarak ele almak iin GetBody metodunun generic versiyonu kullanlr. Bunun sonucu olarak elde
edilen sonu Product tipinden bir dizi olacaktr.
Product[] response = reply.GetBody<Product[]>();

foreach (Product product in response)


{
Console.WriteLine(product.Name+" "+product.ListPrice);
}
}

stemci tarafnda RunProcess metodu arlmadan nce gnderilecek mesajn oluturulmas iin
yine CreateMessage static metodundan yararlanlmaktadr. Yine ilk parametre
olarak SOAP versiyonu, ikinci parametre olarak SOAP Action deeri ve nc parametre
olarakta Body ksmna seriletirilecek nesne rnei belirtilmitir. Servis tarafndan gelen mesaja ait

www.bsenyurt.com Page 71
Body bilgisinin okunmas iinde GetBody<T> metodundan yararlanlmaktadr. stemci tarafnda
dikkat edilmesi gereken noktalardan biriside tm bu ilemleri ierisine
alan Using blounda OperationContextScope nesnesinden yararlanlmas ve o
anki kanal(Channel) bilgisinin kullanlmasdr. rnek uygulamamz bu haliyle test edildiinde
alma zaman grnts aadakine benzer olacaktr.

Ancak elbetteki arka planda yer alan mesaj ieriine Fiddler arac yardmyla
bakldnda Body ksmnda hareket eden Product verilerinin ierii ak bir ekilde
grlebilmektedir.

www.bsenyurt.com Page 72
Dikkat edilecei zere Request mesajnda gnderilen Product nesnelerine
ait ListPrice deerleri, Response mesaj ierisinde 1 birim arttrlmtr. Eer
mesajlarn RAWieriklerine baklrsa SOAP Action bilgisininde set edilmi olduu grlebilir. (Size
tavsiyem GetBody metodlarna olan
arlarda BreakPoint kullanarak request ve responsedeikenlerinin alma zaman
ieriklerini QuickWatch ile izlemenizdir.)

www.bsenyurt.com Page 73
Eer istemciden talep gnderildikten sonra varsaylan olarak 1 dakikalk zaman dilimi
ierisinde servis tarafndan cevap gelmezse aadaki ekran grntsnde yer
alan TimeoutException istisnas ile karlalr.

Bu sorun SendTimeout deeri arttrlarak zmlenebilir. Bu sorun, uzun sren


operasyonlarn sz konusu olduu durumda dikkate alnmas gereken istisnalarn banda
gelmektedir.

www.bsenyurt.com Page 74
Buraya kadar yaptklarmza baktmzda, istemci ve sunucu arasndaki Mesaj ieriklerinin
ynetiminin Mesaj Szlemeleri yardmyla ele alnabildii sonucu ortaya kmaktadr. Buna gre
istenirse, istemci ve sunucu arasnda tanacak bir veri tipinin belirli paralarnn SOAP zarf
ierisindek Header veya Body blmleri arasnda ayrtrlmas mmkn olabilmektedir. Hatta,
istemci ve servis arasnda zel mesaj desenlerinin oluturulmas da sz konusu ve olasdr. Elbette
bu ii tamamlayc en nemli noktaifreleme(Encryption) ilemlerininde hesaba katlmasdr.
Buda yapld takdirde mesajn daha gvenilir bir ekilde ele alnmas ve korunmas mmkn hale
gelmektedir. Dier taraftan istemci ve servis arasndaki mesajlarn trlendirilmemi olmalar
halindede ele alnabildikleri ve ieriklerinin ynetilebildikleride ortadadr. MesajSzlemeleri ile
ilikili olarak daha detay bilgi almak iin, MSDN' de yaynlanan ierii takip etmenizi neririm.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim

rnei ndirmek in Tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Ado.Net Data Services Ders Notlar - 7 (Security)


( 02.02.2009 ) - WCF
Deerli Okurlarm Merhabalar,

Yazlm dnyasnn en nemli zorluklarndan biriside uygulamann kapsamna gre gvenliin etkili
bir ekilde nasl salanaca ile ilikilidir. Burada hassas bilgilerin korunmas, kullanclarn
tannmas ve yetkilendirilmesi, kodun eriim ilkelerinin belirlenmesi, verinin ifrelenmesi gibi pek
ok faktr sz konusudur. Genel anlamda gnvelik farkl ekillerde gz nne alnabilir.

Kimi zaman uygulama ierisinde kullanlan parametrik d ortam deikenlerini korumak


gerekir. rnein uygulamann kulland deikenlerin konfigurasyon(app.config,
web.config gibi) dosyasnda ifrelenerek saklanmas nemlidir ki bu pek ok uygulama
standardnnda ilkeleri arasnda yer almaktadr.
Kimi zaman uygulamann ierisindeki kodlarn ne tr ilemler yapabileceinin
belirlenmesi(Kode Eriim Gvenlii-Code Access Security) nemlidir. rnein
uygulamann, kurulduu sistem zerinde dosya yazma yetkisi olmamasnn salanmas,
yada sadece dosya okuma yapmasna izin verilmesi veya uygulama ierisinden a ortamna
balantya izin verilmemesi gibi.
Kimi zaman uygulamay aan kiilerin dorulanmas ve yapabileceklerinin snrlandrlmas
gerekir(Authentication/Authorization). rnein uygulamay ama yetkisi olan bir
kullancnn sahip olduu role gre her men seeneini kullanamamas gibi.

Vakalar ve gereklilikler oaltlabilir. Tek bir makine zerinde kendi bana alan uygulamalar iin
gvenliin salanmas nispeten daha kolaydr. Ancakistemci/sunucu(Client/Server) bazl
mimariye geildiinde gvenlii salamak her zamankinden dahada zor bir hal almaktadr. Bunun
en byk nedenlerinden birisi farkl ortamlar arasnda verinin, eitli protokollere gre mesajlar
zerinden transfer edilmesi gereklilii ve bu nedenle iletiiminde gvenli hale getirilmesinin
zorluudur. yleki, mesajlarn ifrelenmesi, iletiim kanalnn gvenli hale getirilmesi, aradaki
mesajlarn yakalanmas ve deitirilmesi ihtimaline karlk gerekli tedbirlerin alnmas gibi kstaslar
sz konusudur. Yine durum istemci ve sunucu tarafndaki uygulamalarn belirli olmalar halinde
biraz daha kolay bir ekilde ele alnabilir. Oysaki sunucu tarafnda bir servis uygulamasnn

www.bsenyurt.com Page 75
bulunmas ve buna herhangibir istemcinin balanabilecek olmas gibi durumlarda ulusal bir takm
gvenlik ilkelerine uygun olacak ekilde iletiimi salamak ve mesajlamak gerekmektedir.

Web servisleri gz nne alndnda bu tip gvenlik konularn kolay bir ekilde tesis etmek
adna WSE(Web Service Enhancements) alt yapsndan yararlanlmaktadr..Net
Remoting tabanl datk zmlerde sorumluluk neredeyse gelitiricinin kendisine aittir.
Ancak Windows Communication Foundation uygulamalar gz nne alndnda gvenlik, daha
kolay ve etkili bir ekilde iletiim(Transport) veya mesaj(Message) seviyesinde ele
alnabilmektedir ki bu kriterler u anda konumuz dndadr :)

Ado.Net Data Service' lerde temel olarak birer WCF servisidir. Bununla birlikte sz konusu
servisler bilindii zere istemcilere RESTful modele gre hizmet vermektedir.
Yani HTTPprotokolnn GET,HEAD,DELETE,PUT gibi metodlarn ele alp ATOM,XML,JSON gibi
standartlar kullanmaktadr. Basit bir servis olarak gz nne alndnda gvenlik konusunda
henz yeteri kadar gelimi olmad dnlebilir; mi acaba? te bu makalemizde daha ok bu
soruya cevap bulmaya alacaz.

Her eyden nce en nemli nokta Ado.Net Data Service' lerin veri kaynaklarn
istemciye RESTful modeline gre sunmasdr. Bu adan bakldnda gelitiricilerin daha ok
zerinde duraca nokta verinin eriilebilirliinin gvenli hale getirilmesidir. Dolaysyla Ado.Net
Data Service' leri kullanan istemcilerin, servis tarafnda bir
ekilde dorulanmas(Authenticate) ve sonrasnda durumlarna
baklarak yetkilendirilmeleri(Authorization) gvenliin salanmas adna nemlidir.
Oysaki Ado.Net Data Service rnekleri, aslnda herhangibir uygulama zerinde host edilebilecek
ekilde kullanlabilir. WCF kadar geni bir konsepti yoktur. Bu nedenle kural basittir; dorulama
ilemlerinin sorumluluu aslnda Ado.Net Data Service rneini host eden uygulamaya aittir. Bu
anlamda, servisin bir WCF projesinde veya bir ASP.NET uygulamasnda barndrlmas dorulama
ve yetkilendirme ilemlerinin daha kolay ele alnabilmesi asndan nemlidir. Ado.Net Data
Service' lerinde gvenlik 4 farkl alanda deerlendirilmektedir.

Gvenlik
Kriter Aklama
Alan

Servisi kullanacak olan istemcilerin dorulanmas


iin Host uygulama ortam ele alnr. Sz
Host uygulamaya ait Authentication
gelimiz ASP.NET uygulamas zerinde yaplan bir hosting
dorulama modeli (Dorulama)
ileminde built-in Membership API' si kullanlarak svc
dosyalarna olan eriim kstlandrlabilir.

Metod bazl operasyonlar yazlarak veriye olan eriim


Servis Operasyonlar
kstlandrlabilir. rnein HTTP Get metoduna gre
(Service
sadece tek bir sonuun elde edilmesine izin
Operations)
verilmesi(Single Result) salanabilir.

stemcinin talep ettii verinin elde


edilmesinden(Read) veya
Veri Kesmeleri
Authorization deitirilmesinden(Update,Insert,Delete) nce ilemin
(Data
(Yetkilendirme) kesilerek kstlamalarn yaplmas salanabilir. rnein
Interceptors)
kullancnn yetkisine gre sadece grebilecei rn
listesinin verilmesi gibi.

Servisin d ortama sunduu Entity rneklerinin ilenme


Entity Grnrl ekillerinin snrlandrlmasdr.
(Entity Visibility) rnein Product isimli Entity zerinde sadece yazma
ilemlerine izin verilmesi gibi.

www.bsenyurt.com Page 76
Buradaki kriterlerin uygulanmas ile bir Ado.Net Data Service ve ieriine olan eriim
yetkilendirilebilir. Aslnda teknik detaylar, gelitireceimiz rnein aralarna serpitirerek devam
edebiliriz. lk olarak bize bir test servisi gerekmektedir. Konuyu kolay ilemek adna Ado.Net
Entity Framework esini kullanaraktan Northwind veritabanndaki tm tablolar ele aldmz
dnelim. Sonrasnda ise basit bir Ado.Net Data Service esi gelitireceiz. Peki ama bu eyi
nerede barndracaz? te burada kullanc dorulamasn(Authentication) kolayca tesis
edebileceimiz bir Asp.Net uygulamasn gz nne alabiliriz. Elbetteki Asp.Net Web Site
Administration Tool' unu kullanaraktan bir ka test kullancs ve rol oluturmaktada yarar
olacaktr. rneklerimizde kullanacamz kullanc bilgileri aadaki gibidir.(rnekte SQL Express
Edition kullanlm ve bu nedenle ASPNETDB.MDF dosyas web sitesinin
olduu App_Data klasr altnda oluturulmutur.)

Kullanc ifre Rol

dealer1 dealer1.

dealer2 dealer2. Dealer

dealer3 dealer3.

region1 region1.
Region
region2 region2.

nemli unsurlardan biriside siteye olan ve amacmz gerei zellikle Ado.Net Data
Service elerine olan eriimi kstlamaktr. Yani siteye isimsiz kullanc(Anonymous User)girii
kesin olarak engellenmelidir. Aadaki ekran grntsde, web.config dosyasnda sz konusu
engelleme iin yaplm olan deiikliler ak bir ekilde grlebilir.

Dikkat edilecei zere Form tabanl dorulama kullanlmaktadr ve isimsiz kullanclarn sisteme
girmeleri yasaklanmtr.

Elbetteki Form Tabanl Dorulama(Form Based Authentication) art deildir.


zellikle Intranet sistemlerde Windows tabanl dorulama(Windows Based
Authentication)' da ele alnabilir. Hatta istenirse Passport Tabanl Dorulama da
etkinletirilebilir. Hangisi kullanlrsa kullanlsn, servisi host eden web sisteminin
dorulama yetenekleri, Ado.Net Data Service alma zaman tarafndan ele
alnabilmektedir.

Form tabanl dorulama sz konusu olduundan varsaylan olarak aksi belirtilmedike(Asp.Net


Gvenlik konularn hatrlayalm) Login.aspx isimli bir giri sayfasna ihtiyacmz olacaktr. Bu sayfa
zerinde yine Asp.Net bileenlerinden olan Login kontrol kullanlabilir.

www.bsenyurt.com Page 77
Sonu olarak servis tarafndaki projenin durumu aadaki ekilde olduu gibidir.

Dikkat edilecei zere servisi kullanacak olan kiilerin dorulanmas ilemini host uygulamann
kendisine vermi bulunmaktayz. Buna gre kullanclar herhangibir ekilde servis dosyasn talep
ettiklerinde, eer bir bilete sahip deillerse, otomatik olarak Login.aspx sayfasna
ynlendirileceklerdir. ASPNETDB.MDF veritaban dosyasnda yer alan ve etkin olan bir kullanc ile
sisteme girildinde ise, kodlama tarafnda karar vereceimiz yetkilendirmeler devreye girecektir.
Yani veriye olan eriim istenirse kullancya gre kstlandrlabilecektir. imdi bu durumlar analiz
etmeye alalm. Konuyu son derece basit bir ekilde ele
alacamzdan NorthwindDataService.cs kod ieriini aadaki gibi yazmamz imdilik yeterli
olacaktr.

using System;
using System.Data.Services;
using System.Linq;
using System.Linq.Expressions;
using System.ServiceModel.Web;
using System.Web;
using NorthwindModel;
using System.Collections.Generic;

www.bsenyurt.com Page 78
public class NorthwindDataService
: DataService<NorthwindEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
// Rol tabanl veri ekii ilemleri rnek olarak gsterilebilir;
HttpContext.Current.User.IsInRole();

config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetEntitySetAccessRule("Employees", EntitySetRights.ReadMultiple);
config.SetEntitySetAccessRule("Orders", EntitySetRights.WriteAppend);
config.SetEntitySetAccessRule("Customers", EntitySetRights.None);

config.SetServiceOperationAccessRule("CustomerCities",
ServiceOperationRights.All);
config.SetServiceOperationAccessRule("MySuppliers", ServiceOperationRights.All);

// Eer alttaki satr alrsa FilterForProducts metodu devre d saylr ve Products entity' sine
hi bir ekilde eriilemez.
//config.SetEntitySetAccessRule("Products", EntitySetRights.None);

[QueryInterceptor("Products")]
public Expression<Func<Products, bool>> FilterForProducts()
{
string name = HttpContext.Current.User.Identity.Name;

if (name == "dealer1")
return p => p.Suppliers.SupplierID == 1 || p.Suppliers.SupplierID == 2;
else if (name == "dealer2")
return p => p.Suppliers.SupplierID == 3;
else if (name == "dealer3")
return p => p.Suppliers.SupplierID == 1 || p.Suppliers.SupplierID == 2 ||
p.Suppliers.SupplierID == 7;
else
return p => p.Suppliers.SupplierID != null;
}

[ChangeInterceptor("Products")]
public void ProductChange(Products p, UpdateOperations operation)
{
switch (operation)
{
case UpdateOperations.Add:
break;
case UpdateOperations.Change:
if(!HttpContext.Current.User.IsInRole("Region"))
throw new DataServiceException(405,"UnitPrice iin bu deiiklie izin
verilmedi");
break;
case UpdateOperations.Delete:
break;
case UpdateOperations.None:
break;
default:

www.bsenyurt.com Page 79
break;
}
}

#region Service Operations

[WebGet]
public IQueryable<string> CustomerCities()
{
return (from c in this.CurrentDataSource.Customers
select c.City).Distinct();
}

// filter, orderby gibi operatrler ve key bazl eriim gibi sorgulara izin verilmez. Sadece entity
bazl eriim sz konusudur
[WebGet]
public IEnumerable<Suppliers> MySuppliers()
{
return from c in this.CurrentDataSource.Suppliers
orderby c.CompanyName
select c;
}

#endregion
}

lk olarak uygulamamz test etmeye altmzda Login.aspx sayfasna ynlendirildiimizi


greceiz. Bir baka deyile herhangibir isimiz kullanc, servise dorudan eriilmek
istendiinde http://localhost:1000/SecuritySolutions/login.aspx?ReturnUrl=%2fSecurity
Solutions%2fNorthwindDataService.svc adresine gnderilecektir ve dolaysyla dorulama
srecine girilmi olacaktr. Eer geerli bir kullanc bilgisi ile giri yapabilirsek bu durumda standart
olarak servise eriebildiimizi ve izin verilen sorgulamalar yapabildiimizi greceiz. imdi kodu
biraz analiz etmeye alalm. InitializeService metodu ierisine bakldnda Entity seviyesinde
baz yetkilendirmeler yapld grlmektedir.

config.SetEntitySetAccessRule("*", EntitySetRights.All);
config.SetEntitySetAccessRule("Employees", EntitySetRights.ReadMultiple);
config.SetEntitySetAccessRule("Orders", EntitySetRights.WriteAppend);
config.SetEntitySetAccessRule("Customers", EntitySetRights.None);

config.SetServiceOperationAccessRule("CustomerCities", ServiceOperationRights.All);
config.SetServiceOperationAccessRule("MySuppliers", ServiceOperationRights.All);

Buna gre tm Entity kmelerine eriim hakk izni, ilk satrdaki kod ile verilmitir. Bu
yetkilendirme, ilk satrdaki * ve EntitySetRights.All ile salanmaktadr. Ne varki ikinci
satrdaEmployees Entity ierii iin, ReadMultiple kstlamas yaplmtr. Buna
gre Employees kmesi zerinde rnein anahtar bazl sorgulara izin verilmeyecektir.
YaniEmployees(2) gibi bir talepte bulunulursa HTTP 403 Forbidden hatas alnr. Gerektende
durum Fiddler arac yardmyla izlendiinde aadaki ekran grntsnde yer alan sonular ile
karlalr.

www.bsenyurt.com Page 80
Dikkat edilecei zere istemci tarana dndrlen XML ieriinde Forbidden mesaj yazlmaktadr.
Ayn zamanda hata kodu 403' tr. Bu durum istemci uygulama tarafndan deerlendirilmelidir. u
anda ilk yetkilendirmemizi Entity seviyesinde yapm bulunuyoruz. Grld zere, tm Entity'
lere eriim hakk verilmi olmasna ramen Employeeszerinde bir kstlama uygulanmtr.
nc satrdaki kstlamaya gre Orders kmesi iin sadece yeni e eklenmesine izin
verilmektedir. Bu nedenle Orders entityierii yine tarayc zerinden sorgulanmak
istendiinde HTTP 403 Forbidden hatas alnacaktr. Ancak istemci bir uygulama tarafndan,
Orders isimli veri kmesine yeni elerin eklenmesi ilemine izin verilecektir. Son
olarak Customers Entity' sine herhangibir ekilde eriim izni kesinlikle verilmemektedir.
Nitekim EntitySeyRights enum sabiti iin None deeri verilmitir.

Lakin burada CustomerCities isimli bir operasyon iin izin verildii


gzlemlenmektedir. CustomerCities isimli operasyon string tabanl IQueryable tipinden bir
referans dndrmektedir. erideki sorgu cmlesine bakldnda Customers Entity' si

www.bsenyurt.com Page 81
ierisindeki City adlarnn Distinct fonksiyonu ile benzersiz olacak ekilde dndrld
grlmektedir. Dolaysyla Customers veri kmesini d ortama tamamen kapatp, kendisine ait
ehir adlarn istemciye sunan bir operasyon tanmlamas sz konusudur ki buda bir gvenlik tedbiri
olarak dnlebilir. Yine devam eden satrda MySuppliers isimli bir servis operasyonuna tm
haklar ile eriim izni verilmitir. Bu servis operasyonuna bakldnda
iseIEnumerable<Suppliers> tipinden bir referans dndrd grlmektedir. Operasyon
ierisindeki LINQ sorgusunda zel bir ifade yoktur. Ancak metodun dn
tipininIEnumerable olmasnn bir anlam vardr. Buna gre Suppliers tablosu
sorgulanrken filter, orderby gibi operatrler kullanlamaz. Ayrca anahtar bazl eriimlere de
(rneinSuppliers(2) gibi) izin verilmez. Sadece sonu kmesinin ham hali istemciye sunulur.
Buda sonu itibariyle bir kstlamadr. Nitekim alma zamanda
rnein, SupplierId deeri 3olan Supplier bilgisini almak istediimizde HTTP 400 Bad
Request hatasn aldmz grebiliriz.

www.bsenyurt.com Page 82
Bu IQueryable ve IEnumerable arasndaki fark biraz daha net bir ekilde grm bulunuyoruz.
Yanlz dikkat edilmesi gereken bir nokta vardr. Servis operasyonunun dndrd
bir Entity ierii var iken(rnein IEnumerable<Suppliers>) InitializeService metodu
ierisinde sz konusu tip iin EnititySetRights.None deerinin kullanlmas sonrasnda servis
almayacaktr. rneimizde Customers iin yaplan kstlamaya dikkat
edildiinde MyCustomers isimli operasyonun geriye string bazl bir sonu kmesi dndrd
grlmektedir. Bu servisin almasna engel olmamaktadr.

zellikle Entity tipleri ve servis operasyonlar iin yaplan eriim kstlamalarnda devreye
giren EntitySetRights enum sabitinin alabilecei deerler aadaki tabloda belirtildii gibidir.

EntitySetRights Deerleri

Entity kmesine eriilmesi yasaklanmtr. Metadata ierisinde grnmez ve zerine okuma


None
ilemleri yaplamaz.

ReadSingle Entity zerinde anahtar bazl(Key Based) aramalara izin verilir. (Customers('ALFKI') g

Entity ieriinin sorgulanmasna izin verilir, ancak anahtar bazl eriimlere izin verilmez.
ReadMultiple
rnein Employees(2) iin sonu kmesi elde edilemez.

WriteAppend Yeni Entity rnekleri eklenebilir.

WriteMerge Var olan Entity ierii gncellenirken birletirilme ilemi uygulanr.

WriteReplace Var olan Entity ierii yenisi ile deitirilerek gncellenir.

WriteDelete Silme ilemine izin verilir.

AllRead ReadSingle ve ReadMultiple deerlerinin birleimidir.

AllWrite WriteInsert, WriteUpdate ve WriteDelete deerlerinin birleimidir.

All Tam okuma ve yazma eriimine izin verilir.

Servis operasyonlarnda eriim kstlamalarn belirleyen ServiceOperationRights enum sabitinin


alabilecei deerler ise aadaki tabloda grld gibidir.

ServiceOperationRights Deerleri

None Servis operasyonuna eriim izni yoktur.

ReadSingle Tek bir veri esinin okunmasna izin verilir.

ReadMultiple Servis operasyonu kullanlarak birden fazla veri esinin okunmasna izin verilir.

AllRead Tekil veya oul veri elerinin okunmasna izin verilir.

All Servis operasyonu iin tm haklar salanr.

Kodumuzda ilerlediimizde, FilterForProducts ve ProductChange isimli iki metod ile


karlamaktayz. Bu metodlar veri kesme(Data Interceptor) fonksiyonellikleridir. Dikkat
edilecei zere FilterByProducts metodu ierisinde o anki kullancnn adna baklaraktan rnek
bir ieriin dndrlmesi salanmaktadr. Sz gelimi dealer2 isimli kullanc ile sisteme girildiinde
ve Products ierii talep edildiinde koddaki kesme metodunun ieriine
gre SupplierID deeri 3 olan listenin elde edildii grlr. zellikle durumu SQL Server
Profiler arac yardmyla incelendiinde gerektende kesme metodunun devreye girdii aikardr.

www.bsenyurt.com Page 83
Burada belkide en nemli nokta kesme ilemi srasnda, kullanc
bilgisinin HttpContext.Current.User.Identity.Name ifadesi ile alnmasdr. Bu tahmin edilecei
zere servisi kullanmak iin Login olan kullancnn addr.

rneimizde senaryoyu ok basit bir ekilde ele almak istediimizden kullanc adlarnn dealer1,
dealer2, dealer3 olmas halleri ele alnmtr. Oysaki gerek hayat senaryolarnda daha faydal bir
kesme ilemi yaplabilir. Bununla ilikili olaraktan sizlere bir altrma senaryosu rnei vermek
isterim. Sz gelimi, kullancnn hangi rnlere bakaca bilgisi, kullancnn dahil olduu blgeye
bal olabilir. Bu durumda ASPNETDB.MDF veritabannda yer alan kullanc bilgisi ile, kullanclarn
dahil olduu blgeleri tutan baka bir eletirme tablosu bu senaryo iin ok yararl olabilir. Bylece
kesme metodu ierisinde, eletirme tablosundan yararlanlarak, giren kullancnn sadece dahil
olduu blgeye ait rnleri grmesi salanabilir. Bunu kendi banza denemenizi ve yapmaya
almanz neririm.

rneimizdeki veri kesme metodlar(Data Interceptors) ierisinde servisin host edildii


uygulama ortamnn ieriinin kullanld grlmektedir. Burada Webortamnda
olunmasnn byk bir avantaj salad ok aktr. Nitekim, o
anki HTTP ieriine HttpContext zellii zerinden ulalabilmektedir. Bu sebepten
sisteme giri yapm olan kullancy tespit etmek son derece kolaydr. Ayrca Ado.Net
Data Service' lerin host edildii web ortamlarnda, Application,Session, Caching gibi
yaplarnda ele alnmas mmkn hale gelmektedir.

Gelelim ProductChange metoduna. Bu metod ierisinde giri yapan kullancn Region rolnde
olmas halinde deiiklik yapabilmesine msade edilmektedir. Eer giren kullancRegion rolnde
deilse istemci tarafna HTTP Statu Code 405 mesaj gnderilmektedir. Aslnda kesme
operasyonlarn daha net bir ekilde ele alabilmek iin bir istemci uygulama yazlmasnda yarar
vardr. Veri deitirme ilemleri srasnda devreye giren bu metodda nemli olan noktalardan
biriside UpdateOperations enum sabitinin kullanlmasdr. Bu sabitin deerine gre kullancnn
nasl bir operasyon gerekletirmek istedii kolayca tespit edilebilir. Metodun ilk parametresi kesme
operasyonunun kime uygulanacan iaret etmektedir. Buna gre sz konusu kesme
operasyonlar Products tipine uygulanabilir. Dier nemli bir noktada istemci tarafna HTTP
405 mesajnn DataServiceException tipinden bir nesne rnei frlatlarak gnderiliyor olmasdr.
ok doal olarak bu istisna tipinin istemci uygulama tarafndan ele alnyor olmas
gerekmektedir. (Yani istemci tarafnda try...catch...finally bloklar kullanlarak istisna ynetimi
yaplmaldr.)

www.bsenyurt.com Page 84
Sz konusu sistemde istemci uygulamann, servisten talepte bulunurken belirli bir kullanc bilgisini
gndermesi de arttr. Aslnda bu noktada Client Application Services' lerden
faydalanlabilinir.(Bu konu ile ilikili olarak daha nceki makalemi takip etmenizi
neririm) zellikle .Net tabanl istemcilerde stemci Uygulama Servisinin kullanlmasn neririm.
Tabi bunun iin servis tarafndaki konfigurasyon dosyasnda bir takm deiikliklerin yaplmas
gerekmektedir. Bu sebeple host uygulamann web.config dosyasnda aada yer alan eklemeleri
yapabiliriz.

...
<appSettings/>

<system.web.extensions>
<scripting>
<webServices>
<authenticationService enabled="true"/>
<roleService enabled="true"/>
</webServices>
</scripting>
</system.web.extensions>

<connectionStrings>
...

stemci uygulama tarafnda ise proje zelliklerinden(Properties), Services ksmna gememiz


ve gelitirdiimiz web uygulamasnn adresini iaret etmemiz yeterlidir.

Blyece istemci uygulamann dorulama(authentication) ve rol(role) ynetimi iin gelitirilen


web uygulamasnn yelik sistemini(Membership API) kullanlaca belirtilmi olur. rnek

www.bsenyurt.com Page 85
ierisinde Membership snfn kullanarak dorulama yapacamzdan System.Web.dll assembly'
nn servis referans ile birlikte istemci uygulamaya ekleniyor olmasda gerekmektedir.

Servis tarafnda isimsiz kullanclarn(Anonymous Users) sisteme giriini kapattmz


iin Add Service Reference ksmndan servise ait WSDL ieriini elde edemediimizi
grrz. Nitekim Visual Studio ortamnda sz konusu servis talep edildiinde
otomatikman web uygulamasnn authentication kural devreye girmekte ve
bizi Login.aspx sayfasna ynlendirmeye almaktadr. Hal byle oluncada servise
ulalamamakta ve referans elde edilememektedir.

rnekte servisin host edildii web uygulamasndaki deny user="?" ksm, istemci
uygulamayla ayn solution ierisindeki servis referans eklendikten sonra etkin hale
getirilmitir. Bu elbetteki istenen zm deildir ve ayrca daha sonrada servisin
gncelletirilmesi srasnda problemlere neden olmaktadr.

Dier taraftan datasvcutil arac yardmylada istemci taraf iin gerekli tipler retilmek
istendiinde benzer sonular ile karlalacaktr. Aadaki ekran grntsnde ilk
denemede anonymous kullanclarn geri evrildii senaryo sonras alnan uyar mesaj
grlmektedir. kinci deneme yaplmadan nce iseweb.config dosyasndaki deny
users="?" ksm allow users="?" olarak deitirilmi ve gerekli tiplerin retildii
grlmtr. Elbetteki buda istenen bir aktarm ekli deildir.

Bu noktada belkide servisin kullanlabilmesi iin, istemci tarafnca gerek duyulan proxy
tiplerinin nceden retilip, kullanacak olan uygulamalara datlmas yntemi tercih
edilebilir. Akas bu, servisi kullanacak olan istemcilerin belli olduu durumlarda
dnlebilecek bir senaryodur ki pek ok byk apl irket ii projede gz nne
alnabilir.

Bu arada istemci tarafndaki Console uygulamasnn ieriini aadaki gibi rnekleyebiliriz.

using System;
using System.Data.Services.Client;
using System.Linq;
using System.Net;
using ClientApplication.NorthwindServiceReference;
using System.Web.ClientServices;
using System.Threading;
using System.Web.Security;

www.bsenyurt.com Page 86
namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
NorthwindEntities entities = new NorthwindEntities(
new Uri("http://buraksenyurt:1000/SecuritySolutions/NorthwindDataService.svc")
);

entities.SendingRequest+=delegate(object sender,SendingRequestEventArgs e)
{
ClientFormsIdentity identity = Thread.CurrentPrincipal.Identity as
ClientFormsIdentity;
HttpWebRequest webRequest = e.Request as HttpWebRequest;
if (identity != null)
webRequest.CookieContainer = identity.AuthenticationCookies;
};

try
{
if (Membership.ValidateUser("dealer1", "dealer1."))
{
// QueryInterceptor iin istemci kodu
var tumUrunler = from urun in entities.Products
select urun;

foreach (var urun in tumUrunler)


{
Console.WriteLine(urun.ProductName);
}

// Http durum kodlar(Http Status Code) iin link-


> http://en.wikipedia.org/wiki/List_of_HTTP_status_codes

// ChangeInterceptor iin istemci kodu


var u = (from urun in entities.Products
where urun.ProductID == 1
select urun).First<Products>();
u.UnitPrice +=1;

entities.UpdateObject(u);
entities.SaveChanges();
}
}
catch (DataServiceRequestException excp)
{
string excpMessage = String.Format("Status Code : {0}\n Inner Exception Message :
{1} ",
((DataServiceClientException)excp.InnerException).StatusCode.ToString()
, excp.InnerException.Message
);
Console.WriteLine(excpMessage);
}
}
}

www.bsenyurt.com Page 87
}

Burada belkide en can alc nokta dorulama iin istemci tarafndan kullanc ve ifre bilgilerinin
nasl gnderildiidir. Dikkat edilecek olursa servise talep gnderilmeden nce ilgili dorulama
bilgileri yollanmaktadr. Membership snfnn ValidateUser metodu yardmyla kullanc
dorulandktan sonra ise entity talebinde bulunulmakta ve bir gncelletirme ilemi
gerekletirilmektedir. Uygulamay altrdmzda aadaki ekran grnts ile karlarz.

rn bilgileri alnrken servis tarafndaki FilterForProducts isimli veri kesme metodu devreye
girmi ve delaer1 iin SupplierID deerleri 1 veya 2 olanlar getirilmitir. Yine dikkat edilecek
olursa SaveChanges metodundan sonra servis tarafndaki ProductChange kesme metodunun
devreye girmesi sonucu istemciye hata mesaj dndrlm ve biristisna(exception) olumutur.
Bu son derece doaldr nitekim dealer1 kullancs Region rolnde deildir. Ancak
rnein region1 kullancs ile giri yaparsak bu durumdaSupplierID deeri null olmayan rnleri
ekebildiimizi ve ayn zamanda bunlardan ilkinin UnitPrice deerlerinide deitirebildiimizi
grrz. Hatta SQL Server Profiler arac ile arka plandaki sorgu durumunu izlersek aadakine
benzer bir sorgunun iletildiini kolayca izleyebiliriz.

exec sp_executesql N'update [dbo].[Products]


set [ProductName] = @0, [QuantityPerUnit] = @1, [UnitPrice] = @2, [UnitsInStock] = @3,
[UnitsOnOrder] = @4, [ReorderLevel] = @5, [Discontinued] = @6
where ([ProductID] = @7)
',N'@0 nvarchar(4),@1 nvarchar(18),@2 decimal(19,4),@3 smallint,@4 smallint,@5 smallint,@6
bit,@7 int',@0=N'Chai',@1=N'10 boxes x 20
bags',@2=22.0000,@3=39,@4=0,@5=10,@6=0,@7=1

rneklerdende grld zere Ado.Net Data Service' lerde gvenlii


salarken dorulama(Authentication) ve yetkilendirme(Authorization) adna yaplabilecek
belirli ilemler sz konusudur. Bu ilemler iin baz kurallarn uygulanmas gerekmektedir. Sz
gelimi servis operasyonlar gz nne alndnda, yazlacak olan metodlarda dikkat edilmesi
gereken kurallar unlardr.

Metodun public eriim belirleyicisine sahip olmas gerekmektedir.


Metodun dn tipi IQueryable<T> veya IEnumerable<T> olabilir.
Buradaki T, Entity tipidir. Eer operasyonun dndrd sonu kmesi
zerinde sralama,sayfalama, filtreleme gibi ilemler
yaplacaksa IQueryable<T> tipinin dndrlmesi gerekir.
HTTP Get metoduna uygun arlar iin WebGet, HTTP Post,Delete,Put gibi talepler
iinse WebInvoke nitelii(Attribute) kullanlmaldr.

www.bsenyurt.com Page 88
Benzer ekilde okuma ilemleri srasndaki kesme fonksiyonelliklerininde uygulamas gereken baz
kurallar vardr. Buna gre;

Metodun public eriim belirleyicisine sahip olmas gerekir.


Metoda [QueryInterceptor("EntityName")] niteliinin uygulanmas
gerekir. EntityName yerine kesme ileminin uygulanaca Entity tipinin ad verilir.
Metodun dn tipi Expression<Func<T,bool>> olmaldr. Func temsilcisinde yer
alan T entity tipidir.
Metod parametre almaz.
Metodun ileyii srasnda bir istisna(Excpetion) olusa bile istemci talebi tamamlanr ve
kendisine hata mesaj uygun HTTP Statu Code deeri ile dndrlr.

Eer kesme operasyonu veri gncellenmesi,eklenmesi veya silinmesi ilemleri srasnda


yaplacaksa, izlenilmesi gereken kurallar aadaki gibidir.

Metodun public eriim belirleyicisi olmaldr.


Metoda [ChangeInterceptor("EntityName")] nitelii uygulanmaldr.
Buradaki EntityName, entity tipinin addr.
Metodun dn tipi yoktur. Bu nedenle void olarak tanmlanr.
Metodun iki parametresi vardr. lki entity tipi ikincisi
ise UpdateOperations enum sabitidir. Bu enum sabiti ile metodu ierisinde deitirme,
silme, ekleme operasyonlar ele alnabilir.
Metodun ileyii srasnda bir istisna oluursa, istemciden gelen talep tamamlanr ve
kendisine uygun olan Http Statu Code deerine sahip hata gnderilir. Bu istisna
sonrasnda sunucu tarafndaki asl veri kaynanda herhangibir deiiklik kesinlikle olmaz.

Makalemizi sonlandrmadan nce nemli bir noktay daha vurgulamakta yarar vardr. Servisin
dorulanmas iin istemci tarafndan gnderilen kullanc ad ve ifre bilgileri ak metinler olarak
gitmektedir. Eer rnekler test edilirken Fiddler arac yardmyla arka plandaki paketler izlenirse
aadaki ekran grntsnde yer alan durum ile karalr.

www.bsenyurt.com Page 89
Bu nedenle en uygun zm servisin HTTPS tabanl bir iletiim zerinden hizmet vermesinin
salanmas olarak dnlebilir.

Bu yazmzda Ado.Net Data Service' lerde dorulama ve yetkilendirme ilemlerinin nasl ele
alnabileceini, bir baka deyile gvenliin nasl salanabileceini en temel hatlaryla incelmeye
altk. Ado.Net Data Service konusunda gelitirmeler devam etmektedir. Gvenlik ile ilikili
olaraktan farkl yaklamlarn getirilmeside bu nedenle sz konusu olabilir. Ancak en azndan, host
uygulamann bu ite nemli bir rol stlendii gzden karlmamaldr. Bu yazda kullanlan teknie
gre, dorulama ileminiAsp.Net Web uygulamas devralmtr. Size tavsiyem bunu
bir WCF sitesinden host ederkende gerekletiriyor olmanzdr. Konunun daha kolay pekimesi
adna aadaki grsel dersleride izlemenizi tavsiye ederim. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 90
Ado.Net Data Services-Security(1)

Ado.Net Data Services-Security(2)

Ado.Net Data Services-Security(3)

rnei ndirmek in Tklayn (Boyutun kk olmas iin ASPNETDB.MDF ve log dosyas


kartlmtr. Bu nedenle rnei deneyebilmek iin sz konusu veritabann Asp.Net Web Site
Administration Tool ile oluturmanz gerekmektedir.)

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Dayankl WCF Servisleri(Custom Persistence


Providers) ( 23.01.2009 ) - WCF
Deerli Okurlarm Merhabalar,

Hatrlayacanz zere bir nceki makalemizde, dayankl WCF servislerinin(Durable WCF


Services) nasl gelitirilebileceini incelemeye balamtk. Ksaca hatrlatmak gerekirse dayankl
WCF servislerini u ekilde tanmlayabiliriz; belirli bir sre iin durumlarn bir depolama alannda
saklayarak koruyabilen ve t sre sonrasnda istemci uygulama tarafndan brakld haliyle
kullanlabilen servisler. Konunun ilk aamasnda, varsaylan olarak SQL sunucusu zerindeki bir
depolama alannn kullanld senaryo zerinde durmutuk. (Hatrlayam, SQL sunucusu zerinde
veriyi saklamak ynetsel adan pek ok ii kolaylatrmaktadr.) Bu makalemizde ise kaldmz
yerden devam edeceiz ve aadaki iki soruya ynelik zmler gelitirmeye gayret edeceiz.

1- stemci uygulama servis rneini kullandktan sonra kapatlr(stemcinin kapatma ilemi


srasnda servis rneinin saklama alanndan silinmesini salayacak metodu armad varsaylr).
Bu durumda t sre sonrasnda istemci uygulama ayn servis rneinin ieriini kullanmak isterse
nasl bir sre izlenmeli ve kodlama yaplmaldr?

2- Varsaylan olarak kullanlan SqlPersistenceProviderFactory tipinin salad SQL tabanl


saklama stratejisi yerine zelletirilmi baka bir salayc kullanlabilir mi?(rnein servis rnekleri
dosya tabanl bir sistemde veya farkl bir veritaban zerinde saklanabilirler mi? Oracle,
Access vb.)

lk olarak 1nci sorumuza cevap arayarak yazmza devam edelim. Bilindii zere istemci uygulama,
servise ait bir proxy nesnesi rettiinde ve bunun zerinde baz uzak operasyonlar ardnda,
her iki taraf arasnda oturum(Session) bazl olarak dolaan bir InstanceId deeri sz
konusudur. Buna gre istemci uygulamann daha nceden depolama alanna att bir servis
ieriini tekrardan kullanabilmesi iin, depolama alannda duran bu servis
rneinin InstanceId deerine ihtiyac vardr. Bu deer bilindii zere servis tarafnda retilip
istemciye ierik ile birlikte gnderilir ve operasyon arlarnda karlkl olarak kullanlr. Dolaysyla
istemci uygulama, kullanmak istedii dayankl WCF servisine ait GUID tipinden
olan InstanceId deerine sahip ise, saklanan veri ieriini kullanp ilemlerine brakt yerden
devam edebilir. Bu noktada tabiki istemcinin doruInstanceId deerine sahip olmas nemlidir.

www.bsenyurt.com Page 91
Dier taraftan Exception olumasna neden olabilecek pek ok durum vardr. Sz gelimi istemci
uygulama servis rneinin depolama alanndan kaldrlmasna neden olan bir operasyon ars
yaptktan sonra, InstanceId deerini kullanarak ayn servisin ieriine kesinlikle ulaamaz. nk
servis tarafndaki depolama alannda bu InstanceIddeerine sahip ierik artk
bulunmamaktadr.(Hemen hatrlayalm, varsaylan olarak CompleteInstance=true deerine sahip
olan servis operasyonu, Instance ieriinin depolama alanndan silinmesine neden
olmaktadr.) Gelitirme srasnda bu ve benzeri istisnai durumlara dikkat edilmesi nemlidir. En
azndan istisna ynetim mekanizmalarndan yararlanlmal ve sistemin ileyii ok fazla
aksatlmamaldr.

imdi dilerseniz ilk sorumuzun cevabn bulmak iin kodlamaya yava yava geelim. Bu noktada
ilemleri daha kolay izleyebilmek adna bir nceki makalede gelitirdiimizCommonService isimli
serviste kk bir deiiklik yapyoruz. Sz konusu deiiklikler ile en byk amacmz, istemci
tarafnda CommonValue deerini takip ederek, ilk sorumuzu daha kolay analiz edebilmektir. Buna
gre IncreaseValue metodunun, servis ierisindeki CommonValue alannn deerini geriye
dndrmesini salyoruz. Tabi bu deiikliin hem servis szlemesinde hemde servis szlemesini
uyarlayan tipin ierisinde yaplmas gerekmektedir.

Servis tarafndaki szlemelerde deiiklik olmas halinde(rnein operasyonun dn tipi


veya parametrelerinde deiiklik yaplmas yada yeni operasyonlarn eklenmesi vb...) bu
hizmeti kullanan istemci uygulamalarn, servis referanslarn Update etmeleri mutlak
suretle gereklidir.

rneimizde servis ktphanesinde yapm olduu basit deiiklikler aadaki gibidir.

ICommonService isimli servis szlemesinde yaplan deiiklik;

[OperationContract]
int IncreaseValue(int value);

Servis szlemesini uyarlayan CommonService snfnda yaplan deiiklik;

[DurableOperation()]
public int IncreaseValue(int value)
{
commonValue += value;
return commonValue;
}

Gelelim istemci tarafna. stemci tarafnda bu kez basit bir Windows uygulamas kullanyor
olacaz. (stemci uygulamamz sadece test amaldr bu nedenle ok fazla beklentimiz olmamaldr
:) stemcimizin Form1 tasarm aadaki gibidir.

www.bsenyurt.com Page 92
stemci uygulamamzn kod ierii ise u ekildedir;

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using WinClientApp.CommonServiceReference;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace WinClientApp
{
public partial class Form1
: Form
{
private ServiceCommonClient client=null;

public Form1()
{
InitializeComponent();
// Proxy nesnesi rneklenir.
client = new ServiceCommonClient("WSHttpContextBinding_ServiceCommon");
lblStatus.Text = "Servis iin proxy nesnesi rneklendi";
Text += " (" + DateTime.Now.ToLongTimeString() + ")";
}

private void btnStart_Click(object sender, EventArgs e)


{
// Start metodu arlr. Bu metod ars ile servis tarafnda InstanceData tablosuna kayt
atlr.
client.Start();
lblStatus.Text = "Start metodu arld";
txtInstanceId.Text = client.GetInstanceId().ToString();
}

private void btnIncreaseValue_Click(object sender, EventArgs e)


{
// Sembolik olarak deer arttrm servis zerinden yaplr
lblCommonValue.Text=client.IncreaseValue(10).ToString();
lblStatus.Text = "IncreaseValue metodu arld";

www.bsenyurt.com Page 93
}

private void btnStop_Click(object sender, EventArgs e)


{
// Stop metodu arlr. Bu metod arldnda servis tarafnda InstanceData tablosunda
saklanan satr silinir
client.Stop();
lblStatus.Text = "Stop metodu arld";
}

// Daha nceden kayt edilmi bir instance' kullanmak iin aadaki kod paras kullanlr
private void btnGetContext_Click(object sender, EventArgs e)
{
// IContextManager iin System.WorkflowServices.dll assembly' nn referans edilmesi
gerekir
IContextManager conMng =
((IContextChannel)client.InnerChannel).GetProperty<IContextManager>();
IDictionary<string, string> context = conMng.GetContext();

if (!context.ContainsKey("instanceId"))
{
context.Add("instanceId", txtInstanceId.Text);
conMng.SetContext(context);
}
}
}
}

Bu uygulamada daha nceden depolanan bir servis rneine ulalmak


istendiinden, System.ServiceModel.Channels isim alanndaki IContextManager isimli
arayzden yararlanlmaktadr. Bu arayz System.WorkflowServices.dll assembly' ierisinde
yer aldndan sz konusu .Net Framework 3.5 ktphanesinin istemci uygulamaya referans
edilmesi gerekmektedir. rneimiz tabiki gelitiriciler iin yazlmtr. Son kullancya verildii
takdirde alma zamannda pek ok istisnann olumas muhtemel ve kanlmazdr.(Unutmayn u
anda bir test uygulamas gelitiriyoruz ve analiz yapmaya alyoruz.)

lk olarak servis ktphanesini(Bir nceki makalemizden hatrlayacanz gibi WCF ktphaneleri


otomatik olarak WcfSvcHost program yardmyla host edilebilmekte ve WcfTestClient ile test
edilebilmektedir.) ve windows uygulamamz altralm. Sonrasnda ilk olarak Start dmesine
basacaz. Ardndan IncreaseValue deerini arttrmak iin bir ka ilem yaptrlabiliriz. Ancak hi
bir ekilde Stop dmesine basmayacaz. Bu en nemli test noktamz. Nitekim Stop dmesine
baslmas sonrasnda servis tarafnda arlan operasyon, sahip
olduu DurableOperation niteliinin CompleteInstace zelliinin true deerine sahip olmas
nedeni ile instance' n kaldrlmasna neden olacaktr. Testin bu aamasnda uygulamamzn ekran
grntsde aadakine benzer olacaktr. Yine burada testin ikinci aamas iin nem arz eden
konulardan biriside servis tarafndan retilen InstanceId deeridir. Bu deeri saklamamz
gerekiyor.(Ltfen Form zerindeki tarihe dikkat edin.)

www.bsenyurt.com Page 94
Testimizin ikinci aamasnda uygulamamz kapatp ktmz dnelim. Eer veritabanna gider
ve InstanceData tablosuna bakacak olursak, servis rneinin satr baznda eklenmi olduunu
rahatlkla grebiliriz.

XML verisinde ise servis tarafndaki CommonValue deikeninin aadaki ekilde grld
gibi 41 olarak tutulduu gzlemlenebilir.

Gel zaman git zaman aradan uzunca bir sre geer ve biz ayn uygulamay bir kere daha altrrz.
Ancak bu sefer, Start metodu yerine daha nceden sakladmz
servisInstanceId deerini TextBox kontrolne ekleyip GetContext isimli metodu armalyz.
Buna gre daha nceden kayt edilmi olan servis rnein ieriinin kullanlmas iin ilk adm atm
oluruz ki uygulamann alma zaman ekran grntsde aadaki gibi olacaktr.

www.bsenyurt.com Page 95
Dikkat edilecek olursa uygulamay altrdmda Form' un Text' i zerinde saat bilgisi
olarak 00:16:51 yazmaktayd.(Gerektende ayn gnn akamnda rnei tekrardan altrdm
syleyebilirim). Ancak u anda saat 21:31:45 ve servis rneinin veritabannda kaytl olan
ieriini kullanaraktan, CommonValue deikeninin son deerini 51 olarak deitirmi
bulunuyoruz. Dolaysyla bir servisin nasl dayankl hale getirilebileceini ve bununla birlikte
istemcilerin daha nceki instance' lara nasl ulaabileceklerini grm olduk.

Elbetteki gerek hayat vakalarnda sz konusu instanceId deerlerini istemci tarafnda daha
dzenli bir ekilde saklamak gerekebilir. Belikde uygulama kapatlrken instanceId deeri
konfigurasyon dzeyinde saklanabilir ve bir sonraki alta deerlendirilerek istemcinin, servis
ieriinin son hali zerinden otomatik olarak devam etmeside salanabilir. Tahmin edeceiniz zere
dayankl WCF servisleri, Workflow tarzndaki uygulamalarda daha yaygn olarak kullanlmaktadr.
Nitekim WF uygulamalar kendi ilerinde zaten var olan bir srerlik yapsna sahiptir ve bir akn
anlk olarak uzun sreliine saklanmas mmkndr. yleki WCF servislerini dayankl hale
getirmek iinde Workflow' un ana assembly' larndan olan System.WorkflowServices.dll' dan
yararlanlmaktadr.

Gelelim makalemize konu olan ikinci sorumuza. zelletirilmi bir srerlik


salaycsn(Custom Persistence Provider) nasl gelitirebiliriz? Burada i biraz daha
zorlamaktadr. Bu konudaki en gzel rnek Microsoft tarafndan gelitirilmi olup MSDN den
indirip inceleyebilirsiniz. Biz ok daha basit haliyle ele alacaz ve bu nedenle zellikle asenkron
yaklamlar gz ard edeceiz.

lk olarak PersistenceProviders isimli bir snf ktphanesi(Class Library) oluturarak ie


balayabiliriz. Sz konusu ktphane ierisinde zel bir srerlik salaycs(Persistence
Provider) kullanacamz iin System.ServiceModel.dll, System.WorkflowServices.dll
assembly' larn referans etmemiz gerekiyor. Bunlarn haricinde rneimizde kullanacamz zel
salayc, alma zamanndaki servis rneklerine ait
verileri SOAP(SimpleObjectAccessProtocol) seriletirme yaparak saklayacaktr.

Elbetteki zel srerlik salaycsnn hangi tipte veri kayna ile alaca tamamen
gelitiriceye ve ortam artlarna baldr. Sadece dosya sistemi
deilOracle gibi SQL Server harici veritabanlar da kolaylkla ele alnabilir.

Biz rneimizde SOAP seriletirmesini


kullanacamzda System.Runtime.Serialization.Formatters.Soap.dll assembly' nnda snf
ktphanesine referans edilmesi gerekmektedir. Model temel
olarak Abstract Factory tasarm desenine uygun olarak gelitirilmelidir.

www.bsenyurt.com Page 96
Doruyu sylemek gerekirse biraz karmak grnen bir yap. Ancak incelendii takdirde
ierisinde asenkron operasyonlarn dahi yer aldn(ki bunun uyarlamalarn eklemedik
kodlarmza), Abstract Factory deseninin uygulandn rahatlkla grebiliriz. Bir baka
deyile XmlPersistenceProviderFactory snf, zel depolama ilemleri
iin XmlPersistenceProvider tipini rneklemektedir. Bu, WCF servislerinde zel salayclarn
retimi srasnda kullanlan standart yoldur. rnekte
kullandmzXmlPersistenceProviderFactory tipi, abstract PersistenceProviderFactory tipin
den tremektedir. Bu snfn ierisinde ezilmek(override) zorunda olan CreateProvider isimli
metod isePersistenceProvider tipinden bir referans dndrmektedir. rneimizde sz konusu
dn referans olarak PersistenceProvider snfndan tretilen XmlPersistenceProvidertipi
kullanlmaktadr. Buna ek olarak PersistenceProviderFactory tipi CommunicationObject' ten
tremektedir ve bu sebeptende CreateProvider haricinde ek metodlarda uyarlamaktadr. Sz
gelimi OnBeginClose, OnEndClose gibi metodlar
veya DefaulfCloseTimeout, DefaultOpenTimeout gibi zellikler CommunicationObject tipi
ierisinde abstract olarak tanmlandklarndan otomatik
olarak XmlPersistenceProviderFactory snfnada uygulanmaktadrlar. Ek
olarak, XmlPersistenceProvider tipinin ortaklaa kullanaca Create,Load,Update,Deletegibi
ilevselliklere ait metodlar, XmlPersistenceProviderFactory tipi ierisinde yer almaktadr. ki
snf arasndaki iletiimin salanmas amacyla XmlPersistenceProvider tipininyapc
metodu(Constructor Method) ierisine, XmlPersistenceProviderFactory snfnn alma
zaman referans aktarlmaktadr. Bylece XmlPersistenceProvidertipi ierisinden, factory

www.bsenyurt.com Page 97
snfnda tanmlanan genel yelere eriilebilir. (PersistenceProvider trevli snf
istenirse ProviderPersistenceFactory trevli snf ierisinde dahili tip-inner type olarakta
tasarlanabilir. Microsoft'un rneinde bu tarz bir kullanm sz
konusudur.) XmlPersistenceProviderFactory tipi ile rettii XmlPersistenceProvider snfnn
ierikleri ise aadaki gibidir.

XmlPersistenceProviderFactory ierii;

using System;
using System.ServiceModel.Persistence;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;

namespace PersistenceProviders
{
public class XmlPersistenceProviderFactory
: PersistenceProviderFactory
{
#region Gerekli Snf Deikenleri

// Servis rneklerinin saklanaca varsaylan klasr tutan deiken


private string fileStoragePath = Path.Combine(System.Environment.CurrentDirectory,
"Instances");
// Soap seriletirmesini yapacak olan SoapFormatter deikeni
SoapFormatter sFrmtr = null;
Logger lgr = null;
Guid InstanceId;

#endregion

#region Yardmc Metodlar

private string InstanceFileName()


{
// Dosya ad belirlenir. Ad belirlenirken ayrt edici olmas iin base snftan Id zelliinin
deeri kullanlr
string fileName = Path.Combine(fileStoragePath, InstanceId.ToString() + ".sxml");
return fileName;
}

#endregion

#region XmlPersistenceProvider snf iin kullanlan ortak CRUD metodlar

// Servis rnei iin depolama kaynann oluturulmas ve ieriinin seriletirilmesi amacyla


kullanlr
public object CreateInstance(object instance, TimeSpan timeout)
{
string fileName = InstanceFileName();

// Soap formatter tipinden yararlanlarak servis rneinin seriletirilmesi salanr


using (FileStream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
sFrmtr.Serialize(stream, instance);
}

www.bsenyurt.com Page 98
lgr.AddEventEntry(fileName + " iin Create ilemi yapld, Seriletirme gerekletirildi.",
System.Diagnostics.EventLogEntryType.Information);
return null;
}

// Servis rneinin depolama kaynann silinmesi amacyla kullanlr


public void DeleteInstance(object instance, TimeSpan timeout)
{
// Dosya ad elde edilir
string fileName = InstanceFileName();
// Eer dosya sistemde var ise
if (File.Exists(fileName))
{
// Dosya silinir
File.Delete(fileName);
// Silme bilgsi loglanr
lgr.AddEventEntry(fileName + " iin Delete ilemi yapld.",
System.Diagnostics.EventLogEntryType.Information);
}
else // yok ise
{
// Dosya sistemde bulunamadysa normal artlarn aksine baka bir nedenle silinmi
olabilir. Bu durum loga aktarlr
lgr.AddEventEntry(fileName + " sistemde bulunamadndan Delete ilemi yaplamad",
System.Diagnostics.EventLogEntryType.Warning);
}
}

// Kaydedilmi olan servis rneinin kaynaktan alnp kullanlabilir object haline getirilmesi
iin kullanlr
public object LoadInstance(TimeSpan timeout)
{
string fileName = InstanceFileName();
object result = null;
if (File.Exists(fileName)) // dosya mevcutsa
{
// loglama yap
lgr.AddEventEntry(fileName + " iin Load ilemi yapld",
System.Diagnostics.EventLogEntryType.Information);
// servis rneinin dosya ierisinde tutulan seriletirilmi rneini deSerialize ederk
geriye dndr
using (FileStream stream = new FileStream(fileName, FileMode.Open, FileAccess.Read))
{
result = sFrmtr.Deserialize(stream);
stream.Close();
}
return result;
}
else // dosya bulunamyorsa
{
// uyar mesaj niteliinde loglama yap
lgr.AddEventEntry(fileName + " sistemde bulunamadndan Load ilemi
gerekletirilemedi", System.Diagnostics.EventLogEntryType.Warning);
return null;
}
}

www.bsenyurt.com Page 99
// Kaynakta tutulan servis rneinin gncellenmesi ilemini gerekletirir.
public object UpdateInstance(object instance, TimeSpan timeout)
{
// Dosya ad alnr
string fileName = InstanceFileName();

// Soap formatter tipinden yararlanlarak servis rneinin seriletirilmesi salanr


using (Stream stream = new FileStream(fileName, FileMode.Create, FileAccess.Write))
{
// Gncellenen servis rnei tekrardan ayn dosya zerine seriletirilir
sFrmtr.Serialize(stream, instance);
}

lgr.AddEventEntry(fileName + " iin Update ilemi yapld, Seriletirme gerekletirildi.",


System.Diagnostics.EventLogEntryType.Information);
return null;
}

#endregion

public XmlPersistenceProviderFactory()
{
// Eer servis rneklerinin saklanaca varsaylan klasr yoksa olutur
if (!Directory.Exists(fileStoragePath))
Directory.CreateDirectory(fileStoragePath);

// Soap Formatter deikeni oluturulur


sFrmtr = new SoapFormatter();

// Loglama ilemini yapacak olan snf rnei oluturulur


lgr = new Logger("CustomXmlPersistenceProvider", "Custom Xml Persistence Log(WCF)");

lgr.AddEventEntry("XmlPersistenceProviderFactory rnei oluturuldu",


System.Diagnostics.EventLogEntryType.SuccessAudit);
}

public override PersistenceProvider CreateProvider(Guid id)


{
InstanceId = id;
return new XmlPersistenceProvider(id, this);
}

protected override TimeSpan DefaultCloseTimeout


{
get { return TimeSpan.FromSeconds(10); }
}

protected override TimeSpan DefaultOpenTimeout


{
get { return TimeSpan.FromSeconds(10); }
}

protected override void OnAbort()


{
}

www.bsenyurt.com Page 100


protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback
callback, object state)
{
return null;
}

protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback


callback, object state)
{
return null;
}

protected override void OnClose(TimeSpan timeout)


{
}

protected override void OnEndClose(IAsyncResult result)


{
}

protected override void OnEndOpen(IAsyncResult result)


{
}

protected override void OnOpen(TimeSpan timeout)


{
}
}
}

Grld gibi basit seriletirme(Serialization) ve ters-


seriletirme(DeSerialization) ilemleri gerekletirilmektedir. Bununla birlikte rnein bizim
iin(en azndan benim iin) kolay anlalabilir olmas adna asenkron metodlarn ierikleri
uyarlanmamtr.

XmlPersistenceProvider snfnn ierii;

using System;
using System.ServiceModel.Persistence;

namespace PersistenceProviders
{
public class XmlPersistenceProvider
: PersistenceProvider
{
XmlPersistenceProviderFactory XmlPrsFactory;

public XmlPersistenceProvider(Guid id, XmlPersistenceProviderFactory xmlFactory)


: base(id)
{
XmlPrsFactory = xmlFactory;
}

#region PersistenceProvider ve CommunicationObject yeleri

www.bsenyurt.com Page 101


// Servis rnei depolama alannda ilk oluturulduunda alr.
public override IAsyncResult BeginCreate(object instance, TimeSpan timeout,
AsyncCallback callback, object state)
{
return null;
}

// Silme ilemi baladnda devreye girer.


public override IAsyncResult BeginDelete(object instance, TimeSpan timeout,
AsyncCallback callback, object state)
{
return null;
}

// Ykleme ilemi baladndan devreye girer.


public override IAsyncResult BeginLoad(TimeSpan timeout, AsyncCallback callback,
object state)
{
return null;
}

// Servis rnei gncellemeye baladnda devreye girer


public override IAsyncResult BeginUpdate(object instance, TimeSpan timeout,
AsyncCallback callback, object state)
{
return null;
}

// Depolama alannda servis rneinin kayt altna alnmasnda kullanlr


public override object Create(object instance, TimeSpan timeout)
{
return XmlPrsFactory.CreateInstance(instance, timeout);
}

// Servis rneinin depolama alannda silinmesinin ele alnd metoddur


public override void Delete(object instance, TimeSpan timeout)
{
XmlPrsFactory.DeleteInstance(instance, timeout);
}

// Servis rneinin veri ieriinin depolama alanna ilk kayt edildii aamann sonunda
devreye giren metoddur
public override object EndCreate(IAsyncResult result)
{
return null;
}

// Servis rneine ait veri ieriinin depolama alannda silindii aamnn sonunda devreye
giren metoddur
public override void EndDelete(IAsyncResult result)
{
}

// Servis rnei verisinin depolama alannda ortama yklendii aamn sonunda devreye
giren metoddur

www.bsenyurt.com Page 102


public override object EndLoad(IAsyncResult result)
{
return null;
}

// Servis rnei verisinin depolama alannda gncelletirilmesi sonrasnda devreye giren


metoddur
public override object EndUpdate(IAsyncResult result)
{
return null;
}

// Servis rnei verisinin depolama alanndan ykenmesi aamasnn ele alnd metoddur
public override object Load(TimeSpan timeout)
{
return XmlPrsFactory.LoadInstance(timeout);
}

// Servis rnei verisinin depolama alannda gncelletirilmesi aamasnn ele alnd


metoddur
public override object Update(object instance, TimeSpan timeout)
{
return XmlPrsFactory.UpdateInstance(instance, timeout);
}

// Kapatma operasyonun tamamlanmas iin gereken varsaylan srenin belirlendii zelliktir


protected override TimeSpan DefaultCloseTimeout
{
get
{
return TimeSpan.FromSeconds(10);
}
}

// Ama operasyonunun tamamlanmas iin gereken varsaylan srenin belirlendii zelliktir


protected override TimeSpan DefaultOpenTimeout
{
get
{
return TimeSpan.FromSeconds(10);
}
}

protected override void OnAbort()


{
}

protected override IAsyncResult OnBeginClose(TimeSpan timeout, AsyncCallback


callback, object state)
{
return null;
}

protected override IAsyncResult OnBeginOpen(TimeSpan timeout, AsyncCallback


callback, object state)
{

www.bsenyurt.com Page 103


return null;
}

protected override void OnClose(TimeSpan timeout)


{
}

protected override void OnEndClose(IAsyncResult result)


{
}

protected override void OnEndOpen(IAsyncResult result)


{
}

protected override void OnOpen(TimeSpan timeout)


{
}

#endregion
}
}

Dikkat edilecei zere XmlPersistenceProvider tipi arlkl olarak CRUD ilemleri iin gerekli
olan zorunlu metod arlarn PersistenceProvider abstract snfndan
devralmaktadr. Create, Update, Delete ve Load isimli zorunlu olarak ezilen
metodlar, XmlPersistenceProviderFactory tipi ierisinde tanmlanm
olan CreateInstance, UpdateInstance,DeleteInstance ve LoadInstance fonksiyonelliklerini
armaktadr. Aslnda Factory snf kendisini kullanan birden fazla PersistenceProvider trevli
tipide ele alabilir. Hepsi iin ortak olabilecek pek ok fonksiyonellik fabrika tipi ierisinde
toplanabilecei gibi, PersistenceProvider trevli tiplerede yaylabilir. (Bence bu konuyu
aratrabilirsiniz. Tek birPersistenceProviderFactory trevli tip stnden birden
fazla PersistenceProvider trevli tipi kullanabilmek ve bunlar farkl vakalar iin ele alabilmek.)

Son olarak, ktphanemizde sreci, oluabilecek alma zaman hatalarn loglamak


amacyla Logger isimli birde yardmc snfmz bulunmaktadr. Bu snf yardmyla kodun gerekli
yerlerinde ilgili bilgileri gnlklere ileme ansna sahip oluyoruzki, gelitirme(Development) ve
zellikle test aamalarnda bu olduka iimize yarayacak bir zelliktir. Sz
gelimi WCF ktphanesinin bir Windows Servisi ierisinde host edilmesi halinde, hatalarn
ayklanmas iin ekstra aba sarfetmek gerekmektedir. Bu
nedenle WindowsServisinin host olarak kullanld bir senaryoda log kaytlar hayati bilgiler
verebilir ve hatalarn tespit edilmesi ok daha kolaylaabilir.

Logger snfmzn ierii ise aadaki gibidir;

www.bsenyurt.com Page 104


using System.Diagnostics;

namespace PersistenceProviders
{
/// <summary>
/// Loglama ilemleri iin yardmc snftr
/// </summary>
public class Logger
{
private string LogSource;

/// <summary>
/// Event Viewer ierisinde ayr bir log sekmesi oluturur
/// </summary>
/// <param name="logSource">Log verisinin kayna(Genellikle ilem ad yada program ad
olarak kullanlabilir)</param>
/// <param name="logName">Event Viewer altndaki boumun addr</param>
public Logger(string logSource, string logName)
{
LogSource = logSource;
if(!EventLog.Exists(logName))
EventLog.CreateEventSource(logSource, logName);
}

/// <summary>
/// Yapc metodda oluturulan log kaynana event yazdrr
/// </summary>
/// <param name="mesaj">Event ile ilikili bilgi</param>
/// <param name="entryType">Event in EventLogEntryType tipinden deeridir</param>
public void AddEventEntry(string mesaj, EventLogEntryType entryType)
{
EventLog.WriteEntry(LogSource, mesaj, entryType);
}
}
}

rnek srerlik salaycmz, uygulamann olduu yerde(yada serivis host eden uygulamann olduu
yerde) Instances adl bir klasr amaktadr.

Uygulamada dosyalarn kaydedilecei klasr bilgisi konfigurasyon seviyesinde de


tutulabilir. Hatrlayalm, SqlPersistenceProviderFactory salaycs kullanldnda
rneklerin saklanmas iin kullanlacak veritaban
balants, ConnectionString elementinin zerinden alnmaktadr.

alma zamanndaki servislere ait rnekler bu klasr altnda sxml uzantl olarak tutulmaktadr.
erikleri tahmin edilecei zere SOAP formatndadr. Dosya adlar servis rneine
ait InstanceId deerleri olarak verilmektedir. Ak son derece
basittir. DurableOperation niteliinin CanCreateInstance zelliinin deeri true olan operasyon
ars ile bu klasrde bir dosya oluturulmakta ve servis rneine ait ierik seriletirilmektedir.
Sonrasnda yaplan operasyon arlarnda bu dosya ieriinin ters seriletirilerek objectolarak elde
edilmesi ve ieriinin kullanlmas sz konusudur.
Yine DurableOperation niteliinin CompleteInstance zellii true olan operasyon arldnda
sz konusu servis rneine ait dosya, Instances klasrnden silinmektedir. Tabi istenirse sz
konusu dosyann silinmeyip yeniden isimlendirilerek rnein belirli sreliine sistemde tutulmas
gibi ilemlerde yaplabilir.

www.bsenyurt.com Page 105


Bu teorik ak elbette test ederek onaylamamz gerekmektedir. Bunun iin basit bir istemci ve
servis host uygulamas yazabilir yada zel srerlik salayclarn kullanan servis ktphanesini
dorudan Visual Studio 2008 ortamnda altrabiliriz. Hangisi kullanlrsa kullanlsn servis
tarafndaki konfigurasyon ieriinde bir nceki makalemizde yaptmz
gibi PersistenceProviderFactory trevli tipin belirtilmesi gerekmektedir. rnek uygulamada bu
amala gelitirilmi olan CustomServiceLib isimli servis ktphanesi bir nceki makalede
gelitirdiimiz ICommonService szlemesi ile CommonService tipini
kullanmaktadr. App.config dosyasnn ierii ise aadaki gibidir.

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="CommonServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata httpGetEnabled="true" />
<persistenceProvider
type="PersistenceProviders.XmlPersistenceProviderFactory,PersistenceProviders,
Verison=1.0.0.0" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="CommonServiceBehavior"
name="CustomServiceLib.CommonService">
<endpoint address="" binding="wsHttpContextBinding" bindingConfiguration=""
name="CommonServiceWsHttpEndPoint" contract="CustomServiceLib.ICommonService" />
<endpoint binding="mexHttpBinding" bindingConfiguration="" name="MexEndPoint"
contract="IMetadataExchange" address="Mex" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:40001/CommonServiceV2" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

Grld zere, persistenceProvider elementi ierisinde zelletirilmi


olan XmlPersistenceProviderFactory tipi belirtilmektedir. Sz konusu tipin bulunduu
ktphane referans etme yoluyla kullanldndan br nceki rnekte olduu
gibi Culture veya public key bilgileri bulunmamaktadr. Elbetteki zelletirilmi depolama
salaycsn bnyesinde barndran ktphaneyi Global Assembly Cache' e atabiliriz. Bu durumda
konfigurasyon ierisinde Full Qualified Name' in belirtilmesi gerekmektedir.

CustomServiceLib ktphanesini direkt olarak Visual Studio 2008 zerinden altrarak


ilerleyebiliriz. WcfSvcHost ve paralelinde Wcf Test Client altrldktan sonra ilk yapmamz
gereken Start metodunu armak olmaldr. Bu noktada uygulamann alt
yerdeki Instances klasrne baktmzda aadaki ekran grntsnde olduu gibi sxml uzantl
ve GUID deeri ile adlandrlm bir dosyann oluturulduunu grrz.

www.bsenyurt.com Page 106


Bu admdan sonra test olarak IncreaseValue metodu deiik deerler ile arlabilir. Operasyonun
her arlmasnda, servis rneine ait ieriin oluturulan dosyadan yklenmesi, ters
seriletirildikten sonra ieride yer alan CommonValue deerinin arttrlmas ve rnein son halinin
tekrardan ayn dosya zerine seriletirilmesi admlar gerekleir. rnein u noktada sxml isimli
dosyann ieriine baklrsa aadaki XML bilgisinin tutulduu grlebilir.

Bu andan itibaren Stop metodu arlmadan Wcf Test Client uygulamasndan klabilir. Hatta
ayn rnek defalarca arlp Stop operasyonu kullanlmadan test edilebilir. Her
durumda Instances klasrnde birer dosya oluturulacak ve herhangibir nedenle silinene kadar
sahip olduklar InstanceId deerleri iin servis taraf istemcilere hizmet verebilecektir. Ancak Stop
metodu arlrsa bu durumda Instances klasrnde bununla ilikili olan dosyann silindii ak bir

www.bsenyurt.com Page 107


ekilde grlebilir. leyii daha net bir ekilde anlayabilmek iin kodu debug ederek altrmanz
neririm. Bu durumda Create, Update, Delete, Load metodlar arasndaki geileri ok daha
kolay bir ekilde analiz edebilirsiniz. Son olarakta servis ktphanesini kullanan bir sunucu
uygulama ve istemci gelitirerek yeni salaycy test etmenizi ve sistemin dzgn yrdnden
emin olmanz neririm.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde dayankl WCF servisleri ilikili iki
nemli soruya cevap bulmaya alltk. lk olarak istemcilerin var olan InstanceId' leri kullanarak
servislerin, sunucu zerinde uzun sreliine saklanabilen hallerini nasl kullanabileceklerine deinik.
Sonrasnda ise zel bir srerlik salaycsnn(Custom Persistence Provider) nasl yazlabileceini
grdk. Tabiki buradaki rnekleri gelitirmek, geniletmek tamamen sizin elinizdedir. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnei ndirmek in Tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Dayankl WCF Servisleri (Durable WCF


Services) ( 16.01.2009 ) - WCF
Deerli Okurlarm Merhabalar,

Uzun zamandr Windows Communication Foundation(WCF) konulu bir aratrma zerinde


durmamtk. Aslnda WCF 4.0 ve WF 4.0 ile ilgili yeniliklerin uzun sredir konuulduu u
gnlerde, WCF tarafnda olduka nemli bir yere sahip olan ve hatta Workflow Foundation
asndan da deer arz eden bir konuya deiniyor olacaz. Dayankl WCF Servisleri(Durable
WCF Services).

Durable deyince aklma gelen ilk ey, uzun mrl bir pil markas oluyor :)
Srer...Srer...Srerrr...in mizahi yan bir tarafa dursun, Servis Ynelimli
Mimari(ServiceOrientedArchitecture) uygulamalarnda, bir servisin herhangibir zaman
dilimindeki konumunun ierii ile birlikte uzun sreliine saklanabiliyor olmas bazen elzem olan
gereksinimlerden bir tanesidir. Nitekim baz servis operasyonlarnn gerekletirilmesi srasnda
servisin kapanmas veya istemcinin tekrardan balatlmas gibi vakalar olasdr. Yada ok uzun
sren, ierisinde insan faktr olan bir srecin ele alnd herhangibir servisin, belirli zaman
dilimlerinde son ieriinden yklenerek altrlmas gerekebilir. Normal artlarda WCF servisleri
istemci ile oturum bazl(Session Based) haberlemektedir. Buna gre istemciler her proxy
nesnesi rnekleyip servise balandklarnda bir oturum am olurlar. Ne varki servisin herhangibir
nedenle dmesi, istemcinin program kapatmas gibi durumlarda bu oturum bilgileri ok doal
olarak kaybolabilir. Servisin dmesi sonrasnda, zerinde tad tm veriler bir tedbir alnmad
srece yok olabilir. stemci uygulama yeniden balatldnda, servis ayakta bile olsa yeni
bir proxyrnei oluturduundan, daha nceki servis verilerine ok doal olarak ulalamayadabilir.
Halbuki belkide istemci tarafndan arlan operasyonlarn bazlar, kendisini zaman dilimleri
ierisinde koruyan verilerin son haline ihtiya duyabilir.

zellikle WF yaps ierisinde de, bu tip duraanszlklar olduka nemli vakalar arasnda yer
almaktadr. yleki bir WF ierisinde ok uzun sren operasyonlarn(Long Running
Operations) olmas ok daha yksek bir ihtimaldir. Bu nedenle WF' in kendi doasnda olan akn
herhangibir zamandaki durumunu o anki verileri ile saklamak gibi bir misyonuda

www.bsenyurt.com Page 108


var(Persistence). Gnmzde WF ile WCF' in zellikle .Net Framework 3.5 srmnden itibaren
birbirleri ile daha sk fk olduklarda gz nne alndnda, konunun nemi bir kat daha
artmaktadr. Bu basit bilgiler dahi, bir servisin ierisindeki operasyon bazl verilerin kalc olarak
saklanabilmesinin gerekliliinide ortaya karmaktadr. yleyse biraz daha derinlere dalmaya ne
dersiniz?

Hereyden nce servis tarafnda kalc olarak saklanacak olan nesne nedir? Bu ok doal olarak
servis snfna ait sunucu tarafndan retilen rnein kendisi olmaldr. Dier bir noktada, servis
nesnesinin nerede saklanacadr? Burada akla gelen en pratik zm ok doal olarak bir
veritabandr. Nitekim veritaban ierisinde fiziki olarak servis verilerin saklanmas, saklanan
satrlarn kolayca ynetilmesi ve daha pek ok avantaj sz konusudur. ok krki veritaban
tarafnda gerekli tablolarn(Tables) ve sakl yordamlarn(Stored Procedures)
betikleri(scripts) .Net Framework 3.5 ile birlikte gelmektedir.(.Net Framework 3.0 ierisindede
bu script dosyalarn olduunu vurgulayalm. Ancak 3.5 tarafnda pek ok bug' n dzeldiide bir
gerektir.) Her ne kadar buradaki veritaban yapsn kurmak dnldnde ok zor
olmasada, .Net Framework 3.5ierisinde bu ilem iin gerekli tipler(Types) ve veritaban
oluturma betiklerinin hazr olarak gelmesi gelitiricilerin iini olduka kolaylatrmaktadr.

Servis nesnelerinin depolanmas iin bir SQL veritabannn kullanlmas art deildir.
Varsaylan olarak System.WorkflowServices.dll assembly'
ierisindekiSystem.ServiceModel.Persistence isim alan(Namespace) altnda yer
alan SqlPersistenceProviderFactory tipi kullanlmaktadr.Bu tip dorudan
belirtilen SQL balant cmlesindenki depolama alann kullanmaktadr. Ancak
istenirse, PersistenceProviderFactory abstract snfndan tretme yaplarak zel bir
depolama alannn kullanlmasda salanabilir.

Depolama alannn belirtilmesi elbetteki yeterli deildir. Bununla birlikte WCF alma
zamannn(Runtime), niteliklerden(Attributes) yararlanarak depolama alanna servis
rneklerini ekleme veya kaldrma gibi ilemleri hangi operasyonlar gerekletiinde yapacann
bildirilmesi gerekmektedir. Hatta hangi servis tipinin durable olarak braklacannda WCF alma
zamanna sylenmesi nemlidir. Bu noktada
devreye Durable, DurableOperation gibi nitelikler(Attribute) girmektedir.

Aslnda SQL depolama alan varsaylan olarak kullanldnda, sistem son derece basit bir alma
mantna sahiptir. Dayankl WCF servislerinde istemcinin servis tipine ait bir proxy oluturmasnn
ve Durable hale gelme zelliini balatan operasyonu armasnn ardndan, sunucu tarafndaki
depolama alannda servis rneinin seriletirilmi bir rnei hemen ilgili tabloya kayt olarak
eklenmektedir. Bu kayt bir GUID ile ilikilendirilmekte ve bylece istemci sz konusu GUID' e
sahip olduunda, istedii zaman(elbetteki tablodaki verinin bana bir ey gelmedii, istemci ile
servis arasndaki a balantsnda bir aksaklk olmad srece vb...) ayn servis rneinin verisine
eriip operasyonlarnda kullanabilir. Anlattmz bu alma sistemi varsaylan
olarak SQL depolama alan kullanld durum iin geerlidir. Nitekim GUID retimi, seriletirilen
servis nesne rneinin tabloya eklenmesi, bilgisinin gncellenmesi, silinmesi gibi admlar veritaban
baml ilemlerdir. Bu durumu aslnda aadaki ekil ile kafamzda biraz daha netletirebiliriz.

www.bsenyurt.com Page 109


Bu grselde sadece iki farkl zaman dilimi iin rnek bir durum gz nne alnmaktadr. lk olarak
istemci proxy rneini oluturduktan sonra bir operasyon ars gerekletirir. Bu operasyon
ars sonrasnda, servis rneinin depolama alanna atlmas ve bir GUID' in retilerek sonraki
zaman dilimleri iin istemciye gnderilmesi sz konusudur. Senaryo gerei ileri bir zaman diliminde
istemci ayn servis rneini daha nceden kaydettii ierii ile yeniden kullanmak istemektedir. Bu
durumda servisin T zamanndaki rnek ierii depolama alannda durduundan ve istemcinin bu
servisi bulmas iin gerekli GUID deeri var olduundan(ki bu deer ayn zamanda servisin
instanceId deeri ile eittir), T+N zamannda istemci uygulama, daha nceki servis ieriini son
haliyle kullanmaya devam edebilir. Elbette zaman dilimi ilerledike servisin duraanl devam
ettirilebilir. Ne zamanki istemci, servis rneinin tablodan silinmesi iin gerekli talepte bulunursa(ki
bunu ilerleyen ksmlarda greceiz), ilgili rnek depolama alanndan kaldrlr.

Dilerseniz bu kadar konumay bir kenara brakalm ve adm adm dayankl, sapa salam bir WCF
Servis rnei nasl yazlabilir renmeye ve en nemliside anlayama alalm. lk olarak veritaban
tarafndaki gerekli hazrlklar yapmamz gerekiyor. Bir baka deyile depolama tablolarn,
ve CRUD(CreateReadUpdateDelete) ilemleri iin gerekli Stored Procedure' lerin
oluturulmas lazm. Bu amala varsaylan olarak Windows XP tabanl bir sistemde varsaylan
olarakC:\WINDOWS\Microsoft.NET\Framework\v3.5\SQL\EN adresinde
bulunan SqlPersistenceProviderSchema ve SqlPersistenceProviderLogic isimli SQL betiklerin
i srasyla altryoruz. Hemen belirtelim, ilk olarak emalar
oluturan SqlPersistenceProviderSchema betiinin altrlmas gerekiyor.

www.bsenyurt.com Page 110


Yine nemli bir noktada u. Aman Master veritaban altnda altrmayn :) Depolama alannn
veritaban adn istediiniz gibi belirleyebilirsiniz. rnekte sz konusu
betikler, SQL Server 2008 zerinde(ki 2005 zerindede
yapabilirsiniz) WCFPersistenceStore isimli veritaban altnda altrlmaktadr. Sonu olarak
aadaki ekilde grlen nesneler oluur.

Grld gibi servis rneklerini tutacak olan InstanceData isimli basit bir tablo
ve CRUD operasyonlar ile kilit ama ilemleri iin birer sakl yordam oluturulmutur. Tablo
alanlar yle bir gzden geirildiinde uniquidentifier tipinden bir id alannn olduunu gryoruz
ki bu aslnda istemci taraf iinde nem arz eden instanceId deeri olacaktr. yleki istemcinin
uygulamay kapatp tekrar atktan sonra daha nceden var olan bir instance' a ait servis ve
verisine eriebilmesi istenebilir. Bu durumu bir sonraki makalemizde ele almaya alacaz.
Bunlara ek olarak instanceXML isimli XML veri tipindeki alannda bizim iin u aamada dikkate
deer olduunu syleyebiliriz. Nitekim servis rneinin veri ierii bu alanda seriletirilmi olarak
tutulacaktr. Dolaysyla servisin seriletirilebilir olmasnn gerektii ortaya kmaktadr. (Bu durum

www.bsenyurt.com Page 111


gz nne alndnda aklma hep web tarafnda Session' larn veritabannda tutulmas gelmektedir.
Nitekim bu durumdada Session ieriinin veritabanndaki kk bir alana olduu gibi
aktarlabilmesi iin seriletirilebilir olmas arttr :) )

Veritaban tarafndaki hazrlklarda bu ekilde tamamlandktan sonra artk rnek bir servisin
yazlmasna balayabiliriz. rnek WCF servisimiz .Net Framework 3.5 tabanl birWCF Service
Library' dir ve ktphane iin belkide en nemli nokta System.WorkflowServices (.Net
Framework 3.5) assembly' n referans edilmesi gerekliliidir.

Bu nedenle snf ktphanesine sz konusu assembly' ekleyerek yolumuza devam edebiliriz.


Servis ktphanesi ierisinde yer alan tiplerin kod ierikleri, snf diagram grnts ve app.config
ierii ise aada olduu gibidir.

Snf diagram;

ICommonService isimli servis szlemesi ierii;

www.bsenyurt.com Page 112


using System;
using System.ServiceModel;

namespace ServiceLib
{
[ServiceContract(
Name="ServiceCommon"
,Namespace="http://www.bsenyurt.com/CommonService")]
interface ICommonService
{
[OperationContract]
void Start();

[OperationContract]
void IncreaseValue(int value);

[OperationContract]
Guid GetInstanceId();

[OperationContract]
void Stop();
}
}

Grld zere servis szlemesi ierisinde sembolik olarak 4 farkl operasyon tanm
bulunmaktadr. u anda amacmz sadece dayankl bir WCF servisi yazmak olduundan bize okda
anlaml gelmeyen operasyonlarmzn mevcut olduunu syleyebiliriz. Operasyonlarn uyarlamasnn
yapld CommonService isimli snf ierii ise aadaki gibidir.

CommonService snfnn ierii;

using System;
using System.ServiceModel.Description;

namespace ServiceLib
{
[Serializable]
[DurableService]
class CommonService
:ICommonService
{
int commonValue;

#region ICommonService Members

[DurableOperation(CanCreateInstance=true)]
public void Start()
{
commonValue = 1;
}

[DurableOperation()]
public void IncreaseValue(int value)
{
commonValue += value;

www.bsenyurt.com Page 113


}

[DurableOperation()]
public Guid GetInstanceId()
{
return System.ServiceModel.Dispatcher.DurableOperationContext.InstanceId;
}

[DurableOperation(CompletesInstance=true)]
public void Stop()
{
}

#endregion
}
}

Aslnda burada daha nceki servis gelitirmelerimizden farkl olarak dikkate deer bir ka nokta
bulunmaktadr. Hereyden nce snfn Serializable ve DurableService nitelikleri ile imzalandn
gryoruz. Seriletirilebilir olmas bir gereklilik. Nitekim servis tipinin alma zaman
rneinin, InstanceData tablosundaki instanceXML veya instance alanlarna serilemesi sz
konusudur. Hangi alana serileecei bilgisi ise konfigurasyon dosyasnda belirtilebilir. Yani servis
nesne rneinin veri ieriinin XML olarak yada binary formatta tutulmas salanabilir.

Dayankl bir servis tanmlamasnda en nemli


noktalar DurableService ve DurableOperation nitelikleridir. rnein servis operasyonlarnda
olan Start metodu altnda SQLzerinde CommonService rnei iin bir satr oluturulacaktr.
Dier taraftan bu satrn devamll herhangibir istisnai durum olumassa Stop operasyonuna
yaplan ar ile son bulacaktr.
Nitekim Stop operasyonundaki DurableOperation niteliinde CompleteInstance zelliine true
deeri verilmitir. Dayankl servisler tasarlanrken oturum bazl alma nemlidir. Bu nedenle
aadaki koullara dikkat edilmesi gerekmektedir.

Dayankl WCF servislerinde ierik bazl balayc tipler(Content Based Binding


Types) kullanlmaldr.
rnein WSHttpContextBinding, BasicHttpContextBindingveya NetTcpContextBindin
g gibi.
InstanceContextMode zelliinin deeri PerSession olmaldr ki varsaylan olarak
rneimizde byledir.
ConcurrencyMode zelliinin deeri Multiple olmamaldr.
Eer szlemede sessionlar desteklenmiyorsa tm operasyonlara
ait DurableOperation niteliklerinin CanCreateInstance zelliklerine true deeri
atanmaldr ve eer byle bir durum sz konusu ise IsOneWay true olarak set
edilmemelidir.
Eer DurableService niteliinin SaveStateInOperationTransaction deeri true olarak
belirlenirse, tm operasyonlarn OperationBehavior nitelii ile imzalanmas
veTransactionScopeRequired zelliklerinede true deeri atanmas gerekmektedir.
Yada, TransactionFlowOption zelliinin deerinin Mandatory olmas gerekir. Tm
bunlara ilavetende ServiceBehavior niteliinin ConcurrencyMode zelliinin
deerinin Single olarak belirlenmesi gerekmektedir.

Grld gibi olduka kafa kartrc bir artname dizisi ile kar karyayz. Ancak gerek hayat
vakalarnda bu durumlar altn deerinde nem tamaktadr. Gelelim servis tarafndaki
konfigurasyon dosyas ieriine.

Servis tarafndaki App.config ierii;

www.bsenyurt.com Page 114


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<add name="WCFPerstConStr" connectionString="data
source=.;database=WCFPersistenceStore;integrated security=SSPI"/>
</connectionStrings>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="ServiceLib.CommonService"
behaviorConfiguration="ServiceLib.CommonServiceBehavior">
<host>
<baseAddresses>
<add baseAddress =
"http://localhost:8731/Design_Time_Addresses/ServiceLib/CommonService/" />
</baseAddresses>
</host>
<endpoint address ="" binding="wsHttpContextBinding"
contract="ServiceLib.ICommonService">
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding"
contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="ServiceLib.CommonServiceBehavior">
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="False" />
<persistenceProvider
type="System.ServiceModel.Persistence.SqlPersistenceProviderFactory
, System.WorkflowServices, Version=3.5.0.0, Culture=neutral,
PublicKeyToken=31bf3856ad364e35"
connectionStringName="WCFPerstConStr"
persistenceOperationTimeout="00:00:10"
lockTimeout="00:01:00"
serializeAsText="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

Bu ekilde bakldnda kimimize korkutucu gelebilen konfigurasyon ieriindeki ayarlarn


ounu Microsoft Service Configuration Editor araclyla yapabileceimizi unutmayalm.
Konfigurasyon dosyasndanda grld zere balayc tip(Binding Type) olarak ierik
tabanl wsHttpContextBinding rnei kullanlmaktadr. Daha ncedende belirttiimiz
gibi NetTcpContextBinding veya BasicHttpContextBinding balayc tipleride ele alnabilir.

nemli noktalardan ilki connectionString elementi deeridir. Hatrlayacanz gibi rneimizdeki


servis verilerini kalc olarak WCFPersistenceStore isimli rnek bir veritaban zerinde tutmak

www.bsenyurt.com Page 115


amacyla bir takm n hazrlklar yapmtk. Bu bilgi SqlPersistenceProviderFactory tipi iin
nemlidir. Nitekim provider' n hangi balanty kullanarak ilemler yapacan bilmesi
gerekmektedir. Bu sebepten dolayda persistenceProvider isimli servis davran ierisinde
bir connectionStringName nitelii bulunmaktadr.

kinci nemli nokta elbetteki persistenceProvider isimli servis davran ve ieriidir. Burada
dayankl depolama alan iin gerekli pek ok ayar yaplmaktadr. rnein servis
verisinin text tabanl olarak seriletirilip seriletirilmeyecei serializeAsText deeri ile belirtilir.
Kilitleme ve operasyonlar iin zaman am
sreleri lockTimeout vepersistenceOperationTimeout niteliklerine atanan deerler ile belirtilir.

nc nemli nokta ise, persistenceProvider elementi ierisinde yer


alan type niteliine SqlPersistenceProviderFactory deerinin atanmasdr. Bu varsaylan olarak
ve srekli vurguladmz zere SQL zerinde depolama yaplacan belirtmektedir. type
niteliindeki bu tanmlama srasnda tipin qualified name deerinin tam olarak verilmesi
gerekir (TipAd, AssemblyAd, Assembly Versiyonu,Assembly Culture bilgisi, Assembly
PublicKeyToken deeri).

PublicKeyToken deerini kolay bir ekilde Global Assembly Cache(GAC) ierisinden


de bulabiliriz. Bunun iin aadaki ekran grntsnde olduu gibi Assemblyklasrne
gitmemiz yeterlidir.

Servis tarafnda yaptmz bu hazrlklarn ardndan artk istemci tarafn da gelitirmeye


balayabiliriz. Dayankl bir WCF servisini test ederken en basit haliyle
birConsole Application bizim iin biilmi kaftan olacaktr. Console uygulamamz servis ile
ayn Solution zerinde gelitirdiimizden, servise referansn eklememizde son derece kolay

www.bsenyurt.com Page 116


olacaktr. Bu amala Console uygulamasnda Add Service Reference seeneini kullandktan
sonra aadaki ekran grntsnde olduu gibi WCF servisine ulalabilinir.

Servis referansn istemci tarafna ekledikten sonra otomatik olarak retilen konfigurasyon dosyas
ierii aadaki gibi olacaktr.

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


<configuration>
<system.serviceModel>
<bindings>
<wsHttpContextBinding>
<binding name="WSHttpContextBinding_ServiceCommon" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
bypassProxyOnLocal="false" transactionFlow="false"
hostNameComparisonMode="StrongWildcard"
maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" useDefaultWebProxy="true"
allowCookies="false" contextProtectionLevel="Sign">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="16384" maxBytesPerRead="4096" maxNameTableCharCount="16384" />
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="false" />
<security mode="Message">
<transport clientCredentialType="Windows" proxyCredentialType="None"
realm="" />
<message clientCredentialType="Windows" negotiateServiceCredential="true"
algorithmSuite="Default" establishSecurityContext="true" />
</security>
</binding>

www.bsenyurt.com Page 117


</wsHttpContextBinding>
</bindings>
<client>
<endpoint
address="http://localhost:8731/Design_Time_Addresses/ServiceLib/CommonService/" binding="
wsHttpContextBinding"bindingConfiguration="WSHttpContextBinding_ServiceCommon"
contract="CommonServiceReference.ServiceCommon"
name="WSHttpContextBinding_ServiceCommon">
<identity>
<dns value="localhost" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>

Dikkat edilecei zere istemci tarafnda oluturulan EndPoint ierisinde de aynen servis tarafndaki
konfigurasyon dosyasnda olduu gibi wsHttpContextBinding balayc tipi kullanlmaktadr. Snf
diagramndada izlenebilecei gibi servis referansnn eklenmesi ile birlikte proxy retimi iin gerekli
tiplerde otomatik olarak istemci tarafna eklenmektedir.

Program kodlarmz ise test amal olarak aadaki gibi gelitirebiliriz.

using System;
using ClientApp.CommonServiceReference;

namespace ClientApp

www.bsenyurt.com Page 118


{
class Program
{
static void Main(string[] args)
{
ServiceCommonClient client = new
ServiceCommonClient("WSHttpContextBinding_ServiceCommon");

client.Start();
Console.WriteLine("Service balatld");
client.IncreaseValue(10);
Guid instanceId=client.GetInstanceId();
Console.WriteLine("Instance deeri {0}",instanceId.ToString());
client.Stop();
Console.WriteLine("Uygulamadan kmak iin bir tua basnz");
Console.ReadLine();
}
}
}

lk olarak proxy snfna ait nesne rnei oluturulmaktadr. Hemen


ardndan Start, IncreaseValue, GetInstanceId ve Stop servis metodlar srasyla arlr.
Hatrlanaca zere Start metodu ile Servis rneinin tabloya atlmas, Stop metodundan sonra
ise tablodan servise ait ilgili satrn silinmesi gerekmektedir. Bu ilk vakay analiz etmek iin servis
ktphanesi ve istemci uygulamay ayn anda altrmalyz. Bu nedenle iki n hazrlk yaplmaldr.
Bildiiniz gibi Visual Studio 2008 ile birlikte WCF Servisktphanelerini balatlabilir ve built-in
gelen servis, istemci uygulamalarn kullanarak testler yaplabilir. Bu rneimizde istemci tarafn
kendimiz gelitirdiimiz iin servis ktphanesi zelliklerinden WcfTestClient.exe' nin altrld
komut satr parametresini kaldrmamz gerekmektedir.

Bu ilemin ardndan ise Solution zelliklerine gidip nce snf ktphanesinin sonrasnda ise
istemci uygulamann altrlmas gerektiini belirtmeliyiz.

www.bsenyurt.com Page 119


Bylece servis ktphanesine ait test sunucusu nce alacak sonrasnda ise istemci uygulamamz
yrtlecektir ki bu hazrlk zellikle kodu debug etmemizi kolaylatracaktr. lk test iin istemci
tarafndaki Start metodu arsna bir breakpoint koymamz gerekmektedir.

imdi uygulamay altrp Start metodunu Step Over ile getiimizde SQL sunucusu
zerindeki instanceData tablosunda yeni bir satr oluturulduunu grebiliriz.

www.bsenyurt.com Page 120


Dikkat ederseniz servis rneklendiinde
deil, DurableOperation niteliinde CanStartCreateInstance deeri true olan Start metodu
arsndan sonra bu satr eklenmitir. Satrn id deeri, servis ars iin retilen GUID deeridir
ve aslnda bu deer ierik ile birlikte istemciyede gnderilmektedir. Bu nedenle oturum ierisinde
yaplacak olan dier operasyon arlarnda bu GUID numaras kullanlr. instanceXml isimli alann
ieriine bakldnda (zellikle IncreaseValue metodundan nce) servisin aadaki ierie sahip
olduu grlebilir.

CommonService ierisinde tanmlanm olan commonValue alannn ilk atanan deeri burada
ak bir ekilde grlmektedir. Elbetteki serileen tipin ierisinde ka tane alan(field) varsa,
bunlarn anlk olarak deerlerinin tamam seriletirilen bu ierie atanmaktadr. Eer
kodda F10(Step Over) ile ilerlenmeye devam edilirse IncreaseValue metodu geildikten
sonra XML ieriinin aadaki hale geldii grlr.

Bir baka deyile servis nesne rneinin depolama alannda tutulan ieriindeki alanda da
gncelleme yaplmtr. Kod bu ekilde sonuna kadar devam ettirildiinde ve Stopmetodu

www.bsenyurt.com Page 121


arsda F10 ile geildiinde artk CommonService' in u anki rnei iin alan satrn artk
olmad ak bir ekilde gzlemlenebilir. Ki burada Stop
metodundaki DurableOperation niteliinde CompleteInstance zelliine true deerini
atadmz hatrlamamzda yarar vardr. Bu basit ileyii tekrar edip SQL Server Profiler arac
yardmyla arka plana bakldnda ise aadaki gibi bir sorgu dizisinin altrld
gzlemlenmektedir.

InsertInstance SP' si iin ar

declare @p3 xml


set @p3=convert(xml,N'<CommonService
xmlns="http://schemas.datacontract.org/2004/07/ServiceLib"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="1"
z:Type="ServiceLib.CommonService" z:Assembly="ServiceLib,
Start Version=1.0.0.0, Culture=neutral,
Metodu arsnd PublicKeyToken=null"><commonValue>1</commonValue></CommonServic
a e>')
declare @p7 int
set @p7=0
exec InsertInstance @id='1B9F9AA9-4F5C-46F1-97ED-
C520716CE7AE', @instance=default,
@instanceXml=@p3,@unlockInstance=1,@hostId='97CE292D-D465-49B9-
9200-4A55BCE2D7B3',@lockTimeout=60,@result=@p7 output
select @p7

LoadInstance SP' si iin ar

declare @p5 int


set @p5=0
exec LoadInstance @id='1B9F9AA9-4F5C-46F1-97ED-C520716CE7AE',
@lockInstance=1,@hostId='97CE292D-D465-49B9-9200-4A55BCE2D7B3',
@lockTimeout=60,@result=@p5 output
select @p5

UpdateInstance SP' si iin ar

declare @p3 xml


set @p3=convert(xml,N'<CommonService
IncreaseValue
xmlns="http://schemas.datacontract.org/2004/07/ServiceLib"
Metodu
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
arsnda
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="1"
z:Type="ServiceLib.CommonService" z:Assembly="ServiceLib,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null"><commonValue>11</commonValue></CommonServi
ce>')
declare @p7 int
set @p7=0
exec UpdateInstance @id='1B9F9AA9-4F5C-46F1-97ED-
C520716CE7AE', @instance=default,
@instanceXml=@p3,@unlockInstance=1,@hostId='97CE292D-D465-49B9-
9200-4A55BCE2D7B3',@lockTimeout=60,@result=@p7 output
select @p7

GetInstanceId LoadInstance SP'si iin ar


Metodu declare @p5 int
arsnda set @p5=0

www.bsenyurt.com Page 122


exec LoadInstance @id='1B9F9AA9-4F5C-46F1-97ED-C520716CE7AE',
@lockInstance=1, @hostId='97CE292D-D465-49B9-9200-
4A55BCE2D7B3',@lockTimeout=60,@result=@p5 output
select @p5

UpdateInstance SP'si iin ar

declare @p3 xml


set @p3=convert(xml,N'<CommonService
xmlns="http://schemas.datacontract.org/2004/07/ServiceLib"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance"
xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/" z:Id="1"
z:Type="ServiceLib.CommonService" z:Assembly="ServiceLib,
Version=1.0.0.0, Culture=neutral,
PublicKeyToken=null"><commonValue>11</commonValue></CommonServi
ce>')
declare @p7 int
set @p7=0
exec UpdateInstance @id='1B9F9AA9-4F5C-46F1-97ED-
C520716CE7AE', @instance=default,
@instanceXml=@p3,@unlockInstance=1,@hostId='97CE292D-D465-49B9-
9200-4A55BCE2D7B3',@lockTimeout=60,@result=@p7 output
select @p7

LoadInstance SP' si iin ar

declare @p5 int


set @p5=0
exec LoadInstance @id='1B9F9AA9-4F5C-46F1-97ED-C520716CE7AE',
@lockInstance=1, @hostId='97CE292D-D465-49B9-9200-4A55BCE2D7B3',
@lockTimeout=60,@result=@p5 output
Stop Metodu select @p5
arsnda DeleteInstance SP' si iin ar

declare @p4 int


set @p4=0
exec DeleteInstance @id='1B9F9AA9-4F5C-46F1-97ED-
C520716CE7AE', @hostId='97CE292D-D465-49B9-9200-
4A55BCE2D7B3',@lockTimeout=60,@result=@p4 output
select @p4

Biraz karmak ve gereksiz gibi grlebilir ama bu sorgular ierisinde arlan sakl yordamlara ve
atamalara dikkat etmenizi, ayrca incelemenizi iddetle tavsiye ederim. lk testimiz baarl bir
ekilde alt. Depolama alanna WCF servis rneimizin baarl bir ekilde eklendii, operasyon
arlar srasnda gncellendiini ve son olarakta silindiini grdk. Ancak baka vakalarda sz
konusudur. rnein istemci uygulama sreci balattktan sonra herhangibir sebeple sonlanrsa,
servis tarafnda balatt instance' n ieriine tekrar nasl ulaabilir? Bir baka deyile, daha
nceden balatt servisin verilerine nasl ulaabilir? Dier taraftan, servis tarafnda SQL tabanl bir
depolama alan kullanlmaktadr. Peki ya zel bir depolama yapmak istersek. Yani SQL dndan bir
ortam kullanmak istersek. Sz gelimi dosya tabanl bir sistem kullanlabilir mi? Yada rnein
bir Access tablosu bu i iin gz nne alnabilir mi? Bu durumda nasl ayarlamalar yaplmas
gerekmektedir? Kalc servislerde transaction' lar sz konusu olabilir mi, eer olursa sreler nasl
kontrol altna alnabilir? te bu ve benzer sorularmz cevabn ilerleyen makalelerimizde bulmaya
alyor olacaz. imdilik hevesimizi burada dayankl olarak sakl tutuyor ve bir sonraki
makalemizde grmek zere diyoruz. Tekrardan grnceye dek hepinize mutlu gnler dilerim.

rnei ndirmek in Tklayn

www.bsenyurt.com Page 123


Burak Selim ENYURT
MVP (Connected System Developer-2008,C# 2007,2006)

Ado.Net Senkronizasyon Servisleri(Sync


Services for Ado.Net) ( 03.01.2009 ) - Ado.Net
Deerli Okurlarm Merhabalar,

Birbirleri ile srekli balant halinde olamayan istemci/sunucu(Client/Server) mimarilerinde en


byk problemlerden biriside verilerin karlkl veya tek tarafl olaraktan senkronize edilmeleridir.
ou byk apl saha uygulamasnda, sunucu tarafndaki veri kaynaklarnn istemcide kullanld
durumlar sz konusudur. Bu noktada istemcilerin srekli bal kalamadklar bir ortamn var olmas
olasdr (Occasionally Connected Enivronments). Nitekim istemci ve sunucu arasnda kablosuz
balant olma ihtimali olduka yksektir. Nitekim gnmz teknolojileri dnldnde istemci
uygulamalarn bir ou mobil cihazlar ile, diz st bilgisayarlar zerinde komaktadr. Bu tabiki
daha ok saha elemanlarnn iin ierisine girdii senaryolardr.

Sz gelimi gnlk rn fiyatlandrmalarn kullanarak sat yapan personelin mobil cihazlara sahip
olduu bir durumda, istemcilerin sunucuya srekli olarak bal kalmalar saha zerinde son derece
zor olabilir. (Mobil cihazlar, modern cep telefonlar ve PDA' ler olabilecei gibi dizst
bilgisayarlarda olabilir.) Buna ramen istemcinin sz konusu veriyi kullanarak alabilmesi de
istenebilir. Dier taraftan istemcinin sunucuya baland hallerde ortak veri zerindeki
deiikliklerini gndermesi ve hatta var olan farkllklar kendi sistemine ekmeside istenebilir. Bu
iki tarafl bir senkronizasyon anlamna gelmektedir ki, iki tarafnda birbirleri zerindeki verileri
senkronize etmeleri srasnda pek ok glkle karlalacaktr. Nitekim bu vakada e zamanl bal
olan kullanclarn ortak verilerde yapaca deiikliklerin ele alnmas gerekir ki bunlar
akmalara(Conflicts) neden olmaktadr. Baz durumlarda ise sadece sunucudaki farkllklarn
istemciye aktarlmas veya tam tersi sz konusudur. Bu durumlarda senkronizasyonu ynetmek
nispeten biraz daha kolaydr. Ancak hangi vaka olursa olsun her iki uta yer alan verinin kolay
kodlanabilir, ynetilebilir bir biimde senkronize edilmeleri istenir. En azndan gelitiriciler iin bu
nemlidir.

Ado.Net senkronizasyon servisleri esas itibariyle Microsoft Sync


Framework(MSF) altyapsnn bir parasdr. MSF altyaps ierisinde Sync Services for
File Systemsve Sync Services for FeedSync isimli iki alt alm daha vardr. Sync
Services For Ado.Net zel olarak istemci ve sunucu arasndaki veri senkronizasyonun
salanmasndaAdo.Net' in stne gelmi olan bir tamamlayc olarak dnlebilir.
(Microsoft Sync Framework iin MSDN' den detayl bilgi alnabilir.)

Senkronizasyon ilemlerinde bilinen ve kullanlan farkl teknikler de sz konusudur.


rnein Remote Data Access(RDA) veya Merge Replication. RDA, SQL Server Compact
3.5 ile dier bir SQL veritaban arasndaki senkronizasyon ilemlerinde ele
alnr. Merge Replication ise SQL veritabanlarnn herhangi versiyonlar arasndaki
senkronizasyon srelerinde kullanlr. zellikle Merge Replication veritaban yneticilerine hitap
eder ve SQL kaynaklarn hedefler. Ancak ADO.Net Senkronizasyon
Servisleri ile WCF(Windows Communication Foundation) hizmetlerini kullanarak, sunucu
tarafnda farkl veri kaynaklarna eriebilmek mmkndr. Dier taraftan Ado.Net
Senkronizasyon Servisleri daha ok uygulama gelitiricileri hedef alr. Eer istemci tarafnn
senkronize edecei veri kmesi SQL dnda bir kaynak ise mutlaka Ado.Net Senkronizasyon

www.bsenyurt.com Page 124


Servisi gz nne alnmaldr.RDA, Merge Replication ve Ado.Net Senkronizasypn
Servisleri arasndaki karlatrmalar aadaki tablodan da inceleyebilirsiniz. zellikle karar
verme aamasnda bu tablodaki bilgilerden de yararlanlabilir.

Kullanlabilen Teknikler

Anahtar zellik RDA


Merge Ado.Net Sync
(Remote Data
Replication Services
Access)

Servisler zerinden senkronizasyon salanmas Yok Yok Var

Farkl veri kaynaklar iin destek Yok Yok Var

Deiimsel(Incremental) farkllklarn takibi Yok* Var Var

akma(Conflict) kontrol ve zmleri Yok Var Var

stemci tarafnda View' larn kolayca


Yok Yok Var
oluturulmas(Grsel derslerde ele alnacaktr)

Otomaik ema(Schema) ve veri oluturma Var Var Var

Byk boyutlu DataSet destei Var Var Var

Otomaik olarak ema deiikliklerini retmek Yok Var Yok

Veriyi tekradan birletirmek(Repartition) Yok Var Yok

* RDA deiimsel upload' lar destekler. Verinin istemci tarafna alnmasnda Snapshot modelini
kullanlr. Yani istemci tarafna tm veriyi indirir.

Teknik adan bakldnda Ado.Net Senkronizasyon Servisleri temel olarak aadaki 3


assembly' dan olumaktadr. Ado.Net Senkronizasyon Servisleri taraflarn sahip olduu veri
salayclarna gre 2 katl(Two Tier), N-katl(N-Tier) ve Servis Bazl Mimariye(Service
Oriented Architecture) uygun olacak ekilde kullanlabilmektedir. Eer istemci ve
sunucu Ado.Net veri salayclar zerinden konuuyorlarsa iki katl veya n katl modeller tercih
edilebilir. Ancak sunucu tarafndan SQL d bir veri kayna var ise(Sz gelimi bir XML deposu,
Active Directory vb...) bu durumda servis ynemlimli olacak ekilde bir gelitirme yaplmaldr.
Senkronizasyon her zaman iin istemci tarafnda balatlan bir olaydr ve temel olarak 4 farkl tipte
senkronizasyon teknii kullanlmaktadr.

Kullanlan
Aklama
Teknik

Snapshot Bu teknikte senkronizasyon ilemi balatldnda sunucu tarafndaki verinin


tamam istemci tarafna indirilir. Bir baka
deyile deiimsel(incremental)farkllklar gz nne alnmaz, srekli olarak
son hal indirilir.

Download- Bir nceki senkronizasyona gre farkl olan verilerin download edilmesi sz
Only konusudur. Bir baka deyile sadece deiimsel verilerin indirilmesi sz
konusudur.

Upload-Only Senkronizasyon ileminde istemci tarafndaki veriler zerinde yaplan deiiklikler


ve yeni eklemelerin sunucu tarafna tanmas sz konusudur. Sz gelimi sat
ekibinin herhangibir rn sat iin yapt giriler veya gncellemeler buna
rnek bir vaka olarak dnlebilir.

Bidirectional ift ynl senkronizasyon sz konusudur. Sz gelimi bir kargo datm firmasnn

www.bsenyurt.com Page 125


saha elemanlarnn datlacak kargo bilgilerini almas ve datma ait bilgileri
sunucu zerine gncellemesi gibi bir vaka rnek olarak dnlebilir. Bu noktada
zellikle senkronizasyon ilemleri srasnda oluabilecek e zamanl
veri akmalarnn(Conflicts) kontrol altna alnmas gerekir.

Bu noktada belkide senkronizasyon servislerinin katl mimarideki konumlarn ele almak yararl
olabilir. Bu amala aadaki izelgelerden yararlanabiliriz.

2 Katl Mimari;

ki katl modelde sunucu ve istemci tarafnda senkronizasyon ilemine tabi olan nesneler bazen
ayn uygulama zerinde bulunmaktadr. Her ne kadar ok fazla tavsiye etmesemde iki katl modelin
uygulanmas zellikle Visual Studio 2008 ortamnda son derece kolaydr. Ancak gerek hayat
uygulamalarnda ounlukla sunucu senkronizasyonunu bir servis veya baka bir uygulama tek
bana stlenir.

N-Katl Mimari;

www.bsenyurt.com Page 126


N-katl modelde istemci ve sunucu zerindeki veritabanlar arasndaki iletiim srasnda devreye
giren ve ayr bir katta duran Servis-Proxy tipleri mevcuttur. Genellikle istemci ve sunucu
veribanlar arasnda dorudan balanty gerektirmedii iin 2 katl mimariye gre daha fazla tercih
edilmektedir.

Servis Bazl Mimari;

SOA modeli sunucu tarafndaki veri kaynann SQL olmad durumlarda ele alnabilir. Bu
sebepten dolay sunucu tarafnda sunucu senkronizasyon salaycs veya senkronizasyon
adaptrleri bulunmamaktadr. Bu mimaride istemcinin sunucu taraf ile mutlak suretle bir servis
zerinden konuuyor olmas gerekmektedir. Bir baka deyile sunucu senkronizasyon salaycs ile

www.bsenyurt.com Page 127


senkronizasyon adaptrlerinin grevini servis taraf stlenmektedir. Bu noktada servis
tarafnda WCF gibi gelimi modellerin kullanlmasda mmkndr.(lerleyen grsel derslerimizde
bu konuyuda incelemeye alyor olacaz.)

.Net Framework tarafndan bakldnda Ado.Net Sync Service' ler aadaki 3


temel assembly ve tiplerinden yaralanmaktadr.

Microsoft.Synchronization.Data.dll assembly (Synchronization Agent, Synchronization


Tables ve Synchronization Groups)

Microsoft. Synchronization.Data.SqlServerCe.dll (Client Synchronization Provider)

Microsoft. Synchronization.Data.Server.dll (Server Synchronization Provider ve


Synchronization Adapters)

(Tabi Sync Service For Ado.Net' i kullanabilmek iin ilgili srmn indirip kurmanz
gerekmektedir. Makalenin yazld tarihten sonra farkl versiyonlarn kmas ve
muhtemel deiimlerin olmasnnda sz konusu olduunu belirtmek isterim.
Makalemizde Microsoft Sync Framework 2.0 CTP srm ierisindeki Sync Services
For Ado.Net alt yaps kullanlmaktadr.)

Makalemizin bundan sonraki blmnde teknik detaylar bir kenara brakp ok basit bir rnek
zerinden konuyu daha net bir ekilde kavramaya alacaz. rnekte kullanlmakta
olan Windows uygulamas zerinde, Azon isimli rnek veritabannda yer alan Kitap isimli tablo
iin ift ynl(Bidirectional) senkronizasyon ilemleri yaplmaktadr. Ancak elbette istediiniz
tipte bir veritaban ve tablolarn kullanabilirsiniz. Tablomuzun ilk hali aadaki ekilde grld
gibidir ve bu noktadaki hali olduka nemlidir.

Biraz sonra tablonun u anki alan yapsnn senkronizasyon destei iin deitiini greceiz :)
imdi rnek Windows uygulamamza Local Database Cache isimli yeni birabloun
e(Template Item) ekliyoruz.

www.bsenyurt.com Page 128


Sync uzantl LocalAzon isimli e temel olarak senkronizasyon ilemleri ile ilikili ayarlar
tutacaktr. rnein senkronizasyon tablolarna
ait ema(Schema) bilgileri, balant(Connection) ayarlar, kodlama ksmlar vb... Bu nedenle
ilk olarak karmza aadaki pencere kacaktr.

www.bsenyurt.com Page 129


Burada ilk etapta sunucu veri kayna ve istemci veri kaynana ait balantlar belirtilir. Dikkat
edilecei zere sunucu balants Sql Server(ki rnekte SQL Server 2008 zerinde
durmaktadr) zerindeki veritabann iaret etmektedir. stemci balantsnda ise sdf uzants ile
dikkat eken ve biraz sonra oluturulacak olan Sql Server Compact 3.5srmnde bir veritaban
dosyas ad bulunmaktadr. Advanced ksmna baktmzda ise senkronizasyon
iin transaction tanmlamas yaplabildii de dikkati ekmektedir. Yani tm tablolarn
senkronizasyon ilemlerinin ortak bir transaction ierisinde gerekletirilmesi istei
belirtilebilmektedir. Dier taraftan nemli noktalardan biriside sunucu ve istemci proje
lokasyonlardr. u an itibariyle her iki deerde gelitirmekte olduumuz projeyi iaret etmektedir.
Elbetteki gerek hayat vakalarnda zellikle sunucu proje lokasyonu baka bir uygulamay iaret
etmektedir.(N-Tier veya SOA uyarlamas). Bu adm tamamlamadan nce sol
taraftaki Application ksmna yeni bir offline table eklenmesi gerekmektedir. Bu
amala, Add dmesine basldktan sonra aadaki ekran grnts ile karlalacaktr.

www.bsenyurt.com Page 130


Bu ksmda senkronizasyon srecine dahil olacak tablo(tablolar) veya veritaban nesneleri seilir.
Dikkat edilecei zere verinin istemci tarafna indirilme ekli belirlenebilmektedir. u andaki seime
gre ilk senkronizasyon ileminden sonra deiimsel(Incremental) ve yeni eklemelerin
indirilmesi seenei etkindir.

Senkronizasyon ilemleri srasndaki nemli noktalardan biriside, istemci ve sunucu arasndaki


balantnn tekrardan salanmas sonrasnda karlkl olarak verilerde yaplan ilemlerin nasl ayrt
edilebileceidir. Sz gelimi yeni gncelletirmeler, silmeler veya eklemeler nasl ayrt edilebililr. Bu
sebepten update ilemleri iin varsaylan olarakLastEditDate, insert ilemleri
iin CreationDate isimli iki yeni alann Kitap isimli tabloya eklenmesi sz konusudur. Dier
taraftan silinen satrlar _Tombstone uzantl bir tabloda saklanacaktr ve bu ekilde takip
edilebilecektir. New veya Edit dmelerinden yararlanarak sz konusu parametrelerin farkl
isimlerde oluturulmalarda salanabilir. Burada gelitiricilerin hayatn kolaylatran bir linkte
bulunmaktadr. Tablo eklenmesi tamamlandktan
sonra Configure Data Synchronization penceresinde yer alan Show Code Example linkine
tklandnda rnek bir kod paras grlr.

www.bsenyurt.com Page 131


Bu kod paras senkronize ileminin istemci tarafnda balatlaca yerde kolayca
kullanlabilmektedir ki biz de yle yapyor olacaz :) Configure Data
Synchronizationpencersinden klrken istenirse senkronizasyon ilemleri iin
kullanlacak SQL Script' lerinin istemci uygulamaya eklenmesi salanabilir. Bunun iin aadaki
penceredeki seenekleri varsaylan halleri ile brakmak yeterli olacaktr.

Artk istemci taraf iin gerekli olan trlendirilmi(Typed)


DataSet, DataTable ve DataAdapter retimleri yaplacaktr. Bunun iin var olan Kitap
tablosunun seilmesi yeterlidir.

www.bsenyurt.com Page 132


Senkronizasyon kodlarn eklemeden nce, istemci uygulamada ve sunucu veritabannda olan
dzenleme ve ilaveleri analiz etmeye balayabiliriz. lk dikkat ekici nokta sunucu zerindeki Azon
veritabannda olan ilavelerdir.

www.bsenyurt.com Page 133


Grld zere gncelleme ve ekleme ilemlerinin takibi iin Kitap
tablosuna LastEditDate ve CreationDate isimli datetime tipinden iki alan eklenmitir. Silinen
satrlarn bilgisi iin Kitap_Tombstone isimli bir tablo oluturulmutur. Bu
tablo KitapId ve DeletionDate isimli alanlar iermektedir. Bylece hangi satrn ne zaman
silindii bilgisi tutulabilmektedir. Dier taraftan Insert, Update ve Delete ilemlerinden sonra
devreye giren tetikleyicilerinde(triggers) eklendii grlebilir. Triggerlarn ierikleri ve ne i
yaptklar ksaca aadaki tabloda aklanmaktadr.

Trigger Query Grevi

Kitap_DeletionTrigg ALTER TRIGGER Kitap tablosunda bir satr


er [dbo].[Kitap_DeletionTrigger] silindiindeKitap_Tombstone tablosun
ON [dbo].[Kitap] da silinen kaydn var olup olmamas
AFTER DELETE durumuna
AS gre(@@ROWCOUNTdeeri)
SET NOCOUNT ON ya DeletionDatealann gncellemesi
UPDATE yaplr
[dbo].[Kitap_Tombstone] yada Kitap_Tombstonetablosuna
SET [DeletionDate] = silinen kayt eklenir.
GETUTCDATE()
FROM deleted
WHERE
deleted.[KitapId] =
[dbo].[Kitap_Tombstone].[KitapI
d]
IF @@ROWCOUNT = 0
BEGIN
INSERT INTO
[dbo].[Kitap_Tombstone]
([KitapId], DeletionDate)
SELECT [KitapId],
GETUTCDATE() FROM deleted
END

Kitap_UpdateTrigger ALTER TRIGGER Kitap tablosundan bir satr


[dbo].[Kitap_UpdateTrigger] gncellendiinde, o
ON [dbo].[Kitap] satrn LastEditDate alanna anlk
AFTER UPDATE zaman deeri atanr.
AS
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[Kitap]
SET [LastEditDate] =
GETUTCDATE() FROM inserted
WHERE inserted.[KitapId] =
[dbo].[Kitap].[KitapId]
END;

Kitap_InsertTrigger ALTER TRIGGER Kitap tablosuna yeni bir satr


[dbo].[Kitap_InsertTrigger] eklendikten sonra bu
ON [dbo].[Kitap] satrnn CreationDate alanna o anki
AFTER INSERT zaman deeri atanr.
AS
BEGIN
SET NOCOUNT ON
UPDATE [dbo].[Kitap]
SET [CreationDate] =

www.bsenyurt.com Page 134


GETUTCDATE() FROM inserted
WHERE inserted.[KitapId] =
[dbo].[Kitap].[KitapId]
END;

Peki ya uygulama tarafndaki deiiklikler nelerdir?

Grld zere Sync Services for Ado.Net iin gerekli olan Microsoft.Synchronization.Data,
Microsoft.Synchronization.Data.Server veMicrosoft.Synchronization.Data.SqlServerCe ass
embly' lar projeye referans olarak gelmektedir. Tm senkronizasyon alt yapsna ait tipler
bu assembly' lar ierisinde gelmektedir. Dier taraftan istemci uygulamada yerel bir sdf dosyasda
oluturulmutur. Bu dosya local olarak alabilen Sql Server Compact 3.5 versiyonunda bir
veritabandr. stemci uygulamadaki grsel veri bal bileenler iin
trlendirilmi DataSet ierii AzonDataSet.xsd adyla oluturulmutur. Senkronizasyon ayarlarn
ve ilemlerini stlenen tipleriLocalAzon.sync esi barndrmaktadr. Bunlara ek olarak istemci
taraf iin retilen tiplere baktmzda aadaki snf diagramnda yer alan temel eler dikkat
ekmektedir.

www.bsenyurt.com Page 135


Buradaki tiplerin temel ilevleri aadaki tabloda belirtilmektedir.

Kullanlan Snf Aklama

DbServerSyncProvider Microsoft.Synchronization.Data.Server.dll assembly' ierisinde yer


alan bu snf ServerSyncProvider tipinden tremektedir.

Sunucu zerindeki senkronizasyon tablolarnn bilgilerinin tutulmas,


sunucu zerindeki verilerde son senkronizasyondan sonra olan
deiikliklerin elde edilmesi, sunucu
veritabanna deiimsel(incremental) farkllklarn
aktarlmas, akmalarn(Conflicts) kontrol edilmesi gibi ilemleri
stlenir.

SqlCeSyncProvider Microsoft.Synchronization.Data.SqlServerCe.dll assembly'


ierisinde yer almaktadr.

stemci tarafnda senkronizasyona dahil edilmi tablolarn bilgilerinin


saklanmas, istemci veritabanndaki son senkronizasyondan sonra olan
deiikliklerin elde edilmesi, istemci veritabanna deiimsel farkllklarn

www.bsenyurt.com Page 136


aktarlmas, akmalarn tespit edilmesi gibi kritik ve nemli ilemleri
stlenir.

SyncAdapter Microsoft.Synchronization.Data.Server.dll assembly' ierisinde yer


alan bu snf DbServerSyncProvider ile sunucu veritaban arasnda
kpr vazifesi grmektedir.

Senkronize ileminde ele alnan her tablo iin bu tipten treyen bir snf
retilir. Bu adaptr nesneleri, senkronizasyonun tipine gre gerekli
olan DbCommandrneklerini bir baka deyile SQL sorgularn ierir.

SyncAgent Microsoft.Synchronization.Data.dll assembly' ierisinde yer


almaktadr. Tm senkronizasyon srecinin orkestrasyonunu
stlenmektedir.

SyncTable Microsoft.Synchronization.Data.dll assembly' ierisinde


bulunmaktadr.

Senkronizasyon ilemine tabi olan tm tablolar iin istemci tarafnda


birer adet oluturulur. SyncAgent tipi ierisinde Nested Type(Dahili
Tip) eklinde oluturulmaktadr. Senkronizasyona dahil olan istemci
tablolarna ait ayarlar tamak gibi grevleri vardr.

Makalede gelitirdiimiz rnekte sunucu taraf senkronizasyon tiplerininde istemci uygulama


zerinde olumas normaldir. Nitekim, Configura Data
Synchronization ksmndakiApplication ayarlarna bakldnda istemci ve sunucu uygulamalarn
ayn olduu grlmektedir. Ancak gerek vakalarda sunucu veri kayna ile iletiimi salayan ayrk
bir uygulamann servis bazl olmas sz konusudur ki bu durumda N-Tier veya SOA mimarisine
geilmi olmaktadr.

Testlere balamadan nce istmeci uygulamann tasarmn basit olarak aadaki gibi deitirelim.

www.bsenyurt.com Page 137


Burada GridView kontrol otomatik olarak AzonDataSet ierisindeki Kitap tablosuna baldr ve
zerinde balantsz olarak veri ekleme, karma, gncelletirme ilemleri yaplabilmektedir. Dier
taraftan Senkronize Et balkl dmenin ierii aadaki gibidir.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace ClientApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void kitapBindingNavigatorSaveItem_Click(object sender, EventArgs e)


{
this.Validate();
this.kitapBindingSource.EndEdit();
this.tableAdapterManager.UpdateAll(this.azonDataSet);
}

www.bsenyurt.com Page 138


private void Form1_Load(object sender, EventArgs e)
{
this.kitapTableAdapter.Fill(this.azonDataSet.Kitap);
}

private void btnSenkronizeEt_Click(object sender, EventArgs e)


{
LocalAzonSyncAgent syncAgent = new LocalAzonSyncAgent();
Microsoft.Synchronization.Data.SyncStatistics syncStats =
syncAgent.Synchronize();
Form1_Load(null, null);
}
}
}

Tahmin ettiiniz gibi biz sadece button ieriini ekliyoruz. Burada ilk olarak bir Agent nesnesi
rnekleniyor. Sonrasnda ise Synchronize metodu ile senkronizasyon ilemi balatlyor. Bu
ilemin sonularn istersek retilen SyncStatistics tipi zerinden elde edebiliriz ki bunu loglama
amacyla kullanabiliriz. Yaptmz bu deiiklikler sonrasnda uygulamay test ettiimizde zellikle
ift ynl olarak bir senkronizasyon ilemi yaplamadn greceiz. Bu sorunu zmek iin
aadaki kod parasnda da grld gibiLocalKitap.sync kod dosyasnn ieriini deitirmemiz
ve senkronizasyon tipini sz konusu Kitap tablosu iin belirtmemiz gerekmektedir.

namespace ClientApp {

public partial class LocalAzonSyncAgent {


partial void OnInitialized(){
Kitap.SyncDirection = Microsoft.Synchronization.Data.SyncDirection.Bidirectional;
}
}
}

Artk Kitap tablosu iin ift ynl olaraktan senkronizasyon kontrol yaplacaktr. Bir baka deyile
hem istemci hemde sunucu tarafndaki deiiklikler senkronizasyon ilemleri sonrasnda kar
tarafa iletilecek ve verilerin elenmesi salanacaktr. Elbette birden fazla tablo kullanlmas halinde
bu tablolarn her biri iin ayr ayr senkronizasyon ynleri seilebilir.

Artk ksa bir ka test yaplabilir. lk olarak istemci uygulama altrldnda Kitap tablosunun tm
ieriinin ekildii gzlemlenecektir. Burada tm verinin indirilmesi son derece normaldir. Program
altktan sonra rnein, istemci tarafndaki veri ieriinde eitli deiiklikler yaptmz
varsayalm. rnein KitapId alannn deeri 4 olan satr sildiimizi, yeni bir kitap eklediimizi ve 83
numaral kitabn ad iin bir gncelletirme yaptmz dnelim.

www.bsenyurt.com Page 139


Bu ilemlerin arkasndan deiiklikleri DataSet zerinde kaydedip Senkronize Et dmesine
basarsak, farkllklarn sunucu tarafnada aktarldn grebiliriz. Bu noktada
zellikle LastEditDate ve CreationDate alanlarnn istemci ve sunucudaki deerleri farkllklarn
tespitini kolaylatrmaktadr. Bunu daha rahat grebilmek amacyla Azon.sdf dosyas ierisindeki
Kitap tablosu ile sunucudaki Azon veritabannda yer alan Kitap tablosunun ieriklerini
karlatrmanz neririm.

Yeni kayt ekleme ve gncelleme ilemleri dnda istemci tarafnda birde satr silmitik. Bu nedenle
sunucu veritabanndaki Kitap_Tombstone tablosunda aadaki ekildende anlalaca zere 4
numaral satr(Silinen kitabn KitapId deeri) iin bir ekleme yapld gzlemlenebilir.

kinci test olarak sunucu zerinde deiikliker yapp bunlar istemci tarafna,
uygulamadaki Senkronize Et dmesini kullanarak alabiliriz. u nokta unutulmamaldr;
Senkronize etme ilemi program her aldnda yaplmamaktadr. Nitekim veritabannda deiiklik
yaplsa ve istemci ile sunucu arasnda bir balant olmasa bile, istemci uygulama yerel

www.bsenyurt.com Page 140


veritaban(Local Database-sdf) zerindeki veriler ile alarak, deiiklikler, eklemeler ve silmeler
yapabilir ama, senkronize etme ilemi balamad srece hem deiiklikleri alamaz hem de bunlar
sunucu veritabanna iletemez.

Bir adan bakldnda, yaplan ilemler verilerin normal yollarla karlkl olarak u kaynaklara
gnderilmesinden pek farkl deildir. zellikle balantsz katman modelinde gelitirme yapldnda
benzer ilevsellikleri salayabiliriz. Ne varki Sync Services for Ado.Net alt yaps sunucu ve
istemci tarafndaki senkronizasyonun salanmas adna gelitiriciye daha gl ve ynetilebilir tipler
sunmaktadr. Ayrca senkronize ilemlerinin yaplmas srasnda sunucu veri kaynann sabit
bir SQL veritaban olmas art bulunmamakla birlikte, N-Tier yada SOA tabanl gelitirme
yapmakta mmkndr. Bu alardan bakldnda avantajlar ortadadr.

Konuyu daha iyi kavrayabilmek ve rneimizin gerek ortamdaki almasn izleyebilmek


adna video dersimizi izlemenizi neririm. lerleyen makalelerimizde Ado.Net Senkronizasyon
Servisleri konusuna deinmeye devam ediyor olacaz. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnei ndirmek in Tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Client Application Services (stemci Uygulama


Servisleri) ( 16.12.2008 ) - Web Services
Pek ok istemci uygulama iin nem arz eden konular arasnda dorulama(Authentication), Rol
Ynetimi (Roles Management), profile(Profile) gre kiiselletirme yer almaktadr. zellikle
Web tabanl uygulamalarda bu kstaslar daha ok n plana kmaktadr.
Nitekim Client/Server mimarinin en gzel uyarlamalarndan birisi olan web tabanl
gelitirmelerde, istemcilerin dorulanmas, rollerine gre ne yapabileceklerinin belirlenmesi,
profillerine gre istekte bulunduklar sayfalarn kiiselletirilmesi nemlidir. Bu noktada Asp.Net
2.0srmnden itibaren saym olduumuz bu kriterlerin ok daha kolay bir ekilde
uygulanabilmesi salanmtr. Hatrlanaca zere Asp.Net 2.0 Web Site Administration
Tool veya kod tarafnda Membership API ierisinde yer alan tipler yardmyla, kullanc
hesaplarnn ynetilmesi, eitli rollere atanmas grsel olarak kolayca yaplabilmektedir. Bununla
birlikte Profile API ierisinde yer alan tipler yardmylada, bir web sitesinin kullanc baznda
zelletirilebilmesi son derece kolaylamtr. Ancak bu noktada sz konusu kriterlerin windows
tabanl istemciler(Windows Clients) asndanda deerlendirilebilir olmas olduka kymetlidir.
te tam bu noktada sz konusu kriterlerin servis haline getirilmesi gereklilii ortaya kmaktadr.
Nitekim authentication, role management, profile gibi kstaslar aslnda servis haline
getirilirlerse Asp.Net Web uygulamalar dnda da kullanlabilir hale gelirler. te bu gnk
makalemizin konusu olan stemci Uygulama Servisleri(Client Application
Services) ile, .Net tabanl Windows uygulamalarnn(Windows Presentation Foundation-
WPF yada Windows Forms) sz konusu kriterleri, .Net ierisine gml olan Asp.Net Uygulama
Servisleri(Asp.Net Application Services) zerinden gerekletirebilmeleri mmkndr.

Asp.Net Application Service' ler olmasada windows istemcilerinin dorulama, rol ve


profil ynetimi iin servis bazl mimarilerinin ele almas mmkndr. Sonu itibariyle
burada basit servisler yazlarak bu ihtiyalar karlanabilir. Ancak Asp.Net Application

www.bsenyurt.com Page 141


Service' ler Framework ierisine gml olduklarndan tm istemci eitleri iin bir
standardizasyon getirmektedir. Bununla birlikte Visual Studio 2008 srmnde gelen
bir ka basit yenilikte servislerin kullanmn kolaylatrmaktadr.

Asp.Net Uygulama Servisleri(Asp.Net Application Services) sadece Asp.Net AJAX web


uygulamalarnda deil, .Net tabanl her hangibiri istemci tarafndan ele alnabilir. Bu noktada her
iki istemci uygulama eidide JSON(JavaScript Object Notation) tabanl bir mesaj iletiimini
doal olarak HTTP zerinden gerekletirmektedir. Ne varki Asp.Net Uygulama Servisleri,SOAP
1.1(Simple Object Access Protocol) temelli mesaj gnderen istemcilerede hizmet
verebilmektedir. Buda ok doal olarak .Net dndaki uygulamalarn sz konusu servisleri
kullanabilmesi anlamna gelmektedir. Bir baka deyile rnein Java tabanl bir uygulama bile
Asp.Net Uygulama Servislerini arabilir ve dorulama(Authentication), rol ve profile
ynetimlerini(Role and Profile Management) kullanabilir. stemci eitleri ve servisler
arasndaki ilikiler basite aadaki ekil ile zetlenebilir.

Grld zere uygulama servisleri aslnda birer Web Servisi mantnda


olduundan HTTP zerinden her tr istemcinin ulaabilmesi mmkndr.(WCF bazl bir kullanm
eklide mmkndr. Bunu ilerleyen makalelerimizde yada bir grsel dersimizde ele almaya
alacaz) Bu servislerin temel ilevleri arasnda istemcilerin dorulanmas, dorulama sonrasnda
istemci tarafnda biletler(ticket) almasnn salanmas, istemcinin hangi rolde olduunun tespit
edilmesi ve profiline gre uygulamann ieriinin kiiselletirilmesi saylabilir. Dikkat edilecei zere
sz konusu hizmetler iin bir veri saklama ortam olmas arttr. Varsaylan olarak bu ortam
bilindii zere SQL sunucusu(veya Express srm) zerindeki Membership veritabanlardr.
Ancak istenirse bu veri kaynaklarn kullanan provider' lar servis tarafnda zelletirilebilir ve farkl
depolarn kullanlmas salanabilir. Bunun iin basite konfigurasyon ieriinde bir ka deiiklik
yapmak yeterli olacaktr. Servislerin temel grevleri aadaki tabloda olduu gibi zetlenebilir.

Servis Grevi

Authentication stemcinin dorulanmas ve uygulamaya giri yapabilmesi(Login)


Service(Dorulama amacyla kullanlr. Login ilemi sonrasnda istemci tarafnda saklanacak
Servisi) bir bilet(Ticket)oluturulur. Tahmin edilecei zere bu bilet

www.bsenyurt.com Page 142


bir cookie olarak depolanr ve bir geerlilik sresi vardr.

Roles Service(Rol Uygulama bazl olaraktan istemcinin hangi rolde olduunun Asp.Net
servisi) Role Provider tarafndan denetlenmesi hizmetini stlenir. Buna gre
istemci uygulamada, rnein menlerin veya kontrollerin rol bazl olarak
kullanlabilmesi salanabilir.

Profile Service(Profil stemci uygulamann sunucu zerinde tutulan kullanc verilerine gre
Servisi) herhangibir zamanda farkl biimlerde gsterilebilmesine veya davran
sergilemesine hizmet eden servistir. Burada servis tarafnda tm
kullanclar iin ortaklaa tanmlanm profil zellikleri sz konusudur.
Ancak zellik deerleri her istemci iin farkl olarak tutulabilmektedir.

Bu genel aklamalardan sonra sanyorumki uygulama servisleri hakknda biraz fikir sahibi
olunmutur. Makalemizin bundan sonraki blmnde yer alan hedefimiz ise bir windows istemcisi
zerinden sz konusu servislerin kullanlmasn salamaktr. Bu noktada Visual Studio
2008 srmnn stemci Uygulama Servisilerinin(Client Application Service) ele
alnmasnda byk kolaylklar saladda unutulmamaldr. yleyse hi vakit kaybetmeden ie
balayalm. ncelikli olarak dorulama, rol ve profil ynetimi hizmetlerini stlenecek bir web servisi
gelitiriyor olacaz.

lk olarak bir Web Service Application projesi oluturarak balayabiliriz. Bu uygulama ierisinde
varsaylan olarak gelen Service.asmx dosyasnn sz konusu senaryoda herhangibir kullanm alan
bulunmamaktadr. Servisin tek grevi istemci uygulamaya Authentication, Roles ve
Profile servis hizmetlerini salamaktr. Bu sebepten asmx dosyas silinebilir. u an iin test
servisimiz file-based olarak almtr. Ancak tabiki production ortamlarnda IIS gibi bir sunucu
altnda yaynlanmas nerilir. File-based kullanm nedeniyle Web Servis uygulamasnn
zelliklerinden basit olarak port ve sanal yol(Virtual Path) ayarlamalarn aadaki ekildeki gibi
yapmamz yeterli olacaktr.

Burada belirtilen bilgiler istemci uygulamada ele alnacaktr. imdi web.config dosyas ierisinde
baz basit ayarlamalar yaplmas gerekmektedir. Bu amala web.config dosyas ieriini imdilik
aadaki gibi deitirelim.

www.bsenyurt.com Page 143


Konfigurasyon dosyas ieriinde authentication, role ve profile servislerini etkinletirmek
iin system.web.extensions elementi altnda baz tanmlamalar yaplmtr. Bununla
birlikte provider baznda role ve profile ynetimlerininde etkinletirilmesi
amacyla roleManager ve profile elementleri ele alnmaktadr. Bu basit ayarlamalarn hemen
ardndan kullanc ve rol tanmlamalarnn yaplmasna balanabilir. Bunun iin web servisi
uygulamasnda Web Site Administration Tool' dan yararlanlabilir.

rnein gelitirildii makinede yer


alan machine.config(C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\CONFI
G) ieriinde LocalSqlServer isimli connection stringbilgisi aadaki gibidir.

Bu nedenle Asp.Net Web Site Administration Tool, web servisi uygulamasnn


ierisinde membership ynetimi iin gerekli veritabann(Aspnetdb.mdf) oluturmaktadr.
Elbetteki LocalSqlServer deerinin web servisi uygulamasnn web.config dosyas
ierisinde ezilmesi ve farkl bir lokasyonun iaret edilmeside salanabilir. Eer makinedeki
sunucu zerinde veritabannn oluturulmas istenirse aspnet_regsql komut satr aracndan
yararlnmaldr. Veritaban oluturulduktan sonra ise config dosyas ieriinde oluturulan
veritaban adresi iaret edilerek devam edilebilir.

Asp.Net Web Site Administration Tool zerinde From Internet seenei ile Form Based
Authentication alr. Testler iin iki farkl rol ve kullanc oluturulur. Bu kullanclara ait bilgileri
rnek senaryomuzda aadaki gibi tanmlayabiliriz.

Kullanc ifre Email Gizli Soru Gizli Cevap Rol

buraks buraks1234. buraks@azon.com buraks buraks Yonetici

bili bili1234. bili@azon.com bili bili Calisan

www.bsenyurt.com Page 144


Bu ilemlerin arkasndan AppData klasr altnda aspnetdb.mdf veritaban dosyasnn ald ve
yukardaki kullanc bilgilerinin ilgili tablolara eklendii grlebilir.

Artk windows tabanl istemci uygulamann gelitirilemesine balanabilir. stemci uygulama


asndan en nemli nokta elbetteki yukarda tanmlanm olan web servisine eriilebilmesidir. Bu
amala windows uygulamasnn zelliklerinde aadaki ekran grntsnde yer alan ayarlarn
yaplmas gereklidir.

lk olarak projenin zelliklerinden Services ksmna geilir. Burada Enable client application
services seenei iaretlenmelidir. Sonrasnda ise Authentication, Roles ve Profileservisleri iin
eriim adresleri belirtilir. Dikkat edilecei zere her servis iinde SecurityService isimli web
servis uygulamasnn eriim bilgileri verilmektedir.

Servis bildirimlerinde her bir kstas iin ayr adresler verilebilmektedir.


Dolaysyla Dorulama, rol ve profile ynetimi grevlerini stlenen ve farkl
lokasyonlarda duran 3 farkl servisin tanmlanmas mmkndr.

Windows uygulamasnda basit bir giri formu yer almaktadr. Bu form zerinden kullanc bilgileri
girilmekte ve servise gnderilmektedir. te bu noktada nemli bir referansa ihtiyacmz vardr.
stemci uygulamann System.Web.dll assmebly' n referans etmesi gereklidir. Nitekim ilk
rneimizde kullanacmz Membership snf bu assembly ierisinde yer
alan System.Web.Security isimalannda(Namespace) yer almaktadr.

www.bsenyurt.com Page 145


using System;
using System.Windows.Forms;
using System.Web.Security;

namespace ClientApp
{
public partial class LoginForm
: Form
{
public LoginForm()
{
InitializeComponent();
txtSifre.PasswordChar = '*';
}

private void btnGiris_Click(object sender, EventArgs e)


{
try
{
if (Membership.ValidateUser(txtKullanici.Text, txtSifre.Text))
{
Form1 frm = new Form1();
frm.Show();
this.Hide();
}
else
{
MessageBox.Show("Giri yetkiniz yok", "Yetkisiz Eriim", MessageBoxButtons.OK,
MessageBoxIcon.Stop);
Application.Exit();
}
}
catch (Exception excp)
{
MessageBox.Show(excp.Message);
Application.Exit();
}
}
}
}

Giri formunda kullanc ad ve ifre bilgisi istenmektedir. Sonrasnda


ise Membership snfnn static ValidateUser metodu ile kullanc servis zerinden dorulanmaya

www.bsenyurt.com Page 146


allmaktadr. ValidateUser metodu true veya false deer dndrmektedir. True dnmesi
halinde kullanc bilgisi dorulanmtr. Windows uygulamas
altrldnda, 4500 numaral port zerinden Asp.Net Development Server' nda alt
gzlemlenir. Doru kullanc bilgisi girildiinde formun ald ancak hatal bilgi girilmesi halinde ise
programn kapand gzlemlenebilir.

rnekte dikkat edilmesi gereken noktalardan biriside istemci tarafnda herhangibi proxy tipinin
bilinli bir ekilde fiziki olarak oluturulmaydr. Normal artlarda zellikle windows tabanl
istemcilerin, servisleri kullanabilmeleri iin servise ait proxy tiplerine ihtiyalar vardr. Oysa
Uygulama Servislerinin ele alnmasnda esas olan nokta mesaj al veriidir.

imdi rneimizi biraz daha gelitireceiz. Bu sefer Credential Provider kullanaraktan


bir Login ilemi gerekletirmeye alacaz. Az nceki rnekte LoginForm isimli bir form
tasarlamtk. Bu form ierisindeki dmeye bastmzda Membership snfnn
static ValidateUser metodunu kullanyorduk. Uygulamann ana formuna gei yapmadan nce bu
formun kmasn salamak iinse Main metodu ierisinde aadaki kodlamay kullanmtk.

Application.Run(new LoginForm());

Crendentail Provider kullanaraktan aslnda uygulamaya giri yapld srada otomatik


olarak Login formunun gsterilmesi salanabilir. Olay daha kolay kavramak iin rnek zerinde
adm adm ilerleyelim. Bu amala LoginForm zerinden baz deiiklikler yapmamz
gerekmektedir. lk olarak formumuzun kod yapsn aadaki gibi dzenlemeliyiz.

using System;
using System.Windows.Forms;
using System.Web.Security;
using System.Web.ClientServices.Providers;

namespace ClientApp
{
public partial class LoginForm
: Form, IClientFormsAuthenticationCredentialsProvider
{
public LoginForm()
{
InitializeComponent();
txtSifre.PasswordChar = '*';
FormBorderStyle = FormBorderStyle.FixedSingle;
btnGiris.DialogResult = DialogResult.OK;
btnIptal.DialogResult = DialogResult.Cancel;
}

#region IClientFormsAuthenticationCredentialsProvider Members

public ClientFormsAuthenticationCredentials GetCredentials()


{
if (this.ShowDialog() == DialogResult.OK)
{
return new ClientFormsAuthenticationCredentials(txtKullanici.Text,
txtSifre.Text, chkHatirla.Checked);
}
else
{
return null;

www.bsenyurt.com Page 147


}
}

#endregion
}
}

Dikkat edilecek
olursa LoginForm snfna IClientFormsAuthenticationCrendentialsProvider arayz(Interf
ace) uygulanmaktadr. Bu arayz ierisindeClientFormsAuthenticationCredentials tipinden
nesne rnei dndren GetCrendentials isimli metod bildirimi yer
almaktadr. ClientFormsAuthenticationCredentials snfnn oluturulmas srasnda parametre
olarak kullanc ad ve ifre bilgileri gnderilmektedir. Peki bu form uygulama ierisinde otomatik
olarak nasl kullanlacaktr. Bir baka deyile uygulama altnda LoginForm otomatik olarak
nasl balatlacaktr. Bunun iin projenin zelliklerinde aadaki ekran grntsnde olduu gibi
kk bir bildirim yaplmas yeterlidir.

Burada opsiyonel bir Crendential Provider tanmlamas yaplmaktadr ve LoginForm tipi iaret
edilmektedir. Dolaysyla uygulama balatldnda LoginForm tipinin CrendentialProvider olarak
kullanlaca belirtilmektedir. Bu ilemin hemen ardndan Form1 zerinde Load metoduna
aadaki kodlamalar yaplabilir.

using System;
using System.Windows.Forms;
using System.Web.Security;
using System.Net;

namespace ClientApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

www.bsenyurt.com Page 148


private void Form1_Load(object sender, EventArgs e)
{
try
{
if (!Membership.ValidateUser(String.Empty, String.Empty))
{
MessageBox.Show("Giri Yetkiniz Yok", "Yetkisiz giri", MessageBoxButtons.OK,
MessageBoxIcon.Stop);
Application.Exit();
}
}
catch (WebException excp)
{
MessageBox.Show(excp.Message);
Application.Exit();
}
}
}
}

Dikkat edilecek olursa Membership.ValidateUser metod arsnda String.Empty parametre


deerleri kullanlmtr. Bu son derece doaldr nitekim bu noktada devreye LoginFormsnf
girecektir. Bir baka deyile durum uygulama breakpoint' ler
yardmyla debug modda izlendiinde, Form1_Load' daki ValidateUser arsna gelindikten
sonra LoginForm' un oluturulduu ve modal bir pencere olarak alt gzlemlenebilir.

Uygulama test edildiinde doru kullanc bilgileri girilmesi halinde ana formun(Form1) ald
grlr. Bununla birlikte yanl kullanc bilgileri girilmesi halinde LoginForm' un varsaylan olarak
3 hak tand grlecektir. 3nc giritede baar salanamad takdirde yine program
sonlanacaktr. Beni Hatrla balkl CheckBox kontrol iaretlendii takdirde, sonraki allarda
uygulamann kullanc bilgilerini sormad grlecektir. Yani kullanc bileti istemci tarafnda belirli
sreliine saklanacaktr.(Bu noktada size gzel bir aratrma konusu sunabiliriz. Saklama halinde
istemci bilgisi ne kadar sre ile tutulur. Bu sre nasl zelletirilebilir?) Aslnda u noktada web
uygulamalarnda gerekletirdiimiz Forms Authentication bazl kullanc ynetiminin Windows
versiyonunu yazm bulunuyoruz.

imdi windows uygulamamzda role bazl ilemler yapmaya alacaz. rnein Form1 zerinde
bulunan iki button bileeninin sadece ilgili rollerde grnmesini salayabiliriz.

Sz gelimi Yonetici rolnde olan bir kullanc sadece Muhasebe ilemleri


yapabilecekken, Calisan rolndeki bir kullanc ise sadece BI ilemlerini yapabilecektir. Bunun iin
rnek olarak Form1_Load metodu ierisinde aadaki kodlamalar yapmamaz yeterlidir.

using System;

www.bsenyurt.com Page 149


using System.Windows.Forms;
using System.Web.Security;
using System.Net;
using System.Web.ClientServices.Providers;
using System.Threading;
using System.Security.Principal;

namespace ClientApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
try
{
if (!Membership.ValidateUser(String.Empty, String.Empty))
{
MessageBox.Show("Giri Yetkiniz Yok", "Yetkisiz giri", MessageBoxButtons.OK,
MessageBoxIcon.Stop);
Application.Exit();
}
else
{
IPrincipal principal = Thread.CurrentPrincipal;

if (principal.IsInRole("Yonetici"))
{
Text = String.Format("{0} ({1})", principal.Identity.Name, "Ynetici");
btnMuhasebe.Visible = true;
btnBI.Visible = false;
}
else if (principal.IsInRole("Calisan"))
{
Text = String.Format("{0} ({1})", principal.Identity.Name, "alan");
btnMuhasebe.Visible = false;
btnBI.Visible = true;
}
}
}
catch (WebException excp)
{
MessageBox.Show(excp.Message);
Application.Exit();
}
}

private void btnLogout_Click(object sender, EventArgs e)


{
ClientFormsAuthenticationMembershipProvider prvd
=(ClientFormsAuthenticationMembershipProvider)System.Web.Security.Membership.Pro
vider;

www.bsenyurt.com Page 150


try
{
prvd.Logout();
Application.Restart();
}
catch (WebException excp)
{
MessageBox.Show(excp.Message);
}

}
}
}

Kullancnn hangi rolde olduunu renmek iin Thread snf


zerinden CurrentPrincipal referansna gidilir. CurrentPrincipal, IPrincipal arayz tipinden bir
refernas tamaktadr ve IsInRole metodu yardmyla almakta olan uygulamann sahibi olan
kullancnn parametre olarak belirtilen rolde olup olmad renilebilir. Buna gre windows
uygulamasnn rol bazl zellikleri ayarlanabilir. Form1 ierisinde ayrca Logout ilemi iinde bir kod
eklentisi yer almaktadr. Nitekim LoginForm zerinde Beni Hatrlabalkl CheckBox tkland
takdirde uygulama kullancy her alta hatrlayacaktr. Logout olmak istendii
durumlardaClientFormsAuthenticationMembershipProvider tipine ulamak
ve Logout metodunu armak yeterlidir. Uygulama tekrar test edildiinde nrein buraks isimli
kullanc ile giri yapldnda aadaki ekran grnts ile karlalr.

Benzer ekilde bili isimli kullanc ile girildiinde ise aadaki ekran grnts ile karlalr.

www.bsenyurt.com Page 151


Son olarak makalemizde profil servisinin nasl kullanlabileceini ele almaya alalm. Burada
ama sunucu tarafnda tanmlanan zelliklerin(Properties) her kullanc iin farkl veriler tutacak
ekilde tasarlanmasdr. Bylece dorulanan her kullanc, ayn isimli zelliin farkl deerlerini
sunucu zerinde saklayabilir ve kendi istemci uygulamas zerinde kullanabilir. Bu bir anlamda web
uygulamalarnda sklkla kullanlan kiiselletirmedir(Personalization). Ayn hizmet stemci
Uygulama Servisleri sayesinde, windows tabanl programlara da uygulanabilir. Dilerseniz bu basit
ilemi nasl yapabileceimize bakalm. ncelikli olarak sunucu tarafnda yer
alan web.config dosyas ierisinde basit bir ka bildirimi aadaki gibi yapmamz gerekmektedir.

Dikkat edeceiniz zere profile elementi altnda yer alan properties alt boumu(Child Node)
ierisinde iki adet zellik bildirimi yaplmaktadr. GirisMesaji isimli zellik string tipindendir.
Varsaylan bir deeri vardr. String formatta seriletirilmektedir. simsiz

www.bsenyurt.com Page 152


kullanclar(Anonymous Users) iin bu zellie deer atanmasna izin verilmemektedir.
Ayrca yanlz okunabilir(readonly) bir zellikte deildir. Benzer kriterler SonGirisZamani isimli
ikinci zellik iinde yer almaktadr. Ancak SonGirisZamani isimli zelliin veri tipi DateTime'
dr.profileService elementi ierisinde ise sz konusu zelliklere okuma ve yazma
haklar, readAccessProperties ve writeAccessProperties nitelikleri(Attribute) ile
verilmektedir. Burada birden fazla zelliin aralarna virgller konularak belirtilebildiinde dikkat
edilmelidir. Bu ilemler sonrasnda sunucu tarafnda her istemci iin farkl deerlere sahip
olabilecek zellik tanmlamalar yaplm olmaktadr.

imdi istemci tarafnda baz ilemlerin yaplmas gerekmektedir. ncelikli olarak istemci
uygulamada Properties->Settings ksmna geilir ve Load Web Settings dmesine baslr.

Bu ilemin ardndan sunucu tarafndaki profile servisine balanlmak istenir ki var olan geerli bir
kullanc ile bu gerekletirilebilir.

Eer balant baarl bir ekilde salanrsa, sunucu tarafndaki web.config dosyasnda tanmlanan
profil zelliklerinin istemci uygulamadaki settings ksmna eklendii ak bir ekilde grlebilir.

www.bsenyurt.com Page 153


Bir baka deyile artk istemci tarafnda GirisMesaji ve SonGirisZamani isimli zelliklere tip
baznda eriilebilecektir. Kod tarafnda, formun yklenmesi ile birlikte bu zelliklerin deerleri
okunabilir ve herhangibir amala kullanlabilir. Form kapanrken veya uygulamadan klrkende
istenirse, bu zelliklerin yeni deerlerinin set edilip kaydedilmesi, bir baka deyile servis
tarafndaki aspnetdb.mdf veritabannda yer alan aspnet_Profile tablosuna yazdrlmas
salanabilir. Bu rneimizde sz konusu senaryoyu ok basit bir ekilde deerlendirmeye
alacaz. rnein Form1 in Load metodunu aadaki gibi gncellediimizi dnelim.

private void Form1_Load(object sender, EventArgs e)


{
try
{
if (!Membership.ValidateUser(String.Empty, String.Empty))
{
MessageBox.Show("Giri Yetkiniz Yok", "Yetkisiz giri", MessageBoxButtons.OK,
MessageBoxIcon.Stop);
Application.Exit();
}
else
{
txtGirisMesaji.DataBindings.Add("Text", Properties.Settings.Default,
"GirisMesaji");
lblSonGirisZamani.Text =
Properties.Settings.Default["SonGirisZamani"].ToString();

IPrincipal principal = Thread.CurrentPrincipal;

if (principal.IsInRole("Yonetici"))
{
Text = String.Format("{0} ({1})", principal.Identity.Name, "Ynetici");
btnMuhasebe.Visible = true;
btnBI.Visible = false;
}
else if (principal.IsInRole("Calisan"))
{
Text = String.Format("{0} ({1})", principal.Identity.Name, "alan");
btnMuhasebe.Visible = false;
btnBI.Visible = true;
}
}
}

www.bsenyurt.com Page 154


catch (WebException excp)
{
MessageBox.Show(excp.Message);
Application.Exit();
}
}

Dikkat edilecek olursa txtGirisMesaji isimli TextBox


kontrolne veri balamas(DataBinding) srasnda Properties.Settings.Default veri
kayna(Data Source) olarak gsterilmitir. Son parametrede ise Settings ksmnda tanml olan
zellik adlar verilmektedir. txtGirisMesaji isimli TextBox kontrol iin ift-ynl veri
balama(two-way databinding)sz konusudur. Bylece kontrol ierisinde veri deitirildiinde
sz konusu deiiklik zellik tarafnada otomatik olarak
yanstlacaktr. lblSonGirisZamani isimli Label kontrol ise tek ynl(one-
way) olarak SonGirisZamani zelliine balanmtr.

Form' dan klrken bu verilerin servis tarafna gnderilmesi gerekir ki bir sonraki girite son
deerler kullanlabilsin. Bu durumda rnein Form1_Closing olay metodu ierisinde aadaki
kodlamalar yaplabilir.

private void Form1_FormClosing(object sender, FormClosingEventArgs e)


{
if (Thread.CurrentPrincipal.Identity.AuthenticationType.Equals("ClientForms"))
{
try
{
Properties.Settings.Default["SonGirisZamani"] = DateTime.Now;
Properties.Settings.Default.Save();
}
catch(WebException excp)
{
MessageBox.Show(excp.Message);
}
}
}

lk olarak kullancnn ClientForms tipinde authentication gerekletirip gerekletirmediine


baklr. Bir baka deyile kullancnn Client Application Services kullanarakLogin olup olmad
anlalmaya allmaktadr. Eer bu ekilde bir balant salanm ise SonGirisZamani zelliinin
deeri deitirilir ve Save metodu arlr. Dikkat edilecei zere GirisMesaji isimli profil zellii
iin bir atama yaplmamtr. Bunun sebebi iki ynl veri balama
ileminin txtGirisMesaji kontrol iin kullanlyor olmasdr. Bu metodun almas srasnda baz
hatalar oluabilir. Sz gelimi Save metodu alt srada istemcinin cookie bilgisi silinmi olabilir.
Yada kullanc Logout olmu durumdadr ancak halen daha uygulama ierisindedir ve Save metodu
arlmtr. Dolaysyla ilemin gerekletirilebilmesi iin tekrardan Loginileminin yaplmas
gerekmektedir. Dier taraftan kayt ilemi srasnda servis ile olan balantnn kurulamama
ihtimalide vardr. Bu gibi durumlar ele alnaraktan daha gl bir profil kaydetme sreci
oluturulabilir. (Burada nasl bir tedbir alnabileceinide bir aratrma konusu haline
getirebilirsiniz) Artk uygulamay bu haliyle test edebiliriz. Bilhassa ayn uygulamadan iki rnek
balatp iki farkl kullanc ile girilmesini tavsiye ederim. Bu durumda her iki kullanc iinde farkl
profil verileri tutulduu gzlemlenebilir. Aadaki test ekranlarnda olduu gibi.

www.bsenyurt.com Page 155


Bu testin sonrasnda sunucu tarafndaki aspnetdb.mdf veritabannda yer
alan aspnet_Profile tablosu ieriine bakldnda her iki kullanc iinde ilgili satrlarn
oluturulduu grlebilir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde stemci Uygulama


Servislerini(Client Application Service), Visual Studio 2008 ortam zerinde basit bir ekilde
ele alarak,Windows tabanl istemcilerde Authentication,Roles ve Profile hizmetlerinin nasl ele
alnabileceini basit bir ekilde incelemeye altk. Sz konusu kriterlerin birer servis olarak .Net
Framework ierisine dahil edilmesi sonrasnda herhangibir .Net istemcisinin bunlar
kullanabileceini anladk. Burada .Net tabanl istemcilerin JSON formatnda mesajlama yaptn
ancak .Net d uygulamalarnda SOAP 1.1 formatn kullanarak bu servisleri ele alabileceklerine
deindik ki bunu ilerleyen makalelerimizde ele almaya alacaz.

Makalemizde gelitirmeye altmz rnein bir benzerinin adm adm yapln C#Nedir?
adresinde yer alan grsel derstende e zamanl olarak takip edebilirsiniz. Tekradan grnceye
dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

www.bsenyurt.com Page 156


Ado.Net Data Services Ders Notlar - 6
(Optimistic Concurrency) ( 30.10.2008 ) - WCF
Deerli Okurlarm Merhabalar,

stemci-Sunucu(Client-Server) bazl uygulamalar gz nne alndnda, istemcilerin ayn


veriler zerinde birbirlerinden habersiz ekilde deiiklikler yapabilme ihtimali olduka mehur bir
vaka olarak bilinmektedir. zellikle .Net tarafnda balantsz katman(Disconnected
Layer) uygulamalarnda bu tip vakalar son derece nemlidir. Zaman zaman bu tip vakalar ile
mcadele etmek ve tedbirler almak gerekir. Vaka aslnda u ekilde ifade edilebilir; "sunucu
zerinden ayn veri ieriklerini eken istemci programlar, sunucu ile balantlarn kestikten sonra
kendi uygulama alanlar zerine aldklar verilerde deiiklik yapabilirler. Ancak bu noktada sunucu
ile srekli bir balantlar olmadndan, baka istemcilerin ayn veriler zerinde deiiklikler yapp
yapmadklarn tam olarak bilemezler. Bu sebepten ayn veriler zerinde birbirlerinden habersiz
olacak ekilde yaptklar deiiklikleri sunucuya gnderebilirler." te bu noktada sunucu tarafnda
durumun nasl ele alnaca nem kazanr. Bu amala eitli denetleme mekanizmalar kullanlabilir.
Bu yazmzda hepinizin kulanda bol bol Optimistic Concurrency kelimelerinin nlayacan
imdiden syleyebilirim.

Bahsetmi olduumuz bu vaka bazen grmezden gelinebilecek olmasna karn ou durumda


kontrol altna alnmas gereken bir sorun olarak deerlendirilir. in ierisine birde deiikliklerin
sunucu zerindeki veritabanna gnderilmesi srasnda devreye alnan Transaction' lar girerse,
vaka kendi ierisinde dahada karmaklar. Ancak bizim u andaistemediimiz tek ey bu vakay
dahada kartrmaktr. Bunlara karn sz konusu vakada zmsel
olarak optimistic(iyimser) yada pesimistic(ktmser) yaklamlarn uygulanabilir olduklarnda
bilmek gerekir. Peki bu durumun Ado.Net Data Service' ler ile olan balants nedir? Hereyden
nce Ado.Net Data Service hangi modeli baz alr? Baz ald model nasl uygulanr?

Bildiiniz gibi bu ana kadarki ders notlarmzda ve grsel derslerimizde Ado.Net Data Service'
lerin, web programlama modeline uygun olarak altn ve EDM(Entity Data
Model)yada Custom LINQ Provider gibi katmanlar zerinde veri sunumu gerekletirdiine
deindik. Ayrca, Ado.Net Data Service' ler bir sunucu uygulama zerinden host edilmek zorunda
olmakla birlikte, bunlar tketen farkl istemci uygulamalar yazlabilmektedir. Bir baka deyile tipik
bir istemci-sunucu modeli sz konusudur. Bunlara ilaveten iin ierisinde, istemci tarafna
ekilebilen veriler ve tabiki CRUD(CreateRetriveUpdateDelete) operasyonlar sz konusudur. Bu
operasyonlar ierisinde yer alan CUD fonksiyonellikleri ve istemcilerin veriyi kendi uygulama
alanlarna ektikten sonra sunucu ile herhangibir balantlarnn kalmay, istemcilerin ayn veriler
zerinde birbirlerinden habersiz deiikliker yapabilecekleri sonucunu dourmaktadr. Peki bu tarz
bir sorun ile nasl mcadele edilebilir? Ado.Net Data Service zm
olarak, Optimistic Concurrency yaklamnn ele alnmasna izin vermektedir.

Optimistic Concurrency yaklamna gre, istemci tarafna ekilen veriler


gncelletirilmek zere sunucu tarafna gnderildiklerinde ilk hali ile karlatrlrlar.
Bylece ilk okumadan sonra baka bir istemcinin ayn veriyi deitirip deitirmedii
kontrol altna alnabilir. Eer bir deiiklik var ise istemcinin bu konuda uyarlmas
gerekir. Bu uyarl zerinde allmakta olan modele gre ounlukla
bir istisna(Exception) olarak ele alnr. Sz gelimi Ado.Net tarafndan
bildiimizDBConcurrencyViolation bu tip bir istisnadr. Tabi iin ierisine servis
ynelimli bir zm girdiinde bu, ounlukla bir Fault Message formatna uygun olacak
ekilde hata bilgisi ieren bir XML verisidir. Eer veriler bakas tarafndan
deitirilmemise tabiki gncelleme ilemi sunucu tarafndada onaylanacaktr.

www.bsenyurt.com Page 157


Peki Ado.Net Data Service tarafnda bu yaklam nasl ele alnmaktadr? Artk bu noktadan sonra
adm adm basit bir rnek zerinde ilerlenilmesinde yarar olaca kansndaym. rneimizi
gelitirirken en byk yardmclarmzdan biriside Fiddler isimli HTTP Debugging Proxy arac
olacaktr. Nitekim akma olmas halinde istemciler ve sunucu arasnda gidip
gelen HTTP paketlerinin incelenmesi gerekmektedir. Test senaryomuz son derece basittir. Ayn veri
satr zerinde deiiklik yapacak en az iki istemci uygulamann altrlmas ve bu esnada
oluacak istisnalarn(Exceptions) ve HTTP paketlerinin izlenmesi hedeflenmektedir. Bunlarn
yannda SQL tarafnda neler olduunu gzlemlemek adnada SQL Server Profiler aracndan
yararlanmamz gerekecektir. Tabi ncelikli olarak basit bir WCF Service uygulamas gelitirerek
balamalyz. Sz konusu servisimiz daha nceden gelitirdiimiz Azon isimli veritabann ve
ierisinde bir ka satr veri ieren Kitap isimli tabloyu istemci tarafna sunacak ekilde
gelitirilecektir. Bu nedenle WCF Serviceuygulammz iin gerekli olan n hazrlklar aadaki
gibidir.

EDM(Entity Data Model) ieriimiz;

Burada hemen bir zellii vurgulamak gerekiyor. EDM diagramnda yer alan Kitap Entity tipi
ierisinde yer alan zelliklerin her birisi iin Concurrency Mode isimli bir zellik yer
almaktadr.Properties penceresinden ulalabilen bu zelliin deeri varsaylan
olarak None eklindedir. Buna Mixed deerini vermemiz halinde Optimistic Concurrency iin sz
konusu zellik deerlerinin hesaba katlaca belirtilmi olunur. rneimizde bu
amala Ad ve Fiyat zelliklerinin Concurrency Mode deerleri Mixed olarak belirlenmitir. Ki
senaryomuzda sadece bu alanlarn deerleri iin Optimistic Concurreny kontrol yaplacaktr.

www.bsenyurt.com Page 158


Kitap tablosuna ait bir ka satrlk veri ierii;

AzonServices.svc.cs ieriimiz;

using System;
using System.Data.Services;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Web;
using AzonModel;

public class AzonServices


: DataService<AzonEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}

Tahmin edeceiniz gibi istemci tarafnda CRUD operasyonlar


yaplabileceinden EntitySetRights.All enum sabiti deeri kullanlmtr. Buraya kadar geldikten
sonraAzonServices.svc isimli Ado.Net Data Service rneinin altndan emin olmakta yarar
vardr. Bunun iin servisi basit bir tarayc uygulama ierisinde amamz yeterli olacaktr.
Aadakine benzer bir ekran grnts ile karlarz.

www.bsenyurt.com Page 159


Yanlz burada Kitap entity ierii talep edildiinde, atom formatnda retilen XML verisinde yeni
bir attribute tanmlamas karmza gelecektir.

www.bsenyurt.com Page 160


Her bir entity elementi ierisinde m:etag isimli bir attribute(nitelik) tanmlanmtr. m takma
adl isim alanna sahip bu nitelikler ierisinde her bir kitabn Ad ve Fiyat bilgilerinin yer aldna
dikkat edin. Hatrlayacanz gibi, EDM diagramnda bu
zelliklerin Concurrency Mode deerlerini Mixed olarak belirlemitik. Bu nedenle akma
kontrol iin ilgili zelliklerin deerleri XML ktsna dahil edilmitir. Bundan
dolay etag yada entitytag ad verilen nitelikler ierisinde tanan zellik deerleri, akma
kontrol iin istemci ile sunucu arasnda gidip gelen paketlerde nem kazanmaktadr.

Gelelim istemci uygulamamza. Amacmz Optimistic Concurrency modelini Ado.Net Data Service'
ler zerinde incelemek olduundan imdilik iimizi grecek basit bir program yazmamz yeterli
olacaktr. Sanyorumki ne demek istediimi anladnz :) Basit

www.bsenyurt.com Page 161


bir Console Application gelitiriyoruz. Uygulamamza ayn solution ierisinde yer alan
servisimizide ekledikten sonra istemci uygulama kodlarmz aadaki gibi gelitirebiliriz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClientApp.AzonServiceReference;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
// Proxy nesne rnei oluturulur.
AzonEntities proxy = new AzonEntities(new
Uri("http://buraksenyurt:1000/AdventureHost/AzonServices.svc"));

// Concurrency testi iin ID si 81 olan Kitap verisi ekilir


Kitap kitap81 = (from k in proxy.Kitap
where k.KitapId==81
select k).First<Kitap>();

// 81 nolu ID' ye ait kitap bilgileri gsterilir


Console.WriteLine("{0} : {1} : {2} :
{3}",kitap81.KitapId,kitap81.Ad,kitap81.Fiyat,kitap81.StokMiktari);

// Test amacyla rastgele bir art deeri retilir ve 81 nolu Kitap nesne rneinin Fiyat
deeri deitirilir
Random rnd = new Random();
int yeniFiyatArtisi = rnd.Next(1, 10);
kitap81.Fiyat = kitap81.Fiyat + yeniFiyatArtisi;

// Buras test noktas


Console.WriteLine("{0} in fiyat {1} olarak deitirilecek. Onaylamak iin tua basn.",
kitap81.Ad, kitap81.Fiyat);
Console.ReadLine();

// Nesne gncellenir
proxy.UpdateObject(kitap81);

// Bir istisna blou ierisinde SaveChanges metodu arlr.


try
{
proxy.SaveChanges();
Console.WriteLine("lem tamam");
}
catch (Exception excp)
{
// Burada beklenen hata mesaj InnerException ierisinde gelir
Console.WriteLine(excp.InnerException.Message);
}

Console.ReadLine();
}

www.bsenyurt.com Page 162


}
}

Ksaca istemci uygulamada neler yaptmzdan bahsedelim. ncelikli olarak proxy nesnesi
rnekleniyor. Fiddler aracn Web Development Server zerinden altracamz iin daha
nceki makalemizde bahsettiimiz gibi 1000 numaral portu ve makine adn kullanyoruz. lerleyen
ksmlarda test amacyla KitapID deeri 81 olan kitap bilgilerini istemci tarafna LINQ sorgusu
zerinden ekiyoruz. Elde edilen Kitap nesne rneinin Fiyat zelliini Random snf ile retilen
rastgele bir deer kadar arttryoruz. Sonrasnda ise bir Console.ReadLine ars grmekteyiz. Bu
arnn olduu yer ayn uygulamadan ayn makinede birden fazla altrdmzda test yapmamz
kolaylatracaktr. Bu arnn ardndan UpdateObject metodu iletiliyor. Sonrasnda
ise try...catch bloklar ierisinde alnm olan bir SaveChanges metodu ars gryoruz. Bu
ar istemci tarafndaki gncelletirmenin sunucuya iletilmesine neden oluyor. te bu noktada
eer bir akma sz konusu ise istemci tarafna bir exceptiondndrlecektir. Gelin hemen bir
test yaparak ie balayalm. Testimizde ayn uygulamadan iki adet altryor ve birinde
deiiklikleri sunucuya gnderdikten sonra , ikincisi iinde ayn ilemi yapmay deniyoruz. Sonu
olarak bu test sonrasnda aadaki ekran grntleri oluacaktr.

Her iki uygulama alp ilk uygulamadaki gncellemeler servis tarafnda gnderildiinde;

kinci uygulamada devam edilip yeni deerler ile ayn veri gncellenmek zere servise
gnderildiinde;

Grld gibi ikinci uygulamaya bir adet Fault Exception gnderilmi


ve etag deerinin Request Header' daki gncel etag deeri ile uyumad belirtilmitir. Bir
baka deyile ikinci uygulamann gncelletirmek istedii satr bakas tarafndan gncellenmitir.

www.bsenyurt.com Page 163


Hemen Fiddler arac ile arka planda olanlar inceleyelim. Birinci uygulama altrldnda ilk
olarak 81 numaral KitapID deerine sahip veri ekilmektedir. Bu tipik olarak HTTPGet arsdr
ve Request(stek) ile Response(Cevap) paketlerine ait Header(Balk) ierikleri aadaki
ekran grntsnde olduu gibidir.

Standart bir iletiim olduu gzlemlenmekle birlikte Respons Header ierisinde ETag isimli bir
bilgi daha yer almaktadr. Bu bilgiye gre ilk uygulamaya ekilen kitap satrnda Ad deeriAdo.Net
Data Services Pro, Fiyat deeri ise 71.0000 dr. kinci uygulamada ayn talepte bulunacaktr ve
yine yukardaki ekran grntsnde yer alan paket alverii sz konusudur. Bu durumda ikinci
uygulama iin sz konusu olan Response Header ierisindeki ETag deeride ayndr. Gelelim
3nc paket alveriine.

www.bsenyurt.com Page 164


Request Header ierisinde If-Match isimli bir bilgi yer ald grlmektedir. Bu bilgiye
gre Ado.Net Data Services Pro ve 71.0000 deerlerinin dorulanmas istenmektedir. u
durumda baka bir uygulama yada veritaban zerinden dorudan olacak ekilde, 81 numalar
kaytta bir deiiklik olmadndan Response Headers ierisinde sz konusu verinin gncellenen
deerlerine ait bilgiler istemci tarafna gnderilmektedir. Bir baka deyile imdi ETag deerinin
ierii Ado.Net Data Services Pro ve 76.0000 dr. Dikkat edilecei zere Fiyat deimitir.
Ancak arkada unutmamamz gereken ikinci uygulamamz vardr. Bu uygulmada tua basp devam
edildiinde, Fiddler zerinden 4nc paket alverii aadaki gibi yakalanmaktadr.

www.bsenyurt.com Page 165


Bu kez Request Header ierisindeki ETag deeri 71.0000 deeri iin talepte bulunur. Ancak az
nceki uygulamada ETag deerinde yer alan Fiyat 76.0000 olarak deimitir. Dolaysyla If-
Match karlatrmas baarl olmayacaktr. Bunun sonucu olarakta geriye HTTP/1.1
412 kodu (Precondition Failed) dner.

HTTP 1.1 durum kodlar(Status Codes) ve aklamalar iin WC3 zerinden


yaynlanan adresinden bilgi alabilirsiniz.

ok doal olarak bu hata iin istemci tarafna bir exception bilgisi gnderilmitir. Bu
arada SQL tarafnda neler olduunuda bilmekte yarar vardr. Ayn
sre SQL Server Profilerzerinden incelendiinde ilk uygulamann gncelletirme ileminden
hemen nce 81 numalar KitapID iin bir Select sorgusu altrld sonrasnda ise
aadakiSQL ifadesinin devreye girdii grlr.

www.bsenyurt.com Page 166


exec sp_executesql N'update [dbo].[Kitap]
set [Ad] = @0, [Fiyat] = @1, [StokMiktari] = @2, [KategoriId] = @3
where ((([KitapId] = @4) and ([Ad] = @5)) and ([Fiyat] = @6))
',N'@0 nvarchar(25),@1 decimal(19,4),@2 int,@3 int,@4 int,@5 nvarchar(25),@6
decimal(19,4)',@0=N'Ado.Net Data Services
Pro',@1=76.0000,@2=35,@3=1,@4=81,@5=N'Ado.Net Data Services Pro',@6=71.0000

Dikkat edelim! Where ifadesinden sonra KitapID, Ad ve Fiyat alanlar hesaba katlmtr. Bunun
en byk nedeni EDM diagramnda Concurrency Mode deeri Fixed olarak belirlenen
zelliklerdir. Dolaysyla bu Where kriteri bozulmadndan gncelletirme ilemi yaplmtr. Oysaki
ikinci uygulama tua baslarak devam ettirildiinde, Update sorgusunun altrlmad onun
yerine 81 nolu KitapID iin bir Select sorgusunun iledii grlr. Akabindede
zaten ETag verilerindeki uyumazlk nedeni ile istemciye bir hata mesaj gnderilmektedir. Buraya
kadar anlattklarmzn zetini aadaki tablo ile zetleyebiliriz.

lem Aklama (HTTP Trafii ve SQL taraf)

Birinci Uygulama alr.

Kitap kitap81 = (from k in proxy.Kitap HTTP Get Paketi Gnderilir.


where Select sorgusu 81 no iin alr.
k.KitapId==81 Response bilgisi HTTP 200 Ok.
select ETag bilgisi "Ado.Net Data Services Pro,
k).First<Kitap>(); 71.0000"

kinci Uygulama alr.

Kitap kitap81 = (from k in proxy.Kitap HTTP Get Paketi Gnderilir.


where Select sorgusu 81 no iin alr.
k.KitapId==81 Response bilgisi HTTP 200 Ok.
select ETag bilgisi "Ado.Net Data Services Pro,
k).First<Kitap>(); 71.0000"

Birinci Uygulamada Fiyat bilgisi gncellenir.

HTTP Merge paketi gider.


If-Match bilgisi "Ado.Net Data Services Pro,
71.0000" dir. Karlatrma dorudur.
Birinci Uygulamada SaveChanges metodu
SQL tarafnda Update sorgusu alr gncelleme
alr.
yaplr.
Response iin ETag deeri "Ado.Net Data
Services Pro, 76.0000" olur.

kinci Uygulamada Fiyat bilgisi gncellenir.

HTTP Merge paketi gider.


If-Match bilgisi "Ado.Net Data Services Pro,
71.0000" dir.
kinci Uygulamada SaveChanges metodu
SQL tarafnda 81 iin veriler istenir.
alr.
If-Match bilgisindeki Fiyat verisi iin uyumazlk
vardr.
HTTP/1.1 412 (Precondition Failed) gnderilir.

Tabi iin bir de dier eklini ele almak gerekir. Yani Fixed deerlerini kullanmadmz durum.
Burada sadece servis tarafndaki EDM diagramnda deiiklik yapmak yeterli olacaktr. Bir baka
deyile istemci tarafnda, Concurrency modelinin deitirildiine dair bir servis gncellemesi
yaplmasna gerek yoktur. Tabi byle bir durumda her iki uygulamann gncelleme ilemleride

www.bsenyurt.com Page 167


geerli olacaktr ve buna grede en son yazann verisi tabloya yanstlacaktr. Ayn rnei buna gre
test ettiimizde SQL tarafna giden Updatesorgularnn aadakine benzer olduu grlmektedir.

exec sp_executesql N'update [dbo].[Kitap]


set [Ad] = @0, [Fiyat] = @1, [StokMiktari] = @2, [KategoriId] = @3
where ([KitapId] = @4)
',N'@0 nvarchar(25),@1 decimal(19,4),@2 int,@3 int,@4 int',@0=N'Ado.Net Data Services
Pro',@1=88.0000,@2=35,@3=1,@4=81

Dikkat edilecei zere sadece Primary Key alan hesaba katlmtr. Yine Fiddler arac ile istemci
ve servis arasndaki HTTP trafii incelendiinde If-Match yada ETag gibi
bilgilerinRequest veya Response Header' lar ierisinde yer almad grlr. Grld zere
senaryonun gerektirdiklerine gre servis tarafnda Optimistic Concurrency modeli tercih edilebilir
veya edilmez. Eer bu model tercih edilirse istemci tarafndaki uygulamalarda mutlaka Exception
kontrolnn yaplmas gerekmektedir. Bylece geldik bir yazmzn daha sonuna. Bir sonraki
yazmzda grnceye dek hepinize mutlu gnler dilerim.

rnei indirmek iin tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Ado.Net Data Services Ders Notlar - 5 (Custom


LINQ Provider-CUD) ( 24.10.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Ado.Net Data Services konusu ile ilintili bir nceki ders notlarmzda, EDM(Entity Data
Model) zerinden CUD(CreateUpdateDelete) ilemlerinin nasl yaplabileceini incelemeye
almtk. Ancak durum zel LINQ Provider kullanm sz konusu olduunda biraz daha
karmaklamakta. Nitekim Custom LINQ Provider kullanlmas halinde istemci tarafndan
gelen CUD taleplerine karlk servis tarafnda zel kodlamalarn yaplmas gerekiyor. Bu noktada
ders notlarmz ierisinde belkide oumuzun korkup fazla bulamak istemedii bir konuya ksacada
olsa deineceimizi imdiden ifade etmek isterim. Reflection(Yansma) :)

"Hayda brea nereden kt bu reflection" diyenelerimiz eminim ki vardr. yleyse ksaca bu kavram
hatrlamaya alalm. Reflection teknikleri ile alma zamannda(Runtime) .Net CLR tiplerine
ait(ister kullanc tanml ister nceden tanmlanm tipler) metadata bilgilerine ulalabilmektedir.
Bu adan bakldnda zellikleplug-in tabanl uygulama gelitirmelerde, IDE tasarmlarnda
kullanlmaktadr. Hatta alma zamannda tiplere ait canl nesne rneklerinin retilip kullanlmas
bile mmkndr. Sz gelimi .Net Reflector gibi aralar Reflection teknikleri yardmyla
gelitirilirler. Peki konunun Ado.Net Data Service' ler ile olan ilikisi nedir? Neden bu tekniklere
ihtiya vardr?

Reflection tekniklerinin kalbinde Type isimli tip yer alr. Bu basit tipten yararlanarak
alma zamannda herhangibir tipe ait bilgileri elde etmek, tiplere ait nesne rnekleri
oluturmak gibi ilemler yaplabilir. Bu basit ilemler ile plug-
in uygulamalar, Reflection gibi .Net Assembly' larnn ieriini gsteren programlar

www.bsenyurt.com Page 168


yazlabilir. Hatta IDEgelitirmelerindede Reflection tekniklerinden yararlanlmaktadr.

Bu sorunun sorulmasn nedeni servis tarafnda Custom LINQ Provider kullanlmasdr.


stemciler CUD ilemleri iin servis tarafna nesne verisi ieren HTTP paketleri gnderirler. Servis
tarafnda yer alan herhangibir LINQ Provider' n bu nesne ieriklerini ilgili veri kaynaklarna
eklemesi, kartmas yada deitirmesi iin alma zamannn anlayabilecei belirli kurallara
uymas gerekir. Bylece herhangibir Custom LINQ Provider alt yapsnn CUD ilemlerini
gerekletirebilmesi bir standart altna alnm olunur. yleyse burada servis tarafnda uyulmas
gereken bir kurallar dizisi sz konusudur. Bu kurallar yle bir yap ierisinde tanmlanmaldrki .Net
CLR' a zg olmaldr. te bu noktada nasl bir tip olabilir sorusunu kendinize sormanz
gerekmektedir? Interface(Arayz). Bilindii zere bir arayz, uyguland tipin uymas gereken
kurallar belirtmektedir. Ancak bunun yannda ok biimlilik zelliine sahiptir ve bu nedenle
alma zamannda kendisini implemente eden tiplere ait nesne rneklerini tayabilmektedir.
Buda plug-in tabanl mimarilerde nem arz eden bir konudur. Bu imdiki senaryomuzda gerekli bir
bilgi deildir belki ama arayzlerin ne ie yaradnda anlatan gzel bir tanmlamadr.

Interface(Arayz) tipi sadece kendisini uyarlayan tiplerin uymas


gereken ye(member) tanmlamalarn ierir. Bunun dnda i
yapan yeler(members)iermez. Ayrca polimorfik bir baka deyile ok biimlilie
destek verirler. Dolaysyla bir arayz tipini kullanarak alma zamannda kendisinden
treyen birden fazla nesneyi iaret etmek ve bunlarn hepsi iin ortak ilemler yrtmek
mmkndr. Nitekim bu ortak ilemler arayz ierisinde tanmlanm olup, arayz
implemente eden tiplerde yazlma zorunluluu bulunan ve farkl ekillerde uygulanabilen
yelerdir. (Bu noktada ah keke u C# derslerindeki temel konular biraz daha
aratrsaydm diyenleriniz olabilir. Vakit ok ge deil...)

Bu anlatlanlardan zet olarak u sonucu kartabiliriz. Ado.Net Data Service ierisinde


kullanlan tayc varlk tipinin(Container Entity Type) CUD ilemleri iin belirli kurallara
uymas ve bu kurallar uygulamas gerekmektedir. Bu dayatma iin .Net
CLR ierisinde System.Data.Services isim alannda yer alan IUpdatable adl bir interface tipi
tanmlanmtr. Bu arayzn ye metodlar ile CUD ilemleri iin gerekli uyarlamalarn yaplmas
istenir. Bakn henz Reflection tekniklerinden birisini kullanmaktan bahsetmediimizi belirtelim.
Bunu bir nesneyi servis tarafnda rneklerken kullanyor olacaz.

u anda neler hissetiinizi biliyoru ve size hak veriyorum. Bu yazlanlar biraz skc. Aslnda adm
adm bir rnee geerek ilerlemekte yarar var. Gelin hi vakit kaybetmeden birWCF
Service uygulamas gelitirelim ve ierisinde Custom LINQ Provider kullanan bir Ado.Net Data
Service esi oluturalm. Bu amala alan WCF Service uygulamasna srasyla aadaki tipleri
entegre etmemiz yeterli olacaktr. lk olarak servis tarafndaki gelitirmelerimizin genel
grnmne snf diagram grntsnden bir bakalm.

Snf diagram(Class Diagram);

www.bsenyurt.com Page 169


ncelikli olarak Entity tipimizi gelitirelim. Product isimli snfmz basit olarak bir rne ait Id, ad,
fiyat, stok miktari gibi bilgileri tayacak ekilde tasarlanmtr.

Product snf;

using System;
using System.Linq;

namespace ServerApp
{
public class Product
{
public int ProductID { get; set; }
public string Name { get; set; }
public double ListPrice { get; set; }
public int UnitsInStcok { get; set; }
}
}

Product entity tipini ierisinde kullanan ve istemcilere sunan tayc tipimiz ise aadaki gibidir.
Yanlz burada dikkat edilmesi gereken en nemli nokta sz konusu tipin IUpdatablearayzn
uygulam olmasdr.

www.bsenyurt.com Page 170


ShopEntites snf;

using System;
using System.Linq;
using System.Reflection;
using System.Data.Services;
using System.Collections.Generic;

namespace ServerApp
{
// CUD ilemlerine destek vermesi amacyla ShopEntities tipine IUpdatable arayz
uyarlanmtr.
public class ShopEntities
:IUpdatable
{
// Product tipinden listeyi tutacak generic koleksiyonumuz
static List<Product> _products;

// Static yapc metod(Constructor) ierisinde bir kereliine _product koleksiyonu rnek


veriler ile doldurulur.
static ShopEntities()
{
_products = new List<Product>
{
new Product{ ProductID=1, Name="Dvd Player", ListPrice=100, UnitsInStcok=100},
new Product{ ProductID=2, Name="Mp3 Player 8 Gb", ListPrice=50,
UnitsInStcok=150},
new Product{ ProductID=3, Name="15.4 inch LCD", ListPrice=190,
UnitsInStcok=50},
new Product{ ProductID=4, Name="320 Gb Hdd", ListPrice=120,
UnitsInStcok=200},
new Product{ ProductID=5, Name="1 Tb Hdd 3.5inch", ListPrice=250,
UnitsInStcok=175}
};
}

// stemci tarafna sunulacak olan readonly(yanlz okunabilir) zellik


public IQueryable<Product> Products
{
get
{
// AsQueryable<> ile generic List koleksiyonunun sorgulanabilir olmas salanr
return _products.AsQueryable<Product>();
}
}

#region IUpdatable Members

// Yeni bir Product nesnesinin oluturulmas ve eklenmesi srasnda devreye girer


public object CreateResource(string containerName, string fullTypeName)
{
// Activator kullanlarak tipin full adndan bir nesne oluturulmas salanr
var newProduct = Activator.CreateInstance(Type.GetType(fullTypeName));
// Oluturulan nesne rnei Product tipine dntrlerek _products isimli generic
koleksiyona eklenir
_products.Add((Product)newProduct);

www.bsenyurt.com Page 171


// Eklenen yeni nesne rnei metoddan geriy dndrlr
return newProduct;
}

// Silme ilemi srasnda devreye giren metod


// Parametre olarak silinecek entity nesne rnei gelir
public void DeleteResource(object targetResource)
{
// Gelen nesne rnei Product tipine dntrlr ve _products isimli koleksiyondan
Remove metodu ile kartlr
_products.Remove((Product)targetResource);
}

// Update(gncelleme) ilemi srasnda devreye giren metoddur.


public object GetResource(IQueryable query, string fullTypeName)
{
object r = null;
var numarator = query.GetEnumerator();
while (numarator.MoveNext())
{
if (numarator.Current != null)
{
r = numarator.Current;
break;
}
}
return r;
}

// gelen nesnenin belirtilen zelliinin deerini geriye dndren metoddur


public object GetValue(object targetResource, string propertyName)
{
var targetType = targetResource.GetType();
PropertyInfo targetProperty = targetType.GetProperty(propertyName);
return targetProperty.GetValue(targetType, null);
}

// Gelen nesnenin ilgili zelliine gelen deeri atayan metoddur.


// Bu metod veri ekleme ve gncelletirme ilemleri srasnda ilgili nesne rneinin her bir
zellii iin alr
public void SetValue(object targetResource, string propertyName, object propertyValue)
{
Type targetType = targetResource.GetType();
PropertyInfo targetProperty = targetType.GetProperty(propertyName);
targetProperty.SetValue(targetResource, propertyValue, null);
}

public object ResolveResource(object resource)


{
return resource;
}

// Deiikliklerin kaydedilmesini salayan metoddur.


// Sz konusu rnekte veriler bellek zerinden tutulduundan uygulanmasna gerek yoktur.
public void SaveChanges()
{

www.bsenyurt.com Page 172


}

public void RemoveReferenceFromCollection(object targetResource, string propertyName,


object resourceToBeRemoved)
{
throw new NotImplementedException();
}

public object ResetResource(object resource)


{
throw new NotImplementedException();
}

public void SetReference(object targetResource, string propertyName, object


propertyValue)
{
throw new NotImplementedException();
}

public void AddReferenceToCollection(object targetResource, string propertyName, object


resourceToBeAdded)
{
throw new NotImplementedException();
}

public void ClearChanges()


{
throw new NotImplementedException();
}

#endregion
}
}

Woooww! Evet biraz korkutucu bir implemantasyon. Ama en


azndan Custom Membership Provider yazarkenki kadar korkutucu deil :) Aslnda tm
arayzn uyarlamasn gerekletirmi deiliz. Nitekim sz konusu rnekte kullanlan Product tipi
ierisinde herhangibir navigasyon zellii bulunmamaktadr. Dier taraftan sadece CUD ilemleri
iin gerekli temel metodlarn uygulandn ifade edebiliriz. Hereyden
nce CreateResource metoduna dikkat etmemiz gerekiyor. Notlarmzn banda belirtmi
olduumuz gibi Reflectiontekniklerinin burada iyi bir kullanmn gryoruz. Nitekim ilk olarak
parametre olarak gelen string ifadeden yararlanlarak bir nesne rnei oluturuluyor ki bu
noktada .Net Remotinggnlerinden hatrlayacamz mehur Activator snf kullanlmakta.
Yine GetValue ve SetValue metodlar ierisinde parametre olarak gelen bilgilerden yararlanlarak
bir zellik deerinin set edilmesi veya elde edilmesi ilemlerinde Reflection teknikleri kullanlyor.
Tabi bizim odaklanmak istediimiz nokta Ado.Net Data
Service ierisinde Custom LINQ Providerkullanlmas halinde CUD ilemlerinin nasl
gerekleecei. Buraya kadar yaptklarmz ile iin zor ksmn az da olsa atk. imdi
aadaki svc ieriine sahipAdo.Net Data Service esinide WCF projemize ekleyelim.

using System;
using System.Data.Services;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Web;
using ServerApp;

www.bsenyurt.com Page 173


public class ShopServices
: DataService<ShopEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}

CUD ilemeri gerekletireceimiz iin SetEntitySetAccessRule metodu ierisinde All sabit


deerini kullanyoruz. Artk istemci tarafn ve istemci iin gerekli test kodlarn yazabiliriz. Her
zamanki gibi basit bir Console uygulamas iimizi grecektir. Elbette
servisimizide Add Service Reference seenei ile istemci uygulamaya eklememiz gerekiyor.
stemci tarafnda yaplan servis ekleme ilemi sonrasnda aadaki snf diagramnda grlen tipler
oluacaktr.

Daha nceki ders notlarmzdan da hatrlayabileceimiz gibi, veri ekleme ilemleri


iin AddToProducts metodu oluturulmutur. Bunun
dnda DataServiceContext zerindenUpdateObject, DeleteObject metodlarnda kullanyor

www.bsenyurt.com Page 174


olacaz. Nitekim bu metodlar ile, silme ve gncelleme operasyonlar gerekletirilecektir. stemci
uygulamamzn kod ierii ise rnek olarak aadaki gibi gelitirilebilir.

stemci uygulama kodlar;

using System;
using System.Linq;
using System.Collections.Generic;
using ClientApp.ShopServiceReference;

// Not: Kod ierisinde Exception kontrolleri yaplmamtr


namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
ShopEntities proxy = new ShopEntities(new
Uri("http://buraksenyurt:1000/ServerApp/ShopServices.svc"));

// Yeni bir Product nesne rnei oluturulur


Product newProduct = new Product
{
ProductID = 6,
Name = "HP Mouse",
ListPrice = 12,
UnitsInStcok = 100
};

// Nesne rnei eklenir


proxy.AddToProducts(newProduct);

// Ekleme operasyonu servis tarafna gnderilir


proxy.SaveChanges();

// ProductID deeri 2 olan Product nesnesi istenir.


var prd = (from p in proxy.Products
where p.ProductID==2
select p).First<Product>();

// Baz zelliklerin deerleri sembolik olarak deitirilir


prd.ListPrice += 10;
prd.UnitsInStcok += 15;
// Nesne gncellemesi yaplr
proxy.UpdateObject(prd);

// Update operasyonu servis tarafna gnderilir


proxy.SaveChanges();

// Silme ilemine rnek olmas iin son eklenen Product istenir


var lastPrd = (from p in proxy.Products
where p.ProductID == newProduct.ProductID
select p).First<Product>();

// Nesne silinmesi yaplr


proxy.DeleteObject(lastPrd);

www.bsenyurt.com Page 175


// Delete operasyonu servis tarafna gnderilir
proxy.SaveChanges();
}
}
}

rnekte ilk olarak bir Product nesne rnei oluturulmakta ve sonra AddToProducts metodu ile
ilave edilmektedir. Tabiki bu ekleme ileminin servis tarafna gnderilmesi
iin, SaveChangesmetodunun arlmas gerekir. Gncelleme ilemi iin UpdateObject metodu
kullanlmaktadr. Silme ilemi iinse DeleteObject metodu. Elbette her iki
ileminde HTTP paketleri ierisine gmlerek servis tarafna gnderilmesi
iin SaveChanges metodu arlmaldr. stemci uygulama bu haliyle altrldnda herhangibir
sorun olmadan ilemlerin gerekletii grlr. (Ancak siz bu uygulamay test ederken
mutlaka Debug modda altrn ve kk bir tavsiye; WCF tarafndaki debug ilemleri iin hem
servis hemde istemci uygulamay debug modda altrmalsnz.)

Uygulama test edilirken eer SaveChanges metodlarnda breakpoint' ler ile ilerlenir ve arka
planda Fiddler gibi bir Http Debugging Proxy arac kullanlrsa uygulamann tamamnn almas
sonrasnda aadaki sonularn elde edildii grlr.

Fiddler arac basit bir HTTP Debugging Proxy uygulamasdr


ve IIS zerinde 80 numaral porta gelen ve giden tm HTTP paketlerini izleyebilmenizi,
ieriini grebilmenizi salar. Lakin Asp.Net Development Server ile kullanmnda baz
n ayarlar yaplmas gerekmektedir. Fiddler aracnn kullanm Ado.Net Data Services'
lerde BatchProcessing ilemlerinin ele alnd grsel dersimizde incelenmitir.

HTTP Paketlerinin Fiddler arac zerinden incelenmesi;

Bu durumu biraz analiz edelim. lk olarak yeni bir Product ekleniyor. Bu ekleme ilemi istemci
tarafnda yaplan SaveChanges metodu ars sonrasnda, servis tarafna bir HTTPpaketi olarak
gidiyor ki bu POST metoduna gre hazrlanm bir pakettir. Yine Fiddler yardmyla paketin
ieriinin aadaki gibi olduu grlebilir.

www.bsenyurt.com Page 176


Header ierii;

Paket ierii;

Sonrasnda ise bir HTTP Get talebi gelmektedir. Nitekim kod ierisinde gncelleme rnei
iin, ProductID deeri 2 olan rn bilgisi istenmitir. Bunun sonucu olarak tabiki istemci tarafna
da bir ierik gnderilmektedir. Yine Fiddler arac yardmyla bu ierie baklabilir.

www.bsenyurt.com Page 177


ProductId deeri 2 olan rnn istemci tarafna ekilmesinin ardndan bir gncelleme ilemi
gerekletirilir. Koda dikkat edecek olursak bu ilemler iin UpdateObject ve
ardndan SaveChanges metodlar arlmaktadr. SaveChanges metodu bu kez istemciden servis
tarafna HTTP Merge paketi gnderir ve bu paket ierisinde gncelletirilen yeni deerler yer alr.
Buna gre servise gelen Request paketinin Header ierii aadaki gibidir.

Paket ile gnderilen bilgiler ise yine Fiddler arac ile grlebilir.

www.bsenyurt.com Page 178


Son olarak silme operasyonunda nce silinmek istenen veri servis tarafndan talep edilmitir. Bu
noktada yine bir HTTP Get ars gerekleir. Bu ilemden sonra istemci
kodlarndaDeleteObject ve ardndan yine SaveChanges metodlar
arlmtr. SaveChanges ars sonrasnda ise bu kez bir HTTP Delete talebi istemciden servis
tarafna doru gnderilecektir.

Arka planda HTTP paketlerinde neler gittiini grdk. Burada Fiddler aracna ounuzun ak
olduunu hisseder gibiyim. Ayn SQL Server Profiler gibi son derece baarl bir izleme arac.

Gelelim kod tarafndaki metod ileyilerine. Sz gelimi veri ekleme ilemi srasnda istemci
tarafnda AddToProducts ve SaveChanges metodlarn kullanyoruz. Peki ya servis tarafnda
uyguladmz IUpdatable arayzne ait hangi metodlar devreye giriyor. Bu durumu analiz etmek
iin Debug modda biraz dolamam gerektiini ifade etmek isterim. Sonunda aadaki sonulara
ulaabildim. Tabi sz konusu sreler yukardaki gelitirdiimiz rnee gre ilemektedir.

Insert ilemine ait sre;

www.bsenyurt.com Page 179


stemci tarafnda ilk olarak AddTo[EntityName](rnein AddToProducts) metodu arlr.
Sonrasnda ise SaveChanges metodu yrtlr. SaveChanges metodu insertilemi iin
gerekli HTTP paketinin Post metoduna gre servis tarafna gnderilmesinde rol oynar. Bunun
karlnda servis tarafnda
srasyla CreateResource, SetValue,SaveChanges ve ResolveResource metodlar
arlr. CreateResource metodu ile HTTP paketinde gelen istekte yer alan tipin, alma
zamannda oluturulmas ve ilgili veri kaynana eklenmesi ilemleri
gerekletirilir. SetValue metodu ise oluturulan tipin her zellii iin alr. Bir baka deyile
zelliklerin deerlerinin verilmesinde devreye girer. rnekte veriler bellekteki koleksiyonlarda
tutulduu iin geri dn deeri olmayan ve parametre almayan SaveChanges metodu ierisinde
herhangibir ilem yaplmamtr.

Update ilemine ait sre;

www.bsenyurt.com Page 180


stemci tarafnda bu kez ncelikli olarak UpdateObject ve sonrasnda SaveChanges metodlar
arlr. Servis tarafnda ise ncelikli olarak gncellenecek verinin elde edilmesi
iin GetResource metodu devreye girer. Insert srecine benzer bir ekilde SetValue metodu
gncellenecek zellikler iin tek tek alr ve yine
srasyla SaveChanges,ResolveResource metodlar devreye girer.

Delete ilemine ait sre;

Silme ileminde istemci tarafnda srasyla DeleteObject ve SaveChanges metodlar alr.


Bunun karlnda Delete metodunu ieren bir HTTP paketi servis tarafna gnderilir. Servis

www.bsenyurt.com Page 181


tarafnda ise yine silinmek istenen verinin elde edilmesi iin GetResource metodu ilk olarak
devreye girer. Sonrasnda ise DeleteResource ile bu verinin kaynaktan kartlmas salanr.
rnekte bir koleksiyon kullanldndan bu basit bir Remove ileminden te deildir. Son olarak
yine SaveChanges ve ResolveResource metodlar arlr.

Grld zere kendi gelitirdiimiz Custom LINQ Provider' larn kullanld senaryolarda en
kritik nokta IUpdatable arayznn kullanlmasdr. Bu arayzn yazmzda kullanlan rnek
implemantasyonu ile basit CUD ilemleri gereketirilebilir. Bylece geldik Ado.Net Data Service'
ler ile ilikili bir ders notumuzun daha sonuna. Bir sonraki yazmzda grnceye dek hepinize
mutlu gnler dilerim.

rnei indirmek iin tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Ado.Net Data Services Ders Notlar - 4 (CUD


Operasyonlar) ( 16.10.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Ders notlarmz tutmaya devam ediyoruz. Bu gn Ado.Net Data Service' ler yardmyla
istemcilerden veri ekleme(Insert), silme(Delete) ve gncelleme(Update) ilemlerinin nasl
yaplabileceini incelemeye karar verdim. Tabiki Ado.Net Data Services konusu halen
daha Astoria kod adyla anlmakta. Dolaysyla zaman ierisinde uygulanan metod adlarnda ve
kullanl biimlerinde deiiklikler olmas muhtemel. Yine u an itibariyle neler yapabileceimize
bakmakta yarar var nitekim bir WCF fanatii olarak Ado.Net Data Services alm beni son
derece heyecanlandryor. Bu kadar laf salatasndan sonra ksaca konuya girmeye ve basit bir rnek
gelitirmeye ne dersiniz?

Ado.Net Data Service operasyonlarna yaplan istemci arlarnn HTTP bazl olduklarn
ve GET,POST,PUT,DELETE gibi metodlara gre uygulandklarn biliyoruz. stemci tarafndan
servis operasyonlarna doru eklenmek, silinmek veya gncellenmek amacyla gnderilen verilerin
ounluuda POST metoduna uygun olacak ekilde paketlenmektedir. Ancak elbetteki istemci
tarafnda bu paketin manuel olarak hazrlanmas gibi ilemler ile uramamza gerek yoktur.
Nitekim istemci tarafnda oluturulan servis rneine ait ye metodlar yardmyla bu paketlerin
otomatik olarak hazrlanmas, gnderilmesi salanabilmektedir. Her zamanki gibi adm adm
ilerleyeceimiz bir rnek konuyu pekitirmek asndan ok daha yararl olacaktr.

lk olarak veritaban zerindeki hazrlklarmz yapalm. rneimizde Azon isimli(Benim


seminerlerimi takip edenler bu isimdeki hayali irketi hatrlayacaktr :) ) bir veritabann ve bunun
zerinde yer alan Kategori ve Kitap isimli tablolar kullanyor olacaz. imdi hi vakit
kaybetmeden aadaki SQL Script' ini SQL Management Studio zerinde altrabilir ve rnek
veritaban, tablo ve test verilerinin eklenmesini salayabilirsiniz.

--Test veritaban oluturulur


Create Database Azon
GO

www.bsenyurt.com Page 182


--Test veritabann kullan
Use Azon
GO

-- Kategori tablosu oluturulur


Create Table Kategori
(
KategoriId int identity(1,1) not null,
Ad nvarchar(20) not null,
Constraint Pk_Kategori Primary Key(KategoriId)
)
GO

--Kategori tablosu iin test verileri girilir


Insert into Kategori (Ad) Values ('Programlama');
Insert into Kategori (Ad) Values ('SOA zmleri');
Insert into Kategori (Ad) Values ('Web Programlama');

--Kitap tablosu oluturulur


Create Table Kitap
(
KitapId int Identity(1,1) not null,
Ad nvarchar(50) not null,
Fiyat money not null,
StokMiktari int not null,
KategoriId int not null,
Constraint Pk_Kitap Primary Key(KitapId)
)
GO

--Kitap tablosu iin test verileri eklenir


Insert into Kitap (Ad,Fiyat,StokMiktari,KategoriId) Values ('Her Ynyle C#',50,100,1);
Insert into Kitap (Ad,Fiyat,StokMiktari,KategoriId) Values ('Essential C# 3.0',80,25,1);
Insert into Kitap (Ad,Fiyat,StokMiktari,KategoriId) Values ('Programming WCF',75,120,2);
Insert into Kitap (Ad,Fiyat,StokMiktari,KategoriId) Values ('SOA For Dummies',35,45,2);
Insert into Kitap (Ad,Fiyat,StokMiktari,KategoriId) Values ('Asp.Net 3.5 Step By Step',70,80,3);

--Relation Oluturulur
ALTER TABLE Kitap WITH CHECK ADD CONSTRAINT FK_Kitap_Kategori FOREIGN KEY(KategoriId)
REFERENCES Kategori (KategoriId)
GO

ALTER TABLE Kitap CHECK CONSTRAINT FK_Kitap_Kategori


GO

Kategori ve Kitap tablolar yine bir birlerine bal kmeler olarak tasarlanmtr. Bylece
bir Kategori ve buna bal Kitap satrlarnn Entity rnekleri zerinden eklenmesinin analizi iin
gerekli ortam hazrlanm olur. Her iki tablo arasndaki ilikinin veritaban zerinde tanmlanm
olmasda son derece nemlidir. Nitekim bu tanmla yaplmad takdirde EDM(Entity Data
Model) ierisinde oluturulan Entity tipleri arasndada bir Association en azndan otomatik olarak
olumayacaktr. Sradaki aamada servisimiz iin gerekli host uygulamann yazlmas
gerekmektedir. Ado.Net Data Service' leri bu ana kadarki ders notlarmzda srekli
olarak WCF Service ablonlar zerinde tuttuk. imdilik gelenei bozmuyoruz. Yine ilerimizi
kolaylatrmas asndan EDM katmann kullanyor olacaz. Daha nceki ders notlarmzda ve
grsel derslerimizde bu konuya deindiimiz iin tekrar etmeyeceiz ancak oluan EDM modelinin
aadakine benzer olmas gerektiinide hemen vurgulayalm.(Bu aamay tamamlarken nceki

www.bsenyurt.com Page 183


ders notlar veya grsel derslere bakmadan ilerlemeye almanz sizin yararnza olacaktr.
Bildiiniz gibi pratik mkemmelletirir.)

KitapServisi olarak isimlendirdiimiz svc dosyasna ait kod ierii ise aadaki gibi olmaldr.

using System;
using System.Linq;
using System.Data.Services;
using System.ServiceModel.Web;
using System.Collections.Generic;
using AzonModel;

public class KitapServisi


: DataService<AzonEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}

Tahmin edilecei zere AzonEntites isimli tayc tip ierisindeki tm Entity tipleri tm haklar ile
istemcilere almaktadr. Burada varsaylan olarak bulunan AllRead deerini kullanamayz. Nitekim
verilerin eklenmesi, gncellenmesi ve silinmesi operasyonlar iin izin verilmesi gerekir. Burada
kolaya kaarak All enum sabiti deerini kullandk. Bu adma kadar geldikten sonra yapmamz
gereken ilk i servisin alp almadn test etmek olmaldr. Bu amala servisin herhangibir
taraycda almas yeterlidir. Eer bir sorun yoksa aadaki ekran grntsne benzer bir ktnn
elde edilmesi gerekir.

www.bsenyurt.com Page 184


Sradaki admmzda istemci uygulamann oluturulmas ve servis referansnn eklenmesi yer
almaktadr. Yine ok sevineceiniz ve yazarken byk keyif alacanz birConsole Application :)
gelitiriyor olacaz. Console uygulamamza ayn solution ierisinde oluturduumuz Ado.Net
Data Service rneini ise Add Service Reference seenei ile ekleyeceiz. Aynen aadaki
ekran grntsnde olduu gibi.

Bu ilemin ardndan solution ieriinin aadakine benzer olmasn bekleyebiliriz.

www.bsenyurt.com Page 185


Artk birazda kod yazalm. lk kod rneinde toplu bir insert ileminide gerekletiriyor olacaz.
lk nce bir Kategori rneini oluturup istemci tarafndaki Entity nesnesine ilave edecek ve bu
deiiklii veritabanna doru gndereceiz. Sonrasnda ise bu Kategori altnda
olacak Kitap nesnelerini rneklerinin deerlerini veri tabanna gndereceiz. te kodlarmz;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ClientApp.AzonSpace;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
// Proxy nesnesi rneklenir
AzonEntities proxy = new AzonEntities(new
Uri("http://localhost:1630/HostApp/KitapServisi.svc"));

// Yeni bir kategori nesnesi rneklenir


Kategori windowsClient = new Kategori { Ad = "Windows Programlama" };

// Oluturulan Kategori nesne rnei bellek zerindeki Entity rneine ilave edilir
proxy.AddToKategori(windowsClient);
// Yeni kategorinin veritabanndaki tabloya eklenmesi iin SaveChanges metodu arlr.
// (Bu noktada SaveChanges arlmas art deildir. Bu sadece KategoriId' nin tablodan
elde edilmesini salamada rol oynamaktadr)
proxy.SaveChanges();
Console.WriteLine("{0} ID si ile {1} Kategorisi
eklendi",windowsClient.KategoriId.ToString(),windowsClient.Ad);

// Generic bir List koleksiyonunda tutulacak ekilde Kitap nesne rnekleri oluturulur.
List<Kitap> kitaplar = new List<Kitap>()

www.bsenyurt.com Page 186


{
new Kitap { Ad = "Windows Form 2.0 Programming", Fiyat = 90, StokMiktari = 10 },
new Kitap { Ad = "Pro WPF", Fiyat = 75, StokMiktari = 12 },
new Kitap { Ad = "Core Windows Programming", Fiyat = 90, StokMiktari = 16 }
};

// Tm kitaplar dolalr
foreach (Kitap k in kitaplar)
{
// Her bir Kitap nesne rnei ilgili Entity rneine ilave edilir.
proxy.AddToKitap(k);
// O andaki kitap ile yukarda oluturulan Kategori arasndaki iliki kurulur
proxy.AddLink(windowsClient, "Kitap", k);
}

// Deiiklikler veritabanna gnderilir


// Batch enum sabit deeri ile tm isteklerin tek bir HTTP paketinde gnderilmesi salanr
proxy.SaveChanges(System.Data.Services.Client.SaveChangesOptions.Batch);

// Eklenen kategori servis tarafndan talep edilir


var eklenenKategori = (from k in proxy.Kategori
where k.KategoriId == windowsClient.KategoriId
select k).First();
// Elde edilen kategoriye ait kitap bilgilerinin yklenmesi istenir
proxy.LoadProperty(eklenenKategori, "Kitap");

Console.WriteLine("\n{0} kategorisine eklenen kitaplar\n",eklenenKategori.Ad);


// Eklenen kategoriye bal kitaplar listelenir
foreach (Kitap k in eklenenKategori.Kitap)
{
Console.WriteLine("{0} {1} {2}
{3}",k.KitapId.ToString(),k.Ad,k.StokMiktari.ToString(),k.Fiyat.ToString("C2"));
}
}
}
}

Kodlarda zellikle zerinde durmamz gereken nokta bir Entity nesne rneinin oluturulmas
sonrasnda kullanlan AddTo[EntityAd], AddLink ve SaveChanges isimli
metodlardr.AddTo[EntityAd] metodlar, servis referansnn eklenmesi srasnda istemci tarafnda
oluturulan Entity tiplerinin her birisi iin service tipine eklenir. Sz
gelimi Kitap iinAddToKitap, Kategori iinse AddToKategori. Bunu snf diagramndanda
grebiliriz.

www.bsenyurt.com Page 187


AddTo[EntityAd] metodlar parametre olarak aldklar Entity nesne rneklerini tayc servis
tipinin takip etmesinde rol oynarlar. Aslnda kendi ilerinde AdoToObject metodunu
armaktadrlar. Bu izleme ilemi aslnda SaveChanges metodu iin nem arz etmektedir.
Nitekim eklenen, silinen veya gncellenen nesne deerlerinin veritabanna doru yanstlmas
ilemini gerekletirmektedir. Bu noktada durup kodu debug ederek ilerlemenizi neririm.
zellikle SaveChanges metodu arlmadan nce proxy nesne rnei
ierisinde Kategori veya Kitap zellikleri ierii ile SaveChanges ars sonras ieriklere
bakldnda durum daha net bir ekilde grlebilir. Sz gelimi ben testleri yaparken aadaki
sonular elde ettim.

SaveChanges ars ncesi;

www.bsenyurt.com Page 188


SaveChanges ars sonras;

www.bsenyurt.com Page 189


SaveChanges metodunun arlmas srasnda
birde System.Data.Services.Client.SaveChangesOptions.Batch enum sabiti deeri
kullanlmtr. Bu deer ile birden fazlaHTTP paketinin yerine tm istein tek bir HTTP paketi
ierisinde gnderilmesi salanabilmektedir bu servis ile istemci arasndaki trafik aknn
younluunu azaltc bir etkendir.(Bu konu ile ilikili olarak(Batching) bir grsel ders hazrlyor
olacam.)

Tabi SaveChanges ars srasnda sunucu tarafndaki veri kayna zerindede bir
takm SQL sorgu ifadeleri alacaktr. Burada SQL Server Profiler aracnn kullanmanz iddetle
tavsiye ederim. rnein veri ekleme testleri srasnda benim yakaladm rnek sql ifadeleri
aadaki gibi olumutur.

-- Kategori iin Insert ars


exec sp_executesql N'insert [dbo].[Kategori]([Ad])
values (@0)
select [KategoriId]
from [dbo].[Kategori]
where @@ROWCOUNT > 0 and [KategoriId] = scope_identity()',N'@0
nvarchar(19)',@0=N'Windows Programlama'

-- lk Kitap iin Insert ars


exec sp_executesql N'insert [dbo].[Kitap]([Ad], [Fiyat], [StokMiktari], [KategoriId])
values (@0, @1, @2, @3)

www.bsenyurt.com Page 190


select [KitapId]
from [dbo].[Kitap]
where @@ROWCOUNT > 0 and [KitapId] = scope_identity()',N'@0 nvarchar(28),@1
decimal(19,4),@2 int,@3 int',@0=N'Windows Form 2.0
Programming',@1=90.0000,@2=10,@3=27

-- kinci kitap iin Insert ars


exec sp_executesql N'insert [dbo].[Kitap]([Ad], [Fiyat], [StokMiktari], [KategoriId])
values (@0, @1, @2, @3)
select [KitapId]
from [dbo].[Kitap]
where @@ROWCOUNT > 0 and [KitapId] = scope_identity()',N'@0 nvarchar(7),@1
decimal(19,4),@2 int,@3 int',@0=N'Pro WPF',@1=75.0000,@2=12,@3=27

-- nc kitap iin Insert ars


exec sp_executesql N'insert [dbo].[Kitap]([Ad], [Fiyat], [StokMiktari], [KategoriId])
values (@0, @1, @2, @3)
select [KitapId]
from [dbo].[Kitap]
where @@ROWCOUNT > 0 and [KitapId] = scope_identity()',N'@0 nvarchar(24),@1
decimal(19,4),@2 int,@3 int',@0=N'Core Windows Programming',@1=90.0000,@2=16,@3=27

lk kodda dikkat ekici noktalardan biriside Kategori nesne rnei eklendikten sonra Kitap nesne
rneklerinden oluan bir koleksiyonun nasl ilave edildiidir. Burada dng ierisinde
arlan AddToKitap metodu haricinde AddLink isimli bir fonksiyon yer almaktadr. Bu metod, o
anki Kitap nesne rneinin hangi Kategori' ye bal olacann belirlenmesinde rol oynamaktadr.
Bu sebepten dolayda kodun SQL tarafndaki retiminde 3 Kitap iin
altrlan Insert sorgularnda KategoriID deerleri otomatik olarak set
edilmitir. AddLinkmetodu arlmad takdirde bu ilikinin salanmas mmkn olmamaktadr.
lk rnek kodumuzu tamamlam bulunuyor. te testler srasnda oluan rnek bir ekran kts.

Srada gncelletirme ilemleri var. Bu amala aadaki rnek kod satrlarn gz nne alabiliriz;

// Gncellenecek veri kmesi ekilir.


// rnein KategoriId deeri 1 olan Kitaplar ekilir
var tumKitaplar = from k in proxy.Kitap
where k.Kategori.KategoriId==1
select k;

// Elde edilen sonu kmesindeki her bir Kitap nesne rnei zerinde basit bir gncelletirme yaplr
foreach (Kitap k in tumKitaplar)
{
Console.WriteLine("Gncelletirme ncesi {0} iin Fiyat {1}",k.Ad,k.Fiyat.ToString("C2"));
k.Fiyat += 10;
// Yaplan gncellemeler entity zerinde onaylanr
proxy.UpdateObject(k);

www.bsenyurt.com Page 191


}
// Deiiklikler veritabanna gnderilir
proxy.SaveChanges();

// Sonular test etmek iin servis tarafndan 1 numaral kategoriye bal kitaplar tekrar istenir
Console.WriteLine("\nDeiiklikler Sonras Liste\n");
var kategori1Kitaplari = from k in proxy.Kitap
where k.Kategori.KategoriId == 1
select k;
// Her bir kitabn bilgisi ekrana yazdrlr
foreach (Kitap k in tumKitaplar)
{
Console.WriteLine("Gncelletirme ncesi {0} iin Fiyat {1}", k.Ad, k.Fiyat.ToString("C2"));
}

Bu kod parasnda rnek olarak KategoriId deeri 1 olan Kategoriye bal Kitap nesnelerinin
fiyatlarnn 10 birim arttrlmas salanmaktadr. Bizim iin bu kod parasnda dikkat edilmesi
gereken fonksiyonellikler UpdateObject ve
yine SaveChanges metodlardr. SaveChanges metodu SQL tarafnda aadaki sorgu ifadelerinin
olumasna neden olur.

-- ki Update yakalanr. Nitekim 1 numaral kategoride sadece iki Kitap vardr.


exec sp_executesql N'update [dbo].[Kitap]
set [Ad] = @0, [Fiyat] = @1, [StokMiktari] = @2
where ([KitapId] = @3)
',N'@0 nvarchar(14),@1 decimal(19,4),@2 int,@3 int',@0=N'Her Ynyle
C#',@1=90.0000,@2=100,@3=1

exec sp_executesql N'update [dbo].[Kitap]


set [Ad] = @0, [Fiyat] = @1, [StokMiktari] = @2
where ([KitapId] = @3)
',N'@0 nvarchar(16),@1 decimal(19,4),@2 int,@3 int',@0=N'Essential C#
3.0',@1=120.0000,@2=25,@3=2

Burada iki adet Update sorgusunun oluturulmas son derece doaldr.


Nitekim 1 numaral Kategori' ye bal sadece iki adet Kitap bulunmaktadr. Kodun altrlmas
sonrasnda ise programn ekran grnts aadakine benzer olacaktr.

Burada hemen bir test yapmanz neririm.


lk Console.WriteLine arsn UpdateObject metodunun sonrasna koyduunuz
takdirde Kitap nesne rneklerinin deerlerinin annda gncellenip gncellenmediini(Entity
tarafnda) analiz edebilirsiniz.

Son olarak basit bir silme operasyonu ilemini ele alyor olacaz. Bu son kod parasndaki
amacmz bir Kategori ve buna bal Kitap verilerinin silinmesini salamak. te rnek kod
paramz;

www.bsenyurt.com Page 192


// nce kullancya Kategori listesi sunulur
Console.WriteLine("\nSilme Operasyonu\n");
var kategoriler = from k in proxy.Kategori
select k;
foreach (Kategori kategori in kategoriler)
{
Console.WriteLine("{0} {1}",kategori.KategoriId.ToString(),kategori.Ad);
}
// Kullancdan silmek istedii kategorinin KategoriId deeri istenir
Console.WriteLine("Silmek istediini kategori id' yi sein");
int secilenKategoriId;

// Eer ekrandan alnan deer Int32' ye Parse edilebilirse


if (Int32.TryParse(Console.ReadLine(),out secilenKategoriId))
{
Kategori secilenKategori = null;
try
{
// Ekrandan girilen ID deerine ait Kategori nesne rnei talep edilir
secilenKategori = (from k in proxy.Kategori
where k.KategoriId == secilenKategoriId
select k).First<Kategori>();

// nce bu Kategorinin KategoriId deerine sahip Kitap listesi alnr


var kitapListesi = from k in proxy.Kitap
where k.Kategori.KategoriId == secilenKategoriId
select k;
// Elde edilen her bir Kitap nesne rnei DeleteObject metodu ile kartlr
foreach (Kitap kitap in kitapListesi)
{
proxy.DeleteObject(kitap);
Console.WriteLine("{0} kartlacak",kitap.Ad);
}

// Son olarak seilmi olan Kategori nesnesi kartlr


proxy.DeleteObject(secilenKategori);
Console.WriteLine("{0} kategorisi kartlacak", secilenKategori.Ad);

// Deiikliklerin veri kayna zerinde de yaplmas iin SaveChanges metodu arlr.


proxy.SaveChanges(System.Data.Services.Client.SaveChangesOptions.Batch);
Console.WriteLine("Deiiklikler gnderildi...");
}
catch
{
}
}

Kodda ncelikli olarak kullancya var olan Kategori listesi gsterilir ve silmek
istedii Kategoriye ait KategoriId deerini girmesi istenir. Bunun sonrasnda sz
konusu Kategori ve buna bal Kitaplar bulunur. nce Kitap nesne rnekleri tek
tek DeleteObject metodu ile kartlmak zere iaretlenir. Sonrasnda ise ayn ilem
seilen Kategori iin yaplr. Son olarak tm ilemlerin SaveChanges metodu ile veritabanna
gnderilmesi salanr. Bu noktada SQL tarafnda oluturulan sorgu ifadeleri aadakilere benzer
olacaktr. (Bu ifadelerin yakalanmas iin SQL Server Profiler aracn kullandmz hatrlayalm)

-- 43 nolu KategoriId deerine sahip Kitap verileri silinir

www.bsenyurt.com Page 193


exec sp_executesql N'delete [dbo].[Kitap]
where (([KitapId] = @0) and ([KategoriId] = @1))',N'@0 int,@1 int',@0=75,@1=43

exec sp_executesql N'delete [dbo].[Kitap]


where (([KitapId] = @0) and ([KategoriId] = @1))',N'@0 int,@1 int',@0=76,@1=43

exec sp_executesql N'delete [dbo].[Kitap]


where (([KitapId] = @0) and ([KategoriId] = @1))',N'@0 int,@1 int',@0=77,@1=43

-- 43 nolu KategoriId deerine sahip Kategori silinir


exec sp_executesql N'delete [dbo].[Kategori]
where ([KategoriId] = @0)',N'@0 int',@0=43

Sonu olarak rnek ekran kts aadaki gibi olacaktr.

Burada hemen bir noktay vurgulayalm. Normal artlar altnda ayn silme operasyonunu veritaban
zerinde gerekletirmek istesek, nce Kitap verilerini sonra ise Kategori verilerini silmemiz
gerekirdi. Bildiinin gibi bunun nedeni Kategori ve Kitap tablolar arasnda tanml olan Foreign
Key bamll ve bunun sonucu olan Constraint tir.Ayn mantk kod tarafnda art deildir. Bir
baka deyile nce Kategori iin DeleteObject sonrasnda ise Kitap topluluu
iin DeleteObject metodu arlabilir. Nitekim organizasyon ve doruSQL altrma
sras SaveChanges metodu sonrasnda olumaktadr. Bunu kod zerinde deneyerek test etmenizi
neririm.

Buraya kadar yaptklarmz ksaca zetlersek eer veri ekleme, gncelleme ve silme ilemleri
srasnda SaveChanges metodunun asl ii yklendiini ve veri kaynanda sorgu ifadelerinin
oluturulmas iin gerekli HTTP paketlerini hazrladn dnebiliriz. stemci tarafnda nesne
rnei eklemek iin AddTo[EntityAd] yada AddToObjectmetodlarn kullanabileceimizi
grdk(Sonuta AddTo[EntityAd] kendi iinde AddToObject metodunu armakta). Ayrca silme
ilemlerinde DeleteObject ve gncelletirme ilemlerinde ise UpdateObject fonksiyonlarn ele
aldk. Dier taraftan ilikisel nesnelerin balanmas iinse AddLink fonksiyonelliinin ele alnmas
gerektiini rendik. Nihayetinde bir ders notumuzun sonunda daha geldik. Ancak akllarda(en
azndan benim aklmda ve biraz sonra sizin aklnzda) yle bir soru oluabilir. Eer servis
tarafnda zel bir LINQ Provider ve buna bal tipler kullanlyorsa Insert,Update ve
Delete ilemleri nasl gerekletirilebilir? Nitekim EDM modelinde veri
kaynanda SQL olduundan bu ilemler iin SQL sorgu ifadeleri kullanlmaktadr. te bu analizi

www.bsenyurt.com Page 194


bir sonraki ders notlarmzda inceliyor olacaz. Bylece geldik bir makalemizin daha sonuna.
Makalemizde yer alanCRUD ilemlerini u ve bu grsel derslerden de inceleyebilirsiniz. Tekrardan
grnceye dek hepinize mutlu gnler dilerim.

rnei indirmek iin tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Ado.Net Data Services Ders Notlar - 3 (stemci


Gelitirmek) ( 06.10.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Hatrlayacanz gibi daha nceki iki ders notumuzda Ado.Net Data Service rneklerinin nasl
gelitirilebileceini incelemeye almtk. Hatrlatmak gerekirse, Ado.Net Data Service' ler ile
verilerin Entity Data Model(EDM) veya Custom LINQ Provider bazl katmanlar
zerinden REST modeline gre sunulmas mmkn olmaktadr. Bu noktada sz konusu
servislerin WCF' in REST modelini kullanan ve Ado.Net zerine odaklanm bir alm olduu
grnde hem fikir olabiliriz. Ne varki Servis Ynelimli Mimari(Service Oriented
Architecture-SOA) temelli zmlerde yap-bozun en nemli iki parasn servis ve istemciler
oluturmaktadr. Bir baka deyile, servislerin tamamlaycs olan ve ilgili hizmetleri
kullanacak istemci uygulamalar(Client Applications) olmaldr. te bu yazmzda istemci
uygulamalar gz nne alacaz.

Ado.Net Data Service ve istemci arasnda geen bu hikayede, anahtar neme sahip bir ka
kelimede yer almaktadr. WCF, Ado.Net, REST vb. Bunlar az ok istemcilerin kimler
olabileceinide ortaya kartan terimlerdir. Aslnda bir servis istemcisinin herhangibir uygulama
olabilmesi istenir. Platform kriterleri gzetilmeksizin. Fakat gemi zamanlarda sadece belirli
platformlara ynelik zmler de ele alnmam deildir ki halen daha popler olarak pek ok alt
yapda kullanlmaktadr. Buna verilebilecek en gzel rnek belkide .Net Remoting zmleridir.
.Net Remoting temelli uygulamalar sadece .Net tabanl istemci ve sunucular baz almaktadr. Bu
bir kstlamadr ama performans ve verimlilik gibi avantajlarda getirmektedir. Ancak zaman
ilerledike farkl tipte platformlarn ortaklaa haberleebilmesi daha byk nem arz etmeye
balamtr. Buda Xml Web Service' lerin popler olmasnn nedenlerinden birisidir :) Ama uzun
zamandr elimizde ok daha gl bir kozun olduunu da belirtmek
isterim; Windows Communication Foundation.

Tekrardan sihirli kelimelerimize dnelim. WCF kelimesi, gelitireceimiz servisin WCF kurallarnn
bir sonucu olarak ortaya ktnn ak bir gstergesidir. Buda kendi ierisinde WCF' in nimetlerini
barndracak bir servis zmn ifade eder ki buna JSON(JavaScript Object
Notation), Syndication, Web Programming Model gibi pek ok nemli kriterde dahil olur.
Dolaysyla WCF servislerini ele alabilen tm istemci eitleri bu senaryoda olasdr.
Ancak Ado.Net kelimesi, servisimizi belirli bir yne doru odaklamaktadr. Buna gre gelitirilen
servis tamamen verilerin(Data) sunumu zerine konulandrlmaktadr. Bu zorunluluk olmamakla
birlikte btnl salayc bir hedef olarak grlmelidir. Buda istemci tipini belirleyici dier bir
etkendir. Ancak REST(REpresentationalStateTransfer) kelimesi olay biraz daha
belirginletirmektedir. Sz konusu istemciler REST modeline gre talepte bulunabilmelidir.
Yani HTTP protokol zerinde GET,HEAD,POST,DELETE gibi metodlara gre talepte bulunabilmeli
ve gelen sonularda irdeleyebilmelidirler.

www.bsenyurt.com Page 195


Doruyu sylemek gerekirse bu kelimeleri bir kenara brakp herhangi eit istemci uygulama ele
alnabilir diyerekten iin ierisinden de syrlabiliriz :) Yinede gncel teknolojiler gz nne
alndnda aadaki maddelerde yer alan istemci tiplerinin dikkat ekecei ortadadr.

Ajax Tabanl Web Sayfalar (Ajax Based Web Pages)


Silverlight Nesneleri
WPF(Windows Presentation Foundation), WinForms gibi Windows Uygulamalar
Dier Servisler (WCF Servisleri, Xml Web Servisleri, .Net Remoting Uygulamalar, Windows
Servisleri vb...)
Snf Ktphaneleri-Class Libraries

Bu tipler oaltlabilir. Ancak benimde dikkatimi eken ve zellikle zerinde durulmaya deer
eitler Ajax tabanl web sayfalar ve Silverlight nesneleridir ki bunlar u zaman itibariyle son
derece popler uygulamalardr. Yanlz dikkat edilmesi gereken baka noktalarda vardr. Sz gelimi
bir Ado.Net Data Service rnei farkl servisler tarafndanda tketilebilir. Byle bir durumda
tketici servisin kendisi, aslnda tkettii servis iin bir istemci olmaktadr. Yine extreme senaryolar
gz nne alnabilir. Sz gelimi ActiveDirectory hizmetini zel bir LINQ Provider ile gvenli bir
ekilde farkl bir lokasyona bir Ado.Net Data Service olarak sunabiliriz. rnein dnya zerindeki
bir otele ait tm nesnel verilerin Active Directory kkenli olaraktan tek bir merkezde tutulduunu
dnn. Dier lokasyonlardaki oteller bu merkezi verileri kullanmak isteyecektir. Bu noktada
tketici istemciler bir servis olup sz konusu hizmeti kapal a ierisinde(Intranet diyebiliriz) ele
alabilir ve dier istemcilere sunabilir. Ki bu kapal a istemcileride sz konusu lokasyondaki otelin
ierisinde yer alan eitli tipteki uygulamalardr. Bu tabiki gerek bir vaka deil ancak sizlerde bu
cmlede bir ka dakikalna durup eitli Ado.Net Data Service senaryolar dnebilir ve bunlar
yakn evrenizdeki yetkin kiiler ile tartarak analiz edebilirsiniz.

stemci hangi eitten olursa olsun servis ile olan iletiimini kod seviyesinde kolaylatrmak
asndan genellikle Proxy nesneleri gz nne alnr. Bu bir zorunluluk deildir.
Nitekim REST modeline gre servise gidecek olan HTTP paketlerinin manuel olarak hazrlanp
gnderilmeside mmkndr. yleki bu ilem
iin HttpWebRequest yadaHttpWebResponse tipleri kolayca gz nne alnabilir. Bir anlamda
rnein, XML Web Servislerinde bir SOAP(Simple Object Access Protocol) paketinin
bahsettiimiz tipler ile hazrlanp gnderilmesinden ve geri gelen cevabn alarak ele alnmasndan
farkl bir ilem deildir. Ne varki Proxy kullanm kodlamacnn iini olduka kolaylatrr. nk bu
sayede gelitirici bildik kodlar yazarken sanki kendi ortamndaki bir nesneyi kullanyormu hissine
kaplr. Gelip giden paket ierikleri ile uramak zorunda kalmaz. Halbuki sz konusu servis
talepleri, proxy tarafndan servisin anlayaca paketler haline getirilerek gnderilir. Benzer ekilde
servisten gelen paketlerde proxy tarafndan alarak istemcidekialma
zaman(RunTime) nesnelerine devredilir. Bu konuda aadaki ekil biraz daha aydnlatc bilgi
verebilir.

www.bsenyurt.com Page 196


Tabi burada proxy tiplerinin gelitirme zamannda eklenmesi gibi bir zorunluluk yoktur. Baz
uygulama eitlerinde rnein Ajax temelli web sayfalarnda sz konusu proxy tiplerine ait nesne
rnekleri alma zamannda transparant olarak oluturulup kullanlabilirler. Ajax tabanl bir web
istemcisi zerinden bir Ado.Net Data Service' in kullanm okda kolay deildir. in zellikle benim
amdan keyifsizletii nokta istemci taraf iin javascript kodlar dktrlmesi gerekliliidir. Ajax
tabanl bir web formunda bir Ado.Net Data Service' inin nasl kullanlabileceini ilgili grsel
dersten takip edebilirsiniz.

Peki biz bu yazmzda neler yapacaz? Aslnda yukardaki listede yer almayan bir istemci uygulama
gelitiriyor olacaz :) Tahmin edeceiniz zere bir Console uygulamas. Sonuta amacmz bir
istemci uygulamada basit REST taleplerinde bulunabilmek. Bunun iinde grsel detaylarn fazla
olmad ve odan tamamen koda kayd bir ortam kullanmamz renmemiz asndan nemli
olacaktr. te Console uygulamas sememizin(yada sememin) nedenide budur? Her zaman
olduu gibi basit bir Ado.Net Data Service' i gelitireceiz. Senaryomuzda
yine AdventureWorks veritabann ve buradaki ProductSubCategory, Product tablolarn ele
alacaz. Bu tablolar arasndaki bire ok iliki istemci tarafnda ilikisel veri ekme ilemlerini analiz
etmemizi salayacaktr. Ado.Net Data Service' in nasl gelitirileceini daha nceki notlarmzda ve
grsel derslerimizde yeterince ele almtk. Bu nedenle sadece EDM(Entity Data
Model) grafiinin, AdventureWorksServices.svc.cs kodlarnn ve Solution ieriininin
aadakilere benzer olmasna zen gstermeniz yeterli olacaktr.(Servis uygulamasnn bir WCF
Service ablonu olduunu hatrlatalm.)

EDM Grafii;

www.bsenyurt.com Page 197


Solution erii;

AdventureWorksServices.svc.cs ierii;

www.bsenyurt.com Page 198


using System;
using System.Data.Services;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Web;
using AdventureWorksModel;

public class AdventureWorksServices


: DataService<AdventureWorksEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.All);
}
}

Sonrasnda ise istemci Console uygulamas iin gerekli proxy tiplerini reteceiz. Proxy retimi
iin iki farkl seeneimiz bulunmaktadr. Bunlardan birisi WCF Servislerindende aina
oluumuz Add Service Reference seeneidir. Bu seenei kullandmzda karmza gelen
dialog penceresinde Ado.Net Data Service adresinin yazlmas yeterli olacaktr. Elbette gelitirilen
rnek gerei Discover mensnden Services in Solution seenei ele alnabilir. Nitekim servis
ve istemci uygulamalarmz ayn solution ierisinde yer almaktadr.

Bu noktada normal bir WCF Service referans eklerken karmza kan seeneklerden tamamnn
aktif olmad hemen gze arpmaktadr. yleki bir WCF servisi bu teknik ile eklenirken aktif
olan Advanced dmesi Ado.Net Data Service eklenirken aktif deildir. Buda olay bazl asenkron
ayarlamalar, eriim belirleyicileri(Internal veya Public) gibi baz seeneklerin kullanlamad

www.bsenyurt.com Page 199


anlamna gelmektedir. Ekleme ilemi sonrasnda istemci uygulama tarafnda servis ile ilikili proxy
referanslarnn oluturulduu ak bir ekilde grlebilir.

Yine burada edmx uzantl tip dikkati ekmektedir. Bu akas bir XML ieriidir ve istemci tarafna
indirilmi olan seriletirilebilir tipler ile ilgili eletirmeleri zerinde tamaktadr. Yine dikkat ekici
noktalardan birisi istemci taraf iin bir config dosyas oluturulmam olmasdr. Nitekim bu
modelde EndPoint kullanm sz konusu deildir. Zaten talepler basit HTTP metodlar olacak
ekilde servise ulatrlmaktadr ki bu aamada retilen tayc(Container) snf devreye
girmektedir(AdventureWorksEntities). Oluturulan tiplere bakldnda ise aadaki snf
diagramnda yer alan almlarn olutuu grlr. Dikkat edilecei zere servis tarafndan sunulan
entity tipleri istemci tarafndada oluturulmutur. Asl yklenici tip
ise AdventureWorksEntities isimli DataServiceContext trevli snftr. Bu snf
sayesinde CRUD operasyonlarnn tamam kolay bir ekilde istemci tarafnda ele alnabilir.

www.bsenyurt.com Page 200


Dier Proxy retme teknii ise SvcUtil aracnn Ado.Net Data Service' ler iin gelitirilmi olan
versiyonu DataSvcUtil komut satr programdr. Komut satrndan proxyretimi
iin Visual Studio 2008 Command Prompt zerinden DataSvcUtil aracnn aadaki resimde
olduu gibi kullanlmas yeterli olacaktr. kt AdventureProxy.cs isimli dosya ierisine
yaplmaktadr. Uri parametresinden sonra ise Proxy retimi iin kaynak olan Ado.Net Data Service
adresi verilmitir.

Elbette elimizde Visual Studio 2008 gibi bir IDE olmad durumlarda proxy retimi
iin DataSvcUtil aracn kullanmak gerekmektedir. Aksi durumda
ise Add Service Referenceseenei ok daha mantkldr. Sonu olarak ben
rneimizde Add Service Reference seeneini ele aldm.

Artk ve nihayet istemci tarafndaki kodlarmz gelitirmeye balayabiliriz. ncelikli olarak kk


bebek admlar ile balamakta yarar vardr. rnein tmProductSubCategory listesini elde etmek
istediimizi dnelim. Bu durumda kodlarmz aadaki gibi gelitirmemiz yeterli olacaktr.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Data.Services.Client;
using ClientApp.AdventureSpace;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
// ncelikli olarak Proxy nesnesi rneklenir.
// Parametre olarak Ado.Net Data Service' in URL bilgisi kullanlr.
AdventureWorksEntities proxy = new AdventureWorksEntities(new
Uri("http://localhost:1740/AdventureServices/AdventureWorksServices.svc"));

// CreateQuery metodu parametre olarak Entity adn almaktadr.


// Metodun dndrd sonu kmesi DataServiceQuery tipi ile ele alnabilir.
// stenirse var anahtar kelimeside gz nne alnabilir. Her iki durumdada for dngs
alacaktr.
DataServiceQuery<ProductSubcategory>
subCategories=proxy.CreateQuery<ProductSubcategory>("ProductSubcategory");
// var subCategories = proxy.CreateQuery<ProductSubcategory>("ProductSubcategory");

// Elde edilen sonu kmesinin her bir eleman ProductSubcategory snf tipindendir.
foreach (ProductSubcategory subCategory in subCategories)
{
//Her bir alt kategorinin Name ve ProductSubcategoryID zelliklerinin deerleri

www.bsenyurt.com Page 201


yazdrlr.
Console.WriteLine("{0} :
{1}",subCategory.ProductSubcategoryID,subCategory.Name);
}
}
}
}

Bunun sonucu olarak aadakine benzer bir ekran grnts elde ederiz.

imdi ii biraz daha ilerletelim. Sz gelimi bu alt kategorilerin isimlerine gre tersten sral bir
ekilde gelmesini istediimizi dnelim. Bu durumda CreateQuery metodu
ierisindeProductSubcategory?$orderby=Name desc eklinde bir ifade kullanmamz
kanlmazdr. Ne varki CreateQuery metodu sadece Entity adlar ile almaktadr ve bu nedenle
ek parametreler alamaz. Dolaysyla bu denemenin sonucu olarak aadaki ekran grntsnde
yer alan istisnaya(Exception) dlr.

yleyse are nedir? Parametrik bir sorgu sz konusu ise eer bu durumda Execute metodunun
kullanlmas gerekmektedir. Bir baka deyile kodlar aadaki ekilde deitirmek yeterli olacaktr.

AdventureWorksEntities proxy = new AdventureWorksEntities(new


Uri("http://localhost:1740/AdventureServices/AdventureWorksServices.svc"));

www.bsenyurt.com Page 202


// Parametrik sorgu gnderimi iin Execute metodu kullanlmaldr.
var subCategories = proxy.Execute<ProductSubcategory>(new
Uri("/ProductSubcategory?$orderby=Name desc", UriKind.Relative));

foreach (ProductSubcategory subCategory in subCategories)


{
Console.WriteLine("{0} : {1}",subCategory.ProductSubcategoryID,subCategory.Name);
}

Program altrldnda aadaki ekran grnts elde edilir. Dikkat edilecei zere alt kategoriler
isimlerine gre tersten sral olacak ekilde elde edilmektedir.

Bu sorgular son derece basittir. i biraz daha kartrmaya ne dersiniz? rnein A dan Z' ye
sralanm alt kategorilerden ilk n ve bunlara bal rnleri elde etmek istediimizi dnelim.
Bu noktada ProductSubcategory ve Product tipleri arasndaki iliki(Association) son derece
nemlidir. Bu sonular elde etmek iin kodlar ilk etapta aadaki gibi gelitiririz.

AdventureWorksEntities proxy = new AdventureWorksEntities(new


Uri("http://localhost:1740/AdventureServices/AdventureWorksServices.svc"));

var subCategories = proxy.Execute<ProductSubcategory>(new


Uri("/ProductSubcategory?$orderby=Name&$top=3", UriKind.Relative));

foreach (ProductSubcategory subCategory in subCategories)


{
Console.WriteLine("{0} : {1}",subCategory.ProductSubcategoryID,subCategory.Name);
// O andaki alt kategoriye bal rnleri gezmek iin Product zelliinden yararlanlr.
foreach (Product product in subCategory.Product)
{
Console.WriteLine("\t {0}, {1},
{2}",product.ProductID.ToString(),product.Name,product.ListPrice.ToString());
}
}

Ancak program altrldnda hi beklenmedik bir sonu elde edilir. Aynen aadaki resimde
olduu gibi. Dikkat edilecei zere sadece Alt kategori adlar ve ID deerleri elde edilmi bal olan
rn listeleri gelmemitir.

www.bsenyurt.com Page 203


Sebep son derece aktr. nk sadece ProductSubcategory ierii servis tarafndan istenmitir.
Bunlara bal Product nesne topluluklar alnmamtr. Grsel derslerimizdende hatrlayacanz
zere expand anahtar kelimesininin kullanlmasnn sebebide budur. Dolaysyla kodda aada
grld gibi kk bir deiiklik yapmak gerekecektir.

var subCategories = proxy.Execute<ProductSubcategory>(new


Uri("/ProductSubcategory?$orderby=Name&$top=3&$expand=Product", UriKind.Relative));

Bu haliyle kod altrldnda aadaki sonular elde edilir.

Makalenin bu ksmlarnda iimden "bylesine nemli ve bir o kadar da gzide bir teknoloji
ierisinde LINQ kullanlmaz m?" diye geirmiyor deilim. Tahmin ediyorumki sizlerinde bu
ynde baz beklentileri vardr. yleyse gelin kollar svayalm ve aadaki kod parasn gz nne
alalm.

using System;
using System.Linq;
using System.Collections.Generic;
using System.Data.Services.Client;
using ClientApp.AdventureSpace;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
AdventureWorksEntities proxy = new AdventureWorksEntities(new
Uri("http://localhost:1740/AdventureServices/AdventureWorksServices.svc"));

var subCategories = from sc in proxy.ProductSubcategory


orderby sc.Name descending
select sc;

foreach (ProductSubcategory subCategory in subCategories)


{
Console.WriteLine("{0} :
{1}",subCategory.ProductSubcategoryID,subCategory.Name);
}

www.bsenyurt.com Page 204


}
}
}

Bu kez grdnz gibi Execute yada CreateQuery gibi metodlar kullanmadk. Bunlarn yerine
dorudan bir LINQ sorgusu yazdk ve ite sonu;

Aslnda yazlan LINQ sorgusu istemci tarafnda bir HTTP ifadesinin oluturulmasna ve servise
doru gnderilmesine neden olmaktadr. yleki debug modda subCategoriesdeikenine
bakldnda aadaki ekran grntsnde olduu gibi bir QueryString ifadesi olutuu
gzlemlenir.

Buna gre ProductSubcategory ve bunlara bal rnlerin elde edilmesi iin yazlm olan kod
parasnda LINQ ifadelerini aadaki gibi kullanarak ayn sonularn elde edilebilecei ak bir
ekilde grlebilir.

AdventureWorksEntities proxy = new AdventureWorksEntities(new


Uri("http://localhost:1740/AdventureServices/AdventureWorksServices.svc"));

// Take metodu ile A...Z ye sralanm listenin ilk 3 eleman alnm olunur.
var subCategories = (from sc in proxy.ProductSubcategory
orderby sc.Name
select sc).Take<ProductSubcategory>(3);

// Elde edilen alt kategoriler dolar


foreach (ProductSubcategory subCategory in subCategories)
{
Console.WriteLine("{0} : {1}",subCategory.ProductSubcategoryID,subCategory.Name);
// O andaki alt kategoriye bal rnlerin ekilmesi iin LoadProperty metodu kullanlr. kinci

www.bsenyurt.com Page 205


parametre ilikinin tand zellik addr.
proxy.LoadProperty(subCategory, "Product");
// Artk o andaki alt kategori iin yklenen Product satrlar dolalabili
foreach (Product product in subCategory.Product)
{
Console.WriteLine("\t{0} {1}
{2}",product.ProductID.ToString(),product.Name,product.ListPrice.ToString());
}
}

Bu kod parasnda tek dikkat edilmesi gereken nokta LoadProperty zelliinin kullanmdr.
Nitekim bu zellik ile ilikisel veriler yklenmedii takdirde alt kategoriye bal rn listeleri servis
tarafnda ekilmez.

ster Execute metodu olsun ister LINQ sorgusu olsun, ilikisel zelliklerce tanan
verilerin ekilmesi iin srasyla expand anahtar kelimesinin
yada LoadPropertymetodunun kullanlmas gerekir.

Artk sizde farkl sorgulama rnekleri deniyerek istemci tarafnda neler yaplabileceini analiz
edebilirsiniz. Grld zere bir Ado.Net Data Service' in istemci tarafndan ele alnmas standart
bir servis kullanmna ok benzemektedir. Proxy tipleri burada ii kolaylatrmakla birlikte LINQ
sorgularnnda kullanlabiliyor olmas kiisel grme gre son derece nemlidir.

Bylece bugnk ders notlarmznda sonuna gelmi bulunuyoruz. Bu ders notlarmzda basit bir
istemcinin nasl gelitirilebileceini incelemeye altk. Konu ile ilikili olaraktan ilgili grsel
dersi takip etmenizi neririm. Bir sonraki ders notlarmzda istemci
tarafnda CRUD(CreateReadUpdateDelete) operasyonlarnn nasl ele alnabileceini analiz
etmeye alacaz; ve eer mmkn olursa zel LINQ Provider kullanlmas halinde, servis
tarafnda Insert, Update, Delete oparasyonlarna olanak salamak iin neler yaplmas
gerektiine deiniyor olacaz. Tekrardan grnceye dek hepinize mutlu gnler dilerim.

rnei indirmek iin tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

Ado.Net Data Services Ders Notlar - 2 (Custom


LINQ Providers) ( 24.09.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Son bahar yada k gibi mevsimler ile zellikle yamurlu ve kasvetli gnlerde her gelitiricinin
aratrma ve renme sreci ve verimliliinde belirgin bir art gzlemlenir. Bu herkes iin byle
olmasada en azndan benim iin geerli bir durumdur. te bu felsefe ve ruh haliyle ktmz yolda
son makalemizde Ado.Net Data Services konusuna deinmeye balam ve ders notlarmz
kaleme almtk. kinci ders notlarmzn konusu ise LINQ Provider kullanarak zel bir balama
ileminin nasl yaplabileceini grmek.

www.bsenyurt.com Page 206


Hatrlayacanz gibi Ado.Net Data Service Entry Point' leri istemcilerden gelen HTTP taleplerini
ele almak zere tasarlanmaktadr. Bu tipteki servislerin belirgin amac, veriler zerindeki hizmetleri
operasyonel bazda istemcilere sunabilmektir. Bu nedenle arka planda bir veri eriim
katman(Data Access Layer) mutlaka sz konusudur. Temel olarak DAL ierisinde iki farkl
alm olduundan bir nceki yazmzda ksaca bahsetmitik. Buna gre Entity Data
Model veya LINQ Provider seenekleri sz konusudur. Bu gnk ders notlarmzda ele
alacamz LINQ Provider, ounlukla Entity tiplerinin gelitirici tarafndan tasarlanp farkl veri
kaynaklarna balanmas istendii durumlarda dnlr. Bilindii zere gnmzde pek ok veri
kayna iin yazlm LINQ Provider aralar sz konusudur. Sz gelimi Active Directory zerinde
alacak ekilde tasarlanmLINQ to Active Directory salaycs mevcuttur. Hatta daha
ilginlerinden biriside ktphanemde yer alan saysz kitab getirdiim Amazon sitesi iin yazlm
olan LINQ to Amazon salaycsdr ki kitap arama ilemleri iin gelitirilmitir. Saysz LINQ
salaycsnn olduunu ve Robert Shelton un blog adresinden bazlarn inceleyebileceinizi
belirtmek isterim. Madem zel LINQ Provider tipleri yazlabiliyor ve ok farkl veri kaynaklarna
balanlabiliyor, balanrken LINQ mimarisinin nimetlerinden yararlanyor; bu sistemler neden
servis bazl olacak ekilde istemcilere yaynlanamasnlar? te bu noktad devreye Ado.Net Data
Services girmektedir.

Sanyorumki bu kadar laf kalabalndan sonra bir rnek gelitirerek hareket etmekte yarar vardr.
e yine Ado.Net Data Service rneinin Host edilecei bir WCF Serviceuygulamas ile
balanacaktr. Sonrasnda ise kendi LINQ Provider ortammz iin gerekli tipler ve yeleri
gelitirilecektir. Tm bu ilemler tamamlandnda ise her zamanki gibi istemci uygulama yazmaya
gerek kalmadan basit bir tarayc zerinde gerekli testler yaplacaktr. ncelikli
olarak DepoServisleri isimli
bir WCF Service uygulamasn Visual Studio2008 Professional Service Pack 1 zerinde
oluturalm. Sonrasnda ise snf diagram ve kod ierii aadaki gibi olan tipleri projemize ilave
edelim.

www.bsenyurt.com Page 207


using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Services.Common;

public class Kategori


{
public int KategoriID { get; set; }
public string Ad { get; set; }
// Kategori bal Kitaplara ulamak iin IList<Kitap> tipinden bir zellik kullanlmaktadr
public IList<Kitap> Kitaplar { get; set; }
}

// DataServiceKey nitelii ile Kitap snfnn anahtar-Key zelliinin Numara olduu belirtilir.
[DataServiceKey("Numara")]
public class Kitap
{
public int Numara { get; set; }
public string Ad { get; set; }
public double BirimFiyat { get; set; }
// Bir kitabn yazalarna gei yapmak iin IList<Yazar> tipinden bir zellik kullanlr
public IList<Yazar> Yazarlar { get; set; }
}

www.bsenyurt.com Page 208


// Yazar snf iin Key zellii string tipinden olan SicilNo' dur.
[DataServiceKey("SicilNo")]
public class Yazar
{
public string SicilNo { get; set; }
public string AdSoyad { get; set; }
}

// Entity tiplerini ierisinde barndran snf


public class DukkanEntities
{
static List<Kategori> _kategoriler;
static List<Kitap> _kitaplar;
static List<Yazar> _yazarlar;

// static yapc DukkanEntities' e ait taleplerin says ne olursa olsun ilk seferde bir kereliine
alt iin, bellek zerinde tutulacak nesne topluluklarnn oluturulmas srasnda performans
kazanm salamaktadr.
static DukkanEntities()
{
// rnek kategori verileri oluturulur.
_kategoriler = new List<Kategori>
{
new Kategori{ KategoriID=1, Ad="Bilgisayar Kitaplar"},
new Kategori{ KategoriID=2, Ad="Bilim Teknik Kitaplar"},
new Kategori{ KategoriID=3, Ad="izgi Roman"},
};

// rnek kitap verileri oluturulur.


_kitaplar = new List<Kitap>
{
new Kitap{ Numara=9001, Ad="Red Kit", BirimFiyat=10},
new Kitap{ Numara=9002, Ad="Ten Ten' in Maceralar", BirimFiyat=9.99},
new Kitap{ Numara=9003, Ad="rmcek Adm", BirimFiyat=8.99},
new Kitap{ Numara=9004, Ad="Batman", BirimFiyat=6.99},
new Kitap{ Numara=9005, Ad="Barbar Conan", BirimFiyat=13.44},
new Kitap{ Numara=9006, Ad="Superman", BirimFiyat=12.34},
new Kitap{ Numara=9007, Ad="Martin Myster", BirimFiyat=23.45},
new Kitap{ Numara=8002, Ad="Programming C#", BirimFiyat=45},
new Kitap{ Numara=8003, Ad="LINQ Unleashed", BirimFiyat=44.45},
new Kitap{ Numara=7450, Ad="Essential WCF For .Net Framework 3.5",
BirimFiyat=44.50},
new Kitap{ Numara=1240, Ad="Fermant' nn Son Teoremi", BirimFiyat=5},
new Kitap{ Numara=2450, Ad="Saylarn Gc", BirimFiyat=7.5},
new Kitap{ Numara=2470, Ad="Evrenin Ksa Tarihi", BirimFiyat=9.99}
};

// Kategori ve Kitaplar arasndaki ilikiler veriler zerinden salanr


for (int i = 0; i < _kategoriler.Count; i++)
_kategoriler[i].Kitaplar = new List<Kitap>();
for (int i = 0; i <= 6; i++)
_kategoriler[2].Kitaplar.Add(_kitaplar[i]);
for (int i = 7; i <= 9; i++)
_kategoriler[0].Kitaplar.Add(_kitaplar[i]);
for (int i = 10; i <= 12; i++)
_kategoriler[1].Kitaplar.Add(_kitaplar[i]);

www.bsenyurt.com Page 209


// rnek yazarlar oluturulur
_yazarlar = new List<Yazar>
{
new Yazar{ SicilNo="Y100", AdSoyad="Ali"},
new Yazar{ SicilNo="Y101", AdSoyad="Veli"},
new Yazar{ SicilNo="Y104", AdSoyad="Mehmet"},
new Yazar{ SicilNo="Y103", AdSoyad="Burak"},
new Yazar{ SicilNo="Y107", AdSoyad="Selim"},
new Yazar{ SicilNo="Y108", AdSoyad="Kamil"},
new Yazar{ SicilNo="Y109", AdSoyad="Cemil"},
new Yazar{ SicilNo="Y110", AdSoyad="Nazl"},
new Yazar{ SicilNo="Y120", AdSoyad="Aye"},
new Yazar{ SicilNo="Y111", AdSoyad="Fatma"},
new Yazar{ SicilNo="Y110", AdSoyad="Melike"}
};

// Kitaplar ile yazalar arasndaki verisel balantlar salanr


Random rnd = new Random();
for (int i = 0; i < _kitaplar.Count; i++)
{
_kitaplar[i].Yazarlar = new List<Yazar>();
for(int j=0;j<3;j++)
_kitaplar[i].Yazarlar.Add(_yazarlar[rnd.Next(0,_yazarlar.Count-1)]);
}
}

// REST modelinde talep edilebilecek zellikler IQueryable<T> tipinden tanmlanr


public IQueryable<Kategori> Kategoriler
{
get
{
return _kategoriler.AsQueryable<Kategori>();
}
}
public IQueryable<Kitap> Kitaplar
{
get
{
return _kitaplar.AsQueryable<Kitap>();
}
}
public IQueryable<Yazar> Yazarlar
{
get
{
return _yazarlar.AsQueryable<Yazar>();
}
}
}

Yukardaki kod satrlar ilk etapta karmak grnebilir ancak iin teorisi olduka kolaydr.
Hereyden nce REST modeline gre darya sunmak isteyeceimiz tiplerin bir tasarmnn servis
tarafnda olmas gerekir. Bu tasarmn karl tahmin edilecei zere snftr. rnek senaryoda bir
kitap dkkannda olmas muhtemel materyallere ait snflar
tasarlanmtr. Kategori, Kitap ve Yazar. Elbetteki bunlar tamamen farazi tasarmlardr. nemli

www.bsenyurt.com Page 210


olan ve kavramamz gereken nokta, Entity Data Model' dan bamsz ve LINQ yapsn
kullanarak Ado.Net Services iin gerekli Data Access Layer' n gelitirilmesidir.

Bir nceki makaleyi hatrlyorsak eer, URL satrndan ProductSubcategory(2) gibi taleplerde
bulunabileceimizi grmtk. Buradaki 2 saysal
aslnda,ProductSubCategory tablosunun PrimaryKey olarak set
edilmi ProductSubCategoryID alannn deeriydi. Dolaysyla EDM ierisinde bunu iaret edecek
biimde tasarlanmProperty' ler sz konusudur. imdi tekrardan Kategori, Kitap ve Yazar
snflarna dnelim. Dikkat edilecei zere Kitap ve Yazar snflarnn
banda DataServiceKey isimli birnitelik(Attribute) kullanlmaktadr. Bu nitelik sayesinde
snfn anahtar zellii(Key Property) belirlenir. Kitap iin bu zellik int tipinden
olan Numara iken, Yazar iin stringtipinden olan SicilNo' dur. Tabi burada dier bir vaka daha
vardr. Kategori snf iin bu tip bir nitelik kullanlmamtr. Bunun sebebi ise, alma
zamannn Key Property' lere bakarken ya [SnfAd][ID] yada ID isiminde zellikler aramasdr.
Dikkat edilecek olursa Kategori snfnda KategoriID isimli bir zellik bulunmaktadr.

DataServiceKey nitelii(Attribute) sadece snf seviyesinde(Class Level) uygulanabilir


ve System.Data.Services.Common isim alan(Namespace) altnda yer almaktadr. ki
adet ar yklenmi yapcs(Overloaded Constructor) vardr. stenirse bir snfn birden
fazla zelliine Key Property niteliinin kazandrlmasn salayabilir.

Snf tasarmlarnda dikkat ekici noktalardan bir dieri ise IList<T> tipinden zelliklerin
kullanlmasdr. rnein Kategori ve Kitap snflar ierisinde
srasylaIList<Kitap> ve IList<Yazar> tipinden zellikler yer almaktadr. Bu yaklam EDM' nin
kullandnn neredeyse aynsdr. Ama; bir entity nesne rnei zerinden ilikisel dier entity
nesne rneklerine gei yapabilmektir. Sz konusu entity nesne rnekleri birer snf olduundan bu
geite liste bazl zelliklerin kullanlmas son derece doaldr.

Buraya kadarki ksmlarda kafa kartrc herhangibir nokta olmad dncesindeyim. Eer
skldysanz benim gecenin ilerleyen u saatlerinde yaptm gibi scak bir nescafeyi yudumlanz
yada demlenmi gzel bir ay imenizi tavsiye ederim.

Artk kalan detaylara bakabiliriz. Servis tarafnda darya sunulacak olan tipler birer koleksiyon
ierisinde tutulmaldr. Hatta bu koleksiyonlar birer zellik olarak barndracak bir baka
deyile entity tiplerini ierecek bir taycnn(Container) var olmasda gerekir. Bu
nedenle DukkanEntity isimli bir snf tasarlanmaldr. Bu snf ierisinde bellek zerinde tutulacak
olan Entity nesneleri iin gerekli yeler ve kodlar yer almaktadr. Ancak dikkat edilmesi gereken en
nemli unsur Entity zelliklerinin IQueryable<T> tipinden tanmlanm olmamlardr ki Ado.Net
Data Services taraf iin bu sorgulanabilmeyi salayan kk bir detaydr. Bu
amala Kategoriler, Kitaplar ve Yazarlar isimli yanlz okunabilir zellikler(Read Only
Properties) oluturulmu ve DukkanEntities snf ierisine dahil edilmitir. Sz konusu
zelliklerin get bloklarnda AsQueryable metodunun kullanld hemen dikkat ekmektedir.
AsQueryable fonksiyonu, IList<T> tipinden olan snf iin liste bazl koleksiyonlarn IQueryable<T>
arayz(Interface) tarafndan tanabilmesi iin gelitirilmi bir metoddur.

Sanyorumki yazy okumakta olan herkesin iinde(ve hatta yazmakta olan benim) sistemin nasl
alacana dair youn bir merak var. Bu merak gidermeden nce yapmamz gereken kk bir i
daha var. Oda Ado.Net Data Service' i WCF Service tipindeki projemize Add New Item seenei
ile eklemek. (Bu noktada hemen unu vurgulayalm; Ado.Net Data Service tiplerinin illede bir WCF
Service ablonunda olmas art deildir. stenirse bir Web projesine eklenebilir. Hatta istenirse
manuel olarak bir host uygulamada yazlabilir ki bu konuya ilerleyen yazlarmzda deiniyor
olacaz.)

www.bsenyurt.com Page 211


rnee DukkanServisleri.svc olarak eklenen Ado.Net Data Service' in kod ierii ise aadaki
gibi gelitirilebilir.

using System;
using System.Data.Services;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Web;

public class DukkanServisleri


: DataService<DukkanEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
}
}

Her zamanki gibi servis rneklenirken devreye giren InitializeService metodu ierisinde, gerekli
eriim haklar tanmlanr. * iaretini kullandmz iin DukkanEntities ierisinde
tanml IQueryable<T> temelli tm zellikler darya almaktadr. AllRead sabit deeri
kullanld iinde, sz konusu tiplerin sadece okuma amal olaraktan d ortama sunulmas
salanr.

Artk rnekler test edilebilir. Bir nceki makalemizdede belirttiimiz gibi herhangibir istemci
uygulama yazmamza gerek yoktur(Bu noktada biraz tembellik ettiimi aka belirtebilirim). Basit
bir tarayc uygulama, rnein Internet Explorer bizim iin yeterlidir. rnekteki kodlar doru
olarak gelitirdiysek eer, DukkanServisleri.svc iin alma zamannda aadakine benzer bir
ktnn alnmas gerekir. Eer sizlerde e zamanl gelitirdiiniz rneinizde benzer sonular
alyorsanz herey yolunda gidiyor demektir.

www.bsenyurt.com Page 212


Sistem altna gre bir ka sorgulama denemesi yaplabilir. Aada test amal bir ka sorgu
yer almaktadr.

rnek 1: Tm Kategorilerin elde edilmesi.

URL : http://localhost:1304/CustomLinqProvider/DukkanServisleri.svc/Kategoriler

www.bsenyurt.com Page 213


rnek 2: ki numaral kategorideki kitaplarn elde edilmesi

URL : http://localhost:1304/CustomLinqProvider/DukkanServisleri.svc/Kategoriler(2)/Kitaplar

www.bsenyurt.com Page 214


rnek 3: Kitaplar ierisinden en pahal 3 nn elde edilmesi

URL :
http://localhost:1304/CustomLinqProvider/DukkanServisleri.svc/Kitaplar?$orderby=BirimFiyat
desc&$top=3

Burada & kullanlarak birden fazla anahtar kelimenin birlikte kullanm ele alnmaktadr.

www.bsenyurt.com Page 215


rnek 4: Kitaplar ve her kitaba ait Yazar listelerinin elde edilmesi

URL :
http://localhost:1304/CustomLinqProvider/DukkanServisleri.svc/Kitaplar?$expand=Yazarlar

expand anahtar kelimesi sayesinde her Kitaba ait Yazar listelerinin ekilmesi ve XML ierisine
gmlmesi salanr.

www.bsenyurt.com Page 216


rnek 5: SicilNo deeri Y100 olan yazarn elde edilmesi

URL : http://localhost:1304/CustomLinqProvider/DukkanServisleri.svc/Yazarlar('Y100')

Burada SicilNo string bir zellik olduunda parantezler ierisinde tek trnak iareti kullanlmtr.

www.bsenyurt.com Page 217


rnek 6 : 1 numaral Kategorideki 8002 numaral kitabn yazalarnn elde edilmesi

URL :
http://localhost:1304/CustomLinqProvider/DukkanServisleri.svc/Kategoriler(1)/Kitaplar(8002)
/Yazarlar

Bu rnektede zellikler arasnda iki kademeli gei yaplmaktadr. Kategori' den Kitap' a, Kitap' tan
Yazara. Bu noktada snflar ierisinde tanmlanan zellikleri hatrlamanz neririm.

www.bsenyurt.com Page 218


Ltfen sizlerde deiik sorgulamalar deneyerek konuyu zmsemeye ve baka neler
yaplabileceini grmeye alnz.

Grld gibi EDM' den bamsz olarak Ado.Net Data Services zerinden gelitirme yapmak
olduka kolaydr. Yazmzn balarndada belirttiimiz gibi, farkl LINQProvider gelitirmeleri
yapabilir ve bunlar Ado.Net Data Services zerinden REST modeline gre sunabiliriz. Biz
makalemizde ele aldmz rnekte bellek zerinde tutulan(Memory Based) nesne koleksiyonlarn
kullandk. Burada verinin kayna XML tabanl dosyalarda olabilirdi. Size tavsiyem XML zerinde
tutulan verileri zel LINQ Provider yardmyla birAdo.Net Data Service zerinden darya
sunmaya almanzdr.

Bu makalede ilediklerimizi dilerseniz grsel olarakta izleyebilirsiniz. Her ne kadar ilk iki
makale Ado.Net Data Services hakknda bir fikir vermi olsada henz bir istemci uygulama
yazmadmz ve kolaya kaarak tarayc uygulamalar kullandmz(Kullandm) farkedebilirsiniz
:) te bir sonraki makalemizde bu konuya deinmeye alacaz. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnei indirmek iin tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

www.bsenyurt.com Page 219


Ado.Net Data Services Ders Notlar - 1
(Merhaba) ( 22.09.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Uzun bir aradan sonra yeni bir makale ile daha birlikteyiz. Sanak yal ve tamda bu havada
bir makale yazlr dedirten bir gnde hazrladmz bu yazmzda, daha imdiden gelecek vaat
etmi grnen, .Net Framework 3.5 Service Pack 1 ile birlikte hazr olarak gelen, Visual
Studio 2008 ortamna entegre edilen ve WCF mimarisinin en gzel uyarlamalarndan birisi
olan ADO.Net Data Services(Astoria) zerinde konuuyor olacaz.

Bilindii zere Windows Communication Foundation(WCF), Microsoft un .Net Framework


3.0 ile duyurduu ve 3.5 ile getirdii yeni ilavelerle n plana kard
yeni ServiceYnelimli Mimari(Service Oriented Architecture/SOA) yaklamdr. Bu
yaklamn etkileri gncel projelerde kendini uzun zamandr gstermektedir. SOA yaklamlarnn
arlkl bir biimde kabul grd gnmz zmlerinde veri(Data) ile olan ilikiler gz nne
alndnda Microsoft cephesinde uzun sre nce getirilen yeni bir proje karmza
kmaktadr. Ado.Net Data Services.

Astoria kod ad ile anlan ve stanbul Mecidiyeky deki al veri merkezinin ada olan bu
mimarinin uygulan biimi Visual Studio 2008 Service Pack 1 ile daha da kolay hale gelmi
ve IDE ierisine baarl bir ekilde entegre edilmitir. Peki Astoria neler vaat etmektedir ve nasl
bir mimari modele sahiptir? Dilerseniz ksaca bu konulara deinerek yazmz sabrla okumaya
devam edelim.

ncelikli olarak Ado.Net Data Services bir WCF servis yaklamdr. Bununla
birlikte, WCF mimarisine .Net Framework 3.5 ile getirilen yeniliklerden biriside; servislerin, Web
Programlama Modeline uygun olacak ekilde yaynlanabilmeleridir. Bu Representational State
Transfer(REST) modeline uygun servislerin yazlabilecei anlamna gelmektedir.

Ebellteki Web programlama modelinin(Web Programming Model) WCF tarafna


kazandrd tek avantaj QueryString bazl operasyon destei deildir. Bunun
yanndaJSON(Java Script Object Notation) formatnda yaynlama
ve RSS, Atom bazl Syndication desteide gelmektedir.

Aslnda kafay ok fazla kartrmaya gerek yoktur. Aadaki tablo durumu daha net bir ekilde
zetlemektedir.

HTTP
CRUD Karl
lemi

Post Create, Update, Delete

Get Read

Put Create, Overwrite/Replace

Delete Delete

Bu tabloda anlatlmak istenen udur; HTTP zerinden yaplabilecek olan Post, Get, Put,
Delete gibi arlar tablonun sa tarafnda yer alan veri operasyonlarna dntrlebilirler. O
halde iin iersine veri kelimesinin girdii ortadadr ve ne varki Astoria alm Ado.Net Data
Services olarak gemektedir. O halde Astoria iin, Ado.Net tabanl verileri REST modelinin

www.bsenyurt.com Page 220


belirttii kriterlere uygun olacak ekilde darya sunan servis mimarisidir tanmlamasn yapmak
yerinde olacaktr. Servis talepleri(Requests) HTTPprotokolne gre QueryString bazl
olmaktadr. Bu talepler servis tarafna ulatklarnda ise arka planda bir Data Access
Layer tarafndan karlanmakta ve operasyonel
olarakCRUD(CreateReadUpdateDelete) ilemlerine dntrlmektedir. Sonrasnda istemciye
gnderilecek olan cevaplar XML bazl olarak ele alnmaktadr. Standart olarak ATOMformatnda
bir XML kts istemci tarafna gnderilmektedir. Bu tanmlamalar ksaca bir fikir versede mimari
detaylara bakmakta yarar vardr. Aadaki ekil Astoria mimarisini ksaca zetlemektedir.

ok ksaca mimari zerinden konuarak devam edelim. ncelikli


olarak internet veya intranet zerinden talepte bulunabilecek bir istemci(Client) uygulama sz
konusudur. Bu uygulama standart bir .Net program olabilir. rnein bir Windows/WPF yada
basit bir Console uygulamas. ok doal olarak istemci baka bir servisde olabilir. Ancak
gnmzde Ado.Net Data Service rneklerini kullanacak en popler istemciler web tabanl
olanlardr. Bir baka deyile Ajax Based Client ve Silverlight gibi u birimler rnek olarak
verilebilirler. lerleyen ksmlarda Ajax tabanl bir istemcinin nasl gelitirileceine de deinilecektir.
stemci uygulamalar, servise doru QueryString benzeri formatta bir talepte bulunabilir. rnein;

http://localhost:4501/AdventureServices/ProductService.svc/ProductSubcategory?$orderby=N
ame desc

gibi.

Aslnda bu ifade son derece aktr. Tahmin edilecei zere HTTP tabanl olaraktan localhost isimli
yerel makinede 4501 numaral port zerinden yayn yapan ProductService.svcisimli
bir WCF servisi sz konusudur. Servise giden talep ise unu ifade etmektedir; Ltfen
ProductSubcategory verilerini Name alanlarna gre ters srada olacak ekilde
gnderin. te svc uzantsndan sonra gelen ifade basit bir QueryString tanmlamasdr.
Elbetteki arada kullanlan $ iareti ifadeyi Ado.Net Data Services iin biraz zelletirmektedir. Bu
noktada talebin servis tarafna ulatn dnebiliriz. Peki servis bu noktadan sonra ne
yapmaktadr?

www.bsenyurt.com Page 221


Service tarafnda alma zamannda(RunTime) devrede
olan DataServiceHost (WebServiceHost snfndan treyen ki buda WCF Servislerinde ekirdek
olan ServiceHost snfndan tremektedir.) nesne rnei, gelen talebi arka planda ele alr. Bu
noktada elde iki seenek yer almaktadr. Bunlardan birisi yine Visual Studio 2008 Service Pack
1 ile IDEortamna dahil olan Entity Data Model(EDM) almnn kullanlmasdr. Dieri ise
zel LINQ Provider kullanld seenektir. LINQ Provider kullanm yardmylaREST taleplerinin
nesneler zerindede ele alnmas salanabilmektedir ki bununla ilikili bir rnei ilerleyen
blmlerde gelitiriyor olacaz.

EDM modeline gre veritaban bazl Entity tipler(Types) ve bu tiplere ait yeler(Members) sz
konusudur. Burada temel ama veritaban zerindeki nesnel yaplarn OOP(Object Oriented
Programming) ortamnda karlklar olan snf(Class) tiplerinde ve yelerinde(Her alann
karl olan bir zellik ile) ele alabilmektir. Bylece kod ortamndan veritaban zerine gei
yapmaya gerek kalmadan CRUD operasyonlar kolayca icra edilebilir. EDM asndan olaya
baktmzda sadece yukardaki basit okuma(READ) talebi iin aadaki ekil biraz daha
aydnlatc ve fikir verici olabilir.

Grld zere REST bazl talep, Ado.Net Data Service Entry Point e ulatktan sonra servis
alma zaman tarafndan veritabanna doru basitsorgular(Queries) eklinde gnderilirler.
Bunun doal sonucu olarak baz veri kmeleri elde edilir. Elde edilen sorgu
sonular EDM ierisinde yer alan Entity nesneleri ve yeleri tarafndan deerlendirilir. Nitekim
veritaban tarafndaki nesnelerin karl olan varlklar, EDM ierisinde yer almakta olup alma
zamannda servis operasyonlar tarafndan ele alnmaktadr. Bir baka deyile rnek baz
alndnda, ProductSubCategory tablosu ierisindeki herhangibir satrn(Table Row) karl
olan ProductSubcategory snfna ait nesne rneklerinden oluan
bir koleksiyon(Collection) retimi gerekleir. Bu retim sonrasnda ilgili koleksiyon, servis
alma ortam tarafndan XML kts haline getirilir ve istemciye gnderilir.

www.bsenyurt.com Page 222


Sanyorumki artk bir rnek gelitirerek konuyu pekitirmenin ve makalenin yazld bu yamurlu
gnde ekranmzda bir gne atrmann zaman geldi. lk olarak rnein Visual Studio 2008
Professional Service Pack 1 zerinde gelitirildiini belirtelim.

Ado.Net Data Service' ler esas itibariyle birer WCF servis esi olarak tanmlanrlar. Bu sebepten
dolay sz konusu servislerin bir sunucu uygulama zerinde host edilmeleri gerekmektedir. Burada
istenirse bir WCF Service uygulamas baz alnabilir. Yada herhangibir Asp.Net Web
Site/Asp.Net Web Application zerindede bu ilem gerekletirilebilir. Web tarafndaki
gelitirme kurallarnn buradada geerli olduunu ve buna gre dosya tabanl(File-Based) yada
dorudan IIS zerinde gelitirme yapabileceimizi hatrlayalm. Biz
rneimizde AdventureServices adl WCF Service ablonunu
kullanacaz. AdventureServices isimli proje File-Based olarak gelitirilecektir. Servis
uygulamas oluturulduktan sonra ilk yaplmas gereken, Ado.Net Data Service' in
kullanaca Data Access Layer ortamn hazrlamaktr. Burada daha ncedende belirtildii
zere EDM, LINQ Provider seenekleri mevcuttur.
rneimizde Entity Data Model kullanlmaktadr. EDM nesnesini eklemek iin projeye sa
tkladktan sonra aadaki resimde yer alan Ado.Net Entity Data Modelablonunu semek yeterli
olacaktr.

sim olarak AdventureModel ad kullanlabilir. edmx uzantl dosya seimi yapldktan sonra bir
dizi admdan oluan sihirbaz arabirimi ile karlalr.

www.bsenyurt.com Page 223


lk admda EDM modelinin var olan bir veritabanndan oluturulaca seimi yaplr(Generate
from database). Ancak istenirse Empty Model kullanlarak, EDM tiplerinin grsel olarak
veritabanndan bamsz tasarlanmas ve ilgili snflar ve yelerinin oluturulmas salanabilir. Bu
ounlukla Entity tasarmnn nceden yaplp sonrasnda veriye balama kararnn verilecei
durumlarda ele alnabilir. Ki bu ekilde oluturulan Entity nesneleri ierisinde LINQ Provider' lar
kullanlarak farkl salayclara(rnein XMLveya Object tiplerine) doru eletirmelerde
gerekletirilebilir.

www.bsenyurt.com Page 224


kinci admda balant(Connection) seimi yaplr. Buna gre herhangibir veritaban balants
kullanlabilir. Sz konusu balantlara ilikin bilgiler ise istenirseWeb.config dosyas ierisinde
saklanabilir.

www.bsenyurt.com Page 225


nc admda, oluturulan balant zerindeki veritaban ierii grlr.
Burada tablolar(Tables), grnmler(Views) ve sakl yordamlar(Stored Procedures)yer
almaktadr. Dolaysyla bu admda, EDM ierisindeki tiplerin e dt veritaban objeleri
iaretlenir.

www.bsenyurt.com Page 226


rnekte yukardaki ekildende grlecei zere ProductSubCategory ve Product tablolar ele
alnmaktadr. Bu tablolar arasnda bire-ok(One to many) iliki olmas nedeni ile ilikisel
yaplarda inceleyebilme frsatmz olacaktr. Tm bu ilemler tamamlandktan sonra
aadaki EDM diagramnn olutuu grlecektir.

www.bsenyurt.com Page 227


Dikkat edilecek olursa ProductSubCategory ve Product tablolarnn kendileri birer snf olarak
oluturulmu, alanlar birer ye olarak ilave edilmitir. Bunlara ek olarak her iki tablo
arasndaki iliki(Relation), EDM ierisinde bir Association olarak tanmlanmtr. Dikkat ekici
zelliklerden bir dieri ise snflara ait nesne rnekleri zerinden birbirlerine gei yaplmasn
salayacak zelliklerin(Properties) eklenmi olmasdr. Sz gelimi bir alt kategoriye bal
rnleri elde etmek iin ProductSubcategory tipine ait nesne rnei zerinden Product zellii
kullanlabilir. Oluturulan bu snflar ve e dtkleri veritaban objeleri arasndaki ilikiler
istenirse Model Browser araclyla aadaki ekilde grld gibide izlenebilir.

www.bsenyurt.com Page 228


rnekteki Model Browser grselinde, AdventureWorksModel ksmnda EDM ierii
haritalanmaktadr. Dier taraftan AdventureWorksModel.Store boumu(Node) altnda
ise, EDMieriinin karlklar olan veritaban unsurlar
listelenmektedir. AdventureModel.Designer.cs dosyasna bakldnda ise 3
adet snfn(Class) oluturulduu grlr.

Dikkat edilecei zere Product ve ProductSubcategory tipleri


dnda AdventureWorksEntities isimli bir tipin daha olduu grlmektedir ki yeleri aadaki
ekilde olduu gibidir.

www.bsenyurt.com Page 229


AdventureWorksEntites, ObjectContext snfndan tremitir ve Entity koleksiyonlarnn
ynetimi, EDM nesnelerinin e dt veri objeleri ile olan fonksiyonelliklerin ele alnmas gibi
kritik grevleride stlenmek zere tasarlanmtr. yleki, Product ve ProductSubcategory nesne
topluluklar bu snf ierisinde aadaki kod parasnda olduu gibi tutulmaktadr.

public global::System.Data.Objects.ObjectQuery<Product> Product


{
get
{
if ((this._Product == null))
{
this._Product = base.CreateQuery<Product>("[Product]");
}
return this._Product;
}
}
private global::System.Data.Objects.ObjectQuery<Product> _Product;

public global::System.Data.Objects.ObjectQuery<ProductSubcategory>
ProductSubcategory
{
get
{
if ((this._ProductSubcategory == null))
{
this._ProductSubcategory =
base.CreateQuery<ProductSubcategory>("[ProductSubcategory]");
}
return this._ProductSubcategory;
}
}
private global::System.Data.Objects.ObjectQuery<ProductSubcategory>
_ProductSubcategory;

ObjectQuery<T> tipinden birer readonly zellik(Property) yardmyla! Ve yine bir rnn veya
alt kategorinin eklenmesi iin AddToProduct ve AddToProductSubcategory isimli metodlarda
yer almaktadr. Bu noktada akla yle bir soru gelebilir. Update, Delete ilemleri iin niye
metodlar bulunmamaktadr? Sz konusu sorunun cevab ilerleyen blmlerde verilecektir ve bu
nedenle sizlere biraz dnme ve aratrma sresi kalmaktadr. Bu detaylar imdilik geride
brakarak asl konumuza geri dnmenin yararl olaca kansndaym.
Artk WCF Service uygulamasna bir Ado.Net Data Service eklenebilir. Tek yaplmas gereken
projeye Add New Item seenei ile aadaki ekildede grlenAdo.Net Data Service esini
eklemektir.

www.bsenyurt.com Page 230


Bu ilemin ardndan proje ablounan ProductService.svc servis ve ProductService.cs code-
behind dosyalar eklenecektir. (Sz konusu ilemlerde biz WCF gelitiricilerini artan herhangibir
nokta bulunmamaktadr. Nitekim Web zerinden host edilen bir WCF serviside ayn prensiplerde
oluturulmaktadr. Bir svc ierii ve ounlukla code-behind zerinde tutulan kod
ierii.) ProductService.cs ierii ksaca incelendiinde bir balatma
ileminin(Initialization) yaplmas gerektii grlmektedir. Nitekim servis nesnesi
rneklendiinde EDM ierisindeki hangi tiplerin hangi artlarda yaynlanacann belirlenmesi
gerekmektedir. Bu bir anlamda yetkilendirme sreci olarakta dnlebilir. Sz
konusu ProductService.cs ierii rnek iin aadaki gibi deitirilmelidir.

using System;
using System.Data.Services;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel.Web;
using AdventureWorksModel;

public class ProductService


: DataService<AdventureWorksEntities>
{
public static void InitializeService(IDataServiceConfiguration config)
{
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
}
}

Burada dikkat edilmesi gereken noktalardan


birisi ProductService snfnn System.Data.Services isim alannda(Namesapce) yer
alan DataService<T> generic snfndan tremi olmasdr. Bunun dndan u an iin nem arz
eden nokta static InitializeService metodudur. Bu metod, servis rnei ilk oluturulduunda bir
kereliine devreye girer.config deikeni zerinden yaplan ar ise
nemlidir. SetEntitySetAccessRule metoduna gnderilen ilk parametrede * sembl
kullanlarak, Entity set ierisindeki tm tiplerin ele alnaca belirtilmektedir. kinci parametre
ise EntitySetRights enum sabiti tipinden olup aadaki deerleri alabilir.

www.bsenyurt.com Page 231


Burada AllRead' in anlam tm Entity nesneleri zerinde her eit veri okuma(Read) ileminin
yaplabileceidir. Bir baka deyile EntitySetRights enum sabitinin deerleri ile,
hangiEntity objelerine hangi haklarla eriebilecei belirtilmektedir. Sz gelimi aadaki kod
rneini ele alalm.

config.SetEntitySetAccessRule("Product", EntitySetRights.AllRead);
config.SetEntitySetAccessRule("ProductSubcategory", EntitySetRights.AllWrite);

Bu ifadelere gre Product nesneleri iin sadece okuma ilemi


yaplabilirken, ProductSubcategory nesneleri iinde sadece yazma ilemleri yaplabilmektedir.
Artk herhangibir istemci yazmadan, ProductService.svc servisi test edilebilir. Nitekim hepimizin
itahnn kabarm olduunu ve bir an nce sonular grmek istediinizi hissetmekteyim. yleyse
gelin F5 ile projemizi altralm. Uygulama ilk altrldnda ProductService.svc dosyas
tarayc pencere ierisinde aadaki gibi grnecektir.

Buradan kartlmas gereken ilk sonu Product ve ProductSubcategory elementleri iin


taleplerde bulunulabileceidir. yleyse test sorgularna balanabilir. Sorgulardan kastmz

www.bsenyurt.com Page 232


elbetteki URL satrna girilen QueryString ifadeleri ve bunlarn ATOM tabanl XML ktlarnn nasl
olacadr.

rnek 1 ;
Tm ProductSubcategory satrlarnn elde edilmesi

URL Satr ifadesi :


http://localhost:3030/AdventureServices/ProductService.svc/ProductSubcategory

(Burada hemen bir hatrlatma yapalm.


Eer URL satrnda ProductSubcategory yerine ProductSubCategory yazlrsa Case-
Sensitive zelliinden dolay HTTP 404 Not Foundkts alnr. Dolaysyla QueryString' leri
yazarken Case-Sensitive olmalarna dikkat etmek gerekir.)

Sonu Ekran grnts ;

rnek 2 : 3 Numaral ProductSubcategory bilgisinin elde edilmesi

URL Satr ifadesi :


http://localhost:3030/AdventureServices/ProductService.svc/ProductSubcategory(3)

www.bsenyurt.com Page 233


Sonu Ekran grnts ;

Not : kinci rnekte dikkat edilmesi gereken bir nokta vardr. URL satrnda parantez ierisinde 3
deeri yazlarak ProductSubCategoryID deeri 3 olan alt kategori bilgisi elde edilmitir. Pekiya
servis tarafndan nasl olmaktadrda, parantez ierisindeki deerin ProductSubCategoryID alanna
iaret ettii bilinmektedir. Burada anahtar noktaProductSubcategory snfndaki
ProductSubCategoryID zelliidir.

www.bsenyurt.com Page 234


ekildende grlecei zere EdmScalarPropertyAttribute niteliinin
ierisinde EntityKeyProperty zelliine true deeri verilmitir. Bylece alma zaman, parantez
ierisinde gelen ifadenin bu zellie ait olduunu bilmektedir.

rnek 3 : Product tablosundan ListPrice deeri 3500 birim zerinde olanlarn elde
edilmesi

URL Satr ifadesi :


http://localhost:3030/AdventureServices/ProductService.svc/Product?$filter=ListPrice
gt 3500
(Burada gt=grater then anlamndadr.Buna gre kktr iin lt=less then)

Sonu Ekran grnts ;

rnek 4 : ProductSubcategoryID deeri 1 olan alt kategoriye bal rnlerin listesinin


elde edilmesi

URL Satr ifadesi :

www.bsenyurt.com Page 235


http://localhost:3030/AdventureServices/ProductService.svc/ProductSubcategory(1)/
Product

Sonu Ekran grnts ;

rnek 5 : Product tablosundan ListPrice deeri 3500 birim zerinde olanlarn isimlerine
gre ters srada elde edilmesi

URL Satr ifadesi :


http://localhost:3030/AdventureServices/ProductService.svc/Product?$filter=ListPrice
gt 3500&$orderby Name desc
(ki ayr sorgu ifadesi birletirilirken & kullanlr)

Sonu Ekran grnts ;

www.bsenyurt.com Page 236


rnek 6 : ProductSubCategoryID deeri 4 olan alt kategorinin bilgilerinin elde edilmesi
ve buna bal rnlerinde getirilmesi

URL Satr ifadesi :


http://localhost:3030/AdventureServices/ProductService.svc/ProductSubcategory(4)?$
expand=Product

Sonu Ekran grnts ;

Dikkat edilecei zere inline elementi altnda 4 numaral alt kategoriyi bal Product rneklerinin
entry boumlar yer almaktadr. Service taraf gz nne alndnda expand komutunun
kullanlabilmesini salayan yenin ProductSubcategory snfndaki Product zellii olduuna dikkat
etmek gerekir.

www.bsenyurt.com Page 237


Buraya kadar anlatklarmz umarm sizlere Ado.Net Data Services hakknda biraz fikir
verebilmitir. Eer buraya kadar makaleyi zevkle okuduysanz ite size yapmanz gereken bir ka
dev. ncelikli olarak tarayc uygulama zerinden sorgu gnderdiinizde SQL tarafnda nasl
komutlar altrldna bakmanz neririm. Kod tarafnda ilgili noktalara breakpoint' ler ekleyerek
nesnelerin ne zaman rneklendiklerine(REST sorgusu SQL sorgusuna dntrlmeden ncemi,
sonra m gibi) bakmanz neririm. Baka ne eit sorgular yazabileceinizi filter, orderby,
expand, () dnda ne gibi query komutlar olabileceini aratrn. Bu aratrmalarda baar ile
yaparsanz yle gzel bir stl nescafe' yi deniz kenarnda yudumlamay hak etmisiniz demektir,
stelik gne batarken.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde ksaca Ado.Net Data
Services(Astoria) konusuna deinmeye altk. zet olarak, ADO.Net EDM(Entity Data
Model) veyaLINQ Provider seeneklerini kullanaraktan, verilerin REST(REpresentational State
Transfer) modele uygun bir servis zerinden yaynlanabileceini grdk. Bu makalemizde
herhangibir istemci uygulama gelitirmemi olmamza ramen, sonular deerlendirmek adna bir
tarayc uygulama kullandmz unutmayalm. Nitekim tarayc uygulamalarda hangi eitten

www.bsenyurt.com Page 238


olurlarsa olsunlar potansiyel olarak birer servis istemcisidir. Elbette ilerleyen makalelerimizde
istemci uygulamalarn nasl gelitirilebileceinede deinebileceimizi belirtmek isterim. Ado.Net
Data Service ler ile ilikili yaz dizimizin bu ilk blmne ait grsel bir derside .Net TV den de
izleyebilirsiniz. Bununla birlikte Ado.Net Data Services ile ilikili blog bilgilerine Microsoft'
un u adresinden ulaabilirsiniz. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnei indirmek iin tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

WPF Temeller : Layout Kavram ( 11.08.2008 ) -


WPF
Deerli Okurlarm Merhabalar,

Uzun sredir ara verdiimiz makalelerimize kaldmz yerden devam ediyoruz. Bu makalemizde
ok basit seviyede Windows Presentation Foundation uygulamalarnn temellerinden birisi
olan Layout kavramn inceleme alyor olacaz. WPF uygulamalarnda kullanlan ekranlara ait
element veya kontrollerin mutlaka bir Layout bileeni ierisinde konulandrlm olmalar
gerekmektedir. Layout bileenleri temelde birer Panel olarak dnlmelidir. Bu adan
bakldnda klasik Windows programclnda yer alan(dier kontrolleri zerinden
tayan) Container bileenlerinede benzetilebilirler. WPF uygulamalarnda kullanlabilecek
olan 6 adet temel Layout bileeni bulunmaktadr. Herbirinin kendine zg ekilde elementleri
gsterme ve yerletirme seenekleri vardr. Bu bileenlerin en nemli ortak zellii
ise Panel isimli abstract snftan(Class) tremi(Inherit)olmalardr. Aadaki snf
emasnda(Class Diagram) sz konusu bileenler ve Panel ile aralarnda tretimsel iliki ak bir
ekilde grlebilmektedir.

Layout bileenlerinin tamam, System.Windows.Controls isim alan(namespace)


altnda yer almaktadr. Bu isim alan ise, WPF Managed API katmannda yer
alanPresentationFramework.dll assembly' nn bir parasdr.
Bu assembly ierisinde Layout bileeni dnda st seviye kontrolleri, style' ler vb...
bileenlerde yer almaktadr. Bilindii
zere WPF mimarisinde Managed API katmannda PresentationCore.dll ve WindowsB
ase.dll assembly' larda yer almaktadr.

www.bsenyurt.com Page 239


Canvas bileeni, zerine braklan elementlerin pencerenin sol(Left), sa(Right), st(Top) ve
alt(Bottom) eksenlerine olan uzaklklarna gre bir yerleim planna imkan
tanmaktadr. DockPanel bileeni, elementlerin tm alan kaplayacak ekilde sola, saa, ste, alta
ve geri kalan boluklara(Fill) yanatrlarak yerletirilmelerine izin
vermektedir.StackPanel bileeni varsaylan olarak elementleri alt alta dizen bir yerleim
sunmaktadr. Ancak istenirse elementleri yatay eksende(Horizontal) yan yana olacak biimde
yerletirilebilmelerine de izin vermektedir. WrapPanel bileeni, dikey veya yatay dzlemde
elemanlar birbirlerine bititirerek sralarken ekrann sonlanmas gibi durumlar otomatik hesap edip
gerekli kaydrmalarn yaplmasna olanak tanmaktadr(Kark gelen bu tasvir, ilerleyen
ksmlardaki kodlar ile daha net bir ekilde grlebilecektir). Grid bileeni, hcreleri, satr ve
stunlar kullanarak kontrollerin yerleimlerinin gerekletirilmesini salamaktadr. Son
olarak UniformGrid kontrol ise sabit boyuttaki hcreleri kullanarak bileenlerin ok kolay ve hzl
bir biimde yerletirilebilmelerini salamaktadr.

Dikkat edilecei zere tm Layout bileenleri Abstract Panel snfndan tremektedir.


Buda, gelitirici tanml tayc Layout kontrollerinin yazlabilecei anlamna gelmektedir.
Bilindii zere abstract snflar, kendisinden treyen tiplerin uymas ve ezmesi art olan
ye bildirimlerini iermekte olup dorudan rneklenerek kullanlamayan tiplerdir. Ayrca
abstract snflar polimorfik ekilde davran gsterebilirler. Buda Plug-In tabanl
mimarilerde nem arz eden bir konudur.

Bu ksa teorik bilgilerden sonra rnekler zerinden ilerleyerek Layout bileenlerini kavramakta
yarar olaca kansndaym.

www.bsenyurt.com Page 240


WrapPanel;

lk olarak WrapPanel ile balayalm. rnek bir WPF uygulamasnda yer alan Window snfna
ait XAML(eXtensible Application Markup Language) ieriini aadaki gibi gelitirdiimizi
dnelim. (Makalede yer alan rnekler Visual Studio 2008 Professional zerinde
gelitirilmektedir.)

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<WrapPanel Orientation="Horizontal">
<Button Name="Button1" Content="Giri"/>
<Button Name="Button2" Content="Kaydet"/>
<Button Name="Button3" Content="Hesapla"/>
<Button Name="Button4" Content="Kullanc Deitir"/>
<Button Name="Button5" Content="Detaylar Al"/>
<Button Name="Button6" Content="Ykle"/>
<Button Name="Button7" Content="Bellei Sil"/>
</WrapPanel>
</Window>

Sz konusu Window1 penceresinin tasarm zamanndaki ekran grnts aadaki gibi olacaktr.

Dikkat edilecei zere WrapPanel ierisinde yer alan rnek Button kontrolleri, ekrann boyutuna
gre otomatik olarak aaya kaydrlmaktadr. WrapPanel bileenine aitOrientation zelliinin
varsaylan deeri Horizontal' dr. Bu sebepten ak bir ekilde belirtilmesine gerek
yoktur. Ancak elementlerin(kontrollerin) dikey dzlemde kaydrlmasn
istiyorsak, Orientation zelliine Vertical deerinin verilmesi gerekir. Vertical deeri set
edildikten sonra tasarm zamannda aadaki sonu elde edilir.

www.bsenyurt.com Page 241


Elbetteki alma zamannda ekran boyutlar ile oynanlmas halinde dmelerin yerleimleride
buna gre deiiklik gsterecektir. rnein boyut ile alma zamannda oynandktan sonraki olas
hal aadaki ekran grntsne benzer olacak ekilde elde edilebilir.

DockPanel;

Windows ile programlama yapan herkes zellikle Visual Studio ortamnda


kontrollerin tayclar(Container) ierisindeki yerlerini belirlemede
kullanlan Dock zelliini(Property)bilir. DockPanel bu yaklam uygulacak ekilde
almaktadr. te buna rnek olacak bir XAML kts.

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<DockPanel>
<Button DockPanel.Dock="Top">st Taraf</Button>
<Button DockPanel.Dock="Left">Sol Taraf........</Button>
<Button DockPanel.Dock="Right">Sa Taraf</Button>
<Button DockPanel.Dock="Bottom">Alt Taraf</Button>
<Button>Kalan Ksmlar</Button>
</DockPanel>
</Window>

Burada en nemli nokta ilitirilmi zellik(Attached Property) kullanlarak ilgili


elementin DockPanel taycsnn hangi blgesine yanatrlacann belirlenmesidir. Sz
gelimi DockPanel.Dock zelliine Top deeri verilmesi
ile Button elementinin DockPanel bileeninin st tarafna yanatrlaca belirtilmektedir. lgin
olan noktalardan biriside son Button kontrol iin byle bir zellik tanmlamas yaplmam
olmasdr. Bu ok doal olarak kalan ksm dolduracak bir kontrol yerleimine neden
olmaktadr.Window1' in tasarm zamanndaki grnts aadaki gibi olacaktr.

StackPanel;

StackPanel bileeni makalenin bandada deinildii gibi ierisindeki elementleri eklendii sra ile
yatay veya dikey dzlemde dizerek gstermektedir. Varsaylan olarak tm bileeneleri yukardan
aadaki doru dizmektedir. Hemen aadaki XAML ieriini gz nne alalm.

www.bsenyurt.com Page 242


<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<StackPanel Background="Gold">
<Button x:Name="Button1" Content="Button1" Margin="3,5"
HorizontalAlignment="Left" />
<CheckBox Content="alyor mu?" IsChecked="True"/>
<TextBlock Text="Yaad ehir" VerticalAlignment="Bottom"
HorizontalAlignment="Center"/>
<ComboBox>
<ComboBoxItem Content="stanbul" Foreground="Brown"/>
<ComboBoxItem Content="zmir" Foreground="Red"/>
<ComboBoxItem Content="Ankara" Foreground="Blue"/>
<ComboBoxItem Content="Antalya" Foreground="Goldenrod"/>
</ComboBox>
<Button Content="BilgleriOnayla" x:Name="Button2"/>
</StackPanel>
</Window>

Bu ierikte dikkat edilecei zere Button, CheckBox, TextBlock, ComboBox gibi deiik tipte
bileenler kullanlmaktadr. Normal artlarda StackPanel ierisindeki tm bileenler
kullanabildikleri tm alan kaplarlar. Bu sebepten ComboBox ve BilgileriOnayla
balkl Button kontrolnn yatayda tm alan kapladklar grlr. Ancak
buradaVerticalAlignment, HorizontalAlignment, Width, Height, Margin gibi zellikler ile
oynanarak, kontrollerin boyutlar ve StackPanel ierisinde kaplayacaklar alanlar deitirilebilir.
Sz gelimi Button1 isimli dmede Margin deeri 3,5 olarak verilmitir. Yani sol
st(Left,Top) kenar uzaklklar 3 ile 5 piksel olarak belirlenmitir. Buna ek
olarak HorizontalAlignmentdeerinin Left verilmesi ile Button kontrolnn sol tarafa yakn
kmas ama st taraftan 5, sol taraftan ise 3 piksel uzaklkta durmas salanmtr. Benzer bir
konumlandrma ilemide TextBlock bileeni
zerinden VerticalAlignment ve HorizontalAlignment zelliklerine ilgili deerler atanarak
gerekletirilmektedir. Bunlara gre tasarm zamanndaki ekran grnts aadaki gibi olacaktr.

Eer StackPanel bileeninin Orientation zelliine Horizontal deeri atanrsa sonu aadaki
gibi olacaktr.

www.bsenyurt.com Page 243


Bu kez grlecei zere tm elementler yan yana dizilmektedir. Elbetteki yerleimler biraz
tuhaflamtr ve bunlarn ilgili zellikler yardmyla dzenlenmesi gereklidir.

UniformGrid;

Belkide Grid tipinden tayclardan en kolay kullanma sahip olandr. Nitekim


gelitiricinin hcreleri(Cell), satr(Row) veya stun(Column) zelliklerini dnmesine gerek
yoktur. UniformGrid bileeninde ieriye eklenen elementlere gre hcrelerin boyutlar, satr ve
stun saylar sabitlenmektedir. Sz gelimi aadaki XAML ieriini gz nne alalm.

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<UniformGrid>
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>7</Button>
<Button>8</Button>
</UniformGrid>
</Window>

UniformGrid bileeni ierisine 8 adet Button kontrol eklenmitir. Bu satr ve stun saylar
otomatik olarak belirlendiine gre 3X3' lk bir zgara anlamna gelmektedir. Malum son hcre bo
kalacaktr. te rnek XAML ieriine ait tasarm zaman grnts;

www.bsenyurt.com Page 244


Ancak tabikide kolon(Column) veya satr(Row) saylar ile oynanabilir yada ierideki
elementlerin hcre ierisinde bulunduklar konumlar deitirilebilir. Bu durumu daha iyi analiz
etmek iin aadaki XAML ierii gz nne alnabilir.

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<UniformGrid Columns="4">
<Button Margin="5">1</Button>
<Button Background="RosyBrown" Margin="10,15">2</Button>
<Button>X</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>7</Button>
<Button Foreground="Gold" Background="Black" BorderBrush="Brown"
BorderThickness="2" Margin="7.5">8</Button>
</UniformGrid>
</Window>

Burada grld gibi UniformGrid bileeninin, ierisindeki kontrolleri 4 stundan oluan bir
zgara ierisinde gsterecei Columns isimli zellie atanan deer ile belirlenmektedir. Dier
taraftan baz Button kontrollerinin Margin zellikleri ile oynanarak hcre ierisindeki kenar
boluklarna ait miktarlarda belirlenmektedir. Sz gelimi ilk dme hcrenin tm
kenarlarna 5 piksel uzaklkta olacaktr. Dier taraftan 2 yazl Button bileeni sol tarafa 10 piksel,
hcrenin st tarafna ise 15 piksel uzaklkta olacak ekilde yer kaplayacaktr. Sonu olarak tasarm
zamanndaki ekran kts aadaki gibi olacaktr.

Grid;

www.bsenyurt.com Page 245


Grid bileeninde satrlar ve stunlar gelitirici tarafndan daha detayl bir ekilde ayarlanr. Bu da
sz konusu zgara zerinde ok daha fazla gelitirici kontrol olaca anlamna
gelmektedir. Grid bileeni ierisinde yer alacak elementlerin hangi hcrelere geleceini belirlemek
iin yine Attached Property tekniinden yararlanlmaktadr. Buna
gre Rowve Column zelliklerine atanan deerler ile yerleim hcresi belirlenir. Bu zelliklerin
varsaylan deeri 0' dr. Buna gre kontrol ilk hcreye atanr. Grid kontrolnn hcreleri zerine
Border kullanmda gerekletirilebilir. Grid kontrolne ait rnek bir kullanm
aadaki XAML ieriinde olduu gibi gz nne alnabilir.

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<Grid ShowGridLines="True">
<Grid.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="AliceBlue" Offset="0.50"/>
<GradientStop Color="Gold" Offset="1"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Grid.Background>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="25"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Background="BlueViolet" BorderThickness="2" Grid.Row="2"
BorderBrush="Red" Margin="4" Grid.ColumnSpan="2"/>
<TextBlock Text="No" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
<TextBlock Text="Ad" VerticalAlignment="Bottom" HorizontalAlignment="Right"
Grid.Row="0" Grid.Column="1"/>
<TextBlock Text="Yorum" VerticalAlignment="Bottom"
HorizontalAlignment="Right" Grid.Row="0" Grid.Column="2"/>
<Rectangle Fill="RosyBrown" Grid.Row="1" Grid.ColumnSpan="3" Height="3"/>
<TextBlock Text="10" VerticalAlignment="Center" HorizontalAlignment="Center"
FontWeight="Bold" Foreground="White" Grid.Row="2"/>
<TextBlock Text="Burak Selim
enyurt" TextWrapping="Wrap" VerticalAlignment="Center" HorizontalAlignment="Center"
FontWeight="Bold" Foreground="White" Grid.Row="2" Grid.Column="1"/>
</Grid>
</Window>

lk olarak Grid kontrolnn arka plan


dolgusu(Background) LinearGradientBrush kullanlarak AliceBlue renginden Gold rengine
deiecek ekilde belirlenmitir. Grid ierisindeki satrlar belirlemek
iin RowDefinitions(RowDefinitionCollection tipinden), stunlar belirlemek
iinse ColumnDefinitions(ColumnDefinitionCollection tipinden) koleksiyonlar kullanlr.
Satrlar RowDefinition elementi ile tanmlanrken, stunlar ColumnDefinition ile
tanmlanmaktadr. Satrlar iin ykselik deeri Height zellii ile, stunlar iin genilik
deeri Width zellii ile belirlenir. Dikkat ekici noktalardan

www.bsenyurt.com Page 246


biriside Auto ve * kullanmdr. Auto ifadesine gre ykseklik veya genilik deeri ierideki
elementin boyutuna gre otomatik olarak ayarlanr. Dier taraftan *, "kalan tm mesafeyi kullan"
anlamnda dnlebilir. rnein pencerenin genilii 250 pikseldir. lk stun 25, ikinci stun
ise 50olarak belirlenmektedir. Geriye kalan 175 piksel ise nc stuna * iareti ile
braklmaktadr. Grid ierisinde
kullanlan Rectangle elementinden Grid.ColumnSpan zelliine 3deeri verilmitir. Buna
gre Rectangle elementinin bulunduu 1nci satrdaki 3 hcre birletirilmektedir.
Yine VerticalAlignment ve HorizontalAlignment zelliklerine atanan deerler kullanlarak
kontroln hcre ierisindeki konumu belirlenebilir. Grid kontrol ile ilikili ilgin elementlerden
biriside Border bileenidir. rnekte kullanlan Border elementi Grid bileeninin 2nci satrda yer
alan ilk iki hcresine(Grid.ColumnSpan=2 nedeniyle) uygulanmaktadr. Sonu
itibariyle Grid bileeninin alma zamannda verdii ekran kts aadaki gibi olacaktr.

Canvas;

Son olarak Canvas bileenine bir gz atalm. Bu kontrolde bileenlerin konumlarn belirlemek
iin Top, Lef, Right veya Bottom gibi zelliklerden yararlanlmaktadr. Varsaylan olarak bu
deerler belirtilmedii takdirde bileen 0,0 noktasna konumlandrlmaktadr. Bir baka
deyile Canvas bileeninin sol st kesine yanatrlmaktadr. Canvas bileeni iin rnek olarak
aadaki XAML ierii gz nne alnabilir.

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="150"
Width="250">
<Canvas Background="LightGray">
<Button x:Name="Button1" Content="Button 1"/>
<Button x:Name="Button2" Content="Button 2" Canvas.Left="100"
Canvas.Top="50" />
<Button x:Name="Button3" Content="Button 3" Canvas.Right="100"
Canvas.Bottom="50" />
</Canvas>
</Window>

Dikkat edilecei zere Button1 iin herhangibir konum deeri belirtilmemitir. Button2 iin
ise Left ve Top zellikleri kullanlarak konumlandrma yaplmaktadr. Son Button iin
iseRight ve Bottom zellikleri kullanlmaktadr. Yine dikkat edilmesi gereken noktalardan
birisi Attached Property kullanlm olmasdr. (Bylece ilgili element ierisinde, dahil olduu
elemente ait zelliklere nokta notasyonu ile eriilebilmektedir.) Tasarm zamanndaki ekran
grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 247


Dikkat edilmesi gereken noktalardan biriside Button3' n element srasna gre Button2' nin
stnde km olmasdr. Bu son derece doaldr. Ama istenirse Button2' nin nde durmasda
salanabilir. Bunun iin Panel snfnn ZIndex zellii kullanlmaktadr. Sz gelimi
yukardaki XAML ierii aadaki gibi deitirilebilir.

Dikkat edilecei zere Button2 iin Panel.ZIndex deeri 1 olarak set edilmitir. Buna gre
Button2 element srasna baklmakszn en ne gelmitir.

Buraya kadar gelitirilen basit rnekler ile WPF uygulamalarnda kullanlabilecek


temek Layout bileenleri incelenmeye allmtr. Bu Layout bileenlerinin ihtiyalar
karlamamas halinde ise istenirse Panel abstract snfndan tretme yoluna gidilerek farkl bir
bileenin retilmesi salanabilir. Window bileenleri kendi ilerinde sadece tek
bir Paneltayabilirler. Bir baka deyile iki Layout kontroln Window elementi altnda ayn

www.bsenyurt.com Page 248


seviyede kullanamayz. Ancak bu kstlama, Layout ierisinde Layout kullanlmasn engellemez.
Nitekim ou durumda bir Layout bileeni ierisinde farkl bir Layout bileeni kullanlmas
gerekebilir. Sz gelimi aadaki rnek XAML ieriinde bu durum gsterilmeye allmaktadr.

<Window x:Class="Layouts.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Layout kullanm" Height="250"
Width="250" Loaded="Window_Loaded">
<Grid Background="Gold" ShowGridLines="True">
<Grid.RowDefinitions>
<RowDefinition Height="100"/>
<RowDefinition Height="*"/> <!-- kinci satr kalan tm ksm kaplayacaktr-->
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="75"/>
<ColumnDefinition Width="*"/> <!-- kinci stun kalan tm ksm kaplayacaktr-->
</Grid.ColumnDefinitions>
<Button Content="Gnder" Height="40" Margin="5,0,10,0"/> <!-- Sola 5, saa 10 piksel
uzaklkta olacaktr-->
<StackPanel Grid.Row="1" Grid.ColumnSpan="2" Background="AliceBlue"
Margin="5"> <!-- kinci satrdaki iki stun birletirilir. StackPanel bu blme eklenir.-->
<TextBlock Text="Mesajnz Yaznz"/>
<TextBox Text="" Width="100" HorizontalAlignment="Right" TextWrapping="Wrap"
Height="75" ScrollViewer.VerticalScrollBarVisibility="Visible" Margin="0,0,10,0"/> <!-- Sadan 10
piksel uzaklkta, 100 piksel geniliinde yatay olarak saa yaslanm Wrap zellii ak, 75 piksel
yksekliinde ve dikey kaydrma ubuu grnr olan TextBox-->
</StackPanel>
<UniformGrid Grid.Column="1" Margin="2"> <!-- Bu UniformGrid 1nci stun ierisinde
yer almaktadr.-->
<Button>1</Button>
<Button>2</Button>
<Button>3</Button>
<Button>4</Button>
<Button>5</Button>
<Button>6</Button>
<Button>7</Button>
<Button>8</Button>
<Button>9</Button>
<Button>0</Button>
</UniformGrid>
</Grid>
</Window>

rnek XAML ieriine ait tasarm zaman ekran kts aadaki gibi olacaktr.

www.bsenyurt.com Page 249


Elbetteki Layout bileenlerinin dinamik olarak kod ierisinde ele alnmasda mmkndr.
Senaryonun karmaklna gre Visual Studio 2008 IDE' si kullanlarak Layout' larn ve
ieriklerinin tasarlanmasnda ok daha iyi sonular alnabilir. Hatta Expression ailesindeki
rnlerden yararlanlarak bu grsel bileenlerin profesyonel grnmlere sahip olarak rnsel
nitelikte olmasda daha rahat bir ekilde salanabilir. Ancak bunlarn ncesinde XAML tarafnda
ilgili bileenlerin bu makalede olduu gibi nasl kullanlabileceinin bilinmesinde yarar vardr.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Seriletirme lemlerinde Vekil(Surrogate)


Kullanmak ( 03.07.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde WCF(Windows Communication Foundation) mimarisinde veri


szlemelerinin(Data Contracts) kar taraflarda farkl versiyonlarnn olmas durumunda oluan
vakalar incelemeye almtk. Versiyonlama(Versioning) vakalar dnda seriletirmede nem
arz eden konulardan biriside, servis tarafnda yaynlanan veri szlemeleri ierisinde
seriletirilemeyen(NotSerializable) tiplerin var olmasdr. Bu durum ounlukla, serietirilebilen tipin
kulland baz dahili tiplerin farkl assembly dosyalar ierisinde yer ald vakalarda ortaya
kmaktadr. yleki, dier assembly ierisinde yer alan tipe(type) gelitirici tarafndan mdahale
edilemeyebilir ve bu sebepten seriletirilebilmesi iin DataContract veya DataMemberyeleri
uygulanamayabilir. Bu durum aadaki ekilde rnek bir senaryo zerinden ifade edilmeye
allmaktadr.

www.bsenyurt.com Page 250


Dikkat edilecei zere Urun snf bir veri szlemesi(Data Contract) olacak
ekilde, ServiceLibrary.dll assembly dosyas ierisinde yer almaktadr. Sz konusu snfn
yelerinden Ureten isimlizellik(Property) Uretici snf tipindendir. Ne
varki Uretici snf, Ureticiler.dll assembly dosyas ierisinde yer almaktadr ve seriletirilebilir bir
tip deildir(NotSerializable). Bu sebepten dolayUrun snfnn kullanld bir senaryoda istemci
asndan sorunlar oluacaktr. rnein tipin istemci iin gerekli proxy retimi srasnda metadata
ierisine gmlmesi mmkn olamayacaktr. zm olarak servis
tarafnda seriletirme(Serializing) ve ters-seriletirme(DeSerializing), ema
kartma(Schema Exporting) veya dahil etme(Schema Importing) ilemleri srasnda
mdahalede bulunmak gerekmektedir. Ama nasl?

Seriletirilemeyen tipler servis tarafndan istemcilere Metadata bilgileri ierisinde


gnderilemezler. Bu sebepten dolay istemci iin nem arz eden proxy nesneleri ierisine
konulamazlar ki buda sz konusu tiplerin istemci tarafndan ele alnp kullanlamayaca
anlamna gelir.

Bu noktada bir vekil(Surrogate) snf kullanlma yolu tercih edilir. Vekil snf seriletirilebilir
olmakla birlikte, seriletirilemeyen snfn yelerini tayacak ekilde tasarlanr. Daha sonra
serileen ve serileemeyen snflar arasnda kpr grevi stelenecek ek bir snf daha tasarlanr.
Bu ek snfn grevi seriletirme, ters-seriletirme, ema import ve export ilemleri srasnda,
seriletirilemeyen snf ile eletirme yaplmasn salamaktr. Bu
snf, IDataContractSurrogate arayzn(Interface) uygulayacak ekilde tanmlanr. Buna ek
olarak WCF alma ortamna, seriletirme, tersseriletirme, ema yaynlamak gibi ilemler
srasnda devreye girecek olan IDataContractSurrogate uyarlamal
tipin, davran(behavior) olarak atanmas gerekmektedir ki bu ilemlerde
ounlukla nitelik(attribute) olarak kullanlabilecek bir snf ierisinde ele alnr. :) Bu karmak
srecin adm adm incelenmesinden nce, yukardaki senaryodaki gibi bir durum olumas halinde
alma zamannda neler olacan irdelemekle balamakta yarar vardr. Bu amala ilk
olarak Uretciler.dll isimli assembly, Uretici snfn ierecek ekilde aadaki gibi tasarlanr.

www.bsenyurt.com Page 251


using System;

namespace Ureticiler
{
public class Uretici
{
public int Id { get; set; }
public string Ad { get; set; }
public string Adres { get; set; }
public Uretici(int id,string ad,string adres)
{
Id = id;
Ad = ad;
Adres = adres;
}
}
}

Uretici snf ierisinde yer alan ar yklenmi yapc metod(Overloaded Constructor) nedeni
ile, varsaylan yapc metod(Default Constructor) geersiz kalmaktadr. Buda tipin
seriletirilmesini engelleyecek ve istenilen sorunun olumasna neden olacaktr. Servis
szlemesi(Service Contract), uygulayc snf ve veri szlemesini(Data
Contract) ieren WCF Servisktphanesi(WCF Service Library) ierii ise aadaki
gibidir. (Servis ktphanesinin, Ureticiler.dll assembly dosyasn referans etmesi gerektii
unutulmamaldr.)

www.bsenyurt.com Page 252


Urun snf ierii;

using System;
using System.Runtime.Serialization;

namespace UrunYonetim
{
[DataContract(Name="Urun")]
public class Urun
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Ad { get; set; }
[DataMember]
public double BirimFiyat { get; set; }
[DataMember]
public int StokMiktari { get; set; }
[DataMember]
public Ureticiler.Uretici Ureten { get; set; }
}
}

Urun snf ierisinde yer alan Ureten zelliinin(Property), Uretici tipinden olduuna ve
seriletirilemediine dikkat edilmelidir.

IUrunYonetici arayz ierii;

using System;
using System.ServiceModel;

namespace UrunYonetim
{

www.bsenyurt.com Page 253


[ServiceContract(Name="UrunServisi",Namespace="http://www.bsenyurt.com/Urun
Servisi")]
public interface IUrunYonetici
{
[OperationContract]
void UrunEkle(Urun urun);

[OperationContract]
Urun UrunGuncelle(Urun urun);
}
}

IUrunYonetici arayz ierisinde iki adet operasyon tanmlanmtr. UrunEkle metodu,


parametre olarak Urun tipinden bir nesne rnei alr. UrunGuncelle metodu ise parametre olarak
alnanUrun zerinden bir takm gncellemeler yaplmasn ve geriye dndrlmesini salamak
zere tanmlanmtr. Dikkat edilecei zere her iki operasyonda Urun isimli veri szlemesini
kullanmaktadr.

UrunYonetici snf ierii;

using System;

namespace UrunYonetim
{
public class UrunYonetici
:IUrunYonetici
{
#region IUrunYonetici Members

public void UrunEkle(Urun urun)


{
String bilgi = String.Format("{0} numaral {1} rn eklenmitir", urun.Id, urun.Ad);
Console.WriteLine(bilgi);
}

public Urun UrunGuncelle(Urun urun)


{
urun.Ureten = new Ureticiler.Uretici(1, "Adventure Vendor", "Adventure yolu
zeri");
urun.StokMiktari += 10;
urun.BirimFiyat += 1.1;
return urun;
}

#endregion
}
}

Servis tarafndaki uygulama yine olaylarn basit bir ekile anlalabilmesi iin Console projesi
eklinde tasarlanmaktadr. Servis uygulamasna ait konfigurasyon dosyas ve kod ierii
balangta aadaki gibidir.(Servis
uygulamasnn System.ServiceModel.dll ile UrunYonetim.dll assembly dosyalarn referans
etmesi gerektii unutulmamaldr.)

Konfigurasyon(App.config) ierii;

www.bsenyurt.com Page 254


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UrunServisiBehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="UrunServisiBehavior"
name="UrunYonetim.UrunYonetici">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
name="UrunServisiTcpEndPoint" contract="UrunYonetim.IUrunYonetici" />
<endpoint address="Mex" binding="mexTcpBinding" bindingConfiguration=""
name="UrunServisiMexEndPoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:2501/UrunServisi" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

rnekte TCP bazl bir EndPoint kullanlmaktadr. Bununla birlikte istemci iin gerekli
olan Proxy snfnn kolay retilebilmesi amacyla yine TCP bazl
bir MexEndPoint kullanlmaktadr.

Servis taraf Program ierii;

using System;
using System.ServiceModel;
using UrunYonetim;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(UrunYonetici));
host.Open();
Console.WriteLine(host.State);
Console.WriteLine("Kapatmak iin bir tua basn");
Console.ReadLine();
host.Close();
}
}
}

www.bsenyurt.com Page 255


stemci uygulama iin gerekli olan proxy snf ve konfigurasyon dosyas
ierii MEX EndPoint kullanm nedeni ile svcutil arac veya Visual Studio->Add Service
Reference yardmyla ekilebilir. Tabi bu ilemler srasnda servis uygulamasnn alyor olmasna
dikkat edilmelidir. Ne varki, sz gelimi svcutil arac ile ilgili servis zerinden metadata bilgisi
ekilmek istendiinde aadaki ekran grnts ile karlalr.

Her ne kadar hata mesaj ok ak olmasada ve tutarl bir bilgi vermesede sorun, Uretici snfnn
seriletirilemiyor olmasndan kaynaklanmaktadr. Bu sebepten istemci tarafna aktarlacak
olanMetadata bilgisi kesilmitir. Nitekim seriletirilemeyen bir tipin, istemci
tarafna export edilecek olan ema(Schema) ieriine dahil edilmesi mmkn deildir. te sorun
burada balamaktadr. zm ise ilerleyen admlarda ele alnacaktr. Blmn bandada belirtildii
gibi ilk olarak, seriletirilemeyen tipin yerine geecek bir vekil snf yazlmaldr ki bu
ounlukla Surrogate DataContract olarak anlr.

www.bsenyurt.com Page 256


Yukardaki ekle gre Uretici snf iin UreticiSurrogated isimli bir vekil tip tayin edilmitir. Bu
snfn kendisi bir veri szlemesi olacak ekilde tanmlanmtr. Burada en nemli nokta vekil tipin
seriletirilebilir olmasdr. UreticiSurrogated snf servis tarafnda aadaki gibi tasarlanabilir.

using System;
using System.Runtime.Serialization;

namespace UrunYonetim
{
[DataContract(Name="Vendor")] // Bilinli olaraktan Vendor ad verilmitir.
public class UreticiSurrogated
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Ad { get; set; }
[DataMember]
public string Adres { get; set; }
}
}

www.bsenyurt.com Page 257


Bu snf sadece ve sadece seriletirilemeyen Uretici snf yerine kullanlacak vekil tiptir. imdi
seriletirme, ters seriletirme, ema yaynlama gibi ilemler srasnda devreye girecek olan bir
snfn daha tasarlanmas gerekmektedir. Bu snfn en nemli zellii
ise IDataContractSurrogate arayzn(Interface) uyguluyor olmasdr. Bu arayze ait
metodlar yukarda bahsedilen ilemler srasnda devreye girmektedir. Sz konusu WCF servis
ktphanesi ierisinde aadaki gibi
tasarlanabilir.(IDataContractSurrogate arayznn(Interface) kullanlabilmesi
iinSystem.Runtime.Serialization.dll assembly dosyasnn projeye referans edilmesi
gerekmektedir.)

using System;
using System.Runtime.Serialization;
using Ureticiler;

namespace UrunYonetim
{
public class UreticiSurrogater
:IDataContractSurrogate
{
#region IDataContractSurrogate Members

public object GetCustomDataToExport(Type clrType, Type dataContractType)


{
return null;
}

public object GetCustomDataToExport(System.Reflection.MemberInfo memberInfo, Type


dataContractType)
{
return null;
}

// Bu metod seriletirme(Serialization), ters-seriletirme(DeSerialization), schema import ve


export ilemleri srasnda devreye girer.
// Serileemeyen tip ile Surrogate tip arasndakai eletirmeyi yapar.
// type isimli metod parametresi seriletirilmi, ters seriletirilmi, emas import veya export
edilmi tipi iaret etmektedir.
public Type GetDataContractType(Type type)
{
if (typeof(Uretici).IsAssignableFrom(type))

www.bsenyurt.com Page 258


return typeof(UreticiSurrogated);
return type;
}

// Bu metod surrogate tip rneinin orjinal tip rneine dntrlmesi srasnda kullanlr.
// Ters-seriletirme(Deserialization) ilemi srasnda alr.
public object GetDeserializedObject(object obj, Type targetType)
{
if (obj is UreticiSurrogated)
{
UreticiSurrogated surrogated = (UreticiSurrogated)obj;
Uretici uretici = new Uretici(surrogated.Id,surrogated.Ad,surrogated.Adres);
return uretici;
}
return obj;
}

public
void GetKnownCustomDataTypes(System.Collections.ObjectModel.Collection<Type>
customDataTypes)
{
}

// Orjinal tip rneini, surrogate tip rneine dntrmek iin kullanlr.


// Seriletirme ilemi iin bu metod gereklidir.
public object GetObjectToSerialize(object obj, Type targetType)
{
if (obj is Uretici)
{
Uretici uretici = (Uretici)obj;
UreticiSurrogated surrogated = new UreticiSurrogated();
surrogated.Ad = uretici.Ad;
surrogated.Id = uretici.Id;
surrogated.Adres = uretici.Adres;
return surrogated;
}
return obj;
}

// Schema import' u srasnda bu metod altrlr.


public Type GetReferencedTypeOnImport(string typeName, string typeNamespace, object
customData)
{
if (typeName == "UreticiSurrogated")
return typeof(Uretici);
return null;
}

public System.CodeDom.CodeTypeDeclaration
ProcessImportedType(System.CodeDom.CodeTypeDeclaration typeDeclaration,
System.CodeDom.CodeCompileUnit compileUnit)
{
throw new NotImplementedException();
}

#endregion

www.bsenyurt.com Page 259


}
}

Bu ilemin ardndan servis tarafnda davranlarn(Behavior) Surrogater tipine gre


zelletirilmesi ve Metadata Export ilemleri iin gerekli ek kodlamalarn yaplmas
gerekmektedir. lk olarakSurrogate implemantasyonunun nasl yaplaca ele alnmaldr. Bu
amala kod tarafnda aadaki admlar izlenmelidir.

lk olarak ServiceHost nesnesi zerinden tm ServiceEndPoint nesneleri dolalr.


Her bir ServiceEndpoint rnei ierisinden o andaki EndPoint bileenine
ait OperationDescription nesneleri bulunur.
Bulunan OperationDescription nesneleri
ierisinde DataContractSerializerOperationBehavior rnekleri Find metodu ile aranr.
Eer DataContractSerializerOperationBehavior rnekleri
bulunursa, DataContractSurrogate zelliine gelitirilen Surrogater nesne rnei atanr.
Bylece ilgili operasyon arsnda, orjinal tip ile Surrogate tipin eletirmelerini yapacak, bir
birleri arasnda seriletirme geilerini salayacak olan tip, WCF Runtime ortamna
bildirilmi olunur.
Opsiyonel olarak eer sz konusu davran
bulunamassa, DataContractSerializerOperationBehavior rneinin oluturulmas,
yine DataContractSurrogate zelliie ilgili atamann yaplmas ve bukez davrann ilgili
operasyona eklenmesi gerekmektedir.

Sz konusu admlara gre aadaki gibi bir kod paras gelitirilebilir.

using System;
using System.ServiceModel;
using System.ServiceModel.Description;
using UrunYonetim;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(UrunYonetici));
SurrogaterEkle(host);
host.Open();
Console.WriteLine(host.State);
Console.WriteLine("Kapatmak iin bir tua basn");
Console.ReadLine();
host.Close();
}

private static void SurrogaterEkle(ServiceHost host)


{
foreach (ServiceEndpoint endPoint in host.Description.Endpoints)
{
foreach (OperationDescription oprDesc in endPoint.Contract.Operations)
{
DataContractSerializerOperationBehavior dcBehavior =
(DataContractSerializerOperationBehavior)oprDesc.Behaviors.Find<DataContractSerializ
erOperationBehavior>();
if (oprDesc.Behaviors.Find<DataContractSerializerOperationBehavior>() !=

www.bsenyurt.com Page 260


null)
dcBehavior.DataContractSurrogate = new UreticiSurrogater();
}
}
}
}
}

Burada Servis uygulamas zerinde SurrogaterEkle metodu ile sz konusu ilemler


gerekletirilmektedir. Sunucu uygulama bu haliyle altrldnda
ve debug penceresinde ServiceHost nesnesiQuick Watch ile izlendiinde aadaki ekran
grnts yakalanabilir.

Bu ekran grntsnde, 0 indisli EndPoint zerinde tanml olan IUrunYonetici szlemesine


ait UrunEkle operasyonunun davranlarna dikkat edilmelidir. DataContractSerializer tipinden
olan davrann ierisinde yer alan DataContractSurrogate zelliinin
deerinin, UreticiSurrogater olarak set edilmi olduu ak bir ekilde grlmektedir.

Surrogate kullanmnda Microsoft tarafndan nerilen Best Practices ise, bu tip operasyon
davran atamalar ve ema export ilemleri iin zel olarak yazlm
bir niteliin(Attribute) kullanlmasn nermektedir. Yazda gelitirilen rnek dnld
takdirde bu niteliin servis szlemesinde(Service
Contract) kullanlmas, IContractBehavior, IOperationBehavior veIWsdlExportExtension ar

www.bsenyurt.com Page 261


ayzlerini uygulamas gerekmektedir. IContractBehavior ve IOperationBehavior arayzlerinin
baz yeleri kullanlarak yukardaki kod parasnda yaplan davran tanmlamalar
gerekletirilebilmektedir. Dier taraftan IWsdlExportExtension arayz ile gelen metodlar
sayesinde, Metadata yaynlamasnn Surrogate tipine gre yaplabilmesi salanabilmektedir. Sz
konusu nitelik aadaki gibi gelitirilebilir.

using System;
using System.Runtime.Serialization;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;

namespace UrunYonetim
{
public class SurrogaterAttribute
: Attribute
, IContractBehavior
, IOperationBehavior
, IWsdlExportExtension
{
#region IContractBehavior Members

public void AddBindingParameters(ContractDescription description, ServiceEndpoint endpoint,


BindingParameterCollection parameters)
{
}

public void ApplyClientBehavior(ContractDescription description, ServiceEndpoint


endpoint, System.ServiceModel.Dispatcher.ClientRuntime proxy)
{
foreach (OperationDescription oprDesc in description.Operations)
{
SurrogateUygula(oprDesc);
}
}

public void ApplyDispatchBehavior(ContractDescription description,


ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.DispatchRuntime dispatch)
{
foreach (OperationDescription oprDesc in description.Operations)

www.bsenyurt.com Page 262


{
SurrogateUygula(oprDesc);
}
}

public void Validate(ContractDescription description, ServiceEndpoint endpoint)


{
}

#endregion

#region IWsdlExportExtension Members

public void ExportContract(WsdlExporter exporter, WsdlContractConversionContext


context)
{
if (exporter == null)
throw new ArgumentNullException("exporter");

object dataContractExporter;
XsdDataContractExporter xsdDCExporter;
if (!exporter.State.TryGetValue(typeof(XsdDataContractExporter), out
dataContractExporter))
{
xsdDCExporter = new XsdDataContractExporter(exporter.GeneratedXmlSchemas);
exporter.State.Add(typeof(XsdDataContractExporter), xsdDCExporter);
}
else
{
xsdDCExporter = (XsdDataContractExporter)dataContractExporter;
}
if (xsdDCExporter.Options == null)
xsdDCExporter.Options = new ExportOptions();

if (xsdDCExporter.Options.DataContractSurrogate == null)
xsdDCExporter.Options.DataContractSurrogate = new UreticiSurrogater();
}

public void ExportEndpoint(WsdlExporter exporter, WsdlEndpointConversionContext context)


{
}

#endregion

#region IOperationBehavior Members

public void AddBindingParameters(OperationDescription description,


BindingParameterCollection parameters)
{
}

public void ApplyClientBehavior(OperationDescription description,


System.ServiceModel.Dispatcher.ClientOperation proxy)
{
SurrogateUygula(description);
}

www.bsenyurt.com Page 263


public void ApplyDispatchBehavior(OperationDescription description,
System.ServiceModel.Dispatcher.DispatchOperation dispatch)
{
SurrogateUygula(description);
}

public void Validate(OperationDescription description)


{
}

#endregion

private static void SurrogateUygula(OperationDescription description)


{
DataContractSerializerOperationBehavior dcsOperationBehavior =
description.Behaviors.Find<DataContractSerializerOperationBehavior>();
if (dcsOperationBehavior != null)
{
if (dcsOperationBehavior.DataContractSurrogate == null)
dcsOperationBehavior.DataContractSurrogate = new UreticiSurrogater();
}
}
}
}

Artk tek yaplmas gereken sz konusu niteliin servis szlemesinde aadaki gibi
uygulanmasdr.

[ServiceContract(Name="UrunServisi",Namespace="http://www.bsenyurt.com/UrunServisi")]
[Surrogater]
public interface IUrunYonetici
{
[OperationContract]
void UrunEkle(Urun urun);

[OperationContract]
Urun UrunGuncelle(Urun urun);
}

Bu ilemlerin tamamlanmas ile birlikte istemci iin gerekli olan proxy ve config retimleri
gerekletirilebilir. Servis uygulamas alyorken svcutil arac kullanlrsa, aadaki ekran
grntsnde olduu gibi ilgili retimlerin baarl bir ekilde yapld grlebilir.

www.bsenyurt.com Page 264


Bu admlarn arndan istemci iin
retilen proxy(UrunYonetici.cs) ve konfigurasyon(output.config) dosyalar rnek
bir Console uygulamasnda aadaki kod parasnda olduu gibi kullanlabilir.

using System;
using UrunYonetim;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Balamak iin bir tua basnz");
Console.ReadLine();
UrunServisiClient client = new UrunServisiClient("UrunServisiTcpEndPoint");
Urun urn = new Urun()
{
Ad = "Mouse",
BirimFiyat = 12,
Id = 1,
StokMiktari = 50,
Ureten = new Vendor()
{
Id = 1001,
Ad = "Adventure 1",
Adres = "Adventure 1 Yolu zeri Minesotta"
}
};
client.UrunEkle(urn);
Urun guncellenen = client.UrunGuncelle(urn);
Console.WriteLine("{0} guncellendi", guncellenen.Ad);
}
}
}

UrunServisiClient isimli nesne konfigurasyonda dosyasndan belirtilen ilgili EndPoint noktasna


gre oluturulduktan sonra, Urun snfna ait bir nesne C# 3.0 object initializer ile
rneklenmektedir. Bu rnekleme srasnda Ureten zellii Vendor isimli tipe ait bir rnek
almaktadr. (Burada Vendor iin varsaylan yapc metodun var olduuna, oysaki seriletirilemeyen

www.bsenyurt.com Page 265


Uretici tipinde byle yapcnn yazlmadna dikkat edilmelidir.) Sonrasnda ise servis zerinden
nce UrunEkle ardndan UrunGuncelle metodlar arlmaktadr. nce servis uygulamas
ardndanda istemci uygulama altrlrsa aadakine benzer bir ekran kts alnr.

stemci uygulama iin retilen proxy dosyas ieriine bakldnda ise, aadaki snf
diagramnda(Class Diagram) grld gibi Vendor isimli bir tipin retildii farkedilebilir.

Vendor ad tesadfi deildir nitekim, UreticiSurrogated snfnda


kullanlan DataContract niteliinde, Name zelliine bu deer verilmitir. Bu sebepten dolay
istemci tarafna Metadata aktarm srasnda tanan tipin adda Vendor olarak set
edilmektedir. Vendor isimli snf aslnda seriletirilemeyen Uretici tipinin yerine istemci tarafnda
kullanlan vekildir. Buraya kadar anlatlanlar ile seriletirilemeyen bir veri szlemesinin, Surrogate
teknikleri sayesinde istemci tarafna nasl aktarlabilecei ve servis ile olan iletiimde nasl
kullanlabilecei incelenmitir. Surrogate kullanm ile ilgili olaraktan daha detayl bilgi
iin http://msdn.microsoft.com/en-us/library/ms733064.aspx adresindeki makaleyi takip
etmenizi; ayrca rnei daha kavrayabilmek iin mutlaka breakpoint' ler ile incelemenizi neririm.
Bylece geldik bir makalemizin daha sonuna.Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 266


Seriletirme lemlerinde
Versiyonlama(Versioning) Vakalar ( 22.06.2008 )
- WCF
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde WCF(Windows Communication Foundation) mimarisinin kulland


seriletirici tiplerden bahsetmi ve son olarak versiyonlama(Versioning) vakalarna deinmitik.
Bu makalemizde ise versiyonlama vakalarnn rnek uygulama zerinden test ederek analiz etmeye
alacaz. Versiyonlama vakalarnn merkezinde veri szlemesi(Data Contract) farkllklar yer
almaktadr. Daha ncedende deinildii zere farkl versiyonlama vakas bulunmaktadr. New
Members, Missing Members, Round-Trip. Bu blmde ilk olarak yeni yelerin(New
Members) olutuu vaka irdelenmeye allacaktr. Sz konusu senaryoda, istemci veya servis
tarafnn sahip olduu veri szlemesinin yeni bir versiyonunu, kar taraf ile paylat bir ortam
sz konusudur. WCF alma zaman varsaylan olarak byle bir durum ile karlatnda, fazladan
gelen yenin kendisini ve ieriini grmezden gelmektedir. Ancak yinede fazla yeleri ieren nesne
verisi, kar tarafa iletilmektedir. ncelikli olarak tm versiyonlama rneklerinde kullanlacak olan
ve aadaki snf emasnda(Class Diagram) grlen tipleri ieren bir WCF servis
ktphanesi(WCF Service Libary) gelitirildiini dnelim.

Servis ktphanesinde yer alan Urun isimli snf bir veri szlemesi(Data Contract) olacak ekilde
aadaki gibi tanmlanmtr. Bu nedenle DataContract ve DataMember nitelikleri kullanlmaktadr.

using System;

www.bsenyurt.com Page 267


using System.Runtime.Serialization;

namespace AdventureLib
{
[DataContract]
public class Urun
{
[DataMember]
public int Id { get; set; }

[DataMember]
public string Ad { get; set; }

[DataMember]
public double Fiyat { get; set; }
}
}

Servis szlemesi(Service Contract) ve uygulayc tipe ait kod ierikleri ise aadaki gibidir.

IUrunYonetim;

using System;
using System.ServiceModel;

namespace AdventureLib
{
[ServiceContract(Name="Adventure Product
Service", Namespace="http://www.bsenyurt.com/AdventureProductService")]
public interface IUrunYonetim
{
[OperationContract]
void UrunEkle(Urun urn);
}
}

UrunYonetim;

using System;

namespace AdventureLib
{
public class UrunYonetim
:IUrunYonetim
{
#region IUrunYonetim Members

public void UrunEkle(Urun urn)


{
string bilgi = String.Format("{0} {1} {2}", urn.Id.ToString(), urn.Ad,
urn.Fiyat.ToString("C2"));
Console.WriteLine(bilgi);
}

#endregion

www.bsenyurt.com Page 268


}
}

UrunYonetim snf ierisinde yer alan UrunEkle metodu, parametre olarak Urun tipinden bir
nesne rnei almaktadr. Senaryoda ilgili operasyonun herhangibir deer dnrp
dndrmemesinin bir nemi yoktur. Servis tarafndaki uygulama ise basit bir Console projesi
olarak tasarlanabilir. Bu uygulamann konfigurasyon ierii ve Main metoduna ait kod blou
aadaki gibidir.

Servis taraf konfigurasyon ierii;

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


<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging"
switchValue="Verbose,ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="c:\vs2005projects\wcf
samples\wcfserializationandencoding\sunucu\app_messages.svclog"
type="System.Diagnostics.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" name="ServiceModelMessageLoggingListener"
traceOutputOptions="None">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true"
logMessagesAtServiceLevel="true" logMessagesAtTransportLevel="true" />
</diagnostics>
<behaviors>
<serviceBehaviors>
<behavior name="ProductServiceBehavior">
<serviceMetadata />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ProductServiceBehavior"
name="AdventureLib.UrunYonetim">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
name="ProductServiceTcpEndPoint" contract="AdventureLib.IUrunYonetim" />

www.bsenyurt.com Page 269


<endpoint address="Mex" binding="mexTcpBinding" bindingConfiguration=""
name="ProductServiceMexTcpEndPoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:4500/ProductService" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

Servis tarafnda, istemciden gelen mesaj ierikleri izlenmek istendiinden Diagnostics zellii
alm ve Mesaj seviyesinde izleme yaplmas iin gerekli konfigurasyon ayarlar tesis edilmitir.
Bylece istemciden servis tarafna gelen veri szleemesi ieriklerine detayl bir ekilde baklabilir.
Bunlarn dnda, TCP bazl MetadaEXchange yaynlamas iin ek bir EndPoint noktasda yer
almaktadr.

Servis uygulama Main metodu kodlar;

using System;
using System.ServiceModel;
using AdventureLib;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(UrunYonetim));
host.Open();
Console.WriteLine("Servis Ak. Kapatman iin bir tua basnz");
Console.ReadLine();
host.Close();
}
}
}

stemci tarafnda proxy retimi amacyla svcutil aracndan faydalanlmaktadr. Nitekim servis
tarafnda TCP zerinden MEX(MetadataExchange) yaynlamas yapldndan bu
mmkndr.(retim ilemi srasnda servis uygulamasnn alyor olmas gerektiini hatrlamakta
yarar vardr. Aksi takdirde ilgili URL zerinden Metadatabilgisi ekilemez.) Svcutil aracnn
kullanm sonras retilen istemci tarafl Proxy dosyasnda, Urun snf aadaki ekilde yer
almaktadr.

www.bsenyurt.com Page 270


[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Urun", Namespace="http://schema
s.datacontract.org/2004/07/AdventureLib")]
public partial class Urun
: object, System.Runtime.Serialization.IExtensibleDataObject
{
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private string AdField;
private double FiyatField;
private int IdField;

public System.Runtime.Serialization.ExtensionDataObject ExtensionData


{
get{return this.extensionDataField;}
set{this.extensionDataField = value;}
}

[System.Runtime.Serialization.DataMemberAttribute()]
public string Ad
{
get{return this.AdField;}
set{this.AdField = value;}
}

[System.Runtime.Serialization.DataMemberAttribute()]
public double Fiyat
{
get{return this.FiyatField;}
set{this.FiyatField = value;}
}

[System.Runtime.Serialization.DataMemberAttribute()]
public int Id
{
get{return this.IdField;}
set{this.IdField = value;}
}
}

www.bsenyurt.com Page 271


Dikkat edilecei zere servis tarafnda tanml veri szlemesi ieriinde yer alan
ve DataMember nitelii ile iaretlenmi olan tm zellikler burada da yer almaktadr. Bunlarn
yannda Urun snfnn istemci
versiyonunun IExtensibleDataObject isimli arayz(Interface) uygulad
ve ExtensionData isimli bir zellie(Property) sahip olduuda gzden karlmamaldr. Bu
arayz Round-Trip vakalarnda nem kazanmaktadr ve ekstra bilgilerin tanmas amacyla
kullanlmaktadr. (lerleyen rneklerde bu durum servis taraf iin aratrlmaktadr.) imdilik
istemci tarafndaki Urun snfnn aadaki gibi StokMiktari isimli yeni bir zellie sahip olduu
varsaylsn. Bylece istemcinin ilgili veri szlemesinin yeni bir srmne sahip olduu vakas
canlandrlabilir. Bu amala manuel olarak proxy dosyasna mdahelede bulunulabilir.

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.Runtime.Serialization", "3.0.0.0")]
[System.Runtime.Serialization.DataContractAttribute(Name="Urun",
Namespace="http://schemas.datacontract.org/2004/07/AdventureLib")]
public partial class Urun
: object, System.Runtime.Serialization.IExtensibleDataObject
{
private System.Runtime.Serialization.ExtensionDataObject extensionDataField;
private string AdField;
private double FiyatField;
private int IdField;
private int StokMiktariField;

public System.Runtime.Serialization.ExtensionDataObject ExtensionData


{
get{return this.extensionDataField;}
set{this.extensionDataField = value;}
}

[System.Runtime.Serialization.DataMemberAttribute()]
public string Ad
{
get{return this.AdField;}
set{this.AdField = value;}
}

www.bsenyurt.com Page 272


[System.Runtime.Serialization.DataMemberAttribute()]
public double Fiyat
{
get{return this.FiyatField;}
set{this.FiyatField = value;}
}

[System.Runtime.Serialization.DataMemberAttribute()]
public int Id
{
get{return this.IdField;}
set{this.IdField = value;}
}

[System.Runtime.Serialization.DataMemberAttribute()]
public int StokMiktari
{
get{return this.StokMiktariField;}
set{this.StokMiktariField = value;}
}
}

imdide istemci tarafndaki Console uygulmasnda aadaki kodlarn yazld gz nne alnsn.

using System;
using AdventureLib;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Balamak iin bir tua basn");
Console.ReadLine();
AdventureProductServiceClient client = new
AdventureProductServiceClient("ProductServiceTcpEndPoint");
Urun mouse = new Urun()
{
Id=10,
Ad="Microsoft Optical Mouse",
Fiyat=8.45,
StokMiktari=190
};
client.UrunEkle(mouse);
}
}
}

Buna gre istemci uygulama Urun snfnn StokMiktari zelliinide kullanaraktan servis tarafna
bir operasyon arsnda bulunmaktadr. Bir baka deyile istemci tarafndanUrun snfnn yeni
versiyonuna ait bir nesne ierii seriletirilerek servis tarafna gnderilmektedir. Eer
rnek, WCF servis ktphanesinde yer alan UrunEkle metoduna alma
zamannda breakpoint konularak incelenirse aadaki ekran grnts ile karlalr.

www.bsenyurt.com Page 273


Dikkat edilecei zere servis tarafndaki Urun tipinde StokMiktari isimli bir zellik
bulunmadndan WCF alma zaman, istemciden gelen paketteki Urun verisini ters
seriletirdikten(DeSerialization) sonra grmezden gelmi ve StokMiktari zelliini atlamtr. Peki
gerektende istemci uygulama, StokMiktari zelliini ieren bir veri paketini servis tarafna
gndermi midir? te servis tarafnda yaplan Diagnostics ayarlarnn faydas bu noktada kendini
gstermektedir. app_messages isimli svclog dosyas alrsa, aadaki ekran grntsnde yer
alan ierik ile karlalr.

www.bsenyurt.com Page 274


Dikkat edilecei zere XML ieriinde StokMiktari isimli bir elementin ve 190 deerinin servis
tarafna gnderildii ak bir ekilde grlebilir. Ancak, WCF alma zaman tarafndan bu element
ierii grmezden gelinmektedir. Bu WCF alma zamannn, New Members vakasndaki tipik
davrandr.

kinci vakaya(Missing Members) gelindiindeyse; bu kez taraflardan birisinde(zellikle istemci


asndan bakldnda) ilgili veri szlemesinin eski versiyonunun kar tarafa gnderilmesi durumu
sz konusudur. Bu durumu analiz etmek iin istemci tarafnda yer alan Urun snfndan Fiyat ve
son eklenen StokMiktari zelliklerinin kaldrld dnlebilir. Bu durumda istemci tarafnda Id ve
Ad zellikleri olan, servis tarafnda ise Id,Ad ve Fiyat zellikleri olan birer veri szleme tipi sz
konusudur.

www.bsenyurt.com Page 275


imdi ayn uygulama tekrardan test edilirse alma zamanndaki Debug grntsnde, servis
tarafna ulamayan ye zellik(Fiyat zellii) iin varsaylan bir deerin otomatik olarak atand
grlr.

Missing Members vakasna gre, eksik yelerin tiplerine gre varsaylan deer
atamalar otomatik olarak yaplmaktadr. Buna gre referans tipli deikenler
iinnull(rnein String tipi), ilkel deer
trleri iinse 0 veya 0.0 deerleri, bool alan iin false deeri atanr. Dier taraftan
istenilirse, veri szlemesi ierisinde aadaki kod paras uygulanaraktan, varsaylan
deerin farkl bir ekilde set edilmeside salanabilir. Tahmin edilecei zere bu metod
ters seriletirme(DeSerializing) srasnda devreye girmektedir.

[OnDeserializing]
void OnDeserializing(StreamingContext context)
{
Fiyat=1;
}

www.bsenyurt.com Page 276


stemcinin gnderdii mesaj ieriine svclog dosyas zerinden bakldnda ise,
sadece Id ve Ad zelliklerinin deerlerinin gnderildii ak bir ekilde grlmektedir.

Grld gibi WCF alma zaman servis tarafnda yine olay sessiz bir ekilde rtpas etmitir. Bu
bir anlamda iyi olabilir. Ancak servis tarafndaki veri szlemesinde(Data Contract) yer alan
baz yeler iin IsRequired deeri true olarak belirlenirse, durum biraz daha farkllar. Sz gelimi
son rnee gre, Fiyat zelliinin servis tarafnn kulland WCF Service Library ierisinde
aadaki gibi deitirildii varsaylsn.

[DataContract]
public class Urun
{
[DataMember]
public int Id { get; set; }

[DataMember]
public string Ad { get; set; }

[DataMember(IsRequired=true)]
public double Fiyat { get; set; }
}

Bu duruma gre gelitirilen uygulama test edildiinde istemci tarafndaki UrunEkle metodunun
icras srasnda istemci tarafna aadaki istisnann(Exception) frlatld
grlr.(Detayl Exception bilgisi iin servis tarafnda ServiceDebug davran eklenmi
ve IncludeExceptionDetailOnFaults zelliinin deeri true olarak belirlenmitir.)

www.bsenyurt.com Page 277


Dikkat edilecei zere Fiyat isimli bir element deerinin beklendii ifade edilmektedir.
Dolaysyla IsRequired zelliine true verilmesi halinde Missing Members vakasnda ortama
biristisna(Exception) frlamas sz konusudur.

Bilindii gibi Serializable niteliine(Attribute) sahip tiplerde seriletirilebildikleri


iin WCF uygulamalarnda taraflar arasnda gnderilebilmektedirler.
Lakin, Serializable nitelii uygulanm tipler ierisindeki tm zellikler
aslnda IsRequired=true davrann sergilerler. Ancak, zellikle .Net Remoting ile
yazlm uygulamlardan kalanSerializable tiplerin
kullanld WCF senaryolarnda, OptionalField nitelii(Attribute) kullanlarak ilgili
yeler iin IsRequired=false davran tanmlanabilir.

Tabi baz hallerde servisin veya istemcinin kulland veri szlemesi ayr
bir library ierisinde olabilir ve mdahele edilemeyebilir. Bu durumda ilgili
ktphanedekiserializable tiplerin tamamna ait zellikler/alanlar, WCF alma
zaman IsRequired=true eklinde yorumlanacaktr. Bu
durumda Missing Members vakasna gre, olas istisnalara kar gerekli tedbirlerin
alnmas gerekebilir.

Round-Trip vakasnda ise, istemcinin servis tarafna veri szlemesinin yeni bir versiyonunu
gnderdii ancak servis tarafndaki operasyon sonrasnda da istemciye veri szlemesinin eski
halinin dndrld dnlmektedir. Olay daha iyi anlamak IUrunYonetim servis szlemesine
aadaki fonksiyonelliin eklendii gz nne alnsn.

www.bsenyurt.com Page 278


using System;
using System.ServiceModel;

namespace AdventureLib
{
[ServiceContract(Name="Adventure Product
Service",Namespace="http://www.bsenyurt.com/AdventureProductService")]
public interface IUrunYonetim
{
[OperationContract]
void UrunEkle(Urun urn);

[OperationContract]
Urun UrunGuncelle(Urun urn);
}
}

Operasyon dikkat edilecei zere, Urun tipinden bir parametre almakta ve yine Urun tipinden bir
nesne rneini geri dndrmektedir. Senaryo gerei operasyon srasnda istemciden gelen Urun
nesnesinde deiiklik yaplmakta ve gncel hali istemci tarafna gnderilmektedir. Lakin istemci
tarafndan servis tarafna gelen Urun nesne rneinde, servis tarafnn kulland Urun tasarmnda
olmayan StokMiktari isimli bir zellik bulunduu varsaylmaktadr. Buna gre doal olarak servis
taraf StokMiktari isimli zellii sessizce gz ard etmektedir. Sonrasnda ise Urun deikeninin
tad nesne zerinde aadaki rnek gncellemeyi yapp istemci tarafna gndermektedir.

using System;

namespace AdventureLib
{
public class UrunYonetim
:IUrunYonetim
{
#region IUrunYonetim Members

public void UrunEkle(Urun urn)


{
string bilgi = String.Format("{0} {1} {2}", urn.Id.ToString(), urn.Ad,
urn.Fiyat.ToString("C2"));
Console.WriteLine(bilgi);
}

public Urun UrunGuncelle(Urun urn)


{
urn.Fiyat += 10;
return urn;
}

#endregion
}
}

Bu durumda istemci tarafnda set edilen stok miktar deeri doal olarak sfrlanm olur. Durumu
canlandrmak iin istemci tarafndaki kodlarn aadaki ekilde deitirildii gz nne
alnsn.(Elbette servis szlemesinde bir deiiklik yapld iin istemci
tarafndaki proxy dosyasnn svcutil arac

www.bsenyurt.com Page 279


veya Visual Studioortamndan Add Service Reference seenei ile yeniden oluturulmas
gerekebilir. Bununla birlikte senaryonun gereklenmesi iin istemci tarafnda sfrlanan Urun snf
ierisine StokMiktari isimli zelliin yeniden eklenmesi de gerekmektedir.)

using System;
using AdventureLib;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Balamak iin bir tua basn");
Console.ReadLine();
AdventureProductServiceClient client = new
AdventureProductServiceClient("ProductServiceTcpEndPoint");
Urun mouse = new Urun()
{
Id=10,
Ad="Microsoft Optical Mouse",
Fiyat=8.45,
StokMiktari=190
};
Urun donenUrun = client.UrunGuncelle(mouse);
string urunBilgisi = String.Format("{0} {1} {2} {3}", donenUrun.Id.ToString(),
donenUrun.Ad, donenUrun.Fiyat.ToString("C2"), donenUrun.StokMiktari.ToString());
Console.WriteLine(urunBilgisi);
}
}
}

Servis ve istemci taraf altrldnda aadaki sonular gzlemlenir.

Dikkat edilecei zere istemci


tarafnda 190 olarak set edilen StokMiktari deeri, UrunGuncelle operasyon arsndan
sonra 0 olarak braklmtr. Oysaki servis tarafna ulaan mesajlara svclog dosyasndan
bakldnda aadaki ekran grntsnde olduu gibi 190 deerinin aktarld grlebilir.

www.bsenyurt.com Page 280


Peki zmsel bir yaklam var mdr ve nedir? zm, IExtensibleDataObject
arayznn(Interface) servis tarafnda kullanlan veri szlemesine uygulanmasdr. Bu arayz
sayesinde, istemciden servis tarafna gnderilen ancak servis tarafnda var olmayan zellik
deerlerinin tanmas ve elde edilmesi mmkn olabilmektedir. Bu amala servis tarafnn
kulland Urun snfna aadaki gibi IExtensibleDataObject arayznn uygulanmas yeterlidir.

using System;
using System.Runtime.Serialization;

namespace AdventureLib
{
[DataContract]
public class Urun
:IExtensibleDataObject
{
[DataMember]
public int Id { get; set; }
[DataMember]
public string Ad { get; set; }
[DataMember(IsRequired=true)]
public double Fiyat { get; set; }

private ExtensionDataObject extensionData;

#region IExtensibleDataObject Members

public ExtensionDataObject ExtensionData

www.bsenyurt.com Page 281


{
get{return extensionData;}
set{extensionData = value;}
}

#endregion
}
}

IExtensibleDataObject arayz sadece ExtensionData isimli bir zellik iermektedir. Bu


zellik ExtensionDataObject veri trndendir. Servis tarafndaki ilgili operasyon
arsdebug modda incelendiinde aadaki verilere ulald grlr.

Dikkat edilecei zere, extensionData alannn ieriinde, istemci tarafndan


gnderilen StokMiktari zelliine ait bilgiler ve set edilen 190 deeri yer almaktadr. Buna
greUrunGuncelle metodunun istemciye dndrd Urun nesnesinin
ieriinde StokMiktari zellii 190 deeri ile korunmaktadr. alma zamannda uygulamalarn
ekran kts aadaki gibidir.

Round-Trip vakasnda rnektende grld zere IExtensibleDataObject arayz ile bir


zm retilebilmektedir ki bu Microsoft tarafndan Best-Practice olarakta belirtilmektedir.

www.bsenyurt.com Page 282


Versiyonlama farkllklar dnda seriletirme ile ilikili olaraktan dikkat edilmesi gereken farkl
konularda vardr. Sz gelimi servis tarafndan yaynlanan bir veri szlemesi
ierisinde seriletirilemeyen(NonSerializable) ve gelitirici tarafndan dorudan mdahalede
bulunulamayan sonradan tanml tipler var olabilir. Bu durumda vekil veri szlemeleri(Surrogate
DataContract) kullanlarak veri szlemesinin seriletirilmesi yoluna gidilebilir. Bu konu bir sonraki
makalede zmleyiciler(Encoding) ile birlikte ele alnmaya allacaktr. Bylece geldik bir
makalemizin daha sonuna. Bu makalemizde ksaca seriletirme ilemlerinde ortaya kabilecek olan
versiyonalama vakalar analiz edilmeye almtr. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF Seriletirme(Serialization) ( 16.06.2008 ) -


WCF
Deerli Okurlarm Merhabalar,

Seriletirme(Serialization) ve zmleme(Encoding) ou zaman bir birlerine kartrlan


kavramlar olabilmektedir. Oysaki aralarnda ok ince ama bir o kadarda nemli farkllklar vardr.
Seriletirme ve zmleme, SOA(Service Oritented Architecture) tarzndaki uygulama
zmlerinde sklkla kullanlmaktadr. Nitekim bu tip mimarilerde servis ve istemci arasnda
yaplan veri transferlerinde bilginin seriletirilmesi ve mesajlarn zmlenmesi gerekmektedir.
Seriletirme zet olarak nesne grafiinin(Object Graph) bytedizisine dntrlmesi olarak
dnlebilir. Bu sayede alma zaman(Run-Time) nesne rneklerinin herhangibir kaynakta
srekli olarak saklanmas mmkn olabilmektedir. Bir baka deyile nesneye ait veri ieriinin, bir
dosyada, veritabannda, bellekte tutulmas mmkndr. Ancak en nemli olan ksm sz konusu
nesne ieriinin baka bir ortama herhangibir protokol zerinden tanabiliyor olmasdr ki
bu datk uygulama(Distributed Applications) zmlerinde kilit rollerden birisidir.

Peki duruma WCF(Windows Communication Foundation) asndan bakldnda gze arpan


noktalar nelerdir? WCF tarafnda seriletirme sadece nesne grafiinin bir byte dizisine
dntrlmesi olarak yorumlanmaz. Bunun yerine nesne grafiinin bir XML InfoSet(XML
Information Set) ieriine dntrlmesi olarak yorumlanr. XML InfoSetierii WCF
mesajlarnn oluturulmasnda kullanlmaktadr. XML InfoSet, XML' in bir st kmesi olarak
dnlebilir. XML InfoSet sayesinde, XML ieriinin sadece Textformatnda olma zorunluluu
ortadan kalkmaktadr. Bir baka deyile nesne ieriinin, rnein binary XML formatnda
retilmesi mmkn olabilmektedir. Bu WCF asndan nemlidir
nk interoperability, performans gibi konularda XML formatnn Text bazl olmayan
versiyonlarnn kullanlmasnn avantajlarndan yararlanlabilinir.

XML InfoSet, WCF mimarisine zg bir kavram deildir. Nitekim Asp.Net Web
Service modelindeki uygulamalarda XML InfoSet yaklamn kullanmaktadr.

WCF mimarisinde kullanlmakta olan seriletirici tipler aadaki gibidir.

www.bsenyurt.com Page 283


zmleme(Encoding) ksaca, WCF mesajlarnn byte dizisi haline dntrlmesi olarak ele
alnabilir. Bu sayede mesajn ieriinin iletiim kanallar(Transport Channels) zerinden
aktarlabilmesi mmkn olmaktadr. WCF mimarisi temel olarak be farkl zmleme
formatn(Encoding Formats) desteklemektedir.

WCF tarafnda duruma gre yukarda bahsedilen formatlar ele alan hazr encoder tipleri
bulunmaktadr. zellikle .Net uygulamalar arasnda bir mesajlama sz konusu ise performans
adna BinaryMessageEncoder, platformlar aras uyumluluk
(Interoperability) gerekiyorsa TextMessageEncoder veya MtomMessageEncoder, Ajax taba
nl web istemcilerinin yer ald senaryolarda ise, JsonMessageEncoder tipleri devreye
girmektedir. nemli olan noktalardan biriside WCF tarafnda encoding sisteminin
geniletilebilmesidir. Yani yeni kan zmleme formatlarna uygun eklemeler ve ilaveler
yaplabilir.

Seriletirme ve zmleme WCF tarafnda bir arada dnlmesi gereken konulardr. Nitekim,
nesne ieriinin seriletirilerek XML InfoSet haline getirilmesi sadece srecin ilk admdr.
Sonrasnda bu InfoSet bilgisinden yararlanlarak kar tarafa gnderilecek olan mesajn retilmesi
iin bir zmleme(Encoding) ilemi yaplr. Bu srecin sonunda oluturulan mesaj, iletiim
kanallar zerinden kar tarafa gnderilir. Burada hatrlanmas gereken noktalardan biriside,
encoding ilemlerinde alma zamannda oluan kanal ynn(Channel Stack) ieriidir.
Bilindii gibi bu ynnda mutlaka Encoding Channel ve Transport Channel kanallarnn olmas

www.bsenyurt.com Page 284


gerekir. teEncoding Channel ierisinde, seriletirilerek InfoSet haline gelen bilginin
ilgili Encoder tipine gre zmlenerek mesaj ierii haline getirilmesi salanmaktadr.

lk olarak WCF seriletirme opsiyonlarna bakmakta yarar bulunmaktadr. WCF, varsaylan


olarak DataContractSerializer tipini baz alarak seriletirme ilemlerini
gerekletirmektedir.DataContractSerializer, nesneyi seriletirirken XSD emalarn kullanr. Bir
baka deyile sz konusu CLR(Common Language Runtime) tipini, karl olan XSD tipi ile
ifade eder. Bu sayede farkl platformlarn seriletirilen nesneyi kullanabilme imkan doar. rnein
.Net tarafndaki System.String tipi XSD tarafnda xs:String olarak ele alnr. Bu tipin
kullanld veri szlemesini(Data Contract) kullanacak olan bir java
uygulamasda java.lang.String tipini karlk olarak ele alr. Bir baka deyile XSD format ilkel
veri tiplerini baz alaraktan bir kpr vazifesini grr. Elbette karmak tiplerde(Complex
Type) ilkel tip seviyelerine indirilerekten seriletirme ilemine tabi tutulurlar. Tabiki burada gz
ard edilmemesi gereken nemli bir nokta vardr. zellikle karmak
tiplerde DataContract ve DataMember nitelikleri(attributes) ile seriletirme ilemi
salanmaktadr. (lerleyen rneklerde aadaki yer alan Urun isimli tip kullanlmaktadr.)

using System;
using System.Runtime.Serialization;

namespace Formatters
{
[DataContract(Namespace="http://www.bsenyurt.com/Urun")]
class Urun
{
private int _id;
private string _ad;
private double _listeFiyati;
private DateTime _stokTarihi;

public Urun(int id, string ad, double listeFiyati, DateTime stokTarihi)


{
Id = id;
Ad = ad;
ListeFiyati = listeFiyati;
StokTarihi = stokTarihi;
}

www.bsenyurt.com Page 285


[DataMember]
public DateTime StokTarihi
{
get { return _stokTarihi; }
set { _stokTarihi = value; }
}

[DataMember]
public double ListeFiyati
{
get { return _listeFiyati; }
set { _listeFiyati = value; }
}

[DataMember]
public string Ad
{
get { return _ad; }
set { _ad = value; }
}

[DataMember]
public int Id
{
get { return _id; }
set { _id = value; }
}
}
}

DataContractSerializer ile Seriletirme

DataContractSerializer tipi .Net Framework 3.0 ile birlikte gelen ve WCF tarafnda varsaylan
olarak kullanlan bir seriletiricidir. Yukarda yer alan Urun snfna ait nesne rneini seriletirmek
amacyla DataContractSerializer tipi, rnek bir Console uygulamasna ait aadaki kod paras
ile ele alnabilir.(Sz konusu Console uygulamas .Net Framework3.5 ablonunda gelitirilmitir.)

using System;
using System.IO;
using System.Xml.Schema;
using System.Runtime.Serialization;

namespace Formatters
{
class Program
{
static void Main(string[] args)
{
#region DataContractSerilazier ile Type Seriletirme

// Seriletirilecek nesne rnei.


Urun mouse=new Urun(1,"Mx Mouse Optic",10,new DateTime(2004,1,1));

// Seriletirici snf rneklenir.

www.bsenyurt.com Page 286


// Parametre olarak seriletirilecek veri szlemesi tipi verilir.
DataContractSerializer dcSerializer = new DataContractSerializer(typeof(Urun));

// Seriletirme sonularnn yazlaca rnek bir Stream oluturulur.


FileStream stream2 = new FileStream("Urun.xml", FileMode.Create,
FileAccess.Write);
// WriteObject metodu ile stream2 nesnesi ile tanmlanan Stream zerine mouse isimli
Urun nesne rnei verisi aktarlr
dcSerializer.WriteObject(stream2, mouse);
stream2.Close(); // Stream kapatlr.

#endregion

#region DataContractSerializer ile Type Ters-Seriletirme

// Urun.xml dosyas var ise ters seriletirme ilemleri yaplr.


if (File.Exists("Urun.xml"))
{
// DataContractSerializer nesnesi rneklenir.
DataContractSerializer dcDeSerializer = new
DataContractSerializer(typeof(Urun));
// Seriletirilmi veri ieriinin bulunduu dosyay okumak iin bir Stream rneklenir.
FileStream stream5 = new FileStream("Urun.xml", FileMode.Open,
FileAccess.Read);
// ReadObject metodu ile parametre olarak verilen Stream ierisindeki bilgi ters
seriletirme ilemine tabi tutulur.
// Dn tr object olduu iin sonucun uygun tre cast edilmesi gereklidir.
Urun urn=(Urun)dcDeSerializer.ReadObject(stream5);
// Elde edilen nesne rnei bilgisi ekrana yazdrlr.
Console.WriteLine("Id :{0} Ad:{1} Fiyat:{2} Stok Tarihi:{3}", urn.Id.ToString(),
urn.Ad, urn.ListeFiyati.ToString("C2"), urn.StokTarihi.ToString());
// Stream kapatlr.
stream5.Close();
}

#endregion

#region DataContractSerializer ile Array Seriletirme

Urun[] urunler ={
new Urun(2,"A Mouse Optic",11.2,DateTime.Now),
new Urun(3,"Y Mouse Optic, Kablolu",9.49,DateTime.Now),
new Urun(5,"Z Mouse",3.45,new DateTime(2008,2,3)),
};

// DataContractSerializer nesne rneini oluturulurken parametre olarak Urun tipinden


dizi verilmitir
DataContractSerializer dcArraySerializer = new
DataContractSerializer(typeof(Urun[]));
FileStream stream3 = new FileStream("Urunler.xml", FileMode.Create,
FileAccess.Write);
dcArraySerializer.WriteObject(stream3, urunler);
stream3.Close();

#endregion

www.bsenyurt.com Page 287


#region DataContractSerializer ile Array Ters-Seriletirme

if (File.Exists("Urunler.xml"))
{
DataContractSerializer dcDeSerializer = new
DataContractSerializer(typeof(Urun[]));
FileStream stream6 = new FileStream("Urunler.xml", FileMode.Open,
FileAccess.Read);
Urun[] gelenUrunler = (Urun[])dcDeSerializer.ReadObject(stream6);
Console.WriteLine("rnler");
foreach (Urun urun in gelenUrunler)
{
Console.WriteLine("Id :{0} Ad:{1} Fiyat:{2} Stok Tarihi:{3}", urun.Id.ToString(),
urun.Ad, urun.ListeFiyati.ToString("C2"), urun.StokTarihi.ToString());
}
stream6.Close();
}

#endregion
}
}
}

Bu kod parasnda Urun tipine ait bir nesne rnei ve bir dizinin seriletirilmesi ve serileen dosya
ieriinden tekrardan elde edilmesi(DeSerialization) ilenmektedir. Seriletirme
ileminde WriteObject metodu, ters seriletirme ileminde ise ReadObject metodlar
kullanlmaktadr. Seriletirme ve TersSeriletirme ilemlerinde tipe ait bilgilerin alnmas
iinDataContractSerializer nesne rneinin retimi srasnda devreye
giren yapc(Constructor) metoddan yararlanlr. Dikkat edilecei zere, Urun ve Urun[] tip
bilgileri yapc metoda parametre olarak verilmektedir. ReadObject metodu,
ilgili Stream zerinden gelen veriyi okumakta ve ters seriletirme ilemine tabi tutmaktadr.
Elbette dnen veri tr objectolduundan uygun tipe dntrlmesi gerekir. rnekte dosya
sistemi Stream olarak kullanlmaktadr. Uygulamann almas sonrasnda seriletirme ilemi
sonucu retilen Urun.xml ve Urunler.xml dosyalarnn ierikleri aadaki gibi olacaktr.

Urun.xml ierii;

Urunler.xml ierii;

www.bsenyurt.com Page 288


alma zamannda oluan ekran kts ise aadaki gibidir. Dikkat edilecei
zere Stream ierisindeki bilgilerden Urun ve Urun[] tipleri elde edilerek sonular ekrana
yazdrlmaktadr.

Burada merak edilen noktalardan biriside mesajlama srasnda kullanlan XSD emasnn ieriinin
ne olduudur. .Net Framework 3.0 ile birlikte gelen XsdDataContractExportertipinden
yararlanlaraktan, sz konusu XSD emasnn ierii manuel olaraktan retilebilir ve incelenebilir.
Aadaki kod parasnda bu durum ele alnmaktadr.

// XSD formatna dntrme yapacak tip tanmlanr


XsdDataContractExporter exporter = new XsdDataContractExporter();
exporter.Options = new ExportOptions();
exporter.Export(typeof(Urun)); // Export ilemi gerekletirilir

// Export ilemi sonucu oluan XSD bilgisi herhangibir stream zerine aktarlabilir
FileStream stream = new FileStream("UrunSchema.xsd", FileMode.Create,
FileAccess.Write);

// Export edilen XmlSchemaSet ierisindeki tm XmlSchema tipleri dolalr


foreach (XmlSchema set in exporter.Schemas.Schemas())
{
// ktnn kolay anlalr olmas asndan o anki XmlSchema rneinin TargetNamespace
zelliinin deerinin DataContract niteliinde belirtilen Namespace bilgisine eit olup olmadna
baklr
if (set.TargetNamespace == "http://www.bsenyurt.com/Urun")
set.Write(stream); // Eit ise XmlSchema ierii dosyaya yazlr

www.bsenyurt.com Page 289


}
stream.Close();

Bu kodun almas sonucu aadaki ekran grntsnde yer alan XSD emasnn retildii
grlr. (Burada if ifadesi kaldrld takdirde ierikte oluacak farklln izlenmesi ve analiz
edilmesi nerilir.)

Grld gibi Urun isimli karmak tip ierisindeki ilkel tiplerin(Primitive Type)
tamam, XSD karlklarna evrilerek ele alnmaktadr. te DataContractFormatter ile
seriletirilen bir Urun nesne rnei iki uygulama arasnda hareket ederken bu ema bilgisinden
yararlanlmaktadr.

NetDataContractSerializer ile Seriletirme

Baz durumlarda hem istemci hemde sunucu tarafnda veri szlemelerinin aslna uygun ekilde
kullanld durumlar sz konusu olabilir. Bu zellikle ayn tip .Net uygulamalarn olduu
senaryolarda sz konusudur. Bu sebepten WCF ierisinde buna destek olacak
ekilde NetDataContractSerializer tipi kullanlmaktadr. Ne yazkki WCF' in bu tipe dorudan
destei yoktur. Bu sebepten ekstra kod yazlmas ve WCF tarafnda seriletirilecek olan tipin
alma zaman iin zel bir nitelik(attribute) tasarlanmas gerekmektedir. Yukarda tasarlanan
rnek iin NetDataContractSerializer aadaki kod parasnda olduu gibi kullanlabilir.

using System;
using System.IO;
using System.Runtime.Serialization;

namespace Formatters
{
class Program
{
static void Main(string[] args)
{
#region NetDataContractSerializer ile Type Seriletirme

// Urun tipine ait nesne rnei oluturulur.


Urun lcd = new Urun(9, "LCD 17inch", 125.45, DateTime.Now);
// NetDataContractSerializer nesnesi rneklenir.
NetDataContractSerializer netSerializer = new NetDataContractSerializer();

www.bsenyurt.com Page 290


// Seriletirmenin yaplaca fiziki dosyay iaret eden Stream alr.
FileStream stream4 = new FileStream("NetUrun.xml", FileMode.Create, FileAccess.Write);
// WriteObject metodu ile lcd isimli Urun nesne rnei, stream4 ile belirtilen Stream
zerine aktarlr.
netSerializer.WriteObject(stream4, lcd);
// Stream kapatlr
stream4.Close();

#endregion

#region NetDataContractSerializer ile Type Ters Seriletirme

// NerUrun.xml dosyas var ise ilemleri yap.


if (File.Exists("NetUrun.xml"))
{
// NetDataContractSerializer nesnesi rneklenir
NetDataContractSerializer netDeSerializer = new NetDataContractSerializer();
// FileStream nesnesi rneklenir
FileStream stream7 = new FileStream("NetUrun.xml", FileMode.Open, FileAccess.Read);
// ReadObject metodu parametre olarak ters seriletirilecek tipe ait verileri tayan
Stream rneini alr.
// Metod geriye object tipini dndrd iin cast ilemi yaplr.
Urun gelenLcd = (Urun)netDeSerializer.ReadObject(stream7);
// Elde edilen nesneye ait bilgiler ekrana yazdrlr
Console.WriteLine("Id :{0} Ad:{1} Fiyat:{2} Stok Tarihi:{3}", gelenLcd.Id.ToString(),
gelenLcd.Ad, gelenLcd.ListeFiyati.ToString("C2"), gelenLcd.StokTarihi.ToString());
// Stream kapatlr
stream7.Close();
}

#endregion

#region NetDataContractSerializer ile Array Seriletirme

Urun[] urunler ={
new Urun(2,"A Mouse Optic",11.2,DateTime.Now),
new Urun(3,"Y Mouse Optic, Kablolu",9.49,DateTime.Now),
new Urun(5,"Z Mouse",3.45,new DateTime(2008,2,3)),
};

NetDataContractSerializer netdcArraySerializer = new


NetDataContractSerializer();
FileStream stream8 = new FileStream("NetUrunler.xml", FileMode.Create,
FileAccess.Write);
netdcArraySerializer.WriteObject(stream8, urunler);
stream8.Close();

#endregion

#region NetDataContractSerializer ile Array Ters Seriletirme

if (File.Exists("NetUrunler.xml"))
{
NetDataContractSerializer netdcDeSerializer = new
NetDataContractSerializer();
FileStream stream9 = new FileStream("NetUrunler.xml", FileMode.Open,

www.bsenyurt.com Page 291


FileAccess.Read);
Urun[] gelenUrunler = (Urun[])netdcDeSerializer.ReadObject(stream9);
Console.WriteLine("Net rnler");
foreach (Urun urun in gelenUrunler)
{
Console.WriteLine("Id :{0} Ad:{1} Fiyat:{2} Stok Tarihi:{3}", urun.Id.ToString(),
urun.Ad, urun.ListeFiyati.ToString("C2"), urun.StokTarihi.ToString());
}
stream9.Close();
}

#endregion
}
}
}

rnekte Urun ve Urun[] dizilerinin NetDataContractSerializer kullanlarak seriletirme


ilemlerine tabi tutulmas ele alnmaktadr. Dikkat edilecei
zere NetDataContractSerializertipine ait nesneler rneklenirken DataContractSerializer' da
olduu gibi tip bildirimi yaplmamaktadr. Bunun sebebi, seriletirilen tipin zaten uygulama
tarafndaki ilgili assembly ierisinde var olmasdr. Dier taraftan yine WriteObject metodu ile
seriletirme, ReadObject metodu ilede ters seriletirme ilemleri gerekletirilmektedir.
retilen NetUrun.xml ve NetUrumler.xmldosyalarnn ierikleri ise aada grld gibidir.

NetUrun.xml ierii;

NetUrunler.xml ierii;

www.bsenyurt.com Page 292


Dikkat edilecei zere DataContractSerializer ile retilen XML ktlarnda farkl bir sonu
olumaktadr. Hereyden nce z:Assembly nitelii ierisinde Urun tipinin yer
ald Assembly bilgisi bulunmaktadr. Bunun nemli bir sonucu vardr. Serileen ieriin ele
alnd taraflarda Urun tipinin yer ald Assembly' n var olmas arttr ki aslnda bu
durum SOA mimarisinin uygulan biimlerinde tercih edilen yollardan birisi deildir. erikte gze
arptan noktalardan biriside z:Id isimli niteliklerdir(Attributes). Bu niteliklerin sadece referans
tiplerine uygulandna dikkat edilmelidir(String,Array gibi). z:Id temel olarak referans tiplerinin
korunmasna ynelik olarak kullanlmaktadr. Bir dier dikkat ekici nitelik ise Urun[] dizisinin
seriletirilmesi sonras ortaya kan z:Size bilgisidir. Buradada seriletirilen dizi ierisindeki eleman
says yer almaktadr. zet olarak NetDataContractSerializer,WCF alt yapsnda dorudan
desteklenmemektedir. Her iki taraftada tipe ait Assembly bilgisinin olmasn gerektirmektedir.
stne stelik nesne rneinin bilinen .Net CLR tiplerine eletirilerek XML ieriine alnmasn
salamaktadr. Bu sebeplerden dolay ilgili seriletiricinin kullanlmas pek yaygn deildir.

DataContractJsonSerializer ile Seriletirme

Bilindii zere .Net Framework 3.5 ile birlikte WCF mimarisinde Ajax tabanl istemciler iin
destek gelmektedir. Bu destein temelinde ise JSON(JavaScript Object Notation) formatl
veriler sz konusudur. Bu noktada WCF alt yaps DataContractJsonSerializer tipini ele
almaktadr. Bu tipte seriletirme destei iin WebScriptEnablingBehavior niteliinin
veyaWebHttpBehavior niteliinde zmle iin JSON tipinin seilmesi yeterlidir. Sz konusu
seriletirme tipi sayesinde Javascript, Asp.Net Ajax ve Silverlight tabanl web uygulmalarna
destek verilebilmektedir. Aadaki kod parasnda yukardaki rneklerde
kullanlan Urun ve Urun[] dizi rneklerinin JSON seriletirilmesi ele
alnmaktadr.(DataContractJsonSerializer tipi System.Runtime.Serialization.Json isim alan
(Namespace) altnda yer almaktadr. Ancak bu isim alanna eriebilmek iin
projeyeSystem.ServiceModel.Web.dll assembly' nn referans edilmesi gerekmektedir.)

using System;
using System.IO;
using System.Xml.Schema;

www.bsenyurt.com Page 293


using System.Runtime.Serialization;
using System.Runtime.Serialization.Json;

namespace Formatters
{
class Program
{
static void Main(string[] args)
{
#region DataContractJsonSerilazier ile Type Seriletirme

// Seriletirilecek nesne rnei.


Urun mouse = new Urun(1, "Mx Mouse Optic", 10, new DateTime(2004, 1, 1));

// Seriletirici snf rneklenir.


// Parametre olarak seriletirilecek veri szlemesi tipi verilir.
DataContractJsonSerializer dcJsonSerializer = new
DataContractJsonSerializer(typeof(Urun));

// Seriletirme sonularnn yazlaca rnek bir Stream oluturulur.


FileStream stream10 = new FileStream("UrunJson.xml", FileMode.Create,
FileAccess.Write);
// WriteObject metodu ile stream10 nesnesi ile tanmlanan Stream zerine mouse isimli
Urun nesne rnei verisi aktarlr
dcJsonSerializer.WriteObject(stream10, mouse);
stream10.Close(); // Stream kapatlr.

#endregion

#region DataContractJsonSerializer ile Type Ters-Seriletirme

// UrunJson.xml dosyas var ise ters seriletirme ilemleri yaplr.


if (File.Exists("UrunJson.xml"))
{
// DataContractJsonSerializer nesnesi rneklenir.
DataContractJsonSerializer dcJsonDeSerializer = new
DataContractJsonSerializer(typeof(Urun));
// Seriletirilmi veri ieriinin bulunduu dosyay okumak iin bir Stream rneklenir.
FileStream stream11 = new FileStream("UrunJson.xml", FileMode.Open,
FileAccess.Read);
// ReadObject metodu ile parametre olarak verilen Stream ierisindeki bilgi ters
seriletirme ilemine tabi tutulur.
// Dn tr object olduu iin sonucun uygun tre cast edilmesi gereklidir.
Urun urn = (Urun)dcJsonDeSerializer.ReadObject(stream11);
// Elde edilen nesne rnei bilgisi ekrana yazdrlr.
Console.WriteLine("Id :{0} Ad:{1} Fiyat:{2} Stok Tarihi:{3}", urn.Id.ToString(),
urn.Ad, urn.ListeFiyati.ToString("C2"), urn.StokTarihi.ToString());
// Stream kapatlr.
stream11.Close();
}

#endregion

#region DataContractJsonSerializer ile Array Seriletirme

Urun[] urunler ={

www.bsenyurt.com Page 294


new Urun(2,"A Mouse Optic",11.2,DateTime.Now),
new Urun(3,"Y Mouse Optic, Kablolu",9.49,DateTime.Now),
new Urun(5,"Z Mouse",3.45,new DateTime(2008,2,3)),
};

DataContractJsonSerializer dcJsonArraySerializer = new


DataContractJsonSerializer(typeof(Urun[]));
FileStream stream12 = new FileStream("UrunlerJson.xml", FileMode.Create,
FileAccess.Write);
dcJsonArraySerializer.WriteObject(stream12, urunler);
stream12.Close();

#endregion

#region DataContractJsonSerializer ile Array Ters-Seriletirme

if (File.Exists("UrunlerJson.xml"))
{
DataContractJsonSerializer dcJsonDeSerializer = new
DataContractJsonSerializer(typeof(Urun[]));
FileStream stream13 = new FileStream("UrunlerJson.xml", FileMode.Open,
FileAccess.Read);
Urun[] gelenUrunler = (Urun[])dcJsonDeSerializer.ReadObject(stream13);
Console.WriteLine("JSON rnler");
foreach (Urun urun in gelenUrunler)
{
Console.WriteLine("Id :{0} Ad:{1} Fiyat:{2} Stok Tarihi:{3}", urun.Id.ToString(),
urun.Ad, urun.ListeFiyati.ToString("C2"), urun.StokTarihi.ToString());
}
stream13.Close();
}

#endregion
}
}
}

DataContractJsonSerializer snfna ait nesne rnekleri kullanllrken yapc metoda, type bilgisi
verilmektedir. DataContractSerializer tipine benzer
olaraktan WriteObject veReadObject metodlar ile stream zerine seriletirme yapmak
ve stream zerinden seriletirilen bilgileri okumak mmkndr. Kodun almas sonras retilen
ktlar ise aadaki gibidir.

UrunJson.xml ierii;

UrunlerJson.xml ierii;

www.bsenyurt.com Page 295


JSON kts, XML ktsna gre daha az yer tutmaktadr. Bununla birlikte ktnn okunurluu ok
daha kolaydr. Dikkat edilecei zere bilgiler key:value iftleri eklinde yazlmtr. Buda
zellikle javascript tarafnda veriye eriimde byk kolaylk salamaktadr.

XmlSerializer ile Seriletirme

.Net Framework 2.0 ile birlikte gelen tiplerden birisi olan XmlSerializer ile, seriletirme
admlarn zelletirmek mmkndr. Dier taraftan tm Asp.Net Web
Service modeli,XmlSerializer zerine kurulmutur. Bu nedenle Asp.Net Web
Service uygulamalarnn WCF tarafna aktarlmasnda kolaylk salamaktadr. Dier taraftan baz
vakalarda tiplerin kaynak kodlarna eriilemedii veya yeniden derleme ilemlerinin yaplamad
durumlar bulunmaktadr. Bu durumlarda XmlSerializer tipinden faydalanlabilir. Nitekim bu
vakalarda tiplere DataContract yada DataMember niteliklerinin uygulanmas sz konusu deildir.

XmlSerializer ile temel olarak farkl modelde seriletirme ilemi gerekletirilebilir. lk modele
gre varsaylan yapc(Default Constructor) kullanlr ve
tipin public olanzellik(Property) veya alanlar(Field) serileir. Dier modelde serileen
yelerin ktlarnn zelletirilmesi amacyla XmlElement, XmlAttribute gibi nitekiklerden
yararlanlr. Son modelde ise IXmlSerializable arayz(Interface) implemantasyonu
gerekletirilerek seriletirme ileminin zelletirilmesi salanr.

WCF tarafnda tanml bir servis szlemesinin(Service


Contract) ktlarda XmlSerializer modelini kullanmas
iin XmlSerializerFormat niteliinden yararlanlmas gerekmektedir.

Karar Vermek

Eer seriletirme ilemi srasnda serileen tipe ait zel ilemler yaplmas
isteniyorsa XmlSerializer tipinden yararlanlabilir. Bununla birlikte
istemcilerinAJAX(AsynchronousJavascriptAndXml) veya Silverlight tabanl olmalar
halinde JSON formatnda seriletirmeyi tercih etmekte yarar
bulunmaktadr. NetDataContractFormatter tipi ne yazkki her iki taraftada serileecek tipe
ait Assembly' n olmasn ve zel kodlamalar yaplmasn gerektirdiinden(Nitekim alma
zamanna bu seriletiricinin kullanlacann sylenmesi iin zel attribute yazlmas
gerekmektedir) ok fazla tercih edilmemektedir. Bunlarn dnda kalan varsaylan durumlarda
ise WCF zaten otomatik olarakDataContractFormatter tipinden yararlanmaktadr. Bu sebepten
gelitiricinin sadece DataContract ve DataMember niteliklerini kullanmas yeterlidir.

Versiyonlama(Versioning)

Buraya kadarki ksmda WCF tarafnda ele alnabilecek olan seriletirici tiplerden ksaca
bahsedilmitir. Seriletirme srecinde nem arz eden konulardan biriside versiyonlamadr. Nitekim
eski istemcilerin yeni servis ile yada tam tersine, eski servislerin yeni istemciler ile almas
gerektii durumlar sz konusu olabilir. Servis ve istemci tarafnn ayn veri szlemesine(Data
Contract) sahip olduklar durumlarda versiyon farkllklarna kar hazrlkl olmalar gerekebilir.
WCF tarafnda versiyonlama problemi aslnda sessiz bir ekilde grmezden gelinmektedir. Ancak
yinede veri szlemelerine ait versiyon farkllklar olduunda, vakann nasl ele alnmas

www.bsenyurt.com Page 296


gerektiinin bilinmesinde yarar vardr. Temel olarak farkl versiyonlama senaryosu
bulunmaktadr.

Yeni yeler(New Members)

Bu senaryoda taraflardan birisi veri szlemesinin yeni versiyonunu kar tarafa gndermektedir.
Yeni yelere sahip szleemeyi gnderen tarafn istemci veya servis olmas farketmemektedir. Bu
vakada alc taraf, gelen yeni yeleri grmezden gelmektedir. rnein yukardaki ekilde
taraflardan birisi Urun tipinin yeni bir versiyonunu kar tarafa gndermektedir. Yeni
versiyonda Id,Ad ve Fiyat alanlarna ek olarak Stok isimli yeni bir alan daha bulunmaktadr. Kar
tarafta ise bu alan grmezden gelinir. Yinede yeni versiyona ait veri ieriinin tamam kar tarafa
gnderilmekte ve ters seriletirme(Deserializing) ilemi srasnda gelen yeni ye
ierikleri atlanlmaktadr(Ignore).

Kayp yeler(Missing Members)

www.bsenyurt.com Page 297


zellikle eski veri szlemelerini kullanan istemciler ile servis tarafnda yeni veri szlemesinin yer
ald durumlarda sz konusudur. Burada servis taraf istemciden gelen eksik yelerin yer ald
veri szlemesini ters seriletirme ilemine tabi tutarken varsaylan deerlerin atanmasn
salamaktadr. Bir baka deyile yine sessiz bir ekilde versiyon fark grmezden gelinir ve eksik
yeler iin ilk deerler atanr. Elbette OnDeserializing nitelii ile imzalanm bir metoddan
yararlanlarak eksik yeler iin farkl deerlerin verilmesi salanabilir. Tabi bu senaryoda ekstra bir
durumda vardr. Bilindii zere DataMember niteliinin IsRequired zellii bulunmaktadr. Bu
zellie gre ilgili yeye ait deerin istemci tarafndan gelmesi arttr. Bu durum ilerleyen
ksmlardaki rneklerde irdelenmektedir.

Round-Trip

Bu durumda istemci yeni yelere sahip veri szlemesi ieriini servis tarafna gndermektedir.
Ancak servis tarafda operasyon ars sonucunda geriye ayn veri tipini
dndrmektedir. Servis taraf, ters seriletirme ilemi srasnda gelen fazla yeyi kesip darda
brakt iin, operasyon sonucunda istemci tarafna eksik veri ierii gnderilecektir. Dier tarafan
senaryo aadaki ekildeki gibi olabilir.

www.bsenyurt.com Page 298


Burada istemci tarafnda veri szlemesinin yeni yeler ieren bir versiyonu
bulunmaktadr. Urun snfnda yer alan Stok isimli zellik yeni yedir.
Ancak Service 1 tarafnda Stokzelliine sahip olmayan eski veri szlemesi kullanlmaktadr. Bu
durumda Service 1, doal olaraktan Stok zelliini ve deerini grmezden gelecektir. Ne
varki Service 1 kendisine gelen Urun nesne verisini krptktan sonra, son
haliyle Service 2 tarafna gndermektedir. Oysaki Service 2 tarafnda Urun tipine ait yeni veri
szlemesi yer almaktadr. Bu durumdadaStok zelliine varsaylan ilk deer atanr. Dolaysyla
istemcinin ilk etapta Stok deeri tamamen ortadan kaybolmaktadr. Burada istemci
ve Service 1 arasnda New Membersversiyonlama koullar; Service 1 ile Service 2 arasnda
ise Missing Members versiyonlama koullar olumaktadr. Round-
Trip senaryosunda, IExtensibleDataObject arayznden yararlanlarak durumun belirli llerde
kontrol altna alnmasda salanabili ki ilerleyen rneklerde bu durumda incelenmektedir.

Bylece geldik WCF mimarisinde seriletirme, versiyonlama ve zmleme ile ilgili ilk makalemizin
sonuna. Devam eden makalemizde versiyonlama koullarn rnekler zerinden incelemeye
alacaz. zellikle Round-Trip hallerinde IExtensibleDataObject arayz
kullanmn, IsRequired zelliinin deerinin Missing Members vakasna olan etkisini,
seriletirilen tipler iin vekil(Surrogate) tip kullanmn ve zmleyiciler(Encoders) arasnda
karar vermede dikkat edilmesi gereken hususlar irdeliyor olacaz. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

ServiceHost Snfndan Geniletmek ( 05.06.2008


) - WCF
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 299


WCF(Windows Communication Foundation) mimarisinde sunucu(Server) tarafndaki alma
ortamnnn(WCF Runtime) hazrlanmas ile ilikili olaraktan ServiceHost snf kullanlmaktadr.
Bir baka deyile ServiceHost snf uygulama sunucusu(Application Server) zerindeki
gerekli hazrlklarn yaplmasn salamaktadr. ServisHost snf ounlukla, servis
nesnesinin IIS(Internet Information Services) veya WAS(Windows Activation
Services) zerinden yaynlanmad durumlarda kullanlmaktadr. Nitekim IIS ve WAS,
ServiceHost tiplerinin alma zamannda kendileri ele almaktadr. Bununla birlikte gelitirici
tarafndan tretilen ServiceHost tiplerinin IIS veya WAS ortamlarnda ele alnacak ekilde
zelletirmelerinin yaplmasda mmkndr. System.ServiceModel isim alan altnda yer
alan ServiceHost snf ServiceHostBase isimli abstract snftan tremektedir. Doal olarak
sunduu baz kurallar deitirilebilir bir baka deyile ezilerek(override) yenide yorumlanabilir.

zellikle ok sayda servisin yaynland vakalarda, uygulama sunucusu zerindeki alma zaman
davranlarnn farkl ve daha kolay konfigure edilmesi istenebilir. te bu tip
ihtiyalarda gelitirici(Developer) tarafndan ServiceHost tipinden tretilen(Inherit) snflara
ait nesne rneklerinin kullanlmas tercih edilebilir. rnein, birden fazla EndPoint iin varsaylan
olarak kapal olan Metadata yaynlamasnn(Metada Publishing) kod tarafnda almas
veya EndPoint gibi bilgilerin bir veri kayna zerinden(rnein bir veritaban-database)
okunmasn salamak iin zel ServiceHost tiplerinin tasarlanmas tercih edilebilir. te bu
blmde zel ServiceHost snflarnn nasl yazlabilecei incelenmektedir. ncelikli olarak
ServiceHost tipinin snf diyagram(Class Diagram) daki grntsne bakmakta ve Framework
ierisindeki yerini grmekte yarar vardr.

Genel olarak tretme dorudan ServiceHost snf zerinden yaplmaktadr. Ezilebilen


yeler(overridable members) arasnda en ok kullanlan ApplyConfigurationmetodudur. Bu
metod ile Host iin yklenen konfigurasyon bilgilerine eriilmesi ve baz davranlarn deitirilmesi
mmkn olabilmektedir. Sz gelimi yaznn banda belirtilen vakalardan ilkinde, EndPoint
noktalarnn her biri iin otomatik olarak Metadata Publishing retilmesinin istendii bir
durumda ApplyConfiguration metodu ierisinde gerekli eklemelerin yaplmas salanabilir.

www.bsenyurt.com Page 300


Bylece servis uygulamasna ka tane EndPoint eklenirse eklensin her biri iin Metadata
Publishing otomatik olarak eklenebilmektedir.

Varsaylan olarak Metadata Publishing seenei kapaldr. Bunun


sebebi Metadata bilgisinin istemeden yaynlanmasnn nne
gemektedir. Metadata yaynlamasnn ak olmas halinde kullanlan EndPoint' ler
ierisindeki balayc tiplerin(Binding Type) eitlerine grede farkl protokoller
zerinden servis bilgilerinin ekilmesi salanabilmektedir. Bir baka deyile servisin ne
yapt, hangi operasyonlar sunduu bilgileri Metadata eklinde sunulabilir. Bu,
istemciler iin gerekli olan proxynesnelerinin retilmesinde ele alnmaktadr. Sz konusu
metadata bilgilerinin elde edilmesi iin svcutil arac komut satrndan kullanlabilir.
Yada Visual Studio 2008ortamnda Add Service Reference seeneinden
yararlanlabilir.

Lakin yle senaryolar vardrki metadata bilgisinin yaynlanmas istenmez. Sz gelimi bir
servisi kullanan baka bir servis olduu gz nne alnsn. Tketici servis
iinproxy nesnesi nemlidir ve manuel olarak retilip datlabilir. Ancak
servisin metadata bilgisinin bu iki servis dndaki istemciler(Clients) tarafndan elde
edilmesiistenmemektedir. te bu gibi olaslklar nedeni ile Metadata yaynlamas
varsaylan olarak kapaldr.

Yazda ilk olarak Metadata yaynlamasnn otomatik olarak almasn salayacak bir rnek
zerinde durulacaktr. Lakin bu rnekte ServiceHost snfndan treyen bir tip kullanlmaktadr.
Ama ncesinde Metadata yaynlamasnn birden fazla EndPoint zerinden yapld bir senaryoda
konfigurasyon dosyasn ierisinde nasl bir ayarlama yaplmas gerektiini incelemekte yarar vardr.
Bu amala aadaki servis szlemesinin(Service Contract) bulunduu bir WCF servis
ktphanesi(WCF Service Library)gelitirildii gz nne alnsn.

Servis szlemesi ve uygulayc tip ierii;

using System;
using System.ServiceModel;

namespace ServisKutuphanesi
{
[ServiceContract(Name="Cebir

www.bsenyurt.com Page 301


Servisi",Namespace="http://www.bsenyurt.com/CebirServisi")]
public interface ICebir
{
[OperationContract]
double DaireAlan(double r);

[OperationContract]
double DaireCevre(double r);
}

public class Cebir


: ICebir
{
#region ICebir Members

public double DaireAlan(double r)


{
return Math.PI*r * r;
}

public double DaireCevre(double r)


{
return 2 * Math.PI * r;
}

#endregion
}
}

Senaryoda odaklanlmas gereken nokta zel ServiceHost tipi gelitirilmesi olduundan, servis
szlemesi ve uygulayc tip mmkn olduunca basit tutulmutur. Service tarafndaki uygulamada
en byk sorun Cebir servisine ait farkl EndPoint noktalar iin Metadata yaynlamasnn
yaplmak istenmesidir. Bu nedenle uygulama sunucusu grevini stlenen programdaki
konfigurasyon dosyasnda, Mex EndPoint tanmlamalarnn yaplmas gerekir.

Mex EndPoint tanmlamalar ile TCP, HTTP, HTTPS, NetPipe gibi protokoller
zerinden Metadata yaynlamas yaplabilmektedir. Burada en nemli
noktaIMetadataExchange arayzdr(interface). Bilindii gibi
bir EndPoint ierisinde Address,Binding ve Contract tanmlamalar
yaplmaktadr. IMetadataExchangemetadata yaynlamas iin gerekli
szlemeyi(bildirmektedir). Balayc
olarak mexHttpBinding, mexHttpsBinding, mexNamedPipeBinding, mexTcpBindin
g tipleri kullanlmaktadr. Address bilgisinde ise ounlukla baseAddress ile tanmlanan
bilgiye ilave olaraktan Mex yazlmas yeterli olmaktadr. Burada Mex bir takma ad grevini
stlenmektedir.

Host uygulama basit bir Console projesi olarak tasarlanmtr ve konfigurasyon dosyas ierii
aada grld gibidir.

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>

www.bsenyurt.com Page 302


<behavior name="MetadataExchangeBehavior">
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MetadataExchangeBehavior"
name="ServisKutuphanesi.Cebir">
<endpoint address="" binding="netTcpBinding" name="CebirTcpEndPoint"
contract="ServisKutuphanesi.ICebir" />
<endpoint address="" binding="basicHttpBinding" name="CebirHttpEndPoint"
contract="ServisKutuphanesi.ICebir" />
<endpoint address="" binding="netNamedPipeBinding" name="CebirPipeEndPoint"
contract="ServisKutuphanesi.ICebir" />
<endpoint address="Mex" binding="mexTcpBinding" name="CebirMexTcpEndPoint"
contract="IMetadataExchange" />
<endpoint address="Mex" binding="mexHttpBinding" bindingConfiguration=""
name="CebirMexHttpEndPoint" contract="IMetadataExchange" />
<endpoint address="Mex" binding="mexNamedPipeBinding"
bindingConfiguration="" name="CebirMexPipeEndPoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:3400/CebirServisi" />
<add baseAddress="http://localhost:3401/CebirServisi" />
<add baseAddress="net.pipe://localhost/CebirServisi" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

Dikkat edilecei zere senaryoya uygun olmas asndan birden fazla farkl EndPoint kullanlmakta
ve farkl protokollerin her biri iin birer Mex EndPoint noktas ilave edilmektedir.
Hem EndPoint noktalar hemde Mex EndPoint noktalar iin TCP, HTTP ve Named
Pipe formatnda gereken temel adres(base address) tanmlamalar host elementi ierisinde
yaplmaktadr. Buna gre istemciler servis arlarnda temel adreslerde belirtilen lokasyonlara
talepte bulunabilir. Dier taraftan Mex adres deerlerine sahip EndPoint noktalar
zerindenproxy retimide salanabilir. Servis uygulamasnn konfigurasyon bilgilerine gre aslnda
aadaki ekilde ifade edilen yaynlamalar sz konusudur.

www.bsenyurt.com Page 303


zetle servis zerinde Metadata yaynlamas iin sunulan her adres bilgisi
zerinden Proxy ve Config dosyas retimleri gerekletirilebilmektedir. Servis uygulamasna ait
program kodlar ise aadaki gibidir.

using System;
using System.ServiceModel;
using ServisKutuphanesi;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Cebir));
host.Open();
Console.WriteLine("Sunucu dinlemede");
Console.ReadLine();
host.Close();
}
}
}

Program kodlarnda standart olarak ServiceHost rnei oluturulmu ve Cebir nesne rnei
parametre olarak verilerek gerekli WCF alma ortam tesis edilmitir. Sonrasnda ise servis
nesnesi alarak(Open metodu ile), istemciden gelen talepleri dinlemek zere konulandrlmtr.
Bu durumda servis uygulamas alrken, svcutil arac kullanlaraktan Mex EndPoint noktalar
zerinden proxy ve config dosyas retimleri gerekletirilebilmektedir. Aadaki ekran
grntsnde bu durum irdelenmektedir.

www.bsenyurt.com Page 304


Grld gibi baseAddress elementlerinde belirtilen adreslerin tamam
zerinden proxy ve config dosyas retimi yaplabilmektedir. Elbetteki retilen config dosyalarnn
her
biri NetTcpBinding, BasicHttpBinding ve NetNamedPipeBinding tabanl EndPoint bildirimleri
nin n birden ierecektir.

Artk yazya konu olan rnee geilebilir. zel olarak yazlan ServiceHost trevli bir snf
ierisinde, konfigurasyon dosyasndan gelen tm baseAddress bilgileri iin otomatik
olarak Mex EndPoint eklenmesi salanmaya allacaktr. Bunun iin aadaki gibi bir snf
tasarlanmas yeterlidir.

www.bsenyurt.com Page 305


Grld gibi tek yaplmas gereken ServiceHost tipinden bir snf tretmek ve bu senaryo
iin ApplyConfiguration metodunu ezmektir. SmartServiceHost snfnn kod ierii aadaki
gibidir.

using System;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace Sunucu
{
class SmartServiceHost
:ServiceHost
{
// Yapc metoda gelen servis tipi ve adres bilgileri ServiceHost snfnn e den yapc
metoduna(Constructor) ynlendirilir
public SmartServiceHost(Type servisTipi,params Uri[] adresler)
:base(servisTipi,adresler)
{
}

protected override void ApplyConfiguration()


{
base.ApplyConfiguration(); // Konfigurasyon dosyasndaki bilgilerin yklenmesi iin bu
metod ars yaplmaldr

// Eer servis iin Metadata Publishing ak deilse bunun eklenmesi salanr


ServiceMetadataBehavior
servisDavranisi=this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (servisDavranisi == null)
{
servisDavranisi=new ServiceMetadataBehavior();

www.bsenyurt.com Page 306


this.Description.Behaviors.Add(servisDavranisi); // MEX eriimi iin yeni bir servis
davran eklenir
}

// host elementi ierisindeki tm baseAddress deerleri dolalr


foreach (Uri temelAdres in this.BaseAddresses)
{
string schemaBilgisi = temelAdres.Scheme; // ema bilgisi alnr
if (schemaBilgisi == Uri.UriSchemeNetTcp) // ema Tcp bazl ise
{
// Tcp iin bir Mex EndPoint eklenir
// lk parametre MEX iin gerekli servis szlemesidir
// kinci parametrede yer alan Create metodu ile gereki Mex EndPoint retimi
salanr
this.AddServiceEndpoint("IMetadataExchange",
MetadataExchangeBindings.CreateMexTcpBinding(), "Mex");
}
else if (schemaBilgisi == Uri.UriSchemeNetPipe) // ema Pipe bazl ise
{
// Pipe iin Mex EndPoint eklenir
this.AddServiceEndpoint("IMetadataExchange",
MetadataExchangeBindings.CreateMexNamedPipeBinding(), "Mex");
}
else if (schemaBilgisi == Uri.UriSchemeHttp) // ema Http bazl ise
{
servisDavranisi.HttpGetEnabled = true; // Http zerinden yaynlamann
yaplaca belirtilir
// Http iin Mex EndPoint eklenir
this.AddServiceEndpoint("IMetadataExchange",
MetadataExchangeBindings.CreateMexHttpBinding(), "Mex");
}
else if (schemaBilgisi == Uri.UriSchemeHttps) // ema Https bazl ise
{
servisDavranisi.HttpsGetEnabled = true; // Https zerinden yaynlamann
yaplaca belirtilir
// Https iin Mex EndPoint eklenir
this.AddServiceEndpoint("IMetadataExchange",
MetadataExchangeBindings.CreateMexHttpsBinding(), "Mex");
}
}
}
}
}

ServiceHost snfna ait bir nesne rneklenirken servis nesnesinin tipi ve kullanlacak adres bilgileri
parametre olarak verilmektedir. Bu nedenle SmartHostService snfnn ilgili yapc
metodundan(Constructor), base anahtar kelimesi ile ServiceHost snfnda e den yapc
metoda parametre aktarm gerekletirilmektedir. Dier taraftan senaryoda istenen, var
olan EndPoint noktalar iin Mex tanmlamalarnn yaplmasdr. Bu nedenle konfigurasyon
dosyasnn ieriine ulalmas ve servis tanmlamalarnda(Service Description) gerekli
ilavelerin yaplmas gerekmektedir. Sz konusu ilemler iin ApplyConfiguration metodu
ezilmitir.

www.bsenyurt.com Page 307


ApplyConfiguration metodu dnda ezilebilecek olan dier yelerde aadaki ekilde
grld gibidir.

Dikkat edilecei zere servisi kapatma, ama veya hata olumas anndaki olay
metodlarn ezilmesi dahi mmkndr.

ApplyConfiguration metodu ierisinde ilk olarak base.ApplyConfiguration() fonksiyonuna ar


yaplarak konfigurasyon dosyasndaki ayarlarn ortama yklenmesi salanmaktadr. Sonrasnda ise
servis davrannda Metadata yaynlamas iin gerekli elementin var olup olmadna baklr. Eer
yoksa eklenmesi salanr. lerleyen admlardaysa konfigurasyon dosyasndaki tm temel adresler
tek tek dolalr. Her temel adresin ema(Scheme) tipine baklarak uygun
bir Mex EndPoint yklemesi yaplmaktadr. Burada ema bilgisi elde edildikten
sonra Uri snfnn UriSchemeHttps, UriSchemeHttp, UriSchemeNetPipe, UriSchemeNetTcp
sabit deerleri ile kyaslama yaplmakta ve duruma gre uygunEndPoint retimleri
gerekletirilmektedir.
Tm Mex EndPoint noktalar IMetadataExchange arayzn, szleme(Contract) tipi olarak
kullanmaktadr. Bununla birlikte uygunbalayc tiplerin(Binding Type) retimi
iin MetadataExchangeBindings snfnn CreateMexHttpsBinding, CreateMexHttpBinding, C
reateMexNamedPipeBinding veCreateMexTcpBinding gibi metodlar kullanlmaktadr. Artk
servis uygulamasnda ServiceHost yerine SmartServiceHost snf aadaki kod parasnda
olduu gibi kullanlabilir.

using System;
using System.ServiceModel;
using ServisKutuphanesi;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
// ServiceHost host = new ServiceHost(typeof(Cebir));
SmartServiceHost host = new SmartServiceHost(typeof(Cebir));
host.Open();
Console.WriteLine("Sunucu dinlemede");
Console.ReadLine();
host.Close();
}

www.bsenyurt.com Page 308


}
}

Artk konfigurasyon dosyasnda yaplan Mex EndPoint noktalarna ait bildirimler kaldrlabilir.
Servis uygulamas altrldnda debug moddayken, SmartServiceHost snf ierisinde ezilmi
olan ApplyConfiguration metodunun sonunda aadaki ekran grntsne ulalabilir.

Dikkat edilecei zere alt adet EndPoint tanmlamas yer almaktadr. Bunlardan
de Mex EndPoint noktalardr. Dolaysyla istemciler kendileri iin
gerekli Proxy veconfig dosyas retimlerini yine gerekletirebilirler.

Sz konusu rnekte SmartServiceHost nesnesi bir Console uygulamas zerinde ele


alnmaktadr. Oysaki bu tipin IIS veya WAS tabanl bir host uygulama tarafndanda ele alnmas
istenebilir. Burada devreye bir fabrika nesnesi(Factory Object) girmektedir.
Nitekim IIS zerinden yaynlanan svc uzantl dosyalara ait ServiceHost direktifi ierisinde
bulunan Factory nitelii(attribute) ile, kullanlacak olan ServiceHost tipi belirtilebilmektedir.
Sz konusu senaryoda zel bir ServiceHost tipi olduundan bunun retiminden sorumlu
bir Factory snfnnda gelitirilmesi gereklidir.

Yaznn bu blmnde
gelitirilen ServiceHost trevli SmartServiceHost snfnn IIS zerinden host edilen
bir WCF Service zerinden nasl kullanlaca ele alnmaktadr. Bu amala ncellikle IIS zerinde
bir WCF servis almas gerekmektedir. Sz konusu proje servis ktphanesinide referans
etmelidir. Sonrasnda ise uygulamaya aadaki snfn eklenmesi yeterlidir.

www.bsenyurt.com Page 309


using System;
using System.ServiceModel.Activation;

public class SmartServiceHostFactory


:ServiceHostFactory
{
protected override System.ServiceModel.ServiceHost CreateServiceHost(Type
serviceType, Uri[] baseAddresses)
{
return new SmartServiceHost(serviceType, baseAddresses);
}
public SmartServiceHostFactory()
{
}
}

SmartServiceHostFactory snf ierisinde CreateServiceHost isimli metod


ezilmektedir(overriding). Dikkat edilecek olursa metod geriye SmartServiceHost tipinden bir
nesne rnei dndrmektedir. Bir baka deyile WCF alma ortamn tesis edecek nesne rnei
retilmektedir. CreateServiceHost metoduna gelen parametrelerden ilki, svc dosyasnda yer
alan Service niteliinin deerini tamaktadr. Elbette svc dosyas ierisinde
hangi Factory nesnesinin kullanlacann bildirilmeside gereklidir. Bu nedenle svc dosyasnn
ierii aadaki gibi dzenlenmelidir.

<%@ ServiceHost Language="C#" Debug="true"


Service="ServisKutuphanesi.Cebir" Factory="SmartServiceHostFactory" %>

Dikkat edilmesi gereken nemli bir nokta vardr. IIS zerinden yaynlama yapld ve bu
senaryoda WAS kullanlmad iin web.config dosyas ierisinde net.pipe venet.tcp formatndaki
adreslere izin verilmeyecektir. Dolaysyla u aamada test olmas asndan sadece HTTP bazl
bir EndPoint noktasna yer verilmektedir. Web.configdosyas iin rnek ierik aadaki gibidir.

<?xml version="1.0"?>

www.bsenyurt.com Page 310


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="" name="ServisKutuphanesi.Cebir">
<endpoint address="" binding="basicHttpBinding"
name="CebirHttpEndPoint" contract="ServisKutuphanesi.ICebir" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:3401/CebirServisi" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

Bu ilemlerin ardndan Service.svc dosyas herhangibir tarayc uygulamadan talep edilirse


otomatik olarak HTTP Metadata Publishing' in ald grlcektir. Tabiki SvcUtilarac
ilede metadata bilgileri ekilebilir.

Yazya ikinci bir rnek ile devam edelim. Bu rnekte zel olarak yazlm olan ServiceHost snf,
WCF alma ortam iin gerekli EndPoint bilgilerini bir veritaban tablosundan almaktadr. Byle
bir senaryo ounlukla servis tarafndaki bildirimlerin konfigurasyon dosyas darsnda daha
gvenli bir yerden tedarik edilmesi istendii durumlarda gz nne alnabilir. Senaryonun ok
karmak olmamas amacyla basit bir tablo zerinde EndPoint oluumlar iin gerekli bir ka alan
bilgisi tutulmaktadr. lk olarak bu tablonun tasarm ile ie balanabilir. Tablonun oluturulmas iin
gerekli sorgu cmlesi aadaki ekilde tasarlanabilir.

USE [ServiceBase]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
SET ANSI_PADDING ON
GO
CREATE TABLE
[dbo].[EndPoints]
(

www.bsenyurt.com Page 311


[EndPointId] [int] IDENTITY(1,1) NOT NULL,
[Name] [varchar](20) COLLATE Turkish_CI_AS NOT NULL,
[ServiceAlias] [nvarchar](20) COLLATE Turkish_CI_AS NOT NULL,
[Protocol] [nvarchar](10) COLLATE Turkish_CI_AS NOT NULL CONSTRAINT
[DF_EndPoints_Protocol] DEFAULT (N'net.tcp'),
[ServerName] [nvarchar](50) COLLATE Turkish_CI_AS NOT NULL CONSTRAINT
[DF_EndPoints_ServerName] DEFAULT (N'localhost'),
[PortNumber] [int] NULL,
[Binding] [nvarchar](20) COLLATE Turkish_CI_AS NOT NULL,
[Contract] [nvarchar](50) COLLATE Turkish_CI_AS NOT NULL,
CONSTRAINT [PK_EndPoints] PRIMARY KEY CLUSTERED
(
[EndPointId] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF,
ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]

GO
SET ANSI_PADDING OFF
GO
ALTER TABLE [dbo].[EndPoints] WITH CHECK ADD CONSTRAINT [CK_Bindings] CHECK
(([Binding]='WS2007FederationHttpBinding' OR [Binding]='WS2007HttpBinding' OR
[Binding]='WSFederationHttpBinding' OR [Binding]='WebHttpBinding' OR
[Binding]='WSDualHttpBinding' OR [Binding]='WSHttpBinding' OR [Binding]='BasicHttpBinding' OR
[Binding]='MsmqIntegrationBinding' OR [Binding]='NetPeerTcpBinding' OR
[Binding]='NetMsmqBinding' OR [Binding]='NetNamedPipeBinding' OR [Binding]='NetTcpBinding'))
GO
ALTER TABLE [dbo].[EndPoints] CHECK CONSTRAINT [CK_Bindings]
GO
ALTER TABLE [dbo].[EndPoints] WITH CHECK ADD CONSTRAINT [CK_PortNumber] CHECK
(([PortNumber]>=(0) AND [PortNumber]<=(65535)))
GO
ALTER TABLE [dbo].[EndPoints] CHECK CONSTRAINT [CK_PortNumber]
GO
ALTER TABLE [dbo].[EndPoints] WITH CHECK ADD CONSTRAINT [CK_Protocol] CHECK
(([Protocol]='net.p2p' OR [Protocol]='net.pipe' OR [Protocol]='https' OR [Protocol]='http' OR
[Protocol]='net.msmq' OR [Protocol]='net.tcp'))
GO
ALTER TABLE [dbo].[EndPoints] CHECK CONSTRAINT [CK_Protocol]

Bu sorgu ifadesinde hatalarn nne mmkn olduunca geebilmek iin Port numaras, balayc
tip ad ve protokol bilgilerinin girii kstlamalar(Constraints) ile kontrol altna alnmaktadr. Bu
ekilde Binding, PortNumber ve Protocol alanlarna girilecek olan deerler snrlandrlmaktadr.
Elbette bu tabloya EndPoint bilgilerinin girilmesi iin bir uygulama arayz kullanlacaksa, giri
kontrollerinin veritaban yerine program tarafnda yaplmasda sz konusudur. Nitekim bu
sayede WCF alt yapsndan tiplerin(rnein balayc snflar, enum sabitleri vb...) alma
zamannda validasyon sreleri ierisine dahil edilmesi garanti edilmi olacak ve tutarl veri girii
salanabilecektir. Tabloda rnek olarak aadaki verilerin sakland gz nne alnabilir.

www.bsenyurt.com Page 312


Bu tabloda ye alan Protocol, ServerName ve PortNumber bilgileri yardmyla EndPoint iin
gerekli adres(Address) oluturulabilir. Adres bilgileri baseAddress olacak ekilde ele alnabilir.
Yine EndPoint iin gerekli szleme(Contract) bilgisi Contract isimli alandan tedarik edilebilir.
Son olarak balayc(Binding) bilgisi iin Binding alanndaki metinsel bilgiden yararlanlmaktadr.
Tabiki alma zamannda ilgili balayc tipe ait nesne rnei gerektiinden bu metinsel bilginin
karl olan balayc tip iin ek bir kodlama yaplmas gerekebilir. EndPoint bilgilerinin saklanaca
bu tabloyu kullanacak olan tretilmi ServiceHost snfnn tasarm ise aadaki ekilde
yaplabilir.

using System;
using System.ServiceModel;
using System.Data.SqlClient;
using System.ServiceModel.Channels;
using System.ServiceModel.Description;
using System.ServiceModel.MsmqIntegration;

namespace Sunucu
{
class TableBasedServiceHost
:ServiceHost
{

public TableBasedServiceHost(Type servisTipi, params Uri[] adresler)


: base(servisTipi, adresler)
{
}

protected override void ApplyConfiguration()


{
// Service iin Metadata davran olup olmadna baklr. Yoksa bir tane oluturulur.
ServiceMetadataBehavior servisDavranisi =
this.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (servisDavranisi == null)
{
servisDavranisi = new ServiceMetadataBehavior();
this.Description.Behaviors.Add(servisDavranisi); // MEX eriimi iin yeni bir servis
davran eklenir
}

// ServiceBase veritabanndaki EndPoints tablosundan satrlar okunur.


using (SqlConnection _conn = new SqlConnection("data
source=.;database=ServiceBase;integrated security=SSPI"))
{
SqlCommand _cmd = new SqlCommand("Select
EndPointId,Name,ServiceAlias,Protocol,ServerName,PortNumber,Binding,Contract From
EndPoints", _conn);
_conn.Open();
SqlDataReader reader = _cmd.ExecuteReader();
string adres = null;
while (reader.Read())
{
// Servis iin gerekli baseAddress bilgileri oluturulurken PortNumber alannn
deerinin null olup olmadna baklr
// Bu alan null ise sunucu adndan sonra port numaras bilgisi verilmez.
if (!String.IsNullOrEmpty(reader["PortNumber"].ToString()))
adres = String.Format("{0}://{1}:{2}/{3}",

www.bsenyurt.com Page 313


reader["Protocol"].ToString(), reader["ServerName"].ToString(),
reader["PortNumber"].ToString(), reader["ServiceAlias"].ToString());
else
adres = String.Format("{0}://{1}/{2}", reader["Protocol"].ToString(),
reader["ServerName"].ToString(), reader["ServiceAlias"].ToString());
// Elde edilen adres verisinden bir Uri nesne rnei oluturulur
Uri baseAddress = new Uri(adres);
// Oluturulan baseAddress bilgisi servise eklenir.
this.AddBaseAddress(baseAddress);
// EndPoint oluturulur ve eklenir.
// EndPoint noktasnn oluturulmas srasnda balayc tip(Binding Type) iin
BaglayiciUret isimli yardmc metod kullanlr.
this.AddServiceEndpoint(reader["Contract"].ToString(),
BaglayiciUret(reader["Binding"].ToString()), "");

#region MEX EndPoint Ekleme lemleri

// Adresteki scheme bilgisine gre gerekli Mex EndPoint noktalar oluturulur.


string schemaBilgisi = baseAddress.Scheme;
if (schemaBilgisi == Uri.UriSchemeNetTcp) // TCP iin
{
this.AddServiceEndpoint("IMetadataExchange", MetadataExchangeBindin
gs.CreateMexTcpBinding(), "Mex");
}
else if (schemaBilgisi == Uri.UriSchemeNetPipe) // PIPE iin
{
this.AddServiceEndpoint("IMetadataExchange", MetadataExchangeBindin
gs.CreateMexNamedPipeBinding(), "Mex");
}
else if (schemaBilgisi == Uri.UriSchemeHttp) // HTTP iin
{
servisDavranisi.HttpGetEnabled = true;
this.AddServiceEndpoint("IMetadataExchange", MetadataExchangeBindin
gs.CreateMexHttpBinding(), "Mex");
}
else if (schemaBilgisi == Uri.UriSchemeHttps) // HTTPS iin
{
servisDavranisi.HttpsGetEnabled = true;
this.AddServiceEndpoint("IMetadataExchange",
MetadataExchangeBindings.CreateMexHttpsBinding(), "Mex");
}

#endregion
}
reader.Close();
}
}

// EndPoints tablosunda balayc adlar string olarak tutulduundan Binding tipinden nesne
retimi gerekletiren bir metoddan yararlanlmaktadr.
private Binding BaglayiciUret(string baglayiciAdi)
{
Binding baglayici = null;
switch (baglayiciAdi)
{
case "NetTcpBinding":

www.bsenyurt.com Page 314


baglayici= new NetTcpBinding();
break;
case "NetNamedPipeBinding":
baglayici = new NetNamedPipeBinding();
break;
case "WS2007FederationHttpBinding":
baglayici = new WS2007FederationHttpBinding();
break;
case "WS2007HttpBinding":
baglayici = new WS2007HttpBinding();
break;
case "WebHttpBinding":
baglayici = new WebHttpBinding(); // System.ServiceModel.Web referansnn
ekli olmas gerekir
break;
case "WSDualHttpBinding":
baglayici = new WSDualHttpBinding();
break;
case "WSHttpBinding":
baglayici = new WSHttpBinding();
break;
case "BasicHttpBinding":
baglayici = new BasicHttpBinding();
break;
case "MsmqIntegrationBinding":
baglayici = new MsmqIntegrationBinding();
break;
case "NetPeerTcpBinding":
baglayici = new NetPeerTcpBinding();
break;
case "NetMsmqBinding":
baglayici = new NetMsmqBinding();
break;
default:
baglayici = new NetTcpBinding();
break;
}
return baglayici;
}
}
}

TableBasedServiceHost nesnesi ierisinde yer alan ApplyConfiguration metodu


ierisinde, EndPoints tablosundaki satrlardan
yararlanlarak base address, EndPoint ve Mex EndPointnesnelerinin oluturulmas
salanmaktadr. Elbette bu yeni ServiceHost trevli snfa ait nesne rneinin kullanlmas iin bir
uygulama sunucusuna ihtiya vardr. Bu amalaConsole uygulamasnn kodlarn aadaki gibi
deitirmek yeterlidir.

using System;
using System.ServiceModel;
using ServisKutuphanesi;

namespace Sunucu
{
class Program

www.bsenyurt.com Page 315


{
static void Main(string[] args)
{
TableBasedServiceHost host = new TableBasedServiceHost(typeof(Cebir));
host.Open();
Console.WriteLine("Sunucu dinlemede");
Console.ReadLine();
host.Close();
}
}
}

Programn baarl bir ekilde alt grlr. Debug mod


ierisindekyen TableBasedServiceHost snfnna ait ApplyConfiguration metodu ileyiini
tamamlandnda servise ait ierik aadaki Quick Watch grntsnde olduu gibidir. Dikkat
edilecek olursa tabloda rnek olarak girilen tm base adres deerleriBaseAddress zelliinin
iaret ettii koleksiyona yklenmitir. Bununla birlikte alt
adet EndPoint tanmlamas EndPoints zellii ile iaret edilen koleksiyona eklenmitir. Bunlardan
bir nceki rnektine benzer olacak ekilde Mex EndPoint bilgileridir. Servis tipi zaten yapc
metod ile bildirilmektedir. Son olarak szleme bilgisininde ImplementedContractszelliine set
edildii grlmektedir.

www.bsenyurt.com Page 316


Tabiki buradaki senaryo bir Best Practices olarak alglanmamaldr. Tablo tasarm daha farkl bir
ekilde dzenlenebilir. Bununla birlikte balant, tablo ad ve alanlarnn deime ihtimali gz
nnde bulundurularak bunlarn ServiceHost trevli snf ierisine aktarm iin gerekli nlemlerin
alnmas gereklidir. Elbette daha ileri bir senaryoda dnlebilir. Sz gelimi, servisin
kullanaca EndPoint tanmlamalar tablodaki alanlarda seriletirilmi(Serialize) ekilde
tutulabilir. Hatta birden fazla servis nesnesi(Service Instance) iin birden
fazla EndPoint tanmlamasnn yaplabilecei ilikisel(Relational) bir veritaban tasarmda sz
konusu olabilir. Sz konusu servislerin kullandEndPoint bilgilerinin tablolardaki ilgili alanlara
eklenmesi iinde yetkilendirilmi(Authorized) bir ekran(rnein bir Windows uygulamas)
tasarlanabilir. Bylece EndPoint girileri yetki dahilinde yaplr. Dier
taraftan EndPoint bilgileri XML gibi ak bir dosyada durmadklarndan grece daha gvenli bir
ortamda saklanrlar. stelik bu veritabannn servis uygulamasnn host edildii sunucunun
arkasnda bir sunucuda yer aldda gz nne alnabilir. Bu vizyon ok daha fazla geniletilebilir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde ServiceHost trevli bir snfn nasl
gelitirilip kullanlabilecei iki rnek senaryo zerinden incelemeye altk. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

www.bsenyurt.com Page 317


Burak Selim ENYURT
selim@bsenyurt.com

WCF - P2P(Peer-to-peer) Programlamaya Giri


( 25.05.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Datk mimari uygulamalar(Distributed Applications) gelitirilirken


ounlukla Client/Server veya N-Tier modelleri gz nne alnmaktadr. Oysaki datk mimari
uygulamalar iin Peer-to-Peer(P2P) modelide sz konusudur. P2P modelinde istemci ve sunucu
arasnda bir fark yoktur ve alt yap hazrlklar dier modellere gre biraz daha karmaktr.
Programlama zorluu nedeni ile gelitiriciler zaman zaman bu modelden kanrlar. Oysaki
gnmzde P2P zerine kurulu olan pek ok sistem yer almaktadr. P2P uygulamalarna rnek
olarak, IRC(Internet Relay Chat), annda mesajlama(Instant Messaging), dosya
paylam(File Sharing), Oyunlar, grsel ve sesli veri aktarm, veri kopyalama(Data
Replication) programlar gsterilebilir. Dolaysyla P2P modelinin datk mimari zmlerinde
aslnda nemli bir yeri bulunmaktadr. P2P tabanl sistemlerde
zellikle leklenebilirlik(Scalability) ve gvenilirlik(Reliability), dier datk mimari
modelleri ile kyaslandnda daha yksek verimlilik gstermektedir.

P2P programlar baarl bir ekilde tesis


edildiklerinde scalability ve reliability manasnda belirgin stnlk ve avantajlar
salamaktadr.

Scalability : Kaynak kullanmnn artmasyla sistem performansnn deer kaybetmeden


ykselebilmesi leklenebilirlik olarak ifade edilebilir. Bu orann yksek olmas bir avantaj
olarak grlebilir.

Reliability : Kurulu olan sistemin gvenilirliini, ayn zamanda devamlln ifade eder.

ok doal olarak Windows Communication Foundation(WCF) ierisindede P2P destei


bulunmaktadr. Bu blmde WCF mimarisi ile P2P zmlerinin nasl gelitirilebileceine giri
yaplmaktadr. Balamadan nce dier datk mimari modellerine ksaca bir gz atmakta ve P2P ile
aralarndaki farklar analiz etmeye almakta yarar
bulunmaktadr.Client/Server(stemci/Sunucu) modeli aadaki ekil ile basite zetlenebilir.

www.bsenyurt.com Page 318


Bu modelde istemci, sunucu zerinden yaynlanan fonksiyonellikler iin talepte(Request) bulunur.
Sunucunun grevi ise bu taleplere karlk cevaplar(Response) retmektir. Bu mimariye
verilebilecek en gzel rnek Web sunucular ve tarayc uygulamalardr(Browser
Applications). Sz gelimi IIS(Internet Information Services) sunucu grevini
stlenirken, Internet Explorer, Netscape Navigator, Mozilla Firefox gibi tarayc uygulamalar
istemci roln yklenmektedir. Bu modelde aslnda istemci ve sunucu uygulamalar ayn sistemin
bir parasdr. Her zaman IIS yada Internet Explorer gibi hazr program arayzleri olmayabilir.
Sz gelimi WCF mimarisinde Self Hosting tekniine gre sunucu
program,Console, Windows, WPF, Windows Service, WAS(Windows Activation
Service) uygulamas olacak ekilde gelitirilebilir. Buna paralel olarak istemci taraf iinde ayn
durum geerlidir. Yinede sonu itibariyle istemci taraf talepte bulunan, sunucu taraf ise bu
talepleri karlayan roldedir. Client/Server modelinde merkeziletirme olanann bulunmas bir
avantaj olarak grlebilir.

N-Tier yada ok katmanl mimaride, datk uygulama gelitirme modellerinden birisidir. Aslnda bu
model datk mimari tarafnda ounlukla 3 katmanl(3-Tier) olacak ekilde uygulanmaktadr.
Aadaki ekilde bu durum ksaca ifade edilmeye allmaktadr.

www.bsenyurt.com Page 319


Bu model aslnda Client/Server mimarinin geniletilmi bir hali olarak dnlebilir. Katmanlar
ayr fiziki paralara blmlenebilmektedir. Datk mimari asndan zelliklei
mantnn(Business Logic) farkl bir makineye alnmas leklenebilirlii(Scalability) arttran
bir faktrdr. Hatta bu fiziki blnme ile yk dengesinin datlmas(Load Balancing),
daha gvenli(Secure) bir ortamn tesis edilmesi gibi avantajlarda salanabilmektedir. Tabiki, bu
fiziki blnm iin donanma yaplan yatrmda bu iin cabas olarak grlebilir.

P2P modelinde ise sistemin tm katlmclar(ki bunlar peer node-boum olaraktanda


adlandrlmaktadr) ounlukla hem istemci hemde sunucu grevini
stlenebilmektedir.Client/Server veya N-Tier modelleri ile datk uygulama zmleri
gelitirilmesi P2P' e gre daha kolaydr. Ayrca ynetimin merkeziletirilmesi yada gvenliin gl
bir ekilde salanmasda sz konusudur. Fakat blmn bandada belirtildii
zere, leklenebilirlik(Scalability) ve gvenilirlik(Reliability) gibi konularda P2P mimarisi
gerekten ne kmaktadr. (Tabiki, leklenebilirlik olgusu, P2P dndaki modellerdede vardr
ancak maliyeti daha yksek olmaktadr. zellikle sunucu yatrmlar gz nne
alndnda.) Elbetteki bu farkllklar gerek hayat vakalarnda duruma gre tercih edilebilirler.
Hatta baz vakalarda karma modellerin kullanldda grlmektedir.

Genel olarak P2P modelinde yer alan uygulamalar bir Mesh Network ierisinde gruplanrlar. Sz
konusu Mesh Network' lerin iki farkl uygulan biimi vardr. Bunlardan birisi Paral Bal
Mesh(Partially Connected Mesh) modelidir ve aadaki ekildekine benzer bir yaklam
sunmaktadr.

www.bsenyurt.com Page 320


Bu modele gre Mesh Network ierisinde yer alan boumlar(Peer Nodes) yaknlarndaki
komularna dorudan baldr. Bir baka deyile sistem ierisindeki programlar en yakn
bilgisayardaki ile konuabilmektedir. (Birbirlerinin komu boumlar olarakta grlebilirler.) Bu
modelde boumlarn tamam birbirlerine bal deildir. Bu nedenle rnein komu olmayan bir
boumda yer alan katlmcya mesaj aktarm iin, mesajn srayla birbirlerine bal olan boumlar
zerinden hareket etmesi gerekmektedir. Bu bir dezavantaj olarak grlebilir. Dier taraftan bu tip
sistemlerde Mesh Network' e dahil olan katlmc saysnn artmas ile
birlikte, leklenebilirliinde arttr gzlemlenmektedir. Doal olarak bu bir avantajdr. Dier
modelde ise Mesh Network ierisinde yer alan tm katlmclar(PeerNode) birbirlerine baldr. Bu
durum aadaki ekil ile zetlenebilir.

www.bsenyurt.com Page 321


ounlukla Mesh Network ierisindeki katlmc saylarnn dk olduu durumlarda tercih edilen
bir modeldir. ok doal olarak Mesh alarnda katlmc uygulamalarn birbirlerini bulabilmesi veya
haberleebilmesi iin bir takm protokollerin rol oynamas gerekmektedir. Sz gelimi UDP(User
Datagram Protocol) gibi. Windows Communication Foundation bu amala Peer Name
Resolution Protocol(PNRP) isimli protokol varsaylan olarak kullanmaktadr. Bu
protokol Windows XP Service Pack 2 ve Windows Vista ile birlikte gelmektedir. Ancak
istenirse PNRP yerine kullanlacak zel zcler(Resolver) ele alnabilir ki bu blmde ele
alnacaktr.

PNRP(Peer Name Resolution Protocol) protokol sistemde ykl deilse, Windows


XP Service Pack 2 iin Add Remove Windows Components kmsna girip, Network
Services bileenlerinden Peer to Peer birimini eklemek yeterli olacaktr.

zellikle uygulama gelitirildikten


sonra "System.InvalidOperationException: Resolver must be specified. The
default resolver (PNRP) is not available." gibi bir alma zaman
istisnasnn(Runtime Exception) alnmasnn nedeni ilgili PNRP hizmetinin yklenmemi
olmasdr.

PNRP yklenmesi tek bana yeterli deildir. Peer Name Resolution Protocol
Service alyor olmas gerekmektedir. Bunun iin Administrator Tools blmden yer
alanServices ksmndan yararlanlabilir yada komut satrndan net start pnrpsvc emri
aadaki ekran grntsnde oldugu gibi uygulanabilir.

www.bsenyurt.com Page 322


Ne varki PNRP sadece XP ve Vista iin geerlidir. Sz
gelimi Windows Server 2003 sisteminde altrlamamaktadr. Dier
taraftan PNRP IPv6 alt yapsn kullanmaktadr. Bu nedenle IPv6 destei olmayan
ynlendiricilerin(Routers) olduu sistemlerde ala alnamamaktadr. Ayrca Vista ile
birlikte PNRP 2.0 versiyonu gelmektedir. Buna gre XP ile Vista sistemlerin birbirleriyle
konumas gerektii durumlarda XP sistemler iin ek ykleme yaplmas gerekmektedir.
te bu tip sorunlarn olabilecei vakalarda, zel peer zclerinin(Custom Peer
Resolver) gelitirilmesi ve kullanlmas nerilmektedir. Bu sayede Mesh
Network ierisine dahil olan katlmclarn tutulu ekilleride zelletirilebilir. Sz gelimi
veritaban zerinde saklanabilir.

P2P programlamada nem arz eden konulardan biriside mesajlarn ulatrlma eklidir. Bu noktada
iki farkl teknik bulunmaktadr. Directional ve Flooding. Directional mesajlamaya gre, Mesh
Network ierisinde yer alan herhangibir boumdan(Node) kan mesaj, hedef
bouma(node) ulancaya kadar komu boumlar zerinden ynlendirilir. Floodinghaberlemede
ise mesaj, Mesh Network ierisindeki tm boumlara gnderilir ve mesaj almas gereken boum
tarafndan yakalanr. ok doal olarak Flooding modelinde aynMesh Network ierisinde yer alan
bir boumda alan uygulamaya mesajn defalarca gelmesi sz konusu
olabilmektedir. WCF mimarisi, P2P programlamada Flooding mesajlama modelini
kullanmaktadr. Bununla birlikte WCF gelitiricisi iin en nemli olan noktalardan birisininde
balayc tip seimi olduu bilinmektedir. WCF, P2P iin balayc tip(Binding
Type)olarak NetPeerTcpBinding snfn ele alnmaktadr.

Bu basit teknik detaylardan sonra WCF tarafndan P2P tarz bir uygulamann nasl gelitirilebilecei
adm adm incelenebilir. rnekte PNRP hizmeti yerine CustomPeerResolverServicetipi
kullanlarak bir servis uygulamas tasarlanacak ve IRC benzeri basit bir program ortam
gelitirilecektir. Bu zmsel yaklam ayn zamanda Microsoft tarafndanda nerilmektedir. Bu
amala zel zcy ieren ayr bir servis uygulamas yazlmaldr. rnek olarak bu
bir Console uygulamas olabilir. Sz konusu uygulamann kod ierii aadaki gibidir.

zel zc Service Kodu;

using System;
using System.ServiceModel;
using System.ServiceModel.PeerResolvers;

namespace IRCServer
{
class Program
{
static void Main(string[] args)
{
CustomPeerResolverService resolver = new CustomPeerResolverService();
ServiceHost customResolver = new ServiceHost(resolver);

www.bsenyurt.com Page 323


resolver.Open();
customResolver.Open();
Console.WriteLine("zmleyici aktif. kmak iin bir tua basnz...");
Console.ReadLine();
}
}
}

Burada dikkat edilmesi gereken ilk nokta CustomPeerResolverService snfna ait bir nesne
rnei kullanlmasdr. CustomPeerResolverService snf zel peer zc iin gerekli temel
uyarlamalar(Basic Implementations) iermektedir. Sz konusu
tip IPeerResolverContract arayznden(Interface) tretilmitir. IPeerResolverContractaray
z zellikle peer uyarlamasnda zel ilemler yaplmas istendii durumlarda ele alnmaktadr. Sz
gelimi peer zmleyicisinin veritaban ilikili olmas
isteniyorsa,IPeerResolverContract arayzn uygulayan bir snfn yazlmas ve ilgili yelerin
ezilmesi gerekmektedir. Sonrasnda ise uygulama ierisinde bu snfn, peer zc olarak
kullanlaca belirtilmelidir. rnekte byle bir ihtiya olmadndan .Net Framework 3.0 ile birlikte
gelen hazr CustomPeerResolverService snf kullanlmaktadr.

zc Servise ait konfigurasyon ierii;

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


<configuration>
<system.serviceModel>
<services>
<service
name="System.ServiceModel.PeerResolvers.CustomPeerResolverService">
<endpoint address="net.tcp://localhost:4500/IRCResolver"
binding="netTcpBinding" bindingConfiguration="ResolverBindingConfig"
contract="System.ServiceModel.PeerResolvers.IPeerResolverContract" />
</service>
</services>
<bindings>
<netTcpBinding>
<binding name="ResolverBindingConfig">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>

services elementi ierisine dikkat edilecek


olursa, net.tcp://localhost:4500/IRCResolver adresi zerinden NetTcpBinding balayc tipini
ele alan, herhangibir gvenlik modunun kullanlmad
ve IPeerResolverContract szlemesini(Service Contract) bildiren bir EndPoint tanmlamas
yapld grlmektedir. Elbette, Mesh Network ierisine dahil olacak olan
katlmclarn(PeerNode) birbirleriyle haberleebilmeleri iin tasarlanan bu zel peer zc servis
uygulamasnn alyor olmas gerekmektedir. ok doal olarak bu uygulama a ortamnda bir
sunucu zerinde host edildii takdirde(Sz gelimi Windows Server 2003 zerinde koan
bir Windows Service ierisinden sunulabilir) aa bal tm istemci uygulamalarn
birbirleriyle P2P zerinden haberleebilmesi salanabilir. stelik TCP bazl yaynlama yapld iin
performans asndan da olduka tatmin edici sonular alnacaktr.

www.bsenyurt.com Page 324


stemci tarafnda yer alacak ve Mesh ana katlmc(PeerNode) olarak dahil olacak program basit
bir Windows uygulamas olarak tasarlanmaktadr. Bu uygulamann grsel arayz aadaki
gibidir.

Kullanclar istedikleri bir isim ile Mesh ana dahil olabileceklerdir. Bununla birlikte mesaj
gndermek, dier katlmclarn mesajlarn grmek veya IRC kanalndan ayrlmak gibi ilemleride
yapabileceklerdir. Katlmclar iin nemli olan operasyon sz konusudur. Mesh ana dahil
olmak, adan ayrlmak ve adaki herkese mesaj gnderebilmek. Bunlarn bir servis szlemesine
ait operasyonlar olduu aktr. Dolaysyla istemci tarafnda bu ilevsellikleri barndran bir
szleme arayz tasarlanmaldr. Dier taraftan bu tip bir P2P almada, kanaln ift ynl
iletiim(Duplex Communication) salayacak ekilde alabiliyor olmas ve hatta sz konusu
operasyonlarn asenkron olarak yrtlebilmesi gereklidir. Bu
sebepten DuplexChannel kullanlmas ve operasyonlarn OneWay olarak iaretlenmesi
gereklidir. Windows uygulamasna ait olan Formsnfnn kendisi bu
senaryoda szlemeyi(Service Contract) uygulayan tip olacaktr. Bunlara ek olarak istemci
tarafndan alacak olan kanal iinde IClientChannelarayznn hesaba katlmas gerekmektedir.
Katlmc uygulama tarafndan bakldnda snf diagram(Class Diagram) ierii aadaki
gibidir.

www.bsenyurt.com Page 325


Katlmc uygulamann kodlar aadaki gibidir.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace ChatApp
{
public partial class Form1
: Form
,IIRCSozlesmesi
{
string _kullanici=null;
InstanceContext _instanceContext=null;
DuplexChannelFactory<IIRCChannel> _fabrika = null;
IIRCChannel _katilimci = null;

www.bsenyurt.com Page 326


IOnlineStatus _onlineDurum = null;

public Form1()
{
InitializeComponent();
}

private void Form1_Load(object sender, EventArgs e)


{
btnKatil.Enabled = true;
btnAyril.Enabled = false;
btnMesajiGonder.Enabled = false;
txtMesajlar.ScrollBars = ScrollBars.Vertical;
}

#region IChat Members

public void DahilEt(string uyeAdi)


{
txtMesajlar.Text += String.Format("*** {0} IRC' ye katld. ***", uyeAdi);
txtMesajlar.Text += Environment.NewLine;
}

public void MesajGonder(string uyeAdi, string mesaj)


{
txtMesajlar.Text += String.Format("({0}) -> {1}", uyeAdi,mesaj);
txtMesajlar.Text += Environment.NewLine;
}

public void Ayril(string uyeAdi)


{
txtMesajlar.Text += String.Format("*** {0} IRC' den ayrld. ***", uyeAdi);
txtMesajlar.Text += Environment.NewLine;
}

#endregion

private void btnKatil_Click(object sender, EventArgs e)


{
if (!String.IsNullOrEmpty(txtKullaniciAdi.Text))
_kullanici = txtKullaniciAdi.Text;
else
_kullanici = "simsiz";

_instanceContext = new InstanceContext(this);


_fabrika = new DuplexChannelFactory<IIRCChannel>(_instanceContext,
"ClientEndPoint");
_katilimci = _fabrika.CreateChannel();
_onlineDurum = _katilimci.GetProperty<IOnlineStatus>();

_onlineDurum.Online += delegate(object snd, EventArgs ea)


{
txtMesajlar.Text += "*** Hat Ak ***";
txtMesajlar.Text += Environment.NewLine;
txtMesajlar.Text += _onlineDurum.ToString();
txtMesajlar.Text += Environment.NewLine;

www.bsenyurt.com Page 327


};
_onlineDurum.Offline += delegate(object snd, EventArgs ea)
{
txtMesajlar.Text += "*** Hat Kapal ***";
txtMesajlar.Text += Environment.NewLine;
txtMesajlar.Text += _onlineDurum.ToString();
txtMesajlar.Text += Environment.NewLine;
};
_katilimci.Open();
_katilimci.DahilEt(_kullanici);

btnKatil.Enabled = false;
btnAyril.Enabled = true;
btnMesajiGonder.Enabled = true;
}

private void btnAyril_Click(object sender, EventArgs e)


{
_katilimci.Ayril(_kullanici);
_katilimci.Close();
_fabrika.Close();

btnKatil.Enabled = true;
btnAyril.Enabled = false;
btnMesajiGonder.Enabled = false;
}

private void btnMesajiGonder_Click(object sender, EventArgs e)


{
_katilimci.MesajGonder(_kullanici, txtMesaj.Text);
txtMesaj.Clear();
}
}

public interface IIRCChannel


: IIRCSozlesmesi, IClientChannel
{
}

[ServiceContract(CallbackContract = typeof(IIRCSozlesmesi))]
public interface IIRCSozlesmesi
{
[OperationContract(IsOneWay = true)]
void DahilEt(string uyeAdi);

[OperationContract(IsOneWay = true)]
void MesajGonder(string uyeAdi, string mesaj);

[OperationContract(IsOneWay = true)]
void Ayril(string uyeAdi);
}
}

IIRCSozlemesi isimli arayz(Interface), servis szlemesini tanmlamaktadr. Bu szleme


ierisinde yer alan DahilEt, MesajGonder ve Ayril isimli operasyonlar asenkron(asynchronous)
olarak almaktadr ve tek ynldr(OneWay). Bu sebepten IsOneWay zelliklerine true deeri

www.bsenyurt.com Page 328


atanmtr. Dier taraftan CallbackContract olarak IIRCSozlesmesiarayznn kendisi
bildirilmitir. Bilindii gibi ift ynl iletiim(Duplex Communication) kurulacandan bir geri
bildirim szlemesinin(Callback Contract) tanmlanmas gerekmektedir. Bylece istemciler
birbirleri zerinden bamsz olarak operasyon arlar gerekletirebilir ki, P2P haberlemede
taraflarn birbirleri zerinde operasyon geri bildirimlerinde bulunmas gereklidir. Bu sayede bir
katlmcnn gnderecei bir mesaj Mesh aa dahil olan dier kullanclarada iletilebilir. (Client
Callback ile ilikili detayl bilgi iin daha nceki bir makaleden de yararlanabilirsiniz).

rnekte yer alan form uygulamasnn kendisine ait nesne rnei, Mesh an bir katlmcs olarak
rol oynamaktadr. Bu sebepten InstanceContext rnei oluturulurken parametre
olarak this verilmitir. (Burada this doal olarak alma zamannda Form1 nesne rneini iaret
etmektedir.) Sonrasnda ise bir DuplexChannelFactory<T> nesne rnei, InstanceContext nesne
rneinin kendisi ve konfigurasyon dosyasnda belirtilen EndPoint deeri iin
rneklenmektedir. DuplexChannelFactory<T> generic snf ile, ift ynl iletiimi ele alacak olan
bir referansn retilmesi salanmaktadr. Bu katlmclarn her biri ift ynl iletiimi salayabilecek
ekilde birer kanal, Mesh ana doru amaktadr. Bu kanaln oluturulmas srasndada
devreye CreateChannel metodu girmektedir. Mesh ana dahil olan kullanc referansndan
yararlanlarak online veoffline olma durumlarna ait olaylar da ele alnabilir. Bu
amala IOnlineStatus arayznn alma zamannda tad referanstan yararlanlmaktadr.
rnekte nemli olan noktalardan biriside konfigurasyon ierisinde yer alan istemci
tarafl EndPoint bildirimidir. Sz konusu uygulama iin bu bildirim aadaki gibidir.

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


<configuration>
<system.serviceModel>
<client>
<endpoint address="net.p2p://BizimIRC" binding="netPeerTcpBinding"
bindingConfiguration="Varsayilan" contract="ChatApp.IIRCSozlesmesi"
name="ClientEndPoint" />
</client>
<bindings>
<netPeerTcpBinding>
<binding name="Varsayilan" port="0">
<security mode="None" />
<resolver mode="Custom">
<custom address = "net.tcp://localhost:4500/IRCResolver"
binding="netTcpBinding" bindingConfiguration="ResolverBindingConfig" />
</resolver>
</binding>
</netPeerTcpBinding>
<netTcpBinding>
<binding name="ResolverBindingConfig">
<security mode="None"/>
</binding>
</netTcpBinding>
</bindings>
</system.serviceModel>
</configuration>

Konfigurasyon dosyasnda dikkat edilmesi gereken en nemli noktalardan


birisi netPeerTcpBinding elementi ierisinde yer alan resolver boumudur. Bu boum
ierisinde modeniteliine(attribute) verilen Custom deeri ile zel bir peer zc servisinin
kullanlaca ifade edilmektedir. Dier tarafan sz konusu zel peer zc servisin hangi adres
zerinden host edilii , hangi balayc tipin(Binding Type) kullanld bilgileri ise custom isimli
elementin address ve binding niteliklerinde belirtilmektedir. Dikkat edilecek
olursaaddress niteliinin deeri servis uygulamasnn host ettii adrestir. client elementi

www.bsenyurt.com Page 329


ierisinde tanmlanan endpoint boumunda ise address ksmnda net.p2p://BizimIRC adresi
yer almaktadr. Bu adres Mesh ann adresi olarakta dnlebilir. Bir baka deyile katlmclarn
dahil olaca Mesh ann yolu tayin edilmektedir. Ayrca balayc tip
olarak netPeerTcpBinding kullanlmaktadr. Gelitirilen rnek gvenlik ile ilikili olaraktan ek bir
zellik iermemektedir. Bu nedenle security elementlerinde yer alan modedeerleri None olarak
bildirilmitir. netPeerTcpBinding elementinde yer alan port niteliinin deeri 0 olduu iin,
katlmc uygulamalar altklar makinede bo bulduklar bir port zerinden kanal oluturacaklar ve
Mesh ana aacaklardr. (.Net Remoting mimarisinde gelitirilen rneklerdede port deerine 0
verilmesi ile ayn anlamda olduuna dikkat edelim.) Artk uygulamalar test edilebilir. Aadaki
Flash animasyonunda senaryoya ait sonular irdelenmektedir. (Flash Video boyutu 560 Kb olup
yklenmesi sabr isteyebilir.)

Grld gibi B isimli katlmc Mesh ana dahil olduktan sonra sistem online moda gemitir.
Bununla birlikte Mesh ana giren her kullanc bilgisi dier bal PeerNode' larada annda iletilir.
Bylece katlmclar aa dahil olan kullanclar grebilmektedir. Katlmclarn gnderikleri mesajlar
dier tm katlmclarn ekrannda annda grlebilmektedir. Dier taraftan adan ayrlan
katlmclarn bilgileride dierlerine iletilmektedir. Burada ilgi ekici noktalardan biriside her katlmc

www.bsenyurt.com Page 330


iin ayr Peer Node ID deerlerinin retilmesidir. Sistemin offline moda gemesi ise sadece bir
katlmc kalmas durumunda meydana gelmektedir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde WCF mimarisi zerinde P2P(Peer-
to-Peer) programlamaya giri yapmaya altk ve rnek olarak basit bir IRC senaryosu gelitirdik.
Senaryoda, var olan PNRP(Peer Name Resolution Protocol) servisi yerine .Net Framework ile
birlikte gelen CustomPeerResolverService snfn kullandk. lerleyen makalelerimizde P2P
tabanl senaryolarda, gelitirici tarafndan yazlm zel bir peer zmleyici servisin nasl ele
alnabileceini ve gvenlii nasl salayabileceimizi incelemeye alacaz. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Performans ( 20.05.2008 ) - WCF


Deerli Okurlarm Merhabalar,

Uzun bir aradan sonra tekrar birlikteyiz. Windows Communication Foundation mimarisinin
gelitirilmesininin tek amac, var olan datk mimari modellerini bir at altnda birletirmek
deildir. Buna paralel olaraktan WCF mimarisi, .Net Remoting, Xml Web Servisleri, WSE(Web
Service Enhancements), MSMQ(Microsoft Message Queue), COM+ gibi pek ok datk
uygulama gelitirme modelinin alma zaman alt yapsnn kolayca oluturulabilmesinide
hedeflemektedir. Burada dekleratif programlama modelinin benimsenmesinin nemli katks vardr.
Sonuta gelitiricinin sklkla yapmak zorunda kald alt yap hazrlklarnn attribute(nitelik) veya
konfigurasyon bazl olacak ekilde ayarlanabilmesi son derece avantajldr. Bu adan bakldnda
olayn kilit noktas WCF' in ABC(AddressBindingContract)' sinde yer alan balayc
tiplerdir(Binding Types). Bilindii zere WCF mimarisi .Net Framework 3.0 ile birlikte
gelmitir. Bununla birlikte u an itibariyle .Net Framework 3.5 srmnde ek yeniliklerde
iermektedir(rnein Web Programlama Modeli, WorkFlow Foundation ile Tam
Entegrasyon, JSON, AJAX destei gibi). Balayc tiplerin saysnn ok olmasnn, gelitiricilerin
karar verme noktasndaki ilerini zorlatrdda bir gerektir. Bu nedenle ounlukla yardmc
tablolardan veya diagramlardan yararlanlmaktadr.

Yazn geldii bu scak gnlerde yazdmz bu makalemizde, biraz hafiften ilerleyecek ve bu


balayc tiplerden ok sk kullanlanlar arasndaki performans farklarn incelemek iin nasl bir yol
izleyebileceimizi incelemeye alacaz. Nitekim senaryoya gre seilebilecek balayc tiplerin
birden fazla olmas halinde performans kriterleri n plana kmaktadr. ncelikli olarak u anda
kullanlan balayc tipler ve aralarndaki belirgin farkllar gz nne almakta yarar vardr. te
aadaki tablo bu farkllklar dile getirmektedir.

www.bsenyurt.com Page 331


Grld gibi balayc tiplerin birbirlerine gre farkl kullanm sahalar ve senaryolar
bulunmaktadr. Buradaki balayc tiplerde yeterli gelmiyorsa bu durumda zel balayc
tiplerin(Custom Binding Type) yazlmasda tercih edilebilir ki baz senaryolarda(rnein Front-
End Service yazlmas gereken durumlar veya Reply Attack gibi vakalarda) bu gereklidir.
Yukardaki tablo karar vermek iin tam olarak yeterli deildir. Karar verirken ele alnmas gereken
sorular arasnda platform bamszlk(Interoperability), gvenilirlik(Relaibiliyu),
performans, WS-* artnameleri(Specifications), gvenlik(Security) gibi pek ok kriter
bulunmaktadr. te bu noktada da devreye aadaki gibi bir tablo girmektedir.

www.bsenyurt.com Page 332


Grld gibi bu tabloda yer alan kriterlerden yararlanarak hangi balayc tipin kullanlaca
kolay bir ekilde kararlatrlabilir. Sz gelimi ift ynl(Duplex)iletiimin sz konusu olduu bir
vaka varsa, kriterler snrldr. Bir baka deyile byle bir
senaryoda WsDualHttpBinding, NetTcpBinding, NetNamedPipeBinding veNetPeerTcpBindi
ng tiplerinden birisi kullanlabilir. Ancak karar vermek halen daha zor olabilmektedir. Belkide bir
balang noktas olsa bu i daha da kolaylaabilir. O halde bir ak emas son derece yerinde olur.
Mesela;

www.bsenyurt.com Page 333


ncelikli olarak baka servisler ile uyumlu bir ekilde konuulup konuulmayacana karar verilerek
balayan bu i aknn farkl versiyonlarda bulunmaktadr. Ancak Juval Lwy ve Steve Resnic' in
nerdii rnek karar verme admlarndan biriside bu izelgedir. Karar vermede nemli olan
kriterlerden biriside elbetteki Performans' tr. ounlukla gerek hayat ortamlarnda, yazlan
uygulamalarn gerek deeri performanslar ile llmektedir. Bu durumda akla gelen sorulardan
ilki vakaya gre hangi balayc tipin en iyi performans verdiidir. te yazmzn bu blmnden
itibaren 4 temel ve sk kullanlan balayc tip arasndaki saniye bana den ar(Calls Per
Seconds) saylarn test edeceimiz rnek bir senaryo zerinde durmaya alacaz.
Vakamzda NetTcpBinding, WsHttpBinding, BasicHttpBinding veNetNamedPipeBinding bal
ayc tipleri ele alnmaktadr.

Bilindii zere NetTcpBinding balayc tipi ounlukla intranet tabanl sistemlerde yksek
performans ile gz nne kmaktadr. Ne varki WS destekli servisler ile konuulmas gereken
vakalarda WsHttpBinding balayc tipi sklkla deerlendirilmektedir. Tm bunlarn yannda
zellikle WS Basic Profile 1.1 ve ncesi yazlm Web Servisleri ile olan
haberlemede BasicHttpBinding biilmi kaftandr. Elbette yle vakalar vardrki ayn makine
zerinde komakta olan servislerin bir birleriyle haberlemesi sz konusudur. ok doal olarak
byle bir durumda NetNamedPipeBinding tipi n tarafa kmaktadr.

.Net Framework 3.0 ile birlikte, WCF tarafnda gelitirilen servislerinin performans
deerlerinin llebilmesi amacyla, ServiceModelEndPoint, ServiceModelOperation,
ServiceModelService isimli performans nesneleri(Performance
Objects) gelmektedir. Bu deerler Performance Monitor arac yardmyla ele alnabilir
yada kod tarafndan deerlendirilebilir.

Dilerseniz rnek zerinden devam edelim. ncelikli olarak kendimize bir adet WCF Servis
Library gelitiriyor olacaz. (Sz konusu servis ktphanesi Visual Studio 2008 kullanlarak.Net
Framework 3.5 ablonunda gelitirilmitir.) Servis tarafna sunulacak
olan szleme(Contract) ve uygulayc tipin ierii aadaki gibidir.

www.bsenyurt.com Page 334


ITester arayz(Interface);

using System;
using System.ServiceModel;

namespace ProcessLib
{
[ServiceContract]
public interface ITester
{
[OperationContract]
string GetString();
}
}

Szlemeyi uygulayan Tester snf(Class);

using System;

namespace ProcessLib
{
public class Tester
:ITester
{
#region ITester Members

public string GetString()


{
return "".PadRight(1000, 'Q');
}

#endregion
}
}

Servis szlemesinin sunduu operasyon sadece string dndren bir metoda sahiptir. Test
srasnda bu metod kullanlaraktan istemci tarafndan yaplan ykl operasyon arlarnn sonular
irdelenmeye allacaktr. Artk Host uygulamann yazlmasna balanabilir. Olaylarn basit ekilde

www.bsenyurt.com Page 335


analiz edilebilmesi iin Host uygulama Consoleolarak tasarlanmaktadr. Bu uygulama kendi
ierisinden 4 farkl EndPoint sunmaktadr. Bunlar vakada yer alan balayc tiplerin her biri iin ele
alnmaktadr. Bu amala konfigurasyon dosyasnn ierii aadaki gibi gelitirilebilir. (Bu aamaya
gelmeden nce Host uygulamaya System.ServiceModel.dll ve WCF Snf Ktphanesine ait
assembly nesnelerinin eklenmesi gerektiinide hatrlayalm.)

Host uygulama tarafndaki konfigurasyon (App.Config) ierii;

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


<configuration>
<system.serviceModel>
<diagnostics performanceCounters="All" />
<services>
<service name="ProcessLib.Tester">
<endpoint address="net.tcp://localhost:9000/TesterService"
binding="netTcpBinding" bindingConfiguration="" name="TesterServiceTcpEndPoint"
contract="ProcessLib.ITester" />
<endpoint address="http://localhost:9001/TesterService"
binding="basicHttpBinding" name="TesterServiceHttpEndPoint" contract="ProcessLib.ITester"
/>
<endpoint address="http://localhost:9002/TesterService"
binding="wsHttpBinding" bindingConfiguration="" name="TesterServiceWsHttpEndPoint"
contract="ProcessLib.ITester" />
<endpoint address="net.pipe://localhost/TesterService"
binding="netNamedPipeBinding" bindingConfiguration="" name="TesterServicePipeEndPoint"
contract="ProcessLib.ITester" />
</service>
</services>
</system.serviceModel>
</configuration>

Konfigurasyon dosyasnda en ok dikkat eken noktalardan biriside diagnostics isimli elementtir.


Bu elementin ierisinde yer alan performanceCounters niteliine atanan All deeri
sayesindePerformance Monitor zerinden lmler yaplabilmektedir. Bu sebepten servis
tarafndaki konfigurasyon dosyasnda mutlaka bildirilmelidir.

Host Uygulama Kodlar;

using System;
using System.ServiceModel;
using ProcessLib;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Tester));
host.Open();
Console.WriteLine("Servis dinlemede\nKapatmak iin bir tua basn");
Console.ReadLine();
host.Close();
}
}

www.bsenyurt.com Page 336


}

Host uygulama 4 farkl EndPoint zerinden hizmet vermektedir. Tm EndPoint' ler Tester isimli
servis tipini kullanmaktadr. Buna gre 4 farkl tipte istemcinin bu servis zerinden hizmet almas
mmkndr. stemci tarafn gelitirmeden nce gerekli proxy tipinin retimi
iin svcutil aracndan aadaki ekran grntsnde yer ald gibi yararlanlabilir.

Artk istemci uygulamann gelitirilmesine balanabilir. Buradada rnei basit bir ekilde ele
alabilmek iin bir Console uygulamas gz nne alnmaktadr. Yine nemli olan nokta
konfigurasyon dosyasnn ieriidir. Drt EndPoint iin testler ayn istemci zerinden
yaplacandan konfigurasyon ierii aadaki gibi tasarlanmtr.

stemci uygulama konfigurasyon(App.config) ierii;

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


<configuration>
<system.serviceModel>
<client>
<endpoint address="http://localhost:9001/TesterService"
binding="basicHttpBinding" contract="ITester" name="ClientHttpEndPoint" />
<endpoint address="net.tcp://localhost:9000/TesterService"
binding="netTcpBinding" bindingConfiguration="" contract="ITester"
name="ClientTcpEndPoint" />
<endpoint address="http://localhost:9002/TesterService"
binding="wsHttpBinding" bindingConfiguration="" contract="ITester"
name="ClientWsHttpEndPoint" />
<endpoint address="net.pipe://localhost/TesterService"
binding="netNamedPipeBinding" bindingConfiguration="" contract="ITester"
name="ClientPipeEndPoint" />
</client>
</system.serviceModel>
</configuration>

www.bsenyurt.com Page 337


stemci uygulamann kodlar;

using System;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Balayc tipi seiniz...");
Console.WriteLine("NetTcpBinding iin 1");
Console.WriteLine("BasicHttpBinding iin 2");
Console.WriteLine("WsHttpBinding iin 3");
Console.WriteLine("NetNamedPipeBinding iin 4");

string secim=Console.ReadLine();
Console.WriteLine("Saya Deerini Giriniz");
int sayac;
if (!Int32.TryParse(Console.ReadLine(), out sayac))
sayac = 100000;

switch (secim){
case "1":
TestiBaslat("ClientTcpEndPoint",sayac);
break;
case "2":
TestiBaslat("ClientHttpEndPoint", sayac);
break;
case "3":
TestiBaslat("ClientWsHttpEndPoint", sayac);
break;
case "4":
TestiBaslat("ClientPipeEndPoint", sayac);
break;
default:
TestiBaslat("ClientTcpEndPoint", sayac);
break;
}
}

private static void TestiBaslat(string baglayici,int testSayisi)


{
Console.WriteLine("Test Balad\nDeneme Sayisi {0}\nSeilen EndPoint
{1}",testSayisi,baglayici);
TesterClient client = new TesterClient(baglayici);
for (int i = 0; i < testSayisi; i++)
{
string result = client.GetString();
}
Console.WriteLine("Test tamamland...");
client.Close();
}
}
}

www.bsenyurt.com Page 338


stemci uygulama GetString isimli metodu sembolik olarak girilen deer kadar (varsaylan
olarak 100000(Yzbin) kere) armaktadr. Bu bize test iin yeterli sreyide vermektedir. Dier
taraftan elbetteki bu test deerleri makinenin zelliklerine gre farkllk gsterecektir. Dier
taraftan balayc tipler arasndada belirgin farkllklar olduu gzlenecektir. Bunun en byk
nedenlerinden birisi ilgili balayc tipin arka tarafta kulland kodlama(Encoding) ve iletiim
protokoldr(Transport Protocol). (Makalede yer alan rnein testlerinin yapld makine 1 Gb
RAM kapasiteli olup, Intel Centrino ilemcilidir. Ayrca Windows XP Service Pack 2 iletim sistemine
sahiptir. Testlerde yer alan istemci ve sunucu uygulama ayn makine zerinde komaktadr.)

Artk testlere balanabilir. Performance Counter zerinden alma zaman lmlerinin


yaplabilmesi iin servis uygulamasnn alyor olmas gerekmektedir. Sonrasnda
ise Performance Monitor kullanlarak lmler yaplabilir. Performance Monitor uygulamasna
komut satrndan perfmon yazlarak ulalabilir. Servis uygulamas balatldnda Counter olarak
eklenebilecek seeneklerde ilgili servis uygulamasna ait rnek grlebilecektir.

Biz testlerimizde ServiceModeService 3.0.0.0 Performans nesnesinin Calls Per Second isimli
sayacn kullanyor olacaz. Bu saya servise gelen saniye bana operasyon arlarn
gstermekte olup balayc tiplerin alt yap hazrlklar nedeni ile ne kadar yava veya ne kadar hzl
olduklarn gstermektedir. Performance Monitor sonular test programnda kullanlan her
balayc tip iin aadaki ekran ktlarnda olduu gibidir.

NetTcpBinding iin Calls Per Second sonular;

www.bsenyurt.com Page 339


BasicHttpBinding iin Calls Per Second sonular;

WsHttpBinding iin Calls Per Second sonular;

NetNamedPipeBinding iin Calls Per Second sonular;

www.bsenyurt.com Page 340


Tm bunlar bir arada deerlendirildiinde, saniye bana den operasyon arlar iin
aadaki grafikte grlen sonular ortaya kmaktadr. Bu grafikte tepe noktalarnn yaklak
maksimum ve ortalama deerleri ele alnmaktadr. Bu en azndan tahmini olarak, bu drt balayc
tip arasndaki performans farkllklar hakknda fikir vermektedir.

ok doal olarak ayn makine zerinde alan servisler aras haberlemede tercih
edilen NetNamedPipeBinding iin en yksek deerler ortaya kmaktadr. Dier taraftan
zellikle TCP ve Binary seriletirme kullanan NetTcpBinding deerleride olduka yksektir.
Bunlarn yannda WsHttpBinding gerekten ok dk deerler ile gze arpmaktadr. Bunun en
byk nedeni WS standartlarna gre mesajlarn hazrlanmas srasnda geen sre kayplardr.
Tabiki bu kriter tek bana yeterli deildir. Sz gelimi servisin Host edildii sunucunun operasyon
bana maliyet(Cost Per Operation) gibi performans deerleride gz nne alnabilir. Bu ve
daha pek ok performans testi yaplabilir.

Buraya kadar anlatlanlar gz nne alndnda sadece balayc tipler arasndaki farkllklar analiz
etmek iin basit olarak nasl bir yol izlenebilecei ele alnmtr. Bunun dnda WCF ile gelitirilen

www.bsenyurt.com Page 341


servislerin Xml Web Serviceleri, .Net Remoting veya COM+ ile gelitirilen modellere gre belirgin
performans farkllklar olduu bilinmektedir. Bu konu ile ilikili daha detayl
bilgiye http://msdn.microsoft.com/en-us/library/bb310550.aspx ulaabilirsiniz. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF ile WF Entegrasyonu - 2 ( 23.04.2008 ) -


WCF
Deerli Okurlarm Merhabalar,

Bir nceki yazmzda WCF(Windows Communication Foundation) servislerinin, WF(Windows


WorkFlow) uygulamalar ierisinden nasl arldn incelemitik. Bu yazmzda ise tam tersine,
bir Workflow rneinin servis olarak nasl sunulabileceini analiz ediyor olacaz. Baz durumlarda
kod aklarnn birer servis olarak istemcilere sunulmas gerekebilir. Burada sz konusu kod
aklarnn Servis Ynelimli Mimarinin(Service Oriented Architecture) imkanlarndan
yararlanyor olmas istei n plana kmatadr. ok doal olarak servis gibi yaynlanan ak
tipleri(Workflow Instance), istemci ile olan mesajlamalarnda SOA temelli olanaklar
kullanabilir hale gelmektedir. Bu noktada WCF ile WFentegrasyonu gz nne alnmaldr.

WCF servisleri WF uygulamalar ierisinden arlrken arlkl olarak .Net Framework 3.5 ile
birlikte gelen SendActivity bileeni kullanlmaktadr. WF rneklerinin servis olarak yaynlamasnda
ise barol oyuncusu yine .Net Framework 3.5 ile birlikte gelen ReceiveActivity isimli activity
bileenidir. zellikle Visual Studio 2008 kullanlarak servis destekliWorkflow ktphaneleri kolay
bir ekilde gelitirilebilmektedir. Bu amala Visual Studio
2008 ortamna Sequential Workflow Service Library ve State Machine Workflow ServiceLi
brary proje ablonlar eklenmitir. Tabi ok doal olarak gelitirilen i ak servislerinin bir
uygulama tarafndan barndrlmas(Hosting) ve yaynlanmasda
gerekmektedir. Host seenekleri WF servisleri iinde ayndr. IIS zerinde, WAS(Windows
Activation Service) yardmyla veya Self-Hosting seeneklerine gre barndrma ve yaynlama
yaplabilir. nemli olan noktalardan birisie normal WCF servislerinden farkl olaraktan Host alma
ortamn WorkflowServiceHost tipinin ynetmesidir.

WF uygulamasnn servis olarak yaynlanmas iin istemcilere bir szleme(Contract) bildirimi


yaplmas gerekmektedir. ok doal olarak bu szleme(Contract) birarayz(Interface) olarak
tanmlanmaldr. Arayz ierisinde yer alan operasyonlar darya ReceiveActivity bileeni ile
sunulabilirler. Buna gre szleme ierisinde tanmlanan her operasyon
iin(OperationContract nitelii ile imzalanm metodlar) birer ReceiveActivity oluturulmaldr.
Bu noktada karlalan nemli sorulardan biriside, istemcinin bu operasyona nasl parametre
gnderecei veya cevap alacadr. Nitekim bir WCF ktphanesinde ounlukla asl ii yapan
bileen, szleme tipinin uyguland bir snftr(Class). WF asndan bakldnda ise bu
grevi Workflow snf ierisinde
tanmlanan zellikler(Properties) yada alanlar(fields) stlenmektedir. Bir baka
deyile, ReceiveActivity irtibatta olduu operasyon iin gerekli parametreler ile haberlemek
adna sz konusu zellik veya alanlardan yararlanr. Dolaysyla asl iReceiveActivity ierisinden
yaplmaldr. ReceiveActivity bileeninin composite bir bileen olarak tanmlanmasnn sebebide
budur. ReceiveActivity ierisine rneinCodeActivity gibi bileenler dahil edilerek operasyonun
asl iinin yaplaca kod bloklarnn iletilmesi salanabilir. stemci asndan olaya bakldnda

www.bsenyurt.com Page 342


yine bir proxynesnesinin servis ile olan haberlemeyi salad ortadadr. Aslnda aadaki ekil
durumu biraz daha kolay bir ekilde aklamaktadr.

ekle gre WorkflowActivity snfnn ReceiveActivity bileenleri, darya servis zerinden


sunulan operasyonlar ile ilikili talep alma ve cevap gnderme ilemlerini stlenmektedir. ok doal
olarak servisi bir EndPoint zerinden darya sunmak gerekmektedir. EndPoint tanmnda dikkat
edilmesi gereken noktalardan biriside, balayc tipin(Binding
Type) basicHttpContextBinding, netTcpContextBinding yada wsHttpContextBinding bilee
nlerinden birisi olmasldr. Bu balayc tiplerin ortak zellii servis destekli i aklar(Service-
Enabled Workflow) ile haberleilebilmesini salamalardr. Ancak istenirse zel
balayclara ContextBindingElement tipi uygulanarak workflow destekli hale getirilmeleride
salanabilir. stemci uygulama ok doal olarak servis ile olan haberleme srasnda proxy
snfndan yararlanmak durumundadr.

WF ve WCF entegrasyonun bir sonucu olarak istemciler bir Workflow aktivitesini servis
bazl olacak ekilde arp kullanabilmektedir. Bylece istemciler bir kod ak
srecini servis tabanl dnerek ele alabilirler.
Buna JSON(JavaScriptObjectNotation) gibi mesajlama desteklerinin eklenebilecei
dnldnde birWorkflow rneinin herhangibir platform zerinden
kullanlabilmeside mmkn hale gelmektedir. Bu WCF tanmnda yer alan "her hangibir
CLR tipinin servis olarak yaynlanabilmesi" ilkesinin bir sonucu olarak grlebilir.

Bu kadar karmak ve teorik bilgiden sonra rnek bir uygulama zerinden hareket
ederek WF uygulamalar ierisinde servis yaynlamasnn nasl yaplabileceini adm adm
incelemeye alalm. e ilk olarak servis szlemesini ve operasyonlar iin gerekli aktivite

www.bsenyurt.com Page 343


bileenlerini ierecek olan ktphaneyi tasarlamak ile balamak doru olacaktr. Bu amala Visual
Studio 2008 ortamnda bir Sequential Workflow Service Library projesi atmz
dnelim.(Bu ablon New Project->WCF sekmesi altnda yer almaktadr.)

Sz konusu servis ktphanesine(WFSiparisKutuphanesi) bakldnda ilk dikkati eken nokta


referanslar ksmna Workflow destei iin eklenen assembly' lardr.

Bu noktada ablon olarak getirilen IWorkflow1.cs, Workflow1.cs ve App.config isimli dosyalar


silinmitir. rnekte kullanlan servis szlemesi ierii ise aadaki snf diagramnda grld
gibidir.

www.bsenyurt.com Page 344


using System;
using System.ServiceModel;
using System.Runtime.Serialization;

namespace WFSiparisKutuphanesi
{
[ServiceContract(Namespace = "http://www.bsenyurt.com/UrunSiparisServisi",
Name = "UrunSiparisServisi")]
public interface ISiparisSozlesmesi
{
[OperationContract]
string SiparisVer(UrunBilgisi urun);
}

[DataContract]
public class UrunBilgisi
{
[DataMember]
public string UrunKodu { get; set; }
[DataMember]
public int Adet { get; set; }
[DataMember]
public DateTime SiparisTarihi { get; set; }
}
}

ISiparisSozlesmesi isimi servis szlemesi(Service Contract) SiparisVer isimli tek bir


operayon sunmaktadr. SiparisVer metodu parametre olarak UrunBilgisi snfna ait bir nesne
rnei almaktadr. Bu nesneye ait veri, alma zamannda istemci tarafndan servise doru
geleceinden seriletirilebilir olmas gerekmektedir. Bu sebepten doal olarak veri
szlemesi(Data Contract) olacak ekilde tasarlanmtr. SiparisVer isimli operasyon ayn
zamanda geriye string tipinden bir deerde dndrmektedir. Bylece darya sunulacak olan
servis szlemesi tanmlanmtr. Artk bu szlemeyi kullanacak olan aktivite snfnn yazlmas
gerekmektedir. rnekte bunun iin bir adet Sequential Workflow Activity snf ele alnacaktr.
Bunun iin projeye Add->Sequential Workflow seenei ile yeni bir ak snf eklenmelidir.

www.bsenyurt.com Page 345


Bu admda Sequential Workflow(with code seperation) seenei iaretlenerek devam
edilebilir. Bylece dizayn taraf ile kodu birbirinden ayr tutacak bir ak tipi oluturulacaktr.

WFSiparis.xoml (XOML-eXtensible Object Markup Language) tasarm zamannda gerekli


aktivite tiplerini barndracaktr. WFSiparis isimli snf SequentialWorkflowActivity tipinden
tremektedir. Servis szlemesi ierisinde yer alan SiparisVer metodu bu ak nesnesi
ierisinde ReceiveActivity bileeni tarafndan ele alnmaldr. Bununla
birlikte SiparisVermetodunun UrunBilgisi ve dndrecei deer iin
birer zellik/alan(Property/Field) iermesi gerekmektedir. ncelikli olarak
bir ReceiveActivity bileeni tasarm ekranna srklenip
braklmaldr. ReceiveActivity bileeni SendActivity bileenine benzer
olaraktan ServiceOperationInfo zelliini iermektedir. ok doal olarak bu zellikten
yararlanlarak hangi operasyonun ele alnaca ve kullanlacak(yada otomatik olarak

www.bsenyurt.com Page 346


retilecek) olan parametreler belirlenmelidir. ServiceOperationInfo zelliinde yer alan nokta
dmesine basldktan sonra aadaki arayz ile karlalr.

Burada yine Import seenei kullanlarak aadaki ekran grntsnde olduu gibi ilgili servis
szlemesinin seilmesi gerekmektedir.

ok doal olarak ISiparisSozlesmesi otomatik olarak gelecektir. Bu noktada Workflow ierisinde


birden fazla servis szlemesi tutulabilecei de unutulmamaldr. Bu seim ilemini takiben
aadaki ekran grnts elde edilir ve artk operasyon seimi ve bunun iin gerekli snf
zelliklerinin oluturulmas admna geilebilir.

www.bsenyurt.com Page 347


Dikkat edilecei zere Parameters ksmnda String tipinden yn Out olan
ve UrunBilgisi tipinden yn In olan birer parametre grlmektedir. Bu parametrelerin ak
ierisinde ele alnmas iin karl olan zelliklerin veya alanlarn snf ierisine ya manuel yada
otomatik olarak dahil edilmesi arttr. Sonu olarak aadaki ekran grnts ile karlalacaktr.

www.bsenyurt.com Page 348


Burada ReturnValue ve urun zellikleri iin otomatik zellik rettirilmesi salanabilir. Sz gelimi
aadaki ekran grntsnde rnek olarak SiparisVer metodunun geri dn tipi iin otomatik
zellik rettirilmesinin nasl saland gsterilmektedir.

Ayn ilem urun zellii iinde yapldktan sonra receiveActivity1 iin son durum aadaki gibi
olacaktr.

ok doal olarak bu yaplan deiiklikler sonrasnda WFServis isimli snfn ierii aadaki gibi
deiecektir.

namespace WFSiparisKutuphanesi
{
public partial class WFSiparis : SequentialWorkflowActivity
{
public static DependencyProperty receiveActivity1_urun1Property =
DependencyProperty.Register("receiveActivity1_urun1", typeof(WFSiparisKutuphanesi.UrunBilgisi),
typeof(WFSiparisKutuphanesi.WFSiparis));

www.bsenyurt.com Page 349


public static DependencyProperty receiveActivity1__ReturnValue_1Property =
DependencyProperty.Register("receiveActivity1__ReturnValue_1", typeof(System.String),
typeof(WFSiparisKutuphanesi.WFSiparis));

[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Parameters")]
public UrunBilgisi receiveActivity1_urun1
{
get
{
return
((WFSiparisKutuphanesi.UrunBilgisi)(base.GetValue(WFSiparisKutuphanesi.WFSiparis.receiveActivit
y1_urun1Property)));
}
set
{
base.SetValue(WFSiparisKutuphanesi.WFSiparis.receiveActivity1_urun1Property, value);
}
}

[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Parameters")]
public string receiveActivity1__ReturnValue_1
{
get
{
return
((string)(base.GetValue(WFSiparisKutuphanesi.WFSiparis.receiveActivity1__ReturnValue_1Property
)));
}
set
{
base.SetValue(WFSiparisKutuphanesi.WFSiparis.receiveActivity1__ReturnValue_1Proper
ty, value);
}
}
}
}

Artk ReceiveActivity ierisine istemcilere dndrlecek olan cevap iin


gerekli activity bileeninin eklenmesi admna geilebilir. Sonu itibariyle
istemciler SiparisVer metoduna arda bulunduktan sonra bir aktivitenin iletilmesi
gerekmektedir. Bu aktivite ReceiveActivity ierisinde tanmlanabilir. Sz gelimi CodeActivity bu
ilem iin idealdir. Operasyona istemciden gelen bilgi, aktivite
snfnn receiveActivity1_urun1 zellii zerinden elde edilebilir. Metoddan istemciye
dndrlecek olan string deer isereceiveActivity1_ReturnValue1 zelliine set edilmelidir. Bu
atama ilemide CodeActivity bileeni ierisinde yaplabilir. (Burada CodeActivity kullanlmas art
deildir. nemli olan aktivite snf ierisine eklenen zellikler yardmyla istemciden operasyona
gelen parametre bilgilerinin alnabilmesi veya geriye dndrelecek bir sonucun retilebilmesi ve
istemci tarafndan ele alnabilmesidir.) imdi ReceiveActivity ierisine
bir CodeActivity eklediimizi dnelim.

www.bsenyurt.com Page 350


CodeActivity1 bileeninin ExecuteCode zelliine rnek olarak SiparisiIsle deerini verip kod
ieriini aadaki gibi gelitirdiimizi dnelim. (u anda ama WF servislerinin nasl yazlacan
grmek olduundan Console tabanl host ve istemci uygulamalar yazlacaktr. Bu
nedenle CodeActivity bileeninin iaret edecei metod ierisinden o andaki talep bilgilerini
deerlendirmek amacyla Console ekranna bilgi yazdrlmaktadr.)

private void SiparisiIsle(object sender, EventArgs e)


{
// Operasyona gelen istemci arsnda UrunBilgisi nesne rneine ait veriler bulunmaktadr. Bu
verilere aktivite snfnn zellikleri zerinden eriilebilir.
Console.WriteLine("Adet talebi : {0} Urun Numaras : {1} stek Tarihi :
{2}", receiveActivity1_urun1.Adet, receiveActivity1_urun1.UrunKodu,receiveActivity1_ur
un1.SiparisTarihi.ToString());
receiveActivity1__ReturnValue_1 = "Istek Alnmtr"; // stemciye operasyonda dnecek
olan sonu
}

Artk servisi barndracak olan Host uygulamann yazlmasna balanabilir. Host uygulama daha
ncedende bahsedildii gibi WCF mimarisinin izin verdii herhangibir eitte olabilir(IIS, Console,
WPF, WAS, Windows Service...). rnekte Host uygulama basit bir Console projesi olarak
gelitirilmektedir. Host uygulamada nemli olan noktalardan birisi, Workflow Servicektphanesi
ile birlikte, Workflow ve WCF alma ortamlar iin gerekli assembly' lara ihtiya olduudur. Bu
nedenle ilk etapta Console uygulamasnda System.ServiceModel, System.Workflow.Activites,
System.Workflow.ComponentModel, System.WorkflowServices ktphanelerinin referans
edilmesi gerekmektedir. Host uygulama iin nem arz eden noktalardan biriside alma zaman
ortam iin gerekli konfigurasyon ayarlardr. Aynen WCF servislerinin yazlmasnda olduu gibi
config dosyalarndan yararlanlabilir yada kod baznda gerekli ayarlamalar yaplabilir. rnekte
kullanlan config dosyas ierii aadaki gibidir.

Host Uygulama App.config;

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


<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="WFSiparisBehavior"
name="WFSiparisKutuphanesi.WFSiparis">
<endpoint address="" binding="wsHttpContextBinding"

www.bsenyurt.com Page 351


name="WfSiparisWsHttpEndPoint"
contract="WFSiparisKutuphanesi.ISiparisSozlesmesi" />
<endpoint address="mex" binding="mexHttpBinding" name="MexEndPoint"
contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:10001/WFSiparisServisi" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="WFSiparisBehavior" >
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

Konfigurasyon dosyasnda grld gibi iki adet EndPoint tanmlamas yaplmaktadr. Bunlardan
birisi balayc olarak wsHttpContextBinding tipini kullanmaktadr.
DierEndPoint ise base address zerinden metadata eriimine izin veren bir Mex(Metadata
Exchange) EndPoint olarak tanmlanmtr. (Elbette host uygulamann IIS zerinde tutulduu bir
senaryoda Mex EndPoint bildirimine gerek yoktur.) Host uygulamann Main metoduna ait kodlar ise
aadaki gibi gelitirilebilir.

using System;
using System.ServiceModel;
using System.Workflow.Runtime;
using WFSiparisKutuphanesi;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
// Workflow servisi iin gerekli alma ortamnn hazrlanmasn WorkflowServiceHost tipi
stlenir
// Parametre olarak yaynlanacak servis bazl kullanlacak olan aktivite snf belirtilir.
WorkflowServiceHost host = new WorkflowServiceHost(typeof(WFSiparis));
// Host uygulama aldndan devreye girecek olay metodu
host.Opened += delegate(object sender, EventArgs arg)
{
Console.WriteLine("Host opened");
};
// Host uygulama kapatldnda devreye girecek olan olay metodu
host.Closed += delegate(object sender, EventArgs arg)
{
Console.WriteLine("Host Closed");
};
host.Open(); // Host alr
Console.WriteLine("Servis alyor. Kapatmak iin bir tua basn");

www.bsenyurt.com Page 352


Console.ReadLine();
host.Close(); // Host kapatlr
}
}
}

Artk istemci uygulamann yazlmasna geilebilir. Ama ncesinde istemci iin gerekli proxy tipinin
ve konfigurasyon dosyas ieriinin retilmesi gerekmektedir. ki seenek vardr. Svcutil arac
ve Visual Studio 2008 ortamnda ele alnabilen Add Service Reference. Svcutil arac komut
satrndan aadaki ekran grntsnde yer ald gibi kullanlabilir. Tabiki bu ilem
srasnda Host uygulamann alyor olmas ve servisin dardan eriilebilir durumda bulunmas
gerekmektedir.

Visual Studio 2008 ortamnda Add Service Reference seenei yardmyla da Proxy ve config
retimi gerekletirilebilir. Elbette bu yaklamda da Host uygulamann alyor olmas
gerekmektedir.

www.bsenyurt.com Page 353


rneimizde yer alan proxy ve config dosyalarnn retimi iin Add Service Reference yaklam
kullanlmtr. Yukardaki ekran grntsndende takip edilebilecei gibi istemci uygulama base
address ile belirtilen Url adresi zerinden servis szlemesine eriebilmekte ve yaynlanan servis
operasyonlarn grebilmektedir. stemci uygulamada basit bir Console projesi olarak
tasarlanmtr ve Main metodunun kod ierii aadaki gibidir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Istemci.WFSiparisServisi;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Sipari iin bir tua basn");
Console.ReadLine();

www.bsenyurt.com Page 354


// SiparisVer metodu iin gerekli parametre retilir
UrunBilgisi urn = new UrunBilgisi()
{
Adet = 10,
UrunKodu = "AB-100",
SiparisTarihi = DateTime.Now
};

// Proxy retimi gerekletirilir


UrunSiparisServisiClient servis = new UrunSiparisServisiClient();
Console.WriteLine("Talep gnderiliyor");
// WF Servis operasyonu arlr
string cevap=servis.SiparisVer(urn);
// Operasyon sonucu gsterilir
Console.WriteLine(cevap);

Console.ReadLine();
}
}
}

nce Host uygulama sonrasnda istemci uygulama altrlarak test edildiinde aadaki ekran
grnts elde edilir. Grld gibi istemci uygulama Workflowoperasyonunu baarl bir ekilde
kullanabilmitir.

Hatta birden fazla istemci uygulama altrldndada WF servisinin baarl bir ekilde her
istemciye cevap verdii grlmektedir.

www.bsenyurt.com Page 355


Ancak dikkat edilmesi gereken nemli bir durum vardr. Ayn istemci uygulama tarafndan ikinci bir
sipari istei geldiinde, bir baka deyile SiparisVer metodu ayn proxy rnei zerinden ikinci bir
kez arldnda ne olacaktr? Bunun iin koda aadaki satrlar eklediimizi dnelim.

cevap = servis.SiparisVer(new UrunBilgisi() { Adet = 8, SiparisTarihi = DateTime.Now, UrunKodu


= "KL-450" });
Console.WriteLine(cevap);

Uygulama test edildiinde alma zamannda ikinci SiparisVer metodu arsnda aadaki
istisna(Exception) mesajnn alnd grlr.(Detayl hata mesajnn istemci tarafndanda
grlebilmesi iin servis tarafnda <serviceDebug includeExceptionDetailInFaults
="true"/> bilgisinin eklenmi olmas gerekmektedir.)

www.bsenyurt.com Page 356


Bunun sebebi gelen talep sonrasnda sunucu tarafnda ilgili istemci iin retilen Workflow servis
rneinin cevap verdikten sonra artk olmaydr. Bu nedenle ikinci talep aslnda istemcinin daha
nceden kulland Workflow servis rnei iin yapt istektir. Oysaki host uygulama tarafnda bu
Workflow servis rneinin ii nceki talebin sonulanmas ile bitmitir. (Tabi burada kolaya
kalarak pratik bir zm olarak istemci uygulama ierisinde her operasyon ars ncesinde yeni
bir proxy retimi yoluna gidilebilir ki bu tavsiye edilen bir yol deildir.) te burada uzun sreli
duraan olmas gereken bir Workflow servisi rnei sz konusudur. Yani Workflow rneinin
durumunu korumas gerekmektedir.Persistence servisleri kullanlarak bu sorun zmlenebilir. Bu
amala SqlWorkflowPersistenceService tipinden yararlanlarak ilgili duraanln
gerekletirilmesi salanabilir. Tabi bu amala ncelikli olarak SQL zerinde ilgili veritabannn
oluturulmas ve tablolarn hazrlanmas gerekmektedir. Sonrasnda ise ilgili PersistenceService' in
rneklenip Workflow servisi alma ortamna kod yardmyla yada konfigurasyon baznda
bildirilmesi gerekmektedir. Bu konu yaznn kapsam dna ktndan burada ele alnmayacaktr.

Bylece geldik bir makalemizin daha sonuna. Bu makalede basit olarak Workflow rneklerinin birer
servis olarak nasl yaymlanabileceini adm adm incelemeye altk. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF ile WF Entegrasyonu - 1 ( 17.04.2008 ) -


WCF
Deerli Okurlarm Merhabalar,

Bilindii zere Window Communication Foundation ve Windows Workflow Foundation, .Net


Framework 3.0 ile birlikte gelen nemli teknolojilerdendir. WCF servis ynelimli
mimariye(Service Oriented Architecture) yeni bir yaklam getirip, datk mimari uygulama
gelitirme kavramlarn bir at altnda toplayarak gl, daha platform bamsz ve gvenilir bir
ortamda gelitirme yaplabilmesini olanakl klan bir alt yap sunmaktadr. WF ise, birden fazla

www.bsenyurt.com Page 357


admdan oluan kod srelerinin i ak(Workflow)tarznda olay gdml(Event-
Driven) yada srasal (Sequential) olacak ekilde tasarlanarak eitli .Net uygulamalarnda
kullanlabilmelerini mmkn klan bir alt yap tesit etmektedir. Workflow, srelere ait aklarn
hazrlanmasnda arlkl olarak aktivite tiplerini(Activity Types) kullanmaktadr. Bu aktivitelerin
dallara ayrlmas, atallanmas, birbirlerine katlmas gibi pek ok ilem de, Workflow ortam
tarafndan sunulmaktadr. WF ile gelitirilen i aklar ksa srecei gibi uzunda(Long-Running
Workflows) srebilir. Bu nedenle WF ortam zellikle uzun sren aklarn, sistem yeniden
balatmalar(reboot) gibi vakalara kar ayakta durabilmesi iin kalc olarak saklama ilemlerine
destek de vermektedir. WF mimarisinin yetenekleri sadece bununlada snrl deildir. rnein
Transaction destei dier yetenekleri arasnda gsterilebilir.

Windows Workflow Foundation ile Windows Communication


Foundation arasndaki entegrasyon gerek anlamda .Net Framework 3.5 ve Visual
Studio 2008 ile birlikte salanmtr.

WF aslnda, .Net Framework 3.5 ve Visual Studio 2008 ile gelen yenilikler
sayesinde WCF ortamnn gerek anlamda bir tamamlaycs teknoloji olarak grlmektedir. Bu
anlamda WF uygulamalar ierisinden WCF servislerinin arlmas ve kod aknn ilgili servis
noktalar(Service EndPoint) zerinden yrtlmesi salanabilmektedir. Tam tersine WF
ierisindende servis yaynlamas yaplabilmektedir. Bu entegrasyon sayesinde srelerin
istemcilere gl(Robust), gvenilir(Reliable) ve gvenli(Secure) bir ekilde sunulmasda
salanmaktadr. yleki bu entegrasyonun doal sonucu olarak i mantnn(Logic) farkl
formatlarda(MTOM, SOAP, Binary, JSON, X509 vb...) dolam,IIS(Internet Information
Services), WAS(Windows Activation Service) ve Windows Service gibi ortamlar
zerinden host edilme imkan gibi pek ok fonksiyonellik ele alnabilmektedir.

WCF ile WF entegrasyonu srasnda servis ile olan etkileimin modellenebilmesi iin Send,
Receive gibi aktivitelerden yararlanlmaktadr. Send aktivitesi
sayesinde WF ierisinden bir WCFservisine mesaj gnderilmesi salanabilir ki bu
noktada Proxy nesneleride devreye girmektedir. Dier taraftan Receive aktivitesi
sayesinde workflow' un kendisinin bir servis gibi sunulabilmesiolanakl hale gelmektedir.

SendActivity ve ReceiveActivity tipleri .Net Framework 3.5 ile birlikte gelmitir.

Aktivasyon alt yapsnn host edilmesi iinse ServiceHostBase abstract snfndan treyen
ve .Net Framework 3.5 ile birlikte gelen WorkflowServiceHost tipinden yararlanlmaktadr.
Servis ve istemci arasndaki nemli konulardan biriside korelasyonun salanmasdr. Bu bir
anlamda istemcinin doru servis rnei ile iletiime geebilmesi demektir ki bunun salanabilmesi
iin eklenmi olan yeni davran(Behavior) ve balayclar(Bindings) sz konusudur.

Bu teorik bilgilerden sonra rnekler ile devam edelim. lk olarak bir WF uygulamas ierisinde
bir WCF servisinin nasl arlabileceini incelemeye alacaz. WF ierisinden bir WCF servis
noktasna ulamak iin SendActivity, InvokeWebServiceActivity, CodeActivity aktivite
tiplerinden yararlanlabilir. Bunlardan en gl olan SendActivity

www.bsenyurt.com Page 358


dir. InvokeWebServiceActivity Web servislerinin proxy snf araclyla arlmasn
salamaktadr. WCF tarafndan asmx modeline uygun yaynlama yaplabildiinden bu aktivite
tipide tercih edilebilir. Nevarki SendActivity tipine gre herhangibir stnl
bulunmamaktadr. SendActivity WCF servisi ile senkron(synchronous) olarak haberleilmesini
salar ve tek ynl(One-Way), talep-cevap(Request-Response), talep-hata(Request-
Fault) desenlerini ele alr. Tek ynl desene gre servise talepte bulunulduktan sonra bir cevap
beklenmez. Talep-Cevap desenine gre ise servisten yaplan istee bir sonu gelinceye kadar
beklenir(Synchronous). Son desene gre ise ya cevap gelir yadahata mesaj(Fault Message).
Bunlarn dnda zel aktiviteler(Custom Activity) yazlarak i mantnn sz konusu aktivite tip
ierisine gmlmesi ve servisin ele alnmasda salanabilir.

Elbette ilk olarak bir servis ktphanesinin(WCF Service Library) ve host uygulamann tasarlanmas
gerekmektedir. rnekte kullanlacak olan servis ktphanesinin ierii aadaki gibidir.

Product snf;

[DataContract]
public class Product
{
[DataMember]
public int ProductId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public double ListPrice { get; set; }
}

Product snf Production.Product tablosundaki herhangibir satra


ait ProductID,Name ve ListPrice bilgilerini tamak zere tasarlanm ve bu sebepten bir veri
szlemesi(DataContract) olacak ekilde tanmlanmtr.

www.bsenyurt.com Page 359


IProductManager arayz(Interface);

[ServiceContract(Name="Urun
Servisi",Namespace="http://www.bsenyurt.com/UrunServisi")]
public interface IProductManager
{
[OperationContract]
Product GetProduct(int productId);
}

Servis szlemesi(Service Contract) Product tipinden nesne rnekleri dndren tek bir
operasyon tanm iermektedir.

ProductManager snf;

public class ProductManager


: IProductManager
{
#region IProductManager Members

public Product GetProduct(int productId)


{
Product prd = null;
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select ProductId,Name,ListPrice From
Production.Product Where ProductId=@PrdId", conn);
cmd.Parameters.AddWithValue("@PrdId", productId);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
prd = new Product { ProductId = Convert.ToInt32(reader["ProductId"]), Name =
reader["Name"].ToString(), ListPrice = Convert.ToDouble(reader["ListPrice"]) };
reader.Close();
}
return prd;
}

#endregion
}

ProductManager snfnda yazlan GetProduct metodu, parametre olarak gelen deere


gre Production.Product tablosundan bir satr verisini ekmektedir. Eer parametre olarak gelen
id deerine bal bir satr varsa ProductId,Name,ListPrice deerlerinin topland Product nesne
rnei geri dndrlmektedir. Snf ktphanesinin tanmlanmasndan sonra host servis
uygulamasnn yazlmas gerekmektedir. rnekte Host, basit bir Console uygulamas olacak ekilde
aadaki gibi tasarlanmtr.

Program snf ierii;

using System;
using System.ServiceModel;
using ProductServices;

www.bsenyurt.com Page 360


namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(ProductManager));
host.Open();
Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
host.Close();
}
}
}

App.config ierii;

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="UrunServisiBehavior">
<serviceMetadata/>
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="UrunServisiBehavior"
name="ProductServices.ProductManager">
<endpoint address="" binding="netTcpBinding" bindingConfiguration=""
name="UrunServisiTcpEndPoint" contract="ProductServices.IProductManager" />
<endpoint address="mex" binding="mexTcpBinding"
name="UrunServisiMexEndPoint" contract="IMetadataExchange" />
<host>
<baseAddresses>
<add baseAddress="net.tcp://localhost:9001/UrunServisi" />
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

lerlemeden nce App.config dosyas ieriinin incelenmesinde yarar vardr. Servis uygulamas iki
adet EndPoint sunmaktadr. UrunServisiTcpEndPoint isimli servis noktas TCP(netTcpBinding
balaycsn kullandna dikkat edelim) bazl olacak ekilde bir yaynlama
yapmaktadr. address bilgisi verilmemi olmasna ramen host elementi ierisinde
tanmlanan baseAdress bilgisi kullanlmaktadr. Dier EndPoint ise IMetadaExchange arayzn
servis szlemesi olarak kullanan ve mexTcpBinding balaycsn baz alarak mex isimli bir adres
zerinden yaynlama yapan bir servis noktas sunmaktadr. Bu EndPoint sayesinde baseAddress
elementi ile bildirilen TCP adresi zerinden Metadata Exchange ilemi gerekletirilebilir. Bir
baka deyile almakta olan servis uygulamasna bal adres zerinden proxy nesnesi retimi
gerekletirilebilir. nemli olan noktalardan biriside proxy retiminin salanmasdr. Bu nedenle

www.bsenyurt.com Page 361


servise metadata yaynlamas iin bir servis davran(Service Behavior) eklenmitir. Bylece
servis operasyonlar servis dna sunulabilir hale gelmitir.

WF uygulamas, dardan bir WCF servisini armak iin proxy nesnesinden


yararlanmaktadr. Bu proxy nesnesi Visual Studio 2008 ortamnda Add Service
Referenceile kolay bir ekilde eklenebilecei gibi svcutil arac yardmylada aadaki
ekilde olduu gibi ekilebilirde.

Hangisi tercih edilirise edilsin rnee gre servis uygulamasnn alr durumda olmas
gerekmektedir.

Artk WF uygulamasnn yazlmasna balanabilir. rnekte Sequential Workflow Console


Application ablonu kullanlmaktadr. Proje aldktan sonra servis uygulamasnn alyor
olmasna dikkat edereken, Add Service Reference seenei ile proxy snfnn retilmesi ve WF
uygulamasna eklenmesi salanabilir.

www.bsenyurt.com Page 362


Bu ilemin arkasndan WF uygulamas ierisinde aadaki gibi servisa ait bilgilerin indirildii ve
proxy snfnn(Reference.cs ierisinde yer almaktadr) retildii grlebilir.

rnekte WF ierisinden servisi armak iin SendActivity tipi kullanlacaktr. lk olarak Workflow1
tasarm ortamna SendActivity bileeni srklenmelidir.

www.bsenyurt.com Page 363


SendActivity bileeninin nemli olan baz yeleri vardr.
Bunlardan ServiceOperationInfo zellii yardmyla etkileimde bulunulacak olan servisin ve ilgili
operasyonunun seilmesi salanr. AfterResponse alannn iaret ettii olay sayesinde, servis
tarafndan cevap geldikten sonra iletilmesi istenen kodlarn icra edilmesi salanmaktadr. Benzer
ekildeBeforeSend alannn iaret ettii olay sayesinde, servise mesaj gnderilmeden nce
iletilmesi gereken bir kod mant var ise, bunun icra edilmesi salanmaktadr. stenirse zel
servis adresleri CustomAdress zellii ile tanmlanabilir. rnekte ilk
olarak ServiceOperationInfo zelliinden yararlanlarak kullanlacak operasyon seilmelidir.

www.bsenyurt.com Page 364


Import dmesine basldktan sonra ekrana gelen ara birimde, projeye az nce referans edilmi
olan serviste grlecektir(ServiceReference1). Bu ilemin hemen arkasndanUrunServisi tipine ift
tklanrsa aadaki ekran grnts elde edilir.

www.bsenyurt.com Page 365


Grld gibi servise ait GetProduct operasyonu eklenmitir. Parameters ksmnda,
operasyonun ald ve geri dndrd deikenlere ait bir takm bilgiler yer almaktadr. Buna
operasyon productId isimli Int32 tipinden bir parametre almakta ve Product tipinden bir sonu
dndrmektedir. OK dmesine basldktan sonra Parameters ksmnda yer alan
deikenlerin Properties penceresine birer zellik olaraktan eklendii izlenebilir.

Bu zelliklerin yannda yer alan nokta dmelerine basldnda, ilgili alanlarn servis
operasyonuna balanmas iin gerekli zellik/alan(Property/Field) tanmlamalarnn yaplaca
bir ekran ile karlalr. Bu ekrandan yararlanlarak Workflow snf ierisinde yazlm var olan

www.bsenyurt.com Page 366


zelliklere/alanlara balama yaplabilecei gibi Bind to a new member sekmesinden
faydalanlarak yeni zelliklerin annda oluturulmasda salanabilir. rnein ReturnValue zellii
iin aadaki ekran grntsnde yer alan seimler kullanlm ve
annda sendActivity1_ReturnValue1 isimli bir yenin oluturulmas salanmtr.

Ayn ilem productId isimli aktivite zellii iinde yaplmaldr. Bu ilemlerin ardndan Workflow1
snf ierisine DependencyProperty tipinden iki yeni zelliin aadaki gibi eklendii grlr.

namespace WfdenServis
{
public sealed partial class Workflow1: SequentialWorkflowActivity
{
public Workflow1()
{
InitializeComponent();
}

public static DependencyProperty sendActivity1__ReturnValue_1Property =


DependencyProperty.Register("sendActivity1__ReturnValue_1",
typeof(WfdenServis.ServiceReference1.Product), typeof(WfdenServis.Workflow1));

[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Parameters")]
public WfdenServis.ServiceReference1.Product sendActivity1__ReturnValue_1
{
get
{
return
((WfdenServis.ServiceReference1.Product)(base.GetValue(WfdenServis.Workflow1.sendActivity1__
ReturnValue_1Property)));
}
set
{
base.SetValue(WfdenServis.Workflow1.sendActivity1__ReturnValue_1Property, value);
}
}

public static DependencyProperty sendActivity1_productId1Property =

www.bsenyurt.com Page 367


DependencyProperty.Register("sendActivity1_productId1", typeof(System.Int32),
typeof(WfdenServis.Workflow1));

[DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
[BrowsableAttribute(true)]
[CategoryAttribute("Parameters")]
public Int32 sendActivity1_productId1
{
get
{
return
((int)(base.GetValue(WfdenServis.Workflow1.sendActivity1_productId1Property)));
}
set
{
base.SetValue(WfdenServis.Workflow1.sendActivity1_productId1Property, value);
}
}
}
}

Son olarak SendActivity bileeninin ChannelToken zellii ayarlanarak EndPoint bilgilerinin


verilmesi ve WF' in hangi servis ile nasl mesajlaacann ele alnmas gerekmektedir. Bu bilgiler
ok doal olarak Add Service Reference ilemi sonras gelen App.config dosyas ierisinde yer
almaktadr. Bu amala ChannelToken zelliine bir isim verildikten sonra gelecek
olan EndpointName zelliine App.config dosyas ierisindeki ilgili servis noktasnn ad
yazlmaldr. Sonrasnda ise ChannelToken nesnesinin kapsam(Scope) belirlenir. Bu
kapsam OwnerActivityName zellii yardmyla set edilmektedir. rnekte sz konusu zellikler
aadaki ekran grntsnde olduu gibi belirlenebilir.

Artk test ilemleri balatlabilir. Console formatnda bir Workflow uygulamas


gelitirildiinden Main metodu ierisinde gerekli parametre tanmlama ve sonu alma ilemleri
kolaylkla gerekletirilebilir. Bu amala Main metodu aadaki gibi geniletilebilir.

using System;
using System.Collections.Generic;
using System.Linq;

www.bsenyurt.com Page 368


using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;
using WfdenServis.ServiceReference1;

namespace WfdenServis
{
class Program
{
static void Main(string[] args)
{
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object sender,
WorkflowCompletedEventArgs e)
{
waitHandle.Set();
Product result = e.OutputParameters["sendActivity1__ReturnValue_1"]
as Product;
if(result!=null)
Console.WriteLine("{0} : {1} {2}", result.ProductId.ToString(),
result.Name, result.ListPrice.ToString("C2"));
else
Console.WriteLine("rn bulunamad");
};

workflowRuntime.WorkflowTerminated += delegate(object sender,


WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Message);
waitHandle.Set();
};

Dictionary<string, object> parametreler = new Dictionary<string, object>()


{ { "sendActivity1_productId1", 680 } };
WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(WfdenServis.Workflow1),parametreler);

instance.Start();

waitHandle.WaitOne();
}
}
}
}

Bilindii gibi WorkflowInstance nesne rnei


oluturulurken Dictionary<string,object> tipinden olan ikinci parametre ile i ak ierisindeki
zelliklere deer aktarm gerekletirilebilmektedir. Bu sebepten
rnekte parametreler isimli Dictionary<string,object> tipinden bir koleksiyon tanmlanm
ve sendActivity1_productId1 ismi ile 680 deeri verilmitir. sendActivity1_productId1 isimli
zellik hatrlanaca gibi SendActivity bileeninin bir parasdr ve GetProduct metodunun
ald productId alanna e dmektedir. Bu sayede servis tarafndaki ilgili operasyona parametre
gnderimi gerekletirilmektedir. Servis tarafndaki ilemler sonlandnda tasarlanan i akna

www.bsenyurt.com Page 369


gre otomatik olarak WorkflowCompleted olay tetiklenmektedir. Bu
olayn WorkflowCompletedEventArgs tipinden olan e parametresine
ait OutputParameters zelliinin iaret ettii koleksiyon, i akna ait tm zelliklere
ulalabilmesini salamaktadr ki bunlardan biriside GetProduct isimli servis metodunun dn
deerini iaret eden ve SendActivitybileenine ait
olan sendActivity1_ReturnValue_1 isimli anahtardr(key). Bu anahtarn
sonucu Product tipinden olaca iin as anahtar kelimesi ile bir dntrme ilemi yaplmakta ve
sonu null deilse elde edilen deikene ait bilgiler ekrana yazdrlmaktadr. Uygulamann test
edilebilmesi iin ncelikli olarak servis tarafnn alyor olmas gerekmektedir. Buna gre i
ak uygulamasnn 680 productId deeri iin verecei kt aadaki gibi olacaktr.

Elbette tasarlanan akn tipine bal olaraktan, servise ait operasyonlarn admlarn arasnda
herhangibir yerde tetiklenmesi ve arkasndan sonularn alnmas iin baka aktivitelerin(rnein
CodeActivity) i akna eklenmeside sz konusudur. Sz gelimi yazlan son rnekte ek bir
CodeActivity bileeni kullanlabilir. Bunun iin tasarm zamannda aadaki gibi
bir CodeActivity bileeni eklendiini ve ExecuteCode zelliindede UrunuGetir isimli bir metod
bildirimi yapldn varsayalm.

Buna gre UrunuGetir metodunun ierii aadaki gibi tasarlanp SendActivity arsndan
sonra GetProduct operasyonunun sonularnn alnmas
salanabilir. (BuradasendActivity1_ReturnValue_1 deerine zelliine dorudan eriilmesi son
derece doaldr nitekim metodun tanmland yer Workflow1 snfnn iidir.)

private void UrunuGetir(object sender, EventArgs e)


{
WfdenServis.ServiceReference1.Product prd = sendActivity1__ReturnValue_1 as
WfdenServis.ServiceReference1.Product;
Console.WriteLine(prd.Name + " " + prd.ListPrice.ToString("C2"));
}

www.bsenyurt.com Page 370


Grld gibi SendActivity bileeni sayesinde bir i ak nesnesi ierisinden WCF tabanl servis
arlmas, bu servisten sunulan operasyonlarn icra edilmesi, varsa operasyon sonularnn
alnmas gibi aksiyonlar kolay bir ekilde gerekletirilebilmektedir. Bu yazda bir WCF servisinin,
WF ierisinden nasl arlabileceinin temelleri zerinde durulmu ve basit bir rnek adm adm
ilenmeye allmtr. Bir sonraki makalede ise bir WF uygulamasnn servis olarak nasl
sunulaca konularna deinilmeye allacaktr. Bylece geldik bir makalemizin daha sonunda. Bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

LINQ Maceralarm ( 10.04.2008 ) - C# 3.0


Deerli Okurlarm Merhabalar,

Language INtegrated Query(LINQ) mimarisi sayesinde CLR nesneleri(Common Language


Runtime Objects) zerinden SQL tarz sorgu ifadeleri yazlabilmektedir.
Hatta LINQ mimarisi, SQLveritaban(LINQ to SQL) ve XML (LINQ to XML) kaynaklar zerindede
kullanlabilmektedir. zellikle IEnumerable<T> arayzn uyarlayan tiplere ait nesne rnekleri
iin, Select,Where, GroupBy, Sum, Avg, Distinct ve daha pek ok bilinen sorgulama metodu
uygulanabilmektedir. LINQ ierisinde yer alan imkanlar gz nne alndnda, .Net Framework
1.1,2.0 ve 3.0 ile gelitirilmi pek ok projenin .Net 3.5' e aktarlarak bu olanaklardan
yararlanabilmeleri iin gerekli gei hazrlklarnn ciddi anlamda dnldde ortadadr.
stelik Visual Studio 2008, getirdii oklu framework destei sayesinde .Net Framework 2.0,
3.0 ve 3.5 arasndaki geilerin kolayca yaplabilmesini salamaktadr. Bu gibi konular gz nne
alndnda bir gelitirici olarak LINQ' in daha nceki kod paralarnda kullanlabilecei yeni
yerlerde merak konusu haline gelmektedir. te bu makalemizde, LINQ sorgularn farkl kod
paralarnda kullanmaya alyor olacaz.

LINQ mimarisinin kullanlabilecei alanlar gz nne alndnda, Reflection(Yansma),


IO(Dosya giri/k), Balantsz Katman(Disconnected Layer) sadece bir ka basit alan
olarak n plana kmaktadr. Ancak bu alanlar pek ok uygulamada nemli grevler stlenmektedir.
Sz gelimi yansma teknikleri ile IDE gelitirilmesi(Visual Studio benzeri), Plug-In tabanl
uygulamalar yazlmas, nitelik(Attribute) bazl olacak ekilde alma ortamnn organize
edilmesi(zellikle deklerafit programlama tekniklerinde) gibi ilevsellikler n plana kmaktadr.
Dosyalama ilemleri en basit anlamda resim ileme programlarndan, XML ayrtrma
uygulamalarna kadar pek ok alanda kullanlmaktadr. ok doal olarak Ado.Net mimarisine gre
gelitirilen pek ok uygulamada balantsz katman nesneleri grlebilmektedir. Sadece bu
konular bile gz nne alndnda baz kod ihtiyalar iin diziler, dngler ve koullu ifadelerin ok
sk kullanldda gze arpmaktadr. Ancak LINQ sorgular sayesinde bu ilemler ok daha basit bir
ekilde gerekletirilebilir. Elbetteki geniletme metodlarnn stlendii yk erevesinde sz
konusu dnglerin, koullu ifadelerin ortadan kalkmas gibi bir durum mmkn deildir. Ancak
kodun ok daha etkin bir ekilde ve bir sorgulama diline yatkn olaraktan gelitirilmesi nemli bir
avantajdr.

Bilindii gibi LINQ sorgularnda yer alan anahtar kelimeler(keywords) aslnda arka
planda birer geniletme metoduna(Extension Methods) karlk gelmektedir. Bu
metodlar sz gelimi basit bir arama ilemi iin
gereken dngsel veya koullu ifadeleri kapslleyerek gelitiricinin zerinden
almaktadr. Bu sayede gelitirici SQL diline yatkn bir ekilde sorgular yazabilmekte ve
kodun daha etkili, leklenebilir, anlalr bir ekilde gelitirilmesine
odaklanabilmektedir.

www.bsenyurt.com Page 371


Dilerseniz hi vakit kaybetmeden rneklerimize balayalm.

lk olarak dosyalama ilemlerini gz nne alarak ilerleyebiliriz. Sz gelimi, herhangibir klasr


ierisinde yer alan Jpg uzantl dosyalardan boyutu 1000 kb zerinde olanlarn tespit edilmesini
istediimizi dnelim. Bu ilemi VS 2008 tabanl bir Console Uygulamasnda aadaki kod
paras ile gerekletirebiliriz.

string klasorAdresi= @"C:\Documents and Settings\BurakSenyurt\My Documents\My


Pictures\Google Pictures\";
DirectoryInfo dInfo = new DirectoryInfo(klasorAdresi);
var resimDosyalari = from fInfo in dInfo.GetFiles()
where fInfo.Extension == ".jpg" && fInfo.Length >= 1000 * 1024
select new
{
fInfo.Name
,fInfo.Length
,fInfo.CreationTime
};
foreach (var dosya in resimDosyalari)
Console.WriteLine(dosya);

DirectoryInfo snfnn GetFiles metodu FileInfo tipinden bir dizi dndrmektedir. Bu dizi
bir Array tipi olduu iin LINQ ile birlikte gelen geniletme metodlarn(Extension
Methods) kullanabilmektedir. Dolaysyla LINQ ifadesi ierisinde from, select, where gibi
anahtar kelimeler kolay bir ekilde ele alnabilmektedir. FileInfo dizisi zerinden dosya
uzants(Extension) .jpg ve uzunluu(Length) 1000 Kb zerinde olanlar tespit edilirken
ayn zamanda isimsiz bir tip(Anonymous Type) retimide gerekletirilmekte ve ilgili dosya
iinad(Name), uzunluk(Length) ve oluturulma zaman(CreationTime) bilgilerinin yer ald
yeni bir nesne rnei oluturulmaktadr. Program kodunun kts rnek klasr iin aadaki gibidir.

Elenceli deil mi? yleyse devam edelim. Diyelimki dosyalama ilemleri ile ilgili olaraktan yle bir
ihtiyacmz oldu;Bir klasr ierisindeki dosyalar tiplerine gre gruplayp, her grup ierisinde
kaar adet dosya bulunduunu renmek istiyoruz. Bu kodun LINQ ifadesini yazmadan

www.bsenyurt.com Page 372


nce, LINQ olmadan nasl gelitirilebileceini dnmenizi neririm. LINQ ile bu sorgu aadaki
kod parasnda olduu gibi gerekletirilebilir.

string adres = @"C:\Windows\";


DirectoryInfo dInfo = new DirectoryInfo(adres);
var dosyaGruplari = from fInfo in dInfo.GetFiles()
group fInfo by fInfo.Extension into grp
select new
{
Uzanti = grp.Key,
Toplam = grp.Count()
};

foreach (var dosyaGrubu in dosyaGruplari)


Console.WriteLine(dosyaGrubu.ToString());

Bu seferki LINQ ifadesinde group by kullanm sz konusudur. Group By sayesinde aynen SQL' de
olduu gibi gruplama ilemi nesneler zerinde yaplabilmektedir. rnekte Windowsklasr
altndaki dosyalar FileInfo tipinin Extension zelliine gre gruplanmaktadr. Sonrasnda ise
gruplanan koleksiyon zerinden Count geniletme metodu kullanlmakta ve her bir tip grubu iin
kaar dosya olduu hesaplanmaktadr. lk rnekte olduu gibi yine isimsiz tip(Anonymous
Type) kullanlarak dosya grubuna ait uzant ve toplam dosya says bilgileri elde edilmektedir.
Sonu olarak uygulamann ekran kts aadaki gibi olacaktr.

imdide herhangibir klasrdeki jpg uzantl


dosyalardan L harfi ile balayanlar boyutlarna gre tersten sralayarak elde etmek
istediimizi dnelim. LINQ kullanmadmz takdirde bize en ok sorun kartacak noktalardan
biriside tersten sralama ilemi olacaktr. Bunu salamak iin doal olarak FileInfo dizisi
zerinden ters sralama algoritmas uygulanmas gerekir. Oysaki LINQ ifadeleri ile bu ilem iin
gerekli kod paras aadaki gibi kolayca gelitirilebilir.

string klasorAdresi = @"C:\Documents and Settings\BurakSenyurt\My Documents\My


Pictures\Google Pictures\";
DirectoryInfo dInfo = new DirectoryInfo(klasorAdresi);

var dosyalar=from fInfo in dInfo.GetFiles()


where fInfo.Extension==".jpg" && fInfo.Name[0]=='L'

www.bsenyurt.com Page 373


orderby fInfo.Length descending
select new
{
fInfo.Name,
fInfo.Length
};

foreach (var dosya in dosyalar)


Console.WriteLine("{0} \t{1}",dosya.Length,dosya.Name);

Bu kez orderby anahtar kelimesi(ki bu arka planda OrderBy geniletme metoduna


dntrlmektedir) kullanlarak dosyalarn boyutlarna gre tersten sralanmas salanmtr.
Sonu olarak kodun ekran kts aadakine benzer olacaktr.

LINQ sorgular dosyalama ilemleri dnda zellikle reflection(yansma) tarafndada etkili bir
ekilde kullanlabilir. Yazmzn bundan sonraki ksmndada yansma teknikleri
ierisinde LINQ ifadelerini rnekler zerinde ele almaya alacaz. ncelikli olarak Process'
lerden balamak taraftarym. Bilindii zere .Net uygulamalar sistem zerinde alan Process' ler
ierisinde ayr uygulama alanlar(Application Domains) altna dahil edilirler. Hatta bu
uygulama alanlar kendi ilerinde, birden fazla(en az bir tane olmak zere) Thread' ede sahip
olabilirler. Sistem zerinde alan Process' lerin yada o anda almakta olan gncel Process' in
bilgilerini almak iin Process snfnn farkl metodlar bulunmaktadr. Bizimde aklmza gelen soru
udur; acaba sistem zerinde almakta olan Process' ler ierisinde sadece tek bir Thread'
e sahip olanlarhangileridir. Nitekim bilindii zere baz Process' ler kendi ilerinde birden fazla
Thread iermektedir. Bu amala aadaki gibi bir kod paras gelitirilebilir.

var processes = from prc in Process.GetProcesses()


where prc.Threads.Count == 1
orderby prc.ProcessName descending
select new
{
prc.ProcessName
, prc.PagedMemorySize64
};
foreach (var process in processes)
Console.WriteLine(process.ToString());

www.bsenyurt.com Page 374


Process snfnn static GetProcesses metodu ile o anda sistemde almakta olan Process' ler
elde edilmektedir. Sonrasnda where anahtar kelimesi ile Threads zellii zerinden Count deeri
kontrol edilir. 1 olanlar adlarna(ProcessName) gre orderby anahtar kelimesinden
yararlanlarak tersten sralanacak ekilde yeni bir isimsiz tip ierisinde toplanrlar. Bu isimsiz
tip(Anonymous Type) rnek olarak Process' in ad(ProcessName) ve sayfalanm bellek
boyutu(PagedMemorySize64) deerlerini iermektedir. Sonu olarak kodun kts, allan
sistem zerinde aadaki gibi olmutur.

Reflection ile balamken hzmz kesmeyelim ve yeni bir sorgu ile devam edelim. Bu kez yle
bir ihtiyacmz var; bir assembly' n referans ettii assmebly' lar ierisindenversiyonu .Net
Framework 2.0 olmayanlar bulmak istiyoruz. Bu tip bir durumda var olan Assembly' n
yklenmesi ve referans ettii Assembly' larn GetReferencedAssemblies metodu ile ekilmesi
gerekir. Ne tesadftrki GetReferencedAssemblies metodu AssemblyName tipinden bir dizi
dndrmektedir. Dolaysyla bu dizi zerinden LINQ ifadeleri kullanlabilmesi olasdr. Sz konusu
ihtiya iin aadaki gibi bir kod paras dnlebilir.

AssemblyName[] result1 =
Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.EnterpriseSer
vices.dll")
.GetReferencedAssemblies();
var framework2Olmayanlar = from asmb in result1
where asmb.Version != new Version(2, 0, 0, 0)
select new
{
AssemblyAdi = asmb.FullName
,IslemciMimarisi =
asmb.ProcessorArchitecture
,HashAlgoritmas = asmb.HashAlgorithm
};

foreach (var a in framework2Olmayanlar)


Console.WriteLine(a.ToString());

rnek olarak System.EnterpriseServices.dll assembly' kullanlmaktadr. Sorgu ierisinde dikkat


edilecek olursa GetReferencedAssemblies metodu ile elde edilen sonu kmesi zerinden ekilen
her bir AssemblyName nesnesinin Version zelliine baklmaktadr. Sonrasnda ise yine
bir isimsiz tip kullanlarak sadece Assembly'
n ad(FullName), ilemcimimarisi(ProcessorArchitecture) ve hash algoritmas(HashAlgor
ithm) deerleri toplanmaktadr. rnein ekran kts aadaki gibi olacaktr.

www.bsenyurt.com Page 375


LINQ sorgular ierisinde baz yerlerde harici metodlarnda arlmas mmkndr. Sz gelimi
bir koul kontrol iin iterasyonun o andaki nesnesinin denetlenmesi gerektii durumlarda harici
metod arlar gerekebilir. rnein dll uzantl dosyalar ile dolu bir klasr ierisinde .Net
Assembly' olarak yklenebilenlerin tespit edilmesini istediimiz dnelim. Byle bir
senaryoda Assembly snfnn static LoadFrom metodu olduka ie yarayacaktr. Nitekim sz
konusu dll herhangibir nedenle yklenebilen birAssembly deilse alma zaman
istisnas(Runtime Exception) oluacaktr. Aadaki kod paras bu durumu analiz etmek iin
gelitirilmitir.

class Program
{
static void Main(string[] args)
{
string path = @"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727";
DirectoryInfo klasor = new DirectoryInfo(path);
var assemblyOlanlar = from dosya in klasor.GetFiles("*.dll")
where Yuklenebildinmi(dosya.FullName)
select dosya;

foreach (var asmb in assemblyOlanlar)


Console.WriteLine(asmb.FullName);
}

static bool Yuklenebildinmi(string assemblyAdresi)


{
try
{
Assembly asmbly = Assembly.LoadFrom(assemblyAdresi);
return true;
}
catch
{
return false;
}
}
}

GetFiles metodu ile dll uzantl FileInfo dizisi elde edildikten sonra her bir eleman
iin Yuklenebildimi isimli bir metod ile denetleme ilemi gerekletirilmektedir. Yuklenebildimi
isimli fonksiyon,Assembly.LoadFrom metodu ie yaryorsa true deerini,
yaramyorsa false deerini dndrmektedir. Buna gre true deeri dnen dosyalarn yklenebilen
assembly' lar olduu sonucuna varlmaktadr. Uygulamann alma zamanndaki grnts
aadakine benzer olacaktr.

www.bsenyurt.com Page 376


Yine assembly' lar zerinden LINQ sorgular yazmaya devam edelim. rnein
bir assembly ierisinden darya sunulan harici tipler gz nne alnsn. Burada iin ierisine
gruplama fonksiyonelliinide katarak, hangi isim alan(namespace) ierisinden ka adet tipin
darya sunulduu bilgiside elde edilebilir. Bu ii gerekletirmek iin rnek olarak aadaki gibi
bir kod paras gz nne alnabilir.

Assembly systemAsmb =
Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Web.dll");
var hariciTipler = from t in systemAsmb.GetExportedTypes()
group t by t.Namespace into ng
orderby ng.Key descending
select new
{
IsimAlaniAdi = ng.Key,
TipSayisi = ng.Count()
};
foreach (var hariciTip in hariciTipler)
Console.WriteLine("{0} isim alanndan {1} tip vardr", hariciTip.IsimAlaniAdi,
hariciTip.TipSayisi.ToString());

Bu LINQ sorgusunda GetExportedTypes metodu yardmyla rnek olarak System.Web.dll


assembly' ierisinden darya sunulmakta olan harici tiplerin listesi Type trnden bir dizi olarak
elde edilmektedir. Sonrasnda ise her tip, Namespace zelliinin deerine gre group anahtar
kelimesi yardmyla ng isimli deiken altnda gruplanmaktadr. Gruplanan veriler sonucu elde
edilen liste Namespace adlarna gre tersten(descending) sralanmaktadr. Bu noktada
devreye orderby anahtar kelimesi girmektedir. Elde edilen listeden isim alan adlar Key zellii ile
ve tip saylarda Count geniletme metodu ile ekilerek yeni bir isimsiz tip altnda toplanmaktadr.
Kod parasnn almasnn sonucu oluan rnek ekran kts ise aadaki gibidir.

Peki herhangibir assembly ierisinde ka farkl isim alan olduunu bulmak istersek. Normal
artlarda bu ilem iin isim alan adlarn ektikten sonra bir fonksiyonellik gelitirilmesi
gerekmektedir. Oysaki LINQ ile birlikte genen Distinct geniletme metodu sayesinde sz
konusu ilem aadaki kod parasnda olduu gibi kolayca gerekletirilebilir.

Assembly systemAsmb =
Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.Xml.dll");
var isimAlanlari = (from t in systemAsmb.GetTypes()

www.bsenyurt.com Page 377


select t.Namespace).Distinct();
Console.WriteLine("\n{0} assembly' ierisinde {1} farkl isim alan ad vardr",
systemAsmb.FullName,isimAlanlari.Count()-1);
foreach (var isimAlani in isimAlanlari)
Console.WriteLine(isimAlani);

Burada dikkat edilmesi gereken noktalardan biriside Distinct ilevselliinin bir metod
olarak select sorgusunun arkasndan kullanlmasdr. Buna ek olarak Count geniletme
metoduilede farkl isim alanlarnn says ekilmektedir. rnekte yer alan System.Xml.dll
assembly' iin ilgili sonular aadaki gibi olacaktr.

Reflection ile ilikili olarak LINQ sorgularn kullanacamz son bir rnek ile devam edelim. Bu
sefer bir assembly ierisinde yer alan tiplerin toplam saylarn tredikleri base type' lara
gre gruplayarak elde etmeye alyor olacaz. Bu amala, Type snfnn BaseType zellii
gruplama ileminde kullanlabilir. Sz gelimi System.dll assembly' ierisindeki
tipleri BaseType zelliklerinin deerlerine gre gruplamak istersek aadaki kod paras yeterli
olacaktr.

Assembly systemAsmb =
Assembly.LoadFrom(@"C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\System.dll");
var tipler = from m in systemAsmb.GetTypes()
group m by m.BaseType into grp
select new
{
grp.Key
,Toplam = grp.Count()
};
foreach (var tip in tipler)
Console.WriteLine("{0} \t{1}", tip.Key, tip.Toplam.ToString());

Bir nceki rnektekine benzer olacak ekilde yine group by fonksiyonu kullanlmaktadr. Sonu
olarak retilen isimsiz tip ierisinde BaseType ad ve toplam tip says deerleri yer almaktadr.
rnek kodun alma zamanndaki ekran kts aadakine benzer olacaktr.

www.bsenyurt.com Page 378


LINQ(Language INtegrated Query) ifadeleri pek ok dizi tipi ve koleksiyon zerinde etkin bir
ekilde kullanlabildiinden, akla gelen konulardan biriside grsel uygulamalarda yer
alanControls koleksiyonlardr. Bir windows uygulamasnda
yada web uygulamasnda Container grevi stlenen ve bu sebepten Controls koleksiyonuna
sahip olan nesnel topluluklar zerinde de LINQ sorgular altrlabilir. Bunu basit bir rnek
zerinden inceleyebiliriz. Sz gelimi aadaki ekran grntsde yer alan bir Windows Formumuz
olduunu dnelim.

Amacmz imdilik bu form zerinde hangi tipte kontroller bulunduunu gstermek. Bu amala
basit olarak aadaki gibi bir kod paras yeterli olacaktr.

private void button2_Click(object sender, EventArgs e)


{
lstSonuclar.Items.Clear();

IEnumerable<Control> kontroller=Controls.Cast<Control>();

var farkliTipler = (from kontrol in kontroller


select kontrol.GetType()).Distinct().OrderBy(k => k.Name);

www.bsenyurt.com Page 379


foreach (Type farkliTip in farkliTipler)
lstSonuclar.Items.Add(farkliTip.Name);
}

Bu kod parasda belkide en nemli noktalardan biriside Controls zellii zerinden


kullanlan Cast<T> geniletme metodudur. Cast<T> metodu kullanlmad
takdirde Controlszellii zerinden Select, Where, GroupBy gibi LINQ sorgularnda nem arz
eden fonksiyonelliklere eriilemedii grlr. Cast<T> metodunun buradaki
grevi Controlskoleksiyonu ierisindeki bileenleri, parametre olarak verilen generic tipe
dntrerek IEnumerable arayznn tayabilecei bir nesne topluluu referans halinde
retmektir. Bylece LINQ sorgular iin gerekli fonksiyonellikler elde edilebilmektedir. Windows
formu zerindeki grsel bileenler Control snfndan tremektedir. Bu sebepten Cast<T>
metodunun generic parametresi Control tipindendir. Bu dntrme ileminin
ardndan Distinct ve OrderBy geniletme metodlarnnda yer ald bir LINQ sorgusu altrlmas
mmkn olmaktadr. Select sorgusunda, GetType metodunun kullanlmasnn sebebi tiplerin
benzersiz ekilde ele alnmak istemesidir. Sonu olarak uygulamann alma zamanndaki ekran
kts aadakine benzer olacaktr.

Grld gibi form zerinde hangi tipten kontrollerin var olduu listelenmektedir. Yeni bir sorgu
ile devam edelim. Bu sefer form zerindeki kontrolleri tiplerine gre gruplayp her bir tipten ka
adet olduunu bulmak istediimizi dnelim. Bu basit gruplama ileminin kodu aadaki gibi
gelitirilebilir.

private void button2_Click(object sender, EventArgs e)


{
lstSonuclar.Items.Clear();

IEnumerable<Control> kontroller=Controls.Cast<Control>();

var farkliTipler = from kontrol in kontroller


group kontrol by kontrol.GetType() into grp
select new
{
KontrolAdi=grp.Key
,Toplam=grp.Count()

www.bsenyurt.com Page 380


};

foreach (var farkliTip in farkliTipler)


lstSonuclar.Items.Add(String.Format("{0} :
{1}",farkliTip.KontrolAdi,farkliTip.Toplam.ToString()));
}

Bu sefer gruplama ilemi Control tipinin GetType metoduna gre yaplmaktadr. Uygulama
kodunun ekran kts aadaki gibi olacaktr.

Cast<T> metodu dorudan LINQ geniletme metodlarnn kullanlamad pek ok senaryoda


ele alnabilir. Sz gelimi aadaki kod paras ok basit olarakApplication Log altndaki
girilerden programn altrld gn ierisinde retilenlerin ekilmesini salamaktadr.

EventLog logs = new EventLog("Application", ".", "");


IEnumerable<EventLogEntry> entries = logs.Entries.Cast<EventLogEntry>();

var girisler = from entry in entries


where entry.TimeGenerated.Day == DateTime.Now.Day
select new
{
entry.Category,
entry.CategoryNumber,
entry.EntryType,
entry.TimeGenerated
};

foreach (var giris in girisler)


Console.WriteLine(giris.ToString());

Bu kod parasnda kullanlan Cast<T> geniletme metodu


geriye, IEnumerable<EventLogEntry> arayz(interface) tarafndan tanacak bir nesne
topluluu referans dndrmektedir. IEnumerable<T> arayzne ulald iinde LINQ sorgusu
kolay bir ekilde ele alnm ve aadaki ekran ktsnn retilmesi salanmtr.

www.bsenyurt.com Page 381


Cast<T> metodu ile benzer zellie sahip bir dier nemli metodda OfType<T> geniletme
metodudur. Bu metod bir nesne topluluu zerinde, generic parametre tipine gre
filtreleme yaplabilmesini ve geriye LINQ sorgularnn uygulanabilecei bir
IEnumerable<T> referans dndrlmesini salamaktadr.

Cast<T> metodu ile OfType<T> metodu benzer ilevsellie sahip grnmekle birlikte
arada nemli farklar vardr. OfType<T> metodu temel olarak generic parametre tipine
gre bir filtreleme yapmakta iken, Cast<T> metodu generic parametre
tipine dntrme yapmaktadr. Bu sebepten dntrme yaplamayaca
durumlardaCast<T> metodu, alma zamannda InvalidCastException istisnas
retilmesine neden olur. Oysaki OfType<T> metodu bu durumu tamamen grmezden
gelir ve dier nesneden devam eder. OfType<T> kendi ierisinde is anahtar kelimesini
kullanarak tip kontrol yapmaktayken, Cast<T> dorudan dntrme admn uygular.

imdi OfType<T> metodunu rnek bir senaryo zerinden ele almaya alalm. rnein
uygulamamzda kullandmz .Net Framework 2.0 ile gelitirilmi bir ktphane olsun. Bu
ktphane ierisinde yer alan metodlardan bazlarnnda ArrayList gibi tr gvenli olmayan
koleksiyonlar dndrdn dnelim. Referansta bulunan uygulamann .Net 3.5 tabanl olduu
dnlecek olursa, gelen koleksiyon nesneleri zerinden LINQ sorgular altrlmas istenebilir.
Bu noktada OfType<T> metodu olduka ie yarayacaktr. Sz konusu senaryoyo ele almak iin
aadaki tipi ieren bir snf ktphanesi(Class Library) olduunu dnelim.

public class Yardimci


{
public ArrayList ListeyiAl()
{
ArrayList liste = new ArrayList();
liste.Add("Burak");
liste.Add("Bili");
liste.Add("Behet");
liste.Add("Necdet");
liste.Add("Kerim");
liste.Add("Mayk");
liste.Add(19.90);
liste.Add(10);
liste.Add(true);
liste.Add(false);
liste.Add('C');
return liste;
}
}

www.bsenyurt.com Page 382


Kod parasnda kastl olarak ArrayList ierisine farkl tipte veriler atlmtr.
Eerki LINQ sorgusunda bu metoddan dnen deerler ierisinden sadece string tabanl olanlar ele
almak istiyorsak, OfType<T> metodunu aadaki kod parasnda olduu gibi kullanabiliriz.

GenelIslemler.Yardimci yrdm = new GenelIslemler.Yardimci();

var besHarfliler = from nesne in yrdm.ListeyiAl().OfType<string>()


where nesne.Length == 5
select nesne;

foreach (string nesne in besHarfliler)


Console.WriteLine(nesne);

OfType<string> metodu buradaki kullanma gre ListeyiAl fonksiyonundan


gelen ArrayList ierisindeki tm nesnelerde, is kontroln yaparak sadece String olanlar geriye
dndrmektedir. Sonrasnda nesnelerin karakter uzunluu kyaslanarak 5 ise ekilmektedir.
Program kodunun kts aadaki gibi olacaktr.

Yazmzda son olarak .Net Framework 2.0 ile yazlm ve DataTable nesnelerini kullanan bir
uygulamay .Net 3.5' e tayarak basit LINQ sorgularn nasl ele alabileceimizi incelemeye
alacaz. (LINQ sorgularnn ilevselliinin n plana kt vakalarda, var olan .Net
uygulamalar .Net 3.5 versiyonuna terfi edilmek durumdan kalabilir.) Bu amala ilk olarak .Net
Framework 2.0 ile gelitirilmi ve test amacyla aadaki kodlara sahip bir Console uygulamamz
olduunu dnelim.

using System;
using System.Data;
using System.Data.SqlClient;

namespace Net20DataTable
{
class Program
{
static void Main(string[] args)
{
DataTable tbl = null;

using (SqlConnection conn = new SqlConnection("data


source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlDataAdapter adapter = new SqlDataAdapter("Select
ProductId,Name,ListPrice,Class,SellStartDate,ProductSubCategoryId From Production.Product",
conn);
tbl = new DataTable("Products");
adapter.Fill(tbl);
}
}
}
}

www.bsenyurt.com Page 383


Kod, AdventureWorks isimli SQL Server 2005 veritabanna balanmakta
ve Production emasndaki Product tablosundan bir ka alan ekmektedir. ekilen veri kmesi
ilenilmek zere bir DataTable nesnesi ierisinde toplanmaktadr. ok doal olarak uygulama .Net
Framework 2.0 tabanl olduundan, LINQ ifadelerinin DataTable zerinden uygulanmas(veya
baka balantsz katman nesneleri zerinden) mmkn deildir. Eer
elimizde Visual Studio 2008 var ise yaplmas gerekenler ok basittir. ncelikli olarak proje
zelliklerinden(Properties) Application sekmesine geilmeli ve Target Framework seenei .Net
Framework 3.5 olarak deitirilmelidir.

Bu ilemin ardndan uygulamann bir kere daha derlenmesinde yarar vardr. (Sz konusu admlarn
ardndan System.Core.dll assembly' nn projeye hemen referans edildiide
grlebilir.) Artk LINQ sorgularnn yazlmasna balanabilir. DataTable iin bu sorgularn
uygulanabilmesi iin AsEnumerable metodunun eriilebilir olmas gerekmektedir. Ancak bu
geniletme metoduna u anda eriilemedii grlmektedir. Bunun
sebebi System.Data.DataSetExtensions.dll assembly' nn projeye referans edilmemi
olmasdr. Dolaysyla ncelikle bu assembly' n referans edilmesi gerekmektedir.

Artk uygulamada yer alan DataTable zerinde LINQ sorgular altrlabilir. te bir rnek;

var altKategorisi4OlanUrunler = from row in tbl.AsEnumerable()


where row["ProductSubCategoryId"].ToString() == "4"
select new
{
Id = Convert.ToInt16(row["ProductId"]),
Ad = row["Name"].ToString(),
Fiyat = Convert.ToDouble(row["ListPrice"])
};

www.bsenyurt.com Page 384


foreach (var urun in altKategorisi4OlanUrunler)
Console.WriteLine(urun.ToString());

Bu kod parasnda grlen LINQ sorgusuna


gre DataTable ierisinden ProductSubCategoryId alannn
deeri 4 olanlarn ProductId,Name,ListPrice kolonlarnn verilerinden oluan yeni bir isimsiz
tip(Anonymous Type) topluluu elde edilmektedir. Kodun ekran kts aadakine benzer
olacaktr.

Grld gibi LINQ sorgular .Net Framework ierisinde pek ok farkl alanda
uygulanabilmektedir. Reflection, IO, Windows Forms Controls, Application Log,
DataTable, eski bir uygulamadan gelen ArrayList bu yazda ele alnan basit bir ka alandr. LINQ
sorgular Office rnlerinde dahi kullanlabilmektedir. Sz gelimi Outlook ierisindeki
kontaklar LINQsorgular ile filtrelenebilir. rnekleri arttrmak ve yaymak mmkndr. Ancak
unutulmamas gereken noktalardan biriside bu ilemlerin yaplmas iin LINQ sorgularnn
olmasnn zorunlu olmaddr. yleki LINQ sorgularda znde, .Net Framework 3.5 ile
gelen geniletme metodlarn(Extension Methods) youn bir ekilde ele almaktadr. Bir baka
deyile LINQ olmadanda metodlar yardmyla bu istekler karlanabilir. Dier taraftan LINQ
sorgularnn getirdii dil esneklii, kullanm kolayl, anlalabilirlik gz ard edilmemelidir. Her
gelitirici kulland programlama dili yardmyla nesneler zerinden SQL benzeri sorgu
ifadeleri yazabilmek ister. LINQ bu imkan salayarak nemli bir a kapatmaktadr. Bylece
geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

C# 3.0 : Derinlemesine Lambda fadeleri (


31.03.2008 ) - C# 3.0
Deerli Okurlarm Merhabalar,

C# programlama dilinin 3nc versiyonu ile birlikte gelen nemli yeniliklerden


biriside lambda(=>) operatrdr. Bu operatrn kullanld ifadeler
yardmyla temsilci(delegate)oluturulmas, kod blounun yazlmas, sonularn alnmas ve tip
tahmini(Type Inference) gibi ilemlerin tek seferde gerekletirilmesi mmkndr. Bu sebepten
dolayLINQ(Language INtegrated Query) sorgularnda yer alan geniletme
metodlarnda(Extension Methods) byk neme sahiptir. Ne varki lambda operatrn
kavramak iin ona olan ihtiyacn nereden dodunu bilmek ve nasl bu operatre ulaldn
anlamak gerekmektedir. En iyi balang noktas elbetteki C# dilinin ilk versiyonudur. Bu yazmzda
lambda operatrnn getirdii avantajlar grmeye alrken derinlemesinede inceliyor olacaz.

www.bsenyurt.com Page 385


Hereyden nce C# 1.0 versiyonunda kullanc tanml bir tipe ait koleksiyonlar zerinde baz
sorgulamalar yapmak istediimizi dnelim. C# 1.0 versiyonunda generic mimari kavram
yoktur. Bu sebepten generic olarak trden bamsz ve .Net Framework ierisinde nceden
tanmlanm olan koleksiyonlar bulunmamaktadr. Bunun yerine elemanlar her
zaman object trnden olan ArrayList, Stack, Queue gibi Collection bazl koleksiyonlar
ile Hashtable ve SortedList gibi Dictionary bazl koleksiyonlar mevcuttur. Eer sadece bizim
istediimiz tip ile alacak kuvvetle trlendirilmi bir koleksiyon(Strongly Typed
Collection) kullanmak istersek CollectionBase veya DictionaryBase abstract snflarndan
tretme yolunu tercih edebiliriz. Bylece sadece istenilen tipler ile alacak bir koleksiyonumuz
olur.(Lakin bu koleksiyon tip gvenli-type safety olmasna ramen gereksiz boxing ve
unboxing ilemlerini engellemez.) u an iin asl ama bu koleksiyon ierisinde yer alan tipler
zerinde farkl sorgular altrabilmektir. Sz gelimi bir personelin bilgirini tanmlayan snfa ait bir
koleksiyon ierisinden, alann maana, adna, giri tarihine gre sorgular yaparak alt
koleksiyonlarn ekilmesini salayacak fonksiyonelliklerin olmas istenebilir. Hatta bu metodarn
saysnn arttrlmasnada olanak verecek ekilde esnek bir yapnn gelitirilmesi istenebilir.
Dolaysyla alt koleksiyonlar elde edebilmek iin gelitirilen ortak bir metodun kullanaca koulsal
fonksiyonelliklerin iaret edilebilmesi son derece yararl olur. te bu
noktada temsilciler(Delegates) devreye girmektedir. Bu cmleler ile tam olarak neye sebebiyet
verdiimizi grmek zere C# 1.0 dilinin yeteneklerinin kullanld aadaki program kodu gz
nne alnabilir.

Kod ierii;

www.bsenyurt.com Page 386


using System;
using System.Collections;

namespace DotNet1Deyken
{
enum Departman
{
BilgiIslem
,Yazilim
,Muhasebe
,InsanKaynaklari
,GenelMudurluk
}

class Personel
{
int _id;
string _ad;
string _soyad;
Departman _bolumu;
double _maas;
DateTime _girisTarihi;

public DateTime GirisTarihi


{
get { return _girisTarihi; }
set { _girisTarihi = value; }
}

public string Soyad


{
get { return _soyad; }
set { _soyad = value; }
}

public double Maas


{
get { return _maas; }
set { _maas = value; }
}

internal Departman Bolumu


{
get { return _bolumu; }
set { _bolumu = value; }
}

public string Ad
{
get { return _ad; }
set { _ad = value; }
}

public int Id
{
get { return _id; }

www.bsenyurt.com Page 387


set { _id = value; }
}

public Personel(int id, string ad, string soyad, Departman bolumu, double maas,DateTime
girisTarihi)
{
Id = id;
Ad = ad;
Soyad = soyad;
Bolumu = bolumu;
Maas = maas;
GirisTarihi = girisTarihi;
}
public override string ToString()
{
return String.Format("{0} {1} {2} {3} {4} {5}", Id.ToString(), Ad, Soyad.ToUpper(),
Bolumu.ToString(), Maas.ToString("C2"), GirisTarihi.ToShortDateString());
}
}

class PersonelList
: CollectionBase
{
public void Ekle(Personel prs)
{
List.Add(prs);
}
public void Cikart(Personel prs)
{
List.Remove(prs);
}
}

delegate bool KontrolHandler(Personel p);

class Program
{
static bool DepartmaniIKmi(Personel p)
{
return p.Bolumu == Departman.GenelMudurluk;
}
static bool AdininBasHarfiBmi(Personel prs)
{
return prs.Ad[0] == 'B';
}
static bool Maas1000Uzerindemi(Personel prs)
{
return prs.Maas > 1000;
}

static PersonelList Bul(PersonelList liste,KontrolHandler handler)


{
PersonelList sonucListesi = new PersonelList();
foreach (Personel prs in liste)
{
if (handler(prs))

www.bsenyurt.com Page 388


sonucListesi.Ekle(prs);
}
return sonucListesi;
}

static void Listele(PersonelList liste)


{
foreach (Personel prs in liste)
Console.WriteLine(prs.ToString());
Console.WriteLine("");
}

static void Main(string[] args)


{
PersonelList calisanlar = new PersonelList();

calisanlar.Ekle(new Personel(1000,"Mayk","Hemr", Departman.BilgiIslem,1050,new


DateTime(1979,10,1)));
calisanlar.Ekle(new Personel(1001,"Byk","Bakan",
Departman.GenelMudurluk,53000,new DateTime(1989,2,3)));
calisanlar.Ekle(new Personel(1002,"EmSi","Hemmr",
Departman.GenelMudurluk,13500,new DateTime(1990,2,4)));
calisanlar.Ekle(new Personel(1003,"Tombul","Raydr",
Departman.InsanKaynaklari,2250,new DateTime(1994,8,5)));
calisanlar.Ekle(new Personel(1008,"irine","irin", Departman.BilgiIslem,900,new
DateTime(1991,3,6)));
calisanlar.Ekle(new Personel(1006,"Burak","Selim", Departman.InsanKaynaklari,2250,new
DateTime(1976,7,3)));
calisanlar.Ekle(new Personel(1004,"Osvaldo","Nartayyo", Departman.Muhasebe,3500,new
DateTime(1975,6,3)));
calisanlar.Ekle(new Personel(1005,"Higuin","Kim", Departman.Yazilim,1250,new
DateTime(1974,4,2)));
calisanlar.Ekle(new Personel(1007,"Karim","Cabbar", Departman.Yazilim,750,new
DateTime(1975,2,7)));
calisanlar.Ekle(new Personel(1011, "Billl", "Geytis", Departman.Yazilim, 650, new
DateTime(1976, 3, 8)));

// Departman Insan Kaynaklar olanlarn bulunmas


PersonelList sonuclar1=Bul(calisanlar, new KontrolHandler(DepartmaniIKmi));

// sminin ba harfi B olanlarn bulunmas


PersonelList sonuclar2 = Bul(calisanlar, new
KontrolHandler(AdininBasHarfiBmi));

// Maa 1000 YTL zerinde olanlarn bulunmas


PersonelList sonuclar3 = Bul(calisanlar, new
KontrolHandler(Maas1000Uzerindemi));

Listele(sonuclar1);
Listele(sonuclar2);
Listele(sonuclar3);
}
}
}

www.bsenyurt.com Page 389


ncelikli olarak bu uzun Console uygulamas kodlarnda neler olduuna bir
bakalm. Personel isimli snf bir alann Id' sini, adn, soyadn, ie giri tarihini, maan,
departmann ve maan tutacak ekilde tanmlanmtr. Bu snfa ait rneklerin ieriklerinin kolay
bir ekilde string olarak alnabilmesi iinde ToString metodu Personel tipi
ierisinde ezilmitir(override). Personelin blm, Departman isimli bir enum sabiti ile
belirtilmektedir. PersonelList isimli snf CollectionBase abstract snfndan tretilmektedir. Bu
nedenle Collection tabanl bir koleksiyondur. Konunun kolay anlalabilmesi iin
sadece Ekle ve Cikart isimli iki fonksiyonellie sahiptir. Bu metodlar sadece Personeltipinden
parametreler almaktadr. Buda zaten PersonelList isimli koleksiyonun tip gvenli(Type
Safety) olmasn salamaktadr. Dikkatimiz eken tiplerden
biriside KontrolHandler isimlitemsilcidir(delegate).

Temsilcileri(delegates) metodlar iaret edebilecek ekilde kullanlabilen .Net tipidir.


Bir temsilci iaret edebilecei metodun parametrik yaps ile dn
tipinidebelirtmektedir.

Sz konusu temsilci, Personel tipinden bir parametre alan ve geriye bool deer dndren
metodlar iaret edecek ekilde tanmlanmtr. Bu temsilcinin tek bir tasarm amac vardr. Buna
gre, bir Personel nesne rneinin herhangibir art salayp salamadna
dair true veya false deer dndrecek bir metodun iaret edilmesini salamaktadr. Peki neden
byle bir temsilciye ihtiyacmz vardr? Bu sorunun cevabn Bul isimli fonksiyon vermektedir.

static PersonelList Bul(PersonelList liste,KontrolHandler handler)


{
PersonelList sonucListesi = new PersonelList();
foreach (Personel prs in liste)
{
if (handler(prs))
sonucListesi.Ekle(prs);
}
return sonucListesi;
}

Dikkat edilecek olursa Bul metodu geriye PersonelList tipinden bir nesne rnei dndrmektedir.
Bu nesne rnei metod ierisinde oluturulmaktadr. Oluturulma ilemi srasnda ise belirli bir
arta baklmaktadr. Nitekim bu artn ne olduu belli deildir. Ancak artn sonucunun alnmasn
salayan metodu iaret edebilecek KontrolHandler tipinden birtemsilci, fonksiyona parametre
olarak gelmektedir. Temsilci nesne rnei alma zamannda(runtime) ilgili fonksiyonu iaret
edeceinden, if ifadesi ierisindeki ar aslnda o andaki Personel nesne rnei iin koul
metoduna doru yaplan bir yrtmeden baka bir ey deildir.

Artk tek yaplmas gereken artlar salayacak metodlarn yazlmas ve sonrasnda ise Bul
fonksiyonelliinin kullanlarak ilgili sonu kmesinin alnmasdr. rnein IK departmannda
alan personelin bulunabilmesi iin DepartmanIKmi isimli bir metod gelitirilmitir.

static bool DepartmaniIKmi(Personel p)


{
return p.Bolumu == Departman.GenelMudurluk;
}

Bu metod basite gelen Personel nesne rneinin Bolumu zelliine bakmakta ve


geriye true yada false deerini dndrmektedir. Baka bir rnek olarak maa 1000 YTL
zerinde olanlarn elde edilmesi istenebilir. Bunun iinde Maas1000Uzerindemi isimli bir metod
gelitirilmitir.

www.bsenyurt.com Page 390


static bool Maas1000Uzerindemi(Personel prs)
{
return prs.Maas > 1000;
}

Tahmin edilecei zere bu fonksiyonda, KontrolHandler temsilcisinin belirttii yapya uygun bir
ekilde tasarlanmtr. Bu yaklamlar gz nne alndnda koleksiyon ierisinde istenildii gibi
filtreleme yaplabilecei grlmektedir. Tek art temsilciye uygun tipte bir karlatrma
fonksiyonelliinin var olmasn salamaktr. Uygulamann alma zamanndaki kts aadaki gibi
olacaktr.

Grld gibi maa 1000 YTL zerinde olanlar, IK departmannda alanlar ve isminin ba harfi B
olanlar kolay bir ekilde elde edilmektedir.

Bu yaklam her ne kadar kolay ve anlalr olsada baz skntlar olduu ortadadr. Hereyden
nce Bul fonksiyonunun parametresi olan temsilci tipinin iaret edecei metod bloklarnn ayr ayr
yazlyor olma art vardr. Dier taraftan sz konusu mimari uanda sadece PersonelList isimli
koleksiyona uygulanabilecek ekilde tasarlanmtr. Hatta KontrolHandler isimli temsilci dahi
sadece Personel tipleri ile alabilecek ekilde ele alnabilmektedir. Oysaki bu yapnn herhangibir
koleksiyon tipi ierisinde ele alnabilmesi salanabilmelidir. Bu, ilgili yapnn sadece uygulama bazl
deil Framework bazl olacak ekilde geniletilebilmesini salayacaktr ki bu olduka nemlidir.
Elbette bu i sanld kadar kolay deildir. Nitekim trden bamsz olacak ekilde fonksiyonel
yaplarn olmas arttr. Peki yleyse olaya C# 2.0 asndan bakmaya alalm. Bu sefer
elimizde isimsiz metodlar(Anonymous Methods) ve generic mimari gibi olduka gl kozlar
yer almaktadr. Dolaysyla yukardaki rnek mimari modeli C# 2.0 ierisinde aadaki ekilde ele
alnabilir.

using System;
using System.Collections.Generic;

namespace DotNet2Deyken
{
enum Departman
{
BilgiIslem
,Yazilim
,Muhasebe
,InsanKaynaklari
,GenelMudurluk
}

www.bsenyurt.com Page 391


class Personel
{
int _id;
string _ad;
string _soyad;
Departman _bolumu;
double _maas;
DateTime _girisTarihi;

public DateTime GirisTarihi


{
get { return _girisTarihi; }
set { _girisTarihi = value; }
}

public string Soyad


{
get { return _soyad; }
set { _soyad = value; }
}

public double Maas


{
get { return _maas; }
set { _maas = value; }
}

internal Departman Bolumu


{
get { return _bolumu; }
set { _bolumu = value; }
}

public string Ad
{
get { return _ad; }
set { _ad = value; }
}

public int Id
{
get { return _id; }
set { _id = value; }
}

public Personel(int id, string ad, string soyad, Departman bolumu, double maas, DateTime
girisTarihi)
{
Id = id;
Ad = ad;
Soyad = soyad;
Bolumu = bolumu;
Maas = maas;
GirisTarihi = girisTarihi;
}

www.bsenyurt.com Page 392


public override string ToString()
{
return String.Format("{0} {1} {2} {3} {4} {5}", Id.ToString(), Ad, Soyad.ToUpper(),
Bolumu.ToString(), Maas.ToString("C2"), GirisTarihi.ToShortDateString());
}
}

// Koul kontroln yapabilecek metodlar ieren tr bamsz temsilci(Generic Delegate) tanm


delegate bool KontrolHandler<T>(T parametre);

class Program
{
// generic tipten oluan koleksiyon zerinden alt kme ekme ilemini stlenen metod
static List<T> Bul<T>(List<T> liste,KontrolHandler<T> handler)
{
List<T> sonuclar = new List<T>();
foreach (T eleman in liste)
if (handler(eleman)) // Generic temsilcinin iaret edecei karlatrma metodu
arlr.
sonuclar.Add(eleman);
return sonuclar;
}

// Generic Listeleme fonksiyonu


static void Listele<T>(List<T> liste)
{
foreach (T t in liste)
Console.WriteLine(t.ToString());
Console.WriteLine("");
}

static void Main(string[] args)


{
List<Personel> calisanlar = new List<Personel>();

calisanlar.Add(new Personel(1000, "Mayk", "Hemr", Departman.BilgiIslem, 1050, new


DateTime(1979, 10, 1)));
calisanlar.Add(new Personel(1001, "Byk", "Bakan", Departman.GenelMudurluk, 53000,
new DateTime(1989, 2, 3)));
calisanlar.Add(new Personel(1002, "EmSi", "Hemmr", Departman.GenelMudurluk, 13500,
new DateTime(1990, 2, 4)));
calisanlar.Add(new Personel(1003, "Tombul", "Raydr", Departman.InsanKaynaklari, 2250,
new DateTime(1994, 8, 5)));
calisanlar.Add(new Personel(1008, "irine", "irin", Departman.BilgiIslem, 900, new
DateTime(1991, 3, 6)));
calisanlar.Add(new Personel(1006, "Burak", "Selim", Departman.InsanKaynaklari, 2250,
new DateTime(1976, 7, 3)));
calisanlar.Add(new Personel(1004, "Osvaldo", "Nartayyo", Departman.Muhasebe, 3500,
new DateTime(1975, 6, 3)));
calisanlar.Add(new Personel(1005, "Higuin", "Kim", Departman.Yazilim, 1250, new
DateTime(1974, 4, 2)));
calisanlar.Add(new Personel(1007, "Karim", "Cabbar", Departman.Yazilim, 750, new
DateTime(1975, 2, 7)));
calisanlar.Add(new Personel(1011, "Billl", "Geytis", Departman.Yazilim, 650, new
DateTime(1976, 3, 8)));

www.bsenyurt.com Page 393


// Anonymous Method yardmyla arama ilemleri yaplr
// Bul metodunun ikinci parametrelerinin nasl verildiine dikkat edelim

// Insan Kaynaklar departmannda alanlarn bulunmas


List<Personel> IKCalisanlari=Bul<Personel>(calisanlar,delegate(Personel p)
{
return p.Bolumu ==
Departman.Yazilim;
}
);

// ubat aynda ie girenlerin bulunmas


List<Personel> SubatAyindaBaslayanlar = Bul<Personel>(calisanlar,
delegate(Personel p)
{
return p.GirisTarihi.Month == 2;
}
);

//Departman Yazilim olanlardan Maa 1000 YTL zerinde olanlarn bulunmas


List<Personel> MaasiVeDepartmaninaGore = Bul<Personel>(calisanlar,
delegate(Personel p)
{
return (p.Maas >= 1000 &&
p.Bolumu == Departman.Yazilim);
}
);
Listele<Personel>(IKCalisanlari);
Listele<Personel>(SubatAyindaBaslayanlar);
Listele<Personel>(MaasiVeDepartmaninaGore);
}
}
}

Bu uzun kod parasnda bir nceki versiyona gre en byk farkllklar generic koleksiyon
ile generic ve isimsiz metod(Anonymous Method) kullanmlardr. Dikkat edilecek olursa
herhangibir tipteki List koleksiyonu zerinde arama ilemi yaplabilmesini salayacak
ekilde generic bir Bul metodu yer almaktadr. Dahada nemlisi, koleksiyon ierisindeki
elemanlarn kyaslama ilemlerinin yaplaca metodlar iaret edebilecek olan
temsilcide generic olarak tanmlanmtr. Bu sayede T tipindeki bir List koleksiyonu
ierisinde Bulmetodunun kullanlabilmesi ve o tip iin bir koullandrma yaplabilmesi
salanmaktadr. Fakat btn bunlara ramen en ok dikkate deer ksmlardan biriside, isimsiz
metodlarn kullanmdr. Bu sebepten dolay bir nceki rnekte olduu gibi, ayr ayr karlatrma
metodlarnn yazlmasna gerek kalmamaktadr. Tam aksine Bulmetodunun kullanld yerlerde
ikinci parametrelerde isimsiz metod kullanlarak koul deyimlerinin ayn ifade ierisinde
tanmlanabilmeside salanmtr. rnein ubat aynda ie giren personelin bulunabilme srecini
gz nne alalm. Burada Bul metodu, calisanlar isimli generic koleksiyondaki Personel nesne
rneklerini tek tek dolamal, GirisTarihizellikleri zerinden Month deerlerinin 2 olup
olmadna bakmal ve eer yleyse bunlar yeni bir koleksiyonda birletirerek geriye
dndrmelidir. simsiz metodlar yardmyla bu i aada grld gibi tek bir ifadede
salanabilir.

List<Personel> SubatAyindaBaslayanlar = Bul<Personel>(calisanlar, delegate(Personel p)


{
return p.GirisTarihi.Month
== 2;

www.bsenyurt.com Page 394


}
);

Dikkat edilecek olursa delegate anahtar kelimesi burada KontrolHandler tipini iaret etmektedir.
Dahas kod yazlrken generic mimarinin, Visual Studio IDE' si ierisinde aadaki ekilde ele
alnd grlmektedir.

Grld gibi Bul metoduna generic parametre olarak Personel tipi


verildiinde, liste isimli List<T> koleksiyonu ve handler isimli KontrolHandler temsilcisi
otomatik olarak bu tiple alacak hale gelmektedir. Buda Bul metodunun generic yapsndan
kaynaklanmaktadr.

Sonu olarak program kts aadaki gibi olacaktr.

Elbette Bul fonksiyonu gelitirici tarafndan yazlm bir metoddur. Oysaki .Net Framework
2.0 zellikle List<T> koleksiyonlar zerinde bu tip filtreleme ve arama ilemlerinin
gerekletirilmesi amacyla hazr Predicate temsilcisini kullanan Find, FindAll, Exists,
FindIndex, FindLast, FindLastIndex, RemoveAll gibi metodlar iermektedir. (Burada hazr bir
temsilcinin olmas gelitiricinin uygulamadan bamsz olacak ekilde, Framework' n kullanld
her yerde sz konusu koullandrma metodlarn iaret ederek, baka hazr CLR tipi metodlarna
parametre olarak verebilecei anlamna da gelmektedir.) Dolaysyla yukarda gelitirilen
rnek, .Net Framework 2.0' n tipleri sayesinde aadaki hale getirilebilir.

class Program
{
static void Listele<T>(List<T> liste)
{
foreach (T t in liste)
Console.WriteLine(t.ToString());
Console.WriteLine("");
}

static void Main(string[] args)


{
List<Personel> calisanlar = new List<Personel>();

#region Test Verileri

www.bsenyurt.com Page 395


// Test verilerinin girildii kodlar

#endregion

List<Personel> BHarfliler =
calisanlar.FindAll(delegate(Personel p)
{
return p.Ad[0] == 'B';
}
);
List<Personel> SubattaBaslayanlar=
calisanlar.FindAll(delegate(Personel p)
{
return p.GirisTarihi.Month == 2;
}
);
List<Personel> GenelMudurlukCalisanlari =
calisanlar.FindAll(delegate(Personel p)
{
return p.Bolumu == Departman.GenelMudurluk;
}
);

Listele<Personel>(BHarfliler);
Listele<Personel>(SubattaBaslayanlar);
Listele<Personel>(GenelMudurlukCalisanlari);
}
}

Bu kez delegate anahtar kelimesi FindAll metodunun istedii Predicate<T> temsilcisini iaret
etmektedir. Kod yazm srasnda intellisense ile bu ak bir ekilde grlmektedir.

Mimaride halen daha eksiklikler vardr. zellikle veri taban uygulamalarnda yer alan sorgulama
tekniklerinin, programatik tarafta ifade edilme zorluklar bilinmektedir. ok basit olarak
dnldnde, bir veritaban tablosunun program tarafnda Entity olarak snf bazl ifade
edilmesi sonrasnda gelitiricilerin beklentisi, veri sorgulama dili esnekliinin nesnel olarakta
salanabilmesidir. Bir baka deyile bilinen select, where, group by, distinct, sum vb...
sorgulama kelimelerinin, program tarafndaki nesnel varlklar zerinde de uygulanamabilmesi
istenmektedir. te bu LINQ mimarisinin gelitirilmesinin en byk nedenlerinden de birisidir. Peki
elde bulunan imkanlar ile bu nasl salanabilir? Yoksa dile yeni bir takm kolaylatrc zelliklerin
entegre edilmesimi gerekmektedir?

Hereyden nce son rnekte yer alan FindAll metodu ile, bir koleksiyon zerinde filtreleme
yaplabildii grlmektedir. Bu bir anlamda Where ve Select gibi ifadelerin bir karl olarak gz
nne alnabilir. Ancak bu yeterli deildir. Yeni tipler gelitirmeden, var olan .Net
Framework tiplerine FindAll metoduna benzer fonksiyonel yenilikleri ilave edebilmek
gerekmektedir. te bu noktada Extension metodlar devreye girerek
zellikle IEnumerable<T> uyarlamal tiplerin geniletme metodlar ile LINQ mimarisine destek
verebilmesi salanmaktadr. in ierisinde yine temsilci(delegate) tipleri rol
almaktadr. LINQ mimarisine destek verebilmek iin pek ok temsilci tipi gelitirilmi
ve Framework ierisine dahil edilmitir. Bu kadar ilerlemeden nce, yazya konu olan rnein C#

www.bsenyurt.com Page 396


3.0 ierisindeki gelitirilme ekline bakmakta yarar vardr. Nitekim ilk hedef Lambda ifadelerinin
roln kavramaktr.(Bu seferki rnek Visual Studio 2008 zerinde .Net Framework 3.5 seilerek
yaplmtr.)

using System;
using System.Collections.Generic;
using System.Linq;

namespace DotNet3Nokta5Deyken
{
enum Departman
{
BilgiIslem
,Yazilim
,Muhasebe
,InsanKaynaklari
,GenelMudurluk
}
class Personel // Bu snfta otomatik zellikler(Automatic Property) kullanlmtr.
{
public int Id { get; set; }
public string Ad { get; set; }
public string Soyad { get; set; }
public Departman Bolumu { get; set; }
public double Maas { get; set; }
public DateTime GirisTarihi { get; set; }

public override string ToString()


{
return String.Format("{0} {1} {2} {3} {4} {5}", Id.ToString(), Ad, Soyad.ToUpper(),
Bolumu.ToString(), Maas.ToString("C2"), GirisTarihi.ToShortDateString());
}
}
class Program
{
static void Main(string[] args)
{
// Object Initializers' dan faydalanlmtr.
List<Personel> calisanlar = new List<Personel>()
{
new Personel(){Id=1000, Ad="Mayk", Soyad="Hemr",

www.bsenyurt.com Page 397


Bolumu=Departman.BilgiIslem, Maas=1050, GirisTarihi=new DateTime(1979, 10, 1)},
new Personel(){Id=1001, Ad="Byk", Soyad="Bakan",Bolumu=
Departman.GenelMudurluk,Maas= 53000,GirisTarihi= new DateTime(1989, 2, 3)},
new Personel(){Id=1002, Ad="EmSi", Soyad="Hemmr",
Bolumu=Departman.GenelMudurluk, Maas=13500, GirisTarihi=new DateTime(1990, 2, 4)},
new Personel(){Id=1003, Ad="Tombul", Soyad="Raydr",
Bolumu=Departman.InsanKaynaklari, Maas=2250, GirisTarihi=new DateTime(1994, 8, 5)},
new Personel(){Id=1008, Ad="irine", Soyad="irin",Bolumu= Departman.BilgiIslem,
Maas=900, GirisTarihi=new DateTime(1991, 3, 6)},
new Personel(){Id=1006, Ad="Burak", Soyad="Selim",
Bolumu=Departman.InsanKaynaklari,Maas= 2250, GirisTarihi=new DateTime(1976, 7, 3)},
new Personel(){Id=1004, Ad="Osvaldo", Soyad="Nartayyo",
Bolumu=Departman.Muhasebe, Maas=3500,GirisTarihi= new DateTime(1975, 6, 3)},
new Personel(){Id=1005, Ad="Higuin", Soyad="Kim",Bolumu= Departman.Yazilim,
Maas=1250,GirisTarihi= new DateTime(1974, 4, 2)},
new Personel(){Id=1007, Ad="Karim", Soyad="Cabbar", Bolumu=Departman.Yazilim,
Maas=750, GirisTarihi=new DateTime(1975, 2, 7)},
new Personel(){Id=1011, Ad="Billl", Soyad="Geytis", Bolumu=Departman.Yazilim,
Maas=650,GirisTarihi= new DateTime(1976, 3, 8)}
};

// B ile balayanlar
var AdiBIleBaslayanlar = calisanlar.FindAll((Personel p) => (p.Ad[0] == 'B'));

// Departman Yazilim olanlar (Burada type inference sz konusu)


var YazilimDepartmaniCalisanlari = calisanlar.FindAll(p => p.Bolumu ==
Departman.Yazilim);

//Giris yl 1976 ncesi olanlar ekilirken baka bir metod arlyor.


var GirisYili1976OncesiOlanlar = calisanlar.FindAll(
p =>{
if (p.GirisTarihi.Year < 1976)
{
PrimArttir(p);
return true;
}
else
return false;
}
);

Listele<Personel>(AdiBIleBaslayanlar);
Listele<Personel>(YazilimDepartmaniCalisanlari);
Listele<Personel>(GirisYili1976OncesiOlanlar);
}

private static void PrimArttir(Personel p)


{
Console.WriteLine("\t"+p.Ad+" "+p.Soyad.ToUpper()+" iin prim arttrm talebi");
}

static void Listele<T>(IEnumerable<T> liste)


{
foreach (T t in liste)
Console.WriteLine(t.ToString());
Console.WriteLine("");

www.bsenyurt.com Page 398


}
}
}

rnekte C# 3.0 ile birlikte gelen pek ok yenilik kullanlmaya allmtr. var anahtar kelimesi,
koleksiyon ve Personel nesnelerininin balatlmas(object initialization), otomatik
zellikler(automatic properties) gibi. Ancak yazmzda odaklanacamz nokta => operatr ve
ierisinde yer ald ifadelerdir. Dikkat edilecek olursa FindAll metodlarnn ierisinde kullanlan
parametrelerde => operatrleri yer almaktadr. lk metod ars aadaki gibidir.

var AdiBIleBaslayanlar = calisanlar.FindAll((Personel p) => (p.Ad[0] == 'B'));

Burada => operatrnn sol tarafnda Personel tipinden bir deiken tanm yer almaktadr.
Operatrn sa tarafnda ise yine parantezler ierisinde p deikeninin Ad zelliinin ilk karakterine
baklmaktadr. Daha nceki rneklerden hatrlanaca gibi FindAll metodu Predicate temsilcisini
parametre olarak almaktadr. Bu temsilci geriye bool deer dndren ve generic tipte parametre
alan metodlar tayabilemektedir. Bu sebepten Lambda operatrnn sa tarafnda yer alan kod
parasnn bool tipinden bir deer dndryor olmas arttr. Predicate temsilcisinin iaret edecei
metodun alaca parametre ise operatrn sol tarafnda belirtilmektedir. Peki burada Lambda
operatr neyi salamaktadr? Nitekim ayn ama iin isimsiz metod(anonymous
method) kullanmda mmkndr. Hatta isimsiz metod kullanmadanda yaplabildii grlmektedir.
Ne farki fonksiyonel programlama ortamlarna bakldnda bu tip ifadelerin yaygn bir ekilde ele
alnd grlmtr. Bununla beraber => operatr burada, temsilcinin rneklenmesi, iaret
edecei metoda parametre aktarlmas, uygun tipte sonu reten bir kod blounun yazlmas
operasyonlarnn tek bir ifade ierisinde gerekletirilmesini salamaktadr.

kinci kullanm ekli ilkinden biraz daha farkldr.

var YazilimDepartmaniCalisanlari = calisanlar.FindAll(p => p.Bolumu ==


Departman.Yazilim);

Bu sefer dikkat ekici nokta => operatrnn sol ve sa tarafndaki


deyimlerde parantez kullanlmay deildir. Dikkat edilmesi gereken nokta operatrn sol
tarafnda sadecep yazlmasdr. Oysaki bir nceki kullanm eklinde temsilcinin iaret ettii metoda
aktarlacak olan parametrenin tipi ak bir ekilde belirtilmitir. Burada tip tahmini(type
inference) kavram devreye girmektedir. yleki FindAll metodunun, List
koleksiyonunun generic yapsna gre kullanaca tipin Personel olma olasl muhtemeldir. Bu
son derece doaldr nitekim calisanlar deikeni List<Personel> tipinden bir koleksiyonu
tamaktadr. Buna gre compiler, p deikeninin Personel tipinden olacan tahmin eder. Bu
tahminin ne kadar tutarl olduu Visual Studio IDE' si ierisinde intellisense zellii ile ak bir
ekilde grlebilmektedir.

www.bsenyurt.com Page 399


Grld gibi lambda operatrnn sa tarafnda p deikeni kullanlmak istendikten sonra,
tahmin edilen tipin yeleri ekrana gelmektedir.

nc kullanm ekli ise aadaki gibidir.

var GirisYili1976OncesiOlanlar = calisanlar.FindAll(


p =>{
if (p.GirisTarihi.Year < 1976)
{
PrimArttir(p);
return true;
}
else
return false;
}
);

Burada ise tek fark lambda operatrnn sa tarafnda yer alan deyimlerde normal kod
bloklarnnda gelitirilebiliyor olmasdr. Bir baka deyile Predicate temsilcisinin istedii
ekilde bool deer dndrmek dnda, metod ars gibi farkl deyimlerde yaplabilmektedir.

Gelitirilen son rnek altrldnda aadaki ekran grntsnde yer alan sonularn alnd
grlmektedir.

Lambda operatrleri zellikle LINQ ierisinde yer alan geniletme metodlarnda sklkla
kullanlmaktadr. Bilindii zere LINQ sorgularnn desteklenmesi
iinEnumerable(System.Core.dll assembly' ierisinde yer alan System.Linq isim alannda yer

www.bsenyurt.com Page 400


almaktadr) isimli static snf ierisine ok sayda geniletme metodu(Extension
Methods) dahil edilmitir. Bu snfn en byk zelliklerinden biriside ierisinde yer alan
metodlarnn IEnumerable<T> trevli tipleri geniletmesidir. Dier taraftan sz konusu snf
ierisinde ounlukla Func isimli generic temsilci kullanlmaktadr. Bu temsilcisinin farkl
versiyonlar aadaki gibidir.

delegate TResult Func<TResult>(T arg)


delegate TResult Func<T, TResult>(T arg)
delegate TResult Func<T1,T2, TResult>(T1 arg1, T2 arg2)
delegate TResult Func<T1,T2,T3 TResult>(T1 arg1, T2 arg2, T3 arg3)
delegate TResult Func<T1,T2,T3,T4, TResult>(T1 arg1, T2 arg2, T3 arg3, T4 arg4)

Func bir temsilci olduu iin, kullanlaca her yerde lambda operatrleri ele alnabilir. Buna ok
basit olarak aadaki kod parasn rnek gsterebiliriz.

double sonuc = calisanlar


.Where<Personel>(p => p.Bolumu == Departman.Yazilim)
.Sum<Personel>(p => p.Maas);
Console.WriteLine(sonuc.ToString("C2"));

int sonuc2 = calisanlar.Aggregate(0,(toplam,p) => p.Maas>2000?toplam+=1:toplam);


Console.WriteLine(sonuc2.ToString());

lk kullanmda departman yazlm olan personelin maalarnn toplam bulunmutur. kinci


kullanmda ise lambda operatrnn iki parametreyi birden temsilciye gnderdii grlmektedir.
Dikkat edilecek olursa operatrn sol tarafnda toplam ve p isimli deikenler
tanmlanmaktadr.(Bu iki parametre bildirimi eer parantezler iersinde yazlmassa derleme zaman
hatas alnr. Dolaysyla lambda operatrnn sol tarafnda birden fazla parametre olacaksa
bunlarn parantezler ierisine alnmas gerekmektedir.) Buradaki toplam deikeni yine tahmin
edilerek int tipinden belirlenmitir. Bu tarz bir kullanm normaldir nitekim Func temsilcisinin bu
ekilde iki parametre ile alan versiyonu mevcuttur. Buna gre Aggregate metodu, personelin
maa 2000 YTL zerinde olanlar var ise, toplam deikeninin deerini 1 arttrarak geriye
dndrmektedir. (Bu ilem iin Sum metoduda kullanlabilir. Aggregate geniletme metodunun
yazlmasnn amac Sum, Count, Max, Min, Avg gibi standart gruplama fonksiyonlar dndaki
gereksinimlerin karlanmasdr.)

Artk Lambda operatrnn kullanm hakknda fikir sahibi olduumuzu sanyorum. imdi dier
noktalara deinmeye alalm. Sz gelimi lambda operatrnn yer ald
ifadeler IL(Intermediate Language) tarafnda nasl yorumlanmaktadr? Bu noktada lambda
operatrnn, isimsiz metod kullanm ile ayn IL ktsn verdiini syleyebiliriz. rnek olarak
aadaki kod parasn gz nne alalm.

using System;

namespace LambdaVeCIL
{
delegate T IslemHandler<T>(T T1,T T2);

class Program
{
static void Main(string[] args)
{
IslemHandler<double> hnd = (x, y) => x + y;

www.bsenyurt.com Page 401


IslemHandler<int> hnd2=
delegate(int a,int b){
return a + b;
};
}
}
}

Yukardaki kod parasnda yer alan IslemHandler isimli generic temsilci tipi, T trnden
iki parametre alan ve yine T trnden sonu reten metodlar iaret edebilecek ekilde
tasarlanmtr. hnd deikeni oluturulurken lambda ifadesinden, hnd2 oluturulurkende isimsiz
metoddan(anonymous method) yararlanlmtr. Bu kodun IL ktsna ildasm arac ile
bakldnda aa yapsnn aadaki gibi olduu grlr.(Aa yapsnn kolay bir ekilde elde
edilmesi iin Dump TreeView seeneinden yararlanlmtr.)

Program ierisinde b__0 ve b__1 adlar ile tanmlanm iki adet metod olduu grlmektedir.
Tahmin edilecei zere bu iki ye, lambda ifadesi ve isimsiz metod kullanm sonras oluturulmu
metodlardr. Bir baka deyile lambda operatr kullanldnda aynen isimsiz metodlarda olduu
gibi IL tarafnda i yapan metod oluturulmaktadr. Bu metodlar derleyici tarafndan oluturulan
gizli metodlardr. Compiler tarafndan oluturulduklar
iin CompilerGenerated nitelii(Attribute) ile imzalanmlardr.
Eer Mainmetodunun IL ktsna baklrsa aadaki kod paralarnn retildii grlr.

.method private hidebysig static void Main(string[] args) cil managed


{
.entrypoint
// Code size 66 (0x42)
.maxstack 3
.locals init ([0] class LambdaVeCIL.IslemHandler`1<float64> hnd,[1] class
LambdaVeCIL.IslemHandler`1<int32> hnd2)
IL_0000: nop
IL_0001: ldsfld class LambdaVeCIL.IslemHandler`1<float64>
LambdaVeCIL.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_0006: brtrue.s IL_001b
IL_0008: ldnull
IL_0009: ldftn float64 LambdaVeCIL.Program::'<Main>b__0'(float64,float64)

www.bsenyurt.com Page 402


IL_000f: newobj instance void class LambdaVeCIL.IslemHandler`1<float64>::.ctor(object,
native int)
IL_0014: stsfld class LambdaVeCIL.IslemHandler`1<float64>
LambdaVeCIL.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_0019: br.s IL_001b
IL_001b: ldsfld class LambdaVeCIL.IslemHandler`1<float64>
LambdaVeCIL.Program::'CS$<>9__CachedAnonymousMethodDelegate2'
IL_0020: stloc.0
IL_0021: ldsfld class LambdaVeCIL.IslemHandler`1<int32>
LambdaVeCIL.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0026: brtrue.s IL_003b
IL_0028: ldnull
IL_0029: ldftn int32 LambdaVeCIL.Program::'<Main>b__1'(int32,int32)
IL_002f: newobj instance void class LambdaVeCIL.IslemHandler`1<int32>::.ctor(object,native
int)
IL_0034: stsfld class LambdaVeCIL.IslemHandler`1<int32>
LambdaVeCIL.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0039: br.s IL_003b
IL_003b: ldsfld class LambdaVeCIL.IslemHandler`1<int32>
LambdaVeCIL.Program::'CS$<>9__CachedAnonymousMethodDelegate3'
IL_0040: stloc.1
IL_0041: ret
} // end of method Program::Main

Her ne kadar IL(Intermediate Language) taraf kark grnsede dikkat edilmesi gereken
noktalar IL_0001 - IL_0020 aralndaki yapnn IL_0020 - IL_0040 arasndaki ile ayn
olmasdr. Sz edilen ilk aralkta lambda ifadesinin kullanld satra ait retimler yer almaktadr.
kinci parada ise isimsiz metod kullanmna ait retimler bulunmaktadr. Yazmzn asl
amac IL tarafndaki retimleri kavramak deildir ancak sonu itibariyle lambda ifadeleri, isimsiz
metodlar ile ayn IL ktlarnnretilmesini salamaktadr.

Son olarak lambda ifadeleri kullanlrken dikkat edilmesi gereken baz durumlar gz nne alalm.

1 - Lambda ifadelerinde tanmlanan deikenler dier metodlar tarafndan kullanlamazlar. Baka


bir deyile, deikenlerin kapsam lambda ifadesinin snrlardr. Aadaki ekran grntsnde bu
durum ifade edilmektedir. Grld gibi ifade ierisinde tanmlanan d deikenine kapsam
dndan eriilememekte ve derleme zaman hatas(Compile-Time Error) alnmaktadr.

2 - Elbette lambda ifadesi dnda tanmlanm olan bir deikene, ifade ierisinden
eriilebilmektedir. Sz gelimi aadaki ekran ktsndanda grlecei gibi, ddeikeni lambda
ifadesi dnda 10 olarak tanmlanm ve metod arsndan sonra 11 olarak deitirilmitir.

www.bsenyurt.com Page 403


3 - Lambda ifadelerinin sol tarafnda yer alan parametrelerde ref ve out anahtar kelimeleri
kullanlamaz.

Bu yazmzda lambda ifadelerinin genel kullanm zerinde durulmaya almtr. Lambda


ifadelerinin getirdii kolayl grmek amacyla C# 1.0 tarafndan C# 3.0 tarafna doru ilerlenmeye
allmtr. Lambda ifadeleri ile ilikili bir dier nemli konuda ifade aalardr(Expression
Trees). Bu konuyu ilerleyen yazlarmzda incelemeye alacaz. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

C# 3.0: Derinlemesine Extension Method


Kavram ( 21.03.2008 ) - C# 3.0
Deerli Okurlarm Merhabalar,

Bilindii zere Language INtegrated Query(LINQ) mimarisinin uygulannda C# 3.0(Visual


Basic 9.0) ile birlikte gelen yenilikler olduka nemli bir yere sahiptir. Bu yeniliklerin ou var
olan .Net Framework 2.0 yapsn bozmadan geniletebilmek amacyla
tasarlanmtr. Geniletme Metodlar(Extension Methods) bu yeniliklerden sadece bir
tanesidir.(Object Initializers, Anonymous Types, Partial Methods, var anahtar kelimesi, auto-
implemented property, => operatr dier C# 3.0 yenilikleri arasnda saylabilir) Sz konusu
yeniliin k amac geniletilemeyen tiplere yeni fonksiyonelliklerin eklenebilmesinin
salanmasdr. yleki bu sayede koleksiyonlar(Collections), DataTable, dizi(Array) gibi var
olan CLR tipleri(Common Lanugage Runtime) zerinde LINQ tarz sorgu ifadelerinin
yazlabilmesi olanakl hale gelmitir.

rnein IEnumerable<T> arayzne(Interface) uygulanan geniletme


metodlar(Extension Methods) sayesinde T trnden koleksiyonlar zerinde Sum, Count,
Select, Average, OrderBy,Distinct gibi fonksiyonellikler uygulanabilmektedir. Bunun
iin System.Linq isim alan(Namespace) altnda Enumerable isimli static bir snf
gelitirilmi ve ierisine aadaki snf diagramda(Class Diagram) bir ksm grnen
pek ok geniletme metodu ilave edilmitir.

www.bsenyurt.com Page 404


Bilindii zere SQL sorgularna benzeyen LINQ ifadeleri aslnda arka planda metodlar yardmyla
iaret edilebilirler. Nitekim programatik ortamlar bu tarz bir yaklam gerektirmektedir. stelik bu
ilemler yaplrken var olan tiplerin ieriklerine mdahale edilmemekte, sadece ek fonksiyonellikler
katlmaktadr. Bu nedenle geniletme metodlar LINQ ifadelerinin kullanlabilmesinde nemli bir
role sahiptir. Bu makalemizde geniletme metodlarn derinlemesine incelemeye alacak ve
ayrntlara bakyor olacaz.

Geniletme metodlar var olan tiplere ek fonksiyonellikler kazandrlmasn salarken


bunlarn orjinal yapsn asla bozmazlar. Tanmlandklar programda, uygulandklar tipin
bir paras olarak yaar ama o tipin orjinalliine etki etmeden ek ilevselliklerin
kullanlabilmesini olanakl klarlar.

Hereyden nce nesne tabanl programlama dillerinde(Object Oriented Programming


Language), kaltm(Inheritance) sayesinde var olan tiplerin(Type) geniletilmesi mmkndr.
Ancak tretilmesine izin verilmeyen tiplerde mevcuttur. Sz gelimi sealed anahtar kelimesi ile
imzalanm olan tipler tretme teknii yardmyla geniletilemez. stelik .Net ierisinde bu ekilde
tanmlanm olan saysz snf vardr. rnein String snf sealed olarak imzalanm bir snf
olduundan kendisinden tretme yaplmasna izin verilmemektedir. (stelik String paral bir
snf(Partial Class)' da deildir.)

www.bsenyurt.com Page 405


Bu nedenle bu snfa ek fonksiyonellikler ilave edilmesi mmkn deildir. Oysaki var
olan .Net tiplerinin(yada kendi gelitirdiimiz ama tretme yaplmasna izin verilmeyen
tiplerin)yapsn bozmadan yeni fonksiyonelliklerin katlarak uygulamalar ierisinde ela alnmas
istendii vakalar sz konusudur. Ki nesnelerin SQL tarznda sorgulanabilmeside buna bir rnek
olarak verilebilir. Bu sebepten geniletme metodlarnn nemi olduka fazladr.

Geniletme metodlar(Extension
Methods), deer(value) ve referans(reference) trleri
ile arayzlere(Interface) uygulanabilir. Deer tr olarak yaplar(struct) gz nne
alnabilir. Nitekim yaplar aka belirtilmesede kendilerinden tretilme yaplmasna izin
vermemektedir.

Geniletme metodlar ele alnrken gzden karlmamas gereken bir nokta daha vardr. Geniletme
metodlar nesne ynelimli programlama jargonundaki kurallardan birisi deildir. Sadece .Net
Framework mimarisine zg bir kavramdr. Geniletme metodlar bu anlamda bir tipin paylaml
fonksiyonlar olarakda dnlebilir. Hatta bu metodlar .Net Framework 3.5 ncesi srmlerdeki
tipler iinde uygulanabilirdir. Tabi ncelikli olarak geniletme metodlarnn(Extension
Methods) C# 3.0 ierisinde nasl yazldna bakmata yarar vardr. Geniletme metodlarnn
yazlmasnda basit kural vardr. Bu metodlar static bir snf ierisinde static olarak
tanmlanmal ve uygulanacaklar tipi ilk parametrelerinde this anahtar kelimesi ile birlikte
almaldr.(Ki bunlarn bir takm sebepleri vardr) rnek olarak ayr bir snf ktphanesi ierisinde
gelitirilmi olan aadaki snf gz nne alabiliriz.

Merkez isimli static snfn ierii aadaki gibidir.

using System;
using System.Drawing;

www.bsenyurt.com Page 406


namespace Genisletmeler
{
/// <summary>
/// Geniletme fonksiyonelliklerini ieriri
/// </summary>
public static class Merkez
{
/// <summary>
/// Bir string ierisindeki tm karakterlerin Ascii deerlerini ele alp byte dizisi eklinde geriye
dndrr. Eer string null veya empty ise exception dndrr.
/// </summary>
/// <param name="s">Byte deerleri dndrlecek string parametre</param>
/// <returns>Ascii deerleri</returns>
public static byte[] GetAscii(this string s)
{
if (String.IsNullOrEmpty(s))
throw new Exception("String veri olmaldr.");
byte[] result = new byte[s.Length];
for (int i = 0; i < s.Length; i++)
{
result[i] = (byte)s[i];
}
return result;
}

/// <summary>
/// Int32 tipinden bir saynn faktryelinin bulunmasn salar
/// </summary>
/// <param name="sayi">Faktryel deeri hesap edilecek deiken</param>
/// <returns>Saynn faktryeli</returns>
public static double Faktoryel(this Int32 sayi)
{
if (sayi == 0
|| sayi == 1)
return 1;
else
return sayi*Faktoryel(sayi-1);
}

/// <summary>
/// ki Point arasndaki uzakln pisagor teoremine gre hesap edilmesini salar.
/// </summary>
/// <param name="nokta1">Birinci nokta</param>
/// <param name="nokta2">kinci nokta</param>
/// <returns>Mesafe</returns>
public static double Uzaklik(this Point nokta1,Point nokta2)
{
int xFarki = nokta1.X - nokta2.X;
int yFarki = nokta2.X - nokta2.Y;
return Math.Sqrt((xFarki * xFarki) + (yFarki * yFarki));
}
}
}

www.bsenyurt.com Page 407


Merkez isimli static snf ierisinde 3 farkl metod yer almaktadr. Bu metodlardan
GetAscii String snfna, Faktoryel Int32, Uzaklik ise Point yaplarna(Struct) uygulanmaktadr.
GetAscii metodu yardmyla string bir deikenin karakterlerinin byte tipinden bir dizi olarak elde
edilmesi salanmaktadr. Faktroyel metodu Int32 tipinden deikenlere uygulanabilmekte olup,
basit olarak saynn faktryelini hesaplamaktadr. (stelik yinelemeli-Recursive bir metod olarak
tasarlanmtr. Buna gre geniletme metodlarnnrecursive formasyonda kullanlabilecei
sylenebilir.) Uzaklik isimli metod ise dierlerinden farkl olarak birde ek parametre almaktadr.
Buna gre Point tipinden bir deikenin baka bir Point ile arasndaki uzakln bulunabilmesi
salanmaktadr. (Yani kabaca iki nokta arasndaki mesafenin pisagor teoremi erevesinde
hesaplanmas gerekletirilmeltedir.) Bir baka deyile geniletme metodlar(Extension
Methods) uygulanacaklar tipi belirten ilk parametreden sonra ek parametrelerde alabilmektedir.
Sz konusu snfn zellikleCIL(Common Intermediate Language) tarafna nasl aktarldn
incelemeden nce kullanmna baklabilir. Bu amala Merkez isimli static snf
ierenktphaneyi(Class Library) referans eden basit bir Console uygulamas gelitirilip
aadaki kodlar test amacyla kullanlabilir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Genisletmeler;
using System.Drawing;

namespace DerinlemesinExtensionMethods
{
class Program
{
static void Main(string[] args)
{
// String snf sealed olarak imzalanmtr bu nedenle kendisinden tretme yaplp ek
fonksiyonellikler katlamaz.
string ad = "Burak Selim";
byte[] asciiDegerleri=ad.GetAscii();
foreach(byte b in asciiDegerleri)
Console.Write(b.ToString()+" ");

// Int32 bir struct' tr. Struct' lar aka belirtilmesede sealed' dr. Yani kendilerinden
tretme yaplamaz. Ancak geniletme metodlar yardmyla bunlar ek fonksiyonellikler katlabilir.
int sayi = 3;
Console.WriteLine(sayi.Faktoryel());

// Point .Net Framework ierisinde System.Drawing isim alannda tanmlanm olan struct
tipidir. Kendisinden tretme yaplamaz. Ancak extension method sayesinde Uzaklik isimli bir
metoda sahip olabilir
Point pn = new Point(10, 20);
Console.WriteLine("ki Nokta Aras Uzaklk {0}",pn.Uzaklik(new Point(20,
30)).ToString());
}
}
}

Uygulama test edildiinde aadakine benzer sonular ile karlalr.

www.bsenyurt.com Page 408


Grld gibi string, int ve Point tipinden deikenler zerinden yeni fonksiyonellikler
kullanlabilmektedir. Peki bu sistem alt tarafta nasl yrmektedir? Sonu itibariyle var olan bir CLR
tipinin(Common Language Type) bozulmadan geniletilebilmesinin ancak alma zaman
motoru(Runtime Engine) tarafndan nemli olduu ortadadr. Hatta dikkat edilecei
zere Visual Studio gelitirme ortam, eklenen geniletme metodlarn intellisense zelliinde
aynen aadaki ekran grntsnde olduu gibi gsterebilmektedir.

alma zamannda baz bilgilere baklmas sz konusu ise eer, niteliklerden(Attribute)


yararlanlmaktadr. Bilindii zere nitelikler yardmyla alma zamanna ekstra metadata bilgileri
aktarlabilmektedir. Bu sebepten geniletme metodlarnda da barol oyuncusu
olarak System.Core.dll assembly' nda System.Runtime.CompilerServices isim
alan(Namespace) altnda bulunan Extension isimli bir nitelik(Attribute) grev almaktadr. Bu
her ne kadar kod tarafnda sadece Visual Basic 9.0 ile grlsede, IL tarafnda rahat bir ekilde
tespit edilebilmektedir.

Yukardaki IL grntsndende dikkat edilecei zere GetAscii isimli


metod ExtensionAttribute nitelii ile imzalanmtr. Bu son derece anlamldr nitekim
hem compiler hemdealma zaman(Runtime) iin, takip eden metodun, ilk parametre ile
belirtilen tip iin bir geniletme olduu belirtilmektedir. Bir baka deyile sz konusu nitelik
derleyiciye veya alma zamanna, ilk parametredeki tip iin baz ek bilgiler gnderir ve yeni
fonksiyonellii kazanmasn salar. Buraya kadar geniletme metodlarnn ne olduundan ve nasl

www.bsenyurt.com Page 409


uygulandndan bahsetmeye altk. Geniletme metodlar ile ilikili dikkat edilmesi gereken baz
noktalar da vardr. Dilerseniz yazmzn ilerleyen ksmlarnda bu konulara deinelim.

1 - Geniletme metodlar ar yklenebilirler(Overloading)

Metodlar ayn isim altnda birden fazla kez yazlabilirler(Buna u an iin verilebilecek en gzel
rneklerden birisi WriteLine metodudur. Dikkat edilecei zere bu metodun 19 farkl versiyonu
bulunmaktadr.) Bu ksaca metodun ar yklenmesi(Method Overloading) olarak
adlandrlmaktadr. Metodun ar yklenmesi srasndaki nemli kriter, parametre tipleri ve
saylarnn belirledii imzalardr(Method Signature). ok doal olarak geniletme metodlarda
ar yklenebilirler. Sz gelimi Merkez snf ierisinde iki nokta arasndaki uzakl bulmak iin
tasarlanm olan Uzaklik metodunun farkl bir versiyonu aadaki gibi yazlabilir.

/// <summary>
/// ki Point arasndaki uzakln pisagor teoremine gre hesap edilmesini salar
/// </summary>
/// <param name="nokta1">Metodun uygulanaca Point tipinden deiken</param>
/// <param name="x2">X2 Deeri</param>
/// <param name="y2">Y2 Deeri</param>
/// <returns>Mesafe</returns>
public static double Uzaklik(this Point nokta1, int x2, int y2)
{
int xFarki = nokta1.X - x2;
int yFarki = nokta1.Y - y2;
return Math.Sqrt((xFarki * xFarki) + (yFarki * yFarki));
}

Bu versiyon dierinden farkl olarak Point tipinden ikinci bir parametre almak yerine int tipinden
iki ayr parametre kullanmaktadr. Burada metodlarn hem parametre saylar hemde tipleri
farkllamay salamaktadr. Merkez snf bu haliyle rnek uygulamada kullanldnda aadaki
ekran grntsnden de izlenebilecei gibi iki farkl Uzaklik metodunun arlabilecei grlr.

Burada akla hemen u soru gelebilir. Merkez snfnn haricinde baka bir static snf
ierisinde, Point tipi iin Uzaklik metodunun ar yklenmi baka bir versiyonu yazlabilir mi? Eer
yazlrsa sz konusu uygulamada bu versiyon kullanlabilir mi? Bu sorulara cevap verebilmek iin
Console uygulamas ierisinde aadaki gibi bir static snf tanmlamas yapldn varsayalm.

static class Genisletme


{
public static double Uzaklik(this Point nokta1, double x2, double y2)
{
double xFarki = nokta1.X - x2;
double yFarki = nokta1.Y - y2;
return Math.Sqrt((xFarki * xFarki) + (yFarki * yFarki));
}

www.bsenyurt.com Page 410


}

Merkez snf Genisletmeler isim alan altnda ve stelik farkl assembly ierisinde yer
almaktadr. Genisletme isimli snf
ise DerinlemesineExtensionMethods isimli Consoleuygulamas ierisinde tanmlanmtr. Bu
durumda Main metodu ierisinde Point tipinden bir deiken kullanlmak istendiinde Uzaklik
isimli fonksiyonun 3 farkl versiyonuna ulalabildii grlecektir.

Bir baka deyile farkl static snflar ierisindede olsalar geniletme metodlar ar yklenebilirler.

2 - CLR Tipi(Common Language Runtime Type) ierisinde tanml olan bir fonksiyonun
ayns extension method olarak yazlp, rnek(Instance) tipe ait metod
ezilebilir(Override) mi?

Bu bir anlamda orjinal CLR tiplerinin gvenlii ile ilikilide bir konudur. Nitekim tretilmesine izin
verilmeyen tiplerin asl tasarm amalarndan biriside ieriklerinin deitirilmesinin engellenmesidir.
Bu anlamda sealed olarak iaretlenmi tiplerin aslnda geniletme metodlar yardmyla ek
fonksiyonelliklere sahip olabilmesi ve hatta ar ykleme yaplabilmesi orjinal tipte tanml
metodlarn ezilip ezilemeyecei vakasn ortaya karmaktadr. Bu durumu analiz etmek iin basit
olarak String tipinde tanml olan bir metodun aynsn extension method olacak ekilde
tanmlamaya alabiliriz.

public static string Insert(this string s,int siraNo, string metin)


{
Console.WriteLine("Extension Method");
return metin;
}

Burada String snfnn Insert metodunun ayns extension metod olarak yazlmaya
allmaktadr. Uygulama derlendiinde herhangibir hata mesaj alnmaz. Ancak string bir deiken
zerinden Insert metodu arldnda aadaki ekran grntsnde olduu gibi orjinal versiyonun
kullanlabilecei grlr.

Buna gre derleyici asndan nesne rnei(Object Instance) metodunun daha ncelikli olduu
ortadadr. Bir baka deyile geniletme metodlar yardmyla orjinal nesne rneine ait metodlar
ezilemezler.

3 - Bir tip ierisinde tanml zellik yada alan ile ayn isimde bir extension metod
tanmlanrsa.

Bu durumu analiz edebilmek iin aadaki kod paras gz nne alnabilir.

www.bsenyurt.com Page 411


sealed class Materyal
{
public int Katsayi;
}
static class Genisletme
{
public static void Katsayi(this Materyal mtr)
{
Console.WriteLine("Geniletme metodu");
}
}

Burada tanmlanan Materyal isim snf sealed olarak imzalanmtr ve


ierisinde int tipinden Katsayi isimli bir alan(Field) iermektedir. Bu tip bir snfn baka
bir nesne kullancs(Object User) tarafndan geniletilmek istendii bir durumda, bilinsiz
olarak ayn isme sahip geniletme metodlar eklenebilir. Bunu sembolize eden Genisletme snf
kendi ierisinde, Materyal snfndaki alanla ayn adda olan Katsayi isimli bir metod iermektedir. Ne
varki kod tarafnda Materyal snfna ait bir rnek oluturulduunda, Katsayi geniletme metoduna
eriilemedii ak bir ekilde grlmektedir.

Dikkat edilecek olursa sadece Katsayi isimli nesne alan(Field) grnmektedir. Fakat burada
olduka enteresan bir durumda sz konusudur. Eer kodda srar edilir ve Katsayi geniletme
metodu kullanlmak istenirse derleme zaman hatas alnmad grlr. Hatta kod yrtldnde,
geniletme metodunun alt grlecektir. Bu durum aslnda geniletme metodlarnn
isimlendirilmesinin nemli olduunu gstermektedir.

4 - Extension metodlar dilden bamszdr.

Geniletme metodlar daha ncedende bahsedildii gibi CIL(Common Intermediate


Language) tarafnda Extension nitelii ile imzalanrlar. Bu sebepten dolayda .Net destekli diller
tarafndan kullanlabilirler. Sz gelimi C# kodlamas ile gelitirilmi geniletme metodlar, Visual
Basic ile yazlmakta olan bir proje ierisinde kullanlabilir. Elbette tam tersi durumda geerlidir.
Konuyu daha kolay analiz etmek iin Merkez isimli snf ieren C# tabanl ktphaneyi basit
bir Visual Basic Console uygulamasnda aadaki gibi deneyebiliriz.

Imports Genisletmeler
Imports System.Drawing

Module Module1

Sub Main()

Dim str As String = "Burak Selim enyurt"


Dim dizi As Byte() = str.GetAscii()
For i As Int32 = 0 To dizi.Length - 1
Console.Write(dizi(i).ToString() + " ")

www.bsenyurt.com Page 412


Next

Console.WriteLine()

Dim sayi As Integer = 4


Console.WriteLine(sayi.Faktoryel().ToString())

Dim nokta1 As New Point(3, 4)


Console.WriteLine(nokta1.Uzaklik(6, 8).ToString())

End Sub

End Module

Visual Basic tarafnda kod yazyor olsakta, Visual Studio arabiriminin intellisense zellii C# ile
yazlm geniletme metodlarn gsterecektir. Sonu itibariyle burada yaplan farkl
bir assembly ierisinde tip ve yelerine erimektir.

Elbetteki kodun alabilmesi iin C# ktpanesinin Visual Basic tabanl projeye referans edilmesi
gerekmektedir.

Bu ilemin ardndan uygulama altrlrsa geniletme metodlarnn baarl bir ekilde alt
grlr.

www.bsenyurt.com Page 413


5 - Object tipinin geniletilmesi.

Object tipide geniletme metodlarna sahip olabilir. .Net Framework ierisinde yer alan tipler
object trevli olduklarndan ok doal olarak tanmlanan geniletme metodlarn kullanabilirler. Bu
durumu test edebilmek iin sembolik olarak aadaki geniletme metodunu eklediimizi
dnelim.

public static string GetTypeName(this object obj)


{
return obj.GetType().Name;
}

Metod basite herhangibir nesnenin tip adn dndrmektedir. Metodun uygulanna bakldnda
ise herhangibir tipteki deikenden sonra arlabildii grlecektir.

Aada, rnek bir kod paras kullanm ve alma zaman kts yer almaktadr.

int puan = 51;


Console.WriteLine(puan.GetTypeName());

Point nokta3 = new Point(3, 4);


Console.WriteLine(nokta3.GetTypeName());

string firmaAdi = "FreeLancer";


Console.WriteLine(firmaAdi.GetTypeName());

Visual Basic 9.0' da zellikle Object tipinden bir deikene atama yapldnda,
geniletme metodlarn armak alma zaman istisnasna(Run Time
Exception) neden olmaktadr.

www.bsenyurt.com Page 414


Dim obj As Object = 3.14F
Console.WriteLine(obj.GetTypeName())

Bu kullanm alma zamannda MissingMemberException istisnasnn(Exception)


frlatlmasna neden olmaktadr. Sorun Object tipinin Late-Bound olmasndan
kaynaklanmaktadr. Bunun zmek iin type inference kavramndan(C# karl var
anahtar kelimesi) yararlanlabilir. (Dim obj=3.14F)

Ne varki bu durum C# tarafnda geerli deildir. Bu nedenle C# tarafnda aadaki kod


paras sorunsuz olarak almaktadr.

Object obj = 3.14f;


Console.WriteLine(obj.GetTypeName());

Object tipi iin geniletme metodlar var anahtar kelimesi ile birliktede kullanlabilirler. Aadaki
kod paras bu durumu gstermektedir. Bu kod ierisinde var anahtar kelimesi ile tanmlanan
nesne isimli deiken eitliin sol taraf gz nne alndnda float(Single yaps-
struct) tipindendir. Bu sebepten nesne zerinden arlanGetTypeName isimli geniletme
metodu geriye Single deerini dndrecektir.

var nesne = 3.14f;


Console.WriteLine(nesne.GetTypeName());

6 - .Net Framework 2.0 hedefli bir uygulama ierisinde extension metodlar kullanlabilir
mi?

Extension nitelii System.Core.dll assembly' ierisinde tanmlanmtr


ve System.Runtime.CompilerServices isim alannda bulunmaktadr. System.Core.dll' i .Net
Framework 3.5 ile gelmekte olsada .Net Framework 2.0 motorunu kullanarak almaktadr. Bu
noktada .Net 2.0 ile gelitirilmi bir uygulamada extension metod kullanm sz konusu olabilir mi?
Akla ilk gelen yntem System.Core.dll assembly' nn ilgili projeye referans edilmesidir.
Ancak Visual Studio 2008 ierisinde bu denendiinde .Net 2.0 tabanl projeye sz konusu
referanslarn eklenemedii grlecektir.

Browse seenei ile ekleme yaplmaya allsada durum deimeyecektir. Ancak izlenecek basit bir
yol ile .Net 2.0 tabanl projede extension metod kullanm salanabilir. Bunun iin
uyulamada System.Runtime.CompilerServices isimli bir namespace tanmlanr ve

www.bsenyurt.com Page 415


ierisine Extension isimli bir attribute snf eklenir. Bu ilemin ardndan extension metod
yazlabildii hatta kullanlabildii grlecektir. Durumu daha iyi analiz etmek amacyla .Net
2.0 tabanl bir Console uygulamasna ait aadaki kod paras gz nne alnabilir.

using System;
using System.Runtime.CompilerServices;

// 1nci : lk olarak System.Runtime.CompilerServices adl isim alan ierisinde ExtensionAttribute


isimli bir nitelik tanmlanr
namespace System.Runtime.CompilerServices
{
// 2nci: Nitelik assembly, snf ve metod seviyesinde uygulanabilir. Bir kere kullanlabilir.
[AttributeUsage(AttributeTargets.Assembly| AttributeTargets.Class|
AttributeTargets.Method,AllowMultiple=false,Inherited=false)]
public class ExtensionAttribute :
Attribute
{
}
}
namespace DerinlemesineExtensionMethods2
{
static class ExtensionMethods
{
// Eer ExtensionAttribute tanmlanmazsa this keyword kullanm iin derleme zaman hatas
alnacaktr.
public static string GetTypeName(this object obj)
{
return obj.GetType().Name;
}
public static double Faktoryel(this Int32 sayi)
{
if (sayi == 0
|| sayi == 1)
return 1;
else
return sayi * Faktoryel(sayi - 1);
}
}
class Program
{
static void Main(string[] args)
{
int puan = 12;
Console.WriteLine(puan.GetTypeName()); // Extension metod kullanm

int sayi = 4;
Console.WriteLine(sayi.Faktoryel().ToString());
}
}
}

Uygulama altrldnda geniletme metodlarnn ie yarad grlebilir.

www.bsenyurt.com Page 416


Tabi bu vaka Visual Studio 2008 zerinde .Net 2.0 tabanl bir proje ablonu iin
gereklenmektedir. Nitekim derleme aamasnda sadece C# 3.0 derleyicisi geniletme
metodunu deerlendirebilmektedir. Bir baka deyile Visual Studio 2005 ortamnda
ayn rnek altrlamayacaktr.

7 - Arayzlere geniletme metodlar eklenebilir.

LINQ(LanguageINtegratedQuery) mimarisinin temelinde yatan geniletme metodlarnn


ou arayzlere(Interface) uygulanmaktadr. Bylece, geniletme metodlarnn uyguland
arayz tiplerinden treyen trlerin tamam, sz konusu ek fonksiyonellikleri kullanabilir duruma
gelmektedir. Bu gerektende nemli bir yetenektir. ok doal olarak gelitirici tarafndan yazlm
olan yada Framework ierisinde yer alan arayz tiplerine geniletme metodlar eklenebilir.
Aadaki rnek kod parasnda bu duruma rnek olacak bir metod ierii yer almaktadr.

public static IEnumerable<string> HaricindeKalanlar(this IEnumerable<string>


koleksiyon,string aranan)
{
foreach (string s in koleksiyon)
{
if (s != aranan)
yield return s;
}
}

HaricindeKalanlar isimli geniletme metodu, IEnumerable<string> tipinden


treyen generic koleksiyonlara uygulanabilmektedir. Grevi parametre olarak verilen string deer
dnda kalan elemanlar tespit ederek yeni bir IEnumerable<string> tipi ierisinde geriye
dndrmektedir.(lerin kolaylatrlmasnda .Net 2.0 ile birlikte gelen yield anahtar kelimesinin
nemli bir rol vardr.) Buna gre IEnumerable<string> arayznden treyen her
tip, HaricindeKalanlar isimli geniletme metodunu kullanabilmektedir. Sz gelimi aadaki kod
parasnda List<string>, Stack<string>, Queue<string> tiplerine uygulanmaktadr.

List<string> isimler = new List<string> { "Burak", "Ahmet", "Mehmet", "Mehmet", "Ahmet",


"zgr", "Emrah", "Blent" };
Stack<string> isimler2 = new Stack<string>(isimler);
Queue<string> isimler3 = new Queue<string>(isimler);

var sonuc1=isimler.HaricindeKalanlar("Ahmet");
var sonuc2 = isimler3.HaricindeKalanlar("Ahmet");
var sonuc3 = isimler.HaricindeKalanlar("Mehmet");

alma zamannda rnein sonuc3 deikeninin ierii aadaki ekran grntsndeki gibi
olacaktr. Dikkat edilecei zere Mehmet ismi dnda kalanlar elde edilmektedir.

www.bsenyurt.com Page 417


Buraya kadar bahsedilenler ksaca deerlendirilirse, geniletme metodlarnn aadaki avantajlar
saladndan bahsedilebilir.

Var olan tiplere(Types) yeni fonksiyonellikerin eklenebilmesi salanr. yleki yazlm olan
uygulamalarn alma sistemini bozmadan yeni fonksiyonellikler katarak genilemelerine
yardmc olur.
Tiplere yeni fonksiyonellikler eklenirken orjinal ieriklerine mdahale edilmesine gerek
kalmaz.
zellikle kaynak koda(Source Code) eriilemedii durumlarda ek ilevselliklerin
katlabilmesinde nemli rol oynar.
Tipleri treterek geniletmek mmkndr, ancak tretilmelerine izin verilmeyen(Sealed
Types) tipler sz konusu olduunda zm geniletme metodlardr.

Yinede geniletme metodlarnn nesne ynelimli programlama modeli nosyonunun bir paras
olmadn dnmekte yarar vardr. yleki nesne ynelimli programlama nosyonu gz nne
alndnda, tip geniletmesi aslnda tretme ile gereklenmektedir. Bylece geldik bir makalemizin
daha sonuna. Bu makalemizde ksaca geniletme metodlarn(Extension Methods) derinlemesine
incelemeye altk. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Visual Studio 2008 ile Gelen Yenilikler (


14.03.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Yazlm dnyas eitli rn gruplarn ve bunlarn retimini ieren materyaller iermektedir. Son
kullancya(End User) veya gelitiricilere(Developers) ynelik olarak tasarlanan rnlerin
yazlmasnda eitli program gelitirme arabirimleri kullanlmaktadr. Belkide bunlardan en popler

www.bsenyurt.com Page 418


olanlar Microsoft tarafndan retilen Visual Studioailesidir. Visual Studio.Net ile balayan
servende ksa bir sre ncede Visual Studio 2008 srm son haliyle yaynlanmtr. Yeni srm
zellikle .Net Framework 2.0, 3.0 ve 3.5 iin ortak ve tek bir gelitirme ortam sunmasyla
hemen dikkati ekmektedir. Bu ve benzer zelliklerin yannda Windows Communication
Foundation zmleri iinde ek bir takm yenilikleri gelmektedir.

Gze arpan yeniliklerden ilki WcfSvcHost.exe ve WcfTestClient.exe isimli yardmc


uygulamalardr. Visual Studio 2008 kurulumundan sonra C:\Program Files\Microsoft Visual
Studio 9.0\Common7\IDE klasr altna eklenen bu programlar sayesinde
herhangibir WCF servis ktphanesi(WCF Service Library) Host ve istemci uygulamalara
ihtiya duyulmadan test edilebilir. Genellikle bir servis ktphanesi gelitirilirken ve test edilirken
ekstra aba sarfederek basit bir Host uygulama ve istemci(Client) yazlmas gerekmektedir.
Ancak Visual Studio 2008ile gelen yardmc aralar sayesinde buna gerek kalmadan basit testler
yaplabilmektedir. stelik VS 2008 ile gelitirilen WCF servis ktphaneleri, IDE
ierisinden Start(F5 veya Ctrl+F5-Start Without Debugging) edildiklerinde otomatik
olarak WcfSvcHost.exe ve WcfTestClient.exe aralar devreye girmektedir. Bir baka deyile
yazlan WCF servis ktphaneleri annda altrlp test edilebilir. Sz konusu aralar komut
satrndanda altrmak ve kullanmak mmkndr. Yazda ilk olarak bu aralar tannmaya
allacaktr. Elbette test amacyla bir WCF servis ktphanesine ihtiya vardr. Bu amala VS
2008 ortamnda ierikleri aadaki gibi olan tipler gelitirilerek ie balanabilir.

Servis szlemesinin ierii;

[ServiceContract]
interface IAdventureSrv
{
[OperationContract]
Urun UrunBul(int id);

www.bsenyurt.com Page 419


[OperationContract]
double Topla(double[] sayilar);
}

Szlemeyi uygulayan snfn ierii;

class AdventureSrv
:IAdventureSrv
{
#region INorthwindSrv Members

public Urun UrunBul(int id)


{
Urun urn = null;
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select Name,ListPrice From Production.Product
Where ProductId=@PrdId", conn);
cmd.Parameters.AddWithValue("@PrdId", id);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
// C# 3.0 Object Initializers kullanlarak Urun nesnesi rneklenmektedir.
urn = new Urun()
{
Ad=reader["Name"].ToString()
,Fiyat=Convert.ToDouble(reader["ListPrice"])
};
reader.Close();
}
return urn;
}

public double Topla(double[] sayilar)


{
return sayilar.Sum<double>(s => s); //C# 3.0 Extension Methods kavram
kullanlmtr.
}

#endregion
}

Urun snfnn ierii;

[DataContract]
class Urun
{
[DataMember]
public string Ad;

[DataMember]
public double Fiyat;
}

www.bsenyurt.com Page 420


Servis szlemesi(Service Contract) basit olarak iki adet metod iermektedir. UrunBul isimli
metod ayn zamanda Urun isimli snfa ait nesne rnei dndrmektedir. Dier taraftan Urun
snf veri szlemesi(Data Contract) eklinde tanmlanmtr. Dier taraftan metodun
parmametrik yapsnn test aralarndaki kullanmn daha kolay irdelemek iin Topla isimli
fonksiyon, double tipinden bir dizi ile almaktadr. Kod ierisinde Urun snfna ait nesne
rneklenirken C# 3.0 Object Initializers teknii kullanlmaktadr. Topla metoduna
gelen double tipinden dizinin ierisindeki saylarn toplamn bulmak iinse Sum<T> metodu(C#
3.0 Extension Methods) ele alnmaktadr. Gelitirilen servis ktphanesinin
zellikle WcfSvcHost iin nemli olan ksm konfigurasyon bilgileridir. Nitekim WcfSvcHost.exe
uygulamas kod bazl Host ayarlama ilemlerini ele alamaz. Bir baka deyile test iin ktphanenin
mutlaka config dosyasnn yazlm olmas gerekir. stemci tarafnn, servis
zerinden Host edilecek tiplere ait servis metadata bilgilerini ekebilmek iin MEX(Metadata
Exchange) EndPoint tanmlanmas yaplmamasnda da yarar vardr. Bunlara gre rnek olarak
bir config ierii aadaki gibi tasarlanabilir.

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


<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="MexBehavior" name="AdventureSrv">
<endpoint address="net.tcp://localhost:45001/AdventureSrv"
binding="netTcpBinding" name="AdvTcpEndPoint" contract="IAdventureSrv" />
<endpoint address="http://localhost:45002/AdventureSrv"
binding="wsHttpBinding" name="AdvWsHttpEndPoint" contract="IAdventureSrv" />
<host>
<baseAddresses>
<add baseAddress="http://localhost:45000/" />
</baseAddresses>
</host>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MexBehavior" >
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

Konfigurasyon dosyasndanda grld gibi servis


ktphanesi Tcp(NetTcpBinding) ve WsHttp(WsHttpBinding) bazl iki
farkl EndPoint sunmaktadr. Bununla birliktehttp://localhost:45000 adresi
zerinden Metadata yaynlamasda yaplmaktadr. Metadata bilgisinin ekilebiliyor olmas,
istemciler iin gerekli olan Proxy snfnn retilmesinde nemli bir yere sahiptir.

WcfSvcHost aracnn kullanm amac bir servis ktphanesinde tanmlanan


hizmetlerin Host edilmesini salayacak otomatik bir Windows uygulamasn balatmaktr. Bu
uygulama altrldnda, parametre olarak verilen servis ktphanesi ve konfigurasyon dosyasn
kullanarak Host ilemini gerekletirir. Ayn zamanda konfigurasyon dosyasnda
tanmlanan EndPoint noktalarnda tanmlanan servis szlemelerine(Service Contract) ait
metadata bilgilerinin yaynlanmasnda salayabilir. Basit olarak yukardaki rnek ktphaneyi Host
etmek zere WcfSvcHost arac komut satrndan aadaki gibi kullanlabilir.

www.bsenyurt.com Page 421


WcfSvcHost /service:GenelIslemler.dll /config:GenelIslemler.dll.config

Service ile tanmlanan parametreden sonra servis ktphanesi ismi


verilmektedir. Config parametresinde ise konfigurasyon dosyas iaret edilir. Bu ilemin ardndan
WcfSvcHost uygulamasnn Tray Icon' a atld grlr.

Bir baka deyile WcfSvcHost uygulamas arka planda Exit seenei ile klana kadar almaya
ve servisleri yaynlamaya devam edecektir.(Close seenei yada X iareti
kullanldnda WcfSvcHost uygulamas Tray Icon olarak almaya devam
etmektedir.) WcfSvcHost uygulamasnn alma zamanndaki grnts ise aadaki gibidir.

Dikkat edilecei zere yaynlanan servisin ad, durumu ve Metadata ieriinin alnabilecei URL
adresi bilgileride gsterilmektedir. Servis uygulamas baarl bir ekilde altrldktan sonra
istenirse WcfTestClient arac yardmyla istemcilerin denenmesine
balanabilir. WcfTestClient arac ald parametrelere gre bir Windows uygulamas balatr ve
servisten ald metadata bilgilerine gre kullanlabilecek hizmetleri ve metodlar gsterir. En basit
kullanmnda servis ktphanesinde belirtilen base address bilgisi aadaki gibi parametre olarak
belirtilir.

WcfTestClient http://localhost:45000/

www.bsenyurt.com Page 422


Bu ilemin arkasndan WcfTestClient arac bir Windows uygulamas altracak ve parametre
olarak verilen adresin metadata bilgisinide kullanarak, arlabilecek hizmet noktalarn
listeleyecektir. Arabirimde servis ile ilikili metodlara ift tklanarak altrlmalar ve sonularnn
grlmesi de salanabilir. Sz gelimi UrunBul isimli metod 1deeri ile altrldnda aadaki
sonular elde edilir.

Invoke dmesine baslmas ile birlikte UrunBul metoduna bir ar gerekletirilir. Bu arnn
sonucunda elde edilen Urun nesne rnei ve veri ierii Responsesekmesinde grlmektedir.
Burada talep(Request) ve cevap(Response) paketlerinin ieriklerinin XML tarafndaki
hallerinede baklabilir. Bunun iin XML sekmesine geilmesi yeterlidir. Bu durumda aadaki kt
elde edilir. (Bu XML ieriklerinin daha nceden belirtilen paketlerin istemci tarafndan manuel olarak
hazrlanarak gnderilmesinde olduka ie yarayaca da gz nne alnmaldr.)

www.bsenyurt.com Page 423


Servis tarafnda yer alan metodlardan Topla fonksiyonu parametre olarak double tipinden bir dizi
almaktadr. Bu tip bir metodun WcfTestClient arac ile altrlmas esnasnda ncelikli olarak ka
adet deer gnderilecei(bir baka deyile dizinin boyutu) belirlenir. Daha sonra ise deiken
deerleri girilir ve fonksiyon arlr. Bu durum aadaki ekilde grld gibi rneklenebilir.

www.bsenyurt.com Page 424


WcfTestClient aracnn kullanm srasnda eer Host uygulama (WcfSvcHost) almyor yada
herhangibir nedenle servislere ait metadata bilgileri ekilemiyorsa alma zaman
istisnas(Runtime Exception) alnr. rnekte WcfSvcHost uygulamas kapalyken WcfTestClient
altrlmak istenmi ve sonu olarak aadakine benzer bir hata ekran alnmtr.

www.bsenyurt.com Page 425


WcfSvcHost uygulamasnn parametrik yaps kullanlarak istenirse ayn
anda WcfTestClient uygulamasnnda altrlmas salanabilir ki Visual Studio 2008 ortamnn
servis ktphanesinin altrlmas sonras gerekletirilen ilemde budur. Bunun
iin WcfSvcHost aracn aadaki gibi kullanmak yeterlidir.

WcfSvcHost /service:GenelIslemler.dll /config:GenelIslemler.dll.config


/client:WcfTestClient /clientargs:http://localhost:45000/

Client parametresinden sonra istemci uygulama olarak WcfTestClient iaret edilmektedir.


Bununla birlikte WcfTestClient alrken gerekli
olan base address bilgiside clientargsparametresinden sonra belirtilmektedir. Bu ilemin
ardndan nce WcfSvcHost uygulamas, sonrasnda ise WcfTestClient uygulamas alacak ve
hizmetler balatlarak istemci tarafndan kullanlabilir hale getirilecektir. WcfTestClient aracnn
yararl zelliklerinden biriside istemci iin retilen konfigurasyon dosyasn gsteriyor olmasdr.
Dolaysyla bu config dosyas istenirse gerek istemci uygulamalar iinde kullanlabilir. rnekte bu
ierik config isimli sekme altnda yer almaktadr.

www.bsenyurt.com Page 426


rnekte yer alan servis ktphanesinde(WCF Service
Library), hem TCP hemde WS bazl EndPoint noktalar tanmlanm olduundan istemci iin
retilen config dosyas ierisinde iki farkl binding elementinin yer ald ak bir ekilde
grlmektedir.

WCF istemcileri gelitirilirken nemli olan noktalardan biriside Proxy retimidir. Bilindii gibi Proxy
nesneleri yardmyla istemci tarafndan servis operasyonlarna eriebilmek nesne-metod(Object-
Method) ilikisi erevesinde olabilmektedir. Proxy retimi iin Visual Studio 2008 tarafnda
servis referanslarn eklemek gerekmektedir. Bu amala Add Service Reference seenei
kullanlmaktadr. (Bu seenek zaten WCF servis eklentilerinin Visual Studio 2005 yklemesinden
sonrada kmaktadr.)

www.bsenyurt.com Page 427


rnekte yer alan servis ktphanesine ait servis referansn eklemek iin ncelikli
olarak WcfSvcHost uygulamasnn altrlmas gerekmektedir. Bu ilemin ardndanbase
address zerinden WSDL ierii talep edilebilir. Sonu olarak basit
bir Console uygulamasna Add Service Reference seenei yardmyla, GenelIslemler.dll WCF
Service Libraryprojesi ierisinde tanmlanm olan servis aadaki ekran grntsnde olduu
gibi eklenebilir.

Grld gibi WCFSvcHost arac ile altrlan servise ait operasyonlar elde edilebilmektedir.
Burada nemli olan fark Advanced sekmesine geildiinde servis ile ilikili detayl ayarlamalarn
yaplabilecei bir ekranla karlalmasdr.

www.bsenyurt.com Page 428


Access level for generated classes seenei kullanldnda, proxy ierisinde retilecek olan
tiplerin hangi eriim belirleyicisi(Access Modifier) ile oluturulaca belirtilmektedir. Tip
baznda Public ve Internal olmak zere iki farkl seenek yer almaktadr. Baz durumlarda baka
bir servis ktphanesinin(Sz gelimi baka bir WCF Servis ktphanesi) elde
ettii proxy tiplerinin sadece o assembly ierisinde geerli olmas istenebilir. Byle bir
vakada Internal seeneini iaretlemek gerekmektedir. kinci olarakGenerate Asynchronous
Operations seenei iaretlendiinde servis operasyonlarn asenkron olarak arabilmek iin
gerekli fonksiyonel alt yapnn yklenmesi salanmaktadr.

Baz durumlarda servis operasyonlarnn uzun zaman almas sz konusudur. Bu gibi


vakalarda istemcilerin operayon sonularn beklemeden almasna devam edebilmesi
iin bilinen asenkron arma tekniklerinden(Polling, WaitHandle, Callbak, Even-
Based) yararlanlmaktadr.

Yaznn bu blmnde, Console tipindeki istemci uygulamaya eklenecek olan servis referans
iin Internal eriim belirleyicisi ve asenkron eriim seenei uygulanmaktadr. Buna gre istemci
tarafna eklenen tiplerin snf diagramndaki(Class Diagram) grnts ve ierikleri aada
olduu gibidir.

www.bsenyurt.com Page 429


Hatrlanaca gibi Xml Web Servisleri, Visual Studio 2005 srm ile birlikte olay tabanl
asenkron arma(Event-Based Asynchronous Invoking) modelini uygulamaya balamtr.
Bu basit asenkron modelde, zaman alan servis operasyonlar ilemlerini tamamladnda otomatik
olarak tetiklenen bir olay(Event) sayesinde sonular uygulama ortamna alnabilmektedir. Bylece
istemci tarafnda BeginInvoke, EndInvoke gibi metodlarn
kullanld Polling, Callback,WaitHandle gibi tekniklerde grece daha basit bir uygulama ekli
ortaya kmaktayd. Modelin uygulanmas srasnda istemci tarafnda
baz olay(Event) ve temsilci(Delegate) tanmlamalar oluturulmaktadr. Ayn durum Visual
Studio 2008 sayesinde WCF servislerinede kolay bir ekilde uygulanabilir.

AdventureSrvClient isimli proxy snfna bakldnda Topla ve UrunBul isimli metodlar


iin Async son eki ile biten versiyonlar yer almaktadr. Tahmin edilecei zere bu metodlar
yardmyla ilgili servis operasyonlarna asenkron arlar gerekletirilebilir. Dier taraftan ilemler
tamamlandktan sonra devreye girecek olan olaylar
ise ToplaCompleted veUrunBulCompleted olarak eklenmitir(Completed kelimesi ile
bittiklerine dikkat edilmelidir). Sz konusu olaylar devreye girdiinde, operasyon sonularn
alabilmek iinseCompletedEventArgs kelimesi ile biten argman snflarnn oluturulduu
grlebilir. stemci tarafna yazlacak aadaki kod paras yardmyla servis metodunun olay
tabanl(Event Based) olacak ekilde asenkron olarak altrlmas salanabilir.

using System;
using System.Threading;

www.bsenyurt.com Page 430


namespace Istemci
{
class Program
{
static void Main(string[] args)
{
// Proxy nesnesi AdvTcpEndPoint isimli EndPoint noktasn baz alacak ekilde oluturulur.
AdvService.AdventureSrvClient proxy = new
Istemci.AdvService.AdventureSrvClient("AdvTcpEndPoint");
// UrunBul metodu tamamlandktan sonra devreye girecek olan UrunBulCompleted olay
yklenir
proxy.UrunBulCompleted += new
EventHandler<Istemci.AdvService.UrunBulCompletedEventArgs>(proxy_UrunBulComple
ted);
proxy.UrunBulAsync(1); // UrunBul metoduna yaplan asenkron ar

// Console tarafnda sembolik olarak yazlm kodlar


// bu dng devam ederken servis tarafndaki metodun sonularnn alnmasyla birlikte
proxy_UrunBulCompleted isimli olay metodu tetiklenmektedir.
for (int i = 0; i < 10; i++)
{
Console.WriteLine("...");
Thread.Sleep(1000); // Olay daha iyi izlemek iin ana thread 1 saniye duraksatlr
}
}

// Asenkron olarak arlan servis metodu bittiinde devreye girecek olan olay metodu
static void proxy_UrunBulCompleted(object
sender, Istemci.AdvService.UrunBulCompletedEventArgs e)
{
// UrunBul metodu geriye Urun tipinden nesne rnei dndrmektedir. Bu sebepten
UrunBulCompletedEventArgs snfnn Result zellii Urun tipinden bir deer dndrr. Bu sayede
Ad ve Fiyat alanlarna eriilebilmektedir.
Console.WriteLine(e.Result.Ad+" "+e.Result.Fiyat.ToString("C2"));
}
}
}

Elbette istenirse Callback, WaitHandle ve Polling modellerine gre asenkron eriimlerde


gerekletirilebilir. Nitekim Begin ve End kelimeleri ile balayan metodlarn eklenmelerinin
nedenide budur. Begin ve End metodlarnn oluturduu skntlardan biriside
zellikle Windows veya WPF uygulamalarnda ortaya kartaca thread senkronizasyon
problemleridir. Mehur Illegal Cross Thread Exception oluumuna neden olabilecek bu durumda
tedbir olarak metod invoker' lardan yararlanlmaktadr. Bununla birlikte proxy' nin
tredigi ClientBase<T> abstract snf kendi ierisinde potected eriim belirleyicisi ile
iaretlenmi InvokeAsync isimli bir metod iermektedir. Bu metod senkronize problemlerini
ortadan kaldrmak zereproxy snf ierisindeki olay tabanl asenkron fonksiyonlar tarafndan
kullanlmaktadr.

www.bsenyurt.com Page 431


Dikkat edilecek olursa UrunBulAsync metodu son
olarak ClientBase<T> ierisindeki InvokeAsync metodunu altrmaktadr. Bu metodun
parametrik yaps aadaki gibidir ve istemci tarafnda threadlerin senkronize almasn
salayacak ekilde tasarlanmtr.

protected void InvokeAsync(


ClientBase<TChannel>.BeginOperationDelegate beginOperationDelegate
, object[] inValues
, ClientBase<TChannel>.EndOperationDelegate endOperationDelegate
, SendOrPostCallback operationCompletedCallback
, object userState
);

zellikle SendOrPostCallback isimli temsilci(delegate) senkronizasyon ile ilikili geri bildirim


metodunu iaret etmekle grevlidir.

Advanced sekmesinde dikkati eken noktalardan bir dieride servis operasyonlarnda koleksiyon
bazl dnen trlerin istemci tarafnda ele aln ekillerinin deitirilebilmesidir. Nitekim u anda
servis referans eklenmitir. Var olan referansa ait zellikle nasl deitirilebilir? Yine Visual Studio
2008 ile gelen yeniliklerden biriside Configure Service Referenceseeneidir.

Bu seenek sayesinde, daha nceden eklenmi olan bir servis referansna ait zellikler
deitirilebilmektedir. Koleksiyon dndren opersayonlarn istemci tarafndaki durumunu daha net
kavrayabilmek iin servis tarafna eklenmi aadaki operasyon ve metodlar gz nne alnabilir.

www.bsenyurt.com Page 432


[ServiceContract]
interface IAdventureSrv
{
// Dier tanmlamalar
[OperationContract]
List<double> RastgeleSayilar(int baslangic, int bitis);

[OperationContract]
Hashtable Isimler();
}

class AdventureSrv
:IAdventureSrv
{
// Dier metod uyarlamalar

public List<double> RastgeleSayilar(int baslangic,int bitis)


{
List<double> liste = new List<double>();
Random rnd=new Random();
for (int i = baslangic; i < bitis; i++)
liste.Add(rnd.NextDouble());
return liste;
}

public Hashtable Isimler()


{
Hashtable dict = new Hashtable();
dict.Add(1001, "Burak");
dict.Add(1002, "Mayk");
dict.Add(1005, "Conn");
return dict;
}
}

Servis tarafnda List<double> ve Hashtable tiplerinden deer dndren iki operasyon yer
almaktadr. Normal artlarda WCF servisine ait proxy snf retilirken List<T> gibi koleksiyonlar
iin T tipinden bir dizi(Array) baz alnmaktadr. Hashtable, SortedList gibi koleksiyonlar
iinse Dictionary<object,object> tipi ele alnmaktadr. Bu nedenle istemci uygulamadaki servis
ierii Update Service Reference seenei ile gncelletirilirse Isimler ve RastgeleSayilar adl
fonksiyonlarn aktarm aadaki gibi olacaktr.

public System.Collections.Generic.Dictionary<object, object> Isimler() {


return base.Channel.Isimler();
}

public double[] RastgeleSayilar(int baslangic, int bitis) {


return base.Channel.RastgeleSayilar(baslangic, bitis);
}

Ancak istenirse bu aktarm tipleri deitirilebilir. Bunun iin Advanced sekmesinde yer
alan Collection Type ve Dictionary Collection Type deerlerini deitirmek yeterli olacaktr.
Aadaki ekran grntsnde bu durum gsterilmektedir.

www.bsenyurt.com Page 433


Bu ilemin ardndan ilgili operasyonlarn Proxy snf ierisindeki yaplarnn aadaki gibi
deitirildii grlebilir.

public System.Collections.Generic.List<double> RastgeleSayilar(int baslangic, int bitis) {


return base.Channel.RastgeleSayilar(baslangic, bitis);
}

public System.Collections.Hashtable Isimler() {


return base.Channel.Isimler();
}

Dikkat edilecei zere, servis tarafnda sunulan operasyonlardaki dn tiplerinin aynen istemci
tarafndaki proxy snfnada aktarlmas salanmaktadr. Tabi bu noktada istemci tarafndaki proxy
snfnn .Net baml hale geldiinede dikkat etmek gerekmektedir.

Visual Studio 2008 gelitirme ortam .Net Framework 3.5 ablonu altnda birden fazla WCF
ktphanesi sunmaktadr.

WCF servisleri, Workflow Foundation ierisindede zaman zaman


kullanlmaktadr. Workflow Foundation mimarisinde iki farkl i ak tipi
vardr. Sequential ve State Machine. Bir WCF servisi bu tipteki i aklar ierisinden kullanlabilir
yada i ak bir WCF servisinin paras haline gelebilir. Bu noktada Sequential Workflow Service
Library ve State Machine Workflow Service Library ablonlar kullanlabilir. Bilindii gibi .Net
Framework 3.5 ile WCF tarafnda RSS, Atom formatl yaynlamalara destek verilmektedir. Bu tip
bir proje ablonu iin Syndication Service Library kullanlabilir.

Buraya kadar anlatlanlara gre Visual Studio 2008 ile birlikte gelen WCF yenilikler aadaki tablo
ile zetlenebilirler.

zellik Aklama

WcfSvcHost Herhangibir Host uygulamas yazlmasna gerek kalmadan WCFservis


ktphaneleri test amal olarak yaynlanabilmektedir.Visual Studio
2008 varsaylan olarak WCF Servisktphaneleri iin bu arac kullanmaktadr.

WcfTestClient Yaynlanan servislerin test edilmesi iin kullanlan Windows uygulamasdr. Servise
ait operasyonlarn annda grlmesi,
kullanlmas, talep(Request) vecevap(Response) paketlerinin data veya XML f
ormatnda okunabilmesi, farkl EndPoint noktalarnn test edilebilmesi gibi

www.bsenyurt.com Page 434


imkanlar sunmaktadr. Visual Studio 2008 varsaylan olarak WCF Servis
ktphanelerinin altrlmasnda WcfSvcHostuygulamasndan sonra bu program
altrrak annda testin yaplabilmesini salamaktadr.

Add Service Advanced sekmesindeki ayarlar yardmyla oluturulacak proxysnf ve ilikili


Reference - tiplerine ait pek ok detay ayarlanabilir.
Advanced
Sekmesi

Public/Intern stemciye eklenen servis referans ierisindeki tiplerin eriim belirleyicileri(Access


al Modifiers) vakaya gre public yada internalolarak set edilebilir.

Koleksiyon List<T> gibi koleksiyonlar(IEnumerable<T>, IList<T> vb...) istemci


Eletirme tarafnda T[] dizileri eklinde ele alnrlarken, Hashtable gibi
koleksiyonlar Dictionary<object,object> olarak yorumlanr. Bu eletirme
Advanced sekmesindeki Collection Type ve Dictionary Collection
Type seenekleri yardmyla deitirilebilir.

Asenkron Web servislerindeki hazr retime benzer ekilde olay tabanl asenkron (event
Proxy based asynchronous) yrtme desenlerinin eklenmesi salanabilir. stelik bu
Metodlarn uyarlamada threadsenkronizasyonunu etkili hale getirmeyi kolaylatrc
retimi fonksiyonellikler vardr.

Configure stemci tarafna eklenmi olan bir servisin koleksiyon eletirme, eriim
Service belirleyicisi gibi pek ok zellii sonradanConfigure Service Reference seenei
Reference yardmyla deitirilebilir.

Yeni Library zellikle WWF(Windows Workflow Foundation) tarafna ve .Net Framework


ablonlar 3.5 ile WCF' e getirilen Web programlama modelinin bir rn
olan Syndication yaynlama iin ek proje ablonlar gelmektedir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde yakn zamanda son haliyle
yaynlanan Visual Studio 2008 rnnn Windows Communication Foundation iin getirdii
yenilikleri basit seviyede ele almaya altk. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Kod Tarafndan Ynetmek ( 07.03.2008 ) - WCF


Deerli Okurlarm Merhabalar,

Windows Communication Foundation ile gelitirilen Servis Ynelimli Uygulama(SOA-


Service Oriented Architecture) zmlerinde konfigurasyon bazl(Configuration
Based)gelitirme sreci olduka yaygndr. Konfigurasyon dosyalar ierisinde yer alan bilgiler
yardmyla WCF alma zaman(WCF Runtime) ortam otomatik olarak baz ilemler gerekletirir.
Sz gelimi istemci(Client) ve servis(Service) arasnda tanacak olan mesajlarn
zmlenmesi(Encoding), bunlarn seilen balayc tipin(Binding Type)belirledii protokole
gre aktarlmas gibi alt yap(Infrastructure) hazrlklar otomatik olarak gerekletirilir. Hatta
istemcinin servis zerinden talep ettii bir operasyon(Service Operation), servis tarafndaki
konfigurasyon bilgilerinden yola klarak hazrlanan alma zaman sayesinde, anlaml bir metod
ars haline dnr.

www.bsenyurt.com Page 435


Ne varki baz vakalarda, WCF altyap hazrlklarnn konfigursayon bazl olmas tercih edilmez.
Bunun en byk nedenlerinden bir taneside, konfigurasyon bilgilerinin XML(eXtensible Markup
Lanuage) bazl ak text dosyalarnda duruyor olmasdr. Buda ilgili dosyann dardan
deitirilebilecei anlamna gelmektedir. Her ne kadar servis tarafnn Hostedilecei
uygulama administrator(veya bu gruba dahil kullanclarn) yetkisindede olsa, sz
gelimi HTML Metadata Publishing zelliinin konfigurasyon ierisinde, program koduna girmeye
gerek kalmadan, yanllklada olsa deitirilmesi istenmeyebilir. nk bunun etkisi sonrasnda
istemcilerin servise ait metadata bilgisini ekememesi gibi durumlar ortaya kmaktadr. Bu gibi
baz sebeplerden dolay, WCF alt yap hazrlklarnn zellikle servis tarafnda iken, kod
baznda(Code Based) gerekletirilmesi tercih edilebilir. Bu yazda arlkl olarak kod tarafnda
gerekli hazrlklarn nasl yaplabilecei gibi konulara deinilmektedir.

WCF mimarisi ierisinde ok sayda CLR tipi(Common Language Runtime-Type) yer


almaktadr. Bu tiplerin bazlar geniletilebilir ve alma zamannda(Runtime) kullanlabilir.
Hatta var olan tiplerden yararlanarak zel durumlar iin birleik tipler tasarlanabilir. Sz gelimi var
olan balayc tiplerden(Binding Types) bir kann bir arada kullanlaca zelletirilmi bir
balayc tip tasarlamak mmkndr. Burada CustomBinding isimli CLR tipi nemli rol
oynamaktadr.

Bu blmde ok gze batan WCF tipleri ele alnmaya allmaktadr. Ancak hereyden
nce WCF alma zamann kavramakta yarar vardr. Bu nedenle Hostuygulamann(servis tipinin
yaynlayan programn) almaya balad andan itibaren ilerlemek daha dorudur. Host uygulama
altnda, servis iin tanmlananEndPoint bilgilerinden yararlanlarak
birer ChannelListener nesnesi ve bir kanal yn(Channel Stack) oluturulur.

Bilindii gibi EndPoint ierisinde servisin Address, Binding ve Contract bilgileri yer
almaktadr. Bu bilgiler alma zaman ortamnn hazrlanmasnda nemli deer sahiptir.
Bu sebepten dolay kanal yn(Channel Stack) hazrlanrken EndPoint ierisindeki
bilgilerden yararlanlr.

ChannelListener nesneleri aslnda EndPoint noktalarn ilgili kanallara balamakla grevlidir.


yleki, URI(Uniform Resource Identifier) zerinden bir mesaj
geldiinde, ChannelListenernesne rnei ilgili mesaj kanal ynnn(Channel Stack) en altnda
yer alan iletiim kanalna(Transport Channel) aktarr. Gelen mesaj ieriinin iletiim kanal
asndan bir nemi yoktur. Nihayetinde bu bilgi byte tipinden bir akmdr(Stream). Bununla
birlikte iletiim kanal gelen mesaj aldktan sonra, zmleme kanalna(Encoding
Channel) iletir. zmleme kanalnn, gelen mesajlar ierisindeki operasyonel talepleri alp nesne-
metod ilikisine dntrmek gibi nemli bir grevi vardr. zmleme kanal SOAP(Simple
Object Access Protocol), plain text, binary data veya MTOM(Message Transmision
Optimization Mechanism) gibi formatlar kullanmaktadr. (Hatta .Net Framework 3.5 ile gelen
yenilikler ile birlikte JSON-JavaScript Object Notation formatnn kullanlabilmeside olanakl hale
gelmitir.)

letiim(Transport) ve zmleme(Encoding) kanallar balayclarn(Bindings) olmassa


olmaz paralardr. Bir baka deyile kanal yn(Channel Stack)ierisinde mutlaka ve mutlaka
var olmalar gerekmektedir. Ancak duruma gre bu kanallarn arkasna gvenilir
oturumlarn(Reliable Sessions) salanmas ve Replay saldrlarnn engellenmesi, gnveliin
salanmas, transaction ynetiminin gerekletirilmesi gibi ilemler iin ek kanallarda ilave
edilebilir. Bu durumda zaten birden fazla kanaln bir arada ele alnd zel bir kanal ynn
oluumu sz konusudur.

kili zmleme Kanal(Binary Encoding Channel) WCF' e zeldir. Bu


nedenle interoperability destei olmayan senaryolarda daha ok ele
alnr. MTOM(Messsage Transmision Optimization Mechanism) zmleme kanal,

www.bsenyurt.com Page 436


byk boyutlu verilerin binary formatta ve interoperability' nin nemli olduu
vakalarda ele alnr.

Bu adan bakldnda, tm iletiim kanallar varsaylan olarak baz zmleyicileri


kullanrlar. Sz gelimi HTTP/HTTPS tabanl kanallar varsaylan olarak textformatl
zmleme kanallarn ele alrken, TCP binary formatl zmleme kanallarn kullanr.
Elbette bu noktada gelitiriciler kanal ve zmleme kanallarn istedikleri gibi
zelletirebilir ve farkl kombinasyonlar ister konfigurasyon bazl, ister kod bazl olacak
ekilde gelitirebilirler.

u ana kadar anlatlanlar gz nne alndnda kanal ynn ierisinde yer alan tiplerden geilerek
tepeye ulald grlr. Kanal ynnn en tepe noktasna ulalmasnn ardndan ilgili mesaj
bir ChannelDispatcher nesnesi tarafndan karlanr. ChannelDispatcher nesnesi ilgili mesaj alr
ve bir EndPointDispatchernesnesine aktarr.(ChannelDispatcher arkasnda mesajn iletilebilecei
birden fazla EndPointDispatcher nesnesi olabilir) EndPointDispatcher nesnesinin grevi, gelen
mesajn ieriine gre uygun olan servis metodunun altrlmasdr. Bununla
birlikte EndPointDispatcher nesnesi gelen mesaj ierisinden servis tarafndaki metod iin gerekli
parametreleride
almaktadr. ChannelDispatcher ve EndPointDispatcher nesneleri, ServiceHost nesnesi
rneklendiinde otomatik olarak retilirler.

stemcinin servis tarafndan talep ettii operasyon ars kanal ynndan geerek metod ars
haline geldikten sonra , metod zerinden alnan sonular ayn yolla geriye dnecektir. stemci,
servisten gelen mesaj ele alrken, WCF alma zamannn rettii ChannelFactory nesnesinden
yararlanr. Bununla birlikte istemci tarafnda nem arz eden nesnelerden
biriside Proxy bileenidir. Proxy nesnesi ilgili metod arlarnn request mesajlarna
evrilmesinden ve gelen cevaplarnda(Responses) istemci programn anlayaca kodlara
dntrlmesinden sorumludur.

WCF alma ortam ile ilikili nemli noktalardan biriside davran(Behavior) tanmlamalardr.
Davran tipleri sayesinde WCF altyaps ierisindeki paralarn nasl yryecei belirlenebilir. .Net
Framework 3.0 ve 3.5 ierisinde tanmlanm olan saysz davran tipi(Behavior Type) vardr.
Bu tipler sayesinde rnein, transactionierisindeki operasyonlarn toplu olarak nasl
gerekletirilecei, verinin nasl ve ne ekilde seriletirilecei, mesajlarn gnderilmesi yada
alnmas srasnda kullanlacak olanehliyetlerin(credentials) larn tayini, servis
zerinde debug yaplp yaplamayaca, HTTP zerinden metadata publishing aktarmna izin
verilip verilmeyecei, exception detaylarnn istemci tarafnada frlatlp frlatlmayaca ve daha pek
ok alma zaman davran belirlenebilir. Davranlar, WCF alt yaps ierisinde yer alan tiplere
veya yelere(Members) uygulanabilirler. Sz gelimi kimi davranlar sadece metodlara, kimileri bir
servisin tamamna, kimileride szlemelere(Contracts) uygulanabilirler. Tabi istenirse
zelletirilmi davran tipleri(Behavior Type) tasarlanabilir. Davranlar kod
baznda imperative yada konfigurasyon dosyalar ierisinden declerative tarzda kullanlabilir.

Davranlar(Behaviors) gelitiriciler tarafndan yazlan bir servisin, daha sonra


yneticiler tarafndan farkl ekillerde davranabilmesini salamak amacyla gelitirilmi
yaplardr. Hazr olan davran tipleri sayesinde, alt yapya(Infrastructure) mdahale
etmeye, ek kod yazmaya veya hazrlk yapmaya gerek kalmadan istenen deiimler
gerekletirilebilmektedir.

Buraya kadar anlatlanlar gz nne alndnda WCF(Windows Communication


Foundation) mimarisinin, servis ve istemci taraflarnda ieren alt yaps kabaca aadaki ekilde
grld gibi ele alnabilir.

www.bsenyurt.com Page 437


ekildende grlecei zere kanal ynn(Channel Stack) en alt noktasnda bulunan Transport
Channel ve Encoding Channel kanalarnn ardndan farkl tipte kanallar gelebilmektedir. Daha
ncedende bahsedildii gibi bu kanallar Transaction, Security, Relaibility gibi konularla ilgili
olabilir. Burada sz konusu olan kanal yn(Channel Stack)kombinasyonu kod
tarafnda CustomBinding tipi yardmyla yada konfigurasyon baznda customBinding elementi ile
karlanabilmektedir. Ebeltte eklenecek olan kanallarn mantkl ve dzgn bir srada olmalar
arttr. Burada sz konusu olan sra iin aadaki ekil gz nne alnmaldr.

www.bsenyurt.com Page 438


Bu kadar teorik bilgiden sonra adm adm basit bir rnek zerinde ilerleyerek kod baznda WCF alt
yap hazrlklarn nasl yaplabilecei incelenmeye balanabilir. ncelikli olarak bir WCF servis
ktphanesi(WCF Service Library) gelitirilmelidir. Sz konusu servis ktphanesi ierisinde
yer alacak olan tipler(szleme-Service Contract ve uygulayc snf) basit olarak aada grld
gibidir.

IHesaplamalar arayznn ve Hesaplayici snfnn ierikleri aadaki gibidir.

using System;
using System.ServiceModel;

namespace ServisIslemleri

www.bsenyurt.com Page 439


{
[ServiceContract]
public interface IHesaplamalar
{
[OperationContract]
double DaireAlan(double r);
}

public class Hesaplayici


: IHesaplamalar
{
#region IHesaplamalar Members

public double DaireAlan(double r)


{
return Math.PI * r * r;
}

#endregion
}
}

Konunun basit olarak ele alnmas amacyla szleme ve uygulayc tipler yaln bir ekilde
tasarlanmlardr. nemli olan ksm servis uygulamas ierisinde programatik olarak yaplacak
ayarlamalardr. Bu amala Visual Studio 2008 ortamnda
gelitirilen Console uygulamasnda System.ServiceModel.dll ve servis ktphanesi(WCF
Service Library) assembly' larnn referanslarnn mutlaka var olmas gerekmektedir.

Servis uygulamasnn kodlar basit olarak aadaki gibi tasarlanabilir.

using System;
using System.ServiceModel.Channels; // Kanal tipleri iin eklenen isim alandr.
using System.ServiceModel;
using ServisIslemleri;

namespace Sunucu
{
class Program
{

www.bsenyurt.com Page 440


static void Main(string[] args)
{
CustomBinding binding = new CustomBinding(); // zel bir balayc tip snf
rneklenir. Dikkat edilecei zere bilinen bir Binding tipi oluturmaktan bir fark yoktur.

// lk rnek olarak Reliable Session iin bir Binding tipi oluturulur ve eklenir.
ReliableSessionBindingElement rBinding =
new ReliableSessionBindingElement(true); // Mesajlarn gnderildii srada iletilmesini
salamak iin yapc metoda true deeri verilmitir. tenirse Ordered zelliine true deeri
atanaraktanda bu ilem salanabilir.
rBinding.FlowControlEnabled = true;
rBinding.MaxRetryCount = 3; // Mesajlarn baarl ekilde iletimi iin maksimum tekrar
says belirlenir.
binding.Elements.Add(rBinding); // Oluturulan Bindin elementi eklenir.

SecurityBindingElement sBinding=SecurityBindingElement.CreateSecureConversatio
nBindingElement(SecurityBindingElement.CreateSspiNegotiationBindingElement());
sBinding.LocalServiceSettings.DetectReplays = true; // Replay ataklarn kontrol et.
binding.Elements.Add(sBinding); // Oluturulan SecureBindingElement, CustomBinding
nesnesinin ELements koleksiyonuna eklenir.

// zmleme kanal iin gerekli binding elementi oluturulur


TextMessageEncodingBindingElement tBinding =
new TextMessageEncodingBindingElement();
binding.Elements.Add(tBinding); // CustomBinding nesne rneinin elements
koleksiyonuna eklenir.

// letiim kanal iin gerekli element oluturulur


TcpTransportBindingElement tcpBinding = new TcpTransportBindingElement();
tcpBinding.TransferMode = System.ServiceModel.TransferMode.Buffered; //
Mesajlarn transfer modu belirlenir
binding.Elements.Add(tcpBinding); // Elements koleksiyonuna eklenir.

/* ServiceHost nesnesi oluturulur. Parametre olarak servis szlemesini uygulayan tipin


ad verilir. ServiceHost nesnesi rneklendiinde, kanallarn oluturulmasnda salar. Ayn zamanda
talep edilen servis rneklerinin yaam srelerini ynetir. Bunlar gerekletirirken ChannelListener,
ChannelDispatcher, EndPointDispatcher tiplerinin otomatik olarak rneklenmesinide salar.*/
ServiceHost host = new ServiceHost(typeof(Hesaplayici));

// EndPoint eklenir. lk parametre szleme tipi(Contract), ikinci parametre


balayc(Binding Type), son parametre ise adres(Address) bilgisidir.
host.AddServiceEndpoint("ServisIslemleri.IHesaplamalar", binding,
"net.tcp://localhost:45000/HesaplamaServisi");
host.Open(); // host alr. Open metodundan sonra ChannelListener gelen talepleri
dinlemeye balar. Gelen mesajlar kanal ynna devreder. ChannelDispatcher nesnesi ise bu
mesajlar kanal ynnn en stnden alr ve uygun olan EndPointDispatcher nesnesine devreder.
Console.WriteLine("Servis dinlemede...\nKapatmak iin bir tua basnz...");
Console.ReadLine();
}
}
}

Burada sadece rnek olmas asndan baz kanallar iin gerekli elementler oluturulmakta
ve CustomBinding nesne rneinin Elements koleksiyonu ierisinde toplanmaktadr. Sz konusu
element nesne rneklerinin pek ok zellii ve metodu burada gz ard edilmektedir. Ama

www.bsenyurt.com Page 441


programatik olarak zel bir balayc tipin oluturulmas ve ServiceHost nesne rnei zerinden
kullanlabilmesidir. Sz konusu uygulama altrldnda aadaki ekran grnts ile karlalr.

WCF alt yapsn programalamakla ilikili olarak Microsoft kaynaklarnn gsterdii rneklerde
yaplan almalardan biriside istemci ve servis arasndaki mesajlarn yakalanmasdr. (Yakalama
ilemini takiben mesaj ieriklerinin rnein herhangibir algoritmaya gre sktrlmas, baz
dorulama srelerinden geirilmesi gibi ek fonksiyonellikler yaplabilmektedir.) Bu ilem
iin IDispatchMessageInspector arayzn(Interface) uygulayan bir snf yazmak yeterlidir.
Daha sonra sz konusu snf rnei servis tarafnda davran(Behavior) olarak ele alnmaktadr.
Sz konusu davrann yazlmas iinse IServiceBehavior arayzn uygulayan bir snfn
gelitirilmesi ve ierisindeki uygun metodlarda mesaj yakalamak zere tasarlanan tipin ele alnmas
gerekmektedir. Davrann servis seviyesinde uygulanmas halinde, gelen tm mesajlarn
yakalanmas sz konusudur. Mesaj yakalama sreci ile ilikili tipler istemci tarafnada uygulanabilir.

Yaznn bu blmnde mesaj yakalamak iin gerekli ilemlerin programatik olarak nasl
gerekletirilecei ele alnmaktadr. Bu amala servis uygulamasna aadaki snf
diagramnda(Class Diagram) grlen tiplerin eklenmesi yeterlidir.

MesajYakalayici isimli
snf IDispacthMessageInspector arayzn(Interface) uygulamaktadr. Sz konusu
arayz AfterReceiveRequest ve BeforeSendReply isimli iki metodun uygulanmasn
beklemektedir. Tahmin edilecei zere AfterReceiveRequest metodu ile, istemcinin talep ettii
operasyonun servis tarafnda altrlmasndan hemen nce mesajn yakalanmas mmkn
olmaktadr. Hatta istenirse mesaj ierii burada deitirilebilir ki bu ok dikkatli bir ekilde ele
alnmas gereken bir durumdur. BeforeSendReplyisimli metod ise, servis tarafndan talep edilen

www.bsenyurt.com Page 442


metod tamamlandktan sonra devreye girmektedir. rnekteki snfta sadece ve sadece gelen ve
giden mesajlara ait bilgiler ele alnmaya allmaktadr. MesajYakalayici snfna ait kod ierisi
aadaki gibidir.

using System;
// IDispatchMessageInspector araynzn yer ald isim alandr.
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.Xml;
using System.ServiceModel.Description;

namespace Sunucu
{
class MesajYakalayici
:IDispatchMessageInspector
{
#region IDispatchMessageInspector Members

// Servis zerinden talep edilen metod altrlmadan hemen nce devreye giren metoddur.
// ilk parametrenin ref olarak tanmlandna dikkat edelim. Yani gelen mesajda yaplacak
olan deiiklikler alma ortamn dorudan etkileyecektir.
public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message
request, System.ServiceModel.IClientChannel channel,
System.ServiceModel.InstanceContext instanceContext)
{
// System.Runtime.Serialization referans eklenmedii takdirde MessageId zellii iin
derleme zaman hatas alnmaktadr.
Console.WriteLine("\n\n");
Console.WriteLine("*******Request Bilgisi********");
Console.WriteLine("Message Id : " + request.Headers.MessageId.ToString());
Console.WriteLine("MessageVersion Addressing : "
+ request.Headers.MessageVersion.Addressing);
Console.WriteLine("To : " + request.Headers.To.AbsolutePath);
Console.WriteLine("Action : " + request.Headers.Action);
Console.WriteLine("Encoder : "+request.Properties.Encoder);

MessageBuffer buffer = request.CreateBufferedCopy(Int32.MaxValue);


request = buffer.CreateMessage();
Console.WriteLine("Mesaj Body
:"+buffer.CreateMessage().GetBody<XmlElement>().InnerXml);

return null;
}

// Servis metodu tamamlandnda devreye giren metoddur.


public void BeforeSendReply(ref System.ServiceModel.Channels.Message reply,
object correlationState)
{
Console.WriteLine("\n\n");
Console.WriteLine("*******Reply Bilgisi********");
Console.WriteLine("Action : " + reply.Headers.Action);
Console.WriteLine(reply.ToString());
}
#endregion
}
}

www.bsenyurt.com Page 443


Yazlan bu mesaj yakalama snfnn EndPointDispatcher nesnelerinin her birinde uygulanabilmesi
iin servis tarafnda bir davran belirtilmesi gereklidir. MesajYakalayiciBehavior snfnn
yazlmasnn amalarndan biriside budur. EndPointDispatcher noktlarna mesaj yakalama
ilemini stlenen snflarn eklenmesi iin ApplyDispatcherBehaviormetodundan
yaralanlmaktadr.

using System;
// IDispatchMessageInspector araynzn yer ald isim alandr.
using System.ServiceModel.Dispatcher;
using System.ServiceModel.Channels;
using System.Xml;
using System.ServiceModel.Description;

namespace Sunucu
{
// Mesaj yakalama snfnn uygulanmas iin bir davran tipi (Behavior Type) gelitirilir
public class MesajYakalayiciBehavior
: IServiceBehavior // Davran tipleri IServiceBehavior arayznden trerler.
{
#region IServiceBehavior Members

/* Ek balayc parametrelerin ilave edilebilmesini salayan metoddur. Sz konusu d ortam


parametreleri metoda BindingParameterCollection tipinden aktarlr. WCF alma zaman tarafndan
servisin dinledii her bir URI iin bir kere arlr.*/
public void AddBindingParameters(ServiceDescription serviceDescription,
System.ServiceModel.ServiceHostBase serviceHostBase,
System.Collections.ObjectModel.Collection<ServiceEndpoint> endpoints,
BindingParameterCollection bindingParameters)
{
}

/* ServisHost nesnesine behavior nesnesinin uyguland metoddur. rnekteki mesaj


yakalaycnn uygulanaca yerdir. Servis tarafndan kullanlan her bir EndPointDispatcher nesnesi
iin birer mesaj yakalayc bu metod ierisinden eklenebilir. */
public void ApplyDispatchBehavior(ServiceDescription serviceDescription,
System.ServiceModel.ServiceHostBase serviceHostBase)
{
/* Aadaki kod paras sayesinde, EndPointDispatcher' lara ulaan her mesaj yada
iletilen servis metodundan EndPointDispatcher' a dnen her mesaj MesajYakalayici nesne rnei
zerinden gemek durumundadr. */
// ChannelDispatchers ierisindeki her bir ChannelDispatcher nesnesini ele al
foreach (ChannelDispatcher cd in serviceHostBase.ChannelDispatchers)
{
// O anki ChannelDispatcher ierisindeki her bir EndPointDispatcher nesnesini ele al
foreach (EndpointDispatcher ed in cd.Endpoints)
{
// MesajYakalayici nesne rneini MessageInspectors koleksiyonuna ekle
ed.DispatchRuntime.MessageInspectors.Add(new MesajYakalayici());
}
}
}

/* Servisin alma zamannda gerekli zellikleri salayp salamadnn denetlenebilecei


yerdir.artlara uymayan durumlarda szlemenin geri evrilmesi amacyla metod ierisinde
exception frlatlmas gibi ilemler yaplabilir */
public void Validate(ServiceDescription serviceDescription,

www.bsenyurt.com Page 444


System.ServiceModel.ServiceHostBase serviceHostBase)
{
}

#endregion
}
}

Artk servis tarafnda MesajYakalaycBehavior isimli davrann uygulanma ilemi


gerekletirilebilir. Bunun iin host isimli nesne rnei zerinden Open metodu arlmadan
hemen nce aadaki kod parasnn yazlmas yeterlidir.

host.Description.Behaviors.Add(new MesajYakalayiciBehavior());

Sz konusu davrann eklenmesi iin ServiceHost nesne rneinin Description zellii zerinden
ulalan Behaviors zelliinin Add metodu kullanlmaktadr. Elbette sonular grebilmek iin
istemci tarafndan talep(Request) gelmesi gerekmektedir. stemci uygulama olayn kolay bir
ekilde analiz edilebilmesi ve zellikle mesaj yakalaycnn etkilerinin grlebilmesi iin basit
bir Console projesi olarak gelitirilmektedir. Yazdakine benzer senaryolarda
ounlukla svcutil aracndan yararlanlarak istemci(Client) iin gerekli
olan proxy snf(Class) ve config dosyasnn retilmesi yolu tercih edilir.
Yada metadata publishing seenei aktif braklarak istemcilerin servis referanslarn eklemeleri
salanabilir. Bazen gvenlik nedeniyle metadata publishing seeneinin kapatld durumlar sz
konusudur. rnek senaryoda istemci taraf iin gerekli olan proxy snf svcutilarac yardmyla
rneklenmekte ve otomatik retilen config dosyas kullanlmaktadr. Bu amala svcutil aracndan
aadaki ekran grntsnde olduu gibi yararlanlmas yeterlidir.

Bu ilemin arkasndan retilen Proxy.cs ve App.config dosyas rnek bir Client uygulamasnda
ele alnabilir. retilen config dosyas otomatik olarak basicHttpBinding bazl birbalayc
tipi(Binding Type) kullanmaktadr. Oysaki rnekte yer alan servis taraf CustomBinding tipini

www.bsenyurt.com Page 445


ele almaktadr. Bu sebepten istemci tarafndaki config dosyasnn ierii aadaki gibi
deitirilemelidir.

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


<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="HesaplamaServisiBindingConfig">
<reliableSession />
<security authenticationMode="SecureConversation"
requireSignatureConfirmation="false">
<localClientSettings/>
<secureConversationBootstrap />
</security>
<textMessageEncoding />
<tcpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint
address="net.tcp://localhost:45000/HesaplamaServisi" binding="customBinding" bindingConfig
uration="HesaplamaServisiBindingConfig" contract="IHesaplamalar"
name="HesaplamalarClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

zel balayc tiplerin konfigurasyon dosyas ierisinde tanmlanmas iin bindings elementi altnda
yer alan customBinding alt elementinden yararlanlr. Config dosyas ierisinde dikkat edilecei
zere servis tarafndaki CustomBinding bildirimlerine uygun olacak ekilde baz tanmlamalar
yaplmaktadr. Buna gre gvenilir oturumlar iinrelaibleSession elementi, gvenlik
iin security elementi, text bazl mesaj zmlemesi iin textMessageEncoding elementi ve son
olarak TCP bazl iletiimi iaret edecek ekildetcpTransport elementi kullanlmaktadr. Elbetteki
bu elementlerin doru srada yazlmalarda olduka nemlidir. Console uygulamasnn kodlar ise
aadaki gibi gelitirilebilir.

using System;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
HesaplamalarClient proxy =new
HesaplamalarClient("HesaplamalarClientEndPoint");

Console.WriteLine("Devam etmek iin bir tua basnz...");


Console.ReadLine();
Console.WriteLine(proxy.DaireAlan(10).ToString());
}
}
}

www.bsenyurt.com Page 446


Uygulama test edildiinde servis ve istemci ekranlarnda aadaki sonularn alnd grlecektir.

Dikkat edilecei zere servis tarafndaki mesaj dinleyici snf ierisindeki metodlar devreye
girerekten, istemciden gelen ve istemciye gnderilen paket ieriklerinin yakalanmas ve bunlar
hakknda bilgi alnmas ilemleri baarl bir ekilde gerekletirilmitir. Peki istemci asndan
bakldnda ayn ilemler kod tarafndan nasl yaplabilir. Bunun iin ncelikli olarak istemci
tarafnda, servis operasyonlarnn bildirimlerini ieren bir arayz(Interface) tipinin tasarlanm
olmas gerekmektedir. Bu tipin aadaki gibi tasarland dnlsn.

using System;
using System.ServiceModel;

namespace Istemci
{
[ServiceContract]
public interface IHesaplamalarV2
{
[OperationContract(Action = "http://tempuri.org/IHesaplamalar/DaireAlan",
ReplyAction = "http://tempuri.org/IHesaplamalar/DaireAlanResponse")]
double DaireAlan(double r);
}
}

www.bsenyurt.com Page 447


Bu arayz tipinin grevi alma zaman iin gerekli proxy nesnesi retildiinde, ilgili nesne
referansn tayabilmektir. Ayrca, DaireAlan metoduna ait operasyonel
bilgilerin,OperationContract nitelii ierisinde Action ve ReplyAction zellikleri ile nasl
tanmlandna dikkat edilmelidir. Servis tarafndaki szleme ierisinde
herhangibir namespacetanmlanmam olduundan, varsaylan olarak http://tempuri.org n
ifadesi tm operasyon bilgilerinin banda yer almaktadr. stemci tarafndaki kodlarda dikkat
edilmesi gereken en nemli nokta CustomBinding tipinin servis tarafndakine uygun olacak
ekilde tasarlanmasdr. Bu amalar istemci tarafndaki kodlarn aadaki gibi revize edilmesi
yeterlidir.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
CustomBinding binding = new CustomBinding();

ReliableSessionBindingElement rBinding = new ReliableSessionBindingElement();


binding.Elements.Add(rBinding);

SecurityBindingElement sBinding =
SecurityBindingElement.CreateSecureConversationBindingElement(SecurityBindingElement.CreateS
spiNegotiationBindingElement());
binding.Elements.Add(sBinding);

TextMessageEncodingBindingElement eBinding = new


TextMessageEncodingBindingElement();
binding.Elements.Add(eBinding);

TcpTransportBindingElement tcpBinding = new TcpTransportBindingElement();


binding.Elements.Add(tcpBinding);

IHesaplamalarV2 proxy =
ChannelFactory<IHesaplamalarV2>.CreateChannel(binding, new
EndpointAddress("net.tcp://localhost:45000/HesaplamaServisi"));

Console.WriteLine("Devam etmek iin bir tua basnz...");


Console.ReadLine();
Console.WriteLine(proxy.DaireAlan(10).ToString());
}
}
}

stemcinin ilgili operasyonel arlar yapabilmesi iin bir proxy nesne rneine ihitya vardr. Bu
nesne rneinin retilmesi iin ChannelFactory snfnnCreateChannel metodundan
yararlanlmaktadr. Dikkat edilecei zere, bu metodun ilk parametresi balayc tipi ifade
etmektedir. rnekteki balayc tipi CustomBindingtrnden olup servis tarafndaki bildirime
uygun olacak kanal bilgilerini iermektedir. Dier taraftan ikinci parametre ile servisin adres bilgisi
iaret edilir. Uygulama bu haliyle altrldndada ayn sonularn elde edilii grlebilir.

www.bsenyurt.com Page 448


WCF mimarisinde istenirse istemci tarafndan servise gnderilecek olan mesajlarn manuel olarak
hazrlanmasda mmkndr. Bu Web servislerinde SOAP bazl mesajlarn ieriklerinin hazrlanp
gnderilmesi ile benzer bir durumdur. zellikle WCF istemcilerinin, WCF harici servisler ile
haberlemesi gerektii durumlarda mesajlarn manuel olarak hazrlanmas sz konusu olabilir.
Byle bir durumda istemci tarafnda herhangibir proxy nesnesi olmadan operasyon arlar
yaplabilmektedir. Bu konuya ilerleyen yazlarda deinmeye alacam. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

AJAX ve JSON Destei ( 25.02.2008 ) - WCF


Deerli Okurlarm Merhabalar,

Son yllarda zellikle Web uygulamalarnda AJAX(Asynchronous Javascript And XML) mimarisi
olduka yaygn bir ekilde kullanlmaktadr. zellikle sunucu tarafl(Server-
Side)alan Asp.Net gibi web uygulamas gelitirme modellerinde istemciler(Clients) tarafndan
sunucuya(Server) doru gerekletirilen POST ilemleri srasnda, sayfann tamamnn
gnderilmesi sz konusudur. AJAX modeli sayesinde istemci tarafnda yer alan sayfann tm ierii
yerine sadece deitirilmesi istenen paralarn sunucuya gnderilmesi, ilenmesi ve cevaplarn
alnarak tarayc uygulama(Browser Application) zerinde gsterilmesi mmkn olmaktadr.
Bylece sayfann gerektende deimesi gereken ieriinin istemci ve sunucu arasndaki hareketi
sz konusudur. Bir baka deyile gereksiz olan ieriin sunucuya tekrar gnderilmesinin,
ilenmesinin nne geilmesi salanmaktadr. Bu bir anlamda son kullanc(End User) iin daha
zengin etkileime sahip ve performansl bir web ortam oluturulmas anlamna da gelir.

AJAX mimarisi, Asp.Net AJAX ile .NET platformu zerinde ok daha kolay bir ekilde uygulanabilir
hale getirilmitir. Microsoft' un .Net Framework mimarisine getirdii bu ilave yenilik hakknda
sylenecek ve yazlacak ok ey vardr. Bu yazdaki hedef ise Windows Communication
Foundation servislerinin(WCF Services) AJAX bazl istemcilere hizmete verebilecek ekilde nasl
gelitirileceklerinin renilmesidir. Nitekim Web uygulamalarda kendi ilerinde WCF servislerine
eriebilir ve kullanabilirler. Bununla birlikte WCF mimarisi AJAX tipindeki
istemcilereJSON(JavaScript and Object Notation) formatnda veri ierii sunabilme
kapasitesine de sahip hale gelmitir. e ilk olarak Asp.Net AJAX tipindeki istemcileri ele alarak
balamakta yarar vardr.

Asp.Net AJAX modeli aslnda iki nemli paradan oluur. Bu paralardan birisi istemci betik
ktphanelerdir(Client Script Libraries). Dier para ise sunucu tarafl betik
kontrollerdir(Server Side Script Controls). Asp.Net AJAX sayfalarndan bir WCF servisine
ulamak son derece kolaydr. Bunun iin ncelikli olarak servisin adres
bilgisinin ScriptManagerblou ierisinde belirtilmesi gerekir. Bu ilemden sonra istemci tarafndan
sanki bir JavaScript fonksiyonu arlyormu gibi WCF servisine ait operasyonlar(Service
Operations)kullanlabilir. Elbette servis tarafndan sunulan EndPoint noktasnn AJAX tipinden
istemcilere hizmet verecek ekilde ayarlanm olmas gerekir.

AJAX istemcileri iin WCF servisleri gelitirmek eer Visual Studio 2008 gibi bir
gelitirme ortam kullanlyorsa ok kolaydr. Nitekim bir Web uygulamasna Add New
Itemile Ajax Enabled WCF Service ablonun eklenmesi yeterlidir.

www.bsenyurt.com Page 449


Ajax-enabled WCF Service seeneini kullanmadanda AJAX uyumlu WCF servisleri gelitirilebilir.
Bunu yapmann temel olarak iki farkl yolu vardr. Buna gre servisin kod tarafnda yada
konfigurasyon bazl olacak ekilde gelitirilmesi mmkndr. Kod tarafnda yaplan gelitirme
ounlukla Dinamik Host Aktivasyon(Dynamic Host Activation) olarak bilinmektedir. Hangi
model seilirse seilsin, AJAX istemcilere destek verecek EndPoint noktasna sahip olan WCF
servisinin, IIS(Internet Information Services) zerinde Host ediliyor olmas arttr. Dynamic
Host Activation modeline gre gelen talepleri deerlendirmek
zere WebServiceScriptHostFactory isimli bir CLR tipi (Common Language Runtime
Type) devreye girmektedir. Bilindii zere IIS zerinden yaynlanan WCF servislerinde svc uzantl
bir dosya bulunmaktadr. Sz konusu dosyada yer alan Service direktifi(Directive) ne
ait Factoryniteliinde(Attribute) WebScriptServiceHostFactory atamas yaplarak, alma
zamannda gelen taleplerin(Requests) dinamik olarak retilen bir EndPoint tarafndan
karlanmas salanmaktadr. Bir baka deyile AJAX istemcilerin gnderecekleri talepere gre
EndPoint dinamik olarak uygun bir ekilde WebScriptServiceHostFactory tipi tarafndan retilir.

WebScriptServiceFactory snf, alma zamannda herhangibir konfigurasyon bilgisine


ihtiya duymadan servise, Asp.Net Ajax EndPoint noktas eklenmesini salar. Bu snfn
retimi hem IIS(Internet Information Services) hemde (WAS)Windows Process
Activation Services ortamlar tarafndan desteklenmektedir. WebScriptServiceFactory
tipi, ServiceHostFactoryBase abstract snfndan
treyen ServiceHostFactory snfndan kaltlmtr.

Konuyu daha net kavrayabilmek adna basit bir rnek ile devam edilmesinde yarar vardr. rnekte,
IIS zerinden Ajax istemcileri iin Dynamic Host Activation mantna uygun olacak ekilde bir
servis gelitirilmektedir. Her zamanki gibi ie servis ktphanesinin(WCF Service
Library) tasarlanmasyla balanlmasnda yarar vardr. Servis ktphanesi ierisinde yer alacak
olan tipler dnda Web zerinde AJAX istemcilere hizmet verilecei iin ilgili
operasyonlarn WebGet yada WebInvoke nitelikleri(attribute) ile imzalanmas gerekmektedir.
Bu nedenle WCF servis ktphanesinin System.ServiceModel.Web.dll isimli assembly
referansna sahip olmas gerekmektedir.

www.bsenyurt.com Page 450


Servis taraf imdilik geriye ilkel tip dndren tek bir metoda sahiptir.

using System;
using System.ServiceModel;
using System.ServiceModel.Web;

namespace OrtakIslemler
{
[ServiceContract(Namespace="OrtakServis")]
public interface IMatematik
{
[OperationContract]
[WebGet]
double DaireAlan(double r);
}

public class Matematik : IMatematik


{
#region IMatematik Members

www.bsenyurt.com Page 451


public double DaireAlan(double r)
{
return Math.PI * r * r;
}

#endregion
}
}

IMatematik isimli servis szleme arayz(Interface) geriye double deer dndren


ve double tipinden parametre alan DaireAlan isimli bir operasyon tanmlamaktadr. lgili
operasyonun WebGet nitelii ile imzalandna dikkat edilmelidir. Servis szlemesini
uygulayan Matematik isimli snf ise DaireAlan metodunu uygulamaktadr. Servis
uygulamas IISzerinden yaynlama yapmas gerektiinden Visual Studio 2008 ortamnda Add
New Web Site ile WCF Service ablonundan bir proje oluturulabilir. Sz konusu uygulamada u
an iin web.config dosyasnn olmasna gerek yoktur. Nitekim ilk ama Dynamic Host
Activation modelini uygulamaktr. Dier taraftan servis ktphanesinin ilgili web uygulamasna
referans edilmesi gerekmektedir. Sonu itibariyle AjaxServiceDemo isimli WCF Service
uygulamasnn Solution Explorer zerinden grlen ilk hali aadaki gibi olmaldr.

Artk Service.svc dosyasnn ierii aadaki gibi gelitirilebilir.

<%@ ServiceHost Language="C#"


Debug="true" Service="OrtakIslemler.Matematik" Factory=System.ServiceModel.Activati
on.WebScriptServiceHostFactory %>

Service niteliinde standart olarak servis nesnesine ait tipin bildirimi yaplmaktadr. Bununla
birlikte Ajax istemcilerine hizmet verilmesini salayabilmek
iinde Factory niteliineSystem.ServiceModel.Activation.WebScriptServiceHostFactory bilgi
si atanmtr. Bu noktadan sonra svc dosyas herhangibir tarayc penceresinden talep edilebilir.
Yanlz dikkat edilemesi gereken bir nokta vardr. Yaznn hazrlandn tarih itibariyle Vista iletim
sistemi zerinde yer alan IIS 7.0 srmnde aadaki ekran grntsnde yer alan hata mesaj
ile karlalmaktadr.

www.bsenyurt.com Page 452


Bu sorunun imdilik zm iin IIS 7.0 zerinde ilgili WCF servisine
ait Authentication bilgisinden sadece tek bir modelin seili olmasn salamaktr. Nitekim ilgili
WCF servisi iin hem Anonymous hemde Windows Authentication modlar aktiftir. rnekte
sadece Anonymous modun seil halde braklmas salanlmaldr.

Bu dzeltmeden sonra service.svc yeniden talep edilirse aadaki ekran grnts elde edilir.

www.bsenyurt.com Page 453


Grld gibi standart olarak bir WCF servisine HTTP zerinden yaplan talep sonras karlalan
ekran retilmitir. Elbette burada herhangibir ekilde konfigurasyon ayar yaplmadndan yada
ilgili nitelikler ile servise veya EndPoint noktasna bir davran(Behavior) belirtilmediinden HTTP
zerinden metadata bilgisi ekilmesine izin verilmemektedir.

ster Dynamic Host Activation modeli ister konfigurasyon bazl modele gre AJAX
istemcilere hizmet verecek ekilde tasarlanm olsun, bir WCF servisi
ek EndPoint noktalar ierebilir. Sz gelimi hem AJAX istemcilere hizmet veren
hemde SOAP protokol zerinden hizmet veren EndPoint noktalarna sahip bir WCF
servisinin tasarlanmas mmkndr.

Artk AJAX uyumlu istemcinin yazlmasna balanabilir. Sz konusu istemci Visual Studio
2008 ortamnda gelitirilen bir Asp.Net uygulamasdr. Dier taraftan .Net Framework
3.5ablonu seilecei iin dorudan AJAX desteide otomatik olarak gelmektedir. Sayfann en
nemli olan noktalarndan birisi ScriptManager ieriidir. Nitekim ScriptManager elementi
ierisinde kullanlmak istenen servisin adresi mutlaka belirtilmelidir. rnek aspx sayfasnn ierii
aadaki gibidir.

www.bsenyurt.com Page 454


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script type="text/javascript">

function ServisCagir()
{
var proxy = new OrtakServis.IMatematik();
var r=parseFloat(document.getElementById("txtYaricap").value);
proxy.DaireAlan(r,Basarili,Basarisiz,null);
}

function Basarili(sonuc)
{
document.getElementById("lblSonuc").value=sonuc;
}
function Basarisiz()
{
document.getElementById("lblSonuc").value="Bir sorun var.";
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>

<asp:ScriptManager ID="ScriptManager1" runat="server">


<Services>
<asp:ServiceReference
Path="http://localhost/AjaxServiceDemo/Service.svc" />
</Services>
</asp:ScriptManager>

<br />Daire Yarap :<asp:TextBox ID="txtYaricap"


runat="server"></asp:TextBox><br />
<input type="button" id="btnHesapla" value="Daire Alan

www.bsenyurt.com Page 455


Bul" onclick="ServisCagir()" /><br />
<br />
<input type="text" id="lblSonuc" />
</div>
</form>
</body>
</html>

ScriptManager kontrol kendi ierisinde birden fazla servis noktas tanmlanabilmesini salayacak
ekilde Services isimli bir alt elemente sahiptir. Bu element ierisinde ServiceReferenceisimli
bileenler kullanlr. ServiceReference bileeninin Path zelliine verilen deer kullanlmak istenen
WCF servisine ait URL bilgisini tamaktadr. Dier taraftan javascriptkodlarnda dikkat edilecei
zere btnHesapla isimli input kontrolne basldnda alan ServisCagir isimli bir metod yer
almaktadr. Bu metod ierisinde nce bir proxy nesnesi oluturulmaktadr. Bu nesne
oluturulurken OrtakServis.IMatematik isimli tipten
yararlanlmaktadr. OrtakServis ad, ServiceContract niteliinde
belirtilen Namespacedeerinden gelmektedir. Dier taraftan IMatematik ismi ise, servis
szlemesinin(Service Contract) addr. Buna gre retilen proxy nesnesi
zerinden DaireAlan metodu arlarbilir.

Metod ars gerekletirilirken ilk parametre olarak, DaireAlan metodunun


bekledii yarap deeri verilmektedir. kinci parametre sz konusu operasyon baarl bir ekilde
tamamlanrsa devreye girecek olan ve sonularn alnabilecei geri bildirim fonksiyonunun addr.
Bu metod ierisinde arlan servis operasyonunun sonucu alnmas gerektiinden ilgili metod,
DaireAlan operasyonunun dn deerini parametre olarak almaktadr. nc parametre ile
belirtilen metod ise, servis zerindeki operasyonun arlmas esnasnda bir hata olumas halinde
devreye girecek olan metoddur. Son parametre null olarak geilmekle birlikte
ounlukla HttpContext tipinin kullanlmas gerektii durumlarda ele alnmaktadr. Artk istemci
uygulama altrlp test edilebilir. Eer dme tklanrsa sayfann tamamnn Post edilmeden,
sadece servis operasyonun arld ve sonucun ekrandaki ilgili TextBox kontrolne alnd
grlebilir.

imdi WCF servisinin Dynamic Host Activation yerine konfigurasyon bazl olarak nasl ina
edileceine baklabilir. Konfigurasyon dosyas kullanldnda WebHttpBindingbalayc
tipinin(Binding Type) ve EnableWebScript davrannn(Behavior) kullanlmas gerekir. Sz
gelimi az nce gelitirilen WCF servis uygulamasnn konfigurasyon tabanl olacak ekilde
altrlmas iin web.config dosyasnda yer alan system.serviceModel elementinin ieriinin
aadaki gibi tasarlanmas yeterlidir.

<system.serviceModel>

www.bsenyurt.com Page 456


<behaviors>
<endpointBehaviors>
<behavior name="AjaxEndPointBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="OrtakIslemler.Matematik">
<endpoint address="http://localhost/AjaxServiceDemo/Service.svc" behaviorCo
nfiguration="AjaxEndPointBehavior" binding="webHttpBinding"
name="AjaxEndPoint"contract="OrtakIslemler.IMatematik" />
</service>
</services>
</system.serviceModel>

Dikkat edilecei zere AjaxEndPoint isimli EndPoint tanmlanrken webHttpBinding balayc


tipinin(Binding Type) kullanlaca belirtilmitir. Ayrca EndPoint davran
ierisinde enableWebScript elementi kullanlmtr. Bu durumda istemci uygulama test edildiinde
yine WCF servisinin baarl bir ekilde alt grlebilir.

AJAX uyumlu WCF servislerinde nem arz eden konulardan biriside, istemcilerin servis
operasyonlarna yaptklar talep sonras dnecek olan verinin formatdr. AJAX destekli WCF
servisleri XML(eXtensible Markup Language) tipinde veri formatn kullanmakla birlikte .Net
Framework 3.5 ile JSON(JavaScript Object Notation) desteinede sahip olmulardr ki ou
AJAX servisi varsaylan olarak JSON bazl yaynlama yapmaktadr. Daha nceki blmlerden de
hatrlanaca gibi, bir servis operasyonuna
uygulanan WebGet ve WebInvokeniteliklerine(attribute) ait ResponseFormat zelliklerinin
deerleri kullanlarak JSON formatnda veri dntrlecei belirtilebilmektedir. Dier
taraftan WCF AJAX EndPointnoktalar hem JSON hemde XML formatndaki taleplere cevap
verebilmektedir. application/json tipindeki talepler(requests) tahmin edilecei
zere JSON format ile alakaldr. Bununla birlikte text/xml formatndaki taleplerde XML format
ile alakaldr. Tabi Ajax destekli servislerde sorun oluturan nemli noktalardan biriside, .NET
tiplerinin JSON formatnaseriletirme(Serialization) ilemleridir. Bu nedenle ilk olarak JSON
seriletirmesine bir gz atmakta yarar vardr.

JSON (JavaScript Object Notation) zellikle AJAX uyumlu servisler(Ajax Enabled


WCF Services/Web Services) ile istemciler arasnda hzl veri dei tokuu yaplmasna
olanak tanyan nemli veri format(Data Format) standartlarndadr.

JSON seriletirmede de servis tarafndan istemciye yaynlanan veri tiplerinin nemi byktr.
Nitekim WCF gibi .Net tabanl bir ortamda, CLR tiplerinin JSON karlklarnn bilinmesinde yarar
vardr. Bu amala ncelikli olarak aadaki tablonun gz nne alnmas yararl olabilir. Hemen
hemen tm CLR tipleri(Common Language Runtime Types)uygun JSON tiplerine
dntrlmektedir.

.Net Tipi JSON Karl

Int16, Int32, Double, Decimal gibi saysal tiplerin tamam. Number

Boolean Boolean

String, Char String

Timespan, Guid, Uri String

www.bsenyurt.com Page 457


XmlElement, XmlNode gibi Xml tipleri String

ISerializable, DataSet gibi tipler String

Enum Number

Byte Dizisi Number Dizisi

DateTime veya
DateTime
String

Collections(Koleksiyonlar), Dictionary Tipleri ve Arrays


Array
(Diziler)

Herhangibir tipin Null deeri Null

DataContract niteliini(Attribute) uygulam tipler Complex Type

ISerializable arayzn(Interface) uygulam tipler Complex Type

Empty Complex
DBNull
Type

XmlQualifiedName String

Buradaki tablo .Net ve JSON tipleri arasndaki eletirmelerin basit bir zetidir. Tip dnmleri
srasnda gz nne alnmas gereken olduka fazla kural ve vaka bulunmaktadr. (Sz konusu
durumlar makalemizin konusunu amaktadr. Ancak detayl bilgi iin MSDN kaynaklarndaki ilgili
balantya baklabilir.)

Normal artlarda WCF servisleri JSON seriletirmesini otomatik olarak gerekletirmektedir.


zellikle kullanc tanml tiplerde (User Defined Types) veri szlemesi
tanmlanarak(DataContract ve DataMember nitelikleri-attribute yardmyla) seriletirme ilemi
otomatik hale getirilmektedir. Yinede baz
durumlarda JSON seriletirilme(Serialization) ve ters-
Seriletirme(DeSerialization) ilemlerinin elle yaplmas gerekebilir. Bu amala .Net
Framework 3.5 ile birlikte gelen DataContractJsonSerializer tipinden yararlanlabilir.

System.ServiceModel.Web.dll assembly' ndaki System.Runtime.Serializetion.Json isim


alannda(Namespace) bulunan DataContractJsonSerializer, XmlObjectSerializer abstract s
nfndan tremi selaed olarak imzalanm bir CLR tipidir. Sealed olarak iaretlenmi olmas
nedeniyle kendisinden tretme(Inherit) yaplamamaktadr. Temel grevi
tipleri(Types) JSON formatnda veri olarak seriletirmek veya tam tersini yapmaktr. JSON
seriletirmeyi daha iyi kavramak iin bir rnek ile devam edilmesinde yarar vardr. Bu
amalaVisual Studio 2008 ortamnda .Net Framework 3.5 tabanl bir Console uygulamas
gelitirildii gz nne alnsn. ncelikli olarak System.ServiceModel.Web.dll ' inin projeye

www.bsenyurt.com Page 458


refarans edilmi olmas gerekmektedir. Ayrca DataContract ve DataMember niteliklerini
kullanabilmek iinde System.Runtime.Serialization.dll assembly' nn referans edilmesi arttr.

rnek olarak class diagram grnts aadaki gibi olan Urun isimli bir snf(Class) tasarlanabilir.

using System;
using System.Runtime.Serialization;

namespace JSONSerilestirme
{
[DataContract]
class Urun
{
private int _id;
private string _ad;
private double _fiyat;
private DateTime _stokGirisTarihi;

[DataMember]

www.bsenyurt.com Page 459


public DateTime StokGirisTarihi
{
get { return _stokGirisTarihi; }
set { _stokGirisTarihi = value; }
}

[DataMember]
public double Fiyat
{
get { return _fiyat; }
set { _fiyat = value; }
}

[DataMember]
public string Ad
{
get { return _ad; }
set { _ad = value; }
}

[DataMember]
public int Id
{
get { return _id; }
set { _id = value; }
}

public Urun(int id, string ad, double fiyat, DateTime stokGirisTarihi)


{
Id = id;
Ad = ad;
Fiyat = fiyat;
StokGirisTarihi = stokGirisTarihi;
}
}
}

Urun snf DataContract nitelii(Attribute) ile imzalanmtr. Bununla birlikte seriletirmeye tabi
tutulacak olan Id,Ad,Fiyat,StokGirisTarihi zellikleride(Properties) DataMembernitelikleri ile
iaretlenmilerdir. Seriletirme ve ters-Seriletirme iin rnek olarak aadaki gibi bir kod paras
gz nne alnabilir.

using System;
using System.Runtime.Serialization.Json;
using System.IO;

namespace JSONSerilestirme
{
class Program
{
static void Main(string[] args)
{
// Urun snfna ait bir nesne rneklenir.
Urun dvd = new Urun(1, "Double Layer DVD Box 150", 30, DateTime.Now);

#region Kullanc tanml bir tipi JSON Seriletirme

www.bsenyurt.com Page 460


// Json seriletirme ilemleri iin DataContractSerializer tipi rneklenir. rnekleme ilemi
srasnda parametre olarak seriletirilecek olan tip belirtilir.
DataContractJsonSerializer serializer = new
DataContractJsonSerializer(typeof(Urun));
// Seriletirme rnek olarak bir dosyaya doru yaplacaktr.
using (FileStream stream = new FileStream("UrunJason.xml", FileMode.Create,
FileAccess.Write))
{
// WriteObject metodu ile ilk parametrede belirtilen stream zerine, ikinci parametrede
belirtilen nesne rneinin verisi seriletirilir
serializer.WriteObject(stream, dvd);
}

#endregion

#region JSON datasn DeSerialize edip Object haline getirme

// Dosyadaki veriden nesne elde edilecei iin FileStream oluturulur.


using (FileStream stream = new FileStream("UrunJason.xml", FileMode.Open,
FileAccess.Read))
{
// ReadObject metodu ile stream ile belirtilen dosya ierisindeki JSON formatl veri
okunur Object olarak elde edilir. Sonrasnda ise kullanlabilmesi iin Urun tipine cast edilir.
Urun okunanDvd = (Urun)serializer.ReadObject(stream);
Console.WriteLine(okunanDvd.Id+" "+okunanDvd.Ad+"
"+okunanDvd.Fiyat.ToString("C2")+" "+okunanDvd.StokGirisTarihi.ToString());
}

#endregion
}
}
}

Seriletirme ilemi sonrasnda oluan UrunJason.xml dosyasnn ierii aadaki gibi olmaktadr.

{"Ad":"Double Layer DVD Box


150","Fiyat":30,"Id":1,"StokGirisTarihi":"\/Date(1203765080248+0200)\/"}

Ayrca ters seriletirme(DeSerializetion) ilemi sonrasnda ise programn ekran kts aadaki
gibidir. Grld gibi dosyada duran JSON formatl veri ieriinden Urun nesne rnei elde
edilmitir.

Elbette Urun tipinden nesne rneklerini bnyesinde barndran bir dizide JSON formatnda
seriletirilebilir ve hatta okunabilir. Aadaki kod parasnda bu durum rneklenmeye
allmaktadr.

Urun[] urunler ={
new Urun(2,"Urun X",1.45,new DateTime(2007,12,2))

www.bsenyurt.com Page 461


,new Urun(3,"Urun Y",2.34,new DateTime(2008,2,3))
,new Urun(4,"Z Urun",34.56,new DateTime(2006,6,7))
};

DataContractJsonSerializer arraySerializer = new


DataContractJsonSerializer(typeof(Urun[]));
using (FileStream stream = new FileStream("Urunler.json", FileMode.Create, FileAccess.Write))
{
arraySerializer.WriteObject(stream, urunler);
}

using (FileStream stream = new FileStream("Urunler.json", FileMode.Open, FileAccess.Read))


{
Urun[] gelenUrunler=(Urun[])arraySerializer.ReadObject(stream);
foreach(Urun urn in gelenUrunler)
Console.WriteLine(urn.Ad);
}

Bu kez seriletirme ileminde Urun tipinden bir dizi(Array) sz konusudur. Bu


sebepten DataContractJsonSerializer snfna ait nesne rneklenirken parametre
olarak typeof(Urun[])bilgisi verilmektedir. Sonu olarak retilen JSON formatl veri ierii
aadaki gibi olacaktr.

[{"Ad":"Urun
X","Fiyat":1.45,"Id":2,"StokGirisTarihi":"\/Date(1196546400000+0200)\/"},{"Ad":"Urun
Y","Fiyat":2.34,"Id":3,"StokGirisTarihi":"\/Date(1201989600000+0200)\/"},{"Ad":"Z
Urun","Fiyat":34.56,"Id":4,"StokGirisTarihi":"\/Date(1149627600000+0300)\/"}]

Hemen yeni bir kod paras ile bir DataSet nesne rneinin JSON formatnda nasl serileeceine
bakmakta yarar vardr. Nitekim veri taban uygulamalarnn ok sk kullanlmas nedeni ile WCF
servislerinden zellikle balantsz katmana(Disconnected Layer) ait tiplerin dndrlmesi sk
rastlanan bir durumdur. Bu amala Console uygulamasna aadaki kod parasnn eklenmesi
yeterlidir.

using (SqlConnection conn = new SqlConnection("data


source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlDataAdapter adapter = new SqlDataAdapter("Select Top 5 ProductId,Name,ListPrice From
Production.Product", conn);
DataSet set = new DataSet();
adapter.Fill(set);

DataContractJsonSerializer dataSetSerializer = new


DataContractJsonSerializer(typeof(DataSet));
using (FileStream stream = new FileStream("Products.json", FileMode.Create, FileAccess.Write))
{
dataSetSerializer.WriteObject(stream, set);
}
}

Bu kodun alma sonrasn oluan Products.json dosyasnn ierii aadaki gibi olur.

"<DataSet><xs:schema id=\"NewDataSet\"
xmlns:xs=\"http:\/\/www.w3.org\/2001\/XMLSchema\" xmlns:msdata=\"urn:schemas-microsoft-

www.bsenyurt.com Page 462


com:xml-msdata\"> <xs:element name=\"NewDataSet\" msdata:IsDataSet=\"true\"
msdata:UseCurrentLocale=\"true\"> <xs:complexType> <xs:choice minOccurs=\"0\"
maxOccurs=\"unbounded\"><xs:element name=\"Table\">
<xs:complexType><xs:sequence><xs:element name=\"ProductId\" type=\"xs:int\"
minOccurs=\"0\"\/> <xs:element name=\"Name\" type=\"xs:string\"
minOccurs=\"0\"\/><xs:element name=\"ListPrice\" type=\"xs:decimal\"
minOccurs=\"0\"\/><\/xs:sequence> <\/xs:complexType><\/xs:element><\/xs:choice>
<\/xs:complexType> <\/xs:element><\/xs:schema><diffgr:diffgram
xmlns:diffgr=\"urn:schemas-microsoft-com:xml-diffgram-v1\" xmlns:msdata=\"urn:schemas-
microsoft-com:xml-msdata\"><NewDataSet> <Table diffgr:id=\"Table1\"
msdata:rowOrder=\"0\"><ProductId>1<\/ProductId> <Name>Adjustable
Race<\/Name><ListPrice>0.0000<\/ListPrice><\/Table><Table diffgr:id=\"Table2\"
msdata:rowOrder=\"1\"><ProductId>2<\/ProductId> <Name>Bearing
Ball<\/Name><ListPrice>0.0000<\/ListPrice><\/Table><Table diffgr:id=\"Table3\"
msdata:rowOrder=\"2\"><ProductId>3<\/ProductId><Name>BB Ball
Bearing<\/Name><ListPrice>0.0000<\/ListPrice><\/Table><Table diffgr:id=\"Table4\"
msdata:rowOrder=\"3\"><ProductId>4<\/ProductId><Name>Headset Ball
Bearings<\/Name><ListPrice>0.0000<\/ListPrice><\/Table><Table diffgr:id=\"Table5\"
msdata:rowOrder=\"4\"><ProductId>316<\/ProductId><Name>Blade<\/Name>
<ListPrice>0.0000<\/ListPrice><\/Table><\/NewDataSet><\/diffgr:diffgram><\/DataSet>"

Daha ncedende belirtildii gibi DataSet tipinin JSON karl String olarak ifade edilmektedir. Bu
nedenle retilen kt ift trnaklar ierisinde yer almaktadr.

Bu blmde son olarak kullanc tanml bir tipin(User Defined


Type) WCF servisinden JSON formatnda dndrld ve AJAX uyumlu bir istemci tarafndan
ele alnd rnek gelitirilmeye allmaktadr. Burada servis
operasyonunun JSON formatnda cevap(Response) vermesi ve POST metoduna gre almas
iin WebInvokenitelii(attribute) ile imzalanm olmas gerekmektedir. stemci tarafnda ise
gelen cevabn ayrtrlmas ve kullanlmas ele alnmaktadr. lk olarak servis tarafnda kullanlacak
olan standart WCF servis ktphanesi gelitirilerek ie balanabilir. rnek ktphane ierisinde yer
alacak tipler aadaki gibidir.

Servis szlemesi(Service Contract), uygulayc snf ve veri szlemesi(Data


Contract) tiplerin ierii ise aadaki gibidir.

www.bsenyurt.com Page 463


Urun Snf;

using System;
using System.Runtime.Serialization;

namespace VeriServisKutuphanesi
{
[DataContract]
public class Urun
{
[DataMember]
public int Id;
[DataMember]
public string Ad;
[DataMember]
public double Fiyat;
}
}

Servis Szlemesi ve Uygulayc Tip;

using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Data.SqlClient;

namespace VeriServisKutuphanesi
{
[ServiceContract(Namespace="AdventureVeriHizmeti")]
public interface IVeriIslemleri
{
[OperationContract]
[WebInvoke(ResponseFormat = WebMessageFormat.Json)]
Urun UrunBul(int urunId);
}

public class VeriIslemleri


: IVeriIslemleri
{
#region IVeriIslemleri Members

public Urun UrunBul(int urunId)


{
Urun u = null;
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select ProductID,Name,ListPrice From
Production.Product Where ProductID=@ID", conn);
cmd.Parameters.AddWithValue("@ID", urunId);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
u = new Urun()

www.bsenyurt.com Page 464


{
Id=Convert.ToInt32(reader["ProductID"]),
Ad=reader["Name"].ToString(),
Fiyat=Convert.ToDouble(reader["ListPrice"])
};
}
}
return u;
}
#endregion
}
}

UrunBul isimli metoda WebInvoke nitelii uygulanmtr. Dikkat edilecei


zere ResponseFormat zelliine WebMessageFormat.Json deeri atanmtr. Bu atama,
metodun ktsnn istemcilere JSON formatnda gnderileceini belirtmektedir. UrunBul isimli
metod parametre olarak ald urunId deerine gre Product tablosundan ektii satr baz
alarak Urun tipinde bir nesne rnei oluturup dndrmektedir. Servis taraf yine IIS(Internet
Information Services) zerinde konulandrlm olarak tasarlanmaldr. Bu
amala WCF Service ablonunda bir uygulama alarak devam edilebilir. Sz konusu uygulama
ok doal olarak VeriServisKutuphanesi.dll' ini referans etmelidir. Bununla
birlikteService.svc dosyasnn ierii aadaki gibi tasarlanabilir.

<%@ ServiceHost Language="C#"


Debug="true" Service="VeriServisKutuphanesi.VeriIslemleri" %>

rnekte AJAX uyumlu EndPoint noktas Web.config dosyas ierisinde tanmlanmaktadr.


Web.config dosyasnda yer alan serviceModel elementinin ierii aadaki gibidir.

<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="AjaxEndPointBehavior">
<enableWebScript />
</behavior>
</endpointBehaviors>
</behaviors>
<services>
<service name="VeriServisKutuphanesi.VeriIslemleri">
<endpoint
address="http://localhost/AjaxServiceDemo2/Service.svc" behaviorConfiguration="Aja
xEndPointBehavior" binding="webHttpBinding" bindingConfiguration=""
name="AjaxEndPoint" contract="VeriServisKutuphanesi.IVeriIslemleri" />
</service>
</services>
</system.serviceModel>

Gelelim istemci tarafndaki uygulamamza. Bu sefer ilk rnekten farkl


olarak ScriptManager kullanmadan WCF Servis operasyonunu arlmaktadr. Bu amala
gelitirien Asp.Net Web uygulamasnda yer alacak olan aspx sayfasnn ierii aadaki gibi
gelitirilebilir.

www.bsenyurt.com Page 465


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script type="text/javascript">

function Getir()
{
var productId = document.getElementById("txtProductId").value;

if(productId)
{
var xmlHttp;
try
{
xmlHttp = new XMLHttpRequest();
}
catch (e)
{
try
{
xmlHttp = new ActiveXObject("Msxml2.XMLHTTP");
}
catch (e)
{
try
{
xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
}
catch (e)
{
alert("Taraycda AJAX destei yok.");
return false;
}
}
}

xmlHttp.onreadystatechange=function()
{
if(xmlHttp.readyState == 4)
{
var sonuc = eval("(" + xmlHttp.responseText + " )").d;

www.bsenyurt.com Page 466


document.getElementById("txtId").value = sonuc.Id;
document.getElementById("txtName").value = sonuc.Ad;
document.getElementById("txtListPrice").value = sonuc.Fiyat;
}
}

var url = "http://localhost/AjaxServiceDemo2/service.svc/UrunBul";

var mesajGovde = '{"urunId":'+


document.getElementById("txtProductId").value + '}';

xmlHttp.open("POST", url, true);


xmlHttp.setRequestHeader("Content-type", "application/json");
xmlHttp.send(mesajGovde);
}
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
rn Numaras : <asp:TextBox ID="txtProductId" runat="server" />
<input type="button" onclick="return Getir();" value="Getir" />
<br />
<br />
<table>
<tr>
<td>Urun Id</td>
<td><input id="txtId" type="text" /></td>
</tr>
<tr>
<td>Ad</td>
<td><input id="txtName" type="text" /></td>
</tr>
<tr>
<td>Fiyat</td>
<td><input id="txtListPrice" type="text" /></td>
</tr>
</table>
</div>
</form>
</body>
</html>

stemci tarafnda klasik olarak AJAX uyumlu Javascript kodlar yer almaktadr. nemli olan
noktalardan bir tanesi, xmlHttp isimli nesnesinin rneklenmesinden sonra open metodu
ile WCFservisine doru yaplan ardr. Dikkat edilecek olursa WebInvoke nitelii nedeni
ile http://localhost/AjaxServiceDemo2/Service.svc/UrunBul isimli bir URL bilgisi
kullanlmaktadr. Dier taraftan istemciden servis operasyonuna doru gnderilecek
olan talebin(Request) balk ksmnn ieriinin JSON olaca setRequestHeader metodu ile
belirlenmektedir. Sonrasnda send metodu ile ilgili paket WCF servisine gnderilmektedir. lem

www.bsenyurt.com Page 467


tamamlandnda devreye giren fonksiyon ierisinde responseText zelliinden de yararlanlarak
dnen cevap alnmakta ve sayfa zerindeki ilgili bileenlere gelen deerler aktarlmaktadr.
Burada d isimli zellik yardmyla aslnda Urun tipinin verisine ulalabilmektedir. Bunu daha iyi
grebilmek iin ilgili kodlar debug edilerek QuickWatch ktsna baklabilir.

Dikkat edilecek olursa dnen cevap ierisinde Urun nesne rnei d isimli bir deiken olarak
gelmektedir. Bu deiken zerinden Ad, Fiyat ve Id isimli alanlarada eriilebilmektedir. alma
zamannda(Runtime) F11 ile step into modunda hareket edildiinde istemci tarafna aadaki
ekran grntsnde yer alan bir ieriin geldii grlr.

te bu bilgiden yararlanlarak gelitirilen istemcide Getir balkl dmeye basldnda aadaki


ekran grnts elde edilecektir.

www.bsenyurt.com Page 468


Elbette burada gzden karlmamas gereken baz noktalar vardr. ncelikli olarak veri ieriin
istemciye Null gelme olasl vardr. Bu da ok doal olarak alma zaman hatalarnn olumas
anlamna gelmektedir. Bu gibi noktalar elbetteki gerek bir uygulamada mutlaka ele alnmaldr.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde ksaca WCF servis
uygulamalarnn AJAX destekli olacak ekilde nasl gelitirilebildiklerini incelemeye altk. Burada
nemli olan JSON veri format ile ilikin olaraktanda .Net Framework 3.5 ile
gelen DataContractJsonSerializer tipini inceleme frsat bulduk. Son olarakta JSON formatnda
ierik sunan bir WCF servisinin AJAX tabanl bir istemci ile nasl arlabileceini inceledik. Bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Web Bazl Programlama Modeli ( 14.02.2008 ) -


WCF
Deerli Okurlarm Merhabalar,

Web programlama modelinin en byk avantajlarndan biriside istemci(Client) tarafndaki


uygulamalar dnmeye gerek kalmadan istemci-sunucu(Client/Server) mimarisine uygun
sistemler gelitirilebilmesidir. Basit olarak HTTP protokolnn farkl metodlarna gre ileyen bu
sistemde, istemcilerin farkl tipte olabilecek tarayc programlar(Browsers)zerinden talepte
bulunmalar sz konusudur. zellikle servis ynelimi mimari(Serivce Oriented
Architecture) yaklamlarna bakldnda rnein Xml Web Servislerinde(Xml Web
Services) HTTP protokolnn basit GET metoduna gre taleplerde(Requests)
bulunulabilmektedir. Bu istemci tarafna bir proxy nesnesi koymadan servis
fonksiyonelliklerini HTTP protokolnn basit bir metoduna gre arabilme anlamnada
gelmektedir. (Bununla birlikte Web servislerinde SOAP(Simple Object Access
Protocol)protokolne uygun olacak ekilde proxy kullanmadan talepte bulunulup cevap
alnabileceide bilinmektedir.)

Hal byle olunca WCF(Windows Communication Foundation) gibi gelimi bir datk
mimari(Distributed Architecture) modelinde Web bazl servis destei olmamas dnlemez.
Ne varki WCF, zellikle .Net Framework 3.5 ile gelen yeni tipler sayesinde Web bazl

www.bsenyurt.com Page 469


programlama modeli(Web-Based Programming Model) yeteneklerine kavumutur. Bu model
temel olarak SOAP bazl olmayan EndPoint noktalarnn tasarlanabilmesini salamaktadr. Bu
sayede bir WCF servisi istemci tarafn programlamaya gerek kalmadan, basit tarayc arayzleri
sayesinde hizmet verebilmektedir.(Tabi burada POST benzeri metodlarda istisnai baz durumlar
olabileceide gz ard edilmemelidir). stelik web programlama modelinin doas gerei istemciler
servis zerindeki fonksiyonellikleri kullanrken queryString tarznda
parametrik taleplerde(Requests) de bulunabilirler. Web programlama modelinde salanmas
gereken nemli baz hususlar vardr. Buna gre;

Modelin URI(Uniform Resource Identifier) destei olmaldr. Bu destek sz konusu


servis operasyonlarnn istemci tarafna parametrik olabilecek ablonlara(template) uyan
adresler ile sunulabilmesi iin gereklidir.
HTTP protokolnn farkl metodlar iin destek olmaldr. Gnmzde en ok
kullanlanlar GET ve POST metodlardr. Sadece istemci tarafna veri alma gibi ilemler sz
konusu olduunda GET metodu, tam tersine servis tarafna parametreler gnderip
dzenleme, veri aktarma yada operasyon arma gibi ilemler sz konusu olduunda
POST,PUT gibi metodlar kullanlr.
Farkl tipte veri formatlarna destek olmaldr(Multiple Data Format Support). Bu destek
sayesinde XML(eXtensible Markup Lanugage), JSON(JavaScript Object
Notation), binary ierikli stream (video, resim, ses dosyas gibi), dz metin(Plain
Text) bazl veriler kullanlabilmektedir.

WCF Web programlama modeli, servislerin REST(REpresentational State


Transefer) tipinde gelitirilebilmesini salamaktadr. REST, www(World Wide
Web) gibi sistemlerin prensiplerini referans etmektedir. Bu prensipler basit olarak
bir network mimarisinin kaynaklar nasl adresleyecei ve ne ekilde tanmlayacan
belirtmektedir. Detayl bilgi iin Wikipedia

Tahmin edilecei zere WCF mimarisi .Net Framework 3.5 ile gelen tipler sayesinde bu temel
zelliede destek verecek ekilde geniletilmitir. WCF mimarisindeki bu yeni genilemede rol alan
balca tipler(Types) aadaki ekilde grld gibi ele alnabilirler.

www.bsenyurt.com Page 470


HTTP zerinden GET, POST, PUT gibi metodlar ile gelen arlar ynetimli kod(Managed
Code) tarafnda ele almak iin WebGetAttribute ve WebInvokeAttribute
nitelik(attribute)snflarndan yararlanlmaktadr. Bu nitelikler temel olarak,
operasyonlarn URI bilgilerine nasl balanacan ve hangi HTTP metodlar ile eletirileceini
belirlemekte kullanlrlar. WebGetAttribute nitelii GET operasyonlar iin ele
alnrken, WebInvokeAttribute POST, DELETE, PUT gibi operasyonlarn kullanmn
salamaktadr.

HTTP zerinden POST, GET, PUT, DELETE metodlar kullanlr. Bu metodlarn ileyi
ekli ou zaman CRUD tablosunda aadaki gibi ifade edilir.

HTTP CRUD

POST Create, Update, Delete

GET Read

DELETE Delete

PUT Create, Update

WebGetAttribute snnn drt nemli zellii(property) vardr. WebMessageBodyStyle enum


sabiti tipinden olan BodyStyle zellii yardmyla parametre ve dn
deerlerinin XML elementleri ieriine sarmalanp(wrap) sarmalanmayacana karar
verilir. WebMessageBodyStyle enum sabitinin ierdii
deerler Bare, WrappedRequest,WrappedResponse ve Wrapped' dr. Bare deerine
gre talep(request) ve cevap(response) mesajlarndaki veriler
sarmalanmazlar. Wrapped deerine gre her iki haldede
sarmalanrlar. WrappedRequest deerine gre sadece taleplerin
sarmalanmas, WrappedResponse deerine gre ise sadece cevaplarn sarmalanmas sz
konusudur. WebGetAttribute snfnn dier
zellikleri RequestFormat, ResponseFormat ve UriTemplate yeleridir.

RequestFormat ve ResponseFormat zellikleri WebMessageFormat enum sabiti tipinden


deerler almaktadr. WebMessageFormat enum sabitinin deerleri XML veya JSON(JavaScript
Object Notation) olabilir. Bir baka deyile cevaplarn ve taleplerin hangi formatta
oluturulacana karar verilir. WebGetAttribute snfnn belkide en nemli
yesideUriTemplate zelliidir. Bu zellie atanan deer ile GET arm iin
bir URI ablonu(template) belirlenmi
olur. WebInvokeAttribute snfda WebGetAttribute snf ile ayn zelliklere sahiptir. Nitekim
birde ek zellii vardr ki buda Method isimli yedir. Method zellii string bazldr
ve POST, DELETE yada PUT gibi HTTP metodlarn gstermektedir. Bu zelliin varsaylan
deeri POST olarak belirlenmitir.

Web programlama modelinde yer alan nemli tiplerden bir dieride WebHttpBinding snfdr.
Bu balayc tip(Binding Type) ile servis EndPoint noktalarnn, SOAP bazl mesajlama
yerine POX(Plain Old Xml) bazl mesajlamaya izin verecek ekilde almas salanmaktadr.
Buna gre Web bazl EndPoint(Web-Based EndPoint) noktalarnn POX(Plain Old XML) bazl
mesajlama yapt sylenebilir. Dier taraftan bu balayc tip XML,JSON ve anlalmas
g binary tipteki(ounlukla video, resim gibi) verilerin okunmas ve yazlmas amacyla
kullanlmaktadr.

WCF Web programlama modeli SOAP(Simple Object Access Protocol) bazl


mesajlamay kullanmadndan WS-* protokollerini desteklemez. Ancak WCF
mimarisinin ayn servis zerinde birden fazla EndPoint konulandrabilme zellii nedeni

www.bsenyurt.com Page 471


ile SOAP destekli olan ve olmayan EndPoint noktalarnn bir arada kullanlmas
mmkndr. Bir baka deyile bir servisin ilgili operasyonlar WS-* destekli olacak
ekilde bir EndPoint zerinden sunulurken, ayn servis zerindeki dier
bir EndPoint Web programlama modelini ele alabilir.

WebServiceHost snf SOAP bazl olmayan web stilindeki servislerin host edilmesi
iin ServiceHost tipinden tretilmitir. Eer servisi host eden uygulamada
altrlanWebServiceHost nesne rnei, Web bazl herhangibir EndPoint bulamassa otomatik
olarak bir tane retecektir. Bu retim srasnda servis adresini(Base Address) baz alan
birEndPoint noktas oluturulur.

Web programlama modelinde yer alan yardmc tiplerden UriTemplate ve UriTemplateTable son
derece nemli grevler stlenmektedir. Hereyden nce HTTP bazl talepler servis operasyonlarna
ulatklarnda bir URI tarafndan karlanmaldr. Bu URI bilgilerinin ynetimli kod (Managed
Code) tarafnda ifade edilmesinde sz konusu tipler grev almaktadr. URI ablonlar(URI
Templates) temelde path ve query olmak zere iki temel paradan oluurlar. Sz gelimi
aadaki ekilde baz rnek URI ablonlar yer almaktadr.

Burada sol taraftaki kutucukta gerek kullanmlar yer alrken sa taraftada karlk
gelen URI ablonlar grlmektedir. Ssl parantezler ierisinde yer alan ksmlar deiken olmakla
birlikte dier ksmlar sabittir. Elbette bu URI' lerin banda birde base URI address bilgisi
gelmektedir. UriTemplate sayesinde bir URI ablonunun kolay bir ekilde oluturulmas, var olan
bir gerek URL adresi ile eletirilmesi(Match) gibi ilemler yaplabilir. UriTemplate tipi
ounlukla WebGetAttribute yada WebInvokeAttribute nitelikleri ile kullanlr. ok doal olarak
bir servisin sunabilecei birden fazla URI ablonu ve dolaysyla UriTemplate nesnesi sz konusu
olabilir. Birden fazla UriTemplate tipinin bir arada daha kolay ynetebilmek
iinde UriTemplateTable isimli snf kullanlmaktadr. Bu iki tipin kullanm nem arz ettii iin
basit bir Console uygulmas zerinde fonksiyonelliklerini incelemekte yarar vardr. Bu
amala Visual Studio 2008 ortamnda .Net Framework 3.5 ablonunda bir Console uygulamas
atmz ve System.ServiceModel.Web.dll assembly' n ilgili projeye referans ettiimizi
dnelim. Bu assembly tahmin edilecei zere Web programlama modeli iin gerekli temel tipleri
bnyesinde barndrmaktadr. Aadaki kod paras basit olarak UriTemplate tipinin kullanmn
rneklemektedir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Web;
using System.Collections.Specialized;

namespace YardimciTipler
{
class Program

www.bsenyurt.com Page 472


{
static void Main(string[] args)
{
#region UriTemplate Kullanm

// Yeni bir URI ablonu oluturulurken ssl parantezler ierisinde yer alan verilen
deiken dierleri ise sabittir.
UriTemplate uriTemp = new
UriTemplate("satislar/{sehirAdi}/{ilceAdi}?tarih={satisTarihi}");

// deikenlerin pozisyonuna gre balama


// Bu metod ile ssl parantezler ierisine gelecek veriler sral olarak eklenirler
Uri uri1 = uriTemp.BindByPosition(new Uri("http://localhost"), "Istanbul",
"Kadky", "2007");

// deikenlerin adlarna gre balama


// Bu metodda parametre ad - deeri eletirmesi bilgilerini tayan NameValueCollection
koleksiyonu kullanlr.
NameValueCollection values = new NameValueCollection()
{
{"sehirAdi","Ankara"}
,{"ilceAdi","Esenboa"}
,{"satisTarihi","2007"}
};
Uri uri2 = uriTemp.BindByName(new
Uri("http://www.bsenyurt.com/servisler"), values);

// Eletirme yapmak ve doruluunu tespit etmek


Uri uri3 = new Uri("http://localhost/satislar/Istanbul/Besiktas?tarih=2008");
// Eer Match metodu geriye null deer dndrmemise URI ierii ablonda belirtilene
uygundur.
UriTemplateMatch match=uriTemp.Match(new Uri("http://localhost/"), uri3);
if (match != null)
Console.WriteLine("Match geerlidir");

#endregion
}
}
}

rnektende grld zere bir UriTemplate nesnesi rneklendiinde ounlukla


bir URI ablonuda tanmlar. Sonrasnda bu ablonda yer alan parametrelere deer aktarm
iin BindByPosition yada BindByName gibi metodlar kullanlabilir. Dier taraftan
bir URI bilgisinin, UriTemplate ile belirtilen ablona uygunluunu denetlemek
iin Match metodundan yararlanlabilir. (BindByName metodunun uygulan srasnda C# 3.0
object initializers zelliinden yararlanldnada dikkat edelim.) Dier taraftan aadaki kod
parasnda da basit olarak UriTemplateTable kullanm rneklenmektedir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel.Web;
using System.Collections.Specialized;

namespace YardimciTipler

www.bsenyurt.com Page 473


{
class Program
{
static void Main(string[] args)
{
#region UriTemplateTable Kullanm

// UriTemplateTable yardmyla birden fazla UriTemplate' in tek saklanmas ve bir arada


tutulmas salanabilir.
UriTemplateTable uriTable = new UriTemplateTable(new
Uri("http://localhost"));

// UriTemplate' ler tamam KeyValuePairs zellii ile iaret edilen koleksiyonda tutulurlar.
uriTable.KeyValuePairs.Add(new KeyValuePair<UriTemplate, object>(new
UriTemplate("satislar/{Sehir}/{Ilce}"), "IlceBazli"));
uriTable.KeyValuePairs.Add(new KeyValuePair<UriTemplate,object>(new
UriTemplate("satislar/{Sehir}/{Ilce}?tarih={SatisTarihi}"),"SatisBazli"));
uriTable.KeyValuePairs.Add(new KeyValuePair<UriTemplate,object>(new
UriTemplate("satislar/{Sehir}/{Ilce}?yetkili={Yetkili}"),"YetkiliBazl"));
uriTable.KeyValuePairs.Add(new KeyValuePair<UriTemplate, object>(new
UriTemplate("satislar/*"), "TumSatislar"));

foreach (KeyValuePair<UriTemplate, object> kv in uriTable.KeyValuePairs)


{
Console.WriteLine("{0} : \t {1}", kv.Value, kv.Key);
}
#endregion
}
}
}

UriTemplateTable snf UriTemplate rneklerini KeyValuePairs isimli zelliin iaret ettii


koleksiyonda saklamaktadr. Yukardaki kod parasna alma zamanndadebug modda
bakldnda uriTable isimli deikenin ieriinin aadaki gibi olduu grlebilir.

Web stilinde tasarlanan servisler bir tarayc uygulama yardmyla URL baznda arlabilirler. URL
zerinden servis tarafna gelecek olan web bazl taleplerde kullanlan parametrelerinin veri
formatlarda nemlidir. Bunlar ayn zamanda arlan operasyonlarn geri dndrd deer tipleri
iinde nemlidir. Kullanlabilecek veri formatlar

Byte

www.bsenyurt.com Page 474


SByte
Int16
Int32
Int64
UInt16
UInt32
UInt64
Single
Double
Char
Decimal
Boolean
String
DateTime
TimeSpan
Guid
DateTimeOffset
Enums
TypeConverterAttribute niteliini uygulayan

tipler olabilir.

WCF Web programlama modelinde dikkat edilmesi gereken noktalardan


biriside gvenlik(Security) dir. Bu modele gre gvenlik sadece HTTPS eklinde
yaniiletiim(transport) seviyesinde salanabilir. Bunun nedeni Web tabanl WCF
modelinin SOAP zarflarn(Envelope) kullanmaydr. Normal artlarda mesaj
seviyesinde(Message Level Security) gvenlik uygulandnda gvenlik ile ilikili baz
bilgiler SOAP zarflarnda yer alan balk(Header) ksmna yazlr. Oysaki web bazl
modelde bu tip bir alan yoktur. Dolaysyla sadece iletiim seviyesinde gvenlik
uygulanabilmektedir.

Artk Web bazl rnek bir servis gelitirerek devam edebiliriz. lk olarak servis
szlemesini(Service Contract) ve uygulayc tipi barndracak olan WCF servis
ktphanesini(WCF Service Library) gelitirmekte yarar vardr. Sz konusu ktphanenin Web
tabanl model tiplerini kullanabilmesi iin doal olarakSystem.ServiceModel.Web.dll assembly'
n referans etmesi gerekmektedir. Sz konusu ktphanedeki tiplerin aadaki gibi tasarland
varsaylabilir.

www.bsenyurt.com Page 475


IUrunHizmetleri isimli servis szlemesi int, double, DataSet, Urun tipinden deerler dndren
operasyonlar tanmlamaktadr. Ayn zamanda WebInvoke niteliinin(attribute)kullanmn
rneklemek amacyla deer dnrmeyen bir operasyon daha tanmlamaktadr. UrunCek isimli
operasyon geriye Urun tipinden bir nesne rnei dndrmektedir. Urun snfnn ierii aadaki
gibidir.

[DataContract]
public class Urun
{
[DataMember]
public int Id;
[DataMember]
public string Name;
[DataMember]
public double ListPrice;
}

Urun snf basit olarak Product tablsoundaki belirli bir satrn ProductId,Name ve ListPrice
alanlarnn deerlerini tamak zere tasarlanmtr. ok doal olarak Urun nesne
rnei serileme(Serialization) ilemine tabi
tutulacandan DataContract ve DataMember nitelikleri(attributes) ile imzalanmtr. Bir baka
deyile bir veri szlemesi(Data Contract) tanmlanmaktadr. Servis szlemesini(Service
Contract) tayan IUrunHizmetleri arayznn(Interface) ierii ise aadaki gibidir.

[ServiceContract]
public interface IUrunHizmetleri

www.bsenyurt.com Page 476


{
[OperationContract]
[WebGet(UriTemplate="urunler/{altkategoriId}")]
DataSet UrunListesi(string altKategoriId);

[OperationContract]
[WebGet]
Urun UrunCek(int urunId);

[OperationContract]
[WebInvoke(UriTemplate="guncelle?sinifi={sinifi}&altKategori={altKategoriId}")]
void UrunGuncelle(string sinifi, int altKategoriId);

[OperationContract]
[WebGet(UriTemplate="toplamaIslemi?sayi1={x}&sayi2={y}")]
int Toplam(int x, int y);

[OperationContract]
[WebGet(UriTemplate="toplam?kategori={altKategoriId}")]
double ToplamFiyat(int altKategoriId);
}

UrunListesi isimli operasyon geriye DataSet dndrmektedir. Bu DataSet ierii rnlerin alt
kategori deerine gre elde edilmektedir. Sz konusu operasyon HTTP GET metoduna gre talep
edilebilir. Dikkat edilecei zere WebGet niteliinin UriTemplate zelliinde ssl parantezler
ierisinde metod parametresi ile ayn isimde olacak ekilde bir tanmlama yaplmaktadr. UrunCek
operasyonu geriye Urun tipinden bir nesne rnei dndrmekle birlikte urunId deeri queryString
zerinden alnmaktadr. WebGet niteliinde UriTemplate kullanlmamas nedeniyle
talepte UrunCek?urunId=1 gibi bir adres kullanlmaldr. Bir baka
deyile WebGet niteliinde UriTemplate kullanlmad
durumlarda, MetodAd?parametreAd1=deeri1&parametreAd2=deeri2 tarz adresler ile
talepte bulunulabilinir. UrunGuncelle isimli operasyon, ierisinde sinifi ve altKategori queryString
parametrelerini bulunduran adres taleplerine HTTP POST metoduna gre cevap verecek ekilde
tanmlanmaktadr. Bu sebepten dolay URL satrndan bir bilgi gnderilmesine gerek yoktur.
Toplam operasyonu URI bilgisi ierisinde birden fazla queryString parametresini ele alp basit bir
veri tipini geriye dndrecek ekilde tasarlanmtr. Benzer ekilde ToplamFiyat operasyonuda
belirli bir alt kategerideki rnlerin toplam liste fiyat deerini bulacak bir fonksiyonellii
tanmlamaktadr. Sz konusu servis szlemesini(Service Contract) uygulayan snfn ierii ise
aadaki gibidir.

public class UrunHizmetleri


: IUrunHizmetleri
{
string conStr = "data source=.;database=AdventureWorks;integrated security=SSPI";
#region IUrunHizmetleri Members

public DataSet UrunListesi(string altKategoriId)


{
DataSet set = null;
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand("Select
ProductId,Name,ListPrice,ProductSubCategoryId,Class,SellStartDate From Production.Product
Where ProductSubCategoryId=@SubCatId", conn);
cmd.Parameters.AddWithValue("@SubCatId", altKategoriId);
SqlDataAdapter adapter = new SqlDataAdapter(cmd);

www.bsenyurt.com Page 477


set = new DataSet();
adapter.Fill(set);
}
return set;
}

public Urun UrunCek(int urunId)


{
Urun u = null;
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand("Select ProductId,Name,ListPrice From
Production.Product Where ProductId=@PrdId", conn);
cmd.Parameters.AddWithValue("@PrdId", urunId);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
u = new Urun()
{
Id=urunId
,Name=reader["Name"].ToString()
, ListPrice=Convert.ToDouble(reader["ListPrice"])
};
}
reader.Close();
}
return u;
}

public void UrunGuncelle(string sinifi, int altKategoriId)


{
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand("Update Production.Product Set
ListPrice=ListPrice+1 Where Class=@Class and ProductSubCategoryId=@SubCatId", conn);
cmd.Parameters.AddWithValue("@Class", sinifi);
cmd.Parameters.AddWithValue("@SubCatId", altKategoriId);
conn.Open();
cmd.ExecuteNonQuery();
}
}

public int Toplam(int x, int y)


{
return x + y;
}

public double ToplamFiyat(int altKategoriId)


{
double result = 0;
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand("Select Sum(ListPrice) From Production.Product
Where ProductSubCategoryId=@SubCatId", conn);
cmd.Parameters.AddWithValue("@SubCatId", altKategoriId);

www.bsenyurt.com Page 478


conn.Open();
result =Convert.ToDouble(cmd.ExecuteScalar());
}
return result;
}

#endregion
}

UrunHizmetleri isimli snf ierisinde yer alan operasyon uyarlamalarnn


ou AdventureWorks veritabannda yer alan Production.Product tablosu zerinden
almaktadr. Dn tipleri iin nemli olan serileebilmeleridir. imdi bu servis ktphanesini
sunacak olan basit bir host uygulama yazlabilir. Bu amala bir Console projesi gz nne
alnabilir. Sunucu uygulamann System.ServiceModel.Web.dll, System.ServiceModel.dll
assembly' lar haricinde servis szlemesini(Service Contract) ve uygulayc tipi barndran
ktphaneyide(WCF Service Library) referans etmesi gerekmektedir. Bu ilemlerin ardndan Host
uygulama kodlar aadaki gibi gelitirilebilir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UrunLib;
using System.ServiceModel.Web;
using System.ServiceModel;
using System.ServiceModel.Description;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
WebServiceHost host = new WebServiceHost(typeof(UrunHizmetleri), new
Uri("http://localhost:60001/"));
ServiceEndpoint ep=host.AddServiceEndpoint(typeof(IUrunHizmetleri), new
WebHttpBinding(), "");

host.Opened += delegate(object sender, EventArgs e)


{
Console.WriteLine("Servis ak");
};
host.Closed += delegate(object sender, EventArgs e)
{
Console.WriteLine("Servis kapatld");
};

host.Open();

Console.WriteLine("Kapatmak iin bir tua basn");


Console.ReadLine();
host.Close();
}
}
}

www.bsenyurt.com Page 479


lk olarak bir adet WebServiceHost nesnesi rneklenmektedir. WebServiceHost snfnn yapc
metoduna(Constructor) parametre olarak szlemeyi uygulayan snf tipi(Class Type) ve
yaynlanaca adres bilgisi verilmektedir. Sonrasnda zorunlu olmamakla
birlikte WebHttpBinding balayc tipini barndran bir EndPoint host isimli WebServiceHost
nesne rneine eklenmektedir. Dier EndPoint tanmlamalarnda olduu gibi nce servis
szlemesi(Service Contract), sonrasnda balayc tip(Binding Type) bildirilir. Servis
adresi(Service Address) ise zaten host nesnesi rneklenirken tanmland iin bo geilebilir. Bu
ilemlerin ardndan servis Open metodu ile alr. Eer yazlan kodlarda herhangibir aksilik yoksa
uygulamann alma zaman grnts aadakine benzer olmaldr.

Artk HTTP GET metodu bazl taleplerde bulunulabiliriz. Sz konusu talepleri(Request) basit
bir tarayc(Browser) uygulamas yardmyla gerekletirmek mmkndr. Elbette
istemcilerin cevap(Response) alabilmeleri iin Host uygulamannda alyor olmas arttr.
Aada sz konuzu operasyon arlar ve ekran grntleri yer almaktadr.

Toplama ilemi iin yaplan ar ;


http://localhost:60001/ToplamaIslemi?sayi1=4&sayi2=6 (4 ve 6 saylarnn toplam geriye
dndrlmektedir)

UrunListesi operasyonu iin yaplan ar ; http://localhost:60001/urunler/1 (1 numaral


ProductSubCategoryId deerine sahip rnlerin DataSet ierisinde toplanm listesini verir)

www.bsenyurt.com Page 480


UrunCek isimli metoda yaplan ar
; http://localhost:60001/UrunCek?urunId=1 (ProductId alan deeri 1 olan Product tablosu
satrnn ierii Urun tipine gre ekilir)

ToplamFiyat operasyonu iin yaplan ar


; http://localhost:60001/toplam?kategori=1 (ProductSubCategoryId deeri 1 olan rnlerin
ListPrice alanlarnn toplam elde edilir.)

www.bsenyurt.com Page 481


Tabi sunucunun almamas halinde gelecek olan istemci taleplerinde aadaki gibi ekran
grntleri ile karlalabilir.

Grld gibi URL bazl olacak ekilde servis operasyonlar arlabilmekte ve sonular
alnabilmektedir. Gelelim UrunGuncelle isimli metodun test edilmesine. Bu operasyon bir istemci
uygulama zerinden test edilebilir. POST metoduna gre bir talepte bulunulacandan
istemcinin servis szlemesini(Service Contract) varsa veri szlemesini(Data
Contract) bilmesi gerekmektedir. Bunlarn dndan istemci
uygulamann System.ServiceModel.dll, System.Runtime.Serialization.dll(3.0
versiyonu) ve System.ServiceModel.Web.dllassembly' larn referans etmesi gerekmektedir.
Bu amala hazrlanan rnek istemci bir Console uygulamas olarak tasarlanabilir. Sz konusu
uygulamann kodlar ise aadaki gibidir.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
using System.Data;
using System.ServiceModel.Web;
using System.Runtime.Serialization;

namespace Istemci
{
[DataContract]

www.bsenyurt.com Page 482


public class Urun
{
[DataMember]
public int Id;
[DataMember]
public string Name;
[DataMember]
public double ListPrice;
}

[ServiceContract]
public interface IUrunHizmetleri
{
[OperationContract]
[WebGet(UriTemplate = "urunler/{altkategoriId}")]
DataSet UrunListesi(string altKategoriId);

[OperationContract]
[WebGet]
Urun UrunCek(int urunId);

[OperationContract]
[WebInvoke(UriTemplate = "guncelle?sinifi={sinifi}&altKategori={altKategoriId}")]
void UrunGuncelle(string sinifi, int altKategoriId);

[OperationContract]
[WebGet(UriTemplate = "toplamaIslemi?sayi1={x}&sayi2={y}")]
int Toplam(int x, int y);

[OperationContract]
[WebGet(UriTemplate = "toplam?kategori={altKategoriId}")]
double ToplamFiyat(int altKategoriId);
}

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Balatmak iin bir tua basn");
Console.ReadLine();
using (WebChannelFactory<IUrunHizmetleri> cf = new
WebChannelFactory<IUrunHizmetleri>(new Uri("http://localhost:60001")))
{
IUrunHizmetleri hiz=cf.CreateChannel();
hiz.UrunGuncelle("M", 1);
}
}
}
}

lk olarak WebChannelFactory generic tipinden bir nesne rneklenmektedir. Burada generic tip
olarak servis szlemesi kullanlmaldr. Dikkat edilecek olursa parametre olarak servisin host
edildii URL adresi verilmekedir. Sonrasnda yaplan metod ars HTTP POST tekniine gre
sunucuya ulaacak ve operasyon sonulandrlacaktr. nce sunucu sonrasnda ise istemci
altrlrsa istemci uygulama baarl bir ekilde yrtlecek
ve Class deeri M, ProductSubCategoryID deeri 1 olan Product tablosu

www.bsenyurt.com Page 483


satrlarnnListPrice deerlerinin 1 birim arttrld grlecektir. Tahmin edilecei gibi istemci
tarafnda yaplan bu metod ars, sunucuya HTTP protokolnn POST metoduna gre
ulaacaktr. Metod ierisinde kullanlan parametre deerleride servis tarafna vardklarnda aynen
alnp deerlendirilebilecektir. Eer sunucu almyorken istemci altrlrsa alma
zamannda EndPointNotFoundException snf tipinden bir istisna(Exception) alnd
grlebilir.

Buraya kadar ilenenler gz nne alndnda, istemcilerin HTTP zerinden GET,POST, PUT,
DELETE gibi metodlar kullanarak WCF operasyonlarn talep(Request) edebilecei
grlmtr. Host uygulama test olmas asndan Console olarak tasarlanm olmakla
birlikte IIS(Internet Information Service) zerindede konulandrlabilir. Bu tip bir
durumda svc uzantl servis dosyasnda yer
alan Service direktifinde Factory isimli nitelii(attribute) kullanmak
ve System.ServiceModel.Activation.WebServiceFactory deerini atamak yeterlidir. Bylece
geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Mesaj Szlemeleri(Message Contracts) (


09.02.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Servis tabanl uygulamalarda en nemli noktalardan biriside aradaki bilgi transferlerinin nasl ve ne
ekilde gerekletirildiidir. Gerek uki, bu bilgi transferinin oluma ekli ou zaman gelitiricinin
gznden kaan yada ok fazla ilgilenmedii bir konu olmaktadr. Nitekim ou servis gelitirme
arac buradaki sz konusu ieriin hazrlanmasn , gnderilmesini veya alnmasn
otomatikletirmektedir. zellikle Windows Communication Foundation tarafnda, bilginin
istemci ve servis arasndaki dolamnda balayc tiplerin(Binding Type) seilmesi ile zaten
arka tarafta ne ekilde bir haberleme olaca ve paketlerin nasl hazrlanaca belirlenmi olur.
Aslnda servis ve istemci tarafnda mesaj bazl bir iletiim olduu son derece aktr. Farkl
platformlar zerinde koan servislerin haberlemeleri yada farkl tipteki istemci uygulamalarn
servisleri kullanabilmeleri gerektiinde ise, aradaki haberlemenin bir standart zerinde ve esnek
olmas beklenir. Bu nedenle zellikle SOAP bazl web servisleri gz nne alndnda mesajn tipi
ve ieriide bellidir. te burada SOAP(Simpe Object Access Protocol) tarz mesajlardan sz
edilebilir. Tipik olarak SOAP mesajlar bir zarf olarak temsil edilmekte(SOAP
Envelope) veHeader, Body isimli iki paradan olumaktadr. Aadaki ekilde bu ierik temsil
edilmeye allmtr.

www.bsenyurt.com Page 484


Peki bu mesajlarn makalemize konu olmasnn sebebi nedir? Bilindii zere WCF mimarisinde
eitli tipte szlemeler(Contracts) sz konusudur. rnein servislerin ne i yaptnn, nasl
fonksiyonellikler sunduunun ifade edilmesinde Sevis Szlemeleri(Service
Contracts) kullanlmaktadr. Benzer ekilde istemci tarafna
aktarlacakseriletirilebilir(Serializable) tipler sz konusu ise Veri Szlemeleri(Data
Contracts) tanmlanr. Yine istemci tarafna aktarlacak istisna mesajlarnn eitli durumlar iin
zelletirilmesi dnldnde Hata Szlemeleri(Fault Contracts) kullanlr. Ancak bu
szleme eitleri dnda birde Mesaj Szlemeleri(Message Contracts) bulunmaktadr. te bu
yazmzn konusuda budur.

Yazmza servis odakl uygulamalarda mesajlarn yerini konumlandrmaya alarak baladk.


zellikle SOAP tabanl bu mesajlar gerektiinde zel olarak tasarlanabilirler. WCFtarafnda bunu
gerekletirebilmek iin Mesaj Szlemelerinden yararlanlr. Mesaj szlemelerinin ne zaman
kullanlacana karar verilmesi genellikle zordur. Farkl platformlar iin destek verebilme
imkan(Interoperability) ve mesaj kontrol ounlukla karar vermeyi kolaylatrmaktadr.
Gerektende servis tarafndan istemciye gnderilecek veya alnacak mesajlarn farkl platformlara
destek verebilecek ekilde tasarlanmas gerektii durumlarda zel Mesaj Szlemeleri gz nne
alnabilir. Dier taraftan Mesaj Szlemeleriile tanacak bilginin deiik
paralarnn SOAP paketinin Header veya Body ksmna ayrtrlmas ve bu sayede de, gerekli
olmayan paralarn mesaj ile birlikte tanmamas salanabilmektedir. Bu tam anlamyla aradaki
mesajlamann kontrol altna alnmas anlamna gelmektedir. Hatta, istemci ve servislerin belirli
olduu vakalarda, arada zel bir mesaj formatna gre veri ieriinin tanmasda mmkn olabilir.
Dier taraftan gz ard edilmemesi gereken bir noktada, mesaj seviyesinde gvenliktir. Mesaj
Szlemeleri kullanlrken bir tipin SOAP zarfnn ierisindeki yaylm belirlenebildii gibi(hangi
ksmlar Header' da olacak vb...) verinin ifrelenmeside(Encryption) zelletirilebilir. Bylece
vakaya gre bir mesaj deseninin oluturulmas ve kullanlmas mmkn olabilmektedir.

ou durumda Mesaj Szlemeleri yerine Veri Szlemelerininde ayn ii yapyor


olduu grlr. Ancak genel kanya gre, eer bir tip n sayda mesaj ierisinde
kullanlacaksa(yani reusable type olarak dnlebilirse) Veri Szlemesi olarak
tanmlanmas nerilmektedir.
Ancak tip(type) sadeceistek/cevap(Request/Respone) modeline gre bir kereliine
kullanlyorsa, Mesaj Szlemesi olacak ekilde tanmlanr.

Mesaj szlemelerinin uygulanmas son derece kolaydr. Ancak dikkat edilmesi gereken noktalar
vardr. Hereyden
nce MessageContract, MessageHeader, MessageBodyMember,MessageHeaderArray gibi n
iteliklerinden(attributes) yararlanlarak Mesaj Szlemesi tanmlanabilmektedir. Bununla
birlikte servis operasyonlarnda Mesaj Szlemelerinin kullanlmas sz konusu ise metod
yapsnda uyulmas gereken kurallar vardr. Buna gre metod desenleri aadaki rnekler olduu
gibi olmaldr. Bu tablodaki rnek kullanmlarda yer

www.bsenyurt.com Page 485


alan ProductOrderResponse ve ProductOrderRequest isimli tipler rnek Mesaj Szlemesi
snflardr.

Geerli Mesaj Szleme Kullanmlar


[OperationContract] Operasyonun dn tipi
ProductOrderResponse CompleteOrderProcess(ProductOrderReques ve parametresi Mesaj
trequest); Szlemesi tipindendir.
Operasyon parametre
almamakta ve Mesaj
[OperationContract]
Szlemesi tipinden
ProductOrderResponse CompleteOrderProcess();
referans
dndrmektedir.
Operasyon Mesaj
Szlemesi tipinden
[OperationContract]
parametre almakta ama
void CompleteOrderPrococes2(ProductOrderRequest request);
deer
dndrmemektedir.
Geersiz Mesaj Szleme Kullanmlar
Parametrenin Mesaj
Szlemesi olduu
durumlarda dn tipi
[OperationContract]
olarak Mesaj Szlemesi
int CompleteOrderProcess(ProductOrderRequest request);
harici bir tip
kullanlamaz. Exception
retir.
Birden fazla Mesaj
[OperationContract]
Szlemesi parametre
void
olarak
ComplteOrderProcess(ProductOrderRequest request1,ProductOrderR
kullanlamaz. Exception
equest request2);
retir.

Bu ksa teorik bilgileri devam ettireceiz ancak dilerseniz basit bir rnek zerinden ilerleyerek
devam edelim. ncelikli olarak bir WCF Snf Ktphanesi projesi oluturduumuzu dnelim.
Bu projemizde yer alacak olan tiplerin snf diygramndaki grnts aadaki gibi tasarlanabilir.

www.bsenyurt.com Page 486


Snf diyagram(Class Diagram) gzmz korkutmasn. Senaryomuz aslnda
sadece Mesaj Szlemelerinin nasl kullanlacan gstermeye ynelik olduundan ok anlaml
olmayan operasyonlar iermekte. Bu yzden rnek olarak bir sipari srecine zel mesajlar
tasarladmz bir durum sz konusu. Kullanlan tiplerin ierikleri srasyla aadaki gibidir;

Product Snf. (Veri Szlemesi-Data Contract olarak tanmlanmtr)

using System;
using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace = "http://Northwind/ProductTransferService/Product")]
public class Product
{
[DataMember(Order=0)]
public int ProductId { get; set; }
[DataMember(Order=1)]
public string Name { get; set; }
[DataMember(Order=2)]
public double ListPrice { get; set; }
[DataMember(Order=3)]
public DateTime OrderDate { get; set; }
}

www.bsenyurt.com Page 487


}

CustomerNumber yaps-struct.(Veri Szlemesi-Data Contract olarak tanmlanmtr)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace =
"http://Northwind/ProductTransferService/CustomerNumber")]
public struct CustomerNumber
{
[DataMember]
public char Region { get; set; }
[DataMember]
public int Number { get; set; }
[DataMember]
public string LastName { get; set; }
}
}

Receiver Snf(Veri Szlemesi olarak tanmlanmtr)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace="http://Northwind/ProductTransferService/Receiver")]
public class Receiver
{
[DataMember]
public int ReceiverId { get; set; }
[DataMember]
public string Name { get; set; }
[DataMember]
public CustomerNumber Number { get; set; }
[DataMember]
public int RequestedProductCount { get; set; }
}
}

Sender Snf.(Veri Szlemesi olarak tanmlanmtr)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace = "http://Northwind/ProductTransferService/Sender")]
public class Sender
{
[DataMember]
public int SenderId { get; set; }
[DataMember]
public string Name { get; set; }

www.bsenyurt.com Page 488


[DataMember]
public CustomerNumber SenderNumber { get; set; }
}
}

RequestStatus Enum sabiti.(Veri Szlemesi olarak tanmlanmtr. Enum sabiti sz konusu


olduu iin deerler DataMember yerine EnumMember isimli nitelik ile iaretlenmitir.)

using System.Runtime.Serialization;

namespace ProductTransferLib
{
[DataContract(Namespace =
"http://Northwind/ProductTransferService/RequestStatus")]
public enum RequestStatus
{
[EnumMember]
Ok,
[EnumMember]
Error,
[EnumMember]
Waiting
}
}

Buraya kadar tanmladmz tipler ierisinde snf, yap ve enum sabiti tipleri sz konusudur. Bu
tipler birer Veri Szlemesi olarak tanmlanmtr ve MesajSzlemeleri ierisinde ele
alnmaktadr. Yazmzn konusu olan Mesaj Szlemelerinden iki adet tanmlanmaldr. Bu
tanmlamalardan birisi istek(Request) dier isecevap(Response) ieriklerinin yapsn iaret
etmektedir. Bir baka deyile, istemciden servise gelecek veya geriye dndrlecek
olan SOAP zarflarnn ierikleri kod yardmyla belirlenmektedir. stemci tarafndan gelecek olan
taleplere ait Mesaj Szlemesi aadaki kod parasnda olduu gibi tanmlanmtr.

using System;
using System.ServiceModel;

namespace ProductTransferLib
{
[MessageContract]
public class ProductOrderRequest
{
#region Header Ksmna yazlacak zellikler

[MessageHeader]
public Guid OrderNumber { get; set; }
[MessageHeader]
public DateTime OrderDate { get; set; }
[MessageHeader]
public Product OrderedProduct { get; set; }

#endregion

#region Body ksmna yazlacak zellikler

[MessageBodyMember(ProtectionLevel=System.Net.Security.ProtectionLevel.None)

www.bsenyurt.com Page 489


] // ProtectionLevel iin varsaylan dere None' dur.
public Sender OrderSender { get; set; }
[MessageBodyMember]
public Receiver[] Receivers { get; set; }

#endregion
}
}

ProductOrderRequest isimli snf bir Mesaj Szlemesi olacak ekilde tanmlanmtr. Bu


nedenle MessageContract nitelii ile imzalanmtr. Bu nitelik
sadece snf(Class) veya yaplara(Structs) uygulanabilir. Yazmzn banda
mesajn Header ve Body ksmlarndan bahsetmitik. Header ksmnda tanacak
olan alan(Field)veya zellikleri(Property) belirtmek iin MessageHeader nitelii
kullanlmaktadr. rnektende grld gibi, Header ksmnda Guid, DateTime gibi bilinen tipler
dndaProduct isimli gelitirici tanml bir snfada yer verilmitir. Sz konusu tipler mesaj ierisine
alnrken seriletirilmektedir. Bu nedenle Product snf ve dier gelitirici tanml tipler
birer Veri Szlemesi olarak tanmlanmtr. Body ksmnda yer alacak zellik veya alanlar
ise MessageBodyMember nitelii ile tanmlanrlar.
Yine Body ksmndada, Sender ve Receiver isimli gelitirici tanml Veri Szlemelerine yer
verilmektedir. zellikle Receiver tipinden bir Array kullanldnada dikkat edilmelidir.

Header veya Body ksmlarnda Array' ler


kullanlyorsa MessageHeader ve MessageBodyMember nitelikleri bu dizilerin
elemanlarn bir elementin alt elementleri(Child Element) olacak ekilde
konumlandrr. rnein;

<diziAdi>
<diziElemanTipiAdi>ierii</diziElemanTipiAdi>
<diziElemanTipiAdi>ierii</diziElemanTipiAdi>
</diziAdi>

Ancak istenirse her bir dizi elemannn ayr birer boum olarak ele alnmas salanabilir.
Bunun iin MessageHeaderArray nitelii kullanlr.

<diziAdi>ierii</diziAdi>
<diziAdi>ierii</diziAdi>

Yanlz bu nitelik sadece dizilere uygulanabilir. Bir baka


deyile koleksiyonlara uygulanamamaktadr.

Eer SOAP ieriinde byte tipinden bir diziye yer


verilmise MessageHeader veya MessageBodyMember niteliklerinin kullanlmas
halinde bunlar dorudan Base64 tipine dntrlrler. Ancak,
eer MessageHeaderArray nitelii kullanlyorsa, ele alnan seriletirme tipine
gre(DataContractSerializer, XmlSerializer gibi) bir aktarm gerekletirilir.

MessageHeader ve MessageBodyMember niteliklerinde yer alan ProtectionLevel zellii


kullanlarak dijital olarak
imzalama(Sign) veya ifreleme(Encryption) salanabilir.ProtectionLevel zellii System.Net
.Security.ProtectionLevel enum sabiti tipinden bir deer alabilir. Bu
deerler None, EncryptAndSign, Sign olabilir. Varsaylan deeri None' dur. Signseilirse dijital
imzalama sz konusudur. EncryptAndSign seilirsede ifreleme ve dijital imzalama sz
konusudur. Elbette None dndaki deerlerin ie yaramas iin WCF alma ortamna ynelik

www.bsenyurt.com Page 490


olaraktan gerekli Binding ve Behavior ayarlamalarnn yaplmas gerekir. Aksi durumda alma
zamannda dorulama ilemi srasnda bir istisnas alnr. ProtectionLevel, Header ksmnda her
bir eleman iin ayr ayr uygulanmaktadr. Body ksm sz konusu olduunda ise ka eleman olursa
olsun hepsi iin aynProtectionLevel seviyesi sz konusudur. Buna
gre MessageBodyMember nitelii iinde seviyesi yksek olan ProtectionLevel deeri, dierleri
iinde uygulanr. Sz gelimi 3 farklMessageBodyMember iin
srasyla None, EncryptAndSign, Sign deerleri belirlenmise, tm mesaj gvdesi
iin EncrptyAndSign seenei gz nne alnmaktadr.

SOAP ile ilikili web servisi standartlarnda 1.1 versiyonu iin Actor ve 1.2 iin Role ad
verilen bir zellik yer almaktadr. Bu zelliin deerini WCF tarafnda ele almak
iin MessageHeader niteliinin Actor zellii kullanlr. Bunun
dnda MustUnderstand ve Relay zelliklerindende yararlanlarak, SOAP standarlarna
gre baz niteliklerin mesajlama srelerine kazandrlmas da salanabilir.

stemciye gnderilecek cevap mesajnn ierii ise ProductOrderResponse isimli Mesaj Szlemesi
ile tanmlanmaktadr.

using System.ServiceModel;
using System;

namespace ProductTransferLib
{
[MessageContract]
public class ProductOrderResponse
{
[MessageBodyMember]
public RequestStatus Status { get; set; }

[MessageBodyMember]
public DateTime ProcessDate{ get; set; }

[MessageBodyMember]
public byte[] OrderPicture { get; set; } // Burada byte[] tipinden bir dizi sz konusu olduu
iin SOAP body' si ierisinde Base64 tipinden bir kodlama(encoding) sz konusu olacaktr

[MessageHeader]
public int OrderdProductCount { get; set; }
}
}

ProductOrderResponse tipi Mesaj Szlemesi olarak tanmlanrken ama istemci tarafna


gnderilecek olan SOAP mesajnn Header ve Body ksmlarnda neler olacana karar
verilmesidir. Dikkat edilecei
zere Body ksmnda RequestStatus enum sabiti, DateTime ve byte[] dizisi tipinden bir ierik
yer almaktadr. Dier taraftan Header ksmnda ise rnek olarak int veri tipinden bir deer
dndrlmektedir.

Bir tipin hem MessageContract hemde DataContract olacak ekilde tanmlanmas da


mmkndr. Byle bir vakada, WCF alma zamannda servis operasyonlar
uygulanrken, sz konusu tip iin Mesaj Szlemesi kriterleri gz nne alnmaktadr.

Artk istemci ve servis arasnda dolaacak olan SOAP mesajlarna ait ierikler tanmlanmtr.
Dolaysyla bu mesajlama modelini kullanacak bir Servis Szlemesi ve uygulayc snf

www.bsenyurt.com Page 491


tasarlanabilir. Dikkat edilecei zere Servis Szlemesinde yer
alan CompleteOrderProcess isimli operasyonun dn tipi ve parametresi
birer MesajSzlemesidir.

using System.ServiceModel;

namespace ProductTransferLib
{
[ServiceContract(
Name="ProductTransferService"
,Namespace="http://Northwind/ProductTransferService")]
public interface IProductTransferService
{
[OperationContract]
ProductOrderResponse CompleteOrderProcess(ProductOrderRequest request);
}
}

Operasyonun uygulan iinse aadaki gibi bir kod rnei gelitirilebilir.

using System;
using System.IO;

namespace ProductTransferLib
{
public class ProductTransferService
:IProductTransferService
{
#region IProductTransferService Members

public ProductOrderResponse CompleteOrderProcess(ProductOrderRequest request)


{
DateTime requestDate = request.OrderDate;
Guid requestOrderNumber = request.OrderNumber;
Sender requestSender = request.OrderSender;
Receiver[] requestReceivers = request.Receivers;

int orderedProductCount = 0;
foreach (Receiver receiver in requestReceivers)
{
orderedProductCount += receiver.RequestedProductCount;
}

// Not : XP_HDD.gif resminin byte ieriinin dizi boyutu istemci tarafna gnderilebilecek
varsaylan dizi limini aabilir. Bu nedenle istemci tarafndaki konfigurasyon ayarlarnda
maxArrayLength deerinin bilinli olarak arttrlmas gerekebilir.
return new ProductOrderResponse
{
ProcessDate=DateTime.Now,
Status= RequestStatus.Ok,
OrderPicture=File.ReadAllBytes(System.Environment.CurrentDirectory
+ "\\XP_HDD.gif"),
OrderdProductCount=orderedProductCount
};
}

www.bsenyurt.com Page 492


#endregion
}
}

Burada request deikeninden yararlanlarak istemci tarafndan gelen SOAP paketindeki mesaj
ierii ele alnmakta ve kullanlmaktadr. Sembolik olarak paket ierisinde
gelenReceivers dizisindeki her bir Receiver nesne rneinin sipari saysnn toplam tespit
edilmektedir. Ayrca rnek byte[] ierii dndrlmesi iin kk bir resim
dosyasndan(XP_HDD.gif) yararlanlmaktadr. lemin tarihi, durumu, sipari ile ilikili resim ve
toplam sipari says bilgileri kullanlaraktanda bir cevap mesaj oluturulmakta ve istemci tarafna
gnderilmektedir.

SOAP mesajlarnn ierikleri aslnda XML tabanldr. Bu ierii


ynetirken Mesaj Szlemeleri, nesne tabanl bir modeli ele alabilmemizi
salamaktadr. Bir baka deyile, kod tarafnda XML yaps ile uramak yerine, nesne
tabanl bir modeli kullanarak mesaj ieriini kolayca oluturabilmemiz olanakl hale
gelmektedir ki bu gelitirme sreci iin nemli bir avantajdr.

Bu ilemlerin tamamlanmasnn ardndan servis ktphanesini Host edecek basit bir uygulama
gelitirilebilir. Biz rneimizde her zaman olduu gibi, sunucu ve istemci taraflar iin
birer Console uygulamas gelitiriyor olacaz. Sunucu uygulama kodlar ve konfigurasyon ierii
aadaki kod paralarnda olduu gibi tanmlanabilirler.

Sunucu uygulama kodlar;

using System;
using System.ServiceModel;
using ProductTransferLib;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(ProductTransferService));
host.Open();
Console.WriteLine("Servis dinlemede.\nKapatmak iin bir tua basnz.");
Console.ReadLine();
host.Close();
}
}
}

Sunucu taraf konfigurasyon ierii;

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="ProductTransferServiceBehavior">

www.bsenyurt.com Page 493


<serviceDebug includeExceptionDetailInFaults="true" />
<serviceMetadata />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="ProductTransferServiceBehavior"
name="ProductTransferLib.ProductTransferService">
<endpoint address="" binding="basicHttpBinding"
bindingConfiguration="" name="ProductTransferServiceHttpEndPoint"contract="Produc
tTransferLib.IProductTransferService" />
<endpoint address="Mex" binding="mexHttpBinding"
bindingConfiguration="" name="ProductTransferServiceMexEndPoint" contract="IMeta
dataExchange" />
<host>
<baseAddresses>
<add baseAddress="http://buraksenyurt:1000/ProductTransferService"
/>
</baseAddresses>
</host>
</service>
</services>
</system.serviceModel>
</configuration>

Sunucu uygulama basit olarak HTTP tabanl bir sunum yapmakta ve BasicHttpBinding balayc
tipini ele almaktadr. Bununla birlikte istemci tarafnn, servise ait Metadata bilgisini ekebilmesi
iin IMetadataExchange arayzn kullanan bir MexHttpBinding EndPoint' ide
kullanlmaktadr.

stemci uygulamamz kullanrken yine Add Service Reference seenei ile


ayn solution ierisinde yer alan rnek servise ait referans retimini gerekletirebiliriz. stemci
tarafna ait konfigurasyon ierii aadaki gibidir(Bu ierik Add Service Reference seeneinin
kullanlmas sonucunda otomatik olarak retilmektedir.)

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


<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="ProductTransferServiceHttpEndPoint" closeTimeout="00:01:00"
openTimeout="00:01:00" receiveTimeout="00:10:00" sendTimeout="00:01:00"
allowCookies="false" bypassProxyOnLocal="false" hostNameComparisonMode="StrongWildcard"
maxBufferSize="65536" maxBufferPoolSize="524288" maxReceivedMessageSize="65536"
messageEncoding="Text" textEncoding="utf-8" transferMode="Buffered"
useDefaultWebProxy="true">
<readerQuotas maxDepth="32" maxStringContentLength="8192"
maxArrayLength="163840" maxBytesPerRead="4096" maxNameTableCharCount="16384"/>
<security mode="None">
<transport clientCredentialType="None" proxyCredentialType="None" realm=""
/>
<message clientCredentialType="UserName" algorithmSuite="Default" />
</security>
</binding>
</basicHttpBinding>

www.bsenyurt.com Page 494


</bindings>
<client>
<endpoint address="http://buraksenyurt:1000/ProductTransferService"
binding="basicHttpBinding" bindingConfiguration="ProductTransferServiceHttpEndPoint
"
contract="ProductTransferServiceReference.ProductTransferService"
name="ProductTransferServiceHttpEndPoint" />
</client>
</system.serviceModel>
</configuration>

stemci tarafndaki rnek kod ierii ise aadaki gibidir.

using System;
using System.IO;
using ClientApp.ProductTransferServiceReference;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
ProductTransferServiceClient client = new
ProductTransferServiceClient("ProductTransferServiceHttpEndPoint");

Sender sndr = new Sender


{
Name="Burak Selim",
SenderId=10001,
SenderNumber=new CustomerNumber{ Number=1, Region='A',
LastName="SENYURT"}
};

Receiver[] receivers = {
new Receiver{ Name="Bil", Number=new CustomerNumber{ LastName="Geyts",
Region='B', Number=1}, ReceiverId=10002, RequestedProductCount=100},
new Receiver{ Name="Deyv", Number=new CustomerNumber{ LastName="Masteyn",
Region='C', Number=2}, ReceiverId=10003, RequestedProductCount=150},
new Receiver{ Name="Co", Number=new CustomerNumber{ LastName="Satriyani",
Region='C', Number=3}, ReceiverId=10055, RequestedProductCount=75}
};

RequestStatus requestStatus;
DateTime processDate;
byte[] orderPicture;

Console.WriteLine("Sipari iin bir tua basnz.");


Console.ReadLine();

int result=client.CompleteOrderProcess(
DateTime.Now,
Guid.NewGuid(),
new Product{ ProductId=1, Name="Her
Ynyle WCF", ListPrice=10, OrderDate=DateTime.Now},
sndr,

www.bsenyurt.com Page 495


receivers,
out orderPicture,
out processDate,
out requestStatus);

Console.WriteLine("result {0}",result.ToString());
File.WriteAllBytes(System.Environment.CurrentDirectory + "\\ResponsePicture.gif",
orderPicture);

Console.WriteLine("lemler tamamland. kmak iin bir tua basnz.");


Console.ReadLine();
}
}
}

stemci uygulamada servise ait proxy nesnesi rneklendikten


sonra CompleteOrderProcess metodunun ihtiyac olan parametreler
hazrlanmaktadr. CompleteOrderProcess metodu
aslnda ProcessOrderResponse Mesaj Szlemesi tipinden bir parametre almaktadr. Ne varki
istemci tarafnda metodun uygulan ekli biraz farkldr. Hereyden nce, servise
gnderilecek SOAP paketi ierisinde yer alacak Header ve Body elementlerinin her biri, istemci
tarafnda ayr birer metod parametresi ekline ele alnmaktadr. Metodun arlmas sonucu
istemciye dnecek olan SOAP mesajndaki Header ksmnda yer alan int deer aslnda istemci
tarafnda, CompleteOrderProcess' in dn deeridir. Yine istemciye dndrlen
ve Body ksmnda yer alan orderPicture,processDate ve requestStatus deikenleri
ise, CompleteOrderProcess metodunun out tipinden parametreleri olarak ele
alnmaktadr. orderPicture deikeni bir byte[] dizisi olarak mesaj ieriinden toparlanmakta ve
fiziki olarak istemci tarafndaki bir dosyaya yazdrlmaktadr. Bu tahmin edilecei zere servis
tarafndan gnderilen resimdir. Projemizde hem sunucu hemde istemci uygulamamz
altrdmzda aadaki ekran grntsnde yer alan sonular elde ederiz.

Aslnda burada artc bir sonu yoktur. Nesne tabanl olacak ekilde istemci ve servis arasndaki
tipler kolay bir ekilde kullanlmtr. Ancak bizim iin nemli olan arka planda hareket
eden SOAP mesajlarnn ieriklerinin ne hale geldiidir. Bu
amala Fiddler isimli HTTP Debugging aracndan yararlanrsak, rnein altrlmas sonrasnda
a trafiinde, aadaki ekran grntsnde yer alan mesajlamann olutuunu grrz.

www.bsenyurt.com Page 496


Dikkat edilecei zere, Mesaj Szlemelerinde Header ve Body ksmlarnda hangi bilgilerin yer
almasn istiyorsak buna gre bir aa yaps olumutur. Request ksmna ait
olan SOAP zarfnn XML ierii tam olarak aadaki gibidir.

<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:OrderDate xmlns:h="http://Northwind/ProductTransferService">2009-02-
08T01:53:03+02:00</h:OrderDate>
<h:OrderNumber xmlns:h="http://Northwind/ProductTransferService">9476df3d-0f74-4643-
9fcf-b7344d5da37d</h:OrderNumber>
<h:OrderedProduct xmlns:h="http://Northwind/ProductTransferService"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<ProductId xmlns="http://Northwind/ProductTransferService/Product">1</ProductId>
<Name xmlns="http://Northwind/ProductTransferService/Product">Her Ynyle
WCF</Name>
<ListPrice xmlns="http://Northwind/ProductTransferService/Product">10</ListPrice>
<OrderDate xmlns="http://Northwind/ProductTransferService/Product">2009-02-
08T01:53:03+02:00</OrderDate>
</h:OrderedProduct>
</s:Header>
<s:Body>
<ProductOrderRequest xmlns="http://Northwind/ProductTransferService">
<OrderSender xmlns:a="http://Northwind/ProductTransferService/Sender"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Name>Burak Selim</a:Name>

www.bsenyurt.com Page 497


<a:SenderId>10001</a:SenderId>
<a:SenderNumber
xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>SENYURT</b:LastName>
<b:Number>1</b:Number>
<b:Region>65</b:Region>
</a:SenderNumber>
</OrderSender>
<Receivers xmlns:a="http://Northwind/ProductTransferService/Receiver"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:Receiver>
<a:Name>Bil</a:Name>
<a:Number xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>Geyts</b:LastName>
<b:Number>1</b:Number>
<b:Region>66</b:Region>
</a:Number>
<a:ReceiverId>10002</a:ReceiverId>
<a:RequestedProductCount>100</a:RequestedProductCount>
</a:Receiver>
<a:Receiver>
<a:Name>Deyv</a:Name>
<a:Number xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>Masteyn</b:LastName>
<b:Number>2</b:Number>
<b:Region>67</b:Region>
</a:Number>
<a:ReceiverId>10003</a:ReceiverId>
<a:RequestedProductCount>150</a:RequestedProductCount>
</a:Receiver>
<a:Receiver>
<a:Name>Co</a:Name>
<a:Number xmlns:b="http://Northwind/ProductTransferService/CustomerNumber">
<b:LastName>Satriyani</b:LastName>
<b:Number>3</b:Number>
<b:Region>67</b:Region>
</a:Number>
<a:ReceiverId>10055</a:ReceiverId>
<a:RequestedProductCount>75</a:RequestedProductCount>
</a:Receiver>
</Receivers>
</ProductOrderRequest>
</s:Body>
</s:Envelope>

Bu XML ierii incelendiinde tam olarak Mesaj Szlemesinde belirttiimiz kriterlere uyulduu
grlmektedir. Sz
gelimi Header ksmnda OrderDate, OrderNumber veOrderProduct elementleri yer
almaktayken, Body ksmnda ProductOrderRequest elementi tarafndan sarmalanm
olan, OrderSender ve Receivers elementleri
bulunmaktadr.Receivers aslnda Receiver[] dizisinin kullanlmas nedeni ile kendi ierisinde
birden fazla Receiver alt elementi iermektedir. Burada gelitirici tanml
tiplerin(Product,Receiver,Sender gibi) Veri Szlemesi olarak tanmlanmalar
nedeniyle XML elemetleri ierisine aktarlm olmalarda gzden karlmamaldr. Yine
istemciye dnen mesajn(Response)tam ieriine bakldnda aadakine benzer
bir SOAP kts ile karlalmaktadr.

www.bsenyurt.com Page 498


<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<h:OrderdProductCount
xmlns:h="http://Northwind/ProductTransferService">325</h:OrderdProductCount>
</s:Header>
<s:Body>
<ProductOrderResponse xmlns="http://Northwind/ProductTransferService">
<OrderPicture>R0lGODlhIAAgAPcAAAAAAB8hNR4hODMpHCQgLiIkNyYqRysvUC4wQy
0wTi0xUzU3SzE1VjE1WzU5Xjs
+VDw/WDU6Yzk+ZTk/bDg5dTFILDl0FzpGRz5BXD5CYz1CbD5EdVYzLXI/SF9OMF1
WP05tK0JoN0pxNVF5JVR1M2lfPn
FHKn5GP3VpL31vN31wL3d0OEZIVkZUSUFFY0FGbURIZEZKaklLYExPaEJIek1SaEx
Td1VWalNXd1prWFp1Rl96bWRcS
2JNYGtrRnhuRGdlaGNkdmh5eTc3mDxDxT5P2Dxdxj5d3T9g1z9r40VMg0pRiVZbhFR
bl1hkilljl0Nxr0h2t1tlqFVzqGFmjW
ZpgWtthGlti2Npl25xiGd6l25xkG1ym3ByhnN0inl2h3N2kXF2m3R4lnR5mXp8lWNqq2p
zp2xzsXN5q3l+pXp/qnR7tEFW0E
Jt0EN85l+fGkmLJ0mSIVOKJFWJNVeXJFqpH1y2GFqiJGOWKWK3Hm2oIV6KVFnFGGn
NF3POGnrSGWHJIHbNInvQIHiDiH
qAonyCuH6Qr0qK3kOF7EeP8EqU8Vua6lWb8miW1XGYzWWk8XSq73et8H+x8YM2N
5oxJ7MsG4pfPIN4K5J7LpR0OKFV
KaB2HbB+FYNtQpp8eKRNR7JyRtAqE+UsEfg+D/Q2ENRNE9dyH8F0NuxHD/pJDfxWDO
1+HP1lDv12EbeDC7OaFKmUIqm
XNruDK72nEKyMfoHSHYTRJMeKCMiRCN+GH9WWBc2xDNqjA8GnIv2GE/uaF/CGIf2W
IOCrBOS1BfqlHPq0HfysIfu3I+vG
A/fXBPrcFvzeKfzeOP3gOIKDj4yDlZCCkYaKrYGHs4CGu4SJtYWLvYqPtIiNuo6TvJWXp
pGVu5+ivoiOwIySwpGWxJSZxJ
ecyJmdxJmeyJ2hw52iy4i28JK88aGlxqGmzKSpzqmsyaar0Kmt0a6xzK2x07a4zbG11bS4
17a52Lq907m92ZzC8b7B3K3J
7aXH8MTG3MjL4c7R5dHT5gAAAAAAAAAAACH5BAEAAP8ALAAAAAAgACAAAAj/AP8JH
EiwoMGDCNvNsCcvHjx37tixW
5cuHTpy5MSB++atW7UM2BDaszduGxkyXrp0AWMFTBYrYqpY+8bxmxpu0xDSs5eGTIIX
DjRIcCBBgoYAWxCE4ditG45
q1Q7mo0ePEJkFCAoM8GCCA4ECBWAsCAOuo1OPB/nJgzdP3z5auY4Ra6UK1ad3+aaKa1r
NBreoBvM5hLf21K9jv+iOCu
VlkLhv1TxWe1ponsF58DK707bKWDFfrFKRopRDzpwdY8II2QMHS2WD9B5C9BRMri9Vojvo
oGOnT58/f/pYoFLonMF0E
CeCClZsLm5RN0bw/g2cTwUsa74ZRAdP4jhTxIr9/2KlalSlG3Tq8KHeh88DJ2uobU+QThw0YLI
yWdJUitSk0nX4VosgfcT
BhAsNoGHQQ9es8wwLNzjhhA01nNADCXTk0YcftgQCSAhmwGeGQe6MQ006UjhyTzmPJGLEEl
yAcIeGgXTIBwtrPLHGG
QXls04Y6URziDn4lMMIIkcM8cUNLcjxhh54iHABE2tg8QSPBOmDDhbsmPFIPfVEwogbR1CQyS2Y
8LAACx9ckoIZa5SBA
5YDtUMOF+JAAQk+5jyiSBJEBMEJL8Mko0wzyiRTghlnYNFEGe0Q5A453VATRTlFPoLkEEDowgsyh
jKTDDIxnHHGE2WU
oQ5BF4lDyCL14P8jphtsUNCJLsIkY+gyybzChKlnpGoNQdpoNEUjhmjxBBRtEPHCJroUmswyia5wJTep
SiHfQN885gQLz4
BBhRMwUHDDLZ/q2oyuLEgjTqplSFEGQeBsRA013dCTDzloUBGEK8KAqgyvu1hRDbxSSPEEQZA11c01
3HTjDj/6qNPFD
7DM0kssKDzwaLwJN9HEQO9QY8A13fxVzTTTFFJIN95EcwUONdCwBKogS6GEAiMPhFxEE1Fk0UXhFB
0
OTdqEow022i
zN9IgDMbCBEgUYoEADEUQwAQ00NKCAAgd8DfbUSpQ9NQ4EZUCDElZnPcEGG3DttQNifz01EzgoYfM
VB
ME9sLYBAhj
QgAZxr+2113XH7cMKeivhBUHZxBADBA9U/gAGGLjgAgYZYO555pprHgMNCJVu+umop6766gcFBAA7

www.bsenyurt.com Page 499


</OrderPicture>
<ProcessDate>2009-02-08T01:53:03.46875+02:00</ProcessDate>
<Status>Ok</Status>
</ProductOrderResponse>
</s:Body>
</s:Envelope>

Gzden kamayacak olan nokta OrderPicture elementinin ieriidir :) Tahmin edilecei zere bu
elementin ierii, servis tarafndaki resmimizin byte[] dizisi haline geldikten sonra, SOAPmesaj
ieriine Base64 kodlamasna gre seriletirilmi halidir. Bu ierik, istemci tarafnda ters
seriletirilme ileminden sonra yine byte[] dizisi olacak ekilde ele alnabilmektedir. Bunlarn
haricinde Header ksmnda OrderProductCount elementinin, Body ksmnda
ise ProductOrderResponse elementi ile sarmalanm
olan OrderPicture, ProcessDate ve Statusalt elementlerinin olduu grlmektedir.

Mesaj Szlemelerinde ele alnan bir dier durumda trlendirilmemi versiyonlarn


kullanlmasdr(Untyped Message Contracts). Burada System.ServiceModel.Channels isim
alannda yer alan Message snf ele alnmaktadr. SOAP 1.1 ve SOAP 1.2 uyumlu mesajlar iaret
edebilen bu snf yardmyla, istemciden gelen talepler ele alnabilir ve cevaplar
oluturularak Message tipinden rnekler zerinden kar tarafa gnderilebilir. Son olarak bu
durumu deerlendirip makalemizi tamamlayalm. Bu amala Servis Szlememizeaadaki
ekran grntsnde yer alan yeni bir operasyon ilave ettiimizi dnelim.

RunProcess isimli operasyon parametre ve dn deeri olarak Message tipini kullanmaktadr. Sz


konusu operasyon metodunun ProductTransferService ierisindeki uyarlamas ise aadaki gibi
yaplabilir.

// Untyped Message alp veren rnek servis operasyonu metodu.


public Message RunProcess(Message request)
{
// Servise gelen Untyped Message ' n Body ksmnda yer alan Product dizi ieriini elde etmek
iin GetBody metodunun generic versiyonundan yararlanlr.
Product[] products = request.GetBody<Product[]>();

// stemciye dndrelecek Untyped Message' n Body ksmnda yer alacak rnek Product ierii
iin dizi oluturulur.
Product[] resultSet=new Product[products.Length];

www.bsenyurt.com Page 500


// Gelen mesajn Body ksmndan elde edilen dizi zerinde rnek ilemler yaplr.
// rnekte ListPrice bilgisi 1 birim arttrlmtr.
for (int i = 0; i < products.Length; i++)
{
products[i].ListPrice += 1;
resultSet[i] = products[i];
}

// Operasyondan dndrelecek olan Untyped Message oluturulur.


// lk parametre SOAP versiyonunu belirtir. rnein "SOAP 1.1".
// kinci parametre servis operasyonunda ReplyAction zelliine atanan deerdir.
// nc parametre ise Body ksmnda yer alacak olan nesne rneidir.
Message response = Message.CreateMessage(request.Version,
"ReplyAction",resultSet);

// Untyped Message geriye dndrlr.


return response;
}

RunProcess isimli servis operasyonu, istemciden gelen mesajn Body ksmnda yer
alan Product nesne verilerini ele almakta ve rnek olarak ListPrice deerlerini 1 birim arttrarak
geriye dndrmektedir. Metoda gelen trlendirilmemi mesajn gvdesindeki veri ieriini ele
alabilmek iin GetBody<T> metodundan yararlanlr. Tahmin edilecei zere metodun kulland
generic tip zerinden bir XML ters seriletirme ilemi sz konusudur. Nitekim istemciden gelen
mesaj XML tipindedir ve kod ierisinde nesnel olarak kullanlmas gerekmektedir. Bunlara ek
olaraktan, servisin istemciye gnderecei trlendirilmemi mesajn retimi
iin, Message snfnn static CreateMessage fonksiyonundan yararlanlr. Metodun ar
yklenmi(overload) 11 farkl versiyonu bulunmaktadr. rneimizde kullandmz halinde, ilk
parametre ile SOAP versiyonu, ikinci parametre ile SOAP Action ad ve son olarak nc
parametre ilede Body ksmna gelecek olan nesne rnei belirtilmitir. Eklenen bu yeni
fonksiyonellik nedeniyle istemci tarafnda yer alan servis referansnnda gncellenmesi
gerekmektedir. Bu gncelleme ileminin ardndan RunProcess isimli operasyon istemci tarafnda
rnek olarak aadaki kod parasnda grld gibi kullanlabilir.

Console.WriteLine("\nUntyped Message\n");

// Gncel kanal implementasyonundan yararlanarak OperationContextScope nesnesi rneklenir.


// OperationContextScope nesnesinden yararlanarak gelen ve giden mesajlarn ierikleri
ynetilebilir, Header, Body gibi ksmlarna mdahale edilebilir.
using (new OperationContextScope(client.InnerChannel))
{
// Untyped mesaj ierisinde gnderilecek olan Product nesneleri iin bir dizi hazrlanr.
Product[] products =
{
new Product{ Name="Programming WCF", ListPrice=12, OrderDate=DateTime.Now,
ProductId=19},
new Product{ Name="Programming C# 3.0", ListPrice=16, OrderDate=DateTime.Now,
ProductId=21}
};

// stemciden servise gnderilecek olan Untyped Message hazrlanr.


// lk parametre mesaj versiyonudur. (SOAP 1.1 gibi).
// kinci parametre servis szlemesinde RunProcess operasyonunda belirtilen Action zelliinin
deeridir.
// nc parametre ise mesaj ieriinde gnderilecek olan seriletirilebilir nesne rneidir. Bu

www.bsenyurt.com Page 501


rnekte Product tipinden bir dizi kullanlmaktadr.
Message request =
Message.CreateMessage(OperationContext.Current.OutgoingMessageHeaders.MessageV
ersion, "RequestAction", products);

// Operasyon ars yaplr ve parametre olarak hazrlanan Untyped Message rnei gnderilir.
// ar sonucu yine bir Untyped Message rneidir.
Message reply = client.RunProcess(request);

// Servisten gelen Untyped Message ierisindeki Body ksmnda tutulan Product topluluunu dizi
olarak ele almak iin GetBody metodunun generic versiyonu kullanlr. Bunun sonucu olarak elde
edilen sonu Product tipinden bir dizi olacaktr.
Product[] response = reply.GetBody<Product[]>();

foreach (Product product in response)


{
Console.WriteLine(product.Name+" "+product.ListPrice);
}
}

stemci tarafnda RunProcess metodu arlmadan nce gnderilecek mesajn oluturulmas iin
yine CreateMessage static metodundan yararlanlmaktadr. Yine ilk parametre
olarak SOAP versiyonu, ikinci parametre olarak SOAP Action deeri ve nc parametre
olarakta Body ksmna seriletirilecek nesne rnei belirtilmitir. Servis tarafndan gelen mesaja ait
Body bilgisinin okunmas iinde GetBody<T> metodundan yararlanlmaktadr. stemci tarafnda
dikkat edilmesi gereken noktalardan biriside tm bu ilemleri ierisine
alan Using blounda OperationContextScope nesnesinden yararlanlmas ve o
anki kanal(Channel) bilgisinin kullanlmasdr. rnek uygulamamz bu haliyle test edildiinde
alma zaman grnts aadakine benzer olacaktr.

Ancak elbetteki arka planda yer alan mesaj ieriine Fiddler arac yardmyla
bakldnda Body ksmnda hareket eden Product verilerinin ierii ak bir ekilde
grlebilmektedir.

www.bsenyurt.com Page 502


Dikkat edilecei zere Request mesajnda gnderilen Product nesnelerine
ait ListPrice deerleri, Response mesaj ierisinde 1 birim arttrlmtr. Eer
mesajlarn RAWieriklerine baklrsa SOAP Action bilgisininde set edilmi olduu grlebilir. (Size
tavsiyem GetBody metodlarna olan
arlarda BreakPoint kullanarak request ve responsedeikenlerinin alma zaman
ieriklerini QuickWatch ile izlemenizdir.)

www.bsenyurt.com Page 503


Eer istemciden talep gnderildikten sonra varsaylan olarak 1 dakikalk zaman dilimi
ierisinde servis tarafndan cevap gelmezse aadaki ekran grntsnde yer
alan TimeoutException istisnas ile karlalr.

Bu sorun SendTimeout deeri arttrlarak zmlenebilir. Bu sorun, uzun sren


operasyonlarn sz konusu olduu durumda dikkate alnmas gereken istisnalarn banda
gelmektedir.

www.bsenyurt.com Page 504


Buraya kadar yaptklarmza baktmzda, istemci ve sunucu arasndaki Mesaj ieriklerinin
ynetiminin Mesaj Szlemeleri yardmyla ele alnabildii sonucu ortaya kmaktadr. Buna gre
istenirse, istemci ve sunucu arasnda tanacak bir veri tipinin belirli paralarnn SOAP zarf
ierisindek Header veya Body blmleri arasnda ayrtrlmas mmkn olabilmektedir. Hatta,
istemci ve servis arasnda zel mesaj desenlerinin oluturulmas da sz konusu ve olasdr. Elbette
bu ii tamamlayc en nemli noktaifreleme(Encryption) ilemlerininde hesaba katlmasdr.
Buda yapld takdirde mesajn daha gvenilir bir ekilde ele alnmas ve korunmas mmkn hale
gelmektedir. Dier taraftan istemci ve servis arasndaki mesajlarn trlendirilmemi olmalar
halindede ele alnabildikleri ve ieriklerinin ynetilebildikleride ortadadr. MesajSzlemeleri ile
ilikili olarak daha detay bilgi almak iin, MSDN' de yaynlanan ierii takip etmenizi neririm.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim

rnei ndirmek in Tklayn

Burak Selim ENYURT


MVP (Connected System Developer-2008,C# 2007,2006)

RSS, Atom Formatl erik


Paylam(Syndication) ( 08.02.2008 ) - WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation, Net Framework 3.5 ile gelen baz yeni CLR(Common
Language Runtime) tipleri sayesinde RSS 2.0 ve Atom 1.0 formatlarnda yada dier zel
formatlarda ierik paylam(Syndication) yaplmasna izin veren zelliklere sahip olmutur. Bu
tipler sayesinde bir WCF servisi(Service) zerinden
zellikle HTTP protokolnnGET, POST, HEAD ve benzeri metodlarna gre talep-
cevap(Request-Response) ilemleri gerekletirilebilmektedir. Bir baka
deyile EndPoint noktalar zerinden farkl tipte verilerin, dnya standartlarna uygun olacak
ekilde yaynlanmas mmkndr. te bu makalemizde bir WCF servisi zerinden en basit
haliyle RSS veya Atom formatnda ierik paylamlarnn nasl yaplabileceini incelemeye
alacaz.

RSS veya Atom gibi formatlarn ortak noktas platform bamsz(Interoperability) veri
ierikleri sunulabilmesi iin gerekli standartlar ieriyor olmalardr. Bu sayede yaynlanan veriyi
alacak olan istemcilerin(Clients) farkl zelliklerinin dnlmesine gerek kalmamaktadr. Burada
sz konusu olan platform bamsz yaynlanabilen veriler genellikleFeed olarak adlandrlrlar. Feed
yaps kendi ierisinde, ierik yaynlamas ile ilgili olaraktan yazar(author), balk(title),
adres(url) ve bunlar ile ilikili olan metadata bilgilerini barndrr. Ayrca kendi ierisinde birden
fazla e(Item) barndrabilir. Bu elerin her biride kendi ierisinde balk(title), adres(url),
oluturulma tarihi(creation date), aklama(description), kategori(category) gibi bilgileri
barndrmaktadr. Bu ieriklerin u anda popler olan iki farkl sunu ekli RSS(Really Simple
Syndication) ve Atomteknikleridir. Her ikiside XML(eXtensible Markup Languge) tabanl
olacak ekilde ierik paylam standartlar sunarlar.

RSS/Atom gibi ierik yaynlama formatlarnn ortak zellikleri, platform bamsz bir
ierik iin gerekli olan metadata standartlarn salyor olmalardr.

www.bsenyurt.com Page 505


Sz konusu formatlarn her ikisde Windows Communication Foundation tarafndan
desteklenmektedir. WCF, sz konusu Feed ve Feed Item' lar ile allabilmesini kolaylatrmak
adna SyndicationFeed, SyndicationItem, SyndicationLink, SyndicationPerson gibi pek
ok CLR tipi iermektedir. Tahmin edilecei zere bu tiplerin isimlendirilmeleri, ierik paylam
formatlarnda kullanlan element adlar ile benzerdir. Ancak en nemli
avantaj, RSS yada Atom gibi formatlara ynetimli kod tarafndan(Managed Code) dorudan
destek veriliyor olmasdr. u anda WCF ierisinde farkl ierik paylam formatlarna destek
verebilmek amacyla Atom10FeedFormatter, RSS20FeedFormatter vb tipler yer almaktadr.

Peki sz konusu RSS veya Atom formatl ierikler hangi amalarla kullanlmaktadrlar? Sz gelimi
haber sitelerinin hemen hepsi gncel balklar ortak bir standartta yaynlayabilmek
iin XML tabanl olan RSS veya Atom formatl ierikler sunarlar. Ayn sistem blog siteleri iinde
geerlidir. Pek ok blog sitesinde en gncel giriler(Entry) RSS veya Atom formatnda(yada iki
formatta birden olacak ekilde) yaynlanmaktadr. Elbetteki bu yaynlanan ierikler XML formatl
olduundan, baka sistemler tarafndan alnp yorumlanabilirler. Sz gelimi haber balklar yada
blog girileri yada bir topluluk sitesinde yaynlanan son makalelerin listesi XML ieriklerinden alnp
ilenebilirler. lenen bu veriler uygulama bamsz olacak ekilde deiik kontroller ile son
kullanclara sunulabilirler. rnein farkl haber sitelerinin RSS/Atom ieriklerini kullanarak
istemcilere birer zet eklinde sunan intranet tabanl web siteleri son derece yaygndr. Bu tip bir
sistemde istemciler dorudan internete kamasalarda, intranet zerinde eriebildikleri ortak
bir portal zerinden eitli haber sitelerinin gncel konu balklarna bakabilir ve bilgi alabilirler.
Tabiki burada bahsetmi olduumuz senaryolar en yaygn
kullanlanlardr. Gelitirici(Developer) olarak baktmzda paylalabilen herhangibir veri
topluluunu RSS/Atom formatlarnda yaynlayabileceimiz sonucu ortaya kmaktadr.

RSS/Atom gibi formatlarda sunulan ierikler standartlatrlm XML verileridir. Bu


veriler versiyonlara gre farkllk gsterebilir. Ancak her haldede, XML
ieriklerinin ayrtrlp(Parse) kullanlmas mmkndr. .Net ierisinde ezelden beri
gelen XML tipleri ile bu ilemler gerekletirilebilir. Ancak WCF asndan olaya
bakldnda gze arpan noktalar unlardr;

RSS veya Atom formatl verilerin ynetimli kod(Managed Code) tarafnda


kolayca ele alnmasn salayan tipler .Net Framework 3.5 ierisinde
gelmektedir. Bylece RSS veya Atom formatl ieriklerin oluturulmas veya
okunmas(ayrtrlmas) dahada kolaylamaktadr.
WCF, .Net 3.5 ierisinde gelen destekler ile HTTP Get gibi bir metod
yardmyla EndPoint' ler zerinde RSS/Atom destei verebilecek ekilde
kullanlabilmektedir.

Sz gelimi bir veri ynetim sistemi zerinde alan bir WCF servisi, log bilgilerini yetkili
kiilere RSS/Atom formatnda sunacak ekilde URL destei verebilir. Burada URL desteinden
kast http://localhost:5001/VeriYonetimSistemi/LogServisi?kullaniciId=5 gibi bir adrestir.
Dikkat edilecek olursa URL zerinden yaplacak olan bu talep(request) sonrasnda, WCF
servisi kullancID deeri 5 olan kiiyi bulup, log bilgilerini RSS/Atom formatnda hazrlayarak
email olarak gnderebilir. Hemen bu noktada aadaki ekil ile olay daha net kavrayabiliriz.

www.bsenyurt.com Page 506


ekilden de anlalaca zere servisin HTTP Get metoduna gre RSS/Atom destei
bulunmaktadr. Bu sistemin gerekletirilebilmesi iin .Net Framework
3.5 ierisindeWebHttpBinding ve WebHttpBehavior isimli yeni tipler yer almaktadr. Tahmin
edilecei zere WebHttpBinding yeni balayc tiplerdendir(Binding
Type) ve HTTP protokolnnGet gibi metodlarna EndPoint zerinden destek verilmesini
salamak amacyla gelitirilmitir. Burada nemli olan noktalardan biriside
servisin RSS yada Atom formatnda veri ieriklerini nasl hazrlayacadr. Yine daha ncedende
belirtildii gibi bu aslnda XML formatl bir metin ieriinin hazrlanmasndan baka bir ey deildir.
Ne varki .Net Framework 3.5ierisinde gelen yardmc tipler sayesinde bu ilemlerin ynetimli
kod(Managed Code) tarafnda yaplmas mmkndr. Bu
amala SyndicationFeedFormatter veSyndicationItemFormatter abstract tiplerinden tremi
olan eitli snflar bulunmaktadr. Aadaki snf diagramlarnda temel olarak kullanlabilecek
formatlama tipleri gsterilmektedir.

Feed formatlama iin kullanlan tipler;

www.bsenyurt.com Page 507


Grld gibi Atom 1.0 ve RSS 2.0 tarzndaki Feed formatlar iin ikier tip yer almaktadr. Sz
konusu snflarn generic versiyonlar olduunada dikkat edelim.

Item formatlama iin kullanlan tipler;

www.bsenyurt.com Page 508


Grld gibi Atom 1.0 ve RSS 2.0 standartlarna uygun olacak ekilde Item formatlamas iin
kullanlan ikier farkl tip vardr. Bu tiplerden
hepsi SyndicationItemFormatterabstract snfndan tremekte ve XML seriletirmesi iin
gerekli IXmlSerializable arayzn(Interface) uygulamaktadr.Bu bilgiler nda kendi
formatlama modellerimizide gelitirebileceimizi syleyebiliriz. Bu tarz bir ilem
iin Feed veya Item formatlamasnn farkl bir versiyonunu yazmak
istiyorsak SyndicationItemFormatter,SyndicationFeedFormatter abstract snflar
ile IXmlSerializable arayzn gz nne almamz yeterlidir.

.Net 3.5 ierisindeki nesne modeline


bakldnda SyndicationFeed, SyndicationItem, SyndicationCategory, SyndicationPerson,
SyndicationContent gibi pek ok CLR tipinin(Common Language Runtime Type) yer ald
grlr. Bu tiplerden belkide en ok
kullanlanlar SyndicationFeed ve SyndicationItem snflardr. Sz konusu
snflar System.ServiceModel.Web.dll assembly ierisinde yer
alan System.ServiceModel.Syndication isim alannda(Namespace) bulunmaktadr.

Bu kadar teorik bilgiden sonra bir ka rnek ile konuyu geniletmeye alalm. lk olarak basit
bir Console uygulamas gelitirecek ve RSS 2.0/ Atom 1.0 formatlarnda ieriklerin nasl
hazrlanabileceini incelemeye alacaz. Bu amala Visual Studio 2008 zerinden .Net
3.5 modeline uygun olacak ekilde bir Console uygulamas amamz
veSystem.ServiceModel.Web.dll' ini projeye referans etmemiz yeterlidir.

www.bsenyurt.com Page 509


Bu ilemin ardndan kodlar aadaki gibi gelitirebiliriz.

using System;
using System.ServiceModel.Syndication;
using System.Collections.ObjectModel;
using System.Xml;

namespace SyndicationFormatlama
{
class Program
{
static void Main(string[] args)
{
// Bir Feed oluturulur. Parametreler title, description ve Uri bilgileridir.
SyndicationFeed feed=new SyndicationFeed("Makaleler","Burak Senyurt .Net
Makaleleri",new Uri("http://www.bsenyurt.com"));
// Feed yazar tanmlanr. Yazarlar SyndicationPerson tipi ile temsil edilebilirler.
feed.Authors.Add(new SyndicationPerson("selim@bsenyurt.com"));
// Feed iin bir kategori tanmalas yaplr. Bu kategori tanmlamas SyndicationCategory
tipi ile temsil edilebilir.
feed.Categories.Add(new SyndicationCategory(".Net Teknolojileri"));
// Feed ieriinin dili belirtilir.
feed.Language = "TR-TR";
// Son gncelleme tarihi atanr.
feed.LastUpdatedTime = DateTime.Now;

// Feed ierisinde yer alacak elerin her biri SyndicationItem tipindendir.


// SyndicationFeed tipinin Items zellii bu nesne rneklerini barndrr.
// Items zellii Collection<SyndicationItem> tipinden koleksiyonlar kullanr.
// C# 3.0 Object Initializers yardmyla koleksiyon oluturulur ve rnek eler eklenir.
Collection<SyndicationItem> items = new Collection<SyndicationItem>()
{
// Feed ierisindeki eler(Items) SyndicationItem tipi ile temsil edilirler.
// Parametreler title,content,uri,id,lastUpdatedTime
new SyndicationItem("WCF - Front End Service Gelitirmek","WCF
ierisinde ierik yaynlama",new
Uri("http://www.bsenyurt.com/MakaleGoster.aspx?ID=241"),"1",new DateTime(2008,1,30))
,new SyndicationItem("Adm Adm State Machine Worflow
Gelitirmek","Finite State Machine nasl gelitirilir.",new
Uri("http://www.bsenyurt.com/MakaleGoster.aspx?ID=240"),"2",new DateTime(2008,1,15))

www.bsenyurt.com Page 510


};

feed.Items = items; // oluturulan elere ait koleksiyon Feed iin set edilir.

// Atom 1.0 notasyonunda formatlama iin SyndicationFeed nesne rneinin


GetAtom10Formatter metodu ile Atom10FeedFormatter nesnesi rneklenir.
Atom10FeedFormatter atom10Formatter = feed.GetAtom10Formatter();

// Rss 2.0 notasyonunda formatlama iin SyndicationFeed nesne rneinin


GetRss20Formatter metodu ile Rss20FeedFormatter nesnesi rneklenir.
Rss20FeedFormatter rss20Formatter = feed.GetRss20Formatter();

// Atom ieriinin kaydedilecei Xml dosyas XmlWriter tipi ile oluturulur


XmlWriter atom10writer = XmlWriter.Create("MakalelerAtom.xml");
// Formatter nesnesinin WriteTo metodu ile Atom 1.0 notasyonunda formatlanan veri
ierii XmlWriter nesnesinin iaret ettii fiziki dosyaya yazlr.
atom10Formatter.WriteTo(atom10writer);
// XmlWriter nesnesi kapatlr
atom10writer.Close();

// Atom 1.0 iin yaplan formatlama ilemi Rss 2.0 iin benzer ekilde yaplr.
XmlWriter rss20writer = XmlWriter.Create("MakalelerRss.xml");
rss20Formatter.WriteTo(rss20writer);
rss20writer.Close();
}
}
}

Yukardaki kod parasnda rnek olarak oluturulan Feed ierikleri Atom 1.0 ve RSS
2.0 formatlarna uygun olacak ekilde fiziki XML dosyalarna yazdrlmaktadr. Feedoluturulmas
iin SyndicationFeed snfna ait nesne rnekleri kullanlr. Bununla birlikte ierik paylam ile ilgili
ekstra metadata bilgileri sz konusu nesne rneinin eitli zellikleri yardmyla belirlenebilir.
rnein ierii paylaan yazar Author zellii ile belirlenebilir. Yazar gibi bilgiler ierisinde mail
adresi tarznda ek verilerde olabileceindenSyndicationPerson snfna ait nesne rnekleri
ile author elementinin ynetimli kod tarafnda ele alnmas salanabilmektedir. Benzer durum
kategori bilgileri iinde geerlidir. Kategori iin SyndicatioCategory snfndan
yararlanlmaktadr. Feed ierisinde yer alan bilgilendirici eler(Items), SyndicationFeed snf
ierisinde yer alan Itemszellii(Property) ile tutulmaktadr. Items zellii her bir
eleman SyndicationItem snfndan olan generic Collection tipi ile ele alnabilir.

Feed ve ierii oluturulduktan sonra bu verinin Atom 1.0 veya RSS 2.0 formatnda retilmesi
iin Atom10FeedFormatter ve Rss20FeedFormatter snflarna ait nesne rneklerinden
yararlanlmaktadr. Bu nesne rneklerinin retimi iin SyndicationFeed snfna
ait GetAtom10Formatter ve GetRss20Formatter metodlar kullanlr. Veri
ierikleri XML formatl olarak yazlabileceklerinden fiziki kayna iaret etmek
adna XmlWriter tipinden yararlanlr. Sz konusu uygulama
altrldndaMakalelerRss.xml ve MakalelerAtom.xml dosyalarnn ieriklerinin aadaki gibi
olutuu grlr.

MakalelerRss.xml ierii;

www.bsenyurt.com Page 511


MakalelerAtom.xml ierii;

www.bsenyurt.com Page 512


Her iki yapnn ieriini aadaki grafik ile daha kolay bir ekilde de karlatrabiliriz.

www.bsenyurt.com Page 513


Grld zere arada baz farkllklar mevcuttur. Ancak her iki formatta genel standarttr. Gelelim
bu ierikleri bir WCF servisi zerinden nasl yaynlayabileceimize. ncelikli
olarak RSS formatnda yaynlama yaplmasna izin veren bir WCF Servis Ktphanesi(WCF
Service Library) gelitiriyor olacaz. Bu amala Visual Studio 2008 ortamnda .Net
Framework 3.5 ablonlar ierisinde yer alan WCF Service Library proje tipi seilerek ie
balanabilir. Elbette Synidaction iin gerekli tipleri kullanacamzdan servis
ktphanesinin System.ServiceModel.Web.dll assembly' nda referans etmesi gerekmektedir.

Servis ktphanesi ierisinde yer alacak olan szleme(Contract) ve uygulayc snfa ait snf
diyagram(Class Diagram) ile ierikleri ise aadaki gibidir.

www.bsenyurt.com Page 514


IPaylasim arayznn(Interface) ierii;

using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Collections.Generic;
using System.ServiceModel.Syndication;

namespace RssAtomLibrary
{
[ServiceContract]
public interface IPaylasim
{
[OperationContract]
[WebGet]
Rss20FeedFormatter RssCiktisi();
}
}

Arayz(Interface) tanmlamasnda belkide dikkati eken en nemli noktalardan


biriside WebGet isimli niteliin(attribute) kullanllmasdr. Bu nitelik sz konusu
servise HTTP Getmetoduna gre talepte(Request) bulunabileceini gstermektedir.

Paylasim snfnn(Class) ierii;

using System;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Web;
using System.Collections.Generic;
using System.ServiceModel.Syndication;

namespace RssAtomLibrary
{

www.bsenyurt.com Page 515


public class Paylasim : IPaylasim
{
#region IPaylasim Members

public Rss20FeedFormatter RssCiktisi()


{
// ncelikle bir Feed oluturulur
SyndicationFeed feed = new SyndicationFeed();

// erik paylam yapan yazarlar SyndicationPerson snf yardmyla tanmlanrlar ve


Authors koleksiyonuna dahil edilirler.
feed.Authors.Add(new SyndicationPerson("selim@bsenyurt.com", "Burak Selim
Senyurt", "http://www.bsenyurt.com"));
feed.Authors.Add(new SyndicationPerson("kariim@bsenyurt.com", "Kariim Abdul
Cabbar", "http://www.bsenyurt.com"));

// eriin ilgili olduu kategoriler SyndicationCategory snf yardmyla rneklenir ve


Categories koleksiyonuna dahil edilir.
feed.Categories.Add(new SyndicationCategory(".Net"));
feed.Categories.Add(new SyndicationCategory("C#"));

// erik il ilgili aklama TextSyndicationContent snf yardmyla eklenir


feed.Description = new TextSyndicationContent(".Net ve C# arlkl makaleler",
TextSyndicationContentKind.Html);
feed.Language = "Tr-Tr"; // erik dili belirtilir
feed.LastUpdatedTime = DateTime.Now; // Son gncelleme tarihi belirtilir
feed.Title=new TextSyndicationContent(".Net ile ilgili Herey"); // eriin bal
TextSyndicationContent snf yardmyla belirtilir.

// Ogeler eklenir
List<SyndicationItem> items = new List<SyndicationItem>()
{
// Feed ierisindeki eler(Items) SyndicationItem tipi ile temsil edilirler.
// Parametreler title,content,uri,id,lastUpdatedTime
new SyndicationItem("WCF - Front End Service Gelitirmek","WCF ierisinde
ierik yaynlama",new Uri("http://www.bsenyurt.com/MakaleGoster.aspx?ID=241"),"1",new
DateTime(2008,1,30))
,new SyndicationItem("Adm Adm State Machine Worflow Gelitirmek","Finite
State Machine nasl gelitirilir.",new
Uri("http://www.bsenyurt.com/MakaleGoster.aspx?ID=240"),"2",new DateTime(2008,1,15))
};

feed.Items = items;
return new Rss20FeedFormatter(feed);
}

#endregion
}
}

Paylasim snfnn RssCiktisi isimli metodu Rss20FeedFormatter tipinden bir nesne rneini
dndrmektedir. Bu nesne rneklenirken parametre olarak SyndicationFeed tipinden oluturulan
nesne rnei parametre olarak verilmektedir. Servis ktphanesinin(Service Library) bu
ekilde hazrlanmasnn ardndan artk Host uygulamann yazlmasna geilebilir. Host uygulama
servis ktphanesini, System.ServiceMode.dll ve
yine System.ServiceModel.Web.dll assembly' larn referans etmelidir.

www.bsenyurt.com Page 516


Host uygulama basit olarak bir Console program eklinde tasarlanabilir.

using System;
using System.ServiceModel;
using System.ServiceModel.Web;
using RssAtomLibrary;
using System.ServiceModel.Syndication;
using System.Xml;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
WebServiceHost host = new WebServiceHost(typeof(Paylasim), new
Uri("http://localhost:65001/MakalePaylasimServisi"));

host.Open();

Console.WriteLine("Servis durumu {0} ", host.State);


Console.WriteLine("Host dinlemede...kmak iin bir tua basnz...");
Console.ReadLine();

host.Close();
}
}
}

Host uygulamada ilk dikkati eken noktalardan birisi WebServiceHost snfna ait bir nesne
rneinin kullanlmasdr. Bilindii gibi normal artlarda ServiceHost snfndan
yararlanlmaktadr. WebServiceHost nesnesi rneklenirken ilk parametre olarak servis
szlemesini(Service Contract) uygulayan snfn tipini almaktadr. Sonraki parametrede ise
servis adresi belirlenmektedir. Host' un almas iin yine Open metoduna bavurulmaktadr.
Benzer ekilde kapatma ilemi iinde Close fonksiyonundan yararlanlr. Bu ilemlerin ardndan
servis uygulamas altrlabilir. Servis uygulamas alyorken herhangibir tarayc
penceresinden http://localhost:65001/MakalePaylasimServisi/RssCiktisiadresi talep edilirse
aadaki ekran ktsnda yer alan grnt elde edilecektir.

www.bsenyurt.com Page 517


Grld gibi servisteki RssCiktisi isimli metodun sonucu HTTP zerinden elde edilebilmektedir.
Burada dikkat edilmesi gereken nemli bir nokta vardr. URL adresinin sonu, RSS kts veren
metodun ad ile ayndr. Eer farkl bir adres girilirse Service EndPoint bulunamayacak ve
aadakine benzer bir ekran ile karlalacaktr.

Bu durum istemci tarafnada bir alam zaman istisnas(Runtime Exception) olarak


yansyacaktr. Peki istemci kod tarafndan bu tip bir ierii nasl ele alabilir? Bu amala basit bir
istemci uygulamay Console projesi olacak ekilde gelitirip devam edelim. Istemci tarafnda
standart XmlReader veya XmlDocument nesneleri yardmyla HTTP Get ile talep edilen servis
ierii ekilebilir. Ancak .Net Framework 3.5 ierisinde gelen Syndication tipleri yardmyla bu

www.bsenyurt.com Page 518


ilemi gerekletirmek ok daha kolaydr. Bu nedenle istemci tarafndaki
uygulamaya System.ServiceModel.Web.dll assembly' nn referans edilmesi gerekmektedir.

Dikkat edilecei zere herhangibir ekilde servis referans eklenmemi yada proxy snf
oluturulmamtr. Nitekim servise gnderilecek olan talep(request) aslndaEndPoint davran
sergileyen bir metoda doru HTTP Get zerinden salanacaktr. Bu sebeplerden istemci tarafndaki
kodlar ok basit olarak aadaki gibi gelitirilebilirler.

using System;
using System.Xml;
using System.ServiceModel.Syndication;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("RSS ieriini ekmek iin bir tua basnz");
Console.ReadLine();

XmlReader reader =
XmlReader.Create("http://localhost:65001/MakalePaylasimServisi/RssCiktisi");
SyndicationFeed feed = SyndicationFeed.Load(reader);

Console.WriteLine(feed.Title.Text);
foreach (SyndicationPerson yazar in feed.Authors)
{
Console.WriteLine("\t{0} \t {1}",yazar.Name,yazar.Email);
}

foreach (SyndicationItem item in feed.Items)


{
Console.WriteLine(String.Format("{0} : {1}
{2}",item.Id,item.Title.Text,item.Links[0].Uri));
}
}
}
}

lk olarak XmlReader snfndan


yararlanlarak http://localhost:65001/MakalePaylasimServisi/RssCiktisi adresinden talepte

www.bsenyurt.com Page 519


bulunulmaktadr. Bu talep sonras elde edilen XML ktsnn SyndicationFeed snf tarafndan
daha kolay bir ekilde ele alnabilmesini salamak
amacyla static Load metoduna XmlReader nesne rnei parametre olarak verilir. Bu ilemin
ardndan Feed ile ilgili olarak balk(title) bilgisi elde edilir. Bununla
birlikte SyndicationPerson snf ve Authors zelliklerinden yararlanlarak yazarlara
aitisim(Name) ve elektronik posta(e mail) bilgileri ekilir. Son olarakta Items koleksiyonu
dolalarak var olan tm eler SyndicationItem snfna ait nesne rnekleri yardmyla ele alnr.
rnek olarak elerin Id, balk(Title) ve url bilgileri verilir. stemcilerin talepte bulunabilmesi
ve Feed ieriklerini ekebilmesi iin ok doal olarak servis tarafnnn alyor olmas gerekir. Eer
bu art salanrsa aadakine benzer bir ekran grnts ile karlalacaktr.

Grld gibi Feed ierii istemci tarafna baarl bir ekilde aktarlmtr.

erik paylam(Syndication) ile ilikili bir dier nemli konuda bir servisin yeri
geldiinde RSS 2.0 formatnda yeri geldiinde de Atom 1.0 formatnda ierik paylamna izin
vermesidir. Bu amala servis tarafnda baz deiiklier yapmak gerekecektir. Bu amala az nce
gelitirilen servis ktphanesindeki(WCF Service Library) arayz(Interface) aadaki gibi
deitirerek ie balayalm.

[ServiceContract]
[ServiceKnownType(typeof(Rss20FeedFormatter))]
[ServiceKnownType(typeof(Atom10FeedFormatter))]
public interface IPaylasim
{
[OperationContract]
[WebGet]
Rss20FeedFormatter RssCiktisi();

[OperationContract]
[WebGet(UriTemplate="IcerikOzeti?icerikTipi={icerikTipi}")]
SyndicationFeedFormatter IcerikOzeti(string icerikTipi);
}

ncelikli olarak ServiceKnownType nitelii(attribute) ile


servisin Rss20 ve Atom10 formatlarndan nesne rnekleri dndrebilecei belirtilmektedir.
Nitekim ierik paylam modelinde ilgili servis metodlarnn SyndicationFeedFormatter snf ile
tanabilecek tipler dndrmeleri arttr. Dier taraftan IcerikOzeti metodunda
kullanlan WebGet niteliinde birquerystring bildirimi yaplmaktadr. Bu querystring bildirimi
metoda HTTP Get zerinden gelecek olan parametre bilgisinin ablonunu

www.bsenyurt.com Page 520


tanmlamaktadr. Arayz szlemesini(Interface Contract) uygulayan snf ierisindeki
metodun ise aadaki gibi gelitirilmesi yeterlidir.

public SyndicationFeedFormatter IcerikOzeti(string icerikTipi)


{
SyndicationFeed feed = new SyndicationFeed();

feed.Authors.Add(new SyndicationPerson("selim@bsenyurt.com", "Burak Selim Senyurt",


"http://www.bsenyurt.com"));
feed.Authors.Add(new SyndicationPerson("kariim@bsenyurt.com", "Kariim Abdul Cabbar",
"http://www.bsenyurt.com"));

feed.Categories.Add(new SyndicationCategory(".Net"));
feed.Categories.Add(new SyndicationCategory("C#"));

feed.Description = new TextSyndicationContent(".Net ve C# arlkl makaleler",


TextSyndicationContentKind.Html);
feed.Language = "Tr-Tr";
feed.LastUpdatedTime = DateTime.Now;
feed.Title = new TextSyndicationContent(".Net ile ilgili Herey");

List<SyndicationItem> items = new List<SyndicationItem>()


{
new SyndicationItem("WCF - Front End Service Gelitirmek","WCF ierisinde ierik
yaynlama",new Uri("http://www.bsenyurt.com/MakaleGoster.aspx?ID=241"),"1",new
DateTime(2008,1,30))
,new SyndicationItem("Adm Adm State Machine Worflow Gelitirmek","Finite State
Machine nasl gelitirilir.",new
Uri("http://www.bsenyurt.com/MakaleGoster.aspx?ID=240"),"2",new DateTime(2008,1,15))
};
feed.Items = items;

if (icerikTipi == "atom")
return new Atom10FeedFormatter(feed);
else if (icerikTipi == "rss")
return new Rss20FeedFormatter(feed);
else
return null;
}

Bu metod ierisinde dikkat edilmesi gereken en nemli nokta icerikTipi deerine


gre Atom10FeedFormatter veya Rss20FeedFormatter tipinden nesne rnekleri
dndrlmesidir. Bu sebepten dolayda metodun dn
tipi SyndicationFeedFormatter tipindendir. Artk istemciler servise talepte
bulunurlarken rss veya atom formatnda ierik isteyebilirler. Aadaki ekran ktlarnda bu durum
ak bir ekilde grlmektedir.

Rss talebi;

www.bsenyurt.com Page 521


Atom talebi;

www.bsenyurt.com Page 522


Bylece geldik bir makalemizin daha sonuna. Bu makalemizde basit olarak .Net Framework
3.5 ile gelen tipler sayesinde bir WCF(Windows Communication Foundation) servisi
zerinden RSS 2.0veya Atom 1.0 formatnda ierik paylamnn nasl yaplabileceini incelemeye
altk. lerleyen makalelerimizde WCF in .Net Framework 3.5 ile gelen yeniliklerini incelemeye
devam edeceiz. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Front-End Service Gelitirmek ( 30.01.2008 ) -


WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation(WCF) mimarisinde belkide en kritik unsurlardan


birisi EndPoint kavramdr. EndPoint, Servis Ynelimli Mimari(Service Oriented Architecture
- SOA)uygulamalar gelitirmek iin kullanlan WCF modelinde, istemciler(Clients) ile
servis(Service) arasndaki haberlemede yer alan kritik bir paradr. WCF' in temellerini
incelediimiz daha nceki yazlarmzda, EndPoint kavramnn aslnda WCF mimarisinin ABC' si
olduundan bahsetmitik. ABC bilindii zere adres(Address),

www.bsenyurt.com Page 523


balayc(Binding) veszleme(Contract) bilgilerinden olumaktadr. Buna gre bir EndPoint
yardmyla, servisin istemcilere hangi adresten, hangi protokolle, hangi kurallara gre neyi
sunaca bilgisi aktarlabilir. Bununla birlikte, EndPoint' ler istemci tarafndan gelecek olan taleplerin
karlanmasnda da byk neme sahiptir.

Bir WCF servisi, kendi zerinde birden fazla EndPoint bilgisi tayabilir. stelik bu EndPoint' ler
ayn szleme(Contract) veya farkl szlemeler(Contract) iinde tanmlanm olabilirler. Bu
noktada WCF servisi ald mesaj hangi EndPoint bileenine ileteceinede karar vermektedir. ok
doal olarak gelitiriciler bu karar aamasna mdahale edebilir ve EndPoint ynlendirmelerini
programlayabilirler. te bu da Front-End Service ad verilen WCF servislerinin gelitirilebilmesine
neden olmaktadr ki makalemizin konusuda budur. Baz durumlarda bir WCF servisi,
istemcilerden(Clients) gelecek olan mesajlar asl servislere ynlendirmek iin kullanlabilir.
Aadaki ekilde bu durum analiz edilmeye allmaktadr.

Bu grafie gre istemcilerin talepleri(Requests) Front-End Service tarafndan karlanmakta,


sonrasnda ise bu talepler(Request) ilgili olan asl WCF servislerine ynlendirilmektedir. Hatta
ynlendirme ilemi Front-End Service' in arkasnda duran asl WCF servisi ierisindeki farkl
EndPoint noktalarna doruda olabilir. Bu tarz bir ynlendirme iin pek ok sebep vardr. zellikle
istemcilerin kullanmak istedikleri servislere dorudan eriemedii durumlar gz nne alnabilir.
rnein arka tarafta duran WCF servisleri ile istemciler(Clients) farkl ve birbirlerini
gremeye alarda(Network) bulunabilirler. Dier yandan, Front-End Service' lerin baz
avantajlarda vardr. rnein yk dengelemesini (Load Balancing) daha iyi yapabilirler. Bu
performans ve dengeli ynetim asndan nemli bir unsurdur.

Load Balancing modelinde, Front-End Service genellikle istemcilere(Clients) tek bir adres
zerinden hizmet vermektedir. stemcilerden gelen talepler arka servislere eit ekilde
datlmaktadr. Bir baka deyile istemciler hep ayn adrese talepte bulunurlarken, Front-
End Service arka tarafta duran farkl port numaralarna sahip EndPoint noktalarna yk
eit ekilde yaymaktadr. Bu sayede arka tarafta daha dengeli alan bir servis topluluu
tasarlanmas mmkn olmaktadr.Tabi bunun iin yazlan Front-End Service ierisinde
zel kodlama yaplmas gerekmektedir.

Ayrca, kt niyetli mesajlarn szmasnn engellemesi iinde tek bir merkez olarak kullanlabilirler.
Elbetteki arka tarafta ynlendirilme yaplacak servis ve EndPoint says ok fazla olabileceinden
Front-End Service ynetimi biraz daha zordur.

www.bsenyurt.com Page 524


Front-End WCF Service' ler istemciden gelen talepleri(Request) deerlendirerek
uygun olan gerek arka WCF Service' lerine ynlendirirler.

Front-End Service' ler ounlukla iki ana kategoride ele alnmaktadr. Adres tabanl
ynlendirme(Address-Based Routing) yapanlar ve ierik tabanl ynlendirme(Content-
Based Routing) yapanlar. Adres tabanl ynlendirme sisteminde, istemcilerin hangi EndPoint
noktalarna talep (Request) gnderdikleri nemlidir. Ancak ierik tabanl ynlendirme sisteminde
istemcilerin talep olarak gnderikleri mesaj ieriklerine baklr. Mesaj ieriklerinden rnein
kullancya ait kimlik bilgileri(Identity Informations), transaction id deerleri vs... elde
edilebilir. Bunlarn durumuna gre uygun olan WCF servislerine ynlendirme ilevini Front-End
Service stlenir. rnein bir servise talepte bulunan kullanclarn iki farkl profilde olduklarn gz
nne alalm. Aadaki ekilde bu durum gsterilmeye allmaktadr.

Burada zel kullanclar taleplerine hizmet alrlarken, Front-End Service tarafndan daha hzl bir
sistem zerinde konulandrlm bir WCF servisine ynlendirilmektedirler. Dier taraftan normal
kullanclar iin bu tip bir ynlendirme daha farkl yaplmaktadr. te bu tam anlamyla Front-End
Service' e gelen kullanclarn kimlikleri(Identity) ile alakaldr ve ierik tabanl
ynlendirme(Content Based Routing) sisteminin bir rneidir. Nitekim kimlik bilgileri
ounlukla mesaj ieriklerinden elde edilebilmektedir.

WCF mimarisi ierisinde Front-End Service' lerin nasl yazlacan incelemeden nce, bir WCF
servisinin gelen mesajlar kabaca nasl ele aldn anlamakta yarar vardr. zellikle kod tarafnda
gelen taleplerin ele alnmasnda nemli rol oynayan CLR Tipleri(Common Language Runtime
Types) bulunmaktadr. Hereyden nce WCF alma zaman motoru(WCF Runtime
Engine) gelen talepleri deerlendirmek iin kanal ynlarn(Channel Stacks) kullanmaktadr.
Bu kanal ynlar ChannelDispatcher veEndPointDispatcher ad verilen tiplere ait nesne
rnekleri ile sk bir ilikidedir. En basit anlamda ChannelDispatcher nesne rnekleri, gelen
taleplerin doru EndPointDispatcherbileenlerine aktarlmasndan sorumludur. Bu anlamda bir
ChannelDispatcher nesnesi, birden fazla EndPointDispatcher bileenini ele
alabilmektedir. EndPointDispatcher nesnesleri, gelen mesajlar zmlemek ve servis ierisindeki
uygun yerlere iletmekten sorumludur. EndPointDispatcher nesneleri ounlukla servis ierisinden
talepte bulunulan fonksiyonellie ait metod arlarn gerekletirmektedir. Bu son derece basit ve
yzeysel bir bak asdr. Nitekim bu ilemler srasnda ok sayda ek yardmc CLR(Common
Language Runtime) nesneside devreye girmektedir. Aslnda alma zamanndaki durum az ok
aadaki ekilde grld gibidir.

www.bsenyurt.com Page 525


Grld gibi istemcilerden EndPoint noktalarna doru gelen mesajlar kanal ynlar(Channel
Stack) zerinden ChannelDispatcher nesne rneklerine ulamaktadr. Sonrasnda ise
talepler(Requests) uygun olan EndPointDispatcher bileenleri tarafndan ele alnmaktadr. Bu
noktada dikkat edilmesi gereken bir husus vardr. Gelen mesaj herhangibir EndPointDispatcher
tarafndan karlanmassa ServiceHost nesnesinin UnknownMessageReceived olay tetiklenir.
ok doal olarak bu olayn kontrol gelitirici(Developer) tarafndan yaplabilir.

Front-End Service' ler ierisinde, istemciden(Clients) gelen talepler gerek WCF servislerine
ynlendirilmeden nce pek ok ilemde gerekletirilebilmektedir. rnein kimlik dorulama yada
arka servislere parametre aktarma gibi ilemler sz konusu olabilir. Dier yandan Front-End
Service' lerin tasarlanmas srasnda dikkat edilmesi gereken baz noktalar vardr. Ynlendirici
servisin, hedef servis szlemelerini uyguluyor olma zorunluluu nedeni ile ynetilebilirlik
zorlamaktadr. Buna bal olarak seriletirilebilir(Serializable) verilere ait szlemelerinde
ynlendirici servis tarafndan bilinme zorunluluu sz konusudurki bu da
ynetilebilirlii(Management) zorlatrmaktadr.

Bu ksa bilgilerden sonra adm adm bir Front-End WCF Servisinin nasl oluturulaca
incelenmeye balanabilir. ncelikli olarak iki adet servis gelitirilecek ve bu servisler
birerEndPoint noktas barndracak ekilde tasarlanacaktr. Bu noktada Front-End Service,
gelen talepleri(Request) dorudan arka taraftaki uygun servis ve EndPoint noktalarna
ynlendirmekle grevli olacaktr. Senaryo kabaca aadaki ekilde grld gibidir.

www.bsenyurt.com Page 526


Ynlendirme ilemlerini kolay bir ekilde anlayabilmek iin basit
olarak BasicHttpBinding balayc tipinden(Binding Type) yararlanlmaktadr. Back-
End servisler iki adettir ve her biri farkl port numaralar zerinden HTTP bazl olacak ekilde
yaynlama yapmaktadr. Her iki Back-End Service uygulamasda Console olacak ekilde
tasarlanmaktadr. Elbetteki gerek hayat senaryolarnda bu servisler IIS(Internet Information
Service) zerinden yada bir Windows Servisi ierisinde gml olacak ekildede alabilirler. u
durumda her iki istemcide bu farkl HTTP servislerine talepte bulunmaktadr. Bizim amacmz
bir Front-End Service yazmak ve zerinden Load-Balancing yaparak istemcilerden gelecek olan
talep ykn servislere eit ekilde datmaya almaktr. Front-End Service gelitirilmeye
balamadan nce ilk olarak servis szlemesinin(Service Contract) yer aldWCF snf
ktphanesini(WCF Service Library) tasarlayarak ie balanmaldr. Bu ktphanenin ierii
konunun anlalr olmas asndan mmkn olduu kadar basit tutulmutur.

www.bsenyurt.com Page 527


ICebir arayzne(Interface) ait kod ierii aadaki gibidir.

[ServiceContract]
public interface ICebir
{
[OperationContract]
int Topla(int x, int y);
}

Cebir snfna(Class) ait kod ierii ise aadaki gibidir.

[ServiceBehavior(InstanceContextMode= InstanceContextMode.PerCall)]
public class Cebir : ICebir
{
#region ICebir Members

public int Topla(int x, int y)


{
return x + y;
}

#endregion
}

Bu ilemin ardndan Back-End Service' lerin tasarlanmasna balanabilir. Her iki


serviste Console uygulamas zerinden host edilmektedir. Aralarndaki tek fark yaynlama
adreslerindekiport numaralarnn farkl olmasdr. Sembolik olarak bu port numaralar 50001 ve
50002 olarak set edilmektedir. Sz konusu Console uygulamalar ok doal olarak MatematikLib
isimliWCF servis ktphanesini(WCF Service
Library) ve System.ServiceModel.dll assembly' n referans etmelidir.

www.bsenyurt.com Page 528


Bununla birlikte konfigurasyon dosyasnn(App.config) ierii aadaki gibidir.

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="CebirServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="CebirServiceBehavior" name="MatematikLib.Cebir">
<endpoint address="http://localhost:50001/Matematik/Cebir.svc" binding="b
asicHttpBinding" bindingConfiguration="" name="HttpEndPoint" contract="MatematikLib.ICebir"
/>
</service>
</services>
</system.serviceModel>
</configuration>

EndPoint tanmlamalar BasicHttpBinding balayc tipini kullanmaktadr. Bununla birlikte her iki
serviste ayn WCF szlemesini(ICebir) sunmaktadr. Yukardaki konfigurasyon dosyasnn sahibi

www.bsenyurt.com Page 529


olan sunucu uygulama HTTP protokolne gre 50001 numaral port zerinden yaynlama
yaparken dier Console uygulamasda 50002 numaral port zerinden hizmet vermek zere
ayarlanmtr. zellikle gerek hayat vakalarnda, ayn servis ierisinde yer alan birden fazla
farkl EndPoint tanmlamas da sz konusu olabilir. Yada bu farkl tipteki EndPoint bileenleri
farkl servisler zerine yaylm olabilir. Servis uygulamalarna ait kod ierikleri aadaki gibi
tasarlanabilir.

using System;
using System.ServiceModel;
using MatematikLib;

namespace BackEndService1
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Cebir));
host.Open();
Console.WriteLine("Host dinlemede\nKapatmak iin bir tua basnz");
Console.ReadLine();
host.Close();
}
}
}

Standart olarak servis uygulamas, Cebir tipi zerinden bir ServiceHost nesnesi rneklemekte
ve Open metodu ile hizmete balamaktadr. Uygulama kapatlrkende Close metodu yardmyla
hizmet sonlandrlmaktadr. Bu basit servisleri kullanacak olan istemcilerde
birer Console uygulamas olarak tasarlanabilirler. Sz konusu istemci uygulamalar iin
gerekli proxy snflarnn elbette retilmesi arttr. Bu amala svcutil arac kullanlarak aadaki
ekran grntsnde olduu gibi istemciler iin gerekli proxy snflar retilebilir.(HTTP zerinden
yaynlama yaplmasna ramen servis uygulamalar IIS zerinden host edilmediklerinden Visual
Studio IDE' si ierisinde Add Service Reference seenei kullanlamamaktadr. Bu nedenle svcutil
aracndan yardm alnmaktadr.)

www.bsenyurt.com Page 530


Bu ilemlerin ardndan ilgili proxy snf ve konfigurasyon dosyas istemci uygulamalara
eklenmelidir. stemci uygulamalar iin oluturuluan output.config dosyasnn ierii biraz daha
sadeletirilerek aadaki hale getirilebilir. Bu rnekte IIS zerinden bir hosting yaplmadndan
konfigurasyon dosyasnda yer alan EndPoint elementi
ierisine addressnitelii(Attribute) atlmayacaktr. Bu nedenle adres bilgisininde ak bir ekilde
girilmesi arttr. (Bununla birlikte Output.config adnn App.config olarak deitirilmesi nerilir)

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


<configuration>
<system.serviceModel>
<client>
<endpoint
binding="basicHttpBinding" address="http://localhost:50001/Matematik/Cebir.svc" co
ntract="ICebir" name="CebirClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

stemci uygulamann kod ierii aadaki gibi tasarlanabilir.

using System;

www.bsenyurt.com Page 531


using System.ServiceModel;

namespace HttpClient1
{
class Program
{
static void Main(string[] args)
{
CebirClient client = new CebirClient();
double toplam=client.Topla(4, 5);
Console.WriteLine(toplam.ToString());
Console.WriteLine("kmak iin bir tua basnz.");
Console.ReadLine();
}
}
}

kinci istemci uygulamada ayn trden olmakla birlikte sadece 50002 numaral port adresi
zerinden talepte bulunacak ekilde ayarlanmaldr. Bylece elimizde hazr bir sistem mevcuttur.
Artk Front-End Service' in yazlmasna balanabilir. Front-End Service uygulamasda aslnda bir
servis uygulamas olduundan kendi ierisinden istemcilere birszleme(Contract) sunmak
durumundadr. Ne varki burada istemcilerden gelen taleplerin, dengeli bir ekilde arka
servislere(Back-End Services) ynlendirilmesi sz konusudur. Ayrca gelenSOAP paketlerinin
ayrtrlarak uygun olan arka servislere aktarlmasda gereklidir. Dolaysyla Front-End
Service kendi ierisinde zel bir servis szlemesi sunmaldr. Bu nedenle ilk olarak ierii
aadaki gibi olan bir WCF Servis ktphanesinin(WCF Service Library) gelitirilmesi
gereklidir.

IRouterContract arayzne(interface) ait kod ierii aadaki gibidir.

www.bsenyurt.com Page 532


using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace RouterLib
{
[ServiceContract]
public interface IRouterContract
{
[OperationContract(Action="*",ReplyAction="*")]
Message MesajIsle(Message msg);
}
}

Arayz ierisinde dikkat ekici noktalardan


birisi OperationContract nitelii(Attribute) ierisinde
uygulanan Action ve ReplyAction zellikleridir. Her iki zellie * deerinin verilmesi ile, talep
edilen operasyon istekleri ne olursa olsun ilem yaplaca belirtilmetkedir. Buradaki operasyon
isimleri bilindii zere WSDL(Web Service Description Language) dkmannca belirtilen
adlardr. Servis tarafnda her ne kadar tek bir fonksiyonellik sz konusu olsada birden fazla ilevin
olduu senaryolarda kabul edilen ve cevaplanan operasyon adlarnn belirtilmesi yerine * seenei
sklkla kullanlmaktadr. Bunun yannda arayz(Interface) ierisindeki
metod System.ServiceModel.Channels isim alannda yer alan Message tipinden bir parametre
almakta ve ayn tipten bir rnek dndrmektedir. Bu metodun amac, istemciden gelen mesajlarn
arka servislere ynlendirilmesini salamaktr. Ayrca arka servislerden gelen mesajlarnda
istemcilere ulatrlmasnda nemli bir role sahiptir. Gerektende Message snfnn asli
grevi EndPoint noktalar arasndaki iletiimi salamaktr. Gelitirilen bu arayz
uygulayan RouterContract isimli snfa ait kod ierii ise aadaki gibidir.

using System;
using System.ServiceModel;
using System.ServiceModel.Channels;

namespace RouterLib
{
[ServiceBehavior(ValidateMustUnderstand=false,InstanceContextMode=
InstanceContextMode.PerCall)]
public class RouterContract : IRouterContract
{
private static IChannelFactory<IRequestChannel> fabrika = null;
private EndpointAddress adres1 = new
EndpointAddress("http://localhost:50001/Matematik/Cebir.svc");
private EndpointAddress adres2 = new
EndpointAddress("http://localhost:50002/Matematik/Cebir.svc");
private static int dengeSayaci = 1;

static RouterContract()
{
BasicHttpBinding binding = new BasicHttpBinding();
fabrika = binding.BuildChannelFactory<IRequestChannel>();
fabrika.Open();
}

#region IRouterContract Members

public Message MesajIsle(Message msg)

www.bsenyurt.com Page 533


{
IRequestChannel kanal = null;
Message cevap = null;
try
{
if (dengeSayaci % 2 == 0)
kanal = fabrika.CreateChannel(adres1);
else
kanal = fabrika.CreateChannel(adres2);

dengeSayaci++;
kanal.Open();
cevap = kanal.Request(msg);
kanal.Close();
}
catch (Exception exp)
{
}
return cevap;
}
#endregion
}
}

ncelikli olarak snf ierisinde iki adet EndPointAddress deikeni tanmlandna dikkat edelim.
Bu deikenler tahmin edilecei zere Back-End Service' lere eriim adreslerini tamaktadrlar.
Dier taraftan ynlendirici serviste PerCall modelinde tasarlanmtr. Buda istemcilerden gelecek
her arda bir servis rnei(Service Instance)oluturulaca anlamna gelmektedir. Burada
sadece tek bir servis referans olmasn salamak iin static yapc metod(Static
Constructor) ierisinde baz kodlamalar yaplmaktadr. MesajIsle metodu ierisinde ncelikli
olarak IRequestChannel arayzne ait bir deiken tanmlanmaktadr. Bu deikenin retilmesi
iin genericIChannelFactory<T> tipinden olan fabrika isimli deikenin CreateChannel metodu
kullanlmaktadr. Bir baka deyile istemciden gelen talepler sonrasnda dengeSayaci deikeninin
ieriine gre uygun olan kanal nesnesi(Channel Object) oluturulmakta ve bu kanal
alarak talebin(Request) aktarlmas ve sonucunun alnarak geriye dndrlmesi
salanmaktadr.

Request metodu, MesajIsle metoduna gelen Message tipinden parametre deerini kullanarak,
oluturulan kanal nesnesine bir talepte bulunmaktadr. Bu talep Front-End Service' inarkasnda
yer alan Back-End servislerden birisine doru gerekletirilir. Request metodu arka servisten
gelen cevab yine bir Message deikeni tipinden alarak sonucun elde edilmesini
salamaktadr.(Servis taraf ile manuel olarak konuma tekniklerini ilerleyen makalelerimizde
incelemeye alacaz). Artk ynlendirici servis tasarlanabilir. Bunun iin yine
bir Console uygulamas gz nne alnabilir. Console uygulamas bu kez RouterLib WCF servis
ktphanesini(WCF Service Library) referans etmelidir.

www.bsenyurt.com Page 534


Sz konusu Front-End Service uygulamasnn konfigurasyon ierii aadaki gibi tasarlanabilir.

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="RouterServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="RouterServiceBehavior"
name="RouterLib.RouterContract">
<endpoint address="http://localhost:50003/Matematik/Cebir.svc" binding="b
asicHttpBinding" bindingConfiguration="" name="RouterEndPoint"
contract="RouterLib.IRouterContract" />
</service>
</services>
</system.serviceModel>
</configuration>

Bu konfigurasyon dosyas ierisinde dikkat edilmesi gereken en nemli nokta adres bilgisidir.
Dikkat edilecei zere 50003 numaral porttan hizmet verecek bir EndPoint tanmlamas
yaplmaktadr. Buna gre istemciler 50001 veya 50002 iin ayr ayr talepte bulunmaktansa,
sadece 50003' e istekte bulunacaklardr. Onlar karlayan Front-End Service'
te LoadBalancing algoritmasna gre arka servisler arasnda talepleri dengeli bir ekilde
paylatracaktr. RouterService isimli Front-End Service uygulamasnn kod ierii ise aadaki
gibidir.

using System;

www.bsenyurt.com Page 535


using System.ServiceModel;
using RouterLib;

namespace RouterService
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(RouterContract));
host.Open();
Console.WriteLine("Ynlendirici servis dinlemede\nkmak iin bir tua basnz");
Console.ReadLine();
host.Close();
}
}
}

Bu ilemin arkasndan tek yaplmas gereken istemci uygulamalardaki konfigurasyon dosyalarnda


yer alan adres bilgisini http://localhost:50003/Matematik/Cebir.svc olacak ekilde
deitirmektir. Test aamasnda nce Back-End Service' lerin altrlmas, sonrasnda Front-
End Service' in yrtlmesi gerekmektedir. Bu servislerin tamam alt srece istemciler
hizmet alabilirler. Uygulama eer debug edilerek altrlrsa MesajIsle metodu ierisinde aadaki
Flash grselinde yer alan durumun olutuu grlr.

www.bsenyurt.com Page 536


Burada dikkat edilecei zere istemcilerden gelen iki talep sonrasnda, if dngs farkl arka servis
eriimleri gerekletirmektedir. Buda zaten kurulan Load-Balancing algoritmasnn bir sonucudur.
Sonu olarak Front-End Service' in eklenmesi ile birlikte sistem aadaki ekilde grlen hale
gelmitir.

www.bsenyurt.com Page 537


Gerek hayat senaryolarnda Back-End Service ierisinde yer alan EndPoint noktalar
farkl balayc tipleri(Binding Type) kullanyor olabilirler. Bu durumda ynlendirici servislerin
tasarlanmas biraz daha zorlamaktadr. rnein WS standartlarna uygun balayc
tiplerin(rnein WsHttpBinding gibi) kullanld durumlarda gvenlik(Security) ile ilikili
ayarlamalarn mutlaka yaplmas gerekmektedir.
Buda mesaj(Message) yada iletiim(Transport) gvenlii iin ek ayarlamalarn hem istemciler
hemde servisler zerinde gerekletirilmesi anlamna gelmektedir. Bu makalemizde bu tip konular
gz ard edilerek basit anlamda Load-Balancing yapan bir ynlendirici servisin nasl
tasarlanabilecei incelenmeye allmtr. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Adm Adm State Machine Workflow


Gelitirmek ( 15.01.2008 ) - WWF
Deerli Okurlarm Merhabalar,

yle i aklar vardrki, sre(Process) ierisinde yer alan admlar arasndaki geiler herhangibir
zamanda ve herhangibir olayn meydana gelmesi sonrasnda mmkn olur. ounlukla
terminolojide Sonlu Durum Makinesi(Finite State Machine) olarak geen bu yaklama gre,
herhangibir nesnel varln zaman ierisinde sahip olabilecei durumlar iaret edilmektedir. ok

www.bsenyurt.com Page 538


doal olarak bu durum, programatik ortamda yer alan i problemlerinin zmndede gz nne
alnmaktadr. te bu makalemizde Sonlu Durum Makinesi(Finite State Machine) kavramn
irdelemeye ve Windows Workflow Foundation ierisindeki kullanmn aratrmaya alacaz.
Balamadan nce Sonlu Durum Makinesi(Finite State Machine) kavramn anlamaya alamakta
yarar vardr.

ncelikli olarak sonlu kelimesinin kullanlmasnn sebebi sz konusu nesnel varln sahip
olabilecei durumlarn(State) sayl olmasdr. Bir baka deyile bu yaklama gre bir makinenin
sahip olabilecei durumlarn says bellidir. Dier taraftan makinenin zaman ierisinde sahip
olabilecei haller onun durumlarn(States) ifade etmektedir. Makine doal olarak bu durumlara
sahip olan nesnel yapy temsil etmektedir. Sonlu durum makinelerinde(Finite State
Machine) durumlar arasndaki geiler bir aksiyon sonucu gerekleir. Tahmin edilecei zere sz
konusu aksiyonlar ounlukla bir olaydr ve genellikle insan etkileimi sonras gereklemektedir.
Ne varki burada insan etkileimi sonucu olay tetiklenmesi zorunluluk deildir. nsan etkileimi
olmas nedeniyle, olaylar herhangibir zaman dilimi ierisinde meydana gelebilir. Bu tip vakalara
mhendislik eitimlerinde verilmekte olan iki basit rnek vardr. Hepimizin yakndan tand, metro
istasyonlarnda, duraklarda, okullarda veya baz kafelerde grdmz otomat makineleri ile
herkese ak olan amarhanelerde yer alan ve jeton ile alan ykama makineleri bu iki rnei
oluturmaktadr.

Finite State Machine' lerde insan ile olan etkileim n planda


olup, durumlar(States) aras geiler ounlukla insanlar tarafndan
tetiklenen olaylara(Events) baldr.

Otomat makinesinin kendisi gz nne alndnda zaman ierisinde sahip olabilecei


baz durumlar(State) vardr. rnein makine almyordur, alyordur, para veya jeton
bekliyordur, seilen rn veriyordur yada tadilattadr. Burada bahsedilen hallerin tamam
birer durum(State) olarak irdelenir. Bu durumlar arasndaki geiler iin ounlukla makinenin
baz aralar insanlar tarafndan kullanlr. Dikkat edilecek olursa makine zaman ierisinde
herhangibir anda herhangibir durumuna geebilir. Tabiki baz durumlara geiler srasnda baz
koullarn salanmas gerekebilir. Benzer senaryo ykama makinesi rnei iinde
geerlidir. (lerlemeden nce para veya jeton ile alan bir amar makinesinin zaman iinde sahip
olabilecei durumlar ve bu durumlar arasndaki geiler iin gereken olaylarn neler olabileceini
kat zerinde tasarlamaya almanz neririm.)

Finite State Machine' ler otomat, amar makinesi gibi gerek hayat rnekleri dnda retim
hattnda yer alan sanayi makinelerinin otomasyon srelerinde, oyun programlamada yer alan
karakterlerin zaman ierisindeki hareket dalmlarnda, transaction ierisinde alan bir para
aktarma veya kredilendirme srecinde ve benzer senaryolarda gz nne alnabilir. Modelin
bylesine popler olmas, zellikler programatik ortamlarda kolay bir ekile anlalabilmelerini
salamak amacyla UML formasyonunda da ifade edilmesini gerektirmitir. Sz gelimi aadaki
ekran grntsnde otomat makinesinin Finite State Machine diagram yer almaktadr.

www.bsenyurt.com Page 539


Normal artlarda bu diagramlarda ekranda grlen krmz baloncuklar elbetteki yer almaz.
Hereyden nce Finite State Machine ierisinde yer alan makinenin mutlaka bir balang
durumu(Initial State) ve son durumu(Finalization State veya Terminal State olarak
adlandrlr- i ie iki yuvarlan olduu para ile ifade edilir) vardr. Balang durumunda
makinenin ilk konumdaki hali gz nne alnr. Son durumda ise makinenin var olan durumlar sona
erdikten sonraki hali ele alnmaktadr. ekilde balang durumundan, Para Bekleniyor isimli
duruma gei yaplabilmektedir. Bu gei iin gereken, makineyi kullanan kiinin para atmasdr.
Para Bekleniyor durumuda, para yeterli oluncaya kadar kendisine gei yaplmasna salayacak
ekilde bir olaya sahiptir. Para yeterli olduktan sonra ise rn Seimi Bekleniyor isimli duruma
gei yaplabilir. Burada ise kii rn semekte ve sonrasnda makine seilen rn hazrlayarak
Biti durumuna girmektedir. Bu senaryoda pek ok durum gz ard edilmitir. rnein seim
yapldktan sonra makinenin arza yapp rn vermemesi halinde girilecek durum veya para st
verme durumlar gibi.

Hemen ikinci bir rnek ile devam edelim. Sz gelimi bir Windows uygulamas zerinden kontrol
edilen uzaktan kumandal bir otomobilin sahip olabilecei durumlara ait bir Finite State
Machinediagram sz konusu olabilir. Bu diagram aadakine benzer bir ekilde ele alnabilir.

www.bsenyurt.com Page 540


Burada otomobilin kendisi programatik ortamda bir nesne ile ifade
edilebilir. Durumlar(States) arasndaki geileri salayan ise Windows uygulamasndan
tetiklenen nesne olaylar(Events)olabilir. Arabann ekle gre sahip olabilecei durumlar belirlidir.
Bu durumlarda sz konusu olabilecek olaylarda ayn ekilde belirli ve sayldr. Bir durumdan baka
bir durumua gei veya geilerde birden fazla sayda olay sz konusu olabilir. Sz gelimi Motor
alyor durumundayken, OnIlerle, OnMotoruDurdur veya OnGeriGit gibi olaylar tetiklenerek
farkl duruma gei yaplmas salanabilir. Buda bize durumlar arasndaki geilerde birden fazla
olayn sz konusu olabileceini gstermektedir. Hatta baz noktalarda ortak olaylarda sz
konusudur. rnein araba ileri veya geri giderken OnDur olay tetiklenerek durmas salanabilir.
OnDur olay hem Geri Gidiyor hemde Ilerliyor durumlar(States) iin geerli ortak bir olaydr.

Sanyorumki buraya kadar anlatlanlar sayesinde Finite State Machine yaklam hakknda biraz
fikir sahibi olunmutur. Bundan sonraki ksmlarmzda ise .Net Framework 3.0 ile
gelen Windows Workflow Foundation asndan Finite State Machine modeline bakyor
olacaz. Nitekim sz konusu model gerek hayat rneklerine benzer olacak ekilde programatik
ortamdaki nesnel yaplar iinde sz konusu olabilmektedir. Bu noktada WWF bize kolaylatrc bir
yaklam sunmakta ve State Machine tarz i srelerinin .Net uygulamalarnda rahata ele
alnabilmelerine olanak tanmaktadr.

Windows Workflow Foundation(WWF) iki temel i ak modelini ele alr. Sequential


Workflows ve State Machine Workflows. Daha ncedende bahsedildii gibi Sequential
Workflows tipinden olan i aklarnda admlar yada aktiviteler arasndaki geilerin nasl ve ne
zaman olaca bellidir. Hatta bu geiler srasnda koullarn kullanlmas ok sk rastlanan bir
durumdur. Stata Machine Workflow tipindeki i aklarnda ise daha ncedende deinildii gibi
admlar veya durumlar arasndaki geiler d olaylarn tetiklenmesine baldr. State Machine
Workflow aklarndan, aktivitenin kendisi StateMachineWorkflowActivity snfndan

www.bsenyurt.com Page 541


rneklenmektedir. (Workflow mimarisindeki hereyin birer aktivite(Activity) tipi olduunu
hatrlayalm) StateMachineWorkflowActivity tipinin .Net ierisindeki yerine bakldnda
aadaki snf diagramnda(Class Diagram) yer alan hiyeraride olduu grlr.

Dikkat edilecei zere StateMachineWorkflowActivite snfda eninde sonunda


bir Activity tipidir. Kendi ierisinde tanmlanm olan yelerden bir kan aklayarak devam
edelim. CompletedStateName zellii ile, biti durumu(Finalization State) ifade edilir. Bu
zellik nemlidir nitekim Workflow' un hangi durumdan sonra sonlanacan belirtmektedir. Ancak
yazlmad vakalarda vardr. Benzer ekilde InitialStateName zellii balangtaki durum
aktivitesini iaret etmektedir. alma zamannda istenirse o anda makinenin bulunduu durum
ad CurrentStateName zellii ile elde edilebilir. Benzer ekilde PreviousStateName zellii ile o
anda bulunulan durumdan bir nceki durum ad elde edilebilir ki bu hangi durumdan gelindiini
renmek iin kullanlabilir. Buradaki rnek zellikler(Properties) dnda st snflardan gelen
pek ok ye(Member) yer almaktadr. Amacmz u an iin bu tipin tm yelerini renmek
deildir. Bunun yannda bir StateMachineWorkflowActivity tasarlanrken ierisinde ounlukla
aadaki ekilde yer alan tipler kullanlr.

www.bsenyurt.com Page 542


Burada belkide en kritik ve deerli tip StateActivity snfdr. StateActivity, aslnda makinenin
ierisinde bulunaca durumlar iaret etmektedir. ok doal olarak bir StateActivity
ierisinde StateInitializationActivity yada StateFinalizationActivity tanmlanabilir. Ancak bir
StateActivity ierisinde bunlardan sadece bir tane bulunabilir. te yandan StateActivity
ierisinde, StateInitializationActivity veya StateFinalizationActivity tiplerinin tanmlanmas
zorunlu deildir. Bunlar opsiyonel olarak ele alnmaktadr. Durumlar(States) arasndaki geiler
iin EventDrivenActivity tipi kullanlmaktadr. StateActivity ierisinde birden
fazla EventDrivenActivity nesnesi tanmlanabilir. Nitekim daha ncedende bahsettiimiz gibi, bir
durumda(State) sz konu olabilecek birden fazla olay(Event) olabilir. Her EventDrivenActivity
mutlaka olaylar alabilecek bir aktivite tipi ierir. Bunu
salayan HandleExternalEventActivitytipidir. Sz konusu aktivite tipini takiben herhangibir
baka aktivitede gelebilir. rnein bir olayn tetiklenmesinin ardndan host uygulama zerinden
arlabilecek harici metodlarn ele alnmas, kod iletilmesi gibi ilemler yaplabilmektedir. ekilde
dikkat edilecei zere EventDrivenActivity ierisinde son
olarak SetStateActivity kullanlmaktadr. Bu tip sayesinde bulunulan durumdan dier bir duruma
geilmesi salanmaktadr.

ekilde dikkat edilmesi gereken noktalardan biriside StateActivity tipleri dnda


ve StateMachineWorkflowActivity ierisinde kalan alanda EventDrivenActivity bileenlerinin
tanmlanabilmesidir. Baz hallerde durumlar(States) arasndaki geilerde kullanlmayan
olaylar(Events) sz konusu olabilir. Sz gelimi otomobilin selektr yapmas herhangibir anda
herhangibir duruma gei yaplmasn gerektirmeyecek bir vaka olarak ele alnr. Bu sebepten bu
vakaya ilikin olay ele alacak EventDrivenActivity nesnesinin bir StateActivityierisinde
tanmlanmasna da gerek yoktur.

www.bsenyurt.com Page 543


Baz durumlarda StateActivity bileenleri kendi ilerindede birden fazla StateActivity ierebilir.
Bu genellikle ierideki aktivitelerin ayn olaylar ele ald durumlarda sz konusudur. Bu tip
aktiviteler Recursive Compositon Activities olarakda adlandrlmaktadr. Aada ekilde bu
durum ele alnmaya allmaktadr.

Burada her iki StateActivity tipi ierisinde yer alan HandleExternalEventActivity nesneleri ayn
olay ile ilgilenmektedir. Byle bir durumda sz konusu StateActivity aadaki ekilde grld
gibide tasarlanabilir. (Otomobil rnei gz nne alndnda Geri gitme veya ileri gitme durumlar
ierisinden Durma durumuna geilmesi iin ayn olaylar ele alnmaktadr.)

www.bsenyurt.com Page 544


Grld gibi StateActivity1 ve StateActivity2 nesne rnekleri genel bir StateActivity nesnesi
ierisine alnmtr. Bununla birlikte her ikisinin EventDrivenActivity nesneleri dar alnarak tek
bir noktada toplanmtr. Nitekim her iki alt aktivitede ayn EventDrivenActivity nesnelerini ele
almaktadr.

Bu kadar teorik bilgiden sonra bir rnek yaparak devam etmekte yarar vardr. Makale yazlmadan
nce yaplm olan aratrmalarda Microsoft' un Otomat makinesi rneini kulland, APress' in
ise bir arabann durumlarn ele ald gzlenmitir. Bizde senaryo olarak APress tarafndan ele
alnan Otomobil rneini kendimize gre adm adm gelitirmeye ve anlamaya alacaz. e ilk
olarak yeni bir State Machine Workflow Library projesi aarak balayalm. Bunun
iin Visual Studio 2008 ortamnda New Project->WF sekmesinden ilgili proje
ablonunu(Project Template) sememiz yeterlidir.

www.bsenyurt.com Page 545


Proje oluturulduunda otomatik olarak Workflow1.cs dosyas tasarm penceresinde alacak ve
aadaki ekran grnts oluacaktr.

Burada grld gibi Workflow1.cs ierisinde varsaylan olarak bir InitialState bileeni
bulunmaktadr. imdi rnein temasn oluturan arabann zaman ierisindeki durumlar gz nne
alnabilir. Bu durumlar listeledikten sonra ise gerekli tiplerin hazrlanmasna balanabilir.
Hereyden nce arabann zaman ierisindeki durumlar arasndaki geileri salayacak olan
olaylarn veri deiimi salayacak ekilde tasarlanm bir arayz(Interface) ierisinde yer almas
salanmaldr. Bu amala projeye aada snf diagram(Class Diagram) ve kod kts yer
alan arayz(Interface) eklenir.

[ExternalDataExchange]
public interface IArabaHizmetleri
{
event EventHandler<ExternalDataEventArgs> ArabayiCalistir;
event EventHandler<ExternalDataEventArgs> MotoruDurdur;
event EventHandler<ExternalDataEventArgs> Dur;
event EventHandler<ExternalDataEventArgs> Ilerle;
event EventHandler<ExternalDataEventArgs> GeriGit;
event EventHandler<ExternalDataEventArgs> ArabadanCik;
event EventHandler<ExternalDataEventArgs> SelektorYap;

www.bsenyurt.com Page 546


void OnMesajGonder(string message);
}

Bu arayz(Interface) basit olarak i akna yerel bir servis(Local Service) zerinden


sunulabilecek ye bildirilmlerini iermektedir ki bunlar ounlukla olay ve metod tanmlamalardr.
Dier taraftan arayz tipi ExternalDataExchange nitelii(attribute) ile iaretlenmitir.
Bu niteliin(Attribute) uygulanmas sayesinde arayz tipi, i aklar tarafndanyerel bir
servis(Local Service) olarak kullanlabilir hale gelir. Arayz(Interface) ierisinde durum
geileri(State Transitions) iin gerekli temel olay tanmlamalar yer almaktadr. rnein arabann
ilerlemesi iin Ilerle yada geriye gitmesi iin GeriGit olaylarna ait bildirimler bulunmaktadr.
Bununla birlikte arayz, OnMesajGonder isimli bir metod bildirimi de iermektedir. Bu metod i
ak(Workflow) tarafndan, host uygulamaya mesaj gndermek amacyla kullanlacaktr.

Bilindii gibi arayzler(Interface), sadece ye bildirimleri ieren


tiplerdir. Polimorfik yaplar vardr ve oklu kaltma(Multi Inheritance) destek
verirler. ounluklatretme(Inheritance) iin kullanlr ve treyen yelerin mutlaka
uymas gereken kurallar bildirirler. Plug-In tabanl programlamada, tip
geniletmelerinde, ortak szlemelerin sunulmasnda(Sz gelimi WCF gibi SOA-Service
Oriented Architecture mimarilerinde) vb... gibi senaryolarda sklkla kullanlrlar.

Arayzn tanmlanmasndan sonra bunu uygulayan snfn tasarlanmas gerekmektedir.


Bu snf(Class) ayn zamanda yerel bir servis(Local Service) olacaktr. Sz konusu snf
ve MesajGonder iin kullanlan yardmc olay parametresinin ierii aadaki gibidir.

MesajAlindiEventArgs snf;

[Serializable]
public class MesajAlindiEventArgs : ExternalDataEventArgs
{
private string _bilgi;

public string Bilgi


{
get { return _bilgi; }
set { _bilgi = value; }
}
public MesajAlindiEventArgs(Guid ornekId, string bilgi)
: base(ornekId)

www.bsenyurt.com Page 547


{
_bilgi = bilgi;
}
}

ExternalDataEventArgs snfnn tm yapc metod(Constructor Method)


versiyonlar Guid tipinden bir ilk parametre alrlar. Bu sebepten base anahtar kelimesi
kullanlarakMesajAlindiEventArgs snfna gelen Guid deerinin st snf rneine gnderilmesi
salanmaktadr.

ArabaYerelServisi snf;

public class ArabaYerelServisi :IArabaHizmetleri


{
#region IArabaHizmetleri Members

public event EventHandler<ExternalDataEventArgs> ArabayiCalistir;


public event EventHandler<ExternalDataEventArgs> MotoruDurdur;
public event EventHandler<ExternalDataEventArgs> Dur;
public event EventHandler<ExternalDataEventArgs> Ilerle;
public event EventHandler<ExternalDataEventArgs> GeriGit;
public event EventHandler<ExternalDataEventArgs> ArabadanCik;
public event EventHandler<ExternalDataEventArgs> SelektorYap;

public void OnMesajGonder(string message)


{

www.bsenyurt.com Page 548


if (MesajAlindi != null)
{
MesajAlindiEventArgs args = new
MesajAlindiEventArgs(WorkflowEnvironment.WorkflowInstanceId, message);
MesajAlindi(this, args);
}
}

#endregion

#region Host uygulama tarafndan kullanlan yeler

public event EventHandler<MesajAlindiEventArgs> MesajAlindi;

public void OnArabayiCalistir(ExternalDataEventArgs args)


{
if (ArabayiCalistir != null)
ArabayiCalistir(null, args);
}

public void OnMotoruDurdur(ExternalDataEventArgs args)


{
if (MotoruDurdur != null)
MotoruDurdur(null, args);
}

public void OnDur(ExternalDataEventArgs args)


{
if (Dur != null)
Dur(null, args);
}

public void OnIlerle(ExternalDataEventArgs args)


{
if (Ilerle != null)
Ilerle(null, args);
}

public void OnGeriGit(ExternalDataEventArgs args)


{
if (GeriGit != null)
GeriGit(null, args);
}

public void OnSelektorYap(ExternalDataEventArgs args)


{
if (SelektorYap != null)
SelektorYap(null, args);
}

public void OnArabadanCik(ExternalDataEventArgs args)


{
if (ArabadanCik != null)
ArabadanCik(null, args);
}

www.bsenyurt.com Page 549


#endregion
}

ArabaYerelSinifi isimli snf(Class), ilgili arayz(Interface) uygulamak dnda Host uygulama


tarafndan tetiklenebilecek metodlarda iermektedir. Bu metodlar kendi ilerindende aka ait
durum geileri iin gerekli olaylarn tetiklenmesinde kullanlmaktadr. Snf ierisinde yer
alan OnMesajGonder isimli metod parametre olarak string tipinden bir deiken almaktadr. Bu
parametre deeri i akndan(Workflow) gelmekte olup Host uygulamaya iletilmektedir. Bu
iletim srasnda MesajAlindi isimli olay devreye girmektedir ki bu olay sadece i akn barndran
Host uygulama tarafndan ele alnabilir. Tahmin edilecei zere OnMesajGonder metodunun
parametre deeri i ak tasarlanrken belirlenecektir. MesajAlindi olay tetiklenirken parametre
olarak ExternalDataEventArgs snfndan tremi olan MesajAlindiEventArgs snf
kullanlmaktadr.

Bu ilemlerin tamamlanmasnn ardndan Durum Makinesinin(State Machine) tasarlanmasna


balanabilir. Bu amala Workflow1.cs zerinden gerekli dzenlemelerin yaplmas gerekmektedir.
lk olarak arabann sahip olabilecei tm durumlar StateActivity bileenleri yardmyla i ak
zerine alnrlar. Balangta StateActivity bileenlerininName zelliklerinin deerlerinin aadaki
tabloda yer ald gibi deitirildiini dnelim.

StateActivity
Bileeni
Ksa Bilgi
Name zellii
Deeri

MotorCalismiyor Arabann motorunun almad durumu iaret eder.

Arabann motorunun almak olduu durumu iaret


MotorCalisiyor
eder.

ArabaIlerliyor Arabann ileri doru hareket ettii durumu iaret eder.

Arabann geriye doru hareket ettii durumu iaret


ArabaGeriGidiyor
eder.

ArabadanCikilmistir Arabadan inildikten sonraki durumu iaret eder.

Bunun sonrasnda i akna(Workflow) ait ekran grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 550


Son ilemleri takiben i aknn balang ve biti durumlar belirlenebilir. Bunun iin Workflow1'
in zellikler(Properties) penceresinden InitialStateName veCompletedStateName zelliklerine
ilgili deerlerin verilmesi gerekmektedir. Senaryo gerei MotorCalismiyor balang
ve ArabadanCikilmistir biti durumlarn(State)bildirmektedir.

Artk ilk durumdan dierine geisi salayacak olan olay aktivitesi tanmlanabilir. Bu
amala MotorCalismiyor isimli StateActivity ierisine bir adet EventDrivenActivity bileeni
srklenir. EventDrivenActivity bileeninin Name zelliine MotorCalistirOlayi ad verilebilir.
Sonu olarak ekran grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 551


Daha ncedende bahsettiimiz gibi EventDrivenActivity ierisinde genel olarak 3 farkl aktivite
kullanlr. Bu senaryoda sz konusu olayn tetiklenmesi iinHandleExternalEventActivity bileeni
ele alnmaldr. Dier taraftan yerel servis zerinden harici metod ars
iin CallExternalMethodActivity bileeni deerlendirilir. Son olarak olayn tetiklenmesi sonras
geilecek olan durumu iaret etmek iin SetStateActivity bileeni
kullanlmaldr. EventDrivenActivity bileeni ierisine bahsedilen kontrolleri oluturmak
iin MotorCalistirOlayi zerinde ift tklanmas yeterlidir. Sonu olarak ilk durum iin
tasarlanan EventDrivenActivity bileeninin ierii aadaki ekran grntsnde yer ald gibi
olacaktr.

lk olarak HandleExternalActivity bileeni ile balayalm. Bu bileenin InterfaceType zelliine


tetiklenecek olan olayn bildirimini ieren arayz ad verilmelidir. Bu amala nokta dmesine
basldnda aadakine benzer bir arabirim ile karlalr. Bu arabirimden ayn proje ierisindeki

www.bsenyurt.com Page 552


veya farkl bir projedeki ExternalDataExchangeniteliini uygulayan arayzler grlebilir.
rneimizdede IArabaHizmetleri arayz aktif olarak gelmektedir.

Arayz seimi yapldktan sonra EventName zelliinde ele alnabilecek olan, bir baka
deyile interface tipi ierisinde bildirilmi olan olaylarn listesi gelecektir. rneimizdeki ilk durum
iin ArabayiCalistir olay seilmelidir. EventDrivenActivity iin sz konusu olan durum aadaki
gibidir.

Gelelim CallExternalMethodActivity bileenine. Bu bileen iinde yine arayz(Interface) seimi


yaplmaldr. InterfaceType zelliine yaplan atamann ardndan altrlacak olan harici metodun
ad MethodName zelliinden seilir. rnekte harici metodun ald string bir parametrede sz
konusudur. Bu parametrede message isimli zellie atanan deer ile belirtilir.

www.bsenyurt.com Page 553


Burada dikkat edilmesi gereken noktalardan biriside, OnMesajGonder metodunun parametrik
yapsna uygun olacak ekilde bir zelliin IDE' deki Properties penceresine eklenmi olmasdr.
rnekte message isimli olan parametre, zellik penceresine birer bir ayn olacak ekilde gelmitir.
Harici metod arlmasnda tamamladktan sonra geilecek olan durum bileenini belirlemek
gerekmektedir. Bunun
iinde SetStateActivity bileeninin TargetStateName zelliine StateActivity adnn atanmas
yeterlidir. lk durumda aracn motoru altrldktan sonra MotorCalisiyor durumuna(State)
geilmektedir.

stenirse ilk durum iin StateInitializationActivity bileeni de eklenebilir. Bylece makinenin ilk
konumdaki durumu iin gerekli hazrlklarn yaplmas salanabilir. Sz gelimi rnek
senaryoda OnMesajGonder metodunun harici olarak arlmas ve mesaj olarakta "Araba hazr"
denilmesi salanabilir. Bunun iin MotorCalismiyor aktivitesi ierisine bir
adetStateInitializationActivity bileeni atanmas ve bu bileenin ierisinede bir
adet CallExternalMethodActivity bileeni
eklenerek InterfaceType, MethodName ve message zelliklerinin deerlerinin belirlenmesi
yeterlidir.

www.bsenyurt.com Page 554


Bylece ilk durum tamamyle hazrdr. Akn u andaki grnts aadaki gibi olacaktr.

Burada yapm olduumuz admlarn aynlarn dier durumlar iinde gerekletirmeliyiz.


Makalemizin dahada uzamamas iin buradaki admlarn gsterilmesini atlyoruz. Gereken
ayarlamalar yapldktan sonra i aknn son hali aadaki ekran grntsndeki gibi olmaldr.
Dikkat edilecei zere olas durum geileri ince ok izgiler ile daha belirgin haldedir.

www.bsenyurt.com Page 555


Burada ekstradan selektr yapma durumununda, State Machine zerinde ayr
bir EventDrivenActivity olarak tanmlanmas gereklidir. Bu aktivite ierisinde
sadeceHandleExternalEventActivity ve CallExternalMethodActivity bileenlerinin kullanlmas
yeterlidir. Dikkat edilecei zere SetStateActivity kontrolnn kullanlmas gerekli deildir.
Nitekim selektr yapma olaynn arkasndan geilecek herhangibir durum gz nne
alnmamaktadr. Bu nedenle SelektorYapOlay isimli EventDrivenActivity ierisinde aadaki
bileenlerin tasarlanmas yeterlidir.

Host uygulamaya gemeden nce u durumda gz nne alnmaldr. Tasarm penceresine


bakldnda ArabaGeriGidiyor ve ArabaIlerliyor StateActivity bileenleri ierisinde
ayn EventDrivenActivity nesnelerinin kullanld grlmektedir ki buda arac durdurma olayn
iaret etmektedir. Bu nedenle makalemizin bandada belirttiimiz gibi
bu StateActivity bileenlerinin ortak bir StateActivity ierisine alnmas dnlebilir. Bu

www.bsenyurt.com Page 556


sebepten tasarm ekranna ortak bir StateActivity bileeni srklenip, dierlerini iine almas
salanmaldr. Aadaki ekran grnts bu durumu ak bir ekilde ifade etmektedir.

ncelikli
olarak HareketEdiyor isimli StateActivity ierisine ArabaGeriGidiyor ve ArabaIlerliyor isimli S
tateActivity nesneleri srklenmitir. Sonrasnda ise bunlardan herhangibirisinde yer
alan ArabayiDurdurOlayi isimli EventDrivenActivity bileeni HareketEdiyor isimli StateActivi
ty ierisine kartlm ve dierininki silinmitir.

Artk host uygulamann yazlmasna balanabilir. rneimizde host uygulamas basit


bir WPF(Windows Presentation Foundation) program olarak tasarlanacaktr. Sz konusu WPF
uygulamasnn State Machine Workflow
ktphanesi(Library) dnda, System.Workflow.Activities,
System.Workflow.Components ve System.Workflow.Hosting assembly' larnda referans
etmesi gerekmektedir. YarisPisti isimli WPF uygulamamzn Window1 penceresine ait ekran
grnts ve XAML(eXtensible Application Markup Language) ierii ise aadaki gibidir.

www.bsenyurt.com Page 557


XAML ierii;

<Window x:Class="YarisPisti.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="300"
Width="300">
<Grid>
<Label Height="42" Margin="28,0,22,32" Name="lblGelenMesaj"
VerticalAlignment="Bottom" Content="Durum Bilgisi"></Label>
<Button Height="23" HorizontalAlignment="Left"
Margin="26,25,0,0" Name="btnYeniAraba" VerticalAlignment="Top"
Width="88" Click="btnYeniAraba_Click">Yeni Araba</Button>
<Button Height="23" Margin="26,60,0,0" Name="btnMotoruCalistir"
VerticalAlignment="Top" Click="btnMotoruCalistir_Click" HorizontalAlignment="Left"
Width="88">altr</Button>
<Button Height="23" HorizontalAlignment="Left" Margin="28,97,0,0"
Name="btnMotoruKapat" VerticalAlignment="Top" Width="86" Click="btnMotoruKapat_Click">
Motoru Kapat</Button>
<Button HorizontalAlignment="Right" Margin="0,129,44,110" Name="btnSelektorYap"
Width="84" Click="btnSelektorYap_Click">Selektr</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,26,44,0" Name="btnIlerle"
VerticalAlignment="Top" Width="83" Click="btnIlerle_Click">lerle</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,58,44,0" Name="btnGeriGit"
VerticalAlignment="Top" Width="83" Click="btnGeriGit_Click">Geri Git</Button>
<Button Height="23" HorizontalAlignment="Right" Margin="0,95,44,0" Name="btnDur"
VerticalAlignment="Top" Width="83" Click="btnDur_Click">Dur</Button>
<Button HorizontalAlignment="Left" Margin="28,129,0,110" Name="btnArabadanIn"
Width="86" Click="btnArabadanIn_Click">n</Button>
</Grid>
</Window>

Window1 penceremizin kod ierii ise aadaki gibidir.

using System;

www.bsenyurt.com Page 558


using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using ArabaStateMachineLib;
using System.Workflow.Runtime;
using System.Workflow.Activities;

namespace YarisPisti
{
public partial class Window1 : Window
{
// Workflow alma ortam iin gerekli nesne tanmlanr
WorkflowRuntime _wf;
ArabaYerelServisi _arabaServisi; // Yerel Servis nesnesi tanmlanr
Guid ornekId = Guid.Empty; //ExternalDataEventArgs snf parametre olarak Guid
almaktadr. Bu sebepten ornekId isimli bir deilen tanmlanmtr.

public Window1()
{
InitializeComponent();

_wf = new WorkflowRuntime(); // alma zaman oluturulur


_wf.StartRuntime(); // WF alma zaman balatlr
ExternalDataExchangeService excSrv = new
ExternalDataExchangeService(); // Bir adet ExternalDataExchangeService servisi oluturulur ve
u anki WF alma zamanna AddService metodu ile eklenir.
_wf.AddService(excSrv);

// Yerel Servis(Local Servis) nesnesi rneklenir.


_arabaServisi = new ArabaYerelServisi();
// Host zerinden ele alnacak MesajAlindi olay yklenir.
_arabaServisi.MesajAlindi+=new
EventHandler<MesajAlindiEventArgs>(_arabaServisi_MesajAlindi);
// Yerel servis ExternalDataExchangeService rneine eklenir
excSrv.AddService(_arabaServisi);
}

// Label ieriinin gncellenmesi iin aadaki gibi Invoker kullanm gereklidir. Aksi takdirde
alma zamannda istisna alnr.
private delegate void GuncellemeTemsilcisi();
void _arabaServisi_MesajAlindi(object sender, MesajAlindiEventArgs e)
{
ornekId = e.InstanceId;
GuncellemeTemsilcisi dlg = delegate()
{
lblGelenMesaj.Content = e.Bilgi.ToString();
};

www.bsenyurt.com Page 559


// Normal Windows uygulamalarnda this.Invoke ile arabilmemiz mmknken WPF
uygulamalarnda Dispatcher nesnesinden yararlanlmaktadr
Dispatcher.Invoke(System.Windows.Threading.DispatcherPriority.Normal, dlg);
}

// Yeni araba aslnda Workflow1 tipinden yeni bir State Machine Workflow rnei
oluturulmasn salamaktadr.
private void btnYeniAraba_Click(object sender, RoutedEventArgs e)
{
WorkflowInstance wfOrnegi = _wf.CreateWorkflow(typeof(Workflow1), null);
wfOrnegi.Start(); // State Machine Workflow balatlr
ornekId = wfOrnegi.InstanceId; // ExternalDataEventArgs' ta kullanlmak zere InstanceId
deeri aln ve GUID tipinden olan ornekId deikenine atanr.
}

// Olaylar iin gerekli argmanlarn alnmas salanan metod


private ExternalDataEventArgs ArgumanAl()
{
ExternalDataEventArgs args = new ExternalDataEventArgs(ornekId);
args.WaitForIdle = true;
return args;
}

private void btnIlerle_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnIlerle(ArgumanAl()); // Servis zerinden ilgili olay metodu
tetiklenir
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void btnMotoruCalistir_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnArabayiCalistir(ArgumanAl());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void btnGeriGit_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnGeriGit(ArgumanAl());
}
catch (Exception ex)
{

www.bsenyurt.com Page 560


MessageBox.Show(ex.Message);
}
}

private void btnMotoruKapat_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnMotoruDurdur(ArgumanAl());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void btnDur_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnDur(ArgumanAl());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void btnArabadanIn_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnArabadanCik(ArgumanAl());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}

private void btnSelektorYap_Click(object sender, RoutedEventArgs e)


{
try
{
_arabaServisi.OnSelektorYap(ArgumanAl());
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}

Uygulamamz altrdmzda aadaki video grntsndeki gibi State Machine


Workflow baarl bir ekilde yklendii ve alt grlmektedir. Tabiki gei yaplamayan

www.bsenyurt.com Page 561


durumlarda sz konusudur. rnein araba ileri gidiyorken geri gidiyor durumuna geilmesi sz
konusu deildir. Bu tip hallerde, try...catchbloklar devreye girerek retilen
istisna(Exception) mesajlar MessageBox ierisinde grlecektir.

Bylece geldik bir uzun makalemizin daha sonuna. Bu


makalemizde State Machine Workflow tipinden i aklarn ksaca ne olduklarn, nasl
tasarlandklarn incelemeye altk. Bunu yaparken StateActivity, EventDrivenActivity,
HandleExternalEventActivity, SetStateActivity, CallExternalMethodActivity vb aktivite tiplerinden bir
kana deinme frsatmzda oldu. Ayrca durumlar(States) aras geileri salayan
olaylarn yerel bir servis(Local Service) ierisinde nasl gelitirilebileceini grdk. Son olarakta
gelitirilenWorkflow projesini bir WPF host uygulamasnda yrtmeyi inceledik. rnek senaryo
olarak APress yaynlarndan olan ve Bruce Bukovics tarafndan yazlan Pro WF kitabnda yer
alan CarService i aknn daha basit bir versiyonunu adm adm aklamal olarak rneklemeye
altk. zel olarak host uygulamay WPF zerinde gelitirdik. Bylece Window uygulamalarnda
kullandmz method invoker kavramnn burada Dispatcher zellii zerinden ele alnabileceini
grme frsatn elde ettik.(Dispatcher kavramna ilerleyen makalelerimizde deinmeye alyor
olacam) State Machine Workflow tipinden i aklarnn, bu senaryo dnda gerek
.Netnesneleri ierisindeki kullanmn aratrmanz ve rneklemeye almanz iddetle tavsiye
ederim. lerleyen makalalerimizde Windows Workflow Foundation ile ilgili farkl konulara
deinmeye devam ediyor olacaz. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WWF : alma Zaman Motoru, Singleton ve


Factory Desenleri ( 04.01.2008 ) - WWF
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde i ak(Workflow) kavramn anlamaya alm, Windows Workflow


Foundation(WWF) mimarisini yzeysel olarak incelemi ve basit bir kaSequential

www.bsenyurt.com Page 562


Workflow rnei gelitirmitik. Bu makalemizde ise WWF mimarisinin sunduu alma zaman
ortamn derinlemesine kavramaya alacaz. Arlkl olarak zerinde durmaya alacamz konu
ise WorkflowRuntime snf olacak.

aklar herhangibir .Net uygulamas tarafndan host edilebilmektedir. Burada ama ana
uygulamann belirli i kurallarn ve mantn barndran sre veya sreleri tutarl bir ekilde ele
alabilmesi ve kullanabilmesidir. ok doal olarak i aklar, host uygulama gz nne alnrken
ortaya bir i ak alma zaman(Workflow Runtime) kmaktadr. Buda Windows
Workflow Foundation ierisinde yer alan nemli bileenlerden birisi anlamna gelmektedir. WWF
mimarisi ierisinde pek okbileen(Components) yer almaktadr. Byk resme bakldnda
barol oynayan bileenler aadaki ekilde grld gibidir.

Snf ktphanaleri(Class Libraries) i


ak(workflow) uygulamalar gelitirebilmek(Develop), ynetebilmek(Manage), alma
zaman hareketliliklerini izleyebilmek(Trace) iin gerekli tm tip tipleri iermektedir. Bunlarn
dnda ana bileenler iin gerekli tiplerde burada yer almaktadr. Sz gelimi nceden
tanmlanm alma zaman servisleri(Runtime Services) gibi. WF tasarm zaman aralar
sayesinde, i aklarnn Visual Studio ortamnda kolay bir ekilde gelitirilebilmesi
salanmaktadr. WF alma zaman servisleri(WF Runtime Services) i aklar iin hayati
nemi olan yada opsiyonel olarak ek avantajlar kazandran baz hizmetleri iermektedir. Bu yapya
yazmzn ilerleyen ksmlarnda yeniden bakyor olacaz.

WWF ierisinde yer alan ekirdek alma zaman motoru(Core Runtime)


WorkflowRuntime snf tarafndan temsil edilmektedir. Ne varki WorkflowRuntime snf tek
bana anlaml olabilecek bir yapda deildir. Bu nedenle i aklarnn(Workflows) alma
zamann ynetebilmesi iin, bir host uygulama tarafndan ele alnmas gerekmektedir. Bu host
uygulama tahmin edilecei gibi herhangibir .Net uygulamas olabilir.

WPF(Windows Presentation Foundation) Uygulamalar


Windows Uygulamalar
Windows Servisleri
Asp.Net Web Uygulamalar
Console Uygulamalar

Buna gre host uygulama i ak alma zamann(Workflow Runtime) barndrrken, i ak


alma zamanda i ak rneklerini(Workflow Instances) barndrmaktadr. Sz konusu
durumu aadaki ekil ile daha net bir biimde grebiliriz.

www.bsenyurt.com Page 563


Bir WWF ortam oluturulduunda host uygulama ierisinde ele alnan pek ok alma zaman
kavramda sz konusudur. ak rnekleri, bu rneklerin ierisinde yer
alan aktiviteler(Activities), kurallar(Rules), i ak alma zaman ierisinde yer alan baz
unsurlar, servisler vb...Aadaki ekilde host uygulama asndan bakldnda, alma zaman
ortam ierisinde sz konusu olan unsurlar temsil edilmeye allmaktadr.

Dikkat edilmesi gereken noktalardan bir taneside host uygulamann birden fazla WF alma zaman
ortamna sahip olabilmesidir. Buna gre tek bir uygulama alan(Single Application

www.bsenyurt.com Page 564


Domain) kendi ierisinde birden fazla WF alma zaman ortam barndrabilir. Bu WF alma
zaman ortamlarnn her biride, kendi i aklarn bamsz olacak ekilde ynetebilir. Nitekim WF
alma zaman motoru(WF Runtime Engine) birden fazla i ak rneini(Workflow
Instance) ynetecek ekilde tasarlanmtr.

Burada vurgulanmas gereken bir husus vardr. Windows Workflow Foundation ile
ilgili yazlm baz kitaptlarda tek bir uygulama alan(Single Application
Domain)ierisinde sadece tek bir WF alma zaman (WF Runtime) olabilecei
belirtilmektedir. Ancak bu durum WWF' in relase edilmi srmnde ortadan
kaldrlmtr.

Host uygulama bir WorkflowRuntime nesne rneini oluturduktan sonra temel olarak aadaki
ekilde grlen olaylar meydana gelmektektedir.

Grld gibi ilk olarak Host uygulama WorkflowRuntime rneini oluturmaktadr. Ayn
zamanda alma zaman iin gerekli olan servislerde oluturulmakta ve WF Runtime ortamna kayt
edilmektedir(Register). Buradaki servislerin bazlar mecburidir. Bazlar ise opsiyonel olarak ele
alnmaktadr. Host uygulama ayrca, WF Runtime tarafndan tetiklenen olaylar ele alabilmekte ve
bu ekilde WF alma zamann daha kolay izleyebilmektedir.

Workflow alma motorunun en nemli grevlerinden birisi elbetteki i aklarn balatmaktr.


Zaten i aklarn kendiliinden balatlmasnda mmkn deildir. Bu noktada devreye
WorkflowRuntime girmektedir. Balatlan i aklar WF alma zaman motoru(Runtime
Engine) tarafndan ayr bir thread ierisindeasenkron(Asynchronous) olarak yrtlrler.
Birden fazla i ak WF alma zaman motoru tarafndan balatlp ynetilebilmektedir. Ka i ak
olursa olsun, host uygulamadaki ana thread' e paralel olacak
ekilde asenkron(asynchronous) olarak yrtlebilmektedir. Balatlan her i ak WF alma
zaman motoru (WF Runtime Engine) tarafndan izlenmektedir. Buna bal olarak alma
zamannda bir i aknn durumlarnn ele alnabilecei bir takm olaylar sz konusudur. Aadaki
tabloda yer alan olaylar WorkflowRuntime snfna aittir.

www.bsenyurt.com Page 565


Olay(Event) Aklama

WorkflowCreated Bir Workflow nesne rnei oluturulduunda tetiklenen olaydr. Bu olay, i


akna ait aktiviteler almaya balamadan nce, yapc
metod(Constructor) altktan sonra tetiklenmektedir.

WorkflowStarted Bir i ak almaya baladnda tetiklenen olaydr. Bir baka deyile i


ak ierisindeki root aktivite(Activity) icrasna baladnda tetiklenir.

WorkflowLoaded WF alma zaman motoru tarafndan bir i ak bellee yklendiinde, i


akna ait aktiviteler almaya balamadan nce tetiklenen olaydr.

WorkflowUnloaded ak rnei WF alma zaman motoru tarafndan bellekten


kaldrldnda tetiklenen olaydr. ounlukla bir i ak uzun sre bir
ey yapmadan
kaldnda(Idle) ve WorkflowPersistenceService hizmeti
eklenip UnloadOnIdle metodu geriye true dndryorsa otomatik olarak
tetiklenmektedir.

WorkflowCompleted ak rnei tamamlandnda devreye giren olaydr. Bu olay gelitirici


tarafndan mutlaka ele alnmaldr.

WorkflowAborted ak iptal edildiinde tetiklenir. Bir i


ak WorkflowInstance snfnn Abort metodu yardmyla manuel
olaraktanda iptal edilebilir.

WorkflowTerminated Bir i ak ele alnmayan(alnamayan)


bir istisna(Exception), Terminate metoduna yaplan bir ar
yada TerminateActivity aktivitesi nedeniyle sonlandnda tetiklenir. Bu
olayda gelitirici tarafndan mutlaka ele alnmaldr.

WorkflowSuspended Bir i ak Suspend metoduna yaplan ar


ile, SuspendActivity aktivitesine gelinmesi nedeniyle duraksayabilir. Ama
gereken durumlarda WF alma zaman motoru dinamik i aklar
arasnda geileri yaparken geici olarak duraksatmalara bavurabilir. Bu
durumlarda WorkflowSuspended olay tetiklenir.

WorkflowIdled aklar alma zaman motoru tarafndan i yapmadan brakldnda


tetiklenir. Sz gelimi DelayActivity aktivitesi ile karlaldnda i ak
idle durumuna geecektir. Bu noktada WorkflowIdled isimli olay
tetiklenmektedir.

WorkflowResumed Suspend modda olan bir i ak tekrar almaya baladnda tetiklenen


olaydr. Resume metoduna yaplan ar sonucu yada WF alma zaman
motoru tarafndan geici olarak Suspend moda alnan bir i ak tekrar
kald yerden devam etmeye baladnda bu olay tetiklenir.

WorkflowPersisted Eer WF alma zamanna eklenmi bir kalc brakma


hizmeti(Persistence Service) yklyse, i aknn gncel durumu
bellee kaydedildikten sonra bu olay tetiklenebilir. Ancak bu sz konusu
olayn tetiklenme nedenlerinden sadece birisidir.

Started WF alma zaman motoru nesnesi balatldnda tetiklenen olaydr.

Stopped WF alma zaman motoru nesnesi durdurulduunda tetiklenen olaydr.

WF alma zaman motoru, i aklar zerindeki ynetimini daha moduler bir ekilde
gerekletirmek iin baz servislerden yararlanmaktadr. WF ortamnda alma zaman
servisleri(WF Runtime Services) olarak tanmlanan sz konusu hizmetler ekirdek(Core) ve
yerel(Local) olmak zere iki ana kategoride ele alnrlar. ekirdek servisler(Core Services) 4

www.bsenyurt.com Page 566


ana hizmetten olumaktadr ve WF snf ktphanelerinde(Class Libraries) ierisinde
tanmlanm olan snflar ile ifade edilmektedir. Bu hizmetler aadaki grafikte grld gibidir.

WF alma zaman motoru tarafndan ele alnan bu ekirdek servislerden Commit Work
Batch ve Scheduling hizmetleri mutlaka olmak zorundadr.
Ancak Tracking ve Persistencehizmetlerinin kullanm tamamen opsiyoneldir.

Opsiyonel olan servisleri WF alma ortamna yklemek iin u admlar izlenir;

Servise ait nesne rnei oluturulur.


WorkflowRuntime snfna ait nesne rneinin AddService metodu kullanlarak,
ilgili servisin alma ortamna eklenmesi salanr.

Scheduling hizmeti temel olarak alma zamannda i aklarnn icra edilecei thread' lerin
oluturulmas ve ynetilmesi ile ilgilidir. Bu hizmetler WorkflowSchedulerServiceisimli taban
snftan(base class) tremektedir. WorkflowSchedulerService abstract bir sntfr.

Bilindii gibi abstract snflar normal snflar gibi metodlar ierebilen, rneklenemeyen,
tretme amacyla kullanlan ve treyen snflarn mutlaka ezmesi gereken yeleri
barndrabilen, polimorfik(polymorphic) zellik gsterebilen .Net tiplerindendir.

Eer aksi sylenmesse WF alma zaman motoru(WF Workflow Runtime Engine) varsaylan
olarak DefaultWorkflowSchedulerService snfna ait bir rnei kullanlr. Bu rnek sayesinde
birden fazla i aknn thread havuzu(Pool) ierisinde kuyruk temelli olarak ynetilmesi otomatik
olarak salanmaktadr. Elbette burada ikinci bir seenek daha vardr ki

www.bsenyurt.com Page 567


buda ManualWorkflowSchedulerService snfdr. Bu servis kullanldnda i aklarnn
yryecei thread' in oluturulmas host uygulamaya aittir. Ayrca burada tek bir thread sz
konusu olduundan ilemler senkron(Synchronous) olarak yrmektedir. Bu
nedenle ManualWorkflowSchedulerService ounlukla host uygulama Asp.Netile gelitirilmise
tercih edilmektedir.

Commit Work Batch hizmeti dahili i aklar ile harici veri saklama ortamlar
arasndaki tutarll(Consistency) salamak adna WF alma zaman motorununtransaction'
lar ynetmesini salayan bir servistir. Temel
olarak WorkflowCommitWorkBatchService isimli abstract snftan treyen tiplerce
karlanrlar. ekirdek olarak yazlm iki tip
vardr. DefaultWorkflowCommitWorkBatchService ve SharedConnectionWorkflowCommit
WorkBatchService. Tahmin edilecei zere varsaylan olarak kullanlan
hizmetDefaultWorkflowCommitWorkBatchService snfna ait rnek ile
salanmaktadr. SharedConnectionWorkflowCommitBatchService snf
kullanldnda, Persistence veTracking servisleri iin ayn SQL balantsnn kullanlabilmesi
salanmaktadr. Bylece farkl nesneler(objects) arasnda ayn SQL balantsn
kullanan transaction' larn ynetilmesi salanabilmektedir.

Tracking servisi yardmyla i aklarnn bandan geenlerin izlenmesi salanabilmektedir. Taban


snf(Base Class) TrackingService' dir. Abstract olan bu snfn WFalma ortam iin yazlm
herhangibir varsaylan implemantasyonu yoktur. Nitekim bilinli olarak SqlTrackingService snf
kullanlabilir. SqlTrackingService sealed bir snftr. Bu nedenle kendisinden tretme
yaplamamaktadr. Dolaysyla gelitirici tarafndan geniletilmesi mmkn deildir. Bu tip bir ama
varsa dorudan TrackingService snfndan tretme yaplmasnda yarar
vardr. SqlTrackingService hizmeti ile i aklarna ait alma zaman
izlenimleri SQL veritabannda saklanabilmektedir.

Persistence servisi ile alma zamanndaki i aklarnn herhangibir noktada kalc olarak
saklanabilmeleri hedeflenmektedir. Burada taban snf
roln abstractWorkflowPersistenceService stlenmektedir. Tracking hizmetinde olduu gibi
bu servisinde varsaylan bir implementasyonu yoktur. Hizmetin kullanlabilmesi
iinSqlWorkflowPersistenceService snfnn alma zamannda WF ortamna eklenmesi
gerekmektedir. Bu hizmet yardmyla bir i aknn alma zamanndaki
durumu SQL veritabanlarna kaydedilebilir ve istenildii zaman ilgili tablolardan alma ortamna
yklenebilir. (ekirdek servislerinin detaylarn ve kullanmn ilerleyen makalalerimizde incelemeye
alacaz.)

Gelitiriciler ekirdek servislere ait taban snflar(Base Class) kullanarak zelletirilmi


hizmetlerde yazabilirler. Bunun iin abstract olan ekirdek hizmet(Core
Service) snflarndan tretme(Inherit) yapmak yeterlidir.

Gelelim yerel hizmetlere(Local Services). ounluka veri dei toku hizmetleri(Data


Exchange Services) olarak adlandrlan bu servislerde ama, host uygulama ile i ak rnekleri
arasnda bir iletiim kanal oluturmaktr. Bu anlamda baz yardmc aktivite tipleri kullanlr. Sz
gelimi CallExternalMethodActivity bileeni yardmyla bir i ak ierisinden yerel bir servise ait
metod arlabilir. Yada HandleExternalEventActivity bileeni yardmyla i aknn yerel servis
ierisindeki bir olayn tetiklenmesini beklemesi salanabilir. Yazlm olan bir yerel servisin alma
ortamna eklenmesi iin ExternalDataExchangeService snfndan yararlanlr. nce bu snfa ait
bir rnek oluturlur ve WorkflowRuntime nesnesine eklenir. Kullanlmak istenen yerel servis
rnekleri ExternalDataExchangeService rneine ilave edilirler. (Kendi yerel servislerimizi nasl
gelitirebileceimizi ilerleyen makalelerde incelemeye alacaz.)

Buraya kadar WF alma zamannn barol oyuncularn ok ksada olsa tanmaya altk. Artk
arlkl olarak WF alma zaman motoru grevini stlenen WorkflowRuntime snfn rnek

www.bsenyurt.com Page 568


zerinde irdelemeye alacaz. WorkflowRuntime snfnn, alma zaman ortamn ynetmek iin
kullanlan pek ok yesi(Member) bulunmaktadr. Olaylarndan(Events) daha nceden
bahsettiimiz WorkflowRuntime snfnn tm yeleri aadaki snf diagramnda(Class
Diagram) grld gibidir.

AddService metodu yardmyla WF alma zaman


ortamna ekirdek(Core) veya yerel(Local) servislerin eklenmesi
mmkndr. AddService metodu ile WF alma zaman ortamna yklenen
servisler RemoveService fonksiyonu kullanlaraktan kaldrlabilirler. alma
ortamnda, WorkflowRuntime nesnesi tarafndan kullanlan servislerin tamam
istenirse GetAllServices metodunun ar yklenmi versiyonlar yardmyla elde edilebilir. En ok
kullanlan yelerden olan CreateWorkflow metodu ile bir i aknn o andaki WF alma ortam
ierisinde oluturulmas salanr. Bu metod arsnn nemli bir zellii daha vardr. ak rnei

www.bsenyurt.com Page 569


oluturulurken eer WF alma zaman almyorsa, balatlmasn salamaktadr. Balatma ilemi
aslnda StartRuntime metodu ile gerekletirilmektedir. DolaysylaCreateWorkflow metodunun
almayan bir WF ortamna rastladnda yapt arda StartRuntime fonksiyonu
iindir. StartRuntime bilinli olarak dardan da arlabilir.

StartRuntime naslki bir WF alma ortamnn balatlmasn salyorsa StopRuntime metoduda


durdurulmasnda rol oynamaktadr. StartRuntime metoduna yaplan arlar WF alma ortam
iin kullanlan servislerin balatlmasn salarken, StopRuntime metoduna yaplan arlarda sz
konusu servislerin durdurulmasnda rol oynar. WF alma zaman ortamnda
istenirse yrmekte(Executing), saklanmakta(Persisted) veya asl halde(Idled) olan bir i
aknn(Workflow) referansnn elde edilmesi salanabilir. Metodlar
dnda WorkflowRuntime snfnn sadece iki zellii bulunmaktadr. Bunlardan IsStarted zellii
yardmyla, WF alma zaman ortamnn balatlp balatlmad bilgisi true veya false olarak
renilebilmektedir.

imdi WorkflowRuntime nesnesini kod zerinden incelemeye balayabiliriz. lk olarak yazmzn


banda bahsettiimiz gibi tek bir uygulama alan(Single Application Domain)ierisinde birden
fazla WorkflowRuntime nesnesi olabileceini ispat etmeye alarak balayacaz. rneklerimizde
herhangibir i ak(Workflow) rnei kullanlmayacaktr. Bu nedenle basit bir Console
uygulamas zerinden hareket edebiliriz. Sonu itibaryle WorkflowRuntime nesnesi bilindii gibi
bir host uygulamada kullanld takdirde anlaml olmaktadr. Bu
amala Visual Studio 2008 ortamnda bir Console uygulamas aalm ve .Net Framework 3.0
assembly' larndan System.Runtime.Workflow.dll' ini projeye referans edelim.

Sonrasnda ise ana uygulama kodlarn aadaki gibi gelitirelim.

using System;
using System.Workflow.Runtime;

namespace WorkflowRuntimeInceleme
{
class Program
{
static void Main(string[] args)
{
// WorkflowRuntime nesne rneklerinden ilki oluturulur.
WorkflowRuntime rt1 = new WorkflowRuntime();
rt1.Name = "WF1"; // WorkflowRuntime iin bir isim belirlenir

// Started ve Stopped olaylar yklenir


rt1.Started += new EventHandler<WorkflowRuntimeEventArgs>(WfStarted);

www.bsenyurt.com Page 570


rt1.Stopped += new EventHandler<WorkflowRuntimeEventArgs>(WFStopped);

// WorkflowRuntime nesne rneklerinden ikincisi oluturulur.


WorkflowRuntime rt2 = new WorkflowRuntime();
// WF Runtime iin isim belirlenir.
rt2.Name = "WF2";
// Started ve Stopped olaylar yklenir
rt2.Started+=new EventHandler<WorkflowRuntimeEventArgs>(WfStarted);
rt2.Stopped+=new EventHandler<WorkflowRuntimeEventArgs>(WFStopped);

// WorkflowRuntime rnekleri StartRuntime metodu ile balatlr


rt1.StartRuntime();
rt2.StartRuntime();

// WorkflowRuntime rnekleri StopRuntime metodu ile durdurulur


rt1.StopRuntime();
rt2.StopRuntime();
}

// WorkflowRuntime balatldnda devreye giren olay metodu


static void WfStarted(object sender, WorkflowRuntimeEventArgs e)
{
// ki WorkflowRuntime nesne rneide ayn Started olayna balandndan hangisi
olduunun tespiti iin sender' dan yararlanlr
WorkflowRuntime guncelWF = sender as WorkflowRuntime;
// IsStarted zellii ile WF alma zamannn balatlp balatlmad renilir.
Console.WriteLine(guncelWF.Name + " " + e.IsStarted);
}

// WorkflowRuntime durdurulduunda devreye giren olay metodu


static void WFStopped(object sender, WorkflowRuntimeEventArgs e)
{
// ki WorkflowRuntime nesne rneide ayn Started olayna balandndan hangisi
olduunun tespiti iin sender' dan yararlanlr
WorkflowRuntime guncelWF = sender as WorkflowRuntime;
Console.WriteLine(guncelWF.Name+" "+e.IsStarted);
}
}
}

rnekte iki adet WorkflowRuntime nesnesi oluturulmakta ve nce StartRuntime metod


arlar ile balatlmaktadr. Sonrasnda ise StopRuntime metod arlar ile ilgili WF alma
zaman ortamlar durdurulmaktadr. Bu durum geilerini kolay takip edebilmek iin her
iki WorkflowRuntime nesne rnei ayn Started ve Stopped olaylarna balanmtr. Uygulama
altrldnda aadaki ekran grnts elde edilir.

Grld gibi ayn uygulama ierisinde birden fazla WorkflowRuntime nesne rneinin
altrlabilecei ortadadr. Her ne kadar birden fazla WorkflowRuntimeoluturulmas avantajl
grnsede baz durumlarda alma zamannda tek bir rnein olmas istenebilir. Bu ounlukla

www.bsenyurt.com Page 571


performans kazanmlar salayacak bir durumdur. Nitekim sz konusu ihtiya hazrlanma maliyeti
yksek olan nesnelerin bir tane olmasn salamakta kendini gstermektedir.

Bu noktada WWF' i bir kenara brakp "Bir nesnenin alma zamannda tek(Single) olmasn
salamak iin ne yaplr?" sorusuna cevap aramak gerekmektedir. Neyseki Gang-Of-
Four(GOF) sayesinde yllar nce bu tip bir ihtiya iin Singleton Tasarm Deseni(Singleton
Design Pattern) ortaya kmtr. imdi tekrar WWF tarafnda
dnersekWorkflowRuntime nesnelerinin tek olmasn salamak iin Singleton desenini
kullanabileceimizi dnebiliriz. Lakin bu sadece nesnenin tek olmasn salayan bir desendir.
OysakiWorkflowRuntime nesnesinin retiminide dnmemiz gerekmektedir. Bu sebepten
Factory tasarm deseninide iin ierisine katmak anlaml olacaktr. Bir baka
deyile Singleton veFactory tasarm desenlerinin bir karm burada gz nne alnabilir.

Singleton ve Factory tasarm desenlerinin bir arada kullanlmas alma zamannda


sadece tek bir Singleton nesnesinin retilmesini salamaktadr. Esasnda Abstract
Factroy, Builder ve Prototype gibi desenler kendi ilerinde Singleton desenini
barndran zmler sunmaktadr.

Bu amala uygulamaya aadaki gibi bir snf eklediimizi dnebiliriz.

using System;
using System.Workflow.Runtime;

namespace WorkflowRuntimeInceleme
{
public static class WorkflowRuntimeFabrikasi
{
// Singleton WorkflowRuntime rnei hazrlanr.
private static WorkflowRuntime _wfRt = null;
// Lock ileminde kullanlmak zere static bir object oluturulur.
private static object _kilit = new object();

public static WorkflowRuntime WorkflowRuntimeUret()


{
// Multi-Thread uygulamalar gz nne alnarak senkron altrma iin lock kullanlr.
lock (_kilit)
{
// Eer daha nceden bir WorkflowRuntime nesnesi oluturulmamsa
if (_wfRt == null)
{
_wfRt = new WorkflowRuntime(); // WorkflowRuntime nesnesini ret

www.bsenyurt.com Page 572


// Process' den kldnda
AppDomain.CurrentDomain.ProcessExit+=delegate(object obj,EventArgs e)
{
WorkflowKapat(_wfRt); // Workflow ortamn
kapatma metodunu altr
};
// Application Domain Unload edildiinde
AppDomain.CurrentDomain.DomainUnload += delegate(object obj, EventArgs
e)
{
WorkflowKapat(_wfRt); // Workflow ortamn
kapatma metodunu altr
};
_wfRt.StartRuntime(); // WorkflowRuntime balatlr
}
return _wfRt;
}
}
private static void WorkflowKapat(WorkflowRuntime rt)
{
// Eer WorkflowRuntime nesnesi null deilse ve balatlmsa
if (rt != null
&& rt.IsStarted)
{
try
{
rt.StopRuntime();// WorkflowRuntime' durdurmay dene
}
catch // istisna(Exception) oluursa grmezden gel
{
}
}
}
}
}

WorkflowRuntimeFabrikas isimli snf static olarak tasarlanmtr. Bu nedenle alma


zamannda kendisine ait bir rnek oluturulmas mmkn deildir. Buda
standartSingleton deseninde yer alan private yapc metodun(Constructor) yazlma
zorunluluunu ortadan kaldrmaktadr. Bununla birlikte static snflarn(static classes) bir
zellii olarak sadece static yeler ierebilir. Snf ierisinde dikkat edilecei
zere WorkflowRuntime nesnesi static bir alan(Field) olarak
tanmlanmaktadr. Host uygulamann ihtiyac olan WorkflowRuntime nesne rneinin retim
ilemini static olarak tanmlanm olan WorkflowRuntimeUret metodu stlenmektedir.

Dikkat edilecei zere sz konusu metod


ierisinde _wfRt isimli WorkflowRuntime nesnesinin null olup olmad kontrol edilemektedir.
Eer null ise retim yaplmakta ve metoddan geriye dndrlmektedir. Buda zaten ayn metodun
ikinci veya dier arlarnda _wfRt' nin tek olmasn garanti etmektedir. Singleton deseninin
kullanmnda multi-threaduygulamalar sz konusu ise retim yapan metod ierisinde senkronize
etme ilemleri yaplmas nerilmektedir. Bu sebepten dolay ok basit olarak lock kullanm
ile thread' in senkronize edilerek altrlmas salanmaktadr. Herhangibir host uygulama
ierisinde bu snf kullanlmak istendii takdirde, WorkflowRuntime nesnelerini retmek iin
aadaki gibi bir kod parasn yazmak yeterli olacaktr.

www.bsenyurt.com Page 573


WorkflowRuntime wfRt1 = WorkflowRuntimeFabrikasi.WorkflowRuntimeUret();

Elbette ikinci bir WorkflowRuntime nesneside retilmek istenebilir. Bu yapld takdirde


aadaki flash animasyonunda olduu gibi ilk oluturulan rnein kullanlmasna devam edilmesi
salanm olunur.(Flash versiyon 7.0 olup boyut 650 Kb' tr)

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde Workflow alma zaman ortamn
tanmaya alrken, WorkflowRuntime snfna ait nesne rnekleri
iinSingleton ve Factroy desenlerini karma olarak nasl kullanabileceimizi inceledik. Arlkl
olarak WorkflowRuntime snf, yeleri ve kullanm ekli zerinde durmaya altk.
rendiklerimizi aadaki maddeler ilede gz nne alabiliriz.

Workflow alma zaman motoru(WF Runtime Engine), i aklarnn balatlmas,


ynetilmesi, bunlarla ilikili servislerin yklenmesi ve daha pek ok fonksiyonellikten
sorumlu ana WWF bileenlerinden birisidir.
WF alma zaman motorunun kullanm ancak bir Host uygulama sz konusu olduunda
anlamldr.
WF Runtime Engine' in snf karl olan WorkflowRuntime tipine ait birden fazla nesne
rnei ayn uygulama alan(Application Domain) ierisinde kullanlabilir.
Bir Application Domain ierisinde tek bir Singleton WorkflowRuntime nesnesinin
kullanm garanti edilebilir. Bunun iin Singleton ve Factory desenelerinden yararlanlr.
WF alma zaman ortamn ierisinde gerekleen durumlar daha iyi ele alabilmek
iin WorkflowRuntime snfna pek ok olay(Event) ilave edilmitir.

www.bsenyurt.com Page 574


WorkflowRuntime snfna ait metodlar ile, servis balatmak, servisleri elde etmek, i ak
balatmak, servis kaldrmak gibi pek ok WF alma zaman ilevsellii gerekletirilebilir.

lerleyen makalalerimizde Windows Workflow Foundation ile ilgili farkl konulara deinmeye
devam ediyor olacaz. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

lk Bakta Windows Workflow Foundation (


01.01.2008 ) - WWF
Deerli Okurlarm Merhabalar,

Gerek dnyada pek ok i probleminin zmnde i aklarndan(Workflow) yararlanlr.


Temelde bir i probleminin zmnde veya amacnn gerekletirilmesinde izlenen yol birdir. nce
problem ynetilebilir kk paralara blnr. Bu paralar, gerekletirilmesi
gereken grevler(Tasks) olarak dnlebilir. Her bir grevin(Task) ierisinde ona ait
gerekletirilmesi gereken ne varsa admlar(Steps) halinde tasarlanr. Bu admlar dahil olduklar
grevin tamamlanmasnda rol oynarlar. Admlar arasndaki geiler basit olabilecei gibi eitli
evresel koul veya faktrlerede baml olabilir. Bir baka deyile admlar aras
geilerde koullar(Conditions)sz konusu olabilir. Admlar dzenli bir srada olup aralarndaki
geiler nceden tanmlanm ve belirli olabilecei gibi, eitli olaylara gre farkl ekillerde ele
alnabilirlerde. Sonu olarak ortaya i probleminin zm iin tasarlanm
bir sre(Process) ve kontroll bir ak(Control Flow) kar.

aklar(Workflow) sayesinde, i problemlerinin zmlenmesi, istenirse geniletilebilmesi son


derece kolay bir ekilde gerekletirilebilmektedir. Bir i akna pek ok yerde kolaylkla
rastlayabiliriz. Bunlarn bir ksm iin hi bir gelitirme yaplamamakla birlikte ou iin bilgisayar
teknolojisinden yararlanlmaktadr. Bir baka deyile baz i evrelerinde izlenen sreler bilinsiz
olarak kendiliinden bir aka sahip olabilmektedir. Ancak bilgisayar teknolojisinin hzla
yaygnlamas ve verimlilii arttrmas nedeni ile, i aklar yazlmsal ve donanmsal faktrler
zerinden ele alnmaktadr. Bu anlamda i aklarnn(Workflow) ilk uygulamalar dkmanlarn
bir noktadan baka bir noktaya tanmas olmutur. Zaten buda SharePoint Server gibi gelimi
bir sistemde i aklarnn neden kullanldn aklamaktadr. Nitekim portal tarz
uygulamalarda dkman ynetimi(Document Management) ve paylam esastr. Bu noktada,
dkmanlarn kullanclar(Users) ve sistemler(Systems) arasndaki hareketinde eitli onay
mekanizmalarnn devreye girmesi muhtemeldir. Buda ok doal olarak bir i ak ile ifade edilip
tanmlanabilir.

Bir ka yl nce altm zel bir yazlm firmasnda irketlerin i


aklarnn(Workflow) tasarlanabildii bir yazlm projesinde grev almtm. evrelerinin
zm bekleyen ok fazla sayda problemi vardr. Sz gelimi bir elemann ie alm yada iten
kartlma sreleri, irketin mali yapsn gsteren raporlarn onay mekanizmalar, retim hattna
ait sreler ve daha pek ou. Bilgisayar ve yazlmlar sayesinde bu rnek sre ve benzelerine ait
i aklarnn kullanlmas son derece kolaylamaktadr. rnein ie alm srecini ele alalm.
Elemann CV' sinin insan kaynaklar departmanna verilmesi ve bilgisayar ortamna alnmas,
departman ierisinde CV' nin ilgili mercilere gnderilerek onaylarnn alnmas, onay verilmesi
halinde ie alnmak istenen personelin grmeye arlmas, grme sonras tm bilgilerin kayt
altna alnarak srece dahil olan dier kiilerede gnderilmesi, gnderme ilemlerinde mail
sisteminden yararlanlmas gibi ilemler sz konusu olacaktr. Bu ilemlerin her biri arasndaki

www.bsenyurt.com Page 575


geiler karar yaplar ve onay mekanizmalar ile gereklemektedir. Sz gelimi CV' nin ilk
deerlendirmesinde en st mercinin red etmesi halinde i bavurusunda bulunan kiiye olumsuz
cevap verilmesi ve sre ierisindeki ilgili kiilerede bu durumun mail, sms gibi yollarla aktarlmas
iin bir onay mekanizmas ve koullandrmann olmas gerekmektedir.

Dikkat edilecek olursa i aklarnn yukardaki gibi cmlesel olarak ifadesi anlalmasn
zorlatrmaktadr. Hatta bu srecin kapsad alana(Domain) dahil olan kiilerin bilgisayarlarnda
admlar kolayca izleyebilmesi ve kimin stne hangi grev(Task) dyorsa bunu yapabilmesi
demek aslnda bir yazlm sisteminin gelitirilip kurulmas anlamna gelmektedir. Buda doal olarak
yukardakinden daha uzun ve karmak olan i ak anlatmlarnn nce kat zerinde grafiksel
olarak tasarlanmas ve sonrasnda gerekli yazlmn hazrlanmas anlamna
gelmektedir. Gelitiriciler(Developers) bu tip i aklarn sistemlere uygularken grsel
tasarlayclarda(Visual Designer) ele alrlar. Bir baka deyile i aklarnn grsel olarak
tasarlanabilmeside nemlidir. Bu amala gelitirilmi pek ok yazlm(Software) sz konusudur.

Karmak i kurallarn ieren aklarn grsel olarak ele alnmas, akn ierisinde yer
alan adm(Step) ve kurallarn(Rule) kolayca tasarlanabilmesi hatta kodlanabilmesi
demektir. Bu bir i aknn sonradan kolayca deitirilebilmesi bir baka deyile
geniletilebilmesininde kolaylatrlmas anlamna gelmektedir.

Bu yazlmlarn genel amac, pek ok i aknn ounlukla birden fazla bilgisayarn olduu
sistemlerde kurulmas ve kullanlabilmesidir. Elbette birden fazla bilgisayar olmas art deildir.
Baz durumlarda tek bir bilgisayar zerindeki programlar iin sz konusu olabilecek i aklarda var
olabilir. (Aslnda Windows Workflow Foundation mimarisinin bu modeldeki i aklarna daha
yakn olduunu dnebiliriz.)

Bu ksa bilgilerden sonra bir i akn tanmlamak ok daha kolaylamaktadr. Bir i


ak(Workflow) herhangibir i probleminin zm iin gereken admlar(Steps), onay
mekanizmalarn ve karar yaplarn(Condition) ieren bir model sunmaktadr. Bir baka deyile
bir i ak, belirli kurallar(Rules) zerine sralanm admlar topluluu olarakta dnlebilir.
zellikle bilgisayar teknolojileri zerinden baktmzda bir i aknn aslnda farkl bir programlama
modeli sunduuda gz nne alnabilir. Bu alardan bakldnda i ak denildiine akla gelen pek
ok kavramda bulunmaktadr. Bu kavramlar aadaki maddelerde belirtildii gibidir;

Grsel emalar
Kurallar(Rules)
Politikalar(Policies)
Sisteme giren(Input) ve kan(Output) veriler
Kiiler(Users)
Organizasyonlar(Organizations)
Yordamlar(Procedures)
Temel Grevle(Tasks)
Admlar(Steps)
Aktiviteler(Activities)

Peki Windows Workflow Foundation ile kastedilen nedir? Microsoft bu Foundation ile i
aklarnn tasarland bir programm retmitir? Aslnda Windows Workflow Foundationtek bir i
alan(Single Domain) ierisinde yer alan tek bir uygulamay(Single
Application) hedeflemektedir. Bir baka deyile Windows Workflow
Foundation .Net uygulamalarnn kullanabilecei i aklarnn(Workflow) tasarlanmas iin
gerekli altyapy sunan bir Framework 3.0 yaklamdr.

www.bsenyurt.com Page 576


aklar ounlukla BizTalk Server' un sunduklar ile karlatrlr. BizTalk ile zellikle
elektronik ticarete uygun olacak ekilde farkl platformlar zerinde yer alan sistemlere ait
i sreleri baarl bir ekilde ele alnabilmektedir. Oysaki Windows Workflow
Foundation sadece iletim sistemi seviyesinde(Operating System
Level) dnlmtr.

Bu anlamda Microsoft otoriteleri BizTalk' un interapplication(Birden fazla uygulama-


Mutliple Applications) olarak ele alnmas gerektiini, Windows Workflow
Foundation' n ise intraapplication(Tek bir uygulama-Single Application) eklinde
dnlmesi gerektiini vurgulamaktadr. Ancak bu bir kst deildir.
Nitekim WWF ierisinde Web Servisleri gibi SOA(Service Oriented
Architecture) modelleri sayesinde d platformlara klmas ve i srecinin bu ekilde
geniletilmeside mmkndr.

Windows Workflow Foundation mimarisi sayesinde i aklar grsel olarak tasarlanp


kodlanabilirler. Ancak tasarlanan bu i aklarnn ie yarayabilmesi iin bir uygulama tarafndan ele
alnmalar arttr. Sz konusu uygulamalar host grevini stlenmekte olup bir veya daha fazla i
akn barndrp kullanabilirler. Windows Workflow Foundation mimarisi pek ok fayda
salamaktadr. Sz konusu faydalar aadaki maddeler ile zetlenebilir.

aklarnn kolayca ve etkili bir biimde tasarlanabilmesi iin grsel tasarmc(Visual


Designer) sunar.
Sistemin insan ile etkileimde olduu modellerde aktiviteler(admlar) arasndaki sre
farklar olabilir. Bu nedenle i aknn gncel durumlarnn kaydedilebiliyor ve daha sonra
sonra baka bir zaman diliminde tekrar yklenebiliyor olmas gerekir. WWF bunu
salamaktadr.
aklar iin gerekli alma zaman(Run-Time) ortam dnda, pek ok tipte
farkl aktivite(Activity) iin destek,
aktivitelerin denetlenmesi(Monitoring),izlenmesi(Tracing) salanmaktadr.
Sequential i ak destei vardr. Bu aklar ounlukla sistem etkileimi olan bir baka
deyile insan faktr fazla bulunmayan durumlarda sz konusudur. Bu tip aklarda
admlarn sras ve dzenei bellidir.
State Machine i ak destei vardr. Bu tip aklarda insan etkileimi sz konusudur.
ounlukla aktivitiler arasndaki geilerin baz olaylarn tetiklenmesine bal olduu
durumlarda kullanlr.

Windows Workflow Foundation, i aklarn esas alan bir programlama modeli sunmaktadr.
Sz konusu programlama modeli deklaratif(declarative) yaklam ele almaktadr. Buna gre i
mant ayrk bileenler ierisinde kapsllenir(encapsulation). Nitekim bileenler arasnda
aklarn nasl ylendirileceini belirten kurallar deklaratif olarak tanmlanabilirler.

Windows Workflow Foundation mimarisinin nasl kullanldn daha net kavrayabilmek iin basit
rnekler zerinden devam etmekte yarar var. lk rnekte son derece basit bir i akn tasarlayp
bunu kullanacak olan bir Console uygulamas gelitiriyor olacaz. Sonrasnda ise i akn farkl
.Net uygulamalarnda da kullanabilmek adna bir snf ktphanesi(Class Library) ierisinde
tasarlayp rnek bir Windows uygulamas ierisinden altracaz. Daha ncedende belirtildii
gibi WWF ierisinde tasarlanm bir i aknn(Workflow) ie yarayabilmesi iin
bir host uygulama tarafndan ele alnmas gerekmektedir. lk
rneimizde Host program Console uygulamas olarak tasarlanacaktr. rneklerimizi Visual
Studio 2008 RTM srm zerinde tasarlyor olacaz. Ancak istenirse gerekli geniletmeler
yklenerek Visual Studio 2005 ilede WWF gelitirmeleri yaplabilir. Elbette .Net Framework 3.0'
n ykl olmas arttr.

lk olarak aadaki ekran grntsnde olduu gibi Workflow sekmesinde yer alan proje
ablonlarndan(Project Templates) birisinin seilmesi gerekmektedir.

www.bsenyurt.com Page 577


Dikkat edilecek olursa Sequential ve State Machine i aklarnn(Workflow) gelitirilmesi iin
gerekli proje ablonlar(Project Template) bulunmaktadr. Her iki tip iinde birer snf
ktphanesi(Class Library) ve Console uygulamas ablonu yer almaktadr. ok doal olarak
gelitirilen i aklarnn farkl tipte .Net uygulamalarnda kullanlaca durumlar sz konusu
olduunda Workflow Library ablonlarn uygulamak daha doru bir yaklam olacaktr. Windows
Workflow Foundation ile gelitirilen i aklarnda aktivitelerin(Activity) byk nemi vardr.
Gelitiriciler isterlerse kendi zel aktivite tiplerinide(Custom Activity Types) yazabilirler. Bunun
iinde Workflow Activity Libraryablonu kullanlr.

Makalemizdeki ilk rneimizde sonular hemen irdeleyebilmek adna Sequential Workflow


Console Application tipinden bir uygulama yazyor olacaz. Buna ilikin proje ablonu seildikten
sonra uygulama ierisine aadaki ekran grntsnde olduu gibi Workflow1 isimli bir i ak
tipinin eklendii grlr.

www.bsenyurt.com Page 578


ak ierisine rnek aktiviteleri eklemeden nce proje ierisinde oluturulan tiplerden
bahsetmekte yarar vardr. Hereyden nce bir i ak projesi
oluturulduundaSystem.Workflow.Activities, System.Workflow.ComponentModel ve Syste
m.Workflow.Runtime isimli assembly' larn referans edildii grlr.

Tahmin edilecei gibi bu assembly' lar ierisinde i aklarnn gelitirilmesi, altrlmas,


denetlenmesi ve izlenmesi iin gerekli temel tipler yer almaktadr. Bunlarn
dnda console uygulamasna dahil edilmi farkl assembly referanslarda bulunmaktadr. Sz
gelimi i ak ierisinde transaction desteini salamak iinSystem.Transactions, ak
ierisinden web servisleri ile iletiime geebilmek
iin System.Web, System.Web.Services gibi assembly' lar rnek olarak gsterebiliriz.

Proje ierisine varsaylan olarak atlan Workflow1 isimli snfn(Class) hiyerarik yaps ise
aadaki snf diyagramnda(Class Diagram) olduu gibidir.

www.bsenyurt.com Page 579


rnek Sequential Workflow Console Application olduundan, ieride kullanlacak varsaylan i
akda Sequential Workflow olarak ele alnmaktadr. Bu sebepten dolaysealed(kendisinden
tretme yaplamaz) olarak tanmlanm Workflow1 isimli snf ilk
etapta SequentialWorkflowActivity snfndan tremektedir. Ancak enteresan olan bir nokta
vardr. rnek gelitirilirken kullanlacak olan standart pek ok akitivite bileeninin Activity isimli
snfdan tredii grlecektir. Dikkate deer olan, aktiviteleri(admlar-
Steps) ieren Workflow tipinin kendisininde aslnda bir aktivite nesnesi olmasdr. (Snf
diyagramnda pek ok tip yer almaktadr. Bu tiplerin detaylarn ilerleyen makalelerimizde inceleme
frsat bulacaz.)

rneimizdeki i aknn ieriini gelitirmeden nce Program.cs dosyas ierisindeki kod


paralarna ksaca bakalm. u aamada Workflow1 tipine ait i akn(Workflow) veya
bakalarn altracak ve yrtcek olan ksm Main metodunun ieriidir.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Workflow.Runtime;
using System.Workflow.Runtime.Hosting;

www.bsenyurt.com Page 580


namespace MerhabaWWF
{
class Program
{
static void Main(string[] args)
{
using(WorkflowRuntime workflowRuntime = new WorkflowRuntime())
{
AutoResetEvent waitHandle = new AutoResetEvent(false);
workflowRuntime.WorkflowCompleted += delegate(object
sender, WorkflowCompletedEventArgs e) {waitHandle.Set();};
workflowRuntime.WorkflowTerminated += delegate(object
sender, WorkflowTerminatedEventArgs e)
{
Console.WriteLine(e.Exception.Messag
e);
waitHandle.Set();
};

WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(MerhabaWWF.Workflow1));
instance.Start();

waitHandle.WaitOne();
}
}
}
}

imdi Main metodu ierisinde neler yapldna ksaca bir bakalm. WorkflowRuntime snf i
aklarnn devreye sokulmas, bunlarn almas iin gerekli ortamn hazrlanmas, alma zaman
i aklarnn izlenmesi, denetlenmesi gibi ilemleri stlenen nemli bir snftr. Pek ok
nemli olay(Event) vardr. Bunlardan rnekte hazr olarak sunulan WorkflowCompleted olay i
aknn tamamlanmas sonrasnda devreye girmektedir. Bir i ak ilemleri tamamlandktan sonra
geriye deer dndrebilir. Bu sebepten dolay WorkflowCompletedEventArgs tipinden olan olay
parametresinin OutputParameters zelliinden yararlanlarak WorkflowCompleted olay metodu
ierisinde sonu alnmas salanabilir.Tahmin edilecei gibi WorkflowTerminated olay,
herhangibir hata nedeni ile(ounlukla bir istisna-exception) i ak tamamlanamadnda
devreye girmektedir. Bu olayla ilikili olan WorkflowTerminatedEventArgs snf zerinden
hareket edilerek oluan istisna(Exception) referans alma
zamannda(runtime) yakalanabilir. Dikkat edilecek olursa Visual Studio tarafndan otomatik
olarak retilen bu kod parasnda olaylara ait fonksiyonelliklerin hazrlanmasndaisimsiz
metodlardan(anonymous methods) yararlanlmaktadr.

Using blou ierisinde oluturulan rneklerden bir dieride AutoResetEvent snfna ait nesnedir.
Bu snf temel olarak thread senkronizasyonu ynetimi amacyla tasarlanmtr. Host uygulamann
kendi ierisinde bir veya daha ok i akn tetiklemesi sonrasnda askda kalmas istenen bir
durum deildir. Nitekim bir i ak(Workflow) altrldnda Workflow alma
zaman(Runtime) bunu host uygulamadaki ana thread' in dnda ayr bir thread ierisine
alacaktr. AutoResetEvent snfnn Set metodu bu tip bir durumda kalndnda bekleyen thread'
in serbest braklmasn salamaktadr. Dikkat edilecek olursa Set metodu
hem WorkflowCompleted hemdeWorkflowTerminated olay metodular ierisinde arlmakta
ve bekleyen thread' in serbest braklmas salanmaktadr.

Main metodu ierisinde rneklenen dier bir nesne snfda WorkflowInstance' dr. Bu
snfta sealed olarak tanmlanmtr. Bir baka deyile kendisinden tretme yaplamamaktadr. Ayn

www.bsenyurt.com Page 581


zamanda yapc metodlar(Constructor) eriimide yoktur. Kendisi
ancak WorkflowRuntime snfnn static CreateWorkflow metodu ile rneklenebilmektedir. Bu
metodun ar yklenmi(Overload) farkl versiyonlar bulunmaktadr. zellikle i akna
dardan parametre deerleri aktarlabilmesini salayan versiyonu vardr ki bu nemlidir. Nitekim
pek ok i aknn balangcnda bir takm d parametre bilgilerine ihtiya vardr. Dier taraftan
bir XOML(eXtensible Object Markup Language) dosyasnda tanml herhangibir i aknn
yklenmesini salayan versiyonuda bulunmaktadr.

Main metodunun sonunda AutoResetEvent snfna ait nesne rnei


zerinden WaitOne fonksiyonu arlr. Bu ar, alan ana thread' in bekleyen i aklar
tamamlanncaya kadar duraksatlmas iin nemlidir. Nitekim i aknn ierisindeki admlarn
gerekletirilme srelerinin belirsiz olmas ihtimali vardr. WaitOne metodu ilerlenip
ilerlenmeyeceine, dier thread' lerden gelen sinyallere gre karar vermektedir. Tahmin edilecei
gibi rnekte yer alan sz konusu sinyal Set metodu ile yaynlanmaktadr.

Artk i ak ierisine rnek bir adm(Step) ekleyerek devam edebiliriz. Daha nceden de
belirtildii gibi admlar aslnda birer aktivite(Activity) olarak dnlebilirler.WWF mimarisi ok
sayda hazr aktivite sunmaktadr. Bu aktivite bileenlerine i akna ait tasarm
penceresindeylen ToolBox ksmndan da eriilebilir. Var olan tm aktivite
bileenleri System.Workflow.ComponentModel isim alannda(Namespace) yer
alan Activity snfndan(Class) tremektedir. Hazr aktivite bileenlerine rnek
olarakIfElseActivity, CodeActivity, CallExternalMethodActivity, DelayActivity, EventDriven
Activity, ReplicatorActivity, ParallelActivity, TerminateActivity ve daha pek ou verilebilir.

Biz rneimizde basit olmas asndan CodeActivity ve IfElseActivity bileenlerini kullanyor


olacaz. CodeActivity bileeni sayesinde i aknn herhangibir admnda altrlmas istenen
kodlar ele alnabilmektedir. Temel olarak bileenin ExecuteCode zelliine atanan deerin iaret
ettii metod, aktiviteye gelindiinde altrlacak olan kodlar iermektedir. IfElseActivity bileeni
yardmyla bir i aknn herhangibir noktasna karar yaplar eklenebilmektedir. IfElseActivity
bileeni kendi ierisinde birden fazla IfElseBranchActivity rnei ierebilmektedir. Bu
IfElseBranchActivity rneklerinin her biri karar yaps ierisindeki farkl dallanmalar ifade
etmektedir.

Dilerseniz rnek zerinden devam ederek i akn tamamlamaya alalm. rnek senaryoda bir
rnn stoktaki miktarna gre alacak bir i ak tasarlayacaz. Sz gelimi stok miktarnn
belirli bir deerin altna inmesi halinde alacak bir i ak sz konusu olabilir. Hatta farkl aralk
deerlerine gre farkl dallanmalar yaplmasda salanabilir. (Bu noktada i aknn ne kadar
anlaml olduu ok nemli deildir. Nitekim hedeflenen, temel bir i aknn WWF altnda
gelitirilmesi ve kullanlmasdr.) lk olarak tasarm zamannda iken Workflow1 zerine
bir IfElseActivity bileenini ToolBox' tan srkleyerek brakalm. Braklma ileminden sonra ilk
etapta aadaki grnt ortaya kacaktr.

www.bsenyurt.com Page 582


Dikkat edilecei gibi IfElseActivity ierisine varsaylan olarak iki
adet IfElseBranchActivity bileeni daha eklenmitir. Bu noktada soldaki IfElseBranchActivity
bileeninin belirtilen koul trueolduunda altrlmas, dierinin ise false durumuna karlk olarak
deerlendirilmesi doru bir yaklamdr. Her bir IfElseBranchActivity kendi ierisinde baka
aktivitelerin tetiklenmesinede neden olmaktadr. Drop Activites Here ksmna bu amala
eitli aktivite bileenleri(Activity Components) braklabilir. IfElseBranchActivity' lerin en
nemli yesi aadaki ekran grntsndende grlebilecei
gibi Condition zelliidir(Property).

www.bsenyurt.com Page 583


Condition zelliine Code Condition ve Declarative Rule Condition olmak zere iki farkl deer
verilebilir. Peki bunlar ne anlama gelmektedir? Code Condition deerinin atanmas halinde koulun
bir metod ile deerlendirilecei belirtilir. Sz konusu metod bool bir deerlendirme
yapmaldr. Declarative Rule Condition seenei sayesinde ise, koul kodun dnda ayr bir
ekilde ele alnr. Bu eit bir kullanm alma zamannda(Run-Time) yeniden derleme
gerektirmeden koul deiiklii yapma imkan sunmaktadr. rneimizde ilk olarak Declarative
Rule Condition seeneini inceliyor olacaz. Bu kriter seildikten sonra Condition zellii altna
iki alt yenin daha eklendii grlecektir.

Bunlardan ConditionName koulun adn ifade ederken, Expression ise koula ait ifadeyi
iermektedir. ConditionName zelliine sembolik olarak Miktar50Altinda verdiimizi dnelim.
Bundan sonra Expression zellii yanndaki nokta dmesine tklarsak aadaki arabirim ile
karlarz.

Bu ekranda geriye true veya false dndrebilecek ekilde bir koul tanmlamas yaplmaktadr.
Dikkat edilecek olursa metin kutusu ieriinde intellisense destei vardr. Ancak bu noktada i
aknn dourduu nemli bir ihtiyata ortaya kmaktadr. Bir ekilde i akna, rne ait stok
miktar deerinin aktarlmas gerekmektedir. Lakin koulun deerlendirmesi gereken durum stok
miktarnn belirli bir deerin altnda olmas halinde yaplacak ilemler ile ilgilidir. Dolaysyla i
akna dardan paramete aktarlmas gerekmektedir.

www.bsenyurt.com Page 584


Bir i akna aktarlacak olan parametreler herhangibir .Net CLR(Common Language
Runtime) tipi olabilir. Bu nemli bir avantajdr, nitekim bir i ak(Workflow)nceden
tanml veya gelitirici tarafndan yazlm herhangibir tip verisi ile balatlabilir.
aklarnn herhangibir .Net CLR tipini parametre olarak alabilmesinde object tipi etkin
bir rol oynar. Elbetteki bir i akna birden fazla parametrede gnderilebilmektedir.

Bunun yapmann yolu ise son derece basittir. Nitekim Workflow tipi aslnda bir snftr.
Dolaysyla Workflow tipine zellikler(Property) ekleyerek d ortamdan parametre aktarm
salanabilir. Bu nedenle rnekte yer alan Workflow1 snfna aadaki gibi bir zelliin ilave
edilmesi yeterlidir.

public sealed partial class Workflow1: SequentialWorkflowActivity


{
private int _stokMiktari;

public int StokMiktari


{
get { return _stokMiktari; }
set { _stokMiktari = value; }
}

public Workflow1()
{
InitializeComponent();
}
}

Artk tasarm tarafna dnlerek ilk IfElseBranchActivity iin gerekli koul aadaki ekran
grntsndeki gibi oluturulabilir.

Buna gre StokMiktari zelliinin(Property) deerinin 10 ile 50 arasndaki olmas halinde,


bu IfElseBranchActitiy bileenin arkasndan gelecek olan aktivite altrlacaktr. Bu noktada ne
yaplmak istendii nemlidir. Sz gelimi bu koulun salanmas halinde reticiye yeni rn talepleri
iin mail veya Sms gnderilmesi gibi ilemler yaptrlabilir. Yine ok basit olarak dnerek hareket
edelim ve mail gnderme ileminin yaplaca kod blounu iaret edecek
bir CodeActivity bileenini aadaki ekran grntsnde olduu gibi tasarm ortamna atalm.

www.bsenyurt.com Page 585


CodeActivity bileeninin en nemli yesi ExecuteCode zelliidir. Bu zellie atanacak olan isim,
bu admda altrlacak olan metodun addr. Bu olay metodunun otomatik olarak oluuturulmas
salanabilir. Bunun iin ExecuteCode zelliine bir metod ad yazlmas ve enter' a baslmas
yeterlidir. rnekteki ExecuteCode zelliine MailGonderismini yazp enter tuuna
bastmzda Workflow1 snfna aadaki metodun otomatik olarak eklendii grlecektir.

private void MailGonder(object sender, EventArgs e)


{
}

Grld gibi retilen metod stadart bir olay metodu yapsndadr. Geriye deer dndrmemekte
ve iki adet parametre almaktadr. mantnda bu admda iletilmesi gereken kodlar nelerse bu
metod ierisine yazlmaldr. Sz gelimi bu admda mail gnderme ilemi yaptrlabilir.

IfElseActivity ierisinde sa tarafta kalan ikinci bir IfElseBranchActivity bileeni daha vardr. u
anki senaryoda bu bileen else olma durumunda ne olacan belirtmektedir. Dier taraftan rnek
senaryoda baka IfElseBranchActivity bileenlerinin eklenmeside mmkndr. rnein Stok
miktarnn herhangibir nedenle 0 ve altnda olmas hali ve Stok Miktarnn 50' nin zerinde olmas
hali gibi. Bu durumlarn her biri iin birer IfElseBranchActivity kontrol eklenip gerekli aksiyonlarn
gerekletirilmesi salanabilir.

IfElseActivity bileenleri ierisine IfElseBranchActivity bileenlerini eklemek iin sa


tklayp Add Branch demek yeterlidir.

www.bsenyurt.com Page 586


Bu amala rneimize aadaki ekildede grld gibi baka IfElseBranchActivity bileenleri
daha eklediimizi dnelim.

Burada ikinci IfElseBranchActivity ierisinde StokMiktari zelliinin deerinin 0' n altnda ve


eit olduu durumda altrlacak bir kod aktivitesi yer almaktadr. 3nc IfElseBranchActivity
ierisinde StokMiktari zelliinin deerinin 50 ile 500 arasnda olduu durumda alacak bir
aktivite bulunur. Son IfElseBranchActivity parasnda ise var olan koullarn dndaki durum ele
alnmaktadr. Genellikle birden fazla IfElseBranchActivity ieren durumlarda tm ihtimallerin dnda
kalabilecek bir seeneide ele almak iinCondition zellii herhangibir ekilde atanmam bo
bir IfElseBranchActivity paras kullanmakta yarar vardr. rnekte bu tarz bir durum iin yine
kod aktivitesi yrtlmektedir. Elbette her CodeActivity bileenin ExecuteCode zelliine ilgili
deerlerin atanmas ve oluan olay metodlarnn kodlanmas gerekmektedir. imdilik bu ksm bizim

www.bsenyurt.com Page 587


amzdan nemli deildir. Nitekim rnee son olarak yaplan eklemelerde kavranmas gereken
birden fazla IfElseBranchActivity bileenin bir arada ele alnabilmesidir.

IfElseBranchActivity ilemlerinde karar mekanizmas olarak Declarative Rule


Condition kullanlmas halinde kurallarn rules uzantl bir XML dosyas ierisine yazld
grlr. Aadaki ekran grntsnde rnekte kullanlan IfElseBranchActivity' ler iin
oluturulan Workflow1.rules dosyasnn sadece bir ksm grlmektedir.

imdi i ak iin daha fazla nem arz eden bir konu zerinde durulmaldr. akna ilgili
parametreler nasl aktarlacaktr? Bu amala Main metodu ierisinde yer alan kod paralarnda baz
deiiklikler yaplmas gerekmektedir. Daha ncedende belirtildii gibi WorkflowRuntime snfna
ait CreateInstance metodunun ikinci parametresi i aklarna deer gndermek iin
kullanlmaktadr. aklar herhangibir .Net CLR tipini parametre olarak aldndan ve d
ortamdan i akna gnderilen deerin hangi zellie aktarldnn bilinmesi gerektiinden generic
Dictionary<string,object> koleksiyonu kullanlmaktadr. Bylece ilgili i aknn hangi zelliine,
hangi deerin aktarlaca belirtilebilir. Bu ayn zamanda i akna birden fazla parametre deeri
gnderilebilmesi anlamnada gelmektedir.

rnekte kullanlan StokMiktari zelliinin(Property) deeri i akna d ortamdan, rnein


Host uygulama ierisinden gelmektedir. Bu nedenle Main metodu ierisinde aadaki
deiikliklerin yaplmas gerekir.

Dictionary<string, object> parametreler = new Dictionary<string, object>();


parametreler.Add("StokMiktari", 45);

WorkflowInstance instance =
workflowRuntime.CreateWorkflow(typeof(MerhabaWWF.Workflow1),parametreler);

lk olarak parametre veya parametreleri tayacak olan Dictionary<string,object> koleksiyonu


rneklenir. Bu generic koleksiyonun anahtarlar(Keys) string,
deerleri(Values) iseobject trnden olmaldr. Daha sonra Add metodu ile parametre ekleme
ilemi gerekletirilir. rnekte StokMiktari isimi zellik iin 45 deerinin verilecei belirtilmektedir.
Son olarakWorkflowInstance rnei oluturulurken CreateWorkflow metodunun ikinci

www.bsenyurt.com Page 588


parametresine, koleksiyona ait nesne rnei atanr. Burada dikkat edilmesi gereken baz noktalarda
vardr. Hereyden nce Dictionary koleksiyonuna eklenen parametre adnn, i
ak(Workflow) snf ierisinde tanmlanan zellik ad(Property Name) ile bire bir uygun
olmas gerekmektedir. Sz gelimi Add metodunda StokMiktari yerine stokmiktari yazlrsa
aadaki ekran grntsnde olduu gibi alma zamannda ArgumentException
istisnas(Exception) alnr.

Bu noktadan sonra i ak baarl bir ekilde alacaktr. rnek olarak tasarlanan i aknn
herhangibir amac ve baars yoktur ancak temel kavramlarn nasl uygulanacan gstermektedir.

Makalemize IfElseBranchActivity bileenlerinde Condition zelliinde Code


Condition seeneini nasl kullanacamz inceleyerek devam edelim. Bu amala rnek olarak
herhangibir IfElseBranchActivity' nin Condition zelliine Code Condition deerini atmamz
yeterli olacaktr.

Burada Condition altnda yer alan Condition zelliinede bir metod ad verilmesi gerekmektedir.
rnein Stok10ile50Arasindami ismini verip enter tuuna bastmz dnelim. Bunun sonucu
olarak workflow1.cs ierisine aadaki metodun eklendii grlecektir.

private void Stok10ile50Arasindami(object sender, ConditionalEventArgs e)


{

Metodun bool tipinde bir deerlendirme yapmas gerekmektedir. Buna karn dikkat edilecei
zere void tipinde oluturulmutur. te bu noktada koulun sonucunu geriye dndrmek
iin ConditionalEventArgs tipinden olan parametrenin, Result zelliinden
yararlanlr. Result zellii bool tipindendir ve koula gre true veya false deerini almaldr.
Buna gre kod aadaki ekilde dzenlenebilir.

private void Stok10ile50Arasindami(object sender, ConditionalEventArgs e)


{
if (StokMiktari >= 10 && StokMiktari <= 50)

www.bsenyurt.com Page 589


e.Result = true;
else
e.Result = false;
}

Eer StokMiktari zelliinin deeri 10 ile 50 arasnda ise bu koul salanm demektir. Bu
durumda Result zelliine true deeri atanmaldr. Eer true deeri
atanrsaIfElseBranchActivity' den sonra gelen aktivitenin altrlmas da salanm olur.
Elbetteki buradaki kod parasnda, koulun salanm olma veya olmama haline gre sradaki
aktiviteye geilmeden nce farkl ilemler yaptrlmasda salanabilir.

Makalemizin son blmnde i akn(Workflow) bir snf ktphanesi(Class Library) olarak


nasl tasarlayabileceimizi ve bunu rnein bir windows uygulamasnda nasl host edebileceimizi
incelemeye alacaz. Bu sefer proje ablonu olarak Sequenatial Workflow Library modelini
sememiz gerekiyor. Oluan snf ktphanesi(Class Library) ierisinde yine standart
olarak Workflow1 isimli bir i ak nesnesi bulunur. rnek olarak bir metin dosyasnn ierisinde
parametre olarak verilen bir kelimenin bulunmas veya bulunmamas halinde yaplabilecek baz
ilemler olduunu ve bunun bir i sreci olarak gz nne alndn dnelim. Sz konusu srecin
birden fazla .Net uygulamas ierisinde ele alnabileceini dnrsek i aknn snf ktphanesi
olarak tasarlanmas son derece mantkldr. aknn bu anlamda dardan almas gereken iki
adet parametre bulunmaktadr. Bunlardan birisi dosya adresini, dieri ise aranacak bilgiyi
tutmaldr. Dier taraftan i akndan Host eden uygulamayada bilgi gnderilmesi istenebilir. Sz
gelimi arama sonularna dair bir string bilgi sz konusu olabilir. Doal olarak 3nc bir zellie
daha gerek vardr. Bu nedenle workflow1 snf ierisine aadaki kod parasnda yer
alan zelliklerin(Properties) eklenmesi gerekmektedir.

public sealed partial class Workflow1: SequentialWorkflowActivity


{
private string _dosyaAdresi;
private string _arananKelime;
private string _aramaSonucu;

public string AramaSonucu


{
get { return _aramaSonucu; }
set { _aramaSonucu = value; }
}

public string ArananKelime


{
get { return _arananKelime; }
set { _arananKelime = value; }
}

public string DosyaAdresi


{
get { return _dosyaAdresi; }
set { _dosyaAdresi = value; }
}

public Workflow1()
{
InitializeComponent();
}
}

www.bsenyurt.com Page 590


lk rneimizdeki gibi bir IfElseActivity ve iki adet IfElseBranchActivity ekliyoruz. Burada dosya
ierisinde bir bilgi arama ilemi yaplmak istendiinden koulun kod yardmyla kontrol edilmesi, bu
nedenle Code Condition seeneinin kullanlmas daha mantkldr. Hatalara ok fazla taklmamak
adna sadece txt uzantl dosyalar ele aldmz
dnelim. IfElseBranchActivity1 bileeninin Condition zelliinin
deerini Code Condition olarak ayarladktan sonra alt Condition zelliinede ArananKelimeVarmi
bilgisini yazalim. BuIfElseBranchActivity1 iin alacak koul kontrol metodunun ad
olacaktr. IfElseBranchActivity2 bileeni iin herhangibir Condition atamas yaplmasna gerek
yoktur. Nitekim otomatik olarak else durumunun deerlendirilecei yerdir. Her iki aktivitenin
arkasndan altrlmak istenen kodlarn yer ald CodeActivity bileenlerinide ekleyelim. Sonuta
i aknn tasarm zamanndaki grnts aadaki gibi olacaktr.

CodeActivity1 iin ArananBilgiVar isimli bir metod, CodeActivity2 bileeni


iinde ArananBilgiYok isimli bir metod devreye girecektir. Buna gre Workflow1 snfnn
balangtaki ierii aadaki gibidir.

using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
using System.Workflow.ComponentModel.Compiler;
using System.Workflow.ComponentModel.Serialization;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using System.Workflow.Runtime;
using System.Workflow.Activities;
using System.Workflow.Activities.Rules;
using System.IO;

namespace StokAkislari
{
public sealed partial class Workflow1: SequentialWorkflowActivity

www.bsenyurt.com Page 591


{
private string _dosyaAdresi;
private string _arananKelime;
private string _aramaSonucu;

public string AramaSonucu


{
get { return _aramaSonucu; }
set { _aramaSonucu = value; }
}

public string ArananKelime


{
get { return _arananKelime; }
set { _arananKelime = value; }
}

public string DosyaAdresi


{
get { return _dosyaAdresi; }
set { _dosyaAdresi = value; }
}

public Workflow1()
{
InitializeComponent();
}

// IfElseBranchActivity1 bileenine ait koul kontrol metodu


private void ArananKelimeVarmi(object sender, ConditionalEventArgs e)
{
if (File.Exists(DosyaAdresi))
{
StreamReader reader = new StreamReader(DosyaAdresi);
e.Result = reader.ReadToEnd().Contains(ArananKelime);
}
else
e.Result = false;
}

// CodeActivity1 iin alacak olay metodu


private void ArananBilgiVar(object sender, EventArgs e)
{
// Aranan bilgi bulunduunda yaplacak ilemler
AramaSonucu = ArananKelime + " " + DosyaAdresi + " iinde bulunmutur";
}

// CodeActivity2 iin alacak olay metodu


private void ArananBilgiYok(object sender, EventArgs e)
{
// Aranan bilgi bulunamadnda yaplacak ilemler
AramaSonucu = ArananKelime + " " + DosyaAdresi + " iinde bulunamamtr";
}
}
}

www.bsenyurt.com Page 592


Amacmz her zamanki gibi konuyu basite kavramak olduundan CodeActivity bileenleri ile
ilikili kod paralar imdilik gz ard edilmitir. Artk host uygulamay yazarak devam edebiliriz. Bu
amala basit bir Windows uygulamas tasarlayacaz. Uygulamamz text tabanl dosyalarn
seimine ve aranacak kelimenin girilmesine izin verecek bir arabirime sahip olacaktr. Buradaki asl
hedefimiz ise bir .Net uygulamas ierisinden herhangibir i aknn(Workflow) nasl
altrlabileceini grmektir. Windows uygulamasnda tahim edilecei gibi
baz Workflow assembly' larnn ve i aklarn tayan ktphanenin eklenmi olmas
gerekmektedir. Sonu itibariyle windows uygulamasnda aadaki ekilde grlen referanslarn
dahil edilmesiyle ie balanmaldr.

Bu noktadan sonra Windows uygulamasnn aadaki gibi tasarlandn dnebiliriz. Kullanc


Dosya Se balkl dmeye bastnda alacak iletiim kutusu ile txt uzantl dosya seebilecektir.
Aranacak kelime bilgiside girildikten sonra srecin balatlmas iin tek yaplmas gereken Sreci
Balat balkl dmeye basmak olacaktr.

Dosya seme ilemi iin OpenFileDialog bileeni kullanlamktadr. Sadece Text tabanl dosyalar
ele alnmak istendiinden Filter zelliine Text Files|*.txt deeri atanmtr. Uygulamann kod
ierii ise aadaki gibidir.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;

www.bsenyurt.com Page 593


using System.Text;
using System.Windows.Forms;
using System.Workflow.Runtime;
using System.Threading;
using StokAkislari;

namespace Istemci
{
public partial class Form1 : Form
{
private WorkflowRuntime _wfRunTime;
private WorkflowInstance _wfInstance;
// Workflow thread' lerinin ynetimi iin AutoResetEvent nesnesi kullanlr
private AutoResetEvent _arEvent = new AutoResetEvent(false);

public Form1()
{
InitializeComponent();

// Workflow alma zaman nesnesi rneklenir


_wfRunTime = new WorkflowRuntime();

// Workflow tamamlandnda devreye girecek olay metodu yklenir


_wfRunTime.WorkflowCompleted += delegate(object sender,
WorkflowCompletedEventArgs e)
{
MessageBox.Show(e.OutputParameters["Ar
amaSonucu"].ToString());
_arEvent.Set();
};

// Workflow' un almas srasnda bir istisna olutuunda devreye girecek olay metodu
yklenir.
_wfRunTime.WorkflowTerminated += delegate(object sender,
WorkflowTerminatedEventArgs e)
{
MessageBox.Show(e.Exception.Message);
_arEvent.Set();
};
}

private void btnDosyaSec_Click(object sender, EventArgs e)


{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
txtDosyaAdresi.Text = openFileDialog1.FileName;
}
}

private void btnSureciBaslat_Click(object sender, EventArgs e)


{
try
{
if (!String.IsNullOrEmpty(txtArananKelime.Text)
&& !String.IsNullOrEmpty(txtDosyaAdresi.Text))
{

www.bsenyurt.com Page 594


// parametrelerin gnderilmesi iin Dictionary koleksiyonu rneklenir
Dictionary<string, object> parametreler = new Dictionary<string,
object>();

// Workflow1 ierisindeki zelliklerin alaca deerler set edilir.


parametreler.Add("DosyaAdresi", txtDosyaAdresi.Text);
parametreler.Add("ArananKelime", txtArananKelime.Text);

// Workflow1 iin bir rnek oluturulur.


_wfInstance = _wfRunTime.CreateWorkflow(typeof(Workflow1),
parametreler);

// Workflow1 balatlr.
_wfInstance.Start();

_arEvent.WaitOne();
}
else
MessageBox.Show("Verilerde eksik var");
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}
}
}

Gelitirilen rnekte form nesnesi retilirken i ak alma ortam(Workflow Run-Time) iin


gerekli ayarlar yaplmaktadr. Bu amala WorkflowRuntime nesnesi
rneklenmekte, WorkflowCompleted, WorkflowTerminated gibi olaylar isimsiz
metodlar(Anonymous Methods) araclyla yklenmektedir. Bir nceki rnekten farkl olarak
dikkat edilmesi gereken nokta WorkflowCompleted olay metodu
ierisinde WorkflowCompletedEventArgs snfna ait OutputParameters zelliinin
kullanldr. Bu zellikteDictionary<string,object> tipinden generic bir koleksiyonu ele
almaktadr. zelliin amac, i akndan uygulama ortamna deer aktarmn salamaktr. Bu
amalaindeksleyici(Indexer) operatr ierisinde, i aknda
tanmlanan AramaSonucu zelliinin ad verilmektedir.

Doal olarak srecin bir ekilde balatlmas gerekmektedir. Bu amala WorflowInstance rnei
oluturulduktan sonra, Start metodu arlmaktadr. Tm bu balatma ilemi ise Form zerindeki
bir Button kontrolne ait Click olay metodu ierisinde gerekletirilmektedir. rnek test
edildiinde bir dkman ierisinde aranan bilginin var olup olmadna dair sonularn alnd
grlecektir. (Tahmin edilecei zere bu tarz bir ihtiya normal bir snf ktphanesi ierisine
alnacak bir tip ilede, i aklarna gerek olmadan tasarlanabilir. Ancak gerek i problemleri gz
nne alndnda tek bana yeterli bir zm olmayacaktr.)

Buraya kadar yazdklarmz ile i ak(Workflow) kavramn, Windows Workflow


Foundation yaklamn incelemeye altk. Giri niteliindeki bu makalemizde, bir i ak iin
gerek hayat senaryolar kullanmam olsakta, WWF ile nasl gelitirilebileceklerini,
herhangibir .Net uygulamasndan nasl kullanlabileceklerini grdk. Bundan sonraki
makalelerimizde WWF mimarisinin baka konularnda incelemeye alyor olacaz. Makalemize
son vermeden nce Windows Workflow Foundation ile ilgili kaynak kitaplarhakknda bilgi vermek
isterim. Sz konusu kitaplar ve bunlara ait zet bilgiler aadaki tabloda yer ald gibidir.

www.bsenyurt.com Page 595


Kitap zet Bilgi

Microsoft Windows Workflow Foundation Step by Step

Mart 2007 tarihinde kan Microsoft Press' e ait bu kitap ierisindeki bilgiler ile
WWF mimarisini adm adm renmek mmkn. Aynen Microsoft Windows
Communication Foundation Step by Step kitabnda olduu gibi olduka iyi bir
anlatma sahip. Ksa srede tamamlanabilecek bu kitap ile WWF mimarisini orta
seviyede renmek mmkn. Toplam 19 blmden oluan kitap ierisinde i
aklarnn SOA ile entegrasyonu, transaction destei, paralel
aktivitilerin(Activities) tasarlanmas gibi ileri seviye konularda yer almakta.

Pro WF: Windows Workflow in .NET 3.0 (Expert's Voice in .Net)

ubat 2007 tarihinde APress tarafndan yaynlanan bu kitap 744 sayfalk bir
ierii 17 blm altnda toplamakta. Workflow konusunda yazlm kitaplar arasnda
temelden ileri seviyeye doru giden ve en anlalr olanlarndan bir tanesi. leri
seviye saylabilecek blmlerde, i aklarnn dinamik gncellenmesi, i aklarnda
seriletirme, i aklarnn izlenmesi gibi konu balklarda yer almaktadr.

Professional Windows Workflow Foundation

Wrox yaynlarndan Mart 2007 tarihinde kartlan bu kitap 410 sayfalk mtevazi
bir ierie sahip. Lakin bu ierik sayesinde ok ksa zamanda Windows Workflow
Foundation mimarisini anlamak ve etkin bir ekilde kullanabilmek mmkn. stelik
kitapta best practices, ileri seviyede aktivite(Activity) tasarlanmas, dinamik
gncelletirme, ofis(Office) sistemleri ile entegrasyon gibi enteresan ksmlarda yer
almakta.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Linq To Sql : Arka Planda Neler Oluyor? (


19.12.2007 ) - LINQ
Deerli Okurlarm Merhabalar,

Veritaban(Database) nesnelerinin programatik ortamda snf gibi tipler(Type) ve metod benzeri


yeler(Members) ile ifade ediliyor olmas, bu tiplere ait nesne rnekleri zerinden sorgulalamalar
yaplabilmesi ihtiyacnda ortaya kartmtr. Bir veritaban nesnesinin programatik taraftaki
karlnn nesne ynelimli(Object Oriented) bir dilde gelitirilmesi son derece kolaydr. rnein
bir tablo(Table) gz nne alndnda, bu tablonun kendisi bir snf(Class) olarak tasarlanabilir.
Benzer ekilde, tablo ierisindekialanlar(Fields) snf iinde yer alan
birer zellik(Property) olarak dnlebilir.
Basit CRUD(CreateRetrieveUpdateDelete) ilemleri, varlk snf(Entity Class)diyebileceimiz
tipin birer ye metodu olarak dnlebilir. Tabloda yer alan kolonlarn baz niceleyicileri(rnein
Null deer ierip iermedikleri, primary key olup olmadklar vb...) snfn kendisi ve yeleri iin
birer nitelik(Attribute) olarak tasarlanabilir. Ne varki bu eletirme kolayl dnda, programatik

www.bsenyurt.com Page 596


tarafta yer alan nesnel yaplar zerinde, SQL cmlelerine benzer ifadeler ile sorgulamalar yapmak
kolay deildir. Nitekim, programatik tarafn SQL benzeri cmelere karlk gelen fonksiyonellikleri
ele alyor olmas gerekmektedir. LINQ(Language Integrated Query) mimariside, temel anlamda
programatik tarafta yazlan ifadeleri arka planda metodlar, temsilciler(Delegates) yardmyla
kurduu bir modele dntrmektedir. LINQ' in kullanld alanlar gz nne alndnda en
popler seeneklerden biriside LINQ to SQL mimarisidir.

Language INtegrated Query to SQL mimarisi ile, varlk tipleri(Entity Types) zerinden
sorgular altrlabilir. Basit anlamda, nesneler(Objects) zerinde uygulanabilen LINQ sorgular,
SQL tarafna ulatklarnda ise bildiimiz sorgu ifadelerine(Query Expressions) dnmektedir.
Bilinen LINQ operatrlerinin veya metodlarnn tamamnn SQL tarafna uygulanamad veya henz
uygulanamad bir gerektir. Nitekim programatik ortamn esneklii nedeni ile, rnein bir dizinin
ters evrilerek elemanlar zerinde dngsel anlamda ilerlenebilmesinin, SQL tarafnda karlnn
bulunmas zordur(ki buda LINQ metodlarndan olan Reverse fonksiyonelliinin neden LINQ to
SQL zerinde kullanlamadnda aklamaktadr).

Bu ana fikirlerden yola karak makalemizdeki ana temamzn, SQL ifadelerine


evrilebilen LINQ operatrlerinin veya fonksiyonelliklerinin, arka planda ne ekilde tasarlandklarn
inceleyebilmektir. Bir baka deyile basit ve karmak LINQ cmlelerinin, SQL tarafnda ele
alnabilen karlklarnn ne olduklarn tespit edebilmektir. Bu aratrmadaki en byk
yardmclarmz ise SQL Server Profiler ve Estimated Execution Plan
aralar(Tools) olacaktr. SQL Server Profiler arac kullanlarak, varlk(Entity) nesneleri
zerinde altrlan LINQ ifadelerinin karl olan SQL sorgu cmlelerini grmek mmkn
olabilmektedir. Dier taraftan Estimated Execution Plan arac sayesinde, LINQ iin arka tarafta
altrlan bir sorgu cmlesinin icra plannn grlmesi ve alternatif ifadeler ile aralarndaki farklar
tespit edilerek daha optimal yollarn gz nne alnmas salanabilir.

Dilerseniz hi vakit kaybetmeden rneklerimize geerek devam edelim. Her zamanki gibi Visual
Studio 2008 RTM zerinden rnek kod paralarmz altryor olacaz. Basit
bir Console uygulamas zerinden ilerlerken AdventureWorks ve Northwind
veritabanlarndaki(Database) baz tablolar kullanyor olacaz. Bu
anlamda AdventureWorks.dmbl veNorthwind.dmbl isimli DataBase Markup
Language ieriklerimiz aadaki ekran grntlerinde yer ald gibi olacaktr.

AdventureWorks.dbml;

www.bsenyurt.com Page 597


AdventureWorks veritabanndan rnek sorgulamalar
iin ProductCategory, ProductSubCategory, Product, SalesPerson ve SalesOrderHeader ta
blolar ele alnmaktadr.

Northwind.dmbl;

Northwind veritabanndan ise Customer ve Supplier tablolar ele alnmaktadr.

lk olarak aadaki gibi basit bir LINQ ifadesi ile balayalm.

AdventureWorksDataContext adw = new AdventureWorksDataContext();

var mClassProducts = from prd in adw.Products


where prd.Class == "M"
select prd;

int mCount = mClassProducts.Count();


double mSumListPrice = mClassProducts.Sum<Product>(prd => (double)prd.ListPrice);

Console.WriteLine(mCount.ToString());
Console.WriteLine(mSumListPrice.ToString("C2"));

lk olarak AdventureWorksDataContext nesnesi rneklenmektedir.


Sonrasnda mClassProducts isimli alana atanan
ifadede AdventureWorksDataContext ierisinde yer alan Productszelliinin karl olan
generic Table<Product> tipi ele alnmaktadr. Buna gre Product nesne
rneklerinden, Class zelliklerinin(Properties) deerleri M olanlar seilmektedir. Daha nceki
makalalerdede belirttiimiz gibi var anahtar kelimesi ile tanmlanm olan deikene atanan bu
ifade alma zamannda hemen yrtlmemektedir. cra ilemi iin bir for iterasyonu olmas yada
ifade zerinden rnekteki gibi Aggregate benzeri fonksiyonelliklerin altrlmas
gerekmektedir. mCount alannn deeri, hazrlanan LINQifadesinde Count metodu uygulanarak
elde edilmektedir. Bir baka ifadeyle, snf M olan rnlerin toplam says
bulunmaktadr. mSumListPrice alanna atanan deer ilede, snf M olan rnlerin liste
fiyatlarnn(ListPrice) toplam elde edilir. Sonrasnda ise bu sonular ekrana yazdrlr. alma
zamannda(run time) uygulamann kts aadaki gibi olacaktr.

Gelelim arka tarafta altrlan SQL sorgu cmlelerine. SQL Server Profiler arac kullanlarak
yaplan almada Count ve Sum aggregate metodlarnn aadaki gibi icra edildii
grlmektedir. Count fonksiyonunun arlmas sonucu alan sorgu u ekildedir;

www.bsenyurt.com Page 598


exec sp_executesql N'SELECT COUNT(*) AS [value]
FROM [Production].[Product] AS [t0]
WHERE [t0].[Class] = @p0',N'@p0 nvarchar(1)',@p0=N'M'

Burada dikkat edilmesi gereken noktalardan birisi Count(*) ifadesidir. Normal artlar altnda
tavsiye edilen yntemlerden birisi Count(ProductID) tarznda bir kullanm yaplmas ynndedir.
Bu tarz bir kullanmn performans ynnde avantaj salad bilinmektedir. Nitekim LINQ tarafndan
gelen ifadeye gre Count(*) eklinde bir SQL fonksiyonu kullanlmtr. Dier
tarafan LINQ sorgusunun aadaki gibi deitirilmesi dnlebilir.

var mClassProducts = from prd in adw.Products


where prd.Class == "M"
select prd.ProductID;

Dikkat edilecei zere burada sadece ProductID alanlar seilmektedir. Bu ifade


zerinden Count metodu kullanlrsa SQL tarafnda icra edilen operasyonun deimedii, bir baka
deyile Count(*) ars yapld grlr. Sum fonksiyonunun arlmas sonucu alan sorgu ise
aadaki gibidir.

exec sp_executesql N'SELECT SUM([t1].[value]) AS [value]


FROM (
SELECT CONVERT(Float,[t0].[ListPrice]) AS [value], [t0].[Class]
FROM [Production].[Product] AS [t0]
) AS [t1]
WHERE [t1].[Class] = @p0',N'@p0 nvarchar(1)',@p0=N'M'

Dikkat edilecek olursa burada Sum ilemi iin bir i Select sorgusu daha yrtlmektedir. Ayn
amaca ynelik olaraktan aadaki gibi bir sorguda gz nne alnabilir.

SELECT SUM(ListPrice) AS [Value]


FROM Production.Product
GROUP BY Class
HAVING Class='M'

Burada Group By kullanm gerekletirilmektedir. LINQ' in Sum metodunu neden farkl bir
ekilde yorumlad tartlabilir. Sonu itibariyle her iki sorgu cmlesininde beklenen icra
planlarna(Esitamted Execution Plan) bakldnda Products gibi sadece 504 satra sahip olan
kk bir tabloda ok fazla bir fark olmad grlmektedir. Ancak tablo boyutunun artmas halinde
bu durumun belirgin performans farkllklarna yol ap amayacana baklmaldr. Aadaki ekran
grntlerinde her iki sorgunun icra planlarna ait icra maliyetleri daha net bir ekilde
grlmektedir.

www.bsenyurt.com Page 599


Dier LINQ to SQL operatrlerini inceleyerek devam edelim.
Sradaki LINQ ifadesinde, Contains metodu ele alnmaktadr. Contains metodu String snfna ait
bir fonksiyondur. Aadaki kod parasnda yer alan ifadeye gre Contains metodunun
grevi, ProductNumber alannda PA hecesi olan Product nesne rneklerinin tespit edilmesinin
salanmasdr.

var allProducts = from prd in adw.Products


where prd.Class == null && prd.ProductNumber.Contains("PA")
select prd;

foreach (Product p in allProducts)


{
Console.WriteLine(p.ProductNumber + " " + p.Name);
}

Sorgu ifadesi null deere sahip olan snflara ait rnlerden, rn numarasnda PA hecesi geenleri
elde etmektedir. Yukardaki kod parasn ieren Console uygulamas altrldnda aadaki
sonular alnacaktr.

www.bsenyurt.com Page 600


Bizim iin asl nem arz eden konu LINQ to SQL ifadesinin SQL sunucusuna nasl gnderildiidir.
Hemen SQL Server Profiler aracna baklrsa aadaki sorgu cmlesinin altrld grlebilir.

exec sp_executesql N'SELECT


[t0].[ProductID], [t0].[Name]
, [t0].[ProductNumber], [t0].[MakeFlag]
, [t0].[FinishedGoodsFlag], [t0].[Color]
, [t0].[SafetyStockLevel], [t0].[ReorderPoint]
, [t0].[StandardCost], [t0].[ListPrice]
, [t0].[Size], [t0].[SizeUnitMeasureCode]
, [t0].[WeightUnitMeasureCode], [t0].[Weight]
, [t0].[DaysToManufacture], [t0].[ProductLine]
, [t0].[Class], [t0].[Style], [t0].[ProductSubcategoryID]
, [t0].[ProductModelID], [t0].[SellStartDate]
, [t0].[SellEndDate], [t0].[DiscontinuedDate]
, [t0].[rowguid], [t0].[ModifiedDate]
FROM [Production].[Product] AS [t0]
WHERE
([t0].[Class] IS NULL) AND ([t0].[ProductNumber] LIKE @p0)'
,N'@p0 nvarchar(4)',@p0=N'%PA%'

Dikkat edilecei zere programatik tarafta yaplan ==null kontrol SQL tarafnda Is
Null olarak, Contains metodu ise Like olarak evrilmitir. Buradaki Like ifadesine
gnderilen %PA%deeri, ierisinde PA hecesi geenleri ifade etmektedir.
yleyse Contains metodu yerine rnein StartsWith fonksiyonu kullanlrsa ne olacana
baklmaldr. Bu amala LINQ to SQL ifadesini aadaki gibi deitirdiimizi dnelim.

var allProducts = from prd in adw.Products


where prd.Class == null && prd.ProductNumber.StartsWith("PA")
select prd;

Bu durumda SQL tarafna gnderilen sorgu cmlesinin ieriine bakldnda LIKE anahtar
kelimesine atanan parametrenin PA% eklinde olduu grlmektedir. Dolaysyla beklenildii
gibi PA hecesi ile balayanlarn tedarik edilmesi iin sorguda gerekli dzenleme yaplmtr.

Bir nceki LINQ to SQL ifadesinde, SQL sunucusu zerinde alan sorguya
bakldnda Product tablosundaki tm alanlarn ekildii grlmektedir. Oysaki ou durumda
elde edilip veri kmesi Entity zerine alndnda yanlzca bir ka alan zerinde ilem
yaplmaktadr. Sz gelimi elde edilen listenin bir GridView zerinde gsterilmesi istendiinde tm
alanlar yerine gerekli olanlarn gsterilmesi tercih edilir. te bu noktada isimsiz
tiplerin(Anonymous Types) faydas ortaya kmaktadr. Buna gre aadaki LINQ to SQL
ifadesini ele alalm.

var allProducts = from prd in adw.Products


where prd.Class == null && prd.ProductNumber.Contains("PA")

www.bsenyurt.com Page 601


select new
{
prd.Name
, prd.ProductNumber
};

foreach (var p in allProducts)


{
Console.WriteLine(p.ToString());
}

Bu rnek kod parasnda PA hecesini ieren ve Class alannn


deeri null olan Product tiplerindeki Name ve ProductNumber zellikleri kullanlarak yeni bir tip
elde edilmektedir. Burada ihtiyalar dahilinde isimsiz tipin(Anonymous Type) hangi
zellikleri(Properties) ierecei belirlenebilir. Bu rnek kod parasnn alma zamannda retecei
kt aadaki ekran grntsndekine benzer olacaktr.

SQL sunucusu tarafna gnderilen sorgu cmlesinin ierii ise aadaki gibidir.

exec sp_executesql N'SELECT [t0].[Name], [t0].[ProductNumber]


FROM [Production].[Product] AS [t0]
WHERE
([t0].[Class] IS NULL) AND ([t0].[ProductNumber] LIKE @p0)'
,N'@p0 nvarchar(4)',@p0=N'%PA%'

Grld gibi sadece istenen alanlarn ekilmesi salanmaktadr. Buda isimsiz tiplerin LINQ to
SQL tarafnda olduka nemli bir rol oynadn gstermektedir.

LINQ to SQL tarafnda kullanlan ilgin fonksiyonelliklerden ikiside Skip ve Take metodlardr.
Skip metodu parametre olarak verilen deer kadar atlanlmasn, Take metodu ise atlanlan
satrdan itibaren ka satr alnacan belirtmektedir. Buda basit olarak bir sayfalamann(Paging)
yaplabilmesine olanak salamaktadr. ok doal olarak metodlar yardmyla programatik ortamda
kolayca uygulanabilen bu tekniin SQL tarafna aktarlmasnda SQL 2005 ile birlikte
gelen Row_Number fonksiyonunun nemli bir rol vardr. Bu metodlar daha iyi analiz etmek iin
aadaki kod parasn ele aldmz dnelim.

var tenCtg = (from cat in adw.ProductSubcategories select cat)


.Skip<ProductSubcategory>(5)
.Take<ProductSubcategory>(10);

foreach (ProductSubcategory c in tenCtg)


{
Console.WriteLine("{0} -> {1} ", c.ProductSubcategoryID.ToString(), c.Name);
}

www.bsenyurt.com Page 602


Yukardaki kod parasnda yer alan LINQ to SQL ifadesine
gre, ProductSubCategories koleksiyonu zerinden ilk satr atlanarak 6nc satrdan itibaren 10
satrlk birProductSubCategory nesne topluluunun ekilmesi amalanmaktadr. Sz konusu kod
parasnn altrlmasnn sonucu oluan program ktsna ait ekran grnts aadaki gibidir.

rnek kod parasnda kullanlan LINQ to SQL ifadesi iin SQL sunucusu zerine gnderilen sorgu
cmlesi ise aadaki gibi olacaktr.

exec sp_executesql N'SELECT [t1].[ProductSubcategoryID], [t1].[ProductCategoryID],


[t1].[Name], [t1].[rowguid], [t1].[ModifiedDate]
FROM (
SELECT ROW_NUMBER() OVER
(ORDER BY
[t0].[ProductSubcategoryID], [t0].[ProductCategoryID],
[t0].[Name], [t0].[rowguid]
, [t0].[ModifiedDate])
AS [ROW_NUMBER], [t0].[ProductSubcategoryID], [t0].[ProductCategoryID], [t0].[Name],
[t0].[rowguid], [t0].[ModifiedDate]
FROM [Production].[ProductSubcategory] AS [t0]
) AS [t1]
WHERE [t1].[ROW_NUMBER] BETWEEN @p0 + 1 AND @p0 + @p1
ORDER BY [t1].[ROW_NUMBER]',N'@p0 int,@p1 int',@p0=5,@p1=10

Dikkat edilecei zere Row_Number fonksiyonu burada nemli bir rol stlenmektedir. imdi son
kod parasnda aadaki gibi bir ekleme daha yaptmz dnelim.

var tenCtg = (from cat in adw.ProductSubcategories select cat)


.Skip<ProductSubcategory>(5)
.Take<ProductSubcategory>(10);

foreach (ProductSubcategory c in tenCtg)


{
Console.WriteLine("{0} -> {1}({2})
",c.ProductSubcategoryID.ToString(),c.Name,c.Products.Count().ToString());
}

Yaplan deiiklie gre, 5nci satrdan itibaren alnan 10 ProductSubCategory nesnesinin her biri
iin Products zelliinden yola klarak Count deerleride hesaplanmaktadr. Bir baka deyile
her bir alt kategorideki rnlerin toplam saylarda elde edilmektedir. Bu kod parasnn alma
zaman(run time) grnts ise aadaki gibidir.

www.bsenyurt.com Page 603


ProductSubCategory ve Product snflar arasnda bire ok(one to many) bir iliki mevcuttur.
Bu iliki programatik taraftada ilgili varlk snflarna(Entity Class) yanstlmaktadr. Bu nedenle
bir ProductSubCategory nesne rnei zerinden Products zellii ile bal olunan Product nesne
topluluuna gei yapmak son derece kolaydr. Bu da gnl rahatl ile Count gibi metodlar
kullanp istediimiz tarzda sonular alabilmemizi olanakl klmaktadr. Ne
varki Count ars for dngs ierisinde, bir nceki sorgudan elde edilen her bir
ProductSubCategory nesne rnei iin ayr ayr yaplmaktadr. Bunun SQL sunucusu zerinde
oluturaca sonu ise udur; elde edilen her bir ProductSubCategory iin, buna bal toplam rn
saysn dndren bir sorgu cmlesi almaktadr. Aadaki ekran grntsnde bu durumun bir
ksm ifade edilmektedir.

www.bsenyurt.com Page 604


Sorgu ifadelerine dikkat edilecek olursa Count metodu arldnda aslnda SQL tarafnda
bir Count hesab yaplmamaktadr. Products zelliine geildiinden, o
ankiProductSubCategoryID deerine bal Product satrlar, programatik taraftaki nesne
topluluuna yklenmektedir. Bu nesneler yklendikten sonra bildiimiz koleksiyonlara ait
olanCount metodu almakta ve toplam rn saylar bu ekilde elde edilmektedir. Hi bir
durumda bu tarz bir yol ile toplam saylarn elde edilmesi tercih edilmemelidir. Grld gibi gayet
masumane olan ama ok ie yarad dnlen basit bir kod paras arka tarafta son derece fazla
sayda ve youn sorgu cmlelerinin almasna neden olmutur.

SQL tarafnda birden fazla tablo zerinde bir arada ilem yaplmas gerektii durumlarda
ounlukla join yaplarndan yararlanlmaktadr. Ayn yap bildiiniz gibi LINQ ile nesneler
zerindede gerekletirilebilmektedir. Sradaki rnekte LINQ to SQL iin join kullanmna
baklmaktadr. Bu amala aadaki gibi bir kod paras gelitirdiimizi dnelim.

www.bsenyurt.com Page 605


var allList = from pc in adw.ProductCategories
join psc in adw.ProductSubcategories
on pc.ProductCategoryID equals psc.ProductCategoryID
join p in adw.Products
on psc.ProductSubcategoryID equals p.ProductSubcategoryID
where p.Class == null && p.ListPrice > 100
select new
{
CategoryName = pc.Name
, SubCategoryName = psc.Name
, ProductNumber = p.ProductNumber
, ProductName = p.Name
};

foreach (var prd in allList)


{
Console.WriteLine(prd.ToString());
}

Buradaki kod parasna


gre ProductCategories, ProductSubCategories ve Products zelliklerine bal
generic Table<T> koleksiyonlar join anahtar kelimesi yardmyla anahtar zellikler zerinden
birletirilmekte ve yeni bir isimsiz tipe(Anonymous Type) ait nesne topluluu elde edilmektedir.
Bu nesne topluluu elde edilirken Class deeri null olan ve rnlerinListPrice deeri 100' den
byk olanlarn elde edilmesi salanmaktadr. Buna gre uygulamann ekran kts aadaki gibi
olacaktr.

Sz konusu LINQ to SQL ifadesinin SQL tarafndaki karl ise aadaki gibidir.

exec sp_executesql N'SELECT [t0].[Name] AS [CategoryName], [t1].[Name] AS


[SubCategoryName], [t2].[ProductNumber], [t2].[Name] AS [ProductName]
FROM [Production].[ProductCategory] AS [t0]
INNER JOIN [Production].[ProductSubcategory] AS [t1] ON [t0].[ProductCategoryID] =
[t1].[ProductCategoryID]
INNER JOIN [Production].[Product] AS [t2] ON ([t1].[ProductSubcategoryID]) =
[t2].[ProductSubcategoryID]
WHERE ([t2].[Class] IS NULL) AND ([t2].[ListPrice] > @p0)',N'@p0
decimal(33,4)',@p0=100.0000

www.bsenyurt.com Page 606


Grld gibi join kelimeleri SQL tarafnda standart inner join muamelesi grmektedir.

Sradaki LINQ to SQL ifadesinde DateTime yapsnn(struct) paralarndan yararlanlmakta


olup, bu ayrtrmann SQL tarafna nasl yanstld incelenmeye allmaktadr. Bu amala
uygulamaya aadaki kod parasn eklediimizi dnelim.

var result = from p in adw.Products


where p.SellStartDate.Month >= 6 && p.SellStartDate.Month <= 12
select new
{
p.ProductNumber
, p.Name
, p.ListPrice
, p.SellStartDate
, p.SellEndDate
};

foreach (var p in result)


{
Console.WriteLine(p.ProductNumber + " " + p.SellStartDate.Month.ToString() + " ");
}

Yukardaki kod parasnda yer alan LINQ ifadesinde, her bir Product nesne
rneinin SellStartDate zellikleri zerinden hareket edilerek Month deerlerine baklmakta ve
6nc ila 12nci ay arasnda olanlar deerlendirilerek yeni bir isimsiz tip(Anonymous Type) ierisinde
toplanmaktadr. rnee ait alma zaman ekran kts aadaki gibidir.

Burada merak edilen konu, Month deerlerinin SQL tarafnda nasl ele alnacadr. Bu amala
rnek altrldktan sonra SQL Server Profiler aracna baklrsa,DatePart SQL fonksiyonunun
kullanld ak bir ekilde grlebilir.

exec sp_executesql N'SELECT [t0].[ProductNumber], [t0].[Name], [t0].[ListPrice],


[t0].[SellStartDate], [t0].[SellEndDate]

www.bsenyurt.com Page 607


FROM [Production].[Product] AS [t0]
WHERE
(DATEPART(Month, [t0].[SellStartDate]) >= @p0)
AND (DATEPART(Month, [t0].[SellStartDate]) <= @p1)'
,N'@p0 int,@p1 int',@p0=6,@p1=12

Bylece SellStartDate alanlarnn ierii DatePart fonksiyonu kullanlaraktan ayrtrlmakta ve


elde edilen Month ksmna grede deer aral kontrol yaplmaktadr.

Baz durumlarda sorgulanan verinin string bazl olmas halinde karakter tabanl kontroller yaplmak
istenebilir. Sz gelimi B harfi ile balayan rnlerin elde edilmesi gibi. Bu gibi
durumlarda string bazl verilerin karakter katar olduu programatik tarafta ele alnmas gereken
bir durumdur. Aadaki kod parasnda hem bu durum ele alnmakta hemde Firstmetodunun
kullanm incelenmektedir.

Product result = (from p in adw.Products select p)


.First<Product>(prd => prd.Name[0] == 'C');

Console.WriteLine(result.Name + " " + result.ListPrice);

Buradaki ifadeye gre, her bir Product nesne rneinin Name zelliklerinin ilk harflerine
baklmaktadr. lk harfi C olan rnlerden ise sadece ilki First metodu yardmyla elde edilmektedir.
Bu ilevsellii gerekletirmek iin First metodu ierisinde lambda(=>) operatr
kullanlmaktadr. Lambda operatr sayesinde eitliin sol tarafndan sa tarafna o anki Product
nesne rnei geirilmektedir. Eitliin sa tarafnda ise o anki Product nesne
rneinin Name zelliinin ilk harfine baklmaktadr. Eer ilk harf C ise o anda zerinde
durulan Product nesne rnei eitliin sandan soluna doru geri dndrlmektedir. rnein
alma zamanndaki ekran kts aadaki gibi olacaktr.

Sz konusu LINQ to SQL ifadesinin SQL tarafna aktarlan sorgu cmlesi ise aadaki gibidir.

exec sp_executesql N'SELECT TOP (1)


[t0].[ProductID], [t0].[Name], [t0].[ProductNumber]
, [t0].[MakeFlag], [t0].[FinishedGoodsFlag], [t0].[Color]
, [t0].[SafetyStockLevel], [t0].[ReorderPoint], [t0].[StandardCost]
, [t0].[ListPrice], [t0].[Size], [t0].[SizeUnitMeasureCode]
, [t0].[WeightUnitMeasureCode], [t0].[Weight], [t0].[DaysToManufacture]
, [t0].[ProductLine], [t0].[Class], [t0].[Style], [t0].[ProductSubcategoryID]
, [t0].[ProductModelID], [t0].[SellStartDate], [t0].[SellEndDate]
, [t0].[DiscontinuedDate], [t0].[rowguid], [t0].[ModifiedDate]
FROM [Production].[Product] AS [t0]
WHERE
UNICODE(CONVERT(NChar(1),SUBSTRING([t0].[Name], @p0 + 1, 1))) = @p1',N'@p0
int,@p1 int',@p0=0,@p1=67

Hereyden nce First metodunun tam karl olarak TOP (1) sz dizimi kullanlmaktadr. Dier
taraftan programatik ortamda [] indeksleyici operatrn kullanarak string veri tipinin ilk
karakterine gememiz ve C harfini kontrol etmemizin karl Unicode, Convert, SubString
SQL fonksiyonlar olmutur. Burada 67 deerinin C harfine karlk geldiini hatrlayalm. Elbette

www.bsenyurt.com Page 608


ekilen veri bir Product tipi olduundan, Product tablsoundaki tm alanlarn Select ifadesine
alnd grlmektedir. Daha ncedende belirtildii gibi, sadece gerekli alanlarn ekilmesi adna kod
tarafnda isimsiz metod(Anonymous Method) kullanmna gidilebilir.

LINQ tarafnda oklu seimlerde(Select Many) yaplabilmektedir. Bu tarz bir kullanma rnek
olarak aadaki kod paras ele alnabilir.

var result = from p in adw.SalesPersons


where p.Bonus >= 1000
from h in p.SalesOrderHeaders
where h.TerritoryID == 1
select new
{
p.SalesPersonID
, p.Bonus
, h.SubTotal
, h.AccountNumber
};

foreach (var r in result)


{
Console.WriteLine(r.ToString());
}

Buradaki sorgu ifadesine gre, SalesPersons koleksiyonunda tutulan SalesPerson nesne


rneklerinden Bonus zelliklerinin deeri 1000' in zerinde olanlar alnmaktadr. Sonrasnda ise
elde edilen kmedeki her bir SalesOrder zerinden SalesOrderHeaders koleksiyonuna
gidilmekte ve blge deeri 1 olanlar ekilmektedir. Bir baka deyile Bonus' u 1000' in zerinde ve
sipari kalemleri 1 numaral blgeye doru yaplm olan sat personelinin elde edilmesi sz
konusudur. Elde edilen veri kmesi deerlendirilerek yeni bir isimsiz tip(Anonymous
Type) ierisinde birletirilmeleri salanmaktadr. rnek kodun alma zamanndaki kts
aadaki gibi olacaktr.

u aamada bizim ilgilendiimiz ksm SQL tarafna gnderilen sorgu cmlesidir. Bu cmlede
aadaki ekildedir.

exec sp_executesql N'SELECT [t0].[SalesPersonID], [t0].[Bonus], [t1].[SubTotal],


[t1].[AccountNumber]
FROM [Sales].[SalesPerson] AS [t0], [Sales].[SalesOrderHeader] AS [t1]
WHERE ([t1].[TerritoryID] = @p0) AND ([t0].[Bonus] >= @p1)

www.bsenyurt.com Page 609


AND ([t1].[SalesPersonID] = [t0].[SalesPersonID])'
,N'@p0 int,@p1 decimal(33,4)',@p0=1,@p1=1000.0000

Burada From kelimesinden sonraki ksma


bakldnda SalesPerson ve SalesOrderHeader tablolarnn birlikte ele alndklar grlmektedir.

Gelelim gruplama fonksiyonelliklerinin SQL tarafna nasl yanstldnda. Bu amala aadaki


rnek kod parasn gz nne alyor olacaz.

var result = from p in adw.Products


where p.Class != null
group p by p.Class into g
select new
{
ClassName = g.Key
,TotalListPrice = g.Sum<Product>(p => p.ListPrice)
};

foreach (var r in result)


{
Console.WriteLine("{0} : {1}", r.ClassName, r.TotalListPrice);
}

rnekteki ifadede, Products koleksiyonundaki her bir Product nesnesinin Class zelliklerine gre
gruplara ayrlmas ve her bir gruba ait ListPrice zelliklerinin toplam deerlerinin bulunmas
salanmaktadr. Bir baka deyile snflar olan rnlerin snflara gre gruplandklarnda, toplam
liste fiyat deerlerinin ne olduu elde edilmektedir. Bu kod parasnn icra edilmesi halinde,
alma zamannda aadakine benzer sonu ortaya kmaktadr.

Grld gibi rnler snflara gre gruplanm ve toplam rn fiyatlarnn deerleri elde
edilmitir. Burada alan LINQ to SQL ifadesinin SQL tarafna gnderilen karl ise aadaki
gibi olacaktr.

SELECT SUM([t0].[ListPrice]) AS [TotalListPrice], [t0].[Class] AS [ClassName]


FROM [Production].[Product] AS [t0]
WHERE [t0].[Class] IS NOT NULL
GROUP BY [t0].[Class]

Aslnda retilen SQL cmlesi tam olarak dndmz ekildedir. Bununla birlikte dikkat edilmesi
gereken bir husus vardr. Buda LINQ sorgusundaki where kelimesinin kullanld yerdir.
rnekte, where ifadesi ile seilen kme zerinde gruplama yaplmaktadr. Bu nedenle group
by kelimesinden nce where kullanlmaktadr. Ancak ayn ifade aadaki haliylede gelitirilebilir.

var result = from p in adw.Products


group p by p.Class into g
where g.Key!=null
select new

www.bsenyurt.com Page 610


{
ClassName = g.Key
,TotalListPrice = g.Sum<Product>(p => p.ListPrice)
};

foreach (var r in result)


{
Console.WriteLine("{0} : {1}", r.ClassName, r.TotalListPrice);
}

Bu sefer gruplanan nesneye ait Key zelliinin null olup olmadna baklmaktadr. Kod bu haliyle
altrldnda da bir nceki ile ayn sonularn elde edildii grlebilir. Ne varki SQL tarafna
gnderilen ifadeye bakldnda aadaki sonular ortaya kmaktadr.

SELECT [t1].[Class] AS [ClassName], [t1].[value] AS [TotalListPrice]


FROM (
SELECT SUM([t0].[ListPrice]) AS [value], [t0].[Class]
FROM [Production].[Product] AS [t0]
GROUP BY [t0].[Class]
) AS [t1]
WHERE [t1].[Class] IS NOT NULL

Sonu bir ncekinden olduka farkldr. Bu kez devreye ek bir alt sorgu cmlesi daha girmektedir.
nce snflara gre gruplanm rnlerin ListPrice deelerinin toplamlar ve snf adlarnn olduu
kme elde edilmektedir. Sonrasnda ise bu kme zerinden Class deerleri null olmayanlar
ekilmektedir. Bu noktada where kelimesinin kod tarafndan yerinin deitirilmesinin nemli olup
olmadna karar vermek gerekebilir. Ancak gelitirilen rnee ait oluturulan sorgularn icra
planlarna(Execution Plan) bakldnda bir fark olmad aka grlmektedir.

www.bsenyurt.com Page 611


LINQ tarafnda yer alan enteresan metodlardan biriside Except metodudur. Bu metoddan
yararlanlarak belirli bir artn dnda kalan nesnel kmelerin elde edilmesi salanabilir. rnek
olarak aadaki gibi bir kod paras gelitirdiimizi dnelim.

var result = (from c in north.Customers select c.City)


.Except(from s in north.Suppliers select s.City);

foreach (var r in result)


{
Console.WriteLine(r);
}

Bu rnekte NorthwindDataContext kullanlmaktadr. Buna gre LINQ ifadesinde ilk parantez


ierisinde kalan ksmda Customers koleksiyonunda duran Customer nesne
rneklerindenCity zellikleri ekilmektedir. Except metodunda yazlan
ifadede Suppliers tablosunda yer alan Supplier nesne rneklerinden City zelliklerini
ekmektedir. Her iki kme bir arada dnldnde ortaya kan sonu udur; Customer nesne
rneklerinde olup, Supplier nesne rneklerinde bulunmayan City zellikleri elde edilmektedir. Daha

www.bsenyurt.com Page 612


dzgn bir ifadeyle, bir baka deyile SQL' ce dndnde, mterilerin yaaypta
tedarikilerinin bulunmad ehir adlarnn elde edildiini syleyebiliriz. Programn alma
zamanndaki kts aadaki gibidir.

Bu tarz bir ihtiyac SQL tarafnda karlamak iin Not In kullanm tercih edilebilir. LINQ tarafnda
metod bazl yazlan bu rnek ise, SQL tarafna aadaki ekilde aktarlmaktadr.

SELECT DISTINCT [t0].[City]


FROM [dbo].[Customers] AS [t0]
WHERE
NOT (EXISTS
(
SELECT NULL AS [EMPTY]
FROM [dbo].[Suppliers] AS [t1]
WHERE (([t0].[City] IS NULL)
AND ([t1].[City] IS NULL))
OR (([t0].[City] IS NOT NULL)
AND ([t1].[City] IS NOT NULL)
AND ([t0].[City] = [t1].[City]))
)
)

Burada nemli olan Exists SQL fonksiyonu ile gereken ilevselliin salanm
olmasdr. Not konulmasnn sebebi, Exists ile belirtilen alt sorgudaki koula uyanlarn darda
braklmasn salamaktr. Nitekim t0 ve t1 tablolarndaki City deerlerine baklarak eit olanlarn
elde edilmesi salanrken Except metodu kullanlmas nedeniyle bunlarn darda tutulmasn
ancak Not anahtar kelimesi salayabilmektedir. Ayrca
hem Suppliers hemde Customers tablosundaki City alanlar iin detayl bir Null kontrol
yaplmaktadr.

Makalemize yine enteresan LINQ fonksiyonlar ile devam edelim. Bu kez Any ve All isimli
metodlar incelemeye alyor olacaz. Bu amala ilk olarak Any metodunun kullanmna ksaca
baklm.

var result = from p in adw.SalesPersons


where p.SalesOrderHeaders.Any(soh => soh.SubTotal >= 224356)

www.bsenyurt.com Page 613


select p;

foreach (SalesPerson person in result)


{
Console.WriteLine("Person Id: " + person.SalesPersonID + " Bonus: " + person.Bonus + " Sales
Last Year : " + person.SalesLastYear);
foreach (SalesOrderHeader header in person.SalesOrderHeaders)
Console.WriteLine("\t" + header.AccountNumber + " Sub Total: " + header.SubTotal);
}

LINQ to SQL ifadesinde SalesPersons koleksiyonundaki her bir SalesPerson ekilmektedir.


Bunlara bal olan SalesOrderHeaders koleksiyonundaki SalesOrderHeader nesne rneklerinin
iseSubTotal deerlerine baklarak seim ilemi koullandrlmaktadr. Any metodunun buradaki
grevi ise udur; SubTotal deerlerinden herhangibiri 224356' nn zerinde olan satrlar elde
edilebilmektedir. Yani, sat personelinin siparilerine ait SubTotal deerlerinden
herhangibiri 224356' nn zerinde olanlarn elde edilmesi salanmaktadr. rnek kod parasnn
alma zamanndaki kts aadaki gibi olacaktr.

Bu tarz bir ileyi iin SQL taraf gz nne alndnda ortaya karmak bir sorgu kaca
dnlebilir. Nitekim LINQ to SQL ifadesinin SQL tarafndaki karl aadaki gibidir.

exec sp_executesql N'


SELECT
[t0].[SalesPersonID], [t0].[TerritoryID], [t0].[SalesQuota]
, [t0].[Bonus], [t0].[CommissionPct], [t0].[SalesYTD]
, [t0].[SalesLastYear], [t0].[rowguid], [t0].[ModifiedDate]
FROM [Sales].[SalesPerson] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [Sales].[SalesOrderHeader] AS [t1]
WHERE ([t1].[SubTotal] >= @p0) AND ([t1].[SalesPersonID] =
[t0].[SalesPersonID])
)'

www.bsenyurt.com Page 614


,N'@p0 decimal(33,4)',@p0=224356.0000

Dikkat edilecei zere Exists anahtar kelimesi kullanlarak SubTotal deeri ele alnmakta ve buna
uyanlarn SalesPerson tablosundan ekilmesi salanmaktadr. Gelelim All metoduna. Bu
sefer Any' den farkl olarak bal olunan kmedeki her bir eleman iin belirtilen koulun salanm
olma art aranmaktadr. Bunu daha net kavrayabilmek iin rneimizi aadaki gibi deitirelim.

var result = from p in adw.SalesPersons


where p.SalesOrderHeaders.All(soh => soh.SubTotal >= 80)
select p;

foreach (SalesPerson person in result)


{
Console.WriteLine("Person Id: " + person.SalesPersonID + " Bonus: " + person.Bonus + " Sales
Last Year : " + person.SalesLastYear);
foreach (SalesOrderHeader header in person.SalesOrderHeaders)
Console.WriteLine("\t" + header.AccountNumber + " Sub Total: " + header.SubTotal);
}

Bu kodun alma zaman kts ise aadaki gibi olacaktr.

Bu sefer bir SalesOrder' n bal olduu SalesOrderHeaders koleksiyonundaki her


bir SalesOrderHeader nesne rneinin SubTotal deerlerinin her biri 80' in zerinde olanlarn
elde edilmesi salanmaktadr. Bir baka deyile bir SalesOrder zerinden ulalan nesne
topluluunda n tane SalesOrderHeader olduu dnlecek olursa, bunlarn her birine
aitSubTotal zelliklerinin deerlerinin 80 ve zerinde olma art konulmaktadr. Sz
konusu All metodu iin SQL tarafnda retilen kt ise aadaki gibidir.

exec sp_executesql N'


SELECT
[t0].[SalesPersonID], [t0].[TerritoryID], [t0].[SalesQuota]
, [t0].[Bonus], [t0].[CommissionPct], [t0].[SalesYTD]

www.bsenyurt.com Page 615


, [t0].[SalesLastYear], [t0].[rowguid], [t0].[ModifiedDate]
FROM [Sales].[SalesPerson] AS [t0]
WHERE NOT (
EXISTS(
SELECT NULL AS [EMPTY]
FROM [Sales].[SalesOrderHeader] AS [t1]
WHERE ((
(CASE
WHEN [t1].[SubTotal] >= @p0 THEN 1 ELSE 0
END)) = 0)
AND ([t1].[SalesPersonID] = [t0].[SalesPersonID])
))'
,N'@p0 decimal(33,4)',@p0=80.0000

Bu kez koulun kontrol iin Case ifadesinden yararlanlmakta ve SubTotal 80' zerinde ise 1,
deilse 0 deeri Where ifadesine katlarak 0 olanlarn ekilmesi salanmaktadr. Yanlz burada yine
Not Exist kullanldnda dikkat etmekte yarar vardr. Buna grede
bir Where ifadesinin SalesPerson tablosu iin retilmesi salanmaktadr.

rneklerimize Concat metodu ile devam edelim. Concat metodunu daha ok iki farkl sonu
kmesindeki belirli zelliklerin bir arada ele alnmasn istediimiz durumlarda gz nne alabiliriz.
Bu bir anlamda iki string' in birletirilemesine benzer bir durumdur. Tabi u anda sz konusu olan
string deil IEnumerable gibi referanslardr. Concat metodunun SQL tarafnda rettii ktya
bakmak iin aadaki rnek kod parasn gelitirdiimizi dnelim.

var result = (from cust in north.Customers select new { cust.Country, cust.City })


.Concat(from supl in north.Suppliers select new { supl.Country, supl.City });
foreach (var r in result)
{
Console.WriteLine(r.Country + ":" + r.City);
}

Bu rnekte NorthwindDataContext tipi kullanlmakta


olup Customers ve Suppliers koleksiyonlarndaki nesnelerde Country ve City deerleri
birletirilip ekilmektedir. Sonuta kodun alma zaman kts aadaki gibi olacaktr.

www.bsenyurt.com Page 616


Elbetteki SQL tarafna bakldnda Concat metodunun aadakine benzer bir dnme urad
grlmektedir.

SELECT [t2].[Country], [t2].[City]


FROM (
SELECT [t0].[Country], [t0].[City]
FROM [dbo].[Customers] AS [t0]
UNION ALL
SELECT [t1].[Country], [t1].[City]
FROM [dbo].[Suppliers] AS [t1]
) AS [t2]

Aka Union All kullanlaraktan iki Select ifadesinin birletirildii ve elde edilen kme
zerinden Country ile City alanlarna ait deerlerin ekildii sylenebilir. rnekte dikkati eken
noktalardan biriside tekrarl alanlarn olmasdr. rnein ekran ktsnn st taraflarna bakldnda
iki adet Mexico kentinin olduu London' un iki kere getii rahat bir ekilde grlebilir. ok doal
olarak tekrarsz bir listenin elde edilmesi istendiinde kod tarafnda Distinct metodunun
kullanlyor olmas yeterli olacaktr. Yani kod parasnda aadaki deiikliin yaplmas yeterlidir.

var result = (from cust in north.Customers select new { cust.Country, cust.City }).Concat(from
supl in north.Suppliers select new { supl.Country, supl.City }).Distinct();

Bu durumda programn kts aadaki gibi olacaktr.

www.bsenyurt.com Page 617


Dier taraftan Distinct metodunun kullanlmas sonrasnda SQL tarafna gnderilen sorgu
cmlesinde ise Distinct anahtar kelimesinin kullanldda aikardr.

SELECT DISTINCT [t3].[Country], [t3].[City]


FROM (
SELECT [t2].[Country], [t2].[City]
FROM (
SELECT [t0].[Country], [t0].[City]
FROM [dbo].[Customers] AS [t0]
UNION ALL
SELECT [t1].[Country], [t1].[City]
FROM [dbo].[Suppliers] AS [t1]
) AS [t2]
) AS [t3]

Ancak burada bir ncekinden farkl bir sorgunun olutuuda gzlerden kamamaldr. Bu kez i ie
alnm Select sorgusu sz konusudur. Oysaki en dta yer alan Selectkullanmna gerek yoktur.
nk Distinct anahtar kelimesi ierideki sorgu cmlesine eklenerekte ayn sonularn alnmas
salanabilir. Ne varki sorgu cmlesini bu ekilde oluturup SQL tarafna gnderen LINQ to
SQL mimarisidir.

Yine ilgin bir LINQ metodu ve SQL karl ile devam edelim. Bu kez iki farkl veri kmesinin
kesiimlerinin elde edilmesinde kullanlabilen Intersect metodu zerinde duracaz. Bu metodun
analizi iin aadaki gibi bir kod paras gelitirdiimizi dnelim.

var result = (from c in north.Customers select c.City)


.Intersect(from s in north.Suppliers select s.City);

foreach (var r in result)


{
Console.WriteLine(r);
}

ncelikli olarak ilk parantezler arasnda Customers koleksiyonundaki her


bir Customer nesnesinin City deerleri ekilmektedir. kinci parantez ierisinde yaplanda
benzerdir. Tek farkSuppliers koleksiyonu iin almakta olmasdr. Intersect metodunun burada
getridii kolaylk ise udur. Customers ve Suppliers koleksiyonlarnda bulundan
ortak Cityzelliklerinin elde edilmesini salamaktadr. Bir baka deyile yine SQL' ciler gibi
konuacak olursak, mterilerin ve tedarikilerin bir arada bulunduu ehirlerin elde edilmesi
salanmaktadr . Buna gre rnein alma zamanndaki ekran kts aadaki gibi olacaktr.

www.bsenyurt.com Page 618


Bu sonucun elde edilmesi iin arka planda altrlan SQL cmlesi ise aadaki gibidir.

SELECT DISTINCT [t0].[City]


FROM [dbo].[Customers] AS [t0]
WHERE EXISTS(
SELECT NULL AS [EMPTY]
FROM [dbo].[Suppliers] AS [t1]
WHERE
(([t0].[City] IS NULL)
AND ([t1].[City] IS NULL))
OR (([t0].[City] IS NOT NULL)
AND ([t1].[City] IS NOT NULL)
AND ([t0].[City] = [t1].[City]))
)

altrlan SQL sorgusu, LINQ tarafnda Except metodu kullanld zamankine benzerdir. Tek fark
burada kesiim kmesinin bulunmas gerektiinden Not Exists kullanlmam olmasdr.

Makalemizde son olarak ?: operatrnn kullanld bir durumu ele almaya alyor olacaz. Bu
operatr u aamada LINQ' e baml olmayan C# programlama dilinin ilk versiyonundan beri var
olan bir aratr. Bu tip bir operatrn LINQ ifadesi ierisinde kullanlmas haline SQL tarafnda
oluacak olan cmlelere bakmaya alyor olacaz. Bu amala aadaki kod parasn
gelitirdiimizi dnelim.

var result = from prd in adw.Products


select new
{
prd.Name
,prd.SafetyStockLevel
,LevelOk = prd.SafetyStockLevel >= 50 ? "Seviye yi" : "Seviye
Dk"
};

foreach (var p in result)


{
Console.WriteLine(p.Name + " | " + p.SafetyStockLevel + " | " + p.LevelOk);
}

Bu kod parasnda kullanlan LINQ ifadesine bakldnda, LevelOk isimli isimsiz tip zelliinin
deerinin SafetyStockLevel zelliinin deerine gre belirlendii
grlmektedir.SafetyStockLevel zelliinin deerinin 50 ve zerinde olmas halinde LevelOk
zelliine Seviye yi deeri atanmaktadr. Aksi durumda ise Seviye Dk deeri atanmaktadr.
Kodun alma zamanndaki kts aadaki gibi olacaktr.

www.bsenyurt.com Page 619


SQL tarafna baktmzda ise aadaki sorgu cmlesinin altrld grlmektedir.

exec sp_executesql N'SELECT [t0].[Name], [t0].[SafetyStockLevel],


(CASE
WHEN [t0].[SafetyStockLevel] >= @p0 THEN CONVERT(NVarChar(12),@p1) ELSE
@p2 END
)
AS [LevelOk]
FROM [Production].[Product] AS [t0]'
,N'@p0 int,@p1 nvarchar(10),@p2 nvarchar(12)',@p0=50,@p1=N'Seviye yi',@p2=N'Seviye
Dk'

Dikkat edilecei zere, LevelOk alannn elde edilmesi srasnda Case When SQL ifadesi
kullanlmaktadr.

Buraya kadar anlatlan rneklerde LINQ operatrlerinden veya metodlarndan bir ksmnn SQL
tarafna nasl aktarldklar incelenmeye allmtr. Dier taraftan makalemizin bandada
belirtildii zere programatik tarafta kullanlan her tr LINQ operatr veya fonksiyonunun SQL
tarafna aktarlmasda mmkn deildir. Sz gelimi aadaki kod parasn ele aldmz
dnelim.

var result = (from ctg in adw.ProductSubcategories select ctg)


.TakeWhile<ProductSubcategory>(sCtg => sCtg.Name[0] == 'A');

foreach (ProductSubcategory sc in result)


{
Console.WriteLine(sc.Name + " " + sc.ProductSubcategoryID.ToString());
}

Bu kod paras yrtlmek istendiinde alma zamannda(run time), aadaki ekran


grntsndende izlenebilecei gibi NotSupportedException tipinden
biristisna(Exception) alnmaktadr.

www.bsenyurt.com Page 620


Nitekim TakeWhile metodunun SQL tarafnda bir karl
yoktur. TakeWhile gibi SkipWhile, Last, ElementAt, Reverse gibi pek ok metodunda SQL
tarafnda karl bulunmadndan desteklenmemektedirler.

Sonu olarak programatik tarafta varlk katman(Entity Layer) zerinde ilemlerimizi olduka
kolaylatran ve nesneler zerinde sorgular altrabilmemizi salayan LINQ to SQL' in gc
ortadadr. Ne varki performansn ne gemesi gereken durumlarda, yazlan LINQ ifadelerinin arka
planda oluturduu SQL ktlar deerlendirilmeli ve en doru ekilde kullanlmalarna gayret
edilmelidir. Zaten zaman ierisinde benzer vakalar iin en uygun LINQ sz dizimlerinin ne olaca
daha net bir ekilde ortaya kacaktr. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

LINQ to SQL ile CRUD lemleri ( 15.12.2007 ) -


LINQ
Deerli Okurlarm Merhabalar,

Language Integrated Query(LINQ) mimarisi zellikle programatik ortamlarda tasarlanan


nesneler zerinde, SQL cmlelerine benzer ifadeler ile sorgulamalar yaplmasna izin vermektedir.
ok doal olarak veritaban(database) tarafnda yer alan tablo(Table), sakl yordam(Stored
Procedure), grnm(View), fonksiyon(Function) gibi unsurlarnda programatik tarafta
birer varlk(Entity) olarak ifade edilebilmesi, LINQ kurallarnn SQL zerindede
gerekletirilebilmesini salamaktadr. Burada varlk katman(Entity Layer) olarakda
dnebileceimiz yap zerinde yer alan nesneler, veritabanndan ekilen sonular
saklayabilmektedir. Bunun yannda programatik ortamdaki varlklar zerinde yeni varlk oluturma,
gncelleme, silme gibi operasyonlarda yaplabilmektedir. te bu makalemizde
ounlukla CreateRetrieveUpdateDelete (CRUD) ilemleri olarak belirtilen bu operasyonlar
nasl yapabileceimizi, adm adm basit rnekler zerinden incelemeye alyor olacaz. (Bu
makalede gelitirilmekte olan rnek kod paralar Visual Studio 2008 RTMortamnda yazlmtr.)

lk olarak rnek bir SQL veritabanndaki tablo(table) yaplarn programatik ortamda tayacak
olan snflarn retilmesi gerekmektedir. Bu amala Visual Studio 2008zerinde basit
bir Console uygulamas aarak ilerleyebiliriz. Burada dikkat edilmesi gereken nemli noktalardan
birisi New Project seimi sonras karmza kacak olan iletiim penceresinden .Net Framework
3.5 versiyonunun iaretlenmi olmasdr.

www.bsenyurt.com Page 621


Bu art olmamakla birlikte, LINQ iin gerekli olan assembly'
larn(rnein System.Data.DataSetExtensions gibi) otomatik olarak referans edilmesini
salamaktadr. Bu admdan sonraentity snflarnn kolay bir ekilde oluturulmasn
salayan LINQ To SQL Class esini projemize eklememiz gerekmektedir.(LINQ to SQL
snflarnn oluturulmas ile ilikili detayl bilgiyi C#Nedir? yer alan grsel dersten renebilirsiniz.)

Bylece veritaban zerindeki nesnel yaplar programatik ortamda ifade edebileceimiz Database
Markup Language(dbml) dosyas otomatik olarak oluturulmaktadr.Adventure.dbml dosyasnn
kod tarafna bakldnda DataContext tipinden tretilmi olan bir snfn yazld grlmektedir.
imdi yapmamz gereken, zerinde ilemler gerekletirilecek olan veritaban nesnelerini tasarm
ortamna srkleyip brakmaktr. lk etapta rnein basit olmas asndan
sadece Production emasnda(schema) yer alan ProductCategory isimli tablo tasarm
ortamna, Server Explorer pencersinden srklenmitir.

www.bsenyurt.com Page 622


Bu basit operasyonun ardndan aadaki snf diagramnda(Class Diagram) olduu
gibi ProductCategory iin bir tipin yazld ve bununla ilikili olaraktanda,DataContext tipinden
treyen AdventureDataContext snf ierisine ProductCategories isimli bir zelliin(Properties)
atld grlmektedir. ProductCategories zellii generic Table<ProductCategory> tipinden bir
nesne referansn iaret etmektedir. Bu generic tip tahmin edilecei zere ProductCategory
tabosundaki tm ierii tayan snftr.

Artk bu noktadan sonra AdventureDataContext snfna ait nesne rneklerini kullanarak


kategorilerin elde edilmesi, sorgulanmas, yeni kategorilerin oluturulmas(Insert), var olanlardan
bir veya bir kann silinmesi(Delete) yada gncellenmesi(Update) gibi ilemler kolaylkla yaplabilir.

www.bsenyurt.com Page 623


lk olarak yeni bir kategoriyi nasl ekleyebileceimizi rnek bir kod paras zerinden incelemeye
alalm. Bu amala Main metodu ierisine aadaki kod satrlarn eklediimizi dnelim.

AdventureDataContext adwContext = new AdventureDataContext();

ProductCategory tools = new ProductCategory()


{
Name = "Tools"
, ModifiedDate=new DateTime(2001,1,1)
};

adwContext.ProductCategories.InsertOnSubmit(tools);

lk olarak AdventureDataContext tipine ait bir nesne rnei oluturulmaktadr. Bu ilemin


arkadasndanda eklenmek istenen ProductCategory nesne rnei C# 3.0 ile birlikte gelennesne
balatclarndan(Object Initializers) yararlanlarak rneklenmektedir. Bu
noktada Table<T> generic tipinden olan ProductCategories snfnn InsertOnSubmitmetodu,
koleksiyonuna ilave edilmek zere yeni bir ProductCategory nesne rneinin eklenmesi iin
kullanlmaktadr. Burada zerinde durulmas gereken nemli bir nokta
vardr.InsertOnSubmit metodu sadece Table<T> koleksiyonuna ilave edilmek zere bir nesne
eklemektedir. Bir baka deyile ProductCategories koleksiyonu zerinde yaplacak bir for
dngsnde eklenen nesne(ler) grlmeyecektir. Bunu test etmek iin aadaki gibi bir kod
parasn ele alabiliriz.

var categories = from category in adwContext.ProductCategories


select category.Name;

foreach(string ctgr in categories)


Console.WriteLine(ctgr);

Bunun sonucu olarak alma zamannda(run time) aadaki ekran grntsn elde ederiz.

Burada sebep son derece aktr. var anahtar kelimesinden(keyword) sonra foreach dngsnn
iterasyona balamasyla birlikte SQL sunucusu zerinde bir select sorgusu alamaktadr. Bu
sorgu SQL Profiler yardmyla kolay bir ekilde yakalanabilir. Aadaki ekran grntsnde bu
durum grlmektedir.

www.bsenyurt.com Page 624


Dolaysyla eklenmek(Insert) zere ilave edilen ProductCategory nesne rnei henz
veritabanna doru gnderilmemitir. Bu ilemin nasl yapldn grmeden nce koleksiyona
eklenen ve insert ilemi iin srada bekleyen nesne rneklerini nasl elde edebileceimize bakalm.
Burada DataContext snfna ait GetChangeSet metodundan yararlanlmaktadr. Bu metod ile
elde edilen ChangedSet nesne rnei
zerinden Inserts,Deletes veya Updates zellikleri(Properties) kullanlarak eklenen, silinen
veya gncellenen rnekler yakalanabilir.

Inserts, Deletes ve Updates zellikleri geriye IList<T> tipinden bir referans


dndrmektedir. Bu referans bilgisinden yararlanlarak eklenen, silinen veya gncellenen
tm nesnelerin yakalanmas mmkndr. IList<T> arayz(Interface) .Net
2.0 versiyonundan beri mevcuttur. Ayrca IEnumerable<T> arayznden tremi
olduundan, elde edilen referans zerinde LINQ sorgularda yazlabilir. Bu sayede
eklenen, silinen veya gncellenen nesnelerin veritabanna yazlmadan nce
sorgulanmalarda mmkn olmaktadr.

rnek uygulamada bu kod paras denenirse eklenen tool isimli yeni kategorininde elde edildii
grlecektir.

www.bsenyurt.com Page 625


ok doal olarak ProductCategoryID gibi alanlar veritaban zerindeki tabloda otomatik olarak
retildiklerinden ve kod ierisinde herhangibir deer atanmadndan henz oluturulmamtr.
Yaplan bu ekleme(Insert) ileminin veritabanna gnderilmesi iin tek yaplmas gereken
ise DataContext tipinin SubmitChanges metodunu altrmaktr.

adwContext.SubmitChanges();

SubmitChanges metodu altrldnda Insert, Update veya Delete kuyruunda bekleyen tm


nesneler iin gerekli SQL sorgular(Queries) yrtlmektedir. Sz gelimi yukardaki rnee
gre SQL Profiler ile arkada alan kodlar izlenirse aadaki sonularn elde edildii grlecektir.

exec sp_executesql N'INSERT INTO [Production].[ProductCategory]([Name], [rowguid],


[ModifiedDate])
VALUES (@p0, @p1, @p2)

SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]',N'@p0 nvarchar(5),@p1


uniqueidentifier,@p2 datetime',@p0=N'Tools',@p1='00000000-0000-0000-0000-
000000000000',@p2='2001-01-01 00:00:00:000'

Bu alan sorgu(Query) basit olarak retilen varlk nesnesinin(Entity Object) veritabanna doru
yazlmasn salamaktadr. stenirse toplu olarak veri ekleme ilemleride gerekletirilebilir. Bunun
iin tek yaplmas gereken InsertAllOnSubmit metodunu kullanmaktadr. Aadaki rnek kod
parasnda toplu bir ekleme ileminin nasl yaplabilecei gsterilmektedir.

adwContext.ProductCategories.InsertAllOnSubmit(
new List<ProductCategory>()
{
new ProductCategory(){Name="Kategori X",
ModifiedDate=new DateTime(2006,12,3),rowguid=Guid.NewGuid()}
,new ProductCategory(){Name="Kategori
Y",ModifiedDate=new DateTime(2006,5,6),rowguid=Guid.NewGuid()}
,new ProductCategory(){Name="Kategori
Z",ModifiedDate=new DateTime(2007,1,4),rowguid=Guid.NewGuid()}
}
);

var eklenenler = adwContext.GetChangeSet().Inserts;

foreach (ProductCategory eklenen in eklenenler)


Console.WriteLine(eklenen.Name);

www.bsenyurt.com Page 626


adwContext.SubmitChanges();

Yine nesne balatclarndan(Object Initializers) yararlanlarak, InsertAllOnSubmit metodu


ierisinde ProductCategory tipinden rnekler alabilecek generic List koleksiyonu oluturulmu ve
3 rnek ProductCategory eklenmitir. lave edilen satrlar elde edebilmek iin
yine GetChangeSet metodu zerinden Inserts zellii kullanlmaktadr.DataContext tipi
zerinden SubmitChanges metodunun altrlmas ile birlikte, varlk(Entity) tiplerine eklenen 3
ProductCategory nesnesi iinde birer Insert sorgusu SQLsunucusu zerinde yrtlmektedir. Bu
durumu daha iyi analiz etmek iin SQL Profiler arac kullanldnda aadakine benzer sonular
alnd grlr.

Dikkat edilecei zere her bir varlk nesnesi(Entity Object) iin birer Insert sorgusu
yrtlmektedir.

Gelelim silme ilemlerine. Silme(Delete) operasyonlarndada ekleme ilemlerine benzer


ekilde DeleteOnSubmit ve DeleteAllOnSubmit gibi metodlar yer almaktadr. Herzamanki gibi
varlk nesneleri zerinden yaplan silme ilemleri GetChangeSet metodu zerinden
ulalan Deletes zellii yardmyla elde edilebilir. Aadaki rnek kod parasnda tek bir satrn
silme ileminin nasl yaplabilecei gsterilmektedir.

ProductCategory silinecekVeri = (from cat in adwContext.ProductCategories


where cat.ProductCategoryID == 25
select cat).Single<ProductCategory>();

adwContext.ProductCategories.DeleteOnSubmit(silinecekVeri);

var silinenler = adwContext.GetChangeSet().Deletes;

foreach(ProductCategory silinen in silinenler)


Console.WriteLine(silinen.Name);

adwContext.SubmitChanges();

www.bsenyurt.com Page 627


Burada dikkat edilmesi gerken baz noktalar vardr. Silinmek istenilen satr veya satrlarn ncelikli
olarak bulunmas gerekir. Bu ok doal olarak Table<T> tipi zerinden bir LINQsorgusu ile
mmkn olabilir. Dolaysyla yukardaki kod parasna gre, silinecekVeri isimli koleksiyon elde
edilirken arka planda aadaki sorgu cmlesi alacaktr.

exec sp_executesql N'SELECT TOP (1) [t0].[ProductCategoryID], [t0].[Name], [t0].[rowguid],


[t0].[ModifiedDate]
FROM [Production].[ProductCategory] AS [t0]
WHERE [t0].[ProductCategoryID] = @p0',N'@p0 int',@p0=25

Bu admdam sonra DeleteOnSubmit metoduna, silinmek istenen varlk(Entity) rnei parametre


olarak verilmektedir. Bu ilem sadece silinecek olan veriler iin kuyrua bir ekleme yapmaktadr.
yleki bu metod arldktan sonra ProductCategories koleksiyonuna baklrsa, 25
numaral ProductCategory tipinin halen daha mevcut olduu grlebilir.

Silinmek istenen verinin programatik ortamda elde edilmesi iin tek yaplmas
gereken GetChangeSet metodu zerinden Deletes zelliine ulamaktr. alma
zamanSubmitChanges metodunu yrttnde ise silinmek istenen entity nesnesi ile ilgili
olaraktan aadaki sorgu cmlesi SQL tarafnda iletilecektir.

exec sp_executesql N'DELETE FROM [Production].[ProductCategory]


WHERE
([ProductCategoryID] = @p0) AND ([Name] = @p1) AND ([rowguid] = @p2) AND
([ModifiedDate] = @p3)',N'@p0 int,@p1 nvarchar(10),@p2 uniqueidentifier,@p3
datetime',@p0=25,@p1=N'Kategori Y',@p2='B68CEBC9-CFFF-4AD5-9F5A-
ADEC8823E88A',@p3='2006-06-05 00:00:00:000'

Sorgu cmlesindende dikkat edilecei zere Where ifadesinden sonra tm alanlar hesaba
katlmaktadr. Bunun sebebi LINQ to SQL mimarisinin Optimistic(yimser)
Concurrency modelini kullanmasdr. Bu modellde bilindii zere kontrol edilebilir tm
alanlar Where ifadesinden sonra hesaba katlmaktadr. Bir baka deyile model, veriyi bakasnn
silip silmediini, gncelletirip gncelletirmediini aratrmaktadr. rnekte 25 numaral kategoriye
ait satr silmeden nce baka birisi deitirmise eer, alma

www.bsenyurt.com Page 628


zamanndaChangeConflictException istisnas alnr. Bu durumu daha iyi analiz etmek iin 25
numaral satr silmek istediimizi gz nne alalm. SubmitChanges metodu arlmadan ncede
veritabanndan manuel olarak yada baka bir program zerinden 25 numaral
satrn Name alannn deerini Kategori X' den Kategori XL' ye deitirelim. Bunu kolay bir ekilde
gerekletirmek iin SubmitChanges satrna breakpoint koyup ilerlemeden nce tabloda
deiiklik yapmak yeterli olacaktr. Byle bir durumda alma zamannda(run time) aadaki gibi
bir durum olaacaktr.

Nitekim biz silmek istediimiz veriyi ektikten sonra Name alannn deeri Kategori X
iken, SubmitChanges' den nce Kategori XL' ye deitirilmitir. Buda doal
olarak Where ifadesinin geersiz olmas anlamna gelmektedir. Ancak bu durum istenirse
deitirilebilir. yleki, varlk(Entity) snflarnda yer alan zelliklerin(Properties)
Column isimliniteliklerine(Attribute) ait ColumnChange zelliinin deeri Never yapldnda
sz konusu zelliklerin Where ifadelerinden sonrasna katlmad grlmektedir. Sz gelimi rnekte
yer alan ProductCategory snfnn Name, rowguid ve ModifiedDate zelliklerinde yer
alan Column niteliinde aadaki gibi bir deiiklik yaptmz dnelim.

[Column(Storage="_Name", DbType="NVarChar(50) NOT NULL",


CanBeNull=false,UpdateCheck=UpdateCheck.Never)]
public string Name

UpdateCheck deerine Never atanmas sonucu sz konusu zelliin deeri WHERE ifadesine
parametre olarak dahil edilmeyecektir. Bu ilemin ardndan rnek olarak baka bir satr daha
silmek istersek arka tarafta alan Delete sorgusunun aadaki gibi oluturulduunu grebiliriz.

exec sp_executesql N'DELETE FROM [Production].[ProductCategory]


WHERE [ProductCategoryID] = @p0',N'@p0 int',@p0=29

Grld gibi sadece ProductCategoryID alan WHERE ifadesinden sonrasna


katlmtr. (Kodun bundan sonraki ksmlarnda Optimistic Concurrency modeline gre
ilerleneceinden UpdateCheck deiiklikleri geri alnmtr.)

stenirse toplu olarak silme ilemleride gerekletirilebilir. rnein Name zelliinin ierisinde
Kategori kelimesi geen satrlar silmek istediimizi dnelim. Bu amala aadaki gibi bir kod
paras gz nne alnabilir. ncelikli olarak Contains metodu ile Kategori kelimesi geen
ProductCategory nesnelerinin bir listesinin elde edilemsi gerekmektedir. LINQ sorgusu buna gre
dzenlenmitir.

var kategoriGecenler = from k in adwContext.ProductCategories


where k.Name.Contains("Kategori")
select k;

adwContext.ProductCategories.DeleteAllOnSubmit<ProductCategory>(kategoriGecenler);

www.bsenyurt.com Page 629


adwContext.SubmitChanges();

Sz konusu kod ierisinde SubmitChanges metodu altrldnda SQL tarafnda, silinmek


istenen her satr iin bir Delete sorgu ifadesinin yrtld grlecektir. rnekte bu kategoriye
uyan 5 satr bulunmaktadr.

Gelelim gncelleme(Update) ilemlerine. Gncelleme


srelerinde, Insert ve Delete ilemlerindeki gibi metodlar sz konusu deildir. Nitekim
gncelleme ilemi aslnda varlk nesnesinin herhangibir zelliinin(zelliklerinin) deerinin
deitirilmesinden baka bir ey deildir. Dolaysyla tek yaplmas gereken deiiklikler
tamamlandktan sonraSubmitChanges metodunu armaktr. Aadaki rnek kod parasnda
rnek olarak Product tablosuna ait bir varlk snf(Entity Class) kullanlmaktadr. Bu snf
oluturmak iin tek yaplmas gereken tahmin edilecei zere Server Explorer'
dan Product tablosunu Adventure.dbml zerine tasarm zamannda srkleyip brakmaktr.

var guncellenecekler = from p in adwContext.Products


where p.ProductSubcategoryID == 1
select p;

foreach (Product prd in guncellenecekler)


prd.ListPrice += 10;

var bekleyenGuncellemeler = adwContext.GetChangeSet().Updates;

adwContext.SubmitChanges();

Bu kod parasnda ProductSubCategoryId deeri 1 olan nesneler elde edilmekte ve


herbirinin ListPrice deeri 10 birim arttrlmaktadr. ok doal olarak yaplan bu
gncellemelerdeUpdates kuyruuna atlacaktr. Sz gelimi rnee gre varsaylan olarak kuyrua
32 Product nesnesi atlmaktadr. Elbette koula uyan kategorilerin her birinin ListPrice zelliklerinin
deerleri deitirildiinde bu gncellemeler Products koleksiyonunada yansyacaktr.

www.bsenyurt.com Page 630


SubmitChanges metodunun iletilmesi ile birlikte gncelleme kuyruunda bekleyen 32
adet Product nesne rnei iin veritabannda Update sorgular altrlacaktr. Aadaki SQL
Profiler ekran grntsnde bu sorgularn bir ksm yer almaktadr.

Buraya kadarki ksmda basit olarak ekleme(Insert), silme(Delete) ve


gncelleme(Update) ilemlerini nasl yapabileceimizi grmeye altk. nemli olan noktalardan
biriside deiikliklerden vazgeersek ne olacadr. Bu nemli bir skntdr.
Nitekim GetChangeSet metodu zerinden elde edilen ChangeSet tipinin
sunduu Deletes, Inserts, Updateszelliklerinin dndrd IList<T> koleksiyonlar alma
zamannda yanlz okunabilir(read-only) ekilde ele alnabilmektedir. Bu
nedenle Clear, Remove, RemoveAt gibi metod arlar hatta null deer atanmas sonras

www.bsenyurt.com Page 631


alma zaman istisnalar alnmaktadr. Sz gelimi son rnek koddaki gncelletirmeleri onaylamak
istemediimizi dnelim. Bu amala Clear metoduna bavurulmas dnlebilir. Ancak bu
durumda alma zamannda aadaki ekran grntsnde yer
alanNotSupportedException istisnas alnacaktr.

Bu noktada Table<T> tipi zerinden ulalabilen GetOriginalEntityState metodu alternatif bir yol
olarak ele alnabilir. Nitekim bu metod, parametre olarak verilen varlk nesnesinin(Entity
Object) deitirilmeden nceki halini elde etmemizi salamaktadr. rnein aadaki kod
parasn ele alalm.

var bekleyenGuncellemeler = adwContext.GetChangeSet().Updates;

Product prdNew = (Product)bekleyenGuncellemeler[0];


Console.WriteLine(prdNew.ListPrice.ToString());

Product prdOriginal = adwContext.Products


.GetOriginalEntityState((Product)bekleyenGuncellemeler[0]);
Console.WriteLine(prdOriginal.ListPrice.ToString());

Burada grld gibi prdNew nesne rneinin ListPrice deeri 3419.99 iken prdOriginal' in deeri
3409.00 dur. Aadaki alma zaman grntsnde bu durum net bir ekilde grlebilmektedir.

Ancak bu teknik yardmyla gncellenmi olan tm satrlarn geri alnmas olduka zordur.
Nitekim Table<T> tipinin yapc metodunun(Constructor) kullanlamad, bu yzden new ile
retilemedii ortadadr. Ayrca var olan DataContext nesnesinin Table<T> tipinden
zellikleri ReadOnly' dir. Bir baka deyile bu zelliklere dorudan atama da yaplamamaktadr.
Sonu olarak DataContext tipinin yeniden rneklenmesi sorunu zmek iin yeterli olacaktr.

www.bsenyurt.com Page 632


Table<T> generic tipi zerinden kullanlan GetModifiedMembers metodu ile,
parametre olarak verilen varlk(entity) nesne rneinin deiiklie urayan
deerlerininorjinal(OriginalValue) ve anlk(CurrentValue) hallerinin elde edilmesi
salanabilmektedir. GetModifiedMembers metodu geriye ModifiedMemberInfo tipinden
bir dizi dndrmektedir. Aadaki ekilde rnek olarak gncellenen satrlardan ilki iin
orjinal ve gncel ListPrice deerlerinin elde edilii gsterilmektedir.

Normal artlarda SubmitChanges metodunun arlmasndan sonra gncelleme, ekleme ve silme


ilemleri otomatik olarak transaction ierisinde altrlrlar. Bir baka deyile SubmitChanges
metodu, veritaban zerinde yaplacak ilemlerin, biz sylemeden otomatik olarak
bir transaction ierisinde olmasn salamaktadr. Sz gelimi aadaki kod parasn ele alalm. Bu
kod parasnda gncelleme(Update) ve yeni rn ekleme(Insert) ilemleri sz konusudur.

var guncellenecekler = from p in adwContext.Products


where p.Class == "M" && p.ProductSubcategoryID==1
select p;

foreach (Product prd in guncellenecekler)


prd.ListPrice += 10;

Product newProduct = new Product()


{
Name = "Yeni Urun"
, ProductSubcategoryID = 1, Color = "Red"
, Class = "M", ListPrice = 100
, ProductNumber = "PRD-1204", ReorderPoint = 10
, StandardCost = 90, ProductModelID = 123
, SafetyStockLevel = 45,SellStartDate=new DateTime(2007,1,1)
, SellEndDate=new DateTime(2008,1,1), DiscontinuedDate=new DateTime(2006,6,6)
, ModifiedDate=DateTime.Now
};

adwContext.Products.InsertOnSubmit(newProduct);

adwContext.SubmitChanges();

lk olarak Class deeri M ve ProductSubCategoryID deeri 1 olan Product tiplerine ait bir koleksiyon
ekilmektedir. Daha sonra bu koleksiyon zerinde dnlerek ListPrice deerleri sembolik olarak 10'
ar birim arttrlmaktadr. Hemen arkasdan rnek bir Product nesnesi oluturulmakta ve
InsertOnSubmit metodu ile eklenecekler listesine aktarlmaktadr. Uygulama altrldnda SQL
Profiler araclyla arkadaki ilemler incelenecek olursa aadaki ekran grntsnde yer alan
sonularn elde edildii grlr.

www.bsenyurt.com Page 633


Dikkat edilecek olursa Insert ve Update ifadelerinin tamam ayn Transaction ierisinde
yrtlmektedir. Dier taraftan ayn kodun aadaki gibi deitirildiini dnelim.

var guncellenecekler = from p in adwContext.Products


where p.Class == "M" && p.ProductSubcategoryID==1
select p;

foreach (Product prd in guncellenecekler)


prd.ListPrice += 10;

adwContext.SubmitChanges();

Product newProduct = new Product()


{
Name = "Yeni Urun"
, ProductSubcategoryID = 1, Color = "Red"
, Class = "M", ListPrice = 100
, ProductNumber = "PRD-1204", ReorderPoint = 10
, StandardCost = 90, ProductModelID = 123
, SafetyStockLevel = 45,SellStartDate=new DateTime(2007,1,1)
, SellEndDate=new DateTime(2008,1,1), DiscontinuedDate=new DateTime(2006,6,6)
, ModifiedDate=DateTime.Now
};

adwContext.Products.InsertOnSubmit(newProduct);

adwContext.SubmitChanges();

Burada SubmitChanges metodu gncelleme ve ekleme ilemlerinden sonra birer kez ayr ayr
arlmaktadr. Bu durumda SQL Profiler aadaki sonular retecektir.

www.bsenyurt.com Page 634


Grld gibi SubmitChanges her arldnda o ana kadar gerekletirilen ne kadar ekleme,
gncelleme veya silme ilemi varsa ayr bir Transaction kapsam ierisinde almaktadr.
Elbetteki istenirse son kod parasndaki tm sorgu ilemlerin ayn transaction
kapsam(Scope) ierisine dahil edilmeside salanabilir. Bunun
iinTransactionScope nesnesinden yararlanlabilir. Aadaki rnek bu durum basit olarak ele
alnmaktadr.(TransactionScope snfnn kullanlabilmesi iin .Net Framework 2.0 ile birlikte
gelen System.Transactions.dll assembly'nn projeye referans edilmesi gerekmektedir.)

using (TransactionScope tScope = new TransactionScope())


{
var guncellenecekler = from p in adwContext.Products
where p.Class == "M" && p.ProductSubcategoryID==1
select p;

foreach (Product prd in guncellenecekler)


prd.ListPrice += 10;

adwContext.SubmitChanges();

Product newProduct = new Product()


{
Name = "Yeni Urun"
, ProductSubcategoryID = 1, Color = "Red"

www.bsenyurt.com Page 635


, Class = "M", ListPrice = 100
, ProductNumber = "PRD-1204", ReorderPoint = 10
, StandardCost = 90, ProductModelID = 123
, SafetyStockLevel = 45, SellStartDate=new DateTime(2007,1,1)
, SellEndDate=new DateTime(2008,1,1), DiscontinuedDate=new DateTime(2006,6,6)
, ModifiedDate=DateTime.Now
};

adwContext.Products.InsertOnSubmit(newProduct);

adwContext.SubmitChanges();

tScope.Complete();
}

Dikkat edilecei zere tm kod paras TransactionScope nesne rneine ait bir using blou
ierisine alnm ve en sonra Complete metodu arlmtr. Bu durumdaSubmitChanges arlar
ayr ayr yaplm olsada tm ilemler ayn transaction kapsamna(Transaction Scope) dahil
edilecektir. TransactionScope kullanlmas ok doal olarak programatik taraftan Transaction ile
ilgili daha fazla ynetsel ilemin yaplabilmesi anlamnada gelmektedir. Sz gelimi izolasyon
seviyeleri(Isolation Level) daha kontroll bir ekilde ele alnabilir. Hatta datk
transaction(Distributed Transaction) geileri daha kolay programlanabilir.

TransactionScope kullanm dnda yerel transaction kullanlarakta ilgili ilemlerin


ayn Transaction ierisinde gereketirilmesi salanabilir. Aadaki rnek kod parasnda bu
durum ele alnmaya allmaktadr.

try
{
var guncellenecekler = from p in adwContext.Products
where p.Class == "M" && p.ProductSubcategoryID == 1
select p;

foreach (Product prd in guncellenecekler)


prd.ListPrice += 10;

// Transaction balatlmas iin balantnn ak olmas gerekir.


adwContext.Connection.Open();

// Transaction balatlr ve AdventureContext tipine bildirilir.


adwContext.Transaction = adwContext.Connection.BeginTransaction();

adwContext.SubmitChanges();

Product newProduct = new Product()


{
Name = "Yeni Urun"
, ProductSubcategoryID = 1, Color = "Red"
, Class = "M", ListPrice = 100
, ProductNumber = "PRD-1204", ReorderPoint = 10
, StandardCost = 90, ProductModelID = 123
, SafetyStockLevel = 45, SellStartDate=new DateTime(2007,1,1)
, SellEndDate=new DateTime(2008,1,1), DiscontinuedDate=new DateTime(2006,6,6)
, ModifiedDate=DateTime.Now
};

www.bsenyurt.com Page 636


adwContext.Products.InsertOnSubmit(newProduct);

adwContext.SubmitChanges();

// Herey yolunda ise Transaction onaylanr


adwContext.Transaction.Commit();
}
catch
{
// Bir aksilik olduysa Transaction geri alnr
adwContext.Transaction.Rollback();
}
finally
{
if (adwContext.Connection.State == ConnectionState.Open)
adwContext.Connection.Close();
}

Dikkat edilecei zere DataContext tipinin Transaction zelliine deer


atanrken Connection zerinden gidilmi ve BeginTransaction metodu kullanlmtr.
BeginTransaction metodunun parametresinden yararlanlarak, Transaction' n izolasyon
seviyeside(Isolation Level) deitirilebilir. Burada Transaction' n oluturulabilmesi iin
balantnn(Connection) ak olmas gerekmektedir. Bu sebeptende finally blou ierisinde ak
kalan balantnn kontroll bir ekilde kapatlmas salanmaktadr. Transaction' a dahil olan
ilemlerin onaylanmas iin Commit metodu kullanlrken bir sorun ile karlalmas halinde o ana
kadar yaplan ilemlerin geri alnmas iinde Rollback metoduna bavurulmaktadr. Sonu
olarak SQL Profiler arac izlendiinde ekleme(insert) ve gncelleme(update) ilemlerinin yine
tek bir Transaction kapsam ierisinde ele alnd grlmektedir.

LINQ To SQL mimarisin u ana kadar ilenen temel CRUD ilemlerinde ele alnmas gereken baka
hususlarda vardr. Sz gelimi e zamanl alan programlarn ayn veriler zerinde ilemler yapt
durumlarda oluan akmalarn(Conflict) ele alnmas gibi. Bu ve benzeri konular ilerleyen
makalelerimizde ve grsel derslerimizde incelemeye alyor olacaz. Bu makalemizde ok basit
ve temel seviyede ekleme(Insert), Silme(Delete) ve Gncelleme(Update) ilemlerini nasl
yapabileceimizi incelemeye altk. Ayrca bu ilemleri yaparken Transaction' larn nasl
kullanlabildiinide grdk. Varsaylan olarak bilinsiz ekilde balatlan Transaction' lar
TransactionScope ile veya Local Transaction teknikleri nasl kontrol edebileceimiz grdk. Bylece
geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Nasl Yaplr? Adm Adm zel HttpHandler (


10.12.2007 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Uzun zaman nce Asp.Net 2.0 ile


ilikili makalelerimizden birisinde HttpHandler ve HttpModule kavramlarndan bahsetmeye

www.bsenyurt.com Page 637


almtk. Bu makalemizde kendi Handler snfmz gelitirmek isteyebileceimiz rnek bir senaryo
zerinde daha durmaya alacaz. Bu sayede HttpHandler snflar yazarak neler yaplabileceinide
daha net bir ekilde grm olacaz. Konuyu daha net kavrayabilmek adna rnek senaryomuz
zerinden adm adm ilerleyeceiz.

Bilindii zere web sunucusuna istemci tarafndan gelen talepler(Requests) baz program ara
yzleri(API) tarafndan karlanr ve uygun ortamlara iletilmek zere iletilirler.
zellikle Asp.Net ile gelitirilen web uygulamalarnda, talep edilen dosya tipine gre devreye giren
HttpHandler snflar bulunmaktadr. Sz gelimi aspx uzantl dosyalarPageHandlerFactory isimli
snf tarafndan ele alnrlar. PageHandlerFactory ve benzer ilevselliklere sahip handler
tipleri IHttpHandler arayzn(interface) uygularlar. Dolaysyla gelitiriciler kendi Handler
tiplerini IHttpHandler arayzn kullanarak yazabilirler.

Gelelim rnek senaryomuza. Sunucu zerinde barndrlan XML(eXtensible Markup


Language) tabanl basit bir metin dosyasn ele alacak zel bir Handler tipi gelitiriyor olacaz.
XML tabanl dosya ierisinde yer alan bilgilerden yararlanlarak ekrana herhangibir sorguya ait
raporlama sonular aktarlacak. Dosyann uzantsnn rnek olarak rapx olduunu dnebiliriz.
Peki bu raporlama ileminde nemli bir rol oynacak olan XML ieriinde neler olmas
gerekmektedir? Bunlarn tespiti XML dosyasnn mantksal aa yapsnn oluturulmasnda
kolaylatracaktr. Sz konusu ihtiyalar aadaki maddeler halinde sralanabilirler.

Hazrlanan rapor iin bir balk(Title) bilgisi tutulabilir. Hatta baln arka plan
rengi(Background Color) verilerek zengin grnmesi salanabilir.
Rapor dosyasnn ka adet sorgu cmlesi(Query) iin destek vereceine karar vermek
gerekmektedir. rnein basit olmas asndan balang itibariyle sadece tek bir sorgu
sonucunun ele alnmasnda fayda vardr.
Sorgu cmlesi, sakl yordam(stored procedure) veya text tabanl ifadeleri iaret edebilir.
Hatta bir veritaban grnmnn(View) desteklenmesi bile salanabilir.
Sorgu cmlesinde parametre kullanmna destek verilebilir. Bu
parametrelerinin QueryString yardmyla Url zerinden veya XML ieriinden alnacana
dair tanmlamalar yaplabilir.
Sorgu cmlesinin alaca sunucu(Server) ve veritaban(Database) ad belirtilmelidir.
Hatta SSPI ile balantya destek verilmeside gz nne alnmaldr.
Hazrlanan raporlarn XML ieriinde belirtilen mail adreslerine gnderilmesi de salanabilir.
Raporun kimler tarafnda grlebileceine dair tanmlamalar yaplabilir. Bu
tanmlamalar kullanc(User) ve hatta rol(Role) baznda gerekletirilebilir.

Bu ihtiyalar dahada arttrlabilir. Bir anlamda gelitiricinin hayal gc burada nem kazanmaktadr.
Yukardaki maddelerde sz geen ihtiyalarn tamam XML' in temel kavramlar ile karlanabilir.
Bir baka deyile eleman(element) ve nitelikler(attributes) sayesinde yukardaki istekler
standartlara uygun olacak ekilde tasarlanabilir.

Sz konusu XML ieriinin alma zamannda(run time) uygun bir standartta


olduunun garanti altna alnmas iin ema (Xml Schema) kullanlmas yararl olacaktr.
Bu ema ile Xml ieriinin arptrlmas Handler tipi ierisinde yaplabilir. emaya
uymayan XML ierikleri iin Handler, istekleri zel olarak tasarlanm bir hata sayfasna
doru ynlendirebilir.

Yukardaki maddeler nda aadaki gibi rnek bir XML ierii gz nne alnabilir.

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


<Raporlar>
<Rapor Id="">
<Baslik ArkaPlan=""></Baslik>

www.bsenyurt.com Page 638


<Baglanti SSPI="">
<Sunucu></Sunucu>
<Veritabani></Veritabani>
<KullaniciAdi></KullaniciAdi>
<Sifre></Sifre>
</Baglanti>
<Sorgu Sp="">
<Cumle></Cumle>
<Parametreler Nereden="">
<Parametre Ad="" Deger=""/>
</Parametreler>
</Sorgu>
<MailListesi MailGonder="">
<Mail></Mail>
<Mail></Mail>
</MailListesi>
</Rapor>
</Raporlar>

Raporlar ana boumu(Root Node) birden fazla Rapor elementi ierebilir. Biz rnein daha kolay
ele alnabilmesi amacyla tek bir Rapor elementi kullanyor olacaz. Raporun
alnaca sunucu(Server), veritaban ad(Database Name), kullanc ad(User
name) ve ifre(Password) bilgileri ise Baglanti elementi altnda tutulmaktadr.
Hatta SSPIkullanmnada destek verilmesi amacyla Baglanti elementi ierisinde
bir nitelik(attribute) tanmlanmaktadr. Sorgularn sakl yordam(Stored Procedure) olup
olmad Sp nitelii ile belirtilebilir. Bunun dnda sorgu ierisinde kullanlan parametreler var ise
bunlarn nereden alnaca Nereden isimli nitelik(attribute) ile belirlenmektedir. yleki raporun
parametreleri, rapx dosyasna tarayc zerinden yaplan arlarda QueryString yardmyla
gelebilir. Yada Parametre elementleri ierisindeki Deger niteliklerinde dorudan tanmlanabilir.
retilen raporlarn mail yolu ile kimlere bildirileceine dair MailListesi elementi ve Mail alt
elementleri kullanlabilir.

Burada ortaya kan nemli bir ihtiya vardr. XML bilgilerinin tutulduu rapx uzantl dosyalarn
ilenmesi, bir HTML ktsnn retilmesi ve talepte bulunan istemcilere gnderilmesi salanmaldr.
Bunu sadece zel bir Handler tipi karlayabilir.

Dilerseniz vakit kaybetmeden Handler tipini yazarak ie balayalm. Gelitirilecek olan Handler
snf ilk etapta tek bir web uygulamasnda kullanlacaktr. Sonrasnda ise bu handler tipinin sunucu
zerindeki her Asp.Net web uygulamas iin geerli olmas salanacaktr. Bu
nedenle Handler tipinin bir snf ktphanesi(Class Library) ierisinde olmasnda yarar vardr.
Handler snfnn IHttpHandler arayznden(Interface) tretilmesi iinde snf
ktphanesine System.Web.dll assembly' nn referans edilmesi arttr. Sz
konusu Handler snfnn diagram grnts ve ierii aadaki gibidir.

www.bsenyurt.com Page 639


using System;
using System.Web;
using System.Data;
using System.Web.Hosting;
using System.Data.SqlClient;
using System.Xml;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.IO;

namespace ReportHandlerLibrary
{
public class RaporHandler:IHttpHandler
{
#region IHttpHandler Members

public bool IsReusable


{
get { return false; }
}

// Gelen talep sonras retilecek HTML ktsn bu metod ierisinden veriyor olacaz
public void ProcessRequest(HttpContext context)
{
// Talep edilen sayfa Request.Path ile yakalanr.
// VirtualPathProvider metodu ile sanal adresin karl olan fiziki yoldaki dosya alarak
Stream halinde elde edilir.
// Stream'den yararlanlarak XML ierii XmlDocument nesnesi ierisine alnr.
XmlDocument xDoc = new XmlDocument();
xDoc.Load(VirtualPathProvider.OpenFile(context.Request.Path));
if (context.Request.QueryString["MailGonder"] == null)
{
// Baslik elementinden raporun bal bilgisi alnr
string baslik = xDoc.SelectSingleNode("Raporlar/Rapor/Baslik").InnerText;
string baslikArkaPlanRengi
= xDoc.SelectSingleNode("Raporlar/Rapor/Baslik").Attributes["ArkaPlan"].InnerText;

// Ekran tasarm oluturulmaya balanr


// retilen kt bir HTML sayfas olacandan HTML elementlerinin kullanlmas

www.bsenyurt.com Page 640


gerekmektedir.
context.Response.Write("<HTML><HEAD><TITLE>" + baslik +
"</TITLE></HEAD>");
context.Response.Write("<BODY>");
// Table elementi oluturulur.
context.Response.Write("<TABLE border='1' width='100%' cellspacing='0'
cellpadding='5'>");
// Tablo 3 satrdan olumaktadr. lk satrn arka plan rengi ve ierisinde yer alacak
metin bilgisi Baslik elementi ve ArkaPlan niteliklerinden alnr
context.Response.Write("<TD style='background-color:" +
baslikArkaPlanRengi + "'>");
context.Response.Write("<H3>" + baslik + "</H3>");
context.Response.Write("</TD></TR>");
// kinci satr ierisinde rapor sonucu retilen grid ierii olmaldr.
context.Response.Write("<TR><TD>");

// Bu hcreye veri ile doldurulan Grid ieriinin HTML kts yazdrlr


context.Response.Write(GridHTMLUret(xDoc,context).ToString());

context.Response.Write("</TD></TR>");
context.Response.Write("<TR><TD>");

// Mail gnderme aksiyonu iin basit bir hyperLink elementi eklenir


context.Response.Write("<a href='"+context.Request.Path +
"?MailGonder=1'>" + "Raporu Mail Olarak Gnder" + "</a>");

context.Response.Write("</TD></TR>");
context.Response.Write("</BODY>");
context.Response.Write("</HTML>");
}
else
{
bool mailGondersinmi = false;
Boolean.TryParse(xDoc.SelectSingleNode("Raporlar/Rapor/MailListesi").Attribut
es["MailGonder"].Value, out mailGondersinmi);
if (mailGondersinmi)
MailGonder(xDoc,context);
}
}

#endregion

// GridView kontrolnn ierii doldurulduktan sonra HTML ierii elde edilir ve bu ierii
tayan StringWriter geriye dndrlr.
private StringWriter GridHTMLUret(XmlDocument xDoc,HttpContext ctx)
{
// SqlDataAdapter nesne oluturulur
SqlDataAdapter adapter = new SqlDataAdapter(KomutHazirla(xDoc,ctx));
DataTable table = new DataTable();
// DataTable doldurulur
adapter.Fill(table);

// GridView kontrol retilir ve veriye balanr


GridView grd = new GridView();
grd.DataSource = table;
grd.DataBind();

www.bsenyurt.com Page 641


//GridView kontrolnn HTML kts elde edilir
StringWriter strWriter = new StringWriter();
HtmlTextWriter writer = new HtmlTextWriter(strWriter);
grd.RenderControl(writer);
return strWriter;
}

// Raporun retilmesi iin gerekli SqlCommand hazrlanyor.


private SqlCommand KomutHazirla(XmlDocument xDoc,HttpContext ctx)
{
bool sp = false;
// Sorgu cmlesinin Stored Procedure olup olmad belirlenir.
Boolean.TryParse(xDoc.SelectSingleNode("Raporlar/Rapor/Sorgu").Attributes["Sp"].Value,
out sp);

// SqlCommand tipi hazrlanr


SqlCommand cmd = new SqlCommand();
// Sorgu cmlesi alnr
cmd.CommandText =
xDoc.SelectSingleNode("Raporlar/Rapor/Sorgu/Cumle").InnerText.Trim();
// Balant cmlesi BaglantiCumlesiOlustur metodundan elde edilir ve Command iin
gerekli SqlConnection hazrlanr.
cmd.Connection = new SqlConnection(BaglantiCumlesiOlustur(xDoc));
// Eer cmle Stored Procedure adn iaret ediyorsa CommandType iin StoredProcedure
enum sabiti deeri verilir
if (sp)
cmd.CommandType = CommandType.StoredProcedure;

// Eer girilmi parametreler varsa bu parametreler Command nesnesine AddWithValue


metodu ile teker teker eklenir.
if (xDoc.SelectSingleNode("Raporlar/Rapor/Sorgu/Parametreler").ChildNodes.Count > 0)
{
string parametreNereden =
xDoc.SelectSingleNode("Raporlar/Rapor/Sorgu/Parametreler").Attributes["Nereden"].Value;
XmlNodeList parametreler =
xDoc.SelectSingleNode("Raporlar/Rapor/Sorgu/Parametreler").ChildNodes;
foreach (XmlNode parametre in parametreler)
{
if(parametreNereden=="Xml")
cmd.Parameters.AddWithValue(parametre.Attributes["Ad"].Value,
parametre.Attributes["Deger"].Value);
else if(parametreNereden=="QueryString")
cmd.Parameters.AddWithValue(parametre.Attributes["Ad"].Value,
ctx.Request.QueryString[parametre.Attributes["Ad"].Value.Substring(1,
parametre.Attributes["Ad"].Value.Length - 1)]);
}
}
// Oluturulan Command nesnesi geri dndrlr.
return cmd;
}

// Sorgularn altrlmas iin gerekli Balant cmlesini oluturan metod


private string BaglantiCumlesiOlustur(XmlDocument xDoc)
{
bool sspi = false;

www.bsenyurt.com Page 642


// Sql balants iin gerekli balant cmlesi(Connection String)
SqlConnectionStringBuilder snf yardmyla oluturulur.
SqlConnectionStringBuilder conStrBuilder = new SqlConnectionStringBuilder();

// Sunucu ve veritaban bilgileri XPath ifadeleri ile alnr.


conStrBuilder.DataSource =
xDoc.SelectSingleNode("Raporlar/Rapor/Baglanti/Sunucu").InnerText;
conStrBuilder.InitialCatalog =
xDoc.SelectSingleNode("Raporlar/Rapor/Baglanti/Veritabani").InnerText;
Boolean.TryParse(xDoc.SelectSingleNode("Raporlar/Rapor/Baglanti").Attributes["Sspi"].Val
ue, out sspi);
if (!sspi) // Eer integrated security ile balanlmyorsa kullanc ad(UserID) ve
ifre(Password) bilgileri alnr.
{
conStrBuilder.UserID =
xDoc.SelectSingleNode("Raporlar/Rapor/Baglanti/KullaniciAdi").InnerText;
conStrBuilder.Password =
xDoc.SelectSingleNode("Raporlar/Rapor/Baglanti/Sifre").InnerText;
}
else
conStrBuilder.IntegratedSecurity = true;

// Oluturulan balant cmlesi(Connection String) geri dndrlr.


return conStrBuilder.ConnectionString;
}

// Mail gnderme seenei aktif ise postalarn gnderilme ilemini gerekletirecek olan
metod.
private void MailGonder(XmlDocument doc,HttpContext ctx)
{
// Mail listesi MailListesi elementinin alt elementlerinden ekilir.
XmlNodeList mailler = doc.SelectSingleNode("Raporlar/Rapor/MailListesi").ChildNodes;
foreach (XmlNode mail in mailler)
{
//TODO: Bu noktada raporun mail olarak gnderilmesine ait ilemler
yaplacaktr.
ctx.Response.Write(mail.InnerText + " adresine rapor mail olarak gnderildi<br/>");
}
}
}
}

Gelitirilen snf ierisinde paralar daha kolay ele alabilmek adna yardmc metodlar yer
almaktadr. Dikkat edilecei zere rapx ieriinin XML formatnda tasarlanmas, ilemleri son
derece kolaylatrmaktadr. Nitekim ieriin XmlDocument snfna ait bir nesne rnei ile bellee
alnmas, ierisindeki elementlerin veya niteliklerin XPathifadeleri ile yakalanmas son derece
kolaydr. stelik XML, platform bamszlk sunduundan bu dkmann baka bir ortama
gnderilerek ele alnmasnn salanmas daha kolaydr. Bu sebepten dolay gnmzn popler
kavramlarndan olan Reporting Services veya LINQ To SQL ierisinde yer alan Database
Markup Language(dbml) gibi yaplar XML zerine oturmaktadr. Snf ierisinde dikkat edilmesi
gereken noktalardan bir dieri ise, HttpContext tipinin ektin ekilde kullanmdr. HttpContext
zerinden ele alnan yeler ile, retilecek HTML ieriinin tasarlanmas veya talep ile gelen
QueryString' lerin yakalanmas sz konusudur. Hatta talep edilen sayfann sanal yolu(Virtual
Path) elde edilip XMLieriinin VirtualPathProvider snfnn OpenFile metodu ile kolay bir
ekilde Stream' e dntrlmeside salanmaktadr. lemleri kolaylatran noktalardan biriside

www.bsenyurt.com Page 643


web kontrollerinin RenderControl metodudur. Bu metod ile kompleks bir GridView kontrolnn
veri dolu ieriinin HTML ktsn almak son derece kolaylamaktadr.

imdi gelitirilen Handler tipini rnek bir web uygulamasnda test edebiliriz. lk olarak tek bir web
uygulamasna zel olacak ekilde Handler tipinin kullanlmasn ele alacaz. Byle bir durumda
ncelikli olarak web uygulamasnn Handler tipini ieren snf ktphanesini(Class
Library) referans etmesi gerekmektedir. rnek olarak OzelHandlerKullanimi isimli web uygulamas
aadaki ekran grntsnden de anlalaca zere ReportHandlerLibrary isimli assembly'
referans etmektedir.

Bunun dnda web uygulamasna ait web.config dosyas ierisinde aada grld gibi gerekli
bildirimler yaplmaldr.

<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<httpHandlers>
<add path="*.rapx"
type="ReportHandlerLibrary.RaporHandler,ReportHandlerLibrary" verb="*"
validate="true"/>
</httpHandlers>
<compilation debug="true"/>
<authentication mode="Windows"/>
</system.web>
</configuration>

httpHandlers elementi system.web elementi ierisinde tanmlanmaldr. rnekte rapx uzantl


dosyalara gelecek herhangibir talebin(Get, Post vb...) type
niteliinde(attribute)belirtilen RaporHandler snfna ait nesne rnei tarafndan karlanaca
belirtilmektedir. Bu adm tek bana yeterli deildir. Ayrca IIS(Internet Information Services)

www.bsenyurt.com Page 644


zerinden, rapx uzantl dosyalara gelecek olan talepler iin AspNet_Isapi.dll' inin devreye
gireceinin belirtilmesi gerekmektedir. rnek senaryo IIS 7.0 zerinde gelitirilmektedir. IIS 7.0
zerinden OzelHandlerKullanimi isimli web uygulamas adna rapx-
AspNet_Isapi.dll eletirmesi iin ncelikli olaran InetMgr arac zerinden ilgili web
uygulamasna geilmeli veHandler Mappings ksm aadaki ekran grntsnde olduu gibi
seilmelidir.

Handler Mappings ksmnda varsaylan ve izin verilen uzant eletirmeleri yer almaktadr. Bu
ksmda sa tklanarak alan menden Add Script Map seilmeli ve gerekli eletirme IIS tarafna
bildirilmelidir.

www.bsenyurt.com Page 645


Add Script Map ile alan iletiim kutusunda ise aadaki ayarlarn yaplmas gerekmektedir.

www.bsenyurt.com Page 646


Buna gre rapx uzantl taleplerin .Net 2.0 alma zamannda yer
alan AspNet_Isapi.dll tarafndan ele alnaca belirtilmektedir. Uygulamaya
ait web.config dosyas ierisinde gerekli Handler tanmlamalar yapld
iin AspNet_Isapi.dll program arayz, gelen talep(Request) iin RaporHandler snfnn
devreye girmesini salayacaktr. Bu ilemin ardndan Handler Mappings ksmna aadaki ekran
grntsnde de grld gibi rapx uzants iin gerekli eletirme eklenecektir.

Yaplan bu deiikliker sonrasnda web uygulmasnda ait web.config dosyas ierisindede


aadaki gibi yeni bir tanmlama oluacaktr. Bir baka deyile IIS(Internet Information
Services) zerinde yaplan eletirmeye ait bilgiler system.webServer elementi
ierisindeki handlers ksmna eklenmektedir.

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


<configuration>
<appSettings />
<connectionStrings />
<system.web>
<httpHandlers>
<add path="*.rapx" type="ReportHandlerLibrary.RaporHandler,ReportHandlerLibrary"
verb="*" validate="true" />
</httpHandlers>
<compilation debug="true" />
<authentication mode="Windows" />
</system.web>
<system.webServer>
<handlers>
<add name="Rapor X" path="*.rapx" verb="*"
modules="IsapiModule" scriptProcessor="C:\Windows\Microsoft.NET\
Framework\v2.0.50727\aspnet_isapi.dll" resourceType="File" />
</handlers>
</system.webServer>
</configuration>

Artk test amacyla web uygulamasna rapx uzantl rnek bir ierik eklenebilir. rnek
olarak AdventureWorks veritabannda yer alan Products tablosu ile ilikili bir rapor dnlebilir.
Bu raporun stok seviyesi belirli bir deerin altnda olan rnlerin kategori bazl saylarn verdiini

www.bsenyurt.com Page 647


dnelim. Buna gre web uygulamas altnda tutulacak olan rapx uzantl metin dosyasnn ierii
aadaki gibi tasarlanabilir.(Bu dosyay eklerken Add New Item-Text
File seerek KategoriBazliUrunler.rapx gibi bir seim yaplmas gerektiine dikkat edilmelidir.)

KategoriBazliUrunler.rapx;

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


<Raporlar>
<Rapor Id="1">
<Baslik ArkaPlan="#FFCC11">Kategori Bazl rn Saylar</Baslik>
<Baglanti Sspi="true">
<Sunucu>localhost</Sunucu>
<Veritabani>AdventureWorks</Veritabani>
<KullaniciAdi></KullaniciAdi>
<Sifre></Sifre>
</Baglanti>
<Sorgu Sp="false">
<Cumle> Select Count(P.ProductID) [Toplam rn Says],PSC.Name [Kategori Ad] From
Production.Product P Join Production.ProductSubCategory PSC On
P.ProductSubCategoryID=PSC.ProductSubCategoryID Group By PSC.Name,SafetyStockLevel
Having P.SafetyStockLevel&lt;@StockLevel
</Cumle>
<Parametreler Nereden="Xml">
<Parametre Ad="@StockLevel" Deger="10"/>
</Parametreler>
</Sorgu>
<MailListesi MailGonder="true">
<Mail>selim@bsenyurt.com</Mail>
<Mail>bsenyurt@csharpnedir.com</Mail>
</MailListesi>
</Rapor>
</Raporlar>

Burada basit olarak Product ve ProductSubCategory tablolarnn Join ile birletirilmi hali
zerinden bir gruplama sorgusu gerekletirilmektedir. Sorgular StockLevel parametresinin deeri
10'dan kk olanlar iin yaplmaktadr. Parametrenin deerinin XML ierisinden geleceini
belirtmek iin Nereden niteliine XML deeri atanmtr. Sz konusu rapor
iin MailListesinde belirtilen kiilere mail gnderme opsiyonu ak braklmtr.
Rapor, localhost isimli sunucudaki AdventureWorks veritaban zerinden SSPI ile
gerekletirilen bir balant zerinden alnmaktadr. Artk OzelHandlerKullanimi adresi
zerinden KategoriBazliUrunler.rapx dosyasna bir talepte bulunulursa aadaki gibi bir sonu
ortaya kacaktr.

www.bsenyurt.com Page 648


Grld gibi sorgu sonucu elde edilen rapor ekrana basit bir tablo olarak baslmtr. Mail
gnderme seenei aktif olduu iinde Raporu Mail Olarak Gnder balkl linkte sayfa ktsnda
yer almaktadr. Bu linke basld takdirde sunucuya yeni bir talep daha gnderilecektir. imdilik
sadece ilgili MailListesi elementinin ierii deerlendirilmitir. Aadaki ekran grntsnde bu
durum gsterilmektedir.

www.bsenyurt.com Page 649


Yeni bir test ile devam edelim. Bu kez raporun parametrelerine ait
deerlerin QueryString yardmyla geldiini gz nne alalm. Ayrca raporun
sonularnn Northwind veritaban altnda yer alan SalesByCategory isimli sakl yordam(stored
procedure) zerinden elde edildiini dnelim. MailGonderme seenei yine aktif olsun. Bu
durumda rapx dosyasnn ieriinin aadaki gibi tasarlanmas gerekecektir.

KategoriBazliSatislar.rapx;

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


<Raporlar>
<Rapor Id="1">
<Baslik ArkaPlan="#CCBB77">Kategori Bazl Satlar</Baslik>
<Baglanti Sspi="true">
<Sunucu>localhost</Sunucu>
<Veritabani>Northwind</Veritabani>
<KullaniciAdi></KullaniciAdi>
<Sifre></Sifre>
</Baglanti>
<Sorgu Sp="true">
<Cumle>SalesByCategory</Cumle>
<Parametreler Nereden="QueryString">
<Parametre Ad="@CategoryName"/>
<Parametre Ad="@OrdYear"/>
</Parametreler>
</Sorgu>
<MailListesi MailGonder="false">
<Mail>selim@bsenyurt.com</Mail>
<Mail>bsenyurt@csharpnedir.com</Mail>
</MailListesi>
</Rapor>
</Raporlar>

Buna gre tarayc


penceresinden http://localhost/OzelHandlerKullanimi/KategoriBazliSatislar.rapx?Categor
yName=Beverages&OrdYear=1999 adresi talep edilirse aadakine benzer bir ekran
grnts ile karlalacaktr.

www.bsenyurt.com Page 650


Elbette uygulamada pek ok hata gz ard edilmektedir. Sz
gelimi KategoriBazliSatislar.rapx iin QueryString parametreleri kullanlmassa alma
zaman hatalar(Run time exceptions) alnmas ok doaldr. Bu gibi hatalarn ele alnmas bir
baka deyile kodun tekrardan revize edilerek dzenlenmesi gerekmektedir.

Gelelim Handler tipinin sunucu zerinde nasl ele alnabileceine. Bunun iin gelitirilen Handler
tipini ieren assembly' n Global Assembly Cache(GAC) ierisine atlmas ve root
web.config dosyas ierisindeki httpHandlers elementi altnda bildirilmesi yeterlidir. rneimizde
gelitirdiimiz ReportHandlerLibraray.dll isimli assembly' GAC'a atmadan nceVisual Studio
2005 ortamnda aadaki gibi Strong Name ile imzalamamz gerekmektedir. (stenirse bu
imzalama ilemi komut satrndan sn.exe arac ilede gerekletirilebilir.)

www.bsenyurt.com Page 651


Bu ilemin ardndan ReportHandlerLibrary' in gacutil.exe arac yardmyla yada srkle brak
teknii ile Windows\Assembly klasrne atlarak GAC' a eklenmesi yeterlidir.

Burada ReportHandlerLibrary projesinin Relase modda retiminin yaplarak, Output


Path olarak
ktnn C:\Windows\Microsoft.NET\Framework\v2.0.50727\klasrn iaret
edecek ekilde dzenlenmesi ve daha sonra buradan GAC' a atlmasda tercih edilebilir.

Sonu olarak Windows\Assembly klasr altna ReportHandlerLibrary' si aadaki ekran


grntsnde olduu gibi eklenmi olacaktr.

www.bsenyurt.com Page 652


imdi tek yaplmas gereken bu assembly' n root web.config ierisinde bildirilmesidir. Bunun
iin C:\Windows\Microsoft.NET\Framework\v2.0.50727\CONFIG klasrnde yer alan
web.config dosyasna aadaki gibi handler bildiriminin yaplmas gerekmektedir.

Bu ilemlerin ardndan IIS zerinden rapx uzantl dosyalara gelecek olan


taleplerin AspNet_Isapi.dll tarafndan ele alnacannda belirtilmesi gerekir. Makalemizin
bandaOzelHandlerKullanimi isimli web sitesi iin yaptmz bu ilemin ayns bu kez root web
sitesi iin benzer ekilde yaplarak gerekletirilmelidir. Sonu itibariyle sunucu
zerinde Asp.Net 2.0 ile gelitirilen herhangibir web sitesi altnda tasarlanacak olan
tm rapx uzantl dosyalar RaporHandler snf tarafndan ele alnabilecektir.

Kendi handler tipimizi root web.config dosyasnda tanmladmzda, web uygulamas


ierisinde yer alan web.config dosyas ierisinde braklan handler tanmlamalar nedeni
ile alma zaman hatalar(Run time exceptions) alnr. Bu nedenle makaledeki
rnekte yer alan OzelHandlerKullanimi sitesindeki rapx dosyalar, root web.config' de
yaplan handler bildirimleri sonras almayacaktr.

www.bsenyurt.com Page 653


Sebep handler tanmlamasnn hem root web.config hemde site ierisindeki web.config'de
iki kez yaplm olmasdr. Bunu dzeltmek iin OzelHandlerKullanimi sitesine ait
web.config ierisinde yaplan handler bildirimlerini kaldrmak gerekmektedir.

Kendi HttpHandler tiplerimizi tasarlamak iin ele aldmz rnek senaryo ok daha fazla
gelitirilebilir. Hatta bir web sunucusu zerinde konulandrlacak olan rapx dosyalarnn daha kolay
hazrlanabilmesini salamak iin grsel bir arabirimde gelitirilebilir. Sadece Rapx uzantl dosyalar
barndracak olan bir Asp.Net uygulamas gelitirilerek tm raporlarn tek bir merkezde toplanmas
salanabilir. Hatta bu ii dahada ileriye gtrecek olursak, raporlarn yetki tabanl olacak ekilde

www.bsenyurt.com Page 654


ele alnabilmesi iin gerekli hazrlklarda yaplabilir. Bu noktada, tasarlanan bu sistemin Reporting
Service alt yapsna ne kadar benzediini tartmakta yarar vardr. Sistemin herhangibir
veritabanna destek verecek ekilde ele alnmas ise ok daha etkili bir raporlama arayz
oluturulmasna n ayak olacaktr.

Bu makalemizde daha nceden ele aldmz ancak geerli bir ihtiya veya senaryo zerine
oturtamadmz HttpHandler kavramn bir rnek zerinde adm adm incelemeye altk.
Sizlerde farkl senaryolar gz nne alarak ve makalede yer alan rnei dahada gelitirirek son
derece etkili sonulara varabilirsiniz. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

.Net Remoting Dnyasndan WCF'e Gemek (


03.12.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Windows tabanl olan Servis Ynelimli Mimari(Service Oriented Architecture) tekniklerinden


biriside .Net Remoting' dir. .Net Remoting mimarisi arlkl olarak TCP bazl ve Binarytabanl
paket iletiminde kullanlr. En byk zelliklerinden birisi, sadece Windows iletim sistemlerinden
oluan alarda koabilmesidir. Elbette HTTP zerinden SOAP-Simple Object Access
Protocol formatna uygun alt yap kurulmasda mmkndr. Bu sayede internet andada ektin
ekilde kullanlabilir. Ancak Windows baml olmas platform bamszln ortadan
kaldrmaktadr. Gnmzde WCF(Windows Communication Foundation) gibi daha
leklenebilir(Scalable), birletirilmi(Unified) bir Servis Ynelimli Mimari(SOA) almda
mevcuttur. Bu durumda gelitiricilerin karsna nemli baz sorular ve sorunlar kmaktadr. te
bunlardan bir ka;

Var olan .Net Remoting alt yaps, WCF tabanl bir hale dntrlebilir mi?
Dntrlrse ne gibi dzenlemeler yapmak gerekir?
Sfrdan WCF tabanl bir model gelitirmek yerine, .Net Remoting WCF'e g etmek mantkl
mdr?
.Net Framework 2.0 hatta 1.1 uyumlu sistemler zerine kurulmu senaryolarda, var olan
.Net Remoting uygulamalarnda yaplacak WCF dzenlemeleri geerli olacak mdr? Yoksa bu
makinelere Framework 3.0 yklenmeli midir?

Bu sorular farkl alardan bakldnda artabilir. lerleyen ksmlarda bu sorulara ve beraberinde


gelen sorunlara cevap bulmamz kolaylatracak ekilde ilerlemeye alacaz.

Windows Communication Foundation, .Net Remoting, Web Servisleri, MSMQ, Named


Pipes, WSE gibi pek ok datk mimari modelini tek bir at altnda birletirip
sunabilmesiyle n plana km bir Servis Ynelimli Mimari(Service Oriented
Architecture) alt yapsdr. Bu alt yap, nceki mimarilerde daha fazla kodlama
gerektiren yada gelitiricileri zorlayan standartlarn(rnein WS-Specifications) kolay
ve etkin bir ekilde uygulanabilmesini hatta bir arada tutulabilmesine de izin vermektedir.

Baz durumlarda almakta olan sistemi yeni bir mimariye adapte etmenin maliyeti ok yksek
olabilir. Sz gelimi lek olarak ok byk apl projelerde sistemi yeniden tasarlamak son derece

www.bsenyurt.com Page 655


sancl bir sre olabilir. Ancak byle bir durum sz konusu deilse karmzda iki alternatif
olacaktr. Var olan sistemi modifiye ederek WCF' e tamak yada sfrdan tasarlamak. Aslnda var
olan bir .Net Remoting alt yapsn bir ka kk deiiklik ile WCF' e tamak son derece kolaydr.
Hereyden nce .Net Remoting ierisinde yer alan temel paralar gz nne alarak ilerlemekte
yarar vardr.

.Net Remoting ile hazrlanm bir sistemde istemcilerin(Clients) kullanacaklar fonksiyonellikleri


barndran uzak nesneler(Remote Objects) bir sunucu(Server) uygulama zerindenClient
Activated Object yada Server Activated Object modeline uygun olacak ekilde yaynlanrlar.
Hatta SAO nesneleride Singleton veya SingleCall olarak tasarlanrlar. stemci uygulamalar
aslnda uzak nesne referanslarn kullanrken bu referanslar Marshal By Reference modeline gre
sunucu zerinde rneklenirler. Bir baka deyile istemci uzak nesneyi sanki kendi uygulama
alan(Application Domain) ierisindeymi gibi kullanrlarken, tm ilevler sunucu zerinde
gereklemektedir.

ok doal olarak burada istemci ve sunucu arasndaki mesaj trafiinin ortak bir zemine oturtulmas
arttr. Bu nedenle genellikle istemci ve sunucu uygulamalar hizmete ait nesne tasarmn ieren
artnamelerin yer ald bir arayz(Interface) tipini ortaklaa referans ederler. Bylece servis
tarafndaki fonkisyonelliklerin i yaplarnn deitirilmesi halinde istemciler zerinde yeniden
gncelleme yaplmasna gerek kalmayacaktr. Ayrca istemciler sadece arayz grebildiklerinden,
ardklar fonksiyonelliklerin i yapsn bilmeyeceklerdir ki buda servis kodunun tam olarak
istemci tarafndan grlmesini engellemektedir. Zaten WCF' in tamamen arayzlere dayal bir
sistemi nermesinin ve kullanmasnn en nemli nedenleride bunlardr.

Bu noktada gelitirici tarafndan tanmlanan seriletirilebilir tiplerinde (Serializable


Types) ortak bir snf ktphanesi(Class Library) zerinde olmas gerekmektedir.
Seriletirilebilir nesneler aslnda servis tarafnda rneklenip sadece varlklar(Entities) istemci
tarafna aktarlan rnekler olarak dnlebilir. Sz gelimi istemcinin talep ettii bir rnn,
Product isimli bir snfa ait nesne rnei olacak ekilde servis tarafnda doldurulmas ve istemciden
elde edilmesi buna rnek olarak verilebilir. Burada istemcinin talebi sonrasnda servis tarafndan
dnen veriler Product isimli snfn zellik(Property) veya alanlarnn(Fields) deerleridir.
Seriletirilebilir nesnelerin WCF mimarisinde ele alnmas ok daha kolaydr.
zellikle versiyonlamann(Versioning) WCF zerinden gerekletirilmesi daha esnektir.

Makalenin konusu .Net Remoting' den WCF' e bir iki admda tanmann nasl
salanabileceini gstermek olduundan, .Net Remoting ve WCF mimarilerinin ok geni
detaylar gz ard edilmektedir.

Artk bir rnek zerinden hareket ederek devam edebiliriz. ncelikli olarak bir .Net
Remoting uygulamasn Visual Studio 2005 zerinden gelitiriyor olacaz. lk olarak istemci ve
servis uygulamasnn ortaklaa kullanaca snf ktphanesini(Class Library) tasarlayarak ie
balanabilir. Snf ktphanesi ierisindeki tiplere ait snf diyagram(Class Diagram) ve kod
ierikleri aadaki gibidir.

www.bsenyurt.com Page 656


IProductManager arayz(Interface);

using System;

namespace AdvLibrary
{
public interface IProductManager
{
Product GetProductInfo(int productId);
}
}

rnein daha basit olarak ele alnabilmesi iin arayz(Interface) tanmlamasnda, geriye Product
tipinden nesne rnei dndrebilen ve integer tipinden bir parametre alabilen GetProductInfo isimli
bir metod bildirimi yer almaktadr.

Product snf(Class);

using System;

namespace AdvLibrary
{
[Serializable]
public class Product
{
public int Id;
public string Name;
public double ListPrice;
}
}

Product isimli snf ierisinde bir rne ait Id, Name ve ListPrice deerleri tutulmaktadr. Bununla
birlikte Product snf iin dikkat ekici en nemli zelliklerden birisideSerializable
nitelii(attribute) ile imzalanm olmasdr. Burada ak bir ekilde Product snfna ait nesne

www.bsenyurt.com Page 657


rneklerinin Marshal By Value olarak sunucudan istemciye serileerek tanabilecei garanti altna
alnmaktadr.

Servis tarafnda yer alan program, sz konusu rnekte bir Console uygulamas olarak
tasarlanmaktadr. Bu uygulamann ok doal olarak yukarda tasarlanan tipleri ieren AdvLibrary
isimli snf ktphanesini(Class Library) referans ediyor olmas gerekmektedir. Nitekim sunucu
uygulama ierisinde asl i yapan snfn uyarlayaca arayz ve kullanaca seriletirilebilir tip bu
snf ktphanesi ierisinde bulunmaktadr.

Gerek hayat senaryolarnda en ok tercih edilen .Net Remoting yntemi, sunucu


uygulamasn bir Windows Service olarak tasarlamaktadr. Bu ynetimi daha gl olan,
leklenebilir ve gvenli bir uygulama seimidir. Bunun dnda IIS(Internet
Information Services) zerinden barndrma(Host) imkanda bulunmaktadr. Dier
taraftan sunucu uygulama bir Windows uygulamas hatta bu rnekte olduu gibi bir
Console uygulamasda olabilir.

Tekrar sunucu uygulamasna dnlecek olursa, IProductManager


isimli arayz(Interface) uygulayan uzak nesne snfnn aadaki gibi tasarlanabilecei
dnlebilir.

using System;
using AdvLibrary;
using System.Data.SqlClient;

namespace ServerApp
{
public class ProductManager:MarshalByRefObject,IProductManager
{
public ProductManager()
{
Console.WriteLine("ProductManager nesnesi oluturuldu...");
}
#region IProductManager Members

public Product GetProductInfo(int productId)


{
Product prd = null;
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
using (SqlCommand cmd = new SqlCommand("Select
ProductId,Name,ListPrice,SellStartDate From Production.Product Where ProductId=@PrdId", conn))

www.bsenyurt.com Page 658


{
cmd.Parameters.AddWithValue("@PrdId",productId);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
if (reader.Read())
{
prd = new Product();
prd.Id = productId;
prd.Name = reader["Name"].ToString();
prd.ListPrice = Convert.ToDouble(reader["ListPrice"]);
}
reader.Close();
}
}
return prd;
}

#endregion
}
}

Bu snf ierisinde yer alan metod uyarlamasnda AdventureWorks isimli veritabanna gidilmekte ve
Production emasnda(Schema) yer alan Product tablosundan parametre olarak gelen ProductID
deerine sahip olan rn bilgisi geriye dndrlmektedir. Nesne oluumlarnn kolay takip
edilebilmesi amacyla ProductManager snf ierisine birde varsaylan yapc metod(Default
Constructor) ilave edilmitir. Burada dikkat edilmesi gereken nokta snfn IProductManager isimli
arayz dnda MarshalByRefObject snfndan tremi olmasdr.

Sunucu tarafndaki Remoting ayarlarn konfigurasyon bazl olarak aadaki config dosyasnda
tanmlayabiliriz.

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


<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="Tcp Server" port="4500"/>
</channels>
<service>
<wellknown mode="Singleton" type="ServerApp.ProductManager,ServerApp"
objectUri="ProductMng.rem" />
</service>
</application>
</system.runtime.remoting>
</configuration>

Konfigurasyon dosyas ierisinde tahmin edilecei zere Wellknown bir nesne tanm yaplmtr.
Bu nesne Singleton modeline gre alacaktr. Bir baka deyile tm istemcilerin talepleri ayn
uzak nesne referans zerinden karlanmaktadr. Sunucu uygulama, uzak nesne(Remote
Object) iin TCP bazl 4500 numaral portu kullanma sunmaktadr. Buradaki konfigurasyon
ayarlarnn sunucu uygulama zerinde tesis edilmesi iinde aadaki balang kodlarnn yazlmas
yeterlidir.

using System;

www.bsenyurt.com Page 659


using AdvLibrary;
using System.Runtime.Remoting;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("..\\..\\App.config",false);
Console.WriteLine("Sunucu dinlemede. Kapatmak iin bir tua basnz...");
Console.ReadLine();
}
}
}

Bu noktada unu hatrlamakta yarar vardr; sunucu uygulama alt srece istemcilerden gelecek
taleplere cevap verilebilir.

Gelelim istemci uygulamaya. Hereyden nce istemci uygulamannda arayz barndran ortak
ktphaneyi referans etmesi gerekmektedir. Dier taraftan istemci uygulamann kod ierii
aadaki gibi olabilir.

using System;
using AdvLibrary;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
IProductManager prdMng = (IProductManager)Activator.GetObject(
typeof(IProductManager), "tcp://localhost:4500/ProductMng.rem");
Product prd=prdMng.GetProductInfo(1);
Console.WriteLine(prd.Name+" "+prd.ListPrice.ToString("C2"));
Console.ReadLine();
}
}
}

Burada en kritik nokta, arayz(interface) tercihi


nedeniyle Activator snfnn GetObject metodunun kullanlmasdr. Bu metod ile aslnda ikinci
parametre ile belirtilen adresten ProductMng.rem isimli tanmlaycnn(Uniform Resource
Identifier) iaret ettii uzak nesne referans talep edilmektedir. stemciye dndrlecek olan
referansn tanabilecei tek yer IProductManager arayz olduundan da metodun dn
tipi bilinli(Explicit) olarak evrilmektedir. Buraya kadar yaplan hazrlklar sonucunda test ilemi
yaplrsa aadakine benzer ktlar elde edilir.

www.bsenyurt.com Page 660


Grld gibi istemciler baarl bir ekilde sunucu zerinden taleplerini
karlayabilmektedirler. (Burada oluturulan sistemin dzgn altnn kontrol edilmesi iin
sunucu uygulama altrlmadan bir istemcinin altrlmas denenebilir. Eer gerekten sunucu
zerindeki nesne kullanlmaya allyorsa alma zamannda istemci tarafnda "No Connection
Could Be Made, Becouse the Target Machine Actively Refused It..." hatas alnr.)

Buraya kadar anlatlanlar basit olarak bir .Net Remoting uygulamasnn alt yapsn
zetlemektedir. Aadaki ekil zerinden, yaplanlar ve sonular tartlabilir.

www.bsenyurt.com Page 661


ekilde .Net Remoting ierisinde 50000 metre yukardan bakldnda gze arpan etkenler
betimlenmeye allmtr. imdi bu sistemi Windows Communication Foundation alt yapsna
tamaya alyor olacaz.

lk yaplmas gereken servis tarafnda sunulmak istenen fonksiyonellikleri tanmlayacak bir


szleme(Contract) oluturmaktr. Burada sz konusu olan servis szlemesi(Service
Contract) bir arayze rahatlkla uygulanabilir. Tek yaplmas
gereken System.ServiceModel.dll isimli .Net Framework 3.0 assembly' nn referans edilmesi
ve ServiceContract ileOperationContract niteliklerinin(attributes) kullanlmasdr. Aadaki
ekilde Visual Studio 2005 zerinden sz konusu assembly' n referans edilii grlmektedir.

Bu ilemin ardndan IProductManager isimli arayzn yaps aadaki gibi deitirilmelidir.

using System;
using System.ServiceModel;

namespace AdvLibrary
{
[ServiceContract]
public interface IProductManager
{
[OperationContract]
Product GetProductInfo(int productId);
}
}

www.bsenyurt.com Page 662


Bu deiiklik arayzn Windows Communication Foundation uyumlu bir servi
szlemesi(Service Contract) olmas iin yeterlidir. ServiceContract nitelii ile tanmlanan
servis szlemesi ierisinden darya sunulabilecek fonksiyonelliklerin
tamam OperationContract nitelii(attribute) ile imzalanmaldr. Yaplan bu deiiklik her ne
kadar ortak ktphane ierisinde olsada sonu itibariyle tm istemcilere gerekli assembly' n
yeniden datlmas gerekmektedir. Ama zaten bu gz nne alnmas gereken bir aamadr.

Gelelim sunucu tarafna. Sunucu tarafndada ok doal olarak yaplmas gereken baz ilemler
vardr. Hereyden nce konfigurasyon ieriinin WCF mimarisine uyumlu olacak ekilde
deitirilmesi gerekmektedir. Bu amala sunucu uygulama tarafndaki App.config dosyasnn
ierii aadaki gibi yenilenmelidir.

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


<configuration>
<!--<system.runtime.remoting>
<application>
<channels>
<channel ref="Tcp Server" port="4500"/>
</channels>
<service>
<wellknown mode="Singleton" type="ServerApp.ProductManager,ServerApp"
objectUri="ProductMng.rem" />
</service>
</application>
</system.runtime.remoting>-->
<system.serviceModel>
<services>
<service name="ServerApp.ProductManager">
<endpoint address="net.tcp://localhost:4500/ProductMng"
binding="netTcpBinding" contract="AdvLibrary.IProductManager" />
</service>
</services>
</system.serviceModel>
</configuration>

Windows Communication Foundation(WCF) mimarisinde servis iin belkide en nemli


kavram EndPoint' dir. EndPoint ierisinde WCF mimarisinin ABC' si yer
almaktadr.AddressBindingConfiguration yardmyla servisin hangi lokasyondan, hangi protokol
ile, hangi nesneyi nasl ve ne ekilde sunduu belirtilmektedir. .Net Remoting bazl gelitirilen
rnekte TCP bazl ve Binary seriletirme yapan bir sistem kullanldndan bu zellikleri
bnyesinde barndran bir tipin WCF tarafnda ele alnmas gerekmektedir. Bu
iiNetTcpBinding isimli snf stlenmektedir. Bu ayn zamanda balayc tiptir(Binding
Type). Contract bilgisi ile tahmin edilecei zere servisin d ortama sunduu szleme ve
operasyonlar belirtilmektedir. Son olarak Address bilgisi ile servis zerinde sunulan nesneye hangi
adres zerinden eriilebilecei belirtilmektedir.

WCF mimarisinde bir servis birden fazla EndPoint sunabilir. Bu gelitiricilere senaryoya
gre birden fazla balayc tipin(Binding Type) ve dolaysyla imkann sunulabildii bir
ortam hazrlayacaktr. Sz gelimi bir servis uygulamas WCF' e gre
yazldnda, MSMQ, TCP, HTTPS zerinden vb... hizmet verebilecek mesaj
seviyesinde(Message Level) yada iletiim seviyesinde(Transport Level) korumal
hizmetleri sunabilir. stelik bunlar iin ayr ayr uygulama eitleri tasarlanmasna gerek
kalmaz. Bir baka deyile bu tip bir senaryo iin ayr bir .Net Remoting,
Xml Web Service veya MSMQ uygulamas yazlmasna gerek yoktur. te WCF' in
birletirici rolnn nemi burada belirgin bir biimde ortaya kmaktadr.

www.bsenyurt.com Page 663


Elbetteki sunucu uygulamann kodlarnda aadaki gibi deitirmek gerekmektedir.
Artk ServiceHost isimli snf balatc rol stlenmektedir.

using System;
using AdvLibrary;
//using System.Runtime.Remoting;
using System.ServiceModel;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
//RemotingConfiguration.Configure("..\\..\\App.config",false);
ServiceHost host = new ServiceHost(typeof(ProductManager));
host.Open();
Console.WriteLine("Sunucu dinlemede. Kapatmak iin bir tua basnz...");
Console.ReadLine();
host.Close();
}
}
}

rnek koda gre ServiceHost nesne rnei, ProductManager isimli snf uzak nesne olarak
hizmete amaktadr. Open metoduna yaplan ardan sonra, sunucu uygulama istemciden gelecek
olan talepleri dinleyecek konuma gelmektedir. Close metoduna yaplan ar sonrasnda ise servis
kapatlmaktadr. Elbette ServiceHost snfnn kullanlabilmesi
iin System.ServiceModel.dll assembly' nn sunucu uygulama tarafnada referans edilmesi
gerekmektedir.

Peki istemci tarafnda neler yaplmaldr? Hereyden nce istemci tarafnda gerekli ayarlarn
konfigurasyon bazl olacak ekilde gelitirilmesi nerilmektedir. Bu amala istemci tarafna
eklenecek olan bir konfigurasyon dosyasnn ierii, rnee gre aadaki gibi tasarlanabilir.

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


<configuration>
<system.serviceModel>
<client>
<endpoint name="ProductMng"
address="net.tcp://localhost:4500/ProductMng" binding="netTcpBinding"
contract="AdvLibrary.IProductManager"/>
</client>
</system.serviceModel>
</configuration>

Konfigurasyon ieriine bakldnda dikkat edilecei zere yine bir EndPoint tanmlamas
yaplmaktadr. Bu EndPoint aslnda istemcinin balant kuraca servis tarafndaki noktay
tanmlamaktadr. stemci tarafndaki kod ierii ise aadaki gibi gelitirilebilir.

using System;
using AdvLibrary;
using System.ServiceModel;

www.bsenyurt.com Page 664


namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
//IProductManager prdMng =
(IProductManager)Activator.GetObject(typeof(IProductManager),
"tcp://localhost:4500/ProductMng.rem");
//Product prd=prdMng.GetProductInfo(1);

ChannelFactory<IProductManager> chn = new


ChannelFactory<IProductManager>("ProductMng");
IProductManager prdMng=chn.CreateChannel();
Product prd = prdMng.GetProductInfo(1);
Console.WriteLine(prd.Name+" "+prd.ListPrice.ToString("C2"));
Console.ReadLine();
}
}
}

ChannelFactory nesne retimi iin gerekli bilgileri, parametre olarak verilen deere gre
konfigurasyon dosyasndan almaktadr. Bylece servis tarafndaki hangi EndPoint ile
konuabileceini bilmektedir. CreateChannel metodu nceden hazrlanan ayarlara gre, servis
taraf ile konuacak olan kanal nesnesini rneklemektedir. Akas CreateChannel metodunun
sonucu .Net Remoting iin kullanlan Activator.GetObject metodunun rettiine benzerdir.
Nitekim aadaki ekran grntsnden de anlalaca
zereCreateChannel metoduda Transparent bir Proxy retmektedir. Bu Proxy, alma
zamannda servis zerindeki EndPoint ile haberlemektedir.

ok doal olarak proxy nesnesinin retilmesinde de


kullanlan ChannelFactory snf System.ServiceModel isim alan(Namespace) altndadr. Bu
nedenle sz konusu isim alann ieren assembly' n istemci uygulamayada referans edilmesi
gerekmektedir.

Artk var olan .Net Remoting uygulamas bu bir ka adm ile WCF formatna evrilmitir.
Uygulamalar test edildiinde aadakine benzer sonular alnacaktr.

www.bsenyurt.com Page 665


Elbetteki servisin ve operasyonlarn davranlar WCF mimarisi ierisinde ok daha geni bir ekilde
ele alnmaktadr. rnekte bunlara gerek kalmadanda WCF' e geilebilecei gsterilmektedir. Ancak
ele alnmas gereken baka noktalarda olabilir.

rnein her istemci iin birer uzak nesne referans sunucu zerinde oluturulmaktadr. Oysaki
tasarlanan .Net Remoting alt yapsnda Singleton modeli benimsenmitir. Bir baka deyile her
istemci talebi(Request) ayn uzak nesne rnei zerinden karlanmaktadr. WCF tarafnda bu,
servis tarafnda sunulan uzak nesnenin bir alma zaman(run-time) davrandr(Behavior).
Dolaysyla bu davrann bir nitelik(attribute) yardmyla belirlenmesi yada konfigurasyon
ieriinde tanmlanmas gerekmektedir. Bu sebepten rnekte yer alan ProductManager snf
banda ServiceBehavior niteliinin(attribute) aadaki gibi kullanlmas gerekir.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class ProductManager:MarshalByRefObject,IProductManager

InstanceContextMode enum sabitinin Single olarak belirlenen deeri rnekte ele alnan
senrayoya uygun olacak ekilde uzak nesne referanslarnn oluturulmasn salamaktadr. Bunun
sonucunda alma zamanndaki durum aadaki gibi olacaktr.

www.bsenyurt.com Page 666


Bunun dnda binary olarak seriletirilebilen Product snf iin herhangibir ekstra alma
yaplmad ortadadr. Nitekim byle bir alma yaplmasna gerek kalmamtr.
Fakat versiyonlama yapld durumlarda WCF mimarisi .Net Remoting' e gre daha efektif bir
zm sunmaktadr.

Burada versiyonlamann(Versioning) nasl sorunlar yaatabileceini anlamak nemlidir. Sz


gelimi Product isimli seriletirilebilir snfn sonradan yazlan ikinci bir versiyonu olduu ve bu
versiyonda iin ierisine SellStartDate isimli yeni bir alan(Field) katld gz nne alnsn. Eski
Product snfn kullanan istemcilerin sorunsuz olarak onunla almaya devam etmelerini, yeni
versiyonu kullananlarn ise yeni eklenen alan ele alabilmelerini salamak iin kuvvetle muhtemel
tasarm aadaki gibi deitirmek gerekecektir.

using System;
using System.Runtime.Serialization;

namespace AdvLibrary
{
[Serializable]
public class Product:ISerializable
{
public int Id;
public string Name;
public double ListPrice;
public DateTime SellStartDate; // Yeni versiyonlar iin eklenen alan.

public Product()
{

public Product(SerializationInfo info, StreamingContext context)


{
Id = info.GetInt32("Id");
Name = info.GetString("Name");
ListPrice = info.GetDouble("ListPrice");
// Versiyonlama nedeni ile oluabilecek hatalar grmezden gelmek iin bir try...catch
try

www.bsenyurt.com Page 667


{
SellStartDate = info.GetDateTime("SellStartDate");
}
catch
{
}
}

#region ISerializable Members

public void GetObjectData(SerializationInfo info, StreamingContext context)


{
info.AddValue("Id", Id);
info.AddValue("Name", Name);
info.AddValue("ListPrice", ListPrice);
info.AddValue("SellStartDate", SellStartDate); // Yeni versiyon iin ekenen kod
satr
}

#endregion
}
}

Burada dikkat edilecek olursa seriletirme


ilemleri ISerializable arayznn(Interface) kullanlmasyla zelletirilerek, deerlerin
aktarm kontroll bir hale getirilmektedir. zelletirme iin ISerializable arayznn uygulanmas
haricinde yapc metodun(Constructor) ar yklenmi(Overload) bir versiyonuda ele alnmaktadr.
Sorunun detaylar ok nemli olmamakla birlikte Windows Communication Foundation ierisinde bu
tip versiyonlamalarnda kontrol edilebilmesi son derece kolaydr. Tek yaplmas gereken aadaki
gibi Product snfn bir veri szlemesi(Data Contract) haline getirmektir.

using System;
using System.Runtime.Serialization;

namespace AdvLibrary
{
[DataContract]
public class Product
{
[DataMember(IsRequired=true)] // Mutlaka olmal
public int Id;

[DataMember(IsRequired = true)] // Mutlaka olmal


public string Name;

[DataMember(IsRequired = true)] // Mutlaka olmal


public double ListPrice;

[DataMember] // Opsiyonel oldu.


public DateTime SellStartDate; // Yeni versiyonlar iin eklenen alan.
}
}

DataMember nitelii(attribute) varsaylan olarak uyguland yeye opsiyonel bir davran


getirmektedir. Bir baka deyile alma zamannda kara tarafn bu alan iermeyen bir tipi

www.bsenyurt.com Page 668


kullanmas halinde hi bir problem olumayacak ve bu alan grmezden gelinecektir. Tam tersine bu
alan kullanan bir versiyon varsa SellStartDate alanda hesaba katlacaktr. Bu sayede
versiyonlamada ok kolay bir ekilde ele alnabilmektedir. Product snfnn tasarlanmasnda dikkat
edilmesi gereken nemli bir nokta vardr. Buna
greDataContract ve DataMember niteliklerinin(attributes) tanmlandklar isim
alan(Namespace), System.Runtime.Serialization.dll assembly' ierisindedir. Dolaysyla snf
ktphanesine bu assembly' n aadaki ekran grntsnde olduu gibi referans edilmesi
gerekmektedir.

Son olarak ele alnmas gereken bir durum daha olabilir. stemci ve servis tarafnn .Net
Framework 2.0 ykl sistemler olduu gz nne alndnda yaplan son deiikliker sonrasnda
uygulamalar sorunsuz bir ekilde alabilecek midir?( Burada iyimser bir yaklam gdlerek .Net
Framework 1.1 versiyonu hi hesaba katlmamtr.)

Yukardaki referans ekleme ksmnda dikkat eken noktalardan biriside Framework


3.0 iin gelitirilmi pek ok assembly' n alma zamannda(Run Time)
v2.0.50727 versiyonuna ihtiya duymasdr. Bir baka
deyile System.ServiceModel veya System.Runtime.Serialization gibi 3.0 assembly'
lar, .Net Framework 2.0ykl bir makinede bellee yklenip alabilirler. Nitekim
ihtiyalar olan v2.0.50727 versiyonlu Common Language Runtime(CLR)' dr.

Aslnda sistemler zerinde .Net Framework 3.0' n ykl olmas sorunun zm iin yeterlidir.
Lakin sadece .Net Framework 2.0 ykl olan bir sistemde deitirilen uygulamalar altrlabilirse,
bir .Net Framework 3.0 ykleme derdinden kurtulunabilinir. Ancak bunun bir dert olup olmadda
tartlmas gereken bir vakadr.

Sz konusu durumu test etmek iin servis veya istemci uygulamalar, zerinde .Net Framework
2.0 ykl olan bir sistemde, System.ServiceModel.dll veSystem.Runtime.Serialization.dll
assembly' larnda kopyalayarak altrmak yeterli olacaktr. Balangta servis ve istemci
tarafnda var olmas dnlen exe, config ve dll dosyalar aadaki gibidir.

www.bsenyurt.com Page 669


Ne yazkki buradaki dll' lerin hedef bilgisayara(bilgisayarlara) tanmalar yeterli
olmamaktadr. .Net Framework 2.0 ykl makinede rnek olarak ServerApp uygulamas
altrldnda aadaki ekran grntsnde yer alan hata ile karlalabilir.

Bunun zerine SMDiagnostics.dll isimli assembly' nda hedef


bilgisayarda ServerApp ve ClientApp program dosyalarnn olduu yere konmas gerekir. Sz
konusu assembly hedef programlarn bulunduu lokasyona tandktan sonra bir deneme daha
yaplrsa aadakine benzer bir hata mesaj ile daha karlalabilinir.

www.bsenyurt.com Page 670


Bu hatann olumasnn en byk nedeni, programn alt makine zerinde .Net Framework
3.0 ykl olmad iin, machine.config' de olmas gereken baz ayarlarn bulunmayndan
kaynaklanmaktadr. Bu nedenle ServiceModelReg aracnn kullanlarak gerekli konfigurasyon
bilgilerinin hedef makineye yklenmesi gerekecektir. Bu sebepten komut satrndan aadaki gibi
bir alma yaplmaldr.

Bu almann ardndan hedef bilgisayarda yer alan konfigurasyon dosyas iin gerekli Handler ve
Module yklemeleri gerekletirilecektir. Artk herey halloldu diye dnlebilir ama bu seferde
ServerApp uygulamas altrldnda aadakine benzer bir hata mesaj daha alnabilir.

www.bsenyurt.com Page 671


ok doal olarak System.IdentityModel.dll' ininde kopyalanm olmas gerekecektir. Bu hata
beraberinde System.IdentityModel.Selectors.dll isimli assembly' nda yklenmesini
gerektirmektedir. Her iki assembly yklensede bu
kez dorulama(Authentication) ve yetkilendirme(Authorization) problemleri olumaktadr.
Bunlarn zm adna config dosyalarnda gerekli dzenlemele yaplabilir. Yinede bu sancl sre
hemen zmlenemeyecektir. Yaznn ilerleyen ksmlarnda konunun daha fazla dalmamas adna
bu yntemler gz ard edilmitir.

Sonu olarak her ne kadar .Net Remoting' den Windows Communication Foundation tarafna
gei yapmak kolay olsada, gerek alma ortamnda zellikle .Net Framework 2.0ykl
sistemlerde baz ayarlamalarn yaplmas gerekmektedir. Bu durum .Net Framework 1.1 ykl
makinelerde tam bir kabus haline gelebilir. Nitekim kopyalanan dll' lerin bazlar CLR
1.1 versiyonunda almayacaktr. Bu nedenle .Net Framework 3.0' n Redistruable paketinin
hedef sistemlere yklenerek almalara devam edilmesi doru bir davran olacaktr. Hatta
istemciler iin bir setup paketinin hazrlanmas ve gerekliliklerden birisi olarak .Net Framework 3.0
seiminin eklenmesi ok yerinde bir davrantr. O halde cevaplanmas gereken bir soru daha
vardr. Bu kadar zahmete girilecekse, sistemin WCF iin yeninde yazlmas yoluna gidilemez midir?
Aslnda bu sorunun cevab daha nceden tasarlanp kullanllmakta olan .Net Remoting sistemine
baldr. Eer yazlan ok fazla kod ve birbirlerine bal para var ise, bir iki dzenleme ile WCF' e
uyumlu bir sistem oluturmak son derece kolaydr.

Bu noktalarda vakay doru deerlendirip karar vermekte ve gerekirse cevap iin profesyonel
destek almakta yarar olabilir.Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - MTOM ve Stream Kullanarak Veri


Aktarm ( 26.11.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Gnmzde resim,ses, video, dokman formatnda kaynaklarn youn olarak kullanld pek ok
sistem bulunmaktadr. Sz gelimi ierik ynetim sistemleri(Content Management
Systems) neredeyse srf bu tip verilerin kullanlmas zerine kurulmutur. Resim, ses, video
formatndaki veri kaynaklarnn oluturduu en byk problem ise boyutlarnn sz konusu
sistemlerde ne kadar etkin bir ekilde leklenebildiidir. Byk boyutlu dosyalar eitli amalarla
kullanlabilirler. rnein bir irketin tm dkmantasyon alt yaps bu tip byk byk dosyalar
zerine kurulu olabilir. Yada retim sektrnde grev alan bir firmann teknik
izimleri ikili(binary) formatta olacak ekilde veritaban zerinde saklanyor olabilir. Bu tarz
verilerin(ister dosyalarda ister veritaban alanlarnda saklanyor olsunlar) ayn bilgisayarda
kullanld uygulamalarda boyutlarn artmas ok fazla problem tekil etmeyebilir. Ancak iin
ierisine istemci-sunucu(Client-Server) tabanl bir ortam girdiinde boyutlarn artmas
zellikle a(Network)zerindeki trafie olumsuz etkiler yanstmaktadr. Dolaysyla farkl
makinelerde koan uygulamalarn arasnda bu tip byk boyutlu verilerin aktarmnda dikkat
edilmesi gereken baz nemli noktalar vardr.

Servis ynelimli mimari(Service Oriented Architecture) uygulamalarn gelitirilmesinde


kullanlan baz platformalar, istemci(Client) ve servisler(Service) arasnda resim, ses, video gibi
yksek boyutlu ieriklere sahip olabilecek verilerin tanmas amacyla ounlukla MTOM(Message

www.bsenyurt.com Page 672


Transimision Optimization Mechanism) standardn kullanrlar. WC3 tarafndan kabul edilmi
bu standarda gre ikili(binary) formattaki verilerin aktarlmas daha performansldr. Windows
Communication Foundation mimarisi de, mesajlarn MTOM ile tanabilmesine olanak
salamaktadr.

Normal artlarda HTTP zerinden hizmet veren herhangibir servis ierisindeki metodlarn
parametrik yaps ve dn tipine bakldnda, istemci ve servis arasnda hareket
edenSOAP(Simple Object Access Protocol) paketlerinin ikili formattaki verileri text formatna
kodland grlr. ok doal olarak bu kodlama(encoding) ilemleri servis tarafna ek bir yk
getirmektedir. Ayn yk istemciye ulaan mesajn ieriindeki text tabanl bilginin
tekrar zmlenerek(decoding) orjinal ikili formattaki haline getirilmesi iinde sz konusudr.
Buradaki metodun yaps gerei sahip olduu saysal nitelikteki ikili deerleri text olarak
kodlamalas(encoding) ok byk problem deildir. Ne varki bir resim dosyasnn bu ekilde ele
alnmas halinde boyutun artmas, kodlama(encoding) ileminin uzamas ve zaman almas
anlamnada gelmektedir. Burada ikili formattaki veri ieriinin text formatl olmas yerine 1 ve 0'
lardan oluacak ekilde kodlanmas gz nne alnabilir. Ancak bu durumdada milyonlarca 1 ve 0'
dan ibaret bir veri ynnn olumasda kanlmazdr.

WCF(Windows Communication Foundation) mimarisinde servis tarafndaki metodlar


varsaylan olarak Base64 tabanl olacak ekilde bir kodlama(encoding) ve zmleme(decoding)
ilemine tabi tutulurlar. Bu ilem sayesinde ikili (binary) formattaki verinin daha az yer tutmas
salanabilir. Ne varki Microsoft kaynaklarnn belirttiine gre, bu kodlama orjinal veri boyutunu
yaklak olarak %140 orannda da arttrmaktadr. te MTOM(Message Transmision
Optimization Mechanism) tabanl mesajlama ile veri
ieriininkodlama(encoding) ve zmleme(decoding) ilemine gerek kalmadan taraflar
arasnda tanabilmesi salanmaktadr. Bunun en byk nedeni MTOM' un ikili formattaki veri
ieriini orjinal mesaja bir ek(Attachment) olacak ekilde tatmasdr. Aadaki ekilde bu
durum biraz daha net bir ekilde ifade edilmektedir.

ekilde dikkat edilecei zere, binary formattaki ierik bozulmadan bir MIME(Multipurpose
Internet Mail Extension) paketi ierisine alnmaktadr. Kalan ierik yine bozulmadan text tabanl
olacak ekilde SOAP Zarf(Envelope) halinde MIME Mesaj ierisine aktarlr. SOAP
gvdesinde(Body) artk MIME mesajna ilave edilen binary ieriin referans tutulmaktadr.

www.bsenyurt.com Page 673


Bylece servis veya istemi tarafnda, binary ieriin text formatna kodlanmas(ve tam tersinin
yaplmas) ilemleri ortadan kalkmaktadr. Buda ok doal olarak mesajlarn hazrlanma, gnderme
ve ilenme srelerinin inanlmaz derecede azalmas anlamna gelmektedir.

MTOM(Message Transmision Optimization Mechanism) tabanl mesajlarn


gvenliinde imzalar(signature) kullanlr. WCF bu imzalar kontrol ederek alnan veya
gnderilen MIME ieriindeki eklerin(attachments) bozulup bozulmadn anlayabilir ve
buna gre uygun alma zaman istisnalarn frlatabilir.

Windows Communication Foundation mimarisinde HTTP bazl olan balayc tiplerin


tamam MTOM tipinde mesajlamay desteklemektedir. Ne varki TCP, MSMQ gibi protokoller
zerinde alan balayc tiplerin(Binding Type) bu tip bir destei yoktur. Bunun en byk
sebebi ise, bu protokollerin ikili(binary) formattaki veriler iin kendi standartlarn kullanyor
olmalardr. Ancak daha ncedende deinildii gibi, zel balayc tipler(Custom Binding
Types) gelitirilerek TCP gibi bir protokol zerinde MTOM kullanm teorik olarak
salanabilmektedir. Aadaki tabloda MTOM tipinde mesajlamaya destek veren(vermeyen)
balayc tipler iaret edilmektedir.

Mesaj Kodlama/zmleme Tipleri


Balayc Tip
(Message Encoding/Decoding
(Binding Types)
Types)

BasicHttpBinding Text / MTOM

NetTcpBinding Binary

NetPeerTcpBinding Binary

NetNamedPipeBinding Binary

WSHttpBinding Text / MTOM

WSFederationBinding Text / MTOM

NetMsmqBinding Binary

MsmqIntegrationBinding Binary

WSDualHttpBinding Text / MTOM

Konuyu daha iyi anlayabilmek iin rnek bir senaryo zerinden hareket etmekte fayda vardr. Bu
amala AdventureWorks veritabannda yer alan rnlere ait fotoraflarn
tutulduuProductPhoto tablosundan yararlanlabilir. Sz konusu tabloda varBinary(MAX) SQL
tipinden LargePhoto isimli bir alan yer almaktadr. lerleyen rnekte LargePhoto isimli alann
ieriinin MTOM ve Stream bazl olacak ekilde istemci tarafna aktarlmas zerinde durulacaktr.
Senaryoda gz nne alnacak tablolar aadaki veritaban diagramnda(Database
Diagram) olduu gibidir. ncelikli olarak en azndan istemciye rn ad ve fotoraf numaras
bilgilerinin gnderilmesinde yarar vardr. Sonrasnda istemcinin setii rne ait fotorafn binary
ierii servis tarafndan geriye doru aktarlacaktr.

www.bsenyurt.com Page 674


Servis tarafndaki uygulamann istemciye rn listesini ve setii rne ait resmi veren
fonksiyonellikler ierdii dnlebilir. Bu fonksiyonellikleri ieren servis snf ve yeleri her
zamanki gibi bir WCF Servis Ktphanesi(WCF Servis Library) olacak ekilde aadaki gibi
tasarlanabilir. Sz konusu ktphane ierisinde yer alacak temel tiplerin snf diagramndaki(Class
Diagram) grnts ise aadaki gibidir.

www.bsenyurt.com Page 675


rnekte rnlere ait fotoraf bilgilerinin istemciye tanmas iin ProductInfo isimli bir snftan
yararlanlmaktadr. Bu snfn ierii aadaki gibidir.

using System;
using System.Collections.Generic;
using System.Runtime.Serialization;

namespace ProductPhotoServiceLibrary
{
[DataContract]
public class ProductInfo
{
private int _productPhotoId;
private string _name;

[DataMember]
public string Name
{
get { return _name; }
set { _name = value; }
}

[DataMember]
public int ProductPhotoId
{
get { return _productPhotoId; }
set { _productPhotoId = value; }
}

public ProductInfo(int productId, string name)


{
ProductPhotoId = productId;
Name = name;
}
}
}

Bu snfta dikkat edilmesi gereken nokta, bir veri szlemesi(Data Contract) tanmlyor
olmasdr. Bu nedenle snf(Class)
DataContract, zellikleri(Properties) iseDataMember nitelikleri ile imzalanmtr. Servis
szlemesi(Service Contract) ierii aadaki gibidir.

using System;
using System.ServiceModel;
using System.Collections.Generic;

namespace ProductPhotoServiceLibrary
{
[ServiceContract(Name="Photo
Service",Namespace="http://www.bsenyurt.com/ProductPhotoService")]
public interface IPhotoService
{
[OperationContract(IsInitiating=true)]
List<ProductInfo> GetProducts();

www.bsenyurt.com Page 676


[OperationContract]
byte[] GetPhotoByProductId(int productPhotoId);
}
}

Arayzn uyguland PhotoService snfnn ierii ise aadaki gibidir.

using System;
using System.Data.SqlClient;
using System.Collections.Generic;

namespace ProductPhotoServiceLibrary
{
public class PhotoService : IPhotoService
{
string conStr = "data source=.;database=AdventureWorks;integrated security=SSPI";

#region IPhotoService Members

// stemci iin gerekli olan rn adlar ve fotoraf numaralar, generic bir List koleksiyonu ile
geriye dndrlmektedir.
public List<ProductInfo> GetProducts()
{
// Generic List koleksiyonu oluturulur
List<ProductInfo> infos = new List<ProductInfo>();

using (SqlConnection conn = new SqlConnection(conStr))


{
// Sql sorgusunda Join kullanlmasnn sebebi ProductPhotoId deerleri ve Name
alanlarnn deerlerinin elde edilmesidir.
using (SqlCommand cmd = new SqlCommand("Select PP.ProductPhotoId,[Name] From
Production.Product P Join Production.ProductProductPhoto PP on P.ProductId=PP.ProductID",
conn))
{
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
// Elde edilen her bir satr iin ProductInfo snfna ait bir nesne rneklenip generic
koleksiyona eklenir.
infos.Add(new ProductInfo(Convert.ToInt16(reader[0]),
reader[1].ToString()));
}
reader.Close();
}
}
return infos;
}

// Belirli bir fotoraf numarasna sahip olan LargePhoto alannn ierii byte dizisi olacak
ekilde geri dndrlr.
public byte[] GetPhotoByProductId(int productPhotoId)
{
byte[] photoContent = null;

www.bsenyurt.com Page 677


using (SqlConnection conn = new SqlConnection(conStr))
{
using (SqlCommand cmd = new SqlCommand("Select LargePhoto From
Production.ProductPhoto Where ProductPhotoId=@PId", conn))
{
cmd.Parameters.AddWithValue("@PId", productPhotoId);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
// Burada GetSqlBytes metodu ilgili alann ieriinin binary olarak byte dizisine
aktarlmasnda yardmc rol oynamaktadr.
if (reader.Read())
photoContent = reader.GetSqlBytes(0).Value;
reader.Close();
}
}

return photoContent;
}

#endregion
}
}

PhotoService isimli snf u an iin iki adet metoda sahiptir. GetProducts isimli metod basit
olarak geriye ProductInfo tipinden nesne rneklerinden oluan generic bir List<> koleksiyonu
dndrmektedir. GetPhotoByProductId metodu geriye byte[] tipinden bir dizi dndrmektedir.
Bu dizi tahmin edilecei zere tabloda varbinary(MAX) tipinden olan LargePhoto isimli alann
ieriini tamaktadr.

Binary dosyann boyutunun ok byk olmas halinde paral olacak ekilde veri
ieriinin toplanmas gz nne alnabilir. Yaplmas gereken servis tarafndaki
fonksiyonellik ierisinde resim ieriini veritaban tablosunda paral olacak ekilde
okuyup toparlamaktr.

imdilik servis taraf MTOM(Message Transmision Optimization Mechanism) format


yerine Text formatnda mesaj kodlamas yapmaktadr. Olayn daha net analiz edilmesi amacylada
gerekli Diagnostics seenekleri aktif hale getirilmektedir. Servis tarafnn ierii basit olarak
aadaki gibidir. (Servis IIS zerinde host edilecek ekilde tasarlanmaktadr.)

Service.svc;

<%@ ServiceHost Language="C#"


Debug="true" Service="ProductPhotoServiceLibrary.PhotoService" %>

Servis(Service) tarafnda mesajlama ile ilikili olan ierii izleyebilmek


adna Diagnostics zellikleri almtr. Buna gre web.config dosyasnn ierii aadaki gibidir.

web.config;

<?xml version="1.0"?>
<configuration>
<system.diagnostics>
<sources>

www.bsenyurt.com Page 678


<source name="System.ServiceModel.MessageLogging"
switchValue="Verbose,ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
<source name="System.ServiceModel" switchValue="Verbose,ActivityTracing"
propagateActivity="true">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="ServiceModelTraceListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="C:\inetpub\wwwroot\AdventureProductService\
web_messages.svclog" type="System.Diagnostics.XmlWriterTraceListener, System,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
<add initializeData="C:\inetpub\wwwroot\AdventureProductService\
web_tracelog.svclog" type="System.Diagnostics.XmlWriterTraceListener, System,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelTraceListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true">
</compilation>
<authentication mode="Windows" />
</system.web>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="PhotoServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="true"

www.bsenyurt.com Page 679


logMessagesAtTransportLevel="true" />
</diagnostics>
<services>
<service behaviorConfiguration="PhotoServiceBehavior"
name="ProductPhotoServiceLibrary.PhotoService">
<endpoint address="http://localhost/AdventureProductService/Service.svc"
binding="basicHttpBinding" bindingConfiguration="" name="ProductPhotoHttpEndPoint"
contract="ProductPhotoServiceLibrary.IPhotoService" />
</service>
</services>
</system.serviceModel>
</configuration>

Servis taraf basicHttpBinding balayc tipini kullanan bir EndPoint sunmaktadr. Bununla
birlikte istemcilerin HTTP zerinden proxy snflarn elde edebilmeleri
iin metaDataPublishing etkin klnmtr. Mesajlarn ieriinin daha detayl bir ekilde analiz
edilebilmesi amacyla Tracing ve Message Logging zellikleri aktif hale getirilmitir. Bu ayarlar
elbetteki Microsoft Service Configuration Editor yardmyla belirlenmek istenirse aadaki
admlar takip edilebilir.

ncelikli olarak Enable MessageLoging ve Enable Tracing tklanarak aktif hale getirilir.

Sonrasnda ise Diagnostics altndaki Message Logging klasrne tklandktan sonra zellikler
penceresinden LogEntireMessage deeri true olarak ayarlanmaldr.

www.bsenyurt.com Page 680


Sources klasr altnda yer
alan System.ServiceModel.MessageLogging ve System.ServiceModel elementlerinin Trace
Level zelliklerine Verbose deeri atanmaldr. Bylece mesaj aktivitelerin en ince ayrntsna
kadar izlenmesi olanakl hale gelecektir.

www.bsenyurt.com Page 681


Gelelim istemci tarafna. stemci program basit bir Windows uygulamas olarak tasarlanabilir.
Programn arayz ve kodlarnn ierii aadaki gibidir.

(Servis tarafna ait Proxy snfnn oluturulmas iin Add Service Reference seenei
kullanlmaldr.)

Add Service Reference sonras otomatik olarak bir App.config dosyas oluturulacak ve ierisine
balang deerleri atanacaktr.

Windows uygulamasna ait kodlar ise aadaki gibidir.

using System;
using System.IO;
using System.Text;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.ComponentModel;
using Istemci.AdventureService;
using System.Collections.Generic;

namespace Istemci
{
public partial class Form1 : Form
{
PhotoServiceClient client = null;

public Form1()
{
InitializeComponent();
client = new PhotoServiceClient();
}

private void button1_Click(object sender, EventArgs e)


{

www.bsenyurt.com Page 682


// Servis tarafndaki GetProducts metodu ile ProductInfo tipinden dizi elde edilir ve her bir
eleman listBox1 isimli ListBox kontrolne eklenir.
ProductInfo[] infos=client.GetProducts();
foreach (ProductInfo info in infos)
listBox1.Items.Add(info);
}

private void listBox1_SelectedIndexChanged(object sender, EventArgs e)


{
short photoId = 0;
// Seilen ListBox eleman ProductInfo tipine dntrldkten sonra ProductPhotoId
zelliinin deeri elde edilir.
Int16.TryParse(((ProductInfo)listBox1.SelectedItem).ProductPhotoId.ToString()
, out photoId);
// GetPhotoByProductId metoduna photoId deeri aktarlarak byte[] dizisi elde edilir ve bir
MemoryStream nesnesi rneklenir.
MemoryStream stream=new
MemoryStream(client.GetPhotoByProductId(photoId));
// MemoryStream rneinden yararlanlarak Image nesnesi oluturulur ve PictureBox
kontrolnn Image zelliine atanr.
pictureBox1.Image=Image.FromStream(stream);
}
}
}

Burada dikkat edilmesi gereken birka nokta vardr. GetProducts metodu


geriye List<ProductInfo> tipinden bir generic koleksiyon yerine ProductInfo tipinden bir dizi
dndrmektedir. Dier taraftan istemci bir Windows uygulamas olduundan ComboBox kontrol
ierisine dizi dorudan balanamaz. Bir baka deyile DataSource zelliini burada kullanmak
yeterli olmayacaktr. Bu nedenle ProductInfo tipinden dizi ierisindeki elemanlarn tek tek
dolalmas ve e olarak eklenmesi gerekmektedir. Ancak bu durumdada ListBox ierisinde rn
adlarnn grlebilmesi iin ToString metodunun ezilmi olmas arttr. Bilindii gibi servis
tarafndaki gelitirici tanml tiplere ait metodlar istemci tarafnda seriletirilmemektedir. O nedenle,
ToString metodunun ezilmi hali sadece bu rnekte yardmc olmas asndan istemci tarafndaki
uygulamada bilinli olarak aadaki gibi ezilmektedir. Bir gerek hayat senaryosunda bu ok
kontrol edilebilir bir durum olamayabilir. Nitekim gncelletirme ve leklendirme zorlamaktadr.

Bu deiikliin arkasndan ListBox zerinden SelectedItem zellii ile elde


edilen Object referans ProductInfo tipine dntrlp ProductPhotoId zelliinin deeri elde

www.bsenyurt.com Page 683


edilebilir. Dolaysyla rnek altrldnda aadaki ekran grntsndekine benzer sonular elde
edilecektir.

Gelelim asl konumuza. Bakalm log dosyalarnda ne gibi sonulara varacaz. ncelikli
olarak Service Trace Viewer yardmyla web_tracelog.svc dosyasnn almas gerekmektedir.
Bu ana kadar yaplanlarn tek amac sz konusu dosya ierisinde, istemciye gnderilen mesaj
formatnn text tabanl olduunun ispat edilmesidir. lk olarak Activity ksmndan Process action
"http://www.bsenyurt.com/ProductPhotoService/
Photo_x0020_Service/GetPhotoByProductId blm seilir. Bu ilemin ardndan A message
was written Description blmne baklrsa Encoder isimli zelliin deerinin aadaki ekran
grntsnde olduu gibi text/xml; charset=utf-8 olduu grlr.

www.bsenyurt.com Page 684


Bu aslnda istemciye dndrlen byte[] dizisinin text tabanl olacak ekilde XML ieriine
kodlandnn bir gstergesidir. Servis tarafndan MTOM' a uygun olacak ekilde mesaj dndrmek
iin tek yaplmas gereken BasicHttpBinding balayc tipinin MessageEncoding zelliinin
deerini MTOM olarak deitirmektir. Bunun iin servis tarafnda yeni bir Binding
Configuration elementinin BasicHttpBinding tipi iin aadaki ekran grntsnde olduu gibi
eklenmesi gerekmektedir.

www.bsenyurt.com Page 685


Sonrasnda balayc tipin(Binding Type) bu konfigurasyon ile eletirilmesi yeterli olacaktr.
Bunun iin ProductPhotoHttpEndPoint zelliklerinden BindingConfigurationelementinin
deerinin aadaki ekran grntsnde olduu gibi Microsoft Service Configuration
Editor zerinden ProductPhotoBindingConfiguration olarak set edilmesi yeterlidir.

Elbetteki servis tarafnda yer alan konfigurasyon dosyasnda


da MessageEncoding zelliinin deerinin true olarak set edilmesi gerekir. Bu
yaplmad takdirde alma zamannda(Run Time) ProtocolException tipinden bir
istisna(Exception) alnabilir.

www.bsenyurt.com Page 686


Bu ilemin ardndan istemci yeniden altrlr ve Service Trace Viewer kullanlarak
GetProductPhotoId' den geriye dndrlen mesaj zelliklerine baklrsa aadaki sonucun ortaya
kt grlecektir.

Uygulama test edilirken dikkat ekici noktalardan biriside baz resim dosyalar alrken aadaki
gibi bir alma zaman hata mesaj alnmasdr.

www.bsenyurt.com Page 687


Bu hatann sebebi aktarlmak istenen veri boyutunun varsaylan MaxArrayLength deerinden byk
olmasdr. Bu sorunu zmek iin balayc tipin konfigurasyon ayarlarnda yer
alan MaxArrayLength deerini deitirmek yeterlidir. Bu zelliin varsaylan deeri 16384 byte'
dr. rnekte bu deer sembolik olarak 65536 yaplmaktadr. Elbetteki bu zelliin deerinin hem
istemci hemde servis tarafnda yaplmas arttr. Sz konusu zellik aadaki ekran grntsnde
olduu gibi Microsoft Service Configuration Editor yardmyla deitirilebilir.

Bu ilemin ardndan rnek uygulama altrlrsa sonularn baarl bir ekilde alnd grlebilir.
Elbetteki boyutun dahada artmas yine ayn istisnann(Exception) alnmasna neden olacaktr.

MTOM standardna uygun olarak hazrlanan mesajlar sayesinde byk


boyutlu ikili(Binary) verilerin gereksiz yere kodlanmadan aktarlmas ve zlmeden alnmas
mmkn olabilmektedir. Yinede veri boyutunun ok fazla olmas halinde MTOM tabanl mesajlarn
hazrlanmasda zaman kaybna neden olacaktr. Nitekim sz konusu byk veri dosyasnn tek
seferde istemciye(veya servise) doru aktarlmas sz konusudur. Ayrca bu byk verinin
alnmas srasnda timeout' lar oluabilir. Peki zm olarak neler yaplabilir? Eer protokol
uygunsa sz konusu byk verilerin istemci ve servis arasnda bir Stream zerinden tanmas
tercih edilmelidir. Bylece sz konusu performans kayplarda ortadan kalkacaktr. Nitekim mesaj
tek seferde hazrlanp tamamnn gnderilmesi yerine iki taraf arasnda alan hat zerinden akmas
salanabilmektedir.

WCF(Windows Communication Foundation) ierisinde yer


alan basicHttpBinding, netTcpBinding, netNamedPipeBinding tipleri Stream aktarmn
desteklemektedir. Tahmin edilecei zere dier balayc tiplerin buna tam destei olmadndan
zel balayc tipleri(Custom Binding Types) kullanmak gerekmektedir. Stream kullanlmas
iin tek yaplmas gereken TransferMode zelliinin deerini aadaki tabloda yer alan
deerlerden birisine set etmektir. (Balayc tipin TransferMode zellii, TransferMode enum sabiti
tipinden deerler alabilmektedir.)

TransferMode
Aklama
Deeri

Streamed Serivise gelen ve servisten kan mesajlar stream zerinden hareket ederler.

Sadece servis tarafna gelen taleplere(Request) ait mesajlarn stream


zerinden hareket etmesine izin verilir. Bu mod seildiinde servis
StreamedRequest
tarafndaki metodun parametresinin tek ve Stream snfndan treyen bir
ekilde tasarlanm olmas arttr.

www.bsenyurt.com Page 688


Sadece servis tarafndan istemciye geri dnen cevaplara(Response) ait
mesajlarn stream zerinden hareket etmesine izin verilir. Bu mod
seildiinde servis tarafnda yer alan operasyonun geriye Stream snfndan
StreamedResponse
tremi bir tip dndrmesi veya bunu out anahtar szc ile metod
parametrelerinde yapmas arttr. (Burada Stream yerine IXmlSerializable
arayzn-interface- uyarlam bir tipin dndrlmeside salanabilir.)

Mesajlar stream zerinden hareket etmezler. Hangi taraf olursa


olsun, ikili(binary) ieriin tamam gnderilmeye hazr hale geldiinde
kar tarafa aktarlrlar. Kar tarafa ulatnda ise tamam tampona
Buffered
alndktan sonra uygulamaya ilenmek zere
aktarlrlar. TransferMode zelliinin varsaylan(Default)
deeri Buffered olarak belirlenmitir.

Her ne kadar stream zerinden mesaj gndermek avantajl gzksede dikkat edilmesi gereken baz
hususlarda vardr. Hereyden nce Stream kullanlmas halinde mesaj seviyesinde
gvenlik(Message Level Security) tesis edilememektedir. Bu nedenle iletiim seviyesinde
gvenlik(Transport Level Security) kullanlmaldr. rnein HTTPS kullanm HTTP zerinden
kullanlacak Stream' ler iin geerlidir. Bunlarn dnda Stream kullanm iinde bir mesaj alma
snr vardr. Biraz nceki rnekte olduu gibi belirlenen boyutun dna kldnda alma zaman
istisnalar alnabilir. Ancak en nemli kstlardan birisi gvenilir oturum(Reliable
Session) amann mmkn olmaydr. Nitekim gvenilir oturumlar mesajlarn tamponlanmas ve
sralanmas ilkelerine gre almaktadr.

Gelitirilen rnekte Stream kullanm iin tek yaplmas gereken servis ve istemci tarafndaki
konfigurasyon dosyalarnda, balayc tip ile ilikili TransferMode zelliinin deerini aadaki gibi
deitirmektir.(Bu ayar istemci taraf iinde yapmak gerekmektedir.)

Buraya kadar anlatlanlar gz nne alndnda MTOM(Message Transmision Optimization


Mechanism) sayesinde mesajlarn ieriklerinin encoding/decoding ilemlerine tabi tutulmadan
kar tarafa aktarlabilmesi salanmaktadr. Bu ayn zamanda WCF(Windows Communication
Foundation) dndaki platformlar ile haberlemedede(Interoperability Destei) nemli bir yere
sahiptir. Dier taraftan MTOM' un baz dezavantajlarn ortadan kaldrmak adna Stream kullanm
tercih edilebilir. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye
dek hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 689


rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - MSMQ(MicroSoft Message Queue) ile


Entegrasyon ( 13.11.2007 ) - WCF
Deerli Okurlarm Merhabalar,

TCP veya HTTP bazl iletiimlerde, taraflarn ayn zaman dilimi ierisinde alyor olmalar
gerekmektedir. Byle bir mesajlama srecinde taraflardan herhangibirin almamas, aradaki
balantnn kopmas gibi nedenlerden dolay tm iletiimin aksamasda muhtemeldir. Baz gerek
hayat senaryolarnda, sistemin taraflar olanistemci(Client), sunucu(Server),
a(Network) bileenlerinin kmesi durumlarnda dahi ilevselliin devam edebilmesi istenebilir.
Bunun dnda, alan sistemin ierisindeki bileenlerin srekli bir balantda olmad durumlarda
bu tip iletiimleri zorlatrmaktadr. Bir baka deyile aa srekli olarak balanamayan
ama offline olarak alabilen istemcilerin bu tip bir mesajlama sisteminin paras olmas
istendiinde senkronizasyon glkleri ortaya kmaktadr.

Ne varki mesajlamalarn kuyruk(Queue) modeline gre tand bir sistemde yukarda bahsedilen
iletiim sorunlarnn yaanmamas salanabilir. Nitekim mesaj kuyruu(Message
Queue) sisteminin gelitirilme amacda aslnda budur. Bu sistem temelde Windows tabanl
bilgisayarlar arasnda kuyruk sistemine dayal bir mesaj alveriinin tesis edilmesini salamaktadr.
Bu iletiimde istemci(Client), servis(Service) ve a(Network) arasnda bir izolasyon
salanmaktadr. Bu izolasyon sayesinde istemci, servis yada a kse, hata retse dahi
fonksiyonelliklerini devam ettirebileceklerdir. Kuyruk temelli iletiimde gvenilir(Reliable) bir
iletiim ortam tesis edilmekte olup transaction kullanlabilmekte, kuyrua atlan mesajlar fiziki
yada deiken(Volatile) olarak saklanabilmektedir. Kuyruk temelli mesajlamann en bilinen
uyarlamas MicroSoft Message Queue bileenidir(Component).

MicroSoft Message Queue(MSMQ), Windows NT srmnden beri gelen bir bileendir. NT


iletim sistemi iin 1.0 versiyonu duyrulan MSMQ bileeninin ok ksa tarihesi aadaki tabloda
olduu gibidir.

Desteklenen
MSMQ
letim zellikler
Versiyonu
Sistemi(Sistemleri)

1.0 Windows NT Varsaylan zellikler...

2.0 Windows 2000 Public mesaj kuyruklarnn Active


Directorydestekli olarak saklanmas
128 bitlik ifreleme destei
Dijital imza destei
Tam COM destei

3.0 * Windows XP HTTP , SOAP destei ile internet zerinden


Windows Server 2003 mesajlaabilme
IIS iin MSMQ destei
Mesajlarn oklu

www.bsenyurt.com Page 690


Dntrlebilmesi(MultiCasting)

4.0 ** Vista Alt kuyruk destei(Subqueue)


Longhorn Server Zehirli mesajlarn ele alnmas(Posion Message
Handling)
Uzak kuyruklardan transaction bazl mesaj alma
destei(Transactional Remote Receive)

* http://www.microsoft.com/windowsserver2003/technologies/msmq/whatsnew.mspx
** http://windowssdk.msdn.microsoft.com/en-us/library/ms701784.aspx

Ayrca 1999 ylnda MSMQ' nun mobil cihazlar iin olan desteide Windows CE 3.0 iletim sistemi
ile birlikte balamtr.

MSMQ Windows tabanl bir bileendir. Ancak farkl bilgisayarlar ilede haberleme olana
mevcuttur. MSMQ' nun grevi aynen dier iletiim sistemlerinde olduu gibi farkl bilgisayarlar
arasnda mesajlamay salayabilmektir. Bu mesajlamadaki tek fark, taraflarn ayn anda alyor
olma zorunluluklarnn bulunmaydr. Hatta sz konusu taraflarda alan uygulamalar bir
aa(Network) bal olmak zorundada deildirler. Byle bir durumda ortaya kan soru iletilmek
istenen mesajlarn kar taraf kapal iken nasl ulatrlacadr? MSMQ bileenleri, mesajlar, kar
taraf hazr oluncaya kadar bir depoda saklamaktadr. Bu deponun tutulu yeri varsaylan olarak
fiziki bir ortamdr. Ancak istenirse performas arttrmak adna geici bir ortamda da saklanabilirler.
Ne varki Volatile olarak adlandrlan bu mesajlar sistemlerin kmesi (MSMQ bileeninin ykl
olduu bilgisayarn rnein yeniden balatlmas-restart) halinde kaybolacaktr. Oysaki fiziki
saklanan mesajlar korunmaya devam edecektir. Buda MSMQ' nun mesajlar iin uzun sreli bir
saklama ortam kullanabildii anlamna gelmektedir(Durable).

MSMQ bileenlerine .NET ortam ierisinde System.Messaging isim


alannda(Namespace) bulunan tipler yardmyla eriilebilmektedir. Bu sebepten programatik
olarak C#, VB.Net ve dier .NET destekli diller yardmyla kuyruklara baklmas, mesaj eklenmesi
ve daha gelimi ynetsel ilemlerin yaplmas mmkndr. Dier taraftan MSMQ' nun C/C++ ile
yazlm olan ve COM tabanl ortamlarda kullanlabilen bir API'side mevcuttur.
Elbette WCF ierisinde MSMQ iin hazr olan baz balayc tipler(Binding
Types) kullanlmaktadr.

MSMQ sonu itibariyle taraflar arasnda mesaj tadndan mesajlarn boyutlarda performans
asndan nemlidir. Varsaylan olarak minimum mesaj bykl 150byte' tr. Bu mesaj
ierisinde, imza(Signature), kaynak ve hedef bilgisayar ID' leri, hedef kuyruun ad(Target
Queue Name), mesaj zellikleri yer alr. Ancak transaction kullanlyorsa
yada dorulama(authentication) ve ifreleme(encryption) sz konusuysa bu boyutun artmas
muhtemeldir. rnein dahili bir sertifika kullanmnda mesaj boyutu 400 bytekadar artmaktadr.
Harici sertifika(Certificate) kullanmnda en az 1 kb' lk bir mesaj boyutu olumaktadr. Bunlarn
dnda HTTP veya MultiCast kullanm sz konusu iseSOAP formatlamadan dolay mesajn
sadece balk ksm(Message Header) 1 kb boyutunda olacaktr. ok doal olarak mesaj
boyutlarndaki bu artlar iletiim hzn olumsuz ynde etkileyebilir. Dolaysyla en uygun
senaryolar(Best Practices) ele almak gerekir. (Blmn sonunda bu konuya ksaca
deinilecektir.)

Peki MSMQ kullanmak iin gerekli senaryolar neler olabilir? Aslnda kuyruk tabanl iletiim, gvenilir
a ortamlarnn sz konusu olmad, a ortamna(Network) arada srada balanabilen
uygulamalarn haberlemesi gerektii durumlarda sklkla ele alnmaktadr. rnein bir servis
uygulamas tarafndan, gn iinde offline ortamlardan gelen siparilerin gn sonunda toplu olarak
ilendii bir senaryo gz nne alnabilir. Aadaki ekilde buna benzer bir senaryo incelenmeye
allmaktadr.

www.bsenyurt.com Page 691


Senaryoda, zaman zaman offline duruma debilecek olan istemciler sz konusudur. Bu istemciler
zerinden gelen sipariler bir sunucuda toplanmaktadr. Siparileri ileyen sunucu tahsilatlar iin
baka bir sunucuyu kullanmaktadr. Burada sz konusu siparileri ileyen servis ile, tahsilatn
yapld sunucu ve PDA cihaznda kullanlan uygulamalarn srekli bir balantda olmad gz
nne alnmaktadr. Byle bir durumda bir sipariin ilenmesi zaman alabilir. Ayrca bu bekleme
srelerinin siparileri ileyen uygulamay etkilemesi istenmez. Yani, bekleyen siparilerin gecikmeli
olarakta olsa ilenebildii ve yeni gelen siparilerinde toplanabildii bir ortamn hazrlanmas
gerekmektedir. Bylece PDA satclar siparileri offline olarak toplayabilir ve daha sonra ilenmek
zere(servis ile balant tekrardan salandktan sonra) servise gnderebilir. Ayrca web zerinden
gelen siparilerin ileme alnd bilgisi annda kullanclara gsterilebilir(Laptop ile ifade edilen
kullanclar). Bu tip senaryolar geniletilebilir. Ancak uygun vakalar ounlukla offline alma
ihtiyac olan, gvenilir bir a ortamnda bulunamayan veya bir aa hi bal olmayan
bilgisayarlarn, asenkron olarak haberlemesi gereken durumlardr.

Burada ok nemli bir nokta vardr. MSMQ gibi kuyruk tabanl iletiimi benimsiyen
sistemler asenkron(asynchronous) olarak almaktadr. MSMQ bu
anlamda,gvenilir(Reliable) ortam oluturabilen, Transaction destei
salayan, balantsz(Disconnected) almaya olanak tanyan, srekli
depolama(Durable)destei veren mkemmel bir asenkron(Asynchronous) iletiim
ortam salamaktadr.

MSMQ bileenlerinin kullanld uygulamalar herhangibir Windows program olabilir. Bu nedenle


bir Windows uygulamasndan(Windows Application), Windows Servisinden(Windows Service),
akll istemciden(Smart Client), web sitesinden MSMQ kullanlabilir. Bu noktada MSMQ ile ilgili
nemli sorunlardan birisi gndeme gelmektedir. rnek bir windows iletim sistemi tabanl
uygulama, MSMQ kullanarak, kuyruk tabanl baka bir sistem ile nasl haberleebilir? Sz gelimi
kuyruk tabanl iletiimi kullanan IBM MQSeries ile bir MSMQ istemcisi nasl haberleebilir?

www.bsenyurt.com Page 692


MSMQ istemcileri yabanc bilgisayarlar(Foreign Computers) ile Connector ad verilen
uygulamalar araclyla haberleebilirler. Connector uygulamalar aslnda bir MSMQ sunucusunda
alr ve yabanc bilgisayarlarn MSMQ istemciler ile olan haberlemelerinde araclk yapar. Bu
araclkta transaction destei olan veya olmayan kanallar sz konusudur. IBM MQSeries ile
iletiimi salayan Connector uygulama Microsoft MSMQ-MQSeries Bridge programdr. Tabi
farkl kuyruk tabanl sistemler iin farkl Connector uygulamalar mevcuttur.

MSMQ' nun yaznn hazrland tarih itibariyle 4.0 versiyonu bulunmaktadr. Bu versiyon
ile gelen baz belirgin zelliklerin bilinmesi gerekmektedir. 4.0 versiyonu alt
kuyruklar(SubQueue), zehirli mesajlarn ele alnmas(Poison Message Handling),
transaction bazl uzak kuyruk destei(Transactional Remote Receive) eklinde 3
nemli yenilik iermektedir.

SubQueues(Alt Kuyruklar): Mesajlarn ek fiziki kuyruklar oluturmadan mantksal


olarak eitli kriterlere gre alt gruplara ayrlabilmesi desteidir.

Zehirli Mesajlarn Ele Alnmas(Poison Message Handling): Zehirli mesajlar, bir


kuyrukta arkadan gelen mesajlar engelleyen niteliktedir. Bir uygulama kuyruktan bir
mesaj okuyup ilemek isterken, mesajdaki hata nedeni ile bu ilemi yapamad
durumlarda, (eer sre bir transaction ierisindeyse) Abort ilemini gerekletirip
mesaj tekrardan kuyrua dndrecektir. Bu mesaj daha sonradan tekrardan ilenmek
amacyla uygulama tarafndan yeniden okunacak ama hatas nedeni ile yine kuyrua geri
dndrlecektir. Bu durumda transaction' n srekli olarak abort edildii ve mesajn
kuyrua gnderildii sonsuz bir dng oluacaktr. Bu dngye neden olan mesaj bir sre
sonra tekrardan deneme saysnnda almas sebebiyle arkadan gelen mesajlarnda
ilenmesini engelleyecektir. te MSMQ 4.0 versiyonu ile birlikte bu tip mesajlarn daha
gl bir ekilde ele alnmas ve sorunun nne geilmesi salanmaktadr. Bunun
iinde Retry Queue(yeniden deneme kuyruu) ad verilen kuyruklar kullanlmaktadr.
(WCF ierisindeki balayc tipler buna destek veren zellikler(Properties) iermektedirler)

Transaction bazl uzak kuyruk destei(Transactional Remote Receive): Tek bir


mesaj kuyruunun ileri ald bir durumda, baka bilgisayarlardaki uygulamalarnda bu
ileri deerlendirdii dnlsn. Uygulamardan biri sradaki bir ii ileyemez ise bu iin
sonradan deerlendirilmek zere tekrardan kuyrua gnderilmesi tercih edilir. Bu tip bir
sre iin transaction destei gerekmektedir. Ayrca istemci bilgisayarlarn ve
kuyruun a(Network) zerinden DTC(Distributed Transaction
Coordinator) eriiminede izin vermesi arttr.

MSMQ, WCF ierisinde de dorudan desteklenmektedir. stelik WCF' in salad


birletirilmi(Unified) model sayesinde, gelitiriciler MSMQ' nun karmak alt yapsndan
uzaklamaktadr. Basit anlamda WCF zerinden MSMQ konseptine bakldnda aadaki durum
sz konusudur.

www.bsenyurt.com Page 693


Burada istemci ve servis uygulamalar ortak bir kuyruu kullanarak iletiim salamaktadr. Kuyruk
ierisinde yer alan mesajlar fiziki bir ortamda sakalanbilmektedir. Microsoft Managament
Console kullanld takdirde kuyruktaki mesajlarn tutulaca yer genellikle aadaki ekildende
grld gibi Windows\System32\msmq\Storage klasrdr.

www.bsenyurt.com Page 694


Dier taraftan gerek bir datk mimari vakasnda mesaj kuyruklar ounlukla istemci ve servis
uygulamalar iin ayr ayr tutulurlar. Bu durum aadaki ekilde olduu gibi ifade edilebilir.

Bu senaryoda istemci ve servis uygulamalar kendi ortamlarndaki kuyruk yneticileri(Queue


Manager) yardmyla haberlemektedir. Kuyruk yneticileri mesajlar kuyrua atmak veya
kuyruktan okumak iin gerekli ynetsel ilemleri stlenmektedir. stemci uygulamalar, servis
uygulamasna gndermek istedikleri mesajlar kuyruk yneticisine iletirler. Kuyruk yneticisi bu
mesajlar tama kuyruuna(Transport Queue) aktarr. Kar taraf hazr olduundada servis
uygulamasndaki kuyruk yneticisine gnderilir. Servis tarafndaki kuyruk yneticisi gelen mesaj
alarak hedef kuyrua(Target Queue) atar. Sonrasnda ise servis tarafndaki kuyruk yneticisi,
hedef kuyrua kabul ettii mesaj ilenmek zere servis uygulamasna ynlendirir. Burada iletiim,
gvenilir bir ortamda gerekletirilir.

WCF(Windows Communication Foundation) tarafnda MSMQ destei iin iki farkl balayc
tip(Binding Type) kullanlmaktadr.
Bunlar netMsmqBinding vemsmqIntegrationBinding tipleridir. netMsmqBinding iki WCF End
Point arasnda MSMQ tabanll bir iletiimi salamak amacyla kullanlr. msmqIntegrationBinding
tipi ise bir WCF End Point ve C, C++, COM veya System.Messaging API' si yardmyla
gelitirimi bir MSMQ destekli uygulama arasnda iletiimin salanmas iin kullanlmaktadr. Yanlz
bu tip kullanlrken nemli bir kst vardr. Bu ksta gre operasyon szlemesi(Operation
Contract) tanmlanrken MsmqMessage tipinden tek parametre alan bir metod sz konusu
olabilir. Bunun tek sebebi WCF dnda olan bir ortam ile ortak haberleebilmeyi salamaktr.

WCF tabanl MSMQ(MicroSoft Message Queue) uygulamlarnda servis tarafnda


tanmlanan operasyonlarn tek ynl(OneWay) olacak ekilde tanmlanmalar
gerekmektedir. Bunun sebepi MSMQ' nun normal artlarda tek ynl iletiimi(One-
Way Transport) kullanyor olmasdr.

www.bsenyurt.com Page 695


Artk bir rnek zerinden hareket edilerek WCF ierisinde MSMQ' nun nasl kullanlabileceine
baklabilir. ncelikli olarak servis szlemesi(Service Contract) ve uygulayc snfn yer
ald WCF Servis Ktphanesinin(WCF Service Libraray) rnek olarak aadaki gibi
tasarland gz nne alnsn.

Servis Szlemesi;

using System;
using System.ServiceModel;

namespace SiparisKutuphanesi
{
[ServiceContract(Name="Siparis
Servisi",Namespace="http://www.bsenyurt.com/SiparisServisi")]
public interface ISiparisYonetici
{
[OperationContract(IsOneWay=true)]
void SiparisEt(int urunNo, int miktar);
}
}

Servis szlemesinde dikkat edilmesi gereken noktalardan


birisi OperationContract isimli nitelikle(Attribute) kullanlan IsOneWay zelliine true deeri
atanmasdr. Daha nceden de bahsedildii gibi MSMQ tipinde haberlemelerde mesajlarn tek
ynl almas sz konusudur. Bu doal olarak mesajn gnderildikten sonra ilenip
ilenmediinden haberdar olunamamas anlamna da gelmektedir. Dolaysyla mimari gerei
operasyonun tek ynl(One Way) olaca belirtilmelidir.

Uygulayc Snf;

using System;
using System.Threading;
using System.ServiceModel;

namespace SiparisKutuphanesi

www.bsenyurt.com Page 696


{
public class SiparisYonetici:ISiparisYonetici
{
#region ISiparisYonetici Members

public void SiparisEt(int urunNo, int miktar)


{
Thread.Sleep(7000);
// Sipari ile ilgili ilemler
}

#endregion
}
}

Uygulayc snf ierisinde sembolik olarak SiparisEt isimli bir metod bulunmaktadr. Bu metodun
herhangibir ilevi yoktur. Sadece MSMQ senaryosunu tamamlayc bir edir. Dier taraftan kuyruk
oluumlarn daha kolay izleyebilmek ve asenkron almay daha kolay takip edebilmek adna
metod ierisinde bilinli olaraktan, alan Thread' in 7 saniye sreyle uyutulmas salanmaktadr.

Servis uygulamas basit bir Console uygulamas olarak tasarlanabilir. Nitekim burada nemli olan
noktalar konfigurasyon dosyas ierisinde yaplan deiikliklerdir. Servis uygulamasna ait
konfigurasyon dosyasnn ierii ve kaynak kodlar aadaki gibidir. (Servis uygulamasnda, WCF
Servis Ktphanesi ve System.ServiceModel.dll assembly' larnn referanslarnn eklenmemesi
unutulmamaldr.)

Servis taraf konfigurasyon dosyas;

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


<configuration>
<system.serviceModel>
<bindings>
<netMsmqBinding>
<binding name="SiparisServisiBindingConfig" receiveTimeout="00:10:00"
deadLetterQueue="System" durable="true" exactlyOnce="true" maxRetryCycles="2"
receiveErrorHandling="Fault" receiveRetryCount="5" retryCycleDelay="00:30:00">
<security mode="None" />
</binding>
</netMsmqBinding>
</bindings>
<services>
<service name="SiparisKutuphanesi.SiparisYonetici">
<endpoint address="net.msmq://localhost/private/SiparisKuyrugu" binding="
netMsmqBinding" bindingConfiguration="SiparisServisiBindingConfig"
name="SiparisServisiEndPoint" contract="SiparisKutuphanesi.ISiparisYonetici" />
</service>
</services>
</system.serviceModel>
</configuration>

Konfigurasyon dosyasnn ierii Microsoft Service Configuration Editor yardmyla da


oluturulabilir. Bu yol izlenirse eer, daha nceden deinilen TCP, HTTP, Named-Pipes, Peer To
Peer gibi balantlardan farkl olarak balayc tip seilirken aadaki ekran grntsnde olduu
gibi MSMQ seilmelidir.

www.bsenyurt.com Page 697


Yaplan bu seimin ardndan editor, istemcilerin MSMQ yada WCF tabanl bir uygulama olup
olmad sorulacaktr. Daha ncedende belirtildii gibi, WCF End Point' leri arasnda yada bir WCF
End Point ile bir MSMQ uygulamas arasnda mesaj kuyruu tabanl iletiim salanabilmektedir. Bu
seime gre kullanlacak olan balayc tip(Binding Type)belirlenmektedir.
rnekte netMsmqBinding ele alnmtr. Bir baka deyile WCF istemcileri ile MSMQ zerinden
konuacak bir servis tasarlanmaktadr.

www.bsenyurt.com Page 698


Bu seimin ardndan adres bilgisinin girilmesi gerekir. MSMQ kullanld iin sz konusu adres
aslnda yerel makinedeki fiziki bir adresi iaret etmelidir. Burada rnek olarak aadaki ekran
grntsnde yer alan adres tanm kullanlmaktadr. Bir baka deyile, yerel makinede yer alan
zel SiparisKuyrugu isimli kuyruk(Queue) adres olarak ele alnmaktadr.

Burada zerinde durulmas gereken noktalardan biriside udur. SiparisKuyrugu


isimli private kuyruk nasl oluturulmutur? Bunun iin sistemde MSMQ' nun kurulu
olmas elbette arttr. MSMQ' nun kurulmas halinde rnein Vista iletim sistemi
zerinde Microsoft Management Console alarak Meesage Queuing klasrne
gidilir. Ardndan menden New->Private Queue seeni iaretlenir.

www.bsenyurt.com Page 699


Bu ilemin ardndan, New Private Queue esinden yararlanarak kuyruun ad girilir.
rnek uygulamada ExactlyOnce zelliine true deeri atanmtr. Bu, mesajlarn yanlz
bir tane gitmesini ve alnmasn salamaktadr. Yani tekrar eden mesajlarn nne
geilmektedir. Ancak bunun iin MSMQ' nun transactional destekli oluturulmas
gerekir. Bu nedenle Transactional seenei iaretlenmelidir.

Sonu olarak ilemler tamamlandnda, ilk haliyle aadaki gibi bir sonu ortaya
kacaktr. (Servis uygulamas altrldktan sonra burada retry isimli bir alt klasr daha
oluturulduu grlebilir.)

Burada private' n zel bir anlam vardr. Bu tanmlamaya gre mesaj kuyruunun, servis
uygulamasnn alt yerel makinede saklanaca belirtilmektedir. AncakWindows Domain' e
dahil edilmi bir kuyruk tanmlamas public olarak yaplarak baka bilgisayarlarnda ayn kuyruu
kullanmalar salanabilir. Bu zellikle aa karak hedef kuyruk ile dorudan konuamayan alt
yaplarda ie yarayabilir. Nitekim bylece aa kamayan istemciler aslnda public lokasyonda duran

www.bsenyurt.com Page 700


bir kuyrua mesajlarn gnderirler. Bu kuyruun bulunduu makinede kuyruktaki mesajlar hedef
servise ynlendirir.

Konfigurasyon ierisinde kullanlan baz nemli ayarlar bulunmaktadr. Bu zelliklerin ksa


aklamalar aadaki tabloda grld gibidir.

zellik Aklama

Durable true veya false deerini alabilir. True olmas halinde mesajlarn
fiziki diskte saklanaca belirtilir. Bu I/O ilemlerinin youn
ekilde kullanlmasn gerektirmektedir. Dolaysyla sistemin en iyi
performansnn elde edilmesinde genellikle false olarak ayarlanr.
Ne varki false deer verilmesi halinde mesajlar Volatile olarak
tutulurlar. Bir baka deyile makine kapatlp aldnda Volatile
mesajlara ulalamaz.

ExactlyOnce true veya false deer alabilir. True olmas halinde sistemde
hareket eden mesajlarn tekrar edilmeyecei garanti altna alnr.
Bir baka deyile mesajlar kaybolmaz veya yanllklada olsa iki
kere gnderilmez. Bu zelliin true olmasnn bir artda kuyruun
transactional olarak tanmlanma zorunluluudur.

Security ksmndan MSMQ normalde iletiim(Transport Level) ve mesaj(Message


Mode Level) seviyesinde gvenlik kullanmna izin verir. Ancak
kendisine ait bir iletiim gvenlii sz konusu
olduundanSSL kullanlmasn gerektirmez. Mesaj seviyesinde
gvenlik ayarlar yapldnda tek art vardr o da sertifika
desteinin MSMQ iin salanm olmas gerekmektedir.

ReceiveRetryCount Kuyruktan uygulamaya doru bir mesajn ulatrlmas iin


maksimum deneme saysn belirtir. Varsaylan deeri 5 tir.

MaxRetryCycles Bir mesaj uygulama kuyruundan retry alt


kuyruuna(SubQueue) transfer
edildiinde,RetryCycleDelay sresinden sonra uygulama
kuyruunda ilenmek zere tekrardan gnderdilir. Buradaki
tekrar says MaxRertyCycle ile belirlenir. Varsaylan deeri 2
dir.

RetryCycleDelay RetryCycle' lar arasndaki sredir. Varsaylan


olarak 30dakikadr. Bir baka
deyile retry alt kuyruundanuygulama kuyruuna ne kadar
srede bir gnderilme denemesi yaplaca belirtilir.

ReceiveErrorHandling Maksimum ulatrma says alp hata olumas halinde nasl bir
etki olaca belirtilir. Varsaylan olarak bu
deer Fault eklindedir. Yani uygulamaya bir istisna mesaj
frlatlacaktr. Dier deerleri ise Drop, Reject ve Move' dur.
Vakaya gre uygun olan deerin seilmesi gerekmektedir.

(Burada sz konusu olan ReceiveRetryCount, MaxRetryCycles, RetryCycleDelay,


ReceiveErrorHandling zellikleri zehirli mesajlarn ele alnmas-Poison Message
Handling iin nemlidir)

Servis taraf uygulama kodlar;

using System;
using System.ServiceModel;

www.bsenyurt.com Page 701


using SiparisKutuphanesi;

namespace Servis
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(SiparisYonetici));
host.Open();
Console.WriteLine(host.State.ToString());
Console.WriteLine("Kapatmak iin bir tua basnz.");
Console.ReadLine();
host.Close();
}
}
}

Artk istemci taraf programlanmaya balanabilir. stemci uygulamada basit


bir Console uygulamas olarak tasarlanabilir. stemci iin gerekli Proxy snfnn retimi
iinSvcUtil.exe aracndan aadaki ekran grntsnde olduu gibi faydalanmak gerekmektedir.

Bu ilemin ardndan istemci uygulamann kodlar ve konfigurasyon ierii aadaki gibi


dzenlenmelidir.

stemci taraf konfigurasyon dosyas;

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


<configuration>
<system.serviceModel>
<bindings>

www.bsenyurt.com Page 702


<netMsmqBinding>
<binding name="SiparisIstemciBindingConfig" receiveTimeout="00:10:00"
maxRetryCycles="2" receiveErrorHandling="Fault" receiveRetryCount="5"
retryCycleDelay="00:30:00">
<security mode="None" />
</binding>
</netMsmqBinding>
</bindings>
<client>
<endpoint address="net.msmq://localhost/private/SiparisKuyrugu" binding="net
MsmqBinding"
bindingConfiguration="SiparisIstemciBindingConfig" contract="SiparisServisi"name="SiparisIst
emciEndPoint">
</endpoint>
</client>
</system.serviceModel>
</configuration>

stemci taraf kodlar;

using System;
using System.ServiceModel;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
SiparisServisiClient client = new SiparisServisiClient("SiparisIstemciEndPoint");
Console.WriteLine("Balamak iin bir tua basnz...");
client.SiparisEt(1, 100);
client.SiparisEt(2, 100);
Console.WriteLine("Kapatmak iin bir tua basnz...");
Console.ReadLine();
}
}
}

Gelelim test aamasna. lk olarak istemci uygulamann altrld varsaylsn. Bu noktada servisin
almad dnlebilir. Bu durumda uygulamadaki fonksiyonellikler alacak ve metod
arlarna ait mesajlar kuyrua yazlacaktr. Bu mesajlar Microsoft Management
Console yardmyla SiparisKuyrugu isimli kuyruktan aadaki gibi grlebilir.

www.bsenyurt.com Page 703


Grld gibi iki metod ars sonras oluan mesajlar SiparisKuyrugu isimli kuyrua atlmtr.
Bunlarn ieriklerinede baklabilir. Bu ierikte tahmin edilecei gibi, mesajn hedef(Target) ve
kaynak(Source) alclar, mesaj ierii gibi bilgiler yer almaktadr. Bu noktadan sonra servis
uygulamas tekrardan altrlrsa kuyruktaki mesajlarn topland ve iletildii tespit edilebilir.
Nitekim servis uygulamas altrldktan sonra SiparisKuyrugu altnda baka bir mesaj
grnmeyecektir.

www.bsenyurt.com Page 704


Buraya kadar anlatlanlar ile WCF mimarisinde basit olarak MSMQ bazl uygulamalarn nasl
gelitirilebilecei incelenmeye allmtr. MSMQ' nunda baz dezavantajlar elbetteki vardr.
Hereyden nce tek ynl bir iletiimin olmas, dier iletiim tekniklerine gre daha yava
almas(zellikle kuyruun fiziki olarak tutulmas nedeni ile) bu dezavantajlar arasnda saylabilir.

MSMQ kullanlaca yerlerde en iyi senaryolar elde edebilmek iin baz kriterlere dikkat
etmek gerekebilir. Sz gelimi hzl ve yksek performansl bir mesajlama(Fast-
Best Effort Queued Messaging) iin transaction bazl olmayan(Non-
Transactional) kuyruklar tercih edilmeli ve buna gre ExactlyOnce zellii
ileDurable zelliklerinin deeri false yaplmaldr.

Gvenilir olarak noktadan noktaya bir mesajlama sz konusu ise(Reliable End-To-


End Queued Messaging), drt alternatif vardr. BasicTransfer, Transactional
Based,Dead-Letter Based ve Poison Message Based. Bu alternatiflerden hangisinin
kullanlacana gre yine konfigurasyon elemanlarnda baz deiiklikler yaplmaldr.

WCF tabanl olmayan uygulamalar ile haberleebilmek


iin msmqIntegrationBinding tipinin kullanmak gerekmektedir. Buda
servisin interoperability destei olmasn salamaktadr.

Bu tip en iyi zmler iin http://msdn2.microsoft.com/en-


us/library/ms731093.aspx adresinden bilgi alnabilir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde zet


olarak MSMQ teknolojisini WCF ierisinde ele aldk. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Replay Attack Etkisini Hafifletmek (


07.11.2007 ) - WCF
Deerli Okurlarm Merhabalar,

WCF(Windows Communication Foundation) ile ilgili bir nceki makalemizde, istemci ve servis
arasnda gvenilir oturumlarn(Reliable Session) nasl alabileceinden bahsetmitik.
Gvenilir oturumlarn yararlarndan biriside, olas cevaplama saldrlarnn(Replay
Attacks) nne gemektir. Bilindii zere cevaplama saldrlarnda, istemci ve servis arasnda
hareket eden mesajlarn yakalanarak bozulmas, deitirilmesi, kesilmesi gibi problemler sz
konusu olmaktadr. stelik deiiklie uratlan mesajlarn zaman ierisinde her hangibir anda,
orjinal servis kaynana yada farkl bir yne doru defalarca gnderilmeleride sz konusudur.

Gvenilir oturumlarda, mesajlarn tekrar etmesini nlemek adna WS-


ReliableMessaging artnamelerine uygun ekilde hareket edilir. Buna gre mesajlarn benzersiz
bir id ile iaretlenmesi ve sralarnn belirlenmesi iin numaralandrlmas sz konusudur. Ne yazkki
gvenilir bir oturum cevaplama saldrlarn tek bana karlamakta yeterli olmayabilir. Aslnda
bunun iin geerli ve yeterli bir senaryo vardr. Aadaki ekil cevaplama saldrlarna ait bir vakay
ifade etmektedir.

www.bsenyurt.com Page 705


Bu senaryoda istemci ve servis arasnda hareket etmekte olan 7 adet mesaj olduu
varsaylmaktadr. Gvenilir bir oturum saland dnlecek olursa, istemcinin servis tarafna
gnderecei her mesajda bir sra numaras olaca sz konusudur. Ne varki senaryoya gre 3
numaral mesaj hacker tarafndan yakalanr. Sonrasnda ise mesajn ierii ve numaras 6 olarak
deitirilerek servis tarafna gnderilir. Bilindii gibi gvenilir oturumlarda, servise gelen mesajlarn
farkl zamanlarda ulama ihtimali gz nne alnarak, bu mesajlarn istemciden gnderildikleri
srada alnmalar iin buffer(tampon) sistemi kullanlr. lerleyen zaman aralnda istemci gerek
6 numaral mesaj servis tarafnda gnderir. Oysaki 6 numaral mesaj zaten servis iin alan buffer
ierisinde durmaktadr. Dolaysyla asl 6 numaral mesaj servis tarafndan geri evrilerek
ilenmeyecektir. te bu durum gvenilir oturumlarn cevaplama saldrlar iin tek bana yeterli bir
zm olmaynn ispatdr.

zmsel bir yaklam olarak mesaj seviyesinde(Message Level) veya iletiim


seviyesinde(Transport Level) gvenlik gz nne alnabilir. Ancak bunlarda tek balarna yeterli
deildir. Mesaj seviyesinde gvenlikte, istemci ve servis arasndaki mesaj bilgileri ifrelenmektedir.
Ne varki mesaj seviyesinde gvenlik uyarlamalar, ounlukla mesaj gvdesindeki ieriin
ifrelenmesi ile ilgilenir. Bu sebepten mesajn balk(Header) ksm yinede hacker' lar tarafndan
yakalanabilir ve sra numaralar bozulabilir. Peki iletiim seviyesinde gvenlik uyarlamalarnda
durum nedir? Bu seviyede gvenlik olduka gl bir zmdr. Ancak iletiim seviyesinde
gvenlik uyarlamalar, noktadan-noktaya alrlar. Bu konu iin yle bir rnek dnlebilir; bir
servisin mesajn gnderdii hedefte baka bir servis olabilir. Mesaj alan servisin, mesajlarn
ieriine snrsz eriim yetkisi vardr. Eer merkez servis ald mesaj baka bir servisede
gnderiyorsa mesaj bozmadndan emin olmak gerekmektedir.

Bu ana kadar yazlp izilenler sz konusu olduunda, cevaplama saldrlarna kar tam anlamyla
bir zm bulunamad dnlebilir. Lakin, WCF ierisinde zel bir takm teknikler yardmyla
cevaplama saldrlarna kar daha gl durulabilir. Tabi tm bu tedbirsel teknikler gvenilir

www.bsenyurt.com Page 706


oturumlar(Reliable Session) zerine kurulmaktadr. Bu tedbirler aktifletirildiinde, WCF
alma zaman(Run-Time) her mesaj iin aadaki kriterlere uygun
bir tanmlayc(Identifier) retir.

Benzersiz(Unique)
Rastgele elde edilmi(Random)
aretlenmi(Signed)
Zaman Damgal(TimeStamp)

Bu deerlerden oluan tanmlayclar(Identifiers) nonce olarak isimlendirilmektedir. Nonce'


larn kullanld bu korunma sisteminin alma ekline gre, servise gelen mesajlarn bozulup
bozulmadklar(Corrupt) bir dizi ilem ile anlalmaya allr. Normalde servis tarafna gelen
mesajlarn nonce deerleri tampona(buffer) alnr. Baka bir mesaj geldiinde balk bilgilerinden
elde edilen nonce deerinin, tamponda olup olmadna baklr. Elde edilen nonce deerinin ayns
tamponda var ise gelen mesaj geri evrilir. Elbette nonce deeri tamponda yoksa mesaj kabul
edilir. Kabul edilen bu mesajn nonce deeri yine tampona eklenir. Nonce' larn kullanld bu
sistemi tesis edebilmek iinWCF ierisinde zel balayc tiplerin(Custom Binding
Types) tanmlanmas gerekmektedir.

Windows Communication Foundation alma zaman(WCF Run-Time) mesajlarn alnp


gnderilmesi srasnda kanal ynlarn(Channel Stack) kullanr. Mesajlar normal artlarda bir
adrese doru hareket ederler. Bu hareket TCP, HTTP gibi bir iletiim protokol zerinden
aktarlrlar. Bu sebepten mesajn ulat yerde bulunan WCF alma zaman(WCF Run-time)
karlama iin iletiim kanallarn(Transport Channels) kullanr. Bu kanal, servis tarafndaki
host nesnesi ald andan itibaren gelen mesajlar dinlemektedir. Servis tarafnda uygun iletiim
kanal tarafndan alnan mesajlar, daha sonra kodlama kanallarna(Encoding
Channels) ynlendirilir. Kodlama kanallarnn grevi istemciden gelen mesajlar zmleyerek
servis nesnesine iletmek ve servisin istemiceye gnderecei mesajlarda kodlayarak iletiim
kanalna(Transport Channel) iletmektir. ok doal olarak iletiim kanalndan geerek mesaj
kanalna gelen bilginin Text veya Binary tabanl olma durumu (hatta WS artnamelerine
gre Microsoft Transmision Opitimision Mechanism'a uygun bir biimde olmas) sz
konusudur. Aadaki ekil temel olarak sz konusu kanallar arasndaki iletiimi ifade etmektedir.

Servis taraf gz nne alndnda en azndan iki kanaln var olmas gerekmektedir. Dolaysyla
cevaplama saldrlarna kar savunma yaplrken oluturulacak olan zel kanal tipleri(Custom
Binding Types) gelitirilirken bunlara dikkat edilmelidir. Dier taraftan WCF ierisinde bu tip

www.bsenyurt.com Page 707


balayc tipleri hazrlamak son derece kolaydr. Basit olarakService Configuration Editor bu
amala kullanlabilir. Bu hazrlklar yaplrken balayc tip ierisine katlan kanallarn srasda
nemlidir.

Artk bir rnek zerinden hareket edilerek devam edilebilir. Her zamanki gibi servis
szlemesi(Service Contract) ve uyarlamasn ieren bir WCF Servis
ktphanesi tasarlayarak ie balamak gerekir. Sz konusu servis szlemesi ierisinde basit
olarak ilevsellii ok nemli olmayan iki metod yer almaktadr. Gvenilir oturum(Reliable
Session) salanmas adna bir oturum var olma gerekliine uygun olacak ekilde tanm
yaplmaktadr. Sz konusu servis ktphanesi ierisinde tanml tipler aada grld gibidir.

Servis szlemesi(Service Contract);

using System;
using System.ServiceModel;

namespace SiparisKutuphanesi
{
[ServiceContract(Name="Siparis Servisi",
Namespace="http://www.bsenyurt.com/SiparisServisi", SessionMode=
SessionMode.Required)]
public interface ISiparisYonetimi
{
[OperationContract(IsInitiating=true)]
void SiparisEkle(int siparisNo);
[OperationContract(IsInitiating=false,IsTerminating=true)]
void SiparisleriOnayla();
}
}

Szleme Uyarlamas;

using System;

www.bsenyurt.com Page 708


using System.ServiceModel;

namespace SiparisKutuphanesi
{
[ServiceBehavior(InstanceContextMode= InstanceContextMode.PerSession)]
public class SiparisYonetimi:ISiparisYonetimi
{
#region ISiparisYonetimi Members

public void SiparisEkle(int siparisNo)


{
// Siparis ekleme adm
}

public void SiparisleriOnayla()


{
// Siparis onaylama adm
}

#endregion
}
}

Bu ilemin ardndan servis ve istemci taraflarnn tasarlanmasna geilebilir. Olayn basit bir ekilde
ele alnmas iin servis ve istemci tarafndaki programlar basit birer Consoleuygulamas olarak
tasarlanabilir. Bu uygulamalarda belkide en nemli ksmlar konfigurasyon ayarlardr. Nitekim
konfigurasyon tarafnda zel balayc tip(Custom Binding Type)tanmlamalar yaplacaktr.
Servis tarafndaki Console uygulamasnn balangtaki hali aadaki gibidir.

Servis uygulamas kod ierii;

using System;
using System.ServiceModel;
using SiparisKutuphanesi;

namespace Servis
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(SiparisYonetimi));
host.Open();
Console.WriteLine(host.State.ToString());
Console.WriteLine("Kapatmak iin bir tua basnz");
Console.ReadLine();
if (host.State == CommunicationState.Opened)
host.Close();
}
}
}

Servis tarafndaki konfigurasyon dosyasnn ilk hali;

www.bsenyurt.com Page 709


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<services>
<service name="SiparisKutuphanesi.SiparisYonetimi">
<endpoint
address="net.tcp://localhost:4500/SiparisServisi.svc" binding="netTcpBinding" name="Siparis
ServisiEndPoint" contract="SiparisKutuphanesi.ISiparisYonetimi"/>
</service>
</services>
</system.serviceModel>
</configuration>

Balangta servis taraf netTcpBinding balayc tipini kullanacak ekilde tasarlanmtr. Ancak
cevaplama saldrlarnn nne kesmek iin burada zel bir balayc tip tasarlanacaktr. imdi adm
adm bu ilemler gerekletirilecektir. lk olarak, Service Configuration Editor zerinden
aadaki ekran grntsnde yer ald gibi New Binding Configuration balantsna tklanr.

Sonrasdan alan Create a New Binding ksmndan customBinding seilerek OK tuuna baslr.
Bu ilemin sonrasnda oluan duruma gre zel balayc tipin ad, aadaki ekran grntsnde
olduu gibi SiparisServisiOzelBaglayici olarak deitirilebilir.

www.bsenyurt.com Page 710


lk bakldnda iletiim kanal olarak httpTransport tipinin ve mesajlama kanal
olarakta textMessageEncoding' in kullanld grlmektedir. rnekte TCP protokol zerinden
bir haberleme hedeflendii iin httpTransport kanal kaldrlmaldr. Bu ilem iin ayn
ekranda, httpTransport seili iken Remove tuuna baslmas yeterlidir.tcpTransport kanalnn
eklenmesi iin aadaki ekran grntsnde iaretlenen admlarn srasyla yaplmas yeterlidir.

www.bsenyurt.com Page 711


Dikkat edilecek olursa Available Elements ksmnda, zel balayc tip ierisinde kullanlabilecek
pek ok kanal eidi bulunmaktadr. tcpTransport tahmin edilecei zere bir iletiim kanal olarak
servise gelen mesajlarn TCP protokol zerinden alnmasn salamaktadr. rnekte mesajlama
kanal olarak textMessageEncoding kullanlmaktadr. Bu nedenle oluturulan zel balayc tip
ierisinde gelen ilgili kanaln kaldrlmasna gerek yoktur.

Sradaki admda gvenlik ile ilgili bir kanaln eklenmesi gerekmektedir. Bu amala
yine Add dmesi ile(yada Add Binding Element Extension balants kullanlarak) alan
pencereden security elementi seilmelidir.

www.bsenyurt.com Page 712


security elementi ierisinde ise AuthenticationMode zelliinin deeri aadaki ekran
grntsnde olduu gibi SecureConversation olarak ayarlanr.

www.bsenyurt.com Page 713


SecureConversation, Organization for the Advancement of Structured Information
Standards (OASIS - http://www.oasis-open.org/home/index.php) tarafndan kabul edilmi
olan WS-SecureConversation artnamelerine uygun olacak ekilde gvenli bir oturumun
salanmas garanti etmektedir.

zet olarak WS-SecureConversation, iki katlmc arasndaki(rnek senaryoya gre istemci ve


servis) mesajlamada ehliyet bilgilerinin tamamnn gnderilmesini gerektirmeyecek bir ortam
salamaktadr. Bunun salanabilmesi iin oturumun en banda, istemci ve servis
arasnda ehliyet(Credential) bilgileri dei toku edilir ve dorulanr. Geri kalan mesajlamalarda
balangtaki ehliyet bilgilerinden treyen gvenlik fileri(security tokens) kullanlr. Bir baka
deyile oturum banda zaten taraflar ehliyet bilgileri ile birbirlerini doruladklarndan, kalan
mesajlamalarda ayn bilgiler tekrardan kontrol edilmez. Buda ok doal olarak mesajlamann
daha hzl gerekletirilmesini salamaktadr.

SecureConversation seildikten sonra, yine security elementinde servis tarafna ynelik olacak
ekilde baz ayarlar kontrol etmek gerekmektedir. lk olarak aadaki ekran grntsnde
grld gibi DetectReplays seeneinin true olmas salanmaldr ki varsaylan olarak byledir.

www.bsenyurt.com Page 714


Bu ksmda olduka fazla sayda ayar ve kafa kartrc zellik yer almaktadr. Ancak en ok dikkat
ekenlerden birisi ReplayCacheSize deeridir. Buraya atanan deer, tamponda tutulacak olan
nonce' larn saysdr. Sz konusu deerin dna talmas durumunda, tamponda duran en eski
nonce deeri atlacak ve yerine son gelen nonce deeri yazlacaktr. Ancak
varsaylan 900000 deeri pek ok vaka iin yeterli bir saydr. Bellek optimizasyonu adna bu
deerin azaltlmasda dnlebilir. Fakat az ncede belirtildii gibi, saynn dna klmas
halindeki durumlar gz nne alnmaldr. Nitekim eski nonce' larn silindii ve yeni gelenlerin
yazld sralarda sistem cevaplama saldrlarna(Replay Attack) kar ksa srelide olsa
savunmasz kalabilir. Bu ilemlerin ardndan elbetteki balayc tipin gvenilir bir
oturum(Reliable Session) aabilmesi iin, yine Add dmesi ile alan
pencereden ReliableSession elementi seilmelidir.

www.bsenyurt.com Page 715


Artk zel balayc tip ierisinde kullanlacak olan tm kanal ve zellikler belirlenmitir. Son
aamada dikkat edilmesi gereken nokta sz konusu kanallarn uygulan srasdr. Bir baka
deyile kanal yn(Channel Stack) ierisindeki srann nemi vardr. Yukarda gelitirilen rnee
gre sra aadaki ekran grntsndeki gibi olmaldr. Buna gre reliableSession ile balayan sra
security, textMessageEncoding(Mesajlama Kanal) ve tcpTransport(iletiim kanal) eklinde devam
etmelidir. Bu sray ayarlamak iin Up ve Down balkl dmeler kullanlabilir.

Elbette oluturulan bu zel balayc tipin(Custom Binding Type) kullanlabilmesi


iin endPoint ile ilikilendirilmesi gerekmektedir. Bu sebepten tek yaplmas
gerekenSiparisServisiEndPoint isimli endPoint seili iken, Binding zelliinin
deerinin customBinding olarak iaretlenmesidir.

www.bsenyurt.com Page 716


Bu ilem srasnda Binding deeri customBinding olarak
seildiinde BindingConfiguration zelliinin deeri otomatik
olarak SiparisServisiOzelBaglayici olarak deiecektir. Servis tarafnda yaplan bu ayarlardan
sonra konfigurasyon dosyasnn son hali aadaki gibi olacaktr.

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


<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="SiparisServisiOzelBaglayici">
<reliableSession />
<security authenticationMode="SecureConversation">
<secureConversationBootstrap />
</security>
<textMessageEncoding />
<tcpTransport />
</binding>
</customBinding>
</bindings>
<services>
<service name="SiparisKutuphanesi.SiparisYonetimi">
<endpoint
address="net.tcp://localhost:4500/SiparisServisi.svc" binding="customBinding" bindingConfig
uration="SiparisServisiOzelBaglayici" name="SiparisServisiEndPoint"
contract="SiparisKutuphanesi.ISiparisYonetimi" />
</service>
</services>
</system.serviceModel>
</configuration>

ok doal olarak burada yaplan konfigurasyon deiikliklerinin istemci tarafndaki uygulamada da


yaplmas gerekmektedir. Ama ncesinde istemci iin gerekli proxy snfnnsvcutil arac yardmyla
aadaki gibi retilmesi salanmaldr.

www.bsenyurt.com Page 717


Sonrasnda ise bu proxy snf Console tipinden tasarlanan istemci uygulamaya tanarak kullanlr.
stemci uygulamann kodlar ve konfigurasyon dosyasnn ierii ise aadaki gibidir.

stemci uygulama kodlar;

using System;
using System.ServiceModel;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Sipari vermek iin tua basn...");
Console.ReadLine();
SiparisServisiClient cli = new SiparisServisiClient("IstemciEndPoint");
cli.SiparisEkle(1);
cli.SiparisEkle(4);
cli.SiparisleriOnayla();
Console.WriteLine("lemler tamamland...kmak iin bir tua basnz");
Console.ReadLine();
}
}
}

stemci uygulama basit olarak servis zerinden SiparisEkle ve SiparisleriOnayla metodlarn


armaktadr.

stemci taraf konfigurasyon dosyas;

www.bsenyurt.com Page 718


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<customBinding>
<binding name="SiparisIstemciOzelBaglayici">
<reliableSession />
<security authenticationMode="SecureConversation">
<secureConversationBootstrap />
</security>
<textMessageEncoding />
<tcpTransport />
</binding>
</customBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:4500/SiparisServisi.svc"
binding="customBinding" bindingConfiguration="SiparisIstemciOzelBaglayici"
contract="SiparisServisi"name="IstemciEndPoint">
</endpoint>
</client>
</system.serviceModel>
</configuration>

stemci tarafndaki konfigurasyon dosyasnn daha kolay retilmesi amacyla, istemci uygulamaya
standard bir app.config dosyas eklendikten sonra Service Configuration Editor yardmyla
alan pencerede Create a New Client sonras alan New Client Element Wizard blm
kullanlabilir. Burada From service config seili iken Config File ksmna servis uygulamasndaki
konfigurasyon dosyasn iaret etmek yeterlidir. Yanlz burada proxy snf kullanld
iin szleme arayz(Contract Interface) adnn servis tarafndaki gibi olmad
unutulmamaldr. Bu nedenle bu retim sonrasnda oluan konfigurasyon
ierisinde endPoint elementinde yer alan binding niteliinin(attribute)deeri uygun ekilde
deitirilmelidir. rnekte bu deer SiparisServisi olarak deitirilmelidir.

www.bsenyurt.com Page 719


Gelinen bu noktadan sonra sistem test edilebilir. Sz konusu sistem cevaplama saldrlarna kar
nlem alan zel bir balayc tipi kullanmaktadr. rnek uygulamalarda yine loglarn izlenmesi
ilemi gerekletirilirse mesajlarn ieriinde yaznn bandada belirtilen tanmlama deerlerinin yer
ald (timestamp gibi...), bununla birlikte mesajlarn boyutlarnn dahada artt grlr. Mesaj
boyutlarndaki bu art ok doal olarak paketlerin bymesi anlamnada gelmektedir. Ancak vaka
ierisinde Replay Attackolasl var ise bu gz ard edilmeli ve gereken tedbirler alnmaldr.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Gvenilir Oturumlar(Reliable Sessions) (


01.11.2007 ) - WCF
Deerli Okurlarm Merhabalar,

WCF(Windows Communication Foundation) bilindii zere bir servis ynelimli


mimari(Service Oriented Architecture) yaklamdr. Buda basite, birbirleriyle
haberleenistemci(client) ve sunucu(server) uygulamalarn var olmas anlamna gelmektedir.
Bu haberleme ok doal olarak bir a(network) ortam zerinde gerekleir. A ortam intranet
gibi bir sistem olabilecei gibi kablolu veya kablosuz(wireless) bir internet ortamda olabilir. Hal
byle olunca arada hareket etmekte olan mesajlarn gvenlii nem arz eden bir konudur. Mesaj

www.bsenyurt.com Page 720


gvenliinden kast sadece ifreleme yada sertifikal bir iletiimin salanmas demek deildir.
Bunlarn salanmas iin WCF mimarisi ierisindede eitli teknikler bulunmaktadr. Bu teknikler bir
yana istemci ve sunucu(servis) arasnda gvenilir bir oturumun(reliable session) var olmas
gereken durumlarda sz konusudur. Gvenilir bir oturum salanmas iin gereken sebepler
arasnda aadaki maddeler gz nne alnabilir;

A ortamnda istemci ve servis arasndaki balantnn kopmas olasdr.


Arada hareket etmekte olan mesajlar kesintiye urayabilir.
stemciden servis tarafna gelmekte olan mesajlar farkl yollar zerinden hedeflerine
ulamaktadr. Byle bir durumda servise farkl sralarda ulamalar sz konusudur. Ancak
mesaj sras nemli olabilir.
Mesajlar beklenmedik bir ekilde kaybolabilir yada farkl bir yere doru ynlendirilebilir.

Bu seenekler gz nne alndnda istemci ve sunucu arasnda gvenilir bir oturum alma ihtiyac
daha belirgin bir ekilde ortaya kmaktadr. Nitekim arada hareket eden mesajlarn nc kiiler
tarafndan yakalanmas zellikle cevaplama saldrlar(Reply Attacks) ile ok farkl amalarla
kullanlabilir. Bunun iin rnek olarak bir alveri sitesinin ileyii ele alnabilir. nc ahs, bir
sipari bilgisine ait mesaj yakalayp defalarca sunucuya ilenmesi iin gnderebilir. Bunun
sonucunda alverii yapan gerek kii, hi yapmam olduu siparilerle kar karya kalacaktr.
stelik nc ahs, bu mesajlar istedii zaman gnderme imkanna sahip olabilir.

Cevaplama saldrlarnn(Reply Attack) dnda istemcilerin gnderecei taleplere ait mesajlarn


servis tarafnda, istemciden gnderildii srada ele alnmas gerekebilir ki buda gvenilir
oturumlarn salanmas iin yeterli nedenlerdendir. Windows Communication Foundation mimari alt
yaps ierisinde gvenilir oturumlar(Reliable Sessions) alabilmesi iin gereken zellikler yer
almaktadr. Nitekim gvenilir oturumlarn alabilmesi iin gerek ve yeter art WS-
ReliableMessaging protokolne uygun bir ortamn salanm olmasdr. WCF bu protokol
dorudan destekleyen eitli balayc tipler(bindiny types) iermektedir.

WS-ReliableMessaging, Web servislerine ynelik olarak gelitirilmi platform bamsz


pek ok standarttan sadece bir tanesidir. Toplu olarak WS-* eklinde ifade edilen tm
Web servisi standartlar
iin http://en.wikipedia.org/wiki/List_of_Web_service_specifications adresinden bilgi
alnabilir.

WS-ReliableMessaging, tek bir kaynak(Source) ve tek bir hedef(Target) arasnda gvenilir bir
mesajlama iin gereken artnameleri ieren Organization for the Advancement of Structured
Information Standards (OASIS - http://www.oasis-open.org/home/index.php) organizasyonu
tarafndan kabul edilmi bir protokoldr. Son olarak 14 Haziran 2007 tarihinde 1.1 versiyonu
yaynlanmtr. WS-ReliableMessaging standardnn amac; gvenilir olmayan bir altyap(Unreliable
Infrastructure) zerinde koan bir kaynak uygulamadan hedef uygulamaya doru gvenilir bir
ekilde mesaj gnderilmesini salamaktr. Mesajn ieriinin ifrelenmesi veya iletiim kanalnn
gvenli hale getirilmesi(rnein Secure Socket Layer ile) konular ile ilgilenmez.
Bu artnameye(Specification) gre gvenilir oturumlarda sz konusu olan mimari model
aadaki ekilde olduu gibidir.

www.bsenyurt.com Page 721


ekilde kaynak uygulama ile hedef uygulama arasndaki bir mesajlama trafii yer almaktadr.
Burada Uzak Mesajlama Kayana mesaj gnderirken WS-ReliableMessaging kullanr. Dier
taraftan burada tek bir kaynak ve tek bir hedef vardr. WCF(Windows Communication Foundation)
bu protokoln kullanmna destek vererekten aadaki maddelerde grlen kazanmlar
salamaktadr;

Kaynaktan gnderilen tm mesajlarn hedefe varmas garantilenir.


Kaynaktan hedefe gnderilen mesajlarn tekrar edilmesi nlenir. Bir baka deyile mesajn
sadece bir tane gnderilmesi garanti edilir.
Kayp mesajlar tespit edilir ve mmknse bunlarnda kaynaktan hedefe doru yeniden
gnderilmesi salanr.
Kaybolan mesajlarn geri alnmayacak durumda olmas
halinde istisna(exception) frlatlmas salanr.
Opsiyonel olarak mesajlarn gnderildikleri srada ilenmeleri garantilenir. WCF bu
amala tampon(buffer) sistemini kullanlr. Buna gre tm mesajlar tamponda toplanr ve
gnderildikleri sraya gre hedef tarafnda ilenir.

WS-ReliableMessaging, mesajlarn servis tarafnda gnderildikleri srada ele alnmalarn


salayan artnameler(Specifications) sunmasna ramen gerek anlamda,MSMQ(MicroSoft
Messaging Queing) sisteminde olduu gibi bir mesaj kuyruu yaps bildirmez. MSMQ bunun iin
farkl bir form kullanr.

WS-ReliableMessaging, Windows Communication Foundation dnda BEA WebLogic,


IBM WebSphere, Apache Sandesha gibi sistemler tarafndanda ele alnmaktadr.

WCF mimarisinde aslnda sz konusu protokoln salanmas iin gereken te ey kaynak ve hedef
uygulamalarn ayn zaman dilimi ierisinde alyor olmalardr. WCF sistemi ierisinde yer alan
balayclardan basicHttpBinding, netNamedPipeBinding, netPeerTcpBinding tipleri gvenili
r oturumlar(Reliable Sessions) desteklememektedir. Bununla birlikte wsDualHttpBinding tipi
iin gvenilir oturumlar kaldrlamaz. MSMQ destei veren balayclardan
olan msmqIntegrationBinding ve netMsmqBinding tipleri ise kendi gvenilir oturum
artnamelerini uygularken WS-ReliableSession standardn kullanmazlar. Aslnda konu ile ilikili
olarak aadaki tablonun gz nne alnmas nemlidir.

www.bsenyurt.com Page 722


Varsaylan Varsaylan
Gvenilir Sral
Balayc Tip Gvenilir Sral
Oturum Mesaj
(Binding Type) Oturum Mesaj
Destei Destei
Hali Destei

netNamedPipeBinding Yok X Var X


netTcpBinding Var Ak Var Kapal

netPeerTcpBinding X
wsDualHttpBinding Var Ak Var Ak

wsHttpBinding Var Kapal Var Ak

wsFederationHttpBinding Var Kapal Var Ak

basicHttpBinding

netMsmqBinding
(Bu balayc standart Web Servisi(asmx)
modelini sunar. Bu modelde varsaylan olarak X
gvenilir oturumlar bulunmamaktadr.)

msmqIntegrationBinding
(MSMQ tabanl bir kuyruk sistemi kullanrlar.)

Bu teorik bilgilerden sonra artk bir rnek ile devam etmekte fayda bulunmaktadr. rnekte basit
olarak netTcpBinding kullanan bir WCF sistemi yer almaktadr. Sistemde yer alan servis
szlemesi(Service Contract) ve uygulayc tipe ait ierikler aada grld gibi olmakla birlikte,
FabrikaLib isimli bir WCF Snf Ktphanesi(WCF Class Library)ierisinde yer almaktadrlar.

Servis szlemesi;

www.bsenyurt.com Page 723


using System;
using System.ServiceModel;

namespace FabrikaLib
{
[ServiceContract(Name="UretimServisi",
Namespace="http://www.bsenyurt.com/FabrikaLib/UretimServisi" ,
SessionMode=SessionMode.Required)]
public interface IUretici
{
[OperationContract(IsInitiating=true)]
int BilesenAl(string[] bilesenAdi);
[OperationContract(IsInitiating=false)]
void Karistir();
[OperationContract(IsInitiating=false,IsTerminating=true)]
bool UretimiYap();
}
}

Servis szlemesinde(Service Contract) dikkat edilecei zere her istemci(Client) iin bir
oturum(Session) almasn garantilemek
adna SessionMode zelliineSessionMode.Required deeri atanmtr. Gvenilir oturumlarda ilk
artlardan birisi, istemci ile servis arasnda bir oturumun sz konusu olmasdr. Bu nedenle bir
oturumun mutlaka hazrlanmas isteinin Servis szlemesinde belirtilmesi yerinde bir karardr.
Bununla birlikte metodlarn ileyi sralarda OperationContract niteliklerine(attribute) ait
zellikler ile belirlenmitir. Buna gre istemci tarafndan ilk arlabilecek metod BilesenAl
fonksiyonu iken oturumu sonlandrma ilemini stlenecek olan ilevse UretimiYap isimli
fonksiyondur.

Uygulayc snf;

using System;
using System.ServiceModel;

namespace FabrikaLib
{
[ServiceBehavior(InstanceContextMode= InstanceContextMode.PerSession)]
public class Uretici:IUretici
{
#region IUretici Members

public int BilesenAl(string[] bilesenler)


{
// Bileenin eklenme ilemi
return bilesenler.Length;
}

public void Karistir()


{
// Bileenin kartrlma ilemi
}

public bool UretimiYap()


{
return true;

www.bsenyurt.com Page 724


}

#endregion
}
}

Her bir istemci iin bir oturumun almasn salamak adna Uretici
snfna ServiceBehavior nitelii ile PerSession atamas yaplmtr. Servis tarafndan sunulmakta
olan fonksiyonelliklerin ne i yapt u aamada ok nemli deildir. rnekteki asl ama, istemci
ve servis arasnda gvenilir bir oturum(Reliable Session) almas ve arada hareket eden
mesajlarn izlenerek(Trace) durumunun detayl analizinin yaplmasdr. Servis taraf basit olmas
asndan bir Console uygulamas olarak tasarlanmtr. Servis tarafna ait Main kodlar ile
konfigurasyon dosyasnn ierii balangta aadaki gibidir.

Servis uygulamas kodlar;

using System;
using System.ServiceModel;
using FabrikaLib;

namespace Sunucu
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Uretici));
host.Opened += new EventHandler(host_Opened);
host.Closed += new EventHandler(host_Closed);
host.Open();
Console.ReadLine();
host.Close();
}

static void host_Closed(object sender, EventArgs e)


{
Console.WriteLine("Servis kapatld");
}

static void host_Opened(object sender, EventArgs e)


{
Console.WriteLine("Servis dinlemede");
}
}
}

Servis taraf konfigurasyon ierii;

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


<configuration>
<system.serviceModel>
<bindings />
<behaviors>
<serviceBehaviors>

www.bsenyurt.com Page 725


<behavior name="UretimServisiBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="UretimServisiBehavior" name="FabrikaLib.Uretici">
<endpoint address="net.tcp://localhost:9000/Fabrika/UretimServisi.svc"
binding="netTcpBinding" name="UretimServisiEndPoint" contract="FabrikaLib.IUretici"
/>
</service>
</services>
</system.serviceModel>
</configuration>

stemci uygulama zerinde, servis tarafnda oluabilecek istisnalar(Exception) detayl bir ekilde
ele alabilmek iin serviceDebug elementinde includeExceptionDetailInFaultsniteliinin
deeri true olarak set edilmitir. stemci tarafda servis taraf gibi bir Console uygulamas olarak
tasarlanabilir.

stemci taraf iin gerekli olan proxy snf ve servise gre otomatik oluturulan
konfigurasyon dosyasnn retimi iin svcutil.exe aracndan aadaki gibi yararlanlmas
gerekmektedir.

svcutil FabrikaLib.dll

svcutil www.bsenyurt.com.FabrikaLib.UretimServisi.wsdl *.xsd


/out:UretimServisi.cs

Bu ilemin ardndan proxy snf ve konfigurasyon dosyas, istemci uygulamaya tanr.

stemci tarafndaki kodlar ve konfigurasyon ierii ise aadaki gibidir.

stemci uygulamas kodlar;

using System;
using System.ServiceModel;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
try
{
Console.WriteLine("lemi balatmak iin bir tua basnz...");
Console.ReadLine();
UretimServisiClient cli = new
UretimServisiClient("UretimServisiClientEndPoint");
cli.BilesenAl(new string[] { "C", "O2", "H2SO4" });
cli.Karistir();
string durum = cli.UretimiYap()==true?"retim gerekletirildi":"retim yaplamad";
Console.WriteLine(durum);

www.bsenyurt.com Page 726


Console.ReadLine();
}
catch (Exception excp)
{
Console.WriteLine(excp.Message);
}
}
}
}

stemci taraf konfigurasyon ierii;

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


<configuration>
<system.serviceModel>
<bindings />
<client>
<endpoint address="net.tcp://localhost:9000/Fabrika/UretimServisi.svc"
binding="netTcpBinding" contract="UretimServisi"
name="UretimServisiClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

Normalde svcutil tarafndan retilen konfigurason dosyas ierisinde ok daha fazla zellik yer
almaktadr. Bu niteliklerin deerleri u aamada nemli olmadndan istemci konfigurasyon
dosyas bilinli olarak yukardaki gibi sadeletirilmitir.

Asl ilemler bundan sonra balamaktadr. Ama gvenilir bir oturum ortam hazrlamaktr. Bunu
gerekletirmek son derece basittir. Tek yaplmas gereken balayc ile ilgili zel konfigurasyonlar
ve iinde yer alan zelliklerin deerlerini uygun bir ekilde belirlemektir. Servis
tarafnda netTcpBinding iin bir BindingConfiguration eklenmelidir. Sz konusu ksmda,
aadaki ekildende grld
gibi ReliableSession Properties blmnden Enabled zellii true olarak belirlenmelidir.
Bylece gvenilir bir oturumun tesis edilecei belirtilmi olunur. InactivityTimeout zelliinin
ald deer ile, mesajlarn kaybolma ihtimali iin gereken bekleme sresi ayarlanr. Yani, 10
dakikalk sre ierisinde beklenen mesaj alnmassa ters giden bir eyler olduuna karar verilir
ve WCF alma zaman(Run Time) bir Fault Exception reterek bunu istemci tarafna
gnderir. Ayn zamanda o ana kadar yaplm olan ilemler geri alnr(Rollback) ve istemci ile
servis arasndaki gncel oturum sonlandrlr. Ordered zelliine atanan deerin true olarak set
edilmesi ile, servise gelen mesajlarn istemcinin gnderdii srada ele alnmalar garanti edilmi
olunmaktadr. Bu zorunlu olmamasna ramen gvenilir oturumlarn salanmas adna nemlidir.

www.bsenyurt.com Page 727


Binding ayarlarnda dikkat edilmesi gereken noktalardan biriside TransferMode zelliinin
deeridir. netTcpBinding balayc tipi(Binding Type) iin bu deer varsaylan olarak aadaki
ekilde grld gibi Buffered olarak belirlenmitir.

NetTcpBinding kulland transfer protokol(TCP) nedeni ile Stream' lere izin vermektedir. Bir
baka deyile istemcinin gnderdii mesajlarn servis tarafnda tamamlanmasn beklemeden
ilenmesine balanabilmektedir. Ancak gvenilir oturumlarda, mesajlarn tamamlandktan sonra,
bir baka deyile servis tarafna ulatktan sonra ele alnmalar doru srada ilenmeleri sz konusu
olduunda nemlidir. Bu sebepten bu varsaylan deerin deitirilmemesi nerilir. Dier taraftan

www.bsenyurt.com Page 728


zellikle WsHttpBinding gibi balayc tipler,Stream yapsn HTTP protokol nedeni ile
desteklemediklerinden her zaman iin Buffered sistemi ile alrlar.

Yukarda yaplan deiiklikler sonrasnda servis tarafnda yer alan konfigurasyon dosyasnn son hali
aadaki gibi olacaktr.

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


<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="BConf" transferMode="Buffered">
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="true" />
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="UretimServisiBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="UretimServisiBehavior" name="FabrikaLib.Uretici">
<endpoint address="net.tcp://localhost:9000/Fabrika/UretimServisi.svc"
binding="netTcpBinding" bindingConfiguration="BConf" name="UretimServisiEndPoint"
contract="FabrikaLib.IUretici" />
</service>
</services>
</system.serviceModel>
</configuration>

ok doal olarak istemci uygulama tarafndada servis tarafndakine benzer olacak ekilde
konfigurasyon ayarlarnn yaplmas gerekmektedir. Ayn admlar izlenildiinde istemci tarafndaki
konfigurasyon dosyasn son halide aadaki gibi olacaktr.

www.bsenyurt.com Page 729


<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="BConf" transferMode="Buffered">
<reliableSession ordered="true" inactivityTimeout="00:10:00"
enabled="true" />
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:9000/Fabrika/UretimServisi.svc"
binding="netTcpBinding" bindingConfiguration="BConf" contract="UretimServisi"
name="UretimServisiClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

Olaya istemci asndan bakldnda alma aamasnda dikkate deer baz noktalar vardr.
Hereyden nce istemci uygulama, servis tarafnda belirtilen timeoutsresi dahilinde mesaj
gndermeyi brakm olabilir. Bu ounlukla istemci uygulama kullancsnn bu ynde bir aksiyon
gerekletirmedii durumlarda sz konusu olabilir. Tabi burada istemci ile servis arasnda bir
oturum aldktan sonraki sre zarf ele alnmaktadr. Bu tarz bir durumda istemcinin a zerinde
asl kald yorumu yaplr. Dolaysyla servisin istenmeyen bir ekilde Fault
Exception dndrmesi olasdr. Bu sebepten, istemci taraftaki WCF alma Zaman(Run
Time) belirli periyodlarda servis tarafna canl olduuna dair mesajlar gnderir. Bylece servis
taraf, kendisine bal oturumun sahibi olan istemcinin halen daha canl olduundan haberdar olur.
Bununla birlikte istemci uygulama, servis tarafndan bir onay mesaj(Acknowledge
Message) bekler. Eer bu mesaj istemci tarafnda belirtilen InactivityTimeout sresinde

www.bsenyurt.com Page 730


alnamyorsa, servisin bir ekilde ld sonucuna varlr ve istemci tarafnda WCF alma
zaman(Run Time) bir istisna(Exception) frlatr. Bu istisna, istemci tarafnda ele alnmal ve
uygulamann istem d ekilde sonlanmasnn nne geilmelidir.

Artk istemci ve servis arasnda gvenilir bir oturum almas iin gereken ayarlar tamamlanmtr.
Bu oturumun tesis edilmesi halinde, arada gidip gelen mesajlarn incelenebilmesi adna servis
tarafnda gerekli ayarlarn yaplmas gerekmektedir. Bu amala yine konfigurasyon
ierisinde Diagnostics ayarlar yaplmaldr. lk olarak EnableMessageLogginglinkine tklanarak
mesaj gnl aktif hale getirilir. Sonrasnda ise Diagnostics klasrnde yer
alan Message Logging ksmna
gidilerek LogEntireMessage deeri true,LogMalformedMessages deeride false olarak set
edilir.

Bu ilemin ardndan Listeners klasrndeki ServiceModelMessageLoggingListener ksmna


gidilerek InitData zelliine bir svclog dosyas ad ve tam adresi aadaki ekilde olduu gibi
bildirilir. Tahmin edilecei zere servis tarafna ulaan ve istemciye giden mesaj ierikleri bu dosya
ierisinde toplanacaktr.

Bu ilemlerin ardndan servis tarafndaki konfigurasyon dosyasnn ierii aadaki gibi olacaktr.

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


<configuration>

www.bsenyurt.com Page 731


<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging"
switchValue="Warning, ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener"
name="Default">
<filter type="" />
</add>
<add name="ServiceModelMessageLoggingListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add
initializeData="c:\app_messages.svclog" type="System.Diagnostics.XmlWriterTraceListener,
System,
Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089"
name="ServiceModelMessageLoggingListener" traceOutputOptions="Timestamp">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMalformedMessages="false"
logMessagesAtTransportLevel="true" />
</diagnostics>
<bindings>
<netTcpBinding>
<binding name="BConf" transferMode="Buffered">
<reliableSession ordered="true" inactivityTimeout="00:10:00" enabled="true" />
</binding>
</netTcpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="UretimServisiBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="UretimServisiBehavior" name="FabrikaLib.Uretici">
<endpoint address="net.tcp://localhost:9000/Fabrika/UretimServisi.svc"
binding="netTcpBinding" bindingConfiguration="BConf" name="UretimServisiEndPoint"
contract="FabrikaLib.IUretici" />
</service>
</services>
</system.serviceModel>
</configuration>

Mesajlarn izlenmesi iin Windows SDK ile birlikte gelen Service Trace Viewer programna
ihtiya vardr. stemci ve servis uygulamas altrlarak test edildikten sonra Service Trace Viewer

www.bsenyurt.com Page 732


yardmyla mesajlama trafii izlenebilir. lk testin ardndan C klasr
altnda app_messages.svclog isimli bir dosya otomatik olarak oluturulup ierii doldurulacaktr.
Dosya, Service Trace Viewer program ile aldnda aadaki ekran grntsne benzer bir
ekilde 15 adet mesajn retildii grlecektir.

imdi bu mesajlar ksaca analiz edilebilir. lk mesajn ierii aadaki gibidir.

<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Action s:mustUnderstand="1">
http://schemas.xmlsoap.org/ws/2005/02/rm/CreateSequence</a:Action>
<a:MessageID>urn:uuid:1d14de59-6695-4149-b218-
cb41783db18d</a:MessageID>

www.bsenyurt.com Page 733


<a:To s:mustUnderstand="1">
net.tcp://localhost:9000/Fabrika/UretimServisi.svc</a:To>
</s:Header>
<s:Body>
<CreateSequence xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">
<AcksTo>
<a:Address> http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</AcksTo>
<Offer>
<Identifier> urn:uuid:be73ae30-145a-4bd6-bf04-
ee6a3b1edfce</Identifier>
</Offer>
</CreateSequence>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

Bu mesaj ile istemci ve servis arasnda gvenilir bir oturum balatlmaktadr. Tahmin edilecei
zere mesaj istemci tarafndan servise gnderilmitir. Ayn gvenilir oturumda yer alan tm
mesajlar ayn benzersiz numara kmesini (Unique Identifier Set) kullanrlar. Bu anlamda ilk
mesajn ierisinde yer alan MessageID deeri ikinci mesaj ierisinde de ele alnmaktadr. kinci
mesaj, servis tarafndan istemciye gnderilen mesajdr ve ierii aadaki gibidir.

<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<a:Actions:mustUnderstand="1"> http://schemas.xmlsoap.org/ws
/2005/02/rm/CreateSequenceResponse</a:Action>
<a:RelatesTo>urn:uuid:1d14de59-6695-4149-b218-
cb41783db18d</a:RelatesTo>
<a:To
s:mustUnderstand="1">http://www.w3.org/2005/08/addressing/anonymous</a:To>
</s:Header>
<s:Body>
<CreateSequenceResponse xmlns="http://schemas.xmlsoap.org/ws/2005/02/rm">
<Identifier> urn:uuid:27079656-f1cf-460d-9289-28f43f664fbe</Identifier>
<Accept>
<AcksTo>
<a:Address>
net.tcp://localhost:9000/Fabrika/UretimServisi.svc</a:Address>
</AcksTo>
</Accept>
</CreateSequenceResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

kinci mesajda retilen Identifier elementinin deerinin, istemci tarafndan sonradan gnderilecek
mesajlarda mutlaka salanmas gerekmektedir. Bylece aradaki mesajlarn ayn gvenilir
oturum(Reliable Session) ierisinde olaca anlalabilir. Buna gre istemci tarafndan ilk metod
ars iin gnderilen nc mesaj ierii aadaki gibi olacaktr.

<MessageLogTraceRecord>

www.bsenyurt.com Page 734


<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-
envelope" xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:AckRequested>
<r:Identifier> urn:uuid:27079656-f1cf-460d-9289-28f43f664fbe
</r:Identifier>
</r:AckRequested>
<r:Sequence s:mustUnderstand="1">
<r:Identifier> urn:uuid:27079656-f1cf-460d-9289-28f43f664fbe
</r:Identifier>
<r:MessageNumber>1</r:MessageNumber>
</r:Sequence>
<a:Action s:mustUnderstand="1">
http://www.bsenyurt.com/FabrikaLib/ UretimServisi/UretimServisi/BilesenAl</a:Action>
<a:MessageID>urn:uuid:a6127691-9534-4f46-a3ff-
97943cd19b30</a:MessageID>
<a:ReplyTo>
<a:Address> http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">
net.tcp://localhost:9000/Fabrika/UretimServisi.svc</a:To>
</s:Header>
<s:Body>
<BilesenAl xmlns="http://www.bsenyurt.com/FabrikaLib/UretimServisi">
<bilesenAdi xmlns:b="http://schemas.microsoft.com/2003/10/Serialization/Arrays"
xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<b:string>C</b:string>
<b:string>O2</b:string>
<b:string>H2SO4</b:string>
</bilesenAdi>
</BilesenAl>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

nc mesaj BilesenAl isimli metod iin bir ar olduundan SOAP paketinin gvdesi
(Body) ierisinde parametre deerleride gnderilmektedir. Dier
taraftanMessageNumber elementi ile gnderilen mesajn sra numarasda belirlenmi olmaktadr.
nc mesaj ile gelen metod arsna karlk olaraktan servis taraf bir cevap mesajn drdnc
mesaj olarak istemciye gnderecektir. Drdnc mesajn ierii aadaki gibidir.

<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:SequenceAcknowledgement>
<r:Identifier> urn:uuid:27079656-f1cf-460d-9289-
28f43f664fbe</r:Identifier>
<r:AcknowledgementRange Lower="1" Upper="1"></r:AcknowledgementRange>
<netrm:BufferRemaining
xmlns:netrm="http://schemas.microsoft.com/ws/2006/05/rm"> 8</netrm:BufferRemaining>
</r:SequenceAcknowledgement>
<r:AckRequested>

www.bsenyurt.com Page 735


<r:Identifier> urn:uuid:be73ae30-145a-4bd6-bf04-
ee6a3b1edfce</r:Identifier>
</r:AckRequested>
<r:Sequence s:mustUnderstand="1">
<r:Identifier> urn:uuid:be73ae30-145a-4bd6-bf04-
ee6a3b1edfce</r:Identifier>
<r:MessageNumber>1</r:MessageNumber>
</r:Sequence>
<a:Action s:mustUnderstand="1"> http://www.bsenyurt.com/FabrikaLib/
UretimServisi/UretimServisi/BilesenAlResponse</a:Action>
<a:RelatesTo>
urn:uuid:a6127691-9534-4f46-a3ff-97943cd19b30</a:RelatesTo>
<a:To s:mustUnderstand="1">
http://www.w3.org/2005/08/addressing/anonymous</a:To>
</s:Header>
<s:Body>
<BilesenAlResponse xmlns="http://www.bsenyurt.com/FabrikaLib/UretimServisi">
<BilesenAlResult>3</BilesenAlResult>
</BilesenAlResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

Bu mesaj ierisindede istemciye biraz nce gnderdii mesajn baarl bir ekilde alnd ve
onayland bilgisi iletilmektedir. Sradaki beinci mesaj ile istemci servise bir onaylama bildirisi
gndermektedir ve ierii aadaki gibidir.

<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:SequenceAcknowledgement>
<r:Identifier> urn:uuid:be73ae30-145a-4bd6-bf04-
ee6a3b1edfce</r:Identifier>
<r:AcknowledgementRange Lower="1" Upper="1"> </r:AcknowledgementRange>
<netrm:BufferRemaining xmlns:netrm="http://schemas.microsoft.com/ws/2006/05/r
m">8</netrm:BufferRemaining>
</r:SequenceAcknowledgement>
<a:Action s:mustUnderstand="1"> http://schemas.xmlsoap.org/
ws/2005/02/rm/SequenceAcknowledgement</a:Action>
<a:To s:mustUnderstand="1">
net.tcp://localhost:9000/Fabrika/UretimServisi.svc</a:To>
</s:Header>
<s:Body></s:Body>
</s:Envelope>
</MessageLogTraceRecord>

Bu mesaj drdnc mesajn ve ieriinin istemci tarafndan alndn servis tarafna


bildirmektedir. SequenceAcknowledgment elementinde yer alan identifier deerine baklrsa
birinci mesajda retilen identifier ile ayn olduu grlebilir. Hemen arkasndan gelen altnc
mesaja bakldnda istemcinin ikinci metod arsn gerekletirdii grlr.

<MessageLogTraceRecord>

www.bsenyurt.com Page 736


<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:Sequence s:mustUnderstand="1">
<r:Identifier> urn:uuid:27079656-f1cf-460d-9289-
28f43f664fbe</r:Identifier>
<r:MessageNumber>2</r:MessageNumber>
</r:Sequence>
<a:Action
s:mustUnderstand="1"> http://www.bsenyurt.com/FabrikaLib/UretimServisi/UretimServisi/Karisti
r</a:Action>
<a:MessageID> urn:uuid:180ea9af-ddbc-4249-8880-
40c412088ce3</a:MessageID>
<a:ReplyTo>
<a:Address>
http://www.w3.org/2005/08/addressing/anonymous</a:Address>
</a:ReplyTo>
<a:To s:mustUnderstand="1">
net.tcp://localhost:9000/Fabrika/UretimServisi.svc</a:To>
</s:Header>
<s:Body>
<Karistir xmlns="http://www.bsenyurt.com/FabrikaLib/UretimServisi"></Karistir>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

eriktende grld gibi Karistir metoduna bir ar gelmektedir. Ancak burada nemli olan
noktalardan biriside MessageNumber deeridir. Dikkat edilecek olursa 2 deeri gelmektedir. Bir
baka deyile bu mesajn ikinci srada ele alnmas gerektii belirtilmi olmaktadr. stemci
tarafndan metod arlar sonucu oluturulan mesajlarn ayn gvenilir oturumda yer almas ama
farkl mesajlar olarak ele alnmas MessageID deerleri sayesinde gerekletirilir. Bu nedenle
burada retilen MessageID deeri bir nceki metod arsnda retilenden farkl olarak
belirlenmektedir. Altnc mesaj iin servisin rettii yedinci mesajn ierii aadaki gibidir.

<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:SequenceAcknowledgement>
<r:Identifier> urn:uuid:27079656-f1cf-460d-9289-
28f43f664fbe</r:Identifier>
<r:AcknowledgementRange Lower="1" Upper="2"></r:AcknowledgementRange>
<netrm:BufferRemaining
xmlns:netrm="http://schemas.microsoft.com/ws/2006/05/rm"> 8</netrm:BufferRemaining>
</r:SequenceAcknowledgement>
<r:Sequence s:mustUnderstand="1">
<r:Identifier> urn:uuid:be73ae30-145a-4bd6-bf04-
ee6a3b1edfce</r:Identifier>
<r:MessageNumber>2</r:MessageNumber>
</r:Sequence>
<a:Action s:mustUnderstand="1">
http://www.bsenyurt.com/FabrikaLib/UretimServisi/UretimServisi/KaristirResponse </a:Action>
<a:RelatesTo> urn:uuid:180ea9af-ddbc-4249-8880-

www.bsenyurt.com Page 737


40c412088ce3</a:RelatesTo>
<a:To s:mustUnderstand="1">
http://www.w3.org/2005/08/addressing/anonymous</a:To>
</s:Header>
<s:Body>
<KaristirResponse xmlns="http://www.bsenyurt.com/FabrikaLib/UretimServisi">
</KaristirResponse>
</s:Body>
</s:Envelope>
</MessageLogTraceRecord>

Bu mesajlama trafii dier metod ars iinde benzer ekilde ileyecektir. stemcinin yapt
metod arlar sona erdikten sonra ise, servis tarafna aadaki mesaj gnderilir. (rnek
uygulamadaki alma sistemine gre Service Trace Viewer sonlandrma talebi onuncu mesaj
olarak elde edilmektedir.)

<MessageLogTraceRecord>
<s:Envelope xmlns:s="http://www.w3.org/2003/05/soap-envelope"
xmlns:r="http://schemas.xmlsoap.org/ws/2005/02/rm"
xmlns:a="http://www.w3.org/2005/08/addressing">
<s:Header>
<r:SequenceAcknowledgement>
<r:Identifier> urn:uuid:be73ae30-145a-4bd6-bf04-
ee6a3b1edfce</r:Identifier>
<r:AcknowledgementRange Lower="1" Upper="3"></r:AcknowledgementRange>
<netrm:BufferRemaining xmlns:netrm=
"http://schemas.microsoft.com/ws/2006/05/rm">8</netrm:BufferRemaining>
</r:SequenceAcknowledgement>
<r:Sequence s:mustUnderstand="1">
<r:Identifier> urn:uuid:27079656-f1cf-460d-9289-
28f43f664fbe</r:Identifier>
<r:MessageNumber>4</r:MessageNumber>
<r:LastMessage></r:LastMessage>
</r:Sequence>
<a:Action s:mustUnderstand="1">
http://schemas.xmlsoap.org/ws/2005/02/rm/LastMessage
</a:Action>
<a:To s:mustUnderstand="1">
net.tcp://localhost:9000/Fabrika/UretimServisi.svc</a:To>
</s:Header>
<s:Body></s:Body>
</s:Envelope>
</MessageLogTraceRecord>

Son mesaj olduunun bildirimi iin r adndaki xml isim alanndaki(Xml Namespace)
LastMessage elementi kullanlr. Bununla birlikte Action elementi ierisinde yaplan
ardaLastMessage bildirimi yaplr. Bu mesajn olumas iin istemcinin oturumu kapatyor
olmas gerekmektedir ki gelitirilen rnekte zaten IsTerminating olarak iaretlenmi metod
arsndan sonra ak olan oturum(Session) kapatlma srecine girecektir. Herey bittikten sonra
retilen mesajlarda yer alan TerminateSequence elementleri ierisinde yer
alanIdentifier deerleri ile istemci ve servis birbilerine artk kaynaklarn kullanmayacaklarn ve
gvenilir oturumu(Reliable Session) kapatacaklar bilgilerini vermektedirler. Yukardaki ileyi
aadaki ekil ilede deerlendirilebilir. ( Mesajlar zerinden bu tarz bir grseli hazrlamak olduka
zorlayc olmutur. Bu nedenle gzden kaan noktalar sz konusu olabilir. Asl dayanak noktas
Service Trace Viewer programnn rettii Message ierikleri olmaldr.)

www.bsenyurt.com Page 738


Mesaj 1 ile Mesaj 5 aras durum;

Mesaj 5 ile Mesaj 9 aras durum;

www.bsenyurt.com Page 739


Mesaj 9 ile Mesaj 15 aras durum;

www.bsenyurt.com Page 740


Elbette gelitirici olarak arka tarafta hareket eden mesajlarn ierikleri ok nemli olmayabilir.
Ancak gvenilir oturumlarda sz konusu olan bir dezavantaj vardr. Buda rnektende grlecei
zere a zerinde istemci ile servis arasnda meydana gelen ekstra mesaj ykdr. Dolaysyla bu
ekstra mesaj yk, zellikle ok fazla istemcinin olduu sistemlerde performans kayb
yaatmaktadr. Dolaysyla gvenilir oturumlar(Reliable Session) kullanmadan nce
gerekliliklerin ortaya konmas doru bir zmsel yaklam olacaktr. Gvenilir oturumlarda
mesajlar iin benzersiz ve tekrar etmeyen tanmlayc deerler kullandndan cevaplama
saldrlarnn (Reply Attack) azaltlmasda sz konusudur. Yinede gvenilir oturumlar almas
cevaplama saldrlar iin yeterli bir savunma mekanizmas sunmaz. Kesin zm iin zel bir
balayc kullanmak gerekir. zel bir balayc yardmyla cevaplama saldrlarna(Reply Attack)
kar nasl ayakta kalnabileceini bir sonraki makalemizde incelemeye alyor olacaz.

Bylece geldik uzun bir makalemizin daha sonuna. Bu makalemizde istemci ve servis arasnda
gvenilir bir oturumun nasl salanabileceini ele alrken arada hareket eden mesajlarda analiz
etmeye gayret ettik. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 741


WCF - Windows CardSpace ile Gvenlik (
25.10.2007 ) - WCF
Deerli Okurlarm Merhabalar,

WCF(Windows Communication Foundation) mimarisini baz alan SOA(Service Oriented


Applications) uygulamalar gelitirilirken, gvenlik(security) bal altnda ele alnmakta olan pek
ok konu vardr. Gelitirilen bir WCF servisinin sadece izin verilen istemciler(clients) tarafndan
kullanlmasda bu konulardan bir tanesidir. Bu amala istemci uygulamalarn veya onlar kullanan
hesaplarn servis tarafnda dorulanmas(authenticate) ve yetkilendirilmesi(authorize) adna
baz teknikler ele alnr. Temel olarak bir istemcinin dorulanmas ve yetkilendirilmesi, onun kim
olduunun bilinmesine baldr(Identification). Kimlik tespiti iin kullanc ad-ifre,
sertifika(certificate) yada Kerberos kart(token) gibi elemanlar gz nne alnr. Dorulama ilemi
srasnda kullanlan kimlik tespiti tekniklerinden biriside .Net Framework 3.0 ile birlikte
gelen Windows Cardspace teknolojisidir.

Windows CardSpace teknolojisi Windows Vista ile birlikte dorudan gelmektedir.


Nitekim Vista varsaylan olaran .Net Framwork 3.0 ykl olarak yaynlanmaktadr. Dier
taraftan .Net Framework 3.0 yklendiinde Windows XP srmlerinde de Windows
CardSpace teknolojisi kullanlabilmektedir.

CardSpace teknolojisi sayesinde, istemciler kendi hazrladklar kart bilgilerini gvenli bir ekilde
servis uygulamasna iletebilirler. Eer istemcilerin gnderdii kart bilgileri ierisinde servisin
ilgilendii bilgiler var ise dorulama(authentication) gereklemi olur. Bu aamadan sonra ise
dorulanan kullanc iin yine yetkilendirme(authorization) ilemlerine geilir. te bu
makalemizde WCF(Windows Communication Foundation) ile gelitirilen servis ynelimli
uygulamalarda CardSpace teknolojisini nasl kullanabileceimizi incelemeye alyor olacaz. Her
zamanki gibi konuyu daha iyi kavrayabilmek adna rnek bir senaryo ve uygulama zerinden adm
adm ilerliyor olacaz. Gelitireceimiz rnekler Windows Vista Business iletim sistemi ykl
bir makine zerinde gelitirilecektir. Ancak balamadan nce kimlik(Identity) kontroln daha iyi
kavrayabilmek adna aadaki gerek dnya senaryolar gz nne alnabilir.

Birinci Senaryo; Kimlik bilgilerindeki detaylarn nemli olmad durumlar.

www.bsenyurt.com Page 742


Yukardaki ekildeki senaryoya gre bir spor klbne girmek isteyen bir birey yer almaktadr.
Kapdaki iri kym grevlinin bu kiiyi ieri almasnn tek art ye kartnn(Membership Card)
mevcut olmasdr. Bunun dnda ye kartnda yer alan detay bilgilerinin iri kym kap grevlisi iin
hi bir nemi bulunmamaktadr. Sz gelimi kart zerinde yer alan yelik numaras, ye ad veya
ye sahibinin doum tarihi gibi bilgiler okda nemli deildir. Geerli bir kartn olmas yeterlidir. Bu
senaryodaki yaklam ma gnlerinde sadece kendi yelerine ak olan klp fanlar iinde
dnlebilir.

kinci Senaryo; Kimlik bilgisinin nc bir sistem tarafndan saland ve kontrol edildii
durumlar.

Bu senaryoda icek dkkanndan kredi kart ile alveri yapmakta olan bir kii yer almaktadr.
Kredi kart ile yaplan alverilerde kartn zerinde yer alan bilgiler kasa grevlisi tarafndan
olmasada banka merkezine balanan pos cihaz asndan nemlidir. Bu tip bir durumda kartn
gerekten kullanan kiiye ait olduunun anlalmas gerekmektedir. Dier taraftan kart sahibinin bu
alverii yapmas iin yeterli hakka sahip olup olmadda nemlidir. Eer bu haklara sahip ise son
aamada kart sahibi olduunu ispat etmek iin uzun zamandr lkemizdede uygulanan pin
numarasnda girmesi gerekmektedir. Burada kartn orjinal ve bakiyesinin yeterli olup olmadn
banka sistemi tarafndan kontrol etmektedir.

Bu senaryolar kulaa ho ve mantkl gelsede, acaba WCF(Windows Communication Foundation) ve


Windows CardSpace ile aralarnda nasl bir ilikileri vardr? Burada bahesedilen senaryolar hak-
tabanl gvenlik (claims-based security) vakkalarna rnek olabilecek gerek dnya
yansmalardr. Bu tip bir gvenlik sisteminde kiilerin kim olduundan ziyade, yaplmas istenen
ilemler iin ilgili kiinin hakk olup olmadnn tespit edilmesi nemlidir. te WCF mimarisi altnda
gelitirilen uygulamalarda Windows CardSpaceteknolojisini sayesinde hak-tabanl gvenlik

www.bsenyurt.com Page 743


(claims-based security) altyaps(infrastructure) salanabilir. Hak-tabanl gvenlik(Claim Based
Security) aslnda ana unsurdan olumaktadr. Bunlar aadaki listede belirtildii gibidir.

Kullanc(Subject): Servise erimek ve fonksiyonelliklerini altrmak isteyen kullanc


veya farkl bir sistem asl znenin(subject) kendisidir. Kullanc, erimek istedii servise,
onun kabul edebilecei haklar sunmakla ykmldr. Yukardaki senaryolar gz nne
alndnda, kredi kart ile klp kapsndan girmek ne kadar mantkszsa, klp kart ile
iekiden iek satn almakta o kadar mantkszdr. Bir baka deyile istemci tarafndan
sunulan haklarn, servis tarafnda kabul edilebilir nitelikte olmas gerekmektedir.
Kimlik Salayc (Identity Provider): Adndanda anlalaca zere, haklar iin gerekli
kimlii salamakta olan organizasyon veya varlktr(entity). Yukardaki senaryolar gz
nne alndnda kredi kartn veren banka veya ye gri kartn veren fan klb, kimlik
salayc konumundadr.
Gvenilir ahs veya Grup(Relying Party): Koruma altna alnm hizmeti(Protected
Service) sunan organizasyon yada varlktr. Kimlik salaycsna(Identity Provider),
kullancnn verdii kartn, kullancnn yapmak istedii ilem ile ilikili haklara sahip olup
olmadn sormakla ykmldr. Sz gelimi kredi kart ile alveri ilemini tasvir eden
senaryoda ieki yada bir baka deyile satc(vendor) gvenilir ahs(Relying
Party) rolndedir.

Windows CardSpace kullanlaraktan istemciler farkl bilgiler ieren eitli bilgi kartlar
(Information Card) oluturabilirler. Servis tarafnda yer alan uygulamann kendisi, dorulayaca
kullanclardan gelecek olan bilgi kartlarn kendi belirleyecei politikalara(Policy) gre kontrol
edebilir. Bilgi kartlar ierisinde ok farkl veriler yer alabilir. Kullancnn ad, email adresi, ya,
doum tarihi, hatta src belgesi veya pasaportu ile ilgili bilgiler dahi olabilir. Bu
noktada Windows CardSpace ile hak tabanl gvenlik(Claim-Based Security) ortam sunulan
bir WCF uygulamasnda, istemcinin bir servis talebi sonras neler olacana bakmakta yarar vardr.
Aadaki maddelerde, istemci(client) ve WCF servisi(Service) arasnda hak-tabanl gvenlik(Claim-
Based Security) gerekletirildiinde izlenen srece ait admlar yer almaktadr.

lk olarak istemci(Client), servisten(WCF Service) bir talepte(Request) bulunur.


Sonrasnda, istemci uygulama zerinde alan WCF alma zaman(runtime), Windows
CardSpace ierisinden kimlik seici uygulamay(Identity Selector) arr.
Kimlik seici(Identity Selector), servisten hak eidini(Claim Type) talep eder. Bir baka
deyile haklarn neye gre dorulanacan ister. rnein kullancnn pin numaras, email
adresi, ev telefonu vb... bir hak eidi olarak elde edilebilir. (Bu bilgi elbetteki WCF servis
uygulamas ve istemci yazlrken konfigursayon ierisinde belirtilir.)
stemci uygulamada alan Identity Selector, servisten gelen hak eidini bnyesinde
barndrdan kartlar kullancya grsel bir arayz ile sunar.
stemci uygulamay altrmakta olan kullanc bir kart seimi gerekletirir. (Kullanclar
istemci uygulamann alt sistemde Windows CardSpace' i kullanarak istedikleri
biimde kart bilgileri oluturabilirler. Bunu kart seim aamasnda dahi yapabilirler.)
stemci uygulamada alan Identity Selector program, kimlik salayc(Identity
Provider) ile iletiim kurar ve istemciye ait kart bilgisi iinden hak eidi(Claim Type) ile
ilikili olann gnderir.
Kimlik salaycs(Identity Provider) gelen metadata bilgisini alr ve bir fi(token) reterek
bunu Kimlik seiciye(Identity Selector) gnderir.
Identity Selector istemci program altran kullancya, oluturulan fiin WCF servisine
gnderilmesini onaylayp onaylamadn sorar. Eer kullanc onaylarsa setii bilgilere gre
oluturulan fi(token) WCF servisine gnderilir.
WCF Servisi gelen fi bilgisini alr ve kullancnn hakknn doruluunu kontrol eder. Eer
fi(token) bilgisi geerli ise ierisinde yer alan kimlik bilgisine(Identity
Information) bakarak kullancnn talepte bulunduu operasyonu yapp yapamayacana
karar verir. Bir baka deyile bu admda yetkilendirme(authorization) durumu ele alnr.
Eer yetki verilirse istemcinin talep ettii fonksiyonellik altrlr.

Durumu biraz daha grselletirmek adna aadaki ak diagramndan da yararlanlabilir.

www.bsenyurt.com Page 744


Bu kadar teorik bilgiden sonra rnek bir senaryo zerinden hareket etmekte yarar vardr. rnekte
servis tarafnda basit bir fonksiyonellik sunulmaktadr. Sz gelimi standart toplama fonksiyonunu
ieren bir WCF servis uygulamas tasarlanabilir. Servis ve istemci uygulamalar ayn makine
zerinde yer almaktadr. Bunun dnda servis ve istemcilerin mesaj seviyesinde gvenli
(Message Level Security) bir ekilde haberlemeleri nemlidir. Burada mesaj seviyesindeki
haberlemenin gvenli olabilmesi iin sertifika(Certificate) kullanm tercih edilmitir. lk nce
ie, istemci tarafnda Windows CardSpace teknolojisini kullanarak basit bir bilgi
kart(Information Card) hazrlayarak balamakta yarar vardr. Bu amalaWindows
Vista zerinde Control Panel ierisinde yer alan Windows CardSpace programnn kullanlmas
yeterlidir. (Windows XP tabanl sistemlerde de Windows CardSpace uygulamasna yine Control
Panel zerinde eriilebilir)

Eer daha nceden yklenmi bir bilgi kart yok ise aadaki gibi bir ekran ile karlalacaktr.

www.bsenyurt.com Page 745


Buradan Add a Card opsiyonunu iaretlenerek devam edilir.

Sradaki admda ise Create a Personel card opsiyonunu seilir. u aamada, kredi kart yada
pasaport bilgisi gibi verileri saklayacak bir bilgi kart(Information Card) oluturulmadndan Install
a Managed Card seeneini ele alnmamaktadr. zleyen admda personel kart bilgilerinin girilmesi
gerekmektedir. Bu ekran rnek olarak aadaki gibi doldurulabilir.

www.bsenyurt.com Page 746


Hak(Claim) ilemleri email adresi zerinden yaplaca iin bu bilginin mutlaka girilmesi nemlidir.
lemler tamamlandktan sonra hazrlanan kartn aadaki gibi eklendii grlecektir.

www.bsenyurt.com Page 747


Test amacyla Garfi isimli hayali kii iin bir test kart daha oluturulmutur. Bu kiinin email
adresindeki bilgiye gre, servis zerinde gerekli fonksiyonellii altrma yetkisi olmayacaktr.
Ama byle bir durumda servisin nasl bir davran sergileyeceinin izlenmesidir.

Artk servis taraf tasarlanmaya balanabilir. Servis uygulamas web


zerinden WsFederationHttpBinding tipini baz alacak ekilde tasarlanacaktr. Burada
WsHttpBinding tipide gz nne alnabilir. Federasyon yada birlik(Federation), farkl sistemler
arasnda dorulama(authentication) ve yetkilendirme(authorization) adna kimlik
bilgilerinden(rnekteki Windows CardSpace ile oluturulanlar gibi) yararlanlmasn salayan bir
kavramdr. Federation tarafndan gz nne alnan kimlik(Identity) bilgileri bir bilgisayar yada
kullancy iaret edebilir. WsFederationHttpBinding bunun iin gerekli olan alt yapy sunan hazr
bir balayc tiptir(Binding Type) ve WS-Federation protokoln desteklemektedir. Bu sebepten
WsFederationHttpBinding tipi iletiim seviyesinde gvenlii(transport level
security) desteklemez ve HTTP zerinden iletiimi zorunlu klar. Tekrardan uygulamaya
dnlecek olursa; servis ktphanesi(WCF Service Library) ierisinde basit olarak toplama
fonksiyonellii sunulmaktadr. WCF servis ktphanesindeki tiplerin ematik gsterimi ve kod
ierikleri aada olduu gibidir.

Snf Diagram(Class Diagram);

Szleme(IMatematik);

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;

namespace MatematikKutuphanesi
{
[ServiceContract(Name="Matematik
Servisi",Namespace="http://www.bsenyurt.com/Matematik/MatematikServisi")]
public interface IMatematik
{
[OperationContract]
double Topla(double x, double y);

www.bsenyurt.com Page 748


}
}

Matematik.cs;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
// System.IdentityModel.dll referans edilmelidir.
using System.IdentityModel.Claims;
using System.IdentityModel.Policy;
using System.ServiceModel;

namespace MatematikKutuphanesi
{
public class Matematik:IMatematik
{
#region IMatematik Members

public double Topla(double x, double y)


{
// nce talepte bulunan istemcinin ilgili ilem iin hakk olup olmad kontrol edilir.
if (KontrolEt())
return x + y;
else
throw new Exception("Dorulanmad");
}

private static bool KontrolEt()


{
// Dorulama ierii ekilir
AuthorizationContext ctx =
OperationContext.Current.ServiceSecurityContext.AuthorizationContext;
// Dorulama ieriindeki her bir ClaimSets gezilir
foreach (ClaimSet cSet in ctx.ClaimSets)
{
// ClaimSet' ler ierisinde Email hakkn ieren Claim' ler gezilir
foreach (Claim clm in cSet.FindClaims(ClaimTypes.Email,
Rights.PossessProperty))
{
// O anki Claim' in Email deeri selim@bsenyurt.com ise metod geriye true dndrr.
if (clm.Resource.ToString() == "selim@bsenyurt.com")
return true;
}
}
return false;
}

#endregion
}
}

Bu snf ierisinde yer alan Topla metodunu, gnderdii kart bilgisinde yer alan email adresi
selim@bsenyurt.com olan kullanc altrabilir. Bunun kontrol iin KontrolEt isimli

www.bsenyurt.com Page 749


geriye bool deer dndren bir metod gelitirilmitir. Bu metod kendi ierisinde, istemciden
gelen fi(token) bilgisi ve ierisindeki Claim Set' lerin elde edilmesi ilemlerini gerekletirilir.
stemciden gelen fi(token) bilgilerinin ieriine bakabilmek iin elde
edilen AuthorizationContext referansnn ClaimSets koleksiyonuna
gidilir. ClaimSets koleksiyonu ierisinde yer alanClaimSet bilgilerinden hak tipi(Claim
Type) email adresi olanlarn yakalanabilmesi iinde FindClaims metodu kullanlr. FindClaims
metodunun dndrecei koleksiyonun her bir elemandaClaim tipindendir. Claim
referanslarnn Resource zelliklerinin deerleri object tipindendir. Bunun sebebi hak tipine gre
gelen verinin farkl tiplerde olabilmesidir. Bunu geerli bir mail adresi ile kyaslamak
iin ToString metodu ile string tipine dntrme ilemi yaplmtr. Burada elbetteki email adresi
kontroln bir veritaban(database) kaynandan yada hakk olan email adreslerinin tutulduu bir
XML dosyasndan yapmak ok daha mantkldr. rnein amac u aamada sadece test olduundan
bu ilemler gz ard edilmitir.

AuthorizationContext tipi System.IdentityModel.Policy isim


alan(Namespace) altnda, ClaimSets ve Claim tipleri
ise System.IdentityModel.Claims isim alan altndadr. Her iki isim
alanda System.IdentityModel.dll assembly' nda yer aldklarndan sz konusu dll
referansnn projeye aka eklenmesi gerekmektedir. Aadaki ekillde
System.IdentityModel referansnn MatematikKutuphanesi isimli WCF Servis
Ktphanesine eklenmi hali grlmektedir.

Artk servis tarafnda, ilgili szlemeyi ve fonksiyonellii sunacak olan uygulama tasarlanabilir.
Burada istemci ve servis arasnda kart bilgileri tanacandan gvenilir bir ortam(Reliable
Session) hazrlanmas gerekmektedir. Bu nedenle servisin kart bilgisi gnderecek olan istemcileri
ile, sertifika(certificate) araclyla haberlemesi gerekmektedir. Bir baka deyile servis
uygulamasnn taleplerde(requests) kullanaca ve istemcilerinde referans edecei bir sertifika
tanmlamasnn yaplmas gerekmektedir. Bu amala ilk olarak, servis uygulamas iin gerekli test
sertifikasn reterek ie balanabilir. Bu sertifikann retimi ve servisin alt makine hesabna
kayd iin Visual Studio 2008 Beta 2 Command Prompt zerinden makecert.exe aracnn
aadaki gibi kullanlmas yeterlidir. Makecert arac X.509 tabanl test sertifikalarnn
retilmesinde kullanlmaktadr.

makecert -sr LocalMachine -ss My -n CN=MatematikServisi -sky exchange

www.bsenyurt.com Page 750


sr ile sertifikann yklenecei yer(location) belirtilirken, ss sonrasnda gelen My ilede Certificate
Store bilgisi tanmlanr. CN ifadesinden sonra oluturulacak olan sertifikann ad belirlenir. sky
parametresinden sonra gelen deer ilede subject' in anahtar tipinin(Key Type) ne olaca belirtilir.
Burada exchange dnda signature deeride verilebilir. (Makecert aracnn kullanm ile ilikili
olarak daha detayl bilgi iin http://msdn2.microsoft.com/en-
us/library/bfsktky3(VS.80).aspx adresinden yardm alnabilir.) Bu komutun altrlmasnn
ardndan Microsoft Management Console(MMC) yardmyla sertifika ayarlarna bakldnda
aadaki ekran grntsnde olduu gibi MatematikServisi isimli test sertifikasnn baarl bir
ekilde Local Computer altnda yer alan Personal ksm altna eklendii grlr.

Sertifika tanmlamas yapldna gre servis tarafndaki uygulamann yazlmas ile ilemlere devam
edilebilir. Servis uygulamas IIS zerinde host edilmek zere tasarlanmaldr. Bu amala yeni
bir WCF Service ablonu oluturulur. Servis uygulamas, MatematikKutuphanesi isimli servis snf
ktphanesini(WCF Service Library) referans etmelidir.

www.bsenyurt.com Page 751


Servis tarafnda yer alan Matematik.svc dosyasnn ierii aadaki gibidir.

<%@ ServiceHost Language="C#"


Debug="true" Service="MatematikKutuphanesi.Matematik" %>

Servis tarafndaki belkide en nemli ksm konfigurasyon dosyasnn ieriidir. Nitekim burada
kullanlacak olan sertifikann bildirimi, hak(Claim) tipinin ne olaca gibi ayarlamalarn yaplmas
gerekmektedir. Bu noktada Microsoft Service Configuration Editor yardmyla grsel olarak
hazrlanan web.config dosyasndaki ServiceModel elementinin ierii aadaki gibidir.

<system.serviceModel>
<bindings>
<wsFederationHttpBinding>
<binding name="MatematikServisiBindingConf" transactionFlow="true">
<reliableSession enabled="true" />
<security>
<message issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion">
<claimTypeRequirements>
<add
claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
isOptional="false" />
</claimTypeRequirements>
</message>
</security>
</binding>
</wsFederationHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="MatematikServisiBehavior">
<serviceMetadata httpGetEnabled="true" />
<serviceCredentials>
<serviceCertificate findValue="MatematikServisi"
x509FindType="FindBySubjectName" />
<issuedTokenAuthentication allowUntrustedRsaIssuers="true" />
</serviceCredentials>
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="MatematikServisiBehavior"
name="MatematikKutuphanesi.Matematik">
<endpoint address="http://localhost/MatematikServisi/Matematik.svc"

www.bsenyurt.com Page 752


binding="wsFederationHttpBinding" bindingConfiguration="MatematikServisiBindingConf"
name="MatematikServisiEndPoint" contract="MatematikKutuphanesi.IMatematik" />
</service>
</services>
</system.serviceModel>

Oluturulan dosyada dikkat edilmesi gereken bir ka nokta vardr. lk olarak istemci ile servis
arasnda gvenilir bir oturum almas gerekmektedir. Bu nedenle balayc tipe ait
olanrelaiableSession elementinin enabled niteliinin(attribute) deeri true olarak belirlenmitir.
Bir sertifika kullanm sz konusu olduundan servis
davranlarndan serviceCredentialsayarlarnn yaplmas gerekmektedir. Bunu salayabilmek iin
serviceCredential elementi aadaki gibi oluturulmutur.

<serviceCredentials>
<serviceCertificate findValue="MatematikServisi"
x509FindType="FindBySubjectName" />

Burada findValue niteliine verilen deer, daha nceden oluturulan MatematikServisi isimli
sertifikadr. Bu X.509 tipindeki sertifikasnn bulunabilmesi
iinde x509FindType niteliineFindBySubjectName deeri verilmitir. Buna gre ilgili sertifika,
nesne adna gre aranacaktr.

Servis taraf, istemcinin talepte bulunduu hizmetler iin hakk olup olmadn, kart bilgisi ile gelen
email adreslerine gre yapmaktadr. Burada politika(policy) olarak kart bilgisindeki email
adresine baklacann sylenmesi gerekmektedir. Bu amala security elementi ierisinde
aadaki ayarlamalar yaplmtr.

<security>
<message issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion">
<claimTypeRequirements>
<add claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
isOptional="false" />
</claimTypeRequirements>
</message>
</security>

Burada en nemli nokta claimType niteliinin deeridir. Bu nitelie(attribute) well-known


URI formatnda bir deer atanmtr. Deerin sonunda yer alan emailaddress, hak iin gerekli
politikayda(Claim Policy) belirlemektedir.

Burada yazlan URI bilgisi programatik olarak static olarak


tanmlanm ClaimTypes snfndaki zellikler(properties) zerindende elde edilebilir.
ClaimTypes snfnn yelerinin bir ksmnn snf diagramndaki grnts aadaki
gibidir. ClaimTypes snf static bir snftr. Bu nedenle ierisindeki yelerin tamam static
olarak tanmlanmtr. Dolaysyla bu yelere nesne rnei olmadan tip ad ile
eriilebilmektedir.

www.bsenyurt.com Page 753


Sz gelimi alma zamannda aadaki kod paras kulanldnda,

Console.WriteLine(ClaimTypes.DateOfBirth);
Console.WriteLine(ClaimTypes.HomePhone);
Console.WriteLine(ClaimTypes.PostalCode);
Console.WriteLine(ClaimTypes.Surname);
Console.WriteLine(ClaimTypes.Webpage);

Claim Tipi olarak kullanlabilecek URI bilgileride u ekilde elde edilecektir. Burada rnek
olarak doum gn, ev telefonu, posta kodu, soyad ve web sayfas gibi bilgiler iin
gereken Well-Known URI bilgileri gsterilmektedir.

Dier taraftan message elementi


ierisinde issuedTokenType niteliinede urn:oasis:names:tc:SAML:1.0:assertion deeri
atanmtr. Bu tanmlamaya gre WCF servisinin, Secure Application Markup Language
1.0 uyumlu bir fi(token) bekledii belirtilmektedir. SAML, kimlik salayc(Identity
Provider) ile servis salayc(Service Provider) arasnda dorulama(authentication) ve
yetkilendirme(authorization) verilerinin dei toku eklini belirleyen bir XML standarddr. rnek

www.bsenyurt.com Page 754


uygulamada, ayn bilgisayardaki Windows CardSpace ile hazrlanm kimlik bilgileri baz
alnmaktadr. Bir baka deyile nc parti bir kimlik salayc(Identity Provider) tarafndan
retilmi bir kart mevcut deildir. Bu sebepten servisin gvenilmez(untrusted) kaynaklardan
gelecek SAML filerin(tokens) kabul edecek ekilde ayarlanmas gerekir. Bunu salamak
iin serviceCredentials elementi
altndaki issuedTokenAuthentication elemeninin allowUntrustedRsaIssuers seeneine true
deeri atanmtr.

stemci uygulamaya gemeden nce servis uygulamas herhangibir tarayc penceresinden talep
edilirse KeySet Does Not Exist mesajl bir alma zaman istisnas alnabilir. Byle bir
durumda WinHttpCertCfg.exe arac
kullanlarak NetworkService yada AspNet hesaplarna(accounts), uygulamada kullanlan
sertifika(Certificate) iin kabul edilmi eriim(grant access) haklarnn verilmesi gerekmektedir.
WinHttpCertCfg arac http://www.microsoft.com/downloads/details.aspx?familyid=c42e27ac-3409-
40e9-8667-c748e422833f adresinde tedarik edilebilir. WinHttpCertCfg arac aadaki ekran
grntsnde olduu gibi kullanlmaldr.

Yukardaki komut ifadesine gre NetworkService hesab iin, MatematikServisi zerine grant access
hakk verilmitir. Artk servis taraf internet taraycs zerinden elde edilebilir.

Artk istemci tarafn yazmak iin gerekli hazrlklara balanabilir. Sistemin alabilmesi iin,
retilen test sertifikasnn ncelikli olarak o anki kullanc iin Trusted People olarak eklenmesi
gerekmektedir. Bunu salayabilmek iin Visual Studio 2008 Beta 2 Command
Prompt zerinden certmgr arac aadaki grld gibi kullanlmaldr.

www.bsenyurt.com Page 755


lk olarak sz konusu sertifikann bir kopyas sadece public key deerini ierecek
ekilde MatematikServisi.cer isimli dosyaya yazdrlr. Sonrasnda altrlan komut ilede, gncel
kullanc(Current User) iin Trusted People olacak ekilde eklenir. Bu ilemlerin ardndan
Microsoft Management Console programndan yararlanlarak Current User altndaki Personel
blmne bakldnda aadaki ekran grntsnde yer ald gibi ilgili sertifika bildiriminin
yapld grlr.

Bu n hazrlklar tamamladktan sonra istemci uygulamann gelitirilmesine balanabilir. stemci


program basit bir Console uygulamas olarak ele alnmaktadr. Console uygulamasnda, gelitirilen
servisin Add Service Reference seenei ile aadaki ekran grntsnde olduu gibi eklenmesi
gerekmektedir.

www.bsenyurt.com Page 756


Sonrasnda ise yine retilen App.config dosyas istenirse grsel olarak istenirse dorudan yazlarak
aadaki hale getirilmelidir.

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


<configuration>
<system.serviceModel>
<behaviors>
<endpointBehaviors>
<behavior name="ClientEndPointBehavior">
<clientCredentials>
<serviceCertificate>
<authentication certificateValidationMode="PeerTrust"
revocationMode="NoCheck" />
</serviceCertificate>
</clientCredentials>
</behavior>
</endpointBehaviors>
</behaviors>
<bindings>
<wsFederationHttpBinding>
<binding name="MatematikServisiEndPoint" transactionFlow="true">
<reliableSession enabled="true" />
<security mode="Message">
<message algorithmSuite="Default" issuedKeyType="SymmetricKey"
issuedTokenType="urn:oasis:names:tc:SAML:1.0:assertion"
negotiateServiceCredential="true">
<claimTypeRequirements>
<add
claimType="http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress"
isOptional="false" />
</claimTypeRequirements>
</message>
</security>
</binding>
</wsFederationHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost/MatematikServisi/Matematik.svc"
behaviorConfiguration="ClientEndPointBehavior" binding="wsFederationHttpBinding"
bindingConfiguration="MatematikServisiEndPoint" contract="ServiceReference.MatematikServisi"
name="MatematikServisiEndPoint">
<identity>

www.bsenyurt.com Page 757


<certificateReference x509FindType="FindBySubjectName"
findValue="MatematikServisi" />
</identity>
</endpoint>
</client>
</system.serviceModel>
</configuration>

stemci tarafndaki konfigurasyon dosyasnn pek ok zellii servis referans eklendikten sonra
otomatik olarak oluturulur. Hereyden nce istemci tarafnda da balayc tip
olarak wsFederationHttpBinding ele alnmaktadr. Dier taraftan istemci ile servis
arasnda gvenilir bir oturum iin(reliable session) gerekli ayarlamalar yaplmtr. Aynen
servis tarafnda olduu gibi hak tipi(Claim Type) email olacak ekilde belirlenmi
ve issuedTokenType niteliine atanan deer ile SAML standardnda bir fi(token) yaynlanaca
bildirilmitir. Sertifika(Certificate) bildirimi Identity elementi ierisinde yaplmaktadr. Servis
tarafndakine benzer olarak sertifika ad ve neye gre aranaca
belirtilmektedir findValue vex509FindType nitelikleri ile belirtilmektedir.

Konfigurasyon dosyasnda gerekli deiiklikler yapldktan sonra Main metodu ierisinde aadaki
gibi bir kod blou gelitirilerek servisin kullanlmas salanabilir.

using System;
using System.Collections.Generic;
namespace CardSpaceIstemci
{
class Program
{
static void Main(string[] args)
{
try
{
ServiceReference.MatematikServisiClient cli =
new CardSpaceIstemci.ServiceReference.MatematikServisiClient();
Console.WriteLine(cli.Topla(3, 4).ToString());
}
catch (Exception excp)
{
Console.WriteLine(excp.Message);
}
}
}
}

Servis tarafnda includeExceptionDetailsInFaults zelliinin deerini true olarak belirlenmi


olduundan, servis tarafndan frlatlacak olan istisna mesajlar(Exception Messages) istemci
uygulama zerinden kolaylkla ele alnabilecektir. Tm bu ilemlerin ardndan istemci uygulama
altrldnda, ekrana kart seimi yaplmas iin bir sorgu penceresi alacaktr. Bu sorgu
penceresinde var olan kartlardan yararlanlabilir yada yeni bir kart oluturularak gnderilmesi
salanabilir.

www.bsenyurt.com Page 758


lk olarak Burak Senyurt Personel Kart isimli bilgi kart(Information Card) seildiinden, kullancya
bir soru sorulacaktr. Bu soruda kullancnn ilgili kart bilgisini servise gndermek isteyip istemedii
belirtilir. Kullanc bunu kabul etmesse bir baka deyile rnein Esc tuu ile arabirimden karsa
istemci tarafnda yine bir alma zaman hatas oluacak ve bununla ilikili bilgiler Log dosyasna
aktarlacaktr.

Send balkl dmeye bastktan sonra aadaki ekran grntsnde olduu gibi servis tarafnda
yaplan toplama ileminin sonucunun elde edilebildii grlr.

www.bsenyurt.com Page 759


Ancak ayn uygulamada Garfi isimli dier kart bilgisi gnderildiinde servis tarafnda retilen
istisna(Exception) mesajnn alndn grrz. Bir baka deyile istemci uygulamadan gnderilen
kart bilgisi ierisindeki email adresine gre, servis tarafnda toplama fonksiyonunun altrlmas
iin gereken hak koullar salanamamtr.

Grld gibi Windows CardSpace kullanlarak, WCF uygulamalarnda hak tabanl


gvenlii(Claim Based Security) salamak olduka kullanl ve etkili bir yoldur. Burada, teknik
detaylara ok fazla girilmeyerek adm adm bu tarz bir sistemin nasl kurulabileceinden
bahsedilmeye allmtr. Nevarki kullanlan sertifika bir test sertifikas olup nc parti bir
salayc tarafndan retilen kart bilgileri ele alnmamtr. Bu tarz gerek senaryo
uygulamalarndada sistemin tasarlanmas ve kurallar ok fazla deiiklik gstermeyecektir.

Bu konu ile ilikili detayl bilgiyi benimde yakndan takip ettiim ve faydalandm John
Sharp imzal MsPress yaynlarna ait Microsoft Communication Foundation Step by
Stepkitabndan da bulabilirsiniz. Sanlann aksine Step by Step olarak belirtilmesine ramen konu
WCF olunca olduka zor ve sk allmas gereken bir kitap olduunuda vurgulamak isterim.
Bylece geldik uzun bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Daha Etkili Profil(Profile) Ynetimi ( 17.10.2007


) - Asp.Net 2.0
Deerli Okurlarm Merhabalar,

Uzun sre nce Asp.Net 2.0 ile gelitirilen web uygulamalarnda Profile API' sinin nasl
kullanldn ksa bir makale zerinden incelemeye almtk. Getiimiz gnlerde Asp.Net 2.0 ile
ilgili bilgilerimi tazelerken profil ynetiminin daha etkin bir ekilde nasl kullanlabileceine dair pek
ok rnek ile karlatm. te bu makalemizde temel olarak profil ynetiminin daha etkin hale
getirilmeye almas iin urayor olacaz. nceleyeceimiz temel konu balklarn aadaki gibi
sralayabiliriz.

ProfileBase tipinden tretmek(Inherit).


Profil bilgilerini kod zerinden ynetebilmek(ProfileManager).
simsiz(Anonymous) kullanclar iin profil bilgilerini kullanabilmek.

Balamadan nce profil kavramn ksaca tanmlamakta yarar olduu kansndaym. Bir web
uygulamasna balanan kullanclarn her biri iin ortak tanmlanp deerleri farkl olabilecek

www.bsenyurt.com Page 760


zellikler topluluu profil bilgisini oluturmaktadr. Bu anlamda zellikle,
bir dorulama(authentication) ve yetkilendirme(authorization) sistemine sahip olan web
uygulamalarnda her kullanc iin deerleri farkl olabilecek zelliklerin tutulmas ve kullanlmas
mmkn olabilmektedir. Bu tip bir sistemin zellikle Asp.Net 1.1 ile gelitirilmesi ekstra kodlamay
gerektirirken Asp.Net 2.0 zerinde yer alan Profile API sayesinde son derece kolaylamtr. Gelelim
Profile API yeteneklerini daha etkili bir ekilde nasl ele alabileceimize.

ProfileBase Tipinden Tretmek(Inherit);

Normal artlarda bir web uygulamas ierisinde profil bilgilerini kullanabilmek


iin web.config dosyas ierisinde profile elementinin ele alnmas gerekmektedir. Nitekim bir web
uygulamasnda kullanlan profil bilgilerinin, baka web uygulamasnda(web uygulamalarnda) ele
alnmasnn istendii vakkalarda mevcuttur. Bu tip bir durumda zm olarak, ProfileBasetipinden
tretme yaplaraktan birden fazla web uygulamasnda ele alnabilecek bir profil snf gelitirmek
mmkndr. ProfileBase snfnn temel yeleri aadaki snf diagramnda(Class Diagram)
grld gibidir.

PorfileBase tipi snf diagramndan(class diagram) da grld gibi SettingBase isimli abstract
snftan(class) tremeketedir. ProfileBase tipine ait yelerden bazlarnn grevleri aadaki tabloda
belirtildii gibidir.

www.bsenyurt.com Page 761


Metodlar(Methods) Aklama

Create Bu metod ile bir kullanc iin profil nesne rnei oluturulur. zel profil
tiplerinin yazlmasnda veya Asp.Net ortam dndaki evrelerde profil
ynetimi sz konusu olduunda ele alnmaktadr. Metod
geriye ProfileBase tipinin tayabilecei referanslar dndrr. ki farkl
versiyonu vardr. Her iki versiyonda ilk parametre olarak kullanc adn
alr. kinci parametre bool bir deerdir ve
kullancnn isimsiz(anonymous) yada dorulanm(authenticated) ol
up olmadn belirtir. Metodun dn deerinin true olmas kullancnn
doruland anlamna gelmektedir.

Save Profil bilgilerini kaydetmek amacyla kullanlr. Herhangibir parametre


almaz ve geriye deer dndrmez(void). Var olan bir ProfileBase nesne
rnei zerinden arlabildii iin ilgili tipe ait zelliklerde yaplan
deiikliklerin kaydedilmesini salar. Kaydetme ilemi veri
kaynana(data source) doru yaplmaktadr. Bu ilem
srasnda IsDirty zellii true deerini alr. lem tamamlandktan sonra
ise false deerini alr.

GetPropertyValue Parametre olarak verilen zelliin deerini object tipinden dndrr.

SetPropertyValue ki parametre alan bu metodun ilk parametresi deeri verilecek zellik


adn, ikinci parametresi ise object tipinden ilgili deeri almaktadr. Bu
metod yardmyla profil ierisindeki bir zellie deer atanabilmesi
salanabilmektedir.

GetProfileGroup Profil ierisinde yer alan zellikler istenirse grup halinde ayrlabilirler.
Bunun iin profile elementi ierisinde yer
alan properties elementlerinde, group alt elementi kullanlmaktadr.
Byle bir durumda gruplanan zelliklerin listesini elde etmek
iin GetProfileGroup metodu kullanlabilir. Bu metod
geriye ProfileGroupBase tipinden bir referans dndrmektedir. Bu
referansn zerinden hareket ederek grup ierisindeki zelliklere ve
deerlerine erimek mmkn olmaktadr. Aadaki snf diagram
grntsnde ProfileGruopBase snfnn yeleri grlmektedir.

zellikler(Properties Aklama
)

Item Profil ierisinde tanmlanm olan zellik adlarn parametre olarak alabilen
indeksleyici sayesinde ilgili zelliin deerinin verilmesi(set) veya elde
edilmesi(get) mmkndr. zellik ad string tipinden verilmekte olup
indeksleyicinin dn deeri object tipindendir.

www.bsenyurt.com Page 762


Properties Static olarak tanmlanm olan bu zellik sayesinde profil zelliklerinin bir
listesinin SettingsPropertyCollection koleksiyon tipinden elde edilmesi
mmkndr. Bu koleksiyonun her bir eleman SettingsProperty snf
tipindendir. Bu tipin yeleri ise aadaki snf diagramnda grld
gibidir. Dikkat edilecek olursa bu yelerden yola karak profilin zellii
hakknda detayl bilgilere ulamak veya ynetmek mmkndr.

UserName Profilin sahibi olan kullanc adn verir. Eer isimsiz bir kullanc girii sz
konusu ise identifier deerini dndrecektir.

IsDirty Profil zelliklerinden herhangibiri deitiriliyorken true deerini dndrr.


Aksi durumda false deerini dndrmektedir.

IsAnonymous Eer kullanc isimsiz(anonymous) ise true deerini dndrr. Aksi


durumda false' dur.

imdi rnek bir senaryo zerinden hareket ederek konuyu biraz daha iyi kavramaya alalm.
ncelikli olarak hedefimiz birden fazla web uygulamasnn kullanabilecei bir Profile tipi
gelitirmek olduundan bir snf ktphanesi(class library) gelitirerek ie balanabilir. ok
doal olarak bu snf ktphanesi ierisinde ProfileBase tipi kullanlacandan ve yeri geldiinde
gncel HTTP ieriine(HttpContext) eriilmesi gerektiinden System.Web.dll assembly' nn ilgili
snf ktphanesine referans edilmesi gerekmektedir.

zel olarak hazrlanacak snfn salamas gereken baz zellikler vardr. lk olarak bu snfn en
azndan XML seriletirilebilir(XML Serializable) olmas gerekmektedir. ok doal olarak bu snf
ierisinde kullanlacak zelliklerin veri tipleride(data types) seriletirilebilir olmaldr. (Kendi
tiplerimizden zellik trleri yazmadmzda ounluklu ilkel tipleri(primitive types) kullanrz. Bu
tiplerin ou zaten seriletirilebilir olduundan sorun kma olasl azalmaktadr. Ancak kendi
tiplerimizi ele aldmzda seriletirilebilir olmalarna dikkat etmek gerekmektedir.) kinci olarak zel
tip ierisinde, web uygulamalarndaki kullanclar iin gerekli profil bilgisini
oluturacakzellikler(property) ayr ayr tanmlanmaldr. Bu zelliklerin kullanm srasnda base
anahtar kelimesi ile st snfa aktarma yaplmasna dikkat edilmelidir. n olarak elbetteki zel
snfn ProfileBase tipinden tretilmi olmas gerekmektedir. Bu tretmenin doal sonucu olarak
ProfileBase snf ierisinde tanmlanm baz yelerin ezilebilecei(override) ortadadr.

www.bsenyurt.com Page 763


Hatrlanaca zere st snfta(base class) sanal(virtual) olarak tanmlan olan
yelerin, treyen snflarda(derived class) ezilme(override)zorunluluu yoktur.
Eer bir zorunluluk getirilmesi isteniyorsa abstract yelerin yer alabildii abstract
snflar veya arayzler(interface) kullanlmaldr.

Aadaki ekilde treyen snf(derived class) ierisinde ezilebilecek yeler gsterilmektedir.


Doal olarak herkes bir Object olduundan, object snfndan gelen baz virtual yelerde bu listede
yer almaktadr.

rnek olarak MyProfile snf aadaki gibi tasarlanabilir. Snf ierisinde kontak bilgilerini saklamak
amacyla Contact isimli bir snf daha kullanlmaktadr. Bu snfa ait nesne rneklerini kullanan
zellikler MyProfile snf ierisinde ele alnarak, kullanc tanml tiplerin durumuda rahatlkla
incelenebilir.

Contact Snf;

public class Contact


{
private string _ad;
private string _soyad;
private string _email;

www.bsenyurt.com Page 764


public string Email
{
get { return _email; }
set { _email = value; }
}

public string Soyad


{
get { return _soyad; }
set { _soyad = value; }
}

public string Ad
{
get { return _ad; }
set { _ad = value; }
}
public Contact(string ad, string soyad, string mail)
{
Ad = ad;
Soyad = soyad;
Email = mail;
}
// XML Seriletirme kural olarak parametresiz bir yapc metod(constructor) olmas
gerekmektedir.
public Contact()
{
}
}

Burada dikkat edilmesi gereken noktalardan biriside Contact snfnn varsaylan yapc
metodunun(Default Constructor) yazlm olmasdr. Profil bilgilerinde kendi tiplerimizi
kullandmz durumlarda varsaylan olarak XML seriletirme gerekletirilmektedir. Dolaysyla yine
varsaylan olarak AspNetDb veritabanndaki aspnet_Profile tablosuna yazlacak olan zellik
deerlerinin XML formatnda seriletirilebilir olmas gerekmektedir. Bu sebepten ilgili tipin
varsaylan yapc metoda sahip olmas gerekir ki bu XML seriletirmenin kurallarndan birisidir. Eer
varsaylan yapc metodu yazmassak alma zamannda profil bilgisini kaydederken aadaki
ekran grntsnde yer alan istisnay(exception) alrz.

www.bsenyurt.com Page 765


MyProfile Snf;

public class MyProfile:ProfileBase


{
public int SonStokDurumu
{
get { return Convert.ToInt32(base["SonStokDurumu"]); }
set { base["SonStokDurumu"] = value; }

www.bsenyurt.com Page 766


}
public DateTime SonGirisZamani
{
get { return Convert.ToDateTime(base["SonGirisZamani"]); }
set { base["SonGirisZamani"] = value; }
}
public Contact Contact2
{
get { return (Contact)base["Contact2"]; }
set { base["Contact2"] = value; }
}
public Contact Contact1
{
get { return (Contact)base["Contact1"]; }
set { base["Contact1"] = value; }
}
public string Bayi
{
get { return base["Bayi"].ToString(); }
set { base["Bayi"] = value; }
}
}

Dikkat edilecek olursa snf ierisinde tasarlanan zelliklere ait get ve set bloklarnda base anahtar
kelimesi ile ProfileBase snfna klmakta ve indeksleyici operatrnden yararlanlarak ilgili
alanlara eriilmesi salanmaktadr. Elbetteki base ile ulalan referansn zellikleri object veri tr
ile altndan set bloklar ierisinde uygun tr dnmlerinin bilinli(explicit) olarak yaplmas
arttr. MyProfile snf ierisinde tanmlanacak zel alanlara(private fields) deer atanmas
durumunda veritabanna herhangibir ekilde bilgi yazlmayacaktr. Byle bir ilem
iin Save metodunun bu snf ierisinde ezilemesi ve kodlanmas gerekmektedir.

imdi MyProfile snfn test etmek amacyla basit bir web uygulamas tasarlayalm. Bu web
uygulamasnda standart olarak AspNetDb veritaban kullanlabilir. Form tabanl
dorulama(Form Based Authentication) sisteminin yer ald web uygulamasnda standart
olarak Login.aspx sayfas kullanc girii iin kullanlrken, Default.aspx sayfas ierisinde rnek test
kodlar yer almaktadr. Web uygulamasna ait konfigurasyon dosyasnn(Web.config) ierii
aadaki gibi olmaldr.

web.config;

<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true" />
<authentication mode="Forms" />
<authorization>
<deny users="?"/>
</authorization>
<profile enabled="true" inherits="CustomProfileLibrary.MyProfile"/>
</system.web>
</configuration>

www.bsenyurt.com Page 767


profile elementi ierisinde inherits niteliine(attribute) atanan deer ile Profile tipinin ne olduu
sylenir. Burada simAlanAd.TipAd(NamespaceName.TypeName) notasyonu kullanlarak
profile bilgilerinin ynetiminin MyProfile snf tarafndan yaplaca belirtilmektedir. Form tabanl
dorulama(Form Based Authentication)
kullanldndanauthentication elementinin mode niteliine Forms deeri atanmtr. simsiz
kullanclarn(anonymous users) siteye giri yapmas istenmediinden authorization elementi
ierisinden sz konusu kullanclar ? karakteri ile deny edilmitir. Gelelim uygulamann rnek web
sayfasna. Sayfann tasarm aada grld gibidir.

Default.aspx sayfas;

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


Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginName ID="LoginName1" runat="server" /><asp:LoginStatus
ID="LoginStatus1" runat="server" />
<br />
<table>
<tr>

www.bsenyurt.com Page 768


<td colspan="2" valign="top">Profil zellikleri&nbsp;<asp:Button ID="btnGetir"
runat="server" OnClick="btnGetir_Click" Text="Bilgileri Getir" /></td>
</tr>
<tr>
<td style="width: 164px" valign="top">Bayi</td>
<td style="width: 100px"><asp:TextBox ID="txtBayi"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td style="width: 164px" valign="top">Kontak 1</td>
<td style="width: 100px">
<table>
<tr>
<td style="width: 100px">Ad</td>
<td style="width: 100px"><asp:TextBox ID="txtKontak1Ad"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px">Soyad</td>
<td style="width: 100px"><asp:TextBox ID="txtKontak1Soyad"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px">Email</td>
<td style="width: 100px"><asp:TextBox ID="txtKontak1Email"
runat="server"></asp:TextBox></td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="width: 164px" valign="top">Kontak 2</td>
<td style="width: 100px">
<table>
<tr>
<td style="width: 100px">Ad</td>
<td style="width: 100px"><asp:TextBox ID="txtKontak2Ad"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px">Soyad</td>
<td style="width: 100px"><asp:TextBox ID="txtKontak2Soyad"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td style="width: 100px">Email</td>
<td style="width: 100px"><asp:TextBox ID="txtKontak2Email"
runat="server"></asp:TextBox></td>
</tr>
</table>
</td>
</tr>
<tr>
<td style="width: 164px; height: 10px" valign="top">Son Giri Zaman</td>
<td style="width: 100px; height: 10px"><asp:Label ID="lblSonGirisZamani"
runat="server" Text="Label"></asp:Label></td>

www.bsenyurt.com Page 769


</tr>
<tr>
<td style="width: 164px; height: 26px" valign="top">Stok Durumu</td>
<td style="width: 100px; height: 26px"><asp:TextBox ID="txtStokDurumu"
runat="server"></asp:TextBox></td>
</tr>
<tr>
<td colspan="2" valign="top"><asp:Button ID="btnKaydet" runat="server"
OnClick="btnKaydet_Click" Text="Bilgileri Kaydet" /></td>
</tr>
</table>
<br />
<br />
</div>
</form>
</body>
</html>

Default.aspx.cs;

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using CustomProfileLibrary;

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


{
protected void btnGetir_Click(object sender, EventArgs e)
{
Getir();
}

protected void btnKaydet_Click(object sender, EventArgs e)


{
Kaydet();
}

private void Getir()


{
try
{
txtBayi.Text = Profile.Bayi;
txtKontak1Ad.Text = Profile.Contact1.Ad;
txtKontak1Email.Text = Profile.Contact1.Email;
txtKontak1Soyad.Text = Profile.Contact1.Soyad;
txtKontak2Ad.Text = Profile.Contact2.Ad;
txtKontak2Email.Text = Profile.Contact2.Email;
txtKontak2Soyad.Text = Profile.Contact2.Soyad;
lblSonGirisZamani.Text = Profile.SonGirisZamani.ToString();

www.bsenyurt.com Page 770


txtStokDurumu.Text = Profile.SonStokDurumu.ToString();
}
catch (Exception excp)
{
Response.Write(excp.Message);
}
}

private void Kaydet()


{
Profile.Bayi = txtBayi.Text;
Contact kontak1 = new Contact(txtKontak1Ad.Text, txtKontak1Soyad.Text,
txtKontak1Email.Text);
Profile.Contact1 = kontak1;
Contact kontak2 = new Contact(txtKontak2Ad.Text, txtKontak2Soyad.Text,
txtKontak2Email.Text);
Profile.Contact2 = kontak2;
Profile.SonGirisZamani = DateTime.Now;
int stok = 1;
Int32.TryParse(txtStokDurumu.Text, out stok);
Profile.SonStokDurumu = stok;
Profile.Save();
}
}

Sayfa basit olarak profil bilgilerinin getirilmesi veya kaydedilmesi iin gereken kodlar iermektedir.
Dikkat edilirse Profile tipi kullanlmaktadr. Nitekim web.config dosyasndaki bildirim nedeni
ileProfile zellii zerinden MyProfile ierisinde tanmlanm olan zelliklere eriilebilmektedir.
Aadaki ekilde bu durum daha net bir ekilde grlebilir.

ok doal olarak daha nceden bir profil bilgisi oluturulmamas durumuna karlk bilgiler
getirilirken Null Reference Exception alnma olasl vardr. Bu nedenle profil bilgileri ortama
ekilirken bir try...catch blou kullanlmas yararl olabilir. Sayfa zerinde test bilgilerinin
kaydedilmesi sonrasnda aspnet_profile tablosunun ieriine baklrsa profil bilgisinin baarl bir

www.bsenyurt.com Page 771


ekilde kaydedildii grlebilir. Dikkat edilecei zere bilgiler XML seriletirmeye uygun olacak
ekilde XML formatnda PropertyValueString alanna yazlmtr.

alma zamannda(run-time) Bilgileri Getir balkl dmeye basldnda ise sz konusu verilerin
ilgili kontrollere doldurulduu grlecektir. Aada bu duruma ait rnek bir ekran kts yer
almaktadr.

Profil Bilgilerini Kod zerinden Ynetebilmek;

Baz durumlarda alma zamannda(run-time) uygulamada kullanlan profil bilgilerinin ynetilmesi


istenebilir. Sz gelimi profilde kaytl bilgilerin gsterilmesi, belirli bir tarihten ncekilerin
kaldrlmas, bir kullancnn profil bilgisinin silinmesi, aktif olmayan profillerin elde edilmesi vb...
ilemler yaplabilir. Bu aslnda basit olarak veritabanna ulamak ve ilgili tablonun alanlarna
bakmaktan baka bir ey deildir. Ne varki Asp.Net Profile API ierisinde sz konusu ynetsel
ilemlerin daha kolay yaplmasn salayan ProfileManager snf mevcuttur. Bu snfn diagram
grnts aadaki gibidir.

www.bsenyurt.com Page 772


Dikkat edilecei zere ProfileManager, static bir snftr(static class).

Static snf kavram C# 2.0 ile birlikte gelmitir. Static snflar sadece static yeler(static
members) ierebilir, tretme(Inheritance) amacyla kullanlamaz veya
rneklenemezler. Normal snflara gre daha hzl ve performansl altklar ortadadr.
Bununla birlikte C# 3.0 ile birlikte gelen extension methods kavramnda nemli bir
yerede sahiptir.

Snfn nemli metodlar ve yapt iler ise aadaki tabloda grld gibidir.

Metodlar(Methods) Aklama

GetAllProfiles ki versiyonu olan bu metod sayesinde bir uygulamadaki


profil bilgilerinin tamam ProfileInfoCollection tipi
ierisinde olacak ekilde elde edilebilir. Her iki
versiyonda ProfileAuthenticationOption enum sabiti
tipinden bir parametre almaktadr. Bu parametrenin
alabilecei deerler All, Anonymous, Authneticated' dr.
Bir baka deyile tm kullanclarn, sadece isimsiz
kullanclarn veya sadece dorulanm kullanclarn profile
bilgilerinin elde edilmesi salanabilir. Ayrca bu metod ile
sayfalamalara uygun olacak ekilde veri ekilmeside
salanabilmektedir.

GetNumberOfProfiles Veritabannda kaytl olan profil saysnn elde edilmesini


salayan bu metod yine ProfileAuthenticationOption enum
sabiti tipinden bir parametre alr. Buna gre sadece isimsiz
kullanclarn(anonymous users), dorulanm
kullanclarn(authenticated users) yada tm
kullanclarn(all users) kaytl olan profil saylar elde
edilebilir.

www.bsenyurt.com Page 773


GetAllInactiveProfiles Profil sahibi kullanclarn LastActivityDate zelliklerinin
deerlerine gre parametre olarak verilen tarih ve
ncesindeki tm profillerin elde edilmesini salayan
metoddur. ki versiyonu vardr ve her ikisinin ilk parametresi
ayndr. lk parametrede ProfileAuthenticationOption deeri
ikincisinde ise tarih bilgisi belirlenir.

GetNumberOfInactiveProfiles Profil sahibi kullanclarn LastActivityDate zelliklerinin


deerlerine gre parametre olarak verilen tarih ve
ncesindeki tm profillerin saysnn integer olarak elde
edilmesini salayan metoddur.

FindProfilesByUserName Belirlenen kullanc adyla eleen profil


bilgilerinin ProfileInfoCollection tipinden dndrlmesini
salamaktadr. ki farkl versiyonu vardr. Her ikiside ilk iki
parametresinde srasyla ProfileAuthenticationOption ve
kullanc ad bilgilerini almaktadr. Sayfalama yaplmasda
salanabilmektedir. Burada kullanc ad
girilirken % karakteri kullanlarak Like benzeri bir sorgulama
yaplabilmektedir.

FindInactiveProfilesByUserName Profil sahibi kullanclarn LastActivityDate zelliklerinin


deerlerine gre belirtilen tarih ve ncesinde olanlarn
parametre olarak verilen kullanc ad ile eleenlerinin
bulunmasn salayan metoddur. Burada kullanc ad
girilirken % karakteri kullanlarak Like benzeri bir sorgulama
yaplabilmektedir. rnein kullanc ad ierisinde ma
geenlerin elde edilip belirtilen bir tarhiten ncesine kadar
aktivitesi olmayanlar listelenebilir.

DeleteProfile Parametre olarak verilen kullancya ait profile bilgisinin


silinmesini salamaktadr. Bu metod silme ilemi baarl
ise true deerini dndrr.

DeleteProfiles Bu metodun iki farkl versiyonu vardr. Bunlardan


birisi ProfileInfoCollection tipinden dieri ise string dizisi
tipinden parametre almaktadr. Dolaysyla profile bilgilerinin
silinmesi istenen kullanc tipleri iki farkl ekilde yklenebilir.

DeleteInactiveProfiles Profil sahibi kullanclarn LastActivityDate zelliklerinin


deerlerine gre belirtilen tarih ve ncesinde olanlarn
silinmesini salayan metod ProfileAuthenticationOption enum
sabiti tipinden deerde almaktadr.

imdi bu snfn kullanld rnek bir web sayfasn projeye dahil edelim. Sayfann tasarm
zamanndaki(design-time) grnts ve kodlar aadaki gibidir.

www.bsenyurt.com Page 774


ProfilYoneticisi.aspx;

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


Inherits="ProfilYoneticisi" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Profil Ynetim Ekran</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Dorulama Tipi :<asp:DropDownList ID="ddlDogrulamaTipi"
runat="server"></asp:DropDownList>
<asp:Button ID="btnTumProfiller" runat="server" OnClick="btnTumProfiller_Click"
Text="Tm Profilleri Getir" /><br />
Kullanc Ad(Benzeri) :
<asp:TextBox ID="txtKullaniciAdi" runat="server"></asp:TextBox>
<asp:Button ID="btnIsmeGoreGetir" runat="server" OnClick="btnIsmeGoreGetir_Click"

www.bsenyurt.com Page 775


Text="sme Gre Getir" /><br />
Aktivite Tarihi :
<br />
<asp:Calendar ID="dtTarih" runat="server"></asp:Calendar>
<br />
<asp:Button ID="btnPasifleriGetir" runat="server" OnClick="btnPasifleriGetir_Click"
Text="Pasifleri Getir" /><br />
Bulunan :
<asp:Label ID="lblKullaniciSayisi" runat="server" Text="Label"></asp:Label><br />
<br />
<asp:GridView ID="grdTumProfiller" runat="server"
OnRowCommand="grdTumProfiller_RowCommand"
OnRowDeleting="grdTumProfiller_RowDeleting">
<Columns>
<asp:CommandField ButtonType="Button" DeleteText="Sil"
ShowCancelButton="False" ShowDeleteButton="True" />
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>

ProfilYoneticisi.aspx.cs;

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Web.Profile;

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


{
protected void Page_Load(object sender, EventArgs e)
{
if (!Page.IsPostBack)
{
// ProfileAuthenticationOption enum sabitinin ieriini Enum snfn GetNames metodu ile
alarak DropDownList kontrolne dolduruyoruz.
ddlDogrulamaTipi.DataSource
= Enum.GetNames(typeof(ProfileAuthenticationOption));
ddlDogrulamaTipi.DataBind();
}
}

// Bu metod var olan tm profil bilgilerini getirmek zere tasarlanmtr


private void TumProfilleriGetir()
{
// DropDownList kontrolnden seilen dorulama kriterinin enum sabitindeki karl

www.bsenyurt.com Page 776


seiliyor.
ProfileAuthenticationOption
dogrulamaKriteri=(ProfileAuthenticationOption)Enum.Parse(typeof(ProfileAuthenticatio
nOption), ddlDogrulamaTipi.SelectedValue);
// GetAllProfiles metodu ile dorulama kriterine uygun olan profil bilgileri ProfileInfoCollection
tipinden bir koleksiyona aktarlr.
ProfileInfoCollection tumProfiller =
ProfileManager.GetAllProfiles(dogrulamaKriteri);
grdTumProfiller.DataSource = tumProfiller;
grdTumProfiller.DataBind();
// Sz konusu dorulama kriterine uyan profillerin says elde edilir.
lblKullaniciSayisi.Text =
ProfileManager.GetNumberOfProfiles(dogrulamaKriteri).ToString();
}

// GridView kontrolnde Delete ilemi gerekletirildiinde alan olay metodudur.


protected void grdTumProfiller_RowCommand(object sender, GridViewCommandEventArgs e)
{
if (e.CommandName == "Delete")
{
int rowIndex=Convert.ToInt32(e.CommandArgument);
string userName=grdTumProfiller.Rows[rowIndex].Cells[1].Text;
// DeleteProfile metodu ile seilen satrdaki UserName bilgisine ait Profil silinir.
ProfileManager.DeleteProfile(userName);
TumProfilleriGetir();
}
}
protected void btnTumProfiller_Click(object sender, EventArgs e)
{
TumProfilleriGetir();
}

// TextBox ierisine girilen kullanc adna benzer olanlarn Profil bilgilerini getirir.
protected void btnIsmeGoreGetir_Click(object sender, EventArgs e)
{
ProfileAuthenticationOption dogrulamaKriteri =
(ProfileAuthenticationOption)Enum.Parse(typeof(ProfileAuthenticationOption),
ddlDogrulamaTipi.SelectedValue);
// % kullanlmas sayesinde ierisinde TextBox' taki bilgi geen kullanc adlarn elde ederiz.
ProfileInfoCollection profiller =
ProfileManager.FindProfilesByUserName(dogrulamaKriteri, "%" + txtKullaniciAdi.Text +
"%");
grdTumProfiller.DataSource = profiller;
grdTumProfiller.DataBind();
lblKullaniciSayisi.Text = profiller.Count.ToString();
}
protected void grdTumProfiller_RowDeleting(object sender, GridViewDeleteEventArgs e)
{

/* aspnet_Users tablosunda LastActivityDate deeri, seilen tarihten daha nce olanlarn elde
edilmesini salar. Bunun iin GetAllInactiveProfiles metodunun ikinci parametresi kullanlr. */
protected void btnPasifleriGetir_Click(object sender, EventArgs e)
{
ProfileAuthenticationOption dogrulamaKriteri =

www.bsenyurt.com Page 777


(ProfileAuthenticationOption)Enum.Parse(typeof(ProfileAuthenticationOption),
ddlDogrulamaTipi.SelectedValue);
grdTumProfiller.DataSource=ProfileManager.GetAllInactiveProfiles(dogrulamaKriteri,
dtTarih.SelectedDate);
grdTumProfiller.DataBind();
lblKullaniciSayisi.Text=ProfileManager.GetNumberOfInactiveProfiles(dogrulamaKriteri
, dtTarih.SelectedDate).ToString();
}
}

Sz konusu rnekte profil ynetimi adna basit ilemler yaplmaktadr. rnek olmas asnda var
olan tm profillerin elde edilmesi, seilen profillerden herhangibirinin silinmesi, ierisinde belirtilen
ada benzer olan profillerin ekilmesi veya belirli bir tarihten ncesine kadar aktivitesi olmayan
profillerin getirilmesi gibi ilemler yaplmaktadr. rnein tm profillerin listelenmesi istendiinde
aadakine benzer bir ekran grnts ile karlalr.

www.bsenyurt.com Page 778


Kullanc ad benzer olanlarn listelenmesine rnek olarak aadaki ekran grntsnde olduu gibi
ierisinde ma kelimesi geenler listelenebilir.

www.bsenyurt.com Page 779


Belirli bir sreden ncesine kadar pasif olan kullanclarn profil listesini elde etmek istediimizde
ise aspnet_User tablosunda yer alan LastActivityDate deeri baz alnr. Bir baka deyile
aktivite durumuna gre hareket eden ProfileManager snf metodlar tarih parametresinin
deerlerini, sz konusu tablodaki alan ile kyaslayarak almaktadr. Bu tabloya ait rnek bir ekran
grnts aada grld gibidir.

www.bsenyurt.com Page 780


alma zamannda rnein 16.09.2007 tarihi ve ncesindeki profil bilgileri elde edilmek
istendiinde aadakine benzer bir ekran grnts ile karlarz.

simsiz(Anonymous) kullanclar iin profil bilgilerini kullanabilmek;

Baz durumlarda siteyi ziyaret eden isimsiz kullanclar(anonymous users) iinde profil
bilgilerinin tutulmas ve saklanmas istenebilir. Profile API, isimsiz kullanclar iin olduka gl
bir hizmet salamaktadr. Sistemin almas aslnda son derece basittir. Gerekli konfigurasyon
ayarlarnn yaplmasnn ardndan siteye balanan isimsiz kullanclar iin
birer GUID retilmektedir. Bu GUID(Global Unique IDentifier) deerleri
bir erez(cookie) yardmyla istemcinin bilgisayarnda saklanrlar. Bylece isimsiz kullanclarn
sunucu tarafnda tespit edilebilmesi kolay bir ekilde salanmaktadr. Dikkat edilmesi gereken
durumlardan birisi istemcilerin oturum(session) alar arasnda farkl tarayclar kullanabilecek
olmasdr. Bu durumu ilerleyen ksmlarda analiz etmeye alacaz. simsiz kullanclara destek
salayabilmek iin web.config dosyas ierisindeanonymousIdentification elementinin ilgili
zelliklerinin deerlerinin atanmas gerekmektedir. Bir nceki rnek ile karmamas asndan bu
kez yeni bir web uygulamas ile devam edelim. Bu seferki rnekte profil

www.bsenyurt.com Page 781


zelliklerini web.config dosyas ierisinde tanmlyor olacaz. Bu amala web.config dosyasnn
ieriini aadaki gibi tasarladmz varsayalm.

Web.config;

<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<compilation debug="true"/>
<authentication mode="Forms"/>
<authorization>
<allow users="*"/>
</authorization>
<anonymousIdentification enabled="true" cookieSlidingExpiration="true"
cookieTimeout="3"/>
<profile enabled="true">
<properties>
<add name="SonGirisZamani" type="System.DateTime" allowAnonymous="true"/>
<group name="Urun">
<add name="UrunAdi" type="System.String" allowAnonymous="true"/>
<add name="UrunFiyati" type="System.Double" allowAnonymous="true"/>
</group>
</properties>
</profile>
</system.web>
</configuration>

anonymousIdentification elementi ierisinde tanmlanabilecek pek ok nitelik(attribute) yer


almaktadr. Bu niteliklerden bazlar yukardaki rnekte
kullanlmtr.cookieSlidingExpiration niteliine true deeri atand iin istemciler, timeout
sresi ierisinde talepte bulunduka erezlerin(cookies) istemci bilgisayarda kalma sresi uzamaya
devam edecektir. (Bu tipik olarak Caching mimarisinde kullanlan Sliding Expiration alma sistemi
ile ayndr.) Bununla birlikte cookieTimeout niteliine atanan 3 deeri ile erezin istemci
bilgisayarda 3 dakika sreyle saklanaca belirtilmektedir. (Uygulamann dorulanm
kullanclar(authenticated users) ile birlikte isimsiz kullanclarada(anonymous
users) hizmet vermesi iin authorization elementi ierisinde bilinli olaraktan tm
kullanclar(*) allow edilmitir.)

lk olarak isimsiz kullanclara ait profil bilgilerinin saklandn ispat etmeye alalm. Bu amala
default.aspx sayfasnn ieriini ve kodlarn aadaki gibi tasarladmz dnelim.

www.bsenyurt.com Page 782


Default.aspx;

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


Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:LoginName ID="LoginName1" runat="server" />
<asp:LoginStatus ID="LoginStatus1" runat="server" />
<br />
<br />
Son Giri Zaman :<asp:Label ID="lblSonGirisZamani" runat="server"
Text="Label"></asp:Label><br />
<br />
Urun Ad :<asp:TextBox ID="txtUrunAdi" runat="server"></asp:TextBox><br />
<br />
Urun Fiyat :&nbsp;<asp:TextBox ID="txtUrunFiyati" runat="server"></asp:TextBox>
<br />
<br />
<asp:Button ID="btnProfilGetir" runat="server" OnClick="btnProfilGetir_Click"
Text="Profil Getir" />
<asp:Button ID="btnProfilKaydet" runat="server" OnClick="btnProfilKaydet_Click"
Text="Profil Kaydet" /></div>
</form>
</body>
</html>

Default.aspx.cs;

using System;
using System.Data;
using System.Configuration;

www.bsenyurt.com Page 783


using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

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


{
protected void btnProfilGetir_Click(object sender, EventArgs e)
{
try
{
lblSonGirisZamani.Text = Profile.SonGirisZamani.ToString();
txtUrunAdi.Text = Profile.Urun.UrunAdi;
txtUrunFiyati.Text = Profile.Urun.UrunFiyati.ToString("C2");
}
catch (Exception exp)
{
Response.Write(exp);
}
}
protected void btnProfilKaydet_Click(object sender, EventArgs e)
{
Profile.SonGirisZamani = DateTime.Now;
Profile.Urun.UrunAdi = txtUrunAdi.Text;
double urunFiyati = 1;
Double.TryParse(txtUrunFiyati.Text, out urunFiyati);
Profile.Urun.UrunFiyati = urunFiyati;
Profile.Save();
}
}

Uygulamay altrdmzda isimsiz bir kullanc ile default.aspx sayfasn aabildiimizi grrz. Bu
aamada rnek bir ka veri girip Profil Kaydet balkl dmeye bastmzda ise bilgilerin baarl
bir ekilde kaydedildiini grebiliriz. rnein aadaki veriler girildiinde
veritabanndaki aspnet_profile tablosunada bir satr eklendii grlecektir.

www.bsenyurt.com Page 784


Dahas kullanc siteye 3 dakikalk sre zarf ierisinde yeni bir talepte(request) bulunduunda ve
Profil Getir balkl dmeye bastnda ilgili bilgileri elde edebiliecektir.

ok doal olaraktan timeout sresi sona erdikten sonra profil bilgileri getirilmek istenirse aadaki
gibi bir ekran grnts alnacaktr.

www.bsenyurt.com Page 785


Bir baka deyile istemci bilgisayardaki erez(cookie) silindiinden sunucuda eleen
bir GUID bulunamamaktadr. (GUID' in bulunamamas isimsiz kullancnn aspnet_users
tablosundan silindii anlamna gelmemektedir) Buda istenen bilgilerin elde edilemeyecei anlamna
gelir. Elbetteki veriler aspnet_profile tablosunda durmaya devam edecektir. Bu
noktadaProfileManager snfnn ilgili metodlarndan yararlanarak belirli periyodlarda sz konusu
verilerin temizlenmesi salanabilir.

Gelelim kullancnn ayn uygulamaya isimsiz olarak farkl tarayclar ile erimesi durumuna. Bu
amala rnei nce Internet Exlplorer ile ap profil bilgilerini kaydediyor olacaz. Sonrasnda ise
3 dakikalk zaman dilimi sona ermeden Firefox ile ayn sayfay yeniden talep edeceiz. rnek
olarak rn adn Vazo, rn fiyatn 4.5 olarak girdiimizi dnelim.

www.bsenyurt.com Page 786


Dikkat edilecei zere Internet Explorer kullanlp kaydedilen profil bilgilerine 3 dakikalk sre
zarf ierisinde baka bir tarayc program olan Firefox Mozilla ierisinde eriilememitir. Tersi
durumda sz konusudur. Buna gre farkl tarayc pencereleri ile gelen taleplerde(request)
sunucunun farkl bir GUID reteceini ve istemci bilgisayara erez olarak yazacan gz nne
almalyz.

simsiz kullanclar(anonymous users) ile ilgili bir dier durumda var olan dorulanm bir
kullanc ile birletirilmeleridir(Migration). Bu durumu daha kolay anlayabilmek
iinamazon.com sitesinin ileyi eklini gz nne alabiliriz. Bu siteye giren kaytl bir kullanc
login olmadan sepete rnler ekleyebilmektedir. Dier taraftan kullanc alveri safhasna geip
sayfaya Login olduunda, isimsiz kullanc olarak sepete att bilgiler var olan kullanc hesabndaki
sepet bilgilerine eklenebilmektedir. Asp.Net 2.0 mimarisinde bu tarz bir ilemi belirli bir lde
kontroll olarak gerekletirebilmek iin
iin Global.asax.cs dosyasnda Profile_OnMigrateAnonymous olay metodunun yklenmesi
yeterlidir. Bu metodun ald ProfileMigrateEventArgs tipinden parametre sayesinde isimsiz

www.bsenyurt.com Page 787


kullanc(anonymous user) iin retilen GUID deerine eriilebilir ve ilgili deerlerin alnarak, login
olan kullancya aktarlmas salanabilir. Yanlz bu noktada daha ncede login olup profil bilgisi
kaydedilmi bir kullancnn bilgileri zerine yazlmamaya allmasna zen gsterilmelidir. Bu
durumu analiz edebilmek iin global.asax.cs dosyasna aadaki kod parasn eklediimizi gz
nne alabiliriz.

<%@ Application Language="C#" %>

<script runat="server">

void Profile_OnMigrateAnonymous(object sender, ProfileMigrateEventArgs e)


{
/* nce isimsiz kullancnn profile bilgisi elde ediliri. GetProfile metodunun dn deeri
ProfileCommon tipinden olaca iin buna gre bir atama yaplr. */
ProfileCommon isimsizProfil = Profile.GetProfile(e.AnonymousID);
/* Login olan dorulanm kullancnn halen aktiv olup olmad renilir. Eer aktiv ise profil
bilgileri mevcut demektir ve stne yazlmas istenmez. Bu nedenle LastActivityDate deerine
baklarak bir kontrol yaplmas gerekmektedir. */
if (Profile.LastActivityDate.Date == DateTime.MinValue.Date)
{
// simsiz kullancnn profil zelliklerinin deerleri ile login olan dorulanm kullancnn
profil zellikleri eletirilir
Profile.SonGirisZamani = isimsizProfil.SonGirisZamani;
Profile.Urun.UrunAdi = isimsizProfil.Urun.UrunAdi;
Profile.Urun.UrunFiyati = isimsizProfil.Urun.UrunFiyati;
Profile.Save(); // Login olan kullanc iin deitirilen profil deerleri kaydedilir.
}
AnonymousIdentificationModule.ClearAnonymousIdentifier();// isimsiz kullanc iin
retilen erezin silinmesi salanrki bu olay tekrar tetiklenmesin
ProfileManager.DeleteProfile(e.AnonymousID); //isimsiz kullancya ait profil deerleri
veritabanndan silinir.
}

</script>

Yukardaki rnek kod parasnda ncelikli olarak isimsiz kullancnn profil bilgileri elde edilmektedir.
Bu amala GetProfile metodu kullanlmtr. Sonrasnda ise, o an Login olmu kullancnn bir profil
bilgisi olup olmad tespit edilir. Bu kontrolde LastActivityDate zelliinden yararlanlr. Burada
ama isimsiz kullancnn(anonymous users) profil bilgilerini, login olmu kullancnn var olan profil
bilgileri zerine yazmamaktr. (Burada global bir kontrol yaplp istemciden bilgilerin stne yazmak
isteyip istemeyecei ele alnaraktanda ilerlenebilir. Bu tamamen uygulamann veya srecin
ihtiyalar dorultusunda verilebilecek bir karardr.) Sonrasnda login olan kullancnn profile
kaydettii bir bilgi yoksa isimsiz kullanc iin oluturulan deerlerin atamas yaplr ve kaydetme
ilemi(save) gerekletirilir. Son olarak olay metodunun tekrardan tetiklenmemesi amacyla
isimsiz kullancya ait bilgi veritabanndan silinir. Ayrca istemcideki erez
bilgiside AnonymousIdentificationModule snfnn static ClearAnonymousIdentifier metodu
ile geersiz klnr. Sonu olarak isimsiz kullanc giri yapp profil bilgisini kaydettikten sonra daha
nceden profil bilgisi bulunmayan bir kullanc gibi Login olursa, var olan bilgileri dorulanm
kullancnnkine aktarlacaktr.

Bylece geldik uzun bir makalemizin daha sonuna. Bu makalemizde profile ynetimini biraz daha
gl ve esnek hale getirmek iin neler yapabileceimizi incelemeye altk. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn (Dosya boyutunun kk olmas amacyla Aspnetdb veritabanlar ve
log dosyalar kartlmtr)

www.bsenyurt.com Page 788


Burak Selim ENYURT
selim@bsenyurt.com

WPF - Sayfa(Page) Kavram, Navigasyon


lemleri ve XBAP ( 04.10.2007 ) - WPF
Deerli Okurlarm Merhabalar,

Yllardr ister byk apl ister kk apl olsun pek ok proje web tabanl olarak gelitirilmektedir.
Projelerde bu tip bir seime gitmenin en byk nedenlerinden biriside web
uygulamalarndaki datm modelinin(Deployment Model) Windows tabanl olanlara gre ok
daha kolay olmasdr. Her ne kadar .Net 2.0 ile birlikte gelen ClickOnce veya daha ncesinden beri
var olan ActiveX gibi datm kolaylatrabilecek teknolojiler var olsada bunlar Web
uygulamalarna olan ynelimi azaltamamtr. Sonu itibariyle web tabanl uygulamalarda, yazlan
paralar yorumlayacak bir tarayc penceresinin(Browser) olmas yeterlidir. Geriye kalan, sz
konusu tarayc pencerelerinin yorumlayaca HTMLieriklerinin oluturulmasdr. Bu amalada son
derece gelimi sunucu(Server-Side) veya istemci tarafl(Client-Side) uygulama gelitirme
modelleri mevcuttur. Asp.Net bu modellerden yanlzca birisidir. Ancak web tabanl uygulamalarda
tarayc tarafndan bakldnda datm dnda salanan baka avantajlarda vardr. rnein,
tarayc penceresi yardmyla uygulama(Application) alan ierisinde bir sayfadan dierine gemek
bir baka deyile navigasyon ilemleri ile dolamak ok kolaydr. Bu tip bir kullanm kolayln
Windows uygulamalarna kazandrmak ekstra kodlamay gerekirmektedir.

Microsoft, .Net Framework 3.0 ile birlikte Windows uygulamalarnn tarayc pencereleri ierisinde
altrlabilmesini salayacak bir yenilik getirmektedir. Ksacas XBAP(XAML Browser
Applications) olarak adlandrlan bu modelde, kstlamalar ile birlikte bir WPF(Windows
Prensetation Foundation) uygulamasn bir tarayc penceresinde amak mmkndr. Yaz
dizimizde bu konuyada deiniyor olacaz. Ama ncesinde bunlarn temelini oluturan
sayfa(Page) kavramn anlamak gerekmektedir.

WPF uygulamalarn sayfa tabanl(Page-Based) olacak ekilde tasarlayabilmekteyiz. Burada


sayfadan kast Page tipinden bir nesnedir. WPF mimarisinde sayfa tabanl uygulamalarda kendi
ilerinde iki ana paraya ayrlmaktadr. Bunlardan birincisi XBAP uygulamalar, dieri ise kendi
bana alan(Stand-Alone) uygulamalardr. Sayfalar(Pages) aslnda daha nceki
makalelerimizde de incelediimiz Window tipine benzetilebilir. Lakin arada ok nemli bir fark
vardr. Window tipi temel olarak bir tayc(Container) grevini stelenebilmektedir. Bu
sebeptende ContentControl tipinden tretilmitir. Ne varki Page tipi
dorudan FrameworkElement tipinden tremektedir. Dolaysyla Page tiplerinin kullanlabilmesi
iin bunu servis edecek bir sunucuya(Host) ihtiya vardr. Sz konusu zet bilgilere gre sayfa
bazl(Page-Based) uygulamalar aadaki gibi kategorize edebiliriz.

Standalone (Kendi NavigationWindow ierisinde kullanlabilen sayfalar.


bana
alan uygulamalar) Bir pencerede(Window) yer alan Frame veya Frame' ler
ierisinde kullanlabilen sayfalar.

Baka bir sayfa(Page) ierisindeki Frame veya Frame' lerde


kullanlabilen sayfalar.

XBAP(Xaml Browser Internet Explorer veya destek veren baka bir tarayc(Browser)
Applications) zerinde alabilen sayfalar. Lightweightolarakta adlandrlan
Uygulamalar basit web tabanl datm modeli iin uygun bir yap sunmaktadr.

www.bsenyurt.com Page 789


Sayfa tabanl(Page-Based) uygulamalarda kullanlan genel tipler aadaki snf diagramnda(Class
Diagram) grld gibidir.

Yukardaki snf diagramnda sayfa-tabanl(Page-Based) uygulamalarda barol oynayan


snflardan(class) bazlar yer almaktadr. Window snf daha nceki windows programlamada yer
alan Form snfnn karl olarak dnlebilir. Bir ierik kontroldr(ContentControl). Bu
nedenle kendi ierisinde baka elementleride barndrmaktadr. Sz gelimi Window ierisinde
bir Frame tanmlanp bu Frame ierisinde de farkl sayfalar(Page) yer alabilir. Frame tipi aslnda bir
sayfa ierisinde bamsz bir para olaraktanda dnlebilir. Frame' leri
bir Page veya Windows elementi ierisinde kullanabiliriz. Temel grevleri aslnda web
uygulamalarndan bilinen benzeri ile ayndr. Bir baka deyile tayc kontrol ierisinde baka
sayfalarn(Page) gsterilebilmesini salamaktadr. Bu tayc zellii nedeni ilede tahmin edilecei
gibi ContentControl snfndan tremektedir. NavigationWindow, ierisinde Page elementlerini
ierebilen bir tiptir. Varsaylan olarak Page elementi ieren bir XAML ierii code-behind dosyas ile
birlikte altrldnda alma zamannda otomatik olarak bir NavigationWindow nesnesi
rneklenmektedir. NavigationWindow nesneleri alma zamannda dinamik olaraktanda
rneklenebilir ve sayfa ieriklerini gstermesi salanabilir.

Bu ksa teorik bilgilerden sonra dilerseniz basit rnekler yardmyla konuyu daha iyi anlamaya
alalm. Eer ayn pencere zerinde yer alacak ve aralarnda geiler yaplabilecek sayfalardan
bahsediyorsak doal olaraktan bunlarn arasnda dolaabilmek gerekmektedir. Dolama ilemleri

www.bsenyurt.com Page 790


iin kullanlabilecek en basit kontrol Hyperlink bileenidir. Bu bileenin NavigateUri zelliinden
yararlanlarak baka bir sayfaya geilmesi, ayn sayfa ierisinde veya baka bir sayfa ierisinde yer
alan bir noktaya gidilmesi(burada anchor benzeri bir kullanmdan bahsediyoruz), baka
bir NavigationWindow ierisinde bir sayfaya ve hatta var olan geerli bir Url adresine gidilmesi
salanabilir. Dolaysyla ilk rneimizde bu durumu analiz etmeye alyor olacaz. Bu
amala Visual Studio 2008 Beta 2 srmnde yeni bir WPF uygulamas ap XAML ierikleri
balangta aadaki gibi olan iki sayfa(Page) tasarlamamz yeterlidir.

Page tiplerini bir WPF uygulamasna eklerken elerden(Item) yararlanlabilir. Bunun


iin projeye sa tklayp Add New Item penceresinden yada, dorudan sa tklaynca
kan menlerden Add->Page ile gerekletirebiliriz.

MainPage.xaml

<Page x:Class="PageKullanimi.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Ana

www.bsenyurt.com Page 791


Sayfa"WindowHeight="250" WindowWidth="400" WindowTitle="Azon Giri
Sayfas" Loaded="Page_Loaded">
<Page.Background>
<ImageBrush ImageSource="Iceberg.jpg" Opacity="0.4"/>
</Page.Background>
<Grid>
<Label Foreground="Black" FontSize="15" FontWeight="Bold" Height="30"
HorizontalAlignment="Left" VerticalAlignment="Top" Width="113" Margin="9,21,0,0">
<Hyperlink NavigateUri="PageX.xaml" ToolTip="Bir sonraki sayfaya gemenizi
salar">Sonraki Sayfa</Hyperlink>
</Label>
<Button Name="btnBilgiSayfasi" Background="LightGray" Width="120" Height="30"
FontSize="12" FontWeight="Bold" HorizontalAlignment="Left" Margin="9,107,0,0"
VerticalAlignment="Top">
<Hyperlink Foreground="Red" NavigateUri="Page2.xaml">Bilgi Giri
Sayfas</Hyperlink>
</Button>
<TextBox Name="txtHosgeldinMesajim" Margin="9,60,33,0" Height="21"
VerticalAlignment="Top" />
</Grid>
</Page>

MainPage ierisinde ilk dikkati eken noktalardan birisi Page elementi ve


zellikleridir. WindowHeight ve WindowWidth zellikleri ile alma
zamanndaki NavigationWindow penceresinin boyutlar set edilmektedir. WindowTitle zellii ile
sayfann NavigationWindow ierisinde gsterilirken sahip olaca balk deeri
verilmektedir. Title zellii ise, navigasyon ilemlerinin yapld Combobox ierisindeki balk
bilgisini belirlemektedir. Aadaki ekil alma zamanndaki bir ekran grnts olup bahsedilen
zellikleri ifade etmektedir.

www.bsenyurt.com Page 792


Page snfnn Window snfnda olduu gibi Show veya Hide gibi metodlar
bulunmamaktadr. Bunun en byk nedeni Page snflarna ait nesne rnekleri aralarnda
gezinirken navigasyon kontrollerinden yararlanlabilmesidir. Dolaysyla klasik windows
programclndan bildiimiz Show veya Hide gibi ilemlere gerek kalmamaktadr.

Bunlarn dnda MainPage ierisinde Label ve Button kontrollerine ait elementler ierisinde
Hyperlink alt elementleri kullanlmtr. Hyperlink bileeni bamsz bir element olarak
kullanlamamaktadr. Dolaysyla Inline-Flow tipinden bir kontroldr. Dier taraftan bu
elementin NavigateUri zellii ile gidilmek istenen sayfalar belirtilmektedir.

Hyperlink elementi Page yerine bir Window ierisinde kullanlmak istendiinde


belirtilen adrese otomatik olarak gidilemeyecektir. Byle bir durumda Window
snfnnRequestNavigate olaynn bilinli olarak ele alnmas ve ynlendirme ileminin
manuel olarak yaplmas gerekmektedir.

Label kontrolnde yer alan Hyperlink elementinde kastl olarak projede yer almayan PageX.xaml' e
gidilmeye allmaktadr. Burada ama olmayan bir adrese gidilmek istendiinde ne olacann
analiz edilmesidir. Button kontrol ierisinde yer alan Hyperlink elementinde ise, XAML ierii
aada yer alan Page2 isimli sayfaya gidilmektedir.

Page2.xaml

<Page x:Class="PageKullanimi.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowTitle="Bilgi Giri Sayfas"
Title="Bilgi Girii" Loaded="Page_Loaded">
<Grid>
<Label FontSize="12" FontWeight="Bold" Height="25" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="85" Margin="0,24,0,0">Tc Kimlik No</Label>
<Label FontSize="12" FontWeight="Bold" HorizontalAlignment="Left" Width="85"
Margin="0,83,0,0" Height="25" VerticalAlignment="Top">Semt</Label>
<Label FontSize="12" FontWeight="Bold" Height="25" HorizontalAlignment="Left"
VerticalAlignment="Top" Width="85" Margin="0,46,0,0">Aranan Hat</Label>
<Button FontSize="14" Margin="125,117,62,0" Name="btnKontrolSayfasi"
Click="btnKontrolSayfasi_Click" Height="24" VerticalAlignment="Top">
Kontrol Sayfas
</Button>
<TextBox Name="txtTcNo" Height="21" Margin="120,27,60,0" VerticalAlignment="Top" />
<TextBox Name="txtArananHat" Height ="21" Margin="120,57,60,0"
VerticalAlignment="Top" />
<TextBox Name="txtSemt" Height ="21" Margin="120,89,60,0" VerticalAlignment="Top" />
</Grid>

www.bsenyurt.com Page 793


</Page>

lk olarak rnei alma zamannda test ederek ie balayalm. Uygulamann yrtlmeye


balamas halinde MainPage.xaml sayfasnn rneklenmesi iin App.xaml' e ait Application
elementi ierisindeki StartupUri zelliinin deeri MainPage.xaml olarak ayarlanmtr. Aadaki
Flash grselinde ilk alma hali gsterilmektedir.

Dikkat edilecek olursa alma zamannda(Run-Time) otomatik olarak bir navigasyon ubuu
oluturulmutur. lk aamada bu ubuk zerindeki dmeler pasiftir. Aktif olmalar iin sayfalar
arasnda gei yaplmas gerekmektedir. Sayfalar aras gei yapldktan sonra navigasyon
dmeleri ile ileri ve geri ynl hareketler yaplabilir. Bununla birlikte Combobox kontrolnden
yararlanlaraktanda dier sayfalara daha kolay bir ekilde gei yaplmasda salanabilir. Bu
rnekte PageX.xaml sayfasna gei yaplmasn salayan Label kontrolne baslmamtr. Bu
yapld takdirde sz konusu sayfa olmad iin aadaki ekran grntsnde yer alan bir alma
zaman istisnas(exception) alnacaktr.

Grld gibi basit bir IOException alnmtr. Elbetteki programatik olarak uygulamay
tasarlarken olmayan sayfalara gidilmemesini salamak gelitiricinin grevidir. LakinNavigateUri ile
var olan bir sayfa dnda geerli bir URL adresinede gidilebilmesi salanabilmektedir. Bir baka
deyile var olan bir web sayfasn alma zamannda oluturulanNavigationWindow ierisinde bir
sayfa olarak gstermek mmkndr. Bu gibi durumlarda gidilmek istenen URL veya Sayfa
bilgisinin geerli olmamas halinde programn istem d bir ekilde sonlanmasnn nne gemek

www.bsenyurt.com Page 794


iin Application nesnesinin NavigationFailed olayn ele almak ve ierisinde istisna bilgisini
kontroll bir ekilde yakalamak en doru yaklam olacaktr. Yukardaki rnekte bunu uygulamak
istediimiz App.xaml ve App.xaml.cs ieriklerinin aadaki gibi tasarlanmas yeterlidir.

App.xaml;

<Application x:Class="PageKullanimi.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"StartupUri="MainPage.xaml"
NavigationFailed="Application_NavigationFailed">
<Application.Resources>
</Application.Resources>
</Application>

App.xaml.cs;

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Windows;

namespace PageKullanimi
{
public partial class App : Application
{
private void Application_NavigationFailed(object
sender, System.Windows.Navigation.NavigationFailedEventArgs e)
{
if (e.Exception != null)
{
MessageBox.Show(e.Uri.ToString() + " adresi bulunamad");
e.Handled = true;
}
}
}
}

rnekte basit olmas asnda sadece hataya neden olsan sayfann Uri bilgisi
bir MessageBox ierisinde gsterilmektedir. Olay metoduna
gelen NavigationFailedEventArgs tipinden e parametresinin Handled zelliine true deeri
atanmasnn sebebi hatann kontroll bir ekilde ele alndnn belirtilmesidir. Aksi durumda
program yine hata sonras, kullancya oluan hatann gnderilip gnderilmeyeceini soran
hepimizin yakndan tand mesaj kutusu ile sonlandrlacaktr. Burada yakalanan hatalar ok doal
olarak baka amalarlada deerlendirilebilir. rnein Log' lanarak, oluan hatalar ile ilikili genel
istatistik ve analizlerin yaplmas salanabilir.

Hyperlink kontroln kullanarak web sayfalarnada gidilebildiinden bahsetmitik. Bunun dnda bir
sayfa ierisinde yer alan herhangibir konuma gidilmeside salanabilirki bu durumparal
navigasyon(Fragment Navigation) olarak adlandrlmaktadr. imdi bu iki kullanm eklini ele
alacamz bir rnek zerinden ilerleyelim. Bu amala projemize Page3.xaml ve Page4.xaml
sayfalarn aadaki ierikleri ile eklediimizi dnebiliriz.

www.bsenyurt.com Page 795


Page3.xaml;

<Page x:Class="PageKullanimi.Page3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" WindowTitle="Dorulama Sayfas"
Title="Dorulama" WindowHeight="250" WindowWidth="400">
<Grid>
<Button Name="btnCSHarpNedir" FontSize="14" FontWeight="Bold" Height="25"
Margin="20,36,30,0" VerticalAlignment="Top">
<TextBlock>
<Hyperlink Foreground="Red"
NavigateUri="http://www.csharpnedir.com">C#Nedir?</Hyperlink>Sayfasna Gider.
</TextBlock>
</Button>
<Button Name="btnIceberg" FontSize="14" FontWeight="Bold" Height="25"
VerticalAlignment="Top" Margin="20,90,30,0">
<TextBlock>
<Hyperlink NavigateUri="Page4.xaml#txtBilgi"
Foreground="Red">Iceberg</Hyperlink>
</TextBlock>
</Button>
</Grid>
</Page>

Sayfann ierisinde kullanlan iki adet Hyperlink kontrol bulunmaktadr. Bunlardan


birisi C#Nedir? sitesine, dieri ise Page4.xaml sayfas ierisinde txtBilgi isimli bileenin olduu
yere ynlendirme yapmaktadr. kinci navigasyon ilemi aslnda paral navigasyon(Fragment
Navigation) ilemi iin bir rnektir. yleki Page4.xaml sayfas ierisinde yer alan txtBilgi isimli
kontrol sayfann alt ksmnda yer almaktadr. Bu nedenle sayfa ierisindeki bu yere navigasyon
ilemi ile gidilmesi ve odaklanlmas mmkn olabilmektedir.

www.bsenyurt.com Page 796


Page4.xaml;

<Page x:Class="PageKullanimi.Page4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Antartika Iceberg"
WindowTitle="Iceberg">
<Grid>
<ScrollViewer VerticalScrollBarVisibility="Visible">
<Canvas Height="299" Width="284">
<Image Canvas.Left="18" Canvas.Top="51" Height="104" Name="image1"
Width="150" Source="Iceberg.jpg" />
<Label Canvas.Left="18" Canvas.Top="26" Height="23" Name="label1"
Width="120">Antartika Hakknda</Label>
<Label Canvas.Left="18" Canvas.Top="166" Height="23" Name="label2"
Width="120">
<Hyperlink NavigateUri="Page4.xaml#txtBilgi">Genel Bilgi</Hyperlink>
</Label>
<TextBox Height="25" Name="txtBilgi" Canvas.Left="18" Canvas.Top="274"
Width="249" />
</Canvas>
</ScrollViewer>
</Grid>
</Page>

Page4.xaml ierisinde de bu sayfadaki txtBilgi kontrolne odaklanlmasn salayan


bir Hyperlink bileeni bulunmaktadr. Dikkat edilecek olursa paral navigasyon
ilemlerindeNavigateUri zelliinde # iaretinden sonra bir bilgi yer almaktadr. Bu bilgi gidilmek
istenen kontroln Name zelliinin(Property) deeridir. rnein alma zamanndaki ileyii
aadaki Flash animasyonunda olduu gibidir.

www.bsenyurt.com Page 797


Grld gibi Page3.xaml ierisinde yer alan dme kontrollerine basldnda C#Nedir? sayfasna
veya Page4.xaml ierisindeki txtBilgi isimli TextBox kontrolnn olduu yere gidilmektedir.
Herhangibir internet veya intranet adresine gidilmesini salayan teknikte mutlaka hata kontrol
yaplmaldr. Dier taraftan bir web sayfasna gidildiinde sayfada grnen ksm klasik windows
programlamadan tandmz WebBrowser kontrolnn sunduu ortama benzemektedir. Bu
sebepten dolay elde edilen sayfa ierisinde arama yapmak, dinamik kod altrmak gibi ilemler
yaplamamaktadr.

Paral navigasyon(Fragment Navigation) ileminin olabilmesi iin, sz konusu sayfa


ierisinde aa yukar hareket edilebilmesi bir baka deyile scrolling olmas
gerekmektedir. Bu amala ScrollViewer kontrolnden yararlanlabilir. Sz konusu
kontroln VerticallScorllBarVisibility ve HorizontalScrollBarVisibility zelliklerine
ilgili deerler atanarak dikey veya yatay ynde kaydrma ubuklarnn(Scroll Bar)
gsterilmesi(yada tam tersi) salanabilir.

Navigasyon ilemleri istenirse manuel olarak kod tarafndan da gerekletirilebilir. Bu


noktada NavigationWindow ierisinde st ksmda grnen navigasyon kontrolleri ve mennn
yapt ilerin kod yardmylada gerekletirilmesi mmkndr. Bunun
iin NavigationService tipinden ve yelerinden(Members) yararlanlabilir. Sradaki rnekte yeni
bir sayfaya gei ilemini kod ile nasl yapabileceimize bakyor olacaz. Page2.xaml ierisindeki
btnKontrolSayfasi isimli Button dmesine tklandnda Page3.xaml sayfasna geilmesini
salamak iin ilgili olay metodunda aadaki kodlar yazmak yeterli olacaktr.

private void btnKontrolSayfasi_Click(object sender, RoutedEventArgs e)


{
this.NavigationService.Navigate(new Page3());
}

NavigationService referansn Button bileenine ait Click olay metodu ierisine yakaladktan
sonra Navigate fonksiyonuna parametre oalrak Page3 tipinin yeni bir nesne rnei verilmektedir.
Bylece Page3 nesne rnei oluturulup NavigationWindow ierisinde gsterilmesi
salanmaktadr. Buna gre rnein alma zamanndaki durumu aadaki Flash grselindeki gibi
olacaktr.

www.bsenyurt.com Page 798


stenirse alma zamannda yeni bir NavigationWindow oluturulmas ve bir sayfann bu rnek
zerinde almas salanabilir. Aadaki rnek kod paras ile, dmeye basld zaman Page3
isimli sayfann yeni bir pencere ierisinde almas salanmaktadr.

private void btnKontrolSayfasi_Click(object sender, RoutedEventArgs e)


{
NavigationWindow nvgWnd = new NavigationWindow();
Page3 pg3 = new Page3();
pg3.WindowTitle = "Yeni Pencerede Alan Dorulama Sayfas";
pg3.Title = "Dorulama(Yeni)";
pg3.WindowWidth = 300;
pg3.WindowHeight = 240;
//pg3.ShowsNavigationUI = false;
nvgWnd.Content = pg3;
nvgWnd.Show();
}

lk olarak yeni bir NavigationWindow nesne rnei oluturulmaktadr. Sonrasnda ise bu


pencerede gsterilmek istenen sayfa rneklenir. Sayfann WindowTilte, Title, WindowWidth,
WindowHeight gibi zellikleri set edildikten sonra NavigationWindow nesne
rneinin Content zelliine oluturulan Page3 nesne rnei atanr. Son olarak Show metodu ile
yeni pencerenin gsterilmesi salanmaktadr. Buradaki yorum satr alrsa eer, yeni pencerede
navigasyon kontrollerinin gsterilmemesi salanm olur. Uygulamay bu ekilde test ettiimizde
aadaki Flash grselindeki etkiler grlecektir.

www.bsenyurt.com Page 799


Sayfalar istenirse Frame' ler ierisinde gsterilebilirler. Bylece bir NavigationWindow ierisinde
birden fazla Frame kullanlarak birden fazla sayfann ayn anda gsterilmesi salanabilir. rnein,
ierisinde harici bir web sitesini, uygulamann kendisi, yardm dkmann barndracak ekilde bir
pencere gelitirilebilir. Frame tipi kendi ierisinde eitli elementler barndrabilmektedir ancak
genel kullanm amac Page tiplerini tamasdr. Bu tanmlamalar Frame tipinin webdeki kullanm
eklini tam olarak andrdnda gstermektedir. Konuyu daha net anlayabilmek iin bir rnek
zerinden ilerlemekte fayda olaca kansndaym. Bu amala projeye aadaki XAML ieriine
sahip yeni bir pencere(Window) eklediimizi dnelim.

<Window x:Class="PageKullanimi.FrameKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Frame Kullanimi" Height="400"
Width="300">
<Grid Margin="2">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Frame NavigationUIVisibility="Automatic" Grid.Row="0" BorderBrush="Black"
BorderThickness="3" Source="Page3.xaml"/>
<Frame Grid.Row="1" BorderBrush="Gold" BorderThickness="3"
Source="Page2.xaml"/>
</Grid>
</Window>

Frame kullanmn kolaylatrmak iin pencere ierisinde iki satrdan oluan bir Grid kontrol
konulmutur. Bu amala Grid kontrol ierisine RowDefinition elementleri ile iki satr eklenmitir.
Hangi Frame' in hangi satrda gsterileceini belirlemek iin Grid.Row elementlerinden
yararlanlmaktadr. Her Frame elementinin Source niteliklerine(attribute) atanan deerler ile
ilerinde gsterecekleri sayfalar belirlenmektedir. NavigationUIVisibility niteliine atanan deer
ile navigasyon kontrolnn Frame ierisinde gsterilip gsterilmeyecei veya rnekteki gibi bunun
otomatik olarak set edilip edilmeyecei belirlenebilir. Sz konusu Frame' ler dikkat edilecek olursa

www.bsenyurt.com Page 800


Page yerine bir Window elementi ierisinde kullanlmtr. rnek yrtldnde aadaki Flash
animasyonunda olduu gibi bir alma zaman sonucu elde edilir.

Flash animasyonundan grlebilecei gibi ilk etapta navigasyon kontrolleri gsterilmemektedir.


Ancak Frame' ler ierisinde yer alan sayfalar zerindeki kontroller yardmyla hareket edildikten
sonra navigasyon kontrolleri grlmektedir. Tabi
istenirse NavigationUIVisibility zelliine Visible deeri atanarak navigasyon kontrolnn
balangta kmasda salanabilir. Yukardaki rnekte meydana gelen ilemler aadaki grafikle
daha net anlalabilir.

stenirse sayfalar baka sayfalarn ierisinde de kullanlabilir. Byle bir durumda i ie


sayfalar(Nested-Page) sz konusu olmaktadr. Aadaki XAML ieriinde bir nested-page
tasarm rnei grlmektedir.

www.bsenyurt.com Page 801


XAML ierii;

<Page x:Class="PageKullanimi.NestedPageKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Nested Page Ornei"
WindowWidth="300" WindowHeight="300">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="89" />
<RowDefinition Height="211" />
</Grid.RowDefinitions>
<StackPanel Grid.Row="0">
<Label Foreground="Red" FontSize="14" FontWeight="Bold">Arama</Label>
<TextBox Text="Aranacak kelimeyi giriniz"/>
<Button Name="btnAra" Content="Ara" FontSize="12" FontWeight="Bold"
Background="Gold" Foreground="Black"/>
</StackPanel>
<Frame NavigationUIVisibility="Automatic" Grid.Row="1" BorderBrush="Black"
BorderThickness="3" Source="Page3.xaml"/>
</Grid>
</Page>

Dikkat edilecek olursa Page elementi ierisinde normal elementler dnda birde Frame elementi
kullanlmaktadr. Bu element ierisinde Source nitelii ile gsterilecek olan sayfa belirtilmektedir.
Bylece alan sayfa ierisinde birbirlerine bal baka sayfalarnda gsterilebilmesi
salanmaktadr. Olay aadaki grafik ile daha net kavrayabiliriz.

Uygulamann alma zamanndaki grnts aadaki Flash animasyonunda olduu gibidir.

www.bsenyurt.com Page 802


Burada dikkat ekici noktalardan biriside Frame ierisinde sayfalar arasnda gezinirken navigasyon
kontrolnn sayfann st ksmnda km olmasdr. Bu durumda Frame' lerin kendi navigasyon
ubuklarna sahip olmas salanabilir. Bunun iin Frame elementinin JournalOwnerShip ad
verilen niteliinden yararlanlr. Bu
nitelik Automatic, OwnsJournal veUsesParentJournal olmak zere farkl deerden birisini
alabilir. OwnsJournal deeri seildiinde aadaki ekran grntsnde olduu gibi Frame' in
navigasyon kontrol kendi ierisinde kacak, sayfann kendi navigasyon kontrol ise en st tarafta
yer alacaktr. Doal olarak bunlar birbirleriylede karmayacak ekilde almaktadr.

UsesParentJournal deerinin seilmesi halinde ise, Frame elementinin navigasyon kontrol bu


rnein ilk versiyonunda olduu gibi st tarafta yer alacaktr. Aslnda burada analiz edilmesi

www.bsenyurt.com Page 803


gereken bir durum daha vardr. Buda sayfann kendisinin navigasyon ilemlerine sahip olmas
halidir. Yani aadaki grafikteki gibi bir senaryo olduunu dnelim.

Dikkat edilecei zere Frame ierisinden baka iki sayfaya daha geilebilmektedir. Dier taraftan
sayfann kendiside(yani Frame' ide ieren Page) Page2.xaml sayfasna gei yapabilmektedir. Bu
tip bir durumda UsesParentJournal deerinin seilmesi zellikle XBAP uygulamalarnda olduka
ie yarayacaktr. Sz konusu kullanmda sayfalar ok fazla paralandndan zaman zaman takibin
zorlatda grlmektedir. Dolaysyla Nested-Page tekniinin bir alternatif olarak bilinmesinde ve
uygun vakkalar bulunduunda ele alnmasnda yarar vardr.

Yazmzn ierisinde belirttiimiz gibi navigasyon ilemlerini manuel olarak kod tarafndan da
yapabiliriz. Burada nemli olan nokta NavigationService zellii ile elde edilecek referans
olacaktr.Bununla birlikte bir sayfann navigasyon sreci ierisinde talep edilmesi halinde neler
olduunun bilinmesinde de yarar vardr. Bir baka deyile, navigasyon srecindeki yaam
dngsn bilmekte yarar vardr. Temelde sre bir sayfann talep edilmesi ile balar. Bu talep
ilemi basit bir Hyperlink kontrol ile olabilecei
gibi, NavigationService snfnn Navigate metodu ilede olabilir. Sonrasnda talep edilen sayfann
yeri tespit edilir. Tahmin edilecei zere burada bir sorun olmas halinde alma zaman istisnas
oluacaktr. Sayfa yeri tespit edildikten sonra bilgileri getirilir. rnein talep edilen sayfa bir
internet sayfas ise download ilemi gerekleir. Bu arada eer sayfann indirilmesi srasnda ilikili
kaynaklar var ise bunlarnda getirilmeside sz konusudur. Takip eden admda sayfa iin
bir ayrtrma(parsing) ilemi uygulanr ve sayfann nesne aac(Object Tree)oluturulur. Bu
ilemi takiben sayfaya ait Initialized ve Loaded olaylarda srasyla tetiklenir. Son aamada
sayfa Render ilemine tabi tutulur ve gsterilir. Bu noktada eer paral navigasyon(Fragment
Navigation) ilemi yaplmsa ilgili kontrole gidilmesi salanr. Aadaki temsili grafik bu ileyii
ksaca zetlemektedir.

www.bsenyurt.com Page 804


Birde bu sre ierisinde tetiklenen baz olaylar sz konusudur. Bu
olaylar Application, Frame, NavigationWindow yada NavigationService' in kendisi tarafndan
ele alnabilir. Daha ok tercih edilen, sz konusu olaylar Application nesnesi seviyesinde ele
almaktr. Bylece uygulama ierisinde yer alabilecek tm sayfalar iin ortak bir noktada olaylarn
kontrol edilebilmesi salanm olur. Burada bahsedilen olaylar Navigating, Navigated,
NavigationProgress, LoadCompleted, FragmentNavigation,
NavigationStopped ve NavigationFailed' dr. Bu olaylarn ileyi sras aadaki ekildeki
gibidir.

www.bsenyurt.com Page 805


lk olarak sre bir sayfann talep edilmesi ile balar. Sonrasnda ise ilgili olaylar tetiklenir.
Aadaki tabloda sz konusu olaylar ile ilikili bilgiler verilmektedir.

Olay(Event) Olay Hakknda Ksa Bilgi

Navigating Yeni bir navigasyon talebi geldiinde alan olaydr.

Navigasyon balamtr ve talep edilen sayfa ile ilgili bilgiler gelmektedir.


Navigated
Ancak sayfann tamam henz gelmemitir.

Bu olaya ilikin metod yazldnda, sayfann yklenmesi tamamlanncaya


kadar bilgilendirme yaplmas salanabilir. rnein sayfann yzde olarak
NavigationProgres kann tamamland bilgisi gsterilebilir. Aslnda bu olay klasik windows
s programlamadaki BackgroundWorker kontrolnn ProgressChange olay
nnkine benzer bir grev stlenmektedir. NavigationProgress olay, talep
edilen sayfa ile ilgili her 1Kb bilgi geldiinde tetiklenmektedir.

Talep edilen sayfann ayrtrma(Parse) ilemi tamamlanmtr. Ancak ilgili


LoadCompleted
sayfann Initialized ve Loaded olaylar henz almamtr.

FragmentNavigati Eer paral navigasyon(Fragment Navigation) sz konusu ise bu olay


on tetiklenir. Bu olay ilgili kontrole doru gidilirken almaktadr.

NavigationService snfnn static StopLoading metoduna yaplan ar


sonucu tetiklenen olaydr. Baz durumlarda uzun sren navigasyon
NavigationStoppe
ilemlerinde(rnein bir web sayfas talebinde) kullanc tarafndan ilemin
d
durdurulmas istenebilir. Byle bir durumda StopLoading metoduna
bavurulmas halinde bu olay tetiklenmektedir. (StopLoading' i alma

www.bsenyurt.com Page 806


zamannda armak son derece kolaydr. Nitekim WPF mimarisinde
navigasyon ilemleri asenkron olarak yrtlmektedir.)

Navigasyon ilemi srasnda bir hata oluursa tetiklenen olaydr. Bu olay


ierisinde oluan hata ile ilikili detayl bilgiye ulalabilir ve sz konusu
NavigationFailed
bilgiler rnein loglama amac ile kayt altna alnabilir yada kullanc farkl bir
ekilde ynlendirilerek uygulamann salkl bir ekilde almas salanabilir.

Doal olarak bu olaylarn tetiklenmesi belirli koullara baldr. Sz gelimi bir sayfaya doru
navigasyon ileminin balatlabilmesi iin Hyperlink kontrolnn NavigateUrizelliinden
yada NavigationService snfnn Navigate metodundan yararlanlr. Navigate metodunun ar
yklenmi olan versiyonlar kullanlarak yukarda bahsi geen olaylara veri aktarmda sz konusu
olabilmektedir. Sz gelimi navigasyonun balad srenin gnderilip ilgili olaylarda gncel sre ile
arasndaki fark hesap edilerek ilemlerin ne kadar srd ortalama olarak tespit edilebililir. Yada
navigasyon ileminin balatld sayfann ierisinde bulunduu NavigationWindow referansnn
gnderilmesi salanarak, Application seviyesindeki olaylarda ele alnmas salanabilir.

Burada manuel olarak navigasyon ilemleri adna ismini ska


duyduumuz NavigationService snfnn baka gl metodlarda vardr. Sz gelimi navigasyon
srecinde yer alan sayfalar arasnda ileri veya geri doru gidilebilmesini salamak
amacyla GoBack ve GoForward metodlarndan yararlanlabilir. Yanlz bu metodlar yardmyla
hareket edilirken herhangibir sebeple hedef sayfa bulunamassa alma
zamannda InvalidOperationException alnr. Bunun nne gemek
iinse CanGoBack ve CanGoForward zelliklerinin deerlerine baklabilir. Bu konu ile ilikili bir
rnei denemenizi iddetle tavsiye ederim. (Yazmz ok fazla uzatacandan bu tarz bir rnei u
an iin gelitirmeyeceiz. Bu konuyu baka bir makalede detayl bir ekilde incelemeye alcaz.)

XBAP Hakknda

Gelelim sayfalar ile ilgili bir dier konuya. Yazmzn banda sayfa bazl(Page-
Based) uygulamalarn gelitirilmesinde kullanlan modellerden bahsederken XBAP(Xaml Browser
Applications) tekniinede deinmitik. XBAP uygulamalarnda sayfalar tarayc
pencerede(browser) gsterilmektedir. u an iin Internet Exploere 6.0 ve st ile Mozilla Firefox'
un son srmnde XBAP uygulamalar altrlabilmektedir. (En azndan makaleyi yazdm
sralarda bu tarayclar ile yaplan testlere gre...)

Varsaylan olarak XBAP uygulamalarnda baz kstlamalar(Restrictions) vardr. Bunlar tahmin


edilecei gibi Code Access Security kurallarnn uygulanmasnnda bir sonucudur. rnein XBAP
uygulamalarnda istemci tarafl olaraktan dosyalara yazmak, veritabanlarna balanmak, registry
ilemleri yapmak yada baka pencereleri tarayc penceresi ierisinde popup ekline amak
varsaylan olarak yasaklanmtr. Bu tarz ihtiyalarn olmas durumunda WPF uygulamasn normal
bir windows uygulamas olarak yazmak ve ClickOnce gibi bir datm modeli ile yaymak daha
doru bir yaklamdr. Yinede kstlama(Restriction) ayarlar ile proje zellikleri zerinden
oynanarak istenirse sz konusu ilemlerin yaplmas salanabilir.

XBAP uygulamalar varsaylan olarak istemci bilgisayardaki tarayc penceresine ait


tampona(Cache) atlrlar. Bir baka deyile ilk talep edildiklerinde istemci bilgisayara
indirilirler(Download). Burada bir ykleme(install) ilemi sz konusu deildir. Fakat yine proje
ayalar ile oynayaraktan uygulamann istemciye install edilmesi salanabilir. Dier taraftan install
edilmemesinin avantajlar vardr. yleki, uygulamadaki deiiklikler istemci tarafndan otomatik
olarak alglanp son srmn herhangibir sorgu penceresine gerek kalmadan indirilmesi ve
altrlmas sz konusudur.

ok doal olarak XBAP uygulamalarnn alabilmesi iin indirildikleri bilgisayar sisteminde


Microsoft .Net Framework 3.0 srmnn ykl olmas gerekmektedir. Eer ykl deilse ilgili
uygulama altrldnda .Net Framework 3.0 indirilmeye allacaktr.

www.bsenyurt.com Page 807


Visual Studio 2008 Beta 2 ile bir XBAP uygulamas oluturmak son derece basittir. Tek
yaplmas gereken proje ablonlarndan aadaki resimde grld gibi WPF Browser
Application esini semektir.

Bu ilemin sonucunda ierisinde varsaylan olarak bir sayfa(Page) ieren bir uygulama oluturulur.
Test olmas amacyla uygulamaya ikinci bir sayfa(Page) daha ekleyip bu sayfalar
arasndaHyperlink ile geiler yapmaya altmz dnelim. Bu amala Page1.xaml ve
Page2.xaml ieriklerinin aadaki gibi olduunu dnelim.

Page1.xaml;

<Page x:Class="MerhabaXBAP.Page1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Ana Sayfa"
WindowTitle="Giri Sayfas" Background="LightGray" WindowHeight="250"
WindowWidth="250" VerticalAlignment="Top" HorizontalAlignment="Left">
<Grid>
<Label Height="33" HorizontalAlignment="Left" Name="label1" VerticalAlignment="Top"
Width="120" FontSize="14" FontWeight="Bold">
<Hyperlink NavigateUri="Page2.xaml">Sayfa 2</Hyperlink>
</Label>
</Grid>
</Page>

Page2.xaml;

<Page x:Class="MerhabaXBAP.Page2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="kinci Sayfa"
WindowTitle="Sayfa 2" Background="Gold" Loaded="Page_Loaded" VerticalAlignment="Top"
HorizontalAlignment="Left" WindowHeight="250" WindowWidth="250">
<Grid>
<Label Height="35" Name="label1" VerticalAlignment="Top" FontSize="14"
FontWeight="Bold" HorizontalAlignment="Left" Width="120">
<Hyperlink NavigateUri="Page1.xaml">Sayfa 1</Hyperlink>
</Label>
</Grid>
</Page>

www.bsenyurt.com Page 808


Uygulamay altrdmzda yada derleme sonucu ortaya kan XBAP uzantl dosyay
rnein Internet Explorer 7.0 zerinde atmzda aadaki Flash grselinde yer alan sonular
elde ederiz.

Dikkat edilecei zere sayfalarn WindowTitle niteliklerine atanan deerler otomatik


olarak Tab' da ve tarayc penceresinin balk ksmnda grlmektedir. Dier taraftan burada
navigasyon kontrolleri oluturulmam otomatik olarak taraycnn navigasyon kontrolleri iin
ierisine dahil edilmitir. imdi gvenlik ile ilikili kstlamalar test etmek amacyla Page2.xaml
sayfasnn Loaded olayn ykleyelim ve ierisine aadaki kodlar yazdmz dnelim.

Page2.xaml.cs;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;

namespace MerhabaXBAP
{
public partial class Page2 : Page
{
public Page2()
{
InitializeComponent();
}

private void Page_Loaded(object sender, RoutedEventArgs e)


{
using (FileStream stream = new FileStream("C:\\Test.txt", FileMode.Append,
FileAccess.Write))
{

www.bsenyurt.com Page 809


using (StreamWriter writer = new StreamWriter(stream))
{
writer.WriteLine(DateTime.Now.ToString() + " ek bilgi");
}
}
}
}
}

Bu durumda uygulamay altrp Page2 isimli sayfaya gemeye


altmzda SecurityException tipinden bir istisna aldmz grrz. Aadaki ekran
grntsnde bu durum ifade edilmektedir.

Daha ncedende belirttiimiz gibi bu istisnann sebebi varsaylan Code Access Security ayarlardr.
Hata mesajndanda grlecei gibi FileIOPermission yetkisi olmadndan sz konusu kodlar
almayp istisna vermitir. Ancak proje zelliklerine girip ilgili izni(Permission) aadaki ekilde
grld gibi vererek dosyaya yazma ileminin gerekletirilebilmesi salanabilir.

www.bsenyurt.com Page 810


Bu ayarlardan sonra uygulama tekrardan test edilirse Test.txt isimli dosyann C dizini altnda
oluturulduu ve ierisine bilgi yazld grlr. Buradaki seeneklerden bir dieri olan This is a
full trust application seilerek, istenirse tm kstlamalarn ortadan kaldrlmas ve istemci
tarafndan yrtlebilmesi salanabilir. Ancak bu XBAP uygulamalarnn birincil amac deildir.

Bir XBAP uygulamasn datrken(Deploye) uygulamaya


ait exe, manifesto ve xbap dosyalarnn nn birden istemci uygulamaya kopyalanmas yeterli
bir seenektir. Elbette sz konusu dosyalar bir intranet sisteminde ortak bir yola(Path)
konularaktanda istemcilerin buradan balatma ilemini gerekletirmesi salanabilir. Sonuta
varsaylan olarak uygulama, istemci bilgisayarn tarayc programnn kullandn n bellek alanna
indirilecektir. Yukarda gelitirimi olduumuz XBAP rneine baktmzda Debugklasr altnda
aadaki ekilde grlen dosyalarn oluturulduunu grrz.

Burada yer alan dosyalardan exe uzantl olan, XBAP uygulamasnn derlenmi halini iermektedir.
Bir baka deyile assembly' n kendisidir e ILDASM, Metadata, manifesto gibi bilgileri iermektedir.
Ne varki sz konusu exe tek bana altrlabilen bir dosya deildir. Bu sebepten zerinde ift
tklandnda hi bir etkileim olmayacaktr. Asl altrc dosya XBAP uzantl olan XML dosyasdr.
Bu dosyann ieriinde, uygulamann giri noktasn iaret eden bilgi vardr. Akas bu dosya
altrldnda istemci bilgisayardaki varsaylan tarayc uygulamas devreye girecek ve exe
yrtlmeye balanacaktr. XBAP uzantl dosyas ierisinde ayn zamanda program yazlrken
retilen dijital imzada yer almaktadr. Bu imza zellikle gncelleme ilemlerinde nem

www.bsenyurt.com Page 811


kazanmaktadr. (Elbette istenirse uygulamann proje zelliklerine gidilip Signing ksmnda baka bir
imza retilip kullanlabilir.) Manifesto dosyasnda ise, uygulamann almas iin gerekli olan dier
programlara ait bilgiler yer almaktadr. Sz gelimi uygulamann almas iin gerekli .Net
Framework versiyonu, bal olan dier assmebly(Class Library gibi)' lar veya uygulamadaki
kodlarn neler yapabileceini belirten izin(Permission) yetkileri gibi bilgiler yer almaktadr. Ne
varki datm ilemi zellikle ilgili uygulamalarda gncellemeler yapld takdirde tekrarlanmak
zorunda olabilir. Bu vakkaClickOnce ile ilgilide olduundan ve makalemizin konusunu atndan
bu yaz dizimizde ele alnmayacaktr. Umuyorumki ilerleyen zamanlarda ele alabiliriz.

Bu makalemizde WPF(Windows Presentation Foundation) ile birlikte hayatmza giren yeni


kavramlardan birisi olan sayfa-tabanl(Page-based) uygulamalar tanmaya altk. Konunun
detaylar iin sizlere 1000 sayfalk Pro WPF: Windows Presentation Foundation in .NET
3.0 kitab tavsiye ederim.

Bylece geldik uzun bir makalemizin daha sonuna. Bu cmleye kadar sabrla okuduunu iin son
teekkr ederim. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WPF - Temel Animasyon lemleri - 2 (


01.10.2007 ) - WPF
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde Windows Prensetation Foundation(WPF) uygulamalarnda animasyon


ilemlerinin temel animasyon tipleri(Basic Animation Types) yardmyla nasl
gerekletirilebileceini incelemeye balamtk. Bu makalemizde animasyon ilemleri zerindeki
ynetimin biraz daha fazla olmasn salamak iin farkl teknikleri gz nne alyor olacaz. Her
zaman olduu gibi konuyu daha iyi kavrayabilmek adna rnekler zerinden ilerlemekte fayda
olduu kansndaym. Dilerseniz hi vakit kaybetmeden ilk rneimiz ile baalaym. Hatrlanaca
zere, WPF uygulamalarnda bileenlerin rotasyon ilemleri
iin RotateTransform, ScaleTransform ve benzeri tiplerin kullanldn grmtk. Bu tip
transformasyon ilemlerini animasyon tipleri ile birlikte kullanmak isteyebiliriz. Sz gelimi bir
Button kontrolnn 3 saniye ierisinde kendi ekseninde 360 derece dnmesini ve bu srada
boyutlarnnda 2 katna karak tekrardan eski haline dnmesini istediimizi dnelim. Bu tip bir
animasyon ileminin Buttton kontrolnn zerine mouse ile gelindiinde balatlmasn ve 3
saniyelik zaman dilimi ierisinde mouse ile kontroln terk edilmesi halinde de durmasnda
salayabiliriz. Burada temel animasyon tiplerinden olan DoubleAnimation olduka ie
yarayacaktr. Hereyden nce animasyon tipinin RotateTransform ve ScaleTransform tiplerindeki
uygun zellikleri kontrol edecek ekilde ayarlanmas gerekir. Bu senaryoyu gerekletirmek
iin XAML ierii aada verilen bir pencere(Window) oluturulmas yeterli olacaktr.

www.bsenyurt.com Page 812


XAML ierii;

<Window x:Class="AnimasyonIslemleri.RotateAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Rotate ve Sacle Animasyon"
Height="220" Width="289">
<Grid>
<Button Name="btnMerhaba" Width="75" Height="40" Content="Merhaba"
Background="Gold" Foreground="Black" FontSize="14" FontWeight="Bold">
<Button.LayoutTransform>
<TransformGroup>
<RotateTransform x:Name="RTrans" Angle="0"/>
<ScaleTransform x:Name="STrans" CenterX="0" CenterY="0" ScaleX="1"
ScaleY="1"/>
</TransformGroup>
</Button.LayoutTransform>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard Name="strBrd">
<Storyboard>
<DoubleAnimation Storyboard.TargetName="RTrans"
Storyboard.TargetProperty="Angle" To="360" Duration="0:0:3"/>
<DoubleAnimation Storyboard.TargetName="STrans"
Storyboard.TargetProperty="ScaleX" To="2.5" Duration="0:0:1.5"/>
<DoubleAnimation Storyboard.TargetName="STrans"
Storyboard.TargetProperty="ScaleY" To="2.5" Duration="0:0:1.5"/>
<DoubleAnimation Storyboard.TargetName="STrans"
Storyboard.TargetProperty="ScaleX" To="1" Duration="0:0:3"/>
<DoubleAnimation Storyboard.TargetName="STrans"
Storyboard.TargetProperty="ScaleY" To="1" Duration="0:0:3"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
<EventTrigger RoutedEvent="Button.MouseLeave">
<EventTrigger.Actions>
<StopStoryboard BeginStoryboardName="strBrd"/>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>

www.bsenyurt.com Page 813


</Button>
</Grid>
</Window>

Burada dikkat edilmesi gereken noktalardan


birisi, RotateTransform ve ScaleTransform elementlerinin DoubleAnimation tiplerinde
kullanlabilmesi iin x:Name nitelikleri ile isimlendirilmi olmalardr. Dier
taraftan RotateTransform, Button bileenin verilen a kadar dndrlmesini salamaktadr. Buna
gre ilk DoubleAnimation elementi 3 saniyelik zaman izgisi(TimeLine) ierisinde ann
deerinin 360 derece olmasn salamaktadr. Sonrasnda gelen drt DoubleAnimation tipi ise ilk
1.5 saniyelik zaman dilimi ierisindeScaleTransform elementinin ScaleX ve ScaleY deerlerini
nce iki buuk katna karmakta sonrasnda ise tekrar eski haline dndrmektedir. Sz konusu
animasyon ilemleriMouseEnter olay tetiklendiinde balatlmaktadr. Dier
taraftan MouseLeave olay tetiklendiinde, bir baka deyile mouse ile Button kontrol zerinden
kldnda animasyon ilemi durdurulmaktadr. Durdurma ilemi iin StopStroyboard elementi
kullanlr. Bu elementin hangi animasyon ilemini durduracan belirtmek
iinBeginStroyboardName niteliine(attribute) ilgili deerin atanmas gerekir. rneimizde bu
deer, BeginStroyboard elementindeki Name niteliinin deeri olan strBrd' dir. Buna gre
istersek birden fazla Storyboard' un olduu bir senaryoda Name niteliinden yararlanarak
hangisinin durdurulacan, duraksatlacan(Pause) yada kartlacan(Remove) belirleyebiliriz.

WPF(Windows Presentation Foundation) mimarisinde farkl Storyboard tipleri vardr.

BeginStoryboard : Storyboard' un balatlmasn salar.


PauseStoryboard : Storyboard duraksatlr.
ResumeStoryboard : Duraksatlan storyboard kald yerden devam eder.
RemoveStoryboard : Storyboard kaldrlr.
SetStoryboardSpeedRatio : Storyboard ierisinde animasyonlarn hz oran
deitirilebilir.
SkipStoryboardToFill : Eer Stroyboard ierisinde tanmlanm bir Fill periyodu
varsa animasyonun otomatik olarak buraya atlamas salanr.

rnei yrttmzde alma zamannda(Run-time) aadaki Flash grselinde yer alan etkileri
izleyebiliriz. (Flash dosyasnn boyutu 264 Kb olduundan yklenmesi zaman alabilir.
Dosyann boyutunun kk olmas iin kalitesi drlmtr. Bu nedenle kitap animasyon hareketi
srasnda iz brakmaktadr. Gerek uygulamada elbetteki byle bir iz yoktur.)

Benzer ilemleri kod tarafnda yapmakta olduka kolaydr. Bunun iin aadaki kodlara ve XAML
ieriine sahip pencereyi ele alabiliriz.

www.bsenyurt.com Page 814


XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaRotateAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Kodla Rotate Animasyon"
Height="250" Width="325">
<Grid>
<Button Name="btnMerhaba" Width="75" Height="40" Content="Merhaba"
Background="Black" Foreground="Gold" FontSize="14" FontWeight="Bold">
<Button.LayoutTransform>
<TransformGroup>
<RotateTransform x:Name="RTrans" Angle="0"/>
<ScaleTransform x:Name="STrans" CenterX="0"
CenterY="0" ScaleX="1" ScaleY="1"/>
</TransformGroup>
</Button.LayoutTransform>
</Button>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation; // Animasyon tiplerinin yer ald isim
alandr(Namespace)

namespace AnimasyonIslemleri
{
public partial class KodlaRotateAnimasyon : Window
{
private void AnimasyonuOlustur()
{
// Storyboard oluturulur
Storyboard strBrd = new Storyboard();

// Birinci DoubleAnimation tipi oluturulur.


// lk parametre To deeridir ve burada 360 dereceyi iaret etmektedir. kinci parametre
ise Duration deeridir.
DoubleAnimation dblAni1 = new DoubleAnimation(360, new
Duration(TimeSpan.FromSeconds(3)));
// Animasyon tipinin RTrans adna sahip elementin AngleProperty zelliine uygulanaca
belirtilir.
Storyboard.SetTargetName(dblAni1, "RTrans");
Storyboard.SetTargetProperty(dblAni1, new
PropertyPath(RotateTransform.AngleProperty));

www.bsenyurt.com Page 815


// Animasyon tipi Storyboard' a eklenir.
strBrd.Children.Add(dblAni1);

// kinci DoubleAnimation tipi oluturulur.


// lk parametre To deeridir ve burada 2.5 katn iaret etmektedir. kinci parametre ise
Duration deeridir. Buna gre zaman izgisinin ilk 1.5 saniyesi ierisinde Button bileeninin ScaleX
deeri 2.5 kat artmaktadr.
DoubleAnimation dblAni2 = new DoubleAnimation(2.5, new
Duration(TimeSpan.FromSeconds(1.5)));
// Animayonun STrans isimli ScaleTransform elementi ierisindeki ScaleX zelliine
uygulanaca belirtilir.
Storyboard.SetTargetName(dblAni2, "STrans");
Storyboard.SetTargetProperty(dblAni2, new
PropertyPath(ScaleTransform.ScaleXProperty));
// Animasyon tipi Storyboard' a eklenir.
strBrd.Children.Add(dblAni2);

// nc DoubleAnimation tipi oluturulur.


// lk parametre To deeridir ve burada 2.5 katn iaret etmektedir. kinci parametre ise
Duration deeridir. Buna gre zaman izgisinin ilk 1.5 saniyesi ierisinde Button bileeninin ScaleY
deeri 2.5 kat artmaktadr.
DoubleAnimation dblAni3 = new DoubleAnimation(2.5, new
Duration(TimeSpan.FromSeconds(1.5)));
// Animayonun STrans isimli ScaleTransform elementi ierisindeki ScaleY zelliine
uygulanaca belirtilir.
Storyboard.SetTargetName(dblAni3, "STrans");
Storyboard.SetTargetProperty(dblAni3, new
PropertyPath(ScaleTransform.ScaleYProperty));
// Animasyon tipi Storyboard' a eklenir.
strBrd.Children.Add(dblAni3);

// Zaman izgisinin 3nc saniyesine gelindiinde Button kontrolnn ScaleX deeri ilk
haline dner.
DoubleAnimation dblAni4 = new DoubleAnimation(1, new
Duration(TimeSpan.FromSeconds(3)));
Storyboard.SetTargetName(dblAni4, "STrans");
Storyboard.SetTargetProperty(dblAni4, new
PropertyPath(ScaleTransform.ScaleXProperty));
// Animasyon tipi Storyboard' a eklenir.
strBrd.Children.Add(dblAni4);

// Zaman izgisinin 3nc saniyesine gelindiinde Button kontrolnn ScaleY deeri ilk
haline dner.
DoubleAnimation dblAni5 = new DoubleAnimation(1, new
Duration(TimeSpan.FromSeconds(3)));
Storyboard.SetTargetName(dblAni5, "STrans");
Storyboard.SetTargetProperty(dblAni5, new
PropertyPath(ScaleTransform.ScaleYProperty));
// Animasyon tipi Storyboard' a eklenir.
strBrd.Children.Add(dblAni5);

// Mouse ile Button alan zerinde gelindiinde animasyon balatlr.


btnMerhaba.MouseEnter += delegate(object sender, MouseEventArgs e)
{
/* kinci parametre Storyboard' un kontrol edilebileceini
gsterir. Bir baka deyile programatik olarak animasyonun durdurulmas, duraksatlmas ve

www.bsenyurt.com Page 816


benzeri ilemlerin yaplabilmesi salanr. */
strBrd.Begin(this,true);
};

btnMerhaba.MouseLeave += delegate(object sender, MouseEventArgs e)


{
// Storyboard' un balatt animasyon kartlr. Dolaysyla
Button asal konum ve byklk olarak ilk deerlerine dner.
strBrd.Stop(this);
};
}

public KodlaRotateAnimasyon()
{
InitializeComponent();
AnimasyonuOlustur();
}
}
}

Kod yapsnda dikkat edilmesi gereken nemli noktalardan birisi, MouseLeave olaynn
gereklemesi halinde var olan amimasyonun durdurulmas(Stop) ileminin Storyboard nesne
rneine ait Stop metodu ile gerekletirimi olmasdr. Lakin burada Stop metodunun ie
yarayabilmesi iin animasyon Begin metodu ile balatlrken ikinci parametrenin true olarak
verilmesi arttr. Bu parametrenin true olarak verilmesi halinde yanlzca Stop metodu
deil, Pause, Resume, Remove gibi ynetsel fonksiyonelliklerinde kullanlabilir hale gelmesi
salanmaktadr.

Animasyon ilemlerinde zaman izgileri (Timeline) ierisinde yer alan KeyFrame' lerin ynetilmesi
ve bu sayede daha gl hareketlerin salanabilmeside mmkndr. Bu amala WPF yaps
ierisine 3 temel KeyFrame tipi konulmutur.
Bunlar LinearDoubleKeyFrame, DiscreteDoubleKeyFrame, SplineDoubleKeyFrame tipleridir.
Sz konusu tiplerin ne ekilde kullanldklarn rnekler ile incelediimizde konuyu daha rahat
kavrayabiliriz. Sradaki rneimizde LinearDoubleKeyFrame tipini kullanyor olacaz. Bu amala ilk
olarak aadaki XAML ktsn ieren bir pencere (Window) hazrladmz dnelim.

XAML ierii;

www.bsenyurt.com Page 817


<Window x:Class="AnimasyonIslemleri.MerhabaKeyFrameAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Merhaba Key Frame Animasyon"
Height="300" Width="300">
<Canvas>
<Rectangle Name="Dortgen" Canvas.Top="0" Canvas.Left ="100" Height="125"
Width="93">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever" AutoReverse="True">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="Dortg
en" Storyboard.TargetProperty="(Canvas.Top)">
<LinearDoubleKeyFrame Value="160" KeyTime="0:0:2"/>
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:4"/>
<LinearDoubleKeyFrame Value="100" KeyTime="0:0:6"/>
<LinearDoubleKeyFrame Value="40" KeyTime="0:0:8"/>
<LinearDoubleKeyFrame Value="80" KeyTime="0:0:10"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
</Window>

Dikkat edilecei zere rnekte


kullanlan LienarDoubleKeyFrame elementleri DoubleAnimationUsingKeyFrames elementi
ierisinde yer almaktadr. Buna gre KeyFrame tiplerininTipAdUsingKeyFrames notasyonu ile
tanmlanm tipler ierisinde olmas gerektii ortadadr. Peki burada yer alan
LinearDoubleKeyFrame elementleri ne ie yaramaktadr?

Value zellii ile tahmin edilecei gibi DoubleAnimationUsingKeyFrames elementinde belirtilen


kontrol ve ilgili zelliin yeni deeri belirlenir. KeyTime nitelii ilede, zelliin zaman izelgesi
ierisinde belirtilen anda deerini almas salanr. Bir baka deyile rnekte kullanlan Dortgen
isimli Rectangle elementinin pencerenin(Window) st ksmndan olan uzakl, zaman
izelgesi(timeline) ierisinde Frame noktalarnda farkl deerlere set edilmektedir. Aslnda durumu
daha iyi kavramak iin pencerenin alma zamanndaki ktsna bakmakta fayda vardr. Aadaki
Flash animasyonunda bu durum iaret edilmektedir.(Flash dosyasnn boyutu 322 Kb
olduundan yklenmesi zaman alabilir.Dosyann boyutunun kk olmas iin kalitesi
drlmtr. Bu nedenle kitap animasyon hareketi srasnda iz brakmaktadr. Gerek
uygulamada elbetteki byle bir iz yoktur.)

www.bsenyurt.com Page 818


Grld gibi drtgenimiz zaman izelgesinin 2nci saniyesinde pencerenin st kenarnn 160
piksel, 4nc saniyesinde tekrardan 0 piksel, 6nc saniyesinde 100 piksel, 8nci saniyesinde 40
piksel, 10ncu saniyesinde ise 80 piksel uzana gelmektedir. Sonrasnda ise bu animasyon
hareketini tersine doru yapmaktadr. Bunun
iin Storyboard elementininAutoReverse zelliine true deerinin atanmas yeterli olmaktadr.
Durumu aadaki ekil ile daha net bir ekilde anlayabiliriz.

Ayn rnei kod yardmylada gerekletirebiliriz. Bunun iin aadaki XAML ieriine ve kodlarna
sahip bir pencere(Window) gelitirmemiz yeterli olacaktr.

www.bsenyurt.com Page 819


XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaMerhabaKeyFrameAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Kodla Merhaba KeyFrame
Animasyon" Height="241" Width="218">
<Canvas x:Name="Bolge">
<Rectangle Name="Dortgen" Canvas.Top="0" Canvas.Left="65" Height="65"
Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
</Rectangle>
</Canvas>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace AnimasyonIslemleri
{
public partial class KodlaMerhabaKeyFrameAnimasyon : Window
{
private void AnimasyonuHazirla()
{
// DoubleAnimationKeyFrames nesnesi rneklenir.
DoubleAnimationUsingKeyFrames dblKeyFrames = new
DoubleAnimationUsingKeyFrames();
// Animasyon tipi, kontrol ve zelliini ilikilendirecek olan StoryBoard oluturulur.
Storyboard strBrd = new Storyboard();
// Animasyon sona erdiinde ayn rotadan geriye doru dnmesi iin AutoReverse
zelliine true deeri atanr
strBrd.AutoReverse = true;
// Animasyonun srekli olmas iin RepeatBehavior zelliine Forever deeri atanr.
strBrd.RepeatBehavior = RepeatBehavior.Forever;
// Hedef kontrol olarak Rectangle tipinden olan Dortgen seilir
Storyboard.SetTargetName(dblKeyFrames, "Dortgen");
// Animasyon deerlerinin uygulanaca zellikl olarak Canvas' n Top zellii seilir.
Storyboard.SetTargetProperty(dblKeyFrames, new
PropertyPath(Canvas.TopProperty));
// KeyFrame deerleri belirlenir.
// lk 1 saniyede Canvas dikeylemesine 120 pikselinci uzakla gelecektir
dblKeyFrames.KeyFrames.Add(new LinearDoubleKeyFrame(120,

www.bsenyurt.com Page 820


KeyTime.FromTimeSpan(new TimeSpan(0, 0, 1))));
// 2nci saniyede Canvas dikeylemesine 0 pikselinci uzakla gelecektir
dblKeyFrames.KeyFrames.Add(new LinearDoubleKeyFrame(0,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 2))));
// 3nc saniyede Canvas dikeylemesine 100 pikselinci uzakla gelecektir
dblKeyFrames.KeyFrames.Add(new LinearDoubleKeyFrame(100,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 3))));
// 4nc saniyede Canvas dikeylemesine 50 pikselinci uzakla gelecektir
dblKeyFrames.KeyFrames.Add(new LinearDoubleKeyFrame(50,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 4))));
// 5nci saniyede Canvas dikeylemesine 75 pikselinci uzakla gelecektir.
dblKeyFrames.KeyFrames.Add(new LinearDoubleKeyFrame(75,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 5))));
// 6nci saniyede Canvas dikeylemesine 25 pikselinci uzakla gelecektir.
dblKeyFrames.KeyFrames.Add(new LinearDoubleKeyFrame(25,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 6))));
// Animasyon tipi StoryBoard nesnesine eklenir
strBrd.Children.Add(dblKeyFrames);
// Animasyonun, Mouse ile Dortgen in zerine gelindiinde balamas salanr.
Dortgen.MouseEnter += delegate(object sender, MouseEventArgs e)
{
strBrd.Begin(this);
};
}
public KodlaMerhabaKeyFrameAnimasyon()
{
InitializeComponent();
AnimasyonuHazirla();
}
}
}

Kod tarafnda dikkat edilmesi gereken noktalardan birisi LinearDoubleKeyFrame nesne


rneklerinin DoubleAnimationUsingKeyFrames tipinin KeyFrames koleksiyonunda tutuluyor
olmasdr.KeyFrames zellii zerinden arlan Add metodu ile ilgili nesnelerin koleksiyona
eklenmesi salanr. Olduka elenceli deil mi? Gelin LinearDoubleKeyKeyFrame nesnelerinin
kullanld baka bir rnek ile devam edelim. Bu yeni rnekte bir ncekinden farkl olarak Canvas'
n Top ve Left zelliklerini rastegele oranlarda deitiriyor olacaz. te rnek XAML ierii ve
kodlarmz.

XAML ierii;

www.bsenyurt.com Page 821


<Window x:Class="AnimasyonIslemleri.KodlaKeyFrameAnimasyon2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="KodlaKeyFrameAnimasyon2"
Height="400" Width="400" Background="LightBlue">
<Canvas x:Name="alan">
<Rectangle Name="dortgenim" Canvas.Top="0" Canvas.Left="0" Height="65"
Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
</Rectangle>
</Canvas>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace AnimasyonIslemleri
{
public partial class KodlaKeyFrameAnimasyon2 : Window
{
Random rnd = new Random();
Storyboard strBrd = new Storyboard();

public void AnimasyonuYurut()


{
double randomT = rnd.Next(1, 250);
double randomL = rnd.Next(1, 250);
Title=String.Format("lk nokta {0}:{1} kinci Nokta
{2}:{3}",randomT.ToString(),randomL.ToString(),(randomT - 25).ToString(),(randomL -
25).ToString());

strBrd.AutoReverse = false;
strBrd.RepeatBehavior = new RepeatBehavior(1);

DoubleAnimationUsingKeyFrames keyFrm1 = new


DoubleAnimationUsingKeyFrames();
keyFrm1.KeyFrames.Add(new LinearDoubleKeyFrame(randomT,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 3))));
keyFrm1.KeyFrames.Add(new LinearDoubleKeyFrame(randomT-25,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 5))));

Storyboard.SetTargetName(keyFrm1, "dortgenim");
Storyboard.SetTargetProperty(keyFrm1, new

www.bsenyurt.com Page 822


PropertyPath(Canvas.TopProperty));
strBrd.Children.Add(keyFrm1);

DoubleAnimationUsingKeyFrames keyFrm2 = new


DoubleAnimationUsingKeyFrames();
keyFrm2.KeyFrames.Add(new LinearDoubleKeyFrame(randomL,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 3))));
keyFrm2.KeyFrames.Add(new LinearDoubleKeyFrame(randomL-25,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 5))));

Storyboard.SetTargetName(keyFrm2, "dortgenim");
Storyboard.SetTargetProperty(keyFrm2, new
PropertyPath(Canvas.LeftProperty));
strBrd.Children.Add(keyFrm2);

strBrd.Begin(this);
}

void dortgenim_MouseEnter(object sender, MouseEventArgs e)


{
AnimasyonuYurut();
}

public KodlaKeyFrameAnimasyon2()
{
InitializeComponent();
dortgenim.MouseEnter += new MouseEventHandler(dortgenim_MouseEnter);
}
}
}

Tahmin edilecei zere dortgenin Top ve Left zelliklerini animayon ierisinde kullanmak
istediimizden iki farkl DoubleAnimationUsingKeyFrames nesne rnei kullanlmas
gerekmektedir. Bu nesne rnekleride kendi ilerinde farkl LinearDoubleKeyFrame nesnelerine
sahiptir. rnein alma zamanndaki(run-time) kts aadaki Flash grselindeki gibi
olacaktr. (Flash dosyasnn boyutu 454 Kb olduundan yklenmesi zaman
alabilir. Dosyann boyutunun kk olmas iin kalitesi drlmtr. Bu nedenle kitap
animasyon hareketi srasnda iz brakmaktadr. Gerek uygulamada elbetteki byle bir iz yoktur.)

www.bsenyurt.com Page 823


LinearDoubleKeyFrame tipi sz konusu deerlere ulalrken akc bir grselliin olmasn salar.
Bunun dnda DiscreteDoubleKeyFrame tipi kullanlaraktan nesnenin belirtilen animasyonda bir
sonraki deerine srayarak gemesi salanabilir. Aslnda bu durumu anlamann en iyi yolu rnek
bir senaryo zerinde ilerlemektir. Bu amala aadakiXAML ktsna sahip
bir pencere(Window) tasarladmz dnelim.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.DiscreteKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="DiscreteDoubleKeyFrame ile
Animasyon" Height="400" Width="400">
<Canvas>
<Rectangle Name="Dortgen" Canvas.Top="0" Canvas.Left="0" Height="75" Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
<Rectangle.Triggers>

www.bsenyurt.com Page 824


<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard AutoReverse="True" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="Dortgen" Storyboard.TargetProperty="(Canvas.Top)">
<DiscreteDoubleKeyFrame KeyTime="0:0:1" Value="150"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:2" Value="30"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:3" Value="120"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:4" Value="60"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:5" Value="90"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:6" Value="75"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="Dortgen" Storyboard.TargetProperty="(Canvas.Left)">
<DiscreteDoubleKeyFrame KeyTime="0:0:1.5" Value="150"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:2.5" Value="30"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:3.5" Value="120"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:4.5" Value="60"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:5.5" Value="90"/>
<DiscreteDoubleKeyFrame KeyTime="0:0:6.5" Value="75"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
</Window>

rnekte iki adet DoubleAnimationUsingKeyFrames elementi kullanlmtr. Bunlardan


birisi Canvas tipinin Top zellii zerinde dieri ise Left zellii zerinden animasyon ilemlerinin
yrtlmesini olanakl klmaktadr. Her biri kendi ierisinde birden
fazla DiscreteDoubleKeyFrame tipi iermektedir. DiscreteDoubleKeyFrame
elementleri KeyTimeniteliinde belirtilen anda, animasyon uygulanan kontroln ilgili
zelliinin value nitelii ile belirtilen deerde olmasn salamaktadr. Sz gelimi animasyondaki
zaman izelgesinin 2nci saniyesinde Top deeri 30 piksel, 1.5nci saniyesinde Left deeri 150
piksel olacak ekilde belirlenmektedir. Daha ncede belirtildii gibi kontroln sz konusu koordinat
noktalarna ulamas srasnda akc bir efekt yerine srama(Jump) efekti uygulanmaktadr. Her
halde bir yerden bir yere nlanmann WPF' cesinin bu olduunu syleyebiliriz. Bu durumu
aadaki Flash grselinden daha net bir ekilde analiz edebiliriz.

www.bsenyurt.com Page 825


Elbetteki ayn rnei kod yardmylada gerekletirebiliriz. Bunun iin aadaki XAML ieriine ve
kodlara sahip bir pencere hazrlamamz yeterli olacaktr.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaDiscreteKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Kod ile Discrete Kullanimi"
Height="300" Width="300">
<Canvas>
<Rectangle Name="Dortgen" Canvas.Top="0" Canvas.Left="0" Height="75"
Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
</Rectangle>
</Canvas>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation; // Animasyon tiplerini ieren isim alandr

namespace AnimasyonIslemleri
{

www.bsenyurt.com Page 826


public partial class KodlaDiscreteKullanimi : Window
{
private void AnimasyonuHazirla()
{
// Storyboard nesnesi rneklenir
Storyboard strBrd = new Storyboard();
// Animasyonun srekli tekrar edecei belirtilir
strBrd.RepeatBehavior = RepeatBehavior.Forever;
// Animasyonun zaman izgisini tamamladnda ayn yoldan geriye dnmesi salanr
strBrd.AutoReverse = true;

// Dortgen nesnesinde Canvas' n Top zellii zerinde Frame bazl animasyon yaplmasn
salayacak ekilde DoubleAnimationUsingKeyFrames nesnesi rneklenir
DoubleAnimationUsingKeyFrames dblA1 = new
DoubleAnimationUsingKeyFrames();
Storyboard.SetTargetName(dblA1, "Dortgen");
Storyboard.SetTargetProperty(dblA1, new PropertyPath(Canvas.TopProperty));

// Frame' lerdeki Top zelliinin deerleri belirtilir. Bunun iin DiscreteDoubleKeyFrame


nesneleri rneklenerek KeyFrames koleksiyonuna eklenir.
dblA1.KeyFrames.Add(new DiscreteDoubleKeyFrame(150,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 1))));
dblA1.KeyFrames.Add(new DiscreteDoubleKeyFrame(30, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 2))));
dblA1.KeyFrames.Add(new DiscreteDoubleKeyFrame(120, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 3))));
dblA1.KeyFrames.Add(new DiscreteDoubleKeyFrame(60, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 4))));
dblA1.KeyFrames.Add(new DiscreteDoubleKeyFrame(90, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 5))));
dblA1.KeyFrames.Add(new DiscreteDoubleKeyFrame(75, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 6))));
// DoubleAnimationUsingKeyFrames nesne rnei Storyboard' a alt element olarak eklenir.
strBrd.Children.Add(dblA1);

DoubleAnimationUsingKeyFrames dblA2 = new DoubleAnimationUsingKeyFrames();


Storyboard.SetTargetName(dblA2, "Dortgen");
Storyboard.SetTargetProperty(dblA2, new PropertyPath(Canvas.LeftProperty));

dblA2.KeyFrames.Add(new
DiscreteDoubleKeyFrame(150, KeyTime.FromTimeSpan(new TimeSpan(0,0, 0, 1,500))));
dblA2.KeyFrames.Add(new DiscreteDoubleKeyFrame(30, KeyTime.FromTimeSpan(new
TimeSpan(0, 0,0, 2,500))));
dblA2.KeyFrames.Add(new DiscreteDoubleKeyFrame(120, KeyTime.FromTimeSpan(new
TimeSpan(0, 0,0, 3,500))));
dblA2.KeyFrames.Add(new DiscreteDoubleKeyFrame(60, KeyTime.FromTimeSpan(new
TimeSpan(0, 0,0, 4,500))));
dblA2.KeyFrames.Add(new DiscreteDoubleKeyFrame(90, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 0,5,500))));
dblA2.KeyFrames.Add(new DiscreteDoubleKeyFrame(75, KeyTime.FromTimeSpan(new
TimeSpan(0, 0, 0,6,500))));
strBrd.Children.Add(dblA2);

// Pencere yklendikten sonra


Loaded += delegate(object sender, RoutedEventArgs e)
{

www.bsenyurt.com Page 827


// Animasyon balatlr
strBrd.Begin(this);
};

}
public KodlaDiscreteKullanimi()
{
InitializeComponent();
AnimasyonuHazirla();
}
}
}

Frame tabanl animasyon


ilemlerinde LinearDoubleKeyFrame ve DiscreteDoubleKeyFrame tipleri dnda kullanlabilen
bir dier snfta SplineDoubleKeyFrame' dir. Bu tip sayesinde, animasyon ilemi srasndaki ileri
ve geri ynl hareketlerde, hzlanma ve yavalama oranlar daha net bir ekilde belirlenebilir. Sz
konusu hzlanma verilerini belirlemek iin, sadece 0.0 ile 1.0 arasnda deerler
alabilen KeySpline zelliinden yararlanlr. Aadaki XAML ieriine sahip rnekte
SplienDoubleKeyFrame tipi kullanlmaktadr.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.SplineKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Spline Kullanimi" Height="422"
Width="181">
<Canvas>
<Rectangle Name="Dortgen" Canvas.Top="0" Canvas.Left="0" Height="75" Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Window.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard AutoReverse="True" RepeatBehavior="Forever">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="Dortgen" Storyboard.TargetProperty="(Canvas.Top)">
<SplineDoubleKeyFrame KeyTime="0:0:3" Value="200"
KeySpline="0.3,0.0 0.9,0.3"/>

www.bsenyurt.com Page 828


</DoubleAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
</Window>

Bu rnein alma zamanndaki kts aadaki Flash animasyonunda olduu gibidir.(Flash


dosyasnn boyutu 298 Kb olduundan yklenmesi zaman alabilir.)

Dikkat edilecek olursa dey dzlemde hareket eden resim 3 saniyelik zaman dilimi ierisinde
pencerenin st noktasndan 200 piksel aaya gelmektedir. Ancak bu hareketi
srasndaKeySpline niteliinde belirtilen deerler nedeni ile dey olarak hzlanarak ve ters ynde
de yavalayarak ilerlemektedir. KeySpline niteliindeki deerler ile oynayarak daha farkl etkiler de
elde edilebilir. Hatta bu deerler ile oynayarak farkl etkilerin nasl oluturulabileceini incelemenizi
iddetle tavsiye ederim. Ayn rnek kod yardmylada aadaki gibi gelitirilebilir.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaSplineKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Kod ile Spline Kullanimi"
Height="397" Width="181">
<Canvas>
<Rectangle Name="Dortgen" Canvas.Top="0" Canvas.Left="0" Height="75"
Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg"/>
</Rectangle.Fill>
</Rectangle>
</Canvas>

www.bsenyurt.com Page 829


</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation; // Animasyon tiplerini ieren isim alandr

namespace AnimasyonIslemleri
{
public partial class KodlaSplineKullanimi : Window
{
private void AnimasyonuHazirla()
{
// Storyboard nesnesi rneklenir, animasyonun tekrarl ve geriye dnl olacak ekilde
alaca belirlenir
Storyboard strBrd = new Storyboard();
strBrd.RepeatBehavior = RepeatBehavior.Forever;
strBrd.AutoReverse = true;

DoubleAnimationUsingKeyFrames dblA = new


DoubleAnimationUsingKeyFrames();

// SplineDoubleKeyFrame nesnesi eklenir. nc parametre ile hzlanma ve yavalama


deerleri belirlenir.
dblA.KeyFrames.Add(new SplineDoubleKeyFrame(200,
KeyTime.FromTimeSpan(new TimeSpan(0, 0, 3)), new KeySpline(0.3, 0, 0.9, 0.3)));
// Animasyonun Dortgen isimli nesneye ve iinde bulunduu Canvas' n Top zelliine
uygulanaca belirlenir
Storyboard.SetTargetName(dblA, "Dortgen");
Storyboard.SetTargetProperty(dblA, new PropertyPath(Canvas.TopProperty));

// Animasyon nesnesi Storyboard' a alt element olarak eklenir


strBrd.Children.Add(dblA);

// Pencerenin yklenmesi tamamlandktan sonra


Loaded += delegate(object sender, RoutedEventArgs e)
{
// Animasyon balatlr
strBrd.Begin(this);
};
}
public KodlaSplineKullanimi()
{
InitializeComponent();
AnimasyonuHazirla();
}

www.bsenyurt.com Page 830


}
}

Bu rneklerdende anlalaca zere farkl veri tipleri iin yazlm olan Frame bazl animasyon
tipleri olduunu syleyebiliriz. Gelitirilen rnekler double tipi ile alan zellikler zerinde Frame
bazl animasyonlar gelitirilebilmesi iin DoubleAnimationUsingKeyFrames tipini kullanmaktadr.
Ancak bu tip
dnda ColorAnimationUsingKeyFrames,PointAnimationUsingKeyFrames, ByteAnimationU
singKeyFrames vb... snflarda yer almaktadr. Tm bu Frame bazl animasyon
tipleri LinearTipAdKeyFrame, DiscreteTipAdKeyFrame ve SplineTipAdKeyFrame snflarna
ait nesne rnekleri ile alabilmektedir. Tabiki bu durum her veri tr iin geerli deildir. Sz
gelimiStringAnimationKeyFrames tipi sadece DiscreteStringKeyFrame snfna ait nesne
rneklerini tayabilir. Dolaysyla enterpoasyon(Interpolation) efektleri gerekletirilemez.

Sradaki rnekte bir Button kontrolnn Text zelliinin ieriini Frame bazl animasyon ileminde
nasl ele alabileceimizi inceleyeceiz. Bu amala XAML ierii aadaki gibi olan bir pencere
tasarladmz dnelim.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.StringKeyFrameAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="StringKeyFrameAnimasyon"
Height="149" Width="278">
<Grid>
<Button Name="btnMerhaba" Width="140" Height="40" FontSize="12"
FontWeight="Bold">
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard RepeatBehavior="Forever">
<StringAnimationUsingKeyFrames
Storyboard.TargetName="btnMerhaba" Storyboard.TargetProperty="Content"
Duration="0:0:6">
<!-- Eer Duration sresi belirtilmesse DiscreteStringKeyFrame
elementlerinden sonuncusu gsterilmiyor. Sonuncusununda gsterilmesi iin Duration sresi son
DiscreteStringKeyFrame' inkinden fazla verilmelidir.-->
<DiscreteStringKeyFrame Value="WPF" KeyTime="0:0:1"/>
<DiscreteStringKeyFrame Value="ile" KeyTime="0:0:2"/>
<DiscreteStringKeyFrame Value="Temel" KeyTime="0:0:3"/>
<DiscreteStringKeyFrame Value="Animasyon"
KeyTime="0:0:4"/>
<DiscreteStringKeyFrame Value="lemleri" KeyTime="0:0:5"/>

www.bsenyurt.com Page 831


</StringAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>

Bu rnein alma zamanndaki ileyii aadaki Flash grselinde olduu


gibidir. DiscreteStringKeyFrame elementlerine ait Value nitelikleri tahmin edilecei zere,
animasyonun baland kontroln ilgili zelliindeki string bilginin t annda ne olacan belirtmekte
kullanlmaktadr. KeyTime niteliine verilen deerler ile sz konusu t anlar belirtilir.

Elbetteki bu rnekteki animasyon etkisi kod yardmylada gelitirilebilir. Aadaki kod paralarnda
bu duruma bir rnek verilmektedir.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaStringKeyFrameAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="KodlaStringKeyFrameAnimasyon" Height="144" Width="300">
<Grid>
<Button Name="btnMerhaba" Width="140" Height="40" FontSize="12"
FontWeight="Bold"/>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

www.bsenyurt.com Page 832


namespace AnimasyonIslemleri
{
public partial class KodlaStringKeyFrameAnimasyon : Window
{
string slogan = "CSharp az keyword ile ok i yapmamz salayan bir dildir";

private void AnimasyonuHazirla()


{
Storyboard strBrd = new Storyboard();
strBrd.RepeatBehavior = RepeatBehavior.Forever;

StringAnimationUsingKeyFrames strA = new StringAnimationUsingKeyFrames();


string[] kelimeler = slogan.Split(' ');
strBrd.Duration = TimeSpan.FromSeconds(kelimeler.Length + 1);
for(int i=1;i<=kelimeler.Length;i++)
{
strA.KeyFrames.Add(new DiscreteStringKeyFrame(kelimeler[i-
1],KeyTime.FromTimeSpan(TimeSpan.FromSeconds(i))));
}
Storyboard.SetTargetName(strA, "btnMerhaba");
Storyboard.SetTargetProperty(strA, new
PropertyPath(Button.ContentProperty));
strBrd.Children.Add(strA);
btnMerhaba.MouseEnter += delegate(object sender, MouseEventArgs e)
{
strBrd.Begin(this);
};
}
public KodlaStringKeyFrameAnimasyon()
{
InitializeComponent();
AnimasyonuHazirla();
}
}
}

Bu kez, bir slogan cmle ierisindeki kelimeler boluk karakterine gre Split metodu ile
ayrtrlmakta ve elde edilen string dizisindeki her bir kelime
iin DiscreteStringKeyFrame temelli, saniyede bir artan animasyon uygulanmaktadr. Bu rnek
kod parasnn alma zamanndaki kts ise aadaki Flash grselindeki gibi olacaktr.

Makalemizde son olarak bir bileenin belirli bir rota zerinde hareket etmesinin animasyon
teknikleri ile nasl gerekletirilebileceini incelemeye alacaz. nceki makalelerimizden
hatrlayacanz gibi, Path ve PathGeometry tiplerini kullanarak birbirlerine bal yaylarn
izilmesi mmkndr. Bu tip bir elementin oluturaca rotay takip eden bir bileen sz konusu

www.bsenyurt.com Page 833


olduunda, animasyon tiplerinden TipAdAnimationUsingPath isimlendirmesi ile
tanmlananlardan yararlanbiliriz. rnein bir PathGeometry ile tanmlanan rotada hareket edecek
bir nesnenin iinde bulunduu Canvas' n Top ve Left zellikleri sz konusu
ise DoubleAnimationUsingPath tipini kullanabiliriz. Aadaki XAML ktsnda bu durum
rneklenmeye allmaktadr.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.PathFrameKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="PathFrameKullanimi"
Height="300" Width="300">
<Window.Resources>
<PathGeometry x:Key="YolGeometrisi">
<PathFigure>
<BezierSegment Point1="0,0" Point2="10,120" Point3="70,40"/>
<ArcSegment Point="150,125" SweepDirection="Clockwise" Size="50,50"
IsLargeArc="True" RotationAngle="60"/>
<ArcSegment Point="200,200" SweepDirection="Counterclockwise" Size="50,50"
IsLargeArc="True" RotationAngle="60"/>
</PathFigure>
</PathGeometry>
</Window.Resources>
<Canvas>
<Path Data="{StaticResource YolGeometrisi}" Stroke="LightGray"
StrokeThickness="2"/>
<Rectangle Height="65" Name="Dortgen" Width="55">
<Rectangle.Fill>
<ImageBrush ImageSource="Kitap.jpg" />
</Rectangle.Fill>
<Rectangle.Triggers>
<EventTrigger RoutedEvent="Rectangle.MouseEnter">
<BeginStoryboard>
<Storyboard AutoReverse="True" RepeatBehavior="Forever">
<DoubleAnimationUsingPath Storyboard.TargetName="Dortgen"
Storyboard.TargetProperty="(Canvas.Top)" PathGeometry="{StaticResource
YolGeometrisi}" Source="Y" Duration="0:0:6" />
<DoubleAnimationUsingPath Storyboard.TargetName="Dortgen"
Storyboard.TargetProperty="(Canvas.Left)" PathGeometry="{StaticResource
YolGeometrisi}" Source="X" Duration="0:0:6" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Rectangle.Triggers>
</Rectangle>
</Canvas>
</Window>

Sz konusu rnekte, Storyboard elementi ierisinde DoubleAnimationUsingPath alt elementi


kullanlmaktadr. Bu elementlerden iki adet tanmlanmasnn sebebi, Dortgen isimli nesnenin Top ve
Left zelliklerinin ayr ayr deitirilmesi gerekliliidir. DoubleAnimationUsingPath tipinde yer alan
niteliklerden Storyboard.TargetName ile animasyonun hangi kontrole uygulanaca belirtilir ki bu
rnekte sz konusu kontrol Dortgen isimli Rectangle dr. Storyboard.TargetProperty nitelikleri
ise Rectangle' n ierisinde bulunduu Canvas' n Top ve Left zelliklerinin deerleri zerinde
hareketlendirmeler yaplacan belirtir. PathGeometry nitelikleri tahmin edilecei zere rota
bilgisini ieren pencere kaynan (Windows Resource) iaret etmektedir. MSDN

www.bsenyurt.com Page 834


kaynaklar Resource olarak yaplan bu tip tanmlamalarn animasyon ilemlerinde performans
ynnden olumlu katk yapacan belirtmektedir. Static kaynak olarak tanmlanan YolGeometrisi
isimli veri kmesi yardmyla Path elementinin rota bilgiside verilmektedir. Bunun
iinde Path elementinin Data niteliine deer atamas yaplmtr. Bu rnein alma zamanndaki
kts aadaki Flash animasyonunda olduu gibidir. (Flash dosyasnn boyutu 352 kb
olduundan yklenmesi zaman alabilir.)

Grld gibi WPF mimarisinde gerek XAML tarafnda gerekse kod tarafnda animasyon ilemleri
iin son derece etkili yollar kullanlabilmektedir. Bence burada nemli olan noktalardan biriside
iaretleme dili ierisinde bu tip gelimi fonksiyonelliklerin gelitirilebilmesidir. lerleyen
makalelerimizde WPF ile ilgili farkl konularada deinmeye alacaz. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WPF - Temel Animasyon lemleri ( 26.09.2007 )


- WPF
Deerli Okurlarm Merhabalar,

Windows uygulamalarnda kullanclara grsel bir len sunmak iin animasyon ilemlerinden
yararlanlr. Ne varki sz konusu animasyonlar gerekletirebilmek amacyla zorlu olan baz
srelerin almas gerekmektedir. Burada aslnda, GDI+(Graphics Device Interface) alt
yapsn(Infrastructure) daha etkili kullanmak adna daha ok ve daha karmak kodlarn yazlmas,
form zerinde animasyonun zaman izelgesine gre Timer bileenleri ile Interval zellii
ve Tick olay(event) gibi yelerlerle uralmas ve hatta yeri geldiinde ana i parasnn(Main
Thread) bozabilecei durumlarn nne gemek iin zel tedbirler alnmas sz konusudur. Hele
birde iin ierisine boyutlu(3D) nesneler girdiinde ve bunlarn zerinde kullanc etkileimli
olaylarn tetiklenebilmesi de istendiinde programcnn gelitirme sreci hem zorlaacak hemde
uzayacaktr. Tabiki gnmzde bu tip ilemleri gerekletirmek iin ele alna pek ok kolaylatrc

www.bsenyurt.com Page 835


yazlm vardr. Ancak bir olaya .Net Windows programcs olarak bakyor olacaz. Durumun
zorluunu daha net anlayabilmek adna, basit olarak form zerinde yer alan bir Button
kontrolnn ykseklik(Height) ve genilik(Width) zelliklerinin srekli olarak belirli oranlarda
byyp kldn dnelim. Bunu Windows programlamada nasl yapmamz gerektiini hayal
edin. Her eyden nce srenin sz konusu olduu bu senaryoda bir Timer bileenin var olmas
ve Tick olaynn uygun ekilde ele alnmas(Handle) gerekmektedir. Oysaki WPF (Windows
Presentation Foundation)mimarisinde bu ve benzeri animasyon ilemleri ok daha kolay, hzl ve
gl bir ekilde gerekletirilebilmektedir. te bu makalemizde sz konusu durumu incemeleye
balayacak ve WPF mimarisinde temel animasyon ilemlerine deineceiz. WPF mimarisinin sz
konusu animasyon gelitirme ilerini nasl kolaylatrdn grmek adna aadaXAML(eXtensible
Application Markup Language) kts aada grlen rnek ile hzl bir ekilde balamakta
yarar olaca kansndaym.

<Window x:Class="AnimasyonIslemleri.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Merhaba Animasyon
(DoubleAnimation)" Height="300" Width="300">
<Grid>
<Button Name="btnMerhaba" Width="100" Height="40" Content="Merhaba"
FontSize="12" Foreground="Blue" FontWeight="Bold">
<Button.Background>
<LinearGradientBrush>
<LinearGradientBrush.GradientStops>
<GradientStop Color="Red" Offset="0.5"/>
<GradientStop Color="White" Offset="0.5"/>
</LinearGradientBrush.GradientStops>
</LinearGradientBrush>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="btnMerhaba"
Storyboard.TargetProperty="Width" By="5" RepeatBehavior="Forever" From="100"
To="150" Duration="0:0:1" AutoReverse="True"/>

www.bsenyurt.com Page 836


<DoubleAnimation Storyboard.TargetName="btnMerhaba"
Storyboard.TargetProperty="Height" From="40" To="60" Duration="0:0:1"
RepeatBehavior="Forever" AutoReverse="True"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>

XAML ieriinde yer alan elementler ve nitelikleri(attributes) hakknda konumadan nce bu


pencerenin alma zamanna bir bakalm. Aadaki Flash animasyonunda alma
zamanndaki(run-time) durum grlmektedir. Dikkat edilecek
olursa pencere(Window) zerindeki Button kontrolnn Width ve Height zelliklerinde
genilemeler olmaktadr. Dikkat ekici bir dier noktada animasyonun, mouse ile Button kontrol
zerine gelindiinde baladdr. Bununla birlikte sz konusu aminasyon srekli olarak devam
etmektedir.

Gelelim XAML ieriinde neler yapldna. Daha nceki makalelerimizden de hatrlanaca gibi
Button bileeninin arka plannda LinearGradientBrush elementi ile geili renklerden oluan bir
dolgu efekti kullanlmaktadr. Button elementinin ierisinde animasyon zelliklerinin belirtildii
yer Button.Triggers alt elementi ile balamaktadr. Hemen altta yer
alanEventTrigger elementinin RoutedEvent niteliine atanan deer ile animasyonun hangi olayn
tetiklenmesi sonras balatlaca belirtilmektedir. rneimizde MouseEnter olay bu amala
kullanlmaktadr. Burada olay ad
belirtilirken tipAd.zellikad (rnein Button.MouseEnter gibi) eklinde olmasna dikkat
edilmelidir. Aksi durumda bir istisna(Exception) alnmas muhtemeldir. Dolaysyla temel anlamda
animasyonlarn balatlabilmesi iin olaylardan yararlanlabildiini ve bunlarn ilgili kontrollere birer
tetikleyici(Trigger) ile balandn syleyebiliriz.

Bir kontroln animasyon ilemlerinde kullanlabilmesi iin IAnimatable arayzn


uyarlam(Implement) olmas gerekmektedir. Sz gelimi Button bileeninin snf
diagramndaki(Class Diagram) grntsne bakldnda IAnimatable arayzn
uyarlad ak bir ekilde grlebilir.

www.bsenyurt.com Page 837


Animasyon ilemlerinde nemli olan noktalardan birisi kontroln veya eklin hangi zelliinin
deerinin, ne ekilde deitirileceidir. lk rnekte Button
kontrolnn Width veHeight zelliklerinin deerlerinin her ikisi birden deitirilmektedir. Peki WPF
mimarisinde hangi kontroln hangi zelliinin deerinin, ne ekilde deitirilecei nasl
belirlenmektedir? te bu noktada devreye StoryBoard tipi ve alt elementleri girmektedir.

StoryBoard tipi hangi kontroln hangi zellii zerinde nasl bir animasyon
uygulanacan belirleyip bunu balatmak ve belirli bir tetikleyici(Trigger) olaya balamak
iin kullanlan nemli bir snftr.

rnek XAML ieriinde dikkat edilecek olursa StoryBoard elementi altnda iki
adet DoubleAnimation elementi tanmlanmtr.

WPF ierisinde yer alan temel animasyon tipleri(Basic Animation Types) uygun veri
trleri ile alacak ekilde tasarlanmlardr. Bu tiplerin
adlar DoubleAnimation,ColorAnimation, PointAnimation,
VectorAnimation rneklerinde olduu gibi TrAdAnimation kelimelerinden
olumaktadr. Animasyon tipleride IAnimatable arayzn uyarlamaktadr. Sz gelimi

www.bsenyurt.com Page 838


rnekte kullanlan DoubleAnimation tipinin snf diagramndaki(Class Diagram) grnts
aadaki gibidir.

Ayrca sz konusu animasyon tipleri Animatable isimli abstract snfdan da


tremektedir. Buna gre ilgili abstract snf ve arayz kullanarak kendi animasyon
tiplerimizde yazabiliriz. WPF ierisinde temel animasyon tipleri dnda yer alan
animasyon tipleride vardr. ColorAnimationUsingKeyFrames gibi. Bu tipleri ilerleyen
makalelerimizde incelemeye alyor olacaz.

Burada animasyon tipinin kullanm ve zellikleri hakknda biraz konumakta yarar vardr. rnekte
yer alan Button kontrolnn animasyon etkisi oluturan zellikleri Width ve Height yeleridir. Bu
zellikler Double tipinden deerler alabilmektedir. Bu nedenle StoryBoard ierisinde tanmlanan
animasyon tipleri DoubleAnimation tipindendir. Dolaysyla animasyon ileminde kullanlacak olan
kontrol zellii iin, uygun olan animasyon tipinin seilmesi gerekmektedir. DoubleAnimation tipi
ierisinde olduka nemli nitelik(attribute) tanmlamalar yer almaktadr.
Bunlardan StoryBoard.TargetName nitelii ile animasyonun uygulanaca kontrol seilmektedir
ki rnekte bu btnMerhaba isimli Button kontroldr. Dier
taraftanStoryBoard.TargetProperty nitelii ile kontroln hangi zelliinin animasyon ileminde
kullanlaca belirtilir. From nitelii ile hedef zelliin hangi deerden balayaca, Tonitelii ilede
hedef zelliin ilgili deerinin hangi deere kadar gelebilecei belirtilir.

Bir baka deyile Button kontrolnn genilii 100 deerinden 150 deerine gelecekse From
niteliine 100, To niteliine ise 150 deerleri atanr. Burada istenirse By nitelii kullanlarak
deerin art oranda belirtilebilir. ok doal olarak animasyonun ne kadar sre devam edecei

www.bsenyurt.com Page 839


bilgisinin de belirtilmesi gerekmektedir. Bu amala DoubleAnimation tipinin Durationnitelii
kullanlmaktadr. Duration nitelii temelde saat:dakika:saniye eklinde bir deer almaktadr.
Buna gre rnek XAML ieriinde yer alan 0:0:1 deeri animasyondaki zaman izgisinin (Timeline)
1 saniye olacan belirtmektedir. RepeatBehavior nitelii ile animasyonun tekrar says belirtilir.
rnekte verilen Forever deerine gre animasyon srekli olarak devam edecektir. Son
olarak AutoReverse deerine true atanarak, 1 saniyelik animasyon sona erdiinde ilemlerin
tekrar balang haline tersten bir animasyon ile gitmesi salanmaktadr. Bu nedenle Flash
animasyonunda grld gibi kontrol bydkten sonra ayn animasyon etkisi ile tersten
klm ve ilk haline gelmitir.

lk rnekte sz konusu animasyon ilemleri iin XAML elementlerinden ve


niteliklerinden(attributes) yararlanlmtr. ok doal olarak kod ile dinamik olarak ayn etkiler
oluturulabilir. Sradaki rneimizde kod tarafnda animasyon ilemlerinin nasl yaplabileceini
incelemeye alacaz. Bu amala penceremize(Window) ait XAML ieriini ve kodlarn
aadaki gibi hazrladmz dnelim.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaMerhabaAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Kodla Merhaba Animasyon"
Height="300" Width="300">
<Grid>
<Button Name="btnMerhaba" Width="100" Height="50" Foreground="Gold"
Background="Black" Content="Merhaba" FontSize="14" FontWeight="Bold">
</Button>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;

www.bsenyurt.com Page 840


using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation; // Animasyon tiplerini barndran isim alandr

namespace AnimasyonIslemleri
{
public partial class KodlaMerhabaAnimasyon : Window
{
private void AnimasyonuHazirla()
{
// Button kontrolnn Width zellii zerinde animasyon ilemi yaptracamzdan ve
Width zellii Double tipinden deerler aldndan DoubleAnimation tipi kullanlmaktadr.
// lk parametre From
// kinci parametre To
// ncd parametre animasyonun sresi
DoubleAnimation dblAnmtr = new DoubleAnimation(100, 150, new Duration(new
TimeSpan(0, 0, 0, 3)));
// Animasyonun tekrar says belirtilir.
dblAnmtr.RepeatBehavior = new RepeatBehavior(2);

// Yeni bir StoryBoard oluturulur


Storyboard strBrd = new Storyboard();
// DoubleAnimation tipi bu storyBoard' a eklenir
strBrd.Children.Add(dblAnmtr);
// Hedef kontrol belirlenir
Storyboard.SetTargetName(dblAnmtr, btnMerhaba.Name);
// Animasyon ileminde Button kontrolnn hangi zelliinin deitirilecei belirtilir.
Storyboard.SetTargetProperty(dblAnmtr,new
PropertyPath(Button.WidthProperty));
// Animasyon Begin metodu ile Button zerine Mouse ile gelindiinde balatlr
btnMerhaba.MouseEnter += delegate(object sender, MouseEventArgs e)
{
strBrd.Begin(this);
};
}

public KodlaMerhabaAnimasyon()
{
InitializeComponent();
AnimasyonuHazirla();
}
}
}

Bu kez animasyon ilemleri kod tarafnda gerekletirilmektedir. rnekte ilk


olarak DoubleAnimation tipinden bir rnek oluturulmu ve yapc metodu ierisinde baz ilk
deerlerin(From, To, Duration gibi) verilmesi salanmtr. Sonrasnda
ise RepatBehavior zellii ile tekrar says belirtilmektedir. Bu rnekte bir ncekinden farkl
olarak Forever deeri yerine 2 kullanlmtr. Buna gre sz konusu animasyon sadece iki kere
tekrar edecektir. Sonrasnda ise her zamanki gibi animasyonu, kontrol ve kontroln zellii ile
ilikilendirecekStoryBoard nesne rnei oluturulur. Animasyonun balatlmas iin yine

www.bsenyurt.com Page 841


kontroln MouseEnter olay gz nne alnmtr. Animasyon ilemi iin StoryBoard nesne
rneinin Begin metodunu kullanmak yeterlidir. Ancak bu metodun uygun olay iin tetiklenmesini
salamak gerekmektedir. Bu amalada isimsiz bir metod(anonymous method) yazlarak hem
Button kontrolnn MouseEnter olay tanmlanm hemde gerekletiinde iletilmesi istenen kodlar
belirlenmitir. rnein alma zamanndaki kts aadaki Flash animasyonunda olduu gibidir.

Gelelim bir dier rnee. nceki rneklerde Button kontrolonn boyutlarn ele alan animasyon tipi
kullanlmtr. Sradaki rnekte ise ColorAnimation tipi barol oynamaktadr. Tahmin edilecei
gibi bu tip, bir rengin baka bir renge dnmnn animasyon olarak gerekletirilmesini
salamaktadr. rnein XAML ierii aadaki gibidir.

<Window x:Class="AnimasyonIslemleri.RenkliAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Renkli
Animasyon(ColorAnimation)" Height="300" Width="300">
<Grid>

www.bsenyurt.com Page 842


<Button Name="btnMerhaba" Foreground="White" Content="Merhaba" FontSize="12"
FontWeight="Bold" Width="100" Height="50">
<Button.Background>
<SolidColorBrush x:Name="DolguRengi" Color="Red"/>
</Button.Background>
<Button.Triggers>
<EventTrigger RoutedEvent="Button.MouseEnter">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<ColorAnimation Storyboard.TargetName="DolguRengi"
Storyboard.TargetProperty="(SolidColorBrush.Color)" From="Red" To="Blue"
AutoReverse="True" Duration="0:0:6" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</Button.Triggers>
</Button>
</Grid>
</Window>

ColorAnimation tip olarak kullanldnda kontrollerin renk deeri alabilen zelliklerinin animasyon
ilemlerinde kullanlabilecei anlalmaktadr. rnekte Button kontrolnn arka plan dolgusu
animasyon ierisine katlmaktadr. Bu nedenle ColorAnimation kontrolnn ele alaca kontrol ve
zellik DoubleAnimation tipinin kullanld rneklerdekinden biraz daha farkldr. Dikkat edilecek
olursa SolidColorBrush elementi ierisinde DolguRengi ismi x:Name nitelii yardmyla
tanmlanmtr. Bu isim StoryBoard.TargetNameniteliinde kullanlmaktadr. Bir baka deyile
StroyBoard tipinin XAML ieriindeki SolidColorBrush elementini bulmas kolaylatrlmaktadr.
Bunun en byk nedenlerinden birisi SolidColorBrush elementinin Button elementinin altnda kalm
olmas ve Button tipine isim ile eriilebiliyor olmasna ralem ayn iin sz konusu SolidColorBrush
iin salanamyor olmasdr. Dier taraftan animasyonda kullanlacak zellik
deeride StoryBoard.TargetProperty elementi ierisinde ele
alnrken (SolidColorBrush.Color) yazm stili kullanlmaktadr. Animasyona gre, Button
kontrolnn arka plan rengi krmzndan maviye doru deiecek ve sonrasnda tekrardan maviden
krmzya dnecektir(AutoReverse=true olduu iin). Animasyondaki zaman
izelgesinin(Timeline) sresi 6 saniyedir. Aadaki Flash animasyonunda uygulamann alma
zamanndaki(Run-time) grnts yer almaktadr.

www.bsenyurt.com Page 843


Ayn etki aadaki kod paras yardmyla dinamik olaraktan da gerekletirilebilir.

XAML erii;

<Window x:Class="AnimasyonIslemleri.KodlaRenkliAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="KodlaRenkliAnimasyon"
Height="300" Width="300">
<Grid>
<Button Name="btnMerhaba" Width="100" Height="50" Content="Merhaba"
Foreground="White" FontSize="14" FontWeight="Bold">
<Button.Background>
<SolidColorBrush x:Name="firca" Color="Red"/>
</Button.Background>
</Button>
</Grid>
</Window>

Kod erii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation; // Animasyon tiplerini ieren isim
alandr(Namespace)

namespace AnimasyonIslemleri
{

www.bsenyurt.com Page 844


public partial class KodlaRenkliAnimasyon : Window
{
private void AnimasyonuAyarla()
{
// Animasyon tipi oluturulur.
// lk parametre balang rengini iaret eder (From)
// kinci parametre biti rengini iaret eder (To)
// nc parametre zaman izgisinin sresidir
ColorAnimation clrAnmtr = new ColorAnimation(Colors.Red, Colors.Blue, new
Duration(new TimeSpan(0, 0, 6)));
// Animasyonun srekli tekrar edecei belirtilir
clrAnmtr.RepeatBehavior = RepeatBehavior.Forever;

// Animasyonu kontrol ve zellii ile ilikilendirecek StoryBoard nesnesi rneklenir.


Storyboard strBrd = new Storyboard();
strBrd.Children.Add(clrAnmtr);
Storyboard.SetTargetName(clrAnmtr, "firca"); // SolidColorBrush kontrolnn
x:name niteliinin deeri ile animasyon uygulanacak kontrol belirtilmi olur.
Storyboard.SetTargetProperty(clrAnmtr, new
PropertyPath(SolidColorBrush.ColorProperty)); // SolidColorBrush kontrolnn Color zellii
zerinde animasyonun uygulanaca belirtilir.

// Animasyon yine MouseEnter olay metodunda Begin metodu ile balatlr.


btnMerhaba.MouseEnter += delegate(object sender, MouseEventArgs e)
{
strBrd.Begin(this);
};
}
public KodlaRenkliAnimasyon()
{
InitializeComponent();
AnimasyonuAyarla();
}
}
}

Yukardaki kodun yer ald pencere altrldnda, bir nceki rnekteki ile ayn etkinin olutuu
grlecektir.

Yazmza PointAnimation tipini ele alacamz son bir rnek ile devam edelim. PointAnimation tipi
adndanda anlalaca zere Point tipinden deerler alabilen kontrol zellikleri(Control Property)
zerinde animasyon ilemleri gerekletirilebilmesi amacyla kullanlr. rnek olarak
aadaki XAML ieriini ele alabiliriz.

XAML ierii;

www.bsenyurt.com Page 845


<Window x:Class="AnimasyonIslemleri.NoktaAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Nokta Animasyon"
Height="300" Width="300">
<Grid>
<Path Name="Daire" Fill="Red" Stroke="Black" StrokeThickness="1">
<Path.Data>
<EllipseGeometry x:Name="daireGeo" Center="15,15" RadiusX="10"
RadiusY="10" />
</Path.Data>
<Path.Triggers>
<EventTrigger RoutedEvent="Path.Loaded">
<BeginStoryboard>
<Storyboard>
<PointAnimation Storyboard.TargetName="daireGeo"
Storyboard.TargetProperty="Center" From="15,15" To="285,15" Duration="0:0:1.75"
AutoReverse="true" RepeatBehavior="Forever"/>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Path.Triggers>
</Path>
</Grid>
</Window>

Burada rnek olarak Path tipinden bir ekil(Shape) kullanlm ve EllipsGeometry tipinden
yararlanlarak bir daire oluturulmutur. Burada Point tipinden deer alan ye Centerzelliidir.
Bu anlamda PointAnimation tipinin hedef ald kontrol aslnda EllipseGeometry nesnesidir. Bu
iaretlemeyi yapabilmek iin yine x:Name niteliinden yararlanlmtr. Dier taraftan
EllipsGeometry nesne rneinin Center zellii animasyon ilemine tabi
tutulacandan StoryBoard.TargetProperty niteliine Center deeri verilmitir. PointAnimation
tipi basit olarak kontroln bir zaman izgisi(Timeline) ierisinde belirli bir koordinata doru hareket
etmesini salamaktadr. Buna gre rnekteki daire ekli, 15:15 noktasndan 285:15 noktasna
doru 1.75 saniyelik zaman dilimi ierisinde hareket edecek
ve AutoReverse zelliine true deerinin atanmas nedeniylede bu sre sonunda tekrardan geriye
ilk konumuna gidecektir. Tahmin edilecei zere RepeatBehavior niteliinin deerinin true olmas
bu ilemi srekli klacaktr. Burada dier rneklerden farkl olarak animasyon ileminin tetiklendii
olay olarak Path.Loaded seilmitir. Buna gre Path, sz konusu pencere(Window) zerine
yklendikten sonra animasyon ilemi dorudan balayacaktr. rnein alma zamanndaki
grnts aadaki Flash grselinde olduu gibidir.

www.bsenyurt.com Page 846


Ayn ileyii kod tarafnda gerekletirmek istersek aadaki satrlar kullanmamz yeterli olacaktr.

XAML ierii;

<Window x:Class="AnimasyonIslemleri.KodlaNoktaAnimasyon"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Kodla Nokta Animasyon
(PointAnimation)" Height="300" Width="300">
<Grid>
<Path Name="Daire" Fill="Red" Stroke="Black" StrokeThickness="1">
<Path.Data>
<EllipseGeometry x:Name="daireGeo" Center="15,15" RadiusX="10"
RadiusY="10" />
</Path.Data>
</Path>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation; // Animasyon tiplerini ieren isim alandr

namespace AnimasyonIslemleri
{
public partial class KodlaNoktaAnimasyon : Window

www.bsenyurt.com Page 847


{
private void AnimasyonuBaslat()
{
// Nokta animasyonu iin gerekli tip oluturulur
// lk parametre balang noktas koordinatlardr From
// kinci parametre biti noktas koordinatlardr To
// nd parametre zaman izelgesinin sresidir Duration
PointAnimation pntAnmtr = new PointAnimation(new Point(15, 15), new
Point(285, 15), new Duration(new TimeSpan(0, 0, 0,1,75)));

// Animasyonu kontrol ve zellii ile ilikilendirecek olan StoryBoard oluturulur


Storyboard strBrd = new Storyboard();
// Animasyon tipi StoryBoard' a eklenir
strBrd.Children.Add(pntAnmtr);
// Animasyonun sonundan tekrardan geriye doru gidilecei belirtilir
strBrd.AutoReverse = true;
// Animasyonun srekli devam edecei belirtilir
strBrd.RepeatBehavior = RepeatBehavior.Forever;
// Animasyonun uygulanaca EllipsGeometry tipi seilir. Buradaki ikinci parametre XAML
tarafndaki x:Name niteliinin deeridir
Storyboard.SetTargetName(pntAnmtr,"daireGeo");
// Animasyonun uygulanaca zellik seilir.
Storyboard.SetTargetProperty(pntAnmtr, new
PropertyPath(EllipseGeometry.CenterProperty));
// Animasyonun, Daire isimli Path yklendikten sonra balatlmas iin Loaded olay metodu
yklenir.
Daire.Loaded += delegate(object sender, RoutedEventArgs e)
{
strBrd.Begin(this);
};
}
public KodlaNoktaAnimasyon()
{
InitializeComponent();
AnimasyonuBaslat();
}
}
}

WPF ierisinde kullanlan temel animasyon tipleri(Basic Animation Types) sadece yazmzda
bahsetiklerimiz ile snrl deildir. System.Windows.Media.Animation isim alannda(Namespace)
yer alan dier animasyon tiplerinin listesi aadaki gibidir.

ByteAnimation
DecimalAnimation
Int16Animation
Int32Animation
Int64Animation
Point3DAnimation
QuaternionAnimation
Rotation3DAnimation
RectAnimation
SingleAnimation
SizeAnimation
TicknessAnimation
Vector3DAnimation

www.bsenyurt.com Page 848


VectorAnimation

Grld gibi kontrollerin pek ok farkl tipteki zellii iin yazlm temel animasyon tipleri vardr.
Animasyon ile ilgili ilemler bu makalede ele aldklarmz ile snrl deildir elbeteki. 3 boyutlu (3D)
animasyon, KeyFrame' lerin kullanm ve dahas da var. Animasyon ilemleri ile ilgili bu ilk
yazmzda temel animasyon tiplerinin tanmaya ve onlar anlamaya altk. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WPF - Grafik lemlerinde ekillerin(Shapes)


Kullanm ( 18.09.2007 ) - WPF
Deerli Okurlarm Merhabalar,

Windows Presentation Foundation(WPF) ile ilgili bir nceki makalemizde, iki


boyutlu(2D) grafiklerin izilmesi amacyla kullanlan fralar(Brushes) incelemeye almtk. Bu
makalemizde ise iki boyutlu ekilleri(Shapes) aratryor olacaz. Vektrel grafiklerde
ekillerin(Shapes) byk nemi vardr. Nitekim temel ekiller kullanlarak asl resimler ve
grntler kolaylkla elde edilebilir. Bir CAD uygulamasnn karmak izelgelerinden, elenceli
ocuk programlarnda kullanlan vektrel grafiklere kadar pek ok alanda temel ekiller yeterli
olmaktadr. Sz gelimi bir ehrin imar planlamasnda kullanlacak bir programda iki boyutlu olarak
dnldnde drtgenler, daireler, elipsler, poligonlar ve dz izgiler evlerin, yollarn, arsalarn,
parklarn ifade edilmesi iin yeterlidir. Senaryolar arttrlabilir ve daha geni alanlarda dnlebilir.
Ancak temel olarak gereken ekiller bellidir. WPF kendi bnyesinde iki boyutlu izimlerin
gerekletirilebilmesi amacyla aada belirtilen ekilleri(Shapes) sunmaktadr.

Ellips : Bu tip yardmyla ii dolu veya bo tam daire yada elipslerin izilmesi mmkndr.
Line : Dz izgilerin izilmesini salayan tiptir. Balang ve biti koordinatlar dz izginin
izilmesi iin yeterlidir.
Rectangle : Drt keli ekillerin izilmesinde kullanlan tiptir. i bo veya dolu dikdrtgen
yada kare gibi ekillerin izilebilmesini salar.
Polygon : N sayda keden oluan poligonlarn izilmesinde kullanlr. Bir gen olabilecei
gibi bir okgen de olabilir. Dier taraftan dzgn keli olmayan bir poligonda
oluturulabilir. Ayrca poligonlarn ii bo veya dolu olacak ekilde oluturulabilmesi de
mmkndr.
Polyline : Birbirlerine biti noktalarndan bal bir baka deyile u uca eklenmi dz
izgilerin(Line) izilmesini salayan tiptir.
Path : Birbirlerine son noktalarndan bal olan dz izgi veya eri (Curve) gibi toplu
ekillerin izidirilmesini salayan tiptir. Farkl ekillerin bir arada kullanlabilmesini salamak
iin geometri(Geometry) tiplerinden yararlanr.

WPF, XAML(eXtensible Application Markup Language) tabanl bir ortam sunduundan,


grafiksel ekillerin tasarm zamannda element bazl olarak gelitirilmeleri ve sonularnn grlmesi
mmkndr. GDI+ mimarisinde ayn durum dnldnde sonularn ancak alma
zamannda(run-time) elde edilebildii unutulmamaldr. Bu nedenle WPF bize byk avantaj
salamaktadr.

www.bsenyurt.com Page 849


Bu ksa bilgilerden sonra rneklerimizi gelitirerek ekilleri daha yakndan tanmaya alalabiliriz.
Her zamanki gibi rneklerimizi gelitirirken Visual Studio 2008 Beta 2srmnden yararlanyor
olacaz. Bu nedenle, final srmnde zellikle IDE bazl baz deiiklikler olma ihtimali olduunu
batan belirtelim. lk rneimizde Ellipstipinden yararlanyor olacaz. Bu amala Window
nesnemizin XAML ieriini aadaki gibi tasarladmz dnelim.

<Window x:Class="GrafiklerleCalismak.Elipsler"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Elipslerin
Kullanm" Height="300" Width="300">
<Grid>
<Ellipse Fill="DarkRed" Width="40" Height="150" Stroke="Coral" StrokeThickness="3"
/>
<Ellipse Fill="Red" Width="150" Height="40" Stroke="Black"
StrokeThickness="3" Opacity="0.75"/>
<Ellipse Width="40" Height="40" Fill="Gold" Stroke="Black" StrokeThickness="3"/>
<Ellipse Width="10" Height="10" Stroke="DarkBlue" StrokeThickness="2"
HorizontalAlignment="Left" Margin="64,56,0,0" VerticalAlignment="Top" />
<Ellipse Height="25" HorizontalAlignment="Right" Margin="0,56,64,0" Stroke="DarkBlue"
StrokeThickness="2" VerticalAlignment="Top" Width="25" />
<Ellipse Height="50" HorizontalAlignment="Right" Margin="0,0,64,56" Stroke="DarkBlue"
StrokeThickness="2" VerticalAlignment="Bottom" Width="50" />
</Grid>
</Window>

Bu rnekte alt adet elips izdirilmektedir. Ellips tipinin Fill nitelii(attribute) yardmyla dolgu
deseni belirtilebilir. Bunun dnda width ve height nitelikleri eit olduklar takdirde tam bir dairenin
izilmesi sz konusudur. Dier hallerde ise, yatay dorultuda veya dikey dorultuda uzayan bir
elips oluumu sz konusu olmaktadr. Kenar izgilerini renk ve kalnlk olarak belirlemek
amacyla Stroke ve StrokeTickness niteliklerine deer atamalar yaplmaktadr. Stroke nitelii
tahmin edilecei zere geerli bir fra(Brush) ile eletirilebilir. Buda izginin dolu bir renk dnda
desenli olabilecei hatta iinde resim barndrabilecei anlamna gelmektedir.

Stroke ve StrokeTickness nitelikleri dier ekillerde de ye almaktadr. Bu nedenle tm


ekillerin izgilerinin olabileceini syleyebiliriz.

Yukardaki XAML ieriini Visual Studio 2008 Beta 2 ortamndaki kts aadaki gibi olacaktr.

www.bsenyurt.com Page 850


ekillerin bu biimde yatay veya dikey dzlemlerde oluturulmas haricinde, asal olaraktanda
yerletirilmesi istenebilir. Bunu bir elips zerinde GDI+ ile gerekletirmek olduka zor ve
zahmetlidir. Oysaki WPF ierisinde yer alan Transform tipleri kullanlarak bu ilemler son derece
kolay bir ekilde gerekletirilebilir.

Transoform' dan kast, eklin asal olarak konumunun deitirilebilmesi, byklnn


ayarlanabilmesi, kendi ekseni zerinde veya farkl bir orjine gre dndrlebilmesi, eklin
x veya y dzlemleri zerinde yer deitirmesi yada eilip bklmesi gibi aksiyonlardr.

kinci rneimizde bu durum incelenmektedir. Yeni penceremizin XAML ieriinin aadaki gibi
olduunu dnelim.

<Window x:Class="GrafiklerleCalismak.ElipsTransform"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="ElipsTransform" Height="300" Width="300" Loaded="Window_Loaded">
<Grid>
<Ellipse Width="125" Height="40" Stroke="Red" StrokeThickness="2"/>
<Ellipse Width="40" Height="125" Stroke="Black" StrokeThickness="2"/>
<Ellipse Width="40" Height="125" Stroke="Red" StrokeThickness="2">
<Ellipse.LayoutTransform>
<RotateTransform Angle="45"/>
</Ellipse.LayoutTransform>
</Ellipse>
<Ellipse Width="40" Height="125" Stroke="Black" StrokeThickness="2">
<Ellipse.LayoutTransform>
<RotateTransform Angle="135"/>
</Ellipse.LayoutTransform>
</Ellipse>
</Grid>
</Window>

Burada dikkat edilmesi gereken en nemli nokta, Ellips.LayoutTransform elementinin ieriidir.


Bu elementin altnda yer alan RotateTransform elementi ierisinde Angle nitelii ile bir a deeri

www.bsenyurt.com Page 851


belirtilmektedir. Bu a deeri, eklin x,y eksenine gre farkl bir derecede dndrlmesini
salamaktadr. rnek XAML ieriinde 45 derece ve 135 derecelik alar ile dndrlm iki elips
yer almaktadr. Bu ieriin tasarm zamanndaki kts aadaki gibi olacaktr.

Atomu WPF ile daha kolay izebildiimizi syleyebiliriz. Bu tip dntrme(Transform) ilemleri
sadece RotateTransform ile snrl deildir. Yazmzn ilerleyen ksmlarnda dier Transform
modellerinede ksaca deinmeye alacaz. ok doal olarak rotasyonlarn programatik olarak
gerekletirilmesi gereken vakkalar olacaktr. Yukardaki atom izelgesininin benzerini kod tarafnda
oluturmak istersek, element ve niteliklerin karl olan uygun snf(class) ve
zellikleri(property) kullanmak yeterli olacaktr. nc rneimizde bu durum incelenmektedir.
Bu amala yeni penceremizin XAML ve kod ieriini aadaki gibi tasarladmz dnelim.

XAML ierii;

<Window x:Class="GrafiklerleCalismak.KodlaElipsTransform"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Kod
Yardmyla Elips Transform" Height="300" Width="300">
<Grid Name="grdEllips">
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;

www.bsenyurt.com Page 852


using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace GrafiklerleCalismak
{
public partial class KodlaElipsTransform : Window
{
private void ElipsCiz(Ellipse elps, int width, int height, int angle,Color color)
{
elps.Width = width;
elps.Height = height;
elps.Stroke = new SolidColorBrush(color);
elps.StrokeThickness = 2;
elps.LayoutTransform = new RotateTransform(angle);
grdEllips.Children.Add(elps);
}
private void Cizdir()
{
ElipsCiz(new Ellipse(), 125, 40, 270,Colors.Red);
ElipsCiz(new Ellipse(), 40, 125, 90,Colors.Gold);
ElipsCiz(new Ellipse(), 125, 40, 45, Colors.DarkBlue);
ElipsCiz(new Ellipse(), 125, 40, 135,Colors.Lavender);
}

public KodlaElipsTransform()
{
InitializeComponent();
Cizdir();
}
}
}

Bir katane elipsi farkl renk, izgi, izgi kalnl ve ada izdirmek istediimizden yardmc
olacak ElipsCiz isimli bir metod tasarlanmtr. Bu metod, parametre olarak gelen Ellips nesne
rneini alp, genilik(Width), ykseklik(Height), izgi rengi(Stroke), izgi
kalnl(StrokTickness) ve rotasyon iin gerekli a(Angle) deerlerini set etmektedir. Dikkat
edilecek olursa, rotasyon ilemi iin RotateTransform tipine ait bir nesne rneklenmekte ve yapc
metoda(Constructor) a deeri verilmektedir. Sonrasnda ise bu nesne rnei, Ellips nesne
rneinin LayoutTransform zelliine atanmaktadr. Sz konusu kod paras yrtldnde
alma zamannda(run-time) aadakine benzer bir ekran grtnts ile karlalr.

www.bsenyurt.com Page 853


Yine kod yardmyla elips izdirmeye rnek olmas asndan aadaki pencerede(Window) gz
nne alnabilir.

XAML ierii;

<Window x:Class="GrafiklerleCalismak.KodYardimiylaElips"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="KodYardimiylaElips" Height="300" Width="300">
<Grid>
<Grid Name="grdTahta" Margin="0,74,0,8" Background="Gold" />
<Button Height="23" HorizontalAlignment="Left"
Margin="10,20,0,0" Name="btnCiz" VerticalAlignment="Top"
Width="75" Click="btnCiz_Click">izdir</Button>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace GrafiklerleCalismak
{
public partial class KodYardimiylaElips : Window
{

www.bsenyurt.com Page 854


private void ElipsCiz()
{
grdTahta.Children.Clear();
Random rnd=new Random();
for (int i = 0; i < 3; i++)
{
Ellipse elps = new Ellipse();
elps.Width = rnd.Next(50, 100);
elps.Height = rnd.Next(50, 100);
elps.Stroke = new SolidColorBrush(Colors.Black);
elps.StrokeThickness = rnd.Next(1, 5);
grdTahta.Children.Add(elps);
}
}

public KodYardimiylaElips()
{
InitializeComponent();
}

private void btnCiz_Click(object sender, RoutedEventArgs e)


{
ElipsCiz();
}
}
}

Bu kez bir dmeye baslmas ile rastgele retilen deerlere gre elipslerin izdirilmesi
salanmaktadr. Bu amala 50 ile 100 arasnda rastgele genilik ve ykselik deerleri elde
edebilmek iin mehur Random snfna ait nesne rneinden ve Next metodundan
yararlanlmaktadr. ou zaman oygun programlamada ekilsel olarak baz oyun karakterlerinin
saha zerinde rastgele konumlarda kmas istenebilir. te bu noktada Random snfna ait
metodlar ve WPF ile gelen yeni ekil izme teknikleri iimizi olduka kolaylatrmaktadr.

Kod yardmyla gerekletirilen rneklerde dikkat edilmesi gereken noktalardan birisi, oluturulan
ekillerin mutlaka bir taycya eklenmi olmalardr. Sz gelimi yukardaki rneklerde Ellips nesne
rnekleri Grid bileenine alt element olarak, Children zelliinin Add metodundan yararlanlarak
eklenmektedir. Son pencereye(Window) ilikin olarak aadaki ekran grntsnde alma
zamannda(run-time) oluabilecek bir rnek kt yer almaktadr.

www.bsenyurt.com Page 855


Sradaki rneimizde poligonlarn nasl izilebileceini incelemeye alacaz. Poligonlar, ok sayda
keden oluabilen ve kapal olarak tasarlanabilen ekillerdir. Poligonlar sayesinde basit bir gen
izilebilecei gibi bir onaltgen' de izilebilir. Yada dzensiz bir kapal ekil oluturulabilir. Burada
nemli olan ke noktalarnn belirlenmesidir. Ke noktalarnn belirlenmesinde Point tipinden
yararlanlr. Point tipi x ve y koordinatlarn bnyesinde tamaktadr. Polygon tipi, ke
noktalarn Points isimli bir koleksiyonda tamaktadr. imdi aadaki XAML ieriini gz nne
alalm.

<Window x:Class="GrafiklerleCalismak.PolygonKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Polygon
Kullanm" Height="300" Width="403">
<Grid>
<Polygon Fill="Gold" FillRule="Nonzero" Stroke="Black" StrokeThickness="2">
<Polygon.Points>
<Point X="20" Y="20" />
<Point X="120" Y="20" />
<Point X="120" Y="120" />
<Point X="220" Y="120" />
<Point X="220" Y="220" />
</Polygon.Points>
</Polygon>
<Polygon Fill="LightSkyBlue" FillRule="Nonzero" Stroke="Black" StrokeThickness="2">
<Polygon.Points>
<Point X="20" Y="20"/>
<Point X="120" Y="20"/>
<Point X="120" Y="120"/>
<Point X="220" Y="120"/>
<Point X="220" Y="220"/>
</Polygon.Points>
<Polygon.LayoutTransform>
<RotateTransform Angle="-45"/>
</Polygon.LayoutTransform>
</Polygon>
</Grid>
</Window>

rnekte iki adet Polygon elementi tanmlanmtr. Bunlardan ikincisine -45 derecelik bir asal
dndrme ilemi uygulanmtr. Her iki Polygon nesne rneinin ke noktalar Polygon.Points alt
elementi(child element) ierisinde yer alan Point alt elementleri ile belirtilmektedir. Polygon
nesnelerinin kenar izgileri Stroke ve StrokTickness niteliklerine atanan deerler yardmyla set
edilmitir. Dier taraftan Polygon' larn dolgu rengi Fill zelliklerine atanan standart
fra(Brush) renkleri ile ayarlanmaktadr. Sz konusu XAML ieriinin Visual Studio 2008 Beta 2
ortamndaki tasarm zaman(design-time) kts ise aadaki gibi olacaktr.

www.bsenyurt.com Page 856


Bir poligon kod yardmylada oluturulabilir. Sradaki rneimizde bir genin kod yardmyla
oluturulmas ve dmeye baslaraktan onbeer derecelik artan alar ile dndrlmesi
rneklenmektedir. Bu amala yeni penceremize(Window) ait XAML ve kod ieriklerini aadaki gibi
tasarladmz dnelim.

XAML ierii;

<Window x:Class="GrafiklerleCalismak.KodYardimiylaPolygonKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Kod
Yardmyla Polygon" Height="300" Width="300">
<Grid Name="grdTahta">
<Button Height="23" HorizontalAlignment="Left" Margin="8,19,0,0" Name="button1"
VerticalAlignment="Top" Width="75" Click="button1_Click">evir</Button>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Timers;

namespace GrafiklerleCalismak
{

www.bsenyurt.com Page 857


public partial class KodYardimiylaPolygonKullanimi : Window
{
Polygon plgy;
int sayac = 1;

private void Cizdir()


{
plgy = new Polygon();
plgy.Points.Add(new Point(50, 50));
plgy.Points.Add(new Point(150, 50));
plgy.Points.Add(new Point(150, 150));
plgy.Stroke = new SolidColorBrush(Colors.LightSalmon);
plgy.StrokeThickness = 2;
grdTahta.Children.Add(plgy);
}

public KodYardimiylaPolygonKullanimi()
{
InitializeComponent();
Cizdir();
}

private void button1_Click(object sender, RoutedEventArgs e)


{
plgy.LayoutTransform = new RotateTransform(sayac*15);
sayac++;
}
}
}

Penceremizin yapc metodu(constructor) ierisinde Cizdir metodu ile bir Polygon nesne rnei
oluturulmakta ve Grid kontrolnn alt elementi olarak eklenmektedir. Polygon nesne rnei bir
geni temsil edeceinden Points koleksiyonunda sadece nokta(Point) eklemesi yaplmtr.
Dndrme ileminin gerekletirildii yer dmenin Clickolay(event) metodudur. Burada dikkat
edilecek olursa yine LayoutTransform zelliine bir deer atamas yaplmaktadr. Bu atama
srasnda yeni bir RotateTransform nesnesi rneklenmekte ve parametre olarak artan bir a
deer verilmektedir. Uygulama test edildiinde alma zamannda aadaki Flash animasyonunda
yer alan kt elde edilecektir. (Flash dosyasn grebilmek iin Flasy Player' n sisteminizde ykl
olmas gerekmektedir.)

www.bsenyurt.com Page 858


imdiki rneimizde dz izgileri nasl izdirebileceimizi incelemeye alacaz. Dz izgi
iin Line tipi kullanlmaktadr. Bir izgi iin belkide en nemli
zelliklerStroke, StrokeTickness, X1, X2, Y1 ve Y2' dir. X ve Y zellikleri yardmyla izginin
balang ve biti noktalar belirlenir. rnein aadaki XAML ieriini ele alalm.

<Window x:Class="GrafiklerleCalismak.LineKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Line
Kullanimi" Height="211" Width="237">
<Grid>
<Line Stroke="RosyBrown" StrokeThickness="2" X1="10" Y1="10" X2="50"
Y2="50"/>
<Line Stroke="Brown" StrokeThickness="3" X1="50" Y1="50" X2="100" Y2="50"/>
<Line Stroke="BurlyWood" StrokeThickness="4" X1="100" Y1="50" X2="50" Y2="140"/>
<Line Stroke="CadetBlue" StrokeThickness="5" X1="50" Y1="140" X2="180" Y2="50"/>
</Grid>
</Window>

Bu ieriin tasarm zamanndaki(design-time) kts aadaki gibi olacaktr.

www.bsenyurt.com Page 859


Dikkat edilecei zere farkl kalnlk, renk ve lokasyonlarda yer alan izgiler elde edilmektedir.
izgiler zellikle kod tarafndada zaman zaman ele alnrlar. Sz gelimi bir harita zerinden bir
ehirden bir ehire doru olabilecek hava yolu rotalarnn belirlenmesi amacyla izgilerden
yararlanlabilir. Bunu ok basit olarak sembolize etmek amacyla aadaki XAML ve kod ieriini
gz nne alabiliriz.

XAML ierii;

<Window x:Class="GrafiklerleCalismak.KodYardimiylaLineKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Kod
Yardmyla Line Kullanm" Height="249" Width="422" WindowStyle="SingleBorderWindow">
<Grid Name="grdTahta">
<Image Name="imgHarita" MouseDown="imgHarita_MouseDown"
MouseUp="imgHarita_MouseUp" Source="map_world_destination.gif" />
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace GrafiklerleCalismak
{
public partial class KodYardimiylaLineKullanimi : Window
{
Point basilanNokta;

public KodYardimiylaLineKullanimi()
{
InitializeComponent();
}

private void imgHarita_MouseDown(object sender, MouseButtonEventArgs e)


{
basilanNokta=e.GetPosition(grdTahta);
}

private void imgHarita_MouseUp(object sender, MouseButtonEventArgs e)


{
Line yol = new Line();
yol.Stroke = new SolidColorBrush(Colors.Red);
yol.StrokeThickness = 2;
yol.X1 = basilanNokta.X;

www.bsenyurt.com Page 860


yol.Y1 = basilanNokta.Y;
Point bitisNoktasi = e.GetPosition(grdTahta);
yol.X2 = bitisNoktasi.X;
yol.Y2 = bitisNoktasi.Y;
grdTahta.Children.Add(yol);
}
}
}

Bu rnekte haritay gstermesi iin bir Image kontrol kullanlmaktadr. Image


kontrolnn source zelliine atanan deer ile arka plan dnya haritas olarak gsterilmektedir.
Kullanclar alma zamannda mouse' un tuuna basp bir noktadan baka bir noktaya gittiklerinde
ve mouse' un tuunu braktklarnda Line nesne rnei oluturulmaktadr. Bunun iin Image
kontrol zerinde mouse tuuna baslma ve braklma anlarnn yakalanmas gerekir. Sz konusu
anlar aina olduumuz MouseDown ve MouseUp olay metodlarnda yakalanrlar. GDI+ ile ayn
ilemleri nasl yaptmz hatrlarsak eer, kontroln MouseDown olayna gelen parametre ile X ve
Y deerlerini ayr ayr aldmz grrz. Burada durum biraz daha farkldr. Nitekim MouseUp ve
MouseDown olay metodlarnda yer alan MouseButtonEventArgs parametresi, mouse tuuna
basldnda o noktadaki X ve Y koordinatlarn yeni bir Point tipi olarak geriye
dndrmektedir. GetPosition metodu X ve Y koordinatlar, zerinden alnmak istenen kontrolde
parametre olarak alr. rnekte bu parametreye Grid kontrolnn referans verilmitir. Dolaysyla
Grid kontrolndeki X ve Y deerleri elde edilebilmektedir.

Mouse zerinde baslan tu brakldnda ise izginin izilme ilemi


gerekletirilmektedir. Line nesne rneinin X1 ve Y1 deerleri tahmin edilecei
gibi, MouseDownierisinde yer alan GetPosition ile elde edilen basilanNokta deikeninden
gelmektedir. izginin son noktas ise bu kez MouseUp olay metodu
ierisindeki GetPosition ars ile alnmakta ve Line nesne rneinin X2 ve Y2 deerlerine
aktarlmaktadr. Son olarak oluturulan izgi, Grid bileenine alt element olarak eklenmektedir. Bu
ekleme ileminin bize getirdii nemli bir avantaj vardr. Yine GDI+ ile Windows programlama
yaptmz dnecek olursak, ayn senaryoda ekrana izgiler izdirmek
iin Graphics nesnesninin DrawLinemetodundan yararlanldn grrz. Ne varki bu metod hep
son izginin izilmesine ncekilerin ise kaybolmasna neden olmaktadr. Oysaki WPF mimarisinde
ekiller bir taycnn alt elementi olarak eklendiklerinden son izilen ekilden ncekiler ekrandan
kaybolmamaktadr. Bu durumu GDI+ ile Windows programlamada gereklemek iin WPF'tekine
benzer bir mantk ile hareket edilmekte ve ekranda duran izgilerin srekli hatrlanmas iin
koleksiyonalardan yararlanlmas gerekmektedir. Yukardaki kodun alma zamanndaki ekran
kts aadaki Flash animasyonunda olduu gibidir.(Flash dosyasn grebilmek iin Flasy Player'
n sisteminizde ykl olmas gerekmektedir.)

www.bsenyurt.com Page 861


Bu rnei daha da gelitirmeye almanz neririm. Olduka fazla eksii var. Sz gelimi, mouse
tuuna basp srklerken farkl renkte bir izginin kartlarak gidilen rotann gsterilmesi
salanabilir. Mouse brakldnda ise asl rengini alan rota ortaya kar. stelik rnek kodda sa
tua veya sol tu kontrol yaplmamtr. Belkide klavyeden tu kombinasyonlar katarak sadece
dz izgi deil erilerin izdirilmesinide salayabiliriz. Bu rnein gelitirilmesini siz deerli
okurlarma brakyorum.

Gelelim Path bileenine. Bu tip aslnda kendi ierisinde birden fazla dz izgi veya eriyi
barndrabilecek ekilde tasarlanmtr. Temelde ekiller birbirleriyle u uca eklenecen ekilde yeni
bir grafik oluturmaktadrlar. Dilerseniz rnek zerinden ilerleyerek konuyu daha iyi anlamaya
alalm. Bu amala aadaki gibi bir XAML ierii oluturduumuzu gz nne alalm.

<Window x:Class="GrafiklerleCalismak.PathKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="Path Kullanimi(Birbirlerine Bal Farkl ekiller)" Height="261" Width="321">
<Grid>
<Path Stroke="Black" StrokeThickness="2">
<Path.Data>
<PathGeometry>
<PathFigure>
<BezierSegment Point1="0,0" Point2="10,120" Point3="70,40"/>
<ArcSegment SweepDirection="Clockwise" Point="150,125" Size="50,50"
IsLargeArc="True" RotationAngle="60"/>
<LineSegment Point="240,40"/>
<QuadraticBezierSegment Point1="35,135" Point2="75,75"/>
<PolyLineSegment>
<PolyLineSegment.Points>
<Point X="10" Y="10"/>
<Point X="50" Y="75"/>
</PolyLineSegment.Points>
</PolyLineSegment>
<PolyBezierSegment>
<PolyBezierSegment.Points>
<Point X="100" Y="100"/>
<Point X="150" Y="150"/>
<Point X="75" Y="180"/>
</PolyBezierSegment.Points>
</PolyBezierSegment>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Grid>
</Window>

Path elementi ierisinde farkl ekillerin u uca eklenmesi iini geometri tipleri stlenmektedir. Bu
geometri tipleride kendi ilerinde segmentler halinde ekilleri barndrmaktadr. Kullanlabilecek
olan geometri tipleri aadaki gibidir.

www.bsenyurt.com Page 862


rnekte sz konusu geometri tiplerinden PathGeometry kullanlmaktadr. PathGeometry
elementinin altnda yer alan tm ekiller Segment anahtar kelimesi ile bitmektedir. Buna
gre,BezierSegment ile balayan ekiller dizisi
srasyla, ArcSegment, LineSegment, QuadraticBezierSegment, PolyLineSegment ve PolyB
ezierSegment ile devam eder. Tm bu alt elementleri farkl nitelikleri ile deiik izgilerin
oluturulmas salanmaktadr. BezierSegment elementinin nitekikleri sayesinde noktadan
bklm bir eri izimi yaplabilmektedir. ArcSegment elementinin nitelikleri ile, balang
koordiantlar, genilik ykseklik deerleri, eilme as ve saat yn yada saatin ters ynnde
izilecek yaylar oluturulabilmektedir. Burada PolyLineSegment' i altnda belirtilen noktalar u
uca bal dz izgilerin oluturulmasn salarken, PolyBezierSegment elementi altndaki
noktalarda, u uca eklenmi erilerin oluturulmasn salamaktadr. rnein tasarm zamanndaki
kts aadaki gibi olacaktr.

Dikkat edilecek olursa, tm izgiler ister eri ister dz olsunlar, u uca eklenerekten birletirilmitir.
Bu nedenle Path tipini rnein harita gibi arka planlarda yollarn birletirilmesi amacyla
kullanabiliriz.

Bu yazmzda son olarak basit anlamda dntrme(Transform) ilemlerine bakyor olacaz.


Transform denilince aklmza gelmesi gerekenler bir eklin yn, byklk, dzlemsel koordinat gibi
deerlerinin deitirilmesidir. Bu sayede bir ekli herhangibir ada dndrebilir, ebatlarn
ayarlayabilir yada herhangibir dzlem zerinde teleyebiliriz. Transform ilemlerinde be farkl tip
rol oynamaktadr. Bu tipler aadaki gibidir.

RotateTransform : eklin belirtilen bir ada, kendi ekseninde yada belirtilen orijine gre
farkl bir eksende dndrlmesini salamak iin kullanlr. Sz gelimi bir eklin farkl
alardan gsterilmesinin salanmasnda nemli rol oynamaktadr.
ScaleTransform : eklin ebatlarnn eit oranda yada farkl oranlarda arttrlmas yada
azaltlmasnda kullanlr. rnein Zoom ilemlerinde bu tip ok faydal olacaktr.
SkewTransform : eklin bklmesini yada eilmesini salamak amacyla kullanlan tiptir.

www.bsenyurt.com Page 863


TranslateTransform : eklin x veya y dzlemleri zerinde farkl noktalara telenmesi
amacyla kullanlan tiptir.
MatrixTransform : Resim ilemede nemli bir yere sahip olan matris algoritmalarnn iki
boyutlu ekiller zerinde de uygulanabilmesini salayan tiptir. Dier Transform tipleri ile
gerekletirilmesi zor olan dntrmelerde kullanlmaktadr. Bu tipi ilerleyen yazlarmzda
ele almaya alacaz.

imdi basit bir rnek ile RotateTransform ve ScaleTransform tiplerinin nasl kullanlabileceini
incelemeye alalm. Bu amala XAML ve kod ieriklerini aadaki gibi gelitirdiimizi dnelim.

XAML ierii;

<Window x:Class="GrafiklerleCalismak.TransformKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Transform
Kullanm" Height="292" Width="330">
<Grid Name="grdTahta" Width="309" Height="253">
<Rectangle Fill="Gold" Stroke="Black" StrokeThickness="2" Name="dortgen"
Width="100" Height="40" />
<Slider Minimum="1"
Maximum="5" ValueChanged="sldScale_ValueChanged" Height="21"
Margin="110,14,89,0" Name="sldScale" VerticalAlignment="Top" />
<Label Height="23" HorizontalAlignment="Left" Margin="0,12,0,0" Name="label1"
VerticalAlignment="Top" Width="92">Scale Transform</Label>
<Slider Height="21" Margin="110,49,89,0" Maximum="360" Minimum="0"
Name="sldRotate" ValueChanged="sldRotate_ValueChanged" VerticalAlignment="Top" />
<Label Height="23" HorizontalAlignment="Left" Margin="0,47,0,0" Name="label2"
VerticalAlignment="Top" Width="92">Rotate Transform</Label>
</Grid>
</Window>

Kod ierii;

using System;
using System.Collections.Generic;

www.bsenyurt.com Page 864


using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace GrafiklerleCalismak
{
public partial class TransformKullanimi : Window
{
public TransformKullanimi()
{
InitializeComponent();
}

private void sldScale_ValueChanged(object sender,


RoutedPropertyChangedEventArgs<double> e)
{
TransformYap();
}

private void sldRotate_ValueChanged(object sender,


RoutedPropertyChangedEventArgs<double> e)
{
TransformYap();
}

private void TransformYap()


{
if (sldRotate != null
&& sldScale != null)
{
TransformGroup grp = new TransformGroup();
grp.Children.Add(new ScaleTransform(sldScale.Value, sldScale.Value));
grp.Children.Add(new RotateTransform(sldRotate.Value));
dortgen.LayoutTransform = grp;
}
}
}
}

Kullanc Slider kontrollerindeki ubuu hareket ettirdike ekran zerindeki drtgenin kendi ekseni
zerinde dnmesi veya byklnn deimesi amalanmaktadr. Bu, ayn ekle birden fazla
dntrme ileminin uygulanmasn gerektirmektedir. Bir baka deyile Rectangle nesne
rneinin LayoutTransform zelliine hem ScaleTransformhemde RotateTransform nesne
rneklerinin atanmas gerekmektedir. Bunun iin TransformGroup ad verilen nesne rneklerinden
yararlanlr. TransformGroup tipi, sahip olduu Childrenzellii ile sunduu koleksiyon ierisinde
farkl Transform tiplerini tayabilmektedir. Dolaysyla TransformYap metodu ierisinde bu ekilde
bir kodlama yaplmaktadr. Uygulamann alma zamanndaki grnts aadaki Flash
animasyonunda olduu gibidir.(Flash dosyasn grebilmek iin Flasy Player' n sisteminizde ykl
olmas gerekmektedir. Dosya boyutu 220 Kb olduundan yklenmesi zaman alabilir.)

www.bsenyurt.com Page 865


Bylece geldik bir makalemizin daha sonuna. Bu makalemizde WPF(Windows Presentation
Foundation) uygulamalarnda iki boyutlu grafik(2D Graphics) ilemlerinde kullanlabilecek ekilleri
ele almaya altk. Son olarak basit bir transform ileminin rnek bir drtgen zerinde nasl
gerekletirileceine deindik. Buradaki bilgilerden yola karak ok daha kolay grafik ilemleri
gerekletirebileceimizi ve eski Windows programlamadaki GDI+ ile zorlandmz vakkalar daha
etkin bir biimde yapabileceimizi grm bulunuyoruz. lerleyen makalelerimizde WPF ile ilikili
baka konularada deiniyor olacaz.Tekrardan grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WPF - Grafik lemlerinde Fralarn(Brushes)


Kullanm ( 11.09.2007 ) - WPF
Deerli Okurlarm Merhabalar,

Windows uygulamalarnda zellikle .Net tarafnda vektrel grafik ilemleri iin ounlukla GDI+ alt
yaps(infrastructure) kullanlmaktadr. Ancak Windows Presentation Foundation(WPF)
mimarisinde ne kan zelliklerden biriside grafik anlamdaki yeteneklerin son derece gelitirilmi
olmasdr. Kiisel grm grafik ynndeki zelliklerin gelimesi dnda bu tekniklerin element
baznda uygulanabiliyor olmas son derece nemli ve yerindedir. Yani XAML tarafnda grafikler ile
daha kolay alabilme imkannn gelmi olmas nemlidir. Bu yazmz ile birlikte WPF ierisindeki
grafiksel eleri incelemeye balyor olacaz. Grafik konusu olduka geni olduundan bir iki yaz
dizisi halinde incelememiz ok daha yerinde olacaktr. Hepimizin GDI+ alt yapsndan aina
olduumuz teknikler aslnda WPF iinde geerlidir. Ancak nemli olan temel baz kavramlar vardr.
Bu kavramlar grafik ilemlerinde nemli bir yere sahiptir. Sz konusu kavramlar ve aklamalar
aada maddeler halinde sunulmaktadr.

Brushes: Bir alann farkl biimlerde boyanabilmesi iin fralara ihtiya vardr. Burada tek
renk tonlamas(Solid), gradyan tonlamalar(Gradients), deiik tipteki desenler(Patterns)
veya resimler(Image) bir eklin boyanmasnda kullanlabilir. Hatta var olan Windows
bileenlerini, grsel materyalleri(rnein video dosyalarn) ekillerin ierisini doldurmak

www.bsenyurt.com Page 866


amacyla kullanabiliriz. Windows Presentation Foundation iersinde bu anlamda tasarlanm
pek ok hazr Brush tipi yer
almaktadr. LinearGradientBrush yadaRadialGradientBrush tipleri bunlara rnek olarak
verilebilir.
Shapes: Grafik uygulamalarnn olmassa olmaz paralarndan birisi de ekillerdir. Kare,
dikdrtgen, daire, elips, yay, izgi vb... bu anlamda gz nne alnabilir. WPF, iki boyutlu
(2D) ekilleri dorudan destekleyen tipler iermektedir.
Transformations: Grafik elerinin ekran zerinde dndrlmelerinin(Rotation),
ebatlarnn ayarlanmasnn(Scaling) salanmas ile ilgili konular kapsar. Sz gelimi bir
karenin kendi ekseninde dnmesi(Rotation) ve byklnn ayarlanmas bu konuya rnek
olarak verilebilir.
Imaging: Bitmap resimlerin farkl formatlara dntrlmesi veya resimler zerinde bilinen
baz efektlerin uygulanmas gibi konular kapsar. Sz gelimi bir resmin daha bulank
gsterilmesinin salanmas bu konuya rnek olarak verilebilir.
Animations: Grafik nesneleri zerinde baz animasyonlarn yaplabilmesi iin gereken
teknikleri ieren kavramdr.

zleyen rneklerimizi yine Visual Studio 2008 Beta 2 srmnde tasarladmz batan
belirtelim. Bu nedenle final srmnde deien baz kullanm kolaylklar olabilir. Elbette artk
relase edilmi olan WPF iinde IDE bazl bir deiiklik olmayacan syleyebiliriz. Dilerseniz basit
bir rnek ile balayalm. lk olarak aadaXAML(eXtensible Application Markup
Language) ierii belirlenen bir pencere(Window) gelitirelim.

Merhaba Fralar;

<Window x:Class="GrafiklerleCalismak.MerhabaFircalar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White" Title="Fill,
Transparant Fill, SolidFillBrush Kullanm" Height="300" Width="300">
<Grid>
<Rectangle Fill="Goldenrod">
<Rectangle.Height>45</Rectangle.Height>
<Rectangle.Width>45</Rectangle.Width>
</Rectangle>
<Rectangle Fill="#99FFCC66" Width="40" HorizontalAlignment="Left" Margin="94,81,0,81"
/>
<Ellipse Margin="78,130,54,42">
<Ellipse.Fill>
<SolidColorBrush Color="BlueViolet" Opacity="0.6"/>
</Ellipse.Fill>
</Ellipse>
<Rectangle HorizontalAlignment="Right" Width="82" Margin="0,58,54,0" Height="45"
VerticalAlignment="Top">
<Rectangle.Fill>
<SolidColorBrush>
<SolidColorBrush.Color>
<Color A="90" R ="50" G="50" B="150"/>
</SolidColorBrush.Color>
</SolidColorBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Window>

Bu rnein tasarm zamanndaki(Design Time) ktsda aadaki gibi olacaktr.

www.bsenyurt.com Page 867


Bu rnekte drt farkl ekil yer almaktadr. lk drtgenimiz Fill niteliinde bilinen bir renk
tanmlamas ile oluturulmu Rectangle nesne rneidir. Bu drtgen aslndaSolidColorBrush iin
en temel rnektir. SolidColorBrush, bir eklin iini boluk brakmayacak ekilde doldurmak zere
tasarlanm bir tiptir. rnekte bu ak bir ekilde belirtilmesede Fill niteliine atanan renk deeri bir
SolidColorBrush oluumunu salamtr.

<Rectangle Fill="Goldenrod">

kinci drtgende ise Fill niteliine hexadecimal olarak deer atamas aadaki gibi
gerekletirilmitir.

<Rectangle Fill="#99FFCC66" Width="40" HorizontalAlignment="Left" Margin="94,81,0,81" />

Yanlz burada dikkat edilmesi gereken bir nokta vardr. Bu da ilk iki hanededeki deerlerdir. Bu
deerler 00 ile FF arasnda olabilien alfa (Alpha) deeridir. Bir baka deyile eklin
saydamlnn(Transparancy) belirlenmesi iin kullanlr. 00 olmas tam saydamlk anlamna gelir.

nc drtgenin izimi srasnda SolidColorBrush elementi ak bir ekilde aadaki gibi


kullanlmtr.

<Rectangle.Fill>
<SolidColorBrush>
<SolidColorBrush.Color>
<Color A="90" R ="50" G="50" B="150"/>

Bu kullanma gre dolgu renginin belirlenmesinde RedGreenBlue kombinasyonuna ve saydamlk


iinde Alpha deerine baklmaktadr. Bu deerler Color elementi ierisinde birer nitelik(attribute)
yardmyla belirlenmektedir. SolidColorBrush elementinin kullanlmas halinde, transformasyon
ilemlerinin gereekletirilmesi dahada kolay olmaktadr. Bu sebepten transformasyon ilemlerinin
sz konusu olduu durumlarda SolidColorBrush elementinin ak bir ekilde rnekteki gibi
kullanlmas nerilmektedir. Son olarak ilk rneimizde drtgenden farkl olarak bir elips(Ellipse)
ekli izdirilmitir.

www.bsenyurt.com Page 868


<Ellipse.Fill>
<SolidColorBrush Color="BlueViolet" Opacity="0.6"/>

Elipsin dolgu rengini belirlemek iinse Ellipse.Fill elementi altnda SolidColorBrush isimli alt
element(Child Element) kullanlmtr. Color niteliine atanan deer ile fra rengi
veOpacity niteliine atanan deer ilede effaflk deeri bildirimitir. Bu rnekteki ilemlerin ou
kod tarafnda da gerekletirilebilir. Sz gelimi elipsin izimi ve doldurulmasn aadaki kodlar
yardmyla salayabiliriz.

public partial class MerhabaFircalarKodIle : Window


{
private void SekilleriCiz()
{
Ellipse elips = new Ellipse();
elips.Margin = new Thickness(78, 130, 54, 42);
SolidColorBrush firca = new SolidColorBrush(Colors.BlueViolet);
firca.Opacity = 0.6;
elips.Fill = firca;
grdAlan.Children.Add(elips);
}
public MerhabaFircalarKodIle()
{
InitializeComponent();
SekilleriCiz();
}
}

Elbette bu kez sonular tasarm zamannda(Design Time) deil, alma zamannda(Run


Time) grlebilecektir. Aadaki ekran grntsnde bu durum gsterilmektedir. Buradan u
sonuca bir kez daha varabiliriz; XAML deki element ve niteliklerin karlklar kod tarafnda snf ve
zelliklere denk gelmektedir.

Gradyan Dolgular (Gradient Brush);

www.bsenyurt.com Page 869


lk rnekte basit olarak SolidColorBrush kullanmna deinmeye altk. Dolgu ilemlerinde
popler olan kullanmlardan biriside Gradyan efektlerin verilmesidir. Bu renkler arasnda yumuak
geilerin olumasna ve bu sayede daha gzel dolgularn grnmesine neden olmaktadr. Byle bir
amac gerekletirmek iin WPF ierisinde eitli tipler yer almaktadr. Sradaki rneimizde bu
durumu incelemeye alacaz. Bu amala aadaki XAML ieriini gz nne alabiliriz.

<Window x:Class="GrafiklerleCalismak.LinearGradientFirca"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="LinearGradientBrush ve RadialGradientBrush Kullanm" Height="304" Width="362">
<Grid>
<Rectangle Margin="16,14,21,0" Height="69" VerticalAlignment="Top">
<Rectangle.Fill>
<LinearGradientBrush>
<GradientStop Color="Blue" Offset="0"/>
<GradientStop Color="Red" Offset="0.25"/>
<GradientStop Color="White" Offset="0.5"/>
<GradientStop Color="Black" Offset="0.75"/>
<GradientStop Color="Gold" Offset="1"/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<Rectangle Margin="96,101,101,18">
<Rectangle.Fill>
<RadialGradientBrush GradientOrigin="0.1,0.75">
<RadialGradientBrush.GradientStops>
<GradientStop Color="Gold" Offset="0"/>
<GradientStop Color="Black" Offset="0.50"/>
<GradientStop Color="DarkSlateGray" Offset="1"/>
</RadialGradientBrush.GradientStops>
</RadialGradientBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Window>

Bu pencerenin tasarm zamanndaki(Design Time) kts aadaki gibi olacaktr.

www.bsenyurt.com Page 870


Burada st taraftaki drtgen ierii LienarGradientBrush ile, alttaki drtgen
ise RadialGradientBrush fralar ile doldurulmutur. Her iki frannda ortak noktalarna
bakldnda farkl renkler ve gei noktalarnn belirlenmesi amacyla GraidentStop elementlerine
bavurulduu grlmektedir. Bu elementler renkleri ve bunlarn gei yerlerinin neresi olduunu
belirtmek amacyla kullanlmaktadr. GradientStop tipine ait nesne
rnekleri, GradientStopCollections ad verilen zel bir koleksiyonda tutulmaktadr. Dier taraftan
ikinci elilde odak noktas dikkat edilecei zere tam merkez deildir. Bunun belirlenmesi
iin RadialGradientBrush elementinin GradientOrigin niteliinden(attribute) yararlanlmaktadr.

Kod Tarafndan Fra(Shape) Kullanm;

u ana kadar gelitirilen rneklerde ekillerin oluturulmas ve ilerinin doldurulmas gibi ilemlerde
ounlukla XAML elementlerinden ve niteliklerinden yararlanlmtr. Bu gelitirici asndan tasarm
zaman(Design Time) iin byk bir esnekliktir. Nitekim ilemlerin sonular annda Visual Studio
arabirimi zerinde grlebilmektedir. Dier taraftan baz durumlarda alma zamannda dinamik
olarak sz konusu ekillerin izilmesi ve doldurulmas istenebilir. rnein .Net ile yazlm grafik
uygulamalarnda bu mutlaka olmas gereken bir zelliktir. Sradaki rnekte basit olarak bir
drtgenin LinearGradientBrush snf ile kod tarafndaki tiplerden ve yelerden yararlanlarak
nasl doldurulaca rneklenmektedir. Bu amala yeni bir Window arkasnda aadaki kodlar
kullanlmtr.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;

namespace GrafiklerleCalismak

www.bsenyurt.com Page 871


{
public partial class KodYardimiylaGradient : Window
{
private void LinearGradientDortgenCiz()
{
// LinearGradientBrush nesne rnei oluturulur.
LinearGradientBrush fircam = new LinearGradientBrush();

// C# 3.0 ile gelen Object Initializers kullanlmtr.


GradientStopCollection noktalar = new GradientStopCollection() { new
GradientStop(Colors.WhiteSmoke, 0), new GradientStop(Colors.RosyBrown, 0.25), new
GradientStop(Colors.Salmon, 0.50), new GradientStop(Colors.Silver, 0.75), new
GradientStop(Colors.Gold, 0.1) };
// Gradient Stop noktalar set edilir
fircam.GradientStops = noktalar;
fircam.Opacity = 0.80; // Saydamlk deeri ayarlanr

fircam.Freeze(); //Nesnenin deitirilemeyeceini belirtir. Bu metod ounlukla


performans asndan kullanlr.

// Drtgen nesnesi rneklenir.


Rectangle dortgen = new Rectangle();
// Drtgenin genilik ve ykseklik deerleri belirlenir.
dortgen.Width = 200;
dortgen.Height = 50;
dortgen.Margin = new Thickness(0, 0, 0, 0); // Sa, sol kenar uzaklklar belirlenir. Buna
gre ekil formun tam ortasnda olacaktr.
dortgen.Fill = fircam; // Dortgenin iinin fircam isimli LinearGradientBrush snfnn
deerleri ile doldurulaca belirlenir.

grdAlan.Children.Add(dortgen); // Dortgen nesnesi Grid alan ierisine eklenir.


}
public KodYardimiylaGradient()
{
InitializeComponent();
LinearGradientDortgenCiz();
}
}
}

Dikkat edilecek olursa XAML elementlerinin tip karlklar kullanlarak istenen sonular elde
edilebilmektedir. LinearGradientBursh ile rneklenen frann renk tonlarn ve gei noktalarn
belirlemek iin GradientStopCollection koleksiyonuna ait bir nesne rneklenmitir.

Bu rnekleme ilemi srasnda C# 3.0 ile birlikte gelen nesne balatclarndan(Object


Initializers) yararlanlmtr. Bylece koleksiyona ait nesneyi rneklediimiz satrda
ierisinde olmasn istediimiz GradientStop nesne rnekleride belirtilebilmitir. Nesne
balatclar sadece koleksiyonlarda deil tiplerin rneklenmesi ilemlerinde de
kullanlabilmektedir.

lerleyen satrlarda frann saydamlk deeri Opacity zellii ile belirtilmektedir. Freeze metodu
zel olarak performans arttrmak adna kullanlmas MSDN dkmanlarnda tavsiye edilen bir
metoddur. Freeze metodu ile ilgili olarak dikkat edilmesi gereken noktalardan biriside bu metod
arsndan sonra fra zelliklerinin deitirilemediidir. Dortgen nesnesi Rectangle snf
yardmyla oluturulmaktadr. Dortgenin iinin hangi fra ile doldurulaca ise Fill zelliine atanan

www.bsenyurt.com Page 872


deer ile belirlenir. Son olarak, drtgenin Grid ierisinde gsterilmesini salamak
iin Children zelliine Add metodu ile Rectangle nesne rneinin eklenmesi salanmtr. Bu
ilemlere gre sz konusu pencerenin alma zamanndaki kts aadaki gibidir.

Resimleri Fralar ile Kullanmak;

ok doal olarak bir eklin iinin resimler ile doldurulmas ve farkl bir taban deseni oluturulmas
istenebilir. Bunun iin WPF ierisinde ImageBrush tipi kullanlmaktadr.
Aadaki XAML ieriinde, drtgenin iinin rnek bir resim ile doldurulmas salanmaktadr.

<Window x:Class="GrafiklerleCalismak.ImageBrushKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="ImageBrushKullanimi" Height="300" Width="300">
<Grid>
<Rectangle Margin="52,48,54,55">
<Rectangle.Fill>
<ImageBrush ImageSource="ArkaPlan.png" TileMode="Tile"
Viewport="0,0,0.1,0.1"/>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Window>

Bu rnein tasarm zamanndaki(Design Time) kts aadaki gibi olacaktr. rnekte ArkaPlan.png
isimli bir resim kullanlmtr.

www.bsenyurt.com Page 873


ImageBrush elementinin dikkate deer nitelikleri ImageSource, TileMode ve ViewPort' dur.
ImageSource ile tahmin edilecei gibi ierik resmi belirlenmektedir. TileMode ile resmin ekil
ierisine nasl denecei belirtilir. ViewPort niteliine atanan drt saysal deer bulunmaktadr.
Bunlardan ilk ikisi konumu, son ikiside ekil ierisinde ka adet resim gsterileceini belirtir.
Yukardaki rnek gz nne alndnda 0.1,0.1 deerlerinin verilmesi ile 10X10 resmin ekil
ierisinde yer ald grlmektedir. TileMode deerlerinin farkl ekillerde ayarlanmasnn sonular
aadakine benzerdir.

TileMode Deerine Gre Dolgu eitleri

FlipX FlipY

FlipXY None

www.bsenyurt.com Page 874


WPF Bileenlerini Fra ile Kullanmak;

Var olan resimleri ekillerin ierisini boyamak amacyla kullanabileceimiz gibi, WPF deki pek ok
bileenide dolgu efekti olarak ele alabiliriz. Bunun iin VisualBrush tipinin kullanlmas yeterlidir.
Sz gelimi bir drtgenin ieriinin Button nesneleri ile doldurulmasn istediimizi dnelim. Bunu
gerekletirmek iin aadaki XAML kts gz nne alnabilir.

<Window x:Class="GrafiklerleCalismak.VisualBrushKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="VisualBrush Kullanimi" Height="300" Width="300">
<Grid>
<Rectangle Margin="40,50,42,50">
<Rectangle.Fill>
<VisualBrush TileMode="Tile" Viewport="0,0,0.2,0.2">
<VisualBrush.Visual>
<Grid>
<Button Content="Selam!"/>
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</Rectangle.Fill>
</Rectangle>
</Grid>
</Window>

Bu sayfann tasarm zamanndaki(Design Time) kts aadaki gibidir.

WPF kontrollerinin dolgu efekti olarak kullanlabilmesini


salayan, VisualBrush elementinin VisualBrush.Visual alt elementidir. Bu elementin ierisinde
bilinen WPF tayclar(Containers) kullanlabilir. rnekte bir Grid kontrol ve ierisidende tek bir
Button nesnesi kullanlmtr. Tabi ViewPort niteliinde belirtilen deerlere gre Button
kontrolnn drtgen ierisindeki yerleim says deiecektir. Aynen ImageBrush tipinde olduu
gibi TileMode niteliinin deerine gre yerleimler aadaki gibi farkl biimlerde olabilir.

www.bsenyurt.com Page 875


TileMode Deerine Gre Dolgu eitleri

FlipX FlipY

FlipXY None

Sistem Renklerinin Fralar ile Kullanm;

Windows iletim sisteminde kullanlan pek ok grnm vardr. rnein masast rengi, aktif olan
pencerelerin bar ksmlarndaki renkler ve aralarndaki geiler vb. ou zaman Windows
uygulamas ierisindeki baz dolgularn, sistemdeki hazr dolgulardan alnmas istenebilir. Byle bir
durumda kullanc, makinesindeki sistem renklerini deitirdiinde Windows uygulamas ierisindeki
ekillerde buna uygun bir biimde gncellenebilecektir. Bunu gerekletirmek
iin SystemColors tipi kullanlr. Aadaki XAML ieriinde bu durum irdelenmektedir.

<Window x:Class="GrafiklerleCalismak.SystemColorsKullanimi"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Background="White"
Title="SystemColors Kullanimi" Height="300" Width="300">
<Grid>
<Rectangle Fill="{DynamicResource {x:Static
SystemColors.WindowBrushKey}}" Margin="26,31,106,0" Height="86"
VerticalAlignment="Top" />
</Grid>
</Window>

Burada Fill niteliine zel bir atama gerekletirilmitir. DynamicResource ifadesini takip eden
ksmda SystemColors.WindowBrushKey ile dolgu rengi, Windows iletim sistemi zerinden
alnmaktadr. Buna gre rnein benim sistemimdeki kt aadaki gibidir.

www.bsenyurt.com Page 876


SystemColors tipi System.Window isim alan(Namespace) altnda yer almakta olan static bir
snftr ve aadaki gibi pek ok hazr deere sahiptir.

Hatrlanaca gibi static snflar(class) rneklenemeyen, tretilemeyen, sadece static


yeler ieren bir tiptir. Normal snflara gre daha hzl altklarndan duruma gre
performans amacyla tercih edilebilirler.

Burada dikkat edilmesi gereken noktalardan birisi tm bu deerlerin Fill ilemlerinde


kullanlmaddr. Bir baka deyile Fill zellii, buradaki static yelerden her birini kabul etmez.
zellikle sistem tarafnda set edilmi olan ve Key anahtar kelimesi ile bitenleri tercih etmek
gerekmektedir.

Drawing ile Fra Kullanm;

Dilersek bir eklin iini izerekte doldurabiliriz. Sz gelimi videolar, metinleri, baka ekilleri izim
amacyla dolgularda ele alabiliriz. Bu olduka geni bir konu olmasna ramen bir rnek yapmadan
gemenin doru olmayaca kansndaym. Bu tip bir ilemde DrawingBrush tipi esas olan

www.bsenyurt.com Page 877


noktadr. DrawingBrush tipi ile oluturulan fralar sz konusu
alanlar, GemoetryDrawing, ImageDrawing, GlpyhRunDrawing, VideoDrawing, DrawingGr
oup gibi tipler yardmyla farkl ekillerde doldurabilirler. Sz gelimi bir metnin ierisinde geometrik
ekiller gsterilmesini(GeometryDrawing ile), yada bir elips ierisinde bir video
oynatlmasn(VideoDrawing ile) salayabiliriz. Aadaki rnek kod parasnda, bir elips
ierisindeintro.wmv isimli videonun oynatlmasn salamak amacyla yazlm ifadeler yer
almaktadr.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Media.Animation;

namespace GrafiklerleCalismak
{
public partial class DrawingBrushKullanimi : Window
{
private void VideoCiz()
{
// Elips oluturulur
Ellipse elips = new Ellipse();
// Ykseklik ve genilik belirtilir.
elips.Width = 250;
elips.Height = 75;

// Video dosyasn oynatacak bir MediaPlayer nesnesi rneklenir.


MediaPlayer oynatici = new MediaPlayer();
// intro.wmv dosyasnn almas salanr.
oynatici.Open(new Uri("..\\..\\intro.wmv",UriKind.Relative));

// DrawingBrush' n kullanaca VideoDrawing nesnesi rneklenir.


VideoDrawing vd=new VideoDrawing();
// Oynatc set edilir.
vd.Player=oynatici;
// Videonun oynayaca alan belirlenir. rnekte bu alan elips' inki ile ayn tutulmutur.
vd.Rect = new Rect(0, 0, 250, 75);

// Fra oluturulur ve Drawing zelliine VideoDrawing nesne rnei aktarlr


DrawingBrush fircam = new DrawingBrush();
fircam.Drawing = vd;

// Elipsin iin dolduracak nesne rnei belirlenir.


elips.Fill = fircam;

// Elips Grid ierisine eklenir


grdAlan.Children.Add(elips);

www.bsenyurt.com Page 878


// Video oynatlr.
oynatici.Play();
}

public DrawingBrushKullanimi()
{
InitializeComponent();
}

private void button1_Click(object sender, RoutedEventArgs e)


{
try
{
VideoCiz();
}
catch (Exception excp)
{
MessageBox.Show(excp.Message);
}
}
}
}

Uygulama test edildiinde aadaki Flash videosunda grld gibi dmeye basldnda ilgili
videonun elips ierisinde oynad grlr. (Flash animasyonunun oynatlabilmesi iin sisteminizde
Flash Player' n ykl olmas gerekebilir.)

Video efektlerini ilerleyen yazlarmzda incelemeye devam ediyor olacaz. imdilik yazmzn
sonuna geldik. Bu yazmzda temel olarak grafik ilemlerinde ekillerin fralar(Brushes) yardmyla
nasl doldurulabileceinin belirlenmesinde kullanlan tipleri, arlkl olarak XAML ierisinde ele
almaya altk. Bir sonraki makalemizde grafik ilemlerinde kullanlabilecek
ekilleri(Shapes) incelemeye alyor olacaz. Tekrardan grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama iin Tklayn

www.bsenyurt.com Page 879


Burak Selim ENYURT
selim@bsenyurt.com

WPF - Veriye Balanmak (Data Binding) (


03.09.2007 ) - WPF
Deerli Okurlarm Merhabalar,

Bu gn gelitirdiimiz programlarn ou veri(Data) ile ilikili kaynaklar kullanmaktadr. zellikle


byk lekli pek ok proje tipi ierisinde mutlaka verilerin kullanlmas sz konusudur. Veriler kimi
zaman mteri bilgilerini, kimiz zaman rn bilgilerini, kimi zamanda uygulamaya ait konfigurasyon
bilgilerini vb... tutar. Verilerin ou zaman veritaban sistemlerinde, fiziki dosyalarda veya program
ierisindeki zel tiplerde saklandklarn grrz. ok doal olarak bu veri depolar ierisinde tutulan
bilgilerin son kullanclara gsterilmeside sz konusudur. Bu noktada, gelitirilen uygulamaya
baklmakszn pek ok veri balama teknii olduunu syleyebiliriz. Ama bu yazmzda
zellike Windows Presentation Foundation(WPF) uygulamalarnda veri balama ilemlerinin
nasl yaplabileceini basit rneklerden hareket ederek incelemeye alyor olacaz. Windows
tabanl programlamada zellikle Visual Studio 2005 ile birlikte veri balama ilemlerinin dahada
geniletildiine ahit olduk. Data Source mens bunun en gzel rneklerinden birisidir. Hatta
XML ve nesne(object) kaynaklarna daha kolay balanlmasn
salayan XmlDataSource ve ObjectDataSource gibi kontrolleri grdk. Aslnda veri
balama(Data Binding) denildii zaman akla gelmesi gereken; "bir tipin herhangibir yesinin
baka bir tipin sahip olduu veriye otomatik olarak erimesidir" diyebiliriz. Form zerindeki bir
metin kutusunun(TextBox) text zelliinin, veritabanndaki bir alana balanmas buna
verilebilecek basit bir rnektir.

Ne varki WPF mimarisinde durum biraz farkl bir hal almtr. zellikle .Net Framework 3.0
ve LINQ(Language Integrated Query) gibi yenilikler, verilerin ileni ve ele aln ekillerinide
deitirmektedir. WPF' e ksaca bakldnda ilk fark edilen noktalardan birisi .Net Framework
2.0 formlarndaki kadar ok kontroln Toolbox sekmesine gelmediidir. Dahas, Visual Studio
2005 uygulama gelitirme ortamndan hatrladmz pek ok veri kontrol burada yer
almamaktadr. stelik bizleri bekleyen saysz yeni kontrol bulunmaktadr. Peki bir WPF
uygulamasnda, pencere(Window) zerindeki kontrollerin eitli zelliklerinin verilere olan
balantlarn nasl gerekletirebiliriz? te bu yazmzda aratracamz ve rnekleyeceimiz
konular bunlar olacaktr.

WPF uygulamlarnda veri kaynaklarna balanabilmek amacyla kullanlan iki temel salayc
bulunmaktadr. Bunlardan birisi XML kaynaklarna balanma ilemini gerekkletirmemizi
salayan XmlDataProvider bileenidir. Dieri ise, herhangibir .Net nesnesine (.Net Object)
balanmamz kolaylatran ObjectDataProvider bileenidir. (Bunlarn dnda zellikle balantsz
katman nesneleri ilede kullanlan DataContext zelliide veri balama ilemlerinde
kullanlmaktadr.) Bu bileenler sayesinde XAML ierisinden ilgili kaynaklara balanma, tek ynl
ve ift ynl olarak veri transfer etme ilemlerini gerekletirebiliriz. Bu tiplerin kullanmn
gsteren basit rneklerimize gemeden nce veri balama ilemine basit ve genel bir bak
atmakta yarar var. Bu amala Visual Studio 2008 Beta 2 srmnde yeni bir WPF uygulamas
ayor ve Window1 penceresinin XAML ieriini aadaki gibi kodluyoruz.

www.bsenyurt.com Page 880


<Window x:Class="DataBindIslemleri.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Bir kontrol niteliini baka bir
kontrodekine balamak" Height="169" Width="275" WindowStartupLocation="CenterScreen"
Name="wndBasitBaglama">
<Grid>
<Button Background="#FFFFCC66" ClickMode="Release" Height="23"
HorizontalAlignment="Left" Margin="10,16,0,0" Name="btnGiris" VerticalAlignment="Top"
Width="75" Click="btnGiris_Click">Giri</Button>
<TextBox Background="Black" Foreground="{Binding ElementName=btnGiris,
Path=Background}" Margin="10,47,44,54" Name="txtSifre" />
</Grid>
</Window>

Bu ilk rneimizde penceremiz zerinde bir Button ve birde TextBox kontrolmz bulunmaktadr.
Dikkat edilmesi gereken nokta TextBox kontrolnn n plan renginin, Button kontrolnn arka plan
rengine balanm olmasdr. Bunun iin TextBox elementi ierisinde Forground niteliine bir
deer atamas gerekletirilmitir. Binding ile balayan bu ifade ierisinde ElementName isimli
zellik verinin kayna olan nesneyi temsil etmektedir. Bu rnekte sz konusu nesne btnGiris isimli
Button kontroldr. Foreground zelliine balanmasn istediimiz veri ierii
ise Path tanmlamas ile belirtilmektedir. Buna gre btnGiris isimli veri
kaynandaki Background isimli zelliin deerinin atanmas sz konusudur. Uygulamay altrp
test ettiimizde rnek olarak aadakine benzer bir grnt elde ederiz.

Burada bahsedilen teknik en basit haliyle veri balamay gstermektedir. imdi ii biraz daha
ilerletip rnek bir XML dkman ierisinden, WPF kontrollerine veri balama ilemlerini nasl
gerekletirebileceimize bakalm. Aadaki gibi bir XML ieriimiz olduunu ve projemizde
Urunler.xml adyla kaydedildiini gz nne alabiliriz.

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

www.bsenyurt.com Page 881


<Depo>
<Urun id="1000">
<Ad>Ekran Kart(VGA)</Ad>
<BirimFiyat>35</BirimFiyat>
<StokMiktari>100</StokMiktari>
<Durum>OK.bmp</Durum>
<Kategori>Yedek Para</Kategori>
</Urun>
<Urun id="1001">
<Ad>Intel Core Duo lemci (CPU)</Ad>
<BirimFiyat>90</BirimFiyat>
<StokMiktari>125</StokMiktari>
<Durum>OK.bmp</Durum>
<Kategori>Yedek Para</Kategori>
</Urun>
<Urun id="1002">
<Ad>17Inch LCD Monitor</Ad>
<BirimFiyat>150</BirimFiyat>
<StokMiktari>35</StokMiktari>
<Durum>Warning.bmp</Durum>
<Kategori>Ekran</Kategori>
</Urun>
<Urun id="1003">
<Ad>250 GB Usb Harddisk</Ad>
<BirimFiyat>150</BirimFiyat>
<StokMiktari>90</StokMiktari>
<Durum>Serious.bmp</Durum>
<Kategori>Depolama Aygt</Kategori>
</Urun>
<Urun id="1004">
<Ad>1 GB Usb Flash Bellek</Ad>
<BirimFiyat>28</BirimFiyat>
<StokMiktari>300</StokMiktari>
<Durum>Warning.bmp</Durum>
<Kategori>Depolama Aygt</Kategori>
</Urun>
</Depo>

XML dkmanmz ierisinde eitli tipte bilgisayar rnlerine ait bilgiler yer almaktadr. Temel
olarak rnn ad, birim fiyat, stok miktar , kategorisi ve durumuna ait bilgisi yer almaktadr. Sz
gelimi bu XML veri kmesi ierisinde yer alan her bir rnn adlarnn bir ComboBox kontrolnde
gsterilmesini istediimizi dnelim. Bu amala yineVisual Studio 2008 Beta 2 zerinde
tasarladmz WPF projemize yeni bir pencere(Window) ekliyor ve XAML(eXtensible
Application Markup Language) ieriini aadaki gibi dzenliyoruz.

www.bsenyurt.com Page 882


<Window x:Class="DataBindIslemleri.Window2"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schem
as.microsoft.com/winfx/2006/xaml"Title="XmlDataProvider ile Xml verilerine basit
balanmak" Height="150" Width="290" WindowStartupLocation="CenterScreen">
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="UrunlerProvider" Source="Urunler.xml"/>
</Grid.Resources>
<ComboBox Height="28" Margin="23,42,60,0" Name="cmbUrunler"
VerticalAlignment="Top" ItemsSource="{Binding Source={StaticResource
UrunlerProvider},XPath=/Depo/Urun/Ad}" FontSize="13" FontWeight="Bold" />
<Label Height="23" HorizontalAlignment="Left" Margin="18,12,0,0" Name="label1"
VerticalAlignment="Top" Width="120" FontSize="12" FontWeight="Bold">rnler</Label>
</Grid>
</Window>

Daha ncedende bahsettiimiz gibi WPF uygulamalarnda veri balama ilemleri


iin XmlDataProvider ve ObjectDataProvider tipleri kullanlmaktadr. Bu rnekte yer
alan Grid alan ierisindeki kontrollerin bir XML veri kaynan kullanacan belirtmek
amacyla Grid.Resources elementi ierisinde XmlDataProvider tanmlamas yaplmtr.
XmlDataProvider elementi bu rnekte iki nemli nitelik(attribute) kullanmaktadr. Bunlardan birisi x
isim alan altnda bulunan Key niteliidir. Key aslnda sz konusu veri kaynann dier kontrollerde
ele alnmasn salamak amacyla bir isim tanmlamas yaplmasn salar. yleki UrunlerProvider
ad, ComboBox kontrolnde ele alnan Binding ifadesinde
kullanlmaktadr. XmlDataProvider elementinin Source niteliinde ise veri kaynann yeri iaret
edilmektedir. Burada Urunler.xml isimli dosya gsterilmektedir. Source zelliine internet
zerindeki bir URL adresi atanabilecei gibi, baka bir fiziki lokasyondaki XML dosya yeride
verilebilir. ComboBox kontrolnde elerin(Items) ieriklerinin aslnda XML dosyasndaki Ad
elementlerinden geleceini belirtmek amacyla aadaki ifade kullanlmtr.

ItemsSource="{Binding Source={StaticResource UrunlerProvider},XPath=/Depo/Urun/Ad}"

Burada en ok gze arpan nokta XPath niteliine atanan deerdir. Tahmin edilecei zere burada
bir XPath ifadesi kullanlm ve Ad elementine kadar geiler yaplmtr. Bu anlamda
zellikle XAML tarafnda, XML veri kaynaklarnn sz konusu olduu durumlarda XPath ifadelerinin
byk nem tadn ifade edebiliriz. rneimizi altrdmzda aadaki ekran grnts elde
edilecektir. Dikkat edilecek olursa Urunler.xml ierisindeki tm rnlerin Ad elementlerinin
deerleri gelmitir.

XmlDataProvider tipinin her zaman iin harici bir XML veri kmesini iaret etmesine gerek
yoktur. XAML ieriinde yer alan gml(Embedded) bir XML veri kmeside bu anlamda
kullanlabilir. nc rneimizde bu durumu analiz ederek yazmza devam edelim. Yeni bir

www.bsenyurt.com Page 883


pencereyi(Window) aadaki gibi tasarladmz dnelim. Kahramanmz yine
bir ComboBox kontrol olacak.

<Window x:Class="DataBindIslemleri.Window3"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schem
as.microsoft.com/winfx/2006/xaml" Title="Inline Xml kaynan kontrollere balamak"
Height="173" Width="280">
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="SehirVerisi">
<x:XData>
<Sehirler xmlns="">
<Sehir kod="+90216" ad="Istanbul Anadolu"/>
<Sehir kod="202" ad="Kahire"/>
<Sehir kod="813" ad="Tokyo"/>
<Sehir kod="+44171" ad="Londra"/>
<Sehir kod="+1718" ad="New York City"/>
<Sehir kod="4989" ad="Mnih"/>
</Sehirler>
</x:XData>
</XmlDataProvider>
</Grid.Resources>
<ComboBox ItemsSource="{Binding Source={StaticResource SehirVerisi},
XPath=/Sehirler/Sehir/@ad}" Margin="15,57,16,51" FontSize="14" FontWeight="Bold" />
<Label Height="23" HorizontalAlignment="Left" Margin="15,22,0,0" Name="label1"
VerticalAlignment="Top" Width="120">ehir Telefon Kodlar</Label>
</Grid>
</Window>

Bu sefer XML veri kmesi XAML dkman ierisinde yer alan Grid' in kayna olarak
tanmlanmtr. Bunun iin XmlDataProvider elementi ierisinde x:XData isimli bir alt eleman(Child
Element) tanmlanmaktadr. Bu elementin ierisinde ise XML veri kmesi bulunmaktadr. Buradaki
XML ierii istenilen ekilde tasarlanabilir. nemli olan noktalardan birisi bir nceki rnekte olduu
gibi yine x:Key niteliinin tanmlanm olmasdr. ComboBox kontrolnde Sehir elementi
ierisindeki ad niteliklerinin(attributes) deerleri gsterilmektedir.ItemsSource niteliine atanan
ifade ierisinde balanlacak veri kayna SehirVerisi olarak belirtildikten sonra ad niteliklerinin
deerlerinin elde edilmesi iin XPath ifadesinde @ iaret kullanlmtr.(Hatrlayalm; XPath
ifadelerinde nitelikleri ele alrken @ iareti kullanlr) Uygulama bu haliyle altrldnda aadaki
ekran grnts ile karlalacaktr.

www.bsenyurt.com Page 884


Grld gibi ad niteliklerinin deerleri ComboBox kontrol ierisine alnmtr. Gelitirdiimiz son
rnein bir ncekinden tek fark, harici bir XML veri kmesi kullanmaktansa,
gml(Embeded) bir XML kaynann kullanlmasdr. Pek ok kaynakta zellikle MSDN' de bu tip
bir XML ierii iin XML veri adas (XML Data Island) tanmlamas yaplmaktadr. XML veri
adalar x:XData elementleri arasnda tutulmak zorundadr.

Sradaki rneimizde yine bir XML veri kaynan ele alacaz. Bu sefer dier rneklerden farkl
olarak ComboBox' n ItemTemplate elementini ele alacaz. Bu sayede ComboBox ierisinde
birden fazla veri bal kontrol yan yana gstermemiz mmkn olacaktr. Bu amala yeni
penceremizi aadaki gibi tasarlamamz yeterlidir.

<Window x:Class="DataBindIslemleri.Window4"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schem
as.microsoft.com/winfx/2006/xaml"Title="DataTemplete Yardmyla Xml verisine balanma"
Height="154" Width="384">
<Grid>
<Grid.Resources>
<XmlDataProvider x:Key="UrunVerileri" Source="Urunler.xml"/>
</Grid.Resources>
<ComboBox Height="40" Margin="21,37,15,0" Name="cmbUrunler"
VerticalAlignment="Top" ItemsSource="{Binding Source={StaticResource
UrunVerileri},XPath=Depo/Urun}"FontSize="14" FontWeight="Bold">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock>
<Label>
<Label.Content>
<Binding XPath="Ad"/>
</Label.Content>
</Label>

www.bsenyurt.com Page 885


<Button>
<Button.Content>
<Binding XPath="StokMiktari"/>
</Button.Content>
</Button>
<Image>
<Image.Source>
<Binding XPath="Durum"/>
</Image.Source>
</Image>
<Button Name="btnSiparisVer" Content="Sipari Ver" FontSize="10"
FontWeight="Bold" Background="Black" Foreground="Gold"/>
</TextBlock>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</Grid>
</Window>

Her zamanki gibi Grid ierisindeki kontrollerin balanabilecei veri kayna


salaycsn XmlDataProvider yardmyla Grid.Resources elementi ierisinde tanmlamaktayz.
Bundan sonra ise ComboBox elementi altnda bir ItemTemplate elementi almaktadr. Bu
element ierisinde yer alan TextBlock elementi altna Label, Button, Image kontrolleri atlmtr.
Hepsinin ortak zellii, hangi niteliklerine veri balayacaksak, bununla ilgili alt elementin almas
ve Binding elementi ile balama ileminin gerekletirilmesidir. Sz gelimi rnn Ad elementinin
deerini Label kontrolnn Content zelliine atamak istiyorsak aadaki gibi bir bildirim
yaplmas yeterlidir.

<Label>
<Label.Content>
<Binding XPath="Ad"/>
</Label.Content>
</Label>

Burada Content elementinin deerinin, Ad isimli elementten alnaca belirtilmitir. Yanlz dikkat
edilmesi gereken bir nokta vardr. Ad elementi aslnda XML aa yapsna bakldnda Depo/Urun
zerinden elde edilebilmektedir. Dolaysyla burada XPath ifadesinde dorudan Ad deerinin
alnabilmesi iin Urun elementlerine ulalm olmas gerekmektedir. Bunu salamak iin ComboBox
bileeninin ItemsSource niteliindeki XPath ifadesi Depo/Urun eklinde ayarlanmtr.
Uygulamay bu haliyle altrdmzda aadakine benzer bir ekran grnts ile karlarz.

www.bsenyurt.com Page 886


Olduka etkileyici deil mi? Bir ComboBox' n her bir esi bir tayc(Container) gibi davranp
birden fazla farkl bileeni ieriyor ve ierikleri bir XML veri kmesinden geliyor. Bence sper.

u ana kadar gelitirdiimiz rneklerimizde XmlDataProvider tipinden yararlandk ve XML veri


kmelerine balandk. XML dndaki veri kaynaklar gz nne
alndnda ObjectDataProvider bileeninin kullanlmas sz konusudur. Bu snf yardmyla
herhangibir .Net tipine balanmak mmkndr. MSDN bu konu ile ilikili olarak ounlukla
koleksiyonlar rnekleyerek ie balamaktadr. Bizde dilerseniz gelenei bozmayalm. imdiki
rneimizde Urun isimli bir snfa ait nesne rneklerini barndran generic
bir List<T>koleksiyonunun veri kayna olarak kullanlmasn ele alyor olacaz. lk olarak
aadaki snf diagramnda (class diagram) grlen Urun isimli tipi tasarlayarak balayalm.

public class Urun


{
public int Id;
public string Ad;
public double BirimFiyat;
public int StokMiktari;
public bool Durum;

public override string ToString()


{
return Id.ToString() + " " + Ad+" "+BirimFiyat.ToString();
}
}

www.bsenyurt.com Page 887


Urun snf yine bir rn tanmlayabilecek baz public alanlara sahiptir. ToString metodunu
ezmemizin(override) sebebi ise, ComboBox kontrolne balandklarnda ne gsterileceini
belirtmektir. Eer bunu belirtmessek, ComboBox kontrolnde
IsimAlaniAdi.TipAdi (Namespace.TypeName) notasyonuna uygun olacak ekilde bir grnt elde
edilir. Gelelim rnlere ait nesne rneklerini tayacak koleksiyon snfn tasarlamaya. UrunListesi
isimli snfmz aadaki gibidir.

public class UrunListesi:List<Urun>


{
public UrunListesi()
{
Add(new Urun() { Id = 1, Ad = "Grafik Kart", BirimFiyat = 35, StokMiktari =
100,Durum=true });
Add(new Urun() { Id = 2, Ad = "Monitor", BirimFiyat = 150, StokMiktari = 50, Durum = false
});
Add(new Urun() { Id = 3, Ad = "CPU X86", BirimFiyat = 145, StokMiktari = 150, Durum =
true });
Add(new Urun() { Id = 4, Ad = "USB Bellek", BirimFiyat = 15, StokMiktari = 250, Durum =
true });
Add(new Urun() { Id = 5, Ad = "HDD 250 Gb", BirimFiyat = 250, StokMiktari = 14, Durum =
false });
}
}

UrunListesi snf veri balanmasnda kullanlacak kaynak bir tip olarak gz nne
alndndan List<Urun> koleksiyonundan tretilmitir. Daha nceki yazlarmzda da deinildii
gibi C# 3.0 ile gelen yeniliklerden birisi olan nesne balatclar(Object Initializers) kullanlarak
Urun nesneleri rneklenmi bir List koleksiyonuna eklenmitir. imdi UrunListesi snfn veri
kayna olarak kullanacak bir pencereyi(Window) aadaki gibi tasarlayabiliriz. Kahramanmz
her zamanki gibi bir ComboBox bileenidir.

www.bsenyurt.com Page 888


<Window x:Class="DataBindIslemleri.Window5"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schem
as.microsoft.com/winfx/2006/xaml" Title="Basit ObjectDataProvider Kullanm" Height="158"
Width="290" xmlns:dahili="clr-namespace:DataBindIslemleri">
<Grid>
<Grid.Resources>
<ObjectDataProvider x:Key="UrunVerileri" ObjectType="{x:Type
dahili:UrunListesi}" />
</Grid.Resources>
<ComboBox FontSize="12" FontWeight="SemiBold" Height="29" Margin="17,44,45,0"
Name="comboBox1" VerticalAlignment="Top" ItemsSource="{Binding
Source={StaticResource UrunVerileri}}" />
</Grid>
</Window>

ObjectDataProvider tipide x:Key isimli bir nitelii kullanarak, veriye balanacak kontrollerin
kullanabilmesi iin ortak bir isim tanmlamas yapmaktadr. XmlDataProvider tipinde Source isimli
nitelik ile veri kmesi belirtilirken ObjectDataProvider tipinde bu i
iin ObjectType nitelii(attribute) kullanlmaktadr. ObjectType niteliinde ise UrunListesi isimli
bir tipin veri kayna olarak kullanlaca ve bunun, dahili kelimesi ile ifade edilen isim alannda
olduu belirtilmektedir. Peki dahili XML isim alan nereden tanmlanmtr? Bunun
iin Window elementinde bir XML isim alan (XML Namespace) tanmlamas aadaki gibi
yaplmtr. Burada, clr-namespace ifadesini izeleyen ismin bir CLR isim alan(Namespace) ad
olduu ve XAML dkman ierisinde dahili ksa ad ile ifade edilecei belirtilmektedir.

xmlns:dahili="clr-namespace:DataBindIslemleri"

Dikkat edilecek olursa, tipin ierisinde yer ald isim alan(Namespace) iaret edilmektedir.
Buradan u sonucada varabiliriz. Veri balama amacyla kullanlan tip farkl bir assembly ierisinde,
dolaysyla farkl bir isim alannda bulunuyorsada ilgili XAML ieriinde kullanlabilir. Farkl
bir assembly sz konusu olduunda aadakine benzer bir tanmlama yeterli olacaktr.

xmlns:dahili="clr-namespace:DataBindIslemleri,assembly=UrunLibrary"

Uygulamay altrdmzda aadakine benzer bir ekran grntsn elde ederiz.

Dikkat edilecek olursa ToString metodu ierii ComboBox kontrollerinde birer e olarak
grlmektedir.

Veri balama ilemlerinde tip olarak DataTable veya DataSet gibi balantsz katman nesne
rneklerinin kullanlmas ok daha yaygndr. Bu tip bir senaryoda DataContext snf ele
alnmaktadr. Sradaki rneimizde bir DataTable ierisindeki veri kmesinin, WPF kontrollerine

www.bsenyurt.com Page 889


nasl balanabileceini incelemeye alacaz. rnek bir senaryo olarakSQL Server 2005 ile
birlikte gelen veritabanlarndan birisi
olan AdventureWorks ve Product, ProductPhoto, ProductProductPhoto tablolarn gz nne
alabiliriz. Bu tablolar arasndaki iliki aadaki ekilde olduu gibidir.

Amacmz resimli rn bilgilerini bir ListBox kontrolnde gsterebilmek. Bu amala ilk olarak
Window6 isimli penceremizin kodlarn aadaki gibi gelitirelim.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data;
using System.Data.SqlClient;

namespace DataBindIslemleri
{
public partial class Window6 : Window
{
string sqlConn = "data source=.;database=AdventureWorks;integrated security=SSPI";
string sorgu = @"SELECT PRD.ProductID, PRD.Name AS ProductName, PRD.SafetyStockLevel
, PRD.StandardCost,PRD.ListPrice, PH.ThumbNailPhoto FROM Production.Product PRD INNER JOIN

www.bsenyurt.com Page 890


Production.ProductProductPhoto PPH ON PRD.ProductID = PPH.ProductID INNER JOIN
Production.ProductPhoto PH ON PPH.ProductPhotoID = PH.ProductPhotoID";

private void VeriyiCek()


{
DataTable dtUrunler = new DataTable();
using (SqlConnection conn = new SqlConnection(sqlConn))
{
SqlDataAdapter da = new SqlDataAdapter(sorgu, conn);
da.Fill(dtUrunler);
}
DataContext = dtUrunler;
}

public Window6()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)


{
lstUrunler.Items.Clear();
VeriyiCek();
}
}
}

Bu kod parasnda zerinde durulacak olan tek


nokta Window snfnn FrameworkElement snfndan kaltmsal olarak
devrald DataContext zelliine DataTablenesne rneinin atanm olmasdr. Bylece bir
anlamda XAML ierisindeki bileenlerin balanabilecei veri ierii set edilmi olur. Buna gre
Window6.xaml dosyasnn ieriini aadaki gibi tasarlayabiliriz.

<Window x:Class="DataBindIslemleri.Window6"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schem
as.microsoft.com/winfx/2006/xaml"Title="Window6" Height="273" Width="567"
Loaded="Window_Loaded">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="Urunler">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=ProductID}"/>
<Label Content="{Binding Path=ProductName}"/>
<Label Content="{Binding Path=ListPrice}"/>
<Label Content="{Binding Path=SafetyStockLevel}"/>
<Image Name="imgPhoto" Source="{Binding Path=ThumbNailPhoto}"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox Margin="13,28,17,31"
Name="lstUrunler" ItemsSource="{Binding}" ItemTemplate="{StaticResource
Urunler}"/>
</Grid>
</Window>

www.bsenyurt.com Page 891


imdi burada neler yaptmza ksaca bakalm. ncelikli olarak Grid.Resources elementi
ierisinde bir DataTemplete oluturulmaktadr. Bu veri ablonu, kullanld yerde nasl bir ierik
sunulacan belirlemektedir. Sz gelimi, Label kontrollerimizin Content zelliklerine yaplan
atamalarda DataContext' in iaret ettii veri kmesindeki alanlar belirlenmektedir. Dier
taraftan Image kontrolnn Source zelliine yaplan atama ile ThumbNailPhoto alanndaki
binary ieriin balanmas salanmtr. Peki bu veri ablonunu kim kullanacaktr? Bunun iin rnek
olarak bir ListBox kontrol ele alnmaktadr. Bu kontrolde ItemsSource zelliine
sadece Binding atanmas, veri kayna olarak DataContext ieriinin ele alnacan
gstermektedir. Dier taraftan veri ablonunun set edildii yer ItemTemplate zelliine yaplan
atamadr. Burada atamada Urunler isimli veri ablonunun (Data Template) kullanlaca
belirtilmektedir. Bu durumda uygulama altrldnda aadakine benzer bir ekran grnts ile
karlalr.

Dikkat edilecek olursa ListBox ierii, DataTable' a yklenen veriler ile dolmutur. Her halde
buradaki en gzel nokta, rn resimlerininde ListBox ierisinde gsterilebiliyor olmasdr. imdi bu
rnei biraz daha farkllatralm. rnein ListBox kontrolnde rn adlar gzkyor olsun.
Bunlardan herhangibiri seildiindeyse, rn ile ilgili dier bilgilerTextBox ve Image kontrollerinde
grnyor olsun. Bunun iin yeni bir pencere(Window) ekleyip aadaki gibi tasarlamamz yeterli
olacaktr.

www.bsenyurt.com Page 892


<Window x:Class="DataBindIslemleri.Window7"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window7" Height="304"
Width="632">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="Urunler">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=ProductName}"/>
</StackPanel>
</DataTemplate>
</Grid.Resources>
<ListBox Margin="13,19,0,18" Name="lstUrunler" ItemsSource="{Binding}"
ItemTemplate="{StaticResource Urunler}" HorizontalAlignment="Left"
Width="139"IsSynchronizedWithCurrentItem="True" />
<Label Height="23" HorizontalAlignment="Left" Margin="176,24,0,0" Name="label1"
VerticalAlignment="Top" Width="61">rn Ad</Label>
<TextBox Text="{Binding Path=ProductName}" Height="21" Margin="270,24,191,0"
Name="txtProductName" VerticalAlignment="Top"></TextBox>
<Label Height="23" HorizontalAlignment="Left" Margin="176,50,0,0" Name="label2"
VerticalAlignment="Top" Width="120">Birim Fiyat</Label>
<TextBox Text="{Binding Path=ListPrice}" Height="21" Margin="270,50,193,0"
Name="txtListPrice" VerticalAlignment="Top" />
<Label Height="23" HorizontalAlignment="Left" Margin="176,77,0,0" Name="label3"
VerticalAlignment="Top" Width="120">Stok Seviyesi</Label>
<TextBox Text="{Binding Path=SafetyStockLevel}" Margin="270,77,193,0"
Name="txtSafetyStockLevel" Height="20" VerticalAlignment="Top" />
<Image Source="{Binding Path=ThumbNailPhoto}" Margin="182,113,195,20"
Name="imgPhoto" />
<Label Content="{Binding Path=ProductID}" Height="49" HorizontalAlignment="Right"
Margin="0,24,57,0" Name="lblProductID" VerticalAlignment="Top" Width="103"
Foreground="Red" FontSize="16" FontWeight="Bold"/>
</Grid>
</Window>

www.bsenyurt.com Page 893


Bir nceki rnek ile karlatrldnda nemli olan tek fark ListBox
kontrolnn IsSynchronizedWithCurrentItem zelliinin deerinin true olarak set edilmi
olmasdr. Eer bu zellie true deerini atamassak, ListBox zerinde dolatmzda, bir baka
deyile baka bir eye getiimizde dier kontrollerin ierikleri DataContextnesnesinden
dolmayacaktr. Bu durumda ListBox kontrolnde dier elere tklasakta hep ilk satrn bilgileri
grnecektir. Uygulamamz bu haliyle altrdmzda aadakine benzer bir ekran grnts
elde ederiz.

Grld gibi rnek kaydn zerine ListBox ile gidildiinde, kontrollerin ierikleride o
an DataContext' te zerinde bulunulan satra ait deerler olarak deimitir.

Baz durumlarda birbirleriyle ilikili olan tablolarn kullanlmasda sz konusudur. zellikle


balantsz katman(Disconnected Layer) nesneleri gz nne alndnda bu tip vakkalar
karlamak iin DataRelation nesnelerinden yararlanmaktayz. Peki DataRelation rnekleri ile
aralarndaki ilikiler(Relations) ifade edilen tablolar WPF uygulamalarndaki kontrollerimize nasl
balayabiliriz? Sradaki rneimizde bu durumu ele almaya alacaz. Sz
gelimi, AdventureWorks veritabannda yer alan ProductSubCategory ve Producttablolarn baz
alalm. Bu tablolar aadaki diagramdanda grlecei gibi
birbirlerine ProductSubCategoryID alanlar zerinden baldrlar.

www.bsenyurt.com Page 894


Bu ilikiyi balantsz katmanda temsil edebilmek
iin DataSet, DataTable ve DataRelation nesnelerine ihtiya vardr. Window8 rneinde, alt
kategorilerin gsterildii bir ComboBox kontrol ve bu kategoriye bal rnlerin gsterildii bir
ListBox kontrol bulunmaktadr. Senaryomuza gre ComboBox kontrolnde deiiklik yaplmas
halinde, seilen yeni alt kategoriye bal rnlerinde ListBox kontrolnde gsterilmesi
istenmektedir. Bu amala ilk olarak verinin ekilmesi ve pencerenin DataContext zelliine
gerekli DataTable nesne rneinin atanmas gerekmektedir. Bu sebepten Window8.xaml.cs
dosyamzn ieriini aadaki gibi gelitirebiliriz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Data;
using System.Data.SqlClient;

namespace DataBindIslemleri
{
public partial class Window8 : Window
{
private string conStr = "data source=.;database=AdventureWorks;integrated
security=SSPI";
private string kategoriSorgusu = "Select ProductSubCategoryID,Name From
Production.ProductSubCategory";
private string urunSorgusu = "Select ProductID,ProductSubCategoryID,Name,ListPrice From

www.bsenyurt.com Page 895


Production.Product";

private void VerileriCek()


{
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlDataAdapter daKategori = new SqlDataAdapter(kategoriSorgusu, conn);
DataTable dtKategori = new DataTable();
daKategori.Fill(dtKategori);

SqlDataAdapter daUrun = new SqlDataAdapter(urunSorgusu, conn);


DataTable dtUrun = new DataTable();
daUrun.Fill(dtUrun);

DataSet ds = new DataSet();


ds.Tables.Add(dtUrun);
ds.Tables.Add(dtKategori);

DataRelation iliski = new DataRelation("SubCatToProduct",


dtKategori.Columns["ProductSubCategoryID"],
dtUrun.Columns["ProductSubCategoryID"]);
ds.Relations.Add(iliski);

DataContext = dtKategori;
}
}
public Window8()
{
InitializeComponent();
VerileriCek();
}
}
}

Burada dikkat edilmesi gereken nokta, DataRelation nesne rneinin mutlaka belirtilmesi
ve DataSet nesne rneinin Relations koleksiyonuna eklenmesi gerektiidir. Pencerede
kullanlacak olan ComboBox bileeninin asl balanaca veri dtKategori tablosu
olduundan DataContext zelliine bu tablonun deeri aktarlmtr. Bundan sonra Window8
penceresininXAML ierii aadaki gibi hazrlanabilir.

<Window x:Class="DataBindIslemleri.Window8"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window8" Height="300"
Width="440">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="KategoriVerisi">
<StackPanel>
<TextBlock Text="{Binding Path=Name}"/>
</StackPanel>
</DataTemplate>
<DataTemplate x:Key="UrunVerisi">
<StackPanel Orientation="Horizontal">
<Label Content="{Binding Path=ProductID}"/>
<Label Content="{Binding Path=Name}"/>
<Label Content="{Binding Path=ListPrice}"/>

www.bsenyurt.com Page 896


</StackPanel>
</DataTemplate>
</Grid.Resources>
<ComboBox Height="25" HorizontalAlignment="Left" Margin="12,35,0,0"
Name="cmbAltKategori" VerticalAlignment="Top" Width="120" ItemsSource="{Binding}"
ItemTemplate="{StaticResource KategoriVerisi}"
IsSynchronizedWithCurrentItem="True"/>
<Label Height="23" HorizontalAlignment="Left" Margin="10,12,0,0" Name="label1"
VerticalAlignment="Top" Width="120">Alt Kategori</Label>
<ListBox Margin="166,35,10,19" Name="lstUrunler" ItemsSource="{Binding
SubCatToProduct}" ItemTemplate="{StaticResource UrunVerisi}" />
<Label Height="23" Margin="166,12,132,0" Name="label2"
VerticalAlignment="Top">Urunler</Label>
</Grid>
</Window>

Grid ierisinde iki adet veri ablonu(Data Templete) kullanlmaktadr. Bunlardan


birisi ComboBox, dieri ise ListBox iindir. ComboBox bileeni kendi ierisinde alt kategori
adlarn gstermektedir. Veri kaynan ItemsSource zellii ile {Binding} olarak
belirttiimizden, DataContext ierisinden DataTable kullanlacaktr. Buna gre ItemTemplate' in
ulaaca KategoriVerisi isimli DataTemplete elementinin ieriine gre alt kategori adlar
grnecektir. Dier tarafan, ComboBox zerinde gezildike DataContext' in iaret ettii veri
kmesi zerindede hareket edilebilmesini salamak
istediimizden IsSynchronizedWithCurrentItem niteliine true deeri verilmesi arttr. ListBox
kontrolnn ItemsSource zelliine dikkat edilecek olursa Binding ifadesinden sonra, DataSet' e
eklenen DataRelation nesne rneinin ad yazlmtr. te bu bizim rneimizin kilit noktasdr. Bir
baka deyile ListBox kontrol, ieriini olutururken Binding ifadesinde belirtilen
iliki(Relation) zerinden hareket edecek ve buna UrunVerisi isimli DataTemplete' e gre verilerini
ykleyecektir. Uygulamamz altrdmzda aadaki ekran grntsnde olduu gibi alt
kategori ve buna bal rnlerin baarl bir ekilde ilikilendirildii ve kontrollere bu deiimin
yanstld grlr. rnekte Shorts alt kategorisi seilmi ve buna bal olan rnlerin bilgiside
(DataTemplete ile ektiklerimiz) ListBox ierisinde gsterilmitir.

www.bsenyurt.com Page 897


Buraya kadar gelitirdiimiz rneklerimizde, WPF uygulamalarnda yer alan kontrollerin eitli veri
kaynaklarna(XML, Database, Object gibi) farkl ekillerde nasl balanabileceklerini incelemeye
altk. zellikle XML bazl veri kaynaklar iin XmlDataProvider tipini, nesne(Object) bazl
kaynaklar iin ObjectDataProvider tipini kullanmay, bunlara ek olarak zellikle veritaban bazl
gerek balantlarda da DataContext tipinden yararlanmay incelemeye altk. nceki Windows
mantna gre XAML getirdii bir takm yenilikler ile, veri balama ileminin epey bir deitii
sonucunuda kartmamz mmkn. Konuyla ilikili detayl bilgilere ve ok daha gzel rneklere
MSDN' den ulaabilirsiniz. Ayrca bir nceki makalemizde tanttmz kitaplarnda ok faydas
olacan syleyebilirim. Bylece geldik bir makalemizin daha sonuna. lerleyen makalelerimizde
WPF ile uygulamalar gelitirmeye devam ediyor olacaz. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WPF-Uygulama Nesnesi (Application Object) (


30.08.2007 ) - WPF
Deerli Okurlarm Merhabalar,

Windows Presentation Foundation windows tabanl uygulama gelitirmeye ok yeni bir yaklam
getirdi. Tabiri yerindeyse pek ok yenilik ile kar karyayz. te bu makalemizde WPF ile
gelitirilen windows uygulamalarnda ekirdek nesnelerden birisi olan Application tipini incelemeye
alacaz. Application nesnesi, WPF uygulamalarnn ekirdek nesnesidir. Genel olarak bir
windows uygulamasnn altrlmas iletim sistemi tarafndan tetiklenen bir aksiyonla gerekleir
ve bu uygulama Process dahilinde ayr bir AppDomainierisinde alr. Buna gre her WPF
uygulamas alt yaam sresi boyunca yanlzca bir Application nesnesine sahip olur. Buda ok
doal olarak, windows uygulamas ierisindeki tm sayfa(Page) veya
pencerelerin(Windows) ortaklaa kullanacaklar global seviyede bir nesnenin sz konusu olmas
anlamna gelmektedir. Aadaki ekilde Application nesnesinin WPF uygulamasndaki yeri tasvir
edilmeye allmaktadr.

www.bsenyurt.com Page 898


Bu, inanyorumki web uygulamas gelitirenler iin tuhaf deildir. Malum web uygulamalarnda da
Application nesnesi vardr ve zellikle uygulama seviyesinde deikenlerin tutulmas iin kullanlr.
Aslnda bu kavram .Net Framework 3.0 ncesi windows programlamadada vardr. yleki
hepimiz Main metod ierisinde kullanlan Application snfn ve yelerini az ok biliyoruz. Ne varki,
WPF ile gelitirilen uygulamalarda Application nesnesinden yararlanarak daha farkl
fonksiyonellikler elde edilebilmektedir. Bunlar maddeler halinde aadaki gibi sralayabiliriz.

Uygulamann yaam sresi izlenebilir. (Application LifeTime)


Komut satrndan uygulamaya gnderilen parametreler(Command Arguments) alnp
ilenebilir.
Uygulamann kapatlma sreci ele alnabilir.
Ele alnamayan istisnalar(Unhandled Exceptions) iin zel durum ynetimleri
gerekletirilebilir.
Uygulama genelinde kullanlabilecek global zellikler(properties) ve
kaynaklar(resources) tanmlanabilir ve kullanlabilir.
Uygulamann derleme(build) srecine ait ayarlar yaplabilir.
XBAP(Xaml Browser APplication) uygulamalarnda navigasyon sreci izlenebilir.

Application nesnesini iletim sistemi ile uygulama kodu arasndaki bir arayz olarakda
dnebiliriz. Uygulama ierisindeki tm pencere(Window) veya sayfalarn(Page) ayn Application
nesnesine eriebilmesini ve bu nesnenin tekliini salamak iin tahmin edilecei zere Singleton
Pattern' e uygun bir retim sistemi sz konusudur. Bu tek nesne retim iini Application
snfnn Current zellii stlenmektedir. Application nesneleri, uygulamann bulunduu
bilgisayarda saklandklarndan zellikle kaynak(resource) veya
zelliklerin(properties) deerlerinin saklanmas gibi durumlarda sunucu(server) gibi kaynaklara
eriime gerek kalmamaktadr. Buda bir avantaj olarak grlebilir.

rneklere balamadan nce, uygulama yaam srecini(Application LifeTime) ele almakta ve


deerlendirmekte yarar olaca kansndaym. Application nesnesi ile birlikte, bir WPF
uygulamasnn yaam srecini daha iyi kontrol edebilmekteyiz. ncelikli olarak aadaki temsili
resmi gz nne alalm. Bu ekilde temel olarak bir WPF uygulamasnn standart yaam dngs,
sreteki temel olaylar ve evresel baz etkiler irdelenmeye allmaktadr.

www.bsenyurt.com Page 899


Hereyden nce WPF uygulmasnn kullanc tarafndan tetiklenmesi sonras iletim sistemi
tarafndan uygulamann bir AppDomain ierisine almas sz konusudur. Bundan sonraki srete
uygulama eitli nedenlerle sonlanncaya kadar ele alabilecek baz olaylar vardr. Uygulama
almaya baladnda Application nesnesinin Startup olay tetiklenir. Bu olay ierisinde uygulama
balatlrken yaplmas istenenler yazlabilir. rnein uygulamann hangi pencere veya sayfasnn
ykleneceine burada karar verilebilir. Startup olayn global seviyedeki zellik ve kaynaklarn
saklanmas halinde, yklenecekleri yer olarakda tasarlayabiliriz. Hatta komut satr
parametrelerininde(Command Line Arguments) bu olay ierisinde ele alnmas salanabilir.
Yazmzn ilerleyen ksmlarnda bununla ilikili bir rnek gelitiriyor olacaz.

Gelelim Activated ve Deactivated olaylarna. Activated olay, WPF uygulamas ilk altrldnda
ve ilk penceresi aldnda otomatik olarak tetiklenir. Bundan sonra uygulama pasif
moda(Deactivate) geinceye kadar almaz. letim sistemi zerinde alan baka uygulamalara
yaplan geilerde, Deactivated isimli olay tetiklenmektedir. Tahmin edilecei zere tekrardan
WPF uygulamasna dnlmesi sonrasnda Activated olay yeniden tetiklenecektir. Bu
tetikleme, taskbar yardmyla sz konusu WPF uygulamasndaki formlardan herhangibirinin
almas halinde, Alt+Tab tu kombinasyonu ile yaplan geiler sonrasnda meydana gelmektedir.
Deactivated olaynda kaynak tketimi yksek olan alma zaman nesnelerinin ileyilerinin
duraksatlmas yada uyku moduna geirilmeleri salanarak iletim sisteminin daha az yorulmas

www.bsenyurt.com Page 900


gerekletirilebilir. Activated olay tetiklendiindede sz konusu kaynaklarn tekrardan ayaa
kaldrlmas ilemleri gerekletirilebilir. Bu tip bir senaryo elbetteki tartmaya ak olmaldr.

Activated ve Deactivated olaylar XBAP(Xaml Browser APplications) uygulamalar


tarafndan desteklenmemektedir.

Gelelim DispatcherUnhandledException olayna. ekildende grlecei zere uygulama kodu


ierisinden alma ortamna frlayacak bir istisnay Application nesnesninin bu olay ierisinde ele
alabiliriz. Uygulama ierisindeki kodlarda bir exception olutuunda(zellikle ele alnmayan-
unhandled exceptions) WPF alma ortam standart bir hata dialog penceresi kartacak ve hata
raporunun gnderilip gnderilmeyecei sorulacaktr. Ardndanda uygulama sonlandrlacaktr.
Ancak, DispatcherUnhandledException olay ierisine
gelen DispatcherUnhandledExceptionEventArgs parametresininin Handled zelliini
kullanarak uygulamann kapatlmas (Eer mmknse tabi) engellenebilir.

SessionEnding isimli olay, iletim sisteminden aadaki aktiviteler gerekletiinde


tetiklenmektedir.

LogOff
Windows Shutdown
Restart
Hibernate

Eer alan WPF uygulamasnda kritik ilemler(rnein halen daha devem eden veya sunucuya
bal halde iken veritaban zerinde transaction bazl gerekleen bir ilem vb. sz konusu
olabilir) sz konusu ise, yukardaki aktivitelerin gereklemesi halinde srecin iptal edilmesi arzu
edilebilir. Bu nedenle Application snfnn SessionEnding olay ele alnr. Bu
amala, SessionEndingCancelEventArgs parametresi kullanlr. Eer SessionEnding ierisinde
ilem iptali yaplmassa Application sfnn Shutdown metodu arlr ve Exit isimli olay tetiklenmi
olur.

SessionEnding olay XBAP(Xaml Browser APplications) uygulamlar tarafndan


desteklenmemektedir.

Bir WPF uygulamasn bilinli olarak sonlandrmak iin Application snfnn Shutdown metodu
kullanlabilir. Aslnda uygulamann ana penceresi(Main Window) kapatldnda, tm pencereleri
kapatldnda veya yukardaki gibi iletim sistemince LogOff, Windows Shutdown, Restart,
Hibernate aksiyonlar gerekletirildiinde otomatik olarak alr. stenirse bir uygulama
ierisindeki ShutDown metodunun hangi durumlarda otomatik olarak
alaca ShutdownMode(ShutDownMode enum sabiti tipinden deerler alr)zellii yardmyla
Application elementi iinden veya uygulama kodundan deitirilebilir. ShutDownMode enum
sabitinin OnLastWindowClose, OnMainWindowClose veOnExplicitShutDown isminde farkl
deeri vardr. OnLastWindowClose varsaylan deerdir ve uygulama ierisinde birden fazla
pencere olmas halinde en sonuncusu kapatldnda uygulamann kapanmas sz konusudur. Bir
baka deyile uygulamann kapatlabilmesi iin ak olan tm pencerelerin kapatlmas gereklidir.
Eer OnMainWindowClose deeri verilirse, uygulama baladnda etklinletirilen pencere
kapatldnda uygulama sonlanr. OnExplicitShutDown seildiinde ise uygulamann kapatlmas
gelitiriciye braklmtr. ShutDown metodu ile yaplan sonlandrma isteklerinde istenirse iletim
sistemine bir k kodu(ExitCode) deeri integer tipinden gnderilebilir. k kodunun deeri, bu
uygulamaya bal baka uygulamalar tarafndan deerli olabilir. ExitCode iin varsaylan deer
sfrdr.

www.bsenyurt.com Page 901


Shutdown metoduna yaplan bilinli ardan sonra veya SessionEnding gerekletikten
sonra Exit isimli olay tetiklenir. Bu olay ierisinde uygulamann son durumuna ait bilgilerin
saklanmas gibi ilemler yaplabilir. zellikle global zellik(Global Properties) ve
kaynaklarn(Resources) saklanma ilemlerinin gerekletirilmesi iin ideal bir lokasyondur. Bu olay
ierisine gelindiinde uygulamann kapatlma sreci artk iptal edilememektedir. Exit olay ierisine
gelen ExitEventArgs parametresi yardmyla, k kodu(Exit Code) deeride yakalanabilir ve buna
gre farkl askiyonlar gerekletirilebilir.

Exit olay XBAP(Xaml Browser APplications) uygulamalarnda da yazlabilir. Ancak


ExitCode deeri XBAP uygulamalarnda grmezden gelinir. Exit olay bir XBAP
uygulamasnda rnein Internet Explorer 7 ile almsa ilgili tab kapatldnda,
tarayc(Browser) uygulama kapatldnda veya baka bir yere navigasyon ile gidildiinde
tetiklenmektedir.

Bu kadar teorik bilgiden sonra birazda pratie gemekte fayda var. Yazmzn bundan sonraki
ksmlarnda rnekler zerinden ilerlemeye alacaz. Ancak bu kez Visual Studio 2008 Beta
2 srmn kullanyor olacaz. Bu nedenle yazdmz kodlarda bir deiiklik olmasada, IDE
zerinde final srm ktnda baz farkllklar olabileceini imdiden sylemek isterim. lk olarak
Visual Studio 2008 Beta 2 de yeni bir WPF uygulamas aarak ie balayalm. Uygulama aldnda
Application snfndan treyen App isimli bir tipin olduunu greceiz. App snfnn tredii
Application snfnn .Net Framework 3.0 ierisindeki yeri snf diagramdan(class diagram)
bakldnda aadaki gibidir.

Uygulamaya ait ayarlarn hem element hemde kod baznda ynetimi iin aadaki ekildende de
grld gibi App.xaml ve App.xaml.cs dosyalar otomatik olarak oluturulacaktr.

www.bsenyurt.com Page 902


Visual Studio 2008 Beta 2 ile bir olay element seviyesinde yklemek son derece kolaydr.
Burada intellisense desteinin tam olarak verildiini syleyebiliriz. rnein Startup olayn
aadaki gibi Application elementi ierisinden seebiliriz. Aadaki ekran grntsndende
grld gibi, Application elementi ierisinde boluk tuuna basldnda kullanlabilecek tm
yeler kacaktr.

Dier taraftan bir olay yklenmek istendiinde (rnein Startup) aadaki ekran grntsnde
olduu gibi geleneksel olarak tab tuundan yararlanarak ilgili olay metodun otomatik olarak
yklenmesi salanabilir.

Bunun sonucunda App.xaml.cs ierisine aadaki olay metodu eklenir.

www.bsenyurt.com Page 903


private void Application_Startup(object sender, StartupEventArgs e)
{

Application elementinin ierii ise aadaki gibi olacaktr.

<Application x:Class="UsingApplicationObjects.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml" Startup="Application_Startup">
<Application.Resources>
</Application.Resources>
</Application>

Visual Studio 2008 Beta 2' nin bu yardmlarna deindikten


sonra Activated ve Deactivated olaylarn inceleyerek devam edelim. Bu amala Application
elementi ierisinde aadaki yklemeler yaplmaldr.

<Application x:Class="UsingApplicationObjects.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml" Activated="Application_Activated"
Deactivated="Application_Deactivated">
<Application.Resources>
</Application.Resources>
</Application>

Sonrasnda ise App.xaml.cs dosyas ierisinde alan olay metodlar aadaki gibi dzenlenmelidir.

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Linq;
using System.Windows;
using System.Diagnostics;

namespace UsingApplicationObjects
{
public partial class App : Application
{
private void Application_Activated(object sender, EventArgs e)
{
Debug.WriteLine("Activated");
}

private void Application_Deactivated(object sender, EventArgs e)


{
Debug.WriteLine("DeActivated");
}
}
}

www.bsenyurt.com Page 904


Test amal bir kod yazld iin System.Diagnostics isim alannda
bulunan Debug snfn WriteLine metodu ile Output penceresine ktlar verilmektedir. Uygulama
ilk altrldnda ve output penceresine bakldnda Activated yazd grlecektir.
Eer Alt+Tab tular veya mouse ile uygulama dna klrsa output penceresine DeActivated
yazd grlecektir. Bir baka deyile Deactivated olay tetiklenmitir. Elbette tekrardan
uygulamaya dnlrse Activated olay yeniden tetiklenecektir.

Sradaki rneimizde Startup ve Exit olaylarn birlikte incelemeye alacaz. Bunun iin bize
rnek bir senaryo gerekmektedir. Application nesnesinin tm uygulama iin geerli olabiliecek
zellik(Property) ve kaynaklar(Resources) saklayabildiinden bahsetmitik. ok doal olarak
bunlar uygulamadan karken saklamak ve uygulama aldnda yeniden yklemek isteyebiliriz.
te bu noktada saklanan bilgileri okuma ilemini Startup olaynda, yazdrma ilemini ise Exit olay
ierisinde ele almalyz. Application nesnesi zerinden bir zellik tanm yapmak ve deerini
vermek son derece kolaydr. Tek yaplmas gereken Application snfnn Properties zellii ve
indeksleyicisinden yararlanmaktr. Ayn durum kaynaklar iinde geerlidir. rnein aadaki ekran
grntsnde zellik ekleme adm gsterilmektedir.

Dikkat edilecek olursa Properties zellii Dictionary bazl bir koleksiyondur ve object tipinden
anahtar-deer(key-value) iftleri ile almaktadr. Buda kendi tiplerimizi zellik olarak
tutabileceimiz anlamna gelir. Dier taraftan Resource yklemek iinde aadaki notasyon
kullanlr.

Resources zelliide aslnda ResourceDictionary tipinden bir koleksiyon dndrmektedir. Bu


koleksiyonda IDictionary arayzn uyarlayan ancak ierisinde Hashtable bazl alan hzl bir
koleksiyondur. (Resource ' lar Application elementi ierisinde ApplicationResource alt elementi
ierisindede tanmlayabiliriz. rnein pencerelerdeki kontroller iin ortak stilleri burada
belirleyebiliriz. Kaynak ynetimi konusunada ilerleyen yazlarmzda deinmeye alacam.)

Bu bilgilerden sonra StartUp ve Exit olaylarnn bildirimlerini yapp kodlayarak devam edebiliriz.
rnek senaryomuzda kullanc sembolik olarak bir pencere(Window) zerinden rn bilgisi girecek
ve bu bilgiler uygulama seviyesinde yazlm bir snfa ait rnekte saklanacaktr. Tahmin edilecei
zere tipe ait rnek Application nesnesinin zellii ile elde edilebilecektir. Urun snfn ayr bir fiziki
dosyada projeye ekleyip aadaki gibi gelitirebiliriz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace UsingApplicationObjects
{
class Urun

www.bsenyurt.com Page 905


{
public int Id;
public string Ad;
public double BirimFiyat;
}
}

Dikkat edilecek olursa, snfn ierisinde zellik(property) veya yapc metod(constructor) dahil
edilmemitir. Nitekim burada C# 3.0 ile gelen object initializers tekniinden yararlanlmak
istenmektedir. Bu anlamda Visual Studio 2008 Beta 2' nin C# 3.0 iinde tam
bir intellisense destei verdiini sylemeliyim. rnein Window1 zerinde yer alan bir Button
kontroln Click olay metodunda Urun snfna ait bir nesneyi object initializers teknii ile
oluturmak istediimizde bu destek ak bir ekilde grlmektedir.

Window1.xaml.cs dosyasnn ieriini aadaki gibi tasarlayabiliriz.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Collections;

namespace UsingApplicationObjects
{
public partial class Window1 : Window
{
public Window1()
{
InitializeComponent();
}

private void button1_Click(object sender, RoutedEventArgs e)


{
Urun bilgisayar = new Urun() { Id = 1000, Ad = "Bilgisayar", BirimFiyat = 1000
};
Application.Current.Properties["SonBakilanUrun"] = bilgisayar;
}
}
}

www.bsenyurt.com Page 906


Application nesnesi zerinden o anki uygulama referansna erimek iin Current zellii kullanlr.
Sonrasnda ise Properties zellii zerinden indeksleyici(indexer) yardmyla, oluturulan Urun
nesne rnei SonBakilanUrun adyla kaydedilir. Artk uygulama alma zamannda burada
oluturulan Application seviyesindeki zellie heryerden eriilebilir. Sz gelimi uygulamadan
karken bu zelliklerin ieriini saklamak istersek App.xaml.cs ierisinde Exit olayn aadaki gibi
kodlamamz yeterli olacaktr.

private void Application_Exit(object sender, ExitEventArgs e)


{
try
{
Urun sonUrun = (Urun)Application.Current.Properties["SonBakilanUrun"]; //
Properties koleksiyonuna eklenmi SonBakilanUrun isimli bir anahtar var ise bunun deeri Urun
tipinden elde edilir.
if (sonUrun != null) // Eer sonUrun nesne rnei null deilse...
{
IsolatedStorageFile storageFile = IsolatedStorageFile.GetUserStoreForDomain(); //
Bu uygulamann ve assembly' n kimlik (Identity) bilgisine gre izole edilmi kullanc odakl
depolama alannn elde edilmesini salar.
IsolatedStorageFileStream stream = new IsolatedStorageFileStream("GlobalApp
Properties.txt", FileMode.Create, storageFile); // Bu uygulama iin dierlerinden ayrlm olan
bir alana path' ten bamsz olacak ekilde GlobalAppProperties.txt dosyasnn almasn salar.
StreamWriter writer = new StreamWriter(stream); // izole edilmi alandaki dosya zerine
yazmak iin bir StreamWriter kullanlabilir.
writer.WriteLine(sonUrun.Id.ToString() + "|" + sonUrun.Ad + "|" +
sonUrun.BirimFiyat.ToString()); // Bilgiler text dosyasna yazdrlr.
writer.Close();
stream.Close();
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}

Tabiki burada illede IsolatedStorageFile kullanlmas gerekmemektedir. Bunun yerine ikili(binary)


veya xml seriletirmeden yararlanlabilir yada bilinen dosya saklama teknikleri tercih
edilebilir.MSDN kaynaklarnda bu konu ilenirken genel olarak
yukardaki IsolatedStorageFile tipinin kullanldn syleyebilirim.
Gelelim Application_Startup olay metodunun ierisine. Bu olay metodunu ise aadaki gibi
kodladmz dnelim.

private void Application_Startup(object sender, StartupEventArgs e)


{
try
{
IsolatedStorageFile storage = IsolatedStorageFile.GetUserStoreForDomain();
IsolatedStorageFileStream stream = new
IsolatedStorageFileStream("GlobalAppProperties.txt", FileMode.Open, storage);
StreamReader reader = new StreamReader(stream);
while (!reader.EndOfStream)
{
string[] keyValue = reader.ReadLine().Split(new char[] { '|' });
Urun urn = new Urun() { Id = Convert.ToInt32(keyValue[0]), Ad =

www.bsenyurt.com Page 907


keyValue[1].ToString(), BirimFiyat = Convert.ToDouble(keyValue[2].ToString()) };
Application.Current.Properties["SonBakilanUrun"] = urn;
}
}
catch (Exception exp)
{
MessageBox.Show(exp.Message);
}
}

Eer GlobalAppProperties.txt isimli dosya var ise buradan elde edilen deerlerden yararlanarak
Urun nesne rnei oluturulur ve Application nesnesinin zellikler koleksiyonuna eklenir. Sz
gelimi yklenen bu deeri yine bir Window' un yklenmesi srasnda ele aldmz dnebiliriz.
Bunun iin test olmas asndan aadaki gibi bir kod yazdmz dnebiliriz.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
Urun urn = (Urun)Application.Current.Properties["SonBakilanUrun"];
if (urn != null)
Title = urn.Ad.ToString(); // Bu pencerenin balnda Urun' un ad gsterilir.
}

Sonuta uygulama altrldnda Window ' un balk ksmnda aadakine benzer bir grnt elde
edilir.

Yaplan testlerde bilgisayarn kapatlp almasndan sonra da Application zelliklerinin


yazld dosyadan baarl bir ekilde okunabildii grlmtr.

Startup olayn komut satr parametrelerini almak iinde kullanabiliriz. Burada Startup olay
metodundaki StartupEventArgs parametresinin args isimli zellii string tipinden bir dizi
dndrmektedir. Bu zellik komut satrndan girilen parametre deerlerini tamaktadr. Ortam
Visual Studio 2008 Beta 2, platformda .Net Framework 3.0 olunca, C# 3.0 ile gelen extension
metodlar(rnein Select, Min, Max, Average, Where, Sum vb...) ve anahtar kelimelerinde
dorudan desteklendiini gryoruz. Aadaki ekran grntsnde bu durum ak bir ekilde
grlmektedir.

www.bsenyurt.com Page 908


rnek senaryomuzda komut satrnda, bir veritaban balants amak iin gerekli baz bilgileri
aldmz dnebiliriz. rnein bu bilgiler sunucu ad, veritaban ad, kullanc ad ve ifre olabilir.
Buna gre komut satrndan uygulamaya gnderilebilecek 4 farkl parametre sz konusudur. Bu
parametre deseninin aadaki gibi olduunu farz edelim.

ProgramAdi.exe s:LONDON d:AdventureWorks u:Burak p:1234

Buna gre Application snfnn Startup olay metoduna aadaki kodlar eklediimizi dnelim.

if (e.Args.Length == 4)
{
if (e.Args[0][0] == 's')
Application.Current.Properties["Sunucu"] = e.Args[0].Substring(2,
e.Args[0].Length-2);
if (e.Args[1][0] == 'd')
Application.Current.Properties["Veritabani"] = e.Args[1].Substring(2, e.Args[1].Length-2);
if (e.Args[2][0] == 'u')
Application.Current.Properties["Kullanici"] = e.Args[2].Substring(2, e.Args[2].Length-2);
if (e.Args[3][0] == 'p')
Application.Current.Properties["Sifre"] = e.Args[3].Substring(2, e.Args[3].Length-2);
}

Burada ok daha farkl algoritmalar dnlebilir. Temel ama, komut satrndan gelecek 4
parametreninde elde edilmesi ve bunlardan var olanlarn uygulama nesnesinin ilgili zelliklerine set
edilmesidir. Bundan sonraki admmzda, herhangibir pencerenin StatusBar kontrolnde, buradaki
bilgilerin ieriini gstermeye alacaz. Sz gelimi Window1 iinde bir StatusBar kontrolnde bu
bilgiler gsterilebilir. zlerek belirtmeliyimki bu StatusBar bileenide WPF' den nce
bildiimiz StatusStrip deil. tiraf etmek gerekirse, StatusBar ierisine kontrolleri atmak iin bir
sre uratm. Sonuta artk kontrolleri ve ieriklerininde hiyerarik bir XML yapsnda dnmemiz
gerektiini rendim. Buna gre StatusBar ierisinde barndrmak istediimiz her kontrol
bir StatusBarItem elementi ierisinde gz nne almalyz. Dolaysyla Window1.xaml ieriini
aadaki gibi gelitirmemiz gerekmektedir.

www.bsenyurt.com Page 909


<Window x:Class="UsingApplicationObjects.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Window1" Height="294"
Width="452" Loaded="Window_Loaded">
<Grid>
<Button Height="23" HorizontalAlignment="Left" Margin="16,57,0,0" Name="button1"
VerticalAlignment="Top" Width="75" Click="button1_Click">Button</Button>
<StatusBar Height="23" Name="stbBilgi" VerticalAlignment="Bottom">
<StatusBarItem>
<TextBlock Name="txtSunucu" Text="Sunucu:"></TextBlock>
</StatusBarItem>
<StatusBarItem>
<Separator/>
</StatusBarItem>
<StatusBarItem>
<TextBlock Name="txtVeritabani" Text="Veritaban:"></TextBlock>
</StatusBarItem>
<StatusBarItem>
<Separator/>
</StatusBarItem>
<StatusBarItem>
<TextBlock Name="txtKullanici" Text="Kullanc:"></TextBlock>
</StatusBarItem>
<StatusBarItem>
<Separator/>
</StatusBarItem>
</StatusBar>
</Grid>
</Window>

Dikkat edilecek olursa, her StatusBarItem ierisinde bir kontrol yer


almaktadr.TextBlock kontrollerinin Text zelliklerinden yararlanarak gerekli bilgileri
gsterebiliriz. Seperator kontrol ise bu haliyle basit olarak dier StatusBarItem kontrolleri
ierisindeki bileenlerin arasnda bir ayra grevi stlenmektedir. (WPF kontrolleri ile ilikili olarak
ilerleyen yazlarmzda detayl incelemeler yapmay dnyorum.) Window1.xaml.cs dosyasnda
ise Loaded olay metodunu amacmza ynelik olarak aadaki gibi kodlayabiliriz.

private void Window_Loaded(object sender, RoutedEventArgs e)


{
Urun urn = (Urun)Application.Current.Properties["SonBakilanUrun"];
if (urn != null)
Title = urn.Ad.ToString();

txtSunucu.Text += Application.Current.Properties["Sunucu"]!=null?
Application.Current.Properties["Sunucu"].ToString():"Tanml Deil";
txtVeritabani.Text += Application.Current.Properties["Veritabani"] != null ?
Application.Current.Properties["Veritabani"].ToString() : "Tanml Deil";
txtKullanici.Text += Application.Current.Properties["Kullanici"] != null ?
Application.Current.Properties["Kullanici"].ToString() : "Tanml Deil";
}

Artk testimizi gerekletirebiliriz. Parametreleri test edebilmek iin proje zelliklerine(Project


Properties) gidip Command Line Arguments ksmn aadaki gibi doldurmamz yeterli
olacaktr.

www.bsenyurt.com Page 910


Uygulama test edildiinde aadakine benzer bir sonu ile karlarz.

Bu son rneimizde komut satrnda WPF(Windows Presentation Foundation) uygulamasna


gelen parametreleri nasl ele alabileceimizi incelemeye altk. Dilerseniz yeni bir rnekle devam
edelim. Bu rneimizde uygulamann kapatma srecini kontrol altna almaya alacaz. Daha
ncedende belirttiimiz gibi, iletim sistemi seviyesinde gelebilecek olan kapatma taleplerini
uygulama ierisinden geri evirme ansna sahip olduumuzu sylemitik. Bunun
iin Application nesnesinin SessionEnding olay metodunu ele almamz yeterliydi. SessionEnding
olay metodunda kilit nokta SessionEndingEventArgs isimli parametredir. Bu parametre
zerinden eriilen ResonSessionEnding zellii ResonSessionEnding enum sabiti tipinden bir
deer alr. Bu enum sabitinin deerleri Logoff veya Shutdown' dr. SessionEndingEventArgs' n bir
dier nemli zellii ise Cancel yesidir. Bu zellie atanan deere gre srecin iptal edilmesi bir
baka deyile Shutdown veya Logoff' dan vazgeilmesi salanabilir. imdi olay metodumuzu
aadaki gibi tasarladmz dnelim. (Elbette SessionEnding olaynn yklenmesi iin
Application elementi ierisine ilgili nitelii eklemeyi unutmamalyz.)

private void Application_SessionEnding(object sender, SessionEndingCancelEventArgs e)


{
MessageBoxResult cevap=MessageBox.Show("Bilgisayar " +
e.ReasonSessionEnding.ToString() + " nedeniyle kapatlyor. ptal etmek ister misiniz?", "Kapatma
Sorusu", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (cevap == MessageBoxResult.No)
e.Cancel = true;
}

Buradaki kod parasnda sembolik olarak kullancya soru sorulmaktadr. Eer kullanc hayr
cevabn verirse iletim sisteminin kapanma sreci iptal edilir. Eer uzun bir sre cevap verilmesse
Windows' un standart End Program penceresi karmza kacaktr. Bu penceredeki progress

www.bsenyurt.com Page 911


tamamlandktan sonra bile No denildiinde Windows kapatma sreci yine iptal edilecektir.
Aadaki ekran grntsnde End Program ktsnnda ele alnd durum gsterilmektedir.

Session_Ending ierisinde daha nceden de bahsedildii gibi kritik kaynak kaydetme gibi ilemler
yaplabilir. Bir baka deyile uygulamann son durumunu (Application State) korumak adna
eitli tedbirler alnabilir.

Bir WPF uygulamasnn kapatlmas ile ilgili olarak ShutdownMode zelliinin deerlerine
bakldndan bahsetmitik. Bu zellii dorudan Application elementi ierisinde belirtebileceimiz
gibi kod yardmylada deitirebiliriz. Varsaylan hali OnLastWindowsClose olan bu deeri
aadaki gibi OnExplicitShutdown olarak deitirdiimizde, uygulamann kapatlabilmesi
iin Shutdown metodunun arlmas gerekmektedir.

imdi bunu test edelim. Bu amala uygulamaya ikinci bir Window daha dahil edilmi ve ana
pencereden Window2 penceresinin almas salanmtr. Window2 penceresini ama ilemini

www.bsenyurt.com Page 912


Window1 zerindeki bir Button kontrolne ait Click olay metodu ierisinde aadaki gibi
gerekletirmekteyiz.

private void btnDigerForm_Click(object sender, RoutedEventArgs e)


{
Window2 wnd2 = new Window2();
wnd2.Show();
}

imdi uygulamamz altralm. Sonradan alan Window2 kapatldnda uygulama doal olarak
sonlanmaz. Lakin ana pencere kapatldnda da uygulama sonlanmaz. Bu iki aksiyonu yaptmzda
ve arka planda alan Process' lere baktmzda uygulamann gerektende sonlandrlmadn
grebiliriz. Aadaki ekran grntsnde bu durum ak bir ekilde grlmektedir.

Dolaysyla programdan kmak iin Shutdown metodunun bilinli olarak arlmas


gerekmektedir. Bunun iin Window1 ierisinden baka bir Button yardmyla aadaki gibi bir
metod arsnda bulunduumuzu dnebiliriz. Dikkat edilecek olursa o anki uygulama nesnesi
zerinden Shutdown metodu arlabilmektedir.

private void btnKapat_Click(object sender, RoutedEventArgs e)


{
Application.Current.Shutdown();
}

Artk uygulamamz baarl bir ekilde kapatlabilir. Daha nceden de belirtildii gibi, iletim
sistemine bir k koduda gnderilebilir. Bunun iin Shutdown metodunun ar yklenmi
versiyonunu kullanmamz ve bir integer deeri parametre olarak vermemiz yeterlidir.

Yazmzda son olarak kod ierisinden frlatlan


istisnalarn DispatcherUnhandledException olaynda nasl yorumlanabileceini inceleyeceimiz
bir rnek gelitireceiz. Bu amala uygulama ierisinden bilinli olarak bir istisna(exception) nesne
rnei frlatmamz yeterli olacaktr. Window1 ierisinde bu amala iki farkl Button kontrol
yerletirilmi ve farkl istisna(Exception) nesne rneklerinin frlatlmas salanmtr.
Window1.xaml.cs ierisindeki yeni kodlar aadaki gibidir.

private void btnArgumentException_Click(object sender, RoutedEventArgs e)


{
throw new ArgumentException();
}

private void btnStackOverFlow_Click(object sender, RoutedEventArgs e)


{
throw new StackOverflowException();
}

imdi uygulamay test edersek .Net Framework 3.0 alma zamannn (Run-time) aadaki
standart pencereyi karttn grrz. stelik penceredeki cevabmzdan sonra rapor gndersekte,
gndermesekte uygulamann sonlandn grrz.

www.bsenyurt.com Page 913


stersek bu pencerenin kmasn engelleyebiliriz. Bunun iin, kod ierisinden ele
alnmam(Unhandled Exceptions) istisnalarn ele alnacan belirtmemiz gerekmektedir. Bu
amac gerekletirmek iin DispatcherUnhandledException olaynda yer
alan DispatcherUnhandledExceptionEventArgs parametresinin Handled zelliine true deeri
ni atamamz yeterlidir. Ancak bu sadece ele alnmam istisnalar iin geerlidir. Hatta ele
alnamayacak cinsten bir istisna olduunda da bu kontrol yeterli gelmeyebilir. Ne demek
istediimizi biraz daha net anlayabilmek iin olay metodlarmzda bir deiiklik yapalm
ve ArgumentException istisnasn yakalayacamz bir try...catch blounu aadaki gibi
uygulama koduna dahil edelim.

private void btnArgumentException_Click(object sender, RoutedEventArgs e)


{
try
{
throw new ArgumentException();
}
catch (Exception excp)
{
MessageBox.Show("Bir istisna olutu");
}
}

Uygulama bu ekilde test edildiinde ve ArgumentException istisnas


oluturulduunda, try...catch bloklarndan dolay .Net Framework' n alma zaman istisna
ynetim mekanizmas devreye girerek yukarda yer alan hata mesaj kutusunu gstermeyecektir.
Bunun sebebi hatann uygulama kodu ierisinde kontroll bir ekilde try...catch bloklar ile ele
alnm(Handled) olmasdr. Ancak ele alnmam istisnalar varsa ve bunlar olutuunda loglama
gibi ek ilemler yaplmak isteniyor ve kurtarlabilirse uygulamann almasna devam etmesi
isteniyorsa DispatcherUnhandledException olay aadaki ekilde olduu gibi deitirilebilir.

private void Application_DispatcherUnhandledException(object sender,


DispatcherUnhandledExceptionEventArgs e)
{
// Burada EventLog dndan bir dosyaya yazdrma ilemleride gerekletirilebilir.
EventLog.WriteEntry("Application", "X Uygulamasnda "+DateTime.Now.ToString()+" zamannda
"+e.Exception.Message+" hatas alnmtr.", EventLogEntryType.Error); // e parametresi
zerinden oluan istisna referans Exception zellii ile yakalanabilir.

www.bsenyurt.com Page 914


e.Handled = true; // Eer oluan istisna kurtarlabilecek cinstense, standart hata mesaj
kutusunun kartlmamas ve uygulamann almaya devam etmesi salanm olur. Bu zelliin
varsaylan deeri false dur.
}

Bu makalemizde WPF uygulamalarnda ekirdek nesnelerden birisi olan Application nesnesini


incelemeye altk. Makalemizi sonlandrmadan nce sizlere WPF ile ilikili faydal olabilecek bir ka
kitap tavsiye etmek isterim.

Essential Windows Presentation Foundation

Addison Wesley yaynlarnn Essential serisinde yer alan kitaplar ounlukla


ierikleri bakmndan ileri seviye konular dahi ieririler. Bu nedenle bu kitap tam
anlamyla bir bavuru kayna olarak dnlebilir. Zaman zaman okura ar
gelebilecek bir ierie sahip olsada kitaplmzda olmas gereken bir kitap.

Pro WPF : Windows Presentation Foundation in .Net 3.0

u sralarda okumakta olduum bu kitap olduka baarl. stelik son kan WPF
kitaplarndan birisi.1000 sayfa olmas nedeniyle okumas biraz zaman alyor :)
Ancak ieriinde WPF ile ilgili hemen her bilgiye ulaabiliyoruz. Bu kitab srarla
tavsiye ederim.

Professional WPF Programming

Dierlerine gre daha az sayfadan(480 sayfa) oluan bu kitap


ierisinde Expression Blend ile ilgili bir blmde yer almakta. ok ksa srede
okunabilecek bir kitap ama baz yerlerde ok fazla detaya girilmedii iin baka
kaynaklara bakmay gerektirebiliyor.

Programming WPF

O'Reilly yaynlarndaki favori yazarm Juval Lowy' ye ait bir kitap olmasada(Onun
Programming WCF kitab bir harika) yeni kan bir yayn olmas ve 863
sayfalk(kabul edilebilir bir sayfa adedi) ieriinin bulunmas bu kitabn okunmas
iin yeterli. Sz gelimi birinci blmn okuduunuzda, WPF in temel yapsnn
renmi ve en byk elementlerini kavram oluyorsunuz.

Application nesnesi ile ilgili olarak deinmediimiz pek ok nokta var. Sz gelimi bu nesneden
yararlanarak uygulamadaki tm pencere yada formlar elde edebiliriz. Application' dan tretilen
App snf ierisine, tm uyguladaki nesnelerin eriebilecei yeler(Metodlar veya zellikler)
koyabiliriz vb. Bu tip konularn ve dahasnn aratrlmasn siz deerli okurlarma brakyorum.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 915


WCF - Client Callback (stemci Tarafl Geri
Bildirim) ( 23.08.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Servis ynelimi mimari (Service Oriented Architecture) zerine gelitirilen sistemler


istemci/sunucu(client/server) tabanl bir iletiimi olanakl klarlar. Bu sistemlerde sreler
ounlukla istemciden sunucuya doru yaplan operasyon talepleri(Request) ve servis tarafndan
istemciye geri dnen cevaplardan(Response) ibarettir. Oysaki baz SOA vakkalarnda rollerin tam
tersine evrilmesi gerekebilir. Bir baka deyile servislerin yeri geldiinde bir istemci gibi hareket
etmesi istenebilir. Sz gelimi bir stok sisteminde yer alan bir servis parasnda, istemcilerin stok
zerinde servis yardmyla yapaca hareketleri gz nne alalm. Bu stok hareketleri istemciden
gelecek olan operasyon arlar sonucu servis tarafnda ele alnyor olsunlar. Buna gre, servise
bal dier istemcilerinde durumdan haberdar olmas istenebilir. Bu bir uyar sistemi olarakda gz
nne alnabilir. Byle bir sistemde ncelikli olarak servis tarafndaki uygulamann istemci tarafnda
yer alan belirli operasyonlar arabiliyor olmas gerekmektedir. Dier taraftan, servis uygulamas
kendisine bal istemcilerin hepsinde bir yaynlama yapmak istiyorsa, olay(event) ynelimli bir
model gelitirilmesi sz konusu olmaldr. Bu makalemizde Windows Communication
Foundation sisteminde istemci tarafl geri bildirimlerin (Client Callback) nasl yaplabileceini ok
basit olarak incelemeye alacaz.

WCF (Windows Communication Foundation), standart istemci sunucu modeli dnda


rollerin tersine dnebilecei iki modeli daha destekler. Bunlar peer-to-peer modeli
veclient callback modelidir. Peer-to-peer modeline gre tm istemciler aktif ve bamsz
olarak birer servistir ve birbirleriyle mesajlaabilir. Client Callback modelinde ise servisler,
istemci tarafnda metod arlar gerekletirebilecek durumdadr.

lk hedef, servis uygulamasnn istemci tarafndaki bir metodu arabilmesini salamak olmaldr.
WCF tarafndan bakldnda, balayc tiplerin(binding types)tamamnn geri bildirim ilemlerini
desteklemedii grlr. Bunun sebebi kullanlan protokoldr. TCP ve IPC gibi protokoller istemci
geri bildirim ilemlerinde doalar gerei dorudan destek vermektedir. Bu
sebepten NetTcpBinding yada NetNamedPipeBinding gibi balayc tipler istemci geri bildirim
ilemlerini doal olarak desteklemektedirler. Ancak HTTPprotokol
balantsz(connectless) olarak alan bir model olduundan geri bildirimi(Callback) dorudan
desteklemez. Bu nedenle BasicHttpBinding veya WsHttpBinding gibi balayc tipleri ile Client
Callback modeli gelitirilemez. Ancak HTTP protokolnnde bu sistemi ift ynl kanallar aarak
gerekletirmek mmkndr. Tahmin edilecei gibi bu kanallardan birisi servisden istemciye doru,
dieri ise ters ynde istemciden servise doru olmaldr. Bunu, tek ynl iki HTTP kanal olarakta
dnebiliriz. WCF ierisinde yer alan balayc tiplerinde WsDualHttpBinding tam olarak bu amala
tasarlanmtr. Bu nedenle WsDualHttpBinding balayc tipini kullanarak, HTTP protokoln baz
alacak ekilde Client Callback destekli uygulamalar gelitirilebilir.

lk olarak bir servisin istemci tarafndaki bir operasyonu nasl arabileceini rnek bir uygulama
zerinden incelemeye alalm. Balamadan nce servis tarafnda ve istemci tarafnda yapmamz
gerekenlerin neler olduunu vurgulamakta yarar var. Servis tarafnda geri bildirim iin bir
arayz(Interface) tanmlanmaldr. Bu arayz istemci tarafnda, herhangibir
snfa(Class) uygulanmaldr. stemciler, kullanmak istedikleri servise ait bir rnek
oluturduklarnda, servis tarafna bir referans verilmelidir. Bu referans kullanarak servisler,
istemciler zerindeki metodlar tetikleyebilirler. Dolaysyla istemci tarafnda geri bildirim tipinin
uygulad bir arayzn var olmas ve bunun servis tarafnda tanmlanm olmas gerekir. Bu
cmleler biraz kafa kartrc olabilir. Bu durum daha ksa bir ekilde; istemcideki bir nesne
referansnn servis tarafndan elde edilebilmesi ve onun sayesinde istemci zerinde, sz konusu
arayz uygulayan bir snfn metodunun servis tarafndan arlabilmesi eklinde de ifade

www.bsenyurt.com Page 916


edilebilir. ncelikle servis szlemesini(Service Contract), geri bildirim szlemesini(Callback
Contract) ve i yapan servis tipini barndracak WCF Class Library projesini gelitirerek
rneimize balayalm. WCF snf ktphanemizdeki tiplerin snf izelgesindeki durumu ve kodlar
aadaki gibidir.

IGeriBildirimSozlesmesi isimli arayz(interface) geri bildirim szlemesinin(Callback


Contract) tanmn yapmaktadr. Bu tanma gre, servisin istemciler zerinden tetikleyebilecei
metod, int tipinden parametre alan ve geriye deer dndrmeyen bir ekilde tanmlanmtr. Geri
bildirim szlemesinin ierii ise aadaki gibidir.

using System;
using System.ServiceModel;

namespace UrunServisi
{
// Callback Contract tanmlanrken, ServiceContract nitelii kullanlmaz.
public interface IGeriBildirimSozlesmesi
{
// Servisin istemciden araca geri bildirim metodundan geriye cevap beklenmesine gerek
olmadndan IsOneWay zelliine true deeri atanmtr.
[OperationContract(IsOneWay = true)]
void OnStokMiktariDegisti(int degistirilenUrunId);
}
}

Tanmlanan bu szlemede dikkat edilmesi gereken en nemli noktalardan


biriside ServiceContract niteliinin uygulanmam olmasdr. Bir geri bildirim
szlemesinde,OperationContract nitelii ile, servisin istemciler zerinden arabilecei
operasyonlarn bildirilmesi yeterlidir.

www.bsenyurt.com Page 917


Servis szlemesi IUrunYoneticiSozlesmesi isimli arayz(interface) ile tanmlanmaktadr. Bu
arayzn kodlar ise aadaki gibidir.

using System;
using System.ServiceModel;

namespace UrunServisi
{
// Servis szlemesinde, Callback szlemesini bildirmek iin CallbackContract zellii kullanlr.
[ServiceContract(CallbackContract=typeof(IGeriBildirimSozlesmesi))]
public interface IUrunYoneticiSozlesmesi
{
[OperationContract()]
void StokMiktariniArttir(int gelenMiktar, int urunNo);
}
}

Burada dikkat edilmesi gereken


nokta, ServiceContract niteliinde CallbackContract tanmlamasnn yaplm olmasdr. Bu
sayede, sz konusu arayz uygulayan servis snfnn, geri bildirim ilemleri srasnda hangi arayz
ile tanan referanslar ele alaca ak bir ekilde bildirilmi
olunur. CallbackContract zellii, type tipinden bir deer ald iin typeof operatrne
bavurulmutur ve geri bildirim szlemesi olan IGeriBildirimSozlesmesi parametre olarak
verilmitir. Servis szlemesini uygulayan snfa ait kodlar ise aadaki gibidir.

using System;
using System.Data;
using System.ServiceModel;
using System.Data.SqlClient;

namespace UrunServisi
{
public class UrunYonetici:IUrunYoneticiSozlesmesi
{
#region IUrunYoneticiSozlesmesi Members

public void StokMiktariniArttir(int gelenMiktar,int urunNo)


{
string sorgu = "Update Products Set UnitsInStock=UnitsInStock+@GelenMiktar Where
ProductID=@PrdId";
using (SqlConnection conn = new SqlConnection("data
source=.;database=Northwind;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand(sorgu, conn);
cmd.Parameters.AddWithValue("@GelenMiktar", gelenMiktar);
cmd.Parameters.AddWithValue("@PrdId", urunNo);
conn.Open();
int guncellenen=Convert.ToInt32(cmd.ExecuteNonQuery());
if (guncellenen > 0)
{
IGeriBildirimSozlesmesi geriBildirim =
OperationContext.Current.GetCallbackChannel<IGeriBildirimSozlesmesi>();
if (((ICommunicationObject)geriBildirim).State ==

www.bsenyurt.com Page 918


CommunicationState.Opened)
{
geriBildirim.OnStokMiktariDegisti(urunNo);
}
}
}
}

#endregion
}
}

UrunYonetici isimli snf ierisinde StokMiktariniArttir isimli bir metod yer almaktadr. Bu metod
sembolik olarak, gelen rn numarasna gre Northwind veritabanndaki Productstablosunda yer
alan UnitsInStock alannn deerini gelenMiktar parametresinin deeri kadar arttrmaktadr. te
burada servisin, istemci tarafnda stok miktarnn arttrldna dair bir geri bildirimde bulunmas
salanmaktadr. Bunun iin, istemcinin servis tarafnda gnderdii ierik
rneinin (InstanceContext) ele alnmas gerekmektedir. stemciler, servise talepte
bulunduklarnda WCF alma ortam(WCF Runtime), o anki kapsama ait ierik rneinin
referansnda mesaj ile birlikte gnderecektir.

OperationContext snfnn Current zellii zerinden arlan GetCallbackChannel generic


metodu ile, IGeriBildirimSozlesmesi tarafndan tanabilecek bir istemci referans elde edilir. te bu
referans, istemci tarafnda geri bildirim szlemesini uyarlayan snfa aittir. Arayzlerin
polimorfik(Polymorphic) yaps nedeni ile, OnStokMiktariDegisti metoduna yaplacak olan ar,
aslnda istemci tarafndaki metoda yaplmaktadr. zetle servis, istemci tarafndaki bir geri bildirim
metodunu tetiklemektedir. stemci uygulama, servis ile olan balantsn herhangibir anda kesebilir.
zellikle OneWay olarak iaretlenmi bir callback operasyonunda bu sorun oluturur. Bu nedenle,
geri bildirim kanalnn ak olduundan emin olup geri bildirim metodunu armak
amacyla, ICommunicationObject arayzne dntrme(cast) ilemi yaplarak State zelliinin
deerine baklmaktadr. State zellii, CommunicationState enum sabiti tipinden bir deer
almaktadr ve rnekte Opened olmas halinde geri bildirim arsnn yaplmas salanmaktadr.
Artk servis szlemesini yaynlayacak Host uygulamann yazlmasna geilebilir. Host uygulama,
basit bir Windows uygulamas olarak tasarlanabilir. Bu uygulamann ekran grnts basit olarak
aadaki gibidir.

ekildende tahmin edilecei zere, program kullancs servisi ama ve kapatma ilemlerini manuel
olarak yapmaktadr. Sunucu uygulamann kodlar aadaki gibi gelitirilebilir.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;

www.bsenyurt.com Page 919


using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.ServiceModel;
using UrunServisi;

namespace Sunucu
{
public partial class Form1 : Form
{
ServiceHost host;

public Form1()
{
InitializeComponent();
btnServisiKapat.Enabled = false;
}

private void ServisiHazirla()


{
host = new ServiceHost(typeof(UrunYonetici));
host.Opening += delegate(object sender, EventArgs e)
{
lblServisDurumu.Text = "Servis Alyor...";
};

host.Opened += delegate(object sender, EventArgs e)


{
lblServisDurumu.Text = "Servis Ald";
btnServisiAc.Enabled = false;
btnServisiKapat.Enabled = true;
};
host.Closing += delegate(object sender, EventArgs e)
{
lblServisDurumu.Text = "Servis Kapatlyor...";
};
host.Closed += delegate(object sender, EventArgs e)
{
lblServisDurumu.Text = "Servis Kapatld.";
btnServisiAc.Enabled = true;
btnServisiKapat.Enabled = false;
};
}

private void btnServisiAc_Click(object sender, EventArgs e)


{
ServisiHazirla();
host.Open();
}

private void btnServisiKapat_Click(object sender, EventArgs e)


{
host.Close();
}
}
}

www.bsenyurt.com Page 920


Servis uygulamasnda, ServisHost rneklemesi yaplmakta ve servisin durumunu daha kolay
izleyebilmek asndan gerekli olaylar generic metodlar yardmyla yklenmektedir. Bylece
program kullanclar, servisin almas ve kapanmas durumunu kolay bir ekilde izleyebilecektir.
Her zamanki gibi sunucu uygulama, WCF altyaps iin gerekliSystem.ServiceModel.dll ile servis
szlemesini ieren UrunServisi.dll isimli snf ktphanesini(WCF Class Library) referans
etmektedir. Bunlara ek olarak sunucu uygulamann WCF iin gerekli konfigurasyon bilgileri ise
aadaki gibi app.config dosyasnda yer almaktadr.

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


<configuration>
<system.serviceModel>
<services>
<service name="UrunServisi.UrunYonetici">
<endpoint address="net.tcp://localhost:9001/UrunServisi.svc" binding="netTc
pBinding" name="UrunServisiEndPoint" contract="UrunServisi.IUrunYoneticiSozlesmesi" />
</service>
</services>
</system.serviceModel>
</configuration>

Bu rnekte NetTcpBinding balayc tipi kullanlmaktadr. stemci tarafn yazmadan nce, gerekli
proxy snfnn retilmesi gerekmektedir. Bu noktada svcutil.exe aracndan aadaki gibi
yararlanlabilir.

Servis tarafnda geri bildirim szlemesi var olduundan, retilen proxy snf dier retimlere gre
biraz daha farkldr. Bu fark grmek iin proxy snf ve beraberinde retilen tiplerin snf
diagramna(class diagram) bakmak yeterlidir.

www.bsenyurt.com Page 921


Hereyden nce, istemci uygulamada, servis tarafndan arlabilecek bir geri bildirim opreasyonun
sz konusu olabilmesi iin, proxy snfnn generic DuplexClientBase zet snfndan(abstract
class) tremi olmas gerekmektedir. Dier taraftan svcutil.exe bu ilemi otomatik olarak
yapmaktadr. rnekte dikkat edilirse, geri bildirim szlemesi tipi, DuplexClientBase snfnn
generic parametresi olarak kullanlmaktadr. Bunun dnda, proxy snfnn ar
yklemi(overload) yapc metodlarnn(constructor) tamamnda ilk
parametreler InstanceContext snf tipindendir. Bu son derece doaldr. Nitekim, servisin istemci
zerindeki bir operasyonu arabilmesi iin, istemcinin kendisine verdii ierik referansn
kullanmas gerekmektedir. Bu nedenle yapc metodun ilk parametresi bu referans istemciden
servis tarafna gndermek iin kullanlr.

imdi gelelim istemci geri bildirim szlemesini uyarlayan snfa. Bu snf gelitirici tarafndan
yazlmaldr. rnekte bu amala Uygulayici isimli bir snf kullanlmtr.

Uygulayici isimli snfn en byk zellii IUrunYoneticiSozlesmesiCallback isimli


arayz(interface) uyguluyor olmasdr. Burada, arayz adnn sonundaki Callback kelimesi
dikkat ekicidir. Svcutil.exe arac bunu otomatik olarak eklemektedir. Bunun dnda Uygulayici
snf, IDisposable arayznde uygulamaktadr ki burada ama proxy rneinin yok edilmesi
srasnda servis ile olan balanty kapatmaya zorlamaktr. Uygulamaci snfna ait kodlar aadaki
gibidir.

www.bsenyurt.com Page 922


using System;
using System.ServiceModel;

namespace Istemci
{
/* Servisin, istemci tarafnda bir geri bildirim operasyonu ars yapabilmesi iin geri bildirim
szlemesini uygulayan bir snfn yazlmas gerekir. */
public class Uygulayici:IUrunYoneticiSozlesmesiCallback,IDisposable
{
private UrunYoneticiSozlesmesiClient proxy=null;

public Uygulayici()
{
proxy = new UrunYoneticiSozlesmesiClient(new InstanceContext(this),
"DefaultBinding_IUrunYoneticiSozlesmesi_IUrunYoneticiSozlesmesi");
}

public void StokMiktariniArttiralim(int artisMiktari,int urunNumarasi)


{
proxy.StokMiktariniArttir(artisMiktari, urunNumarasi);
Console.WriteLine("{0} numaral rnn stok miktarnda {1} adet art
yapld",urunNumarasi,artisMiktari);
}
#region IUrunYoneticiSozlesmesiCallback Members

public void OnStokMiktariDegisti(int degisenUrunId)


{
Console.WriteLine("{0} numaral rnn stok miktarnda deiiklik
oldu.",degisenUrunId.ToString());
}

public void Cikart()


{
proxy.AboneligiKaldir(); /* Abonelik kartma ilemi yaplmad takdirde istemci uygulama
istisna mesajlar alabilir. Bunun iin istemcide alan bir abonelik var ise bunun bilinli olarak
kapatlmasndada yarar vardr. Cikart metodu buna destek vermesi amacyla gelitirilmitir. */
}

#endregion

#region IDisposable Members

public void Dispose()


{
proxy.Close();
}

#endregion
}
}

Snfn yapc metodu ierisinde proxy snfna ait bir nesne rneklenmektedir. Servisin kendisine
bal istemci zerinde bir geri bildirim fonksiyonu arabilmesi iin geri bildirim arayzn
uygulayan tipe ait referansn, proxy oluturulurken servise bildirilmesi gerekir. Bunun iin proxy
snfna ait yapclarn ilk parametreleri daima InstanceContexttipinden bir referans alr. Servis
tarafnda bu ierik rneinden(InstanceContext) yararlanlarak metod ars yapldnda, WCF

www.bsenyurt.com Page 923


alma zaman bu snf ierisindeki ilgili metodu aracaktr ki bu rnekte sz konusu
metod OnStokMiktariDegisti dr. Snf ayn zamanda Dispose metodu ierisinde proxy snfnn
Close metodunuda armaktadr. Bunun sebebi udur; stemci servis tarafnn callback arsn
beklemeden proxy' yi kapatrsa servis tarafnda hatalar oluabilir. Bu nedenle Dispose metodu
ierisinden Close metodu arlr. Artk istemci tarafnda Console uygulamasna
ait Main metodunun ieriini aadaki gibi gelitirebiliriz.

using System;
using System.ServiceModel;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("lemlere balamak iin tklayn");
Console.ReadLine();

Uygulayici uyg = new Uygulayici();


uyg.StokMiktariniArttiralim(10, 1);

Console.ReadLine();
}
}
}

Artk testlere balanabilir. nce sunucu uygulamann altrlmas ve servisin almas


gerekmektedir. Ardndan istemci uygulama altrlarak devam edilirse aadakine benzer ekran
grntleri ile karlalr.

Burada grld gibi, istemci tarafnda servis zerindeki StokMiktariniArttir metodu arldktan
sonra, serviste istemci tarafndaki OnStokMiktariDegisti metodunu altrmtr.

Buraya kadar gelitirilen rnek sadece servis tarafndan istemcideki bir metodun client callback
modeli ile nasl altrabileceidir. Oysaki gerek hayat senaryolarnda, bir istemcinin aksiyonu

www.bsenyurt.com Page 924


sonras dier tm istemcilerinde servis tarafndan haberdar edilmesi istenebilir. Bu durumda
servisin kendisine bal olan istemcileri bilmesi, bunlarn referanslarn tutmas gerekmektedir.
Ayrca istemciler dier istemcilerin aksiyonlarndan servis yoluyla haberdar edilip
edilmeyeceklerinide belirleyebilmelidirler. Ksacas, istemcinin kendisini servis tarafna istedii
zaman abone edebilmesi(Subscribe) ve istedii zamanda abonelikten
kartabilmesi(Unsubscribe) gerekmektedir. Aadaki ekiller ile durum daha net anlalabilir.

lk olarak istemcilere ait rneklerin servis tarafna bildirilmesi bir baka deyile abone edilmesi sz
konusudur.

stemciler servis zerinde operayon arlar gerekletirirler. Bu arlardan haberdar olmak


isteyenler servise abone olurken istemeyenler abonelikten karlar veya hi abone olmazlar. Servis
ise kendisine abone olanlar zerinden geri bildirim metodlarn arabilir ve bylece bilgilendirme
yapabilir. rnein aadaki senaryoya gre, daha nce abone olmu olan stemci A abonelikten
ktktan sonra, istemci D' nin yapaca Stok Miktar Deitirme ileminden, stemci B, stemci C ve
stemci D' nin kendisi haberdar olabilir.

www.bsenyurt.com Page 925


imdi bu ilemi adm adm yapmaya alalm. lk olarak servis szlemesine, istemcilerin abone
olabilmek ve abonelikten kabilmek iin arabilecekleri iki metod tanm eklenmesi
gerekmektedir. Bunun iin IUrunYoneticiSozlesmesi arayzne(interface) aadaki eklemelerin
yaplmas yeterlidir.

using System;
using System.ServiceModel;

namespace UrunServisi
{
[ServiceContract(CallbackContract=typeof(IGeriBildirimSozlesmesi))]
public interface IUrunYoneticiSozlesmesi
{
[OperationContract()]
void StokMiktariniArttir(int gelenMiktar, int urunNo);

[OperationContract()]
void AboneOl();

[OperationContract()]
void AboneligiKaldir();
}
}

Bu deiiklikler nedeniyle, servis szlemesini uygulayan UrunYonetici snf ierisindede AboneOl


ve AboneligiKaldir metodlarnn yazlmas gerekmektedir. stemcilerin geri bildirim referanslarnn
servis tarafnda saklanabilmesi iin generic bir liste koleksiyonu(List<T>) kullanlabilir. AboneOl
metodu ile bu koleksiyona istemcinin geri bildirim referans eklenirken, AboneligiKaldir metodu
ilede istemciden gelen geri bildirim referansnn ilgili koleksiyondan kaldrlmas salanr.
stemcilere yaynlama yapacak olan ayr bir metod ise, istenildiinde servis tarafndan koleksiyonda
tutulan tm istemci geri bildirim referanslarna ait metodlarn arlmas grevini stlenir. Bu
bilgiler nda UrunYonetici snfnn aadaki gibi dizayn edilmesi yeterlidir.

using System;
using System.Data;
using System.ServiceModel;
using System.Data.SqlClient;
using System.Collections.Generic;

namespace UrunServisi
{
public class UrunYonetici:IUrunYoneticiSozlesmesi
{
// stemcilerin geri bildirim referanslarn tutacak olan List<T> koleksiyonu.
private static List<IGeriBildirimSozlesmesi> geriBildirimAboneleri = new
List<IGeriBildirimSozlesmesi>();

#region IUrunYoneticiSozlesmesi Members

// stemcilerin servis tarafndaki geri bildirim listesine abone olmasn salayan metod.
public void AboneOl()
{
// Servise o anda bal olan istemcideki IGeriBildirimSozlesmesi arayzn uygulam snf
referans alnr.
IGeriBildirimSozlesmesi geriBildirim =

www.bsenyurt.com Page 926


OperationContext.Current.GetCallbackChannel<IGeriBildirimSozlesmesi>();
// Eer List<> kolekisyonunda gelen istemci geri bildirim referans yoksa eklenir.
if (!geriBildirimAboneleri.Contains(geriBildirim))
geriBildirimAboneleri.Add(geriBildirim);
}

// stemcilerin, servis tarafndaki geri bildirim abonleri listesinden kartlmasn salayan


metod.
public void AboneligiKaldir()
{
IGeriBildirimSozlesmesi geriBildirim =
OperationContext.Current.GetCallbackChannel<IGeriBildirimSozlesmesi>();
// stemci geri bildirim referans, List<> koleksiyonundan kartlr.
geriBildirimAboneleri.Remove(geriBildirim);
}

private void AboneleriBilgilendir(int urunNumarasi)


{
/* List<> koleksiyonundaki tm geri bildirim referanslar dolalr ve sahibi olan istemci
uygulama halen daha alyorsa (ki bu durum State ile tespit edilmektedir), istemci zerindeki geri
bildirim operasyonu arlr. */
foreach (IGeriBildirimSozlesmesi geriBildirim in geriBildirimAboneleri)
{
if (((ICommunicationObject)geriBildirim).State ==
CommunicationState.Opened)
geriBildirim.OnStokMiktariDegisti(urunNumarasi);
else // Eer istemci canl deilse, servis tarafndaki List<> koleksiyonundan da kartlr.
geriBildirimAboneleri.Remove(geriBildirim);
}
}

public void StokMiktariniArttir(int gelenMiktar,int urunNo)


{
string sorgu = "Update Products Set UnitsInStock=UnitsInStock+@GelenMiktar Where
ProductID=@PrdId";
using (SqlConnection conn = new SqlConnection("data
source=.;database=Northwind;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand(sorgu, conn);
cmd.Parameters.AddWithValue("@GelenMiktar", gelenMiktar);
cmd.Parameters.AddWithValue("@PrdId", urunNo);
conn.Open();
int guncellenen=Convert.ToInt32(cmd.ExecuteNonQuery());
if (guncellenen > 0)
{
AboneleriBilgilendir(urunNo);
}
}
}

#endregion
}
}

www.bsenyurt.com Page 927


Servis tarafndaki bu deiikliklerin ardndan, istemci iin gerekli proxy snfnn svcutil.exe arac
yardmyla yeniden retilmesi gerekmektedir. Bu retim ilemi sonrasnda istemci tarafna atanan
tiplerin son hali aadaki ekran grntsndeki gibi olacaktr.

stemci tarafnda geri bildirim szlemesini uygulayan Uygulayici isimli snfn yapc metodu
ierisinde AboneOl metodu altrlmaktadr.

using System;
using System.ServiceModel;

namespace Istemci
{
public class Uygulayici:IUrunYoneticiSozlesmesiCallback,IDisposable
{
private UrunYoneticiSozlesmesiClient proxy=null;

public Uygulayici()
{
proxy = new UrunYoneticiSozlesmesiClient(new InstanceContext(this),
"DefaultBinding_IUrunYoneticiSozlesmesi_IUrunYoneticiSozlesmesi");
proxy.AboneOl();
}
// Dier kod satrlar
}
}

Main metodu ierisinde ise aadaki test kodlar yazlabilir.

static void Main(string[] args)


{
try
{
Console.WriteLine("lemlere balamak iin tklayn");

www.bsenyurt.com Page 928


Console.ReadLine();

Uygulayici uyg = new Uygulayici();


Console.WriteLine("Abonelik balatld.Devam etmek iin bir tua basn");
Console.ReadLine();
uyg.StokMiktariniArttiralim(10, 1);
uyg.Cikart();
}
catch (Exception exp)
{
Console.WriteLine(exp.Message);
}
Console.ReadLine();
}

Uygulamay bu haliyle test etmeye balayabiliriz. Servis uygulamas altrldktan sonra, bir
katane istemcinin altrlmas ve bunlardan herhangibirinde rn stok miktarnn deitirilmesi
ileminin yaplmas yeterlidir. Yaplan testlerde, bir istemcinin urun stok miktarnda yapt
deiiklik sonras, dier istemcilerinde ilgili deiiklikten haberdar edildii grlmektedir. Aadaki
ekran grntsnde bu testin sonular yer almaktadr.

www.bsenyurt.com Page 929


Gelitirilen rnek TCP protokoln kullanan netTcpBinding balayc tipine ele almaktadr. Oysaki
HTTP protokolnde varsaylan olaran client callbak destei olmadndan yazmzn banda
bahsetmitik. Client Callback destei iin ift ynl HTTP kanallarna ihtiya vardr. Bir baka
deyile tek ynl iki adet kanal HTTP protokol zerinden kullanlarak istenen sistem kurulabilir.
WCF ierisinde bu destei WsDualHttpBinding tipi karlamaktadr. Yazlan rnei, HTTP destekli
hale getirmek iin servis ve istemci tarafnda yaplmas gerekenler vardr. Servis tarafndan ift
kanall HTTP desteini vermesi iin WsDualHttpBinding tipini kullanan yeni bir endPoint bildirimi
yaplmaldr. Bu amala servis uygulamasndaki App.Config dosyasna aadaki bildirim ile yeni
endPoint ilave edilir.

<endpoint address="http://localhost:4500/UrunServisi/UrunServisi.svc" binding="wsDua


lHttpBinding" name="UrunServisWsEndPoint" contract="UrunServisi.IUrunYoneticiSozlesmesi" />

www.bsenyurt.com Page 930


stemci tarafndaki konfigurasyon dosyasnda da WsDualHttpBinding tipini kullanan bir endPoint
bildirimi yaplmaldr.

<endpoint address="http://localhost:4500/UrunServisi/UrunServisi.svc"
binding="wsDualHttpBinding" contract="IUrunYoneticiSozlesmesi"
name="WsDualHttpBinding_IUrunYoneticiSozlesmesi" />

Son olarak istemci tarafnda yer alan Uygulayici isimli snftada baz nemli deiikliklerin yaplmas
gerekmektedir. zellikle proxy snfna ait nesneyi rneklediimiz yerde yaplmas gereken
deiiklikler aadaki gibidir.

public Uygulayici()
{
//proxy = new UrunYoneticiSozlesmesiClient(new InstanceContext(this),
"DefaultBinding_IUrunYoneticiSozlesmesi_IUrunYoneticiSozlesmesi");
proxy = new UrunYoneticiSozlesmesiClient(new InstanceContext(this),
"WsDualHttpBinding_IUrunYoneticiSozlesmesi");
WSDualHttpBinding baglayici = (WSDualHttpBinding)proxy.Endpoint.Binding;
baglayici.ClientBaseAddress = new Uri("http://localhost:4500/UrunServisi/" +
Guid.NewGuid().ToString());
proxy.AboneOl();
}

stemciler WsDualHttpBinding balayc tipini kullandklarnda, iki adet tek ynl HTTP kanal
aarlar. WCF alma zaman, servis tarafndan gelen talepleri varsaylan olarak80 numaral port
zerinden dinleyecektir. Oysaki 80 numaral portu IIS(Internet Information
Services) kullanyor olabilir. Bu durumda istemci uygulama alma zamannda hata mesaj
verecektir. Nitekim 80 numaral port baka bir uygulama tarafndan kullanlmaktadr. Bunun nne
gemek iin, balayc tipin zerinden ClientBaseAddresszelliine geici bir adres deeri atamas
yaplr. Ayn makine zerinde birden fazla istemci uygulamas altrlabileceinden, adreslerin
benzersizliinide garanti altna almak adna rnekte Guid tipinden yararlanlmtr. rnek bu son
haliyle test edilirse, yine servisin abonelere geri bildirimde bulunabildii grlecektir. stelik bu kez
durum HTTP zerinden gerekletirilmektedir. Dolaysyla sistem internet zerinden kullanlabilir
halede gelmitir.

Elbette bu senaryoda dikkat edilmesi gereken durumlar vardr. Sz gelimi, istemcilerin


aboneliklerini kaldrmadklar durumlar gz nne alnabilir. rnein 3 farkl istemci servise abone
olsun. Bunlardan birisi aboneliini kaldrmadan uygulamay kapatm olabilir. Oysaki servis
tarafnda yer alan abone koleksiyonunda 3 adet istemci kaytldr. Dolaysyla dier istemcilerden
birisinin yapt ar sonrasnda, servis tarafndaki aboneleri bilgilendirici metod halen daha var
olmayan istemci abone koleksiyonundan kartlmad iin istemci tarafnda istisna alnmasna
neden olabilir. Bunun nne gemek iin State kontrol yaplsada, yaplan testlerde baz
durumlarda istemcideki proxy ile servis arasndaki balantnn tam olarak kapanmamas halinde bu
tarz bir durum olduu ortaya kmtr. O halde istemci tarafnda yer alan abonelii kaldrma
ileminin rol son derece nemlidir.

Bu makalemizde, WCF uygulamalarnda servislerin istemciler zerinde nasl metod


arabileceini Client Callback teknii ile incelemeye altk. Bu arm ilemini abone bazl hale
getirerek, herhangibir istemcinin bir olay gerekletirmesi sonras servisin dier istemcileride
uyarabilmesini saladk. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

www.bsenyurt.com Page 931


Burak Selim ENYURT
selim@bsenyurt.com

Asp.Net Temelleri : Derinlemesine


Download/Upload lemleri ( 15.08.2007 ) -
Asp.Net 2
Deerli Okurlarm Merhabalar,

Tatile kan herkes, iyi ve dinlendirici geen gnlerin ardndan tekrar hayatn akna kapldnda
ksa sreliinede olsa adaptasyon problemi yaar. Tatildeyken hatrlayacanz gibi hafif ve
dinlendirici bir Asp.Net konusu ile ilgilenmeye almtk. Tatil dnndeki adaptasyon srecinde
de benzer nitelikte bir konuyu incelemenin uygun olaca kansndaym. Bu yazmzda Asp.Net
uygulamalarnda sklkla bavurduumuz temel dosya giri/k (Input/Output -
IO) ilemlerinden yararlanarak Downloadve Upload ilemlerinin nasl yaplabileceini ele almaya
alacaz.

zellikle web tabanl ierik ynetim sistemlerinde (Content Management System), kullanclarn
sunucu zerinde dkmanlar ile etkin bir ekilde alabilmeleri salanmaktadr. Bu sistemlerde
genel olarak kullanc kimlii veya rolne gre istemci bilgisayarlara indirilebilen(Download).
Hatta ou ierik ynetim sisteminde, istemciler herkesin okuyabilecei yada belirli kiilerin
grebilecei ekilde sunucuya dkman aktarma (Upload) ilemleride yapabilirler. Sz gelimi bir
yazlm irketinin ierik ynetim sistemi gz nne alndnda, yazlm departmanndaki
gelitiricilerin hazrladklar teknik dkmantasyonlar Upload veya Download edebilecekleri bir
ortam hazrlanabilir.

Hangi adan baklrsa baklsn, web tabanl olarak yaplan bu ilemler iin irketler byk lekli
sistemler tasarlayp gelitirmitir. Fakat temel ilke ve yaklamlar benzerdir. Dosya indirme veya
gnderme ilemleri, web tabanl bir sistem gz nne alndnda HTTP kurallarna baldr.
Dolaysyla bu kurallarn sadece uygulanma ve ele alnma biimleri programlama ortamlar arasnda
farkllklar gsterebilir. te biz bu makalemizde, Asp.Net 2.0 tarafndan olaya bakmaya alyor
olacaz. lk olarak dosya indirme ilemlerini ele alacaz. Sonrasnda ise Asp.Net 2.0 ile
gelen FileUpload arac yardmyla sunucuya dosya gnderme(Upload) ilemlerinin nasl
yaplabileceini inceleyeceiz. Ek olarak, upload edilen bir dosyann kaydedilmeden, sunucu bellei
zerinde canlandrlp ilenmesinin nasl gerekletirilebileceine bakacaz. Son olarakta, Upload
edilen dosyalarn bir veritaban tablosunda alan(Field) olarak saklanmas iin gereken admlar
greceiz. Dilerseniz vakit kaybetmeden dosya indirme sreci ile ie balayalm.

Dosya indirme (Download) ilemlerinde bilinen IO tiplerinden ve Response snfnn ilgili


metodlarndan yararlanlr. Hatrlanaca gibi herhangibir resim dosyasn bir web sayfas ierisinde
gstermek iin retilen HTML ierii ile oynamak gerektiinden daha
nceki makalemizde bahsetmitik. Dosya indirme(Download) ilemindede ieriin tipi(Content-
Type), uzunluu(Content-Length) gibi bilgiler nem kazanmaktadr. lk rneimizde, IIS
zerinde yaynlanan bir web projesindeki Dokumanlar isimli bir klasrde yer alan dosyalarn
indirilme ilemlerini gerekletirmeye alacaz. Bu amala web uygulamasna ait dokumanlar
klasr altna aadaki ekildende grld zere farkl formatlarda rnek dosyalar atlmasnda
fayda vardr.

www.bsenyurt.com Page 932


Web uygulamamzn ilk amac Dokumanlar klasrndeki dosyalarn listelenmesini salamak olacak.
Bu amala sayfada bir GridView kontrol kullanlabilir. Hatta bu kontroln ieriiFileInfo tipinden
nesnelerden oluan generic bir liste koleksiyonundan (List<FileInfo>) gelebilir. Bylece istemciler
indirebilecekleri dosyalarda grebilir. Download ileminin gerekletirilmesi iin GridView
kontrolnde bir Select Button' dan faydalanlabilir. ndirme ilemi srasnda indirilmek istenen
dosyann fiziki adresi, uzunluu gibi bilgiler nemlidir. Bu bilgileri ve fazlasn FileInfo snfna ait
bir nesne rnei yardmyla elde edebiliriz. Uygulamamza ait Default.aspx sayfasnn ierii
aadaki gibi olacaktr.

<%@ Page Language="C#" %>


<%@ Import Namespace="System.Collections.Generic" %>
<%@ Import Namespace="System.IO" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void Page_Load(object sender, EventArgs e)


{
if (!Page.IsPostBack)
{
string[] dosyalar = Directory.GetFiles(Server.MapPath("Dokumanlar"));
List<FileInfo> dosyaBilgileri = new List<FileInfo>();

foreach (string dosya in dosyalar)


{
dosyaBilgileri.Add(new FileInfo(dosya));
}
grdDosyalar.DataSource = dosyaBilgileri;
grdDosyalar.DataBind();
}
}

protected void grdDosyalar_SelectedIndexChanged(object sender, EventArgs e)


{
string dosyaAdi = Server.MapPath("dokumanlar") + "\\" +
grdDosyalar.SelectedRow.Cells[0].Text;
FileInfo dosya = new FileInfo(dosyaAdi);

Response.Clear(); // Her ihtimale kar Buffer' da kalm herhangibir veri var ise bunu silmek
iin yapyoruz.
Response.AddHeader("Content-Disposition","attachment; filename=" + dosyaAdi); //

www.bsenyurt.com Page 933


Bu ekilde tarayc penceresinden hangi dosyann indirilecei belirtilir. Eer belirtilmesse bulunulan
sayfann kendisi indirilir. Okunakl bir formattada olmaz.
Response.AddHeader("Content-Length",dosya.Length.ToString()); // ndirilecek
dosyann uzunluu bildirilir.
Response.ContentType = "application/octet-stream"; // erik tipi belirtilir. Buna gre
dosyalar binary formatta indirilirler.
Response.WriteFile(dosyaAdi); // Dosya indirme ilemi balar.
Response.End(); // Sre bu noktada sonlandrlr. Bir baka deyile bu satrdan sonraki
satrlar iletilmez hatta global.asax dosyasnda eer yazlmsa Application_EndRequest metodu
arlr.
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Dosya Indirme Islemleri</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<h2>Dosyalar</h2>
<asp:GridView ID="grdDosyalar" runat="server" AutoGenerateColumns="False"
SelectedRowStyle-
BackColor="Gold" OnSelectedIndexChanged="grdDosyalar_SelectedIndexChanged">
<Columns>
<asp:BoundField DataField="Name" HeaderText="Dosya Ad" />
<asp:BoundField DataField="Length" HeaderText="Dosya Uzunluu" />
<asp:BoundField DataField="Extension" HeaderText="Uzants" />
<asp:BoundField DataField="CreationTime" HeaderText="Oluturulma Zaman"
DataFormatString="{0:dd.MMMM.yy}" HtmlEncode="False" />
<asp:BoundField DataField="LastWriteTime" HeaderText="Son Yazlma Zaman"
DataFormatString="{0:dd.MMMM.yy}" HtmlEncode="False" />
<asp:CommandField ButtonType="Button" SelectText="indir"
ShowSelectButton="True" />
</Columns>
</asp:GridView>
</div>
</form>
</body>
</html>

ncelikli olarak sayfamzda neler yaptmza ksaca bakalm. Default.aspx sayfas ilk yklendiinde
(bunu salamak iin IsPostBack zellii ile kontrol yaplmtr) Dokumanlar klasrndeki
dosyalarn adlar elde edilmektedir. Bu ilem iin Directory snfnn GetFiles metodu
kullanlmaktadr. Bir web uygulamas sz konusu olduu iin, sanal klasrn karlk geldii fiziki
adresi bulmak adna Server.MapPath metodu ele alnmaktadr. GetFiles metodu parametre olarak
belirtilen klasrdeki dosya isimlerinin elde edilmesini salamaktr. Bu nedenle geriye string tipinden
bir dizi dndrr. GridView kontrol ierisinde, elde edilen bu dosyalara ait baz temel bilgilerin
gsterilmesi hedeflenmitir. rnekte dosyann ad(Name), uzunluu(Length),
uzants(Extension), oluturulma(CreationTime) ve son yazlma
zaman(LastWriteTime) bilgileri ele alnmaktadr. Elde edilen dosya adlar aslnda fiziki
adresleride iermektedir. Bu nedenle ilgili dosya adlar FileInfo tipinden rneklerin
oluturulmasnda kullanlr. Bu nesne rnekleride generic koleksiyonda toplanr. Son olarak
GridView kontrolne veri kayna olarak generic liste koleksiyonu atanr. FileInfo ile gelen
bilgilerden bazlarn GridView kontrolnde gstermek
istediimizden,AutoGenerateColumns zelliine false deeri atanm ve Columns elementi

www.bsenyurt.com Page 934


ierisinde ilgili alanlar ak bir ekilde yazlmtr. BoundField elementlerine
ait DataFieldniteliklerinin deerleri FileInfo ile gelen nesne rneklerindeki zellik adlar olarak
ayarlanmtr.

ndirilmek istenen dosya iin GridView kontrolne bir adet CommandField elementi dahil
edilmitir. Burada seme ilemi ele alnarak aslnda kk bir hile yaplmaktadr. GridView
kontrolnde seim dmesine basldktan sonra devreye giren SelectedIndexChanged olay
ierisinde dosya indirme(Download) ilemi balatlmaktadr. Teorik olarak Response snfnn
WriteFile metodu ile parametre olarak verilen dosya istemci bilgisayara indirilebilirmektedir. Ancak
n hazrlklar yaplmas gerekmektedir. Bu amala, indirilmek istenen dosya ad, GridView
kontrolnde seilen satra ait ilk hcreden seildikten sonra, Response snfnn ilgili metodlar ile n
hazrlklar yaplr. ndirilecek dosya retilen ktnn Header ksmnda ele alnmaktadr. Benzer
ekilde indirilecek dosyann uzunluuda Header ksmna eklenir. Daha sonra ierik tipi
belirlenir. application/octet-stream deeri, dosyann ikili(binary) formatta indirileceini
belirtmektedir. Bu ilemlerin arkasndanda Response snfnn WriteFile ve End metodlar srasyla
altrlr. End metodu, o anki sayfaya ait yaam srecinin kesilmesini salamaktadr. Bir baka
deyile Response.End arsndan sonra herhangibir kod satr var ise iletilmeyecektir. Hatta,
global.asax dosyasnda yer alan Application_EndRequest metoduda devreye girecektir. Bu
durumu analiz etmeden ncei rneimizi test edelim. Uygulama altrldnda aadakine
benzer bir ekran grnts ile karlalacaktr.

Burada pek ok ek zellik tasarlanabilir. rnein uzantya gre ierik tipi deitirilebilir. Hatta
download ilemi yerine rnek bir dkmann sayfaya kt olarak verilmesi salanabilir. PDF
ieriklerinin taraycda gsterilmesi buna rnek olarak verilebilir. Bunlarn dnda uygulamann
kullancya gre yetkilendirilmesi ve sadece ele alabilecei dosyalar indirebilmesi salanabilir. Bu
tamamen projenin ihtiyalarna ve gelitiricinin kullanclara sunmak istediklerine bal olarak
geliebilecek bir modeldir. indir balklk dmelerden herhangibirine bastmzda indirme ileminin
aadaki ekran grntsnde yer ald gibi balad grlr.

www.bsenyurt.com Page 935


imdi gelelim Response.End metodunun etkisine. Bu durumu analiz etmek iin, Response.End
sonrasna aadaki gibi rnek bir kod satr ekleyelim.

protected void grdDosyalar_SelectedIndexChanged(object sender, EventArgs e)


{
string dosyaAdi = Server.MapPath("dokumanlar") + "\\" +
grdDosyalar.SelectedRow.Cells[0].Text;
FileInfo dosya = new FileInfo(dosyaAdi);

Response.Clear();
Response.AddHeader("Content-Disposition","attachment; filename=" + dosyaAdi);
Response.AddHeader("Content-Length",dosya.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.WriteFile(dosyaAdi);
Response.End();
Response.Write("Dosya indirildi");
}

Hemen arkasndan bilinen yaam dngsn izlemek adna default.aspx sayfasn aadaki gibi
deitirelim.

protected void Page_PreInit(object sender, EventArgs e)


{

www.bsenyurt.com Page 936


Debug.WriteLine("Page_PreInit metodu");
}
protected void Page_Init(object sender, EventArgs e)
{
Debug.WriteLine("Page_Init metodu");
}
protected void Page_Load(object sender, EventArgs e)
{
// Dier kod satrlar
Debug.WriteLine("Page_Load metodu");
}
protected void Page_PreRender(object sender, EventArgs e)
{
Debug.WriteLine("Page PreRender Metodu");
}
protected void Page_Unload(object sender, EventArgs e)
{
Debug.WriteLine("Page Unload Metodu");
}

protected void grdDosyalar_SelectedIndexChanged(object sender, EventArgs e)


{
Debug.WriteLine("Dosya indirme ilemi balyor");
// Dier kod satrlar
Response.End();
Debug.WriteLine("Response.End metodu arld");
Response.Write("Dosya indirildi");
}

Bu deiikliklere ek olarak projeye global.asax dosyas ekleyip


ierisine Application_EndRequest metodunu aadaki gibi dahil edelim.

void Application_EndRequest(object sender, EventArgs e)


{
Debug.WriteLine("Application EndRequest Metodu arld");
}

imdi uygulamay Debug modda altrp output penceresindeki ktlar izleyebiliriz. Bir dosya
indirme ilemi gerekletirildikten sonra sayfann yaam dngs aadaki gibi alacaktr.

Page_PreInit metodu
Page_Init metodu
Page_Load metodu
Dosya indirme ilemi balyor
A first chance exception of type 'System.Threading.ThreadAbortException' occurred in
mscorlib.dll
An exception of type 'System.Threading.ThreadAbortException' occurred in mscorlib.dll
but was not handled in user code
Page Unload Metodu
Application EndRequest Metodu arld

ok doal olarak GridView kontrol zerindeki dmeye basldnda sayfann sunucuya tekrar
gitmesi ve ilenmesi sz konusudur. Bu nedenle sre Page_PreInit ile balamaktadr. Ancak
dikkat edilecek olursa Response.End arsndan sonraki satrlar devreye girmemitir. Debug
penceresine ve taraycdaki ktya herhangibir kod yazlmamtr. Dahas,

www.bsenyurt.com Page 937


bir exception(System.Threading.ThreadAbortException) frlatlm ve sayfa yaam
dngs Page_PreRender metodunu iletmeden dorudanPage_Unload olayn iletmi ve
arkasndan global.asax dosyasndaki Application_EndRequest devreye girmitir. Elbetteki
retilen istisna(exception) Asp.Net alma ortam tarafndan grmezden gelinmektedir. Bu
nedenle istemci herhangibir ekilde hata mesaj ile karlamaz.

Gelelim makalemizin ikinci konusuna. ndirme ilemleri kadar Upload ilemleride nemlidir. Tabi
burada istemcilerin her dosya tipini veya eidini sunucuya gndermesi doru olmayabilir. Kapal
a(intranet) sistemlerinde bu sz konusu olabilir. Nitekim kimin handi dosyay Upload ettiinin
belirlenmesi dnda, bu kiiye ulalmasda kolaydr :). Ancak internet tabanl daha geni
sistemlerde her ne kadar kullanclar tespit edilebilsede, kt niyetli istemcilerin varl nedeniyle
sistemin genelini tehlikeye atmamak adna tedbirler almak doru bir yaklam olacaktr. Biz tabiki
basit olarak Upload ilemlerini ele alacaz ve bahsettiimiz gvenlik konularn imdilik grmezden
geleceiz.

Upload ilemlerini kolaylatrmak adna Asp.Net 2.0, FileUpload isimli bir kontrol getirmektedir. Bu
kontrol basit olarak istemcinin Upload etmek istedii dosyay seebilmesini salamaktadr. Bu
seim ilemi ile birlikte, sunucuya gnderilmek istenen dosyaya ait bir takm bilgilerde FileUpload
kontrolnce elde edilir. rnein ieriin tipi kontrol edilerek sadece baz dosyalarn gnderilmesine
izin verilebilir. lk olarak web uygulamamza aadaki gibi Default2.aspx sayfasn ekleyelim.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void btnGonder_Click(object sender, EventArgs e)


{
if (uplDosya.HasFile)
{
uplDosya.SaveAs(Server.MapPath("Dokumanlar") + "\\" + uplDosya.FileName);
}
else
Response.Write("Upload edilecek dosya yok");
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Upload Islemleri</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Dosyay Sein : <asp:FileUpload ID="uplDosya" runat="server" />
<br />

www.bsenyurt.com Page 938


<asp:Button ID="bntGonder" runat="server"
Text="Gnder" OnClick="btnGonder_Click" />
</div>
</form>
</body>
</html>

ncelikli olarak neler yaptmza bir bakalm. FileUpload kontrol ile dosya seilmesi, gnderme
ilemi iin yeterli deildir. Sayfann sunucuya doru gnderilmesi gerekmektedir. Bu ii basit olarak
bir Button kontrol stelenebilir. Button kontrolmze ait Click olay metodunda ise ncelikli olarak
seili bir dosya olup olmad HasFile zellii ile kontrol edilmektedir. Bu kontrol, dosya semeden
gnderme ilemi yapld takdirde oluacak hatalarn nne geilmesini salamaktadr. Eer seili
olan bir dosya var ise basit olarakFileUpload snfnn SaveAs metodu arlr. SaveAs metoduna
dosyann yol adresinin fiziki olarak verilmesi gerekmektedir. Bu nedenle yine Server.MapPath ile
Dokumanlar klasrnn fiziki adresi elde edilir. FileUpload kontrolnn FileName zellii ile seilen
dosyann ad yakalanmakta ve fiziki adresin sonuna eklenmektedir. Eer kod Debug edilirse, dosya
seildikten sonra Upload ilemi iin dmeye basldnda FileUpload kontrol zerinde, seilen
dosyaya ilikin eitli ek bilgilere ulalabildii grlr.

Sz gelimi dosyann tipi hakknda fikir elde etmek iin ContentType zelliine baklabilir. Buna
gre belirli dosya tiplerinin indirilmesine izin verilmesi istenen durumlara kar tedbirler alnabilir.
Gnderilecek dosyann boyutu ile ilgili olarak bir kstlama getirilmek isteniyorsa ierik
uzunluu ContentLength zellii ile tedarik edilerek gerekli deiiklikler yaplabilir. imdi rnei
deniyerek devam edelim. Basit olarak bir dkman dosyasn aadaki gibi seip Upload etmeyi
deneyeceiz.

www.bsenyurt.com Page 939


Grld zere Browse ileminden sonra otomatik olarak standart Choose File iletiim penceresi
(Dialog Box) ile karlatk. rnekte bir resim dosyas seilmitir. Seim ileminden sonra Gnder
dmesine baslrsa dosyann baarl bir ekilde Dokumanlar klasr altna yazld grlecektir.

Upload ilemleri srasnda yetki problemi nedeni ile IIS altndaki herhangibir klasre
dosya yazma ilemi srasnda hata mesaj alnabilir. Bu durumda ASPNET kullancsna
ilgili klasre yazma hakk verilmesi gerekebilir.

Upload ilemleri srasnda dikkat edilmesi gereken kritik bir say vardr. 4096 byte. Yani 4
megabyte. Boyutu bu deerin zerindeki bir dosyay Upload etmek istediimizde Asp.Net ortam bir
hata retir ve dosyann sunucuya gnderilmesine izin vermez. Ne yazkki hata retimi kodlarn
iletilmesinden nce gerekleir. Bu nedenle kullancya anlaml bir mesaj gsterilmeside pek
mmkn olmamamaktadr. Eer 4 megabyte zerinde dosyalarn upload edilebilmesini baka bir
deyile izin verilen limite kadar olan dosyalarn gnderilebilmesini istiyorsak web.config dosyas
ierisinde httpRuntime elementinin ayarlanmas gerekmektedir. system.web boumu ierisinde
yer alan httpRuntime elementi sayesinde, http alma zamanna ait eitli ayarlamalar
yaplabilmektedir. Bizim ihtiyacmz olan dosya bykl snf ayar iin
rneimizde web.config dosyasn aadaki gibi dzenlememiz yeterlidir.

www.bsenyurt.com Page 940


<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<httpRuntime maxRequestLength="51200"/>
<compilation debug="true"/>
<authentication mode="Windows"/>
</system.web>
</configuration>

Burada yaplan ayarlamaya gre istemciler 50 megabyte' a kadar dosyalar sunucuya


gnderebilecektir. Upload ilemlerini ierik ynetim sistemlerinde resim, dkman veya rnek
uygulamalarn, programlarn gnderilmesinde, grafik ktphanesi tarzndaki sistemlerde eitli
formatta resim veya akc grnt formatlarnn gnderilmesinde ve buna benzer durumlarda
kullanmak yaygndr.

Gelelim makalemizin nc konusuna. Yine istemciden sunucuya doru bir dosya gnderme ilemi
gerekletirmeyi hedeflediimizi dnelim. Ancak bu sefer XML tabanl bir dosyay gnderiyor
olacaz. Bu dosyann zellii, bizim istediimiz ekilde tasarlanm olmas dnda, sunucu
tarafnda annda ilenecek olmasdr. Sz gelimi, XML dosyas ierisinde dinamik olarak sayfaya
yklenmesi istenen kontrollere ait bilgiler yer alabilir. Bu durumda Upload edilen XML dosyasnn
sunucu tarafnda ilenerek bir kt retilmesi gerekmektedir. Bir baka deyile istemciden
sunucuya gnderilen sayfay, fiziki olarak yazmadan ilemek ve kullanmak istediimizi gz nne
alyoruz. Peki bu sistemi nasl yazabiliriz? lk olarak istemcinin gnderecei basit XML dkmann
hazrlayarak balayalm. rnek olarak aadaki gibi bir ierik dnlebilir.

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


<Kontroller>
<Kontrol tip="MetinKutusu" id="metinKutusu1"/>
<Kontrol tip="Dugme" metin="Gonder" id="gonder1"/>
<Kontrol tip="Label" metin="Ad" id="ad1"/>
</Kontroller>

Olay basit bir ekilde ele almak adna Xml ieriini mmkn olduu kadar basit dnmeye
altk. Elbetteki ok daha karmak ve daha ok parametre sunan bir Xml dkman sz konusu
olabilir. imdi bu dosyay nasl ele alacamza bakalm. Dikkat edilmesi gereken noktalardan birisi,
Upload edilecek dkmann XML formatnda olmas gerekliliidir. Bunu salamak iin, ierik
tipine(ContentType) bakmak gerekecektir. Sonrasnda ise Upload edilen dosyann Framework
ierisinde yer alan XML tipleri yardmyla ele alnmas yeterlidir. Sonu olarak Default3.aspx
dosyamzn ierii aadaki gibi olacaktr.

<%@ Page Language="C#" %>


<%@ Import Namespace="System.Xml" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void btnGonder_Click(object sender, EventArgs e)


{
if (uplKontroller.HasFile)
{
HttpPostedFile dosya = uplKontroller.PostedFile;

www.bsenyurt.com Page 941


if (dosya.ContentType == "text/xml")
{
XmlDocument doc = new XmlDocument();
doc.Load(dosya.InputStream);
XmlNodeList kontroller=doc.GetElementsByTagName("Kontrol");
foreach (XmlNode kontrol in kontroller)
{
switch (kontrol.Attributes["tip"].Value)
{
case "Dugme":
Button btn = new Button();
btn.ID = kontrol.Attributes["id"].Value;
btn.Text = kontrol.Attributes["metin"].Value;
phlKontroller.Controls.Add(btn);
break;
case "MetinKutusu":
TextBox txt = new TextBox();
txt.ID = kontrol.Attributes["id"].Value;
phlKontroller.Controls.Add(txt);
break;
case "Label":
Label lbl = new Label();
lbl.ID = kontrol.Attributes["id"].Value;
lbl.Text = kontrol.Attributes["metin"].Value;
phlKontroller.Controls.Add(lbl);
break;
}
}
}
else
Response.Write("Dosya ierii XML olmaldr");
}
else
Response.Write("Dosya bulunamad");
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Upload Edilen Dosyayi O Anda Islemek</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Xml Dosayasn Sein : <asp:FileUpload ID="uplKontroller" runat="server" />
<br />
<asp:Button ID="btnGonder" Text="Gnder"
runat="server" OnClick="btnGonder_Click" />
<br />
Yklenen Kontroller:
<asp:PlaceHolder ID="phlKontroller" runat="server" />
</div>
</form>
</body>
</html>

www.bsenyurt.com Page 942


Dilerseniz kod ierisinde neler yaptmza ksaca bakalm. lk olarak dmeye basldnda HasFile
zellii ile seilen bir dosya olup olmadn kontrol ediyoruz. Sonrasnda ise FileUpload
kontrolnn PostedFile zelliinden yararlanp seilen dosyaya ait baz temel bilgileri
tayan HttpPostedFile tipine ait nesne rneini elde ediyoruz. Bu nesne rnei
zerinden ContentType zelliine geerek ieriin XML olup olmadn text/xml eletirmesi ile
kontrol ediyoruz. Sonrasnda ise okunan dosya ieriini XmlDocument nesnesine
yklyoruz. XmlDocument nesne rneine ait Load metodunun parametresi olarak bir Stream
kullanlabildiinden, HttpPostedFile nesne rneinin InputStreamzelliinden yararlanyoruz.
Son olarak yklenen XML dkman ierisinde dolaarak ilgili nitelikleri okuyor ve dinamik olarak
oluturulan kontrolleri, sayfadaki PlaceHolderkontrolnn Controls koleksiyonuna ekliyoruz.

lemlerin daha salkl olmas asndan yklenen XML ieriinin belirli kurallara uygun
olup olmad bir ema dosyas (XSD olabilir rnein) yardmyla kontrol edilebilir. Sz
gelimi gelen XML dkmannn yaps, element adlar, nitelik adlar veya tipleri bu ema
yardmyla denetlenip, kontrollerin belirli standartlara gre okunabilmesi salanm
olunur. ema kontrolnn nasl yaplabileceine dair daha nceki
bir makalemizden yararlanabilirsiniz.

Uygulamay altrdmzda ve istemci tarafndan Kontrollerim.xml dosyasn yklediimizde


aadaki ekran grntsnde olduu gibi kontrollerin baarl bir ekilde retilip sayfaya
yklendiini grebiliriz.

Sra geldi makalemizin son konusuna. erik ynetimi adna, istemcinin sunucuya gnderdii
dosyalarn veritaban zerindeki bir tabloda tutulmas istenebilir. Eer ilikisel veritaban
sistemi (Relational Database Management System) sz konusu ise, dosyalarn tabloda
tutuluyor olmas tama ilemlerini kolaylatrabilecei gibi, ierik gvenliininde de daha etkin bir
seviyede yaplabilmesini salayacaktr. (Tabi tersine saklanacak dosya boyutlarna gre veritaban
daha hzl iecektir.) Bu tarz bir ihtiyacn k noktas son derece basittir. Her zaman olduu gibi
bir FileUpload kontrol ile istemciye dosya setirilmeli daha sonra ilgili ierik sunucu tarafnda
ilenerek veritabanndaki ilgili tabloya yazdrlmaldr. Burada altralacak komut dnda tablodaki
alan tipide nemlidir. Text tabanl bir ierik gnderilecek olsada, tablo
tarafnda image veyaVarBinary tipinden alanlar tutmak Unicode tutarll asndan daha doru
bir yaklam olacaktr. Dilerseniz bir rnek ile bu durumu incelemeye alalm. lk olarak ierii
saklayacamz basit bir tablo oluturalm. Bunun iin SQL Server 2005 zerinde aadaki gibi bir
tablo gz nne alnabilir.

www.bsenyurt.com Page 943


Dosyalar isimli tabloda, sunucuya gnderilen dosya ieriini saklamak iin image tipinden bir alan
kullanlmaktadr. Bunlara ek olarak dosyann eklenme tarihi,ieriin tipi ve dosya ad bilgileride yer
almaktadr. Sz konusu alanlar dnda, web sitesinde
kullanlan dorulama(Authentication) sistemine gre, Upload ilemini yapan kullancnn
bilgilerinin saklanmas hatta varsa Membership gibi kullanc tablo sistemleri ile ilikilendirilmeside
mmkn olabilir. Gelelim ykleme ilemini tabloya yazacak kodlarmza.

<%@ Page Language="C#" %>


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void btnGonder_Click(object sender, EventArgs e)


{
if (uplDosya.HasFile)
{
string conStr
= ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString;
using (SqlConnection conn = new SqlConnection(conStr))
{
SqlCommand cmd = new SqlCommand("Insert into Dosyalar
(EkleNmeTarihi,DosyaIcerigi,DosyaAdi,IcerikTipi)
Values (@EklenmeTarihi,@DosyaIcerigi,@DosyaAdi,@IcerikTipi)", conn);
cmd.Parameters.AddWithValue("@EklenmeTarihi", DateTime.Now);
cmd.Parameters.AddWithValue("@DosyaIcerigi", uplDosya.FileBytes);
cmd.Parameters.AddWithValue("@DosyaAdi", uplDosya.FileName);
cmd.Parameters.AddWithValue("@IcerikTipi", uplDosya.PostedFile.ContentType);
conn.Open();

www.bsenyurt.com Page 944


int sonuc=cmd.ExecuteNonQuery();
Response.Write(sonuc + " dosya aktarld");
}
}
else
Response.Write("Dosya semelisiniz");
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Upload Edilen Dosyay Veritabanna Yazma</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Dosyay Sein : <asp:FileUpload ID="uplDosya" runat="server" />
<br />
<asp:Button ID="btnGonder" Text="Gnder"
runat="server" OnClick="btnGonder_Click" />
</div>
</form>
</body>
</html>

Yine kodlar ksaca incelemekte fayda var. Her zamanki gibi, istemcinin bir dosya setiinden emin
olduktan sonra gerekli ilemleri yapyoruz. Burada nemli olan nokta altrlacak SQL cmlesinde
kullanlan parametrelerin deerlerinin nasl verildii. Dikkat edilecek olursa, image tipindeki alann
ieriini verirken FileUpload kontrolnn FileBytes zelliinden yararlanyoruz. Burada dikkat
edilmesi gereken noktalardan biriside ok byk boyutlu dosyalarn aktarlmas srasnda
yaanabilecek timeout sorunudur. Byle bir durumda kalnd takdirde balant iin timeout
srelerinin arttrlmas yoluna gidilebilir yada dosyann paralanarak sunucuya gnderilmesi ve
burada o ekilde ele alnmas salanabilir. Uygulama eitli tipteki dosyalar ile test edildiinde
baarl bir ekilde alt grlecektir. Aadaki ekran grntsnde bir ka dosya tipinin upload
edilmesi sonrasndaki durum vurgulanmaktadr.

Her dosya eklenme ileminden sonrada tarayc penceresindeki grnt aadaki gibi olacaktr.

www.bsenyurt.com Page 945


Elbette Upload edilen ieriklerin, istemciler tarafndan indirilmeside gerekecektir. Bu durumda tablo
alanndaki dosya ieriinin stream olarak yazdrlmas gerekir. Tabi bunun
iinResponse snfnn WriteFile metodu yerine BinaryWrite metodunu tercih
edeceiz. (Alternatif bir yaklam olarak, tablodan okunan dosya ieriinin bir temp dosyaya
atlmas ve oradanda WriteFile metodu ile yazdrlmasda dnlebilir) Nitekim dosya ierikleri
tabloda binary olarak tutulmaktadr. yleyse son olarak bu ilemide nasl yapabileceimizi
inceleyeceimiz bir rnek sayfa daha ekleyelim. Default5.aspx sayfamzn ierii aadaki gibi
olacaktr.

<%@ Page Language="C#" %>


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void GridView1_SelectedIndexChanged(object sender, EventArgs e)


{

www.bsenyurt.com Page 946


using (SqlConnection conn = new
SqlConnection(ConfigurationManager.ConnectionStrings["ConStr"].ConnectionString))
{
SqlCommand cmd=new SqlCommand("SELECT DosyaAdi,DosyaIcerigi,IcerikTipi FROM
Dosyalar Where Id=@Id",conn);
cmd.Parameters.AddWithValue("@Id", GridView1.SelectedValue);
conn.Open();
SqlDataReader reader=cmd.ExecuteReader();
if (reader.Read())
{
Response.Clear();
Response.AddHeader("Content-Disposition", "attachment; filename=" +
reader.GetString(0));
byte[] dosyaIcerigi = reader.GetSqlBinary(1).Value;
Response.AddHeader("Content-Length", dosyaIcerigi.Length.ToString());
Response.ContentType = "application/octet-stream";
Response.BinaryWrite(dosyaIcerigi);
}
reader.Close();
}
Response.End();
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Dosyalar<br />
<br />
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataSourceID="dsDosyalar" OnSelectedIndexChanged="GridView1_SelectedIndexChanged
"DataKeyNames="Id">
<Columns>
<asp:BoundField DataField="DosyaAdi" HeaderText="DosyaAdi"
SortExpression="DosyaAdi" />
<asp:BoundField DataField="EklenmeTarihi" HeaderText="EklenmeTarihi"
SortExpression="EklenmeTarihi" />
<asp:BoundField DataField="IcerikTipi" HeaderText="IcerikTipi"
SortExpression="IcerikTipi" />
<asp:CommandField ButtonType="Button" SelectText="indir"
ShowSelectButton="True" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="dsDosyalar" runat="server" ConnectionString="<%$
ConnectionStrings:ConStr %>" SelectCommand="SELECT Id,DosyaAdi, EklenmeTarihi,
IcerikTipi FROM Dosyalar">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>

www.bsenyurt.com Page 947


Tasarladmz sayfay dilerseniz inceleyelim. Basit olarak Dosyalar tablosunun ieriini gstermek
amacyla SqlDataSource ve GridView kontrollerinden faydalanyoruz. Yine ilk rneimizde olduu
gibi indirme ilemini balatmak adna kk hilemizi yaptk ve bir Select dmesi kullandk. Burada
dosya ierii tabloda alan olarak tutulduu iin,SqlCommand ile verinin ekilmesi gerekiyor. Bunu
kolaylatrmak adna GridView ierisinde seilen satra ait Id alannn deerini almalyz. Bu amala
GridView kontrolnnDataKeyNames zelliine Id deerini verdik. Bu
deeri SelectedIndexChanged metodu ierisinden alarak sorgu cmlesinde parametre olarak
kullanyor ve bylece indirilmek istenen dosyaya ait ieriin olduu tablo satrn ekebiliyoruz.
Bizim iin nemli olan nokta, binary ierii okumak
iin SqlDataReader snfnn GetSqlBinary metodunu kullanyor olmamz. Bu metod ile dnen
tipin Value zelliinden faydalanp elde
edilen byte[] dizisini Response snfnn BinaryWrite metoduna parametre olarak verdiimizde
yazma ilemi gerekletirilmi oluyor. Sonu olarak alma zamannda istediimiz sonuca ulayor
ve dosya indirme ilemlerini gerekletirebiliyoruz.

Bu makalemizde Asp.Net uygulamalarnda Download ve Upload ilemlerini detaylar ile


incelemeye altk. lk olarak bir dosyann indirilme ileminin nasl yaplabileceine baktk.
Sonrasnda ise basit olarak bir Upload ilemi ile sunucuya dosya gnderme olayn ele aldk. Upload
ileminin farkl ynlerini ele almak adna, annda sunucu tarafnda ileme ve tabloya satr olarak
ekleme ilemlerini inceledikten sonra, tablodaki bir binary ierii indirme srecine gz attk.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

www.bsenyurt.com Page 948


rnek Uygulama iin Tklayn (Dosyann ok yer tutmamas asndan mdf dosyas kartlmtr)

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net 2.0 URL Rewriting Hakknda Gerekler


( 07.08.2007 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

ok ksa sreliinede olsa tatilde olduum u gnlerde yazlm dnyasndan kopmak hi iimden
gelmedi. Bu nedenle dinlendiim zamanlardan arta kalan srelerde azda olsa bir eyler karalamak
istedim. Sonu olarak daha hafif ve tatil moduna uygun olacak bir yaz ile yeniden beraberiz. Bu
makalemizde Asp.Net 2.0 ile gelitirilen web uygulamalarnda, URL eletirmelerinin (Url
Mapping) nasl dzenlenebileceini, bir baka deyile nasl zelletirilebileceini incelemeye
alacaz. Son kullanclar web ortamnda, kenditarayc(browser) uygulamalarnda yer alan
adres satrlarnda zaman zaman kark ve uzun URL bilgileri ile karlarlar. Genellikle sorgu
katarlarnn(QueryString) kullanld ve bunlarn saylarnn ok olduu durumlarda adres
satrlarn okumak gerekten gleebilir. Sz gelimi aadaki URL bilgisini gz nne alalm.

http://www.azonsitesi.com/urunler.aspx?urunKategori=1&urunAdi=Bilgisayar%20Kitaplari&Sinifi=I
ngilizce&BasimYili=2006

Bunun yerine aadaki gibi bir URL bilgisi ok daha kullanl ve son kullanc asndan okunakl
olabilir.

http://www.azonsitesi.com/Ingilizce/BilgisayarKitaplari/2006Basimi/Goster.aspx

rnekler oaltlabilir. Sz gelimi blog sitelerinde, adres satrlarnda okunan ierie ait bilgilerin
QueryString eklinde durmas yerine
rneinhttp://buraginblogu/Agustos/7/2007/UrlEslestirme/Oku.aspx gibi bir formata
sahip olmas son kullanc asndan ok daha cezbedicidir.

Bu ve benzer durumlarda, adres satrndaki bilginin daha kolay anlalabilecei hale getirilmesi son
kullanc(End User) iin nemli bir hizmettir. Peki bu tarz bir ihtiya nasl karalanabilir. lk
olarak istemciden gelen adres talebine e decek yeni URL bilgisinin sunucu tarafnda ele alnyor
olmas gerekir. Sonrasnda ise sonular istemci tarayc programna istenen formatta
gnderilir. Asp.Net 1.1 kullanld takdirde bu iin zm
zel HttpHandler ve HttpModule snflarnn yazlmas ile mmkn olabilir.(Kendi HttpHandler
yada HttpModuler tiplerimizi nasl yazabileceimize dair bilgileri daha nceden
yaynlanan makalemizden takip edebilirsiniz) Asp.Net 2.0 mimarisindeyse, sadece URL
eletirilmelerinin daha kolay yaplabilmesini salamak amacyla web.config dosyasnda yer
alan system.web boumu(node) ierisinde ele alnabilecek bir urlMappings elementi ve
bunun Configuration API' sinde karl olan UrlMappingsSection snf gelitirilmitir. Bu
sayede konfigurasyon baznda URL eletirmeleri yaplabilmekte ve zel HttpHandler yada
HttpModule tipleri yazlmasna gerek kalmamaktadr.

Her ne kadar urlMappings elementi veya UrlMappingsSection tipi sayesinde, URL


eletirmelerinin yaplmas kolaylamsada baz zel durumlarda yine HttpHandler veya
HttpModule tipleri gelitirmek gerekebilir. Sz gelimi, urlMappings elementinin dorudan
bir regular expression destei yoktur. Dolaysyla benzer yazma sahip URL bilgileri iin

www.bsenyurt.com Page 949


ortak eletirme yapmak adna element baznda bir hamle yaplmas zordur. Bunu
salamak iin HttpModule ve HttpHandler yazmak gerekmektedir. Byle bir ihtiya iin
kendi HttpModule ve HttpHandler tipinizi yazmaya almanz nerilir.

Aslnda Asp.Net 2.0 mimarisinde yer alan URL eletirme sistemi aadaki grafikte grld gibi
almaktadr.

Buna gre istemciden gelen talepler sonras, ilgili web uygulamas Asp.Net alma zaman
ierisinde normal srecine devam eder. Taki sayfann son hali Render ilemine tabi tutulup
istemciye gnderilene kadar. Bir baka deyile Render ileminde nce, Asp.Net alma
zaman(Asp.Net RunTime) web.config ierisinde herhangibir eletirme olup olmadna bakar.
Eer talep edilen URL iin bir eletirme varsa buna
gre HttpContext tipinin RewritePath metodu iletilir ve URL adresi deitirilir. Sonrasnda ise
sayfa istemciye gnderilir.

Dilerseniz rnek bir senaryo zerinden hareket ederek URL eletirmelerinin Asp.Net 2.0
mimarisinde nasl yapldn yakndan incelemeye alalm. Senaryo gerei kullancnn alt
kategorisi ve snfna gre baz rnleri listelediini dnebiliriz. Bu amala SQL Server 2005 ile
gelen AdventureWorks veritabanndakiProductSubCategories ve Product tablolarn gz nne
alalm. Bu tablolara arasnda aadaki ekilde grlen bire-ok(one to many) iliki vardr.

www.bsenyurt.com Page 950


lk olarak default.aspx sayfamz aadaki gibi gelitirelim.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>URL Mapping Ornegi</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" DataSourceID="dsCategories"
AllowPaging="True" AutoGenerateColumns="False">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="Name,Class" DataNavigateUrlFor
matString="~/Urunler/{0}/{1}/Goster.aspx" DataTextField="Title" HeaderText="Alt
Kategori ve Snf" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="dsCategories" runat="server" ConnectionString="<%$
ConnectionStrings:AdvConStr %>" SelectCommand="SELECT DISTINCT
PSC.ProductSubcategoryID, Replace(PSC.Name,' ','') AS Name, RTRIM(PRD.Class) as
Class, PSC.Name+' '+PRD.Class AS Title FROM Production.ProductSubcategory AS PSC INNER
JOIN Production.Product AS PRD ON PSC.ProductSubcategoryID = PRD.ProductSubcategoryID
WHERE (PRD.Class IS NOT NULL)">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>

www.bsenyurt.com Page 951


Default.aspx sayfas ierisinde yer alan GridView kontrol, Product ve ProductSubCategory
tablolarnn birleiminden bir sonu kmesine ait satrlar gstermek zere tasarlanmtr. Sz
konusu sonu kmesi elde edilirken Name ve Class alanndaki boluklarn alnmas
iin Replace ve RTrim isimli T-SQL fonksiyonlarna bavurulmaktadr. GridView bileenine dikkat
edilecek olursa ieride HyperLinkField tipinden bir kontrol kullanlmaktadr. Bu kontroln dikkate
deer zellii ise DataNavigateUrlFormatString niteliidir. Sayfa alma zamannda aadakine
benzer bir sonu verecektir.

Dikkat edilecek olursa balantlarn(Links) hedef URL


bilgisi, HyperLinkField kontrolnn DataNavigateUrlFormatString niteliinin deerine gre
ekillenmektedir. Sz gelimi, rnek ekran grntsnde yer ald gibi M snfndaki Bottom
Brackets rnleri iin URL bilgisi aadaki gibidir.

http://localhost:1292/UrlRewriting/Urunler/BottomBrackets/M/Goster.aspx

Dikkat edilecek olursa bu URL bilgisinin Urunler kelimesinden itibaren olan ksm ok daha okunakl
ve anlamldr. Peki biz bu linke tkladmzda Bottom Brackets kategorisinde ve M snfnda yer alan
rnlerin listesi nasl elde edilebilir. Bu ilemin Urunler.aspx gibi bir sayfa ierisinde ele alnmas
dnld takdirde, seilen balant bilgisine gre ilgili kategori ve snf bilgilerinin sorgu
katar(QueryString) ile dier sayfaya gnderilmesi gerekmektedir. Buda ok doal olarak,
default.aspx sayfasnda seilen URL bilgisine e decek asl URL bilgisinin tanmlanmas ile
mmkn olabilir. te bu noktada, Urunler.aspx sayfasn tasarlamadan
nce, web.config ierisinde aadaki ilaveler yaplmaldr.

<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings>

www.bsenyurt.com Page 952


<add name="AdvConStr" connectionString="Data Source=.;Initial
Catalog=AdventureWorks;Integrated Security=True" providerName="System.Data.SqlClient"/>
</connectionStrings>
<system.web>
<urlMappings enabled="true">
<add url="~/Urunler/BottomBrackets/H/Goster.aspx" mappedUrl="~/Urunler.aspx?AltK
ategoriId=5&amp;AltKategoriAdi=Bottom%20Brackets&amp;Sinifi=H"/>
<add url="~/Urunler/BottomBrackets/L/Goster.aspx"
mappedUrl="~/Urunler.aspx?AltKategoriId=5&amp;AltKategoriAdi=Bottom%20Brackets&amp;Sini
fi=L"/>
<add url="~/Urunler/BottomBrackets/M/Goster.aspx"
mappedUrl="~/Urunler.aspx?AltKategoriId=5&amp;AltKategoriAdi=Bottom%20Brackets&amp;Si
nifi=M"/>
<add url="~/Urunler/Cranksets/H/Goster.aspx"
mappedUrl="~/Urunler.aspx?AltKategoriId=5&amp;AltKategoriAdi=Cranksets&amp;Sinifi=H"/>
</urlMappings>
<compilation debug="true"/>
<authentication mode="Windows"/>
</system.web>
</configuration>

URL eletirmeleri iin system.web elementi ierisinde yer alan urlMappings boumu
kullanlmaktadr. Bu boumda, add elementi ierisinde yer alan url ve mappedUrl nitelikleri ilede
gereken eletirmeler yaplmaktadr. Buna
gre, ~/Urunler/BottomBrackets/M/Goster.aspx gibi bir talep geldiinde
bu, ~/Urunler.aspx?AltKategoriId=5&amp;AltKategoriAdi=Bottom%20Brackets&amp;Si
nifi=M olarak alglanacaktr. & operatrnn ele alnmas srasnda &amp; ifadesinin kullanlmasna
dikkat etmek gerekir. Eer & iareti kullanlrsa derleme zamanda hata mesaj alnr.

Artk gerekli bildirimler yapldna gre Urunler.aspx sayfas aadaki gibi tasarlanabilir.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected void Page_Load(object sender, EventArgs e)
{
lblAltKategoriAdi.Text
= Request.QueryString["AltKategoriAdi"]!=null?Request.QueryString["AltKategoriAdi"].
ToString():"";
lblSinifi.Text
= Request.QueryString["Sinifi"]!=null?Request.QueryString["Sinifi"].ToString():"";
}
</script>

www.bsenyurt.com Page 953


<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Kategori ve snf bazl rnler</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Label ID="lblAltKategoriAdi" runat="server" Font-Bold="True" Font-Size="X-Large"
Font-Underline="True" ForeColor="#C00000"></asp:Label>
Alt Kategorisi
<asp:Label ID="lblSinifi" runat="server" Font-Bold="True" Font-Size="X-Large" Font-
Underline="True" ForeColor="#C00000"></asp:Label> snf<br />
<br />
<asp:GridView ID="grdUrunler" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductId" DataSourceID="dsProducts">
<Columns>
<asp:BoundField DataField="ProductId" HeaderText="ProductId" InsertVisible="False"
ReadOnly="True" SortExpression="ProductId" />
<asp:BoundField DataField="Name" HeaderText="Name" SortExpression="Name" />
<asp:BoundField DataField="ListPrice" HeaderText="ListPrice"
SortExpression="ListPrice" />
<asp:BoundField DataField="Class" HeaderText="Class" SortExpression="Class" />
<asp:BoundField DataField="SellStartDate" HeaderText="SellStartDate"
SortExpression="SellStartDate" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="dsProducts" runat="server" ConnectionString="<%$
ConnectionStrings:AdvConStr %>" SelectCommand="Select
ProductId,Name,ListPrice,Class,SellStartDate From Production.Product Where
ProductSubCategoryId=@SubCatId and Class=@Class">
<SelectParameters>
<asp:QueryStringParameter DefaultValue="1" Name="SubCatId"
QueryStringField="AltKategoriId" />
<asp:QueryStringParameter DefaultValue="M" Name="Class"
QueryStringField="Sinifi" />
</SelectParameters>
</asp:SqlDataSource>
</div>
</form>
</body>
</html>

Bu sayfa sadece QueryString ile gelen parametreler deerlendirmekte ve buna gre belirli bir alt
kategori ve snfa ait rnlerin baz alanlarnn listelenmesini salamaktadr. Bu amala
yine GridView ve SqlDataSource kontrollerinden yararlanlm ve uygun sorgu cmleleri
kullanlmtr. rnek senaryoda yer alan Bottom Brockets alt kategorisi ve M snf seilirse,
Urunler.aspx sayfasnda aadaki ekran grntsnde yer alan ktlar elde edilecektir.

www.bsenyurt.com Page 954


Yukardaki ktya dikkat edilecek olursa URL satr bizim belirlediimiz ekilde kalmtr. Bu ktnn
aynsn elde etmek iin halen daha sorgu katar(QueryString)ifadeleride aka kullanlabilir.
Ayn web uygulamasnda aadaki ekran grntsnde yer alan URL talebi, ayn sonular
verecektir.

Ne varki halen daha baz problemler vardr. Hereyden nce en azndan sz konusu senaryo gz
nne alndnda, var olabilecek tm olaslklar iin web.config dosyasna teker teker URL
eletirmelerinin eklenmesi gerekmektedir. Bir gelitirici olarak bunun kod ierisinden daha etkili
bir ekilde ele alnmas ok doal bir istektir. Neyseki Asp.Net 2.0 ile gelen gl Configuration API
alt yaps sayesinde istersek, kod ierisinde urlMappings ksmna dinamik olarak
yeni elemanlar(elements) ekleyebilir, dzenleyebilir ve kartabiliriz. Bu amala bir admin sayfas
veya farkl bir uygulama olacak ekilde bir admin paneli dahi gz nne alnabilir.(Configuration
API' sinin ynetiminin daha detayl bir ekilde renmek isterseniz daha nce yazlm olan
bir makaleden yararlanabilirsiniz.) Bunun iin aadaki gibi bir sayfa tasarladmz gz nne
alabiliriz.

<%@ Page Language="C#" %>


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

private static void AddMappings()


{
Configuration cfg = ConfigurationManager.OpenExeConfiguration("");

www.bsenyurt.com Page 955


UrlMappingsSection urlMapSct =
(UrlMappingsSection)cfg.GetSection("system.web/urlMappings");
urlMapSct.UrlMappings.Clear();

string query = "SELECT DISTINCT PSC.ProductSubcategoryID, PSC.Name,PRD.Class FROM


Production.ProductSubcategory AS PSC INNER JOIN Production.Product AS PRD ON
PSC.ProductSubcategoryID = PRD.ProductSubcategoryID WHERE (PRD.Class IS NOT NULL) ORDER
BY PSC.Name, PRD.Class";

using (SqlConnection conn = new


SqlConnection(cfg.ConnectionStrings.ConnectionStrings["AdvConStr"].ConnectionString))
{
SqlCommand cmd = new SqlCommand(query, conn);
conn.Open();
string url = "", mappedUrl = "";

SqlDataReader reader = cmd.ExecuteReader();


while (reader.Read())
{
url = "~/Urunler/" + reader.GetString(1).Replace(" ","") + "/" +
reader.GetString(2).Replace(" ","") + "/Goster.aspx";
mappedUrl = "~/Urunler.aspx?AltKategoriId=" +
reader["ProductSubCategoryID"].ToString() + "&AltKategoriAdi=" + reader["Name"].ToString() +
"&Sinifi=" + reader["Class"].ToString();
UrlMapping map = new UrlMapping(url, mappedUrl);
urlMapSct.UrlMappings.Add(map);
}
reader.Close();
}
cfg.Save();
}

protected void btnMappEkle_Click(object sender, EventArgs e)


{
AddMappings();
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Yonetici Sayfasi</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnMappEkle" runat="server" Text="Gncel URL Eletirmelerini Ekle"
OnClick="btnMappEkle_Click" />
</div>
</form>
</body>
</html>

imdi burada gelitirdiimiz kodlar ksaca inceleyelim. Configuration alt yapsna gre, web.config
dosyas ierisinde bilinen hemen her boumun(Node) birer ynetimli tip(Managed
Type) karl vardr. Buradaki tipimiz UrlMappingsSection snfdr. UrlMappingsSection snfda

www.bsenyurt.com Page 956


Asp.Net 2.0 ile birlikte gelmi bir snftr. Snf diagramndan ele alndnda UrlMappingsSection
snfnn Framework ierisindeki yeri aadaki ekilde grld gibidir.

Grld gibi UrlMappingsSection snfnn UrlMappings zellii aslnda UrlMapping tipinden


elemanlar tayan zel bir koleksiyonu(UrlMappingCollection) iaret etmektedir. Yeni
bir UrlMapping nesne rnei eklenmek istendiinde bu koleksiyondan yararlanlr. Bu
koleksiyondaki elemanlar oluturan UrlMapping tipinin Framework ierisindeki yeri ise aadaki
gibidir.

www.bsenyurt.com Page 957


Bu tipi o anki web.config dosyasndan elde etmek amacyla Configuration nesne
rneinin GetSection metodu kullanlmaktadr. Bu metod bilindii gibi XPath ifadelerini parametre
olarak alr.(XPath ile ilgili detayl bilgiyi daha nceki bir makalemizden edinebilirsiniz) Sonrasnda
ise veritabanndan yaplan sorgu sonucu elde edilen veri kmesine
gre url ve mappedUrldeerleri oluturulur. Bu deikenler, her bir satr
iin web.config dosyasna eklenecek UrlMapping tiplerinin yapc
metodlarna(Constructor) parametre olarak verilmektedir. Son olarak oluan UrlMapping nesne
rnei, Add metodu ile web.config/urlMappings elementi ierisindeki yerini almaktadr.

Elbette, bellek zerinde yaplan bu deiikliklerin kalc olmas


adna Configuration tipinin Save metodu kullanlmaktadr. Dikkat edilmesi gereken noktalardan
biriside URL deeri oluturulurken Replace metodu ile Name ve Class alanlarndaki boluklarn
alnmasdr. Eer sz konusu boluklar alnmassa (zellike Class alanlarndakiler alnmassa) bu
linklere tklandnda alma zamannda sayfalarn bulunamadna dair hata mesajlar alnabilir.
Bu ayn zamanda, URL ierisinde geersiz olabilecek karakterler var ise bunlarnda kartlmas veya
deitirilmesi gerektii anlamnada gelmektedir. rnein bolukar ounlukla URL satrna %20
eklinde aktarlrlar. Ancak rnekteki URL bilgisinde klasr tabanl bir yaklam tercih edildiinden
btn boluklarn kartlmas yolu tercih edilmitir. Bu ilemlerin arkasndan Admin sayfas
altrlr ve dme tklanrsa web.config dosyasnn aadaki ekran grntsnde olduu gibi
deitii grlr.

www.bsenyurt.com Page 958


Dikkat edilecek olursa, elde edilen veri kmesine gre, sz konusu olabilecek tm URL
eletirmeleri ilave edilmitir. Configuration API'si saolsun :) imdi default.aspx sayfas arlrsa,
artk GridView kontrol ierisindeki her bir balantnn karlnn olduu ve alt grlr.
Default.aspx iin rnek grnt aadaki gibidir.

www.bsenyurt.com Page 959


lgili balantnn tklanmas sonras ise aadaki sonulara benzer ktlar elde edilebilir.

Buraya kadar rnek bir senaryo zerinden URL eletirmesini incelemeye altk. Son teknikte
dinamik olarak URL eletirmelerini ekledik. Bu teknik her ne kadar gze ho gelsede dezavantajda
vardr. yleki, veri kaynanda deiiklikler yapldnda rnein Alt kategori ad deitiinde yada
yenileri eklendiinde web.config dosyas ierisinde yeni dzenlemelerin yaplmas, bir baka deyile
ilgili fonksiyonun tekrardan arlmas gerekcektir. Bu eitli teknikler ile zlebilir ama yinede
dnlmesi gereken bir admdr.

Sonu olarak Asp.Net 2.0 ile birlikte gelen urlMappings elementi her ne kadar baz avantajlar
salasada eitli kstlamalarda iermektedir. Regular Expression ifadeleri kullanlamadndan, her
bir URL iin gereken eletirmeler teker teker web.config dosyas ierisinde yazlmaldr.
Geri Configuration API' si yardmyla bu bir nebzede olsa alabilmektedir ancak Regular
Expression'n yerini tam anlamyla tutmamaktadr. Regular Expression destei iin gelitiricinin
zel HttpModule ve HttpHandler tiplerini gelitirmesi gereklilii ise bir zorluktur. Bylece geldik

www.bsenyurt.com Page 960


bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net Temelleri : Etkili Trace Kullanm (


02.08.2007 ) - Asp.Net
Deerli Okurlarm Merhabalar,

Web uygulamalarnda son kullanclarn(End Users) ikayeti olabilecei pek ok konu vardr.
Bunlar arasnda popler olanlarndan biriside sayfalarn yava alyor olmasdr. Nihayetinde son
kullanclar her zaman iin sabrsz ve acelesi olan kiiler olarak dnmek doru bir yaklam
olacaktr. Sayfalarn yava alyor yada ge cevap veriyor olmasnn donanmsal yada eitli evre
faktrleri nedeniyle bilinen sebepleri vardr. Sz gelimi balant hznn dk olmas ilk akla gelen
nedendir. Ancak gelitiriciler(developers) olarak bizlerinde zerine den nemli grevler
vardr. Sonu itibariyle bir gelitirici, mininum donanm gereksinimleri karland takdirde hzl ve
yeterli performasta alabilen bir web uygulamas gelitiriyorsa, donanm kapasite ve
yeteneklerinin daha yksek olduu son kullanclarda ayn web uygulamasnn ok daha iyi sonular
verecei dnlebilir.

Trace mekanizmasn kullanmak iin kk bir neden; rnein talep(request) edilen


sayfann retilmesi ve HTML ktsnn hazrlanmas uzun zaman alyor olabilir. Sayfann
retimi srasnda hangi admlarn ok zaman aldn grmek iin Trace mekanizmasndan
yararlanlabilir.

Elbetteki bir web uygulamasnn hzn, performansn ve cevap verebilme yeteneklerini etkiliyecek
pek ok faktr vardr. Yine rnek olarak dnlrse, 10 kullancl bir intranet ortamnda gayet iyi
alan bir web uygulamas, internet' e aldnda karlaabilecei n kullanc talebi sonrasnda
beklenen performans gsteremeyebilir. Buradaki en byk etken kullanc saysdr. Bu nedenle
web uygulamalarn ne kadar iyi programladmz dnsekte, sonulara bakldnda gerek test
gerekse gerek ortamlarda istediimiz sonular alamadmz grebiliriz. Dolaysyla test
aamasnda uygulamann genelini izleyebilmek ve sonular analiz ederek gerekli tedbirleri
alabilmek son derece nemli bir konudur. Bu gibi durumlarda web uygulamasnn genelinin yada
problemli olabilecei dnlen sayfalarn alma zaman ve sonrasndaki hareketlerinin izlenmesi
adna Asp.Net modelinde Trace mekanizasndan faydalanlmaktadr. te bu makalemizde Trace
kavramn derinlemesine incelemeye alacaz.

Trace mekanizmas ile sayfa(Page) veya uygulama seviyesinde(Application Level),


kullancdan gelen bir talebin ilenmesi srasnda ve sonularn elde edilmesinin sonrasnda gerekli
host bilgileri yakalanabilir. Bu bilgiler deerlendirilerek sorunun nerede olduu daha kolay bir
ekilde tespit edilebilir.

Trace; HTTP talebi ile ilgili olaraktan sunucu(server) tarafl alma zaman(run-
time) ve sonras detay bilgilerinin alnmasn salayan bir Asp.Net mekanizmasdr.

www.bsenyurt.com Page 961


Trace mekanizmas sadece sayfa ve uygulama seviyesinde deil, bileen
seviyesindede(Component Level) ele alnabilir. Nitekim, web uygulamalarnda sayfalarn ou
buton arkas programlama yerine bileenleri ele alr. ok doal olarak bileenler ierisinde
meydana gelebilecek sorunlarn ele alnmas srasnda yine Trace mekanizmas ele alnabilir. Trace
ile elde edilen sonular retilen genellikle sayfa sonlarna HTML bilgisi olarak eklenebilirler. Bunun
dnda Trace.axd isimli zel dosyalardanda uygulama genelinde, talep srasna gre sayfalarn
izlenmesi salanabilir.

lk olarak Trace ilemlerini sayfa seviyesinde ele almaya alacaz. Bir sayfann Trace ktsn
yakalamak iin iki farkl yntem vardr. Bunlardan birincisi Page direktifinde yer
alan Trace niteliine true deeri atanmasdr. Dier yol ise kod tarafnda Trace nesne rnei
zerinden IsEnabled zelliine true deerini atamaktr.

Direktik ierisinden Trace mekanizmasnn almas;

<%@ Page Language="C#" Trace="true"%>

Kod tarafndan Trace mekanizmasnn almas;

protected void Page_Load(object sender, EventArgs ea)


{
Page.Trace.IsEnabled = true;
}

Sonu olarak bu iki kullanm ekline gre sayfann sonuna Trace bilgileri aadaki ekran
grntsnde olduu gibi eklenecektir.

www.bsenyurt.com Page 962


Bu ktda tm Trace bilgisi gsterilmemektedir. Temel olarak Trace ktsnda yer alan ksmlar
aadaki tabloda olduu gibidir.

Trace ktsnda Yer Alan Blmler

Bu ksmda talep ile ilikili genel bilgiler yer alr. rnein talep tipi(request
Request type) ilk arda Get iken sayfa sunucuya gnderildikten sonra Post deerini
Details alr. Bir baka rnek detay bilgisi olarakta Session Identity(SessionId) deeri
verilebilir.

Bu ksmda zellikle sayfann yaam dngs(Page Life Cycle) ierisinde yer


Trace
alan olaylarn genel sreleri yer alr. Buradaki bilgilerden hareket ederek
Information
sayfann retimi srasnda hangi ksmlarn ne kadar sre harcad grlebilir.

Sayfa ierisindeki kontrollerin aa yapsn verir. Bylece zellikle form


ierisinde kullanlan baka tayc kontroller(container controls) var ise,
Control Tree
bunlarn ierisinde yer alan alt kontrollerin elde edilmesi iin ne kadar derine
inilebilecei kolayca tespit edilebilir.

Kullancya ait oturum(Session) ierisinde tutulan verilerin deerlerinin ve


Session State
tiplerinin gsterildii ksmdr.

Application Application nesnesi ierisindeki anahtarlar(keys) ve


State deerlerinin(values) gsterildii ksmdr.

www.bsenyurt.com Page 963


Request
Cookies Sayfaya gelen talep srasndaki erezlere ait bilgilerin tutulduu koleksiyondur.
Collection

Response
Sayfadan istemciye dnen cevap ierisinde yer alan erezlere(Cookies) ait
Cookies
bilgilerin tutulduu koleksiyondur.
Collection

Headers stemciden sunucuya gelen HTTP paketindeki balk bilgileri grlebilir.


Collection rnein Accept_Encoding bilgisi.

Response
stemciye dnen HTTP paketindeki balk bilgilerini ierir. rnein retilen ierik
Headers
tipi (Content Type) grlebilir.
Collection

Form Sunucudan istemciye gnderilen form bilgileri grlebilir. rnein


Collection retilen _VIEWSTATE deerine baklabilir.

Querystring Sayfadan istenen query string bilgileri var ise bunlarn adlar ve o anki
Collection deerleri grlebilir.

Server Sunucu deikenleri elde edilebilir. rnein, sunucu uygulamann fiziki


Variables yolu(APPL_PHYSICAL_PATH), yerel ip adresi(LOCAL_ADDR) gibi.

Ayn bilgilere ulamak iin adres satrnda Trace.axd dosyasda talep edilebilir.

Trace.axd, WebResource.axd benzeri bir dosyadr. Dolaysyla alma zamannda zel


ekilde ele alnr. Asp.Net alma ortam Trace.axd taleplerininTraceHandler isimli snfa
ait nesne rneklerine devredilerek karlanmasn salar.

Dolaysyla sz konusu talep sonras oluan ekran kts TraceHandler snf tarafndan
hazrlanr. Makinedeki ana web.config dosyasnn ieriine bakldnda bu aka
grlebilir. Burada dikkat edilmesi gereken noktalardan birisi sadece Trace.axd iin byle
bir handler' n yazlm olmasdr. Trace.axd veWebResource.axd dnda gelecek
talepler HttpNotFoundHandler tarafndan ele alnmaktadr.

www.bsenyurt.com Page 964


Aadaki ekran grntsnde Trace.axd' nin talep edilmesinin rnek sonular gsterilmektedir.

Kod tarafnda Trace bilgilerini ele almak iin Page nesne rnei zerinden Trace zellii
kullanlmaktadr. Aslnda Trace zellii dorudan TraceContext snfna ait bir nesne rnei
dndrmektedir. TraceContext snf sealed olarak iaretlenmi bir tip olduundan
tretilerek(inherit) zelletirilemez. Bu snfn Framework ierisindeki yeri ekilsel olarak aadaki
gibidir.

www.bsenyurt.com Page 965


TraceContext snfnn yeleri gz nne alndnda, Write ve Warn metodlar kod ierisinden
Trace ktsna bilgi yazdrmak amacyla kullanlmaktadr. Bunlarn arasndaki tek fark Warn
metodunun yazy krmz punto ile basyor olmasdr. Dier taraftan her iki metodda 3 farkl ar
yklenmi versiyona sahiptir. Bu versiyonlar yardmyla yazdrlan bilginin kategorisi(Category),
ierii(Message) ve o anda yakalanm bir istisna(Exception) var ise bu istisna nesne rnei
Trace ktsna gnderilebilir. IsEnabled zellii ile daha ncedende belirtildii gibi Trace' in
etklinletirilmesi veya pasif moda ekilmesi salanabilir. TraceMode zellii TraceMode enum
sabiti tipinden deerler alabilmektedir.

Bu deerler sayesinde Trace ktsnda yer alan Trace Information ksmndaki bilgilerin kategori
veya sre bazl olarak sralanp sralanmayaca belirlenebilir. Bu yeler dnda TraceContext snf
zellikle bileenlerin ierisinde ele alnmak istendiinde yapc metoddan bir rnek oluturulmas
gerekmektedir. Bunun iin yapc metodHttpContext tipinden bir parametre alr. Bunu ilerleyen
ksmlarda ele alacaz. TraceContext snfnn birde TraceFinished isimli olay
vardr. TraceContextEventHandlertemsilcisinin tanmlad yapya uygun olay metodu
arlabilir. Bu olay TraceContext snfna .Net 2.0 ile birlikte katlmtr. TraceFinished olay, Trace
bilgileri toplandktan sonra TraceContext snfnn kendisi tarafndan
tetiklenir. TraceContextEventArgs tipinden olan ikinci parametre sayesinde Trace ile ilgili veriler
elde edilebilir ve bu sayede farkl veri kaynaklarna yazlmalar salanabilir. Aadaki kod
parasnda bu olayn kullanm rneklenmeye allmaktadr.

protected void Page_Load(object sender, EventArgs ea)


{
Page.Trace.IsEnabled = true;
Page.Trace.TraceFinished += new TraceContextEventHandler(Trace_TraceFinished);
}

void Trace_TraceFinished(object sender, TraceContextEventArgs e)


{
IEnumerator numarator=e.TraceRecords.GetEnumerator();
while (numarator.MoveNext())
{
TraceContextRecord record = (TraceContextRecord)numarator.Current;
Response.Write(record.Category + " : " + record.Message + "<br/>");
}
}

TraceContextEventArgs tipinden e deikeni zerinden elde edilen koleksiyon ierisindeki her bir
eleman TraceContextRecord snfna ait birer nesne rneidir. Bu tip yardmyla Trace
Information ksmndaki kategori, mesaj, istisna tipi ve uyar olup olmad(IsWarning) bilgilerine
eriilebilir. Aadaki ekran grntsnde bu bilgiler yer almaktadr.

www.bsenyurt.com Page 966


Bu kodun yer ald sayfa ilk talep edildiinde aadaki ekran ktsnda yer alan ierik elde edilir.

Post ileminden sonra ise TraceFinished ierisinden yakalanan mesajlarn says sayfann yaam
dngs nedeni ile artacak ve aadakine benzer bir ekran kts elde edilecektir.

www.bsenyurt.com Page 967


Sz konusu olay metodu ile her ne kadar Trace Information ile ilgili ok az bilgiye ulasakta
zaten geri kalan verilerin ou HttpResponse veya HttpRequest gibi tipler yardmyla elde
edilebilmektedir. Dolaysyla bu olay ierisinde bu tipler araclyla elde edilen veriler baka veri
ortamlarna da yazdrlabilirler.

imdi Trace mekanizmasn farkl yollar ile incelemeye devam edeceiz. lk olarak sayfa
seviyesinde Trace bilgilerini izlemenin nasl faydas olabiliceini grmeye alacaz. Bu amala
aadaki web sayfas ve kodlar gz nne alnabilir. (Bu ve sonraki asp.net sayfalarnda,
ilemlerin kolay takip edilmesi amacyla inline-coding teknii kullanlmtr.)

<%@ Page Language="C#" %>


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void btnCek_Click(object sender, EventArgs e)


{
string urunAdlari="";
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))

www.bsenyurt.com Page 968


{
SqlCommand cmd = new SqlCommand("Select Top 10000 TransactionId From
Production.TransactionHistory", conn);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
urunAdlari += reader["TransactionId"].ToString()+"|";
}
reader.Close();
}
Session.Add("TumKategoriler", urunAdlari);
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnCek" runat="server" Text="Veriyi ek" OnClick="btnCek_Click" />
</div>
</form>
</body>
</html>

Web sayfamzda yer alan dmeye basldnda, TransactionHistory tablosundaki ilk 10000
TransactionId deeri elde edilir ve bunlar bir string ierisinde birletirilerek Session' a atlr. Kod her
ne kadar anlaml gzkmesede (ki gzkmedii ortada :) ) ortaya kard sonular nedeniyle
kayda deerdir. Nitekim sayfa talep edildikten sonra dmeye basldnda sayfann uzun bir
srede kt verdii grlecektir. Burada herhangibir hata grnmemektedir. Ancak sayfann
ktsnn retilmesi ve istemciye gelmesinin neden uzun srdde incelenmelidir. te bu amala
bu sayfa zerinde Trace ilemi gereklenmelidir. Hatrlanaca zere bunu kod veya direktif
ierisinde yapabileceimizi belirtmitik. Bu nedenle Page direktifinde yer
alan Trace niteliine true deerini verelim ve kodlarmz aadaki gibi deitirelim.

using (SqlConnection conn = new SqlConnection("data


source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select Top 10000 TransactionId From
Production.TransactionHistory", conn);
conn.Open();
Trace.Warn("TransactionId Cekme", "TransactionId deerleri ekilmeye balanacak");
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
urunAdlari += reader["TransactionId"].ToString()+"|";
}
Trace.Warn("TransactionId Cekme", "TransactionId deerleri ekildi...");
reader.Close();
}

www.bsenyurt.com Page 969


Burada Warn metodu kullanlarak urunAdlari toplanmadan nce ve toplandktan sonra Trace
ktsna kategori bazl deerler yazdrlmaktadr. Bunun sonucunda sayfa kts aadaki gibi
olacaktr.

Sonular irdelerken From First(s) ve From Last(s) ksmlarndaki sreler ok nemlidir. From
First(s) ile sayfann talepten sonraki yaam dngs baladndan beri geen toplam sre ifade
edilir. Form Last(s) ise, bir nceki ilem ile son ilem arasndaki geen sre farkdr. Bylece kod
yardmyla sayfann alma zaman ktsna baklm ve sre uzamasnn nerede olduu tespit
edilebilmitir. Grld gibi string bilgisini olutururken + operatr nedeni ile verinin oluumu
son derece fazla zaman almtr. Aslnda burada alnacak tedbir son derece basittir. + operatr
yerine StringBuilder kullanmak. Bunun iin kod aadaki gibi deitirilebilir.

StringBuilder builder = new StringBuilder();


using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select Top 10000 TransactionId From
Production.TransactionHistory", conn);
conn.Open();

www.bsenyurt.com Page 970


Trace.Warn("TransactionId Cekme", "TransactionId deerleri ekilmeye balanacak");
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
builder.Append(reader["TransactionId"].ToString());
builder.Append("|");
}
Trace.Warn("TransactionId Cekme", "TransactionId deerleri ekildi...");
reader.Close();
}
Session.Add("TumKategoriler", builder.ToString());

Buna gre sonular aadaki ekran grntsndeki gibi olacaktr.

Grld gibi kod ierisinde pheli bulunulan noktalarda uygulanacak teknikler ile sayfann
alma zamanndaki hali ok daha kolay bir ekilde izlenebilmektedir.

Trace snfna ait Write ve Warn metodlar uygulama ierisinde pek ok yerde
kullanlabilir. Buna gre Trace mekanizmasnn geersiz klnmas haline, sz konusu
metodlar grmezden gelinecei iin, tm uygulama kodunu gzden geirerek bu
metodlara ait satrlarn kaldrlmasna gerek kalmayacaktr.

Uygulama seviyesinde Trace mekanizmasn aktif klabilmek


iin web.config dosyasnda trace elementi kullanlmal ve enabled zelliine true deeri
atanmaldr. Bunun dnda trace elementi ierisinden belirlenebilecek baz ayarlamalarda
yaplabilir. Bylece web uygulamas ierisindeki tm sayfalar iin izleme yaplabilir.

www.bsenyurt.com Page 971


trace elementinin ierisinde kullanlabilecek nitelikler ve anlamlar ise aadaki tabloda olduu
gibidir.

trace Elementine Ait Genel zellikler

requestLimit trace log ierisinde uygulamaya ait ka talebin(request) saklanaca


belirtilir. Limit almas halinde eer mostRecent zelliinin
deeri false ise uygulama yeniden balatlana veya trace log bilinli bir
ekilde temizlenene kadar log' a bilgi atlmaz. Bu niteliin varsaylan
deeri 10 dur. Maksimum olarak10000 deeri verilebilir. 10000' den
byk bir deer verilmesi halinde ise, bu deer otomatik olarak 10000'
e ekilir.

pageOutput true ise Trace bilgileri web uygulamas ierisindeki sayfalarn sonuna
eklenir. false olmas halinde ise izleme bilgileri
sadece Trace.axd zerinden takip edilebilir.

localOnly true olmasl halinde Trace ktsn istemciler gremez. Sadece web
uygulamasnn olduu makinedeki kullanc grebilir. Bu bir anlamda
Trace ktsn sadece gelitiricinin izleyebilmesi anlamnada gelebilir ki
gncel projelerde ska bavurulan bir yntemdir.

enabled true olmas haline uygulama baznda(Application Level) izleme


modu ak olacaktr.

mostRecent varsaylan deeri false olan bu nitelie true deeri verilirse


, requestLimit almas halinde gelen talepler son elde edilen
taleplerin zerine yazlr. Bylece son taleplerin grlebilmesi salanm
olur. Bu nitelik(attribute) Asp.Net 2.0 ile birlikte yeni gelmitir.

traceMode Daha ncedende deinildii gibi, Trace Information ksmnda yer alan
bilgilerin, kategori veya sre bazl sralanp sralanmayacan belirtir.

writeToDiagnosticTrace Varsaylan deeri false olan bu zellik Asp.Net 2.0 ile birlikte gelmi
olup, Trace mesajlarnn System.Diagnostics alt yapsna gnderilip
gnderilmeyeceini belirlemekte kullanlr.

www.bsenyurt.com Page 972


Aada rnek bir trace elementi ierii yer almaktadr.

<?xml version="1.0"?>
<configuration>
<appSettings/>
<connectionStrings/>
<system.web>
<trace enabled="true" requestLimit="5" mostRecent="true" pageOutput="false"
localOnly="true" writeToDiagnosticsTrace="true" />
<compilation debug="true"/>
<authentication mode="Windows"/>
</system.web>
</configuration>

Buna gre son 5 talebe ait trace bilgileri tutulacak, sayfa kts verilmeyecek bir baka
deyile trace.axd ile talep edilebilecek, yanlzca host makinedeki kullanc trace.axd' ye
bakabilecek ve bilgiler System.Diagnostics alt yapsna devredilebilecektir. Dolaysyla uygulama
altrldktan sonra sz konusu izleme bilgileri aadaki gibi olacaktr.

Burada sayfalara ait izleme detaylarna bakmak iin View Details linki kullanlabilmektedir. ktda
yer alan bilgilere bakldnda taleplerin zaman(Time of Request), durumu-status code (rnein
talep edilen sayfa baarl bir ekilde yklendiyse 200, olmayan bir sayfa talep edildiyse 404...),
HTTP' nin hangi metoduna gre (POST, GET...) talep edildii(Verb) ve talep sras(No) gibi bilgiler
yer alr.

Gelitirilen web uygulamas datlrken trace.axd dosyasnn hi bir ekilde talep


edilememesi salanabilir. Bunun iin web.config dosyasnda yer alan system.web elementi altnda
aadaki deiiklii yapmak yeterlidir.

www.bsenyurt.com Page 973


<system.web>
<httpHandlers>
<remove verb="*" path="trace.axd"/>
</httpHandlers>
</system.web>

Buna gre sz konusu web.config dosyasnn ieren uygulamada herhangibir ekilde Trace.axd
dosyas talep edilirse aadaki ekran grnts elde edilecektir.

Gelelim izleme ile ilikili dier konulara. Baz durumlarda kod ierisinde kullandmz Trace
ifadelerinin sadece istisnalar olutuunda tutulmasn isteyebiliriz. Buna ek olarak, trace ierisine
atlacak istisna bilgilerinin sadece host makinedeki kullancya gsterilmesi istenebilir. Trace bilgisini
sadece yerel kullancya gstermek iin localOnly zellii kullanlabilir. Ancak burada durum biraz
daha farkldr. Nitekim, trace baslmakta ama ieride istisna olumas halinde gsterilen ierik
sadece yerel kullanc iin oluturulmak istenmektedir. Bu vakkay zmek iin Trace
ifadelerinin catch bloklar ierisinde ele alnaca ortadadr. Dier
taraftan Write veya Warn metodlarnn nc parametreleri burada nemlidir. Nitekim nc
parametre oluan istisna(Exception) referansn tamaktadr. Exception tipini trace ktsna
vermek dnda, talepte bulunan kullancnnda host makineden geldiini tespit etmek gerekir. Bu
nedenle aadaki admlar izlenebilir.(Olayn daha kolay anlalabilmesi iin konu ema ile
desteklenmitir)

1. Request ile istemcinin Host adresi renilir. Burada Request.UserHostAddress' den


faydalanlabilir.

2. Elde edilen adresin 127.0.0.1 olup olmadna baklr. yleyse talep yerel makineden gelmitir
ve trace alabilir.

3. Talep yerel makineden gelmiyorsa Requset.ServerVariables("LOCAL_ADDR") ile elde edilen


ip adresi ve Request.UserHostAddress ile elde edilen istemci adresi karlatrlr. Bu yerel host
adresinin 127.0.0.1' den farkl olmasna kar alnan bir tedbirdir. Eer eitlerse talebin yine yerel
makineden geldii anlalabilir.

4. Eer taleplerin yerelden geldii anlaldysa kt retilir.

www.bsenyurt.com Page 974


Kod tarafnda ise rnek olarak aadaki sayfa dnlebilir. Burada bilinli olarak
bir istisna(Exception) oluturulmaktadr.

<%@ Page Language="C#" %>


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected bool TraceYazilsinmi()


{
string userHostAddress = Request.UserHostAddress;
if (userHostAddress == "127.0.0.1")
return true;
else
{
string localAddress
= Request.ServerVariables.GetValues("LOCAL_ADDR").ToString();
if (localAddress == userHostAddress)
return true;
else
return false;
}
}

www.bsenyurt.com Page 975


protected void btnBaglantiAc_Click(object sender, EventArgs e)
{
SqlConnection conn = null;
try
{
conn = new SqlConnection("data source=.;database=" + txtVeritabani.Text + ";integrated
security=SSPI");
conn.Open();
Response.Write("Balant ald");
}
catch (Exception excp)
{
if (TraceYazilsinmi())
{
Trace.IsEnabled = true;
Trace.Warn("Developer in Hata Bilgisi", "Balant almas srasnda hata
olutu", excp);
}
}
finally
{
if (conn != null
&& conn.State == ConnectionState.Open)
conn.Close();
}
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Veritaban Ad : <asp:TextBox ID="txtVeritabani" runat="server" />
<asp:Button ID="btnBaglantiAc" runat="server" Text="Balant A"
OnClick="btnBaglantiAc_Click" />
</div>
</form>
</body>
</html>

Uygulamada kullanc textbox kontrolnden girdii veritaban ad iin bir balant amaya
almaktadr. Eer balantnn almas srasnda bir hata oluursa ve kullanc host makineden
talepte bulunmusa Trace ktsnn etkinletirilmesi ve istisna mesajnn buraya yazdrlmas
salanr. Burada istemcinin Ip adresini tedarik edebilmek
iin HttpRequest snfnn UserHostAddress zellii kullanlr. Local_Addr deeri ilede sunucu
deikenlerinden(Server Variables) sunucu ip adresi elde edilmektedir. Nitekim sunucu ip adresi
127.0.0.1' den farklda olabilir. O halde talep eden istemcinin ip adresi ile yerel ip adresinin eit
olup olmadna da baklmaldr. Uygulamay test edip, rnein olmayan bir veritaban ad
girdiimizde sonu sayfas aadaki gibi olacaktr.

www.bsenyurt.com Page 976


Dikkat edilecek olursa istisna bilgisi detayalar ile birlikte Trace Information ksmnda zel
kategori ad ve mesaj ile birlikte grlmektedir. Bu tarz bir alma zaman bilgisi elbetteki
gelitirici(Developer) asndan nemlidir. Ayn sonular ok doal olarak Trace mekanizmas
olmadan da tespit edilebilir. Buradaki temel ama Trace mekanizmasn kullanarak, sayfalarda
oluabilecek hatalarn kesin yerlerini ve konumlarn daha kolay tespit edebilmektir.

Gelelim Trace mekanizmas ile ilgili dier bir konuya. ok doal olarak web uygulamalarnda harici
bileenler(Components) kullanlr. Bileenden kastmz ounlukla bir snf ktphanesi(class
library) veya ayr bir snf dosyasdr. ok doal olarak bu bileenler ierisindeki baz sreler

www.bsenyurt.com Page 977


Trace mekanizmas ierisinde ele alnmak istenebilir. rnein ilk uygulamada gerekletirdiimiz
string birletirme ileminin ayr bir snf ierisinde bir metod olarak ele alndn dnelim.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Data.SqlClient;

public class VeriBileseni


{
public string GetTransactionIdString()
{
HttpContext ctx = HttpContext.Current;
StringBuilder builder = new StringBuilder();
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select Top 10000 TransactionId From
Production.TransactionHistory", conn);
conn.Open();
ctx.Trace.Warn("TransactionId Cekme", "TransactionId deerleri ekilmeye balanacak");
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
builder.Append(reader["TransactionId"].ToString());
builder.Append("|");
}
ctx.Trace.Warn("TransactionId Cekme", "TransactionId deerleri ekildi...");
reader.Close();
}
return builder.ToString();
}
public VeriBileseni()
{
}
}

Burada dikkat edilmesi gereken en nemli nokta Trace snfn kullanmak


iin HttpContext nesnesinin nasl elde edildiidir. Bileenlerde Trace bilgisi ele alnyorsa, bu
bileenin kullanld HTTP ieriinin kullanlmas gerekmektedir. Bu nedenle HttpContext nesne
rnei iin statik(static) Current zelliinden faydalanlmtr. Bylece bileeni o anda kullanan
sayfa ieriine ulalm olunur. Bundan sonra ise Warn veya Write gibi metodlar kullanlabilir.

Bileenin ayr bir snf ktphanesi(class library) olarak tasarlanmas


durumunda, System.Web.dll assembly' nn referans edilmesi gerekecektir. Bunun ise
douraca nemli sonulardan birisi udur; bilenen ierisindeki izleme alt yaps web
baml hale gelmektedir. Bu nedenle alternatif bir yaklam olarak ayr bir dinleyici
mekanizmas zel olarak gelitirilebilir.

www.bsenyurt.com Page 978


Peki sz konusu bileen sadece web tabanl kullanlmyorsa. Bu durumda HttpContext gerekli
ilevsellikleri salamak iin uygun olmayacaktr. Dolaysyla farkl bir yol izlemek gerekmektedir.
.Net Framework izleme mesajlar iin dinleyiciler(Listener) kullanr.
stenirse web.config araclyla yada programatik olarak yeni dinleyiciler eklenebilir. Normal
artlarda Trace.Write gibi bir metod ars yapldnda TraceListener koleksiyonundaki tm
dinleyiciler mesajlar alp ilemeye balarlar. O halde Trace Listener web.config ile ak bir ekilde
belirtilirse, System.Web.dll assembly' n projeye referans etmeden ve HttpContext tipini
kullanmadan Trace ktlar web uygulamasna doru gnderilebilir.

Asp.Net 1.1 ile gelitirme yapyorsak eer, bu ilemler iin zel bir dinleyici yazmamz gerekecektir.
Ne varki Asp.Net 2.0 ile sadece bu i iin tasarlanm WebPageTraceListenerisimli bir snf
gelmektedir. Bu snfn web.config dosyasnda belirtilmesi ve bileen
ierisinde System.Diagnostics isim alan altnda yer alan Trace snfnn kullanlmas yeterlidir.
Bylece bileenimiz trace kts verirken web' e baml olmaktan kurtulmu olacaktr. rnek olarak
az nce gelitirilen VeriBileseni snfn ayr bir snf ktphanesi olarak aadaki gibi tasarladmz
dnelim.

using System;
using System.Data;
using System.Diagnostics;
using System.Data.SqlClient;
using System.Text;

public class BagimsizVeriBileseni


{
public string GetTransactionIdString()
{
StringBuilder builder = new StringBuilder();
using (SqlConnection conn = new SqlConnection("data
source=.;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select Top 10000 TransactionId From
Production.TransactionHistory", conn);
conn.Open();

www.bsenyurt.com Page 979


Trace.Write("TransactionId Cekme", "TransactionId deerleri ekilmeye balanacak");
SqlDataReader reader = cmd.ExecuteReader();
while (reader.Read())
{
builder.Append(reader["TransactionId"].ToString());
builder.Append("|");
}
Trace.Write("TransactionId Cekme", "TransactionId deerleri ekildi...");
reader.Close();
}
return builder.ToString();
}
}

Burada dikkat edilecek olursa herhangibir ekilde System.Web referans kullanlmamaktadr. Bunun
yerine System.Diagnostics isim alan ve burada yer alan Trace snf ele alnmaktadr. Bir nceki
bileenden farkl olarak Warn metodu kullanlamamaktadr. Bunun
nedeni System.Diagnostics isim alannda yer alan Trace snfnn Warn metodunun olmaydr.
Dier nemli noktalardan biriside, System.Diagnostics.Trace snfndaki Write metodu
versiyonlarndan belirli bir Exception nesne rneininin frlatlmasnn mmkn olmaydr. Ancak
istisna mesaj gnderilmesi salanabilir. Bu ilemin ardndan web uygulamasna ait web.config
dosyasnda aadaki deiiklikler yaplmaldr.

<?xml version="1.0"?>
<configuration>
.
.
.
<system.diagnostics>
<trace>
<listeners>
<add name="WebPageTraceListener" type="System.Web.WebPageTraceListener,S
ystem.Web,Version=2.0.3600.0,Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
</listeners>
</trace>
</system.diagnostics>
.
.
.
</configuration>

Burada listeners bilgisi eklenirken system.diagnostics isim elementi ierisindeki trace elementi
kullanlmaktadr. add elementi ierisinde yer alan type kmsnda WebPageTraceListener snfnn
tam ad (Qualified Name) belirtilmektedir. Bildiiniz zere Qualified Name' i oluturan deerler tip
ad, assembly ad, versiyon numaras, kltr ve publicKeyToken bilgisidir. Bu durumu test etmek
iin az nceki rnektekine benzer bir web sayfas aadaki gibi gelitirilebilir.

<%@ Page Language="C#" Trace="true" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void btnCek_Click(object sender, EventArgs e)

www.bsenyurt.com Page 980


{
BagimsizVeriBileseni veriBln = new BagimsizVeriBileseni();
Session.Add("TransactionIDler", veriBln.GetTransactionIdString());
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="btnCek" runat="server" Text="Veriyi ek" OnClick="btnCek_Click" />
</div>
</form>
</body>
</html>

Trace kts ise aadaki gibi olacaktr.

Trace mimarisi ile ilgili olaraktan, ele alnabilecek baka konularda bulunmaktadr. rnein Trace
bilgilerini baka ortamlara aktarmak, mail gnderimi gerekletirilmesi gibi. Tatile ktm u
gnlerde bu kadar bilginin yeterli olaca kansndaym. Dnte Trace mimarisinin ikinci makalesi
ile devam edeceiz. Bylece geldik bir makalemizin daha sonuna. Bu makalemizde trace mimarisini
tanmaya, gerekliliklerini vurgulamaya altk. Sayfa seviyesinde ve uygulama seviyesinde trace
ilemlerinin nasl yaplacan, sadece istisna olutuunda yanlz yerel makineye trace bilgisinin
nasl verileceini, bileen baznda trace' lerin kullanlmasn ve bileenin web ortamndan bamsz
olabilecek ekilde ele alnabilmesini incelemeye altk. Nihayetinde bu uzun makaleyi buraya

www.bsenyurt.com Page 981


kadar sabrla okuduunuz iin teekkr eder bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net Temelleri : Tablo Bazl Resimleri Ele


Almak ( 26.07.2007 ) - Asp.Net
Deerli Okurlarm Merhabalar,

Yazn bu scak gnlerinde daha hafif konularla web maceralarmza devam ediyoruz. Getiimiz
makalemizde Asp.Net uygulamalarnda ektin hata ynetiminin nasl yaplabileceini incelemeye
almtk. Bu kez veritaban tablolarnda ounlukla binary alanlarda saklanan resimlerin, Asp.Net
uygulamalarnda nasl ele alnabileceini rnek projeler zerinden incelemeye alacaz. Bir
Windows uygulamas gz nne alndnda, resimleri gsterebilecek bir PictureBox kontrolnn
eitli zellikleriden yararlanarak herhangibir tabloda tutulan binary ierii kullanmak ve bu ieriin
iaret ettii resmi gstermek son derece kolaydr. Ne varki Asp.Net uygulamalarnda her zaman
iin,render edilerek istemciye gnderilen bir sayfa ierii mevcuttur. Bu ieriin tipi(Content
Type) daha farkldr. Dolaysyla binary formatta tutulan resimleri ele almak iin farkl bir yaklam
gerekmektedir.

Tabloda binary formatta tutulabilen resimleri Asp.Net uygulamalarnda ele almak amacyla,
gsterilmek istenen resmi tek bana yorumlayan bir Asp.Net sayfas mevcuttur. Bu sayfann tek bir
grevi vardr o da ilgili resmi image formatlarndan uygun olana gre sayfaya Render etmektir.
Bunu incemelek iin rnek bir senaryo gz nne almakta fayda olaca kansndaym. Bu
amala SQL Server 2005 ile birlikte gelen ve Production emasnda(Schema) bulunan Product,
ProductPhoto ve ProductProductPhoto tablolar gz nne alnabilir. Bu tablolar arasndaki
iliki ksaca aadaki ekilde grld gibidir.

www.bsenyurt.com Page 982


ProductPhoto isimli tabloda yer alan ThumbNailPhoto ve LargePhoto isimli
alanlarda binary olarak rn resimleri saklanmaktadr(tam olarak varbinary tipinde). Buna gre ilk
rnek senaryomuzda kullanclar rnlerin listelendii bir sayfadan detay bilgilerini almak iin baka
bir sayfaya gei yapacaklardr. Detaylarn verildii sayfada rne aitThumbNailPhoto ieriide
bir resim olarak sayfa gsterilecektir. Balamadan nce ProductPhoto tablosundaki herhangibir
ThumbNailPhoto alannn ieriini resim olarak nasl gsterebileceimize bakalm. Bu amala
ResimGoster.aspx isimli aadaki gibi bir sayfa tasarlanarak ie balanabilir.

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


Inherits="ResimGoster" %>

Eminimki ResimGoster isimli web sayfasnn ierii son derece ilgin gelmitir. Nitekim herhangibir
HTML elementi yer almamaktadr. Aslnda bu sayfann tek amac yklenirken(bir baka
deyile Page_Load olay metodu alrken), rn resmini ekrana binary olarak yazdrmaktr.
Burada elbetteki hangi resmin gsterileceide nemlidir. Bunun iin sayfaya bir ekilde
ProductPhotoID alannn deerinin gelmesi gerekmektedir. Bunun iin en gzel
yol QueryString kullanmdr. yleyse bu sayfann kodlarn yazarak ie devam edelim.

protected void Page_Load(object sender, EventArgs e)


{
string resimId = Request.QueryString["ResimId"];
if (!String.IsNullOrEmpty(resimId))
{
byte[] resimBytes=null;
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select ThumbNailPhoto From
Production.ProductPhoto Where ProductPhotoId=@PhotoId", conn);

www.bsenyurt.com Page 983


cmd.Parameters.AddWithValue("@PhotoId", resimId);
conn.Open();
SqlDataReader reader = cmd.ExecuteReader(CommandBehavior.SequentialAccess);
if(reader.Read())
resimBytes = reader.GetSqlBytes(0).Value;
reader.Close();
if (resimBytes != null)
{
Response.ContentType = "image/gif";
Response.BinaryWrite(resimBytes);
}
else
Response.Write("Resim gsterilemiyor.");
}
}
else
Response.Write("ResimId parametresi eksik yada hatal.");
}

Page_Load olay metodu ierisinde ilk olarak HttpRequest snfnn static QueryString zellii
yardmyla sayfaya gelen ResimId deeri alnmaktadr. Kullanclarn bu sayfay dorudan talep
etme ihtimaline gre ResimId deerinin bo gelme olasl bulunmaktadr. Bu
nedenle String snfnn IsNullOrEmpty metodu ile bir kontrol gerekletirilir. Sonrasnda ise
Production emasndaki ProductPhoto tablosunda gelen deere gre ilgili ThumbNailPhoto alan
ekilir. Eer gelen ResimId ile eleen bir ProductPhotoId alan var ise bu satrn ThumbNailPhoto
alannn deeri SqlDataReader nesne rneine ait Read metodu yardmyla okunur. Okuma ilemi
srasndaGetSqlBytes metodu kullanlmakta ve Value zellii ile elde edilen byte dizisi resimBytes
isimli alana aktarlmaktadr. Dier taraftan HttpResponse snfnn ContentType zellii ile render
edilecek sayfann ierii belirlenmektedir. Burada image/gif deeri ile baslacak ieriin gif
formatnda bir resim olaca belirtilmektedir.

ContentType zelliinin varsaylan deeri text/HTML dir. Bu deer, tahmin edilecei


zere sayfann ktsnn HTML olarak retileceini iaret etmektedir. Yaygn olarak
kullanlan dier versiyonlar aadaki gibidir.

image/gif
image/jpeg
text/plain
application/vnd.ms-excel (ktnn excel dkman olmasn salar)
application/vnd.ms-word (ktnn word dkman olmasn salar)

Son olarak, elde edilen byte dizisinin ktya aktarlmasn salamak iin
yine HttpResponse snfnn static metodlarndan BinaryWrite arlmaktadr.

Artk sayfay test ederek ilemlerimize devam edebiliriz. Elbette doru sonular grebilmek iin
ResimId parametresini Url satrndan gndermekte fayda vardr. Aada rnek
olarak 120 numaral ProductPhotoId deerine sahip satr iin elde edilen kt grlmektedir.

www.bsenyurt.com Page 984


Burada, retilen HTML sayfasnn kaynak kodlarna baklmak istenirse tarayc buna izin
vermeyebilir(rnein Microsoft Internet Explorer 7.0 View Source buna izin vermemitir). Bu
sebepten kty Save As ile kaydetmek gerekebilir. Kaydedilen ktnn ierii aadaki ekran
grntsnde yer ald gibi olacaktr. Dikkat edilecek olursa sayfann kts sonucu oluturulan
ierikte img elementi ve src nitelii yer almaktadr.

Elbette satr olarak karl olmayan bir ResimId deeri girilirse sayfa kts tarayc penceresinde
aadaki gibi olacaktr. rnein ProductPhotoId deeri 17 olan bir satr bulunmamaktadr.

Bununla birlikte kullanc bu sayfay dorudan talep eder ve ResimId parametresini kullanmassa
aadaki ekran ktsn elde eder.

Burada olas baz hatalarn nne geilmek amacyla basit tedbirler alnm ve ekrana bilgi
mesajlar verilmitir. Gerek hayat uygulamalarnda son kullanclarn daha doru ve etkin bir
ekilde uyarlmas bir baka deyile oluan hatalar konusunda bilgilendirilmesi gerekmektedir.

www.bsenyurt.com Page 985


Artk tek yaplmas gereken senaryoyu biraz daha kullanl hale getirmektir. Bu amala rnlerin
gsterildii Urunler.aspx isimli basit bir web sayfas tasarlanarak devam edilbilir. Bu sayfada
rnlere ait bir ka temel bilgi bulunacak ama detaylar iin baka bir sayfaya ynlendirmede
bulunulacaktr. Ynlendirilme yaplan sayfa tahmin edilecei zere rne ait resmide ieren bir
detay sayfasdr. Urunler.aspx sayfasnda basit olarak bir SqlDataSource kontrol ve bu kontrol
ele alan bir GridView bileeni dnlebilir. Buna gre Urunler.aspx sayfasnn kaynak kod taraf
aadaki gibi tasarlanabilir.

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


Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Urunler</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="dsProducts">
<Columns>
<asp:HyperLinkField DataNavigateUrlFields="ProductId" DataNavigateUrlFo
rmatString="UrunDetay.aspx?PrdId={0}" DataTextField="Name" HeaderText="Urun Ad"
/>
<asp:BoundField DataField="ListPrice" DataFormatString="{0:C}"
HeaderText="Liste Fiyat" HtmlEncode="False" SortExpression="ListPrice" />
</Columns>
</asp:GridView>
<asp:SqlDataSource ID="dsProducts" runat="server" ConnectionString="<%$
ConnectionStrings:AdvConStr %>" SelectCommand="SELECT Top 20 ProductID, Name,
ListPrice FROM Production.Product Where ListPrice>=1000">
</asp:SqlDataSource>
</div>
</form>
</body>
</html>

Urunler.aspx sayfasnda yer alan GridView kontrolnde HyperLinkField kontrol kullanlmaktadr.


Bu alan, rnn adn(Name) gstermekte olup zerine tklandnda kullancy UrunDetay.aspx
sayfasna gndermektedir. Bu ilem srasnda da PrdId isimli bir QueryString parametresi
ProductId alannn deerini detay sayfasna tamaktadr. Urunler.aspx isimli sayfann alma
zamanndaki kts aadaki ekran grntsnde yer ald gibidir.

www.bsenyurt.com Page 986


Gelelim UrunDetay.aspx sayfasna. Bu sayfada basit olarak Urunler.aspx sayfasnda seilen
rnlere ait detay bilgileri gsterilecektir. Ancak nemli olan, seilen rnn resmininde
ProductPhoto tablosundan binary olarak ekilerek ekrana bastrlacak olmasdr. Bu amala
tasarlanan Urunler.aspx sayfasnda yine bir SqlDataSource kontrol ve detaylar
iinDetailsView bileeni aadaki gibi kullanlabilir.

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


Inherits="UrunDetay" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Urun Detaylari</title>
</head>
<body>

www.bsenyurt.com Page 987


<form id="form1" runat="server">
<div>rn Detaylar :<br />
<asp:DetailsView ID="DetailsView1" runat="server" AutoGenerateRows="False"
DataSourceID="dsProductDetails" Height="50px" Width="294px">
<Fields>
<asp:BoundField DataField="Name" HeaderText="&#220;r&#252;n Ad"
SortExpression="Name" />
<asp:BoundField DataField="ProductNumber" HeaderText="&#220;r&#252;n
Numaras" SortExpression="ProductNumber" />
<asp:BoundField DataField="SafetyStockLevel" HeaderText="Stok Seviyesi"
SortExpression="SafetyStockLevel" />
<asp:BoundField DataField="ReorderPoint" HeaderText="Sipari Noktas"
SortExpression="ReorderPoint" />
<asp:BoundField DataField="ListPrice" HeaderText="Liste Fiyat"
SortExpression="ListPrice" DataFormatString="{0:C}" HtmlEncode="False" />
<asp:BoundField DataField="StandardCost" HeaderText="Standart Maliyet"
SortExpression="StandardCost" DataFormatString="{0:C}" />
<asp:TemplateField HeaderText="Urun Resmi">
<ItemTemplate>
<img alt="rn Resmi"
runat="server" src='<%#"ResimGoster.aspx?ResimID="+DataBinder.Eval(Container.Data
Item, "ProductPhotoID") %>' id="urunResmi" />
</ItemTemplate>
</asp:TemplateField>
</Fields>
</asp:DetailsView>
<asp:SqlDataSource ID="dsProductDetails" runat="server" ConnectionString="<%$
ConnectionStrings:AdvConStr %>" SelectCommand="SELECT Production.Product.ProductID,
Production.Product.Name, Production.Product.ProductNumber,
Production.Product.SafetyStockLevel, Production.Product.ReorderPoint,
Production.Product.ListPrice, Production.Product.StandardCost,
Production.ProductProductPhoto.ProductPhotoID FROM Production.Product INNER JOIN
Production.ProductProductPhoto ON Production.Product.ProductID
=Production.ProductProductPhoto.ProductIDWHERE (Production.Product.ProductID =
@PrdId)">
<SelectParameters>
<asp:QueryStringParameter DefaultValue="1" Name="PrdId"
QueryStringField="PrdId" />
</SelectParameters>
</asp:SqlDataSource>
</div>
</form>
</body>
</html>

UrunDetay.aspx isimli web sayfasnda dikkat edilmesi ve zerinde durulmas gereken baz noktalar
vardr. ncelikli olarak SqlDataSource kontrolnde kullanlan sorgu basit olarak aadaki ekilde
yer ald(Query Builder ile elde edilmitir) gibi Product ve ProductProductPhoto tablolarnn join ile
birletirilmi bir halidir ve ProductId deerinin whereifadesinde ele almaktadr. Nitekim rn
resminin ProductPhoto tablosundan tedariki iin ProductPhotoID deerinin bilinmesi gerekmektedir.
Bu nedenle Product ve ProductProductPhoto tabloar Join ile birletirilmitir.

www.bsenyurt.com Page 988


Dier taraftan DetailsView kontrol ierisindede resmin gsterilebilmesi iin
bir TemplateField kullanlm ve ItemTemplate ablonu ierisinde img elementi aadaki gibi
kullanlmtr.

<asp:TemplateField HeaderText="Urun Resmi">


<ItemTemplate>
<img alt="rn Resmi"
runat="server" src='<%#"ResimGoster.aspx?ResimID="+DataBinder.Eval(Container.Data
Item, "ProductPhotoID") %>' id="urunResmi" />
</ItemTemplate>
</asp:TemplateField>

Burada dikkat edilmesi gereken en nemli nokta src niteliine(attribute) deer atamasnn nasl
yaplddr. DataBinder snfnn Eval metodunu kullanarak o anki satrn ierisinde yer alan
ProdcutPhotoId deeri ResimGoster.aspx sayfasna ResimID adl parametre ile gnderilmektedir.
Buda yazmzn banda tasarladmz ResimGoster sayfasnn arlmas ve bir resim ieriinin
elde edilerek buradaki img kontrol ierisinde gsterilmesi anlamna gelmektedir. Sonu itibariyle
UrunDetay.aspx sayfas test edildiinde aadakine benzer bir ekran kts ile karlalacaktr.

www.bsenyurt.com Page 989


Buraya kadar yaptklarmz zetleyecek olursak eer, binary olarak tutulan resimlerin gsterilmesi
iin izlenebilecek yollardan birisinin admlar aadaki gibi olacaktr.

lk olarak resim ieriini binary olarak taraycya basabilecek bir aspx sayfas tasarlanr.
Sayfann amac gerei aspx kaynanda(Source) sadece Page direktifi braklr ve dier
ierik silinir. Bu zorunlu deildir. Ancak tavsiye edilen yoldur.
Sayfann Page_Load olay metodu kodlanr.
Page_Load olay metodunda gsterilmek istenen resme ait satrn bulunabilmesi
iin QueryString' den yararlanlabilir.
Resme ait binary ieriin kod tarafnda byte dizisi(byte[]) eklinde ele alnmas salanr.
Elde edilen byte dizisinin sayfaya resim olarak baslmasn salamak iin
nce ContentType zelliinin deeri image/gif veya image/jpeg olarak belirlenir.
Resmi yazdrmak iinse BinaryWrite metodu arlr.

Buradaki rnek gz nne alndnda istemci saysnn fazla olaca dnelecek olursa
performans arttrmak adna parametre bazl olacak ekilde n bellekleme(Caching) yaplmas
salanabilir. Bylece ResimGoster.aspx sayfasnn srekli olarak Page_Load kodlarn
altrmasnn nne geilmi olunur.

Resimlerin ok sk deimedii dnlyorsa ve SQL Server kullanlyorsa tablo baml


bir n belleklemede yaplabilir(Sql Cache Dependency).

Sz gelimi ResimGoster.aspx dosyasnn ierii aadaki gibi deitirilerek sayfann ktsnn belirli
bir sreliine(rnein 60 saniye boyunca) n bellekte tutulmas salanabilir.

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


Inherits="ResimGoster" %>
<%@ OutputCache Duration="60" VaryByParam="ResimID" %>

Gelelim resimlerin ilenmesi ile ilgili dier bir yaklama. rnekte resmi
gsteren img elementinin src niteliinde bir url adresinden yararlanlmaktadr. Elbetteki bu ilem
programatik olarak kod zerindende gelitirilebilir. rnein rn bilgilerini bir DataList kontrol
zerinde gstermek istediimizi varsayalm. Bu kez resim alanlarnn DataList kontrol

www.bsenyurt.com Page 990


ierisindekiimg elementinin src niteliine balanmasn kod tarafndan gerekletirmeye
alacaz. Bu amala aadaki gibi UrunListesi.aspx isimli bir web sayfas hazrlanarak ilemlere
devam edilebilir.

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


<div>
<asp:DataList ID="DataList1"
runat="server" DataSourceID="dsProducts" Width="600px">
<ItemTemplate>
<table>
<tr>
<td colspan="2">
<asp:Label ID="NameLabel" runat="server" Font-Italic="True"
ForeColor="#000040" Text='<%# Eval("Name") %>'></asp:Label>
</td>
<td style="width: 100px; text-align: right">
<asp:Label ID="ProductIDLabel" runat="server" Font-Bold="True"
ForeColor="#C00000" Text='<%# Eval("ProductID") %>'></asp:Label>
</td>
</tr>
<tr>
<td rowspan="3" style="width: 100px">
<img runat="server" id="urunResmi" alt="Urun Resmi" src="" />
</td>
<td style="width: 100px">Standart Maliyet</td>
<td style="width: 100px">
<asp:Label ID="StandardCostLabel" runat="server" Text='<%#
Eval("StandardCost", "{0:C}") %>'></asp:Label>
</td>
</tr>
<tr>
<td style="width: 100px">Liste Fiyat</td>
<td style="width: 100px">
<asp:Label ID="ListPriceLabel" runat="server" Text='<%# Eval("ListPrice",
"{0:C}") %>'></asp:Label>

www.bsenyurt.com Page 991


</td>
</tr>
<tr>
<td style="width: 100px">Snf</td>
<td style="width: 100px">
<asp:Label ID="ClassLabel" runat="server" Text='<%# Eval("Class")
%>'></asp:Label>
</td>
</tr>
<tr>
<td colspan="3"><hr /></td>
</tr>
</table>
</ItemTemplate>
</asp:DataList>
<asp:SqlDataSource ID="dsProducts" runat="server" ConnectionString="<%$
ConnectionStrings:AdvConStr %>" SelectCommand="SELECT Top 20 P.ProductID, P.Name,
P.StandardCost, P.ListPrice, PP.ProductPhotoID, P.Class FROM Production.Product P
INNER JOIN Production.ProductProductPhoto PP ON P.ProductID = PP.ProductID WHERE
P.ListPrice>1400">
</asp:SqlDataSource>
</div>
</form>

UrunListesi.aspx sayfasnda yer alan DataList kontrol Production emasndaki Product ve


ProductProductPhoto tablolarnn birleiminden oluan sonu kmesinden ilk 20 satr gstermek
zere tasarlanmtr ve hatta ListePrice alanna gre filtreleme eklenmitir. Burada zellikle
zerinde durmamz gereken nokta, img elementidir. ItemTemplate zerindeki tablo ierisine
yerletirilen img elementinin src niteliini kod tarafnda ele alabilmek iin DataList
kontrolnn ItemDataBound olayndan yararlanlabilir. Bu olay metodu ierisinde sz konusu img
elementi bulunmal ve src niteliine o anki satrn ProductPhotoId deeri QueryString parametresi
olarak aktarlmaldr. O halde bu amala aadaki kod parasn yazmamz yeterli olacaktr.

protected void DataList1_ItemDataBound(object sender, DataListItemEventArgs e)


{
if (e.Item.ItemType == ListItemType.Item
|| e.Item.ItemType == ListItemType.AlternatingItem)
{
// nce ProductPhotoId deeri bulunmal
string resimId = DataBinder.Eval(e.Item.DataItem, "ProductPhotoId").ToString();
// img elementi bulunmal ve src niteliinin deeri deitirilmeli.
HtmlImage resimElementi = (HtmlImage)e.Item.FindControl("urunResmi");
resimElementi.Src = "~/ResimGoster.aspx?ResimId=" + resimId;
}
}

ItemDataBound olay DataList ierisindeki her bir satr iin alacandan, ilemleri
sadece Item ve AlternatingItem tipindeki satrlarda yapmakta fayda vardr. Bu
amalaDataListItemEventArgs tipinden olan e isimli parametrenin zelliklerinden
faydalanlmaktadr. Sonrasnda ise o anki satr ile gelen ProductPhotoId deerinin elde edilmesi
gerekmektedir. Bu amalada DataBinder snfnn Eval metodu ele alnmaktadr. lk parametre ile
o anki veri satr yakalanmakta, ikinci parametre ilede sz konusu veri
satrndakiProductPhotoId deeri istenmektedir. Eval metodu geriye Object tipinden bir deer
dndrd iin bilinli olarak string tipine dntrlmtr. Nitekim url katarnda kullanlacak
bilgi string' dir.

www.bsenyurt.com Page 992


Bu ilemlerin ardndan img kontrolnn elde edilmesi salanr. Bunun
iinde e.Item zerinden FindControl metodu arlmtr. FindControl metodunun parametresi
kontroln id deerinin iaret etmektedir. Hatrlanaca zere img kontrolnn id niteliine kaynak
tarafnda urunResmi ad verilmitir. img kontrol HtmlImage tipinden bir kontroldr ve
FindControl metodu geriye Control tipinden bir referans dndrdnden sonu referans bilinli
olarak HtmlImage tipine dntrlmtr. Son olarak elde edilen HtmlImage kontrolne ait
referans zerinden Src niteliinin deeri deitirilir. Burada yaplan ilem tm yaz boyunca
zerinde durduumuz konudur. Uygulamay bu haliyle altrdmzda aadakine benzer bir
ekran grnts elde ederiz.

Bu makalemizde tablolarda binary olarak tutulan resim alanlarn web sayfalarnda kk bir hile
ile nasl ileyebileceimizi incelemeye altk. Grsellik hemen hemen tm uygulamalarda nemli
bir faktr olduundan resim alanlarnn bu ekilde ele alnyor olmasn bilmek nemli bir avantaj
salamaktadr. Kullanlan teknikte nemli olan nokta binary alann ieriini tek bana ele alp resim
formatnda kt veren bir sayfann var olmasdr. Ayrca resmi gsteren kontroln basit
bir img bileeni olduuna ve srcniteliinin nemine dikkat edilmelidir. Bu sayfann kts
rneklerden de grld gibi pek ok farkl biimde kullanlabilir ve son kullancya grsel olarak
daha doyurucu bir ierik salanabilir. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

www.bsenyurt.com Page 993


Burak Selim ENYURT
selim@bsenyurt.com

Asp.Net Temelleri - Etkin Hata Ynetimi (Error


Management) ( 18.07.2007 ) - Asp.Net
Deerli Okurlarm Merhabalar,

Uzun sredir Windows Communication Foundation ile ilgili yazlar yaynlyoruz. Sanyorumki biraz
hava deiimine ihtiyacmz olacak. Bu nedenle bu haftaki yazmzda biraz daha hafif ama nemli
olan bir konu zerinde durmaya alacaz. Web uygulamalarnda sunucu tarafl hata ynetimi
(Server Side State Management). .Net ortamnda hatalarn ele alnmasnda kullanlan en bilinen yol
try...catch...finally bloklardr. Ne varki uygulama ortamlar eitlilik gstermektedir. Bir snf
ktphanesi ierisinde yaplan hata kontrol ile datk mimari uygulamalar(distributed
applications) ierisinde yaplan hata ynetimi farkldr.(rnein WCF ierisindeki Fault
Management konusunu hatrlayalm) Bu sebepten Asp.Net uygulamalarndada farkl bir yaklam
ele almak gerekmektedir. Web uygulamalarnda oluan hatalar sonucu ok ho olmayan hata
ekranlar ile karlamak mmkn olabilmektedir. Ancak hatalar kontroll bir ekilde
ynetilebilirlerse, son kullancy bilgilendirebilecek ekilde mesajlar verilip hatalarn dzeltilmesi
ynnde daha salam ve gl admlar atlabilir. Bu ayn zamanda uygulamann tutarll ve
gvenilirlii asndanda nemlidir.

Asp.Net ortam, hatalarn ynetimi amacyla istisna(Exception) tiplerini ve hatalar


yakalayc olay(event) metodlarn gz nne alr. Sz konusu hata ynetimi metod
seviyesinde(Method Level), sayfa seviyesinde(Page Level) ve uygulama
seviyesinde(Application Level) gerekletirilebilir. Aadaki tabloda sz konusu seviyeler ve
aralarndaki temel farklar vurgulanmaya allmaktadr.

Asp.Net Hata Ynetim Seviyeleri (Error Management Levels)

Metod Sayfa Seviyesinde Uygulama Seviyesinde


Seviyesinde

Toparlanabil Bir sayfa ile ilgili Uygulama ierisinde herhangibir sayfada


ir veya bir tm hatalarn tek meydana gelen hatalarn yakalanmas
baka bir merkezden salanr.
deyile ynetilebilmesi Tm web uygulamasnn hata ynetiminin
kurtarlabilir salanr. tek bir merkezden kontrol edilebilmesi
hatalar Olas hatalar salanm olur.
ounlukla sonrasnda Bu
metod kullanclar seviyede global.asax dosyasndaki Applica
seviyesinde ounlukla zel tion_Errorolay metodu ele alnr.
ele alnr. sayfalara Hata sayfasna ynlendirilmeden nce log
Eer olas ynlendirilir. bilgisi yazdrma, fiziki dosyalara bilgi atma
hatalar Bu seviyede veya adminlere mail gnderme gibi ilemler
toparlanama sayfalarn Page_ yaplabilir.
yacak Error olay
cinsten ise metodlar ele
bir st alnr.
seviyeye Hata sayfasna
ynlendirilir. ynlendirilmeden
nce sayfa ile ilgili
log bilgisi

www.bsenyurt.com Page 994


yazdrma, fiziki
dosyalara bilgi
atma veya
adminlere mail
gnderme gibi
ilemler
yaplabilir.

Metod seviyesinden, uygulama seviyesine doru kldka hatalarn merkezi olarak ynetilmesi ve
tek bir merkezden ele alnmas dahada kolaylamakta ancak, detay bilgilerinden gittike
uzaklalmaktadr. Nitekim bir metod ierisinde meydana gelecek bir hata ile ilikili yakalanan
detayn, sayfa veya uygulama seviyesine aktarlmad srece merkezi olarak ayrtrlmas zor
olmaktadr.

imdi gelin bu seviyeleri rnekler yardmyla incelemeye alalm. Metod seviyesinde hata
ynetiminde try...catch...finally bloklar byk nem arz etmektedir. Ancak bu bloklar istenirse
try...catch veya try...finally eklindede yazlabilir. ok doal olarak bunladan hangisinin
kullanlacann kararn vermek iin baz vakkalarn gz nne alnmas gerekmektedir. lk olarak
basit bir rnek ile balayalm. Bu amala kullancnn blme ilemi yapt aadaki gibi bir aspx
sayfas olduunu gz nne alabiliriz.

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

protected void Hesapla_Click(object sender, EventArgs e)


{
double deger1 = Convert.ToDouble(txtDeger1.Text);
double deger2 = Convert.ToDouble(txtDeger2.Text);
double sonuc = deger1 / deger2;
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Hata Yonetimi (Metod Seviyesinde)</title>
</head>
<body>
<form id="form1" runat="server">
<div>
Birinci Deer :
<asp:TextBox ID="txtDeger1" runat="server"></asp:TextBox> <br />
kinci Deer :
<asp:TextBox ID="txtDeger2" runat="server"></asp:TextBox>
<br />
<asp:Button ID="btnHesapla" runat="server" Text="Hesapla" OnClick="Hesapla_Click"
/>
</div>
</form>
</body>

www.bsenyurt.com Page 995


</html>

ncelikle hata kontrol yapmadan sayfay ele almaya alacaz. Bu nedenle rnek olarak ikinci
kutucuu bo brakp Hesapla isimli dmeye basyoruz. Sonu olarak kullanc asndan pekte ho
olmayacak aadaki ekran grnts ile karlarz. (Elbette gelitirme aamasnda bu mesajlar
developer asndan daha kymetli olabilir ;)

Dolaysyla try...catch bloklar yardmyla Hesapla_Click isimli olay metoduna ait kodlarn aadaki
hale getirilmesi daha doru olacaktr.

protected void Hesapla_Click(object sender, EventArgs e)


{
try
{
double deger1 = Convert.ToDouble(txtDeger1.Text);
double deger2 = Convert.ToDouble(txtDeger2.Text);
double sonuc = deger1 / deger2;
}
catch (FormatException err)
{
Response.Write("<b>Deerler saysal olmaldr. Ltfen girdiiniz deerleri kontrol
ediniz.</b><br/>Detayl Mesaj : " + err.Message);
}
catch (Exception err)
{
Response.Write("<b>Beklenmeyen bir hata olutu.</b><br/>Detayl Mesaj : " +
err.Message);

www.bsenyurt.com Page 996


}
}

Bunun sonucunda ayn hata tekrar edilmeye allrsa bu sefer mantkl bir ekran ile karlalacak
ve kullanc hata ile ilikili olarak daha doru bir ekilde bilgilendirilebilecektir.

Elbette metod seviyesinde hata ynetimi adna dikkat edilmesi gereken baz vakkalarda vardr.
Eer oluan hatalarn kurtarlabilme(toparlanabilme) ihtimali varsa try...catch bloklar dngler
(while, for gibi) ierisinde ele alnabilir. Bylece tekrar saysna gre istenen rutin bir ka kez st
ste denenebilir. Dier taraftan oluan istisnalar ile iliikili olarak ekstradan verilebilecek yada
kullanlabilecek bilgiler varsa bunlarn bir st seviyede (sayfa seviyesinde-page level) ele
alnmas iin catch blou ierisinde throw anahtar kelimesine bavurulabilir. Burada
zellikle Exception snfnn ar yklenmi(overload) yapc(constructor) metodlarndan
faydalanlmaktadr.

Dier bir vakka metod iinde kullanlan d kaynaklar ele alr. rnein ilgili rutinler ierisinde
kaynak temizlenmesi gerekiyorsa (balantlarn veya dosyalarn kapatlmas, ynetimsiz-
unmanaged nesnelerin serbest braklmas gibi) finally bloklarn kullanmak doru olacaktr.
Burada finally bloklarnn kullanlmas art deildir. Nitekim usingbloklar
yardmylada, IDisposable arayzn uygulayan tipler iin blok sonunda Dispose arlar
gerekletirilebilir. Son olarak olas hatalar ilgili metod ierisinde ele alnamyorsa metodu aran
yerde yakalanmaldr.

Grld zere vakkalarn says ve metod ierisindeki hata ynetimi eitli ekillerde
yaplabilmektedir. Bu sebepten karar verirken aadaki gibi tablodan faydalanmakta yarar vardr.

Kaynak Olas Eklenecek ilave


Olas hatalar
neri temizlemesi hata var hata bilgisi var
kurtarlabilir mi?
gerekiyor mu? m? m?

Hi bir kontrole hayr yok hayr yok


gerek yok hayr var hayr yok

evet yok hayr yok


try...finally
evet var hayr yok

try...catch hayr var hayr var

try...catch...finally evet evet hayr var

www.bsenyurt.com Page 997


rnein kaynak temizlenmesi gerekiyorsa, olas hatalar var ise ve hatta olas hatalara
eklenebilecek ekstra bilgiler var ise try..catch...finally bloklarn kullanmak daha mantkldr. Ne
varki olas hatalarda, hata mesajna ilave bilgiler eklemek catch bloklar
ierisinde throw kullanmak ile mmkn olabilir. nk ama, bu hatay ele alan bir st seviyeye
bilgi gndermektir. Bunun ele alnabilecei en gzel yer sayfa seviyesidir (Page Level). yleyse
sayfa seviyesinde hata ynetiminin nasl yaplacan inceleyerek devam edelim.

zellikle belirli bir sayfada meydana gelebilecek tm hatalarn tek bir merkezden kontrolnn
salanmas gerektii durumlarda sayfa seviyesinde hata ynetimi gerekletirilebilir. Bu teknikte
nemli olan nokta, Page_Error olay metodunun etkin bir ekilde kullanlmasdr. Aslnda sayfa
seviyesinde hatalar ele alnrken izlenen basit bir yol vardr. Aadaki tabloda bu yol
gsterilmektedir.

Sayfa Seviyesinde Hata Kontrol iin Tavsiye Edilen Yol

Madde 0 Bir hata sayfas tasarlanr. :)

Madde 1 Sayfaya Page_Error olay metodu eklenir.

Sayfann ErrorPage zelliine hata sayfasnn Url bilgisi Page direktifi ierisinde
Madde 2
eklenir.

Page_Error olay metodu ierisinde Server snfnn static GetLastError() metodu ile
Madde 3
son oluan istisna nesne rnei ele alnr.

stenirse ErrorPage zelliine burada deer ve hatta querystring yardmyla bilgi


Madde 4 aktarlmas salanabilir. Bylece hata sayfasna baz ekstra bilgilerin tanmasda
salanm olur.

Gerekirse bu aamada loglama (zellikle sistemdeki event loglara bilgi yazma), fiziki
Madde 4.5 dosyalara bilgi yazdrma, ynetici veya ilgili kiilere mail gnderme gibi ilemler
yaplabilir.

Page_Error isimli olay metodu sayfa seviyesinde ele alnr. Normal artlarda sayfada ele alnmayan
bir hata olutuunda bu metod otomatik olarak arlacaktr. Biz bu metod ierisinde
ynlendirmeler yaparak kullanclar daha akll hata bilgilendirme sayfalarna ynlendirebilir ve
loglama gibi ilemleri gerekletirebiliriz. Page_Error olay metodu ierisinden ilgili hata sayfasna
ynlendirme yaparken Page snfnn ErrorPage zelliine deer atamak gerekebilir. Bu daha
ok querystring yardmyla hata sayfasna ekstra bilgi gnderilecei durumlarda ele alnr. Aksi
durumlarda metod ierisinde deilde Page direktifinde bu zelliin deerinin belirlenmesi yeterlidir.
Ancak burada dikkat edilmesi gereken bir nokta vardr. Eer metod ierisinde ErrorPage zelliine
hata sayfasn atarken querystring kullanlmassa Asp.Net, alma zamannda aspxerrorpath isimli
bir anahtar ve deerini otomatik olarak ekleyecektir. Ki buda hatann olutuu sayfann
yakalanabilmesi ve belkide dinamik bir linkin retilerek tekrar geri gidilebilmesinide salayacaktr.

imdi yukardaki rneimizi sayfa seviyesinde ele almaya alalm. Madde 0' da deindiimiz gibi
ncelikli olarak bir hata sayfas tasarlamakta fayda var. Bu hata sayfas aadaki gibi
tasarlanabilir.

HataSayfasi.aspx;

<%@ Page Language="C#" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">

www.bsenyurt.com Page 998


protected void Page_Load(object sender, EventArgs e)
{
string ekBilgi = Request.QueryString["EkBilgi"];
string sayfa=Request.QueryString["Sayfa"];
string hataMesaji = Request.QueryString["HataMesaji"];
Response.Write("<b>Hata sayfas : </b>" + sayfa+"<br/>");
Response.Write("<b>Ek bilgi : </b>" + ekBilgi + "<br/>");
Response.Write("<b>Hata Mesaj : </b>" + hataMesaji);
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Hata Sayfas</title>
</head>
<body>
<form id="form1" runat="server">
<div>
</div>
</form>
</body>
</html>

Default.aspx sayfasndaki kodlar ise aadaki gibi deitirebiliriz.

protected void Page_Error(object sender, EventArgs e)


{
Exception olusanHata = Server.GetLastError();
ErrorPage = "HataSayfasi.aspx?EkBilgi=" + olusanHata.Message + "&HataMesaji="
+ olusanHata.InnerException.Message + "&Sayfa="+Page.AppRelativeVirtualPath;
}

protected void Hesapla_Click(object sender, EventArgs e)


{
try
{
double deger1 = Convert.ToDouble(txtDeger1.Text);
double deger2 = Convert.ToDouble(txtDeger2.Text);
double sonuc = deger1 / deger2;
}
catch (Exception excp)
{
throw new Exception("Saysal deer giriinde hata olutu", excp);
}
}

Hesapla_Click olay metodu ierisinde yer alan catch blounda throw anahtar szc kullanlarak
bir Exception nesnesi daha frlatlmtr. Bu istisna nesnesinin yakalanaca yer
sayfann Page_Error isimli olay metodudur. Bu metod ierisinde, sayfada oluan son hatay
yakalayabilmek iin Server snfnn GetLastError metodu kullanlmtr. Dikkat edilmesi gereken
noktalardan birisi, throw ile frlatlan Exception nesnesi rneklenirken ilk parametreye rnek bir
ekstra veri konulmasdr. Eklenen bu bilgi GetLastError ile yakalanan Exceptionnesne
rneinin Message zellii ile elde edilebilir. Bu durumda orjinal istisna mesajnnn nereden

www.bsenyurt.com Page 999


alnabilecei bir soru iaretidir. Cevap InnerException zelliidir. InnerException zellii ile
frlatlan asl Exception nesne rnei yakalanabilir. Bunu alma zamannda test ettiimizde
aadaki ekran grntsnde olduu gibi FormatExceptiontipinin InnerException zelliinde
saklandn grebiliriz.

Son olarak ErrorPage zellii ile hata sayfasna gerekli ynlendirme yaplmaktadr. Elbette
ErrorPage kullanlmak zorunda deildir. Bunun yerine Server snfnn Transfer metodu
veya Response snfnn Redirect metodlarnn kullanmda tercih edilebilir. zellikle Server
snfnn Transfer metodu gereksiz roundtrip' lerin nne geilmesini salamakta ama url satrna
bakldnda halen daha ayn sayfada olunduu izlenimini vermektedir.

rnek gelitirilirken dikkat edilmesi gereken bir nokta vardr. Eer rnei ayn makine
zerinde (localhost) test ediyorsak beklediimiz ynlendirme sayfasna gidemediimizi hatta eski
sar ekrann (orjinal hata mesajnn basld sayfadan bahsediyoruz) retildiini grrz. Bunun
nedeni web uygulamasnn zel hata modunun aktif olmaydr. Bir baka
deyile web.config dosyasnda yer alan customErrors elementinin mode niteliine On deerinin
verilmesi gerekir.

Aslnda mode zelliinin 3 farkl deeri vardr. RemoteOnly, On ve Off. RemoteOnly


modu aktif iken zel hata sayfalarn sadece istemciler grebilir. On modunda hem
istemciler hemde localhost kullancs zel hata sayfalarn grebilir. Biz rneklerimizdeki
sayfalarmz ayn makine zerinden test ettiimiz iin bu modu On olarak belirledik.
Gerek bir uygulama ortamna kldnda On yerine RemoteOnly kullanlmas tavsiye
edilir.

<customErrors mode="On"/>

customErrors elementi ierisine error isimli alt elementlerde konulabilir. Bu element sayesinde
sunucu seviyesinde meydana gelen hatalar var ise bunlarn sonucunda zel hata sayfalarna
ynlendirmeler yaplabilir. Sz gelimi aadaki bildirimleri ele alalm.

<customErrors mode="On">
<error statusCode="404" redirect="SayfaYok.aspx"/>
</customErrors>

Buna gre sitede olmayan bir sayfa talep edilirse kullanclar SayfaYok.aspx' e ynlendirilirer.

www.bsenyurt.com Page 1000


Yanlz burada dikkat edilmesi gereken bir nokta vardr. Sonradan ele alacamz
gibi global.asax dosyasndaki Application_Error olay yazlmsa, uygulama
SayfaYok.aspx' e ynlendirilmeden nce buradaki olay metoduna urayacaktr ki burada
bir ynlendirme yapyorsak SayfaYok.aspx yerine oraya gidilebilir. Hatta
Server.ClearError metodu kullanlmsa hata sayfasna gidilmeyedebilir. Buda sistemin
istediimiz ekilde almamas anlamna gelmektedir. Geri Application_Error ierisinde
oluan hata rnein sayfa yok hatas yinede yakalanabilir. rnein Debug modda bu
aadaki ekilde olduu giri grnecektir.

Dolaysyla bu noktalara dikkat etmekte fayda vardr.

rnein u aamada iken web uygulamasn altrdkdan sonra Giris.aspx isimli yazmadmz bir
sayfay talep edersek aadaki ekran grnts ile karlarr.

zellikle SayfaYok.aspx' ten sonra gelen querystring parametresine dikkat


edelim. aspxerrorpath ile gelen deer alnp kullancya daha anlaml bir hata sayfas gsterilebilir.
Biz tekrardan konumuza geri dnelim ve customErrors elementini aadaki haliyle brakalm.

<customErrors mode="On"/>

Bu deiiklikten sonra uygulama alma zamannda test edilirse default.aspx sayfasnda hata
olutuktan sonra HataSayfasi.aspx' e gidildii grlebilir. Tarayc penceresindeki url satrna dikkat
edilecek olursa querystring parametreleri ve deerleride baarl bir ekilde aktarlmtr.

www.bsenyurt.com Page 1001


unu itiraf etmeliyim ki sar ekrann grnts buradakinden daha gzeldir. Dolaysyla hata
sayfalar hazrlanrken biraz daha zenilmeli, gerektiinde projenin sahibi olan irket standartlarna
uygun olaraktan tasarlanmal ve zengin bir bilgi sunacak hale getirilmelidir.

Oluan hatalara ilikin kullanclara bilgi verilmesi dnda, siteyi tasarlayan veya ynetenlerinde
bilgilendirilmesi gerekebilir. Bu bilgilendirme farkl ekillerde yaplabilir. rnein var olan iletim
sistemi loglarna bilgi yazlabilir. rnein Application loglarna. Ya da daha basit olarak fiziki bir
dosyaya hatalar ile ilikili baz bilgiler gnderilebilir. Hatta gerektii yerlerde ok kritik hatalar sz
konusu ise ilgili kiilere mail bile gnderilebilir. Sz gelimi aadaki kod paras
ile Page_Error metodu ierisinde, oluan son hataya ait bilgi fiziki bir dosyaya eklenmektedir.

protected void Page_Error(object sender, EventArgs e)


{
Exception olusanHata = Server.GetLastError();
ErrorPage = "HataSayfasi.aspx?EkBilgi=" + olusanHata.Message + "&HataMesaji=" +
olusanHata.InnerException.Message + "&Sayfa="+Page.AppRelativeVirtualPath;

using (FileStream stream = new FileStream("C:\\HataLogDosyasi.txt",


FileMode.Append, FileAccess.Write))
{
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine("Hata Zaman " + DateTime.Now.ToString() + " Hata Sayfas " +
Page.AppRelativeVirtualPath + " Hata Mesaj " + olusanHata.InnerException.Message);
writer.Close();
}
}

Burada basit olarak FileStream ve StreamWriter tiplerinden yararlanlarak hata bilgileri C:


klasr altndaki bir text dosyasna yazdrlmaktadr. Sonu olarak uygulama test edildiinden
oluturulan hata sonrasnda ilgili dosyaya aadaki ekran grntsnde olduu gibi baz bilgiler
eklenecektir.

Page_Error metodu ierisinde hata sayfasna herhangibir ekilde ynlendirme yaplmamasna


ramen gidilmektedir. Bu metodun bir zelliidir. Metod sonuna gelindiinde, ErrorPage ile
belirlenmi sayfaya otomatik olarak gidilir. ErrorPage deerinin programatik olarak belirlenmesi
haricinde Page direktifi ierisinde ayarlanabileceini daha nceden sylemitik. Bu aadaki ekran
grntsnde olduu gibi dzenlenebilir.

www.bsenyurt.com Page 1002


Elbette metod ierisinde ErrorPage zellii belirtilmise Page direktifinde yaplan tanmlama
geersiz saylacaktr.

Gelelim uygulama seviyesinde hata ynetimine. Bu durumda web uygulamasnda meydana gelecek
hatalarn ele alnabilecei bir merkez sz konusudur. Sz konusu merkez global.asax dosyas
ierisinde yer alan Application_Error isimli olay metodudur. Bildiiniz
gibi global.asax dosyasnda, uygulama genelini ilgilendiren baz olay metodlar yer almaktadr.
rnein uygulama almaya baladnda devreye giren Application_Start, sonlandnda
arlan Application_End yada kullanclarn atklar oturumlarda(Session)devreye
giren Session_Start gibi. Dolaysyla ilk yaplmas gereken ilem web sitesine, eer yok ise bir
global.asax dosyas eklemek olacaktr. Sayfa seviyesindeki hata ynetiminde olduu gibi, uygulama
seviyesinde yaplacak hata ynetimi iinde tavsiye edilen bir yol haritas vardr ve aadaki tabloda
olduu gibidir.

Uygulama Seviyesinde Hata Kontrol iin Tavsiye Edilen Yol

Madde 0 Bir hata sayfas tasarlanr. :)

Madde 1 Sayfalara Page_Error olay metodlar eklenir.

Page_Error olay metodlarnda, son olarak elde


Madde 2 edilen istisna(Exception) nesnesinin referans aynen metod ierisinde olduu gibi
bilinli olarak ortama frlatlr(throw).

global.asax dosyasnda yer alan Application_Error olay metodu kodlanr. Bu metod


Madde 3
ierisinde son hata bilgisi yine GetLastError metodu ile alnr.

Gerekirse bu aamada loglama (zellikle sistemdeki event loglara bilgi yazma), fiziki
dosyalara bilgi yazdrma, ynetici veya ilgili kiilere mail gnderme gibi ilemler
yaplabilir. (Sistem loglarna yazma srasnda dikkat edilmesi gereken durumlardan
birisi ASPNET(IIS 5.0 iin) veya Network Service (IIS 6.0
Madde 3.5 iin) kullancsnn Application, System ve Security loglarna yazma hakk olup
olmaddr. Sz gelimi ASPNET kullancsnn varsaylan olarak Applicationloglarna
yazma hakk varken System ve Security loglarna yazma hakk yoktur. Bu nedenle
ilgili kullanclarn haklarnn zellikle loglara yazma ilemleri srasnda dikkate alnmas
gerekebilir.)

Kullanc hata sayfasna ynlendirilmeden


Madde 4 nce Server snfnn ClearError metodunun arlmas ve hatalarn temizlenmesi
nerilir.

Madde 5 Server.Transfer metodu ile hata sayfasna ynlendirme yaplr.

Buradaki maddelerde dikkat ekici noktalardan biriside son hatann sayfalara ait Page_Error olay
metodlar ierisinde tekrardan frlatlyor olmasdr. Bu bir anlamda hatann bir st seviyeye
aktarlmasdr. Dier taraftan bir gerekliliktir. Nitekim, hata bilinli olarak uygulama seviyesine
gnderilmesse Asp.Net alma ortam(Asp.Net RunTime), hatann ele alnmas

www.bsenyurt.com Page 1003


iin HttpUnhandledException tipinden bir nesne rnei retecektir. Biz hatay kontroll bir
ekilde ele almak istiyorsak bilinli bir ekilde frlatma ilemini stlenmeliyiz.

ok doal olarak web uygulamas ierisinde birden fazla aspx sayfas olduu dnlecek olursa,
hepsine bir Page_Error metodu eklemek ve kodlamak (en azndan GetLastError ile elde edilen
istisna nesnelerini frlatmak) uratrc ve sabrmz test edici olabilir. Burada nesne ynelimli
mimarinin avantajlarndan faydalanmak ok daha aklc bir zm olacaktr. Bir baka deyile tm
sayfalarn tredii bir taban sayfa (base page) ierisindeki Page_Error metodu ele alnabilir.

Alternatif bir yaklam olarak MasterPage kullanm dnlebilir. Her ne kadar


MasterPage ierisine Page_Error isimli bir metod yazlabiliyor olsada, aslnda metod
seviyesinden throw ile exception frlatldnda bu metod herhangibir ekilde tetiklenmez.
Eer Application_Error olay metodu yazlmsa dorudan buraya dlr
ve HttpUnhandledException tipinden bir istisna nesnesi yakalanr. Bu sebepten bu tip
bir durumda MasterPage ierisindeki Page_Error olay metodunun kullanm eklinde bir
zm ne yazkki sz konusu deildir.

lk olarak Application_Error olay metodunu nasl ele alacamza bakalm. ncelikle aspx
sayfalarndaki Page_Error olay metodlarndan yine bir st seviyeye hata frlatmak gerekir. Bu
nedenle rnek olarak default.aspx sayfasndaki Page_Error olay metodu aadaki gibi
deitirilmelidir.

protected void Page_Error(object sender, EventArgs e)


{
Exception olusanHata = Server.GetLastError();
throw olusanHata;
}

Uygulama seviyesinde hata kontrol yaplacandan ilgili olay kodunun global application
class ierisinde yer almas gerekir. Bu nedenle bir adet global.asax dosyas web sitesine dahil
edilmelidir. global.asax dosyasnda Application_Error olay metodu ierisinde ise aadakine
benzer kodlamalar yaplmaldr.

void Application_Error(object sender, EventArgs e)


{
Exception excp = Server.GetLastError();
// Burada loglama, dosyaya yazma, mail gnderme gibi ilemler yaplabilir.
Server.ClearError();
Server.Transfer("GenelHataSayfasi.aspx?EkBilgi="+excp.Message+"&HataMesaji="+
excp.InnerException.Message);
}

Bu sefer global.asax dosyas ierisinden GenelHataSayfasi.aspx isimli web sayfasna querystring


yardmyla bilgi tanmaktadr. GenelHataSayfasi.aspx ierii, HataSayfasi.aspx' e benzemekle
birlikte tek fark hatann meydana geldii sayfa bilgisini ele almyor oluudur. Eer uygulama bu
haliyle test edilir ve yine Default.aspx ierisinde hata yaptrlrsa aadaki ekran grnts ile
karlalr.

www.bsenyurt.com Page 1004


Grld gibi default.aspx ierisindeki metodda oluan hata catch blounda ek bilgi ile tekrar
throw edilmi ve bunu sayfann Page_Error olay metodu yakalamtr. Sonrasnda ise Page_Error
olay metodunda hata tekrar throw ile frlatlm ve bunun sonucunda Application_Error olay
metoduna gidilebilmitir. Aadaki grafikte bu durumun Debug moddaki karl gsterilmektedir.

nce Metod ii;

Sonra Page_Error;

Son olarak Application_Error;

www.bsenyurt.com Page 1005


alma sonrasnda dikkati eken noktalardan birisi tarayc penceresindeki url satrnda
Default.aspx' in grnyor olmasdr. Halbuki u anda zerinde bulunulan sayfa
GenelHataYonetimi.aspx' dir. Bunun sebebi Server.Transfer metodudur. Bunun yerine
Response.Redirect' te tercih edilebilir. Ama daha ncedende belirtildii zere Transfer metodu ile
sunucuya doru gidi geliler azald iin zellikle uygulama seviyesindeki hata ynetiminde tercih
edilen bir tekniktir. lgili hata sayfas dahada gelitirilebilir. rnein hatann olutuu sayfaya
dnlmesi iin gerekli balant bilgileri hata mesaj ile birlikte tanabilir. Bu ve dahas tamamen
sizlerin hayal gcne kalmaktadr.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde Asp.Net uygulamalarnda etkin hata
ynetimi adna metod, sayfa ve uygulama seviyesinde neler yapabileceimizi incelemeye altk.
Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Windows Tabanl Dorulama ve


Yetkilendirme ( 12.07.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Servis ynelimli mimaride(Service Oriented Architecture), datk uygulamalarn bir


ksm intranet tabanl olaraktan Windows iletim sistemleri zerinde konulandrlm olarak
tasarlanmaktadr. Bu sebepten a zerinde tm kullanclarn daha kolay bir ekilde ynetildii var
olan ve bilinen dorulama ve yetkilendirme materyallerinden yararlanmak sk olarak bavurulan
tekniklerdendir. Bir baka deyile kullanc hesaplarnn(Member accounts) ynetimi hazr olan
Windows iletim sistemi unsurlar tarafndan kolayca ele alnabilmektedir. Buda doal olarak
istemcilerin servis tarafnda dorulanmas(Authentication) ve
yetkilendirilmesi(Authorization) iin hazr olan kaynaklarn kullanlabilmesi anlamna gelir.

Sonu itibariyle servis ve istemci taraf asdan gelitiricinin yk biraz daha


hafiflemektedir. Windows Communication Foundation uygulamalarndada intranet tabanl
sistemler iin Windows tabanl dorulama ve yetkilendirme(Windows Based Authentication and
Authorization) ilemlerini, balayc tip (binding type) baznda kolayca gerekletirebiliriz. Bu
blmde zellikle basicHttpBinding tipi yardmyla bu ilemlerin nasl gelitirilebileceini adm
adm incelemeye alacaz. Her zamanki gibi servis tarafndan hizmete sunulacak olan WCF
Service Library' sini gelitirmekle ie balanabilir. Bu ktphane ierisindeki sz konusu
tipler(types) aadaki gibi tasarlanmtr.

www.bsenyurt.com Page 1006


IAritmetik arayz(interface);

using System;
using System.ServiceModel;

namespace CebirLib
{
[ServiceContract(Name="AritmetikServisi",Namespace="http://www.bsenyurt.com/AritmetikS
ervisi")]
public interface IAritmetik
{
[OperationContract(Name="ToplamaOperasyonu")]
int Topla(int x, int y);
}
}

Aritmetik snf(class);

using System;
using System.Threading;
using System.Security.Principal;

namespace CebirLib
{
public class Aritmetik:IAritmetik
{
#region IAritmetik Members

public int Topla(int x, int y)


{
IPrincipal principal = Thread.CurrentPrincipal;
string dogrulamaTipi=principal.Identity.AuthenticationType;
string dogrulandi = principal.Identity.IsAuthenticated ? "Dogrulandi" :
"Dogrulanmadi";
string ad=principal.Identity.Name;

Console.WriteLine("Kullanc : " + ad + "\n" + "Dorulama Tipi : " + dogrulamaTipi + "\n"


+ dogrulandi + "\n");
return x + y;

www.bsenyurt.com Page 1007


}

#endregion
}
}

Aritmetik snf ierisinde yer alan Topla isimli metoda balang olarak baz kod satrlar
eklenmitir. IPrincipal arayzne ait principal isimli deikene, Thread snfnn
static CurrentPrincipal zellii yardmyla atanan deer aslnda alma zamannda servise talepte
bulunan istemci kimliini iaret etmektedir. Bu zelliin dn deerinden faydalanarak dorulama
tipini(Authentication Type), kullancnn adn(Name) ve hatta sonradanda grlecei gibi
kullancnn hangi rolde olduunun tespiti yaplabilmektedir. Daha ok Windows kullanclarn
rollerine(Role) baklarak kod ierisinden yetkilendirme(Authorization) yaplmak istendii
durumlarda kullanlmaktadr.

Srada servis ve istemci tarafndaki uygulamalarn tasarlanmas var. Her iki tarafda olaylar daha
kolay irdelemek asndan birer Console uygulamas olarak tasarlamakta fayda vardr. Servis
tarafndaki Console uygulamas, gelitirilen WCF Servis ktphanesini(CebirLib)
ve System.ServiceModel.dll assembly' n referans etmektedir. Servis tarafna ait kodlar
balang iin aadaki gibidir.

using System;
using System.ServiceModel;
using CebirLib;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Aritmetik));
host.Open();
host.Closing += new EventHandler(host_Closing);
host.Closed += new EventHandler(host_Closed);
Console.WriteLine("Sunucu dinlemede...\n Kapatmak iin bir tua basn...");
Console.ReadLine();
host.Close();
}

static void host_Closed(object sender, EventArgs e)


{
Console.WriteLine("Servis kapatld...Yine bekleriz...");
}

static void host_Closing(object sender, EventArgs e)


{
Console.WriteLine("Servis kapatlyor. Ltfen bekleyiniz...");
}
}
}

Servis tarafnda yer alan konfigurasyon dosyasnn balang ayarlar ise aadaki gibidir.

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

www.bsenyurt.com Page 1008


<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="AritmetikBindingHttpCfg">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service name="CebirLib.Aritmetik">
<endpoint address="http://localhost:1600/AritmetikServisi"
binding="basicHttpBinding" bindingConfiguration="AritmetikBindingHttpCfg"name="Arit
metikServiceHttpEndPoint" contract="CebirLib.IAritmetik" />
</service>
</services>
</system.serviceModel>
</configuration>

Servis tarafnda basicHttpBinding balayc tipi kullanlmaktadr. zerinde durulmas gereken ilk
noktalardan birisi gvenlik modunun(security elementinin mode nitelii
yardmyla) TransportCredentialOnly olarak belirlenmi olmas ve iletiim seviyesinde istemci
yetki belgesi tipi olarak None (transport elementi ierisindeki clientCredentialType nitelii
yardmyla belirlenmitir) deerinin kullanlm olmasdr. Buna gre istemcilerin kimlik bilgileri iin
herhangibir dorulama yaplmaz. Bir baka deyile herkes bu servisi kullanabilir.

stemci tarafndaki Console uygulamasna ait konfigurasyon dosyasnn balang ierii ise
aadaki gibi olmaldr. (stemci uygulama iin gerekli proxy snfsvcutil.exe arac yardmyla
CebirLib.dll' i zerinden elde edilmitir. Bu konu daha nceden ilendiinden burada
tekrarlanmamtr.)

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


<configuration>
<system.serviceModel>
<bindings>
<basicHttpBinding>
<binding name="CebirClientBindingHttpCfg">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<client>
<endpoint address="http://localhost:1600/AritmetikServisi"
binding="basicHttpBinding" bindingConfiguration="CebirClientBindingHttpCfg" contract=
"AritmetikServisi" name="CebirClientHttpEndPoint" />
</client>
</system.serviceModel>
</configuration>

stemci tarafndaki console uygulamasna ait kodlar ise aadaki gibidir.

www.bsenyurt.com Page 1009


using System;
using System.ServiceModel;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
AritmetikServisiClient client = new
AritmetikServisiClient("CebirClientHttpEndPoint");

int sonuc = client.ToplamaOperasyonu(3, 4);


Console.WriteLine(sonuc.ToString());
Console.ReadLine();
}
}
}

Uygulama bu haliyle altrldnda aadakine benzer bir ekran grnts ile karlalr.

Grld gibi kullanc ad, dorulama tipi veya kullanc bilgisinin herhangibir mekanizma ile
dorulanp dorulanmad bilgisi bulunmamaktadr. Bunun sebebi gvenlik
ayarlarnda mode niteliinin deerinin None olarak belirlenmi olmasdr. Durum Aritmetik snf
ierisindeki Topla metodu debug modda incelendiinde ak bir ekilde izlenebilir. Aadaki ekran
grntsnde bu durum yer almaktadr.

Buradan u sonuca varlabilir. None gvenlik modunda hi bir ekilde istemciden yetki bilgileri
gnderilmez. Her istemci isimsiz kullanc(anonymous user) gibi ele alnr.

imdi olay biraz daha farkl bir hale getirelim. mode niteliinin deerini hem istemci hemde servis
tarafnda Basic olarak deitirelim. Ardndan servis ve istemci uygulamalar tekrar altralm. Bu
durumda aadaki ekran grnts ile karlarz.

www.bsenyurt.com Page 1010


Basic modda iken istemcinin servis tarafna kendisini tantmas gerekmektedir. Bu nedenle aynen
hata mesajnda olduu gibi proxy snf zerinden ClientCredentials zellii kullanlmaldr. Sz
konusu operasyonda rnek olarak iki test kullancs oluturulmutur. Garfield ve Rolfield isimli bu
kullanclar, daha sonradan iki farkl Windows Group altnda birletirilecek ve rol bazl
yetkilendirmelerin(Role Based Authorization) nasl yaplaca ele alnacaktr. Sz konusu
kullanclara ait Username ve Password bilgileri aadaki gibidir. Bu kullanclar tamamen hayalidir
:)

Kullanc
ifre
Ad

Garfield Garfi1234.?

Rolfield Garfi1234.?

Bu ilemin ardndan istemci tarafndaki kodlar aadaki gibi dzenlenebilir.

using System;
using System.ServiceModel;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
AritmetikServisiClient client = new
AritmetikServisiClient("CebirClientHttpEndPoint");

client.ClientCredentials.UserName.UserName = "Garfield";
client.ClientCredentials.UserName.Password = "Garfi1234.?";

int sonuc = client.ToplamaOperasyonu(3, 4);


Console.WriteLine(sonuc.ToString());
Console.ReadLine();
}
}
}

Dikkat edilecek olursa client nesne rnei zerinden ClientCredentials zelliine geilmi ve
buradan UserName zellii yardmylada kullanc ad(UserName) ve ifre(Password) bilgileri
belirtilmitir. Servis ve istemci taraf tekrar test edilirse aadakine benzer bir ekran grnts ile
karlalr.

www.bsenyurt.com Page 1011


Yine alma zamannda Topla metodu ierisinde debug ilemi gerekletirilirse, aadaki ekran
grntsnde yer ald gibi WindowsPrincipal tipinin rneklendii ve kullanc
bilgilerinin WindowsIdentity tipi zerinden elde edildii grlr. Bu tipik olarak kullancnn servis
uygulamasnn alt Windows iletim sistemindeki kullanclardan arandnnda bir gstergesidir.

Eer hatal kullanc bilgisi veya yanl ifre girilirse aadakine benzer bir ekran grnts ile
karlalr. (rnein kullanc ad Garfieldd olarak ift d ile bitecek ekilde girilirse.)

Dikkat edilecek olursa alma zamannda MessageSecurityException istisnas alnm ve 403


Forbidden mesaj ile karlalmtr. imdi sz konusu kullanclarn yetkilendirilmesinin nasl ele
alnabileceini incelemeye alalm. Bu amala sz konusu Garfield ve Lorfield isimli kullanclar
Yonetici ve Calisan isimli iki farkl Windows grubunda toplanmtr.

Kullanc
Windows Grubu
Ad

Garfield Yonetici, Calisan

Rolfield Calisan

Topla metodunu sadece Yonetici grubundaki kullanclarn altrmas istenirse


dekleratif(declarative) olarak PrincipalPermission nitelii ele alnmaldr. PrincipalPermission
nitelii(attribute), System.Security.Permissions isim alan altnda yer almaktadr. Bu sebeple
ilgili isim alannn Aritmetik snfna eklenmesinde fayda vardr. PrincipalPermission niteliinin temel
kullanm aadaki gibidir.

www.bsenyurt.com Page 1012


[PrincipalPermission(SecurityAction.Demand,Role="Yonetici")]
public int Topla(int x, int y)
{

PrincipalPermission nitelii metodlar gibi snflarada uygulanabilir. Ancak tavsiye edilen metod
seviyesinde uygulanmasdr. Bununla birlikte kendisinden tretilme yaplmasna izin
vermeyen(sealed class) bir snftr. Bu snfn .Net ierisindeki ierii aadaki gibidir. (Snf
ieriinin elde edilmesi iin zcan Deirmenci tarafndan gelitirilen Fox Decompiler arac
kullanlmtr.)

[ComVisible(true), AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,


AllowMultiple=true, Inherited=false), Serializable]
public sealed class PrincipalPermissionAttribute : CodeAccessSecurityAttribute
{
// Constructors
public PrincipalPermissionAttribute (SecurityAction action);

// Methods
public override IPermission CreatePermission ();

// Properties
public string Name { get; set; }
public string Role { get; set; }
public bool Authenticated { get; set; }

// Instance Fields
private string m_name;
private string m_role;
private bool m_authenticated;
}

Bylece Topla metodunu sadece Yonetici rolndeki kullanclarn arabilecei belirtilmi olur. Eer
istemci tarafndan Lorfield isimli kullanc ile Topla metodu arlrsa aadaki ekran grnts ile
karlalr.

Grld gibi kullanc dorulanm(Authenticate) ancak Yonetici rolnde olmad iin yetkisi
geersiz klnmtr(Unauthorized). Bu sebepten dolay"Access is denied" hata mesaj
ve SecurityAccessDeniedException tipinden bir alma zaman istisnas(runtime
exception) alnmtr. Oysaki Garfield isimli kullanc ile eriilmek istendiinde bir problem
olmadan metod ars gerekletirilebilir.

PrincipalPermission nitelii istenirse bir metod iin birden fazla kez kullanlabilir. Sadece bu rnekte
olduu gibi rollere yetki vermek amacyla deil belirli kullanclar yetkilendirmek yada birden fazla
role izin vermek amacyla kullanlabilir. Aadaki rnekte bu durum analiz edilmektedir.

www.bsenyurt.com Page 1013


[PrincipalPermission(SecurityAction.Demand,Role="Yonetici")]
[PrincipalPermission(SecurityAction.Demand,Name="BURAKSENYURT\\Burak Selim
Senyurt")]
public int Topla(int x, int y)
{

Buradaki tanmlamalara gre BURAKSENYURT alan ierisinde yer alan Burak Selim Senyurt isimli
kullancda Topla metodu iin yetkilendirilmi saylmaktadr.

Elbette tek bir istemci yerine birden fazla istemci


altrldnda Thread snfnn CurrentPrincipal zellii balanan kiiye ait bilgileri ieririr. Sz
gelimi yukardaki rnek kodlara gre birden fazla istemci altrldnda aadakine benzer bir
ekran grnts elde edilebilir.

Kullanclara ait yetki kontrol istenirse kod ierisindende zorunlu bir


ekilde(imperatively) gerekletirilebilir. Bunun iin Aritmetik snf ierisindeki Topla metodu
aadaki gibi dzenlemelidir.

public int Topla(int x, int y)


{
IPrincipal principal = Thread.CurrentPrincipal;
string dogrulamaTipi=principal.Identity.AuthenticationType;
string dogrulandi = principal.Identity.IsAuthenticated ? "Dogrulandi" : "Dogrulanmadi";
string ad=principal.Identity.Name;

#region Kod ierisinden yetki kontrol

WindowsPrincipal wp = (WindowsPrincipal)principal;
if (wp.IsInRole("Yonetici"))
{
Console.WriteLine("Kullanc : " + ad + "\n" + "Dorulama Tipi : " + dogrulamaTipi + "\n" +

www.bsenyurt.com Page 1014


dogrulandi + "\n");
return x + y;
}
else
throw new FaultException("Geersiz yetki");

#endregion
}

lk olarak WindowsPrincipal tipi yakalanr. Bunun iin yine Thread snfndan ve static
yelerinden CurrentPrincipal ile elde edilen referanstan faydalanlr. Elde
edilenWindowsPrincipal nesne rnei zerinden IsInRole metodu yardmyla talepte bulunan
istemci tarafndan gelen kullancnn Yonetici rolnde olup olmad kontrol edilebilir. rnekte
kullancnn Yonetici rol ierisinde olmamas halinde bir FaultException(FaultException kullanm
iin System.ServiceModel isim alannn ilave edilmesi gerekir) istisnas frlatlmaktadr.

Bu tarz bir kod parasn kullanmak zellikle rol tabanl yelik kontrol sz konusu olduunda art
deildir. Nitekim IsInRole metodu zaten o anki Principal zerinden kolaylkla elde edilebilir. Bir
baka deyile aadaki gibi bir kod parasda ayn ilemi grecektir.

if (principal.IsInRole("Yonetici"))
{

Yine Garfield isimli kullanc ile deneme yaplrsa herhangibir sorun ile karlalmadan Topla
metodunun arlabildii grlr. Ancak Lorfield isimli kullanc ile Topla metodu arlrsa
aadaki ekran grntleri ile karlalr.

Basic gvenlik modu genellikle istemcilerin servis ile ayn gvenlik alanna(security
domain) girmedii durumlarda ele alnr. Bu sebepten eer kullanclar zaten gvenlik alanna
varsaylan olarak dahil oluyorlarsa Windows Authentication Mode kullanlarak istemcilerin var olan
ehliyet bilgilerini belirtmeden servise ulamalar salanabilir. Tek yaplmas gereken istemci ve
servis tarafndaki security elementlerinde mode niteliini Windows olarak ayarlamaktr.

Servis taraf;

www.bsenyurt.com Page 1015


stemci taraf;

Eer servis tarafnda Active Directory kullanlyorsa bu durumda rol ynetimi iin Windows
Token Role Provider seilmelidir. Bu ayarlama sadece servis tarafndaki konfigurasyon
dosyasnda aadaki gibi yaplmaldr.

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="AritmetikServiceBehavior">
<serviceAuthorization principalPermissionMode="UseWindowsGroups" />
</behavior>
</serviceBehaviors>
</behaviors>
<bindings>
<basicHttpBinding>
<binding name="AritmetikBindingHttpCfg">
<security mode="TransportCredentialOnly">
<transport clientCredentialType="None" />
</security>
</binding>
</basicHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="AritmetikServiceBehavior" name="CebirLib.Aritme

www.bsenyurt.com Page 1016


tik">
<endpoint address="http://localhost:1600/AritmetikServisi" binding="basicHttpBinding"
bindingConfiguration="AritmetikBindingHttpCfg" name="AritmetikServiceHttpEndPoint"
contract="CebirLib.IAritmetik" />
</service>
</services>
</system.serviceModel>
</configuration>

Grld gibi serviceBehaviors elementi ierisine serviceAuthorization elementi eklenmitir.


Bu element ierisinde yer principalPermissionMode niteliinin deeri
iseUseWindowsGroups olarak belirlenmitir. Her iki durumdada istemci tarafndan servise
kullanc bilgileri otomatik olarak gnderilecektir. Elbette domain' e dahil olmularsa.
Yanlz Windowsmodu kullanldnda ve rol tabanl bir yetkilendirme sz konusu olduunda
istenirse yine istemci tarafnda belirli bir kullanc iin balant gerekletirilmesi salanabilir. Lakin
byle bir durumda istemci tarafndaki kodlarn aadaki gibi ele alnmas gerekir.

AritmetikServisiClient client = new AritmetikServisiClient("CebirClientHttpEndPoint");


client.ClientCredentials.Windows.ClientCredential.UserName = "Garfield";
client.ClientCredentials.Windows.ClientCredential.Password = "Garfi1234.?";
client.ClientCredentials.Windows.ClientCredential.Domain = "BURAKSENYURT"; // Domain
varsaylan ise yazlmak zorunda deildir.

int sonuc = client.ToplamaOperasyonu(3, 4);


Console.WriteLine(sonuc.ToString());
Console.ReadLine();

Bu durumda servis ve istemci altrldnda aadaki ekran grnts elde edilir.

Bu makalemizde basit olarak intranet tabanl sistemlerde basicHttpBinding balayc tipini


kullanarak Windows tabanl dorulama ve yetkilendirmelerin(Windows Based Authentication
and Authorization) nasl ele alnabileceini incelemeye
altk. netTcpBinding veya wsHttpBinding balayc tipleri iin iletiim seviyesinde gvenlik
modunun varsaylan deeri Windows' dur. Dolaysyla bu tipleri kullanrken config dosyas ierisinde
ekstra bir ilem yaplmasna gerek yoktur. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 1017


WCF - Internet zerinden Gvenlii Salamak -
2 ( 05.07.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Hatrlanaca gibi bir nceki makalemizde iletiim seviyesinde(Transport Level) gvenliin


salanabilmesi iin gerekli ayarlarn nasl yaplabileceini incelemitik. Bu makalemizde kaldmz
yerden devam ederek servis tarafndaki dorulama ilemleri iin yelik ve rol
ynetim(Membership and Role Management) sistemini devreye alacak ve istemci tarafn
yazarak test edeceiz. lk olarak nceki yazmzda am olduumuz WCF Service uygulamasna
dnelim. Her zaman olduu gibi basit bir arayz, servis szlemesi(Service Contract) olacak
ekilde tasarlayacaz ve bunun uyarlamasn yapacak bir snf gelitireceiz. lemlerin kolay bir
ekilde anlalabilmesi iin servis tarafndaki tipler mmkn olduu kadar basit dnlmtr.

IAritmetik arayz(interface) ve Aritmetik snfna(class) ait kodlar aadaki gibidir.

using System;
using System.ServiceModel;

[ServiceContract(Name="Cebirci",Namespace="http://www.bsenyurt.com/Cebirci")]
public interface IAritmetik
{
[OperationContract]
double Topla(double x, double y);
}

public class Aritmetik : IAritmetik


{
#region IAritmetik Members

public double Topla(double x, double y)


{
return x + y;
}

www.bsenyurt.com Page 1018


#endregion
}

Aritmetik snf basit olarak istemcilere Topla isimli bir ilevsellik sunmaktadr. Standart olarak
arayze ServiceContract ve OperationContract nitelikleri(attributes) uygulanmtr. WCF
servisinin svc uzantl dosyasnn ierii ise aadaki gibi olmaldr.

<% @ServiceHost Language=C#


Debug="true" Service="Aritmetik" CodeBehind="~/App_Code/Service.cs" %>

Burada nemli olan noktalardan bir tanesi web.config dosyasnn ieriidir. Windows
Communication Foundation iin gerekli ayarlar ierek web.config dosyasnda bu sefer, iletiim
seviyesinde gvenlik ve ehliyet(Credential) kontrol kurallar iinde baz eklemeler yaplmaldr.
Sonu itibariyle web.config dosyasnn balangtaki ierii aadaki gibi tasarlanabilir.

<?xml version="1.0"?>

<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="CebirServiceBindingCfg">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName" />
</security>
</binding>
</wsHttpBinding>
</bindings>
<services>
<service behaviorConfiguration="CebirServiceBehavior" name="Aritmetik">
<endpoint binding="wsHttpBinding" bindingConfiguration="CebirServiceBindingCfg"
name="CebirServiceEndpoint" contract="IAritmetik" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="CebirServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>

<system.web>
<compilation debug="true"/>
</system.web>

</configuration>

Servis tarafnda wsHttpBinding balayc tipi(Binding Type) kullanlmaktadr. Balayc tipe ait
konfigurasyon ayarlarnda dikkat edilecei zere security elementi ierisinde iletiim ve mesaj
seviyesi iin gerekli istemci ehliyet tipleri transport ve message alt elementleri yardmyla
tanmlanmaktadr.

www.bsenyurt.com Page 1019


security elementi ierisindeki mode nitelii TransportWithMessageCredential olarak
ayarlanmtr. Buna gre, daha ncedende bahsedilen mesaj btnl(Integrity), mesaj
mahremiyeti(Privacy) ve mterek dorulama (Mutual Authentication) gibi ilkeler HTTPS
tarafndan salanr. Bu nedenlede servis tarafnn HTTPS ile hizmet verecek ekilde tasarlanm
olmas bir baka deyile sertifikalandrlm olmas arttr(Daha nceden bir sertifika hazrlamamzn
nedenide budur).

Dier taraftan istemcilerin dorulanmas SOAP gvenliine uygun olacak ekilde yaplr. Bir baka
deyile istemcilerin kendilerini servis tarafna kullanc ad, ifre veya sertifika(Certificate) yoluyla
tantmas gerekir. Gelitirilecek olan rnekte kullanc ad ve ifre kullanm ele alnacaktr.
zellikle message elementinde yer alanclientCredentialType niteliinin deeri istemcinin
dorulanmas iin kullanlacak istemci yetki belgesinin(Credential) tipini belirtir.

Windows SDK dkmantasyonuna


gre security mode deeri TransportWithMessageCredential olarak ayarlanmsa,
transport alt elementi grmezden gelinir.

Bu ilemlerin tamamlanmas ile birlikte servis herhangibir tarayc penceresinden talep edilebilir.
Ekran kts aadakine benzer olacaktr.

Bu ktnn elde edilmesi iin adres alanna https://localhost/CebirServisi/CebirService.svc


yazlmas gerekmektedir. Dikkat edilecek olursa http yerine https kullanlmaktadr.

www.bsenyurt.com Page 1020


Servis tarafnda yaplmas gereken ilemlerden biriside kullanc hesaplarnn saklanmas iin gerekli
Asp.Net yelik veritabannn oluturulmasdr. Bu amala Web Site Administraton Tool aracndan
yararlanlabilir. ncelikli olarak Security ksmndan dorulama ilemlerinin internet zerinde
yaplacann bildirilmesi gerekmektedir. Bu nedenleFrom the Internet seenei iaretlenir.

Ardndan bir ka rnek kullanc hesab aadaki ekran grntsnde yer alan Create
User kontrol ile oluturulur.

www.bsenyurt.com Page 1021


rneklerde kullanlmak zere daha sonra farkl rollere atanacak olan buraks ve bulents isimli iki
kullanc oluturulmutur. Bu kullanclarn ifreleride 123456. olarak belirlenmitir. lerleyen
blmlerde rnek rol kullanmlarda ele alnacandan Personel ve Yonetici isimli iki rol Create New
Role kontrol yardmyla tanmlanr (Rollerin kullanlabilmesi iinRoles ksmndan Enable
Roles linkine tklanlmaldr).

Bu ilemin ardndan rnek olarak oluturulan bulents ve buraks isimli kullanclar farkl rollere
atanrlar. buraks isimli kullanc Personel rolne, bulents isimli kullanc ise Yonetici rolne atanr.
Bunun iin Web Site Administrator Tool ierisindeyken, rollerin eklendii kontrolde yer
alan Manage linki kullanlabilir. rnein buraks kullancsnn Personel rolne atanmas sonras
ekran grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 1022


Bu ilemler sonrasnda web.config dosyasna roleManager ve authentication elementleri
aadaki gibi eklenecektir.

<system.web>
<roleManager enabled="true" />
<authentication mode="Forms" />
<compilation debug="true"/>
</system.web>

Yerel(Local) veritaban kullanldndan aynen web uygulamalarnda olduu gibi ASPNETDB.mdf


dosyas App_Data klasr altna alr. (Burada kriter her zamanki gibi root web.config dosyasdr.
Nitekim Asp.Net uygulamalarndan bilindii zere istenirse ASPNETDB veritaban SQL Server
sunucusu zerinde de tutulabilir. Varsaylan ayar local olarak kullanlmasn salamaktadr.)

Bu ilemlerde tamamlandktan sonra yetkilendirme(authorization) ve rol(Role) ilemleri iin servise


ait davran(behavior) tanmlamalar yaplmas gerekmektedir. Bu seferki ayarlamalar Microsoft
Service Configuration Editor yardmyla gerekletirebiliriz. ncelikli olarak
CebirServiceBehavior davranna serviceAuthorization elementi eklenir. Bu ilemin ardndan ilk
olarak PrincipalPermissonMode deeri UseAspNetRoles olarak belirlenir. Sonrasnda
ise RoleProviderName deeri AspNetSqlRoleProvider olarak belirlenir.

www.bsenyurt.com Page 1023


Bylece istemcilerin rol ynetiminin .Net Framework ile hazr olarak
gelen AspNetSqlRoleProvider tipi yardmyla gerekletirilecei belirtilmi olur.
AspNetSqlRoleProvider tipimachine.config dosyas ierisinde tanmlanm olup rol ynetimini
stlenen hazr .Net snflarndan birisidir. Sz konusu tip ayn zamanda Asp.Net Web Site
Administrator aracnn kulland varsaylan rol salaycsdr(default role provider). Temel grevi
kullanclar ile roller arasndaki ilikilerin kurulmas ve kontrol edilmesidir. Aadaki ekran
grntsnde sz konusu salaycnn machine.config dosyasnda bulunduu yer gsterilmektedir.

serviceAuthorization davrannn belirlenmesinden sonra, serviceCredentials isimli bir baka


davrann daha servis tarafnda eklenmi olmas gerekmektedir. Bu sefer sz konusu davran ile
istemcilere ait hesap bilgilerinin kim tarafndan kontrol edilecei belirlenir.
Burada UserNamePasswordValidationMode zelliinin
deeri MembershipProvider veMembershipProviderName zelliinin
deeride AspNetSqlMembershipProvider olarak seilir.

www.bsenyurt.com Page 1024


Burada belirtilen AspNetSqlMembershipProvider, machine.config dosyas ierisinde
tanmlanm olan kullanc dorulama ilemlerini stlenen varsaylan .Net tipidir. Aadaki ekran
grntsnde bu tipin machine.config dosyas ierisindeki yeri gsterilmektedir.

Tm bu ilemlerin ardndan web.config dosyasnn ieriinde yer alan serviceBehaviors ksmnda


aadaki yenilemeler gerekleecektir.

<serviceBehaviors>
<behavior name="CebirServiceBehavior">
<serviceMetadata httpsGetEnabled="true" />
<serviceAuthorization
principalPermissionMode="UseAspNetRoles" roleProviderName="AspNetSqlRoleProvider" />
<serviceCredentials>
<userNameAuthentication userNamePasswordValidationMode="MembershipProvide
r" membershipProviderName="AspNetSqlMembershipProvider" />
</serviceCredentials>
</behavior>
</serviceBehaviors>

Artk istemci taraf tasarlanmaya balanabilir. stemci program, basit bir Console uygulamas olarak
tasarlanacaktr. Hereyden nce istemci iin gerekli proxy snfnn retilmesi gerekmektedir. Ne
varki makaleyi hazrladm sralarda gerek svcutil.exe arac gerek Visual Studio 2005' in Add

www.bsenyurt.com Page 1025


Service Reference seenei https iin hazrlanm olan servise ait proxy snfnn retilmesinde
hatalar frlatlmasna neden olmutur. Burada zm olarak servis https' e tanmadan nce proxy
snfnn retilmesi salanabilir. kinci bir zm yolu ise servisin kulland szleme ve uyarlama
snfn ieren ayr bir snf ktphanesi zerinden svcutil ile proxy rettirmektir. Yada nc bir yol
olarak aada olduu gibi proxy snf manuel olarak yazlabilir :)

Gerekli kodlar aadaki gibi olacaktr;

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
[System.ServiceModel.ServiceContractAttribute(Namespace =
"http://www.bsenyurt.com/Cebirci")]
public interface CebirServisi
{
[System.ServiceModel.OperationContractAttribute(Action =
"http://www.bsenyurt.com/Cebirci/Cebirci/Topla", ReplyAction =
"http://www.bsenyurt.com/Cebirci/Cebirci/ToplaResponse")]
double Topla(double x, double y);
}

[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public interface CebirServisiChannel : CebirServisi, System.ServiceModel.IClientChannel
{
}

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.CodeDom.Compiler.GeneratedCodeAttribute("System.ServiceModel", "3.0.0.0")]
public partial class CebirServisiClient : System.ServiceModel.ClientBase<CebirServisi>,
CebirServisi
{

www.bsenyurt.com Page 1026


public CebirServisiClient()
{
}

public CebirServisiClient(string endpointConfigurationName) :


base(endpointConfigurationName)
{
}

public CebirServisiClient(string endpointConfigurationName, string remoteAddress) :


base(endpointConfigurationName, remoteAddress)
{
}

public CebirServisiClient(string endpointConfigurationName,


System.ServiceModel.EndpointAddress remoteAddress) :
base(endpointConfigurationName, remoteAddress)
{
}

public CebirServisiClient(System.ServiceModel.Channels.Binding binding,


System.ServiceModel.EndpointAddress remoteAddress) :
base(binding, remoteAddress)
{
}

public double Topla(double x, double y)


{
return base.Channel.Topla(x, y);
}
}

stemci tarafndaki app.config isimli konfigurasyon dosyasnn ierii ise aadaki gibi olmaldr.

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


<configuration>
<system.serviceModel>
<bindings>
<wsHttpBinding>
<binding name="CebirServiceBindingCfg">
<security mode="TransportWithMessageCredential">
<transport clientCredentialType="None" />
<message clientCredentialType="UserName"/>
</security>
</binding>
</wsHttpBinding>
</bindings>
<client>
<endpoint address="https://localhost/CebirServisi/CebirService.svc" binding="ws
HttpBinding" bindingConfiguration="CebirServiceBindingCfg" contract="CebirServisi"
name="CebirServiceEndpoint">
</endpoint>
</client>
</system.serviceModel>
</configuration>

www.bsenyurt.com Page 1027


Dikkat edilecek olursa istemci tarafnda yer alan balayc tip(Binding Type) ayarlarnda
da security elementi de yer almaktadr ve servis tarafndaki ile ayn deerlere sahip olacak ekilde
tasarlanmtr. stemci tarafnda gerekletirilen bu ayarlardan sonra Main metodunun ierii
aadaki gibi dzenlenebilir.

CebirServisiClient client = new CebirServisiClient("CebirServiceEndpoint");

client.ClientCredentials.UserName.UserName = "buraks";
client.ClientCredentials.UserName.Password = "123456.";

double sonuc=client.Topla(3, 4);


Console.WriteLine("Sonuc {0}",sonuc.ToString());
Console.ReadLine();

Dikkat edilecek olursa, istemci tarafna ait yetkinlik belgesini gnderirken kullanc ad ve ifre
bilgileri verilmektedir. Bunun iin proxy snfna ait nesne rnei zerinden
eriilenClientCrendetials zellii kullanlmaktadr. ClientCredentials
zellii ClientCredentials snfna ait nesne rneklerini iaret eder. Bu nesne rnei
zerinden UserNamezellii(property) ile UserNamePasswordClientCredential isimli snfa
eriilebilir. UserNamePasswordClientCredential snfnn UserName ve Password isimli iki zellii
bulunmaktadr ve bunlar servis tarafnda tanml olan istemci hesaplarndakiler ile karlatrlmak
zere gnderilir.

Gelitirilen rnekte test amal sertifika kullanlmasnn oluturduu baz negatif etkiler vardr. Bu
nedenle yukardaki kod parasn ieren istemci uygulama yrtldnde alma
zamannda(Runtime) SecurityNegotiationException tipinden bir istisna mesaj alnmas kuvvetle
muhtemeldir.

Az ncede belirtildii gibi bu istisnann sebebi gerek sertifikalarn kullanlmaydr. Yaptm


aratrmalarda bu tip test sertifikalarnn kullanld senaryolar iin Microsoft gelitiricileri
tarafndan yazlm bir snf olduunu tespit ettim. Bu snf yardmyla yukardaki istisna mesajn
atlatmak ve yerel makinelerde testleri baarl bir ekilde gerekletirmek mmkndr. Snfn
ierii Microsoft tarafndan aadaki gibi gelitirilmitir.

PermissiveCertificatePolicy isimli snfn ierii;

using System.Security.Cryptography.X509Certificates;
using System.Net;

// Microsoft' tan alntdr.


class PermissiveCertificatePolicy

www.bsenyurt.com Page 1028


{
string subjectName;
static PermissiveCertificatePolicy currentPolicy;
PermissiveCertificatePolicy(string subjectName)
{
this.subjectName = subjectName;
ServicePointManager.ServerCertificateValidationCallback +=new
System.Net.Security.RemoteCertificateValidationCallback(RemoteCertValidate);
}

public static void Enact(string subjectName)


{
currentPolicy = new PermissiveCertificatePolicy(subjectName);
}

bool RemoteCertValidate(object sender, X509Certificate cert, X509Chain chain,


System.Net.Security.SslPolicyErrors error)
{
if (cert.Subject == subjectName)
{
return true;
}
return false;
}
}

Bu snfn sadece test sertifikalarnn olduu senaryolarda ele alnmasnn, gerek sertifikalarn
kullanld senaryolarda kullanlmamasnn Microsoft tarafndan nerildiini de
hatrlatalm. PermissiveCertificatePolicy snf istemci tarafna eklendikten sonra Main
metodunda proxy snf rneklenmeden nce ele alnmas gerekmektedir.

PermissiveCertificatePolicy.Enact("CN=TestSertifika-HTTPS-Server");
CebirServisiClient client = new CebirServisiClient("CebirServiceEndpoint");

Burada dikkat edilirse Enact metoduna sunucu tarafnda oluturulan test sertifikasnn ad
parametre olarak verilmitir. imdi uygulama bu haliyle test edilirse aadaki ekran grntsnde
olduu gibi baarl bir ekilde alt grlr.

Kullanc ad ve ifre bilgilerinde hata olmas halinde ise


uygulama MessageSecurityException tipinden bir istisna frlatacaktr. Bir baka deyile istemci
servis tarafndan dorulanmam olacaktr.

Gelelim rollerin ne ekilde ele alnabileceine. rnein Topla isimli metodu sadece Personel rolnde
olanlarn ele alabilecei bir senaryo gz nne alalm. Buna gre servis tarafndaki Aritmetik snf
ierisinde yer alan Topla metodunda aadaki dzenlemeleri yapmak yeterli olacaktr.

public double Topla(double x, double y)


{
IIdentity ulasanKullanici = ServiceSecurityContext.Current.PrimaryIdentity;
if (Roles.IsUserInRole(ulasanKullanici.Name, "Personel"))

www.bsenyurt.com Page 1029


return x + y;
else
throw new FaultException("Yetkiniz yok");
}

Buradaki kodlara gre alma zamannda metoda arda bulunan istemciye ait kullanc
bilgileri ServiceSecurityContext snf zerinden ele alnabilir. Elde edilen referans yetki belgesi
gnderen kullancnn ad bilgisinide ierecektir.

ServiceSecurityContext ve Roles snflarnn kullanlabilmesi


iin System.Security.Principal ve System.Web.Security isim alanlarnn uygulamaya
dahil edilmesi gerekir.

Bundan sonra tek yaplan, Roles snfnn IsUserInRole metodunu kullanarak, gncel ierikteki
kullancnn Personel rolnde olup olmadnn tespit edilmesidir. Eer kullanc Personel rolnde ise
hesaplama yaptrlr. Aksi halde bir FaultException retilip istemci tarafna doru frlatlr. stemci
tarafnda bulents isimli kullanc ile Topla metoduna erimek istediimizde alma zamannda
FaultException retildiini grrz.

Ancak istemci tarafndan, Personel rolndeki bir kullanc ile servise ularsak Topla metodu
sorunsuz bir ekilde alacaktr. Bunu buraks kullancs ile deneyebiliriz. Nitekim buraks isimli
kullanc Personel rol ierisinde tanmlanmtr

Bylece geldik bir makalemizin daha sonuna. Bu tamamlayc makalemizde internet


zerinden https ile eriilebilen bir servis zerinde, Asp.Net rol ve yelik ynetimini(Role and
Membership Management) kullanarak dorulama(authentication) ve
yetkilendirme(authorization) ilemlerinin nasl yaplabileceini incelemeye altk. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama iin Tklayn (Dosya boyutunun kk olmas iin veritaban kartlmtr. rnei
denerken sertifika eklemeyi ve veritabann oluturup rnek kullanclar dahit etmeyi unutmaynz.)

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Internet zerinden Gvenlii Salamak -


1 ( 03.07.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation ile gelitirilen datk mimari uygulamalarnda istemci(client)


ve servis(service) arasndaki gvenlii temel olarak mesaj seviyesinde(Message Level)ve iletiim
seviyesinde(Transport Level) salayabileceimizden daha nceki yazlarmzda bahsetmitik. Sz
konusu seviyelerden hangisi tercih edilirse edilsin, istemcilerin servisi kullanrken
dorulanmalar(authenticate) ve gerekli ilemleri yapabilmeleri iin yetkilerine
baklmalar(authorization) gerekir. Windows Communication Foundation, istemcileri

www.bsenyurt.com Page 1030


dorulamak(authenticate) adna alt farkl yol kullanlmasna olanak tanmaktadr. Bunlar aadaki
tabloda grld gibidir.

Windows Communication Foundation Dorulama(Authenticate) Yollar

Yol Aklama

stemcilerin dorulanmas iin tipik olarak servis tarafnda yer alan


windows hesaplarndan (Windows Accounts) faydalanlr. Daha
Windows ok Kerberos veyaNTLM gibi sistemler ele alnr. Bu
teknik intranet tabanl datk mimari uygulamalarnda olduka ie
yaramakta ve tercih edilmektedir.

stemciler servis tarafna kullanc ad(Username) ve


ifre(Password) bilgisi gnderir. Kullanc hesap bilgileri servis
tarafnda ounlukla bir veritaban sistemi zerinde tutulur. WCF
Kullanc Ad/ ifre
servislerinin IIS zerinde tutulabildii gz nne alndnda Asp.Net ile
(Username/Password)
gelen Membership veritabanlarn kullanmak yaygn olarak tercih
edilebilir. WCF servisinin HTTP zerinden yaynland internet tabanl
senaryolarda sklkla kullanlabilir.

stemciler servis tarafna kendilerini geerli bir sertifika yardmyla


X509
tantrlar.

Dorulama(Authenticate) ilemleri iin zelletirilmi yaplar


kullanlr. Biometric buna rnek olarak verilebilir. Sz gelimi
zel (Custom)
istemcilerin parmak izlerine veya gz retinalarna gre dorulanmas
gibi mekanizmalar var olan yaplarn zelletirilmesi ile mmkn olabilir.

Bu dorulama tekniine verilebilecek en gzel rnek .Net Framework


Issued Token
3.0 ile gelmi olan CardSpace mimarisidir.

stemcilerin tamam dorulanr. Bir anlamda da servise herkesin


Yok (None)
eriebilmesi salanm olunur.

stemcilerin kendilerini servis tarafna dorulatmalar esnasnda kullanc bilgilerinin sakland baz
ortamlar sz konusudur. Windows hesaplarnn(account) tutulduu sistemler bellidir. Ancak bunun
dnda zellikle internet tabanl senaryolarda ele alnabilecek ekilde
veritaban(database) kullanmda mmkndr. WCF mimarisinde servis taraf IIS zerinde
barndrlabilmektedir. Bu sebepten dolay kullanclara ait hesap bilgileri iin Asp.Net 2.0 ile birlikte
gelen yelik ynetim sisteminden (Membership Management API) faydalanlabilir. Elbetteki
windows veya veritaban dnda zel depolama sistemleride sz konusu olabilir.

Dorulanan kullanclarn yetkilerine baklmadan ilem yaplmas tam olarak gvenliin


salanamad anlamnada gelir. Dolaysyla servis tarafnda yer alan operasyonlarda dorulanan
kullanclarn rollerine, baka bir deyile yetkilerine baklarak ilerlenilmesinde fayda vardr. WCF
mimarisinde gvenlik denince aklan gelenler sadece authentication ve authorization olmamaldr.
Aslnda Windows Communication Foundation, maksimum gvenliin salanabilmesi iin farkl
ilkenin var olmasn gerektirmektedir. Bunlar, mesaj btnl(Message Integrity), mesaj
mahremiyeti(Message Privacy) ve mterek dorulama(Mutual Authentication) ilkeleridir.

Maksimum Gvenlik iin Salanmas Gereken lkeler

lke Aklama

Mesaj btnl ilkesine gre istemciden servise doru gidecek olan


Mesaj Btnl
mesajn bakalar tarafndan kurcalanp bozulamamas gerekmektedir. Bir
(Message Integrity)
baka deyile bu ilke, kt niyetli kullanclarn(malicious users) arada

www.bsenyurt.com Page 1031


hareket eden mesajlarn btnln bozacak ekilde hamlelerde
bulunamamasnn salanmasn gerektirir.

Bu ilke istemci ve servis arasnda hareket eden mesajlarn gizliliinin


salanmasn gerektirir. Bir baka deyile kt niyetli kullanclar eitli
Mesaj Mahremiyeti
3nc parti yazlmlar kullanarak mesaj ieriklerini okuyamamaldr. Bu ilke
(Message Privacy)
ayn zamanda Message Integrityilkesinin tamamlaycs olarak da
dnlebilir.

stemcilerin doru servis ile haberlemesini, istemciden gelen


Mterek Dorulama
ehliyet(Crendential) bilgilerinin servis tarafnda dorulanmasn ve
(Mutual
bunlara ek olarak tekrarl ataklarn(replay attacks) bertaraf
Authentication)
edilebilmesinin salanmasn hedefleyen ilkedir.

WCF iin sz konusu olan iletiim gvenlik sistemleri yukardaki ilkeleri gz nne alr ve buna gre
maksimum gvenliin salanabilmesini kolaylatrr. Buna gre kendi zel gvenlik sistemlerimizi
gelitirmek istediimizde burada bahsedilen ilkelere uygun olacak ekilde hareket edilmesi gerekir.

WCF mimarisinde iletiim gvenliini salayabilmek adna kullanlabilecek 5 farkl iletiim gvenlik
teknii bulunmaktadr. Bunlar None, Transport, Message, Mixed ve Bothteknikleridir. Message
seviyesinde iletiim gvenlii tekniini daha nceki yazmzda ele almtk. Transport tekniini ise
bu yazmz ile birlikte ele almaya alacaz. Gelelim dier modlara. Mixed modda Message
Integrity ve Privacy ilkelerini salamak iin iletiim(Transport) seviyesinde gvenlik teknii
kullanlr. stemci ehliyetlerini(Client Credential) korumak iinse mesaj(Message) seviyesinde
gvenlik teknii ele alnr. Both iletiim gvenlik tekniinde mesajlar mesaj seviyesinde gvenlik
tekniine gre ifrelenirken, istemciden servis tarafnda gnderilirken Transport tekniine gre
aktarlr.

WCF mimarisinin pek ok konusunda olduu gibi baz ilemleri gerekletirmek iin ele alnmas
gereken olduka fazla faktr vardr. Gvenlik teknikleri ile var olan balayc tipler(binding
types) arasndaki durumda ayndr. Bu sebepten dolay aadaki tablonun bilinmesinde ve ele
alnmasnda fayda vardr.

Balayc Tipler ve letiim Gvenlik Teknikleri Arasndaki liki

Balayc Tip (Binding


Transport Message Mixed Both None
Type)

NetTcpBinding Evet(Varsaylan) Evet Evet Hayr Evet

NetPeerTcpBinding Evet(Varsaylan) Evet Evet Hayr Evet

NetNamedPipeBinding Evet(Varsaylan) Hayr Hayr Hayr Evet

NetMsmqBinding Evet(Varsaylan) Evet Hayr Evet Evet

WSHttpBinding Evet Evet(Varsaylan) Evet Hayr Evet

WSFederationHttpBinding Hayr Evet(Varsaylan) Evet Hayr Evet

WSDualHttpBinding Hayr Evet(Varsaylan) Hayr Hayr Evet

BasicHttpBinding Evet Evet Evet Hayr Evet(Varsaylan)

Bu tabloda hangi balayc tipin hangi iletiim gvenlik tekniklerini destekledii belirtilmektedir.
rnein Both tekniini sadece NetMsmqBinding balayc tipi desteklerken dierleri desteklemez.
Dolaysyla istemci ve sunucu arasndaki gvenliin nasl salanacana karar verildikten sonra

www.bsenyurt.com Page 1032


uygun balayc tiplerin gz nne alnmas iin yukardaki tabloda yer alan bilgilerden
faydalanlabilir.

Bu blmde gelitirilmeye balanacak olan rnekte iletiim seviyesinde gvenlik (transport level
security) teknii kullanlacak olup yaznn ikinci blmnde istemcilere ait ehliyet bilgilerini servis
tarafnda kontrol ederken Sql Membership Provider ve Sql Role Provider API' leri ele
alnacaktr. rnee gemeden nce iletiim seviyesi gvenlik tekniinde seilen balayc tipe gre
hangi ehliyet modellerinin kullanlabileceiinin bilinmesinde fayda vardr. Dolaysyla gz nnde
bulundurulmas gereken bir tablo daha karmza kmaktadr.

Balayc Tipler, letiim Seviyesinde Gvenlik Teknii ve Dorulama Modelleri


Arasndaki liki

Balayc Tip (Binding


Windows Username/Password X509 None
Type)

NetTcpBinding Evet(Varsaylan) Hayr Evet Evet

NetPeerTcpBinding Hayr Evet Evet Hayr

NetNamedPipeBinding Evet(Varsaylan) Hayr Hayr Hayr

NetMsmqBinding Evet(Varsaylan) Evet Hayr Evet

WSHttpBinding Evet(Varsaylan) Evet Evet Evet

WSFederationHttpBinding

WSDualHttpBinding X
BasicHttpBinding Evet Evet Evet Evet(Varsaylan)

Dikkat edilmesi gereken noktalardan


birisi WSFederationHttpBinding ve WSDualHttpBinding balayc tiplerinin iletiim seviyesinde
gvenlik teknii sz konusu olduunda hi bir dorulama modelini desteklemediidir. Bu noktalar
akla kavuturduktan sonra nihayetinde bir rnek gelitirmeye balayarak internet tabanl WCF
uygulamalarnda iletiim seviyesinde gvenlii nasl salayabileceimizi incelemeye balayabiliriz.

letiim seviyesinde gvenlik sz konusu olduundan WCF servisinin IIS zerinde barndrlmas
ve HTTPS protokoln baz alarak hizmet verebilmesinin salanmas gerekmektedir. Ancak
ncesinde gvenli iletiim kanal kullanm iin(bir baka deyile https zerinden hizmet vermek
iin) hayali bir sertifika oluturulmaldr. Hayali sertifikalar oluturmak iin Makecert.exe arac
kullanlabilir. Bu ara tamamen test amal X509 sertifikalarnn retilmesini salamaktadr.

MakeCert.exe arac ile ilgili detayl bilgi iin http://msdn2.microsoft.com/en-


us/library/bfsktky3(VS.80).aspx adresinden bilgi alnabilir.

Test sertifikas oluturmak iin Visual Studio 2005 command prompt zerinden aadaki
komutun yazlmas yeterlidir.

C:\>makecert -sr LocalMachine -ss My -n CN=TestSertifika-HTTPS-Server -sky exchange


-sk TestSertifika-HTTPS-Key

www.bsenyurt.com Page 1033


Succeeded mesaj grld takdirde sertifika baarl bir ekilde oluturulmu
demektir. (Makalemizin amac Makecert aracn tanmak olmadndan aracn parametre detaylar
zerinde durulmayacaktr.) Oluturulan sertifikay grmek iin Microsoft Management Console'
dan faydalanlabilir.

Dier taraftan oluturulan sertifikann iletiim kanal ile (ki burada sz konusu olan yerel
makinedeki 8000 numaral Http portudur) ilikilendirilmesi gerekir. Bu ilem
iin HttpCfg.exearacndan yararlanlabilinir.

Windows XP' de HttpCfg.exe aracn kullanabilmek iin Windows XP Service Pack 2


Support Tools' u indirmek gerekebilir.

Httpcfg.exe arac parametre olarak oluturulan sertifikaya ait parmak


damgasn(thumbprint) kullanr. Parmak damgasn elde edebilmek iin ncelikli olarak Microsoft
Management Console' da aadaki ekran grntsnde yer ald gibi Add/Remove Snap
In seeneinden Certificates iaretlenir.

Certificates seildikten sonra sradaki admda Computer Account seilir.

www.bsenyurt.com Page 1034


Sonraki admda snap-in ynetimini stlenecek olan bilgisayar seilir. Bu varsaylan olarak yerel
bilgisayar (Local Computer) iaret etmektedir.

Bunun sonucunda oluturulan test sertifikas aadaki ekran grntsnde yer ald
gibi Personal->Certificates klasr altnda grlecektir.

Buradanda sertifikann detaylarna geilerek Thumbprint alannn deeri renilebilir.

www.bsenyurt.com Page 1035


Artk HttpCfg arac yardmyla sertifikann port ile ilikilendirilmesi salanabilir. Httpcfg.exe arac
yardmyla sertifikaya ait parmak damgasnn(thumbprint), port ile ilikilendirilmesini salamak
iin aadaki komut, Xp Support Tools Command Prompt zerinden altrlmaldr.

C:\>httpcfg set ssl -i 0.0.0.0:8000 h7eae8740bda1985efceaa1b91d1ce266bfe5788c

HttpSetServiceConfiguration Completed with 0 mesaj grld takdirde operasyonun


baarl bir ekilde tamamland anlalabilir.

HttpSetServiceConfiguration completed with 183 gibi bir mesaj alnmas hata


olutuu anlamna gelir. Hata mesaj zaten var olan dosyaya tekrardan yazlmak
istenmesinden kaynaklanmaktadr. (ERROR_ALREADY_EXISTS 183 Cannot create a
file when that file already exists.) Bu nedenle sertifika unload edilebilir. Sertifikann
Unload edilmesi iin komut satrndan

C:\>Httpcfg delete ssl /i 0.0.0.0:8000

yazlmas yeterlidir. Buna gre yerel makineye ait 8000 port numaras iin tanmlanm
olan ssl sertifikalarna ait bildirimler silinecektir. stenirse, Httpcfg.exe arac yardmyla

www.bsenyurt.com Page 1036


IIS zerinde yklenmi olan sertifikalar grmek iin komut satrndan

C:\>Httpcfg query ssl

yazlmas yeterlidir.

Oluturulan sertifikann IIS zerinde yer alacak WCF uygulamas tarafndan kullanlabilmesi iin
ncelikli olarak bildirilmesi gerekir. zleyen admlarda Windows XP iletim sistemi zerinde yer alan
IIS 5.1 iin sz konusu bildirim ileminin nasl yaplaca ele alnmaktadr. ncelikli olarak Internet
Information Services zerinden Default Web Site sa tklanp
zelliklerden(Properties) Directory Security ksmna geilir ve buradan Server
Sertificate dmesi tklanr.

Burada da Next ile ilerlenip Assign an existing certificate seenei iaretlenir ve devam edilir.
Bylece daha nceki admlarda yklenmi olan sertifikann kullanlabilmesi salanm olmaktadr.

www.bsenyurt.com Page 1037


zleyen admda az nce yklenmi olan sertifika grlebilir. Ykl olan baka sertifikalarda sz
konusu olabilir. Uygun olan sertifika seilerek ilerlemeye devam edilir.

Eer sertifika ykleme ilemi baarl bir ekilde gerekletirildiyse aadaki ekran grnts elde
edilmelidir.

www.bsenyurt.com Page 1038


Bundan sonraki tm admlar onaylanarak ilemler tamamlanr.

Artk WCF Service uygulamasnn yazlmasna balanabilir. Bu amala Visual Studio


2005 zerinden New Web Site seenei ile yeni bir web sitesi alr ve WCF Serviceablonu
seilir. Burada nemli olan nokta IIS zerinde alacak olan sanal klasr iin Secure Socket
Layer kullanlacan belirtmektir. Bunun iin aadaki ekran grntsnde olduu gibi lokasyon
seilirken Use Secure Sockets Layer seeneinin iaretlenmesi yeterlidir.

www.bsenyurt.com Page 1039


rnek servis CebirServisi olarak isimlendirilmitir. Bu ilemin ardndan aadaki ekran
grntsden yer ald gibi ilgili web adresinin banda HTTP yerine HTTPS yazld grlecektir.

Sz konusu admlar tamalandktan sonra oluturulan CebirServisi isimli servisin iletiim


srasnda HTTPS protokolne gre alabilmesi iin, IIS zerinden gerekli hazrlklarn yaplmas
gerekmektedir. Bunun iin ilk olarak IIS altnda yeni alm olan CebirServisi sanal klasrnn
zelliklerinden Directory Security ksmnda gidilir. Yaznn balarnda Default Web Site' a
hazrlanm olan hayali sertifika tantldndan, View Certificate ksm kullanlabilir haldedir.

www.bsenyurt.com Page 1040


View Certificate dmesi tklandktan sonra alan Certificate penceresinde, yklenmi olan test
sertifikasna ait bilgiler aadaki ekran grntsnde olduu gibi grlebilir.

www.bsenyurt.com Page 1041


CebirServisi iin yaplmas gereken bir dier ilem ise, Secure Communications ksmnda yer
alan Edit dmesine tkladktan sonra kan ekrandan, Require Secure Channel(SSL) seeneini
iaretlemektir. Bylece servis ile gvenli iletiimin salanmas iin SSL gereklilii bildirilmi olunur.

Son olarak yine Directory Security ksmndan Anonymous Access and Authentication
Control ierisinde yer alan Edit dmesine tklanp alan pencerede, Integrated Windows
Authentication seenei kaldrlmal ve Basic Authentication iaretlenmelidir.

Yaz dizisinin bu ilk blmnde WCF Servisi iin IIS zerinde gerekli sertifika bildirimlerinin nasl
yaplabileceini incelemeye alrken hayali bir sertifika iin Makecert veHttpcfg aralarn nasl
kullanabileceimizide grmeye altk. Bunlarn dnda iletiim seviyesinde gvenlik sz konusu
olduunda balayc tiplerin ve dorulama modlarnn nasl ele alnmas gerektii zerinde durduk.
Bylece geldik bir makalemizin daha sonuna. Sonraki makalemizde gelitirilen rnei
tamamlamaya alacaz. Tekrardan grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Transaction Yonetimi (Transaction


Management) - 2 ( 28.06.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation iin transaction ynetimi ile ilgili bir nceki makalemizde
teorik bilgiler zerinde durmaya almtk. Bu makalemizde ise, transaction ynetimi iin gerekli
materyalleri toplamaya devam edecek ve bir rnek zerinde konuyu daha net bir ekilde anlamaya
alacaz. rnei gelitirmeden nce zellikle servis ve metod seviyesinde bilinmesi gerekenler
olduunu belirtelim. zellikle servis nesnesi iin alma zaman davranlarn belirlemek
adna ServiceBehavior niteliinin baz zelliklerini kullanmak gerekmektedir. Benzer ekilde
operasyonlarn transaction ile ilikili alma zaman davranlarn belirlemek
iinde, OperationBehavior niteliinin zelliklerinden faydalanlmaktadr.

ServiceBehavior ve OperationBehavior dnda transacation ynetimi iin kullanlan bir dier


nitelik(attribute) ise, TransactionFlow' dur. Bu nitelik servis tarafndaki metodlara uygulanabilen
trdedir. TransactionFlow nitelii temel olarak bir servisin d servisler ile olan ilikilerinde servisler
arasnda akan transaction' larn operasyon kademesinde kabul edilme seviyelerinin belirlenmesinde
kullanlr. Sz konusu seviyeler TransactionFlowOption isimli enum sabiti tarafndan

www.bsenyurt.com Page 1042


belirlenebilir. TransactionFlowOption enum sabitinin deerleri ve nasl bir aka izin verdikleri
aadaki tabloda gsterilmektedir.

TransactionFlowOption
Aklamas
Deeri
NotAllowed WCF alma zaman (runtime) servise akan transactionlar gee
Allowed Transaction istemci tarafnda (istemci gncel servisin konutuu
bir tane oluturur.
Mandatory Sz konusu operasyonun yrtlebilmesi iin istemci uygulma (
SOAP Header (SOAP zarfnn balk ksmnda) ierisinde de tan

Bir servisin baka servis veya istemcilerden gelecek transaction akna izin verip vermemesi
durumlarn kontrol etmek iin ilgili balayc tiplerin (binding types) transactionFlowelementi
kullanlr. Varsaylan olarak transaction flow seenei aktif deildir(disabled). Dolaysyla
transaction aknn kontrol altna alnmasnn istendii durumlarda bilinli olarak almas
gerekmektedir. Bunun iin transactionFlow niteliine true deerinin atanmas yeterlidir.

ServiceBehavior niteliininde transaction ynetiminde kullanlan nemli zellikleri vardr.


Bunlar TransactionAutoCompleteOnSessionClose,RelaseServiceInstanceOnTransactionCo
mplete, TransactionTimeOut ve TransactionIsolationLevel isimli zelliklerdir.
TransactionAutoCompleteOnSessionClose zellii adndanda anlalaca zere oturum
kapatldnda transaction' a ne olacann belirlenmesinde kullanlr. Bunu oturum kapatldnda
transaction' n tamamlanp tamamlanmayacann belirtilmesi olarakda dnebiliriz. Nitekim sz
konusu zelliin deeri true olarak belirlendiinde hatasz olarak tamamlanan bir oturum
sonrasnda ilgili transaction otomatik olarak kapatlr. Normal artlar altnda herhangibir problem
nedeni ile ortama bir istisna(exception) nesnesi frlatldnda otomatik olarak geri alma
(rollback) ilemi gerekleir. Bu zelliin true olarak belirlenmesi bu ilemin daha kontroll bir
ekilde yaplmasnda salar. Ne varki varsaylan deeri false' dur.

RelaseServiceInstanceOnTransactionComplete zellii, transaction tamamlandnda ilgili


servis nesne rneinin serbest(relase) braklp braklmayacann belirlenmesinde kullanlr.
Varsaylan deeri true olarak belirlenmitir.

Eer OperationBehavior niteliinin TransactionScopeRequired deeri true ve ServiceB


ehavior niteliinin ConcurrencyMode zelliinin
deeri Reentrant iseRelaseServiceInstanceOnTransactionComplete zelliinin
deeri false yaplmaldr. Aksi takdirde alma zamannda bir istisna(exception) alnr.
Bunun sebebi RelaseServiceInstanceOnTransactionComplete zelliinin varsaylan
deerinin true olmasdr.

Burada RelaseServiceInstanceOnTransactionComplete zelliine gre transaction' lar


tamamlamann ncelikli olan 4 farkl yolu vardr.

OperationBehavior niteliinde TransactionAutoComplete zelliine true deeri verilir.


Servis tarafnda SetTransactionComplete metodu arlr. Bu zellikle
TransactionAutoComplete zelliinin false olduu durumlarda kullanlr. Genellikle gelitirme
safhasnda operasyonun transaction' tamamlama ihtiyacnn tam olarak kararlatrlamad
durumlarda tercih edilebilir.
stemcinin (yada dier bir servisin) dahil olduu aktif bir transaction ierisindeyken oturumu
kapatmas veya network hatas alnmas halinde eer TransactionAutoCompletezelliinin
deeri false ise otomatik olarak geri alma(rollback) ilemi gerekleir.
Yukardaki durumlarn dnda oluabilecek herhangibir neden transaction' n iptal
edilmesi (abort) ve o ana kadar yaplm ilemler var ise bunlarn geri
alnmas(Rollback) anlamna gelmektedir.

www.bsenyurt.com Page 1043


ServiceBehavior niteliinde transaction ynetimi iin kullanlan bir dier
zellikte TransactionIsolationLevel' dr. Bu zelliin deeri, servis ierisinde yeni bir transaction
aldnda veya servise baka bir istemciden (veya bir servisten) bir transaction aktnda (Flow),
deiken veriler (volatile datas) iin sz konusu olacak izolasyon seviyesinin (Isolation
Level) ne olacan belirler.

Bir transaction tarafndan etkilenen veri, deiken veri(volatile data) olarak


adlandrlr.

Izolasyon seviyeleri sayesinde ortak veriler zerinde dier transaction' larn yapt deiikliklerin
nasl ele alnaca yada transaction' n deiiklie urayan veriyi ne kadar sre kilitleyecei gibi
zellikler belirlenebilir. Sz konusu zelliin deeri IsolationLevel enum sabiti trnden olabilir.
Temel olarak ele alnabilecek 5 farkl izolasyon seviyesi vardr (Chaos ve Unspecified haricinde).
Bunlar aadaki tabloda ksaca zetlenmektedir.

Izolasyon Seviyesi
Aklamas
Deeri
ReadUncommited Transaction boyunca deiken veri (volatile data) zerinde dei
Phantoms, Non-Repeatable Read ve Dirty-Read durumlar oluabil
ReadCommited Transaction boyunca deiken veri zerinde deiiklik yaplabilir a
Dirty-Read durumlar olumaz.
Repeatable Read Transaction boyunca deiken veri zerinde deiiklik yaplamaz a
durumu oluabilir ancak Non-Repeatable Read ve Dirty-Read halle
Serializable En yksek mertebeli izolasyon seviyesi olarak ele alnr. Buna gre
Bu seviye Phantoms, Non-Repeatable Read ve Dirty-Read gibi dur
Snapshot Bu seviye aslnda ReadCommited' n farkl bir formasyonudur ve S
veri okunabilir. Burada veri deitirilmeden nce, son okumadan b
bir durum var ise hata frlatlr. Bu bir anlamda transaction' n son
Read ve Dirty-Read gibi durumlarn olumasna izin vermez. (Snap
ilgili veritaban iin almas gerekmetekdir.)

ServiceBehavior tarafnda yer alan bir dier zellik ise TransactionTimeOut' dur. Bu zellik
tahmin edilecei zere transaction iin zaman am sresini bildirir. Eer belirtilen srede
transaction tamamlanmamsa iptal (abort) sreci balatlr.

Gelelim OperationBehavior niteliinin transaction iin kullanlan zelliklerine. Sz konusu


zellikler, TransactionAutoComplete ve TransactionScopeRequired' dr.
TransactionAutoComplete zelliinin varsaylan deeri true' dur ve buna gre eer ele
alnamayacak(unhandled) bir hata olumamsa sz konusu operasyonun yer ald Transaction
otomatik olarak tamamlanr (Commit). Ele alnamayan istisnalar otomatik olarak Transaction'
n iptal(abort) edilmesini tetiklemektedir.

Transaction' n kod ierisinden tamamlanmas veya iptal edilmesi


istendiinde TransactionAutoComplete zelliinin varsaylan olarak true olan deerinin
bilinli bir ekildefalse olarak belirtilmesi gerekmektedir.

TransactionScopeRequired zellii, uyguland metodun almas srasnda bir transaction


scope gerektirip gerektirmediinin belirlenmesinde kullanlr. Sz konusu zelliin varsaylan deeri
false' dur. Eer metodun almas srasnda bir Transaction Scope gerekiyorsa true olarak
belirlenir. Eer baka bir yerden metoda akan bir transaction var ise, metod ierii gelen

www.bsenyurt.com Page 1044


transaction' a dahil olacaktr. Tam aksine kullanlabilir bir transaction yoksa yeni bir tane
oluturulur ve yrtme yeni alan bu Transaction ierisinde gerekletirilir.

Aslnda TransactionFlow ve TransactionScopeRequired zellikleri gz nne alndnda


bunlarn sahip olabilecei deerlerin etkisini iyi bir ekilde kavramak gerekir. Bu amala rnek bir
senaryo olarak aadaki ekli gz nne alalm.

lk olarak istemci uygulama Servis A zerinden bir operasyon arsnda bulunur. ekle gre Servis
A balayc tipini (Binding Type) istemcilerden gelecek transaction aklarn destekleyecek biimde
tasarlamtr. stelik arlan operasyon iin Servis A, Transaction akna izin vermektedir.
Bununla birlikte istemcide alan bir Transaction mevcut deildir. Lakin Servis A
iin TransactionScopeRequired zelliinin deeri true olarak belirlenmitir. Buna gre sz
konusu operasyon iin Servis A otomatik olarak bir Transaction alan (Scope) aacaktr.

Gelelim Servis B' ye. Servis A, Servis B zerinden de bir operasyon ars yapmaktadr. Servis B'
ye ait balayc tip(binding type) dier istemcilerden transaction akna izin vermektedir. Bununla

www.bsenyurt.com Page 1045


birlikte Servis B' deki operasyonun TransactionFlow zellii Mandatory olarak belirlenmitir. Bir
baka deyile Servis A' nn Servis B' ye bir Transaction ak salamas arttr. Dier taraftan Servis
B' deki TransactionScopeRequired zelliinin deeri true olduundan Servis B' deki operasyon,
otomatik olarak Servis A' dan gelen Transaction Scope' a dahil olacaktr. Buna gre Servis A ve
Servis B ayn Transaction Scope ierisinde alacaktr.

Servis B, Servis C zerinden bir operasyon armaktadr. Servis C' deki duruma baktmzda,
balayc tipin baka servis veya istemcileriden gelen transaction akna izin vermedii
grlmektedir. Bununla birlikte operasyon iinde, transaction akna izin verilmemektedir. Ancak
arlan operasyonun bir transaction ierisinde altrlmas gereklidir.
nk TransactionScopeRequired zelliinin deeri true olarak ayarlanmtr. Bu sebepten
Servis C kendine ait Transaction alan ierisinde almaktadr.

Servis C, Servis D zerinden de bir operasyon armaktadr. Servis C' dekine benzer olarak dier
servis veya istemcilerden gelecek transaction akna izin vermeyecek ekilde balayc tipi
ayarlanmtr. Dier yandan arlan operasyon iinde transaction akna izin verilmemekte ve
yeni bir transaction oluturulmas da engellenmektedir. Dolaysyla buradaki operasyon tamamen
transaction haricinde kendi haline almaktadr.

Buradaki bilgiler nda pek ok senaryo dnlebilir. Kullanlan zellikler gz nnde


bulundurulduunda ok doal olarak olaslklarn says artmakta ve ele alnmalar zorlamaktadr.
Bu sebepten zelliklerin deerlerinin farkl kombinasyonlarnn etkilerini daha kolay bir ekilde
grebilmek iin, aadaki tablodan yararlanlabilir.

Transaction' n
TransactionScopeRequired TransactionFlowOption transactionFlow
Ele Alnd
Deeri Deeri Elementi Deeri
Taraf

true Allowed false


Servis Tarafl
true NotAllowed false

true Mandatory true stemci Tarafl

true Allowed true ift Tarafll

false Allowed false

false NotAllowed false


Tarafsz
false Allowed true

false Mandatory true

Tabloda TransactionScopeRequired, TransactionFlowOption zelliklerinin


ve transactionFlow elementinin deerlerine gre transaction' n hangi tarafta ele alnabilecei
grlmektedir. Servis tarafl modele gre, servis uygulamas her zaman iin kendine ait bir
transaction' a sahiptir. Ayrca servis taraf bu transaction' her zaman iin istemci transaction'
ndan ayr olacak ekilde ele alr. Bir baka deyile servis tarafnn her zaman iin kendi
transaction'nda alt dnlebilir. Senaryoda yer alan Servis C bu durumu tam olarak
karlamaktadr.

stemci tarafl modele gre, servis kendisine istemci tarafndan akan transaction' kullanr. rnek
senaryoda yer alan Servis C bu modele uygun bir ekilde almaktadr. Bu modelde servisin
istemciden akan bir transaction' almas zorunludur. Daha ok, deadlock' larn olumasnn
engellenmesi ve sistem tutarllnn salanmas istenilen durumlarda tercih edilebilir. Nitekim
istemci tarafnda alan transaction, servis tarafna da dahil edildiinden tm ilemler aslnda ayn

www.bsenyurt.com Page 1046


transaction scope ierisinde yer alacaktr. Buda doal olarak deadlock oluma ihtimalini
azaltmaktadr. Bunun dnda istemci ve servislerin saysnn artt bir modelde herkesin ayn
transaction' a dahil olmas,atomicity ilkesinin en iyi biimde karlanmas anlamnada gelmektedir.

ift tarafl modelde servis istemciden kendisine doru akan transaction' kullanabilir yada akan bir
transaction yoksa kendi oluturduu transaction scope' u kullanr. Bu yararl bir modeldir. Eer
istemci tarafndan akan bir transaction var ise tm srecin atomiklii daha tutarl bir ekilde
salanabilir. Yinede istemci tarafndan gelen bir transaction yok ise bu durumda servisin bir kk
transaction (root transaction) aarak tm sreci stne almasda sz konusu olabilir. Bu
alardan bakldnda ok fazla tercih edilebilecek bir modeldir.

Son olarak tarafsz modele gre, servis hi bir durumda transaction' a sahip olmaz. rnek
senaryoda yer alan Servis D buna rnek olarak verilebilir. Tarafsz model daha ok istemci
tarafndaki transaction' larn, servis tarafndan bozulmas istenmeyen durumlarda ele alnabilir.

imdi basit bir rnek ile transaction ynetimini incelemeye alalm. u ana kadar anlatlanlar gz
nne alndnda transaction kullanmnn deiiklik varyasyonlar olabilecei dnlebilir.
rnekte ilk olarak istemci tarafnda oluturulan bir transaction' n servis tarafna aktarlmas ve
burada ele alnarak commit ileminin gerekletirilmesi incelenecektir. Her zaman olduu gibi ie
servisin sunaca arayz szlemesi ve uzak nesne snfn tasarlayarak balamak gerekir.

ISiparisYonetici arayz;

using System;
using System.Transactions;
using System.ServiceModel;

namespace NorthwindYonetici
{
// IsolationLevel enum sabitinin kullanlabilmesi iin System.Transactions.dll' inin projeye

www.bsenyurt.com Page 1047


referans edilmesi gerekmektedir.
[ServiceContract(Name="Siparis_Yonetim_Servisi",
Namespace="http://www.bsenyurt.com/2007/23/6/SiparisYonetimServisi",
SessionMode=SessionMode.Required)]
public interface ISiparisYonetici
{
[OperationContract(Name="SepeteEkle",IsInitiating=true)]
bool SepeteUrunEkle(int urunNumarasi);

[OperationContract(Name="SepettenCikar",IsInitiating=false)]
bool SepettenUrunCikart(int urunNumarais);

[OperationContract(Name="SepetiOnayla",IsInitiating=false,IsTerminating=true)]
bool Onayla();
}
}

SiparisYonetici snf;

using System;
using System.Data.SqlClient;
using System.Transactions;
using System.ServiceModel;
using System.Text;

namespace NorthwindYonetici
{
[ServiceBehavior(TransactionIsolationLevel=
IsolationLevel.Serializable, TransactionTimeout="00:02:00",
InstanceContextMode=InstanceContextMode.PerSession)]
public class SiparisYonetici:ISiparisYonetici
{
private string TransactionInfo(Transaction trx,string mesaj)
{
StringBuilder builder = new StringBuilder();
builder.AppendLine(mesaj);
builder.AppendLine("Gncel Transaction Bilgileri");
builder.Append("Oluturulma zaman (Creation Time): ");
builder.AppendLine(trx.TransactionInformation.CreationTime.ToLongTimeString());
builder.Append("Datk GUID (Distributed GUID): ");
builder.AppendLine(trx.TransactionInformation.DistributedIdentifier.ToString());
builder.Append("Yered belirleyici (Local Identifier) : ");
builder.AppendLine(trx.TransactionInformation.LocalIdentifier);
builder.Append("Durum (Status) : ");
builder.AppendLine(trx.TransactionInformation.Status.ToString());
builder.AppendLine();
return builder.ToString();
}

#region ISiparisYonetici Members

[OperationBehavior(TransactionAutoComplete=false,TransactionScopeRequired=tr
ue)]
[TransactionFlow( TransactionFlowOption.Mandatory)]
public bool SepeteUrunEkle(int urunNumarasi)

www.bsenyurt.com Page 1048


{
// stemci tarafnda bu metoda yaplan her ar sonrasnda o anki transaction iin bir
TransactionCompleted olay yklenir. Bu nedenle ka metod ars var ise hepsi iin
TransactionCompleted olay birer kez alr.
Transaction.Current.TransactionCompleted += new
TransactionCompletedEventHandler(Current_TransactionCompleted);
Console.WriteLine(TransactionInfo(Transaction.Current,"SepeteUrunEkle metodu
arld"));
return true;
}

void Current_TransactionCompleted(object sender, TransactionEventArgs e)


{
Console.WriteLine(TransactionInfo(e.Transaction,"TransactionCompleted Olay
tetiklendi"));
}

[OperationBehavior(TransactionAutoComplete = false, TransactionScopeRequired =


true)]
[TransactionFlow(TransactionFlowOption.Mandatory)]
public bool SepettenUrunCikart(int urunNumarais)
{
Console.WriteLine(TransactionInfo(Transaction.Current, "SepetenUrunCikart metodu
arld"));
return true;
}

[OperationBehavior(TransactionAutoComplete = true, TransactionScopeRequired =


true)]
[TransactionFlow(TransactionFlowOption.Mandatory)]
public bool Onayla()
{
Console.WriteLine(TransactionInfo(Transaction.Current,"Onayla metodu arld"));
/* Yorum satr haline getirildiinde TransactionAutoComplete false ise sz konusu
transaction abort edilir. Ancak TransactionScopeAutoComplete true ise aadaki metodu
armaya gerek kalmadan transaction onaylanr. Ayrca TransactionAutoComplete zellii true ise,
SetTransactionComplete metodunu armak alma zaman hatasna neden olur. Bu aktif olan bir
transaction var ise bununda iptal edilmesine neden olacaktr. */
//OperationContext.Current.SetTransactionComplete(); // Bu ardan sonra
Transaction.Current null deer dndrecektir.
return true;
}

#endregion
}
}

Sz konusu servis snf ierisindeki metodlarda herhangibir balant ifadesi yer almamaktadr.
Sadece bir al veri sepetinin hayali bir uyarlamas bulunmaktadr. Ancak nemli olan baz noktalar
vardr. stemci operasyon arlarn gerekletirirken ilk olarak SepeteUrunEkle metodunu
armaldr. Operasyonlarn tamamlanmas ise Onaylametodunun arlmas ile gerekleir. Bu
metod srasn salamak iin arayze (interface) ait OperationContract nitelii
ve IsInitiating ile IsTerminating zellikleri kullanlmtr.

SiparisYonetici snfndaki metodlarda istemci tarafnda oluturulmas zorunlu olan bir transaction
aknn gelmesini salamak iin TransactionFlow niteliklerinde Mandatorydeeri kullanlmtr.

www.bsenyurt.com Page 1049


Snf ierisinde oluturulan gncel transaction' lar daha kolay takip edeilmek iin TransactionInfo
isimli bir metod kullanlmaktadr. alma zamannda aktif olan bir transaction' elde etmek iin
Transaction snfnn Current zellii ele alnabilir.

Servis veya istemci uygulamalarda, kod tarafnda Transaction, TransactionScope gibi


tipleri kullanabilmek iin projeye System.Transactions.dll' inin referans edilmesi
gerekmektedir.

Current zellii ile alma zamannda elde edilen Transaction nesne rnei
zerinden TransactionInfo zelliine geilerek gncel transaction hakknda baz bilgiler
toplanabilir. rnein oluturulma zaman (Creation Time), datk transaction almsa bunun
GUID numaras (Distributed Transaction Identifier) ve hatta transaction' n o anki
durumu (status) gibi. Bu tanmlamalara ek olarak servise ait transaction' larn izolasyon
seviyesi Serializable, transaction iin geerli zaman am (timeout) sresi ise 2 dakika olarak
belirlenmitir.

Servis uygulamasnda kullanlacak olan konfigurasyon dosyasnn ierii aadaki gibi


tasarlanmaldr.

Servis tarafndaki App.config dosyas;

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


<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="SiparisServisiBindingConfiguration" transactionFlow="true" trans
actionProtocol="OleTransactions">
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="NorthwindYonetici.SiparisYonetici">
<endpoint address="net.tcp://localhost:4500/SiparisServisi"
binding="netTcpBinding" bindingConfiguration="SiparisServisiBindingConfiguration" name
="SiparisServisiEndPoint" contract="NorthwindYonetici.ISiparisYonetici" />
</service>
</services>
</system.serviceModel>
</configuration>

Dikkat edilmesi gereken noktalardan birisi, netTcpBinding balaycs iin gerekli konfigurasyon
ayarlarnda transactionFlow niteliinin true, transactionProtocol niteliinin
iseOleTransactions olarak set edilmi olmasdr. Servis taraf, rnein daha kolay bir ekilde
incelenmesi iin Console uygulamas olarak tasarlanmtr ve kodlar aadaki gibidir.

ServiceHost host = new ServiceHost(typeof(NorthwindYonetici.SiparisYonetici));


host.Open();
Console.WriteLine("Sunucu dinlemede");
Console.WriteLine("Servisi durdurmak iin bir tua basn");
Console.ReadLine();

www.bsenyurt.com Page 1050


host.Close();

Bu admlardan sonra istemci taraf iin gerekli proxy nesnesinin oluturulmas gerekir. Bunun iin
yine svcutil aracndan yararlanlabilir. Dikkat edilmesi gereken noktalardan birisi udur; servis
tarafnda TransactionFlow niteliklerinde bir deiiklik yapldnda bunun proxy snf iinde
gerekletirilmesi bir baka deyile istemci tarafnda gncelletirilmesi gerekir. Dolaysyla proxy
snfnn yeniden retilmesi gerekecektir. Yada manuel olarak istemci tarafndaki proxy snfna
mdahale edilip bu nitelikler ak bir ekilde deitirilmelidir.

Sz gelimi SiparisYonetici snfndaki TransactionFlow niteliklerini Allowed olarak belirleyip,


istemciler iin gerekli proxy snfn rettiimizi dnelim. Daha sonradan TransactionFlow
niteliinde Mandatory seeneini kullanr ve proxy snfn gncellenmez ise, WCF alma
zamannda ProtocolException tipinden bir istisna (exception) retilecektir.

stemci tarafnda yer alacak konfigurasyon dosyasnn ieriinin aadaki gibi olmas
gerekmektedir.

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


<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="SiparisYonetimServisiBinding" transactionFlow="true" transactio
nProtocol="OleTransactions">
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:4500/SiparisServisi"
binding="netTcpBinding" bindingConfiguration="SiparisYonetimServisiBinding" contract="Si
paris_Yonetim_Servisi" name="Siparis_Yonetim_Servisi" />
</client>
</system.serviceModel>
</configuration>

stemci uygulamayda bir Console olarak tasarladmz dnecek olursak, Main metodu
ierisinde aadaki kodlar yazmamz gerekecektir.

Console.WriteLine("Devam etmek iin bir tua basnz");


Console.ReadLine();
Siparis_Yonetim_ServisiClient client = new
Siparis_Yonetim_ServisiClient("Siparis_Yonetim_Servisi");
using (TransactionScope tx =new
TransactionScope(TransactionScopeOption.RequiresNew))
{
client.SepeteEkle(11);
client.SepeteEkle(42);

client.SepettenCikar(42);

if(client.SepetiOnayla())
tx.Complete();

www.bsenyurt.com Page 1051


}
Console.ReadLine();

stemci uygulamada TransactionScope tipine ait bir nesne rnei kullanlarak yeni bir transaction
alan almas salanmaktadr. Bundan sonrasnda ise istemci tarafndan servis zerindeki bir ka
metod arka arkaya arlr. Son olarak using blou terk edilmeden nce eer SepetiOnayla
metodunun dn deeri true ise tx isimli TransactionScope snf nesne rneine
ait Complete metodu arlr. nce sunucu ve sonrasnda ise istemciyi altrdmzda servis
tarafndaki console uygulamasnda aadaki ekran grnts elde edilir.

Burada dikkat edilmesi gereken ilk nokta, SepeteUrunEkle metodunun ilk arlyla beraber elde
edilen datk transaction GUID numarasnn tm metod arlarnda ayn olmasdr. Bu basit
olarak, her operasyonun alan transaction scope' a dahil edildii anlamna da gelmektedir.
SepeteUrunEkle metodu ierisinde Transction iin TransactionCompleted olay yklenmitir. stemci
tarafnda SepeteUrunEkle metodu iki kez arlmtr. Bu nedenle iki
adet TransactionCompleted olay metodu yklenmi ve gncel transaction' a
ait Commited durumu iki kez yakalanmtr. Olay daha iyi kavrayabilmek iin servis tarafndaki

www.bsenyurt.com Page 1052


SiparisYonetici snf ierisindeki SepeteUrunEkle metodu ierisinde aadaki ekran grntsnde
olduu gibi breakpoint konulmas yerinde bir harekete olacaktr.

lk metod ars ile birlikte Compenent Services ierisindeki Distributed Transaction


Coordinator ksmna bakldnda Transaction List ierisinde yeni bir OleTx transaction ald
ve Transaction Statistics ksmndada bu transaction' n aktif olarak yer ald grlmektedir.

Ayn zamanda Transaction Statistics ksmna baklrsa aadakine benzer bir ekran grnts ile
karlalr. Dikkat edilecek olursa aktif olan 1 adet transaction bulunmaktadr.

www.bsenyurt.com Page 1053


Eer ilemler sonuna kadar devam ettirilirse, transaction' n baarl bir ekilde tamamland yine
istatistik ksmndan grlebilir. Burada dikkat edilmesi gereken deerCommited' dr.

imdi Onayla metodundan geriye false deer dndrdmz dnelim. Bu durumda istemci
tarafndaki TransactionScope snfna ait nesne rnei zerindenComplete metodu
tetiklenemiyecektir. Dolaysyla sz konusu transaction' n iptal edilmi olmas gerekir. Gerektende
uygulama altrldnda aadaki ekran grntsnde olduu gibi TransactionCompleted isimli
olay metodu tetiklendiinde, o anki transaction' n durumunun Aborted olduu gzlemlenebilir.

www.bsenyurt.com Page 1054


Benzer ekilde DTC altndaki Transaction Statistics blmne bakldnda bir transaction' n
iptal edildii bilgisi yer alacaktr. (Bu aamada olayn daha iyi analiz edilmesi
iin Services ksmndan Distributed Transaction Coordinator servisi Restart edilmitir. Bu
sebepten aadaki ekran grntsnde olduu gibi nceki rnekle birlikte toplam 2 transaction
olmas gerekirken sadece 1 transaction yer almaktadr.)

Dikkat etmemiz gereken noktalardan biriside transactionFlow elementinin deeridir. Eer istemci
tarafndaki konfigurasyon dosyasnda bu zelliin deeri false olarak
bildirilirse, Mandatoryseenei nedeni ile WCF alma
zamannda InvalidOperationException istisnas alnr. Benzer durum servis taraf iinde
geerlidir. Eer istemcide zelliin deeri true ama servis tarafnda false ise yine WCF alma
zaman servis tarafna bir InvalidOperationException istisnas frlatacaktr.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde WCF iin transaction ynetimini
biraz daha derinlemesine incelemeye altk. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek uygulama iin tklayn.

www.bsenyurt.com Page 1055


Burak Selim ENYURT
selim@bsenyurt.com

WCF - Transaction Yonetimi (Transaction


Management) - 1 ( 19.06.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Transaction (lem) ynetimi zellikle veritaban kaynaklar sz konusu olduunda her sistemde
byk bir nem sahiptir. Basit olarak transaction bir veya daha ok ilem btnn temsil eder.
Btn oluturan sz konusu ilem paralar ounlukla birbirleriyle ilikilidir ve hepsinin baarl bir
ekilde tamamlanabilmesi sonrasnda transaction' n baarl olduu sylenebilir. Bu doal olarak
ilem paralarndan herhangibirinin baarsz olmas sonucunda transaction' nnda baarsz olmas
anlamna gelmektedir. Aadaki ekilde bir transaction' n sre ierisinde sistemin belirli bir
konumdan baka bir konuma geii srasnda stlendii rol ifade edilmeye allmaktadr.

Buna gre sistemin belirli bir konumdan baka bir konuma gemesi srasnda yaplacak ilemlerin
tamam bir btn olarak ele alnmaldr. Sz konusu btn ierisinde meydana gelebilecek
aksamalarda sistem ilk konumuna (Konum A) dnebilmelidir. Tam tersine tm ilemler baarl
olduunda sistem yeni konumuna (Konum B) geebilir. Bu ekilde dnldne transaction
ACID(AtomicityConsistencyIsolationDurability) ad verilen standartlar salamak durumundadr.
Makalemizin konusu Windows Communication Foundation sistemi zerinde transaction ynetiminin
nasl salanabileceinin temellerini incelemektir. Yinede ACID ilkelerinden ksaca bahsetmek
gerektii en azndan hatrlanmasnda fayda olaca kansndaym.

Atomicity ilkesine gre bir transaction' n baarl olmas, ierisinde yer alan tm ilem paralarnn
ayr ayr baarl olmas anlamna gelmektedir. Consistencyilkesi, yaplan ilemler sonucunda
oluan ktlarn tutarll anlamna gelir. Her zaman verilen bir rnek tutarllk ilkesini son derece
gzel anlatmaktadr. Bankalar aras yaplan bir havale ilemi srasnda bir hesaptan kan miktar ne
kadar ise dier hesaba aktarlannda o kadar olmas gerekir. Ne bir fazla ne de bir eksik
olmamaldr. te bu verinin tutarlln korumak olarak dnlebilir. Isolation ilkesine gre bir
transaction ierisindeki tm ilem paralar dier transactionlardan izole olacak ekilde almaldr.
Bu olmad takdirde tutarszlklar oluabilir.

Elbette transaction' larda sz konusu olabilecek Dirty-Read, Phantom, Non-Repeatable


Read gibi durumlarn hangisinin tercih edileceine gre eitli izolasyon seviyeleri (Isolation
Levels)pek ok veri taban sisteminde ele alnmaktadr. Bunlar .Net tarafndaki Transaction
snflarncada kullanlmakta ve IsolationLevel enum sabitleri ile iaret edilmektedir. Sz konusu
seviyeler WCF ierisindede bir servis davran (Service Behavior) olarak belirtilebilmektedir. Sz

www.bsenyurt.com Page 1056


konusu bildirim ServiceBehavior niteliinin TransactionIsolationLevel zelliinin deeri ile
sabitlenmektedir.

Temel Olarak Transaction' larda Dnelecek Senaryolar;

Phantom; balatlan iki transaction olduunu dnelim. Bu transactionlarn birisi ak


iken yeni bir veri girii yapp ilemi onaylyor (Commit) olsun. Bu durumda halen daha
ak olan dier transaction ayn veri kmesini tekrardan talep ettiinde daha nce
kendisinde var olmayan yeni eklenmi bir satr ile karlaacaktr. Bu satrlar
hayalet(Phantom) olarak adlandrlr.

Non-Repeatable Read; yine balatlm iki transaction olduunu dnelim. Bu sefer


ak olan transaction' lardan birisi var olan veri kmesinde belirli bir satrda(satrlarda)
gncelleme ilemi yapm olsun. Sonrasnda ise yaplan bu deiiklikleri
onaylasn(Commit). Ak kalan dier transaction'n tekrardan ayn veri kmesini ektiini
dnelim. Bu durumda ak olan transaction daha nce bakt verilerin deitiini
grecektir. Bu Non-Repeatable Read olarak adlandrlan bir durumdur.

Dirty-Read; yine balatlm iki transaction olduunu gz nne alalm. Bunlardan birisi
veri kmesine herhangibir satr eklemi veya gncellemi olsun. Ancak bu srada dier
transaction'n tekrardan veri ektiini dnelim. Burada dikkat edilmesi gereken durum
udur; iki transaction ak iken, herhangibiri commit edilmeden nce dieri veri
ekebilmektedirler. Dolaysyla dier transaction var olan ekleme ve deiiklikleri o an iin
grecektir. Ne varki bu senaryoda deiiklikleri yapan transaction
ilemleri Commit etmez. Aksine geri alr(Rollback). Bu durumda daha nce tekrardan
veri eken ak transaction' da aslnda geri alnm gncellemeler ve eklemeler
grlmektedir. Bu Dirty-Read durumu olarak adlandrlmaktadr.

Durability ilkesine gre transaction ierisinde yer alan i paralarnda bir aksaklk olmas halinde
sistemin ilk haline dnebilmesi gerekir. Yani talar ilk konumlarndaki yerlerinde kalabilmeldir.

Gelelim WCF ierisindeki duruma. Transaction' lar servis ynelimli mimari (Service Oriented
Architecture) zerinde ele alndnda iin ierisine giren faktrler transaction ynetimini
zorlatrmaktadr. Nitekim ilem paralarnn farkl makinelerdeki, farkl uygulama
alanlar (AppDomain) ierisinde(Dolaysyla farkl sre-process' lerde)olmalar sz konusudur. Bu
ilem paralar eitli kaynaklar (Resources) kullanacaktr. Sz konusu kaynaklar farkl veritaban
sistemleride olabilir. rnein bir servis Microsoft SQL Server zerinde bir ilem gerekletiriyorken,
buna bal olan dier bir ilem parasda Oracle veritaban kullanan baka bir servisin paras
olabilir. Dahas farkl uygulama alanlar(Application Domain) ierisindeki taraflar basit birer istemci
dnda baka servislerde olabilir ve bunlar farkl platformlar zerinde yer alabilir. En iyimser haliyle
dnldnde tek bir AppDomain ierisinde konulandrlm bir WCF Servis uygulamas,
kendisine bal bir veya daha ok kaynak (resource) zerinde alacak transaction' lar kolay bir
ekilde ynetebilir. Aadaki ekilde bu durum analiz edilmeye allmaktadr.

www.bsenyurt.com Page 1057


Burada bilinen Ado.Net Transaction tiplerinin kullanlmas bile yeterlidir. Ne varki az nce
bahsettiimiz gibi servis ynelimli mimari aslnda aadaki ekildekine benzer bir durumuda
iermektedir.

Sanyorumki imdi durum biraz daha kart. Bu ekle gre istemcinin talepte bulunduu ilemler
sonras Servis A, Servis B ve Servis C zerindeki kaynaklardaki ilem paralarnn baarl bir
ekilde tamamlanmasn istemektedir. Bir baka deyile Servis B , Servis C ve Servis A zerindeki
ilem paralarnn hepsinin ayr ayr baarl olmalar gerekmektedir. Burada ortaya bir
koordinasyon problemi ktda son derece aktr. rnein aa maddeler halinde sralanm olan
sorularn sz konusu sistemde nasl karlanabilecei dnldnde, sadece bu iler iin neden
gl koordinasyon uygulamalar yazld daha kolay bir ekilde anlalmaktadr.

Acaba bu sistemde Transaction' kim balatacak?


Diyelimki Transaction birisi tarafndan balatld. Dier ilem paralarn alan bu
Transaction' a kim dahil edecek (auto enlist)? yleki dahil olmadan transaction' n farkl
sistemlere yayld nasl anlalacak?
Geri alma(Rollback) veya onaylama(Commit) ilemlerini kim stlenecek?

www.bsenyurt.com Page 1058


Birden fazla servis sz konusu olduundan bunlar zerinde toplu bir rollback veya commit
karar nasl ve neye gre verilecek?
Eer Transaction' stlenen, bir baka deyile sreci balatp bitirecek olan servis, dier
servislerdeki ilem paralarnn sonularndan nasl haberdar olacak?
Bahsedilen bu ilem paralarn ieren ve yrten servisler farkl platformlarda hatta farkl
iletiim seviyelerinde(Http, Tcp gibi) olduu zaman nasl kontrol altna alnacak?

Grld zere sorular ve sorunlar giderek artmaktadr. zmn ad datk transaction


(Distributed Transactions) dr. Gerektende servis ynelimli mimarilerde(SOA-Service Oriented
Architecture) yer alan ilem paralarn kontrol altna almann tek yol datk transaction' lar
kullanmaktadr. Datk transaction' lar iki nemli paraya sahiptir. lk olarak bu modelde ift ynl
geerli klma (two phase commit) ad verilen bir protokol sz konusudur. kinciside transaction
ynetimini stlenen ve genelde nc parti olarak tedarik edilen bir ynetici
uygulamadr (Dedicated Transaction Manager).

ok basit olarak two phase commit protokoln aklamaya alarak devam edelim. Bu protokol
iki aamadan oluur. lk aamada transaction' a katlan ilem paralarndan sorumlu servisler kendi
ilemlerinin baarl olup olmadklarna dair yneticiye bilgi gnderirler(Pek ok kaynakta bu ilem
oylama-voting olarakta gemektedir). Buradaki ynetici root grevini stlenen bir servise adanm
da olabilir. kinci aamada ynetici, am olduu transaction ierisine katlm ilem paralarnn
oylamalarn deerlendirir. Eer hepsi geerli ise tm bal olan ilem paralar iin ilgili servislere
onaylayn bilgisini gnderir(Commit aamas). Elbetteki tam tersi durumda bal servislere ilemleri
geri almalarna dair baka bir bilgi gnderilecektir(Rollback aamas).

Sz konusu ift ynl geerli klma protokolnn yan sra, Windows Communication Foundation
servislerin bulunduklar farkl platformlara, aradaki iletiim protokollerinin eitliliine gre ayr
transaction protokol ierir. Bunlar Lightweight, OleTx ve WSAT (WS-Atomic) transaction
protokolleridir. Aslnda OleTx ve WS-Atomic kendi ilerinde two phase commit protokoln zaten
ele almaktadrlar.

Lightweight transaction protokolne gre ilem paralar yerel olarak servis ierisinde ele alnr.
Bir baka deyile sz konusu transaction servis snrlar dna kartlamaz. Buda ilgili i
paralarnn baka servislerde balatlacak hizmetlere katlamayaca anlamna gelir. Tipik olarak
bir istemci ve servisin sz konusu olduu durumlarda ele alnabilir. Servis ierisinde yerel olarak
kullanldklarndan performans ynnden avantajldr dier modellerine gre daha avantajldr.

OleTx tipinde, transaction balatld servis, uygulama alan ve makine snrlarn aabilir.
Dolaysyla datk transaction' larn ynetimi srasnda kolayca ele alnabilir. Ancak bu protokol
intranet tabanl Windows sistemleri zerine tasarlanmtr. Bu sebepten firewall gibi sistemlere
taklma riski vardr. Ayrca Windows tabanl gelitirildiinden farkl tipteki platformlar tarafndan
desteklenmeyecektir. Bu nedenle OleTx tipi transaction protokol Windows
tabanl intranet sistemlerinde tercih edilmektedir.

WSAT (Web Service Atomic) tipinden transactionlar aynen OleTx' de oluduu gibi servis,
uygulama alan ve makine snrlarn aabilir. Dier taraftan WS-Atomic global bir standarttr.
zellikle web servislerinde yaygn olarak kullanlmaktadr. Bu nedele ak metin tabanl olarak
altnda farkl platformlar tarafndan kullanlabilir ve OleTx tipinde olduu gibi firewall engeline
taklmaz. Bu sebeten internet tabanl sistemlerdeki datk transaction' larn ynetiminde tercih
edilen bir protokoldr. Elbetteki intranet tabanl sistemlerede istenirse uygulanabilir.

Bildiiniz gibi Windows Communication Foundation ierisinde servisler ile istemciler arasndaki
iletiim salanrken pek ok ayarlamay bnyesinde barndran balayc tipler(Binding
Type) kullanlmaktadr. Balayc tipler iletiim protokol, gvenlik ayarlar dnda, transaction
protokollerininde kolay bir ekilde belirlenmesinde nemli grevler stlenir. Bunlarn bir
ksmnn OleTx yada WSAT transaction protokolleri iin destei bulunmamaktadr. Bir ksmnnda
hi bir transaction protokolne destei bulunmamaktadr. Aadaki tabloda var olan Windows

www.bsenyurt.com Page 1059


Communication Foundation balayc tiplerinin destekledii varsaylan transaction protokolleri yer
almaktadr.

Binding Tipi Transaction Protokol Destei


BasicHttpBinding Destek yok
WSHttpBinding WSAT
WSDualHttpBinding WSAT
WSFederationHttpBinding WSAT
NetTcpBinding OleTx
NetPeerTcpBinding Destek yok
NetNamedPipesBinding OleTx
NetMsmqBinding Destek yok
MsmqIntegrationBinding Destek yok

Burada dikkat edilmesi gereken konulardan


biriside NetTcpBinding, NetNamedPipesBinding iin varsaylan olan OleTx transaction
desteinin WSAT olarak da ayarlanabileceidir. Ancak intranet zerinde koan Windows tabanl bir
sistemde bu performas olumsuz etkileyecek bir deiiklik olabilir. Yinede istenirse, intranet
zerinde farkl platformlar sz konusu olduunda ilgili balayc tipler iin WSAT destei seilebilir.

Bilindii gibi Windows Communication Foundation uygulamalarnda kendi balayc


tiplerimizi (user defined binding type) yazabiliriz. Byle bir durumda hangi transaction
protokolnn kullanlaca tam olarak gelitiriciye baldr.

Artk balayc tipin ele alabilecei transaction protokolleri bilindiine gre geriye bir tek transaction
ynetimini stlenecek bir uygulama bulmak kalmaktadr. Bu tip bir uygulamay gelitirmek olduka
zor olduundan ounlukla nc parti programlar gz nne alnmaktadr. Windows
Communication Foundation dnldnde kullanlabilecek sz konusu yneticiler, LTM
(LightWeight Transaction Manager), KTM (Kernel Transaction Manager) ve DTC
(Distributed Transaction Cooridantor) tipleridir. Bu tiplerden KTM,Windows Vista ile birlikte
gelmektedir.

Sz konusu yneticiler arasnda bizi en ok ilgilendirenlerden ve aina olduklarmzdan birisi DTC'


dir. zellikle Ado.Net 2.0 ile birlikte gelen TransactionScope nesnesinin otomatik olarak DTC
zelliini aktifletirebildii ve datk transaction' larn daha kolay ynetilebilirliini salad gz
nne alndnda, servis ynelimli mimari model iin ne kadar anlaml olduu ak bir ekilde
ortadadr. Datk transaction koordinatr, hem OleTx hemde WSAT transaction protokollerini
destekler. Dolaysyla internet veya intranet tabanl sistemlerde yer alabilecek servis
uygulamalarnda transaction' larn servis snrlar darsna yaynlanabilmesine olanak salar.

DTC(Distributed Transaction Coordinator) transactionlarn oluturulup balatlmasndan, sre


ierisindeki dier uygulama alanlarnda(AppDomain) yer alan servislere ait ilem paralarnn var
olan transaction' a katlmasndan (enlist), kaynak yneticilerinden(Resoruce Managers) gelen
onay mesajlarnn (vote) toplanmasndan ve elbetteki tm ilemlerin onaylanmas(Commit) veya
geri alnmasndan(Rollback) sorumlu genel bir sistem servisi olarak gz nne alnabilir. Bu
adan bakldnda Windows Communication Foundation ile arasnda olduka sk bir iliki olmas
kanlmazdr. Konuyu daha iyi kavrayabilmek iin aadaki ekil gz nne alnabilir.

www.bsenyurt.com Page 1060


stemci uygulama, Makine A zerinde yer alan servisten bir ilem iin talepte bulunmaktadr.
Makine A zerinde yer alan servis bu senaryoda root olarak grev yapmaktadr. Buna gre
transaction' n balatlmasndan hatta sonlandrlmasndan (ister commit ister rollback) kendisi
sorumludur. Makine A' da yer alan servis ilemlerin geri kalan iin Makine B ve C zerinde yer alan
servisleride kullanmaktadr. Burada root servis kendi proxy nesnesi yardmyla B ve C servislerine
bir transaction ID deeri gnderir. Bu transaction ID sistem tarafndan retilen benzersiz ve tekrar
etmeyen bir deerdir. Bunu programlama ortamnda da kullanabildiimiz GUID (Global Unique
IDentifier) deeri olarak dnebiliriz. Sz konusu ID, B ve C servisleri tarafndan kendi
makinelerindeki DTC hizmetlerinede bildirilir. Bir baka deyile B ve C makinelerinde yaplmak
zere olan ilemlerin, transaction ID' si belirtilen srece ait olduklar bildirilir. Dolaysyla B ve C
servislerinin yrttkleri ilemler otomatik olarak, root servis tarafndan alan transaction' a dahil
edilmi olurlar.

Bu ilemlerin ardndan tahmin edilecei zere ift ynl geerli klma protokol(two phase
commit protocol) balar. Yani root servis, transaction' a dahil olmu dier servislerden oylarn
ister. Burada dier makinelerdeki DTC servisleri devreye girerek oylama(vote) sonularn root
DTC servisine iletirler. Eer herkes kabul ediyorsa, bir baka deyile transaction' a dahil olan tm
servisler yaptklar ilemlere onay vermise, root servis ikinci aamaya geer. Bu aamada da
transaction' a dahil olan servislere ilemleri onaylamalarna dair bilgi gider. Sonu olarak ilemler
onaylanr (Commit). Elbetteki dier makinelerdeki DTC' lerden gelecek tek bir iptal istei, tm
transaction' n iptal edilecei ve ilemlerin geri alnmas iin root DTC' den, bal olan servislere
bilgi gnderilecei anlamna da gelmektedir(Rollback). Burada dikkat edilmesi gereken
noktalardan biriside, ynetsel ilemleri stlenen Datk Transaction Koordinasyon(DTC) servisinin,
root makinede olmasdr. Bir baka deyile Servis Ynelimli Mimari (SOA) modelindeki tm DTC'
lerin oylarn kontrol edip, kabul edilmeleri veya iptal ilemlerini gerekletirebilecek tek bir DTC var
olabilir.

Windows Communication Foundation, transaction' lara otomatik olarak bir transaction yneticisi
(transaction manager) atar. Varsaylan olarak tek bana alan ve farkl makineler yada
srelerdeki(process) servislere transaction yaynlamayan sistemler sz konusu olduunda
otomatik olarak ilgili transaction' la LTM(LightWeight Transaction Manager) ilikilendirilir.
Ancak servis tarafndan balatlan transaction' n kendi uygulama alan snrlar dna kmas bir
baka deyile farkl makine veya srelere yaynlanmas halinde transaction yneticisinin seviyesi

www.bsenyurt.com Page 1061


otomatik olarak DTC(Distributed Transaction Coordinator) servisine devredilir. KTM gz nne
alndnda ok deiken kaynaklar (Volatile Resource) vardr. Yinede servis snrlar dna klmas
halinde DTC' ye terfi edilme sz konusudur.

Burada elbetteki kaynak yneticisinin(resource manager) bahsedilen yneticilerden hangisine


destek verdiide ok nemlidir. Kaynak yneticisi olarak SQL Server 2005, Oracle, MSMQ gibi pek
ok sistem gz nne alnabilir. SQL Server 2005 veritaban servisine ait kaynak yneticisinin u an
iin KTM(Kernel Transaction Manager) dnda LTM ve DTC' yi destekledii bilinmektedir.
Aslnda DTC deiken olabilecek her trde kaynak yneticisi tarafndan desteklenmektedir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde teorik olarak Windows
Communication Foundation ortamnda transaction ynetiminin temellerini incelemeye altk.
Grld gibi ynetimin arka tarafnda dikkate alnmas gereken pek ok etken bulunmaktadr.
Dahasda vardr. WCF ile ilgili bir sonraki makalemizde transaction ynetimini rnekler ile
incelemeye ve dier temelleride grmeye alacaz. Tekrardan grnceye dek hepinize mutlu
gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Istemci Tarafl Asenkron arma (Client


Side Asynchronous Invoking) ( 13.06.2007 ) -
WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation ile ilgili bir nceki makalemizde One Way tekniini
uygulayarak istemcilerin asenkron olarak uzak metodlar nasl arabileceklerini incelemitik. One
Way tekniinin elbetteki en byk dezavantaj geriye deer dndren metodlarn ele alnamaydr.
Oysaki ou zaman, ilem sresi uzun zaman alabilecek metodlarn geriye deer dndrd
vakkalarda asenkron eriim tekniklerini kullanmak gerekir. Ancak Windows Communication
Foundation gz nne alndnda asenkron altrma iki farkl ekilde ele alnabilmektedir.
Bunlarda birisi istemci tarafl asenkron arma (Client Side Asynchronous Invoking) modelidir.
Dieri ise servis tarafl asenkron uyarlama modelidir(Service Side Asynchronous
Implementation). Bu makalemizde istemci tarafl asenkron arma modelini incelemeye
alacaz.

stemci tarafl asenkron arma modelinde, proxy snfnn asenkron desene (Asynchronous
Pattern) uygun olacak ekilde Begin ve End ile balayan standart metodlar vardr. Bu metodlar
temelinde IAsyncResult arayzn ele almaktadr. stemci tarafl olarak alan bu modelin, doal
olarak farkl uygulanabilme eitleri vardr. .Net tarafnda asenkron mimarinin ele alnabilen tm
teknikleri Windows Communication Foundation iinde geerlidir. Burada bahsedilen
teknikler Polling, Callback ve WaitHandle modellerini iermektedir. WaitHandle modelininde
kendi ierisinde WaitOne, WaitAny, WaitAll gibi farkl kullanm ekilleri vardr. Bu modellerin
temel etkilerini ve farkllklarn yazacamz rnek kod paralar zerinde Windows Communication
Foundation asndan incelemeye alacaz. Ancak balamadan nce servis tarafl asenkron
uyarlama modelinide aklamakta fayda olaca kansndaym. Servis tarafnda gerekletirilen
asenkron uyarlama teknii istemcinin metodlar asenkron olarak iletmesi
anlamna gelmemektedir. Bir baka deyile istemci yine ard metodu senkronmu gibi ele alr
yani ilerleyebilmek iin metodun sonucunun gelmesini bekler. Metodun asenkron olarak alt yer
servis tarafdr. Aslnda servis tarafndaki ilgili srecin baka bir thread zerine ykld
dnlebilir. Ne varki bu model kodlanmas zor bir teknik iermektedir. Nitekim servis tarafnda

www.bsenyurt.com Page 1062


asenkron olarak ele alnmak istenen metodlarn asenkron tasarm desenine gre yazlmas
gerekmektedir. Az ncede belirttiimiz zere sz konusu modeli bir sonraki makalemizde
incelemeye alacaz.

Dilerseniz rneimize geerek ilemlerimize balayalm. Her zamanki gibi servis tarafnda
yaynlacak olan fonksiyonellikleri ieren tip ve szleme (contract) tanmlamalarn ieren bir WCF
Class Library projesi gelitirerek ie balanabilir. Sz konusu ktphane ierisindeki szleme
arayz (Interface) ve fonksiyonellikleri ieren snf(Class) aadaki gibidir.

IAdventureManager isimli arayz ierii aadaki gibidir.

[ServiceContract(Name="AdventureContract",Namespace=
"http://www.bsenyurt.com/2007/6/6/AdventureService")]
public interface IAdventureManager
{
[OperationContract(Name="AverageListPriceByCategory")]
double AverageListPrice(int subCatId);

[OperationContract(Name="TotalListPriceByCategory")]
double TotalListPrice(int subCatId);

[OperationContract(Name = "GetProductsCountByCategory")]
int ProductCount(int subCatId);
}

AdventureManager isimli snfn ierii aadaki gibidir.

public class AdventureManager:IAdventureManager


{
#region IAdventureManager Members

public double AverageListPrice(int subCatId)


{
Thread.Sleep(5000);
return 1000;

www.bsenyurt.com Page 1063


}
public double TotalListPrice(int subCatId)
{
Thread.Sleep(3000);
return 4500;
}
public int ProductCount(int subCatId)
{
Thread.Sleep(7000);
return 504;
}

#endregion
}

AdventureManager isimli snf ierisinde yer alan metodlarda bilinli olarak Thread snfnn
static Sleep fonksiyonundan faydalanlarak farkl srelerde duraksatmalar yaplmaktadr. Sz
konusu metodlardan sembolik olarak double ve int gibi tiplerden deerler dndrlmektedir.
Gelitirilen WCF snf ktphanesini kullanacak olan servis tarafn yine bir Windows uygulamas
olarak tasarlayabiliriz. (Windows
uygulamasnn System.ServiceModel.dll ve AdventureLib isimli WCF Snf ktphanelerini
referans etmesi gerektiini unutmayalm.)

Windows uygulamasnn form tasarm basit olarak aadaki gibidir;

Windows uygulamasna ait kodlar aadaki gibidir;

ServiceHost host;

private void btnStartService_Click(object sender, EventArgs e)


{
host = new ServiceHost(typeof(AdventureManager));
host.Open();
lblStatus.Text = host.State.ToString();
}

private void btnStopService_Click(object sender, EventArgs e)


{
host.Close();
lblStatus.Text = host.State.ToString();
}

www.bsenyurt.com Page 1064


Windows uygulamasna ait app.config dosyasnn ierii aadaki gibidir;

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


<configuration>
<system.serviceModel>
<services>
<service name="AdventureLib.AdventureManager">
<endpoint address= "net.tcp://localhost:9001/AdventureServices.svc"
binding="netTcpBinding" bindingConfiguration="" name="AdventureEndPoint"
contract="AdventureLib.IAdventureManager" />
</service>
</services>
</system.serviceModel>
</configuration>

Servis TcpBinding tipine gre gelitirilmitir. Bu


nedenle net.tcp://localhost:9001/AdventureServices.svc isimli rnek adres zerinden
sunulmaktadr. Sz konusu konfigurasyon dosyas her zamanki gibi Microsoft Service
Configuration Editor yardmyla Visual Studio 2005 ortamnda daha kolay bir ekilde yazlabilir.

Gelelim istemci tarafna. ncelikli olarak svcutil.exe aracn kullanarak AdventureLib isimli snf
ktphanesinden, istemci iin gerekli proxy snf ve konfigurasyon dosyasnn retilmesi
gerekmektedir. Burada daha nceki rneklerden farkl olarak asenkron desene uygun olacak
ekilde metod retimlerinin yaplmas gerekmektedir. Svcutil aracnn /async(veya ksaltmal
olarak /a) isimli parametresi bu ii otomatik olarak yapmaktadr. Bu nedenle svcutil aracnn
aadaki ekilde kullanmas gerekmektedir.

ncelikli olarak proxy retimi iin gerekli olan wsdl ve schema dosyalarnn retilmesi salamak
adna aadaki komut kullanlmaldr.

svcutil AdventureLib.dll

Sonrasnda ise svcutil arac aadaki haliyle altrlmaldr.

svcutil www.bsenyurt.com.2007.6.6.AdventureService.wsdl *.xsd /out:AdventureProxy.cs /async

www.bsenyurt.com Page 1065


Sonu olarak retilen AdventureProxy.cs isimli snfn ieriine aadaki ekran grntsnde
olduu gibi, Begin ve End ile balayan standart asenkron metodlar ilave edilmi olur. Dikkat
edilecek olursa AdventureManager snf ierisindeki tm metodlarn hem normal hemde Begin ve
End ile balayan versiyonlar ilave edilmitir.

Oluan bu snf ierisinden rnek olarak AverageListPriceByCategory isimli fonksiyon iin yazlm
asenkron metodlar gz nne alnabilir.

public System.IAsyncResult BeginAverageListPriceByCategory(int


subCatId, System.AsyncCallback callback, object asyncState)

www.bsenyurt.com Page 1066


{
return base.Channel.BeginAverageListPriceByCategory(subCatId, callback, asyncState);
}

public double EndAverageListPriceByCategory(System.IAsyncResult result)


{
return base.Channel.EndAverageListPriceByCategory(result);
}

Burada tipik olarak asenkron tasarm desenine uygun metodlar yer


almaktadr. BeginAverageListPriceByCategory metodu Polling, Callback ve WaitHandle mod
ellerine destek verecek ekildeIAsyncResult arayznn(Interface) tayabilecei bir referans
dndrr. Kullanlan modele gre, asenkron alan fonksiyonun sonularn almak
iinEndAverageListPriceByCategory metodu kullanlr. Dikkat edilecek olursa bu metod
parametre olarak IAsyncResult arayznden bir referans kabul eder ve geriye uygun olan metod
ktsn dndrr. Metod ierikleri asenkron deseni otomatik olarak uygulamaktadr. Bir baka
deyie nesne kullancs (object user) sz konusu modelin ierisindeki detaylar ile ilgilenmez.
Sadece uygun olan veya istedii asenkron modeli istemci programa uyarlar.

imdi tek tek istemci tarafndan asenkron arma modellerini uygulamaya alalm. stemci basit
bir Console uygulamas olarak ele alnmtr. Sz konusu uygulamann konfigurasyon dosyasnn
ierii aadaki gibi gelitirilebilir. (stemci uygulamannda System.ServiceModel.dll assembly'
n referans etmesi gerektiini unutmayalm.)

stemci uygulama tarafnda ele alnacak app.config ierii aadaki gibidir.

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


<configuration>
<system.serviceModel>
<bindings/>
<client>
<endpoint address=
"net.tcp://localhost:9001/AdventureServices.svc" binding="netTcpBinding"
bindingConfiguration="" contract="AdventureContract" name="AdventureClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

Balamadan nce senkron almann nasl bir etkisi olacan grmekte fayda vardr. Bu amala ilk
kodlar aadaki gibi gelitirilebilir.

Senkron alma durumu;

Console.WriteLine("Teste balamak iin bir tua basnz");


Console.ReadLine();
AdventureContractClient srv = new AdventureContractClient("AdventureClientEndPoint");

#region Senkron alma

DateTime baslangic = DateTime.Now;

double ortalamaFiyat=srv.AverageListPriceByCategory(1);

www.bsenyurt.com Page 1067


DateTime bitis = DateTime.Now;

Console.WriteLine(ortalamaFiyat.ToString("C2"));
TimeSpan fark = bitis - baslangic;
Console.WriteLine("Geen sre yaklak olarak {0} saniyedir.",fark.TotalSeconds.ToString());
Console.ReadLine();

#endregion

Burada dikkat edilecek olursa AverageListPriceByCategory metodu arldktan sonra istemci


uygulama bir sreliine beklemede kalacaktr. Bu TimeSpan ile elde edilen sre farkndan da
aka grlmektedir. Bir baka deyile istemci uygulamadaki kod ak ortalamaFiyat deerinin
elde edilmesini bekleyecek ve sonu alndktan sonra devam edecektir. Program kodu bu haliyle
altrldnda aadakine benzer bir ekran grnts elde edilir.

Bu tipik olarak senkron alma eklidir. Gelelim dier tekniklere. lk olarak WaitHandle modelini
ele alalm. Bu model temel olarak asenkron olarak altrlan metodlarn, uygulamann belirli bir
noktasnda sonular alnncaya kadar farkl ekillerde beklenilmesini salamaktadr. Dikkat
ederseniz metodlar yine asenkron olarak balatlr ama programn herhangibir noktasnda
sonularnn ortama dnmesi iin beklenir. Bu model daha ok asenkron alan metodlarn
sonularnn uygulamann belirli bir noktasnda girdi olarak kullanlmas gerektii durumlarda ie
yaramaktadr. Sz konusu modelin WaitOne, WaitAll ve WaitAny gibi farkl uygulan biimi
vardr. WaitOne teknii adndanda anlalaca zere sadece tek bir asenkron metodun sonucunun
alnmas iin bir duraksatma gerekletirir. Aadaki rnek kod parasnda WaitOne tekniinin
uygulan biimi yer almaktadr.

WaitOne teknii;

IAsyncResult iar=srv.BeginAverageListPriceByCategory(1, null, null);


Console.WriteLine("Baz ilemler yaplyor...");

iar.AsyncWaitHandle.WaitOne();

double sonuc=srv.EndAverageListPriceByCategory(iar);
Console.WriteLine(sonuc.ToString("C2"));

Console.ReadLine();

Uygulama bu haliyle altrldnda aadaki ekran grnts elde edilir.

www.bsenyurt.com Page 1068


Grld gibi BeginAverageListPriceByCategory arsndan sonra uygulama hemen alttaki
satrdan almaya devam etmitir. Buras tamamen sembolik bir kod paras ierir. ok doal
olarak burada farkl ilemler gerekletirilmesi veya istemci tarafnda yer alacak baka
fonksiyonelliklerin ele alnmas muhtemeldir. Sonrasnda ise iar
isimliIAsyncResult referansnn AsyncWaitHandle zellii ile yakalanan WaitHandle nesne
rneinin WaitOne metodu arlr. Bu metod, altrlan asenkron fonksiyonun sonucu alnana
kadar uygulamann duraksatlmasn salar. WaitOne satr alr almaz artk ilgili metodun
sonular uygulama ortamna derhal alnabilir. Bu nedenle EndAverageListPriceByCategory
metodunun arlmas ve parametre olarak iar isimli IAsyncResult arayznn verilmesi
yeterlidir.

Her zaman iin istemci tarafndan arlacak tek bir asenkron metod olmas sz konusu deildir.
Baz durumlarda birden fazla metod ars asenkron olarak yrtlmek istenebilir. ok doal
olarak bu metodlarnn tamamnn, yine uygulamann belirli bir noktasnda girdi olarak kullanlacak
dn deerleri olabilir. yleyse programn bu ilgili noktasnda asenkron olarak alan tm
metodlarn tamamnn duraksatlmas istenebilir. Bunun iin WaitAll teknii aadaki gibi kullanlr.

WaitAll teknii;

IAsyncResult iar1 = srv.BeginAverageListPriceByCategory(1, null, null);


IAsyncResult iar2 = srv.BeginGetProductsCountByCategory(2, null, null);
IAsyncResult iar3 = srv.BeginTotalListPriceByCategory(5, null, null);

WaitHandle[] handles = new WaitHandle[] { iar1.AsyncWaitHandle,


iar2.AsyncWaitHandle,iar3.AsyncWaitHandle };

Console.WriteLine("Baz ilemler yaplyor...");

WaitHandle.WaitAll(handles);

double sonuc1 = srv.EndAverageListPriceByCategory(iar1);


int sonuc2 = srv.EndGetProductsCountByCategory(iar2);
double sonuc3 = srv.EndTotalListPriceByCategory(iar3);

Console.WriteLine(sonuc1.ToString("C2"));
Console.WriteLine(sonuc2.ToString());
Console.WriteLine(sonuc3.ToString("C2"));

www.bsenyurt.com Page 1069


Console.ReadLine();

WaitAll tekniinde asenkron olarak altrlan metodlardan


sorumlu IAsyncResult referanslarndan elde edilen her bir WaitHandle rnei bir dizi ierisinde
toplanr. Sz konusu dizi WaitHandle snfnn static WaitAll metoduna devredildii satrda
uygulama tm asenkron metodlarn sonularnn gelmesi iin beklemede kalacaktr. ok doal
olarak bu arya kadar yaplan tm ilemler, asenkron metodlarnki ile paralel olarak
yrtlmektedir. Bu program kodlarnn alma zamannda retecei kt aadaki gibi olacaktr.

WaitAny modeli asenkron olarak alan metodlardan tamamlann ortama iade edebilme ilkesine
dayal olarak almaktadr. Sz gelimi rnek servisimizdeki metodlar gz nne alndnda teorik
olarak en ksa srede biten metodun sonucunun ortama alnabilmesi ve sonrasnda dierleri iin
beklennmesi gerekir. Metod sonular ortama dndke asenkron ileyiler tamamlanm olacaktr.

WaitAny modelini WCF ierisinde uyguladmzda alma


zamannda ObjectDisposedException istisnas (Exception) alnmaktadr. Bu istisnann
sebebi aratrldnda, makalenin yazld tarih itibariyle ok kstl bilgiye ulalmaktadr.
Bir zm Erwyn van der Meer tarafndan gelitirilmitir ve deerlendirilebilir. Buna gre
Dispose edilemeyen servis nesnesi iin ekstradan bir snf gelitirilmi ve bu snfn proxy
snf yerine kullanlmas nerilmitir.

stemci taraf iin asenkron arma tekniklerinden biriside Polling ' dir. Bu modelde temel olarak
asenkron olarak balatlan ilemin tamamlanp tamamlanmad kontrol edilir ve bu aralktaki tm
ilemler paralel olarak iletilir. Polling modelinde, asenkron ileyiin tamamlanmadn kontrol
etmek adna IAsyncResult arayznn IsCompleted isimli zelliinden yararlanlr.

Polling teknii;

IAsyncResult iar=srv.BeginTotalListPriceByCategory(4, null, null);

while (!iar.IsCompleted)
{
Console.WriteLine("lemler devam ediyor");
Thread.Sleep(1000);
}

www.bsenyurt.com Page 1070


double sonuc = srv.EndTotalListPriceByCategory(iar);

Console.WriteLine(sonuc.ToString());
Console.ReadLine();

Kodlar bu haliyle altrldnda aadaki ekran grnts elde edilir.

Buna gre while dngs ierisinde kodlar asenkron olarak yrtlen metoddan sonu alnncaya
kadar devam edecektir.

Asenkron eriim teknikleri arasnda en popler olanlarndan birisi Callback' tir. Bu teknikte
asenkron alan metodun ileyii tamamlandnda otomatik olarak bir geri bildirim fonksiyonu
devreye girer ve sonularn uygulama ortamna kolay bir ekilde alnabilmesi salanm olur.
Aadaki kod parasnda Callback modelinin uygulan biimi gsterilmektedir.

Callback Modeli;

class Program
{
static void Main(string[] args)
{
Console.WriteLine("Teste balamak iin bir tua basnz");
Console.ReadLine();
AdventureContractClient srv = new AdventureContractClient("AdventureClientEndPoint");

#region Callback Ornek

IAsyncResult iar = srv.BeginAverageListPriceByCategory(3, new


AsyncCallback(CallbackMetod), srv);

for (int i = 0; i < 10; i++)


{
Console.WriteLine("lemler devam ediyor");
Thread.Sleep(1000);
}

www.bsenyurt.com Page 1071


Console.ReadLine();

#endregion
}

static void CallbackMetod(IAsyncResult iar)


{
AdventureContractClient srv = (AdventureContractClient)iar.AsyncState;
double sonuc=srv.EndAverageListPriceByCategory(iar);
Console.WriteLine(sonuc.ToString());
}
}

Callback modelinde kritik olan nokta Begin... metodunun ald AsyncCallback tipindeki
parametredir. AsyncCallback .Net ierisinde yer alan bir temsilcidir (delegate). Bu temsilcinin
temel grevi ise alma zamannda otomatik olarak arlacak geri bildirim metodunu iaret
etmektir. Bir baka deyile asenkron olarak arlan metod ileyiini tamamlandnda bu
temsilcinin bildirdii metod devreye girecektir. Sonu itibariyle AsyncCallback bir temsilci
olduundan tanmnda iaret edecei metodun yapsda belirtilmektedir. Buna gre geriye deer
dndrmeyen ve IAsyncResult arayz tipinden referanslar alan metodlar iaret edilebilir.

Begin metdunun son parametresi object tipinden bir deer alr. Bu parametre ounlukla geri
bildirim metoduna referans tamak amacyla kullanlr. Sz gelimi yukardaki rnek kod
parasnda, End... metodunun arlabilmesi iin iar zerinden AsyncState ile elde edilen
referans AdventureContractClient snfna cast edilmektedir. Burada AsyncState zelliinin
Begin... arsnda kullanlan srv isimli referans olmasn salamak amacyla son parametreye srv
rnei verilmitir. Uygulama altnda paralel olarak yryen istemci kodlar devam ederken
aynen aadaki ekran grntsnde olduu gibi arada bir yerde, tamamlanan asenkron metodun
sonucu otomatik olarak ortama alnabilmektedir.

Callback modelinde istenirse C# 2.0 ile birlikte gelen isimsiz metodlardan (Anonymous
Methods) da yararlanlabilir. Bu sayede ekstradan Callback metodu yazlmasna gerek kalmamakta
ve temsilcinin baland yerde geri bildirim kodlar ele alnabilmektedir. rnein aadaki kod
parasnda bu ilemin nasl yaplaca gsterilmektedir.

Callback modelinde isimsiz metod kullanm;

www.bsenyurt.com Page 1072


AsyncCallback async = delegate(IAsyncResult ar)
{
double sonuc = srv.EndAverageListPriceByCategory(ar);
Console.WriteLine(sonuc.ToString());
};
IAsyncResult iar = srv.BeginAverageListPriceByCategory(3, async, null);

for (int i = 0; i < 10; i++)


{
Console.WriteLine("lemler devam ediyor");
Thread.Sleep(1000);
}

Console.ReadLine();

Bu seferki modelde ekstradan static(Console uygulamasndaki static Main metodundan armamz


nedeni ile byle tanmlanmak zorundadr) olacak ekilde bir geri bildirim metodu yazlmasna gerek
kalmamtr. Bununla birlikte, Begin metodunun son paramertresi ile bir object referans
tanmasna gerekte yoktur. Bu kod paras altrldnda da benzer sonular alnacaktr.

Bu makalemizde WCF iin istemci tarafl asenkron arma modelini incelemeye altk. Temel
olarak kullanabileceimiz modelden bahsettik. Bu modeller ile ilgili olarak ksaca aadaki zet
bilgileri syleyebiliriz.

Polling modelinde asenkron arlar sonucu alan metodlarn tamamlanp


tamamlanmad srekli olarak kontrol edilir. Bu amala IsCompleted zellii ele alnabilir.
Bu kontrol aralndaki tm ilemler ilgili asenkron arlar ile paralel olarak yrmektedir.
Callback modelinde asenkron olarak yaplan arlar ile alan metodlarn sonular elde
edildiinde, otomatik olarak bir geri bildirim metodu alr. Dolaysyla asenkron yryen
metodlarn tamamlanp tamamlanmadklarnn srekli olarak kontrol edilmesine gerek
yoktur.
WaitHandle modeli 3 farkl ekilde uygulanabilmekte olup asenkron olarak alan
metodlarn uygulamann belirli bir noktasnda girdi olarak kullanlabilecek deerlerinin
alnmas iin bekleme yaplmasn salamaktadr. Bu bekleme tek bir metod iin WaitOne,
tm metodlar iin WaitAll ve srayla bitenleri ortama alma ilkesine
dayanaraktanWaitAny fonksiyonlar ile yaplmaktadr.

Bylece geldik bir makalemizin daha sonuna. Yazmzn bandada belirttiimiz gibi bir sonraki
Windows Communication Foundation makalemizde servis tarafnda asenkron uyarlamann (Service
Side Asynchronous Implementation) nasl yaplabileceini incelemeye alacaz. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

C# Temelleri - Olaylar(Events) Kavramak (


06.06.2007 ) - C# 2.0
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1073


Olaylar (Events), grsel uygulamalar ile uraan her gelitirici tarafndan bilinli veya bilinsiz bir
ekilde kullanlmaktadr. Nesne ynelimli programlama ortamnda olaylar tanmlamak iin klasik
olarak verilen bir rnek vardr. Hepinizin bir sonraki cmlede ne diyeceimi bildiinizden eminim.
Sz konusu rnekte grsel ortamda yer alan bir dme kontrol (ounlukla Button snfna ait bir
nesne rnei) ve bu dmeye kullancnn mouse ile basmas sonucu oluan Click isimli bir olay
mevcuttur. Oysaki olaylarn her zaman iin grsel ortamda olmas ve iletim sistemi tarafndan
alglanacak bir etkileime karlk olarak uygulama ortamna frlatlmas art deildir. Dolaysyla
olaylar kavrayabilmenin en gzel yolu, gelitirici tarafndan yazlan tiplere zel olarak nasl
yazlacan ve kullanlacan bilmekle mmkn olabilir. te bu makalemizde kendi tiplerimiz iin
zel olaylar nasl yazabileceimizi incelemeye balayacak ve olaylar daha derinlemesine
kavramaya alacaz.

ncelikli olarak dme kontrol rneinden syrlp farkl vakkalar dnerek ilerlemeye alalm.
rnek olarak stoktaki rn bilgilerini ieren basit bir snf gz nne alnabilir. rnlerin stoktaki
deerlerininde bu tip ierisinde bir zellik yardmyla sarmalanm(wrap) olduunu dnebiliriz.
Buna gre stok miktarnn belirli bir deerin altna dmesi sonrasnda baka nesne rnekleri
tarafndan ele alnabilecek bir olay tanmlamas yaplabilir. Burada Urun tipi ierisinde tanmlanan
ve bu tipe ait nesne rneklerinin ele alabilecei bir olay sz konusudur.

Baka bir rnek daha. Herhangibir bir kargo irketinin ulatrma filosundaki aralarn programatik
ortamda birer nesne ile ifade edilebildii bir ktphane(library) olduunu dnelim. Bu ktphane
ierisindeki fonksiyonelliklerden biriside, aralarn uydu sistemleri yardmyla dzenli olarak
izlenmesi ve gncel koordinat, anlk hz gibi bilgilerinin elde edilmesi olarak gz nne alnabilir. Bu
hizmeti salayan kodlar ayr bir ktphane olacak ekilde gelitirilmi olarak ticari bir paket halinde
sunulabilir. O halde aralarn belirlenen hz limitlerini amalar sonrasnda oluacak durumlarn sz
konusu ktphaneyi kullanan uygulamalar tarafndan, istenirse ele alnmalarn salamak amacyla
olaylar yazlabilir. Bylece sz konusu program, ara hz limitini at zaman neler yapmak
istiyorsa bunlar istedii ekilde ele alabilecektir.

Temel olarak kendi tiplerimiz iin olay tanmlamak aslnda temsilcileri (delegates) daha kolay
kapsllenmi bir halde sunmak eklinde de yorumlanabilir. Bir olayn(event) tanmlanabilmesi iin
mutlaka bir temsilci tipi ile eletirilmesi gerekmektedir.

Temsilciler(delegates) ok kanall programlamada (multi


threading), asenkron(asynchronous) mimarilerde(Polling, Callback, WaitHandle
gibi) ve son olarak olay tabanl(event based) kodlamada kullanlmaktadr.

Temsilci dnda dikkat edilmesi gereken bir dier noktada olayn bir ekilde ortama frlatlmasn
salamaktr. Dme rneini burada gz nne alabiliriz. Dikkat ederseniz bir dmeye
basldnda gerekletirilmek istenenleri yazmak iin tek yaplan oluan olay metodunun ieriini
doldurmaktan ibarettir. Sistem arka tarafta sz konusu Button nesne rnei iin bir olay yklemsi
yapmaktadr. Peki dmeye basldnda sz konusu olay metodu nasl arlacaktr? (Burada
temsilcinin rolnn ne kadar nemli olduu ortadadr.) Olayn tetiklenmesi iletim sistemi
tarafndan gerekletirilir. Aslnda Button nesne rneinin arka planda yaptklarndan biriside,
iletim sistemindeki bu aksiyonu yakalamaktr. Sonu itibariyle kullancnn sz konusu Button
nesne rneine ykleme yapt olay metodu arlr. Bu anlatlanlar bize unu ifade etmelidir.
Kendi olaylarmz tanmlyorsak, sz konusu olayn dier nesneler tarafndan ele alnabilmesini
salamak iin manuel olarak tetiklemeliyiz. Manuel olarak yaplan bu tetiklemenin sonucunda
alma zamannda ele alnacak olay metodunun iaret edilmesini
ise, temsilciler(delegates) yardmyla salamalyz.

Kendi tiplerimiz iin olay tanmlyorsak bu olayn alma zamannda dier bir nesne
tarafndan ele alnabilmesi iin bir ekilde tetiklenmesi gerekmektedir.

www.bsenyurt.com Page 1074


Aslnda bir olayn tetiklenmesi, bir istisna(exception) nesne rneinin ortama
frlatlmasna(throw) benzetilebilir. Tek fark ortama frlatlan istisnalarn catch bloklar ile
yakalanabiliyor olmasdr. Olaylarda durum farkldr. Ortada bir catch blou yoktur. Bunun yerine
bir abone (subscriber) vardr. Basit olarak olayn tetiklenmesi sonucu altrlacak olay
metodunun bulunduu nesne rneini abone olarak dnebiliriz. Bir baka deyile olay yakalayp
deerlendirecek olan nesne, olayn sahibi olan nesnenin ilgili olayna(event) abone olmaktadr.
Dolaysyla olay tanmlayan ve tetikleyen nesneyi yaymc (publisher) olarakda gz nne
alabiliriz. Aslnda bahsettiimiz kavramlar daha kolay anlayabilmek amacyla aadaki grafii
incelemekte fayda vardr.

Birinci adma gre Program nesnesi Urun tipine ait bir nesne rnei oluturur. Program nesne
rneinden kast aslnda uygulamann ta kendisi olabilir. rnein bir konsol uygulamasndaki
Program snf veya windows uygulamasndaki bir Form nesne rnei olabilir. Hangisi olursa olsun
deimez gerek olaya abone olmak isteyen bir nesnenin olmasdr. Olay tanmlamamzn Urun tipi
ierisinde olduu varsaylrsa, Program nesnesinin ilgili olay metodunu Urun nesnesine abone
etmesi gerekmektedir. Bu ikinci admda sembolize edilmeye allmaktadr.

Nesne kullancs (Object User), Program nesnesi ierisinde olay yklemesi ile birlikte bir olay
metodunuda yazar. Bylece Urun nesnesinin nc admda yapaca tetikleme sonucunda
Program nesnesi tarafndan yazlan olay metodu arlabilecektir. Burada sz konusu olan abone
etme ilemi aslnda Urun snfna ait olayn(event) +=operatr yardmyla Program nesne rnei
ierisinde yklenmesidir. Olaylar tanmlanrken hep bir temsilci(delegate) tipi yardmyla
oluturulurlar. Dolaysyla Program snf ierisinde Urun nesnesi iin ilgili olay += operatr ile
yklendiinde, temsilciye(delegate) parametre olarak verilen metod referans Urun nesnesine
bildirilir. Bylece Urun nesne rnei ierisinde ilgili olay tetiklendiinde hangi metodun arlaca
bilinmektedir.

www.bsenyurt.com Page 1075


Bu kadar teorik bilgiyle aslnda, olaylarn gerek anlamda sadece button ve click kelimelerinden
ibaret olmadn gstermeye altk. Artk birazda pratik yaparak bahsedilenleri rneklemekte
fayda olaca kansndaym. Bu amala basit bir console uygulamasn gz nne alacaz. Konsol
uygulamamz ierisinde yer alan Program snfmzabonemiz(subscriber) olacak. Urun snf
ierisinde tanmlayacamz olay(Event), stoktaki rn says 10 deerinin altna dtnde
tetiklenecek ekilde tasarlanacaktr. Bir olay tanmlanrken mutlaka bir temsilcinin olmas
gerektiinden bahsetmitik. Dolaysyla birde temsilci (delegate) tipi gelitirmemiz gerekecektir.
Sz konusu temsilci tipini ve Urun snfn aadaki gibi tasarlayabiliriz. (rneklerimizde sadece
olay kavramna younlamak istediimizden, yaplmas gereken pek ok kontrol ortadan
kaldrlmtr. rnein rn adnn bo geilmesini, StokMiktari veya BirimFiyat zelliklerine sfrn
altnda deer atanmasn engellemek gibi. Daha pek ok kontrol ve fonksiyonellik dnlebilir
elbette. Siz kendi uygulamalarnzda bu noktalar sakn gzden karmayn ve mutlaka uygulayn.)

using System;

namespace Olaylar
{
delegate void StokAzaldiEventHandler();

class Urun
{
private int id;
private string ad;
private double birimFiyat;
private int stokMiktari;

public event StokAzaldiEventHandler StokAzaldi;

public int StokMiktari


{

www.bsenyurt.com Page 1076


get { return stokMiktari; }
set {
stokMiktari = value;
if (value < 10
&& StokAzaldi != null)
StokAzaldi();
}
}

public double BirimFiyat


{
get { return birimFiyat; }
set { birimFiyat = value; }
}

public string Ad
{
get { return ad; }
set { ad = value; }
}

public int Id
{
get { return id; }
set { id = value; }
}

public Urun(int idsi, string adi, double fiyati, int stokSayisi)


{
Id = idsi;
Ad = adi;
BirimFiyat = fiyati;
StokMiktari = stokSayisi;
}
}
}

imdi kodlarmzda neler yaptmza ksaca bakalm. lk olarak StokAzaldiHandler tipinden


bir temsilci (delegate) tanmlyoruz. Hatrlayacanz gibi zaman zaman .Net ierisinde var olan
isimlendirme standartlarndan bahsediyoruz. Niteliklere ait snf adlarnn Attribute kelimesi
ile, istisna(exception) tiplerinin Exception kelimesi ile bittiklerini biliyoruz. zellikle olaylar ile
ilikili temsilcilerinde ounlukla EventHandler kelimesi ile bittiini grrz. Bu nedenle olay ile
ilikili temsilcimizi StokAzaldiEventHandler olarak isimlendirdik. StokAzaldiEventHandler isimli
temsilci tipi, geriye deer dndrmeyen ve parametre almayan metodlar iaret edebilecek ekilde
tasarlanmtr.

Temsilcilerin (delegate) alma zamannda metodlarn balang adreslerini iaret


ettiklerini ve iaret edebilecei metodun parametrik yaps ile geri dn tipini
belirtiklerini hatrlayalm.

Gelelim Urun snfmza. Urun snf ierisinde UrunAzaldi isimli bir olay(event) tanmlanmtr.

public event StokAzaldiEventHandler StokAzaldi;

www.bsenyurt.com Page 1077


Dikkat edilecek olursa event anahtar kelimesinden sonra StokAzaldiEventHandler isimli temsilci
tipi gelmektedir. Son olarakta olayn ad yer alr. Bylece sz konusu olay iin altrlabilecek olay
metodlarnn yapsn StokAzaldiEventHandler isimli temsilcinin syleyeceide belirtilmi olur.
Geriye kalan tek prz, ilgili olay metodun nasl ve nerede tetikleneceidir. rnek olmas
asndan StokMiktari isimli zelliin set blounda aadaki kod paras kullanlmtr.

set {
stokMiktari = value;
if (value < 10
&& StokAzaldi != null)
StokAzaldi();
}

Burada stok miktar eer 10 rakamnn altndaysa ve StokAzaldi olay null deere eit deilse
StokAzaldi() isimli bir metod ars yaplmaktadr. StokAzaldi olaynn nullolmamas bir
ekilde += operatr ile yklendii anlamna gelmektedir. Yani baka bir nesne bu olaya
kendisini abone(subscribe to) etmitir. Bu durumda sz konusu olay metodunun buradaki set
blou ierisinden arlmas gerekir. Bu i iin yine olay sanki bir metodmu gibi armak yeterli
olacaktr. Nitekim bu ar += operatr ile balanan olay metodunun yrtlmeye balanmas
anlamnada gelmektedir. Buraya kadar += operatr ile olayn yklenmesi gerektiinden bahsedip
durduk. Peki bu nasl gerekletiriliyor? Cevap aadaki kod parasnda olduu gibidir.

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Olaylar
{
class Program
{
static void Main(string[] args)
{
Urun ciklet = new Urun(10001, "Tipitipitip", 1.20, 35);
ciklet.StokAzaldi += new StokAzaldiEventHandler(ciklet_StokAzaldi);

for (int i = 0; i <5; i++)


{
ciklet.StokMiktari -= 7;
Thread.Sleep(600);
Console.WriteLine(ciklet.Ad + " iin stok miktar " + ciklet.StokMiktari.ToString());
}
}

static void ciklet_StokAzaldi()


{
Console.WriteLine("Stok miktar 10 deerinin altnda...Alarrrmmm!");
}
}
}

Main metodu ierisinde Urun snfna ait bir nesne rneklendikten sonra StokAzaldi isimli
olay, += operatr ile yklenmektedir. Burada Visual Studio kullanlyorsa += iaretinden sonra iki
kez tab tuuna basmak yeterli olacaktr. Bu durumda Visual Studio otomatik olarak bir olay
metodu oluturacaktr. rneimizde bu olay metodu ciklet_StokAzaldi adyla anlmaktadr.

www.bsenyurt.com Page 1078


Aslnda bir olay tanmlandnda, bu olayn sahibi olan tip iin CIL (Common
Intermediate Language) ksmnada add_OlayAd ve remove_OlayAd isimli iki metod
eklenir. Bu metodlar ierisinde olay yklemesi yapldnda veya kartldnda, gereken
temsilci balama ve ayrma ilemleri yaplmaktadr.

Program kodu ierisinde test amacyla StokMiktari zelliinin deeri 7er 7er azaltlmaktadr.
Sonuta ekran kts aadaki gibi olacaktr.

www.bsenyurt.com Page 1079


Dikkat edilecek olursa StokMiktari zelliinin 10 deerinin altnda olduu her durum iin otomatik
olarak olay metodu tetiklenmi ve ierisinde yazlan kod paralar altrlmtr.

Yazlan olay her ne kadar faydal grnsede baz eksiklikleri olduu ortadadr. rnein olay metodu
ierisinde bir de stoun o anki miktarnn ne olduunu renebilsek fena olmaz myd acaba? Yada
birden fazla Urun nesne rneini ayn olay metoduna balayacaksak (ki bu mmkndr), olay
metodu ierisinde hangi Urun nesne rneinin ilgili olayn sahibi olduunu tespit edebilsek fena
olmaz myd? te bu iki gereksinime benzer ihtiyalar, .Net ierisinde var olan tm olaylar iinde
geerlidir. O nedenle nceden tanmlanm olan tm olaylar aslnda standart olarak iki parametre
almaktadr. lk parametre olay tetikleyen nesne rneine ait referansn yakalanmas iin
kullanlrken, ikinci parametre olay metodu ierisine bilgi aktarmak maksadyla ele alnr. Bu
standart bir olay temsilcisinin iaret edecei metodun parametrik yapsdr. Tahmin edilecei gibi ilk
parametre object tipindendir. kinci parametre ise genellikle EventArgs gibi kelimeler ile biten zel
bir snftr. Kendi rneimizi gz nne aldmzda ncelikli olarak, olay metoduna zel bilgilerin
aktarlmasn salayacak ekilde bir tipin gelitirilmesi gerekmektedir.

class StokAzaldiEventArgs:EventArgs
{
private int guncelStokMiktari;

public int GuncelStokMiktari


{
get { return guncelStokMiktari; }
set { guncelStokMiktari = value; }
}
public StokAzaldiEventArgs(int gStk)
{
GuncelStokMiktari = gStk;
}
}

www.bsenyurt.com Page 1080


StokAzaldiEventArgs isimli tipin tek yapt, gncel stok miktarn ilgili olay metodu ierisine
tamaktr. Bu tip asl StokAzaldi olay iin anlamldr. Olay argmanlarn tayacak kendi tiplerimizi
gelitirdiimizde bunlarn EventArgs tipinden tretilmesi bir zorunluluk deildir ancak bir
gelenektir. Ama aynen isimlendirme kurallarnda olduu gibi kodun standardize edilmesidir.
Nitekim .Net ierisindeki tm olay argman tipleri, bir ekilde EventArgs snfndan tremektedir.
Bu ekilde olay metoduna bilgi tayabileceimiz bir tip tanmladktan sonra temsilcininde aadaki
gibi deitirilmesi gerekmektedir.

delegate void StokAzaldiEventHandler(object sender,StokAzaldiEventArgs args);

Elbette temsilcide yaplan deiikliklerin olayn tetiklendii yerede adapte edilmesi gerekmektedir.
Bu amala StokMiktari zelliinin set blou aadaki gibi deitirilmelidir.

public int StokMiktari


{
get { return stokMiktari; }
set {
stokMiktari = value;
if (value < 10
&& StokAzaldi != null)
StokAzaldi(this, new StokAzaldiEventArgs(value));
}
}

Dikkat edilecek olursa ilk parametreye this anahtar kelimesi getirilmitir. Hatrlayacanz gibi ilk
parametre iin, olay tetikleyen nesne referansn tadn belirtmitik. te buradaki this anahtar
kelimesi alma zamanndaki(run-time) nesne referansnn alnp ilgili olay metoduna
gnderilmesini salamaktadr. kinci parametrede iseStokAzaldiEventArgs tipinden bir nesne
rnei oluturulmakta ve gncel stok miktarnn deeri value anahtar kelimesi ile yapc metoduna
gnderilmektedir. Tahmin edeceiniz zere nesne rneide, olay metodu ierisinde ele
alnabilecektir. Artk program ierisinde kodlarmzda aadaki gibi dzenlememiz gerekmektedir.

class Program
{
static void Main(string[] args)
{
Urun ciklet = new Urun(10001, "Tipitipitip", 1.20, 35);
ciklet.StokAzaldi += new StokAzaldiEventHandler(ciklet_StokAzaldi);

for (int i = 0; i <5; i++)


{
ciklet.StokMiktari -= 7;
Thread.Sleep(600);
Console.WriteLine(ciklet.Ad + " iin stok miktar " + ciklet.StokMiktari.ToString());
}
}

static void ciklet_StokAzaldi(object sender, StokAzaldiEventArgs args)


{
Console.WriteLine("Gncel stok deeri {0} . Stokta limit altna inilmitir.
Alarrmmmm!",args.GuncelStokMiktari.ToString());
}
}

www.bsenyurt.com Page 1081


Uygulamay bu haliyle altrdmzda aadaki ekran grntsnde yer alan sonular elde
ederiz.

Gelelim olaylar ile ilgili bir baka konuya. Daha ncede birden fazla nesne iin ayn olay metodunun
ele alnabileceinden bahsetmitik. rneimizi gz nne aldmzda, birden fazla Urun nesnesini
ayn StokAzaldi olay metoduna ynlendirme ansna sahibiz. Bu ekilde bir ihtiya zellikle dinamik
olarak oluturulan kontrollerin bir olay metoduna balanarak ele alnmas gibi durumlarda
kullanlmaktadr. Ki bylece bir den fazla olay metodunu dnmek yerine tek bir merkez
metoddan kontrol ve ynetim ilemlerini gerekletirebiliriz. rneimizdeki kod paralarn
aadaki gibi deitirelim.

class Program
{
static void Main(string[] args)
{
Urun ciklet = new Urun(10001, "Tipitipitip", 1.20, 35);
Urun cikolata = new Urun(10034, "Marsi", 2.5, 25);
cikolata.StokAzaldi+=new StokAzaldiEventHandler(urun_StokAzaldi);
ciklet.StokAzaldi += new StokAzaldiEventHandler(urun_StokAzaldi);

for (int i = 0; i <5; i++)


{
ciklet.StokMiktari -= 7;
cikolata.StokMiktari -= 5;
Thread.Sleep(600);
Console.WriteLine(ciklet.Ad + " iin stok miktar " + ciklet.StokMiktari.ToString());
Console.WriteLine(cikolata.Ad + " iin stok miktar " +
cikolata.StokMiktari.ToString());
}
}

static void urun_StokAzaldi(object sender, StokAzaldiEventArgs args)


{
Urun urn = (Urun)sender;
Console.WriteLine("{0} iin gncel stok deeri {1} . Stokta limit altna inilmitir.
Alarrmmmm!",urn.Ad,args.GuncelStokMiktari.ToString());
}
}

www.bsenyurt.com Page 1082


lk olarak ciklet ve cikolata isimli iki ayr Urun nesnesi rneklediimize ama bunlarn her ikisi iinde
ayn olay metodunu kullandmza dikkat edelim.

cikolata.StokAzaldi+=new StokAzaldiEventHandler(urun_StokAzaldi);
ciklet.StokAzaldi += new StokAzaldiEventHandler(urun_StokAzaldi);

Dikkat edilmesi gereken nemli noktalardan biriside olay metodu ierisinde sender isimli
parametre deikeninin nasl kullanlddr. sender isimli deiken cast ilemine tabi tutularak bir
Urun nesne rneine dntrlmekte ve kullanlmaktadr. Burada elbetteki akla u soru gelebilir.
Urun nesne rneine dntrme ilemi yapldktan sonra gncel stok miktar gibi verilerde elde
edebilir bu nedenle StokAzaldiEventArgs gibi tipleri gelitirmeye ihtiyacmz var mdr? Aslnda bu
bir anlamda doru olsada bir argman tipinin var olmas, olay metodu ierisine gerektende ne
aktarmak istediimizi belirten bir kodlama yolu ve standard salamaktadr. Dier taraftan gereksiz
cast ilemlerininde nne geilmi olacaktr. Bunlarn dnda nesne rnei zerinden elde
edilemeyen ancak argmanlar yardmyla ele alnabilecek baz verilerin yaync nesne(publisher
object)ierisinden sadece olay metoduna aktarlmasda salanabilir. Bir gereke daha vardrki o da
biraz sonra generic bir temsilci ile karmza kacaktr.

C# 2.0 ile gelen yeniliklerden biriside isimsiz metodlardr (anonymous methods). Bu kavram
zellikle temsilcilerin ierisinde rol aldg kodlama alanlarnda kullanlmaktadr. Dolaysyla olay
metodlarnda isimsiz olarak tanmlama ve gelitirme ansna sahibiz. Yani yukardaki kodlarmz
aadaki gibi gelitirebiliriz.

static void Main(string[] args)


{
Urun ciklet = new Urun(10001, "Tipitipitip", 1.20, 35);
ciklet.StokAzaldi += delegate(object sender, StokAzaldiEventArgs arg)
{
Urun urn = (Urun)sender;
Console.WriteLine("{0} iin gncel stok deeri {1} . Stokta limit
altndayz. Alarrmmmm!", urn.Ad, arg.GuncelStokMiktari.ToString());
};

for (int i = 0; i <5; i++)


{
ciklet.StokMiktari -= 7;
Thread.Sleep(600);
Console.WriteLine(ciklet.Ad + " iin stok miktar " + ciklet.StokMiktari.ToString());
}
}

www.bsenyurt.com Page 1083


Program altrdmzda yine olay metodunun baarl bir ekilde iletildiini grebiliriz. Burada
dikkat edilecek olursa StokAzaldi olay(event) yklenirken isimsiz metod(anonymous
method) kullanlmtr. delegate anahtar kelimesi otomatik
olarak StokAzaldiEventHandler temsilcisine(delegate) brnmektedir. Sonrasnda gelen kod
blou ierisinde ise olay metodunda yaplmas gerekenler yer almaktadr. Ortada bir olay metodu
ad olmadna dikkat edelim. Buda zaten neden isimsiz metod denildiini aklamaktadr.

C# 2.0 ile birlikte gelen zelliklerden birisi ve belkide en nemliside generic mimaridir. Bildiiniz
gibi generic mimari sayesinde tr bamsz tipler gelitirebilme ansna sahibiz. .Net ierisinde var
olan pek ok tipin bu ekilde tr bamsz versiyonlar gelitirilmi ve tip gvenli ile performans gibi
konularda daha gl tipler ortaya kmtr. Olaylarla ilikili olaraktan, EventHandler isimli
standart temsilci(delegate) tipinin generic bir versiyonu vardr. Sz konusu temsilcinin prototipi
aadaki gibidir.

[SerializableAttribute]
public delegate void EventHandler<TEventArgs> (Object sender,TEventArgs e) where
TEventArgs : EventArgs

Buna gre kendi olaylarmz iin ayrca temsilci yazmaya gerek kalmamaktadr. Dikkat edilecek
olursa TEventArgs isimli generic trn
yazlan kstlama(constraint) sayesindeEventArgs tipinden tremi bir tip olmas
beklenmektedir. Buna gre Urun tipi ierisindeki olay tanmlamasn aadaki gibi deitirebiliriz.

public event EventHandler<StokAzaldiEventArgs> StokAzaldi;

EventHandler<TEventArgs> temsilcisi ilk parametre olarak object tipinden bir deiken


almaktadr. kinci parametre ise EventArgs snfndan tremi bir tiptir. Bizim rneimizde sz
konusu tip StokAzaldiEventArgs snfdr. (Sanrm kendi olay argman tiplerimizi EventArgs
snfndan tretmenin bir faydasn daha grm oluyoruz.) Sonu olarak uygulamann almas
deimeyecektir. Kazancmz ekstradan temsilciler tasarlanmasna gerek kalmaydr. Tabi isimsiz
bir metod kullanmyorsak olayn ykleni eklinide aadaki gibi deitirmemiz gerekecektir.

ciklet.StokAzaldi += new EventHandler<StokAzaldiEventArgs>(urun_StokAzaldi);

Olaylar ile ilgili olarak bilmemiz gereken bir dier noktada; += ile yklenen olaylarn -= ile
kaldrlabildii ve her iki durumunda add ve remove isimli bloklar ierisinde kontrol altna
alnabildiidir. Bu konunun incelemesinide siz deerli okurlarma brakyorum. Bylece geldik bir
makalemizin daha sonuna. Bu makalemizde event kavramn daha detayl bir ekilde incelemeye
altk ve kendi olaylarmz nasl yazabileceimizi grdk. Temel olarak ilediklerimizi aadaki
maddeler ile zetleyebiliriz.

Olaylar temsilcilerin(delegates) zelletirilmi bir hali olarak dnlebilir.


Bir olay tanmlandnda mutlaka bir temsilci tipi ile eletirilir. Nitekim olay meydana
geldiinde arlacak metodun, birisi tarafndan alma zamannda(runtime)iaret
ediliyor olmas gerekir ki bunu temsilciler yapabilir.

www.bsenyurt.com Page 1084


Kendi olaylarmz gelitirirken isimlendirme standard asndan
temsilcilerimizi EventHandler, olay argmanlarn tayacak
snflarmz EventArgs kelimeleri ile bitirmekte fayda vardr.
Olayn tanml olduu nesne tarafndan tetiklenmesi sonrasnda yakalanabilmesi iin, sz
konusu nesneyi kullanan dier nesnenin(subscriber) olaya abone olmas gerekmektedir.
Birden fazla nesne olayn ayn olay metoduna balayabiliriz.
Olay metodlarn iaret edecek temsilciler, ilk parametre olarak olay meydana getiren nesne
referansn tayan object bir deiken, ikinci parametre olarakta olay metoduna bilgi
tayacak bir snf rneini alan metodlar iaret edecek biimde tasarlanrlar.
Olay metodlarn yazmak zorunlu deildir. Bunun yerine isimsiz metodlarda(anonymous
methods) kullanlabilir.
stenirse kendi olaylarmz iin temsilci yazmak
yerine EventHandler<TEventArgs> generic tipi kullanlabilir.
Olaylara argman tayacak tiplerimizi hem kod standard hemde
EventHandler<TEventArgs> destei iin EventArgs snfndan tretmekte fayda vardr.
Olaylarn += operatr ile yklenmesi ve -= operatr ile kaldrlmas durumlarn kontrol
altna almak iin add ve remove bloklarndan faydalanlabilir.

Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - One Way Ticket ( 31.05.2007 ) - WCF


Deerli Okurlarm Merhabalar,

One Way Ticket...One Way Ticket... Bu szleri duyduumda aklma bu arky yapan eruption ve
cover versiyonunu syleyip efsaneleen Boney M gruplar gelir. Ancak One Way ikilisi ne
tesadftrki .Net Remoting mimarisinde de karmza kmaktadr. Ksaca tek yn olarak
evirebileceimiz bu iki kelime aslnda frlat ve unut(fire and forget) anlamndada dnlebilir.
Yada bir baka deyile istemci tarafndan olaya bakldnda, "metodu ardm gerisi umrumda
deil" de denebilir. Ayn kelimelerin Windows Communication Foundation ierisinde de yer
almas elbetteki artc deildir. Nitekim One Way operasyonlar aslnda asenkron istemci-sunucu
modelininde nemli bir parasdr.

Normal artlarda Windows Communication Foundation istemcileri servisten bir talepte


bulunduklarnda, proxy tarafndan hazrlanan mesaj sunucuya gnderilir. Servis gelen mesaj alr,
zmler ve gereken yrtme ilemlerini gerekletirir. Burada sz konusu yrtmeye dahil olan
metodlarn altrlmasnn sonucunda istemciye bu ilemin tamamland bilgisi eer geri dn
deeri var ise onunla birlikte dner. Bu, talep/cevap mesajlama deseni (request/response
messaging pattern) olarak adlandrlan klasik alma modelidir. Ancak burada istemcinin arda
bulunduu metodun tamamlann beklemesi gerekir. Aksi takdirde ilerlemesi sz konusu deildir.
Burada bahsi geen konu kod satrnda bir alt ifadeye geilememesidir. ok doal olarak servis
tarafndaki metodun almasnn uzun srd durumlarda istemci uygulama beklemede olacaktr.

zellikle istemci tarafndaki uygulamalarn arda bulunduklar metodlar geriye deer


dndrmyorlarsa asenkron programlama (asynchronous programmin) adna One
Waytekniinden yararlanlabilir. One Way teknii uygulanmas kolay olmasna ramen dikkat
edilmesi gereken noktalara sahiptir. te bu makalemizde sz konusu noktalara deinerek One Way
tekniinin WCF asndan detaylarn grmeye alacaz.

www.bsenyurt.com Page 1085


stemci programlarn uzak metod armlarnda uygulamalar duraksatmasn engellemek
adna kullanlabilecek tek yol One Way deildir. Dier Asenkron eriim modelleride ele
alnabilir. Bunlar ilerleyen makalelerimizde ele alnacaktr. One Way ve dier asenkron
modellerinde istemci ve sunucu uygulamalarn ayn zaman diliminde alyor olmalar
gerekir. Bunun aksi bir durumda ise Message Queue sisteminin kullanlmasnda fayda
vardr.

One Way formasyonuna uygun bir arm iin OperationContract niteliinin IsOneWay zelliine
true deerini aktarmak yeterlidir. OneWay metodlar ile ilikili bilinmesi gereken ncelikli kurallar
vardr. Hereyden nce OneWay olarak iaretlenenen metodlar geri dn deerine sahip olmazlar.
Bir baka deyile bu metodlar void olarak tanmlanrlar. Burada metoda parametre
olarak ref veya out tipinden aktarmlar yaplmak istenebilir ancak buda mmkn deildir. Dier
taraftan sz konusu metodlar ierisinde ok doal olarak istisnalar(Exceptions) olabilir. Burada sz
konusu olan SOAP hata mesajlar (SOAP Fault Message) istemci tarafna gnderilmez. Bu
sebeplerden tr istemci servis zerindeki metodun baarl bir ekilde tamamlanp
tamamlanmadn asla bilemez.

Ancak en azndan istemcinin gnderdii metod ars mesajnn servise ulap ulamadnn
bilinmesinde yarar vardr. Eer servis uygulamas almyorsa ok doal olarak istemci bir istisna
alacaktr ki bu durumda istemciden gnderilen talebin ulamad zaten dorudan anlalabilir.
Ancak baz iletiim protokollerinde (rneinTcp) gelen mesajlar tampona alnrarak ilenirler. Arka
arkaya gelen bu taleplere ait mesajlarn toplu olarak bir maksimum says vardr. Sonuta birden
fazla istemci sz konusudur ve bunlarn gnderecekleri saysz ar bulunmaktadr. Byle bir
durumda eer servis tarafnda kabul edilebilen maksimum talep says alrsa gelen yeni talepler
var olan yarm kalmlar tamamlanncaya kadar beklemeye alnr. Dolaysyla istemci uygulama her
ne kadar OneWay ars yapsada beklemede kalr. Bu durumla baedebilmek iin gvenilir
oturumlar (Reliable Session) almasnda fayda vardr. Gvenilir oturumlar sayesinde servis, bir
ar aldnda gelen mesaj ilemeye baladna dair istemciye bilgi gnderebilir.

One Way teknii istemci iin nem arz eden SendTimeout srelerini nemsemez. Normal
artlarda istemciler bir metod arsnda bulunduklarnda varsaylan olarak 1 dakikalk bir timeout
sreleri vardr. Eer bu sre ierisinde servisten bir cevap gelmesse otomatik
olarak TimeoutException tipinden bir alma zaman hatas alnr. One way operasyonlarnda ok
doal olarak bu tip bir sre kontrol nemli deildir. Nitekim istemci taraf arda bulunduu
metod iin bir cevap beklememektedir. Ama varsaylan olarak baz aksilikler olacaktr ki ilerleyen
ksmlarda buna deinmeye alacaz.

imdi rnek bir uygulama zerinden ilerleyerek One Way tekniini nasl ele alabileceimizi
inclemeye alacak ve dikkat edilmesi gereken durumlar analiz edeceiz. Bu makalemizdeki
rneimizde, file-based olarak web zerinde barndrlan bir servis uygulamas yer alacaktr.
stemciyi olaylar kolay bir ekilde takip edebilmek adna bir konsol uygulamas olarak
tasarlayabiliriz. Burada dier makalelerimizden farkl olarak wsHttpBinding balayc tipini ele
alacaz. Bu tip aslnda BasicHttpBinding balayc tipine benzerdir ancak gvenilir
oturumlara (reliable sessions) sahip, transcation ynetimine izin veren Http ve Https iletiim
protokollerinin kullanlabildii, WS-Adressing ilemlerin yaplabildii bir ortam sunarak ekstra
imkanlar salar. Gelitirilecek servis uygulamas iin WCF Service ablonu kullanlabilir. Bu amala
ilk olarak Visual Studio 2005 ile aadaki gibi bir servis uygulamas aarak ie balanmaldr. WCF
Service uygulamas file-based olarak host edileceinden ve istemcilerin tek bir adresten ilgili
servise erimeleri istendiinden projenin Properties penceresindeki zelliklerden port numaras
sabit bir deere ayarlanabilir. Bu ilem iin ncelikle Dynamic Ports zelliine false deer atamak
gerekir.

www.bsenyurt.com Page 1086


Servisimiz iin gerekli tiplerimizi ise aadaki gibi gelitirebiliriz. Sz konusu
tipler App_Code klasr ierisinde yer almaktadr.

IRaporUretici Arayz erii;

[ServiceContract(Name = "RaporlamaServisi", Namespace =


"http://www.bsenyurt.com/RaporlamaServisi/2007/30/05")]
public interface IRaporUretici
{
[OperationContract(IsOneWay = true)]
void RaporUret(string kullaniciAdi);
[OperationContract(IsOneWay = true)]
void SatisYapildi(int productId);
}

RaporUretici snf ierii;

public class RaporUretici


: IRaporUretici
{
#region IRaporUretici Members

public void RaporUret(string kullaniciAdi)


{
Thread.Sleep(65000); // 1 dakika 5 saniye duraksatma

www.bsenyurt.com Page 1087


FileStream fs = new FileStream("C:\\Izleme.txt", FileMode.Append, FileAccess.Write);
StreamWriter writer = new StreamWriter(fs);
writer.WriteLine(kullaniciAdi + " N RAPOR RETME EMR VERLD");
writer.Close();
fs.Close();
}

public void SatisYapildi(int productId)


{
Thread.Sleep(65000); // 1 dakika 5 saniye duraksatma
FileStream fs = new FileStream("C:\\Izleme.txt", FileMode.Append, FileAccess.Write);
StreamWriter writer = new StreamWriter(fs);
writer.WriteLine(productId + " RN N SATI YAPILDI");
writer.Close();
fs.Close();
}

#endregion
}

Arayz tanmlamas ierisinde dikkat edilecek


olursa OperationContract niteliinin IsOneWay zelliine true deeri atanmtr. Servis
szlemesini uygulayan snf ierisinde sembolik olarak iki metod yer almaktadr. zellikle bu
metodlarn ierisinde Thread snfnn static Sleep metodu yardmyla uygulama 65 saniye
duraksatlmaktadr. Burada 1 dakikalk TimeOut snrnn almasnn douraca baz sonular
olacaktr. Bu sonular ilerleyen ksmlarda ele alnacaktr. Servis tarafnda yer alan web.config
dosyasnn ierii aadaki gibi tasarlanabilir.

web.config ierii;

<?xml version="1.0"?>
<configuration>
<system.serviceModel>
<services>
<service behaviorConfiguration="RaporlamaServisiBehavior"
name="RaporlamaServisi.RaporUretici">
<endpoint address="http://localhost:2215/RaporlamaServisi/Service.svc" bind
ing="wsHttpBinding" bindingConfiguration="" name="RaporlamaServisiEndPoint"
contract="RaporlamaServisi.IRaporUretici" />
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="RaporlamaServisiBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
<system.web>
<compilation debug="true"/>
</system.web>
</configuration>

www.bsenyurt.com Page 1088


Servis web tabanl olarak host edildiinden svc uzantl bir dosyannda var olmas gerekmektedir.
Bu dosyann ieriinde servis szlemesini uygulayan snfn ad ve fiziki dosya ad aadaki gibi
yer alr.

Service.svc;

<% @ServiceHost Language=C#


Debug="true" Service="RaporlamaServisi.RaporUretici" CodeBehind="~/App_Code/Servi
ce.cs" %>

Servis ile ilgili ilemlere gemeden nce altndan emin olmakta fayda vardr. Servis baarl bir
ekilde hazrlanmsa aadaki ekran grntsnn elde edilmesi gerekir.

Artk istemci iin gerekli kodlar yazlp testlere balanabilir. ncelikli olarak istemci uygulamalar iin
gerekli proxy tipinin retilmesi gerekir. Bunun iin komut satrnda (Visual Studio 2005 Command
Prompt) svcutil.exe arac kullanlabilir yada Visual Studio 2005 ortamnda konsol
uygulamasnda Add Service Reference seenei ile aadaki ekran grntsnde olduu gibi
eklenebilir.

Bu ilemin ardndan istemci uygulamasna ait proje ierisinde gerekli proxy tipi
ve App.config konfigurasyon dosyas retilmi olacaktr.

www.bsenyurt.com Page 1089


stemci uygulamaya ait kodlar aadaki gibi gelitirilebilir.

using System;
using System.Text;
using System.ServiceModel;
using System.Collections.Generic;
using Istemci.localhost;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
try
{
RaporlamaServisiClient srv = new
RaporlamaServisiClient("RaporlamaServisiEndPoint");
Console.WriteLine("Rapor retimini balat..." + DateTime.Now.ToString());
srv.RaporUret("Mayk");
Console.WriteLine("Rapor retimi balatld..." + DateTime.Now.ToString());
Console.WriteLine("rn sat yapld bilgisini gnder..." + DateTime.Now.ToString());
srv.SatisYapildi(1001);
Console.WriteLine("rn sat yapld bilgisi gnderildi..." + DateTime.Now.ToString());

srv.Close();
}
catch (Exception hata)
{
Console.WriteLine(hata.Message);
}
}
}
}

RaporlamaServisiClient nesnesi rneklendikten sonra RaporUret ve SatisYapildi isimli metodlar


arlmaktadr. Bu metodlar iaret eden servis szlemesinde OneWay olduklar belirtilmitir.
Buna gre istemci uygulamann, bu metodlar ierisindeki 65 saniyelik srelerden etkilenmeden
dier kod satrlarn iletmesi gerekmektedir. Bakalm gerekten byle mi olacak?

www.bsenyurt.com Page 1090


Testleri yapabilmek iin hem sunucu uygulamann hemde istemci uygulamann ayn zaman
diliminde alyor olmalar gerekmektedir. Dolaysyla Solution zelliklerinde Multiple Startup
Projects seilmeli ve nce servis uygulamas ardndan istemci uygulama alacak ekilde
ayarlanmaldr.

Bu aamadan sonra uygulama altrlrsa ilk etapta aadaki gibi bir ekran grnts ile
karlalr.

Grld gibi RaporUret ars kolayca alm ancak, SatisYapildi arsndan sonra istemci
uygulama ekran duraksamtr. Oysaki ikinci metodda OneWayolarak arlmaktadr. Dolaysyla
aynen ilk metod arsnda olduu gibi buradada istemci uygulamann dier kod satrlarndan
ilemlerine devam etmesi beklenir. Ne varki byle olmamtr. Sonu olarak bir sre bekledikten
sonra aadaki ekranda grlen hata mesaj ile karlalr.

Peki sorun nedir? stemci uygulama neden alma zamamnda bir istisna alarak sonlanmtr?
Hatta yeterli sre beklenildiinde sunucu tarafnda Izleme.txt dosyasnn ieriine bakldnda
metod ieriklerinin altda gzlemlenebilir.

www.bsenyurt.com Page 1091


Ne varki istemci asndan baz sorunlar olduu ortadadr. Problemin nedeni
oturumlardr (Sessions). Ayn oturum ierisinde gelen arka arkaya iki ar sz konusudur. Bu
arlar doal olarak ayn andalk ilkesine (Concurrency) gre deerlendirilir. Dolaysyla ikinci
ardan sonra istemci uygulama, ilk ar sonucunun tamamlanmasn beklemek durumunda
kalmtr. Bu sebepten servisin zellikle ayn oturum ierisinden gelecek e zamanl metod
arlarna cevap verebilecek ekilde zelletirilmesi gerekir. Burada elebetteki Session moddan
vazgeilmesi tercih edilebilir. rnein PerCall mode seilebilir. Ancak
oturumlarn (Sessions) kullanm amalar gz nne alndnda bir zm yolu bulunmasnda
fayda vardr. Yaplmas gereken servis szlemesini uygulayan RaporUretici
snfna, ServiceBehavior niteliini uygulamak ve ConcurrencyModezelliine Multiple deerini
aadaki gibi vermektir.

namespace RaporlamaServisi
{
[ServiceBehavior(ConcurrencyMode= ConcurrencyMode.Multiple)]
public class RaporUretici
: IRaporUretici
{

Uygulamamz bu haliyle test ettiimizde ise aadaki ekran grnts ile karlarz.

Herey ilk etapta yolunda gibidir. Nitekim SatisYapildi metod ars sonrasndaki kodlarda
almtr. Ancak uygulama kapanrken yine bir hata mesaj alnmtr. Bu hata mesajnn retildii
nokta istemci tarafnda servis iin Close metodunun arld yerdir. Bu arya gelindiinde
istemci uygulama uzun bir sre beklemede kalmtr. Sonrasnda ise bir istisna mesaj frlatarak
sonlanmtr. Bunun sebebi kullanlan WsHttpBinding tipinin
zellikleridir. WsHttpBinding oturumlar kullanan ve varsaylan olarak mesaj seviyesinde
gvenlik (Message-Level Security) kullanan bir balayc (Binding) tipidir. stemci Close
metodunu ardnda servis tarafnda kendisi iin alan oturumu(Session) kapatmak ister. Buna
karlk servis ilgili oturuma ait ilemlerin bitmesini bekler ve tamamlandklarndan emin olduktan
sonra bunu istemciye bir mesaj ile bildirir. rnekte ok doal olarak servis tarafndaki ilemler 1
dakika snrn atndan, sz konusu mesaj istemciye iletilemez. Buda doal olarak istemci
tarafnda bir istisna mesaj frlamasna neden olur. zm olarak gvenlik ile ilgili ayarlar
kapatlabilir ki bu nerilen bir yntem deildir. Dier bir yntem ise iletiim seviyesinde
gvenlik (transport levet security) kullanmaktr. Ancak bu yntemde sertifika kullanlmas
gerekir nitekim Https politikas sz konusudur.

Ancak mesaj seviyesinde yaplabilecek bir seenek daha vardr. Buda gvenilir bir
oturum (Reliable Session) amaktr. Nitekim bu sayede istemcinin yapt arlar sonucu
servisten bir bilgi beklenmesine gerek kalmayacaktr. Bunun iin servis tarafnda ve istemci
tarafnda wsHttpBinding tipi iin konfigurasyon ayarlar yaplmal
ve ReliableSession iinEnabled zelliklerine true deeri atanmaldr. Aadaki ekran
grntsnde servis taraf iin ilgili deiikliklerin Microsoft Service Configuration
Editor yardmyla nasl yapld gsterilmektedir.

www.bsenyurt.com Page 1092


Bu deiiklikler sonucu servis taraf iin konfigurasyon dosyasnn ierii aadaki gibi olur.

Benzer deiikliklerin istemci taraf iinde yaplmas gerekir. Bunun sonucu olarak istemci
tarafndaki konfigurasyon dosyasndada aadaki deiiklikler olacaktr.

www.bsenyurt.com Page 1093


Artk uygulammz bu haliyle test edebiliriz. Aada uygulamann son halinin test sonularna ait
ekran grnts yer almaktadr.

Sonu itibariyle basit bir One Way Ticket arksndan olduka farkl noktalara geldik. Bu ana kadar
grdklerimizden aadaki sonular kartabiliriz.

OneWay teknii ile Windows Communication Foundation uygulamalarnda asenkron


armlar gerekletirilebilir ve performans art salanr. nk istemci uygulama, servis
tarafndaki metod sonularn beklemeden yoluna devam eder.
Gnvenilir oturumlara (Reliable Sessions) izin verilmesi halinde istemci
tarafnda Close metodu uygulandnda servis ile olan balant(Connection), servisten
cevap beklenmeden sonlandrlabilir.

www.bsenyurt.com Page 1094


zellikle oturum(Session) kullanld durumlarda servis zerinde ayn oturuma ait arka
arkaya metod armlarnda, istemci uygulamann duraksamasn engellemek
adna ConcurrencyMode zelliinin deeri Multiple olarak set edilebilir.
ConcurrencyMode zelliinin Multiple olarak belirlenmesi halinde servisin
gerektende thread-safe olup olmadna dikkat edilmelidir. Nitekim Multiple deeri ile,
servis tarafndaki uygulama Multi-Thread hale gelmektedir.

Bu makalemizde asenkron programlama eitlerinden birisi olan One Way metod arm tekniini
incelemeye altk. Asenkron programlamaya ilikin baka rnekleri ilerleyen makalelerimizde
incelemeye alacaz. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - InstanceContextMode ( 24.05.2007 ) -


WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation uygulamalarnda istemciler bavurduklar servisler zerindeki


nesne rneklerini kullanrlar. zellikle kullanlan balaycnn (binding) tipine gre servis zerindeki
nesne rneklerinin farkl ekillerde oluturulup ele alnmas sz konusudur. .Net Remoting ile
uygulama yazan gelitiriciler, istemcilerin talepte bulunaca uzak nesne rneklerinin farkl
modellerde rneklendiklerini bilirler. Burada bahsi geen modeller Server Activated
Object iin Singleton ve SingleCall ile Client Activated Object' dir. rnein CAO modeline gre
istemciler, uzak nesneyi rneklediklerinde sunucu zerinde bir referans oluturulur ve istemciler
bunu kullanr. Singleton ve SingleCall modelleri metod arlar sonucu referans oluturulmasn
salar. Ama Singleton modelinde her istemci iin(dolaysyla her metod ars iin) ayn nesne
rnei, SingleCall' da ise her metod ars iin ayr bir nesne rnei sunucu zerinde
oluturulmaktadr.

Benzer durumlar WCF servislerindeki nesne rnekleri iinde geerlidir. stemci uygulama ile servis
rnei arasndaki ilikiyi kontrol altna alabilmek
iin ServiceBehavior niteliininInstanceContextMode zelliinden yararlanlr.
InstanceContextMode zellii InstanceContextMode enum sabiti tipinden bir deer almaktadr ve
alabilecei deerler PerSession,PerCall ve Single' dr. Bu modlardan hangisinin aktif olduu
zellikle WCF uygulamalarnda oturum ynetimi (Session Management) asndan da
nemlidir.

Varsaylan olarak her istemci iin sunucuda bir adet nesne rnei oluturulur. Servis rnei
istemciden gelen ilk operasyon arsnda (yani ilk metod arsnda) oluur. stemci sunucu ile
olan balantsn kesene kadarda servis rnei sunucuda kalmaya devam eder. Ancak binlerce
kullancnn servise baland durumlarda da her istemci iin bir servis rneinin sunucuda
oluturulmas ve ne zaman kalkacaklarnn istemcinin hareketine bal olmas sunucu belleinin
gereksiz yere iirilmesi anlamna gelir. Dolaysla dier modeller gz nne alnabilir.

Binding Tipine gre Instance Mode trlerinden hangisinin uygulanabilecei deiir.


rnein BasicHttpBinding, Http protokolnn doas gerei iletiim seviyesinde
(transport level) PerSession mode trn desteklemez. Bir baka

www.bsenyurt.com Page 1095


deyile InstanceContectMode hangi deeri alrsa alsn varsaylan olarak PerCall modda
alr. Buda gelecek her istemci operasyon ars iin servis tarafnda bir nesne
rneinin oluturulmas ve operasyon tamamlandnda kaldrlmak zere Garbage
Collector' e devredilmesi anlamna gelir.

lk olarak PerSession, PerCall ve Single modellerinin nasl altklarn teorik olarak bilmekte fayda
vardr.

PerSession Modeli;

PerSession modunda istemciler ilk operasyon arsnda bulunduklarnda servis rnei oluturulur
ve istemci Close metodunu kullanana kadar yada uygulamay kapatana kadar sz konusu rnek
sunucuda kalr. stemci, bir servis rneini elde ettikten sonra bu rnek sadece ilgili istemciye ait
olacak ekilde tahsis edilir. Bir anlamda o istemci iin bir oturum(Session)alm olur. Farkl
istemcilerin ayn oturumu kullanmalar mmkn deildir. stemci uygulamalarda ok kanall
(multithread) kod paralar olabilecei dnldnde ezamanl olarak ayn oturuma ait metod
arlar sz konusu olabilir. Varsaylan olarak bir talep tamamlanmadan baka bir talep gelirse
ncekinin tamamlanmas beklenmektedir. Ama istenirse bu davran
biimide ServiceBehavior niteliinin ConcurrencyMode zellii ile deitirilebilir. Yani istenirse
e zamanl olarak arlara cevap verilmesi de salanabilir.

Bu mod kullanlrken, istemci tarafndan altrlabilecek operasyonlar iin bir sralama belirtilmek
istenebilir. rnein hangi metod ars ile servis rneinin oluturulacann belirtilmesi veya hangi
metod arsndan sonra servis rneinin yok edileceinin belirtilmesi gibi. Bunun iin
de OperationContract niteliinin IsInitiating veIsTerminating zellikleri kullanlr. IsInitiating
zelliine true deeri atandnda, ilgili metoda bir ar geldii zaman servis nesnesi
rneklenecektir. Elbetteki ayn metoda oturum sresince yeni bir ar gelebilir. Bu durumda yeni
bir servis rnei oluturulmaz. Eer false deeri verilirse sz konusu metoda yaplan ar
sonrasnda servise ait bir rnek oluturulmaz. IsTerminating zelliine true deeri atand
takdirde, ilgili metoda dair sz konusu operasyon tamamlandnda servis rnei otomatik olarak
yok edilir. Yani istemcinin Close metodunu armasna gerek kalmaz.

PerCall Modeli;

PerCall modunda, istemcinin yapt her operasyon arsnda servis uygulamasnn alt sistem
zerinde bir nesne rnei oluturulur ve operasyon tamamlandnda(bir baka deyile metod
ars sonlandnda) bu rnek yok edilir. Bu sebepten oturum ynetimi PerSession moduna gre
daha zordur. Bu nedenle oturum ynetimi adna istemcinin kendisini her operasyon arsnda
servise tantabilmesini salayacak bir sistem gerekebilir. Ne varki sunucu kaynaklarnn idareli
kullanlmas adna verimli bir modeldir.

Single Modeli;

Single modunda, servis rnei yine istemci tarafndan gelecek ilk operasyon arsnda oluturulur.
Ne var ki PerSession modelinden farkl olarak var olan istemcinin ve dier istemci uygulamalarn
metod arlar iin servis uygulamas zerindeki ayn nesne rnei kullanlr. Sz konusu servis
rneinin yok edilmesi ise sadece host uygulamann kapatlmas ile gerekleebilir. Bu teknik
kaynak ynetimi adna maksimum fayday salar. Ayrca tm kullanclarn ayn veriyi paylamas
ok daha kolaylar. Lakin burada servisin single thread olup olmadna dikkat etmek gerekir.
Eer yleyse istemcilerden gelecek talepler sonras zaman amlar (timeout) sz konusu
olabilir. Bunun iinConcurrencyMode zelliine Multiple deeri atanarak thread-safe bir ortam
salanabilir.

imdi rnek bir uygulama zerinden bu modelleri incelemeye alalm. rnek uygulamada Tcp
protokol baz alnmaktadr ve bu nedenle NetTcpBinding balayc tipi kullanlmaktadr.

www.bsenyurt.com Page 1096


Tcp protokol iin varsaylan olarak e zamanl balant says maksimum 10 dur. Ancak
istenirse binding configuration ksmndan MaxConfiguration zellii ile bu deitirilebilir.

lk olarak WCF Library ablonunda bir snf ktphanesi gelitirelim. Bu snf ktphanesi ierisinde
yer alan tipler ve ierikleri aadaki gibidir.

Servis szlemesini tanmlayan IUrunYonetici interface(arayz) kodlar aadaki gibidir;

using System;
using System.ServiceModel;

namespace UrunYonetimKutuphanesi
{
[ServiceContract(Name="UrunYonetimServisi",
Namespace="http://www.bsenyurt.com/UrunYonetimServisi")]
public interface IUrunYonetici
{
[OperationContract()]
void SepeteUrunEkle(string urunId);
[OperationContract()]
void SepettenUrunCikar(string urunId);
[OperationContract()]
void SiparisVer();

www.bsenyurt.com Page 1097


}
}

Arayz uygulayan UrunYonetici snfnn kodlar aadaki gibidir;

using System;
using System.IO;
using System.Text;
using System.Threading;
using System.ServiceModel;

namespace UrunYonetimKutuphanesi
{
[ServiceBehavior()]
public class UrunYonetici:IUrunYonetici,IDisposable
{
private FileStream fStr;
private StreamWriter writer;
private StringBuilder builder;

public UrunYonetici()
{
Thread.Sleep(500);
builder = new StringBuilder();
builder.AppendLine(DateTime.Now.ToLongTimeString() + ": UrunYonetici nesnesi
oluturuldu.");
}
#region IUrunYonetici Members

public void SepeteUrunEkle(string urunId)


{
Thread.Sleep(500);
builder.AppendLine(DateTime.Now.ToLongTimeString() + ": Urun ekle metodu arld.");
}

public void SepettenUrunCikar(string urunId)


{
Thread.Sleep(500);
builder.AppendLine(DateTime.Now.ToLongTimeString() + ": Urun kart metodu
arld.");
}

public void SiparisVer()


{
Thread.Sleep(500);
builder.AppendLine(DateTime.Now.ToLongTimeString() + ": Sipari ver metodu
arld.");
}

#endregion

#region IDisposable Members

public void Dispose()


{
Thread.Sleep(500);

www.bsenyurt.com Page 1098


builder.AppendLine(DateTime.Now.ToLongTimeString() + ": UrunYonetici nesnesi iin
Dispose metodu altrld.");
builder.AppendLine("");
fStr = new FileStream("Izleyici.txt", FileMode.Append, FileAccess.Write);
writer = new StreamWriter(fStr);
writer.Write(builder.ToString());
writer.Close();
fStr.Close();
}

#endregion
}
}

UrunYonetici snf ierisinde bir alveri sepetine rn ekleme, rn karma veya sipari verme
gibi rnek fonksiyonellikler vardr. zellikle nesneye ait rneklerin ne zaman oluturulduunu
incelemek adna FileStream, StreamWriter ve StringBuilder tiplerinden yararlanlmakta
ve Izleyici.txt isimli dosyaya log bilgileri aktarlmaktadr. Burada dikkat edilmesi gereken
noktalardan biriside snfa IDisposable arayznn uygulanm olmasdr. Bunun tek
sebebi Garbaga Collector' un nesneyi dispose etmeden nce log dosyasna gereken bilgileri
aktarmaktr. ServiceBehavior niteliinde zel olarak InstanceContextMode deeri verilmemitir.
Nitekim varsaylan deeri PerSession' dr. imdi rnek sunucu ve istemci uygulamalarn
gelitirerek devam edelim. Servis uygulamas bir windows uygulamasdr ve aadaki kodlardan
olumaktadr. (Servis uygulamasnnSystem.ServiceModel ve UrunYonetimKutuphanesi assembly'
larn referans etmesi gerektiini hatrlayalm.)

Servis tarafndaki windows formu;

Servis tarafndaki kodlar;

namespace ServerApp
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

ServiceHost host;

private void btnBaslat_Click(object sender, EventArgs e)

www.bsenyurt.com Page 1099


{
host = new ServiceHost(typeof(UrunYonetici));
host.Open();
lstDurum.Items.Add(DateTime.Now.ToLongTimeString() + host.State);
}

private void btnBitir_Click(object sender, EventArgs e)


{
host.Close();
lstDurum.Items.Add(DateTime.Now.ToLongTimeString() + host.State);
}
}
}

Host uygulamada servisi altrmak iin Open, kapatmak iinse Close metodlar kullanlmaktadr.
Bununla birlikte servis uygulamas UrunYonetici tipini hizmete sunar. Balant iin gereken tm
konfigurasyon ayarlar aada kts grlen App.config dosyasndan elde edilmektedir.

Servis taraf iin App.config ierii;

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


<configuration>
<system.serviceModel>
<behaviors />
<services>
<service behaviorConfiguration="" name="UrunYonetimKutuphanesi.UrunYonetici">
<endpoint address="net.tcp://localhost:4560/UrunYonetim.svc"
binding="netTcpBinding" bindingConfiguration="" name="UrunYonetimServiceEndPoint"
contract="UrunYonetimKutuphanesi.IUrunYonetici" />
</service>
</services>
</system.serviceModel>
</configuration>

Batada belirtildii gibi Http yerine Tcp iletiim protokoln kullanan bir sistem ele alnmaktadr. Bu
nedenle NetTcpBinding balayc tipi kullanlmaktadr.

stemci taraf basit bir Console uygulamas olarak dnlebilir. stemci tarafnda, uzak nesnenin
kullanlabilmesi iin fiziki proxy snfnnda retilmi olmas gerekir. Bu amala
yine svcutil.exe arac kullanlmaktadr. Servis Http zerinden metadata
publishing yapmadndan, nce ktphane zerinden gerekli wsdl ve schema dosyalar elde
edilmeli ve sonrasnda bu bilgilerden faydalanarak gereken proxy snf oluturulmaldr.

nce komut satrndan UrunYonetimKutuphanesi.dll bulunur ve

\> svcutil UrunYonetimKutuphanesi.dll

altrlr. Ardndan

\>svcutil www.bsenyurt.com.UrunYonetimServisi.wsdl *.xsd /out:UrunYonetimClient.cs

komutlar altrlmal ve retilen UrunYonetimClient.cs ve output.config dosyalar istemci


uygulamaya dahil edilmelidir. Output.config dosyasn App.config adyla kaydetmekte yarar vardr.

www.bsenyurt.com Page 1100


Nitekim istemci uygulama konfigurasyon ayalar iin bu dosyay arayacaktr. stemci uygulama
konfigurasyon dosyas aadaki ekilde daha ksa olarak modifiye edilebilir.

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


<configuration>
<system.serviceModel>
<client>
<endpoint address="net.tcp://localhost:4560/UrunYonetim.svc" binding="netTcpBinding"
bindingConfiguration="" contract="UrunYonetimServisi"
name="DefaultBinding_UrunYonetimServisi_UrunYonetimServisi" />
</client>
</system.serviceModel>
</configuration>

stemci uygulama kodlar aadaki gibidir;

using System;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
UrunYonetimServisiClient srv = new
UrunYonetimServisiClient("DefaultBinding_UrunYonetimServisi_UrunYonetimServisi");
srv.SepeteUrunEkle("1000");
srv.SepeteUrunEkle("1004");
srv.SepettenUrunCikar("1000");
srv.SiparisVer();
Console.WriteLine("Uygulamadan kmak iin Bir Tua Basn");
Console.ReadLine();
}
}
}

stemci uygulamada nesne rnei oluturulduktan sonra bir dizi metod arm
gerekletirilmektedir. imdi uygulamay bu haliyele test edelim. ncelikli olarak servis uygulamas
altrlmal ve Balat dmesine baslarak servis almaldr. Sonrasnda istemci uygulamadan bir
ka tane rnek altrmakta fayda vardr. Bylece farkl istemciler iin servis nesnesinin ne ekilde
rneklendii daha kolay takip edilebilir.

www.bsenyurt.com Page 1101


Bu deneme sonrasnda servis uygulamasnn bulunduu klasrde Izleyici.txt isimli bir dosya
oluacak ve ierii aadaki gibi olacaktr.

17:31:53: UrunYonetici nesnesi oluturuldu.


17:31:53: Urun ekle metodu arld.
17:31:54: Urun ekle metodu arld.
17:31:55: Urun kart metodu arld.
17:31:55: Sipari ver metodu arld.
17:31:57: UrunYonetici nesnesi iin Dispose metodu altrld.

17:31:51: UrunYonetici nesnesi oluturuldu.


17:31:51: Urun ekle metodu arld.
17:31:52: Urun ekle metodu arld.
17:31:52: Urun kart metodu arld.
17:31:54: Sipari ver metodu arld.
17:31:58: UrunYonetici nesnesi iin Dispose metodu altrld.

17:31:48: UrunYonetici nesnesi oluturuldu.


17:31:48: Urun ekle metodu arld.
17:31:49: Urun ekle metodu arld.

www.bsenyurt.com Page 1102


17:31:49: Urun kart metodu arld.
17:31:50: Sipari ver metodu arld.
17:31:59: UrunYonetici nesnesi iin Dispose metodu altrld.

Dikkat edilecek olursa altrlan 3 istemci iin 3 ayr UrunYonetici nesne rnei oluturulmu ve bu
istemcilerin yapm olduu metod arlarnn tamam sona erdiinde nesneler dispose edilmek
zere Garbage Collector' e devredilmeye balanmtr. Bu durum NetTcpBinding iin varsaylan
davrantr ve PerSession modunun karldr. Eer servis nesneleri PerCall veya Single modeline
gre altrmak istenirse yaplmas gereken ServiceBehavior niteliini aadaki gibi
deitirmektir. lk olarak PerCall yapldndaki durumu analiz edelim.

UrunYonetici snfndaki deiiklik aadaki gibidir.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
public class UrunYonetici:IUrunYonetici,IDisposable

Buna gre yine rnek olarak 3 istemci altrp denersek Istemci.txt dosyasnn ierii aadaki
gibi olacaktr.

17:37:09: UrunYonetici nesnesi oluturuldu.


17:37:09: Urun ekle metodu arld.
17:37:10: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:10: UrunYonetici nesnesi oluturuldu.


17:37:11: Urun ekle metodu arld.
17:37:11: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:13: UrunYonetici nesnesi oluturuldu.


17:37:14: Urun ekle metodu arld.
17:37:14: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:15: UrunYonetici nesnesi oluturuldu.


17:37:15: Urun ekle metodu arld.
17:37:16: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:16: UrunYonetici nesnesi oluturuldu.


17:37:17: Urun kart metodu arld.
17:37:17: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:18: UrunYonetici nesnesi oluturuldu.


17:37:18: Urun ekle metodu arld.
17:37:19: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:19: UrunYonetici nesnesi oluturuldu.


17:37:20: Urun kart metodu arld.
17:37:20: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:21: UrunYonetici nesnesi oluturuldu.


17:37:21: Sipari ver metodu arld.
17:37:22: UrunYonetici nesnesi iin Dispose metodu altrld.

17:37:22: UrunYonetici nesnesi oluturuldu.


17:37:23: Urun kart metodu arld.
17:37:23: UrunYonetici nesnesi iin Dispose metodu altrld.

www.bsenyurt.com Page 1103


17:37:24: UrunYonetici nesnesi oluturuldu.
17:37:24: Sipari ver metodu arld.
17:37:25: UrunYonetici nesnesi iin Dispose metodu altrld.

Dikkat edilecek olursa, istemcilerden gelen her metod arsnda UrunYonetici snfna ait bir rnek
oluturulmu ve metod ileyii servis tarafnda tamamlandktan sonra sz konusu rnekler
toplanmak zere Garbage Collector' e devredilmitir.

Single modunda test ilemini yapmak iin yine UrunYonetici snfna


uygulanan ServiceBehavior niteliinde aadaki deiiklik yaplmaldr.

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
public class UrunYonetici:IUrunYonetici,IDisposable

Tekrar, rnek olarak 3 istemci altrlp test edilirse Izleyici.txt dosyasna aadaki bilgilerin
yazld grlr.

17:45:13: UrunYonetici nesnesi oluturuldu.


17:45:16: Urun ekle metodu arld.
17:45:16: Urun ekle metodu arld.
17:45:17: Urun kart metodu arld.
17:45:17: Urun ekle metodu arld.
17:45:18: Sipari ver metodu arld.
17:45:18: Urun ekle metodu arld.
17:45:19: Urun ekle metodu arld.
17:45:19: Urun kart metodu arld.
17:45:20: Urun ekle metodu arld.
17:45:20: Sipari ver metodu arld.
17:45:21: Urun kart metodu arld.
17:45:22: Sipari ver metodu arld.
17:45:29: UrunYonetici nesnesi iin Dispose metodu altrld.

Grld gibi ka istemci olursa olsun hepsi iin tek bir UrunYonetici nesne rnei
oluturulmutur.

Makalemizin banda zellikle PerSession modunda hangi metod ars ile nesne rneinin
oluturulabileceini veya hangi metod arsndan sonra servise ait nesne rneinin yok
edilebileceini IsInitiating ve IsTerminating zellikleri ile belirtebileceimizi sylemitik. Bu
modlarn kullanlabilmesi iin ayrca SessionMode zelliinin deerinin Requiredolarak
iaretlenmi olmas gerekmektedir. Nitekim sz konusu operasyonlarn takibi iin bir oturumun var
olmas gerekir. Aadaki kod parasnda sz konusu sistemin IUrunYonetici arayzne uygulan
ekli gsterilmektedir.

[ServiceContract(Name="UrunYonetimServisi",Namespace="http://www.bsenyurt.com/UrunYone
timServisi"
,SessionMode=SessionMode.Required)]
public interface IUrunYonetici
{
[OperationContract(IsInitiating=true)]
void SepeteUrunEkle(string urunId);
[OperationContract(IsInitiating=false)]
void SepettenUrunCikar(string urunId);
[OperationContract(IsInitiating=false,IsTerminating=true)]

www.bsenyurt.com Page 1104


void SiparisVer();
}

Buna gre nesne rnei sadece SepeteUrunEkle metodu ile oluturulabilir. Bir baka deyile
SepettenUrunCikar veya SiparisVer metodlarnn SepeteUrunEkle metodundan nce
altrlamamas garanti altna alnm olunur. Buna gre istemci uygulama kodlarnn aadaki
gibi deitirildii gz nne alnsn.

UrunYonetimServisiClient srv = new


UrunYonetimServisiClient("DefaultBinding_UrunYonetimServisi_UrunYonetimServisi");
srv.SepettenUrunCikar("1000");
srv.SepeteUrunEkle("1000");
srv.SiparisVer();
Console.WriteLine("Uygulamadan kmak iin Bir Tua Basn");
Console.ReadLine();

Dikkat edilecek olursa nce SepettenUrunCikar metodu arlmaktadr. Sonrasnda ise


SepeteUrunEkle ve SiparisVer isimli metodlar altrlmak istenir. Ancak kod bu ekilde
denendiinde alma zamannda aadaki ekran grntsnde yer alan istisna alnr.

Dolaysyla metodlarn alma srasda sz konusu zellikler yardmyla garanti altna alnmtr.
Elbette IsInitiating zelliinin true olarak atand SepeteUrunEkle metodu bir kere altrldktan
sonra dier metodlar istenildii gibi altrlabilir. Dier taraftan aadaki gibi bir kod parasnda
yine dikkatli olunmaldr.

UrunYonetimServisiClient srv = new


UrunYonetimServisiClient("DefaultBinding_UrunYonetimServisi_UrunYonetimServisi");
srv.SepeteUrunEkle("1000");
srv.SepeteUrunEkle("1004");
srv.SepettenUrunCikar("1000");
srv.SiparisVer();
srv.SepeteUrunEkle("1000");
Console.WriteLine("Uygulamadan kmak iin Bir Tua Basn");
Console.ReadLine();

Dikkat edilecek olursa SiparisVer metodundan sonra SepeteUrunEkle metodu altrlmtr. Oysaki
SiparisVer metodu iin IsTerminating zelliinin deeri true olarak atanmtr. Dolaysyla bu
metod arsndan sonra sz konusu servis nesne rnei yok edilecektir. Buna gre istemci
tarafnda aadaki ekranda grld gibiChannelTerminatedException snf tipinden bir
istisna mesaj alnr.

www.bsenyurt.com Page 1105


zetle daha ncedende deindiimiz gibi istemci tarafnda istisna ynetimi adna baz hazrlklar
yapmak (Fault Management) son derece isabetli bir hareket olacaktr.

Bu makalemizde servis tarafndaki nesne rnekleri ile istemci arasndaki ilikilerin ele alnmas
adna InstanceContextMode, IsInitiating, IsTerminating gibi zelliklerden nasl
yararlanabileceimizi ele almaya altk. Oturum ynetimi adna WCF ierisinde ele alnmas
gereken daha pek ok konu vardr. rnein PerCall modda oturum ynetiminin salanmas gibi.
Bu gibi konulara ilerleyen makalelerimizde deinmeye alacaz. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Mesaj Seviyesinde Gvenlik ( 16.05.2007


) - WCF
Deerli Okurlarm Merhabalar,

Datk mimariye ynelik olarak gelitirilen uygulamalarda gvenlik son derece nemli bir
faktrdr. zellikle farkl sreler (process) ierisinde yer alan uygulamalar, birbirleriyle
haberleirken aradaki veri trafii mesajlar zerine kuruludur. Bu mesajlarn a ortamlar zerinden
(Internet-Intranet) hareket etmeside gvenlik ile ilgili olarak dikkat edilmesi gereken noktalarn
saysn arttrr. Temel olarak datk mimarilerde gvenlik dnldnde, kullanclarn sunucu
tarafndan dorulanmas (authentication), dorulanan kullanclarn hangi fonksiyonellikleri
kullanabileceine baklmas (authorization), arada hareket etmekte olan mesajlarn ne ekilde
ifreleneceinin(encryption) veya zmleneceinin(decryption) belirlenmesi gibi konular yer
almaktadr. Bu tip ilemlere ihtiya duyulmasnn bilinen pek ok nedeni vardr. Bunlardan bir ka
aada maddeler halinde listelenmitir.

yi gelitiriciler veya sistem bakmndan sorumlu olanlar, genellikle a zerindeki trafii


kontrol etmek, performans kayplarn tespit etmek amacyla eitli programlar
kullanrlar.(rnein biz makalemizde istemci ile sunucu arasndaki mesajlar grmek
adna Microsoft Service Trace Viewer aracndan faydalanacaz.) Bu programlar
sayesinde a zerinde istemciler ve sunucu arasnda hareket eden mesajlar grlebilir.
Ancak kt niyetli kiilerde bu paketleri takip edebilirler. Eer paketler ierisinde hassas

www.bsenyurt.com Page 1106


bilgiler var ise sz konusu bilgilerin grlmesi istenmeyen bir durumdur. Dolaysyla
mesajlarn eitli algoritmalar ile (TripleDes, SHA vb...) ifrelenmesi ok dorudur.
Yine olaylarn ba kahraman olan kt niyetli kullanclar istemciler ve sunucu arasndaki
mesajlar yakalayp deitirebilirler. Bu bir nceki durumdan biraz daha farkldr. Nitekim
mesajn orjinal haliyle gitmesi yerine bozulmu haliyle tanmas sz konusudur. Bu
yaklam elbetteki veri btnln tamamen bozan bir etki yapar. Sertifikalandrma ve
dijital imza gibi tekniklerin kullanlmas tercih edilerek gereken tedbirler alnabilir.
Baz durumlarda istemciler gerek sunucu yerine, araya alnm baka bir yalanc sunucuya
bavuruda bulunuyor olabilir. zellikle internet tabanl bankaclk uygulamalarnda zaman
zaman duyduumuz bu senaryo datk mimari uygulamalar iinde sz konusu olabilir.
nlem olarak ift tarafl dorulama modeli ele alnabilir.
Kt niyetli kiilerin yakalad mesajlar, sadece bozulmakla kalmaz defalarca sunucuya
gnderilebilir. Dolaysyla sunucunun doru bir ekilde almas engellenmite olur. Bu gibi
bir duruma nlem olarak gvenli bir iletiim ortam salanmas gerekmektedir.

Dikkat edilecek olursa bu basit senaryolar bile, bir datk mimari sisteminin kmesi iin yeterlidir.
WCF mimarisinde kullanclarn dorulanmas srasnda veya dorulama ilemleri sonrasnda arada
hareket edecek mesajlar sz konusu olduunda tanan hassas bilgiler sz konusudur. Sz konusu
bilgilerin gvenliini iletiim seviyesinde (transport level)ve mesaj seviyesinde (message
level) olmak zere iki ekilde salayabiliriz. letiim seviyesinde gvenlii salamann bilinen
yollarndan birisi HTTPS' dir. Dolaysyla iletiim seviyesinde salanan gvenliin iletim sistemi ve
donanma bal olaraktan daha etkili ve performansl olduunu dnebiliriz. Mesaj seviyesinde
salanan gvenlik gz nne alndnda sorumluluk servisin zerindedir. Dier taraftan servis ve
istemci arasnda gidecek bilgilerin ifrelenmesi hem sunucuyu hemde istemciyi ilgilendirmektedir.

zellikle Web servisleri zerinde uygulanabilen gvenlik seenekleri dnldnde (Web


Service Enhancements), Windows Communication Foundation ierisinde benzer imkanlar
salamak ok daha kolaydr. Bu makalemizde ilk olarak mesaj seviyesinde gvenliin nasl
salanabileceine dair adm adm ilerleyeceimiz bir rnek zerinde durmaya alacaz. Her
zaman olduu gibi basit bir snf ktphanesi ile ie balamak gerekiyor. Snf ktphanesi (Class
Library) bir WCF Library olarak tasarlanabilir ve ierisinde aadaki servis szlemesi ile tip yer
alabilir.

Servis szlememize ait arayz (Interface) aadaki gibidir;

using System;
using System.ServiceModel;

namespace AritmetikLib

www.bsenyurt.com Page 1107


{
[ServiceContract(Name="AritmetikServisi",Namespace="http://www.bsenyurt.com/AritmetikS
ervisi")]
public interface IAritmetik
{
[OperationContract]
double Toplam(double x, double y);
}
}

Arayz uyarlayan snf ise aadaki gibidir.

using System;

namespace AritmetikLib
{
public class Aritmetik:IAritmetik
{
#region IAritmetik Members
public double Toplam(double x, double y)
{
return x + y;
}
#endregion
}
}

Bu noktada istenirse retilen assembly' dan faydalanarak istemci iin gerekli proxy snfnn
yazdrlmas salanabilir. Daha nceki makalelerden hatrlayacanz gibi bu amala svcutil arac
kullanlabilir.

Artk servis uygulamasn tasarlamaya balayabiliriz. Amacmz gvenlik konusuna deinmek


olduundan servis ve istemci uygulamay basit birer Console uygulamas olarak ele alacaz. lk
olarak servis uygulamas ile balayalm. Her zaman olduu gibi bu uygulama iin kritik olan
referans System.ServiceModel.dll isimli assmebly' dir. Servis uygulamas iin gereken
konfigurasyon bilgileri balang aamasnda aadaki gibi olmaldr. Bu bilgileri kolay bir
ekilde Edit WCF Configuration seenei ile alan Microsoft Service Configuration
Editor arabirimi yardmylada hazrlayabiliriz.

Servis uygulamas iin konfigurasyon dosyas;

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


<configuration>
<system.serviceModel>
<services>
<service name="AritmetikLib.Aritmetik">
<endpoint address="net.tcp://localhost:9002/AritmetikServisi" binding="netTcpBind
ing" name="AritmetikServerEndPoint" contract="AritmetikLib.IAritmetik" />
</service>
</services>
</system.serviceModel>
</configuration>

www.bsenyurt.com Page 1108


Servis tarafnda TCP protokoln baz alacak ekilde bir ayarlama yaplmtr. Buna gre istemciler
sz konusu endPoint eriimi iin net.tcp://localhost:9002/AritmetikServisiadresini
kullanacaktr. Dier taraftan balayc tip olarak NetTcpBinding tipi ele alnmaktadr. Bu noktadan
sonra sunucu uygulamann kodlar aadaki gibi tasarlanabilir.

using System;
using System.ServiceModel;
using AritmetikLib;

namespace Server
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(Aritmetik), new
Uri("net.tcp://localhost:9002/AritmetikServisi"));
host.Open();
Console.WriteLine("Host state " + host.State);
Console.ReadLine();
host.Close();
}
}
}

Sunucu uygulamann alt sre boyunca istemcilere hizmet verebilmesi ve sz konusu endPoint'
e ait nesne referanslarn kullandrtmas iin her zaman olduu gibi ServiceHost tipinden bir rnek
kullanlmaktadr. Open metodu ile servis almakta, uygulama kapatlrken Close metodu ile sz
konusu servis sonlandrlmaktadr.

stemci uygulamamza ait konfigurasyon dosyasda balang iin aadaki gibi tasarlanabilir.

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


<configuration>
<system.serviceModel>
<client>
<endpoint address="net.tcp://localhost:9002/AritmetikServisi" binding="netTcpBinding
" contract="AritmetikServisi" name="TemelMatClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

stemci uygulamaya ait kodlar ise aadaki gibidir.

using System;
using System.ServiceModel;

namespace Client
{
class Program
{
static void Main(string[] args)
{
try

www.bsenyurt.com Page 1109


{
AritmetikServisiClient client = new
AritmetikServisiClient("TemelMatClientEndPoint");
double sonuc = client.Toplam(3, 5);
Console.WriteLine(sonuc.ToString());
Console.ReadLine();
}
catch (FaultException excp)
{
Console.WriteLine(excp.Message);
}
}
}
}

stemci uygulamada yer alan AritmetikServisiClient isimli snf, svcutil arac yardmyla
AritmetikLib.dll isimli assembly zerinden elde edilmektedir. (Buraya kadarki admlarmz daha
nceki makalelerimizde incelendiinden detayl bir ekilde aklanmamtr.)

Bu makalemizde bizim iin nemli olan mesaj seviyesinde gvenliin (Message Level
Security) nasl salanacadr. lk olarak servis tarafnda baz ayarlamalarn yaplmas
gerekmektedir. rnein, mesaj seviyesinde gvenlik uygulanacann, mesajlarn belirtilen ve
bilinen bir algoritmaya gre ifreleneceinin belirtilmesi vb... Bu amala servis tarafnda yer alan
App.config dosyas Microsoft Service Configuration Editor yardmyla alp yeni bir balayc
konfigurasyon (Binding Configuration) eklenmeli ve EndPoint ile ilikilendirilmelidir.
ncelikle New Binding Configuration linkine tklanarak netTcpBinding tipi seilir ve eklenir. Bir
baka deyile servis tarafnda kullanlan Binding tipi iin gereken ayarlamalarn yaplmas iin yeni
bir element eklenmektedir.

www.bsenyurt.com Page 1110


Uygulama netTcpBinding balayc tipini kulland iin, balayc konfigurasyon ayarlar buna gre
yaplmaldr. Yeni eklenen elementin Security sekmesine geildii takdirde gereken gvenlik
ayarlar ile ilikili zellikler olduu grlebilir.

www.bsenyurt.com Page 1111


Mode zelliinde gveinlik seviyesinin mesaj, iletiim veya bunlarn kombinasyonu olup olmad
belirlenir. rneimizde mesaj seviyesinde gvenlik gerekletirileceinden Mode
zelliine Message deeri verilmitir. AlgorithmSuite zelliinde, mesajlarn hangi modele gre
ifrelenecei belirlenir. Burada olduka fazla ve yeterli seviyede ifreleme algoritmasna ait
tanmlamalar yer almaktadr. Dikkat edilmesi gereken nokta burada belirtilen ifreleme modelinin
istemci iinde ayn olmas gerektiidir. Bu durum Mode zelliinin deeri iinde geerlidir. Yani
servis tarafnda mesaj seviyesinde gvenlik kullanlaca belirtiliyorsa, istemci uygulamada ayn
model kullanlmaldr.

www.bsenyurt.com Page 1112


Biz rnek olarak TripleDesSha256 modelini gz nne alabiliriz. AlgorithmSuite iin varsaylan
deer Basic256' dr. Security ksmnda yer alan zelliklerden bir dieri
olanMessageClientCredentialType ile, istemcilerin dorulamasnn (Authentication) nasl
yaplaca belirlenmektedir.

Ekran grntsndende izlenebilecei gibi sz konusu zellie, Windows, UserName,


Certificate, IssuedToken ve None deerlerinden birisi verilebilir. rnekte Windows deeri
verilmitir. Bir baka deyile istemcilerin servise gnderecekleri ehliyet bilgileri (Credentials)
windows tabanl dorulama modeline gre aktarlacaktr. rnekte yer alan istemci ve sunucu
uygulamalar ayn makine zerinde yer aldklarnda varsaylan olarak makineyi aan kullanc
bilgileri ele alnacaktr.

TransportSecurity ksmndaki zellikler iletiim seviyesinde gvenlik modeli iin gerektiinden u


aamada varsaylan halleri ile braklabilirler. Bu ilemlerin ardndan balayc konfigurasyon bilgileri
iin ServiceBindingConfiguration ad belirtilerek gereken deiiklikler kaydedilebilir.

Artk tek yaplmas gereken servisten sunulan ilgili endPoint iin BindingConfiguration zelliine
hazrlanan ServiceBindingConfiguration deerini vermektir. Bylece endPoint ierisinde kullanlan
binding tipinin belirttii gvenlik ayarlar aktif olarak set edilmi olunur.

Bu ilemlerin ardndan servis taraf iin konfigurasyon dosyasnn ierii aadaki gibi
yenilenecektir. Dikkat edilecek olursa grsel tarafta yaplan tm eklentiler buraya element ve
nitelikler olarak geirilmitir. Dikkat edilmesi gereken nokta, endPoint elementi ierisindeki
bindingConfiguration elementinin deerinin, netTcpBinding alt elementindeki name zelliinin
deeri oluudur.

www.bsenyurt.com Page 1113


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="ServiceBindingConfiguration">
<security mode="Message">
<message algorithmSuite="TripleDesSha256" />
</security>
</binding>
</netTcpBinding>
</bindings>
<services>
<service name="AritmetikLib.Aritmetik">
<endpoint
address="net.tcp://localhost:9002/AritmetikServisi" bindingConfiguration="ServiceBindingCo
nfiguration" binding="netTcpBinding" name="AritmetikServerEndPoint"
contract="AritmetikLib.IAritmetik" />
</service>
</services>
</system.serviceModel>
</configuration>

Srada istemci taraf iin yaplmas gereken ayarlar var. Yine istemci tarafndaki konfigurasyon
dosyasnda, aynen servis tarafndaki konfigurasyon dosyasndakine benzer gvenlik ayarlamalarn
yaplmas gerekmektedir. lk olarak bir bindingConfiguration elementi oluturulmaldr. Bu
elementin security ile ilikili zelliklerinde mesaj seviyesi iin AlgorithmSuitedeeri servis
tarafndaki ile ayn olacak ekilde TripleDesSha256 olarak belirlenmelidir. Dier taraftan ayn
sunucu tarafnda yapld gibi gvenlik modu mesaj seviyesine ekilmelidir. Bu deer,
konfigurasyon dosyasnda security elementi ierisinde yer alan mode nitelii ile set edilmektedir ve
Message olarak ayarlanmtr. Bundan sonra oluturulan bindingConfiguration elementi istemci
tarafndaki endPoint ile bindingConfiguration nitelii yardmyla ilikilendirilmelidir. Bunun sonucu
olarak istemci uygulama iin konfigurasyon dosyasnn son hali aadaki gibi olacaktr.

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


<configuration>
<system.serviceModel>
<bindings>
<netTcpBinding>
<binding name="ClientBindingConfiguration">
<security mode="Message">
<message algorithmSuite="TripleDesSha256" />
</security>
</binding>
</netTcpBinding>
</bindings>
<client>
<endpoint address="net.tcp://localhost:9002/AritmetikServisi"
binding="netTcpBinding" bindingConfiguration="ClientBindingConfiguration" contract="Arit
metikServisi" name="TemelMatClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

www.bsenyurt.com Page 1114


Artk istemci ve sunucu taraf iin mesaj seviyesinde gvenlik ayarlar hazrdr. Ancak bunu test
ederek analiz etmek gerekmektedir. Microsft Windows SDK tam bu ama iin tasarlanm ve
Windows Communication Foundation uygulamalarnda istemci ile sunucu arasndaki mesaj trafiini
izlememizi salayan Service Trace Viewer isimli bir ara ile birlikte gelmektedir.

Ancak sz konusu aracn gelitirilen WCF uygulamasn izleyebilmesi iinde servis


tarafnda Diagnostics ayarlarnn tesis edilmesi gerekir. Bu ayarlarda yine Microsoft Service
Configuration Editor yardmyla kolayca gerekletirebiliriz. Burada sz konusu ayarlar zerinde u
an iin ok fazla durmayacaz. ncelikli olarak amacmz servis ve istemciler arasndaki
mesajlamay izlemektir. zleme(Trace) ilemi iin yaplan ayarlardan sonra servis tarafndaki
konfigurasyon dosyasnn ierii aadaki gibi olacaktr. Dikkat edilmesi gereken noktalardan
birisi sharedListeners elementi ierisinde yer alan initializeData niteliinin deeridir. Burada
uygulamann yazld klasr altnda svclog(Service Log)uzantl bir fiziki dosya bildirimi
yaplmtr. Bu bildirim Service Trace Viewer uygulamas tarafndan ele alnacak dosyay iaret
etmektedir ve log bilgilerinin tamam burada tutulmaktadr.

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


<configuration>
<system.diagnostics>
<sources>
<source name="System.ServiceModel.MessageLogging"
switchValue="Verbose,ActivityTracing">
<listeners>
<add type="System.Diagnostics.DefaultTraceListener" name="Default">
<filter type="" />
</add>
<add name="MessageListener">
<filter type="" />
</add>
</listeners>
</source>
</sources>
<sharedListeners>
<add initializeData="E:\Vs2005Projects\WCF
Samples\MesajSeviyesiGuvenlikTcp\Server\app_tracelog.svclog" type="System.Diagnostic
s.XmlWriterTraceListener, System, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" name="MessageListener" traceOutputOptions="None">
<filter type="" />
</add>
</sharedListeners>
</system.diagnostics>
<system.serviceModel>
<diagnostics>
<messageLogging logEntireMessage="true" logMessagesAtServiceLevel="true"
logMessagesAtTransportLevel="true" />
</diagnostics>
<bindings>
<netTcpBinding>
<binding name="ServiceBindingConfiguration">
<security mode="Message">
<message algorithmSuite="TripleDesSha256" />
</security>
</binding>
</netTcpBinding>
</bindings>
<services>

www.bsenyurt.com Page 1115


<service name="AritmetikLib.Aritmetik">
<endpoint address="net.tcp://localhost:9002/AritmetikServisi"
binding="netTcpBinding" bindingConfiguration="ServiceBindingConfiguration"
name="AritmetikServerEndPoint" contract="AritmetikLib.IAritmetik" />
</service>
</services>
</system.serviceModel>
</configuration>

Bu noktadan sonra istemci ve sunucu uygulamalar test edilebilirler. alma zamannda istemci ve
sunucu aktif iken Service Trace Viewer program altrlp sz konusu svclog dosyas alrsa ilk
bata aadakine benzer bir ekran ile karlalacaktr.

Bu ekranda zellikle dikkat edilmesi gereken ksmlar sol taraftaki Message sekmesinde yer alan
son drt mesajdr. Bu mesajlar aslnda istemciden sunucuya gelen talepleri ve sunucudan istemciye
dnen cevaplar ieren mesajlardr. stemci uygulamann kodlar hatrlanacak olursa burada Toplam
isimli metoda bir ar yaplmaktadr. Topla metodu servis tarafnda altrlp sonucu istemci
tarafna gelmektedir. Dolaysyla istemci Topla metoduna ar yaptnda aktarlan parametre ve
dier bilgiler servise gnderilecek, serviste ilgili fonksiyon altrlacak ve sonucu istemci tarafna
geri bildirilecektir.

www.bsenyurt.com Page 1116


Bu mesajlardan ilki istemciden sunucya gelen bilginin ifreli olarak nasl geldiini gstermektedir.
ifrelenmi veriyi grmek iin sa alt tarafta yer alan Formatter, XML yada Message ksmlar
kullanlabilir. Formatter ksmna baktmzda Envelope
Information blmndeki e:ChiperData ksmnda, istemciden sunucuya gelen
parametrelerinTripleDesSha256 algoritmasna gre ifrelenmi halinin yer ald grlebilir.

Eer takip eden mesaj iin ayn ksma tekrar bakarsak verinin servis tarafndan zmlenmi olan
hali grlmektedir. Dikkat edilecek olursa sz konusu deerler, istemcideki Toplam metodunun
ald parametre ierikleridir.

Bir sonraki mesaj servisin bu metod arsna karlk verecei cevap hakknda bilgiler
iermektedir. Yine Parameters ksmna baklacak olursa aadaki ekran grntsnde olduu gibi
8 deerinin yer aldn farkedilir.

Ancak son mesaj istemciye gnderilecek verinin ifrelenmi halini iaret etmektedir. Bir baka
deyile, 8 deeri aslnda servisten istemciye gnderilmeden nce TripleDesSha256 modeline gre
ifrelenecek ondan sonra iletilecektir.

Eer ayn rnek gvenlik ayarlar yaplmadan test edilirse ve yine Service Trace
Viewer yardmyla istemci ile sunucu arasndaki mesajlamalar izlenirse verilerin herhangibir

www.bsenyurt.com Page 1117


ekilde ifrelenmedii grlebilir. Bu amala istemci ve sunucu tarafndaki konfigurasyon
dosyalarnda security elementlerinin ierisinde yer alan Mode niteliklerinin deerini None olarak
belirlemek yeterlidir.

Bu makalemizde zellikle mesaj seviyesinde gvenlii nasl salayabileceimizi incelemeye altk.


lerleyen makalelerimizde windows tabanl ve iletiim seviyesinde gvenlik ilemlerini nasl
yapabileceimizi incelemeye devam edeceiz. Bylece geldik bir makalemizin daha sonuna. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Hata Ynetimi (Fault Management) (


09.05.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Hata ynetimi her programlama dili ve gelitirme ortam ierisinde yer alan nemli konulardan
birisidir. zellikle kullanclarn yapm olduu ilemler sonucunda oluan veya sistem zerinde
beklenmeyen durumlardan doan hatalarn nne gemek amacyla eitli mekanizmalara
bavurulmaktadr. Bunlardan birisi ve ayn zamanda etkili olanda istisna ynetimidir (Exception
Handling). Microsoft .Net ortamnda istisna ynetimi CLR (Common Language Runtime - Ortak Dil
almaZaman) tarafndan gerekletirilen bir unsurdur. Ne varki, basit bir windows veya web
uygulamasnda etkili bir ekilde ele alnabilen istisnalar, datk mimari uygulamalar (Distributed
Applications) gz nne alndnda daha farkl yaklalmak durumundadr. Bu durumu daha iyi
anlayabilmek iin, datk mimari uygulamalarnn taraflarn gz nne almakta yarar vardr. Biz
her ne kadar sunucu tarafnda .Net ortamn kullanyor olsakta, istemci asndan durum aynen
geerli deildir. rnein datk mimari uyarlamalarndan birisi olan Xml Web Servisleri
dnldnde istemcinin farkl platformda yer alan bir uygulama olmas muhtemeldir. yleyse
dnlmesi gereken iki nemli nokta vardr. Bunlardan birincisi, istemcilerin farkl bir platformda
olabileceidir. Bu CLR tarafnan ele alnabilecek bir istisnann istemci tarafnda ele alnamamas iin
yeter bir sebeptir. nk istemci tarafnda bir CLR ortam bulunmayabilir. kinci nemli nokta ise
sunucu zerinde bir istisna oluursa bunun istemci tarafna nasl bildirileceidir. Bir baka deyile
sunucu tarafnda yakalanan hatann, farkl bir makinedeki farkl bir bellek blgesinde alan bir
uygulamann yakalayabilecei ekilde gnderilebilmesi gerekmektedir. Bu iki noktann oluturduu
sorunu zmenin tek yolu herkesin kabul ettii ortak bir standarda gre istisna bilgisi
yaynlamaktr. te bu noktada devreye SOAP (Simple Object Access Protocol) girer. Bu
protokol rnek olarak web servislerinde oluacak istisnalar istemci tarafna Soap Fault mesajlar
olarak gnderir ki bu mesaj eidi tm platformlar tarafnda kabul edilmitir.

Soap Fault hakknda daha fazla bilgi iin http://www.w3.org/TR/soap12-


part1/#soapfault adresinden faydalanabilirsiniz.

SoapFault, sunucu tarafndan frlatlabilecek istisnalarn nasl bir formata sahip olmas gerektiine
dair kurallar ierir. rnein tm SoapFault mesajlarnda Code (Hata kodu
bilgisi), Reason(Hatann sebebi) gibi hataya ait detayl bilgi alnmasn salayan zellikler yer
almaktadr. .Net Framework, J2EE gibi rnek plaftormlar bu kurallara uygun olacak ekilde
tasarlanm snflar sunarlar. Bylece, yazacamz servisleri kullanacak istemcilerin tamam iin ele
alnabilecek istisna mesajlar oluturma ansna sahip oluruz. Peki Windows Communication

www.bsenyurt.com Page 1118


Foundation iin durum nasldr? WCF ierisindede istemcilerin ele alabilecei ekilde hata mesajlar
tanmlayabilmek iin FaultException isimli snf gelitirilmitir. Aslnda bir WCF servisi ierisinde
istemci uygulamalara frlatlabilecek istisna mesajlar, kar tarafa getiklerinde her zaman
bir FaultException rnei olarak ele alnrlar. Ancak nemli olan bir nokta vardr ki buda, servis
zerinde oluan istisnann mutlaka kar tarafa (istemci uygulamaya) frlatlmas(throw)
gerektiidir.

ou zaman servis tarafnda meydana gelen istisnalar iin, istemciye daha fazla bilgi tayabilecek
ekilde kendi istisna nesnelerimizi organize etmek isteyebiliriz. .Net tarafndan yaklatmzda
bunun yolu ApplicationException snfndan bir tip tretmektir. Lakin WCF iin durum biraz daha
farkldr. Nitekim oluturulan istisna nesne rneinin Soap Fault standartlarna uygun olacak ekilde
istemci tarafna bir mesaj olarak gnderilebilmesi ve orada referansnn ele alnabilmesi (handle)
gerekmektedir. WCF mimarisini tanmaya altmz ilk makalemizde drt eit szleme
(contract) olduundan bahsetmitik. Bunlardan biriside hata szlemesidir(Fault Contract).
Hata szlemeleri basit olarak, servis tarafnda retilen kullanc tanml hatalarn istemciye nasl
tanmas gerektiini bildiren bir szleme eidir. Gelitirici olarak kendi hata bildirimlerimizi
yapmak iin ncelikli olarak hataya ait bilgileri tayacak bir veri szlemesininde (data contract)
tanmlanmas gerekmektedir. Makalemizin ilerleyen ksmlarnda bu ilemlerin nasl yaplacan
adm adm inceleyeceiz.

WCF iin, hata ynetimi ile ilikili olarak dikkat edilmesi gereken bir dier noktada, servisin almas
ve kapanmas arasnda meydana gelebilecek baz beklenmedik tepkilere kar nasl tedbir alnmas
gerektiidir. Her servis almadan nce nesne olarak rneklenmektedir. Bunun programatik
olarak ServiceHost snfna ait bir nesne rneinin oluturulmas olarak dnebiliriz. Sonrasnda
servis alr ve istemcilerden gelecek olan talepler karlanmaya balar. Ne varki servis alrken,
aldnda ve alrken servis tarafnda baz beklenmedik hatalar oluabilir. Bu gibi durumlarda
servise ait Faulted olay tetiklenmektedir. Dolaysyla bu olay ierisinde gereken hazrlklar
yaplarak servisin tekrar ayaa kaldrlmas denenebilir. Burada servisin yaam dngsnnde
bilinmesinde fayda vardr. Bu konuyuda makalemizin sonunda ele almaya alacaz. imdi vakit
kaybetmeden rnek bir senaryo zerinden gidelim. Basit olarak Tcp balaycsn kullanan Console
tabanl sunucu ve istemci uygulamalarn yer ald bir WCF senaryosu gelitireceiz. ncelikli olarak
servis szlemesi ve uyarlamay yapan tipi ieriside barndran RemoteLib isimli WCF Servis
ktphanemizi (WCF Service Library) aadaki gibi tasarlayalm.

INorthwind arayzmz tahmin edeceiniz gibi servis szlememizi(Service Contract) ifade


etmektedir.

using System;

www.bsenyurt.com Page 1119


using System.Data;
using System.ServiceModel;

namespace RemoteLib
{
[ServiceContract(Name="NorthManagerService",
Namespace="http://www.bsenyurt.com/NorthService")]
public interface INorthwind
{
[OperationContract(Name="GetCustomers")]
DataSet GetCustomers();
}
}

Servis szlememizi uygulayan NorthManager isimli snfmzn ierii ise u an iin aadaki
gibidir.

using System;
using System.Data;
using System.ServiceModel;
using System.Data.SqlClient;

namespace RemoteLib
{
public class NorthManager:INorthwind
{
#region INorthwind Members

public DataSet GetCustomers()


{
DataSet ds = null;
SqlConnection conn=null;
try
{
conn= new SqlConnection("data source=.;database=AdventureWorks;integrated
security=SSPI");
SqlDataAdapter da = new SqlDataAdapter("Select
CustomerID,CompanyName,ContactName,ContactTitle From Customers", conn);
ds = new DataSet("CustomersSet");
da.Fill(ds);
}
catch (SqlException excp)
{
Console.WriteLine(excp.Message);
}
finally
{
conn.Close();
}
return ds;
}

#endregion
}
}

www.bsenyurt.com Page 1120


NorthManager snfmz ierisinde yer alan GetCustomers isimli metodumuz basit olarak Northwind
veritabannda yer alan Customers isimli tablodan veri ekip sonu kmesini bir DataSet olarak
geriye dndrmektedir. Ancak SqlConnection nesne rnei oluturulurken veritaban ad olarak
Northwind yerine AdventureWorks ad verilmitir. Bu, alma zamannda ok doal olarak bir
istisnaya neden olacaktr. stisna servis taraf asndan dnldnde GetCustomers metodu
ierisindeki catch blou tarafndan yakalanacaktr. Peki ya sonrasnda ne olacaktr? Gerekten
istemci uygulama burada SqlException istisna nesne rneini yakalayabilecek midir? Bu sorulara
net bir cevap verebilmek iin nce sunucu uygulamamz, ardndan istemci uygulamamz
gelitirerek incelemelerimize devam edelim. Servis uygulamamz bir konsol program olarak
tasarlanabilir. WCF iin gerekli ayarlar konfigurasyon dosyasnda tutacaz. Konfigurasyon
dosyamzn ierii u an iin aadaki gibi yazlabilir.

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


<configuration>
<system.serviceModel>
<services>
<service name="RemoteLib.NorthManager">
<endpoint address="net.tcp://localhost:65002/NorthService" binding="netTcpBinding"
bindingConfiguration="" name="NorthServiceEndPoint" contract="RemoteLib.INorthwind" />
</service>
</services>
</system.serviceModel>
</configuration>

NetTcpBinding balayc tipini kullandmz iin TCP protokol zerinden binary formatlama
gerekleek ekilde iletiim kurabiliriz. Servisimize istemcilerin ulaabilmesi iinde
net.tcp://localhost:65002/NorthService adresi kullanlmaktadr. Elbette siz rnei denerken
istediiniz port numarasn ele alabilirsiniz. Servis szlememizde contract nitelii ierisinde
bildirilmitir. Sunucu uygulamaya ait program kodlarmz ise aadaki gibi olacaktr.

using System;
using System.ServiceModel;

namespace ServerApp
{
class Program
{
static void Main(string[] args)
{
ServiceHost host = new ServiceHost(typeof(RemoteLib.NorthManager));
host.Open();
Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
host.Close();
}
}
}

Servis uygulamas nce ServiceHost tipinden bir nesne rnei oluturmakta ve sonrasnda servisi
kullanma amaktadr. Kullanc uygulamay tua basarak kapattktan sonra alan servis iinde
kapatma emri Close metodu ile verilmektedir. Gelelim istemci tarafna. HTTP zerinden metadata
yaynlamas yapmadmz iin bir nceki WCF makalesinde yaptmz gibi svcutil.exe aracn
RemoteLib.dll assembly' zerinde kullanmamz ve istemci iin gerekli proxy snf ile konfigurasyon
dosyasn retmemiz gerekmektedir. Bu amala komut satrndan svcutil aracn aadaki gibi
kullanalm.

www.bsenyurt.com Page 1121


nce;

svcutil RemoteLib.dll

Sonrasnda ise;

svcutil /namespace:*,RemoteLib.NorthManager www.bsenyurt.com.NorthService.wsdl *.xsd

Tahmin edeceiniz gibi komut satrndan yaptmz bu ilemlerin sonrasnda istemci iin gereken
proxy snf ve config dosyalar baarl bir ekilde oluturulacaktr. stemci uygulamamzn
konfigurasyon dosyasn isterseniz daha basit olmas asndan aadaki gibi oluturabilirsiniz.
Nitekim svcutil ile oluturulan standart output.configdosyas olduka fazla element bilgisi
iermektedir. Tek dikkat edilmesi gereken nokta contract niteliine doru tip bilgisini girmektir.

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


<configuration>
<system.serviceModel>
<client>
<endpoint address="net.tcp://localhost:65002/NorthService" binding="netTcpBi
nding" bindingConfiguration="" contract="RemoteLib.NorthManager.NorthManagerService"
name="NorthClientEndPoint" />
</client>
</system.serviceModel>
</configuration>

Bundan sonra istemci uygulamamzn kod satrlarnda aadaki gibi gelitirelim.

using System;
using System.Data;
using System.ServiceModel;
using RemoteLib.NorthManager;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
try
{
NorthManagerServiceClient srvClient = new
NorthManagerServiceClient("NorthClientEndPoint");
DataSet customers = srvClient.GetCustomers();
if(customers.Tables.Count!=0)
Console.WriteLine(customers.Tables[0].Rows.Count.ToString());
}
catch (FaultException excp)
{
Console.WriteLine(excp.Code.Name+ "\n" + excp.Reason.ToString());
}
}
}
}

www.bsenyurt.com Page 1122


stemci tarafndaki kod paramzda dikkat ederseniz try...catch bloklar arasna aldk. Artk
testimize balayabiliriz.

stemcinin gereken taleplerde bulunabilmesi iin sunucu uygulamann alyor ve ak


olmas gerekecektir. Visual Studio ierisinde debug ilemleri yapmak
isteyebileceimizden Solution zelliklerinden Multiple Startup Projects seeneini
aadaki gibi set ederek F5 (Start) veya Ctrl+F5 (Start without debuging) sonrasnda
nce sunucunun sonrasnda ise istemcinin srayla altrlmalarn salayabiliriz.

Sonu olarak aadaki ekran ktlarn alrz.

Dikkat ederseniz, sunucu tarafndaki catch blouna girilmi ve oluan istisnaya uygun bir biimde
ekrana mesaj kts verilmitir. Ne varki bu istisna mesajn istemci tarafna gnderebilmi deiliz.
Bunun iin batada belirttiimiz gibi servis uygulamasnda bilinli bir ekilde FaultException nesne
rneinin oluturulmas gerekmektedir. Bu amala NorthManager snfmzn GetCustomers
metodundaki catch blounu aadaki gibi dzenleyelim.

catch (SqlException excp)


{
Console.WriteLine(excp.Message);
throw new FaultException(excp.Message, new FaultCode("Veritabani istisnas"));

FaultException snfnn farkl ekilde yklenmi yapc metodlar(constructors) vardr. Burada


kullanlan versiyonda ilk parametre olarak hatann sebebi (Reason) ikinci parametre olarakta hata
kodu (FaultCode) verilmektedir. Oluan istisna sonrasnda retilecek ve istemciye gidecek
olan SoapFault mesaj ierisinde, yapc metod ierisinde kullandmz parametre bilgileri yer
alacaktr. Buna gre uygulamalarmz tekrar altrrsak aadaki ekran grntlerini elde ederiz.

www.bsenyurt.com Page 1123


Grdnz gibi artk istemci tarafnda, sunucudan frlatlan FaultException nesnesinin ieriini
yakalayabilmekteyiz. Servis tarafnda yer alan NorthManager snfna ait GetCustomers metodunda
istisna olutuunda, istemci uygulamalara FaultException tipinden bir nesne rnei frlatmaktansa,
normal bir Excpetion nesnesi frlatlmasda denenebilir (yada baka tipte bir istisna nesne
rnei). Bu durumda istemci uygulama ok farkl bir mesaj alacaktr. Durumu analiz etmek iin
GetCustomers metodu ierisinde aadaki deiiklikleri yapalm.

throw new Exception("Veritaban ad yanl");

Testi tekrar yaptmzda istemci uygulamamz iin aadaki ekran grntsn elde ederiz.

Dikkat ederseniz istemci tarafna son derece enteresan bir kt gelmitir. Asl hata mesajnn
ieriini alabilmek iin servis tarafndaki konfigurasyon bilgilerinde biraz deiiklik yapmak
gerekecektir. ncelikle olarak bir servis davran (service behavior) tanmlanmaldr. Servis
davrannn (Service Behavior) serviceDebug zelliininincludeExceptionDetailInFaults isimli
niteliinede true deeri atanmal ve son olarak bu davran servise bildirilmelidir. Sz konusu
deiiklikleri servis uygulamasnn App.config isimli konfigurasyon dosyasna aadaki gibi
ekleyebiliriz.

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


<configuration>
<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="NorthServiceBehavior">
<serviceDebug includeExceptionDetailInFaults="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service behaviorConfiguration="NorthServiceBehavior" name="RemoteLib.NorthMa
nager">
<endpoint address="net.tcp://localhost:65002/NorthService" binding="netTcpBinding"
bindingConfiguration="" name="NorthServiceEndPoint" contract="RemoteLib.INorthwind" />
</service>
</services>
</system.serviceModel>

www.bsenyurt.com Page 1124


</configuration>

Bylece servis tarafnda rettiimiz FaultException dndaki bir istisnann istemci tarafna tanmas
mmkn olabilir ki istemci uygulamay tekrar test ettiimizde aadaki ekran grntsn elde
edebiliriz.

Burada dikkat edilmesi gereken nemli bir nokta daha vardr. Servis uygulamas tarafnda her
nekadar bir Exception snfna ait nesne rnei frlatsakta, istemci tarafnda bu
yineFaultException snfna ait bir rnek olarak ele alnacaktr. Bunu grebilmek iin istemci
uygulamada FaultException yerine Exception nesnesi yakalanmaya alabilir. Uygulamay debug
ettiimizde aynen aadaki ekran grntsnde olduu gibi istisna tipinin aslnda FaultException
olduu grlecektir.

Gelelim daha gl hata istisna nesnelerinin nasl oluturabileceimize(Strongly Typed Faults).


Yazmzn bandada belirttiimiz gibi, ncelikle istemci tarafna gnderilecek olan mesajn bir veri
szleme olarak tanmlanmas gerekmektedir. Bu amala aadaki gibi bir snf RemoteLib
ierisinde tanmlayabiliriz.

www.bsenyurt.com Page 1125


TabloAdiFault isimli snfmz tipik olarak bir veri szlemesi (data contract) tanmlamaktadr.

using System;
using System.Runtime.Serialization;

namespace RemoteLib
{
[DataContract]
public class TabloAdiFault
{
private string _faultCode;
private string _Message;
private string _Reason;

[DataMember]
public string FaultCode
{
get { return _faultCode; }
set { _faultCode = value; }
}
[DataMember]
public string Message
{
get { return _Message; }
set { _Message = value; }
}
[DataMember]
public string Reason
{
get { return _Reason; }
set { _Reason = value; }
}
public TabloAdiFault(string faultCode,string message,string reason)
{
Reason = reason;
Message = message;
FaultCode = faultCode;
}
}

www.bsenyurt.com Page 1126


}

Burada dikkat edilmesi gereken noktalardan biriside DataContract ve DataMember niteliklerinin


kullanlabilmesi iin System.Runtime.Serialization.dll assembly' nn projeye dahil edilmi olmas
gerekmektedir. (Biz uygulamamz WCF Service Library ablonundan tasarladmz iin bu
assembly' lar otomatik olarak referans edilmi olacaktr.) Artk tanmlam olduumuz bu snfn,
istemcilere FaultException olarak gnderilmesi iin gereken hazrlklar yapabiliriz. ncelikli olarak
bu verinin hangi metodlardan dndrlecekseFaultContract nitelii yardmyla bildirilmesi
gerekmektedir. Bu nedenle servis szlememizde gerekli tanmlamay aadaki gibi yapmamz
yeterli olacaktr.

[ServiceContract(Name="NorthManagerService",Namespace="http://www.bsenyurt.com/NorthSer
vice")]
public interface INorthwind
{
[FaultContract(typeof(TabloAdiFault))]
[OperationContract(Name="GetCustomers")]
DataSet GetCustomers();
}

FaultContract nitelii parametre olarak metoddan dndrlebilecek tipe ait bir bilgi iermektedir.
Bu bilginin istemci tarafna seriletirilerek(Serializable) gitmesi gerektii iin, zaten veri szlemesi
olarak tanmlanmtr. Elbette istisnalar frlatrkende yapmamz gereken baz ilemler olacaktr. Bu
amala GetCustomers metodumuzun ieriini aadaki gibi deitirelim.

public DataSet GetCustomers()


{
DataSet ds = null;
SqlConnection conn=null;
try
{
conn= new SqlConnection("data source=.;database=AdventureWorks;integrated
security=SSPI");
SqlDataAdapter da = new SqlDataAdapter("Select
CustomerID,CompanyName,ContactName,ContactTitle From Customers", conn);
ds = new DataSet("CustomersSet");
da.Fill(ds);
}
catch (SqlException excp)
{
Console.WriteLine(excp.Message);
TabloAdiFault tblFault = new TabloAdiFault("TabloAdi", excp.Message, "Tablo ad
yanl");
throw new FaultException<TabloAdiFault>(tblFault);
}
finally
{
conn.Close();
}
return ds;
}

ncelikle TabloAdiFault snfmz rnekliyoruz. Bu bir exception snf olmadndan istemci tarafna
frlatlabilmesi iin FaultException snfnn ilgili yapc metoduna parametre olarak verilmesi
gerekmektedir. Bu ilem iin Framework ierisinde FaultException snfnn generic bir versiyonu

www.bsenyurt.com Page 1127


kullanlmaktadr. Artk istemci tarafn aadaki gibi kodlayabiliriz. Ancak bu ilemlerin ardndan
istemciler iin gerekli proxy snflarn yeniden oluturmamz gerekecektir.
Dolaysyla svcutil aracn tekrardan ele almalyz. Svcutil aracn kullandmz takdirde oluan
proxy snf ierisinede TabloAdiFault snfnn getirildiini grebiliriz.

ok doal olarak sadece public yeler ve bunlara ilikin alanlar bu snf ierisine dahil edilmitir.
Ama ayn zamanda ExtensionDataObject tipinden deerler ile alan bir zellikte ilave edilmitir
ki bu zellik IExtensibleDataObject arayznden uygulanmaktadr. Artk istemci tarafndaki catch
bloumuzu aadaki gibi kodlayabiliriz.

catch (FaultException<TabloAdiFault> excp)


{
Console.WriteLine("Hata Kodu : "+excp.Detail.FaultCode.ToString() + "\nHata Mesaj : "
+ excp.Detail.Message + "\nSebep : " + excp.Detail.Reason);
}

Detail zellii aslnda generic tipimize ait referans bir baka deyile TabloAdiFault nesne rneini
ele almaktadr.

Dolaysyla Detail zerinden, TabloAdiFault snf ierisinde tanmlanm zelliklere eriebiliriz.


yleki alma zamannda bu zelliklerin deerleri servis uygulamas tarafnda retilip istemci
tarafna tanacaktr. O halde uygulamay deneyip almann sonularn grebiliriz. Aadaki
ekran grntsnde bu sonular yer almaktadr.

www.bsenyurt.com Page 1128


WCF uygulamalarnda hata ynetimi adna sunucu tarafndada yaplmas gerekenler olabilir.
zellikle servisin almas, aldktan sonra kapatlana kadar geen sre ierisinde baz
beklenmeyen sistem hatalar meydana gelebilir. Bu gibi durumlarda istenirse ServiceHost snfna
ait Faulted olay metodu kullanlabilir ve hatalarn ele alnmas salanabilir. Faulted olayn daha iyi
kavrayabilmek iin aslnda bir servisin yaam emberini (life cycle) incelemekte ve hangi
durumlarda Faulted olaynn tetikleneceini bilmekte fayda vardr. Temel olarak bir servis
uygulamasnn oluturulmas (Create), almas (Open), iptal edilmesi (Abort) veya durdurulmas
(Stop) gibi durumlar sz konusudur. Bu durumlar arasnda geiler yaplabilmesi iinde baz
metodlarn arlmas gerekmektedir. Sz gelimi servis nesnesi oluturulduktan sonra amak
iin Open metodu arlr. Bu gibi metod arlar sonrasnda servisin durumu (state) srekli
deiecektir. te bu geiler (transitions) srasnda oluabilecek baz beklenmedik hatalara
karlk Faulted olay ele alnabilir.

ServiceHost snfnn bir servisin durumunu renebilmek


amacyla CommunicationState isimli enum sabitinden deerler dndren State isimli
sadece okunabilir (read-only) bir zellii vardr. Bu enum sabitinin alabilecei
deerler Created, Opening, Opened, Faulted, Closing, Closed dr.

Aadaki izelgede bir servisin alabilecei durumlar, bu durumlar arasnda gei yaplmas iin
gereken metodlar ve Faulted olaynn devreye girebilecei zamanlar ifade edilmeye allmaktadr.

www.bsenyurt.com Page 1129


ekildende greceiniz gibi, Faulted olaynn tetiklenmesi sonrasnda ele alnabilecek senaryolardan
birisi servisin o ana kadar olan tm ilemlerini iptal etmek (Abort) ve servisi tekrardan oluturup
amay denemek olacaktr. Abort metodu arldnda eer askda bekleyen talepler varsa bunlara
cevap verilmesi beklenmez. Oysaki Close metodu arldnda askda bekleyen talepler(request)
var ise bunlar cevaplanr ama emir verildikten sonra istemciden yeni talepler alnmaz. Yukardaki
senaryoyu uygulamak istediimizde servis tarafndaki kodlarmz aada olduu gibi gelitirebiliriz.

using System;
using System.ServiceModel;

namespace ServerApp
{
class Program
{
static ServiceHost host;

static void Main(string[] args)


{
host = new ServiceHost(typeof(RemoteLib.NorthManager));
host.Faulted += delegate(object sender, EventArgs e)
{
host.Abort();
host = new ServiceHost(typeof(RemoteLib.NorthManager));
host.Open();
};
host.Open();

www.bsenyurt.com Page 1130


Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
host.Close();
}
}
}

Dikkat ederseniz Faulted olay metodu ierisinde nce servis Abort metodu ile iptal edilmekte,
sonrasnda servis nesne rnei oluturulmakta ve servis tekrar almaya allmaktadr. Bu olay
metodu ierisinde loglama ilemleride yaplarak hatalarn daha kolay izlenmesi salanabilir.

Bu makalemizde WCF uygulamalarnda hata ynetimini farkl ekillerde ele almaya altk.
zellikle hata ynetiminin basit bir istisna ynetiminden ok daha farkl olmamakla birlikte farkl
platformlarn sz konusu olduu datk bir ortamda daha titiz bir biimde ele alnmas gerektiini
rendik. Bunlarn dnda istemci tarafnda oluacak hatalarn sunucuya gnderilmesi istenebilir.
Ancak istemcilerinin Java gibi farkl platformlar olabilecei gz nne alnrsa istemcinin sunucuya
gnderecei mesajlarn Soap Fault' a uygun olmas gerekecektir. Bu konuyu inceleyip ilerleyen
makalelerimizde ele almaya alacaz. Bylece geldik bir makalemizin daha sonuna. lerleyen
makalelerimizde WCF mimarisinin detaylarn incelemeye devam ediyor olacaz. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

WCF-Windows ve Windows Service Hosting (


04.05.2007 ) - WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation ile iliikili nceki makalelerimizde mimarinin temellerinden ve


bir WCF sevisinin Internet Information Services (IIS) zerinden nasl yaymlanabileceini
incelemitik. Bu makalemizde ise Host uygulama olarak windows uygulamalarn ve windows
servislerini ele almaya alacaz. Gelitireceimiz uygulamalarda ncekilerden farkl olarak
konfigurasyon dosyalarn kullanmayp, programatik kod paralarndan yararlanacaz. Ayrca, HTTP
yerine TCP protokol zerinden haberlemeyi kullanyor olacaz.

Bildiiniz gibi WCF mimarisinde szlemeleri(Contracts) sunan uygulamalar, sadece IIS zerinden
yaynlanmak zorunda deildir. Bu ablon dnda windows uygulamalarn
(HattaWPF uygulamalarn) ve windows servislerinide kullanabiliriz. zellikle windows servisleri
(Windows Service), bulunduklar makine zerinde otomatik olarak balatlabildiklerinden,
ynetilebilirlikleri daha kolaydr ve zellikle windows tabanl intranet sistemlerinde tercih edilirler.
zellikle .Net Remoting zerine yazlan sistemlerde windows servisleri yaygn olarak
kullanlmaktadr.

WCF servislerinin ABC' sinden (AddressBindingContract) hatrlayacanz zere balayclar


(Binding) bizim iin pek ok zorluun stesinden gelmektedir. Daha nceki makalelerimizde
gelitirdiimiz WCF rnek uygulamalarnda sadece BasicHttpBinding tipinden faydalandk. Oysaki
projenin ihtiyacna ve artlara gre dier balayc tipleride gz nne alabilir ve kullanabiliriz. Bu
noktada balayc tipleri (Binding Types) biraz daha tanmakta fayda olaca kansndaym.
Balayc tipler temel olarak istemcilerin, bir servis ile iletiime nasl geebilecei konusunda baz

www.bsenyurt.com Page 1131


esaslar otomatik olarak belirlemekte rol alan varlklar olarak tanmlanabilir. Sz gelimi,
istemcilerden kabul edilebilecek mesajlarn neler olacan balayc tipler yardmyla belirleyebiliriz.
stemciler, servislere eriirken eitli iletiim protokollerini kullanacaktr. rnein HTTP veya TCP.
HTTP intranet dnda internet zerindende kullanlabilecek bir ortam salarken, TCP zellikle
intranet ortamnda maksimum performans salayacak nitelikte bir alt yap salamaktadr. Balayc
tipler bu protokoln ne olacann belirlenmesinde etkin rol oynar. Sz
gelimi BasicHttpBinding tipi HTTP protokol zerinden iletiime geilmesi iin gerekli olan alt
yapy salamaktadr.

Baz WCF servis uygulamalarnda, birden fazla endPoint tanmlamas sklkla uygulanan
bir tekniktir. Sz gelimi intranet tabanl sistemler iin TCP tabanl bir balayc
tipi(Binding) ierecek bir endPoint ile birlikte, internet zerinden gelen isteklere ynelik
olarak , HTTP tabanl ve XML formatnda zmleme yapabilecek bir balayc tipi
kullanacak endPoint tanmlamalar bir arada ele alnp kullanlabilir.

Dier taraftan istemciler ve servis arasnda tanacak olan verinin nasl formatlanacanada
balayc tipler karar vermektedir. Burada sz konusu olan formatlama, verinin XMLolarak m
yoksa binary olarak m seriletirileceidir. Yine binary formatta seriletirme, zellikle intranet gibi
sistemlerde hz ve performans salayacaktr. zellikle image gibi byk boyutlu veri yaplarnn
binary formatta transfer edilmesi performans asndan nemli bir kriterdir. Balayclarn etkin
olarak rol aldklar dier noktalar servisin gvenilirliinin nasl salanaca (reliability) ve
servisin transaction ieren bir operasyonda grev alp almayacadr. Bu ve benzeri kriterler gz
nne alndnda,System.ServiceModel isim alan altnda yer alan nceden tanml balayc
tipler hazr zmler sunmaktadr. Bu elbetteki kendi balayc tiplerimizi yazamayacamz
anlamna gelmemelidir. Dilersek bunuda yapabiliriz. rneklerimizde TCP prokoln ve binary
seriletirmeyi tercih edeceimizden, bununla ilgili olan balayc tipi kullanabiliriz.

Bu ksa bilgilerden sonra dilerseniz rneklerimizi adm adm gelitirmeye balayalm. lk olarak
servis szlememizi (Service Contract) ve bu szlemeyi uygulayacak tipimizi yazmamz
gerekiyor. Amacmz kod tarafnda servisi tesis etmek ve kullanmak olduundan mmkn olduu
kadar basit bir szleme ve tip tanmlamas yapacaz. Bu amala aadaki tipleri ierecek
AritmetikLib isimli bir snf ktphanesi (class library) gelitirerek ie balayabiliriz.

Servis Szlememiz;

using System;
using System.ServiceModel;

www.bsenyurt.com Page 1132


namespace AritmetikLib
{
[ServiceContract(Name="CebirciServisi",
Namespace="http://www.bsenyurt.com/CebirciServisi")]
public interface IAritmetikContract
{
[OperationContract]
double Toplam(double x, double y);
}
}

Servis szlememiz herzamanki gibi bir arayzdr(Interface). Dier tarafan istemcilere


sunulabilecek olan operasyonumuz basit olarak bir Toplama ilemi yapmaktadr. zel
olarakServiceContract isimli niteliimizin Name ve Namespace zelliklerine baz deerler atadk.
Name ve Namespace zellikleri, szlemeye ait WSDL (Web Service Description Language)
elementi ierisindeki ilgili deerleri belirlemekte kullanlmaktadr ve daha sonradan bu szlemenin
istemciler iin gerekli olan proxy snfn retilirken ele alnacaktr.

Szlemeyi uyarlayan tipimiz;

using System;

namespace AritmetikLib
{
public class Cebirci:IAritmetikContract
{
#region IAritmetikContract Members
public double Toplam(double x, double y)
{
return x + y;
}
#endregion
}
}

Cebirci isimli snfmz basit olarak servis szlemesi olan IAritmetikContract isimli arayz
(interface) implemente etmektedir. Servis szlememizi ve tipimizi tanmladktan sonra artk
Windows tabanl Host uygulamamz gelitirmeye baalayabiliriz. Sz konusu uygulamamzn n
yzn aadaki gibi tasarlayabiliriz.

Balat balkl dmeye basldnda, windows uygulamamz ServiceHost snfna ait bir nesneyi
rnekleyerek istemcilerden(Clients) gelecek olan talepleri dinlemeye balayacaktr. Tam tersine

www.bsenyurt.com Page 1133


Durdur balkl dpmeye bastmzda ServiceHost nesne rnei ile alan kanallar kapatlacak ve
Host uygulama artk istemcilere cevap vermeyecektir. Bu ilemler srasnda servisin durumuda
label kontrol ierisinde gsterilecektir. Balamadan nce WCF tiplerini uygulamamz ierisinde ele
alabilmek ve az nce gelitirdiimiz servis szlemesi ve tipimizi kullanabilmek iin
srasyla System.ServiceModel.dll ve AritmetikLib.dll isimli assemblylermz uygulamamza
referans etmemiz gerekmektedir.

Artk uygulamamzn kodlarn aadaki gibi gelitirebiliriz.

using System;
using System.ServiceModel;
using System.Windows.Forms;
using AritmetikLib;

namespace HostApp
{
public partial class Form1 : Form
{
private ServiceHost srvHost;

public Form1()
{
InitializeComponent();
}

private void btnBaslat_Click(object sender, EventArgs e)


{
srvHost = new ServiceHost(typeof(Cebirci));
srvHost.AddServiceEndpoint(typeof(IAritmetikContract), new NetTcpBinding(),
"net.tcp://localhost:4501/CebirciServisi");
srvHost.Open();
lblServisDurumu.Text = srvHost.State.ToString();
btnBaslat.Enabled = false;
btnDurdur.Enabled = true;
}

private void btnDurdur_Click(object sender, EventArgs e)


{
srvHost.Close();
lblServisDurumu.Text = srvHost.State.ToString();
btnDurdur.Enabled = false;
btnBaslat.Enabled = true;

www.bsenyurt.com Page 1134


}
}
}

btnBaslat dmesine ait Click olay metodu ierisinde ilk olarak ServiceHost nesnemiz
rneklenmektedir. Yapc metoda(Constructor), Cebirci snfn tipi verilmitir. Bir baka deyile
servis szlemesini uyarlayan tip bildirilmektedir. Servislerin, istemcilerden gelen
talepleri endPoint' ler yardmyla aldn biliyoruz. Bir endPoint ierisinde adres , balayc
tipve szleme bilgilerininde yer almas gerekiyor. Bu nedenle, ServiceHost snfmza ait nesne
rneimize AddServiceEndPoint metodu yardmyla bir endPoint eklemekteyiz. Bu metodun ilk
parametresi servis szlememize ait tipi temsil etmektedir. kinci parametrede dikkat
ederseniz NetTcpBinding tipinden bir nesne rnei verilmektedir. Birbaka deyile TCP protokol
zerinden, binary formatta zmleme kullanlarak iletiime geileceini bildirmi oluyoruz. Son
parametre ise servisimizdeki bu endPoint' e nasl ulalabilecei bilgisini iermektedir. Bu
parametrede makine ad, iletiim protokol, port numaras ve nesne takma ad gibi bilgiler yer
almaktadr.

Bu admlardan sonra tek yaplmas gereken servisin dinlemeye balamasn salamaktr. Bu amala
ServiceHost tipinden nesne rneimizin Open metodunu kullanyoruz. btnDurdur isimli dmemize
ait Click olay metodunda ise Close metodu arlarak servisin kapatlmas salanmaktadr.
stemciyi yazmadan nce windows uygulamasn balatarak test edebilirsiniz. Eer sistemde ykl
bir Firewall var ise, 4501 numaral portun almasna karn bir uyar mesaj verecektir. Bunu kabul
ederek devam etmek gerekmektedir. Aksi takdirde portun kullanlmas engelleneceinden,
istemcilere cevap verilemez ve servis almaz.

Bir Host uygulama herhangibir iletiim portunu kullanarak hizmet vermeye baladnda,
baka bir Host uygulama ayn makine zerindeki ayn iletiim portunu kullanamaz. Byle
bir durumuda alma zaman istisnas (Runtime Exception) alnacaktr.

Artk istemci tarafn programlayabiliriz. Bildiiniz gibi WCF sisteminde yer alan istemcilerimiz,
servislere ait endPoint' ler ile haberleirken proxy snflarn kullanmaktadrlar. uanki
senaryomuzda servisimizi IIS zerinden host etmediimiz iin HTTP tabanl olacak ekilde
metadata publishing yapamamaktayz. Ancak svcutil.exe arac ile AritmetikLib isimli dll' imizden
yararlanarak istemci iin gereken proxy snf ve konfigurasyon dosyalarn rettirebiliriz. Bu amala
ArtimetikLib.dll ' ini herhangibir yerden svcutil arac ile aadaki gibi ele almalyz.

svcUtil AritmetikLib.dll

www.bsenyurt.com Page 1135


SvcUtil aracn bu ekilde kullandmzda library ierisinde yer alan servis szlemesi ve tiplerden
yararlanlaraktan bir takm metadata ve ema dosyalar retilecektir.

ok basit olarak dnecek olursak, bu dosyalarn istemciler iin gereken proxy snflarn retmek
amacyla kullanlabileceini dnebiliriz. Sonu itibariyle IIS zerinden yaplan Host ilemlerindede
bir WSDL dkman gerekmektedir ki burada bu
ii www.bsenyurt.com.CebirciServisi.wsdl isimli dosya stlenmektedir. Bu ilemin ardndan
yine svcutil aracn aadaki gibi kullanarak istemciler iin gerekli proxy snf ve konfigurasyon
dosyasn retebiliriz. (Buradaki dosya isimlerinin tesadf olmadn syleyelim.
Hatrlarsanz ServiceContract niteliimizin Namespace zelliine
http://www.bsenyurt.com/CebirciServisi deerini vermitik.)

svcutil www.bsenyurt.com.CebirciServisi.wsdl *.xsd /out:AritmetikClient.cs

Komut baarl bir ekilde alt takdirde istemciler iin AritmetikClient.cs ve output.config isimli
fiziki dosyalar retilecektir. Oluturulan proxy dosyas ierisinde CebirciServisi,
CebirciServisiChannel isimli iki arayz yer almaktadr. stemci tarafndan rneklenerek
kullanlabilecek olan CebirciServisiClient isimli snf CebirciServisi isimli arayz uygulamakatadr.
Servis ile iletiimde nemli bir rol stelenen kanal temsil eden CebirciServisiChannel isimli tipimiz
ise hem CebirciServisini hemde IClientChannel arayzn uygulamaktadr. IClientChannel
arayz temel olarak istemciler iin taban arayzdr(base interface) ve WCF iletiimi iin gerekli
alma zaman fonkisyonellikleri salamaktadr. rnein kanaln alma zamannda almas veya
dispose edilmesi gibi ilemlerin yaplmasn salayan fonksiyonellikler ierir. (Bunun gibi mimari
detaylar ilerleyen makalelerimizde ele almaya alacaz.)

www.bsenyurt.com Page 1136


Artk istemci uygulamamz gelitirmeye balayabilir ve az nce retilen proxy tipimizi burada
kullanarak sunucu ile iletiime geebiliriz. lemlerimizi basit bir ekilde ele almak amacyla
istemcimizi sradan bir Console uygulamas olarak tasarlayacaz. Uygulamamzn
yine System.ServiceModel assembly' n referans etmesi ve komut satrndan SvcUtil arac
yardmyla rettiimiz proxy snfn iermesi gerekmektedir.

Output.config dosyasn istemci uygulamaya eklemek zorunda deiliz. u aamada istemci


tarafndan servisi armak iin gerekli ayarlar programatik olarak yapyor olacaz. lgili referans
ve proxy tipini ekledikten sonra kodlarmz aadaki gibi gelitirebiliriz.

using System;
using System.ServiceModel;

www.bsenyurt.com Page 1137


namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Devam etmek iin tua basn");
Console.ReadLine();
CebirciServisiClient client;
client = new CebirciServisiClient(new NetTcpBinding(), new
EndpointAddress("net.tcp://localhost:4500/CebirciServisi"));
Console.WriteLine(client.Toplam(4, 5).ToString());
Console.ReadLine();
}
}
}

lk olarak CebirciServisiClient isimli snfmza ait bir nesne rnei oluturuyoruz. Bunu
gerekletirirken yapc metodumuza ilk parametre olarak NetTcpBinding tipinden bir nesne
rnei atanmaktadr. Sunucu tarafnda NetTcpBinding tipini kullandmz iin istemci tarafndada
uygun bir balayc tipin kullanlmas gerekmektedir. kinci parametre olarak
bir EndpointAddress nesne rnei oluturulmaktadr. Bu snfn yapc metodunda verdiimiz
adres ise, servis tarafnda belirttiimiz eriim adresidir. Son olarak uzak nesne metodumuzu
altrmaktayz. Artk istemcimizi test edebiliriz. Elbetteki nce sunucu uygulamann altrlmas
ve servisin almas gerekmektedir. Eer sunucu uygulama zerinden servis almadan istemci
altrlrsa aadaki gibi alma zaman hatas(Runtime Exception) alrz.

Exception mesaj zellikle .Net Remoting uygulamalar gelitirenler iin tandk bir cmle
iermektedir. No Connection could be made because the target machine actively refused
it. :) Bu ayn zamanda istemcimizin gerekten belirtilen adreste kendisini dinleyecek bir WCF servis
uygulamas aradnnda bir gstergesidir. Aadaki flash animasyonunda basit olarak sistemimizin
nasl alt gsterilmektedir.

www.bsenyurt.com Page 1138


Gelelim Windows uygulamasndan sunmu olduumuz hizmeti bir windows servisi zerinden nasl
sunacamza. Aslnda WCF tarafndan baktmzda sadece windows servisi ortamna ayak
uydurmamz yeterli olacaktr. Gelin rneimiz zerinden devam edelim. lk olarak solution' mza
bir Windows Service projesi eklememiz gerekiyor. Projemizi oluturduktan sonra, her zaman
olduu gibi System.ServiceModel.dll isimli assembly' n ve servis szleemesi ile uzak nesne
snfn barndran snf ktphanemizin (AritmetikLib.dll) referans edilmesi gerekmektedir.

Windows servisleri, web servislerine benzer olarak herhangibir grsel arabirime sahip deildir.
yapan metodlar, olay tabanl almaktadr. Dolaysyla ilgili servis, windows iletim sisteminin
servislerine eklendikten sonra, balatlmas, durudurulmas yada hata olumas gibi durumlarda
yaplmas gereken kodlar ilgili olay metodlarna yazlmaktadr. Bizim windows servisimiz
balatldnda uzak nesneleri istemci uygulamalarn hizmetine sunacak ekilde dinlemede
olmaldr. Dier taraftan servis kapatldnda ise, Host uygulamann kulland serviceHost nesne
rnei artk istemcilere cevap vermeyecek ekilde kapatlmaldr. Bu duruma gre servis snfmzn
kodlar aadaki gibi olmaldr.

using System;
using System.Collections.Generic;
using System.ServiceProcess;
using System.ServiceModel;
using AritmetikLib;

namespace AritmetikWinServis
{
public partial class Service1 : ServiceBase
{
private ServiceHost srvHost;

public Service1()
{
InitializeComponent();
}

protected override void OnStart(string[] args)


{

www.bsenyurt.com Page 1139


srvHost = new ServiceHost(typeof(Cebirci));
srvHost.AddServiceEndpoint(typeof(IAritmetikContract), new NetTcpBinding(),
"net.tcp://localhost:65001/CebirciServisi");
srvHost.Open();
}

protected override void OnStop()


{
srvHost.Close();
}
}
}

Dikkat ederseniz makalemizin banda gelitirdiimiz Windows uygulmasndaki kodlarmzdan okda


farkl bir ilem gerekletirmiyoruz. Servis OnStart olay metodu ierisinde oluturulurken,
endPoint' in eklenmesi ve almasda burada yaplmaktadr. Benzer ekilde OnStop olay metodu
ierisinde servisimiz kapatlmaktadr. Bundan sonraki admlarmzda servisimizi windows
sistemine install etmek iin gerekli ilemleri yapmamz gerekmektedir. Sz konusu admlar
makalemizin konusu dnda olduundan yzeysel olarak ele alnacaktr. ncelikli olarak
servisimize Add Installer seenei ile gereken ykleyici tipleri ekliyoruz.

Bu ilemin sonucunda servise ServiceProcessInstaller ve ServiceInstaller tiplerinden iki adet


bileen eklenecektir.

ServiceProcessInstaller bileeninin yelerinden Account zelliinin deerini Local System olarak


ayarlayalm. ServiceInstaller bileenimizin, Display Name zelliine Aritmetik Servis deerini
atayalm. Bu sistem servislerine baktmzda, gelitirdiimiz windows servisini bulmamz
kolaylatracaktr. Uygulamamz derlendikten sonra iletim sistemine yklenmeye hazr hale
gelecektir. Ykleme ilemi iin Visual Studio 2005 Command Prompt
zerindeyken installUtil aracn aadaki gibi -i parametresi ile kullanmamz gerekmektedir.

www.bsenyurt.com Page 1140


InstallUtil arac ilemleri baarl bir ekilde tamamladktan sonra servislerde, eklemi olduumuz
windows servisi grlebilir.

Sisteme yklediimiz servisi kaldmak iin installUtil aracnn -u parametresini


kullanmak gerekmektedir.

www.bsenyurt.com Page 1141


Servisimizi buradan altrdmzda artk istemciler tarafndan kullanlabilir hale gelecektir. stemci
tarafnda tek yapmamz gereken port bilgisini deitirmek olacaktr. rnein bu makalede
gelitirdiimiz Console uygulamasnn kodlarn aadaki gibi deitirmek yeterlidir.

CebirciServisiClient client;
client = new CebirciServisiClient(new NetTcpBinding(), new
EndpointAddress("net.tcp://localhost:65001/CebirciServisi"));
Console.WriteLine(client.Toplam(4, 5).ToString());

Mimarinin yine doru bir ekilde tesis edildiini kontrol etmek adna, gelitirilen servis kapal iken
istemci uygulama altrlabilir. Eer "No Connection could be made because the target
machine actively refused it" hatas alnabiliyorsa, istemcinin gerektende sunucu servisi
aradn anlayabiliriz. Elbette servis altrldktan sonrada istemciyi test edip hereyin yolunda
gittiinden emin olmakta fayda vardr. Aadaki Flash animasyonunda bu durum gsterilmektedir.

Bu makalemizde WCF mimarisinde yer alan Host uygulama modellerinden Windows ve Windows
Servislerini ksaca incelemeye altk. Ayn zamanda, konfigurasyon dosyas kullanm yerine kod
tarafnda neler yapabileceimize deindik. zellikle TCP tabanl bir binding tipi
kullandmzda(NetTcpBinding), bir baka deyile HTTP zerinden Metadata yaynlanmas sz
konusu olmadnda, istemciler iin gerekli olan proxy snflarnn svcutil arac yardmyla nasl
kolay bir ekilde retilebileceine bakmaya altk ve bylece bir makalemizin daha sonuna geldik.
lerleyen makalelerimizde WCF mimarisinin detaylarn incelemeye devam ediyor olacaz. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

WCF - Adm Adm IIS Hosting ( 28.04.2007 ) -


WCF
Deerli Okurlarm Merhabalar,

Windows Communication Foundation ile ilikili bir nceki makalemizde mimarinin detaylarna
yakndan bakmaya alm ve rnek bir uygulama gelitirmitik. Bu makalemizde ise birWCF
Service projesi gelitirmeye alacaz. Bir baka deyile HTTP protokoln
kullanarak, IIS zerinden bir .Net ktphanesini servis olarak yaynlayacaz.

www.bsenyurt.com Page 1142


WCF servislerini Self Hosting ve IIS Hosting olmak zere iki farkl ekilde
yaynlayabiliyoruz. Bununla birlikte Self Hosting modeli kendi
ierisinde Console, Windows, Windows Service ve Vista ile gelen Windows
Activation Service (WAS) olmak zere drt farkl seenekten olumaktadr.

Ayrca kendi tiplerimizi dndren metodlar sz konusu olduunda veri


szlemelerini(DataContract) nasl kullanabileceimize yakndan bakma frsat bulacaz. Bunlara
ek olarak zellikle .Net Remoting mimarisinde bizi her zaman zorlayan konfigurasyon
ayarlarnn(ou zaman ezberlemek zorunda olduumuz ve hatrlamakta glk ektiimiz), WCF
ierisinde Edit WCF Configuration seenei yardmyla Visual Studio 2005 ierisinden grsel
olarak nasl daha kolay hazrlanabileceinide incelemeye alacaz.

Aslnda IIS(Internet Informatin Service) zerinden eitli tipte istemcilerin (hangi platformda
olduklarna baklmakszn) belirli fonksiyonellikleri kullanabilmesi amacyla Xml Web
Servisleri (Xml Web Services) olduka fazla kullanlan bir SOA (Service Oriented
Architecture) modelidir. Dolaysyla WCF ierisinde de buna benzer bir model vardr ve WCF
Serviceolarak adlandrlmaktadr. Visual Studio 2005 iin, Framework 3.0' a ynelik eklentileri
yklediinizde Web Site ablonlar arasnda WCF Service seeneide gelmektedir. Ancak biz bunu
kullanmayp biraz daha elle ilerleyeceiz ve alt yap ierisinde yer alan paralar daha net olarak
grmeye alacaz. Konuyu daha iyi kavrayabilmek iin rnek bir senaryo zerinden gideceiz ve
baz basit veritaban ilemlerini ele alacaz. Gelin hi vakit kaybetmeden ie balayalm ve adm
adm ilerleyelim.

Bildiiniz gibi WCF tamamen nitelik(attribute) tabanl bir mimariye dayanmaktadr. Bununla
birlikte istemci tarafna yaynlanacak olan, baka bir deyile metadata ierii gnderilecek olan
tip(type) aslnda ilgili nitelikler ile imzalanm bir szleme(contract) dir. Szlemeler genellikle bir
arayz eklinde tasarlanmakta olup asl ilevsellikleri yerine getirecek olan uzak nesne
modellerinin(snflar) tretilmesinde de kullanlr.

.Net Remoting mimarisinden hatrlarsanz eer; uzak nesneleri (Remote


Objects) yaynlamada ele alnan modellerden birisi arayz(Interface) kullanmn
iermektedir. Burada temel ama istemci tarafnda, sunucuda rneklenen uzak nesne
referansn tayabilecek bir tip olmasdr. Bununla birlikte istemci tarafnn kesin olarak
uzak nesne fonksiyonelliklerinin nasl altn grmesi gibi bir ans yoktur. (Elbette bu
durum MarshalByReference nesneler iin geerlidir. Bildiiniz
gibiMarshalByValue tipler zaten sunucuda rneklenip istemci tarafna tm varl ile
seriletirilerek(Serialization) geerler). Ayrca, sunucu tarafndaki uzak nesne
metodlarnn i yaplarnda meydana gelecek deiiklilikler sonucu, istemcilere yeniden
datm(deployement) ilemi uygulanmasna gerek kalmamaktadr.

yleyse ilk yapmamz gereken ierisinde servis szlemesini(Service Contract) ve gerekli


fonksiyonelliklere ait tanmlamalar barndracak bir arayz(interface) tasarlamaktr. rneimizde,
WCF servisimizi IIS zerinden sunacamzdan bahsetmitik. Bu sebepten ilk olarak bir snf
ktphanesi(class library) gelitirmeli ve bu ktphane ierisine servis szlememizi(Service
Contract), uzak nesnemizin modelini(class), veri szlemesine(Data Contract) sahip tipimizi
katmalyz. Sonrasnda IIS zerinden ilgili ktphanemizi iaret edecek bir sanal klasr (virtual
path) oluturmalyz. Yaynlama ortam IIS olduundan, WCF iin gerekli konfigurasyon
ayarlarn web.config dosyas ierisinde tutmamz gerekmektedir. Bu noktada konfigurasyon
ayarlarn grsel bir arayz kullanarak kolay bir ekilde oluturabiliriz. Dier taraftan ayn web
servislerinde olduu gibi asmx uzantl dosyalarn grevini stlenen svc uzantl bir dosya
oluturmalyz.

lk olarak bilgisayarmzn herhangibir yerinde konulandrlacak bir snf ktphanesi (class library)
projesi oluturalm. UrunKutuphanesi isimli projemizi yine .Net Framework 3.0 sonras Visual

www.bsenyurt.com Page 1143


Studio 2005 iin gelen eklentilerden WCF Service Library olarak aabiliriz. Ama bu ablon
yoksada nemli deildir. nk yapmamz
gereken System.ServiceModel,System.Runtime.Serialization ve System.IdentityModel asse
mbly' larn referans edecek olan bir proje gelitirmektir. (Bu assembly' larn .Net Framework 3.0 ile
geldiklerine dikkat edelim.)

Snf ktphanemiz ierisinden, AdventureWorks ierisindeki tablolara ilikin baz hizmetler


vereceiz. Bunlardan biriside HumanResources emasndaki Employee tablosundan herhangibir
alan bilgisini dndrecek bir metod olacaktr. Lakin bu metodun dnnde biz kendi
gelitireceimiz snfmza ait bir nesne rneini dndreceiz. Bu nedenle ilk olarak aadaki gibi
bir snf, ktpanemiz ierisine katarak ie balayabiliriz.

[DataContract]
public class Employee
{
[DataMember]
public int EmployeeId;

[DataMember]
public string Title;

[DataMember]
public DateTime BirthDate;

[DataMember]
public int VacationHours;

www.bsenyurt.com Page 1144


public Employee()
{
}
public Employee(int id, string title, DateTime birth, int vacation)
{
EmployeeId = id;
Title = title;
BirthDate = birth;
VacationHours = vacation;
}
}

Employee isim snfmz ok basit olarak bir ka public alan(Field) ile, ar yklenmi(overload) ve
varsaylan yapc(default constructor) metodlar iermektedir. Ancak burada asl dikkat edilmesi
gereken snfn ve yelerin nitelikleridir. Dikkat ederseniz snfmz DataContract nitelii(attribute)
ile, public olan alanlarmz ise DataMembernitelikleri ile iaretlemi durumdadr. DataContract ve
DataMember isimli niteliklerimiz System.Runtime.Serialization isim alan altnda yer alan
snflardr. Bylece servisimizin dndrecei zel bir tip iin gerekli veri szlemesini bildirmi
bulunuyoruz.

Eer servis metodlarmz geriye ilkel tipler dndrmyorsa (int, double, string gibi), zellikle
Employee gibi gelitirici tarafndan tasarlanm tipler sz konusu ise mutlaka bir veri
szlemesinin(data contract) tanmlanmas gerekmektedir. (lerleyen makalelerimizde veri
szlemelerine daha detayl bir ekilde bakmaya alacaz.) Artk kendi veri szlememizide(Data
Contract) tanmladmza, bir baka deyile servisteki ilgili metoddan geriye nasl bir tip
dndrleceini bildirdiimize gre, i yapan metodlarmz ierecek tip iin gerekli servis
szlemesini (service contract) yazarak ilemlerimize devam edebiliriz. IAdventure isimli
arayzmn ierii aada grld gibidir.

[ServiceContract(Name="Adventure Works Services")]

www.bsenyurt.com Page 1145


public interface IAdventure
{
[OperationContract]
Employee GetEmployee(int employeeId);

[OperationContract]
DataSet GetAllProducts();

[OperationContract]
List<string> GetAllSubCategoryNames();

[OperationContract]
double AverageSubTotalFromHeaders();
}

IAdventure arayzmze(interface) ait yelerde zellikle eitli tiplerden dn deerleri


kullanmaya altk. Bildiiniz gibi, yazacamz servisin istemciler tarafndan kullanlacak bir
szlemesi olmas gerekmektedir. Herhanbiri arayzn veya snfn bir servis szlemesi (Service
Contract) salayacan bildirmek iinServiceContract nitelii ile imzalamak gerekmektedir.
Benzer ekilde servisin sunabilecei metodlar bildirmek iinse OperationContract isimli nitelik
kullanlmaktadr. ServiceContract ve OperationContract isimli
nitelikler(attributes), System.ServiceModel isim alan(namespace) altnda yer almaktadr.

Servis szlememizi tanmladktan sonra, uzak nesne olarak asl i yapan metodlar tayacak ve
istemcilerin bavuruda bulanabilecei snf tasarlayabiliriz.AdventureManager isimli snfmz
hereyden nce IAdventure arayzn uyarlamaldr(Implementation).

class AdventureManager:IAdventure
{
#region IAdventure Members

public Employee GetEmployee(int employeeId)


{
Employee emp=null;
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select EmployeeId,Title,BirthDate,VacationHours
From HumanResources.Employee Where EmployeeId=@EmpId", conn);
cmd.Parameters.AddWithValue("@EmpId", employeeId);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();

www.bsenyurt.com Page 1146


if (dr.Read())
{
emp = new Employee();
emp.EmployeeId = Convert.ToInt32(dr["EmployeeId"]);
emp.Title = dr["Title"].ToString();
emp.VacationHours = Convert.ToInt32(dr["VacationHours"]);
emp.BirthDate = Convert.ToDateTime(dr["BirthDate"]);
}
dr.Close();
}
return emp;
}

public DataSet GetAllProducts()


{
DataSet ds=null;
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlDataAdapter da = new SqlDataAdapter("Select
ProductId,Name,ListPrice,Class,SellStartDate From Production.Product", conn);
ds = new DataSet();
da.Fill(ds);
}
return ds;
}

public List<string> GetAllSubCategoryNames()


{
List<string> categoryNames = null;
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select ProductSubCategoryId,Name From
Production.ProductSubCategory Order By Name", conn);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();
categoryNames = new List<string>();
while (dr.Read())
{
categoryNames.Add(dr["Name"].ToString());
}
dr.Close();
}
return categoryNames;
}

public double AverageSubTotalFromHeaders()


{
double average=0;
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("Select Avg(SubTotal) From
Sales.SalesOrderHeader", conn);
conn.Open();

www.bsenyurt.com Page 1147


average = Convert.ToDouble(cmd.ExecuteScalar());
}
return average;
}

#endregion
}

AdventureManager isimli snfmz ierisinde kullandmz metodlar basit Ado.Net


fonksiyonelliklerini ele alarak farkl tiplerde sonular retmektedir. Konumuz WCF olduu iin
metod ierisindeki kod paralarnn ileyi ekline ok fazla deinmeyeceiz. Srada servis iin
gerekli sanal klasrn, svc dosyasnn ve web.config dosyasnn oluturulmas admlar yer
almaktadr.

lk olarak IIS zerinde sanal klasrmz oluturalm. zellikle IIS zerinden host edilen assembly'
lar gz nne alndnda, dll' in Bin klasr altnda yer almas ve Bin klasr ile ayn seviyede
bir web.config dosyas olmas gerekmektedir. Sz konusu web.config dosyas uzak nesne
kullanm iin gerekli alt yap ayarlarn barndrmaktadr. rneimizde IIS altna aacamz sanal
klasr(Virtual Directory) iinde ayn durumu ele almak istediimizden proje zelliklerine
girip Build sekmesinde yer alan Output Path zelliinin
deerinin bin\debug adresinden bin\ adresine ekilmesi yeterli olacaktr. Bylece, kodda
yapacamz deiikliker annda canl ortamada yansyacaktr.

Bu tarz bir ilem zorunlu deildir. Sanal Klasrn(Virtual Directory) iaret edecei baka bir fiziki
adreste belirlenebilir ancak yine Bin klasrnn olmas, dll' in kopyasnn burada yer almas ve bin
ile ayn seviyede bir web.config dosyasnn alt yap ayarlarn ierecek ekilde olmas arttr.
rneimizde, yapacamz derlemelerin annda yansmalarn test edebilmek amacyla bu tarz bir
n hazrlk yapmay tercih ediyoruz. Artk IIS altnda sanal klasrmz oluturabiliriz. Aadaki
flash animasyonunda basit olarak IIS zerinde yapmamz gereken admlar gsterilmektedir. (Flash
animasyonunun boyutu 187 kb olup yklenmesi zaman alabilir.)

www.bsenyurt.com Page 1148


Makalemizde ilerlemeden nce Web servisleri ile HTTP zerinden iletiime geerken devreye giren
asmx uzantl dosyalar gz nne almamzda fayda olacaktr. Sonu itibariyle WCF servisimizi IIS
zerinden host ederken asmx ile ayn amaca ynelik bir dosya var olmaldr ki bu sayede istemciler
URL zerinden servis metadata ieriini talep edebilsinler. te WCF iin bu grevi yerine
getiren svc uzantl bir servis dosyas olacaktr. Bu dosya ayn zamanda EndPoint iin gerekli
adres tanmlanrkende ele alnacaktr. (Bildiiniz gibi bir WCF servisi ierisinde birden fazla EndPoint
yer alabilir ve bunlarn ayrt edici zelliklerinden biriside adresleridir.) Bu nedenle projemize
aadaki ierie sahip olan svc uzantl bir dosya eklememiz gerekmektedir. Bu dosya tipini eler
arasndan bulamayabilirsiniz. Bu nedenle bo bir text dosyasn svc uzants ile kaydederek sorunu
aabiliriz.

<%@ServiceHost Service="UrunKutuphanesi.AdventureManager"%>
<%@Assembly Name="UrunKutuphanesi"%>

Svc dosyamz ierisinde iki direktif yer almaktadr. ServiceHost direktifi ierisinde Service' e ait tip
bilgisi yer alr. Bir baka deyile uzak nesne grevini stlenecek olan tipimizi bildiririz. Dikkat
ederseniz notasyon olarak isimAlan.tipAd format kullanlmtr. Assembly direktifinde ise sz
konusu tipin, ierisinde yer ald assembly ad bildirilmektedir.

www.bsenyurt.com Page 1149


Artk web.config dosyamz iin gerekli konfigurasyon tanmlamalarn yapabiliriz. (Yada grsel
aracmz yardmyla kolayca ina edebiliriz :) ) Bu amala projemize yeni birApplication
Configuration File esi (Item) ekleyelim ve ismini web.config olarak deitirelim.
Konfigurasyon ayarlarmz yapmak iin web.config dosyamza sa tklayp, Edit WCF
Configuration seeneini iaretlememiz yeterli olacaktr.

Edit WCF Configuration vastasyla alan yardmc arabirim aslnda, IIS zerinde yer alan Asp.Net
sekmesindeki Edit Configuration linki yardmyla alana benzemektedir. Ancak kullanm amac
tamamyla WCF' a yneliktir ve daha da nemlisi IDE dna kmadan gerekli n hazrlklarn
yaplabilmesini salamaktadr.

Elbette buradaki ayarlar yapmadan nce bir WCF servisi iin gereken temel konfigurasyon
ayarlarnn ne olduunu bilmek gerekmektedir. Bu konu ile ilgili bir nceki makalemizden de
hatrlayacanz gibi, WCF' nin ABC' si nemli bir rol oynamaktadr.
Yani AddressBindingContract lemesinden sz ediyoruz. Bu kurallar konfigurasyon dosyamzda
da gz nne almalyz. WCF Configuration arabirimi, service ve istemci(Client) taraf iin ayr ayr
konfigurasyon dosyalar hazrlanabilmesine olanak tanmaktadr. u aamadan biz
servis(Service) taraf iin gerekli konfigurasyon ayarlarn yapacaz. Bu amala Create a New
Service linkinden faydalanabilir yada manuel olarak Configuration sekmesini kullanabiliriz. Biz
rneimizde Create a New Service linkinden faydalanacaz.

Bu linke tklandktan sonra sihirbaz bizden uzak nesne grevini stlenecek tipi sememizi
isteyecektir. rneimizde sz konusu olan tip AdventureManager snfdr. Bu seimin arkasndan
sihirbaz, servis szlemesini(Service Contract) ieren tipi belirtmemizi isteyecektir. rneimizde

www.bsenyurt.com Page 1150


bu yk stlenen IAdventure isimli arayzdr(Interface). WCF Configuration IDE' si eer ilk
admda seilen tipin uyarlad ve ServiceContract niteliini tayan bir arayz var ise bunu
otomatik olarak bulacaktr. Bir sonraki admda balant tipi seilir. Burada HTTP, TCP, MSMQ,
Peer To Peer gibi seenekler yer almaktadr. rneimizde HTTP tipini seerek ilerleyeceiz. Takip
eden admmzda WSI (Web Service Interoperability) ayarlar yaplabilir veya varsaylan hali ile
braklabilir. Biz bu adm deitirmeden devam edebiliriz. Son admda ise servisimiz iin
bir endpoint adresi bildirilmesi gerekmektedir.

WCF mimarisinde istemciler(Clients), WCF Servisleri ile haberleirken taleplerini proxy snflarna
iletirler. Proxy snflar ise servis zerinde yer alan endpoint' ler ile haberleebilirler. Bu sebepten
servis tarafnda endpoint tanmlamalarnn yaplmas gerekmektedir. Bir endpoint tanmlamas
ierisinde servisin adres bilgiside bulunur. Bu sebepten bu admda HTTPprotokolne uygun bir
adres girilmesi gerekir. Zaten rneimizi IIS zerinden sunduumuz ve sanal klasrmz buna
gre oluturduumuz iin vereceimiz adres
bellidir.http://localhost/AdventureService/Adventure.svc .Dikkat ederseniz adresimizde daha
nceden oluturduumuz Adventure.svc isimli dosyamzda yer almaktadr. Bylece imdilik gerekli
WCF ayarlarn tamamlam bulunuyoruz. Aadaki Flash animasyonuda gerekli ayarlarn nasl
yapldn izleyebilirsiniz. (Flash dosyasnn boyutu 229 kb olduu iin yklenmesi zaman alabilir)

Bu ilemlerin ardndan web.config dosyamzn ieriide aadaki gibi olacaktr.

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


<configuration>
<system.serviceModel>

www.bsenyurt.com Page 1151


<services>
<service name="UrunKutuphanesi.AdventureManager">
<endpoint address="http://localhost/AdventureService/Adventure.svc" binding="
basicHttpBinding" bindingConfiguration="" contract="UrunKutuphanesi.IAdventure" />
</service>
</services>
</system.serviceModel>
</configuration>

Artk servisimizin alp almadn tarayc penceremiz zerinden test edebiliriz. Tek yapmamz
gereken http://localhost/AdventureService/Adventure.svc adresini talep etmek olacaktr. Bu talep
sonucunda eer herey yolunda ise aadakine benzer bir ekran grnts ile karlarz.

Yine dikkat edilecek olursa servisin metadata yaynlamasnn(MetaData Publishing) aktif


olmadn grrz. Bildiiniz gibi metadata bilgisi istemcilerin proxy snflarn oluturabilmeleri iin
gereklidir. Bunu salamak maksadyla yeni bir servis davran(Service Behavior) oluturulmal
ve servise bildirilmelidir. Bu amala ilk olarak Advanced sekmesinde yer alan Service
Behaviors ksmndan yeni bir davran nesnesi eklenmeli ve aadaki ekran grntsnde yer
alan ayarlar yaplmaldr. Bu ayarlara gre eklenen servis davranna bir isim verilmi (Name
zellii ile) ve serviceMetadata elementi dahil edilmitir.

www.bsenyurt.com Page 1152


ServiceMetadata elementinin ieriininde aadaki gibi dzenlenmesi gerekmektedir.
Burada HttpGetEnabled zelliinin deerini true olarak belirlemeliyiz ki HTTP zerinden servis
metadata ieriini ekebilelim.

Sonrasnda ise servisimizin belirtilen davran kullanacan bildirmemiz gerekmektedir. Bunun


iinde servisin, BehaviorConfiguration elementine aadaki ekran grntsnde olduu gibi az
nce oluturulan Service Behavior nesnesinin adn vermeliyiz.

Bu ilemlerin ardndan servisimize ait web.config dosyasnn son halide aadaki gibi olacaktr.

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


<configuration>

www.bsenyurt.com Page 1153


<system.serviceModel>
<behaviors>
<serviceBehaviors>
<behavior name="AdventureServiceBehavior">
<serviceMetadata httpGetEnabled="true" />
</behavior>
</serviceBehaviors>
</behaviors>
<services>
<service
behaviorConfiguration="AdventureServiceBehavior" name="UrunKutuphanesi.AdventureMan
ager">
<endpoint address="http://localhost/AdventureService/Adventure.svc"
binding="basicHttpBinding" bindingConfiguration="" contract="UrunKutuphanesi.IAdventure" />
</service>
</services>
</system.serviceModel>
</configuration>

Grdnz gibi servisimiz iin berlilediimiz davran ve servis ile olan ilikisi otomatik olarak
konfigurasyon dosyasna element ve nitelikler yardmyla yanstlmtr. Servisimizi tarayc
penceresi zerinden yeniden talep edersek aadaki ekran grnts ile karlarz. Dikkat
edersek, servise ait Wsdl dkmann elde edebilmemizi salayacak bir link bilgiside yer almaktadr.

Bu kadar ilemden sonra artk istemcimizi yazmaya balayabiliriz. stemci tarafnda herhangibir
uygulama sz konusu olabilir. Biz mimariyi basit bir ekilde ele almaya altmzdan bir Console
uygulamas gelitireceiz. Yine Visual Studio 2005' in Add Service Reference seeneini
kullanarak ilgili servisi otomatik olarak uygulamamza ekleyebilir ve gerekli proxy snfnn kolay bir
ekilde oluturulmasn salayabiliriz.

Visual Studio 2005 dnda, bir WCF servisine ait metadata bilgisini elde edip proxy snfn
ve istemci iin gereken konfigurasyon dosyasn elde etmek amacyla, svcutilisimli
Framework 3.0 aracda kullanlabilmektedir.

Console uygulamamz oluturduktan sonra projeye sa tklayp Add Service


Reference seeneini kullanarak WCF servisimizi projemize eklememiz gerekmektedir. Burada
ieride kullanmak istediimiz isim alannn adnda belirtebiliriz. Varsaylan olarak ayn web
servislerinde olduu gibi localhost verilmektedir.

www.bsenyurt.com Page 1154


Bu ilemin ardndan istemci iin gereken proxy snf ve konfigurasyon dosyas otomatik olarak
oluturulacaktr. Artk aadaki kod satrlarn kullanarak sanki sradan bir web servisini
kullanyormu gibi WCF Servisimizi ele alabiliriz.

using System;
using System.Data;
using Istemci.localhost;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
localhost.AdventureWorksServicesClient adw =
new Istemci.localhost.AdventureWorksServicesClient();
DataSet ds = adw.GetAllProducts();
Console.WriteLine("Urun says {0} dr",ds.Tables[0].Rows.Count.ToString());

string[] categoryNames=adw.GetAllSubCategoryNames();
foreach (string category in categoryNames)
Console.WriteLine(category);

Employee emp=adw.GetEmployee(1);
Console.WriteLine(emp.Title + " " + emp.BirthDate.ToShortDateString() + " " +
emp.VacationHours.ToString());

Console.WriteLine("Ortalama Sub Total


{0}",adw.AverageSubTotalFromHeaders().ToString("C2"));
}
}
}

Uygulamay bu haliyle altrdmzda GetAllProducts metodu iin aadaki gibi alma zaman
istisnas (run-time exception) alrz.

www.bsenyurt.com Page 1155


Bunun sebebi istemci tarafnda oluturulan konfigurasyon dosyasnda
belirtilen MaxReceivedMessageSize boyutunun dk olmasdr. Nitekim dnen DataSet
ieriinin yer ald paketin boyutu ok daha fazladr. Bu nedenle istemci uygulamaya ait App.config
dosyasn Edit WCF Configuration ile ap aadaki ekran grntsnde olduu
gibiMaxReceivedMessageSize ve MaxBufferSize zelliklerinin ayn deere set edilmesi gerekir.
rneimizde bu deerlerin sonuna bir 0 eklenmitir. Burada dikkat edilmesi gereken noktalardan
birisi de, her iki deerinde ayn olmas zorunluluudur. Aksi takdire alma zamannda yine bir
istisna alrz.

Bu sebepten ayarlarmz rnein aadaki gibi olmaldr.

rneimizdeki kodlarmz incelersek eer, ilgin olan bir nokta olduunu


farkederiz. GetAllSubCategoryNames metodu servis tarafnda geriye generic bir List koleksiyonu
dndryorkan, istemci tarafnda metodun dn string[] tipinden bir dizi olmutur. Buda
aslnda farkl tipteki istemciler iin ortak bir standart koyulmaya alld eklinde yorumlanabilir.
Uygulamay altrdmzda aadakine benzer bir ekran grnts elde ederiz.

www.bsenyurt.com Page 1156


Bu makalemizde Windows Communication Foundation ats altnda, servislerimizi IIS zerinden
nasl yaynlayp kullanabileceimizi incelemeye altk. Bunu yaparken bir servis
szlemesini(Service Contract) nasl tanmlayabileceimizi, bu szlemeyi uygulayan asl uzak
nesne snfnn geriye kullanc tanml bir tip dndrmesi halide veri szlemesini(data
contract) nasl gelitirmemiz gerektiini grdk. Bunlara ek olarak zellikle IIS
Hosting iin svc uzantl dosyalarn roln inceledik ve konfigurasyon dosyalarn daha kolay
oluturabilmemizi salayan Edit WCF Configuration seeneini ele aldk. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler
dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Kendi Web Part Bilesenlerimizi Gelistirmek - 2 (


20.04.2007 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1157


Kendi web partlarmz nasl gelitirebileceiimizi ve bu sayede kiiselletirilebilir web sunucu
kontrollerini nasl yazabileceimizi bu konu ile ilgili bir nceki makalemizde incelemeye almtk.
Bu makalemizde ise kendi Web Part bileenlerimize zel fiillerin (Web Part Verbs) nasl
eklenebileceini ve sz konusu fillerin ne ekilde ele alnabileceini incelemeye alacaz. Web
Part kontrollerini herhangibir WebPartZone altnda kullandmzda standart olarak
baz fiilere(Verbs) sahip oluruz. Tahmin edeceiniz gibi bu deerler
aslnda WebPartManager tarafndan ele alnmakta ve sayfa zerinde uygun olan web part
alanlarnn (Web Part Zone) gsterilmesini salamaktadr. Sz gelimi kullanc Edit isimli fiili(Verb)
setiinde WebPartManager bileeni, EditorZone kontroln aktif hale getirmekte ve sz konusu
Web Part kontrolnn deitirilebilen yada dzenlenebilen zelliklerinin(Properties) bulunduu bir
bileeni (rnein PropertyGridEditorPart kontrol) gstermektedir. Bu adan bakldnda
fiillerin (Verbs) varsaylan olarak WebPartManager bileenine ait Display Mode deerleri ile yakn
bir ilikide olduklarn syleyebiliriz. Elbette farkl ekilde davranabilen fiillerde(Verbs) vardr.
rnein Minimize fiili, bulunduu Web Part' n ierisinde yer ald WebPartZone alannn
klmesini salarken, Restore fiili tekrardan eski haline getirilmesine olanak vermektedir.

Kendi Web Part bileenlerimizi gelitirdiimizde var olan fiillerin(Verbs) bize yetmedii durumlar sz
konusu olabilir. Bu sebepten dolay istersek kendi Web Part fiillerimizi (Web Part Verbs)
oluturabilir ve kod tarafnda ele alarak farkl aksiyonlarn gerekletirilmesini salayabiliriz. Burada
temel dayanak noktas WebPartVerb isimli snftr(class). Bu snfIStateManager isimli arayz
uyarlayan (implement) bir tiptir. Kullanm amac, Web Part bileeni iin zel bir fiili tanmlamaktr.
Fiile ait isim (Name), aklama (Description), seilme durumu(Checked), resmi(ImageUrl) vb gibi
bilgileri ierisinde barndran bir snftr. Kullanclar bu fiili setiklerinde bir aksiyonun
gerekletirilmesi gerektii ak bir ekilde ortadadr. Buda doal olarak bir metodun alma
zamannda (run time) tetiklenmesi anlamna gelmektedir. te bu sebeple tanmlanan fiilerin
gereklemesi halinde altrlacak olan metodlar iaret
eden WebPartEventHandler temsilcilerinden (delegates) faydalanlmaktadr. Bu temsilcinin
prototipi ise aadaki gibidir.

public delegate void WebPartEventHandler(object sender, WebPartEventArgs e);

Dikkat ederseniz WebPartEventHandler temsilcisi standart bir olay temsilcisidir. kinci paramete
olay metoduna baz bilgileri tamakta olan WebPartEventArgs snfna ait bir nesne rneidir. Bu
tipte doal olarak EventArgs snfndan tretilmitir. lk parametre ise fiili gerekletiren referansn
bir baka deyile WebPartVerb nesne rneinin taycsdr.

Hatrlayalm ; Temsilciler (Delegates) alma zamannda metodlarn bellek zerindeki


balang adreslerini iaret eden tiplerdir(types). Tanmlandklarnda, iaret edebilecekleri
metodun yapsnda (parametreleri ve dn tipi) belirtirler. Olay tabanl programlamada
(Event based programming), Asenkron (Asynchronous) mimaride yer alan Polling,
Callback, WaitHandle gibi modellerde, ok kanall uygulamalarda (Multi Thread
Applications) kullanlmaktadrlar

Bize gereken tiplerin neler olduunu rendik. Peki bunlar kendi Web Part kontrolmzde nasl ele
alacaz. Bunun iin WebPart snfndan tretme yoluyla kendi Web Part kontrol snfmza
gelen Verbs isimli zelliin ezilmesi (override) gerekmektedir.

public virtual WebPartVerbCollection Verbs { get; }

Yukarda prototipi grnen bu zellik, yanlz okunabilir(read only) bir zelliktir ve


geriye WebPartVerbCollection tipinden bir referans dndrmektedir. WebPartVerbCollection snf
trlendirilmi (strongly typed) bir koleksiyonu temsil etmekte ve Web Part bileenine eklenecek
ekstra fiileri tamaktadr. Dolaysyla bu zelliin get blou ierisinde istediimiz fiileri(Verbs)
oluturmamz ve gereken olay metodu yklemelerini yapmamz gerekecektir.

www.bsenyurt.com Page 1158


Bu makalemizde zellikle zerinde duracamz konu kendi fiillerimizi nasl yazacamzdr. Konuyu
daha iyi anlayabilmek iin rnek bir senaryo zerinden hareket edeceiz ve gze ho gelecek bir
Web Part kontrol gelitirmeye alacaz. Bu sefer bir nceki Web Part bileenimizden farkl
olarak, Render metodu yerine CreateChildControls metodunu ezip, bileen iindeki kontrollerin
daha kolay bir ekilde nasl oluturulabileceini de greceiz. Dilerseniz amacmzdan bahsederek
rneimizi gelitirelim. Sitemizde eitli kategorilerde duvar katlar(Wallpapers) olduunu
dnelim. Siteye giren kullanclar setikleri kategorideki duvar katlarndan ka tane istiyorlarsa
grebilecekler ve istediklerine tkladklarnda byk versiyonlarna bakp bilgisayarlarna
indirebilecekler. Bu senaryda Web Part kullanacamz iin resim says ve kategori gibi bilgileri
kiselleetirme(Personalization) ansnada sahip olacaz. Web Part kontrolmz, seilen
kriterlere gre, kontroln sayfaya her iziliinde rastgele resimler seecek ve bunlar gsterecektir.
Peki kendi fiillerimizi bu senaryo ierisine nasl katabiliriz? Kullanclarn isterlerse Web Part
kontrolne eklenen resimleri yatay veya dikey dzende grebileceklerini gz nne alalm. Bunun
iin Yatay Diz ve Dikey Diz balkl rnek fiilleri Web Part kontrolmze ekleyip, resimlerin sayfa
zerindeki dizili ynlerini belirleyebiliriz. stelik bu fiillerin deerlerini kiiselletirirsek, sayfay son
braktmz haliyle elde edebiliriz. rnek Web Part kontrolmz bitirdiimizde aadaki ekran
grntlerindekine benzer sonular elde edeceiz.

rnek olarak Uak kategorisinde her ziyaretimizde rastgele 3 resmin yanyana


gsterilmesi;

Web Part kontrolmz iin gelitireceimiz fiiller(Verbs);

Dikey Diz balkl Verb seildiindeki durum;

www.bsenyurt.com Page 1159


Artk kontrolmz gelitrimeye balayabiliriz. Web Part bileenimizi yine bir Web Control
Library ktphanesinde ele alabiliriz. ResimPart adl Web Part snfmzn WebPart snfndan
tremesi(Inherit) gerektiini hatrlayalm. Kontrolmz kendi ierisinde kiiselletirilebilir
(Personalizable) 3 zellik barndrmaldr. Bunlardan birisi ziyaretinin grmek istedii resim
saysn tutan GosterilecekResimSayisi zelliidir. Ziyaretinin grmek istedii kategorinin bilgisini
ise ResimKategori isimli zellik ile tutabiliriz. Son olarak ziyaretinin setii fiile (Verb) uygun
olacak ekilde bir deikenin de kiiselletirilmesi nemlidir ki bir sonraki ziyarette son braktmz
haliyle bir dizilim elde edebilelim. Bu amalada ziyaretinin son setii fiili kiiselletirilebilir bir
zellik olacak ekilde CizimYonu ismiyle saklayacaz. Dilerseniz bahsetmi olduumuz
zellikleri(Property) aadaki gibi yazarak makalemize devam edelim.

[ToolboxData("<{0}:ResimPart runat=server></{0}:ResimPart>")]
public class ResimPart:WebPart
{
#region Kiiselletirilebilir zellikler iin alan tanmlamalar

private ResimKategorisi _kategori;


private int _gosterilecekResimSayisi;
private Yon _cizimYonu;

#endregion

#region Kiiselletirilebilir zellikler

[WebBrowsable(true)]
[WebDescription("Bakmak istediimiz resimlerin kategorisi")]
[WebDisplayName("Resim Kategorisi")]
[Personalizable(PersonalizationScope.User, false)]
public ResimKategorisi Kategori
{
get { return _kategori; }
set { _kategori = value; }
}

www.bsenyurt.com Page 1160


[WebBrowsable(true)]
[WebDescription("Seilen kategoride gsterilecek resim says")]
[WebDisplayName("Resim Says")]
[Personalizable(PersonalizationScope.User, false)]
public int GosterilecekResimSayisi
{
get{return _gosterilecekResimSayisi <= 0 ? 1 : _gosterilecekResimSayisi;}
set{_gosterilecekResimSayisi = value <= 0 ? 1 : value;}
}

[WebBrowsable(true)]
[WebDisplayName("Resimlerin Yn")]
[WebDescription("Resimler dikey veya yatay gsterilebilmesini salar")]
[Personalizable(PersonalizationScope.User, false)]
public Yon CizimYonu
{
get{return _cizimYonu;}
set{_cizimYonu = value;}
}

#endregion
}

Bir nceki makalemizden de hatrlayacanz gibi, zelliklerimizi kiiselletirmek iin gerekli


nitelikler ile iaretliyoruz. Resimlerin ynn ve var olan resim kategorilerini birer enumsabiti
ierisinde saklamaktayz.

Enum sabitleri bu senaryoda olduka ie yarar. Ne varki kategori isimlerinin deitii


yada yeni kategorilerin eklendii durumlarda koda girip gncelleme yapmak ve
uygulamay tekrardan build etmek gerekecektir. Alternatif bir yol olarak bu tip bir verinin
kod dnda bir ortamda, rnein bir Xml dosyasnda veya veritabanndaki bir parametre
tablosunda saklanmas gz nne alnabilir.

Normal artlarda resimlerin kategorisi iin daha farkl bir yntem izlemek salkl olacaktr. Kendi
sistemimizde, aadaki ekran grntsnde yer alan klasr yapsn baz alacak bir enum sabiti ele
alnmaktadr. Resimlerin bir kk birde orjinal hallerini tutmak iin klasrleme mantn
kullanyoruz. Buna gre sz konusu resimleri kategori adlar eklinde olan klasrler ierisinde yer
alan big ve small alt klasrlerinde ayrtrm durumdayz. Web Part kontrolmz kk boyutlu
resimleri small isimli klasrler altndan ekerken, zerlerine tklandnda orjinal byklklerindeki
versiyonlar ise bo bir tarayc penceresinde aacak ekilde big isimli alt klasrlerden ekmektedir.

www.bsenyurt.com Page 1161


Buna gre kullancnn enum sabiti yardmyla setii kategorideki resimleri grebilmesi iin, klasr
ad ile enum sabiti adnn ayn olmas gerekir. Bu durumda yanllkla klasrn isminin deitirilmesi
sonucu sistem beklediimiz ekilde almayacaktr. zellikle istenen kategoriye bal klasr
bulunamayacandan alma zaman istisnalar (run time exception) alnmas kanlmazdr. Bu
durumun nne gemek iin neler yaplabileceini dnmekte fayda olaca kansndaym. Bize
yardmc olacak enum sabitlerimiz aadaki gibidir.

public enum ResimKategorisi


{
araba,
ucak,
manzara,
komik
}

public enum Yon


{
DikeyYon,
YatayYon
}

imdide Web Part kontrolmz iin gerekli fiillerimizi (Verbs) gelitirelim. Hatrlayacanz gibi
makalemizin banda bu i iin Verbs zelliini ezmemiz(override) gerektiini sylemitik. Bu
zellik ierisinde tanmlayacamz WebPartVerb tipinden nesne rneklerinin yapc
metodlar(constructors) ierisinde, ilgili fiil(Verb) seildii zaman altrlacak olan metodu iaret
edecek bir temsilci tanm yaplmaktadr. Bunlar hesaba katarak Web Part kontrolmzn ieriini
ilk aamada aadaki gibi gelitirebiliriz.

WebPartVerb vrbYatay, vrbDikey;

public override WebPartVerbCollection Verbs


{
get
{
vrbDikey = new WebPartVerb("DikeyDizilim", new WebPartEventHandler(DikeyDiz));
vrbYatay = new WebPartVerb("YatayDizilim", new WebPartEventHandler(YatayDiz));

www.bsenyurt.com Page 1162


vrbDikey.Text = "Dikey Diz";
vrbYatay.Text = "Yatay Diz";

WebPartVerb[] verbs = new WebPartVerb[2];


verbs[0] = vrbDikey;
verbs[1] = vrbYatay;
WebPartVerbCollection verbCollection = new WebPartVerbCollection(verbs);

return verbCollection;
}
}

public void YatayDiz(object sender, WebPartEventArgs e)


{
CizimYonu = Yon.YatayYon;
}
public void DikeyDiz(object sender, WebPartEventArgs e)
{
CizimYonu = Yon.DikeyYon;
}

imdi neler yaptmza ksaca bakalm. Kendi yazacamz fiillerimizi WebPartVerb tipinden
tanmladktan sonra get blou ierisinde oluturmaktayz. Bu ilemi yaparken ikinci parametre ile
bir WebPartEventHandler temsilci rnei tanmladmza ve DikeyDiz ile YatayDiz isimli
metodlar iaret ettiimize dikkat edelim. Buna gre, kullanclar bu fiillerden birisine tkladnda
YatayDiz ve DikeyDiz isimli metodlar alacaktr. Bu metodlarn ierisinde Web Part kontrolmz
iin tanmladmz CizimYonu zelliinin deerini berlilemekteyiz.
Oluturulan WebPartVerb kontrollerini bir dizi ierisinde topladktan sonra
bir WebPartVerbCollection koleksiyonunun retilmesinde kullanyoruz. Son olarak get bloundan
bu koleksiyonu geri dndrmekteyiz. Peki fiilin seilmesi sonucunda resimleri yatay veya dikey
olarak nasl yerletireceiz?

Sonu itibariyle seilen resimlerin ekrana alnmas ve belirli bir yne doru izilmesi demek, Web
Part kontrolnn ekrana izilmesi srasnda (Render) uygun HTML taklarnn(Tag) oluturulmas
demektir. Hatrlayacanz gibi bir nceki makalemizde bu i iin Render metodunu kullanmtk.
Render metodu dnda var olan Web sunucu kontrollerinden yararlanaraktanda ayn ilemi
gerekletirebilmekteyiz. Sonu itibariyle Web Part kontrolleride birer tayc (Container)
olduundan bir Controls koleksiyonuna sahiptir. Dolaysyla sunucu kontrollerini oluturup bu
koleksiyona ekleyerek HTML elementleri ile fazla uramadan render ilemlerini gerekletirebiliriz.
Web Part kontrollerinde bu ilem iin tek yapmamz gereken CreateChildControls metodunu
ezmek olacaktr. Kendi rneimiz iin bu metodu aadaki gibi ezebiliriz.

protected override void CreateChildControls()


{
string sanalAdres = HttpContext.Current.Request.Url.ToString();
sanalAdres = sanalAdres.Substring(0, sanalAdres.LastIndexOf('/'));
string sanalResimAdresi = sanalAdres + ("/images/") + Kategori.ToString();
string fizikiKlasor = HttpContext.Current.Request.PhysicalPath;
fizikiKlasor = fizikiKlasor.Substring(0, fizikiKlasor.LastIndexOf('\\'));
int siraNo = 0;

try
{
FileInfo[] resimDosyalari = DosyalariAl(fizikiKlasor);
Random rnd = new Random();

www.bsenyurt.com Page 1163


Table tablo = new Table();

if (CizimYonu == Yon.DikeyYon)
{
for (int i = 0; i < GosterilecekResimSayisi; i++)
{
TableRow satir = new TableRow();
siraNo = rnd.Next(0, resimDosyalari.Length);
TableCell hucre = HucreOlustur(sanalResimAdresi, siraNo, resimDosyalari);
satir.Cells.Add(hucre);
tablo.Rows.Add(satir);
}
}
else if (CizimYonu == Yon.YatayYon)
{
TableRow satir = new TableRow();
for (int i = 0; i < GosterilecekResimSayisi; i++)
{
siraNo = rnd.Next(0, resimDosyalari.Length);
TableCell hucre=HucreOlustur(sanalResimAdresi, siraNo, resimDosyalari);
satir.Cells.Add(hucre);
}
tablo.Rows.Add(satir);
}
Controls.Add(tablo);
}
catch
{
}
}

private static TableCell HucreOlustur(string sanalResimAdresi, int siraNo, FileInfo[]


resimDosyalari)
{
string miniResimDosyaAdresi = sanalResimAdresi + "/small/" + resimDosyalari[siraNo].Name;
string buyukResimDosyaAdresi = sanalResimAdresi + "/big/" + resimDosyalari[siraNo].Name;
TableCell hucre = new TableCell();

string resim = "<a href='" + buyukResimDosyaAdresi + "' target='_blank'><img src='"


+ miniResimDosyaAdresi + "'/></a>";
hucre.Text = resim;
return hucre;
}

private FileInfo[] DosyalariAl(string fizikiKlasor)


{
DirectoryInfo fizikiKlasorBilgisi = new DirectoryInfo(fizikiKlasor + "\\images\\"
+ Kategori.ToString() + "\\small\\");
FileInfo[] resimDosyalari = fizikiKlasorBilgisi.GetFiles();
return resimDosyalari;
}

Burada kendimize gre bir algoritma gelitirdik. Temel olarak CreateChildControls metodu
seilen fiile gre yatay veya dikey dizilime uygun olacak ekilde bir HTML Table retmekte
veControls koleksiyonuna eklemektedir. Burada sz konusu
olan Table, TableRow ve TableCell tipleri ynetimli kod(managed code) tarafnda gelitirilmi

www.bsenyurt.com Page 1164


sunucu bileenleridir ve alma zamannda retilen sayfa ierisinde HTML Table, HTML TR (Satr),
HTML TD (Hcre) elementlerine dntrlmektedir. zel olarak, resimlerin kk hallerini
gstermek ve zerlerine tklandnda orjinal boyutlarnda amak iin a href ve img HTML
elementlerinden faydalanlmaktadr. Sizler bu kod parasn daha efektif hale getirerek (rnein
optimize ederek) daha leklenebilir bir ekle dndrebilirsiniz. Artk gelitirdiimiz WebPart
bileenini rnek bir web uygulamas zerinde deneyebiliriz. Bu amala gelitireceimiz web
uygulamasnn kiiselletirmeye destek verebilmesi amacyla Membership ayarlarn iermesi
doru olacaktr. Sonu olarak aadaki Flash animasyonunda grlen kty elde ederiz. (Flash
dosyasnn boyutu 180 Kb olup yklenmesi zaman alabilir)

Yukardaki Flash animasyonundanda grdnz gibi, sisteme giren bir kullanc kendisine gre
istedii kategorideki resimleri gsterebilmekte ve bunlar yatay veya dikey olarak dizebilmektedir.
Bizim dikkat etmemiz gereken nokta kendi fiillerimizin burada ilenebilir olmasdr. Yukarda
gelitirdiimiz ResimPart isimli Web Part kontrolmzde fiillerimizi ayr olay metodlarna
ynlendirdik. Dilersek tm fiillerimizi ayn metod ierisinde ele alabiliriz. Bunun iin ncelikli
olarak WebPartVerb bileenlerimizi olutururken
kullandmzWebPartEventHandler temsilcilerini (delegates) ayn metodu iaret edecek ekilde
oluturmalyz.

vrbDikey = new WebPartVerb("DikeyDizilim", new WebPartEventHandler(VerbUygula));

www.bsenyurt.com Page 1165


vrbYatay = new WebPartVerb("YatayDizilim", new WebPartEventHandler(VerbUygula));

Daha sonra VerbUygula isimli metodumuzu aadaki gibi kodlamamz yeterli olacaktr.

public void VerbUygula(object sender, WebPartEventArgs e)


{
string tetiklenenVerbId=((WebPartVerb)sender).ID;
if (tetiklenenVerbId == "DikeyDizilim")
CizimYonu = Yon.DikeyYon;
else if (tetiklenenVerbId == "YatayDizilim")
CizimYonu = Yon.YatayYon;
}

Tm fiiller ayn olay metodu ierisinde ele alnacaklarndan, olay meydana


getiren WebPartVerb nesne rneinin kim olduunun bilinmesi gerekmektedir. Bunun iin olay
metodunun ilk parametresinden yararlanlmtr. sender isimli deiken, olay metodu
ierisinde WebPartVerb tipine dntrlm ve ID zelliinin deerine baklarak CizimYonu
isimli enum sabitine uygun deeri atanmtr. Uygulamay bu haliyle test ettiimizde ilk
versiyondaki ile ayn sonular elde ederiz.

zmemiz gereken bir durum daha vardr. Bu da hangi Verb seildiyse bunun bana bir check
iaret konulmasnn salanmasdr. Bu amala WebPartVerb snfnnChecked zelliinin deerinin
true veya false olarak deitirilmesi yeterlidir. Lakin asl problem bununla iliki kodun nereye
yazlmas gerektiidir. Web sayfalar ve ierisinde yer alan kontrollerin yaam dngs olay biraz
karmak hale getirmektedir. Senaryomuzda, iaretleme operasyonu iin gerekli kod
parasnn CreateChildControls metodu ierisine konulmas dnlebilir. Yada bu ilemi fiilleri
ele aldmz olay metodu ierisine koyabiliriz. Ancak hi birisi ie yaramayacaktr. Bunun sebebi
Web Part bileenimizin, sunucu tarafndaki yaam dngsdr. Dilerseniz yaam dngsn
inceleyerek devam edelim. Sayfa ilk kez talep edildiinde dolaysyla Web Part kontrolde ilk kez
oluturulduundaki olay ileyi sras gz nne alndnda, Web Part kontrolmzdeki baz
yelerin ileyi sras aadaki gibi olacaktr.

Kullanc bir fiil (Verb) setikten sonra sayfa sunucuda tekrar oluturulup, web part kontrolmzde
yeniden oluturulacaktr. Bu ikinci request sonrasnda ylerin ileyi sras ise aadaki gibidir.

www.bsenyurt.com Page 1166


Grld gibi her iki yaam dngs srasnda son olarak Verbs isimli zellie girilmektedir.
Dolaysyla iaretleme kodlarn buraya dahil edebiliriz. Bununla birlikte gze arpan bir dier
durum, ikinci talep sonrasnda Verb zelliinin iki kez devreye giriyor olmasdr. Bu sebepten, Verb
zelliinin get bloundaki kodlar aadaki gibi optimize edilmeli veWebPartVerb bileenleri ile
ilgili koleksiyonun oluturulma ilemlerinin sadece bir kez yaplmas garanti altna alnmaldr.

WebPartVerb vrbYatay, vrbDikey;


WebPartVerbCollection verbCollection;

public override WebPartVerbCollection Verbs


{
get
{
if (vrbYatay == null && vrbDikey == null)
{
vrbDikey = new WebPartVerb("DikeyDizilim", new WebPartEventHandler(VerbUygula));
vrbYatay = new WebPartVerb("YatayDizilim", new WebPartEventHandler(VerbUygula));

vrbDikey.Text = "Dikey Diz";


vrbYatay.Text = "Yatay Diz";

WebPartVerb[] verbs = new WebPartVerb[2];


verbs[0] = vrbDikey;
verbs[1] = vrbYatay;
verbCollection = new WebPartVerbCollection(verbs);
}
if (CizimYonu == Yon.DikeyYon)
{
vrbDikey.Checked = true;
vrbYatay.Checked = false;
}
else if (CizimYonu == Yon.YatayYon)
{
vrbDikey.Checked = false;

www.bsenyurt.com Page 1167


vrbYatay.Checked = true;
}

return verbCollection;
}
}

Artk alma zamannda setiimiz fiillerin yannda tik iaret aadaki resimdekine benzer bir
ekilde kacaktr.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde kendi Web Part kontrollerimize zel
fiilleri (WebPartVerb tipinden nesne rneklerini) nasl ekleyebileceimizi rnek bir senaryo
zerinden incelemeye altk. Makalemizin sonlarnda kontrollerin yaam dngsnn ne kadar
nemli olabileceini grdk. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler
dilerim.

rnek Uygulama in Tklaynz. (Resimlerin boyutlarnn byk olmas nedeni ile Big isimli
kasrlerlerdeki resim dosyalar ve App_Data altndaki ASPNETDb.mdf dosyalar silinmitir. Test
ederken bunlar gz nne almay unutmaynz.)

Burak Selim ENYURT


selim@bsenyurt.com

C# Temelleri : Nitelikleri(Attributes) Kavramak


( 11.04.2007 ) - C#
Deerli Okurlarm Merhabalar,

Nitelik(Attribute) eninde sonunda her dotNet programcsnn kulland ve karlat bir kavramdr.
zellikle yansma (Reflection) konusu ile birlikte anldndan, .Net Framework ierisinde nemli bir
yere sahiptir. .Net Framework ierisinde pek ok modelde niteliklerden aktif olarak
faydalanlmaktadr. Web servislerinden windows kontrollerini gelitirmeye, kendi web part
bileenlerimizi yazmaktan seriletirmeye kadar pek ok alanda ie yaramaktadr. Hatta ok popler
olarak, katmanl mimarilerde ve nitelik bazl (attribute based) programlama modellerinde de ele
alnmaktadr. te bu makalemizde nitelikleri incelemeye alacak ve zellikle kendi niteliklerimizi
nasl gelitirebileceimize deineceiz.

Hereyden nce, nitelii (Attribute) tanmlamakta fayda vardr. Nitelikler, uygulandklar tiplerin
(types) yada yelerin (members) alma zamanndaki davranlarnn deitirilmesine olanak
salayan snflardr. Niteliklerin snf(class) olduu rahatlkla sylenebilir. Nitekim var olan veya
bizim tarafmzdan gelitirilen nitelikler daima Attribute snfndan tremek zorundadrlar.
Attribute, abstract bir snftr. Dolaysyla rneklenemez ancak bir nitelik snfnn iermesi gereken

www.bsenyurt.com Page 1168


temel yeleri bnyesinde barndrr. Aslnda niteliklerin belkide en nemli zellii, retilen assembly
ierisinde yer alan tip ve yelere ekstra bilgiler katabilmeleridir. Bir baka
deyile metadata ierisine ilave bilgiler eklenebilmesini salamaktadr. Bu noktada ortaya nemli
bir soru kar. Sz konusu ekstra veriler kim tarafndan ve nasl deerlendirilecektir? te bu
noktada yansma(Reflection) konusu ok byk nem tamaktadr. yleki, alma
zamannda(run-time) herhangibir tipin ve yelerinin hakknda bilgi sahibi olabilme imkan ayn
zamanda metadata ieriinide elde edebilme anlamna gelmektedir.

Nitelikler(Attributes), .Net Framework' de var olan veya gelitiriciler tarafndan yazlan


tip(type) veya yelere(members) alma zamannda davranlarnn farkl ekillerde ele
alnabilmelerini salayan ekstra metadata (veri hakknda veri) bilgileri ekler. Bu metadata
bilgileri retilen assembly' lar ierisinde yer alr ve yansma(Reflection) teknikleri ile
alma zamannda deerlendirilebilir.

Niteliklerin faydasn ve ne ie yaradklarn daha net bir ekilde anlayabilmek iin aadaki rnek
senaryolar gz nne alnabilir.

Asp.Net Web Uygulamalarnda Kendi Kontrollerimizi Gelitirirken

Daha nceki makalelerimizde kendi web server kontrollerimizi nasl yazacamza ksaca
deinmitik. imdi yle dnelim. Yazdmz bu kontrollerin ele alnd bir gelitirme ortam var
m? Cevabn Visual Studio IDE ortam olduunu gayet iyi biliyoruz. Peki nasl oluyorda, bir kontrol
ToolBar zerinden alp sayfaya braktmzda, zellikler (Properties) pencersinde, o kontrol snfna
ait baz yeler (zellikler, olaylar) getiriliyor? Demekki, IDE bir alma zaman ortam olarak
srklenip braklan kontroln hangi yelerinin Properties penceresinde grnmesi gerektiini
anlayabiliyor. Hatrlayacanz gibi zelliklerin bana, hatta kontrol snfnn bana atlan baz
nitelikler(attributes) vard.

[Browsable(true)]
[Description("Hangi Gn?")]
[Bindable(true)]
[Themeable(true)]
[Category("Tarih Degerleri")]
[DefaultValue("1")]
[Localizable(true)]
public string SeciliGun
{

ok basit olarak SeciliGun isimli zelliin zerine yazlm olan nitelikler, Visual Studio IDE' si iin
anlamldr. Nitekim Visual Studio alan bir uygulama olaraktan, alma zamannda (run-time)
ilgili niteliklerin deerlerine bakarak baz hamlelerde bulunur. rnein Browsable niteliinin true
deerine sahip olmas, SeciliGun zelliinin Visual Studio IDE' sindeProperties penceresine
eklenmesi gerektii anlamna gelir. Description nitelii ierisindeki metinsel bilgiler, IDE
tarafndan deerlendirilip yine Properties penceresinde gsterilir. (Dier niteliklerin ne amala
kullanldklarn Web Server Control Yazmak - 2 isimli makaleden bulabilirsiniz.)

Kendi Web Part Bileenlerimizi Gelitirdiimizde

Bundan bir nceki makalemizde kendi Web Part bileenlerimizi nasl gelitirebileceimiz
incelemitik. Gelitirdiimiz Web Part bileenlerinin baz zelliklerinin
kiiselletirilebilmesi(personalizable) ve alma zamannda istemcinin bilgisayarnda yer alan
tarayc pencersindeki bir PropertyGridEditorPart ierisinde alp deitirilebilmesi iin aadaki
niteliklerden faydalandk.

www.bsenyurt.com Page 1169


[WebBrowsable(true)]
[WebDescription("Verilen Url adresine gre Rss bilgisini okur")]
[Personalizable(PersonalizationScope.User)]
[WebDisplayName("Rss Bilgisi Alnacak Url")]
public string Url
{
get { return _Url; }
set { _Url = value; }
}

te buradaki nitelikleri deerlendiren kii, Asp.Net Runtime Host' un ta kendisidir. Yine alma
zamanndaki bir ortamn karar mekanizmalarnda ihtiya duyaca baz bilgiler metadata ierisine
nitelikler yardmyla eklenmektedir. Buna gre rnein, Asp.Net Runtime
Host, Personalizable niteliinde PersonalizationScope isim enum sabitinin deerini User olarak
grdnde takip eden zelliin kiiselletirme amal olarak her kullanc iin ayr olacak ekilde
veritabanna yazlmas gerektiini anlayacaktr. Yine WebBrowsableniteliine true deeri verilmesi
sayesinde, ilgili zelliinde istemcilerin tarayc penceresinde grlecek
olan PropertyGridEditorPart ierisinde ele alnabileceinide anlayacak ve sayfann sunucundan
istemciye olan hareketinde, render ilemini bu kritere gre deitirecektir. (Dier niteliklerin ne
yapt ile ilgili olaraktan Kendi Web Part Bileenlerimizi Gelitirmekisimli makalemizden
yararlanabilirsiniz.)

Nesneleri Binary Formatta Seriletirmekte

Bildiiniz gibi bir nesneyi ikili (binary) formatta seriletirmek iin BinaryFormatter
snfnn Serialize metodundan yararlanrz. Benzer ekilde ters seriletirme ilemi
iindeDeserialize metodunu kullanrz. Ancak hepimizin yakndan tand bir kural vardr. Bir tipin
ikili formatta(binary) seriletirilebilmesi iin Serializable nitelii ile iaretlenmi olmas gerekir.
Binary formatta seriletirmenin olduu yerler gz nne alndnda sz konusu niteliin nemi
ortaya kmaktadr. rnein web uygulamalarnda sessionbilgilerinin veritabanndan tutulmasna
karar verildiinde veya Profile bilgilerinde kendi tiplerimizi yada var olan tipleri tablodaki binary
alanda tutmak istediimizde...

Windows Communication Foundation' da Kontratlar(Contrats) Hazrlarken

Yakn zamanda, .Net Framework 3.0 ile gelen ve Microsoft tabanl datk mimari (distributed
architectures) modellerini tek bir at altnda toplayan Windows Communication Foundation'
da, bir snfn servis olarak yaynlanmas iin ve snf iinden d dnyaya alabilecek
fonksiyonellikler iin yine nitelikleri kullanmaktadr. Aadaki rnek kod
parasnda ServiceContract ve OperationContract isimleriye gelitirilen niteliklerin rnek
uygulan eklini grmektesiniz. (Daha detayl bilgi iin WCF Giri makalesine bakabilirsiniz.)

[ServiceContract]
public interface IMatematikServis
{
[OperationContract]
double Toplam(double x, double y);

void DahiliMetod();
}

Web Servislerinde

Bir web servisinin istemci tarafndan tketilebilmesi iin ounlukla proxy snflarn kullanyoruz.
Elbette istisnai olarak dorudan HTTP veya SOAP zerinden talepte de bulunabilmekteyiz. Nitekim

www.bsenyurt.com Page 1170


proxy snflarnn retilebilmesi iinde, web servisine ait bir WSDL dkmannn ele alnmas
gerekiyor. WSDL (Web Service Description Language) dkman bildiiniz gibi bir web servisinin
tanmlamalarnn ve fonksiyonelliklerin bir XML ierii olarak retilmesini salyor. Peki biz bu
belgeyi herhangibir ekilde talep ettiimizde, bu talebe karlk XML dkman ierisine hangi
snflarn ve hangi metodlarn koyulacan sistem nereden biliyor? te bu noktada
devreye WebService veWebMethod gibi nitelikler(attributes) girmektedir. Bylece WSDL
dkmann hazrlayacak olan HttpHandler hangi snf ve hangi metodu xml ierisine alacan
bilecektir.

Katmanl Mimaride Entity Tiplerinde

zellikle katmanl mimaride nitelikler ok faydal olabilmektedir. rnein, veritabannda yer alan
tablolarn karlklarnn tutulduu snflar iin otomatik olarak select, insert,update ve delete gibi
sorgularn hazrlanmas istendii durumlarda alma zaman iin ekstra bilgilere (additional
metadata) ihtiya vardr. te alma zamanndaki bu ihtiyalar nitelikler yardmyla
karlayabiliriz. Sz gelimi entity tipi ierisindeki alan adlarnn tablolardaki karlklarn, identity
olup olmadklarn yada farkl entity tipleri arasnda, tablolar arasndaki ilikilerin nasl
gerekletirilebileceini belirlemek vb konularda ele alnabilir.

DLINQ (Database Language Integrated Query) de Yer Alan Entity Tiplerinde

u anda C# 3.0 ile birlikte ad en ok anlan modellerden biriside DLINQ(Database Language


Integrated Query) dir. DLINQ temel olarak veritabanndan nesnelere indirgenen kmeler
zerinde LINQ sorgularnn altrlmasna izin veren bir modeldir. (Daha fazla bilgi iin C# 3.0 lk
Bakta DLINQ makalesine bakabilirsiniz) Aslnda model tipik olarak entity katmanlarna dayanan
bir yapya sahiptir. Tablo, alan ve iliki (relation) eletirmeleri vb... iin niteliklerden (attributes)
faydalanlmaktadr.

[Table(Name="Calisanlar")]
class Calisan
{
[Column(Name="Id",Id=true)]
public int Id;

Bir Assembly Hakknda Bilgi Vermek iin AssemblyInfo.cs eriinin Deiitirlmesi

Gelitirdiimiz uygulamalarn rettii assembly' lara ait genel bilgileri AssemblyInfo.cs dosyas
ierisindeki assembly seviyesinde kullanlabilen nitelikler sayesinde metadata ierisine alabiliriz. Bu
sayede gelitirdiimiz Assembly' n hangi kltre destek verdiini(Culture), versiyonunu(Version),
varsa strong key bilgisini, baln (Title), aklamasn (Description) belirtebiliriz. Bu tip bilgiler
metadata ierisine alndktan sonra rnein ClickOnce gibi mimariler tarafndan
kullanlp setup sayfalarnn oluturulmas srasnda kullanlabilir.

Grdnz gibi, nitelikler alma zamannda bir takm uygulama paralar tarafndan
deerlendirilmekte ve buna gre sonular retilmektedir.

Bu ksa bilgilerden sonra gelin kendi niteliklerimizi (Custom Attributes) nasl yazabileceimize
bakalm. Kendi niteliklerimizin kymetlenebilmesi iin onlar ele alacak bir modelede ihtiyacmz
olacaktr. Burada devreye yansma(Reflection) girecek. rnein Sql Server 2005 ile birlikte gelen
AdventureWorks veritabanndaki Production emasnda (Schema) yer alan Product tablosunun
programmz ierisinde bir tip ile ifade edildiini dnebiliriz. Bu tip iin gerekli insert, update,
delete ve select ilemlerinin bu tip ierisindeki metodlar ile yaplmak istendiini dnelim. Bu
durumda yansmadan faydalanarak zelliklerin adlarndan ve o anki deerlerinden yararlanp bizim
iin gereken sorgular otomatik olarak hazrlatabiliriz. Ancak dikkat edilmesi gereken noktalar
vardr. rnein ProductId alan identity tipindendir ve bu nedenlede otomatik olarak artmaktadr.

www.bsenyurt.com Page 1171


Dolaysyla otomatik oluturulacak insert sorgusuna dahil edilmemesi gerekir. Peki alma
zamannda bu alan iaret eden snf zelliinin, insert sorgusuna dahil edilmemesi gerektiini
nereden bilebiliriz? te bu zellikler iin yazacamz bir nitelik yardmyla alma zamannda
davran deitirilmesini salayabiliriz. Gelin ne demek istediimiz rnek zerinden incelemeye
alalm. Bu amala ncelikli olarak bir Product nesnesini temsil edecek bir snf tasarlayacaz.
Amacmz insert, update, delete ve select sorgularnn alp almadn kontrol etmekten ziyade,
bunlarn oluturulmas srasnda niteliklerin deerini anlamak olduundan sadece bir ka temel
zelliin snfa dahil edildiini hatrlatalm. UrunEntity isimli snfmzn genel tasarm u ekilde
olacaktr.

Snfmz ierisindeki niteliklerin uygulanmasn ve metodlarmz ilerleyen ksmlarda gelitireceiz.


Gelelim niteliklerimize. Makalemizin bandada belirttiimiz gibi bir nitelik
mutlaka Attribute snfndan tremelidir ki metadata ierisine eklenebilsin. Bu nedenle snfmzn
eletii tablo ve kolonlar iin kullanlacak TabloAttribute veAlanAttribute snflarn Attribute
snfndan treterek gelitireceiz.

simlendirme standartlar olduka nemlidir. Bu tm gelitiricilerin ayn tarzda kodlama


yapmasn ve kooridanasyon kolayln salar. rnein tm Exception snflarnn
adlar Exception kelimesi ile biter veya tm arayzlerin (interfaces) adlar I harfi ile
balar. Benzer durum nitelikler iinde geerlidir. yleki nitelik snflarnn
adlarda Attribute kelimesi ile bitmektedir. Bu nedenle kendi niteliklerimizi
isimlendirirken adlarnn Attribute kelimesi ile bitmelerine zen gsterilmelidir.

Niteliklerimize ait snf diagram ve kodlarmz ise aadaki gibidir.

www.bsenyurt.com Page 1172


TabloAttribute.cs;

// TabloAttribute isimli niteliimiz sadece snf veya yaplara uygulanabilecektir.


[AttributeUsage(AttributeTargets.Class|AttributeTargets.Struct)]
class TabloAttribute:Attribute
{
private string _tabloAdi;
private string _schemaAdi;

public string TabloAdi


{
get { return _tabloAdi; }
set { _tabloAdi = value; }
}
public string SchemaAdi
{
get { return _schemaAdi; }
set { _schemaAdi = value; }
}

www.bsenyurt.com Page 1173


public TabloAttribute(string tablonunAdi, string schemaninAdi)
{
TabloAdi = tablonunAdi;
SchemaAdi = schemaninAdi;
}
public TabloAttribute(string tablonunAdi)
: this(tablonunAdi, "dbo")
{
}
public TabloAttribute()
{
}
}

AlanAttribute;

[AttributeUsage(AttributeTargets.Property)]
class AlanAttribute:Attribute
{
private string _alanAdi;
private bool _identity;
private bool _nullIcerebilir;

public bool NullIcerebilir


{
get { return _nullIcerebilir; }
set { _nullIcerebilir = value; }
}

public string AlanAdi


{
get { return _alanAdi; }
set { _alanAdi = value; }
}
public bool Identity
{
get { return _identity; }
set { _identity = value; }
}

public AlanAttribute(string alaninAdi, bool identityMi, bool nullIcerirmi)


{
AlanAdi = alaninAdi;
Identity = identityMi;
NullIcerebilir = nullIcerirmi;
}
public AlanAttribute(string alaninAdi, bool identityMi)
: this(alaninAdi, identityMi, true)
{
}
public AlanAttribute(string alaninAdi)
: this(alaninAdi, false)
{
}
public AlanAttribute()
{

www.bsenyurt.com Page 1174


}
}

u andaki amacmz kendi niteliklerimizi nasl yazacamz grmek olduundan tam anlamyla bir
entity tipi oluturmay hedeflemiyoruz. Bu nedenle TabloAttribute isimli snfmz temel olarak
eletirme amacyla tablo ad ve bulunduu ema adn tayacak zelliklere sahip. Benzer ekilde
AlanAttribute isimli snfmzda alan adn, null deer tanabilip tanamyacan, alann identity
tipinde olup olmadn belirten zellikler iermektedir. Grdnz gibi Attribute' tan trettiimiz
snflarn normal snflardan farkl bir yazm tarz bulunmamaktadr. Ancak dikkat ederseniz yazm
olduumuz nitelik snflarmza AttributeUsage isimli baka bir nitelik daha uygulanmaktadr. Bu
niteliin amac, ilgili niteliin hangi seviyelere uygulanabileceini belirlemektir. Bu seviylerin
belirtilmesi iinse AttributeTargets isimli bir enum sabitini ele almaktadr. rnein TabloAttribute
niteliimizi sadece snf(class) ve yaplara(struct) uygulayabilirken, AlanAttribute isimli niteliimizi
sadece zelliklere(Property) uygulanabilir. Bylece ilgili niteliin sadece belirtilen tip veya yelere
uygulanabilmesi adna bir zorlama getirilmi olunur. AttributeTargets isimli enum sabitinin
alabilecei tm deerler ve ksa aklamalar aadaki tabloda grld gibidir.

Deer Aklama

All Nitelik istenilen tipe veya yeye uygulanabilir.

Assembly Nitelik sadece assembly seviyesinde uygulanabilir.

Class Nitelik sadece snflara uygulanabilir.

Constructor Nitelik sadece yapc metoda uygulanabilir.

Delegate Nitelik sadece temsilci tipine uygulanabilir.

Enum Nitelik sadece enum sabitine uygulanabilir.

Event Nitelik sadece olaya uygulanabilir.

Field Nitelik sadece alana uygulanabilir.

GenericParameter Nitelik sadece generic bir parametreye(T) uygulanabilir.

Interface Nitelik sadece arayze uygulanabilir.

Method Nitelik sadece metoda uygulanabilir.

Module Nitelik sadece modl' e uygulanabilir. Burada dikkat edilmesi gereken nokta
module' n bir Visual Basic module' olmaydr. Yani kastedilen .dll veya
.exe uzantl module' lerdir.

Parameter Nitelik sadece parametreye uygulanabilir.

Property Nitelik sadece zellie uygulanabilir.

ReturnValue Nitelik sadece dn tipine uygulanabilir.

Struct Nitelik sadece bir deer trne bir baka deyile yapya uygulanabilir.

imdi bu nitelikleri UrunEntitiy snf ierisinde kullanmaya alalm. lk olarak snfmz aadaki
gibi gelitirelim.

[Tablo(SchemaAdi="Production",TabloAdi="Product")]
class UrunEntity
{
private int _urunId;

www.bsenyurt.com Page 1175


private decimal _fiyat;
private string _urunAdi;
private DateTime _sonSatisTarihi;

[Alan(AlanAdi = "ProductID", Identity = true, NullIcerebilir = false)]


public int UrunId
{
get { return _urunId; }
set { _urunId = value; }
}

[Alan("Name", false, false)]


public string UrunAdi
{
get { return _urunAdi; }
set { _urunAdi = value; }
}
[Alan("ListPrice", Identity = false, NullIcerebilir = false)]
public decimal Fiyat
{
get { return _fiyat; }
set { _fiyat = value; }
}

[Alan("SellStartDate", false, true)]


public DateTime SonSatisTarihi
{
get { return _sonSatisTarihi; }
set { _sonSatisTarihi = value; }
}

public UrunEntity(int idsi, string adi, decimal fiyati)


{
UrunId = idsi;
UrunAdi = adi;
Fiyat = fiyati;
}
public UrunEntity()
{
}
}

Grdnz gibi UrunEntity snfna ve UrunId,UrunAdi, Fiyat ve SonSatisTarihi isimli zelliklerimize


TabloAttribute ve Alan Attribute niteliklerimiz uygulanmtr. Buna gre UrunEntity snfnn aslnda
Production emasndaki Product tablosuna iaret ettiini anlayabiliriz. Ya da, UrunId isimli zelliin
ProductId isimli alana iaret ettiini, null deer ieremeyeceini ve en nemliside Identity bir alan
olduunu anlayabiliriz. Bylece reflection tekniklerini kullanan kodlarmz insert sorgusunu
olutururken ProductId alann hesabe katmayacan anlayabilecektir. Elbette bunun gelitirici
tarafndan kodlanmas gerektiinide unutmayalm. Dier zellikler iinde benzer uygulamalar
yaplmtr. AlanAttribute ve TabloAttribute isimli snflarmz iersinde birden fazla ar yklenmi
yapc metod (constructor) kullandmzdan, niteliklerimizi sz konusu yelere farkl biimlerde
uygulayabiliriz. Bunlardan birisi Name=Value atamas eklinde olan versiyondur. Bu versiyon
dorudan public olan zelliklere(Property) deer atanabilmesini salar. Yani zel olarak ar
yklenmi yapc metodlar olmasada ilgili niteliin zellikleri deitirilebilir.

www.bsenyurt.com Page 1176


Artk bundan sonra niteliklerimizi ele alacamz kodlarmz yazmamz gerekmektedir. Bu basit kod
paras ile, alma zamannda var olan nitelikleride nasl okuyabileceimizi ve buna gre nasl
davran deitirebileceimizi grm olacaz. Bu amala UrunEntity isimli snfmzn Insert
metodunu aadaki gibi gelitirelim.

public int Insert()


{
Type tip = this.GetType();
TabloAttribute tblAtr =
((TabloAttribute[])tip.GetCustomAttributes(typeof(TabloAttribute), false))[0];
string tabloAdi=tblAtr.TabloAdi;
string schemaAdi =tblAtr.SchemaAdi;
StringBuilder insertBuilder = new StringBuilder();
insertBuilder.Append("Insert into ");
insertBuilder.Append(schemaAdi);
insertBuilder.Append(".");
insertBuilder.Append(tabloAdi);
insertBuilder.Append(" (");

// Insert sorgusundaki alan adlar ekiliyor.


foreach (PropertyInfo prp in tip.GetProperties())
{
AlanAttribute
atr=((AlanAttribute[])prp.GetCustomAttributes(typeof(AlanAttribute), false))[0];
if (!atr.Identity)
{
string alanAdi = atr.AlanAdi;
insertBuilder.Append(alanAdi);
insertBuilder.Append(",");
}
}
// Son eklenen virgl kaldrmak iin.
insertBuilder.Remove(insertBuilder.Length-1, 1);
insertBuilder.Append(") Values (");

// insert sorgusundaki deerleri ekiliyor.


foreach (PropertyInfo prp in tip.GetProperties())
{
AlanAttribute
atr=((AlanAttribute[])prp.GetCustomAttributes(typeof(AlanAttribute), false))[0];
if (!atr.Identity)
{
object alanDegeri = prp.GetValue(this, null);
if ((prp.PropertyType.Name == "String")
|| (prp.PropertyType.Name == "DateTime"))
insertBuilder.Append("'" + prp.GetValue(this, null).ToString() + "',");
else
insertBuilder.Append(prp.GetValue(this, null).ToString() + ",");

www.bsenyurt.com Page 1177


}
}
insertBuilder.Remove(insertBuilder.Length - 1, 1);
insertBuilder.Append(")");

//Insert ilemi iin gerekli sorgula altrlr.

return 0;
}

Kod paras biraz arap sana dnm olabilir. Gelin ne yaptmza ve nitelikleri alma zamannda
nasl ele alabildiimize yakndan bakalm. Insert metodunun amac, UrunEntity snf iin gerekli
olan insert sql sorgu cmlesini otomatik olarak oluturmaktr. Bu ilemin alma zamannda
yaplmasn hedeflediimizden youn olarak reflection ilemleri kullanlmaktadr. Bununla birlikte
otomatik olarak artan, bir baka deyile identity tipinde olan bir alann insert sorgusuna dahil
edilmemesi gerekmektedir. yleyse bu bilgiyi ieren nitelik (attribute) ele alnmaldr. Benzer
ekilde zelliklerin hangi tablo alanlarna denk geldii veya snfn hangi emadaki hangi tabloya
denk geldii bilgileride niteliklerimizden alnmaldr. Bu ihtiyalar dorultusunda gelitirilen kodlar
gz nne alndnda herhangibir tipin alma zamannda uygulanan niteliini elde etmek
amacyla GetCustomAttributes isimli metod kullanlmaktadr. Bu metod ilk parametre olarak elde
edilmek istenen niteliin tipini alr. Metodun belkide en nemli zellii geriye objecttipinden bir dizi
dndryor oluudur. Dnen bu dizi ierisinden nitelie ait zellikleri ekebilmek iin bir
dntrme (cast) ilemi yaplmaldr. GetCustomAttributesmetodunun geriye dizi dndrmesinin
sebebi, bir tipe veya yeye birden fazla niteliin uygulanabilecek olmasdr. Elde edilen dizi
tekrardan uygun nitelik(Attribute) tipine dntrldnde indisleme operatr sayesinde
okunmak istenen zelliklere eriilebilir. Ki rneimizde 0 indisli referanslar ekilmitir. Insert
metodunda kullandmz aadaki kod parasnda UrunEntity snfna uygulanan TabloAttribute'
tipinin referans yakalanmaktadr.

TabloAttribute tblAtr =
((TabloAttribute[])tip.GetCustomAttributes(typeof(TabloAttribute), false))[0];

Burada kullanlan GetCustomAttributes metodu tipe aittir. Snf ierisindeki yelere uygulanan
nitelikleri elde etmek iinde ayn yol kullanlr. Nitekim, nitelik(attribute) uygulanabilen tm
yelerin GetCustomAttributes metodu bulunmaktadr. Sz gelimi, UrunEntity snfndaki
zelliklere(properties) uygulanan nitelikleri alma zamannda elde edebilmek
iinGetProperties metodu ile gezilen PropertyInfo referanslarna GetCustomAttributes metodu
aadaki gibi uygulanmtr.

AlanAttribute atr=((AlanAttribute[])prp.GetCustomAttributes(typeof(AlanAttribute),
false))[0];

Bu ekilde nitelik referanslar elde edildikten sonra sz konusu niteliin yelerinin deerlerine
baklabilir.

Her ne kadar makalemizin konusu nitelikleri yazmak olsada reflection ile ilgili baz
noktalara da deinmek gerekir. rnein Insert metodu ierisinde alma zamannda o
anki UrunEntity nesne rneinin zelliklerinin deerlerinin elde edilmesi
iin, GetValue isimli metod kullanlmtr. Bu metodun ilk parametresi, deerleri tayan
nesne rneinin referansdr.

rneimizi herhangibir program ierisinde test etmek iin aadaki gibi bir kod parasndan
faydalanabiliriz. Bu amala rnek bir Console uygulamasn test program amacyla kullanabiliriz.

www.bsenyurt.com Page 1178


Tek yapmamz gereken bir UrunEntity nesne rnei oluturmak sonrasnda ilgili zelliklerinde baz
deerler atamak ve Insert metodunu armaktr.

UrunEntity urn = new UrunEntity();


urn.UrunAdi = "Pentium CPU";
urn.Fiyat = 90;
urn.SonSatisTarihi = DateTime.Now.AddDays(30);
urn.Insert();

Amacmz nitelikleri kavramak olduu iin, Insert metodunun ierisinde insert sorgusunu
altrmak iin gereken Data Access Layer arlar yazlmamtr. Ancak sonular grmek adna
alma zamannda Insert metodunun arld satra bir breakpoint koyarak adm adm (step
into) ilerlemekte fayda vardr. Bunun sonucunda aadaki ekran grntsnde olduu gibi Insert
sorgusunun doru bir ekilde oluturulduunu grebiliriz. Dikkat ederseniz UrunId zellii hi bir
ekilde hesaba katlmamtr. Ayrca zelliklerin tabloda karlk olan adlarna baklarak bu sorgu
cmlesi oluturulmutur.

Program kodumuzdan retilen assembly ierisine ildasm.exe arac yardmyla bakmakta fayda
vardr. Bunu yaptmzda yazdmz niteliklerin o anki bilgileri ile birlikte assembly' n metadata'
sna eklendiini grebiliriz. (Ildasm aracnda metadata' y grebilmek iin Ctrl+M tu
kombinasyonunu kullanrz.) rnek olark UrunId isimli zelliimiz iin eklenen nitelik metadata
ierisinde aadaki ekilde grnecektir.

AlanAttribute' unun Metadata izi;

Property #1 (17000006)
-------------------------------------------------------
Prop.Name : UrunId (17000006)
Flags : [none] (00000000)
CallCnvntn: [PROPERTY]
hasThis
ReturnType: I4
No arguments.
DefltValue:
Setter : (06000015) set_UrunId
Getter : (06000014) get_UrunId
0 Others
CustomAttribute #1 (0c000011)
-------------------------------------------------------
CustomAttribute Type: 06000013
CustomAttributeName: AttributeTemelleri.AlanAttribute :: instance void .ctor()
Length: 54

www.bsenyurt.com Page 1179


Value : 01 00 03 00 54 0e 07 41 6c 61 6e 41 64 69 09 50 > T AlanAdi P<
: 72 6f 64 75 63 74 49 44 54 02 08 49 64 65 6e 74 >roductIDT Ident<
: 69 74 79 01 54 02 0e 4e 75 6c 6c 49 63 65 72 65 >ity T NullIcere<
: 62 69 6c 69 72 00 >bilir <
ctor args: ()

Burada ak bir ekilde niteliin(attribute) zelliklerine atanan deerler de grlebilmektedir.


Benzer ekilde UrunEntity isimli snfmza uygulanan TabloAttribute niteliinin metadata ierisine
yapt katkyda grebiliriz.

TabloAttribute' unun Metadata izi;

CustomAttribute #1 (0c000010)
-------------------------------------------------------
CustomAttribute Type: 06000009
CustomAttributeName: AttributeTemelleri.TabloAttribute :: instance void .ctor()
Length: 46
Value : 01 00 02 00 54 0e 09 53 63 68 65 6d 61 41 64 69 > T SchemaAdi<
: 0a 50 72 6f 64 75 63 74 69 6f 6e 54 0e 08 54 61 > ProductionT Ta<
: 62 6c 6f 41 64 69 07 50 72 6f 64 75 63 74 >bloAdi Product <
ctor args: ()

Yine grdnz gibi SchemaAdi zelliine atanan Production deeri ile TabloAdi' na atanan
Product deerleri buraya Value olarak alnmtr.

Program kodlarmz daha da gelitirmek siz deerli okurlarmzn elindedir. rnein, Insert,
Update, Delete ve Load metodlarn gelitirebilir bunlar gerekirse bir base snf ierisinde
toplanabilir. Bylece geldik bir makalemizin daha sonuna. Bu makalemizde, nitelikleri(attribute)
daha yakndan tanmaya altk ve kendi niteliklerimizimi (Custom Attributes) nasl
yazabileceimizi incelemeye altk. Grdnz gibi niteliklerde birer snf olarak
dnldklerinde gelitirilmeleri son derece kolay tiplerdir. Ne varki niteliklerin asl gc alma
zamannda reflection kullanldnda ortaya kmaktadr. Tekrardan hatrlatmak gerekirse, ama
alma zamannda tiplere ve yelere nasl davranlacana dair kararlarn verilmesinde assembly
ierisindeki ekstra metadata bilgilerinde faydalanlmasdr. Bir sonraki makalemizde grmek
dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Balantsz Katmanda LINQ ( 02.04.2007 ) - C#


3.0
Deerli Okurlarm Merhabalar,

Language Integrated Query (Dil ile tmletirilmi sorgu) yardmyla yapabileceklerimiz saymakla
bitmiyor. Aslnda LINQ projesinin en nemli k nedeni, Anders Hejslberg' n anlatmyla veri ve
nesne eitsizliidir. (data!=objects) Bu ifadeyi, TechEd 2006 sunumlarnda kullanan Anders
Hejslberg, zellikle veri yaplarnn programlama ortamna alnmas sonrasnda, var olan basit sorgu
tekniklerinin uygulanamayndan yaknmaktadr. LINQ projesinin aslnda en temel amac,

www.bsenyurt.com Page 1180


uygulamalarn alma alanlarnda (.Net perspektifinden baktmzda Application Domain' ler
ierisinde), bellek zerinde konulanan nesneler zerinden bildiimiz veri sorgulama kurallarn
uygulayabilmektir. Bir baka deyile, nesne(object) zerinde, var olan veritaban nesnelerini
tayabilen Entity bileenleri zerinde, bellee alnan Xml veri setleri zerinde, sorgulamalar
bilinen allagelmi sz dizimleri ile tek bir standart altnda yapabilmektir. Tm bu farkl nesnel
yaplarn ortak bir sorgulama dilini kullanabiliyor olmas da LINQ projesinin ana fikirlerinden birisidir
aslnda.

Yukardaki grafikte, LINQ projesinin odakland temel modeller ifade edilmeye allmtr. LINQ
sorgular bildiiniz gibi bellek zerinde herhangibir ekilde IEnumerablearayzn uyarlam olan
her tr nesne topluluuna uygulanabilmektedir. Bu nedenle bellek ii nesnelerden (in memory
objects), veritaban(database) balantl Entity nesnelerine kadar pek ok yerde
kullanlabilmektedir.

C# 3.0 ve gelecei ile ilgili olarak nceki makalelerimizde, DLINQ, XLINQ modellerini incelemeye
almtk. Bunlarn yannda LINQ ile yapabileceklerimizi daha derinlemesine kavrayabilmek
maksadyla bol bol sorgu gelitirdik. Bugnk makalemizde ise, zellikle balantsz katman
(disconnected layer) nesneleri zerinde, yani bildiimiz DataSet veDataTable nesne rnekleri
zerinde LINQ sorgularn nasl yazabileceimizi basit bir ekilde incelemeye alacaz. DataSet ve
DataTable gibi bileenler bildiiniz gibi herhangibir veri kaynandan yklenen sonu kmelerini
uygulama belleinde tutmak amacyla kullanlmaktadr. Ne varki alma zamannda, balantsz
katman nesneleri zerindeki verilerde sorgulama yapabilmek iin eitli yollara bavurmamz
gerekir. rnein bunlardan birisi Select metodudur. Bir baka teknikte veri
kmelerini DataView bileenlerine alp filtreleme amacyla yardmc fonksiyonellerden
faydalanmaktr. LINQ, felsefe olarak yukarda bahsettiimiz tm veri kmeleri iin ortak bir
sorgulama ortam sunmaktadr. yleyse balantsz katman nesneleri iinde bu tekilletirilmi
sorgulama modelini nasl ele alabiliriz?Dilerseniz hi vakit kaybetmeden rneimize balayalm. Bu
seferki rneimizi LINQ Windows Application projesi olarak gelitireceiz. Nitekim, DataTable
ieriini ekranda grsel olarak ele alabileceimiz bir ortam olaylar daha net alglayabilmemizi
salayacaktr. Elbetteki bu makalede bahsedilen ilemleri gerekletirebilmek iin sistemimizde
LINQ Preview srmnn ykl olmas gerektiini unutmayalm.

www.bsenyurt.com Page 1181


Herhangibir DataTable zerinden LINQ sorgular altrabilmemiz
iin System.Data.Extensions isimli ktphanenin program ierisinde referans edilmi olmas
yeterlidir. almakta olduumuz LINQ Windows uygulamas bu referans varsaylan olarak
iermektedir.

Hereyden nce uygulamamzn bellek zerinde DataSet ve DataTable nesnelerine sahip olmas
gerekiyor. Bu amala makalemizde AdventureWorks ve Northwind veritabanlarndan
yararlanacaz. DataTable nesnelerimizi doldurmak iin bavurabileceimiz iki yol var. Bunlardan
birisi, standart Ado.Net tiplerinden ve fonksiyonelliklerinden yararlanmak. Bir baka
deyile,DataAdapter tipi ve Fill metodundan bahsediyoruz. Ancak bu kez biraz daha farkl olarak
entity nesnelerinden faydalanacaz. Hatrlarsanz DLINQ konusunu incelediimiz
makalemizde, bir database ve ierisindeki tablolar iin otomatik olarak entity hazrlayabilmemizi
salayan SqlMetal isimli bir aracn LINQ Preview projesi ile birlikte geldiinden bahsetmitik. Bizim
iin gereken Entity snflarn oluturmas iin SqlMetal aracn aadaki gibi kullanp retilen .cs
dosyalarn projemize eklememiz yeterli olacaktr. (SqlMetal aracna, LINQ Preview' u kurduktan
sonra, varsaylan olarak D:\Program Files\LINQ Preview\Bin adresinden ulaabilirsiniz.)

Dolaysyla artk entity nesneleri zerinden DataTable nesne rnekleri ierisine veri doldurma
ilemini gerekletirebiliriz. Yazacamz ilk kod paras, AdventureWorks veritaban ierisinde yer
alan Production emasndaki Product tablosundan baz satrlarn bir DataTable ierisine LINQ
sorgular yardmyla alnmas ilemini gerekletirecektir. Bu amala aadaki kod parasnda
olduu gibi AdventureWorks isimli snfmza ait bir nesne rnei oluturmamz gerekmektedir.

AdventureWorks adWorks = new AdventureWorks("data


source=localhost;database=AdventureWorks;integrated security=SSPI");

Artk entity snflarmza ait nesne rneklerini, adWorks zerinden kullanabiliriz. Aadaki metod
ile, global olarak tanmladmz adWorks nesnesini kullanarak, yine global olarak tanmladmz
dtUrunler isimli DataTable isimli nesne rneine veri doldurma ilemi yaplmaktadr. Biz LINQ

www.bsenyurt.com Page 1182


sorgumuz ierisinden belirli alanlar alp yeni bir isimsiz tip(anonymous type) olarak ekmekteyiz.
Elbetteki bu sorgu ierisinde bildiimiz tm LINQ imkanlarn kullanabiliriz. Where, order by gibi
ifadeler bunlara rnek olarak verilebilir.

private DataTable LoadProductsTable()


{
var urunler =from prd in adWorks.Production.Product
select new {
prd.ProductID
,prd.Name
,prd.ListPrice
,prd.Class
,prd.SellStartDate
,prd.SafetyStockLevel
,prd.StandardCost
};

DataTable dtUrunler=new DataTable("Urunler");


dtUrunler=urunler.ToDataTable();
return dtUrunler;
}

Burada ilk olarak adWorks.Production.Product entity nesnesi zerinden bir LINQ sorgusu
altrlmaktadr. Bunun sonucunda elde edilen veri kmesini bir DataTable ierisine aktarmak iin
ise tek yaplmas gereken ToDataTable isimli metodun arlmasdr. (System.Data.Extensions
isim alan, DataTable ve DataRow' lar iin LINQ sorgular hazrlanmasn salayan pek ok
geniletme metodu iermektedir.)

Kendi rneklerimizi denerken dikkat etmemiz gereken bir nokta vardr. zellikle null
deer alabilen saysal ve tarihsel formatl alanlar iin LINQ sorgular aadaki ekran
grntsnde yer alan alma zaman istisnasna neden olabilmektedir. rnein Product
tablosunda saysal ve null deer alabilen bir alan olarak tanmlanm olan
ProductSubCategoryID iin bu istisna mesaj elde edilmektedir.

Ayn durum null deerler alabilen varchar, nvarchar tipli alanlar iin geerli deildir.
Bunlarn program ortam ierisinde yer alan entity snflar ierisinde string olarak
kullanldna ve string' in zellikle referans tipi olduu iin null deer tayabildiine
dikkat edelim.

Artk elde ettiimiz DataTable nesne rneini herhangibir grsel taycya (container)
balayabiliriz. Bu amala .Net 2.0 ile gelen DataGirdView kontrol biilmi kaftandr. Uygulamada
bu durumu test etmek iin ana formumuzun Load olay metodu ierisinde aadaki rnek kod
paralar yazlmtr.

www.bsenyurt.com Page 1183


adWorks = new AdventureWorks("data source=localhost;database=AdventureWorks;integrated
security=SSPI");

dtUrunler = LoadProductsTable();
dgUrunler.DataSource=dtUrunler;

label1.Text = "rn Says " + (dgUrunler.Rows.Count-1).ToString();

Programn almas sonucu aadaki ekran grntsn elde ederiz. Dikkat ederseniz Product
tablosundan 504 adet rn bilgisi yklenmitir.

Asl amacmz elbetteki DataTable nesne rneini doldurmak deildir. zellikle unu tekrar
belirtmekte fayda vardr. rneimizde Entity tipleri zerinden veri ekme ilemi yaplmtr. Pekala
bunu DataAdapter yardmyla da gerekletirebiliriz. Ancak asl yapmak istediimiz veriyi
balantsz katmana nasl aldmz deil, bellekte veri tayan DataTable zerinden LINQ
sorgularn nasl altrabileceimizdir. Nitekim LINQ, DataTable veya DataSet ierisine verinin nasl
ekildii ile ilgilenmez. Bu amala rnein yukardaki sonular dndren DataTable bileenimizin
ierisinde retim tarihi (SellStartDate alannn deeri) bellirli bir zamandan sonra olanlar bulmak
istediimizi dnelim. Sz konusu sorgu iin aadaki gibi bir kod parasn kullanabiliriz.

var sorgulanabilirUrunler = dtUrunler.ToQueryable();

var sonuclar=from prd in sorgulanabilirUrunler


where prd.Field<DateTime>("SellStartDate")>=dateTimePicker1.Value
select new {
ProductID=prd.Field<int>("ProductID")
,Name=prd.Field<string>("Name")
,ListPrice=prd.Field<decimal>("ListPrice")
,Class=prd.Field<string>("Class")
,SellStartDate=prd.Field<DateTime>("SellStartDate")
,SafetyStockLevel=prd.Field<short>("SafetyStockLevel")
,StandartCost=prd.Field<decimal>("StandardCost")
};

dgUrunler.DataSource=sonuclar.ToDataTable();

www.bsenyurt.com Page 1184


label1.Text="rn Says "+(dgUrunler.Rows.Count-1).ToString();

Dikkat edeceimiz ilk nokta ToQueryable metodunun kullanlmasdr. Bu metodun tek amac
DataTable zerinde LINQ sorgularnn altrlabilmesini salamaktr.
AslndaToQueryable, ToDataTable, Field<T> gibi
metodlar, System.Data.Extensions.dll ierisinde gelen geniletme metodlardr. Bunlar grmek
iin her hangibir decompiler aracn kullanabiliriz. rneiz XenoCode Fox 2007 Community
Edition arac yardmyla System.Data.Extensions.dll ieriine bakacak olursak aadaki sonular
alrz.

Grdnz gibi DataTable iin ToQueryable ve ToDataTable metodlar, DataRow tipi


iin Field<T> metodu vb... yer almaktadr. Field<T> metodu, sorgulanabilir hale getirlmi olan
DataTable ierisindeki DataRow dizileri zerinden istenen alann elde edilebilmesi amacyla
kullanlmaktadr. Dikkat ederseniz generic bir metoddur ve tip olarakta, ekilen alann veri tipini
almaktadr. Bu tipin elbetteki doru girilmesi arttr. Aksi takdirde derleme zaman hatalar alrz.

Peki, sorgumuz tam olarak ne yapmaktadr? Tahmin edeceiniz gibi where anahtar kelimesi
sayesinde SellStartDate alannn deeri DateTimePicker kontrolnde seilen tarihten sonra gelen
satrlar ekilmektedir. Buradaki where cmlesinde yer
alan prd.Field<DateTime>("SellStartDate")>=dateTimePicker1.Value ifadesinin sz konusu
DataTable ierisindeki her bir DataRowiin altn unutmayalm. Bunu daha kolay idrak
edebilmek iin bu tip bir gereksinimi LINQ olmadan eski usuller ile yazmak istediinizi dnn.
Tm satrlar gezeceimiz bir dng yazmamz gerektiini tahmin edebiliriz. Sonu itibariyle
kodumuzu altrdmzda aadaki veri kmesini elde ederiz.

www.bsenyurt.com Page 1185


Sorgularmz eitlendirebiliriz. yleki artk elimizdeki nesne, DataTable zerinden elde edilmi
sorgulanabilir bir DataRow kmesinden baka bir ey deildir ve LINQ ifadelerine dorudan destek
vermektedir. imdi ilemlerimizi biraz daha ilerletelim. rnein birbiriyle ilikili olabilen iki
DataTable zerinde LINQ yardmyla bir Join ilemi gerekletirmeye alalm. Bu amala
Northwind veritabannda yer alan Order ve OrderDetails tablolarndan faydalalanbiliriz. ncelikle bu
tablolar entity nesnelerimize alacaz ve sonrasnda ise DataTable nesne rneklerine ykleyeceiz.
Son olarakta bu iki DataTable rneine ait sorgulanabilir bir nesne zerinden LINQ yardmyla bir
Join ilemi gerekletireceiz. Bu amala programmza aadaki metodlar ekleyelim.

private DataTable LoadOrdersTable()


{
var siparisler=from s in north.Orders
select new {
s.OrderID
,s.ShipAddress
,s.ShipCity
,s.ShipRegion
,s.ShipPostalCode
,s.ShipCountry
};

return siparisler.ToDataTable();
}

private DataTable LoadOrderDetailsTable()


{
var siparisDetaylari=from d in north.OrderDetails
select new {
d.OrderID
,d.UnitPrice
,d.Quantity
};

return siparisDetaylari.ToDataTable();

www.bsenyurt.com Page 1186


}

Metodlarmz srasyla north isimli global olarak tanmlanm entity nesnesi zerinden hareket
ederek Orders ve OrderDetails tablolarndan bellee baz alanlar iin veri ekmektedir. Son olarak
elde edilen sonu kmeleri ToDataTable metodu yardmyla geri dndrlyor. imdi bu iki veri
kmesininde OrderID alanlar zerinden birbirlerine bal olduunu biliyoruz. Dolaysyla birletirme
ilemini gerekletireceimiz sorgu cmesinde bu durumu gz nne almamz gerekiyor. Bu
amala aadaki gibi bir kod parasndan faydalanabiliriz.

AdventureWorks adWorks;
Northwind north;
DataTable dtUrunler, dtSiparisler, dtSiparisDetaylari;

private void Form1_Load(object sender, EventArgs e)


{
adWorks = new AdventureWorks("data source=localhost;database=AdventureWorks;integrated
security=SSPI");
north = new Northwind("data source=localhost;database=Northwind;integrated
security=SSPI");

dtUrunler = LoadProductsTable();
dgUrunler.DataSource = dtUrunler;

label1.Text = "rn Says " + (dgUrunler.Rows.Count - 1).ToString();

dtSiparisler = LoadOrdersTable();
dtSiparisDetaylari = LoadOrderDetailsTable();

dgSiparisler.DataSource = dtSiparisler;
dgSiparisDetaylari.DataSource = dtSiparisDetaylari;
}

private void btnJoin_Click(object sender, EventArgs e)


{
var sorgulanabilirOrders = dtSiparisler.ToQueryable();
var sorgulanabilirOrderDetails = dtSiparisDetaylari.ToQueryable();

var sonuclar=from o in sorgulanabilirOrders


join od in sorgulanabilirOrderDetails
on o.Field<int>("OrderID") equals od.Field<int>("OrderID")
select new {
SiparisID=o.Field<int>("OrderID")
,BirimFiyat=od.Field<decimal>("UnitPrice")
,Miktar=od.Field<short>("Quantity")
,Sehir=o.Field<string>("ShipCity")
,Ulke=o.Field<string>("ShipCountry")
};

dgJoin.DataSource=sonuclar.ToDataTable();
}

LINQ mimarisinde kullandmz Join kalbn burada da aynen kullanmaktayz. Tek dikkat etmemiz
gereken, generic Field<T> metodunu nasl ele aldmzdr. o takma ad ile siparileri tutan
sorgulanabilir DataRow nesne dizisini (sorgulanabilirOrders), od takma ad ilede sipari detaylarn
tutan sorgulanabilir DataRow nesne dizisini (sorgulanabilirOrderDetails) ifade etmekteyiz. Buna

www.bsenyurt.com Page 1187


gre join ilemini OrderID alanlar zerinden gerekletiren ifademiz aadaki gibidir. Burada her
iki DataRow dizisindeki ilgili alanlarn eitliine gre bir kstas getirilmektedir.

on o.Field<int>("OrderID") equals od.Field<int>("OrderID")

Programmz altrdmzda aadakine benzer bir ekran grnts ile karlarz. (TabPage' in
st tarafnda yer alan iki DataGridView bileeni, srasyla Orders ve OrderDetails bilgilerini
gstermektedir.)

Dilersek join ile yazm olduumuz sorgumuza where ile baka kstlamalarda katabiliriz. rnein,
elde edilen sonu kmesinde Quantity alannn deeri 10' un zerindeolanlar elde etmek iin
tek yapmamz gereken sorgumuzu aadaki gibi geniletmek olacaktr.

var sonuclar=from o in sorgulanabilirOrders


join od in sorgulanabilirOrderDetails
on o.Field<int>("OrderID") equals od.Field<int>("OrderID")
where od.Field<short>("Quantity")>10
select new {

www.bsenyurt.com Page 1188


SiparisID=o.Field<int>("OrderID")
,BirimFiyat=od.Field<decimal>("UnitPrice")
,Miktar=od.Field<short>("Quantity")
,Sehir=o.Field<string>("ShipCity")
,Ulke=o.Field<string>("ShipCountry")
};

Where ifadesinde ilgili alann deerinin karlatrma ilemine tabi tutmak iin yine Field<T>
generic metodundan faydalandmzda dikkat edelim.

stersek join ile yaptmz birletirme ilemini, ierisinde DataRelation nesnesi barndran bir
DataSet zerinden de gerekletirebiliriz. Bu sefer devreye st tablodaki herhangibir satra bal alt
satrlarn getirilmesini salayacak GetChildRows isimli bir fonksiyonellik gelecektir. Durumu daha iyi
anlayabilmek iin aadaki kod parasn gz nne alabiliriz.

DataSet ds = new DataSet();


ds.Tables.Add(dtSiparisler);
ds.Tables.Add(dtSiparisDetaylari);

DataRelation drOrdToDtl = new DataRelation("OrdToDetails",


dtSiparisler.Columns["OrderID"],dtSiparisDetaylari.Columns["OrderID"]);
ds.Relations.Add(drOrdToDtl);

var sorgulanabilirOrders=dtSiparisler.ToQueryable();

var sonuclar=from o in sorgulanabilirOrders


from od in o.GetChildRows("OrdToDetails")
select new {
SiparisID=o.Field<int>("OrderID")
,BirimFiyat=od.Field<decimal>("UnitPrice")
,Miktar=od.Field<short>("Quantity")
,Sehir=o.Field<string>("ShipCity")
,Ulke=o.Field<string>("ShipCountry")
};

dgJoin.DataSource=sonuclar.ToDataTable();

DataSet ierisinde yer alan, dtSiparisler ve dtSiparisDetaylari isimli DataTable nesnelerinin iaret
ettii veri kmeleri arasndaki ilikimiz OrderID alanlar zerinden Orders' dan OrderDetails' e
dorudur. Bunu DataSet ierisinde tanmlayan ise Ado.Net' in ilk kndan beri
bildiimiz DataRelation nesnesidir. LINQ sorgumuz, bu nesneyi GetChildRows isimli metod
ierisinde parametre olarak kullanmaktadr. Bylece o takma ad ile temsil edilen
sorgulanabilirOrders ierisindeki her bir DataRow iin bu iliki kullanlabilmektedir. Bu da doal
olarak, ilikinin dier ucunda yer alan siparie ait detay bilgisinin elde edilebilmesi anlamna
gelmektedir. LINQ sorgumuz iki adet from anahtar kelimesi ierdiinden sonu doal olarak bir
Join sorgusunun kts ile ayn olacaktr. Uygulamamz bu haliyle altrdmzda ilk yazdmz
join sorgusundakine benzer sonular elde ederiz.

www.bsenyurt.com Page 1189


DataTable ve DataSet' ler zerinde ToQueryable, ToDataTable, Field<T> metodlar
dnda, LoadSequence, DistinctRows, EqualAllRows, UnionRows, IntersectRows,
ExceptRows, SetField<T> isimli metodlarda kullanlabilmektedir. Bu metodlarn temel amac,
DataTable ve DataRow gibi nesneler zerinde LINQ tekniklerinin daha da geniletilmesini
salamaktr. rnein LoadSequence metodu sayesinde herhangibir sorgu sonucu elde edilen
kmeyi bir var olan bir DataTable ierisine ilave edebiliriz. Bu metod ve dierleri hakknda daha
fazla bilgi almak iin LINQ dkmantasyonundan faydalanabilirsiniz.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde, LINQ' yu DataTable gibi balantsz
katman nesneleri zerinde nasl kullanabileceimizi incelemeye altk. Bir sonraki makalemizde
grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Kendi Web Part Bileenlerimizi Gelitirmek (


28.03.2007 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Web uygulamalarnda var olan bileenlerin yetersiz kald durumlarda kendi kontrollerimizi
gelitirme yoluna gidebiliyoruz. Kendi kontrollerimizi gelitirirken seebileceimiz yollar bellidir. Var
olan bir web bileeninden tretme yolunu seebiliriz (Inherited Controls). Bu durumda kontroln
Html ktsnn ne olacan bir baka deyile Render ilemlerini ok fazla dnmemize gerek
kalmaz. Tek yapmamz gereken var olan yeleri ezmek (override) veya yeni yeler katmaktr. Bir
dier yol birden fazla kontrol ieren komposit bir bileen gelitirmektir(Composite Controls). Bu
teknie verilebilecek en gzel rnek kullanc web kontrolleridir (web user controls). zel bileen
gelitirmenin belkide en zor seenei, kontrol sfrdan yazmaktr. Bu durumda, ilgili bileenin
istemci tarayclarndaki Html ktsn dnmekle kalmayp, ViewState, Postback, Event
Handling gibi temel konularnda gz nne alnmas ve dnlmesi gerekir.

Asp.Net 2.0 ile birlikte WebPart ad verilen bir Framework gelmitir. Bu Framework istersek kolay
bir ekilde kiiselletirilebilir (Personalizable) web kontrolleri yazabilmemizede olanak
salamaktadr. Aslnda bahsettiimiz zelletirilmi kontrollerin birer WebPart tipi olduunu
sylemek gerekir. Dolaysyla, kendi WebPart bileenlerimizi tretme yardmyla kolay bir ekilde
gelitirebilir ve kullanabiliriz. WebPart' lar sfrdan yazlan bileen kontrolleri ve web kullanc
kontrollerine nazaran, WebPart Framework iin tam destek salarlar. Bu da, kiiselletirmenin

www.bsenyurt.com Page 1190


kullanld sayfalarda olduka nemli bir meziyettir. te biz bu makalemizde basit olarak kendi
Web Part bileenlerimizi nasl gelitirebileceimizi incelemeye alacaz.

Normal artlar altnda sayfada yer alan herhangiri Web Part Zone ierisine alnan her bileen
otomatik olarak Web Part muamalesi grr. Lakin kendi Web Part bileenlerimizi gelitirdiimizde,
daha ncedende belirttiimiz gibi Web Part Framework' ierisindeki zelliklerin ve
fonksiyonelliklerin tamamn kullanabilme ansna sahip oluruz. yleyse ieWebPart tipinden
treyen bir snf yazmak ile balamak lazm.

WebPart tipi abstract bir snf olup, bir Web Part bileeni iin gerekli tm temel alt yapy
sunmaktadr.

Bildiiniz gibi, Visual Studio 2005 ierisindeki proje ablonlarndan biriside, Web Control
Library seeneidir. Web Control Library, standart olarak rnek bir zel kontrol (Custom Control)
snf ierir. Ayn zamanda Web ortam iin gerekli temel referanslarda hazr olarak
barndrr. (rnein System.Web) Biz Web Part bileenimizi byle bir kontrol ktphanesi ierisine
dahil edersek, herhangibir web uygulamasnda kolayca kullanabiliriz. Dahas, gelitirdiimiz Web
Part bileenlerini Visual Studio ToolBox ierisinde ele alabiliriz. Bu da Web Part bileenimizi bir
kontrol olarak ToolBox ierisinde tutabileceimiz anlamna gelmektedir.

Gelelim makalemizin rnek senaryosuna. Kendi Web Part kontrollerimizi gelitirmeyi renirken,
standart olarak ele alnan senaryo, RSS bilgilerini tutan bir bileenin yazlmasdr. Bizde gelenei
bozmayp bu tip bir Web Part bileenini nasl yazabileceimizi incelemeye alacaz. Ancak
balamadan nce RSS ile ilikili olarak biraz bilgi vermekte fayda olaca kansndaym. Gnmzde
pek ok web sitesi, gncel olarak yaynlamak istedikleri bilgilerin, bakalar tarafndan kolay bir
ekilde ele alnabilmesi amacyla, Xml tabanl ierikler sunarlar. RSS bu anlamda Xml verisini
standardize etmektedir. Bylece, her RSS ieriinin ayn emaya sahip olmas salanm olur. Bizde
bu yaklam kullanacaz. zellikle .Net Framework, Xml zerinde son derece etkili ynetimli
tipler (managed types) sunmaktadr. Bu tiplerden faydalanarak her hangibir RSS ieriini kolay
bir ekilde ayrtrabiliriz(parsing). Aadaki ekran grntsnde C#Nedir?
sitesinin http://www.csharpnedir.com/Rss.xml adresinden yaynlanan RSS dkmannn bir
parasn grmektesiniz.

www.bsenyurt.com Page 1191


Dikkat ederseniz, rss isimli root element ierisinde channel isimli tek bir alt boum (childe
node) vardr. Bu node ierisinde RSS dkmann sahibi ile ilikili eitli bilgiler yer alr. rnein,
RSS konusunu anlatan balk(title) ve aklama(description) bilgisi, RSS sahibinin web adresi(link)
gibi. Dier taraftan item elementleri ierisindede RSS ile yaynlanmak istenen asl ierik yer alr.
zetle bu RSS dkman ile alma zamannda C#Nedir? sitesinde yaynlanan son makalelerin
listesini elde edebilir, balantlar kullanarak buralara gei yapabiliriz. Eer bu RSS dkmann
internet zerinden talep edersek aadakine benzer bir ekran grnts alrz.

www.bsenyurt.com Page 1192


te Web Part kontrolmz, kii baznda herhangibir RSS bilgisini sunacak ekilde tasarlanacaktr.
Burada RSS' in Url bilgisini ve hatta RSS' in sahibi ile ilgili ksa bir bilgiyi, kii baznda ayr ayr
saklayabiliriz. Gelin Web Part kontrolmz yazarak kiiselletirilebilir bir RSS okuyucunun nasl
yaplabileceini grmeye alalm. lk olarak Web Control Libraryprojemize bir snf ekleyeceiz.
Snfmzn WebPart snfndan tremi olmas gerekmektedir.

Bir snf WebPart abstract snfndan trettiimizde, sz konusu yeni tip, Web Part
Framework' n kullanabileceimiz yelerede sahip olur. Bu yeler WebPart snfnnda
tredii eitli tipler ierisinde toplanmaktadr. Aadaki ekilde, gelitirdiimiz rnek
web part bileeninin nesne hiyerarisini grebilirsiniz.

www.bsenyurt.com Page 1193


lk olarak RssPart isimli bir snf WebPart tipinden treyecek ekilde aadaki gibi tanmlayalm.

[ToolboxData("<{0}:RssPart runat=server></{0}:RssPart>")]
public class RssPart : WebPart
{
}

Gelitirdiimiz snf her ne kadar bir Web Part bileeni olsada, sunucu tarafl (server side) bir
kontroldr. Bu nedenle, aspx dosyalarnn kaynak ksmnda birer tak(tag)ierisinde ele
alnacaktr. ToolboxData isimli niteliin eklenmesinin sebebi de budur. Buna gre Web Part
bileenimizi herhangibir aspx sayfasna eklediimizde aadakine benzer bir element ierii ile
karlarz.

<cc1:RssPart ID="RssPart1" runat="server"/>

Burada cc1 n ekinin (prefix) nereden geldiini merak ediyor olabilirsiniz. Aslnda ToolBox' tan bir
WebPart kontroln sayfaya srkleyip braktmzda otomatik olarak sayfann
bana Register direktifi eklenecektir. (Bu ilk kontrol srklenip brakldnda otomatik olarak
oluur) Bu direktif temel olarak, Asp.Net uygulamasnda kullanlacak olan Web Part bileenini
ieren snf ktphanesinin (Contol Library) referans bilgisinide ierecektir. Ksaca Register
direktifimizinde aadaki gibi olacan syleyebiliriz.

<%@ Register Assembly="MyWebParts" Namespace="MyWebParts" TagPrefix="cc1" %>

Gelelim Web Part kontrolmz ierisindeki yelere. Kontrolmzn RSS belgesine ait Url bilgisini ve
ksa bir balk bilgisini tutacan varsayabiliriz. Bu bilgiler iin yapacamz normal artlar altnda

www.bsenyurt.com Page 1194


birer zellik yazmak olacaktr. Lakin bu sefer zelliklerimizin, kii baznda zelletirilebilmesini
istiyoruz. Bu nedenle Personalizable niteliini kullanmamz gerekiyor.

private string _Url;


private string _RssOwner;

[WebBrowsable(true)] // PropertyGridEditorPart ierisinde bu zelliin gsterilip


gsterilmeyeceini belirtir.
[WebDescription("Verilen Url adresine gre Rss bilgisini okur")]
[Personalizable(PersonalizationScope.User)] // zelliin deerinin Membership tablolarnda
kullanc baznda tutulacan belirtir.
[WebDisplayName("Rss Bilgisi Alnacak Url")] // PropertyGridEditorPart ierisinde Url zellii iin
gsterilecek bilgi
public string Url
{
get { return _Url; }
set { _Url = value; }
}

[WebBrowsable(true)]
[WebDescription("Rss sahibine ait bilgiyi ierir")]
[Personalizable( PersonalizationScope.User)]
[WebDisplayName("Rss Yaymcs")]
public string RssOwner
{
set { _RssOwner = value; }
get{return _RssOwner;}
}

Url ve RssOwner isimli zelliklerimiz, kiiselletirilebilir yelerdir. Personalizable niteliine


atanan PersonalizableScop.User deeri sayesinde Url ve RssOwner zelliklerinin iaret ettikleri
deerlerin, kii baznda Membership API' si zerinden ilgili tablolarda tutulabilecei
belirtilmektedir. WebBrowsable nitelii ile, zelliin bir PropertyGridEditorPart bileeni
ierisinde gsterilip gsterilmeyeceine karar verilebilir. Buna gre Url ve RssOwner isimli
zelliklerimizi, sayfay ziyaret eden kullanclar isterlerse PropertyGridEditorPart ierisinden
deitirebilirler. WebDescription nitelii(attribute), PropertyGridEditorPart ierisinde gsterilecek
olan zelliklerin zerlerine gelindiinde ksa aklama kutucuklar gsterilmesini salar. Son
olarak WebDisplayName nitelii sayesinde, zelliklerin ProperyGridEditorPart ierisinde hangi
adlar ile sunulaca belirtilmektedir.

Kii baznda tutulacak zelliklerimizide belirttikten sonra, Web Part kontrolmzn ekrana nasl
izileceini ayarlayabiliriz. Bildiiniz gibi, her sunucu web bileeni istemci tarafnda Html ktlar
haline getirilirler (Render ilemi). Burada da, belirtilen Url adresindeki RSS dkmann
ayrtrdktan(parsing) sonra rnek olarak linkler halinde gstermek isteyebiliriz. Bu ktnn dzenli
bir formatta olmasn salamak iinde Html tablolarna bavurabiliriz. Bir sunucu kontrolnde, Html
ktsn oluturmak iin Render metodu gz nne alnabilir. Dier
taratfan CreateChildControls metoduna bavurup daha kolay bir biimde kt retebiliriz.
CreateChildControls metodunu ilerleyen makalelerimizde ele almaya alacaz. imdi dilerseniz,
Web Part bileenimiz iin Render metodunu ezelim (override) ve Html ktsn, RSS ieriine
gre hazrlayalm.

protected override void Render(HtmlTextWriter output)


{
if (!String.IsNullOrEmpty(Url))
{

www.bsenyurt.com Page 1195


try
{
XmlReader reader = XmlReader.Create(Url);

DataSet ds = new DataSet();


ds.ReadXml(reader);

DataTable items = ds.Tables["item"];

#region Render Table

// Table elementi render edilmeden nce gerekli style attribute' lar ekleniyor
output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "WhiteSmoke"); //
Arka plan rengi
output.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%"); // genilik belirleniyor
output.RenderBeginTag(HtmlTextWriterTag.Table); // Table iin al taks

output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "Gold");
output.RenderBeginTag(HtmlTextWriterTag.Tr); // Tr al taks (satr)
output.RenderBeginTag(HtmlTextWriterTag.Td); // Td al taks (hcre)
output.Write(ds.Tables["channel"].Rows[0]["title"].ToString()); // Td
ierisine Rss dkmanndan title bilgisi alnyor
output.RenderEndTag(); // Td iin kapan taks
output.RenderEndTag(); // Tr iin kapan taks

// Rss dkmanndaki her bir item iin bir Tr (Table Row) ve ierisinde bir Td (hcre)
oluturuluyor
for (int i = 0; i < items.Rows.Count; i++)
{
output.RenderBeginTag(HtmlTextWriterTag.Tr); // Tr al taks
output.RenderBeginTag(HtmlTextWriterTag.Td); // Td al taks
output.AddAttribute(HtmlTextWriterAttribute.Href,
items.Rows[i]["link"].ToString()); // href isimli attribute sonraki satrda alacak olan A taksna
ilave edilecek. Deeri ise link alannn ierii olacak
output.RenderBeginTag(HtmlTextWriterTag.A);// A taks alyor
output.Write(items.Rows[i]["title"].ToString()); // A taks iine title alannn
deeri yazlyor
output.RenderEndTag(); // A taks kapatlyor
output.RenderEndTag(); // Td taks kapatlyor
output.RenderEndTag(); // Tr taks kapatlyor
}

output.RenderEndTag();// Table' n biti taks </table>


}
catch
{
output.Write("Adres zmlenemedi");
}

#endregion
}
}

Render metodunda, daha nceden Web sunucu kontrol yazmak ile ilikili makalelerimizde
kullandmzdan biraz daha farkl bir yol tercih ettik. Html ieriini olutururken, .Net ierisinde yer
alan kuvvetli tiplerden faydalanrsak hatal Html taks yazma olaslmz daha da azalacak ve

www.bsenyurt.com Page 1196


zellikle tarayc farkllklarn bertaraf edeceizdir. Bu nedenle Render metodu
ierisinde, HtmlTextWriter snfna
ait RenderBeginTag, RenderEndTag, AddAttribute, AddStyleAttribute gibi metodlardan
yararlanlmtr. rneimize gre ieriimiz bir Table elementi ierisinde tek stundan oluan bir
yapda olacaktr. Bu amala bir table taks amak iin

output.RenderBeginTag(HtmlTextWriterTag.Table);

kod satrndan faydalanlmtr. Burada RenderBeginTag, bir taknn oluturulmasn salarken ne


eit bir element olacan parametre olarak gnderdiimizHtmlTextWriterTag sabiti
belirtmektedir. Html ierisinde alan her taknn kapatlmas gerektiini biliyoruz. Bunu kod
tarafnda ifade ederkende yine HtmlTextWriter snfnnRenderEndTag metodundan
faydalanmaktayz. Dikkat edilmesi gereken noktalardan biriside, Html elementlerine niteliklerin
nasl eklendiidir. Dikkat ederseniz, bu amala AddStyleAttribute veAddAttribute metodlarndan
yararlanlmtr. rnein tablomuza arka plan rengi ve genilik vermek iin

output.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, "WhiteSmoke");
output.AddStyleAttribute(HtmlTextWriterStyle.Width, "100%");

kod satrlarndan faydalanlmaktadr. Hangi niteliin ekleneceini belirlemek iin


ise, HtmlTextWriterStyle sabitinden yararlanlr. AddAttribute metoduda benzer ilevsellie sahip
olmakla birlikte destekledii nitelik tipleri daha farkldr.

Gelelim metodun temel olarak yapt ie. lk olarak kiiselletirilebilen Url zelliinden deer
alnmakta ve XmlTextReader nesnesi elde edilmektedir. Hatalarn nne gemek amacyla ilk
olarak Url zelliinin deerinin bo olup olmadna baklr. Bunun haricinde internet balantsnn
kesik olmas gibi hallerde, istenen Url' den RSS bilgileri ekilemeyecei iin bir alma zaman
istisnas(runtime exception) alnacaktr. Bununda nne gemek iin genel bir try-catch blou
kullanlmtr. Bu nedenle ykleme ve Render ilemlerini try blou ierisinde gerekletirmekteyiz.
Burada Url adresinden elde edilen Xml ieriini okumak iin farkl yollarda tercih edilebilir. rnein
dorudan XmlReader zerinden hareket edilebilir veya XPathNavigotor tipinden faydalanlabilir ki
bunlar performans asndan daha etkili yollardr. Biz kodu ok fazla karmaklatrmamak adna
dorudan DataSet kontrolne alyor ve pahal bir maliyetinde altna giriyoruz :) DataSet ierisinde
yer alan channel ve item tablolarndan faydalanarak, RSS ieriindeki bilgilere eriebiliriz. rnein
RSS sahibinin belirttii bal (title), Html tablomuzun ilk satrndaki ilk hcreye alyoruz. Her bir
item elementinin belirttii, balk ve adres bilgilerini ise srasyla title ve link elementlerinden alp
bir a href elementi ierisinde gsteriyoruz. Bildiiniz gibi a href elementi bir link oluturulmasn
salamaktadr.

Web Part kontrolmzn, WebPart snfndan gelen pek ok zelliinide istersek ezebiliriz
(override). rnein, Web Part bileenimizin balk bilgisi(title), imge bilgisi (title icon image) gibi
deerlerini deitirmek isteyebiliriz. Lakin bu tip yelerin deerlerinin kontroln Html ktsnn
retilmesinden nce atanmas gerekir. Bu amala yapc metoddan, zelliin set bloundan yada
kontrole ait PreInit olay metodundan faydalanabiliriz. Gelitirdiimiz rnekte biz yapc metod ve
zellik(property) kullanmay tercih edeceiz. Bu amala snfmza aadaki yeleri eklememiz
yeterli olacaktr.

public override string Title


{
get
{
return _RssOwner;
}
set

www.bsenyurt.com Page 1197


{
_RssOwner= value;
}
}

public RssPart()
{
TitleIconImageUrl = "Bilgi.gif";
}

Yukardaki kod parasnda dikkat ederseniz, WebPart snfnda yer alan Title zellii ezilmektedir ve
kullanc tarafndan kiiselletirilebilen RssOwner zelliinin kulland _RssOwner alannn deerini
iaret etmektedir. Dier taraftan, Web Part bileenimizde hemen balk ksmnn yannda sembolik
bir imge gstermek amacyla yapc metod(constructor) ierisinde TitleIconImageUrl zelliine
bir deer atamas yaplmtr. rnek bir Asp.Net sayfasnda Web Part bileenimizi kullandmzda
tasarm zamannda iken, aadakine benzer bir grnt ile karlarz.

Burada yer alan Bilgi.gif isimli resim, Web Control Library ierisinde yer almaktadr ve herhangibir
Asp.Net projesinde ilgili Web Part bileeni kullandnda otomatik olarak root klasr ierisine
tanacaktr. Bir baka deyile eklenen ilk kontrol ile birlikte gelen web kontrol ktphanesi
referans, beraberinde kaynak olarak bu resim dosyasnda hedef web uygulamas ierisine
tayacaktr. Yaplan bu son ekelemeler ile birlikte Web Part bileenimizin yeni hali aadaki snf
diagramnda gsterildii gibi olacaktr.

www.bsenyurt.com Page 1198


Artk Web Part bileenimizi bu haliyle test edebiliriz. Kiiselletirmenin tam olarak etkilerini
grebilmek iin, bileenimizi Membership ayarlar yaplm rnek bir Asp.Net Web uygulamas
zerinden test etmekte fayda olacaktr. Testleri gerekletirmek iin ekran grnts aadaki gibi
olan bir web sayfasndan yararlanabiliriz.

Unutulmamaldr ki, gelitirdiimiz Web Part bileeninin, Web Part Framework zelliklerini etkin bir
ekilde kullanabilmesi iin bir Web Part Zone ierisinde yer almas gerekir. Bu nedenle, RssPart
isimli Web Part bileenimizi zoneRss isimli bir WebPartZone kontrol ierisinde ele alyoruz. Dier
taraftan, Web Part kontrolmz ierisinde yer alan Url ve RssOwner gibi alma zamannda
kiiselletirilebilir zelliklerini ele alabilmek iin bir Editor Zone kontrolmzde yer almaktadr.
rneimizde sadece editr ksmn gz nne alacamzdan, sayfann Page_Load olay metodu
ierisinde WebPartManager bileenimizin DisplayMode zellii aadaki
gibi EditDisplayMode olarak ayarlanmtr. Gerek bir projede elbetteki kullancnn dier
modlarda seebilecei ekilde kod yazmak gerekir.

wpmYonetici.DisplayMode = WebPartManager.EditDisplayMode;

Sonu olarak uygulamamz altrdmzda, aadaki Flash animasyonunda yer alana benzer bir
sonu ile karlarz.(Flash dosyasnn boyutu 380 Kb tr. Bu nedenle yklenmesi zaman alabilir.)

www.bsenyurt.com Page 1199


Dikkat ederseniz, iki ayr kullanc iin iki ayr RSS bilgisi ele alnabilmektedir. Burak isimli kullanc
kendisi iin Msdn' e ait RSS ieriini tutarken, Melike isimli kullancda C#Nedir? sitesine ait RSS
bilgisini ele alabilmektedir. Bu bilgilerin arka tarafta nereye yazldn kontrol etmek
istersek, Membership bilgilerinin tutulduu veritabannda (ki rneimizde local AspNetDb.mdf
dosyas kullanlmaktadr. Bir baka deyile yelik bilgileri web uygulamasn ait App_Data
klasrnde yer alan AspNetDb.mdf veritaban ierisinde saklanmaktadr.)yer
alan AspNet_PersonalizationPerUser tablosuna bakmamz yeterli olacaktr.

Kendi Web Part bileenlerimizi gelitirirken baka st snf zelliklerini ezebilir ve istediimiz ekilde
almalarn salayabiliriz. Ayn zamanda, bir Web Part bileenine alma zamannda ele alaca
yeni fiili aksiyonlar (verb) ekleyebiliriz. Bu ve benzeri dier konular ilerleyen makalelerimizde ele

www.bsenyurt.com Page 1200


almaya alacacaz. Bylece geldik bir makalemizin daha sonuna. Bu makalemizde basit olarak
kendi Web Part bileenlerimizi nasl yazabileceimizi incelemeye altk. Bunun iin,

kontrolmz tanmlayacak olan snf WebPart isimli abstract snftan tretmemiz


gerektiini,
ieride kullanc baznda kiiselletirme yapacamz zellikler iin Personalizable niteliini
(attribute) kullanmamz gerektiini,
kontroln kiiselletirilebilir zelliklerinin alma zamannda ele alnmas iin
PropertyGridEditorPart kullanmamz gerektiini,
zelliklerin PropertyGridEditorPart ierisinde gzkmesi iin WebBrowsable niteliinin
kullanlmas gerektiini,
istersek var olan Web Part zelliklerini ezerek deitirebileceimizi,
her zaman olduu gibi kontroln Html ktsn manuel olarak dnememiz ve yazmamz
gerektiini,

rendik. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz. (Dosya boyutunun klmesi iin, App_Data klasrne atlan
Aspnetdb.mdf dosyas silinmitir. Test ederken burada bir AspNetdb.mdf dosyas oluturman
gerekecektir. Bunun iin Asp.Net Web Site Administration Tool' dan faydalanabilirsiniz.)

Burak Selim ENYURT


selim@bsenyurt.com

WPF, Xaml, Baml ve Dahas ( 21.03.2007 ) -


WPF
Deerli Okurlarm Merhabalar,

Windows Presentation Foundation (WPF), windows tabanl uygulama gelitirme modeline yeni ve
ok farkl bir soluk getirmitir. Daha ok web uygulama gelitirme sistematiini andran bu yeni
model, .Net Framework 2.0 ile birlikte yapabildiklerimizi tek bir at altnda toplamtr.
Hatrlayacanz zere, benzer bir yaklam modelinin Windows Communication Foundation
(WCF) ierisinde de yer aldndan daha nceki makalelerimizde bahsetmitik. ncelikle bu
noktaya nasl gelindiini vurgulamakta fayda var. .Net Framework 2.0 asndan baktmzda
windows uygulamalarn gelitirirken yaanan baz skntlar vardr. rnein iki boyutlu grafik
ilemleri iin System.Drawing.dll ktphanesinin etkin bir ekilde bilinmesi gerekir. Ancak
windows uygulamalarmza boyutlu grafik modeller katmak istediimizde, .Net Framework' n
dna kmal ve ynetimli (Managed) DirectX API' sini renmeliyizdir. Bunlara ek bir dier
rnek olarakta, akc grsel eleri verebiliriz. Stream Video' lar ileyebilmek iin, en
azndan Media Player API' sinin ynetimli (Managed) halinin ele alnmas gerekmektedir. Peki
Windows Presentation Foundation bize bu anlamda nasl bir getiri salamaktadr. WPF, yukarda
bahsetmi olduumuz zellikleri .Net Framework 3.0 ierisinde tek bir at altnda ele alan bir
model sunmaktadr. Bylece, .Net Framework 2.0 ierisinde ayr ayr ele almak zorunda kaldmz
API ve benzeri paralar, .Net Framework 3.0 ierisinde tek ve benzersiz (unique) bir nesne modeli
ierisinde ele alma ansna sahib oluruz. Temel olarak kazanmlarmz aadaki tablo ile
zetleyebiliriz.

.Net 2.0 .Net 3.0


Kullanlmak stenen Fonksiyonellik
Yaklam Yaklam

ki boyutlu grafik destei (2D Graphics) GDI+ WPF

www.bsenyurt.com Page 1201


Managed Directx
boyutlu grafik destei (3D Graphics)
API

Akc grnt destei (Streaming Video) Media Player API

Bileen ve Windows Form Destei Windows Forms

Windows Presentation Foundation (WPF), Windows XP, Windows Server 2003 ve Vista
sistemlerinde alabilmektedir. Ancak en iyi performas Vista zerinde gstermektedir.

Vista' nn var olan 3D ve animasyon destei nedeni ile WPF uygulamalarn, Windows XP
veya Windows Server 2003 sistemlerindekine gre daha performansl
altrd, teorik olarak belirtilmektedir.

Windows Presentation Foundation ile Windows tabanl uygulamlar gelitirirken karlatmz pek
ok yeni kavramda vardr. Bunlar birisi de XAML dir. XAML, (eXtensible Application Markup
Language- yada bir baka deyile geniletilebilir uygulama iaretleme dili), zellikle windows
tabanl uygulamalar iin gelitirilmi yeni bir iaretleme dilidir. Bu iaretleme dili sayesinde .Net
Framework ierisinde yer alan tipleri birer element olarak ifade edebilme ansna sahip oluruz.

XAML, .Net Framework ierisinde Abstract olmayan ve varsaylan yapc(default


constructor) metoda sahip olan tm tipleri iaretlemeler (markup) ile temsil
edebilmektedir.

Bu gelimeler nedeniyle windows uygulamalarnnda Asp.Net tarz web uygulamalarna son derece
benzediini dnebiliriz. yleki, sunu katmannn grsel bileenlerinin ele alnd taraf ile kod
blm tamamen birbirlerinden ayrlabilmektedir. XAML' in en byk zellii, .Net ierisindeki
abstract olmayan varsaylan yapc metoda sahip tipleri iaret edebiliyor olmasdr. Bu durum
aadaki ekilde temsil edilmeye allmtr.

Dikkat ederseniz, .Net tipi (type) XAML tarafnda bir element olarak temsil edilirken, zellik
(property) veya olay (event) gibi yeler birer nitelik (attribute) olarak ifade edilebilmektedir. Biz
bu makalemizde sadece XAML' i kullanarak Visual Studio 2005 destei olmadan, basit bir Windows
Presentation Foundation uygulamasn nasl gelitirebileceimizi grmeye ve XAML' in arka tarafta
brakt parmak izlerini analiz etmeye alacaz.

www.bsenyurt.com Page 1202


lk olarak var olan Windows programlama modelimizi hatrlamakta fayda var. .Net Framework 3.0
ncesi gelitirdiimiz Windows uygulamalar exe uzantl Protable Executable tipinde Assembly
dosyalardr. Exe uzantl olmalar nedeni ile mutlaka bir giri noktasna (entry point) sahiptirler.
Bu giri noktasnn Main metodu olduunu hepimiz biliyoruz. Dier taraftan bir windows
uygulamas en azndan bir adet grsel form ierir. Bu form, System.Windows.Form snfndan
tremitir ve alma zamannda rneklenip ekrana kartlabilmesi iin Main metodu ierisinde
Application snfna ait static Run metodunun altrlmas gerekmektedir. Main metodunu ieren
tipte aslnda static bir snftr. Bu durumu hatrlamak ve zihinlerimizi tazelemek iin aadaki snf
diagramndan faydalanabiliriz.

Main metodumuzun ierii ise balangta aadakine benzer bir ekilde olacaktr.

static void Main()


{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new Form1());
}

Kurallar WPF ierisindede deimemitir. Ancak uygulama tarz olduka farkl bir hal almtr :)
Dilerseniz XAML kullanarak bir windows uygulamasn nasl yazabileceimizi adm adm inceleyelim.
lk rneimizde herhangibir kod dosyas kullanmayacaz. Nitekim WPF, aynen web tabanl
uygulama mimarisinde olduu gibi inline coding ve code-behind modellerini desteklemektedir.
Kurallarmz dndmzde bize formu temsil edecek bir eleman ve bu formu ekrana basacak
olan baka bir eleman gerektii ortadadr. te bu elemanlar birer XAML dosyas eklinde
oluturacaz. lk olarak formumuzu aadaki gibi hazrlayp Giris.xaml isimli bir dosya olarak
sistemimize kaydedelim.

<Window x:Class="XamlGiris.Giris" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/p


resentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" Title="Xaml
Giris" Width="200"Height="200" Loaded="XamlGiris_Loaded">
<Grid>
<ComboBox Name="cmbSehirler" Height="26" VerticalAlignment="Top"></ComboBox>
<Button Name="MerhabaDe" Width="100" Height="50" Click
="btnMerhabaDe_Clicked">Merhaba De</Button>

<x:Code>
<![CDATA[
protected void XamlGiris_Loaded(object sender,EventArgs e)
{
cmbSehirler.Items.Add("Istanbul");
cmbSehirler.Items.Add("Ankara");
cmbSehirler.Items.Add("Izmir");

www.bsenyurt.com Page 1203


}

protected void btnMerhabaDe_Clicked(object sender, RoutedEventArgs e)


{
string adim=cmbSehirler.Text;
MessageBox.Show("Merhaba "+adim);
}
]]>
</x:Code>
</Grid>
</Window>

Hereyden nce karmzda Xml trevli bir dil vardr. Bu nedenle Xml iin geerli olan kurallar XAML
iinde sz konusudur. rnein byk kk harf duyarll(case sensitive) bunlardan birisidir.
WPF asndan baktmzda ise artk pencerelerimizi Form snf ile deil Window snf ile temsil
ettiimizi syleyebiliriz. Dier taraftan alma zamannda rneklenecek olan tipin tanm Window
elementi ierisindeki x:class (x isimalan altnda) nitelii ile yaplmaktadr. Bu tanmlamada dikkat
ederseniz XamlGiris, tipin ierisinde yer ald isim alann (namespace) temsil etmektedir.

Makalemizin giri ksmndada bahsettiimiz gibi, elementlerimizin .Net tarafndaki zellik(property)


veya olaylar (events) XAML ierisinde elementlere ait nitelikler (attributes) yardmyla ele
alnmaktadr. Sz gelimi, Button nesne rneimiz iin bir Click olayn yklemek istediimizde tek
yapmamz gereken ayn Asp.Net 2.0' da olduu gibi nitelie metod adn atamak olacaktr. rnek
XAML dosyamz ekrana basldnda 200' e 200 piksel boyutlarnda bir pencere oluturulmasn
salayacaktr. Ayn zamanda bu ekran zerinde ierisinde Istanbul, Ankara, Izmir deerleri olan bir
ComboBox ve birde "Merhaba Istanbul" benzeri bir metni mesaj kutusu ile gsterebilecek bir
Button kontrol yer almaktadr. Dikkat ederseniz Button ve ComboBox tipleri burada birer element
olarak iaretlenmektedir. rneimizde inline coding tekniini kullandmz iin, kod bloklarmznn
tamamn <x:Code> isimli element ierisine alyoruz. zellikle XAML' in buradaki kod satrlarn
iaretleme dili gibi yorumlamasn engellemek iinde CDATA sekmesi ierisine alyoruz.

Bir Windows Presentation Foundation (WPF) uygulamasn sadece geerli XAML


dosyalarndan (ister inline coding ister code-behind olsun) oluturabilir ve geerli bir
winexe assembly' haline getirebiliriz.

Gelelim bu pencereyi rnekleyip ekrana bastrlmasn salayacak olan elemanmza. WPF haricinde
varsaylan olarak Program.cs ad altnda ifade edebileceimiz bu dosyay, gelenei bozmamak
adna Program.xaml olarak adlandryor ve aadaki gibi gelitiriyoruz.

<Application x:Class="XamlGiris.Program" xmlns="http://schemas.microsoft.com/winfx/2006


/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Giris.xaml">
</Application>

Grld zere Program.xaml dosyamz ok daha basittir. Giris.xaml ile karlatrldnda belkide
en nemli fark Application isimli bir elementin oluudur. Uygulamann giri noktasnda tayan bu
tipin alma zamanndaki karl ise Class niteliinde(attribute) belirtilen XamlGiris.Program
isimli snfn bir rnei olacaktr. Application elementi ierisinde yer alan StartupUri nitelii,
uygulama altrldna ekran yklenecek olan window tipini tanmlayan xaml dosyasn iaret
etmektedir. Dikkat ederseniz Application ierisinde tanmlanm herhangibir Main metodu
grlmemektedir. Bu ii stlenen kii StartupUri niteliidir. Peki ama nasl?

Yazm olduumuz XAML dosyalar tek balarna hi bir anlam ifade etmez. zellikle C# derleyicisi
XAML kodlarn anlamayaca iin derleyemez. Oysaki bu XAML kaynaklarnn ve kodlarnn bir

www.bsenyurt.com Page 1204


Winexe Assembly ierisinde ele alnmalar arttr. Bunun iin bir n ilemden geirilmeleri, birer
snf (Class) haline getirilmeleri, hatta XAML' deki bileenlerin konumlar gibi niteliklerin tutulaca
kaynaklarn (resources) binary hale getirilip ilgili assembly ierisine atlmalar gerekmektedir. te
bu noktada MSBuild.exe (Microsoft Build Engine)program devreye girer.

MSBuild.exe programn varsaylan olarak ,


D:\WINDOWS\Microsoft.NET\Framework\v2.0.50727 klasr altnda bulabilirsiniz.

Ne varki MSBuild proje dosyas tabanl alan bir sistemdir. Bu sebepten, ncelikli
olarak csproj uzantl ve xml tabanl bir proje dosyas aadaki gibi oluturulmaldr.

<Project DefaultTargets="Build"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<RootNamespace>XamlGiris</RootNamespace>
<AssemblyName>XamlGiris</AssemblyName>
<OutputType>winexe</OutputType>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="Program.xaml" />
<Page Include="Giris.xaml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

Proje dosyamzda PropertyGroup isim element ierisinde, uygulamann ana isim


alan(namespace) RootNameSpace elementi ile belirtilmektedir. Her assembly' n bir ad vardr.
Bu ad belirtmek iin proje dosyas ierisinde AssemblyName elementi
kullanlmtr. OutputType elementi, retilecek olan assembly tipini belirtmektedir ki burada
winexe ktnn Portable Executable bir windows assembly' olduunu gstermektedir.
lk ItemGroup boumu altnda, program ierisinde referans edilen temel assembly bilgilerine yer
verilmitir. kinci ItemGroup boumunda, assembly' n static program snf roln stlenen tipi
temsil eden Program.xaml dosyas ApplicationDefinition elementi ile tanmlanr. Page elementi
ise, uygulamann ierdii pencereleri tanmlayan XAML dosyalarn belirtmek iin kullanlmaktadr.
rneimizde bu dosya Giris.xaml' dir. Son olarak Import elementleri ile proje ierisindeki
kaynaklardan retilecek ktlara ait bilgiler verilir. yleki MSBuild.exe, XAML dosyalarmzdan
otomatik olarak cs uzantl kaynak dosyalar retecektir (AutoGenerated C# Source Files).
Benzer ekilde XAML dosyalarndan faydalanlarak yine otomatik olarak retilecek bir BAML
(Binary Application Markup Language) dosyasda sz konusudur.

BAML (Binary Application Markup Language) kaynak XAML dosyasnda tanmlanan nesne
hiyerarisinin ve zelliklerinin ikili (Binary) karldr. kili olmas nedeni ile insan
gzyle okunabilir deildir. Baml, alma zamannda grsel bileen ve zelliklerin
assembly ierisinden ok daha hzl bir ekilde yklenmesini salamaktadr.

www.bsenyurt.com Page 1205


Bu dosya, temel olarak XAML elementlerinin ekran yerleimleri ile ilikili bilgilerin assembly
ierisine resource olarak dahil edilebilecek ikili dzendeki karlklar olarak dnlebilir. Temel
olarak ina(build) ve derleme(compile) aamalar aadaki ekilde olduu gibi dnlebilir.

Dikkat ederseniz MSBuild.exe ile retilen dosyalar sonrasnda, C# derleyicisi srece dahil olmakta
ve otomatik olarak tretilen *.g.cs, .baml ve *.g.resources dosyalarndan faydalanarak winexe
tipinde bir Assembly' n retilmesini salamaktadr. imdi gelin MSBuild.exe aracmz kullanalm ve
nasl bir sonu elde edeceimize bakalm. Bu amala, MSBuild.exe aracn Visual Studio 2005
komut penceresinden (Command Prompt) aadaki gibi altrmamz yeterli olacaktr.

Eer kodlarda bir hata yoksa klasr yapmz aadakine benzer ekilde olacaktr.

www.bsenyurt.com Page 1206


Dikkat ederseniz bildiimiz iki adet klasr oluturulmutur. Bunlardan bin klasr ierisinde retilen
winexe assembly' vardr. obj klasr ierisinde yer alan debug alt klasrnde ise az nce
bahsettiimiz *.g.cs, .baml ve *.resources dosyalar yer almaktadr.

Exe dosyamz altrdmzda aadakine benzer bir grnt elde ederiz.

Elbetteki burada unu sylemekte fayda var. XAML ierisinde kullanabileceimiz pek ok Layout
var. Biz rneimizde Grid kullandmz iin kontrollerimiz pencere zerine buna uygun olacak
ekilde yerletirilmitir. imdilik amacmz grsel taraf kavramak olmadndan makalemize

www.bsenyurt.com Page 1207


retilen assembly' n ieriini inceleyerek devam edebiliriz. lk olarak retilen *.g.cs uzantl C#
dosyalarna bakmakta fayda var. Aada, XamlGiris.g.cs dosyasnn ksaltlm ierii yer
almaktadr.

using System;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;
using System.Windows.Media.Media3D;
using System.Windows.Media.TextFormatting;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace XamlGiris
{
public partial class Program : System.Windows.Application
{
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent()
{
#line 4 "..\..\Program.xaml"
this.StartupUri = new System.Uri("Giris.xaml", System.UriKind.Relative);

#line default
#line hidden
}
[System.STAThreadAttribute()]
[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public static void Main()
{
XamlGiris.Program app = new XamlGiris.Program();
app.InitializeComponent();
app.Run();
}
}
}

te aradmz Main metodu. Dikkat ederseniz retilen XamlGiris.g.cs dosyas ierisinde bir Main
metodu hatta InitializeComponent isimli baka bir metod daha yer
almaktadr.StartupUri zelliine Uri tipinden bir nesne rnei atandn ve Giris.xaml dosyasn
iaret edecek ekilde oluturulduuna dikkat edelim. Bylece programn giri noktasnn C#
derleyicisi tarafndan anlalabilecek hali retilmi olmaktadr. Gelelim, Giris.g.cs dosyasnn
ieriine.

using System;
// Burada isim alanlarna ait tanmalamalar vardr.

www.bsenyurt.com Page 1208


namespace XamlGiris
{
public partial class Giris : System.Windows.Window,
System.Windows.Markup.IComponentConnector
{
internal System.Windows.Controls.ComboBox cmbSehirler;
internal System.Windows.Controls.Button MerhabaDe;
private bool _contentLoaded;

protected void XamlGiris_Loaded(object sender,EventArgs e)


{
cmbSehirler.Items.Add("Istanbul");
cmbSehirler.Items.Add("Ankara");
cmbSehirler.Items.Add("Izmir");
}

protected void btnMerhabaDe_Clicked(object sender, RoutedEventArgs e)


{
string adim=cmbSehirler.Text;
MessageBox.Show("Merhaba "+adim);
}

[System.Diagnostics.DebuggerNonUserCodeAttribute()]
public void InitializeComponent()
{
if (_contentLoaded)
{
return;
}
_contentLoaded = true;
System.Uri resourceLocater = new System.Uri("/XamlGiris;component/giris.xaml",
System.UriKind.Relative);
System.Windows.Application.LoadComponent(this, resourceLocater);
}

[System.Diagnostics.DebuggerNonUserCodeAttribute()]
[System.ComponentModel.EditorBrowsableAttribute(System.ComponentModel.EditorBrowsabl
eState.Never)]
[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Design",
"CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
void System.Windows.Markup.IComponentConnector.Connect(int connectionId, object
target)
{
switch (connectionId)
{
case 1:
((XamlGiris.Giris)(target)).Loaded += new
System.Windows.RoutedEventHandler(this.XamlGiris_Loaded);
return;
case 2:
this.cmbSehirler = ((System.Windows.Controls.ComboBox)(target));
return;
case 3:
this.MerhabaDe = ((System.Windows.Controls.Button)(target));
this.MerhabaDe.Click += new
System.Windows.RoutedEventHandler(this.btnMerhabaDe_Clicked);

www.bsenyurt.com Page 1209


return;
}
this._contentLoaded = true;
}
}
}

lk bata bildiimiz windows tabanl uygulama modelinden ok farkl bir snf ile kar karya
olduumuzu ifade edebiliriz. Ancak biraz dikkatli baktmzda, snfn XAML kaynak dosyas
ierisinde yer alan grsel bileenleri tanmladn, bunlara ait olay metodlarn uygun temsilciler
(delegate) yardmyla yklediini, olaylara ilikin kod bilgilerini ierdiini grebiliriz. retilen bu cs
uzantl dosyalar, artk C# derleyicisi (csc.exe) tarafndan yorumlanabilirler. Zaten MSBuild.exe' de
gerekli retim ilemlerinden sonra sreci csc.exe' ye devredecektir. retilen Assembly' n ieriini
herhangibir .Net Decompiler arac ile aacak olursak Resources olarak giris.baml isimli bir
dosyann atldn grrz. Dikkatinizi ekerim XAML deil BAML diyoruz.

u ana kadar gelitirdiimiz WPF rneinde, kod paralarn XAML dkmanlar ierisine Inline-
Coding tekniine gre aldk. Microsoft' un ve profesyonel yazlm mimarlarnn nerisi, kod tarafn
XAML tarafndan ayrmak ynndedir. Bu zaten web tarafndanda bildiimiz en optimum yoldur. Bu
neriyi dikkate alp rneimizi code-behindmodeline gre tasarlamak istersek, XAML dosyalar
ierisinde yer alan kodlar xaml.cs uzantl dosyalar ierisine koymalyz. Bununla birlikte proje
dosyas ierisinde de Compile isimli elementleri kullanp code-behind dosyalarnn ne olacan
bildirmeliyiz. Buna gre Giris.xaml ve Program.Xaml ierisindeki tm kod paralarn (CDATA
sekmesi ierisinde yer alanlar) ayr cs dosyalar ierisine aadaki gibi almamz yeterli olacaktr.

Giris.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;

namespace XamlGiris
{
public partial class Giris: Window
{
public Giris()
{
InitializeComponent();
}

www.bsenyurt.com Page 1210


protected void XamlGiris_Loaded(object sender,EventArgs e)
{
cmbSehirler.Items.Add("Istanbul");
cmbSehirler.Items.Add("Ankara");
cmbSehirler.Items.Add("Izmir");
}

protected void btnMerhabaDe_Clicked(object sender, RoutedEventArgs e)


{
string adim=cmbSehirler.Text;
MessageBox.Show("Merhaba "+adim);
}
}
}

Dikkat etmemiz gereken nokta, snfmzn Window snfndan tremesi gerektiidir. Bununla
birlikte pencere zerindeki bileenlerin yklenebilmesi iin yapc metod (constructor)
ierisinde InitializeComponent fonksiyonunun arlmas gerekir.

Program.xaml.cs

using System;
using System.Windows;
using System.Windows.Controls;

namespace XamlGiris
{
public partial class Program: Application
{
}
}

Program isimli snfmz iinde nemli olan nokta Application snfndan tremesi gerektiidir. Bu
ilemlerin ardnda tek yapmamz gereken proje dosyasn aadaki gibi gncellemektir.

<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">


<PropertyGroup>
<RootNamespace>XamlGiris</RootNamespace>
<AssemblyName>XamlGiris</AssemblyName>
<OutputType>winexe</OutputType>
</PropertyGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="Program.xaml" />
<Compile Include = "Giris.xaml.cs" />
<Compile Include = "Program.xaml.cs" />
<Page Include="Giris.xaml" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />

www.bsenyurt.com Page 1211


<Import Project="$(MSBuildBinPath)\Microsoft.WinFX.targets" />
</Project>

Dikkat ederseniz Compile elementleri ierisinde code-behind dosyalar tek tek belirtilmektedir. Bu
sayede MSBuild.exe arac, ina ilemi srasnda hangi XAML dosyas ile hangi cs dosyasn
arptracan anlayabilecektir. Artk MSBuild aracmz kullanabilir ve winexe assembly' nn
retilmesini salayabiliriz. Uygulamamz bir nceki rneimizde olduu gibi ayn ekilde
alacaktr.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde, XAML' in Windows Presentation
Foundation (WPF) ierisindeki yerini anlayabilmek iin bir giri yapmaya altk. XAML kullanarak
bir WPF Assembly' nn Visual Studio' ya bavurmadan nasl gelitirilebileciini, bu gelitirme
ileminin aamalarn ve aslnda arka tarafta meydana gelen deiiklikleri grmeyi amaladk. Ek
olarak, Xaml ve Baml kavramlarnn ne anlama geldiini anlamaya altk. Her zaman olduu gibi
DeCompiler aralar burada iimize olduka yarad. lerleyen makalelerimizde Windows
Presentation Foundation (WPF) uygulamalarna daha derinlemesine bakmaya alacaz. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Profesyonelce Master Pages ( 13.03.2007 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Asp.Net 2.0 ile birlikte gelen en nemli yeniliklerden biriside Master Page kavramdr. Master Page
kavramn ilk rendiimde aklmda oluan tanmlama yleydi; "bir sitedeki sayfalarnn
tamamnn yada bir ksmnn ayn ablon zerinde oturmasn salamak istiyorsak Master Page'
lerden faydalanabiliriz". Oysaki Master Page kullanm ile elde edilen avantajlar sadece grsel
adan gelen bu kolaylk ile snrl deildir. Sonu itibariye her Master Page ayn zamanda arka
planda bir rnek olarak oluturulan bir snf tanmlamasdr. Bu nedenle Master Page uyarlanan
ierik sayfalarnn (Content Page) ortaklaa kullanabilecei fonksiyonellikleri dahi barndrabilir.
Buda tam anlamyla kaltm(inheritance) ile yapabildiklerimizin bir yansmasdr. te bu
makalemizde Master Page kavramnn derinlerine gidip dier avantajlarn ve zellikle dikkat
etmemiz gereken noktalarn neler olabileceini incelemeye alacaz. Temel olarak ele alacamz
konular aada maddeler halinde sralanmtr.

Master Page uygulanmam bir web sayfasna sonradan Master Page uygulamaya
almak.
erik sayfalarndan(Content Page), Master Page yelerine erimek.
(zellikler(Properties) yadmyla erimek, kontrolleri
bulmak(FindControl), MasterType direktifinden yararlanmak)
Ortak fonksiyonellikleri Master Page altnda toplamak.
erik sayfalarndan(Content Page) Master Page' leri dinamik olarak deitirmek.
(Nested) Master Page' ler gelitirmek ve kullanmak.

Bahsetmi olduumuz maddeleri rnek bir senaryo zerinden incelemeye alacaz. Bu nedenle
web uygulamamzda aadaki gibi bir Master Page tasarlam olduumuzu dnelim.

www.bsenyurt.com Page 1212


<%@ Master Language="C#" AutoEventWireup="true"
CodeFile="AzonCityMaster.master.cs" Inherits="AzonCityMaster" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<table border="1" cellpadding="3" cellspacing="1" width="640px">
<tr>
<td colspan="2"><img src="images/csharpnedir.gif" /></td>
</tr>
<tr>
<td valign="top" style="width: 150px"><asp:TreeView ID="TreeView1"
runat="server" DataSourceID="SiteMapDataSource1"></asp:TreeView></td>
<td style="text-align: right"><asp:ContentPlaceHolder ID="ContentPlaceHolder1"
runat="server"></asp:ContentPlaceHolder></td>
</tr>
<tr>
<td colspan="2" style="text-align: right"><span style="font-size: 10pt; font-family:
Verdana; text-decoration: underline">cityadmin@azoncity.com</span>
<img src="images/google_coop.gif" /></td>
</tr>
</table>
</div>
<asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server" />
</form>

www.bsenyurt.com Page 1213


</body>
</html>

Gelitirdiimiz Master Page ierisinde sitedeki dier sayfalara kolay gei yapmamz salayacak
ekilde bir TreeView kontrol ve buna bal olacak ekilde tasarlanm
birSiteMapDataSource bileeni de vardr. Dier taraftan sadece gze ho gelmesi asndan bir
ka resim bileeni dahil edilmi ve tek bir ContentPlaceHolder kullanlmtr.

Master Page' lerin baz nemli zellikleri vardr. Makalemizin konusu olan maddelere gemeden
nce bunlar hatrlamakta fayda olaca kansndaym. Hereyden nce MasterPage' ler
aslnda UserControl snfndan tremitir. Bunu grebilmek iin Visual Studio 2005 ortamnda,
MasterPage kelimesi zerindeyken sa tklayp Go To Definitiondiyebiliriz. Bu durumda,
MasterPage snfnn metadatasn grebiliriz. Dikkat ederseniz ak bir ekilde UserControl tipinden
tredii ortadadr.

Bir dier nemli nokta ise, Master Page' lerin uyguland ierik sayfalarnn (Content Page)
herhangibir ekilde html, head, body, vb... taklar ile birlikte kesinlikle form taksn
iermediidir. te bu ayrt edici zellik makalemizin ilk maddesi iin nemlidir.

1. Master Page uygulanmam bir web sayfasna sonradan Master Page uygulamaya
almak.

ou zaman projelerimizde sonradan Master Page kullanmaya karar verdiimiz durumlar olabilir.
(Yada buna neden olacak baka vakkalar olabilir) Var olan bir Master Page' den , ierik sayfalar
(Content Page) oluturmamz kolaydr. Hatta Visual Studio 2005 buna tam destek vermektedir.
Ancak var olan bir web sayfasna, herhangibir Master Page' i sonradan uygulamak istediimizde
yapmamz gerekenler temel olarak u ekilde zetlenebilir.

erik sayfasnn(Content Page) ierisinde Html, Body, Head, Title vb... ile form
elementlerinin olmamas gerekir.
Sayfann Page direktifi ierisinde Master Page tanmlamas MasterPageFile isimli nitelik
yardmyla yaplmaldr.

www.bsenyurt.com Page 1214


Master Page ierisinde yer alan ContentPlaceHolder' larn, ierik sayfasnda
birer Content bileeni olarak ele alnmas gerekmektedir.

Konuyu daha iyi anlayabilmek iin bir rnek zerinden gidelim ve uygulamamzda kullandmz
sayfalardan herhangibirini ele alalm. rnek olarak aadaki ekran grntsne sahip olan
bloglar.aspx sayfasn kullanabiliriz.

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


Inherits="Bloglar" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<span style="font-size: 10pt; font-family: Verdana"><strong>Aradnz Blog sahibinin
adn giriniz&nbsp;</strong><br /></span>
<asp:TextBox ID="TextBox1" runat="server" Width="208px"></asp:TextBox><span
style="font-size: 10pt;font-family: Verdana"> </span>
<asp:Button ID="Button1" runat="server" Text="Ara" Width="65px" /><span
style="font-size: 10pt;font-family: Verdana"><br /></span>
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="http://www.csharpnedir.com">Yardm</asp:HyperLink><br />
<span style="font-size: 10pt; font-family: Verdana"><strong>Sonular</strong><br
/></span>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True"
Width="214px"></asp:DropDownList>
</div>
</form>
</body>
</html>

imdi gelin adm adm bu sayfaya AzonCityMaster isimli Master Page' imizi uygulayalm. lk
olarak Page direktifi ierisinde MasterPageFile nitelii yardmyla uygulamak istediimiz Master
Page' in fiziki dosyasn belirlemeliyiz. Eer Visual Studio 2005 kullanyorsanz intelli-sense zellii
bize yardmc olacaktr. Aksi takdirde ~ harfinide gz nne alaraktan aadaki kod parasnda
grld gibi bir yol tanmlamas yaplmaldr.

www.bsenyurt.com Page 1215


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Bloglar.aspx.cs"
Inherits="Bloglar" MasterPageFile="~/AzonCityMaster.master" %>

Bir sonraki admmz form elementleri ierisinde yer alan bileenlerimizi bir Content elementi
ierisine almak olacaktr. Buradan u sonucada varabiliriz. erik sayfalar bileen olarak sadece
Content elementlerini iermektedir. erik sayfalar hi bir ekilde form elementi
iermeyeceklerinden (Html, Body vb ksmlarda buna dahildir) Bloglar.aspx isimli sayfamza, Master
Page' deki hangi ContentPlaceHolder bileenini kullanacaksak ona uygun bir Content bileenini
aadaki gibi eklememiz gerekir.

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


Inherits="Bloglar" MasterPageFile="~/AzonCityMaster.master" %>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" ID="Content1" runat="server">

</asp:Content>

Son olarak tek yapmamz gereken Content elementi ierisine, bloglar.aspx sayfasnn bir nceki
halinde yer alan Asp.Net bileenlerini dahil etmek olacaktr. Burada dikkat edilmesi gereken nokta,
Asp.Net bileenlerine ait elementlerin, mutlaka ve mutlaka Content elementinin taklar (tags)
ierisinde olmas gerektiidir. Biz rneklerimizde tek bir ContentPlaceHolder kullandmzdan,
ierik sayfasndaki Content bileenide tektir. Dolaysyla, Master Page ierisindeki
ContentPlaceHolder' larn saysna gre ierik sayfalarnda uygulanmas gereken Content
bileenlerinin says artabilir.

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


Inherits="Bloglar" MasterPageFile="~/AzonCityMaster.master" %>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" ID="Content1" runat="server">
<span style="font-size: 10pt; font-family: Verdana"><strong>Aradnz Blog sahibinin adn
giriniz&nbsp;</strong><br /></span>
<asp:TextBox ID="TextBox1" runat="server" Width="208px"></asp:TextBox><span
style="font-size: 10pt;font-family: Verdana"> </span>
<asp:Button ID="Button1" runat="server" Text="Ara" Width="65px" /><span style="font-
size: 10pt;font-family: Verdana"><br /></span>
<asp:HyperLink ID="HyperLink1" runat="server"
NavigateUrl="http://www.csharpnedir.com">Yardm</asp:HyperLink><br />
<span style="font-size: 10pt; font-family: Verdana"><strong>Sonular</strong><br
/></span>
<asp:DropDownList ID="DropDownList1" runat="server" AutoPostBack="True"
Width="214px"></asp:DropDownList>
</asp:Content>

Bu ilemlerin ardndan Bloglar.aspx isimli sayfamz, Master Page' i uygulayan bir ierik sayfas
haline gelecektir.

www.bsenyurt.com Page 1216


2. erik sayfalarndan(Content Page), Master Page' in yelerine erimek.

Master Page' ler, kendisinden retilen ierik sayfalar iin ortaklaa kullanlabilecek yeler (rnein
metodlar) ierebilirler. zellikle tm sayfalarda sz konusu olabilecek veritaban ilemlerine ait
hazrlklarn tek bir merkezden yaplabilmesini salamak bu ortak fonksiyonellikler iin bir rnek
olarak dnlebilir. Dier taraftan ierik sayfalarndaki srelerin ileyiine gre Master Page
zerindeki kontrollerin davranlarn deitirmek isteyebiliriz. Tm bunlar
aslnda kaltmn(inheritance) bir etkisi olarak karmza kmaktadr. yleki Asp.Net 1.1 ile
gelitirme yapanlarn, Master Page tarz mimariler iin gelitirdikleri zmler kaltm(inheritance)
ilkelerine dayanlarak gerekletirilmitir. Ne varki Asp.Net 2.0 ile birlikte gelen Master Page
kavram, sadece grsel adan deil kod tarafndanda kaltm etkin bir ekilde kullanabilme imkan
salamaktadr. Dolaysyla baz durumlarda ierik sayfalarndan Master Page' lerin ele alnmas
gerekebilir. Bu durumlar bir ka basit rnek ile incelemekte fayda vardr. lk olarak, ierik
sayfalarnda iken, Master Page' in balk bilgisini (Title) ve hatta MasterPage ile birlikte
retilen metadata bilgilerini deitirmek istediimizi dnelim. Bu amala yine bloglar.aspx
sayfasn gz nne alabiliriz. Sayfamzn Load olay tetiklendiinde aadaki ilemleri
gerekletirdiimizi dnelim.

protected void Page_Load(object sender, EventArgs e)


{
this.Master.Page.Title = "Azon ehri Sakinlerinin Bloglar";
HtmlMeta metadatas=new HtmlMeta();
metadatas.Name="Keywords";
metadatas.Content="Blog, Azon, City, Azon City, Yemek, Gurme, Kermes";
this.Master.Page.Header.Controls.Add(metadatas);
this.Master.Page.SmartNavigation = true;
}

www.bsenyurt.com Page 1217


erik sayfasndan eer Master Page referansna gei yapmak istiyorsak, Master zelliinden
faydalanabiliriz. rnek kodumuzda, Master Page yardmyla retilen sayfann title, metadata,
smart navigation gibi zelliklerini deitiriyoruz. Buna gre Title zelliini deitirmek
iin this.Master.Page.Title sz diziminden yararlanlmtr. Metadata bilgisini eklemek iinse
ncelikli olarak HtmlMeta tipinden bir nesne rneklenmitir. Bu nesnenin iki nemli zellii
vardr. Name ve Content. Bu iki zellie atadmz deerlere gre, sayfamzn arama sitelerinde
metadata ierisinde belirttiimiz konu balklar altnda kmas muhtemeldir. retilen metadata
elementinin Master Page' e ait Html ktsna yazlabilmesi
iinde Master.Page.Header.Controls sz diziminden yararlanlmtr. Bir baka
deyile Head elementi ierisine girilerek Controls koleksiyonuna, oluturulan Metadata bilgileri
eklenmitir. Son olarak retilen sayfann SmartNavigation zellii ture yaplmtr. Bloglar.aspx
sayfamz herhangibir tarayc penceresinde atmzda aadaki ekran grntsn elde ederiz.

Sayfamzn HTML ktsna baktmzda ise yapm olduumuz deiikliklerin aadaki gibi
yansdn grebiliriz. Elbetteki bunu rnek olmas asndan sadece tek bir sayfada ele aldk.

<html xmlns="http://www.w3.org/1999/xhtml" >


<head>
<title> Azon ehri Sakinlerinin Bloglar</title>
<meta name="Keywords" content="Blog, Azon, City, Azon City, Yemek, Gurme,
Kermes" />
<style type="text/css">.ctl00_TreeView1_0 { text-decoration:none; }</style>
</head>
<body>
<IFRAME id="__hifSmartNav" name="__hifSmartNav" style="display:none"
src="/DerinlemesineMasterPages/WebResource.axd?d=jcUk5uOrm4IZldJ56Y8MhA2&amp;t=63296
4516087343750"></IFRAME>
<form name="aspnetForm" method="post" action="Bloglar.aspx"
id="aspnetForm" __smartNavEnabled="true">
<div>
<input type="hidden" name="ctl00_TreeView1_ExpandState" id="ctl00_TreeView1_ExpandState"
value="ennn" />
.
.
.

Bir dier senaryo ise, ierik sayfalarndan Master Page ierisindeki her hangibir kontroln
davrann deitirmektir. rnein Master Page zerinde yer alan bir Label kontrol ierisinde,
girilen ierik sayfasna ait bir takm zel bilgilerin yazmas istenebilir. Kullancnn ad bu kontrolde
gsterilebilir yada yetkisine gre renklendirmeler yaplabilir. Senaryolar elbette oaltlabilir.
Odaklanlmas gereken nokta bu kontrole ierik sayfalar zerinden nasl eriilebileceidir. Bu
amala bir ka yntem ele alnabilir. rnein FindControlmetodu yardmyla Label kontrol

www.bsenyurt.com Page 1218


bulunabilir yada Master Page ierisine yazlacak bir zellikten (Property) faydalanlabilinir. Hatta
kullanm kolayl salamas bakmndanMasterType direktifinden de yararlanlabilir.

imdi bunlar teker teker ele alalm. Grsel tabanl uygulamalarda zellikle tayc (Container) rol
stlenen bileenlerin ounun FindControl metodu vardr. Bu metod sayesinde, ID veya Name gibi
zelliklerine gre ilgili tayc ierisinden herhangibir kontrol bulunabilir. Bunun sonrasnda tek
yaplmas gereken kontroln ilgili zelliklerinin deitirilmesidir. Konuyu daha iyi anlayabilmek iin
Master Page ierisine bir Label kontrol atlm ve lblBilgi olarak isimlendirilmitir. Buna gre
Bloglar.aspx sayfasndan bu Label kontrolne eriip ieriini deitirmek iin aadaki gibi bir yol
izlenebilir. (Kod paras bloglar.aspx sayfasnn Page_Load olay metodu ierisinde ele alnmtr.)

Label lblMaster = (Label)this.Master.FindControl("lblBilgi");


lblMaster.Text = "Bloglar sayfasndan geldim";
lblMaster.ForeColor = System.Drawing.Color.Red;
lblMaster.Font.Bold = true;
lblMaster.Font.Name = "Verdana";
lblMaster.Font.Size = 10;

Dikkat ederseniz Master Page ierisindeki lblBilgi kontroln bulmak iin FindControl metodundan
faydalanyoruz. FindControl metodu parametre olarak aranan bileenin ID zelliinin deerini
almaktadr. Elbette FindControl metodunun geri dn deeri Control tipindendir. Bu sebeptende
geri dnen kontrol referansnn deerinin Label olarak ele alnabilmesi iin bilinli bir ekilde
dntrme(explicitly cast) ilemi uygulanmtr. Bylece lblBilgi isimli Label kontrolne ait
alma zaman referansn bloglar.aspx sayfas ierisinde ele alabilir ve zelliklerini deitirebiliriz.
Bunun ardndan aadaki ekran grntsndeki sonucu elde ederiz.

Master Page ierisindeki yelere ierik sayfalarndan eriebilmek iin zelliklerdende (properties)
faydalanabiliriz. Bu durumda, FindControl metodunda olduu gibi cast ilemleri yapmamzda gerek
kalmaz. rnein amacmz sadece Master Page' deki lblBilgi bileeninin metin ieriini
deitirmekse aadaki gibi bir zellik sz konusu olabilir. Elbetteki ihtiyaca gre yazlan zelliin
yanlz okunabilir(readonly) olmas farkl bir tipte deer dndrmesi gerekebilir. Bunlar tamamen
projedeki ihtiyalar dorultusunda belirlenebilecek noktalardr.

public partial class AzonCityMaster : System.Web.UI.MasterPage


{
public string Bilgi
{
get { return lblBilgi.Text; }
set {
if (!String.IsNullOrEmpty(value))
lblBilgi.Text = value;
else
lblBilgi.Text = "Bilinmeyen Bilgi";

www.bsenyurt.com Page 1219


}
}
}

Artk tek yapmamz gereken, ierik sayfasnda, Master Page' in referansn yakalamak ve bunun
zerinden Bilgi isimli zellie eriip kullanmaktr. Bu amala yine bloglar.aspx sayfamzda aadaki
kod parasn kullanabiliriz.

AzonCityMaster azonMstr = (AzonCityMaster)this.Master;


azonMstr.Bilgi = "Bloglar sayfasndan geldim";

Dikkat ederseniz ierik sayfasnn uygulad Master Page referansn elde etmek iin bilinli bir
ekilde(explicitly) dnm ilemi yaplmtr. Eer bu dntrme ilemini yapmassak, Bilgi
isimli zellie eriemeyiz. Sonu itibariyle yapm olduumuz tr dnm sayesinde, Master Page
ierisinde tanmlanm olan Bilgi isimli zellie (property) eriilebilmi ve deeri aadaki ekran
grntsnde olduu gibi deitirilebilmitir.

Master Page' e erimenin bir baka yoluda, MasterType direktifini kullanmaktr. Bu direktif
sayesinde, Master zellii zerinden hi bir tip dnm ilemi yapmaya gerek kalmadan Master
Page referansna eriilebilir. Bunun iin ncelikli olarak, ierik sayfasnda aadaki direktifi
tanmlamamz gerekmektedir.

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


Inherits="Bloglar" MasterPageFile="~/AzonCityMaster.master" %>
<%@ MasterType VirtualPath="~/AzonCityMaster.master" %>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" ID="Content1" runat="server">
.
.
.

Bu bilgilendirmenin ardndan artk this.Master zellii ile dorudan AzonCityMaster referansna


eriebiliriz.

www.bsenyurt.com Page 1220


Dikkat ederseniz, MasterType direktifi ierisinde VirtualPath tanmlamas ile hangi MasterPage' e
ait referansn kullanlaca belirtilmektedir. Bylece ierik sayfasnn Master zelliinin tayaca
referansta belirlenmi olur.

3. Ortak fonksiyonellikleri Master Page altnda toplamak.

Master Page' ler, alma zamannda birletirilecekleri ierik sayfalar adna ortak fonksiyonellikleri
tutmak iinde ok ideal bir ortam hazrlar. Sz gelimi, pek ok web uygulamasnda sklkla
bavurduumuz veri ilemleri bu fonksiyonelliklere rnek olarak verilebilir. Bir baka deyile her
sayfa iin sorgu hazrlama gibi ilemlerin tamamn Master Page ierisinde yer alan bir
fonksiyonellie ykabiliriz. Bylece hem kod optimizasyonunu hemde bakm kolayln salam
oluruz. Yine rnek senaryomuzda yer alan bloglar.aspx sayfasn gz nne alarak devam edelim.
Bu sefer veri girii iin ok basit olarak bir ka kontrol bloglar.aspx sayfasna ilave edilmitir.

Kullanclar yeni bir blog girii yapmak isteyebilir. Bu girie ait kontrollerin i mant, veri girii iin
gerekli sorgunun hazrlanmas ve ilgili Ado.Net ilevselliklerinin altrlmas gibi ilemler, Master
Page ierisinde aadaki gibi toplanabilir. Burada ilerin biraz daha kolaylamas asndan tablo
adna gre sorgu oluturulabilmesi iin Tablolar isimli bir enum sabiti dnlmtr.

public bool Insert(Tablolar tablo,params object[] parametreler)


{
bool eklendi = false;

www.bsenyurt.com Page 1221


switch (tablo)
{
case Tablolar.CitizenBlogs:
// Burada CitizenBlogs tablosuna veri ekleme ilemi yaplr.
return true;
break;
case Tablolar.Citizen:
break;
case Tablolar.Favorites:
break;
}
return eklendi;
}

Bizim iin nemli olan nokta fonksiyonelliimize ierik sayfasndan (Content Page) eriebilmektir.
Hatrlayacanz gibi bir nceki maddemizde MasterType direktifini kullanmtk. Bu nedenle Insert
isimli metoda, bloglar.aspx isimli sayfamzdan aadaki kod parasnda olduu gibi eriebiliriz.

protected void btnEkle_Click(object sender, EventArgs e)


{
this.Master.Insert(Tablolar.CitizenBlogs, txtBlogAdi.Text, txtBlogAdresi.Text);
}

4. erik sayfalarndan(Content Page) Master Page' leri dinamik olarak deitirmek.

Baz durumlarda senaryo gerei, ierik sayfalarnn uygulayaca Master Page' i alma zamannda
deitirmemiz gerekebilir. rnein ou sayfada yer alan print grnmn alma ilemi gz nne
alnabilir. Bu tip bir durumda, Print sayfasnn ieriinin farkl olmas nedeni ile, ayr bir Master
Page' in alma zamannda sz konusu ierik sayfas iin uygulanmas gerekir. Bir baka senaryo
zellikle farkl kltrlere hizmet verecek ierik sayfalarnda sz konusu olabilir. Kullancnn setii
lkeye gre ierik sayfasnn farkl bir Master Page uygulamas istenebilir. Hatta, ierik sayfasndaki
kullancnn yetkisine grede farkl Master Page' lerin uygulatlmas gerekebilir. Tm bu durumlar
temel olarak alma zamannda Master Page' in deitirilebilmesi halinde gerekleebilecek rnek
senaryolardr. Bir ierik sayfasnn alma zamannda uygulad Master Page' i deitirmek iin tek
yaplmas gereken, sayfann MasterPageFile zelliine uygun bir deer atamaktr.

MasterPageFile zellii sadece ierik sayfasnn PreInit olay metodu ierisinde


deitirilebilir. Baka bir yerden deitirme yapmak istediimizde (rnein bir dmenin
Click olay metodu ierisinden), alma zamannda aadaki hata mesajn alrz.

rneimizde aadaki ekran grntsne sahip AzonCitySummerMaster.master isimli ikinci bir


Master Page olduunu dnelim.

www.bsenyurt.com Page 1222


Amacmz bloglar.aspx sayfasnda yer alan dmeler yardmyla Master Page' ler arasnda gei
yapmaktr. Bu dmelerde tek yapacamz bloglar.aspx sayfasna doru ynlendirme yapmak
ve QueryString yardmylada hangi Master Page' e geileceine dair bir anahtar-deer(key-
value) ifti gndermektir.(rnei gelitirirken, bloglar.aspx sayfasna
eklediimiz MasterType direktifini kaldrmak gerekebilir. Nitekim, iki farkl tipten Master Page
olaca iin, kod ierisinde this.Master sz diziminin olduu satrlarda hatalar oluacaktr.)

protected void btnYazGeldi_Click(object sender, EventArgs e)


{
Response.Redirect("~/bloglar.aspx?Yaz=Evet");
}
protected void btnKis_Click(object sender, EventArgs e)
{
Response.Redirect("~/bloglar.aspx?Yaz=Hayir");
}

Az ncede bahsettiimiz gibi, MasterPageFile zelliini sadece PreInit olay metodunda


deitirebiliriz. Dolaysyla tek yapmamz gereken bu olay metodu ierisine aadaki kod
pararlarn eklemek olacaktr.

protected void Page_PreInit(object sender, EventArgs e)


{
if(Request.QueryString["Yaz"]!=null)
{

www.bsenyurt.com Page 1223


string yazmi = Request.QueryString["Yaz"].ToString();
if(yazmi=="Evet")
this.MasterPageFile = "~/AzonCitySummerMaster.master";
else if(yazmi=="Hayir")
this.MasterPageFile = "~/AzonCityMaster.master";
}
}

Uygulamamz altrdmzda aadaki Flash animasyonunda yer alan sonular elde


ederiz. (Flash animasyonunu izleyebilmek iin Flash Player yklemeniz gerekebilir)

5. (Nested) Master Page' ler gelitirmek ve kullanmak.

Baz durumlarda, i master page' ler gelitirmemiz gerekebilir. rnein bir irketin ana Master
Page' inin haricinde departmanlara gre farkl ekillerde uygulanabilecek i Master Page' lerde sz
konusu olabilir. Burada nemli olan, i Master Page' lerin ana Master Page ierisinde yer almasdr.
Teorik olarak her i Master Page, stndeki Master Page' de yer alanContentPlaceHolder' lar
uygulayacak ekilde tasarlanr. Dolaysyla i Master Page' lerde, ierik sayfalar gibi html, head
veya form elementlerini iermezler.

Master Page' lerde, ierik sayfalarnda olduu gibi html, body, form vb elementleri
iermezler. Sadece Content elementlerini ierirler.

Bunun yannda Master direktifi ierisinde mutlaka MasterPageFile nitelii ile st Master Page' in
ne olaca bildirilmelidir. Aadaki ekilde i Master Page' ler ve ierik sayfalarnn genel yaps
ematize edilmeye allmtr.

www.bsenyurt.com Page 1224


Gelin kendi rneimizde bir i Master Page kullanmaya alalm. Sz gelimi, AzonCityMaster isimli
Master Page ierisinde AzonCountyMasterPage isimli bir i Master Page uygulayabiliriz. Tek
yapmamz gereken projemize AzonCountyMasterPage isimli yeni bir Master Page eklemek ve
ieriini aadaki gibi dzenlemek olacaktr.

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


CodeFile="AzonCountyMasterPage.master.cs"
Inherits="AzonCountyMasterPage" MasterPageFile="~/AzonCityMaster.master" %>
<asp:Content ContentPlaceHolderID="ContentPlaceHolder1" ID="SubContent1"
runat="server">
<table>
<tr>
<td><b><h2>le Sayfas</h2></b></td>
</tr>
<tr>
<td><asp:ContentPlaceHolder ID="CountyPlaceHolder"
runat="server"></asp:ContentPlaceHolder></td>
</tr>
</table>
</asp:Content>

Dikkat ederseniz Master direktifi ierisinde MasterPageFile niteliine, AzonCityMaster.master


sayfas atanmtr. Bununla birlikte i Master Page sanki bir ierik sayfasym gibiContent isimli bir
element iermektedir. Bu elementin asl yapt, sz konusu i Master Page' in, st Master Page
ierisindeki hangi ContentPlaceHolder ierisine yerletirileceinin belirtilmesidir. master page' i
uygulamak isteyen ierik sayfalarnn bamsz olarak deitirebilecei bir blge olmas asndan,
rnek ContentPlaceHolder elementi de dahil edilmitir. Bu durumda, AzonCountyMasterPage

www.bsenyurt.com Page 1225


sayfasn uygulayan bir ierik sayfas (Content Page) sadece, CountyPlaceHolder isimli
ContentPlaceHolder ieriini deitirebilecektir.

Ne yazk ki i Master Page' lerin uygulanmas halinde Visual Studio 2005 zerinde hem i
Master Page' lerde, hemde bunlar uygulayan ierik sayfalarnda (Content Page),tasarm
modu (Design Mode) kaybedilmektedir.

Bir baka deyile, AzonCountMaster yada bunu uygulayan bir ierik sayfasnda Design tarafna
gemek istersek aadaki hata mesajn alrz.

Gelelim ierik sayfasna. erik sayfamz normal olarak AzonCountyMasterPage isimli i Master
Page' i uygulayacaktr. Buna gre rnek olmas asndan aadaki gibi bir tasarm dnlebilir.

<%@ Page
Language="C#" MasterPageFile="~/AzonCountyMasterPage.master" AutoEventWireup="tru
e" CodeFile="IlceSayfasi.aspx.cs" Inherits="IlceSayfasi" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="CountyPlaceHolder" Runat="Server">
<asp:TextBox ID="txtIlceAdi" runat="server"></asp:TextBox>
<asp:Button ID="btnBul" runat="server" Text="Bul" />
</asp:Content>

Sayfamz tasarm modunda (Design Mode) dzenleyemeyeceimizi daha nceden belirtmitik. Bu


nedenle gelitirme safhasndayken tam olarak tasarma hakim olamayz. Bu olduka byk bir
dezavantajdr. Ne varki alma zamannda bir sorun olmadn grebiliriz.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde, Master Page kavramn daha detayl
bir ekilde renmeye altk. Master Page' lerin sadece grsel bir yenilik olmadn, kod

www.bsenyurt.com Page 1226


tarafndada iimizi kolaylatracak, kod optimizasyonu ve bakmn etkileyecek zelliklere sahip
olduunu grdk. Master Page' lerin asl yararn grmek asndan, Master Page olmadan bilinen
nesne ynelimli programlama kurallarndan faydalanarak ayn ilemler yaplmaya allabilir. Bu
durumda Master Page' lerin ilemlerimizi gerektenden kolaylatrdn daha iyi anlayabiliriz. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

.Net Tarafnda Xml ile Oynamak-2 ( 08.03.2007 )


- Xml
Deerli Okurlarm Merhabalar,

Yllar nce odamdaki bilgisayarmda arkadalarmn telefon ve doum gn bilgilerini C tabanl bir
programda ktk dosyasna kaydetmeye almtm. O gnlerde sadece bulunduum oda
ierisindeki alanla snrlyken, bir sre sonra internet ortamna tanvermitik. Dolaysyla artk
ktk dosyasn baka ortamlara aktarabilme imkan domutu. Elbetteki bu tama iinin bir
standart dahilinde olmas nemli idi. Sonuta gnmzde bu tip veri tama standartlar iin Xml
kullanr hale geldik. Xml elbette beraberinde pek ok teknolojiyide getirdi. XPath, XQuery, Xslt
bunlardan sadece bazlardr. Dolaysyla bu popler veri standart pek ok programlama dili
tarafndan desteklenir hale gelmitir. Microsoft .Net Framework platformunda buna destek verecek
tipler yer almaktadr. Bunlardan biriside bir nceki makalemizde
deindiimiz XmlDocument tipidir. Serinin bu ikinci blmnde bu tipin dier zelliklerinide
renmeye devam ediyor olacacaz. Hazr ktk dosyas yazma ve okuma ileminden sze
balamken ayn ii Xml dosyas zerinde nasl yapabileceimizi inceleyecebiliriz. Bu makalemizde
telefonlardan ziyade kendi ktphanemizdeki kitaplarmz tayacak olan bir Xml dkman
zerinde baz ilemler yapmaya alacaz. Temel olarak hedeflerimiz aadaki ekilde olduu
gibidir.

Elbette gerekli aksiyonlarn zerinde gerekletirilecei bir Xml dosyasnn olmas gerekir. Bu
dosyann temel desenini aadaki gibi tasarlayabiliriz.

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


<Kitaplik>

www.bsenyurt.com Page 1227


<Kitap Id="">
<Ad></Ad>
<Fiyat></Fiyat>
<Basim></Basim>
<Yazarlar>
<Yazar></Yazar>
<Yazar></Yazar>
</Yazarlar>
</Kitap>
.
.
.
.
</Kitaplik>

ncelikli olarak root elementimizin Kitaplik olacan syleyebiliriz. Kitaplik elementi ierisinde Kitap
tipinden bir ok alt element yer alabilir. Her Kitap elementi iin Id isimli birnitelik(attribute) sz
konusudur. Bununla birlikte bir kitaba ait yazarlarda, Yazalar isimli element altndaki
Yazar boumlar(nodes) ierisinde tutulmaktadr. Dolaysyla programmz ierisindeki mant bu
hiyerariye gre dzenlemeliyiz. Xml dkman zerindeki ilemlerimizi gerekletirmek iin
yine DOM(Document Object Model) kullanyor olacaz. Buna gre XmlDocument nesnesi
olduka iimize yarayacaktr. Bu makalemizde XmlDocument nesnesi zerinden ele alabileceimiz
baz yardmc metod ve zellikler ise aadaki gibidir.

Yardmc Metod Aklamas

GetElementsByTagName Parametre olarak verilen elementin adna gre geriye


bir XmlNodeList dndrr. rneimizde tm Kitap boumlarn elde
etmek istediimiz durumlarda bu metoddan faydalanlmaktadr.

SelectSingleNode Tek bir node elde etmek istediimizde kullanabileceimiz metod.


Bir XPath ifadesi alarak almaktadr. rneimiz gz nne alndnda
belirli bir Id deerine sahip bir node elde edilmek istendii durumlarda
kullanlabilir. Geriye XmlNode tipinden bir nesne rnei dndrmektedir.

CreateNode Herhangibir Xml aac zerinde bir boum(node) oluturmak


istediimizde kullanabiliriz. Genellikle oluturulacak olan boumun
eidinide belirtiriz.
Byleceelement, processing instruction, comment, attribute gibi
Xml yelerini ve benzerlerini oluturabiliriz. rneimizde yeni bir Kitap
eklerken pek ok boumu oluturmamz
gerekecektir. CreateNode metodu ile bu ilevsellikler salanabilir.

AppendChild Genellikle oluturulan bir boumun baka bir bouma eklenmesi


amacyla kullanlr. rneimizde, yeni bir Kitap eklenmek istendiinde
ska kullanacamz bir metoddur.

Load Xml ieriini bellee almak istediimizde ele alacamz metoddur.

Save Xml ieriini fiziki ortama kaydetmek iin kullanabileceimiz metoddur.

Yardmc zellikler Aklamas

FirstChild Xml aac ierisindeki, root boum ierisindeki veya herhangibir boum
ierisindeki alt boumlarndan ilkini elde etmemizi salar. Bu nedenle
geriye birXmlNode referans dner.

PreviousSibling Aa yapsnda o an zerinde durulan boum biliniyorsa, bir ncekinin

www.bsenyurt.com Page 1228


elde edilmesini salar. Geriye XmlNode tipinden bir referans dndrr.

NextSibling Aa yapsnda o an zerinde durulan boum biliniyorsa eer, bir sonraki


boumun elde edilmesini salar. Geriye XmlNode tipinden bir referans
dndrr.

LastChild Root element altndaki veya herhangibir boum altndaki alt


boumlardan sonuncusuna gidilmesini salar. Geriye XmlNode tipinden
bir referans dndrr.

Attributes Bir boumun ierisindeki niteliklere erimemizi salar. zellikle bir Kitap
elementinin Id niteliini(attribute) elde etmek istediimiz durumlarda
kullanabiliriz.

Dilerseniz ncelikli olarak uygulama ekranmz tasarlayarak ie balayalm. rneimizi bir Windows
uygulamas olacak ekilde tasarlayacaz. Bu amala aadaki ekran grtnsndekine benzer bir
form oluturarak ie balayabiliriz.

Bizim iin gerekli olan bir dier ye ise kitaplarmz uygulama ortam ierisinde temsil
edebileceimiz bir tiptir. Bir baka deyile Xml dkman ierisindeki herhangibir Kitap boumunun
alt elementlerinin ve niteliklerinin deerlerini alma zamannda nesnel olarak tayabilecek bir
snf tasarmna ihtiyacmz vardr. Sz gelimizi, kullanc uygulamay atnda eer Kitaplk.xml
isimli bir dosya var ise ve ieriinde Kitap elementleri bulunuyorsa, bunlarn liste kutusuna birer
Kitap nesne rnei olarak atanmas salanabilir. Bunu yaptmzda, liste kutusundan seilen bir
enin iaret ettii Kitap referansn bulabilir ve bu nesne ile ilikili verileri ekebiliriz ki bu zellikle
bir nceki yada bir sonraki bouma geme ilemleri srasnda da nem arz edecektir. Dier taraftan
seilen kitabn, Xml aa yaps ierisindeki yerini bulmak iin kullanlacak XPathsorgusunda Id
niteliinin deeri gerekmektedir ve bunu liste kutusundan seilen e zerinden elde edebiliriz.
yleyse gelin Kitap isimli snfmz aadaki gibi tasarlayalm.

www.bsenyurt.com Page 1229


using System;

namespace ReadAndWrite
{
class Kitap
{
#region Alanlar(Fields)

private int _id;


private string _ad;
private DateTime _basim;
private float _fiyat;
private string _yazarlar;

#endregion

#region zellikler(Properties)

public int Id
{
get { return _id; }
set { _id = value; }
}
public string Ad
{
get { return _ad; }
set { _ad = value; }
}
public DateTime Basim
{
get { return _basim; }
set { _basim = value; }
}
public float Fiyat
{

www.bsenyurt.com Page 1230


get { return _fiyat; }
set { _fiyat = value; }
}
public string Yazarlar
{
get { return _yazarlar; }
set { _yazarlar = value; }
}

#endregion

public Kitap(int id,string ad, DateTime basim, float fiyat, string yazarlar)
{
Id = id;
Ad = ad;
Basim = basim;
Fiyat = fiyat;
Yazarlar = yazarlar;
}
public override string ToString()
{
return Ad;
}
}
}

Bir kitabn birden fazla yazar olabilmektedir. Bu amala bir yazara ait bilgileri tutacak baka bir
snf tasarmda dnlebilirdi. Bu durumda Kitap snfmz kendi ierisinde yazarlar tayabilecek
bir koleksiyon veya diziye sahip olmaldr. Biz rneimizde biraz daha basite katk ve birden fazla
yazar bilgisini aralarna | iareti koyarak tayacak string tipinden tek bir zellik kullandk.

imdi gelelim daha nemli olan ksmlara. zellikle Xml zerinde yapacamz genel ilevsellikleri
tayacak ayr bir tip tasarlayacaz. XmlYoneticisi isimli tipimiz genel olarak, Xml aac zerinde
navigasyon, Xml ieriini liste kutusuna aktarma, Xml boumu gncelleme, silme ve ekleme gibi
ilevsellikleri bnyesinde barndrmaktadr. Elbette bunlarn ilenmesi srasnda ele alnacak baz
yardmc fonksiyonellikler de yer almaktadr. XmlYoneticisi isimli snfmzn emas ve kodlar
aadaki gibidir.

www.bsenyurt.com Page 1231


using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.IO;
using System.Windows.Forms;
using System.Xml.XPath;

namespace ReadAndWrite
{
class XmlYoneticisi
{
XmlDocument _doc;

#region Yapc Metod(lar)

public XmlYoneticisi()
{
_doc = new XmlDocument();

if (!File.Exists("Kitaplik.xml"))
{
XmlProcessingInstruction instructor = _doc.CreateProcessingInstruction("xml",
"version=\"1.0\" encoding=\"utf-8\"");
// Oluturulan processing instruction XmlDocument nesne rneine eklenir.
_doc.AppendChild((XmlNode)instructor);
// root element oluturulur
XmlNode rootNode = _doc.CreateNode(XmlNodeType.Element, "Kitaplik", "");
// root element XmlDocument nesne rneine eklenir.
_doc.AppendChild(rootNode);
_doc.Save("Kitaplik.xml");
}
_doc.Load("Kitaplik.xml");
}

#endregion

www.bsenyurt.com Page 1232


#region Genel Metodlar
/// <summary>
/// Herhangibir Kitap boumu ierisindeki bilgilerini alp bir Kitap nesne rneinde
birletirilmesini salar
/// </summary>
/// <param name="bogum">Bilgileri alnacak olan Kitap boumu (node)</param>
/// <returns>Bogumdaki bilgilerden retilen Kitap nesne rnei</returns>
private Kitap BilgileriAl(XmlNode bogum)
{
int id;
string ad = "", yazarlar = "";
DateTime basim = DateTime.Now;
float fiyat = 0;
// Ad elementinin ierii alnr
ad = bogum["Ad"].InnerText;
// Fiyat elementinin ierii alnr
fiyat = float.Parse(bogum["Fiyat"].InnerText);
// Basim elementinin ierii alnr
basim = DateTime.Parse(bogum["Basim"].InnerText);
// Id niteliinin deeri Attributes zelliine indeksleyici operatr uygulanarak alnr
id = Int32.Parse(bogum.Attributes["Id"].Value);
yazarlar = "";
// Yazarlar elementi ierisindeki tm Yazar alt elementlerinin deerleri alnr.
foreach (XmlNode yazar in bogum["Yazarlar"].ChildNodes)
yazarlar += yazar.InnerText + "|";
// Elde edilen deiken bilgilerinden Kitap nesne rnei retilir.
Kitap ktp = new Kitap(id, ad, basim, fiyat, yazarlar);
// retilen nesne rnei geri dndrlr.
return ktp;
}

/// <summary>
/// XmlDocument nesne rneinin iaret ettii xml dokmanndaki Kitap boumlarn eker ve
her biri iin bir Kitap nesne rnei oluturup, parametre olarak gelen ListBox kontrolne
ykler.
/// </summary>
/// <param name="lst">Windows formundaki liste kontrol</param>
public void KitaplariCek(ListBox lst)
{
// nce Liste kutusu ierii temizlenir
lst.Items.Clear();
/* GetElementsByTagName metodu parametre olarak ald tak adlarn ilgili xml
aacndan eker ve bir XmlNodeList olarak geri dndrr. */
XmlNodeList kitaplar = _doc.GetElementsByTagName("Kitap");
// Elde edilen node listesindeki her bir XmlNode nesne rnei dolalr.
foreach (XmlNode kitapNode in kitaplar)
{
lst.Items.Add(BilgileriAl(kitapNode));
}
}
#endregion

#region Navigasyon Metodlar


/// <summary>
/// nceki ve Sonraki boumlarn hareketi srasnda o an xml aacnda bulunulan elementin

www.bsenyurt.com Page 1233


elde edilmesini salar.
/// </summary>
/// <param name="id">Konumu tespit edilecek olan Kitap elementinin Id deeri</param>
/// <returns></returns>
private XmlNode SecilenNode(int id)
{
/* Id deerine ait XmlNode' unu bulabilmek iin XPath sorgusundan faydalanlr. Buna gre
Kitaplik root elementi ierisindeki Kitap elementlerinden Id niteliinin deeri parametre olarak
gelen deiken deerine eit olan Kitap elementi bulunur. */
XmlNode secilenNode = _doc.SelectSingleNode("/Kitaplik/Kitap[@Id=" + id +
"]");
return secilenNode;
}

/// <summary>
/// Xml aacnda, root element altndaki ilk alt elemente gidilmesini salar
/// </summary>
/// <returns>Gidilen ilk alt elementteki deerler gre retilen Kitap nesne
rneidir</returns>
public Kitap Ilk()
{
// FirstChild zellii ile DocumentElement zellii zerinden uyguland takdirde Kitap
node' larndan ilkine gidilir.
XmlNode bogum = _doc.DocumentElement.FirstChild;
return BilgileriAl(bogum);
}

/// <summary>
/// Xml aacnda bulunulan boumdan bir ncekine geilmesini salar
/// </summary>
/// <param name="id">O an zerinde bulunulan boumun tespiti iin gerekli olan id
deeri</param>
/// <returns>Bir nceki bouma ait bilgilerden retilen Kitap nesne rnei</returns>
public Kitap Onceki(int id)
{
// Eer aa zerinde hangi boumda olduumuzu biliyorsak PreviousSibling zellii
sayesinde bir nceki bouma geebiliriz
XmlNode bogum = SecilenNode(id).PreviousSibling;
return BilgileriAl(bogum);
}

/// <summary>
/// Xml aacnda bulunulan boumdan bir sonrakine geilmesini salar
/// </summary>
/// <param name="id">O an zerinde bulunulan boumun tespiti iin gerekli olan id
deeri</param>
/// <returns>Bir sonraki bouma ait bilgilerden retilen Kitap nesne rnei</returns>
public Kitap Sonraki(int id)
{
// Eer aa zerinde hangi boumda olduumuzu biliyorsak NextSibling zellii sayesinde
bir sonraki bouma geebiliriz
XmlNode bogum = SecilenNode(id).NextSibling;
return BilgileriAl(bogum);
}

/// <summary>

www.bsenyurt.com Page 1234


/// Xml aacnda, root element altndaki son alt elemente gidilmesini salar
/// </summary>
/// <returns>Gidilen son alt elementteki deerler gre retilen Kitap nesne
rneidir</returns>
public Kitap Son()
{
// DocumentElement zellii zerinden uygulanan LastChild zellii sayesinde root element
ierisindeki son elemente gidilir.
XmlNode bogum = _doc.DocumentElement.LastChild;
return BilgileriAl(bogum);
}

#endregion

#region Temel Veri Deitirme Metodlar


/// <summary>
/// Var olan bir boumun ieriin gnceller
/// </summary>
/// <param name="id">Id deeri</param>
/// <param name="ad">Kitabn yeni ad</param>
/// <param name="lstYazarlari">Son haliyle kitabn yazarlarn tayan liste kutusu</param>
/// <param name="fiyat">Kitabn yeni fiyat</param>
/// <param name="basim">Kitabn yeni basm tarihi</param>
/// <param name="ktp">O an zerinde durulan Kitap nesne rneinin lstKitaplar liste
kutusundaki referans</param>
public void Guncelle(int id, string ad, ListBox lstYazarlari, float fiyat, DateTime basim, Kitap
ktp)
{
// nce gncelleme yaplacak olan boum tespit edilir.
XmlNode bogum = SecilenNode(id);
// Boumun elemanlarna yeni deerleri atanr
bogum["Ad"].InnerText = ad;

// Yazalar boumu bir liste kutusundan geldii iin nce xml aacndaki yazarlar boumu
kaldrlr.
bogum.RemoveChild(bogum["Yazarlar"]);
// Sonra son hali ile yazarlar boumu yeniden oluturulur.
XmlNode yazarlar = _doc.CreateNode(XmlNodeType.Element, "Yazarlar", "");
// Oluturulan yazarlar boumu tekrardan aa yaps ierisinde o anki Kitap boumuna
eklenir.
bogum.AppendChild(yazarlar);

// Yazarlar tayan liste kutusunun son ierine gre Yazarlar elementi altndaki Yazar alt
elementleri tekrardan oluturulur.
string yazarlari = "";
for (int i = 0; i < lstYazarlari.Items.Count; i++)
{
XmlNode yazar = _doc.CreateNode(XmlNodeType.Element, "Yazar", "");
yazar.InnerText = lstYazarlari.Items[i].ToString();
bogum["Yazarlar"].AppendChild(yazar);
yazarlari += lstYazarlari.Items[i] + "|";
}
bogum["Fiyat"].InnerText = fiyat.ToString();
// Tarih bilgisini standart olmas asndan Universal formatnda deitiriyoruz
bogum["Basim"].InnerText = basim.ToUniversalTime().ToString();
// aa yapsndaki deiiklikleri son hali ile Xml dosyasna kaydediyoruz.

www.bsenyurt.com Page 1235


_doc.Save("Kitaplik.xml");

// Yaplan deiiklikleri, ilgili Kitap nesne rnei zerindede gerekletiriyoruz.


ktp.Ad = ad;
ktp.Basim = basim;
ktp.Fiyat = fiyat;
ktp.Yazarlar = yazarlari;
}

/// <summary>
/// Bir Kitap boumunun aa yapsndan silinmesini salar
/// </summary>
/// <param name="id">Silinecek Kitap' n Id deeri</param>
public void Sil(int id)
{
XmlNode bogum = SecilenNode(id);
if (bogum != null)
{
// Secilen boumun aa yapsndan kartlmasn salamak iin RemoveChild metodu
kullanlr.
_doc.DocumentElement.RemoveChild(bogum);
// Son deiiklikler iin Save metodu arlr
_doc.Save("Kitaplik.xml");
}
}

/// <summary>
/// Yeni bir Kitap boumunun xml ieriine dahil edilmesini salar
/// </summary>
/// <param name="adi">Eklenecek kitabn ad</param>
/// <param name="fiyati">Eklenecek kitabn fiyat</param>
/// <param name="lstYazarlari">Eklenecek kitabn yazalarn tayan liste kutusu</param>
/// <param name="basimTarihi">Eklenecek kitabn basm tarihi</param>
/// <returns>Yeni bilgilerden elde edilen Kitap nesne rnei</returns>
public Kitap Ekle(int yeniId,string adi, float fiyati, ListBox lstYazarlari, DateTime basimTarihi)
{
// Aa yaps ierisinde yeni bir Kitap boumu oluturulur
XmlElement kitap = _doc.CreateElement("Kitap");

// Id nitelii oluturulur
XmlAttribute id = _doc.CreateAttribute("Id");
// Id niteliinin deeri verilir

id.Value = yeniId.ToString();
// Oluturulan Id nitelii Kitap boumuna eklenir
kitap.Attributes.Append(id);

// Ad boumu oluturulur.
XmlNode ad = _doc.CreateNode(XmlNodeType.Element, "Ad", "");
// Ad boumuna deeri verilir
ad.InnerText = adi;
// Ad boumu Kitap boumu altna eklenir
kitap.AppendChild(ad);

// Fiyat boumu oluturulur


XmlNode fiyat = _doc.CreateNode(XmlNodeType.Element, "Fiyat", "");

www.bsenyurt.com Page 1236


// Fiyat boumunun deeri verilir
fiyat.InnerText = fiyati.ToString();
// Fiyat boumun Kitap boumu altna eklenir
kitap.AppendChild(fiyat);

// Basim boumu oluturlur.


XmlNode basim = _doc.CreateNode(XmlNodeType.Element, "Basim", "");
// Basim boumun deeri verilir
basim.InnerText = basimTarihi.ToUniversalTime().ToString();
// Basim boumu Kitap boumu altna eklenir
kitap.AppendChild(basim);

// Yazarlar boumu oluturulur


XmlNode yazarlar = _doc.CreateNode(XmlNodeType.Element, "Yazarlar", "");

string yazarlarStr = "";


for (int i = 0; i < lstYazarlari.Items.Count; i++)
{
// Gelen liste kutusu kontrolndeki her bir yazar iin Yazar boumu oluturulur ve
Yazarlar boumu altna eklenir
XmlNode yazar = _doc.CreateNode(XmlNodeType.Element, "Yazar", "");
yazar.InnerText = lstYazarlari.Items[i].ToString();
yazarlar.AppendChild(yazar);
yazarlarStr += lstYazarlari.Items[i].ToString() + "|";
}
kitap.AppendChild(yazarlar);
_doc.DocumentElement.AppendChild((XmlNode)kitap);
// Xml aac Kitaplk.xml dosyasna kaydedilir
_doc.Save("Kitaplik.xml");
// Gelen bilgilerden elde edilen Kitap nesne rnei geri dndrlr
return new Kitap(yeniId, adi, basimTarihi, fiyati, yazarlarStr);
}
#endregion
}
}

XmlYoneticisi isimli snfmzn kodlar her ne kadar ok olsada aslnda temel amalar bellidir. Genel
olarak snfmz bellee alnan Xml aa yaps zerinde navigasyon ilemlerini
gerekletirebilmektedir, aaca yeni bir kitap eklemek, seilen kitab silmek veya gncellemek gibi
ilemleride yerine getirebilmektedir. ok doal olarak snfmzn Windows tarafnda kullanlmas
gerekmektedir. Lakin windows formu ierisindede baz kodlamalar yapmamz gerekir.

Windows tarafnda yer alan kalabalk kodlar optimize etmek gerekmektedir. Bu amala
buradaki ilemleri stlenecek ayr bir snf tasarm ele alnabilir. Bunu yapmaya almak
uygulama gelitiriciyi bir adm daha teye tayacak ve kod optimizasyonu, performans,
bakm kolayl gibi konularda uygulamaya byk avantajlar getirecektir.

yleyse gelin ilk aamada Windows uygulamamzda bize gereken kodlar aadaki gibi yazmaya
alalm.

www.bsenyurt.com Page 1237


public partial class Form1 : Form
{
// Ynetsel ilemler iin gerekli olan XmlYoneticisi tipimizi tanmlyoruz
XmlYoneticisi xmlYnt;

public Form1()
{
InitializeComponent();

// Xml zerindeki ilemler iin (ekleme,gncelleme,silme,navigasyon vs...) tasarlanan


XmlYoneticisi nesne rnei oluturulur.
xmlYnt = new XmlYoneticisi();
// Eer Kitaplik.xml dosyas var ise Kitap bilgileri ekilir
xmlYnt.KitaplariCek(lstKitaplar);
}

/* Id deerini otomatik arttrabilmek iin yardmc bir metoda bavurabiliriz. Bu metod liste
kutusundaki Kitap elerinde(eer varsalar) yer alan Id deerlerinin en byn bulur. Bu elbette
tek bana alan bir uygulama olacandan (yani client server mimaride yer almayacandan) e
zamanl akma gibi durumlar ele alnmyor.*/
private int EnBuyuk()
{
int deger1=0;
for (int i = 0;i< lstKitaplar.Items.Count; i++)
{
int deger2=((Kitap)lstKitaplar.Items[i]).Id;
if (deger2 > deger1)
deger1 = deger2;
}
return deger1;

www.bsenyurt.com Page 1238


}
private void Form1_Load(object sender, EventArgs e)
{
// Eer liste kutusunda eleman var ise ilk elemana konumlan
if (lstKitaplar.Items.Count > 0)
lstKitaplar.SelectedIndex = 0;
}

#region Navigasyon ilemleri


private void lstKitaplar_SelectedIndexChanged(object sender, EventArgs e)
{
// Liste kutusunda bir eye tklandndan buna ait bilgileri dier kontrollere aktar
Goster((Kitap)lstKitaplar.SelectedItem);
}

private bool Goster(Kitap ktp)


{
// Eer bir Kitap nesne rnei var ise
if (ktp != null)
{
// Dier kontrolleri doldur
lblId.Text = ktp.Id.ToString();
txtAd.Text = ktp.Ad;
txtBasim.Text = ktp.Basim.ToShortDateString();
txtFiyat.Text = ktp.Fiyat.ToString();
lstYazarlar.Items.Clear();
// Yazar bilgilerinin Yazarlar isimli zellikte bir string katar eklinde tuttuumuz iin |
iaretine gre ayrtrp ele alyoruz.
string[] yazarlari = ktp.Yazarlar.Split('|');
for (int i = 0; i < yazarlari.Length - 1; i++)
lstYazarlar.Items.Add(yazarlari[i]);
return true;
}
else
return false;
}

/* Not: Burada, liste kutusu ierisindeki nesnelerden de dorudan faydalanlabilinir. Ancak Xml
ierisindeki navigasyon ilemlerini renebilmek iin bu yol tercih edilmemitir. */
private void btnIlk_Click(object sender, EventArgs e)
{
// lk bouma ge.
if ((lstKitaplar.Items.Count > 0) && (lstKitaplar.SelectedIndex != 0))
if (Goster(xmlYnt.Ilk()))
lstKitaplar.SelectedIndex = 0;
}

private void btnOnceki_Click(object sender, EventArgs e)


{
/* nceki bouma geme ilemi iin Onceki metodunu aryoruz. Burada doal olarak eer
ilk elemanda isek ya da var olan eleman yoksa hareket edilmesinide engellemeliyiz. If kontrolnn
yaplmasnn sebebi budur. Bu ve benzeri kontrolleri dier navigasyon ilemlerindede yapyoruz. */
if ((lstKitaplar.Items.Count > 0) && (lstKitaplar.SelectedIndex != 0))
if (Goster(xmlYnt.Onceki(((Kitap)lstKitaplar.SelectedItem).Id)))
lstKitaplar.SelectedIndex--;
}

www.bsenyurt.com Page 1239


private void btnSonraki_Click(object sender, EventArgs e)
{
// Sonraki bouma ge
if ((lstKitaplar.Items.Count > 0) && (lstKitaplar.SelectedIndex < lstKitaplar.Items.Count - 1))
if (Goster(xmlYnt.Sonraki(((Kitap)lstKitaplar.SelectedItem).Id)))
lstKitaplar.SelectedIndex++;
}

private void btnSon_Click(object sender, EventArgs e)


{
//Son bouma ge
if ((lstKitaplar.Items.Count > 0) && (lstKitaplar.SelectedIndex < lstKitaplar.Items.Count - 1))
if (Goster(xmlYnt.Son()))
lstKitaplar.SelectedIndex = lstKitaplar.Items.Count - 1;
}
#endregion

#region Temel veri ilemleri

private void btnYazarEkle_Click(object sender, EventArgs e)


{
// Eer yazar liste kutusuna daha nce eklenmemise
if (!lstYazarlar.Items.Contains(txtYazar.Text))
if (!String.IsNullOrEmpty(txtYazar.Text)) // ve txtYazar kutucuu bo deil ise ekle
lstYazarlar.Items.Add(txtYazar.Text);
}

private void Temizle()


{
// Yeni bilgi girii iin kontrollerin ieriini temizle
txtAd.Text = string.Empty;
lblId.Text = string.Empty;
txtFiyat.Text = string.Empty;
txtBasim.Text = string.Empty;
lstYazarlar.Items.Clear();
txtYazar.Text=string.Empty;
}

private void btnYeni_Click(object sender, EventArgs e)


{
// Yeni bir Kitap girilmek istendiinde ncelikle veri girii yaplacak kontrollerin ieriini
temizleriz.
Temizle();
}

// Kullancnn yeni bir kitap eklerken kontrollere eksik veri girii yapp yapmadn denetliyor
private bool GirisKontrol()
{
DateTime tarih;
float fiyat;

// Kullancnn eksik kontrol girip girmediini ele alabilmek iin aadaki bool deiken
atamalar kullanlmtr. TryParse metodunun nasl kullanldna dikkat edelim.
bool tarihGecerli = DateTime.TryParse(txtBasim.Text,out tarih);
bool fiyatGecerli = float.TryParse(txtFiyat.Text,out fiyat);

www.bsenyurt.com Page 1240


bool adGecerli = !String.IsNullOrEmpty(txtAd.Text);
bool yazarlarGecerli = lstYazarlar.Items.Count == 0 ? false : true;
// Eer eksik veri girii yok ise ekleme ilemini yap, tersine eksik veri girii var ise uyar
mesaj ver.
if ((tarihGecerli == false) || (fiyatGecerli == false) || (adGecerli == false) || (yazarlarGecerli
== false))
return false;
else
{
//TODO: Girilen bilginin daha nceden eklenip eklenmediinin kontrol
konulabilir.
return true;
}
}

private void btnKaydet_Click(object sender, EventArgs e)


{
if(!GirisKontrol())
MessageBox.Show("Eksik giri var");
else
{
// Yeni kitab Ekle metodu ile ekliyoruz. Ekle metodu geriye Kitap tipinden bire referans
dndrd iin bunuda alp liste kontrolne otomatik olarak ekleyebiliriz.
Kitap eklenen = xmlYnt.Ekle( EnBuyuk()+1,txtAd.Text, float.Parse(txtFiyat.Text),
lstYazarlar, DateTime.Parse(txtBasim.Text));
lstKitaplar.Items.Add(eklenen);
// Eklenen yeni Kitaba ait bilgileri ilgili kontrollerde gster
Goster(eklenen);
}
}

private void btnGuncelle_Click(object sender, EventArgs e)


{
// Seili olan xml boumunu gncelle
/* Gncelleme ilemi iin Guncelle metodunu kullanmaktayz. Bu metodunda Ekle metodunda
olduu gibi geriye bir Kitap referans dndrmesi belki gz nne alnabilir. Bylece sunu tarafnda
gncellenen bilgiler ile ilikili referansda son hali ile deitirmek mmkn olabilir. */
if (lstKitaplar.Items.Count > 0)
xmlYnt.Guncelle(int.Parse(lblId.Text), txtAd.Text, lstYazarlar,
float.Parse(txtFiyat.Text), DateTime.Parse(txtBasim.Text),
(Kitap)lstKitaplar.SelectedItem);
else
MessageBox.Show("Gncellenecek veri yok");
}

// Seili olan xml boumunu sil


private void btnSil_Click(object sender, EventArgs e)
{
// Eer silinebilecek bir eleman var ise
if (lstKitaplar.Items.Count > 0)
{
// Seili olan eleman liste kutusundan elde edip, bunun zerinden Id zelliinin deerini
alyoruz.
int silinecekKitapId = ((Kitap)lstKitaplar.SelectedItem).Id;
// Xml aacndan kart.Bunun iin Sil metodunu aryoruz.
xmlYnt.Sil(silinecekKitapId);

www.bsenyurt.com Page 1241


// Xml aacndan ve dolaysylada fiziki Xml dosyasndan karttmz eyi Liste
kutusundan da kaldryoruz
lstKitaplar.Items.Remove(lstKitaplar.SelectedItem);
Temizle();
if (lstKitaplar.Items.Count > 0)
lstKitaplar.SelectedIndex = 0;
}
}
#endregion

private void lstYazarlar_KeyUp(object sender, KeyEventArgs e)


{
// yazarlardan biri seili iken Delete tuuna baslrsa onu lstYazarlar isimli liste kutusundan
kartyoruz
if ((e.KeyCode == Keys.Delete)&&(lstYazarlar.Items.Count>0))
lstYazarlar.Items.Remove(lstYazarlar.SelectedItem);
}
}

Uygulamz alma zamannda aadaki rnek ekran grntsnde olduu gibi kullanlabilir. (Video
format flash olup boyutu 239 kb olduundan yklenmesi zaman alabilir.)

Test amacyla 3 yeni kitap girilmitir. Kitaplardan birisi zerinde deiiklik yaplmtr. Var olan bir
kitap silinmitir ve navigasyon ilemleri gerekletirilmitir. Ekran grntsndeki ilemleri
yaptmzda Xml dosyamzn son hali aadaki gibi olacaktr.

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


<Kitaplik>
<Kitap Id="1">
<Ad>.Net in ABC' si</Ad>
<Fiyat>10</Fiyat>
<Basim>28.02.2007 22:00:00</Basim>
<Yazarlar>
<Yazar>Emrah Uslu</Yazar>
<Yazar>Osman okakolu</Yazar>

www.bsenyurt.com Page 1242


<Yazar>Burcu Gnel</Yazar>
</Yazarlar>
</Kitap>
<Kitap Id="2">
<Ad>Her Ynyle C#</Ad>
<Fiyat>29</Fiyat>
<Basim>31.12.2002 22:00:00</Basim>
<Yazarlar>
<Yazar>Sefer Algan</Yazar>
</Yazarlar>
</Kitap>
</Kitaplik>

Programn elbetteki baz buglar vardr, olmaldr. rnein, kullanc arka arkaya Kaydet tularna
basabilir ki bu durumda ayn kitap defalarca eklenir. Bir ekilde bunun nne gemek
gerekmektedir. Program test ettike baka hatalarda kacaktr. Bu hatalar tespit edip, tedbirlerini
almaya almak bizi biraz daha ileriye gtrecektir. Sonu itibariyle testler, uygulama gelitirme
srecinin nemli bir parasdr. yi yaplan testler sonucu tespit edilen sorunlarn en optimal ekilde
zlmeside bu srece dahildir. Dolaysyla uygulamay gelitirmenin siz deerli okurlar iin nemli
bir art olaca kansndaym. Bylece geldik bir makalemizin daha sonuna. Bu
makalemizde XmlDocument tipini ele alrken

Fiziki bir Xml verisinin bellee nasl alnabileceini,


Bellek zerindeki bir aata nasl hareket edebileceimizi,
Xml bilgisini tayan aaa yeni boumlar nasl ekleyebileceimizi,
Aataki herhangibir Xml bilgisini nasl deitirebileceimizi,
Aataki herhangibir Xml boumunu nasl silebileceimizi,
Aa zerinde gerekletirilen deiikliklerin fiziki bir Xml dosyasna nasl
kaydedilebileceini,

rnek bir uygulama zerinden ele almaya altk. Umarm sizler iin yararl bir deneyim olmutur.
Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

.Net Tarafnda Xml ile Oynamak-1 ( 28.02.2007 )


- Xml
Deerli Okurlarm Merhabalar,

Bu makalemiz ile birlikte Xml mimarisini ynetimli kod(managed code) tarafndan ele almaya
alacak ve konular rnek senaryolar zerinden gelitireceiz. Bildiiniz gibiXml(eXtensible
Markup Language) ok yaygn olarak kullanlan, platformlar aras veri tama standartlarndan
birisidir. .Net Framework ierisinde Xml standartlar ile dorudan i yapmamz salayan ynetimli
tipler bulunmaktadr. Bu tipler sayesinde sadece Xml deil, Xml ile ilikili dier standartlarda etkili
bir ekilde kullanabilmekteyiz. Xml Schema, Xslt veXPath mimarileri bunlar arasnda saylabilir.
Biz bu gnk makalemizde alma zamannda dinamik olarak bir Xml belgesini nasl
oluturabileceimizi, bu belgenin kaydedilmesini ve hatta yeniden okunmasn ele alacamz bir
senaryo zerinde duracaz. Dilerseniz ie rnek senaryomuzdan bahsederek balayalm.

www.bsenyurt.com Page 1243


rneimiz bir windows uygulamas olacak ve MDI (Multiple Document Interface) tarznda
tasarlanacak. Ana formun altn yer alabilecek olan alt formlarmz(Child Forms) zerinde mouse
yardmyla dz izgiler iziyor olacaz. izim ilemleri iin GDI+ API' sinden yararlanyor olacaz.
Amacamz ise bu izgilerin ilgili form iin bir Xml dosyasnda kendi belirleyeceimiz bir desende
saklanmasn salamak. Xml tarafnda gemeden nce Windows uygulamamz tasarlamakta fayda
var. Alt formlarmzda izilen izgilerin hatrlanmas ve generic bir koleksiyon ierisinde saklanmas
programatik olarak iimizi olduka kolaylatracaktr. Temel olarak bir izginin, balang ve biti
koordinatlarna ait bilgilerin nemli olduunu dnecek olursak aadaki gibi bir snf bizim iin
yeterli olacaktr.

using System;
using System.Collections.Generic;
using System.Text;

namespace DynamicXmlDocument
{
public class Cizgim
{
private int _X1;
private int _Y1;
private int _X2;
private int _Y2;

public int X2
{
get { return _X2; }
set { _X2 = value; }
}
public int Y2
{
get { return _Y2; }
set { _Y2 = value; }
}
public int X1
{
get { return _X1; }
set { _X1 = value; }
}

www.bsenyurt.com Page 1244


public int Y1
{
get { return _Y1; }
set { _Y1 = value; }
}
public Cizgim(int x1, int y1,int x2,int y2)
{
X1 = x1;
Y1 = y1;
X2 = x2;
Y2 = y2;
}
}
}

Alt formlarmz kendi ilerinde, ekrana izilen izgilerin bilgilerini hatrlamak durumundadr. Nitekim
bunu yapmadmz takdirde formun mimimize edilmesi yada stne baka bir grntnn gelmesi
sonucu, zerlerinde tadklar izgiler kaybolmaktadr. Bunun nne gemek iin form zerindeki
izgilerin hatrlanmas arttr. Bu sebepten alt formlarmz adaki gibi tasarlayabiliriz. Elbette
hatrlanacak olan izgilerin srekli izdirilmesi gerekir. Bu nedenle formlarmzn MouseUp ve Paint
olaylar ierisinde gerekli izdirme operasyonlar tetiklenmelidir.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace DynamicXmlDocument

www.bsenyurt.com Page 1245


{
public partial class Sahne : Form
{
private int _X, _Y;
private bool _MouseDownOk = false;
private List<Cizgim> _Cizgiler;

public List<Cizgim> Cizgiler


{
get
{
return _Cizgiler;
}
}

public Sahne()
{
InitializeComponent();
_Cizgiler = new List<Cizgim>();
}

private void Sahne_MouseDown(object sender, MouseEventArgs e)


{
_X = e.X;
_Y = e.Y;
_MouseDownOk = true;
}

private void Sahne_MouseUp(object sender, MouseEventArgs e)


{
_Cizgiler.Add(new Cizgim(_X,_Y,e.X,e.Y));
_MouseDownOk = false;
}

private void Sahne_MouseMove(object sender, MouseEventArgs e)


{
if (_MouseDownOk)
{
Graphics grp = this.CreateGraphics();
grp.Clear(this.BackColor);
Pen pn = new Pen(Brushes.Blue);
pn.Width = 3;
grp.DrawLine(pn, _X, _Y, e.X, e.Y);
CizgileriCiz();
}
}

private void Sahne_Paint(object sender, PaintEventArgs e)


{
CizgileriCiz();
}

private void CizgileriCiz()


{
Graphics grp = this.CreateGraphics();
Pen pn = new Pen(Brushes.Blue);

www.bsenyurt.com Page 1246


pn.Width = 3;
foreach (Cizgim czg in _Cizgiler)
grp.DrawLine(pn, czg.X1, czg.Y1, czg.X2, czg.Y2);
}
}
}

Bu ksmlarda ok fazla durmayacaz. Nitekim makalemizin konusu dnda kalmaktalar. Ancak


zetle amacmzn GDI+ kullandmzda, sahneler zerindeki izgilerin kaybolmasn engellemek
olduunu syleyebiliriz. Bu formlarmz tayacak olan MDI formumuza ise bir men koyup, yeni
sahneler alabilmesini, var olan sahnelerin kaydedilebilmesini, yada bir Xml ierisinden var olan bir
sahnenin okunabilmesini salayacaz. Bu dzenlemeler ile birlikte uygulamamz temel olarak
aadaki ekran grntsnde olduu gibi alacaktr.

imdi ilk amacmz ile ie balayalm. Alt formlar zerindeki izgilerin sakland generic List
koleksiyonu ieriini, veri format tarafmzca tasarlanacak olan bir Xml dokmannda tutmak ve
fiziki olarak kaydetmek. Bu amala ncelikli olarak Xml verimiz iin bir ablon dnelim. Bu
format herkes kendi istedii ekilde tasarlayabilir. rnein ben herhangibir Sahnenin zerindeki
izgileri aadaki formatta tutmay planladm.

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


<Sahne>
<Cizgim ID="0">
<Koordinatlar>
<Baslangic X="40" Y="40" />
<Bitis X="187" Y="143" />
</Koordinatlar>
</Cizgim>
<Cizgim ID="1">
<Koordinatlar>

www.bsenyurt.com Page 1247


<Baslangic X="241" Y="61" />
<Bitis X="273" Y="259" />
</Koordinatlar>
</Cizgim>
</Sahne>

Xml verisi, bir Sahne ierisindeki her bir dz izgi iin Cizgim isimli bir element tutmaktadr. Bir
izginin balang ve biti noktalarna ati koordinatlarn ise, Baslangic ve Bitis
isimlielementler(elements) ierisinde X ve Y nitelikleri ile tutuluyor. Bir sahne ierisinde birden
fazla izgi olacandan bunlar daha kolay bir ekilde ayrd edebilmek iin Cizgim elementlerine
birde ID isimli nitelikler(attributes) ekledik. Bu tip bir Xml ieriini alma zamannda dinamik
olarak oluturabilmek iin ncelikle Xml ierisindeki aa yapsn kavramak ve buna gre uygun
ynetimli tipleri kullanmak gerekir. Aadaki ekilde, Xml verimiz ierisinde yer alan yelere dair
fikirler verilmektedir.

Buna gre unlar syleyebiliriz;

Dinamik olarak oluturulacak Xml verisi processing instructions komutu ile balamaldr.
Bu zaten geerli bir Xml dokman iin bir kuraldr.
Xml dkmanmzn root elementinin ad Sahne' dir. Xml belgeleri sadece bir tane root
element ierebilir. Ama mutlaka bir root element iermek zorundadr.
Sahne elementi ierisinde birden fazla Cizgim elementi olabilir.
Cizgim elementleri, formun zerindeki izgilerin koordinat bilgilerini tamak zere
Koordinatlar isimli bir alt element(Child Element) iermektedir.
Koordinatlar elementi ierisinde izginin balang ve biti noktalarnn tutulduu
elementler ayn seviyedir.
Balang ve biti noktalarna ait X ve Y deerleri srasyla Baslangic ve Bitis elementleri
ierisinde nitelikler(attributes) yardmyla tutulmaktadr.
Her bir izgi iin otomatik artan bir ID deeri programatik olarak ayarlanmakla birlikte,
Cizgim elementleri ierisinde ID isimli niteliklerde saklanmaktadr.

Artk Xml taraf iin gerekli kodlamalarmz yazabiliriz. ncelikli olarak Xml ilemlerini tek bir at
altnda toplamak adna bir snftan yararlanmakta fayda vardr. Snfmz ierisinde herhangibir alt
formun zerindeki izgileri kaydedecek olan static bir metodu aadaki gibi dnebiliriz.

www.bsenyurt.com Page 1248


using System;
using System.Xml;
using System.IO;
using System.Collections.Generic;

namespace DynamicXmlDocument
{
class XmlDonusturucu
{
public static void ProjeKaydet(string dosya, List<Cizgim> cizgiler)
{
XmlDocument doc = new XmlDocument();
// nce Xml dkmanmzn bandaki processing instruction komutu oluturulur.
XmlProcessingInstruction instructor=doc.CreateProcessingInstruction("xml",
"version=\"1.0\" encoding=\"utf-8\"");
// Oluturulan processing instruction XmlDocument nesne rneine eklenir.
doc.AppendChild((XmlNode)instructor);
// root element oluturulur
XmlNode rootNode = doc.CreateNode(XmlNodeType.Element, "Sahne", "");
// root element XmlDocument nesne rneine eklenir.
doc.AppendChild(rootNode);
// cizgiler koleksiyonundaki eleman says kadar Cizgim elementi oluturulur, alt
elementleri doldurulur ve bunla Sahne node' una (bir baka deyie rootNode' a eklenir.
int cizgiNumarasi=0;
foreach (Cizgim czg in cizgiler)
{
XmlNode cizgimNode = doc.CreateNode(XmlNodeType.Element, "Cizgim", "");

XmlNode idAttribute = doc.CreateNode(XmlNodeType.Attribute, "ID", "");


idAttribute.Value = cizgiNumarasi.ToString();
cizgimNode.Attributes.Append((XmlAttribute)idAttribute);

XmlNode koordinatlarNode = doc.CreateNode(XmlNodeType.Element, "Koordinatlar",


"");
XmlNode baslangicNode = doc.CreateNode(XmlNodeType.Element, "Baslangic", "");

XmlAttribute xAttribute = doc.CreateAttribute("X");


xAttribute.Value = czg.X1.ToString();
baslangicNode.Attributes.Append(xAttribute);

XmlAttribute yAttribute = doc.CreateAttribute("Y");


yAttribute.Value = czg.Y1.ToString();
baslangicNode.Attributes.Append(yAttribute);

koordinatlarNode.AppendChild(baslangicNode);

XmlNode bitisNode = doc.CreateNode(XmlNodeType.Element, "Bitis", "");

www.bsenyurt.com Page 1249


xAttribute = doc.CreateAttribute("X");
xAttribute.Value = czg.X2.ToString();
bitisNode.Attributes.Append(xAttribute);

yAttribute = doc.CreateAttribute("Y");
yAttribute.Value = czg.Y2.ToString();
bitisNode.Attributes.Append(yAttribute);

koordinatlarNode.AppendChild(bitisNode);

cizgimNode.AppendChild(koordinatlarNode);

rootNode.AppendChild(cizgimNode);

cizgiNumarasi++;
}
doc.Save(dosya);
}
}
}

ProjeKaydet isimli metodumuz ilk parametre olarak form zerindeki izgileri saklayan koleksiyon
tipini almaktadr.(List<Cizgim>). kinci parametre olaraksa Xml bilgisinin kaydedilecei dosya ad
verilmektedir. Bir windows uygulamas tasarladmz iin dosya adn saveFileDialog kontrol
yardmyla gnderebiliriz. Peki metodumuzun ierisinde neler yapyoruz? lk
olarak XmlDocument snfnn AppendChild metodunun XmlNode tipinden parametreler aldn
belirtelim. Bunun dnda XmlDocument nesnesi bellea alan veri
alannaElement, Attribute, Comment gibi Xml yelerini eklemek iin gerekli Create metodlarna
sahiptir. Dolaysyla bir Processing Instruction komutuna ihtiyacmz var ise bu durumda
aadaki kod satrndan faydalanabiliriz.

XmlProcessingInstruction instructor=doc.CreateProcessingInstruction("xml", "version=\"1.


0\" encoding=\"utf-8\"");

Bu kod satr ile bir Processing Instruction oluturulur. Sonrasnda ise bunu XmlDocument nesne
rneine ilave etmemiz gerekir. Bylece bellekteki Xml alan ierisine ilgili yeyi dahil etmi oluruz.
Bu amalada aadaki kod satr kullanlabilir.

doc.AppendChild((XmlNode)instructor);

Dikkat ederseniz AppendChild metodu ierisinde bir dntrme ilemi yaplmaktadr. Bunun
sebebi metodun parametre olarak XmlNode tipinden bir deiken beklemesidir.
AslndaXmlElement, XmlAttribute, XmlProcessingInstruction gibi tipleri dndmzde
bunlarn dolaylda olsa XmlNode tipinden trediklerini syleyebiliriz. Buradaki mantk kodun kalan
ksmnada uyarlanmtr. zellikle elementleri olutururken XmlDocument
snfnn CreateNode metodu gz nne alnmtr.

XmlNode cizgimNode = doc.CreateNode(XmlNodeType.Element, "Cizgim", "");

XmlNode idAttribute = doc.CreateNode(XmlNodeType.Attribute, "ID", "");

www.bsenyurt.com Page 1250


rnein yukardaki kod parasnda CreateNode metodlarnda ilk parametre olarak retilmek
istenilen node tipi belirtilmitir. Sonrasnda ikinci parametre olarak node' un ad ve eer varsa
n parametre ilede Xml isim alan(namespace) belirtilmektedir.

CreateNode metodunun ar yklenmi versiyonu vardr. zellikle bir Xml isim alan sz
konusu olduunda, ekilde versiyondan faydalanlabilinir.

Artk snfmz bu haliyle kullanp alt formlarmzn izgilerini Xml formatnda saklamak iin gerekli
kodlar yazabiliriz. Bu amala MDI formumuz ierisindeki Proje Kaydet balkl men esi iin
aadaki kodlar yazmamz yeterli olacaktr.

private void projeYeniToolStripMenuItem_Click(object sender, EventArgs e)


{
// Yeni Sahne nesnesi oluturmak.
Sahne shn = new Sahne();
shn.MdiParent = this;
shn.Show();
}

private void projeKaydetToolStripMenuItem_Click(object sender, EventArgs e)


{
// Eer ekranda sahneler var ise bunlardan aktif olann izgilerini Xml dosyasna kaydet.
if (this.MdiChildren.Length > 0)
{
Sahne shn = (Sahne)ActiveMdiChild;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
XmlDonusturucu.ProjeKaydet(saveFileDialog1.FileName, shn.Cizgiler);
}
}

Dikkat ederseniz yazm olduumuz snf sayesinde, sayfa programcs iin karmak olacak olan
Xml ayrtrma kodlarn kapsllemi olduk. (Encapsulate)

imdide Xml' e yazm olduumuz dosyay okuyup, tekrardan ilgili ekillerini nasl izdireceimizi
grelim. Bu amala XmlDonusturucu snfmza yeni bir static metod ekleyebiliriz. Metodumuzun
yapmas gereken, almak istenen Xml dosyasn parametre olarak almak ve geriye Cizgim tipinden
elemanlar tayan generic bir List koleksiyonu dndrmektir. Ancak Sahne isimli Windows
forumumuzun ierisinde yer alan Cizgiler isimli zelliimiz yanlz okunabilir (read-only) olarak
tasarlanmtr. Dolaysyla ilk nce, bu zellie bir set blou ekleyerek veri atanabilir hale
getirmekle ie balayabiliriz.

public List<Cizgim> Cizgiler


{

www.bsenyurt.com Page 1251


get
{
return _Cizgiler;
}
set
{
_Cizgiler = value;
}
}

Ardndan XmlDonusturucu snfmza aadaki ProjeAc isimli metodumuzu dahil edelim.

public static List<Cizgim> ProjeAc(string dosya)


{
List<Cizgim> cizgiler = new List<Cizgim>();
XmlDocument doc = new XmlDocument();
doc.Load(dosya);
XmlNodeList koordinatlar = doc.SelectNodes("/Sahne/Cizgim/Koordinatlar");
foreach (XmlNode koordinat in koordinatlar)
{
int x1 = Int32.Parse(koordinat["Baslangic"].Attributes["X"].Value);
int y1 = Int32.Parse(koordinat["Baslangic"].Attributes["Y"].Value);
int x2 = Int32.Parse(koordinat["Bitis"].Attributes["X"].Value);
int y2 = Int32.Parse(koordinat["Bitis"].Attributes["Y"].Value);
Cizgim czg = new Cizgim(x1, y1, x2, y2);
cizgiler.Add(czg);
}
return cizgiler;
}

Metodumuzun belkide en can alc noktas XmlDocument nesne rnei


zerinden SelectNodes metodunun arlmasdr. SelectNodes metodu parametre olarak
ald XPathsorgusuna uygun olacak ekilde bir node listesi dndrmektedir. Dolaysyla bu proje
tarafndan oluturulmu bir Xml dosyasn atmzda, Sahne root elementi ierisindeki Cizgim
elementi ierisindeki tm Koordinatlar elementleri elde edilebilecektir.(Tabi varsalar)

XPath ile ilikili olaraktan daha detayl bilgi iin daha nceki
bir makaleden faydalanabilirsiniz.

Bundan sonra, elde edilen node listesi zerinde bir iterasyon gerekletirilmektedir. Bu iterasyon
ierisinde, her bir XmlNode nesne rnei ele alnr. Dikkat ederseniz Baslangic ve Bitis alt

www.bsenyurt.com Page 1252


elementlerindeki X ve Y niteliklerinin deerlerine erimek iin aadaki notasyon kullanlmtr.

koordinat[Alt Elementin Ad].Attributes[Niteliin Ad].Value

Bylece bir cizgi iin tutulan balang ve biti noktas deerlerini kolayca elde edebiliriz.
Metodumuz elde edilen bu deerlere gre Cizgim tipinden nesne rnekleri retmektedir ve bunlar
cizgiler isimli koleksiyonda toplayarak geri dndrmektedir. Artk grsel tarafta tek yapmamz
gereken, MDI pencerimizin mensndeki proje a balkl seenek iin aadaki kodlar
yazmaktr. (Buradada Xml dosyasn aabilmek iin openFileDialog kontrolnden yararlanlmtr.
Sadece Xml uzantl dosyalar amak veya yazmak iin saveFileDialog ve openFileDialog
kontrollerinin Filter zelliklerinden faydalanlmaktadr.)

private void projeAToolStripMenuItem_Click(object sender, EventArgs e)


{
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
Sahne shn = new Sahne();
shn.Cizgiler = XmlDonusturucu.ProjeAc(openFileDialog1.FileName);
shn.MdiParent = this;
shn.Show();
}
}

Eer uygulamamz altracak olursak aadaki flash animasyonundakine benzer bir sonu ile
karlarz. (Flash dosyasnn boyutu 192 kb olduundan yklenmesi zaman alabilir.)

Elbette bu proje iinde sz konusu olan bir sr bug vardr. rnein, kullanclar herhangibir veri
ieriini tayan Xml dosyalarnda aabilmektedir. Byle bir durumda Sahne isimli windows formu
oluturulmakta ama ierisine hi bir izgi doal olarak gelmemektedir. Pekala okuma srasnda

www.bsenyurt.com Page 1253


SelectNodes metodunun dn deerine gre bir takm kontrol mekanizmalar gelitirilebilir.
Nitekim elde edilen XmlNodeList tipinin eleman says 0 ise bu durumda kalan ilemleri yapmaya
gerek yoktur. Ancak daha gvenli bir yol tercih edilebilir. Bir baka deyile kullancy daha detayl
bir ekilde bilgilendirmek amacyla alacak olan Xml dkmannn bizim standart veri ablonumuza
uygun olup olmad bir Xml Schema dosyas yardmyla kontrol edilebilir.

Xml Schema' larn ynetimli kod tarafnda nasl ele alabileceimize dair daha nceki
bir makalemizden yararlanabilirsiniz.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde XmlDocument tipini farkl bir
ekilde kullanmaya altk. Umarm sizler iin yararl bir deneyim olmutur. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

LINQ: Daha Fazla Sorgu ( 21.02.2007 ) - C# 3.0


Deerli Okurlarm Merhabalar,

Bu gnlerde hepimiz .Net Framework 3.0 ve getirileri zerine younlam durumdayz. zellikle
mimari anlamda yaplan kkl deiimler sz konusu. Bu kkl deiiklikler; Windows
uygulamalarnn yeni yz olan WPF (Windows Presentation Foundation) ve XAML (eXtensible
Application Markup Language), datk mimariyi tek at altnda toplamay baaran WCF (Windows
Communication Foundation), ak emalar ve i srelerinin .Net plaformuna dahil edilmesini
salayan WF(Workflow Foundation) ve CardSpace olarak sralanabilir. Ancak bunlarn dnda
Microsoft' un gelecek vizyonu ierisinde yer alan en nemli konulardan biriside C# 3.0 konusudur.
Bildiiniz gibi C#, sfrdan gelitirilmi ve atas olan nesne ynelimli dillerin en iyi zelliklerini
bnyesinde birletirerek bunu gl bir Framework zerinde kullanabilmemizi salayan bir dildir.
Zaman ierisinde C# 2.0 ile gelen yenilikler u anda tm C# gelitiricilerin hayatnn bir paras
haline gelmitir. imdi herkesin gz C# 3.0 zerinde.

C# 3.0, beraberinde LINQ (Language Integrated Query), DLINQ (Database Language Integrated
Query) ve XLINQ (Xml Language Integrated Query) gibi yeni teknolojileride getirmekte ve
desteklemektedir. Biz bu makalemizde daha fazla LINQ ifadesi yazmaya alacaz. Onbir basit
LINQ ifadesi ile dil tabanl sorgular daha yakndan tanmaya balyacak ve elimizdeki gcn farkna
varacaz. Bildiiniz gibi LINQ (Language Integrated Query) zellikle dil ierisinde, Sql tarz
sorgular yazabilmemizi ve bunlar var olan IEnumerable<T> trevli tipler zerinde
kullanabilmemizi salamaktadr. Ancak zellikle LINQ ierisinde kullanlabilen operatrler gz nne
alndnda, olduka etkili sonular alabileceimiz ortadr. Temel olarak LINQ ierisindeki
operatrler aadaki balklar altnda toplanmtr. (Elbetteki bu bilgiler hala deneme aamasnda
olan bir srece aittir ve deiebilir.)

Kstlama Operatrleri (Restriction Operators) -> Where


Gruplama Operatrleri (Grouping Operators) -> Group
Sralama Operatrleri (Ordering Operators) -> OrderBy, ThenBy, Reverse
Blmleme Operatrleri (Partitioning Operators) -> Take, Skip, TakeWhile, SkipWhile
Seme Operatrleri (Projection Operators) -> Select
Set Operatrleri (Set Operators) -> Distinct, Union, Intersect, Except

www.bsenyurt.com Page 1254


Dntrme Operatrleri (Conversion Operators) -> ToArray, ToList, ToDictionary, OfType
Eleman Operatrleri (Element Operators) -> First, FirstOrDefault, ElementAt
retim Operatrleri (Generation Operators) -> Range, Repeat
Gruplama Fonksiyonu Operatrleri (Aggregate Operators) -> Count, Sum, Min, Max,
Averaga, Fold
lm Operatrleri (Quantifiers Operators) -> Any, All
eitli Operatler (Miscellaneous Operators) -> Concat, EqualAll
zel Seri Operatrleri (Custom Sequence Operators) -> Combine

imdi gelin bu operatrlerin bir ksmn incelemeye alalm. ncesinde program ortamnda ele
alabileceimiz baz veri kmelerine ihtiyacmz olacak. Bu veri kmeleri tamamyla test amal
olacaktr. Bunun iin AdventureWorks veritabannda yer alan Product ve ProductSubCategory
tablolarndan faydalanabiliriz. Amacmz ilk olarak buradaki tablolardan test amacyla
kullanabileceimiz veri kmelerini program ortam ierisinde yer alan generic koleksiyonlara
aktarmaktr. LINQ konusu sz konusu olduu iinde, C# 3.0 dili zelliklerinden de faydalanmaya
alacaz.

Var olan Visual Studio 2005 srmnde LINQ projeleri yazmak ve test edebilmek
iin LINQ Preview proje ablonunu kullanamz gerekmektedir. zellikle C# 3.0 yenilikleri
ile ilikili olarak Sefer Algan' n konu ile ilgili makalesinden faydalanabilirsiniz.

Yardmc snfmzn kodlar aadaki gibidir.

Product Snf;

public class Product


{
public int ProductId;
public string Name;

www.bsenyurt.com Page 1255


public double ListPrice;
public DateTime SellStartDate;
public DateTime SellEndDate;
public int ProductSubCategoryId;

public override string ToString()


{
return ProductId.ToString() + " " + Name + " " + ListPrice.ToString("C2") + " " +
SellStartDate.ToString() + " " + SellEndDate.ToString() + " " + ProductSubCategoryId.ToString();
}
}

ProductSubCategory Snf;

public class ProductSubCategory


{
public int ProductSubCategoryId;
public string Name;

public override string ToString()


{
return ProductSubCategoryId.ToString() + " " + Name;
}
}

Product ve ProductSubCategory snflarmzda dikkat ederseniz zellik (Property) kullanmadk.


Ayrca ierideki elemanlara ilk deerlerini kolayca atayabilmek iin yapc metod (constructor) da
yazmadk. Burada C# 3.0 ile gelen nesne balatclarn (object initializers) kullanacamz iin
zellike ve yapc metod kullanmn terk ettik. imdi bu tiplerden yelere ykleme yapacak olan
Helper snfmzn kodlarnda aadaki gibi gelitirelim.

Helper.cs

public class Helper


{
public static List<Product> UrunleriYukle()
{
List<Product> urunler = new List<Product>();
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("SELECT ProductID, Name, ListPrice,
SellStartDate, SellEndDate, ProductSubcategoryID FROM Production.Product WHERE (Name IS
NOT NULL) AND (ListPrice IS NOT NULL) AND (SellStartDate IS NOT NULL) AND (SellEndDate IS
NOT NULL) AND (ProductSubcategoryID IS NOT NULL)", conn);

conn.Open();
SqlDataReader dr=cmd.ExecuteReader();
while (dr.Read())
{
// Object Initializers kullanarak nesneye ilk deerlerini atyoruz.
Product urn=new
Product{ProductId=Convert.ToInt32(dr["ProductID"]),Name=dr["Name"].ToString(),Li

www.bsenyurt.com Page 1256


stPrice=Convert.ToDouble(dr["ListPrice"]),SellStartDate=Convert.ToDateTime(dr["SellS
tartDate"]),SellEndDate=Convert.ToDateTime(dr["SellEndDate"]),ProductSubCategoryId
=Convert.ToInt32(dr["ProductSubCategoryId"])};
urunler.Add(urn);
}
}
return urunler;
}

public static List<ProductSubCategory> AltKategorileriYukle()


{
List<ProductSubCategory> altKategorileri = new List<ProductSubCategory>();
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("SELECT ProductSubCategoryId,Name From
Production.ProductSubCategory", conn);

conn.Open();
SqlDataReader dr=cmd.ExecuteReader();
while (dr.Read())
{
// Object Initializers kullanarak nesneye ilk deerlerini atyoruz.
ProductSubCategory subCat=new
ProductSubCategory{ProductSubCategoryId=Convert.ToInt32(dr["ProductSubCategoryI
d"]),Name=dr["Name"].ToString()};
altKategorileri.Add(subCat);
}
}
return altKategorileri;
}
}

UrunleriYukle ve AltKategorilerYukle isimli metodlarmz sadece bize yardmc olacak yelerdir.


Dikkat ederseniz her ikiside generic List koleksiyonu tipinden deikenler dndrmektedirler. Biz bu
koleksiyonlar zerinde LINQ sorgularmz denemeye alacaz. Testleri daha kolay yapabilmek
iin imdilik bir Console uygulamasndan devam edeceiz. Dilerseniz snma turlarmzda basit
Select ve Where kullanmlar ile balayalm.

Sorgu 1: rnlerden belirli bir alt kategoride olanlarn bulunmas.

var products = Helper.UrunleriYukle();


var subCategories=Helper.AltKategorileriYukle();

Console.WriteLine("\nProductSubCategoryId' si 1 olan Urunler\n");

var resultSet=from p in products


where p.ProductSubCategoryId==1
select p;

foreach(Product prd in resultSet)


Console.WriteLine(prd.ToString());

www.bsenyurt.com Page 1257


lk olarak kaynak verilerimizi Helper snf ierisine dahil ettiimiz static metodlarmz yardmyla
yklyoruz. (Buradan sonraki rnek kodlarmzda products ve subCategories isimli deikenlerin
tad koleksiyon verilerini kullanacaktr.) Bu ilemler srasndada veri tipini kolayca kullanabilmek
iin var anahtar szcnden faydalanmaktayz. Sorgu ifademiz ierisinde select,
where ve from anahtar szckleri kullanlmaktadr. fademize gre products isimli koleksiyon
ierisindeki her bir nesne rnei p adyla tanmlanmaktadr. Sonrasnda ise bu p adl nesnelerden
ProductSubCategoryId zelliinin deeri 1 olanlarn ekilmesi salanmtr. Dikkat ederseniz, p
nesnesinin iaret ettii tr Product tipi olduu iin p.ProductSubCategoryId gibi bir ifade
yazlabilmitir. Uygulamamz altrdmzda aadaki ekran grntsne benzer bir sonu alrz.

imdi elimizde LINQ gibi bir seenek olmadn dnelim. Bu durumda yukardaki ihtiyac
karlamak iin aadakine benzer bir kod paras yazabilirdik. nce, generic koleksiyon ierisinde
dolar, her bir Product nesnesinin ProductSubCategoryId deerine bakar ve 1 olanlar, baka bir
generic List koleksiyonu ierisinde toplardk.

List<Product> urunler = new List<Product>();

foreach (Product prd in products)


if (prd.ProductSubCategoryId == 1)
urunler.Add(prd);

Lakin daha karmak sorgulama ifadeleri gz nne alndnda durum dahada zorlaabilir.
mkansz deildir ama daha fazla kod yazmamz, efor sarfetmemizi ve zaman zaman
optimizasyonu zor olacak kodlar retmemize neden olacak durumlarla karlaabiliriz. rnein, Alt
Kategorilerin ve Urunlerin birbirleriyle birletirileceini, birletirilen kme zerinde gruplama
yaplacan ve hatta bu gruplamalara gre toplam fiyat, toplam rn says gibi deerlerin elde
edileceini dnebiliriz. (Bu pek ok Sql programcsna tandk gelecek bir ihtiyatr.) Bu tarz bir
ihtiyac karlayacak kod parasn elbetteki yazabiliriz. Ama LINQ ile bunu ve benzerlerini ok daha
basit bir biimde, tek satrlk ifadelerde gerekletirme ansna sahibiz. Dilerseniz yeni rnekler ile
altrmalarmza devam edelim.

Sorgu 2: Liste fiyat 3000 birimin zerinde olan rnleri isimlerine gre tersten sral
olacak ekilde elde etmek.

var resultSet2=from p in products


where p.ListPrice>=3000
orderby p.Name descending

www.bsenyurt.com Page 1258


select p;

Console.WriteLine("\nFiyat 3000' den byk olan Urunler. Name alanna gre tersten sral. \n");

foreach(Product prd in resultSet2)


Console.WriteLine(prd.ToString());

Dikkat ederseniz Liste fiyatna gre kontrol ilemini gerekletirmek iin yine where operatrnden
faydalanyoruz. Sralamay Product tipindenki Name alanna gre tersten sralatmak istediimiz
iinde, orderby ve descending anahtar szcklerinden faydalanmaktayz. Kodu bu ekilde
denediimizde aadaki gibi bir ekran ktsn elde ederiz.

Sorgu 3: Fiyat 1000 ile 1500 birim arasnda olan rnleri isimlerine gre tersten
sralayarak elde etmek.

Console.WriteLine("\nFiyat 1000 ile 1500 arasnda olan rnlerin Name alanna gre tersten
sralanm listesi\n");

var resultSet3=from p in products


where p.ListPrice>=1000 && p.ListPrice<=1500
orderby p.Name descending
select p;

foreach(Product prd in resultSet3)


Console.WriteLine(prd.ToString());

Sorgu 2' dekine benzer ekilde yazlan bu kod parasnda tek fark && (ve) operatrnn
kullanlmasdr. Kod altrldnda aadaki ekran grntsndekine benzer bir sonu elde ederiz.
Bu seferki sorgu cmlemiz ListPrice alan iin bir deer aral belirlemekte ve bu kritere uyan tm
rnleri elde etmemizi salamaktadr.

www.bsenyurt.com Page 1259


Sorgu 4: Urunler listesindeki elemanlar elde ederken isimsiz bir tipten yararlanmak.

C# 3.0 beraberinde isimsiz tip (Anonymous Type) ad verilen yeni bir kavram ile birlikte
gelmektedir. Diyelim ki LINQ ifadesi sonrasda ekilen veri kmesi ierisindeki elemanlar tayan
yeni bir tipi kullanmak istemi olalm. ok doal olarak, sorgulamak istediimiz veri kmesi ne
olursa olsun, nceden planlamadmz ekilde bir tipe ihtiyacmz olmas doaldr. te isimsiz tip
bize bu konuda yardmc olabilmektedir. rneimizde bunun basit bir kullanm gsterilmektedir.
Dikkat ederseniz, Product tipine ait Name ve ListPrice alanlarn srasyla UrunAdi ve Fiyat olarak
tayan yeni bir tip tanmlanm ve foreach iterasyonu ierisinde kullanlmtr. (simsiz tipler
aslnda tanmlandklar yerde oluturulan tipler olarak da dnlebilir. Dolaysyla proje
derlendiinde aada karlalan satr iin yeni bir tip CIL tarafna yazlmaktadr.)

Console.WriteLine("\nSelect sorgularnda Anonymous Type Kullanm\n");

var resultSet4=from p in products


select new {UrunAdi=p.Name,Fiyat=p.ListPrice.ToString("C2")};

foreach(var prd in resultSet4)


Console.WriteLine(prd.UrunAdi+" "+prd.Fiyat);

rneimizi altrdmzda aadakine benzer bir sonu elde ederiz.

Sorgu 5: Sql' de Join sorgusu olurda LINQ ierisinde olmaz m?

Hepimiz Sql tarafnda farkl tablolar birletirmek iin Join ifadelerinden faydalanrz,
faydalanmaktayz. Ayn zellik LINQ ile, .Net platformuna da tanmtr. te aada rnek bir
sorgu. Bu sorguda products ve subCategories isimli deikenlerde tutulan koleksiyonlarn ierdikleri
verileri ProductSubCategoryId alanlarnn deerlerine gre birletiriyoruz. Elde edilen sonu
kmesinde, her iki koleksiyonda da var olan zelliklerden kombine edilecek yeni bir tip olsa hi de
fena olmaz aslnda. te isimsiz tipimizin devreye girecei yer buras olacaktr. (Bu tip bir ihtiyac
birde LINQ eklentilerini kullanmadan yapmay denersek, sorgu ifadelerinin gelecekte hayatmz
olduka kolaylatracan daha kolay anlayabiliriz.) Birletirme operasyonu iin join anahtar

www.bsenyurt.com Page 1260


kelimesinden yararlanlmaktadr. on anahtar kelimesinden sonra ise bildiimiz kriter uygulamas
gerekletirilmektedir.

var resultSet6=from prd in products


join ctg in subCategories
on prd.ProductSubCategoryId equals ctg.ProductSubCategoryId
select new{prd.ProductId,prd.Name,prd.ListPrice};

foreach(var p in resultSet6)
Console.WriteLine(p.ToString());

Programmzn ekran kts aadakine benzer olacaktr.

Ekrandaki kt tesadf deildir. simsiz tiplerin ToString metodunun bir sonucudur.

Bir isimsiz tip tanmlandnda bu tip iin CIL tarafna eklenen kodlar ierisinde ToString
metodu ezilip yukardakine benzer bir string dndrmesi salanmtr. Bu kodu
herhangibir decompiler arac ile atnzda da grebilirisiniz.

Sorgu 6: Urunler listesini alt kategorilere gre gruplamak, her bir gruptaki toplam rn
says, ortalama, en yksek, en dk fiyatlar bulmak.

www.bsenyurt.com Page 1261


Byle bir sorgu iin ncelikle rnleri, alt kategorilerine gre gruplamamz gerekmektedir. Sonra
gruplanan veri kmesi zerinde baz gruplama fonksiyonlarn kullanmalyz. Bu cmleleri
sarfettike aslnda bir T-Sql sorgusunu ifade etmeye altm dnyorum. Ama artk Sql deil
LINQ tarafnda ve daha tandk topraklardayz. yleyse hi vakit kaybetmeden rnek kodumuzu
aadaki gibi gelitirelim.

var result7=from prd in products


group prd by prd.ProductSubCategoryId into g
orderby g.Key
select new{
Kategori=g.Key
,UrunSayisi=g.Count()
,ToplamFiyat=g.Sum(prd=>prd.ListPrice)
,EnDusuk=g.Min(prd=>prd.ListPrice)
,EnYuksek=g.Max(prd=>prd.ListPrice)
,OrtalamaFiyat=g.Average(prd=>prd.ListPrice)
};
foreach(var result in result7)
{
Console.WriteLine("Kategori Id {0}",result.Kategori.ToString());
Console.WriteLine("\t Toplam rn Says {0}",result.UrunSayisi.ToString());
Console.WriteLine("\t Toplam Birim Fiyat {0}",result.ToplamFiyat.ToString("C2"));
Console.WriteLine("\t En Dk Birim Fiyat {0}",result.EnDusuk.ToString("C2"));
Console.WriteLine("\t En Yksek Birim Fiyat {0}",result.EnYuksek.ToString("C2"));
Console.WriteLine("\t Ortalama Fiyat {0}",result.OrtalamaFiyat.ToString("C2"));
Console.WriteLine();
}

lk olarak group anahtar szcn kullanarak products ierisindeki Product tiplerini


ProductSubCategoryId alanlarna gre gruplayacamz ve grupladmz verileri g takma isimli tip
ierisinde saklayacamz belirtiyoruz. Hatta elde edilen sonu kmesini, grupladmz verilerin
Key zelliine gre (ki burada Key zellii ProductSubCategoryId alannn deerini iaret
etmektedir) sralatmaktayz. Sralatma ilemi iin bildiimiz orderby anahtar kelimesinden
faydalanyoruz. Sonrasnda ise yine bir isimsiz tip karmza kyor ki sonu kmesinde retilen
satrlar farkl bir nesne rnei olarak kullanabilmek iin tam aradmz yap.

Burada dikkate deer baz noktalar da vardr. zellikle gruplama fonksiyonlarnn nasl
kullanldna dikkat edelim. Burada => gibi bir operatrle karlamaktayz. Bu
operatr Lambda operatr olarak adlandrlan ve C# 3.0 ile birlikte gelen bir yeniliktir. Gruplama
fonksiyonlar aslnda, elde edilen kme ierisindeki elemanlar dolap bunlar zerinde gerekli
fonksiyonlar altracak ekilde tasarlanmlardr. rnein g.Sum(prd=>prd.ListPrice) ars,
sonu kmesindeki prd takma isimli her bir Product tipini dolap ListPrice alanlarn toplayarak bir
sonu retmek zere tasarlanmtr. Dier gruplama fonksiyonlarda buna benzer ekilde
almaktadr. Sonu olarak rnek kodumuz altrdmzda aadakine benzer bir ekran kts
elde ederiz.

www.bsenyurt.com Page 1262


Sorgu 7: Urunler ierisinde ba harfi H olanlarn liste fiyatna gre tersten sralanm
halini seip bir diziye tamak.

Sanrm, LINQ ifadeleri sonras elde edilen sonu kmelerini ie yarayabilecek baka tipte nesnelere
aktarabilmek olduka ie yarar bir fonksiyonellik olurdu. LINQ bu amala elde edilen sonularn bir
diziye (Array), List veya Dictionary koleksiyonlarna aktarlmasn salayan fonksiyonelliklerde
iermektedir. rnein aadaki kod paras, products koleksiyonunda ba harif H olan rnlerin
liste fiyatna gre tersten srlanm halinin bir diziye aktarlmasn salamaktadr. Ba harfe gre
karlatrma yapabilmek iin indeksleyici operatrn Name alan zerinde nasl kullandmza
dikkat edelim. Sonuta Name alan string tipte bir deikendir ve bir karakter dizisini iaret
etmektedir. Bu nedenle C# dilinin tm srmlerinden bildiimiz gibi 0 indisli eleman aslnda Name
alannn iaret ettii verinin birinci karakteri olacaktr.

var result8=from prd in products


where prd.Name[0]=='H'
orderby prd.ListPrice descending
select prd;

var result9=result8.ToArray();

for(int i=0;i<result9.Length;i++)
Console.WriteLine(result9[i].ToString());

Burada barol oyuncumuz ToArray metodudur. ToArray metodu, elde edilen sonu kmesinin bir
diziye aktarlmasn salar. Bylece sonu kmesindeki elemanlara indeks numaralar yardmyla
erimemizde mmkn olmaktadr. Dier taraftan bir dizinin sunaca avantajlar deerlendirme
ansnada sahip olabiliriz. Ayn ilemleri LINQ olmadan yapmaya alrsak, yukardaki kod
parasna dair yzmzde bir tebessm olumamas iin hi bir neden kalmayacaktr. Uygulamann
almasnn sonucunda aadakine benzer bir ekran grnts elde ederiz.

www.bsenyurt.com Page 1263


Sorgu 8: Join ile birletirilmi bir sorgu sonucunu generic Dictionary koleksiyonuna
aktarmak.

Join sorgusu ile urunler ve altKategorileri birletirdiimizi dnelim. Bu sonu kmesinde


ProductSubCategoryId alan Key ve Product nesne rnekleride Value olacak ekilde
birDictionary koleksiyonu olduka iimize yarayabilir. Bildiiniz gibi Dictionary bazl koleksiyonlar
(Hashtable<>, Dictionary<>, Hashtable vb...) verileri key-value iftleri eklinde tutmaktadrlar.
Dolaysyla zellikle birletirilmi veri kmelerinde elde edilen verileri key ve value olacak ekilde
tutmak ie yarayabilir. Bunu gerekletirmek iin aadaki gibi bir kod parasn kullanabiliriz.

var result11=from prd in products


join ktg in subCategories
on prd.ProductSubCategoryId equals ktg.ProductSubCategoryId
select new {Kategori=ktg.Name,Urun=prd};

var result12=result11.ToDictionary(ktgName=>ktgName.Urun.ProductId);

IEnumerator<int> numerator=result12.Keys.GetEnumerator();
while(numerator.MoveNext())
{
var currentProduct=result12[numerator.Current];
Console.WriteLine(currentProduct.Urun.ProductId.ToString()+"
"+currentProduct.Urun.Name+" "+currentProduct.Urun.ListPrice.ToString("C2")+"
"+currentProduct.Kategori);
}

Bu sefer barol oyuncumuz ToDictionary metodudur. Yanlz metodumuz parametresine dikkat


edelim. Burada ktgName adyla her bir urunun ProductId deerleri alnmakta ve Dictionary bazl
koleksiyonun ierisindeki anahtarlara (key) atanmaktadr. Deer (Value) ksmnda ise sorgu sonucu
elde edilen tipler yani Kategori ve Urun alanlarndan oluan isimsiz tiplerimiz eklenmektedir. Son
olarak test amacyla elde edilen Dictionary koleksiyonu ierisindeki anahtarlarda bir numarator
yardmyla dolalmaktadr. Burada bildiimiz ileri ynl iterasyon deseni uygulanmaktadr. Aslnda
uygulamay debug edersek ve result12 deikenine QuickWatch penceresinden bakarsak, sorgu
sonularnn gerektende key-value iftleri eklinde eklendii generic bir Dictionary koleksiyonu ile
karlam oluruz.

www.bsenyurt.com Page 1264


Uygulamamz altrdmzda ise aadakine benzer bir kt elde ederiz.

Sonu kmelerini Dictionary koleksiyonlarna nasl alabiliyorsak List tipinden generic


koleksiyonlarada alabiliriz. Tek yaplmas gereken barol oyuncusunu deitirmek olacaktr. Yani
ToDictionary yerine ToList metodunu kullanamak.

Sorgu 9: rnler ierisinde ka farkl liste fiyat olduunu bulup bunlar kkten bye
doru elde etmek.

Eminimki Sql bilen herkes bu i iin distinct operatrnn kullanlmas gerektiini syleyecektir.
Ayn operatr LINQ ierisinde yer almaktadr. rnein, rnlerin tutulduu koleksiyon ierisindeki
liste fiyatlarn tekrarsz olarak elde etmek istediimizi dnecek olursak aadaki kod
parasndan faydalanabiliriz.

var result13=(from prd in products


orderby prd.ListPrice
select prd.ListPrice).Distinct();

foreach(var result in result13)


Console.WriteLine(result.ToString());

Dikkat ederseniz Distinct metodunu kullanmadan nce, tm LINQ ifadesi paranetez ierisine
alnmtr. Nitekim Distinct operasyonu elde edilen sonu kmesi zerinden uygulanmaktadr.
Kodun almas sonucu programn kts aadaki ekran grntsndekine benzer olacaktr.

www.bsenyurt.com Page 1265


Sorgu 10: rnleri nce adlarna gre kkten bye sonrada liste fiyatlarna gre
bykten ke sralatarak elde etme.

Tipik olarak bahsettiimiz, birden fazla alan zerinde Order By ilemini uygulamaktan baka bir ey
deildir. Bunu gerekletirmek iin, LINQ ifadelerinde orderby operatrnden faydalanabiliriz.
Aadaki kod paras bu ilemi gerekletirmektedir.

var result17=from prd in products


orderby prd.Name,prd.ListPrice descending
select prd;

foreach(var result in result17)


Console.WriteLine(result.ToString());

Dikkat ederseniz orderby anahtar kelimesinden sonra, sralama iin ele alnacak alanlar virgl ile
ayrlarak yazlmtr. Bununla birlikte liste fiyatna gre tersten sralatma yaptrmak istediimiz
iin descending anahtar szcnden yararlanlmtr. zellikle kendi gelitirdiimiz tipleri bir
koleksiyonda kullandmzda ve bu koleksiyon ierisindeki elemanlar sralatmak istediimizde,
genellikle IComparer yada IComparable gibi arayzlerin ilgili snflara uygulanmasn salamamz
gerekir. Oysaki LINQ ile bu tarz bir ihtiya ok daha kolay bir ekilde ele alnabilmektedir. Program
altrdmzda aadakine benzer bir ekran kts elde ederiz. Dikkat ederseniz her rn
alfabetik olarak sraya dizildikten sonra her rn iin ilk harflerine gre kendi ierisinde liste
fiyatna gre tersten sralanmtr.

Sorgu 11: rnlerin isimlerini karakter uzunluklarna gre tersten sralayarak elde etme.

Bu olduka enteresan olacak. products koleksiyonu ierisindeki her bir Product tipinin Name
alanlarn ele alacaz. Bunlarn karakter uzunluklarna gre tersten sralatacaz. te bu elenceli

www.bsenyurt.com Page 1266


sorgunun LINQ karl.

var result18=from prd in products


orderby prd.Name.Length descending
select new{UrunAdi=prd.Name,ListeFiyati=prd.ListPrice};

foreach(var result in result18)


Console.WriteLine(result.UrunAdi);

Dikkat ederseniz tek yaptmz orderby anahtar kelimesinden sonra prd rneklerinin Name
alanlarnn Length zelliklerini ele almak. descending anahtar kelimeside tersten sralatma
ileminin gerekletirilmesini salyor. Kodu altrdmzda gerektende isimlerin uzunluklarna
gre azalan bir formasyonda sralandn grebiliriz.

Bu makalemizde 11 deiik sorguda LINQ' yu daha yakndan tanmaya altk. Makalemizin


banda belirttiimiz gibi LINQ ierisinde olduka fazla sayda operatr yer almaktadr. Anders
Hejlsberg, LINQ teknolojilsini zellikle veritaban programcl yapanlarn dil ierisindede ayn
felsefeyi kullanabilmeleri iin gelitirildiini belirtmitir. Gerektende yukardaki dil ii sorgular buna
verilebecek rneklerden sadece bir kadr. lerleyen makalelerimizin birisinde dier operatrleride
ele almaya alacaz. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

lk Bakta WCF ( 14.02.2007 ) - WCF


Deerli Okurlarm Merhabalar,

Bildiiniz gibi bir sre nce Microsoft .Net Framework' un 3.0 srmnn son halini yaynlad.
Framework 3.0 beraberinde kkl ve gl mimari modeller ile birlikte geldi. Aslnda Framework

www.bsenyurt.com Page 1267


3.0, Framework 2.0 zerine gelen yeni eklentiler ile olumutur. Bu eklentiler, Windows
Presentation Foundation (WPF), Work Flow Foundation (WF), CardSpace ve Windows
Communication Foundation (WCF) dr. Biz bu makalemizde WCF' ok yzeysel olarak anlamaya
balayacak ve konu ile ilikili basit bir rnek gelitirmeye alacaz.

WCF, hzl bir ekilde servis ynelimli mimariyi baz alan uygulamalar yazabilmek iin
gelitirilmi, birletirilmi bir Framework API' si olarak dnlebilir.

WCF aslnda datk mimarinin .Net Framework 3.0 ile gelen yeni hali olarak dnlebilir.
Microsoft, bu gne kadar datk mimari uygulamalarnn (Distributed Applications) gelitirilebilmesi
iin COM+, .Net Remoting, XML Web Servisleri, MSMQ gibi sistemleri gelitirmitir. WCF, temel
olarak bu sistemlerin tamamnn yeteneklerini bnyesinde barndran ve tam SOA (Service Oriented
Architecture - Servis Ynelimli Mimari) destei salayan gl bir Framework API' si olarak
tanmlanabilir. Aslnda ilk zamanlarda fonksiyonel programlamadan nesne tabanl programlamaya
(Object Oriented Architecture) geilmitir. Sonrasnda bu modeli nesnelerin bileen haline
getirilebilmesi sayesinden, bileen ynelimli mimari (Component Oriented Architecture) izlemitir.
Son olarak da , servis ynelimli mimariyi (SOA) kullanlmaya balanmtr. te WCF, SOA
mimarisine tam ve yksek seviyede destek veren bir API olarak karmza kmaktadr.

Temel olarak WCF, servis ynelimli mimariyi dorudan desteklemekte ve iki nemli zellik
iermektedir. Bunlardan birisi, zellikle Microsoft kanadndaki servislerin, farkl platformlar
tarafndan ele alnabilmesidir(Interoperability). Bylece, karmak .Net tiplerini zel olarak Java,
Com gibi modelleri destekleyen eitli tipteki platformlara yayabiliriz. Dolaysyla Linux, Unix vb
sistemler servislerimizin birer potansiyel tketicisi olabilirler. kinci nemli zellik ise, windows
tarafndaki eitli datk mimari modeller arasndaki entegrasyonun tek bir at altnda
toplanabilmesinin salanm olmasdr(Integration). Bu iki zelliin yan sra WCF, CLR (Comman
Language Runtime) tiplerini birer servis olarak sunabilmemizi ve hatta servisleride birer CLR
tipiymi gibi ele alabilmemizi salayan bir mimari salamaktadr. Aadaki ekil, WCF' nn
salad mimari yaklam aklamaya almaktadr.

www.bsenyurt.com Page 1268


Dikkat ederseniz servise,

Ayn makine ierisinde ayn srete (process) yer alan farkl bir uygulama alan (application
domain) zerinden,
Ayn makinede yer alan farkl bir sre (process) ierisindeki farkl bir uygulama alan
(application domain) zerinden,
Farkl bir makinedeki bir sre (process) ierisinde yer alan farkl bir uygulama alan
(application domain) zerinden,

eriebiliriz. stemciler hangi uygulama alan (Application Domain) ierisinde olurlarsa olsunlar,
servis ile olan iletiimlerini bir proxy nesnesi zerinden salamak zorundadr. Bununla birlikte proxy
nesneleri zerinden giden mesajlar servis tarafnda bir endPoint zerinden geerler. Benzer ekilde
servis tarafndan istemcilere giden mesajlarda bu endPoint zerinden karlar. Bu resim aslnda
bildiimiz datk mimari modelin WCF tarafndan bir grndr.

ngilizce baz kaynaklarda, WCF' nn ABC' sinden bahsedilmektedir. Burada ABC aslnda Addresses
(Adresler), Bindings (Balayclar) ve Contracts (Szlemeler) kelimelerinin ba harfleridir. Bu
leme, WCF' nn ekirdeinde yer alan en nemli kavramlardr. yleki, datk modele gre servis
olarak d ortama sunulan her bir CLR tipi iin bir endPoint tanmlanr. Tanmlanmak zorundadr.
Aslnda endPoint bir servisin d ortama sunulan arayz (Interface) olarak dnlebilir. Yani
istemcilerin, proxy zerinden gnderecekleri ve alacaklar mesajlarn servis tarafnda karland
nokta olarak dnlebilir. Bir endPoint ierisinde nemli para vardr.

www.bsenyurt.com Page 1269


Dilerseniz bu kavramlar ksaca anlamaya alalm.

Servis Adresleri (Service Addresses)

WCF' a gre, hizmette bulunan her servis benzersiz bir adrese sahip olmaldr. Genellikle bir servis
adresi, servisin yeri (service location) ve tama protokol (transport protocol) bilgilerinden oluur.
Aslnda servis yerinden kast,

Bilgisayarn ad,
Site ad,
Network ad,
letiim portu ad,
Pipe ad,
Queue ad,
Belirli bir path bilgisi,
URI ad

olabilir. Tama protokollerimiz ise,

HTTP,
TCP,
P2P (Peer To Peer),
IPC (Inter-Process Communication),
MSMQ (Microsoft Message Queuing),

olabilir. Bu bilgiler nda rnek servis adresi ablonu aadaki gibi olacaktr.

[tama protokol(transport protocol)]://[makine ad]:[opsiyonel port numaras]/[opsiyonel URI


bilgisi]

Aada bu desene uygun bir ka rnek servis ad yer almaktadr. Buradaki desenler zellike .Net
Remoting ve Xml Web Servisleri zerinde gelitirme yapanlarada tandk gelecektir.

net.tcp://localhost:4578/MatSrv
net.msmq://localhost:6789/MatSrv
http://localhost:9001/MatSrv

Szlemeler (Contracts)

www.bsenyurt.com Page 1270


Temel olarak bir servisin ne i yaptnn bilinmesi nemlidir. Bu zellikle, istemcilerin ihtiya
duyduu proxy snflarnn yazlmasnda nem arz eden bir konudur. Bu nedenle WCF' da tm
servisler d ortama bir szleme (Contract) sunmaktadrlar. Genel olarak drt szleme tipi vardr.

Servis Szlemesi (Service Contract): Servis zerinden hangi operasyonlar


gerekletirebileceimizi tanmlayan szleme eididir.
Veri Szlemesi (Data Contract) : Servislerden istemcilere giden ve istemcilerden
servise gelen veri tiplerini tanmlayan szleme eididir. Int gibi bilinen tipler iin bu
szlemeler bilinsiz(implicit) olarak hazrlanr. Ancak karmak tiplerde ve zellikle kendi
tiplerimizde ak (explicit) bir ekilde tanmlanmalar gerekir. te bu sayede, Java gibi
platformlar ile konuabiliriz. Nitekim onlarn anlayaca ekilde bir veri szlemesini d
ortama sunma ansmz artk vardr.
Hata Szlemesi (Fault Contract): Servis tarafndan hangi hatalarn frlatlabileceini ve
bunlarn istemciye nasl aktarlacan tanmlayan szleme eididir.
Mesaj Szlemesi (Message Contract): Servislerin mesajlar ile etkileimde bulunmasn
salayan szleme eidir.

Genellikle servisler bir szleme tanmlamak


iin ServiceContract ve OperationContract niteliklerini kullanrlar. Daha sonra gelitireceimiz
ilk rnekte bu niteliklere tekrardan deineceiz. Temel olarak bir tipin servis olarak sunulabileceini
belirtmek iin ServiceContract nitelii kullanlr. Servis ierisinde sunulabilecek metodlar ise
OperationContract ad verilen nitelikler ile iaretlenirler. Bu aslnda WCF' nn baka bir zelliidir.
Nitelik tabanl (Attribute Based) programlama.

WCF uygulamalarn gelitirebilmek iin gereken temel tipler, Framework 3.0 ile
gelen System.ServiceModel.dll, System.IdentityModel.dll,
System.Runtime.Serialization.dllvb... Assembly' lar ierisinde yer alrlar. Bu nedenle
bu Assembly' lar gerektiinde kullanabilmek iin projelere aka referans etmemiz
gerekmektedir.

Balayclar (Bindings)

Balayclar temel olarak servisler ile nasl iletiim kurulacan tanmlamak zere kullanlrlar.
Aslnda bir balayc tip (Binding Type) tama tipi (transport type), protokol(protocol) ve veri
zmlemesi(data encoding) bildirir. Bunlar aslnda servis ynelimli mimari modelde kullanlabilen
senaryolar gz nne alnarak oluurlar. Bu sebepten dolayda WCF, bu nceden bilinen senaryolar
kullanabilmek iin gerekli balayc tipleri nceden bildirmitir. Bu tipler aadaki tabloda yer ald
gibidir.

Tama Veri Platform


Konfigurasyon eidi zmlemesi Destei
Binding Tipi
Elementi (Transport (Data (Inter
Type) Encoding) operatbility)

HTTP /
BasicHttpBinding <basicHttpBinding> Text Var
HTTPS

NetTcpBinding <netTcpBinding> TCP Binary Yok

NetPeerTcpBinding <netPeerTcpBinding> P2P Binary Yok

NetNamedPipeBinding <netNamedPipeBinding> IPC Binary Yok

WSHttpBinding <wsHttpBinding> HTTP/HTTPS Text/MTOM Var

WSFederationBinding <wsFederationHttpBinding> HTTP/HTTPS Text/MTOM Var

NetMsmqBinding <netMsmqBinding> MSMQ Binary Yok

www.bsenyurt.com Page 1271


MsmqIntegrationBinding <msmqIntegrationBinding> MSMQ Binary Var

WSDualHttpBinding <wsDualHttpBinding> HTTP Text/MTOM Var

Buradaki tiplerden hangisini seeceimiz, gelitireceimiz SOA (Service Oriented Architecture)


modelindeki ihtiyalarmz dorultusunda belirlenebilirler. Dikkat ederseniz her balayc tipin
interoperability destei bulunmamaktadr. Bazlar daha yksek performans salayacak ekilde
Binary veri zmlemesini ele alr. Ama kimiside IIS gibi ortamlar zerinden internete alabilecek
protokol desteini sunar. te bu tip kriterlere gre uygun olan balayc tipler seilebilir. Elbette
istersek buradaki tipler dndan kendi balayclarmz da yazma ansna sahibiz. Ancak bahsi
geen tipler hemen hemen her datk uygulama senaryosu gz nne alnarak
tasarlanmtr.Bylece WCF' n ABC' sine ok ksada olsa deinmi olduk.

Gelelim WCF servislerini nerelerde barndrabileceimize. Sonu itibariyle yazlan servileslerin


mutlaka bir windows sreci (Windows Process) zerinden sunulmas gerekmektedir. Artk temel
olarak iki farkl barndrma (Hosting) seeneimiz vardr. IIS Hosting ve Self Hosting. IIS
Hosting sisteminde, gelitirilen servislerin IIS zerinde barndrlmas amalanr. Doal olarak
servisler, web zerinden hizmet verilebilmektedir. Self Hosting modeli ise kendi ierisinde drde
ayrlmaktadr. Windows Aktivasyon Servisi (Windows Activation Service), Windows Servisi, Konsol
uygulamas, Windows Uygulamas.

Windows Aktivasyon Servisi (Windows Activation Service), Vista ile birlikte gelen bir uygulama
eididir. zetle Http destei olmayan host uygulamalar iin IIS benzeri bir ilevsellii salamakla
ykmldr. Dierleri ise zellike .Net Remoting' den aina olduumuz host uygulama tipleridir.
Elbette servislerin hizmet verebilmesi iin host edilmeleri arttr. Bu da servisi sunan uygulamann
srekli alr olmasn gerektirir. Nitekim uygulama almad takdirde istemcilere hizmet
veremez. Buraya kadar anlatklarmzdan yola kacak olursak, WCF cephesinden bir servis
ynelimli sistem iin u admlar takip etmemiz yeterli olacaktr.

Servise ait szlemeyi barndran ve asl fonksiyonelleri ieren bir assembly gelitirilir.
Servisi istemcilere sunacak olan bir host uygulama gelitirilir.
stemcilerin sz konusu servisi kullanabilmeleri iin gerekli olan proxy snf retilir.
stemci uygulama gelitirilir.

www.bsenyurt.com Page 1272


Bu admlar srasnda zellikle servis tarafnda ve istemci tarafnda gereken bir takm ayarlamalar
iin konfigurasyon dosyalarndan faydalanabilir yada programatik olarak gerekli hazrlklarn
yaplmasn salayabiliriz.

Dilerseniz basit bir rnek zerinden hareket ederek rnek bir WCF sistemi gelitirmeye alalm.
lk olarak bir Class Library projesi gelitireceiz. Projemiz ierisinde servis szlemesi roln
stlenecek bir arayz(interface) tipi ve bu arayz tipini uygulayan bir snfmz olacak. WCF' da,
servis szlemlerinin tanmlanmas iin ServiceContractve OperationContract niteliklerinin
kullanlmasn gerekir. Daha nceden de belirttiimiz gibi bu
nitelikler(attributes) System.ServiceModel isim alan (namespace) altnda yer almaktadr. Bu
nedenle ilk olarak projemize bu referans aadaki gibi eklememiz gerekir.

WCF uygulamalarn Visual Studio 2005 zerinde daha kolay gelitirmek iin gerekli
extension' lar yklememiz gerekir. Bu extension' lar yklendii takdirde, proje ablonlar
arasna WCF Service Library seeneide gelecektir. Bu proje ablonu, servis
szlemesinide uygulayan ve n bilgiler veren hazr bir rnek ktphane retmektedir.

imdi snf ktphanemizin ierisine aadaki tipleri ekleyelim.

www.bsenyurt.com Page 1273


using System;
using System.ServiceModel;

namespace MatematikServisLib
{
[ServiceContract]
public interface IMatematikServis
{
[OperationContract]
double Toplam(double x, double y);

void DahiliMetod();
}

public class Matematik : IMatematikServis


{
#region IMatematikServis Members

public double Toplam(double x, double y)


{
return x + y;
}

public void DahiliMetod()


{
}

#endregion
}
}

Burada test amacyla DahiliMetod isimli metod iin OperationContract nitelii kullanlmamtr. Bu
sebepten dolay bu metodun bilgisi servis szlemesine dahil edilmeyecektir. Bir baka deyile
istemciler bu metodu hi bir ekilde kullanamayacaktr.

www.bsenyurt.com Page 1274


imdi srada host uygulamasnn gelitirilmesi var. u an iin WCF' a merhaba demek
istediimizden, host uygulamasnda basit bir konsol projesi olarak gelitireceiz. .Net Remoting
mimarisinden de hatrlanaca gibi, genellikle sunucu ve istemci tarafndaki ayarlar konfigurasyon
bazl dosyalarda tutmay tercih ederiz. Bu bize, uygulamay yeniden derlemeden kanal(channel),
port numaras, uzak nesne bilgisi gibi ayarlarn deitirilebilmesi ve kullanlabilmesi imkann
sunmaktadr. Ayn felsefeyi WCF uygulamalarnda da benimsemekte fayda vardr. Bu nedenle, host
uygulamamz iin gerekli baz bilgileri (endPoint gibi) App.config dosyasnda tutmay tercih
edeceiz. Tahmin edeceiniz gibi konfigurasyon dosyas ierisine WCF' nn ABC' sini koymalyz.
Yani adres (address), balayc (binding) ve szleme (contract) bilgilerini dahil ederek gerekli
endPoint tipini tanmlamalyz. Bu amala konsol uygulamamzn konfigurasyon dosyasn aadaki
gibi gelitirelim.

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


<configuration>
<appSettings>
<add key="adres" value="http://localhost:4590/MatSrv"/>
</appSettings>
<system.serviceModel>
<services>
<service name="MatematikServisLib.Matematik">
<endpoint address="http://localhost:4590/MatSrv" binding="basicHttpBinding" con
tract="MatematikServisLib.IMatematikServis"/>
</service>
</services>
</system.serviceModel>
</configuration>

Dilerseniz konfigurasyon dosyasna yazdklarmz inceleyelim. Servisimize ait bir endPoint


tanmlamamz gerekmektedir. EndPoint servisin sunulduu adres bilgisini, balayc tipini ve servis
szlemesini ilgili niteliklerden almaktadr. endPoint elementleri, service elementleri ierisinde
tanmlanr. Bir service elementi ierisine birden fazla endPoint bilgiside konulabilir. Dier tarafan
service elementleride services elementi tarafndan sarmalanmtr. Dolaysyla birden fazla service
elementininde tanmlanabileceini syleyebiliriz.

Peki istemcilere sunmak istediimiz tipi host uygulama ierisinde servise nasl sunacaz? Bu
amala, System.ServiceModel isim alan altnda yer alan ServiceHost snfn kullanmamz
gerekmektedir. Bu snfn temel grevi, parametre olarak ald tipi, yine parametre olarak ald
adres zerinden istemcilere sunmaktr. Dolaysyla konsol uygulamamz ierisindeki Main
metodunda aadaki kodlar yazmamz servisi sunmak iin yeterli olacaktr. Tekrardan
hatrlatalm; Host uygulamann konfigurasyon dosyasndaki adres deerine eriebilmesi
iin System.Configuration.dll, ServiceHost tipini kullanabilmesi iin System.ServiceModel.dll,
Matematik tipini kullanabilmesi iinde MatematikServisLib.dll assembly' larna referansta bulunmas
gerekir.

www.bsenyurt.com Page 1275


Gelelim host uygulama kodlarmza;

using System;
using System.ServiceModel;
using System.Configuration;
using MatematikServisLib;

namespace HostApp
{
class Program
{
static void Main(string[] args)
{
// Servisin sunulaca base address bilgisi konfigurasyon dosyasndan alnr.
Uri adres=new Uri(ConfigurationManager.AppSettings["adres"]);
// Matematik tipi, Uri zerinden host edilmek zere ServiceHost nesne rneine bildirilir.
ServiceHost srv = new ServiceHost(typeof(Matematik), adres);
// Servis alrken alan event metodu
srv.Opening += delegate(object sender, EventArgs e)
{
Console.WriteLine("Servis alyor...");
};
// Servis aldktan sonraki event metodu
srv.Opened += delegate(object sender, EventArgs e)
{
Console.WriteLine("Servis ald...");
};
// Servis kapanrkenki event metodu
srv.Closing += delegate(object sender, EventArgs e)
{
Console.WriteLine("Servis kapanyor...");
};
// Servis kapandndaki event metodu
srv.Closed += delegate(object sender, EventArgs e)
{
Console.WriteLine("Servis kapand...");
};
// Servis alr
srv.Open();
Console.ReadLine();
// Servis kapatlr
srv.Close();
}
}
}

Uygulamamz altrdmzda aadakine benzer bir ekran grnts elde ederiz. Dolaysyla
servisimiz u an iin baarl bir ekilde almaktadr.

www.bsenyurt.com Page 1276


Gelelim istemci tarafna. Yazmzn banda da belirttiimiz gibi, istemcilerin WCF Servislerini
kullanabilmeleri iin proxy snflarna ve gerekli istemci tarafl konfigurasyon ayarlarna ihtiyalar
vardr. ok doal olarak bu snflarn retilebilmesi iin, servise ait bir metadata bilgisinin olmas ve
d ortama sunulmas gerekmektedir. imdi unu deneyelim. Servisimizi host eden uygulamay
altralm ve herhangibir tarayc penceresinden, http://localhost:4590/MatSrv adresini
girelim. (Tarayc penceresinden bu adresi girerken host uygulamann ak olmas arttr.)

Dikkat ederseniz, servis iin metadata yaynlama hizmetinin u an iin geersiz olduu ibaresi
vardr. lgili servisin metadata' sna ulaamadmzdan, istemciler iin gerekli proxy snfn
retemeyiz. zm, konfigurasyon dosyasna behavior tipi eklemektir. Bu tipi Metadata
Exchange (MEX) davrann uygulayacak ekilde aktif etmemiz gerekir. Bunun iin app.config
dosyamz aadaki hale getirmemiz yeterlidir.

www.bsenyurt.com Page 1277


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="adres" value="http://localhost:4590/MatSrv"/>
</appSettings>
<system.serviceModel>
<services>
<service name="MatematikServisLib.Matematik"
behaviorConfiguration="MatematikBehavior">
<endpoint address="http://localhost:4590/MatSrv" binding="basicHttpBinding"
contract="MatematikServisLib.IMatematikServis"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior name="MatematikBehavior">
<serviceMetadata httpGetEnabled="true"/>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>

imdi host uygulamamz tekrar altrr ve tarayc penceresinden servisimizi tekrar talep edersek
aadaki kty elde ederiz.

www.bsenyurt.com Page 1278


Dolaysyla artk servisimize ait metadata d ortama sunulabilir ve http zerinden elde edilebilir
haldedir. Bir baka deyile proxy snfn oluturabilir ve istemcilerin hizmetine sunabiliriz.
Burada, ?wsdl taksnn olduuna da dikkat edelim. Bu bize Xml Web Servislerinden son derece
tandk gelecektir. Bildiiniz gibi WSDL (Web Service Description Language) bir servisin ne yaptn
Xml olarak syleyebilen ktlarn retilmesinde rol almaktadr. Bu yap WCF ierisindede aynen
kullanlabilmektedir.

Artk istemci tarafn kodlayabiliriz. Ama ncesinde proxy snfmz nasl retebileceimize bakalm.
Bunun iin iki yolumuz vardr. Birincisi .Net Framework 3.0 SDK ile gelen komut satr aralarndan
olan svcutil.exe dir. Dieri ise, Visual Studio 2005 ierisinde yer alan Add Service
Reference seeneidir. Biz bu makalemizde svcutil arac ile proxy snfmz nasl yazacamz
inceleyeceiz. Bunun iin Visual Studio 2005 Command Prompt' ta aadaki komut satr ifadesini
altralm. (svcUtil aracnn baarl bir ekilde proxy snfn ve config dosyasn retmesi iin, host
uygulamann alr olduundan emin olun.)

www.bsenyurt.com Page 1279


svcutil http://localhost:4590/MatSrv?wsdl /out:Proxyim.cs /config:app.config

Grdnz gibi Proxyim.cs ve app.config isimli iki dosya retildi. Artk tek yapmamz gereken
bunlar istemci uygulamada kullanmaktr. retilen proxyim.cs dosyas ierisinde aadaki ekilde
grlen tipler yer almaktadr. Dikkat ederseniz servis szlemesine gre uygun bir snf retimi
gerekletirilmitir. Ayrca istemci iin gereken konfigurasyon ayarlarda otomatik olarak app.config
dosyas ierisine dahil edilmitir.

stemci tarafnda kullanacamz tip MatematikServisClient isimli snftr. stemci uygulamamz


aadaki kodlar yazarak test edebiliriz.

www.bsenyurt.com Page 1280


using System;
using System.Collections.Generic;
using System.Text;
using System.ServiceModel;

namespace Istemci
{
class Program
{
static void Main(string[] args)
{
MatematikServisClient mat = new MatematikServisClient();
Console.WriteLine(mat.Toplam(4, 5).ToString());
Console.ReadLine();
}
}
}

Elbetteki istemci uygulamann alabilmesi iin ncesinde host uygulamann alyor olmas
gerekmektedir. Aksi takdirde EndPointNotFoundException tipinden bir istisna alrz. Bu ayn
zamanda gerketende istemcinin bir sunucuya balanmaya altnnda bir ispatdr. Eer nce
sunucuyu sonrada istemciyi altrrsak uygulamann baarl bir ekilde yrdn ve Toplam
metodunun sonucunun elde edildiini rahatlkla grebiliriz.

Bu makalemizde WCF' a ksa bir giri yapmaya altk. Konuyu daha iyi kavrayabilmek iinde basit
bir rnek gelitirdik. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grmek dileiyle hepinize mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Web Server Control Yazmak - 3 ( 05.02.2007 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde kendi web kontrollerimizi gelitirirken durum ynetimi(state management)
iin ViewState' lerden nasl faydalanabileceimizi incelemitik. Bununla birlikte assembly, snf ve

www.bsenyurt.com Page 1281


metod seviyesinde, alma zaman iin gerekli davranlar eitli nitelikler (attribute) yardmyla
nasl etkileyebileceimizi grmtk. Bugnk makalemizde ise, kendi web kontrollerimiz iin olay
gdml (event based) programlamay nasl salayabileceimizi incelemeye alacaz.

Var olan web kontrollerinin pek ok olay vardr. stersek kendi gelitirdiimiz web sunucu
kontrolleri iinde olay tanmlayabilir ve kullanabiliriz. Ne varki web kontrolleri seviyesinde dikkate
alnmas gereken baz noktalar vardr. Bu noktalar yazmzn ilerleyen ksmlarnda kefedeceiz.
ncelikli olarak olay tabanl programlama iin gereken unsurlar biraz hatrlamaya alalm.
Hereyden nce olaylarn(events), temsilciler(delegates) ile yakn ilikisi vardr. Olay gdml
programlama tarafnda temsilcilerin grevi, meydana gelen olay sonrasnda altrlacak olan olay
metodunu iaret etmektir. Var olan Windows ve Web kontrollerinin sahip olduklar olaylar, yine
Framework ierisinde yer alan deiik temsilciler ile ilikilendirilmitir. rnein bir Button bileenine
ait click olay, EventHandler temsilcisi ile ilikilendirilmitir. Temsilciler alma zamannda iaret
edecekleri metodlarn yaplarnda sylemektedirler. Bir baka deyile iaret edilecek metodun
parametrik yaps ve geri dn tipinide belirtirler. zellikle grsel bileenlere bakldnda, olay
metodlarnn ounlukla iki parametre aldn grrz. Bu parametrelerden ilki, olay meydana
getiren nesne referansn tayabilecek object tipindendir. kinci parametre ise, olay meydana
geldiinde, olay metodu ierisine bilgi tamak amacyla kullanlabilecek trden bir tip olabilir.

Bu kriterler gz nne alndnda, kendi web kontrollerimizi gelitirirken Framework ierisinde var
olan temsilcilerden faydalanabiliriz. Ancak zellikle olay metodunun ikinci parametresinin, olay
metodu ierisine bizim istediimiz tarzda bilgiler tamasn istiyorsak, kendi temsilcilerimizi
yazmay tercih edebiliriz. Biz makalemizde kendi temsilci tipimizi kullanacaz. rnein
TarihKontrolum isimli bileenimiz iin TarihDogrula isimli bir olay dnebiliriz. Bu olay meydana
geldii zaman alacak olan olay metodu ikinci parametre olarak, kontrol ierisindeki verilerin
deerlerini alabilir ve ieride ileyebilir. Bu senaryo gz nne alndnda, ncellikli olarak olay
metoduna gelecek bilgileri tayacak bir parametre snf yazmamz muhakkaktr. Bu snf aadaki
gibi gelitirdiimizi dnelim.

public class TarihKontrolumEventDatas


{
#region Fields

private string seciliGun;


private string seciliAy;
private string seciliYil;

#endregion

#region Properties

www.bsenyurt.com Page 1282


public string SeciliYil
{
get { return seciliYil; }
}

public string SeciliAy


{
get { return seciliAy; }
}

public string SeciliGun


{
get { return seciliGun; }
}

#endregion

#region Constructors

public TarihKontrolumEventDatas(string sg, string sa, string sy)


{
seciliGun = sg;
seciliAy = sa;
seciliYil = sy;
}

#endregion
}

TarihKontrolumEventDatas isimli snfn temel grevi, olay metodu ierisine, kontroln ierisindeki
gn, ay ve yl deerlerini tamaktr. Buna gre temsilcimizide (delegate) aadaki gibi
tanmlayabiliriz.

public delegate void TarihDogrulaEventHandler(object


sender,TarihKontrolumEventDatas eData);

Temsilcimiz object ve TarihKontroumEventDatas tipinden parametreler alan ve geriye deer


dndrmeyen metodlar iaret edebilecek ekilde tasarlanmtr. Bu tipik olarak varsaylan olay
temsilcisi desenidir. Artk kontrolmz iin gerekli olan olay (event) tanmlayabilir ve bu olay
tetikletecek ye metodu ekleyebiliriz. Bu amala TarihKontrolumWithEvent isimli yeni kontrolmze
aadaki eklemeleri yapmamz gerekmektedir.

[Description("Tarih bilgisi deitirildiinde dorulamak iin tetiklenen sunucu tarafl olaydr")]


public event TarihDogrulaEventHandler TarihDogrula;

public void OnTarihDogrula(TarihKontrolumEventDatas eData)

www.bsenyurt.com Page 1283


{
if (TarihDogrula != null)
TarihDogrula(this, eData);
}

OnTarihDogrula isimli metodun tek grevi, kontrole yklenmi TarihDogrula isimli bir olay var ise
bu olay armaktr. Bu arda ok doal olarak, olay ile ilikilendirilmi metodun arlmas
anlamna gelmektedir. Bu deiikliklerden sonra kontrolmz herhangibir Asp.Net sayfasna
srkleyip braktmzda, events ksmnda yeni eklediimiz olay grebiliriz.

Her ne kadar kontrolmze bir olay eklemi olsakta, bu olayn gerekletirilmesi iin sayfann
istemciden sunucuya tekrardan gnderilmesi gerekecektir. Bu ii kontrolmz zerinde
gerekletirmek istediimizi dnecek olursak bize submit eyleminde bulunacak bir input Html
kontrol gerekmektedir. Bu sebepten yeni kontrolmzn Render metodu ierisine aadaki Html
ieriini dahil etmemiz uygun olacaktr.

protected override void Render(HtmlTextWriter writer)


{
// Dier kod satrlar
writer.Write("<input type='submit' value='...' name='sbmButton'/>");
base.Render(writer);
}

Artk web sayfamzda yer alan kontrolmz iin TarihKontrol olayn aadaki gibi ykleyebiliriz.

protected
void TarihKontrolumWithEvent1_TarihDogrula(object sender, BenimWebKontrollerim.Tari
hKontrolumEventDatas eData)
{
Response.Write(eData.SeciliGun + " " + eData.SeciliAy + " " + eData.SeciliYil);
}

www.bsenyurt.com Page 1284


imdi bu olay metodu ierisine bir breakpoint koyalm ve web uygulamamz debug mode zerinden
altralm. Kontrolmz ierisinde yer alan submit dmesine bassakta, olay metodumuz ierisine
giremediimizi greceiz. Dolaysyla yazdmz olay metodu hi bir ekilde ilememitir. Bunun iki
nemli nedeni vardr. Bunlardan birincisi, kontrolmz ierisinde postback ilemini gerekletiren
dmenin adnn kontrolmzn benzersiz ad (unique Id) ile ayn olmamasdr. kinci sebep ise,
istemciden postback ile gelecek olan form verileri ierisinden ay, gn ve yil alanlarnn istemci
tarafndan deitirilen deerlerini elde etmek ve eer bir deiiklik varsa ilgili olay metodunu
frlatmak iin gerekli hamleyi yapmaymzdr. Bahsetmi olduumuz ikinci hamle iin,
kontrolmze IPostBackDataHandler arayznn uyarlanmas (implementation) dnlebilir.

Kendi yazdmz web kontrollerinde event, bu event ile ilikili bir delegate, event metodu
ierisine bilgi tayacak bir tip tanmlamak event based bir kontrol iin yeterli deildir.
Kontroldeki bir aksiyon sonucu, istemcideki sayfay sunucuya gnderecek olan bileenin
adnn kontroln ad ile ayn olmas (UniqueId deeri), kontroln post edilen verilerinin
(postBack Datas) alp ilenmesi ve ilgili olay metodunun frlatabilmesi
iin IPostBackDataHandler arayznn uygulanm olmas gerekmektedir. Eer sadece
postback olaylarn frlatmay dnyorsak, yani form verilerini ilemeyi dnmeden
olay frlatmak ile ilgileniyorsak IPostBackEventHandlerarayzn uygulamamz yeterli
olacaktr.

lk yapmamz gereken deiiklik, Render metodu ierisinde aadaki gibi olmaldr. Bu amala
kontrolmz ierisine birde zellik(property) katabiliriz. Bu zellik yanlz okunabilir (ReadOnly)
olarak tasarlanabilir ve grev olarak, o an retilen bileenin UniqueId deerini tayabilir. Aynen
aadaki gibi.

public string SubmitName


{
get { return this.UniqueID; }
}

protected override void Render(HtmlTextWriter writer)


{
// Dier Kodlar
writer.Write("<input type='submit' value='...' name='" + SubmitName + "'/>");
base.Render(writer);
}

imdide kontrolmze IPostBackDataHandler arayzn uygulamalyz. Bu arayz ierisinde iki


nemli metod vardr. LoadPostData ve RaisePostDataChangedEvent. zellikle LoadPostData
metodu sayesinde, istemciden sunucuya gnderilen sayfa ierisindeki form verisini ekebilir ve
kontrolmzn ierisindeki baz alanlarn deerlerini yakalayabiliriz ki buda istediimiz bir
durumdur. (Hatrlaynz, postback nedeni ile kontrol zerinde yaplan deiiklikleri
kaybediyorduk.) LoadPostData metodunun almas sonrasnda eer true deeri retilirse,
RaisePostDataChanged metodu devreye girecektir. Aksi takdirde RaisePostDataChangedEvent
metodu altrlmayacaktr. Buda ilgili olay metodun, kontrol zerindeki form verilerinde deiiklik
olduu zaman tetiklenmesine neden olacaktr ki bu bir avantaj olarak dnlebilir. Ayrca
RaisePostDataChangedEvent metodu, postback sonras kontrole yklenmi olan olay armamzda
da ie yarayacaktr. Buna gre, kontrolmzn bu arayz uygulam olan son hali aadaki gibi
olacaktr.

www.bsenyurt.com Page 1285


public class TarihKontrolumWithEvent : Control,IPostBackDataHandler
{
[Description("Tarih bilgisi deitirildiinde dorulamak iin tetiklenen sunucu tarafl olaydr")]
public event TarihDogrulaEventHandler TarihDogrula;

public void OnTarihDogrula(TarihKontrolumEventDatas eData)


{
if (TarihDogrula != null)
TarihDogrula(this, eData);
}

// GunMetin, AyMetin, YilMetin,SeciliGun,SeciliAy,SeciliYil zellikeri kodun kolay okunmas


amacyla buradan kaldrlmtr. rnek uygulamay indirip bu kodlar da tedarik edebilirsiniz.

public string SubmitName


{
get { return this.UniqueID; }
}
#endregion

protected override void Render(HtmlTextWriter writer)


{
writer.Write("<span id='lblGun'>" + GunMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='"+this.UniqueID+"Gun' id='Gun'>");
for (int i = 1; i <= 31; i++)
{
if (SeciliGun == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" + i.ToString()
+ "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");

www.bsenyurt.com Page 1286


}
writer.Write("</select>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<span id='lblAy'>" + AyMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='"+this.UniqueID+"Ay' id='Ay'>");
for (int i = 1; i <= 12; i++)
{
if (SeciliAy == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" + i.ToString()
+ "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<span id='lblYil'>" + YilMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='"+this.UniqueID+"Yil' id='Yil'>");
for (int i = 1950; i <= 2050; i++)
{
if (SeciliYil == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" + i.ToString()
+ "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("<input type='submit' value='...' name='" + SubmitName + "'/>");
base.Render(writer);
}

#region IPostBackDataHandler Members

public bool LoadPostData(string postDataKey,


System.Collections.Specialized.NameValueCollection postCollection)
{
bool gunDegisti=false, ayDegisti=false, yilDegisti=false;

string seciliGun = postCollection[this.UniqueID+"Gun"];


if (SeciliGun != seciliGun)
{
SeciliGun = seciliGun;
gunDegisti = true;
}
string seciliAy = postCollection[this.UniqueID + "Ay"];
if (SeciliAy != seciliAy)
{
SeciliAy = seciliAy;
ayDegisti = true;
}

string seciliYil = postCollection[this.UniqueID + "Yil"];


if (SeciliYil != seciliYil)
{
SeciliYil = seciliYil;

www.bsenyurt.com Page 1287


yilDegisti = true;
}
return gunDegisti||ayDegisti||yilDegisti;
}

public void RaisePostDataChangedEvent()


{
TarihKontrolumEventDatas tded = new TarihKontrolumEventDatas(SeciliGun,
SeciliAy, SeciliYil);
OnTarihDogrula(tded);
}

#endregion
}

Kontrolmz bu ekilde bir web sayfasnda tekrardan test edelim. Bu kez LoadPostData,
RaisePostDataChangedEvent, OnTarihDogrula ve web sayfamzdaki
TarihKontrolumWithEvent1_TarihDogrula metodlarna birer breakpoint koyarak debug mode
zerinden kontrolmz izlemeye alalm. Kontrol zerindeki submit dmemize bastmzda
sayfa sunucuya geldikten sonra, kontrol ile ilikili olarak ilk LoadPostData metoduna girilecektir.
Burada NameValueCollection tipinden olan postCollection deikeninin ieriine baktmzda
aadaki ekran grntsndekine benzer bir sonu ile karlarz.

Dikkat ederseniz debug modda postCollection isimli deikenin ieriinden, istemci tarafnda
deitirilen Gun, Ay ve Yil deerleri elde edilebilmektedir. Yani istemciden gelen bu kontole ait form
verilerini ekebiliriz.

Dikkat ederseniz Render metodu ierisinde, Select elementlerinin name attribute' larna
deer verirken this.UniqueId zelliinden faydalanmtr. Bunun sonucu olarak istemci
tarafna giden select elementlerinin adlar ierisinde dahil olduklar kontroln unique id
deeride yer alacaktr. Eer bunu yapmassak, ayn web sayfas ierisinde bu
kontrollerden birden fazlasn kullandmzda, LoadPostData metoduna gelen koleksiyon
bilgisinden, hangi kontrol iin hangi deerlerin geldiini ayrtramayz.

LoadPostData metodu ierisinde bir dizi kontrol ilemi yaplmaktadr. Sonu itibariyle form ile gelen
verilerin sayfann ViewState' i ierisinde tutulan verilerden farkl olmamas halinde bou bouna
olay metodunu altrmay istemediimiz iin bu kontroller yaplmaktadr. Ancak Gun, Ay yada Yil
deerlerini tayan select elementlerinden birisinde olacak bir
deiiklik, RaisePostDataChanged metodunun arlmasn da salayacaktr. Debug modda
ilerlediimiz takdirde,(eer kontrol ierisindeki deerlerde deiiklik varsa), RaisePostDataChanged
olay metoduna girilecektir. Sonrasnda ise bu metod ierisinde yaptmz ar sayesinde
OnTarihDogrula metoduna geilecektir. OnTarihDogrula metodu dikkat ederseniz, kontrol iin bir
TarihDogrula olaynn yklenip yklenmediini kontrol etmektedir. Eer ykl ise, (yani sayfa
gelitirici tarafndan kontrole ait bu olay metodu
yazlmsa) TarihKontrolumWithEvent1_TarihDogrula isimli olay metodundaki kodlar
altrlacaktr. Bu kodlarda basit olarak yaplan, olay verilerini alp ekrana bastrmaktr. Bunu test
kodu olarak yazm bulunuyoruz. zetle kontrolmz aadaki gibi alabilecektir.

www.bsenyurt.com Page 1288


Grdnz gibi artk kontrolmzde deiiklikeri alglayabiliyor, bunlar herhangibir olay ierisinde
kullanabiliyoruz. UniqueId zelliinden yararlanmamzn doal sonucu olarak, sayfa zerinde birden
fazla kontrol kullandmz takdirde de sistemin sorunsuz bir ekilde alabileceini grebiliriz.

Baz durumlarda PostBack verilerini ele almak istemiyor olabiliriz. Yani ama sadece istemciden
sunucuya doru olay tetikletmek olabilir. Bu gibi durumlarda ilgili olaylar tetikleyebilmek
iinIPostBackEventHandler arayznden faydalanabiliriz. Bu arayz, uyguland kontrol
ierisinde RaisePostBackEvent metodunun yazlmasn zorlayacaktr. Bu makalemizde
ilediklerimizden yanmza kar kalan unsurlar aadaki tabloda yer almaktadr.

Yanmza Kar Kalanlar

Web kontrollerimize kendi olaylarmz (event) retmek iin kendi temsilcilerimizden faydalanabilir
yada .Net Framework ierisinde var olan olay temsilcilerinden yararlanabiliriz.

Bir web kontrolnde, istemciden sunucuya postback ilemini gerekletirilmesi iin Submit ilemini
stlenen elementin adnn, kontroln UniqueId deeri ile ayn olmas gerekir.

Form zerinden gelen verilerin (form-datas) ele alnabilmesi iin, submit elementinin adnn,
kontroln ad ile ayn olmas yeterli deildir. Bu verileri okuyabilmek ve sonrasnda ilgili olaylar
tetikleyebilmek iin IPostBackDataHandler arayznn , web kontrolne uygulanmas
gerekmektedir.

Sadece olay tetikletmek amacyla, IPostBackEventHandler arayznn ilgili kontrole


uygulanmasda dnlebilir. Elbetteki hem IPostBackDataHandler hemde IPostBackEventHandler
arayzlerinin bir arada uygulanmas daha gl bir web kontrol oluturulmasna neden olacaktr.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

rnek Uygulama in Tklaynz.

www.bsenyurt.com Page 1289


Burak Selim ENYURT
selim@bsenyurt.com

Web Server Control Yazmak - 2 ( 23.01.2007 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde web sunucu kontrollerini nasl gelitireceimizi incelemeye balamtk. Bu
gnk makalemizde, ViewState' lerin web sunucu kontrollerinde nasl ele alnabileceinden ve
kontrollerin tasarm zamanndaki (design time) yeteneklerinin nitelikler (attributes) yardmyla nasl
arttrlabileceinden bahsetmeye alacaz.

Herhangibir web sunucu kontrolnn (web server control) baz zellikleri (properties) sayfa
retilirken belirlenmek (set) istenebilir. Bu ilem iin sayfann Page_Load olay (event) metodu
ideal bir noktadr. Hatta burada sayfann Postback edilip edilmedii kontrol edilerek, zelliklerin
sadece sayfann ilk ykleniinde belirlenmesi salanabilir. Ancak burada ViewState kullanlmad
takdirde karlalabilecek nemli bir problem vardr. Bu problemi analiz edebilmek iin, bir nceki
makalemizde gelitirdiimiz TarihKontrolum isimli bileenimize yeni zellik daha ekleyerek
analizimize balayalm. Bu zellikler ile liste kutularndaki gn, ay, yl bilgilerinin deerlerini
deitirmeyi ve elde etmeyi hedeflemekteyiz.

private string _seciliGun;


private string _seciliAy;
private string _seciliYil;

public string SeciliGun


{
get{return _seciliGun;}
set { _seciliGun = value; }
}

public string SeciliAy


{
get{return _seciliAy;}
set { _seciliAy= value; }
}

public string SeciliYil


{
get{ return _seciliYil; }
set { _seciliYil= value; }
}

ok doal olarak web sunucu kontrolmze ilikin Render metodu ierisinde de baz deiiklikler
yapmalyz. Nitekim sayfa yklenirken belirlenen gn, ay ve yl deerlerinin, render edilen HTML
ieriine selected nitelii olarak aktarlmas gerekmektedir. Bu nedenle Render metodu ierisinde,
zelliin o anki deeri ile for dngs ierisindeki deerler karlatrlm ve eleme olmas
halinde, ekrana baslacak olan option elementinin yaps deitirilmitir.

protected override void Render(HtmlTextWriter writer)


{

www.bsenyurt.com Page 1290


writer.Write("<span id='lblGun'>" + GunMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='Gun' id='Gun'>");
for (int i = 1; i <= 31; i++)
{
if (SeciliGun == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" +
i.ToString() + "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<span id='lblAy'>" + AyMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='Ay' id='Ay'>");
for (int i = 1; i <= 12; i++)
{
if (SeciliAy == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" +
i.ToString() + "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<span id='lblYil'>" + YilMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='Yil' id='Yil'>");
for (int i = 1950; i <= 2050; i++)
{
if (SeciliYil == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" +
i.ToString() + "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
base.Render(writer);
}

Dikkat ederseniz, zelliklerimizin deerlerini, for dngleri ierisinde yakalyoruz ve buna gre
option elementine selected niteliini (attribute) ekliyoruz. Peki, kontrolmz bu son haliyele
sayfamzda kullandmzda ve sayfann Load olay metodunda aadaki kodlar yazdmzda neler
olacaktr?

protected void Page_Load(object sender, EventArgs e)


{
if (!Page.IsPostBack)
{
TarihKontrolumOld1.SeciliGun = "3";
TarihKontrolumOld1.SeciliAy = "4";
TarihKontrolumOld1.SeciliYil = "2008";
}
}

www.bsenyurt.com Page 1291


Load olay metodu ierisind, eer sayfa ilk kez ykleniyorsa (ki bu kontrol IsPostBack zelliinin
deerine bakarak yapyoruz), web sunucu kontrolmzn ilgili zelliklerine baz balang deerleri
set edilmektedir.

Ancak sayfay tekrardan sunucuya gnderdiimizde, IsPostBack kontrol nedeni ile if blou
ierisindeki kodlar bir kez daha altrlmayacaktr. Bu nedenlede sayfann bir sonraki talep
(request) iin kts aadaki gibi olacaktr. Dikkat ederseniz, SeciliGun, SeciliAy ve SeciliYil
zellikleri balang deerlerine gre yeniden belirlenmitir. (Bu durum, kontroln her sayfa
istediinde yeniden rnekleniinin ve ilk deerlerin atannn doal bir sonucu olarak
dnlebilir.)

Aslnda sorun, istemci (client) ile sunucu(server) arasnda web sunucu kontrol ierisindeki
verilerin (data) tanmyor oluudur. Bu amala bildiiniz gibi Asp.Net uygulamalarndaViewState'
lerden faydalanabiliriz. ViewState' ler sunucu tarafndan yeniden retilen, sayfalar ierisindeki
verileri saklamak amacyla istemci tarafndaki ktya ilave edilen gizli alanlardr (hidden field). Bu
alann ierii string bazldr. Dikkat edilmesi gereken noktalardan birisi, ViewState' in ierisinde ok
yksek boyutlu veri tamasnn, retilecek olan HTML ieriini fazlasyla iirecek olmasdr. Bu
nedenle ViewState ierisine veri atarken ounlukla string tipine dntrlebilen ve ok yksek
boyut iermeyen bilgileri ele almakta fayda vardr. TarihKontrolum isimli bileenimiz ierisinde
GunMetin, AyMetin, YilMetin, SeciliGun, SeciliAy, SeciliYil zelliklerinin ieriklerini ViewState
ierisinde saklayabiliriz. Bylece yukardaki modele gre sayfann ilk retiliinde hazrlanan veri
ierii istemci tarafndaki kt ierisinde yer alan gizli alana ilave edilecektir. Bu ihtiyac
cevaplandrabilmek amacyla, TarihKontrolum bileeninde aadaki deiiklikleri yapmamz yeterli
olacaktr.

www.bsenyurt.com Page 1292


public class TarihKontrolum:Control
{
public string GunMetin
{
get {
if (ViewState["gunMetin"] != null)
return ViewState["gunMetin"].ToString();
else
return "Gn";
}
set { ViewState["gunMetin"] = value; }
}

public string AyMetin


{
get
{
if (ViewState["ayMetin"] != null)
return ViewState["ayMetin"].ToString();
else
return "Ay";
}
set { ViewState["ayMetin"] = value; }
}

public string YilMetin


{
get
{
if (ViewState["yilMetin"] != null)
return ViewState["yilMetin"].ToString();
else
return "Yl";
}
set { ViewState["yilMetin"] = value; }
}

public string SeciliGun


{
get
{

www.bsenyurt.com Page 1293


if (ViewState["seciliGun"] != null)
return ViewState["seciliGun"].ToString();
else
return "";
}
set { ViewState["seciliGun"] = value; }
}

public string SeciliAy


{
get
{
if (ViewState["seciliAy"] != null)
return ViewState["seciliAy"].ToString();
else
return "";
}
set { ViewState["seciliAy"] = value; }
}

public string SeciliYil


{
get
{
if (ViewState["seciliYil"] != null)
return ViewState["seciliYil"].ToString();
else
return "";
}
set { ViewState["seciliYil"] = value; }
}

protected override void Render(HtmlTextWriter writer)


{
writer.Write("<span id='lblGun'>" + GunMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='Gun' id='Gun'>");
for (int i = 1; i <= 31; i++)
{
if (SeciliGun==i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" + i.ToString()
+ "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<span id='lblAy'>" + AyMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='Ay' id='Ay'>");
for (int i = 1; i <= 12; i++)
{
if (SeciliAy == i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" + i.ToString()
+ "</option>");
else

www.bsenyurt.com Page 1294


writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<span id='lblYil'>" + YilMetin + "</span>");
writer.Write("&nbsp;&nbsp;");
writer.Write("<select name='Yil' id='Yil'>");
for (int i = 1950; i <= 2050; i++)
{
if (SeciliYil==i.ToString())
writer.Write("<option selected='selected' value='" + i.ToString() + "'>" + i.ToString()
+ "</option>");
else
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
}
writer.Write("</select>");
base.Render(writer);
}
}

zelliklerimiz hepsi ayn prensiple almaktadr. Get bloklarnda, eer ViewState ierisinde tutulan
bir veri var ise bu veri string tipine dntrlerek elde edilir. Set blounda ise zellie atanan
deerler, ViewState ierisine baz anahtar ifadeler (key) ile eklenmektedir. rnein SeciliGun
zelliinin iaret edecei deer iin ViewState ierisinde seciliGun isimli bir anahtara (key), deer
atamas yaplmtr. Set bloklar, dikkat ederseniz sayfann Load olay metodu ierisindeki kodlarda
devreye girmektedir. Bu nedenle sayfa ilk retilii srasnda bu zelliklere balang deerleri
atanmaktadr. Bu atama sonrasndaki deerler, istemciye gnderilecek olan ierikte yer alan
ViewState alan ierisine dahil edilecektir. Dolaysyla istemci sayfay tekrardan sunucuya
gnderdiinde, alan (yada deserialization ilemine tabi tutulan) ViewState ierisinden, zelliklerin
deerleri alnacaktr. Bu deerleride Render metodu ierisinde zelliklerin Get bloklarndan
aldmzdan, kontroln ilgili zellikleri balang deerlerine dndrlmeyecektir. Aadaki video
grntsnde kontrolmzn yeni ve eski halleri incelenmeye allmtr.

st taraftaki kontrolmz ViewState kullanmayan TarihKontrolumOld isimli snfa ait bir rnektir.
Alttaki kontrolmz ise TarihKontrolum snfna ait ViewState kullanan nesne rneimizdir. Halen
daha baz problemlerimiz vardr. rnein kullanc tarayc penceresi ierisindeyken, gn, ay veya
yl bilgilerinden birisini deitirip sayfay tekrardan sunucuya gnderirse, deitirdii ierii son hali
ile elde edemeyecektir. Bu sayfann ierisindeki kontrollerin verisinin istemciden yaplan
deiiklikler sonucu, sunucuya gnderilmeyiinden kaynaklanmaktadr. Sorunu zmek iin
postback ilemi sonucu istemciden gelen veriyi ilememiz gerekmektedir. Bu sorunu nasl
zeceimizi yaz dizimizin ilerleyen makalelerinde incelemeye alacaz.

www.bsenyurt.com Page 1295


Makalemizin bundan sonraki blmnde, sunucu kontrollerimizin tasarm zamanndaki (design
time) niteliklerini (attribute) nasl deitirebileceimizi grmeye alacaz. Nitelikleri (attribute)
snf(class), zellik(property) veya assemblye baznda uygulayabiliriz. Bu nitelikler, gelitirdiimiz
web sunucu kontrollerini kullanan sayfa gelitiriciler iin nemlidir. Nitekim, web sunucu
kontrolnn Visual Studio.Net ortam ierisindeki davranlarn belirlemektedir.

Attribute' lar uygulandklar tip veya yelerin alma zamanndaki davranlarn


belirlememize yarayan tiplerdir. Assembly' larn Metadata' sna eklendikleri iin alma
zamanda reflection yardmyla ele alnrlar ve alma ortamnn gerekli davran
deiikliklerini yapabilmelerini salarlar. ok bilinen attribute' lara rnek
olarak Serialization, WebMethod, WebService vb' lerini verebiliriz.

Gelitireceimiz web sunucu kontrollerinde kullanabileceimiz snf(class), zellik(property) ve


assembly seviyesindeki baz nitelikler(attributes) ve ilevleri aadaki tabloda zetlenmeye
allmtr.

Assembly Bazndaki Aklamas


Nitelikler
(Attributes)

TagPrefix Kontrol sayfaya srklenip brakldnda, arka taraftaki elemente ait n


ekin (prefix) ne olacacan belirleyebilmemizi salar.

Snf Bazndaki Aklamas


Nitelikler
(Attributes)

ToolBoxData Bu nitelik ile kontroln, sayfann arka tarafnda nasl yazlacan


belirtebiliriz.

DefaultProperty Kontrol sayfaya ilk srklendiinde ele alnacak olan varsaylan


zelliin (default property) ne olacan belirtir. rnein bir Button
bileeni iin Text zellii varsaylandr.

DefaultEvent Kontrol sayfaya ilk srklendiinde ele alnacak olan varsaylan


olayn (default event) ne olacan belirtir. rnein bir Button bileeni iin
Click olay varsaylandr.

zellik Bazndaki Aklamas


Nitelikler
(Attributes)

Browsable Bu nitelik ile, zelliin Vs.Net ierisindeki Properties penceresinde gsterilip


gsterilmeyecei belirlenir. Varsaylan olarak zelliin deeri true' dur.
stelik kontroller ierisinde kullanlan her zellik bu nitelie varsaylan
olarak sahiptir.

Description zellik ile ilgili bir aklama girilmesini salar. Bu, zellikle sayfa
gelitiriciler (page developers) iin nemlidir. nk zelliin ne amala
kullanlaca hakknda bilgilerin verilmesini salamaktadr.

Bindable Eer zellik, veriye balanacaksa (data binding) bu niteliin kullanlmas


gerekir.

Themeable zellie theme ve dolaysyla skin uygulanabilmesini salamak istiyorsak


bu zellii kullanrz.

Category zelliin hangi kategori (Category) bal altnda sunacamz belirtir.

www.bsenyurt.com Page 1296


DefaultValue zelliin varsaylan olarak hangi deeri (default value) tayacan
belirtmektedir.

Localizable Eer bu nitelik false olarak belirtilirse, zelliin ierii sz konusu aspx iin
retilen resource sayfalarnda gsterilmez. True olmas halinde ise
gsterilir. Buda ilgili zelliin yerelletirmede kullanlabilmesini salar.

DesignOnly zelliin sadece tasarm zamannda ele alnp alnmayacan belirtir.

Dilerseniz bu nitelikleri ve etkilerini incelemeye alalm. lk olarak assembly


seviyesindeki TagPrefix niteliini ele alacaz. Bu nitelii, kontrollerimizi barndran ktphane
ierisindeki AssemblyInfo.cs dosyas ierisinde kullanmamz gerekmektedir. TagPrefix
nitelii System.Web.UI ierisinde yer aldndan, gerekli isim alannnda (namespace) bu snf
ierisine dahil etmekte fayda vardr. Temel olarak TagPrefix nitelii, kontroln web sayfas zerine
srklenmesi sonrasnda arka planda oluturulacak olan elementin n ekini belirlemek amacyla
kullanlr. Varsaylan olarak cc1 olan kontrol elementi n ekini deitirmemizi salayacaktr.

Dikkat ederseniz TagPrefix niteliine ait yapc metod (constructor) iki parametre almaktadr. Bu
parametrelerden ilki, kontroln bulunduu isim alannn addr. kinci parametre ise n ekin addr.
Bu deiiklilerden sonra kontrolmz herhangibir sayfa zerine srkleyip braktmzda
aadaki sonucu elde ederiz.

Grdnz gibi kontrolmzn n eki, assembly dosyasnda belirttiimiz ekilde deitirilmitir.


Gelelim dier niteliklere. Snf baznda (Class Level) uygulayabileceimiz nitelikler iin aada bir
rnek yer almaktadr.

www.bsenyurt.com Page 1297


[DefaultProperty("SeciliGun")]
[ToolboxData("<{0}:TarihKontrolum runat='Server'><{0}:TarihKontrolum>")]
public class TarihKontrolum:Control
{

Burada rnek olarak ToolboxData ve DefaultProperty nitelikleri kullanlmtr. ToolboxData,


yazm biimindende grld gibi, kontroln aspx tarafnda nasl yazlacan belirtmektedir.
Tahmin edeceiniz gibi {0} yazan yere, AssemblyInfo.cs dosyasnda tanmlanan TagPrefix
niteliindeki deer gelecektir. stenirse runat='Server' yazld yerde baka attribute' lar
konularak, rnein kontroln zelliklerinin ilk deerlerinin gsterilmesi salanabilir. Aadaki kod
parasnda bu durum gsterilmitir.

[ToolboxData("<{0}:TarihKontrolum SeciliGun='10' SeciliAy='2' SeciliYil='2007' runat='Server


'><{0}:TarihKontrolum>")]

Burada tanmlanan SeciliGun, SeciliAy ve SeciliYil niteliklerinin aslnda, TarihKontrolum snf


ierisindeki zelliklere (properties) iaret ettiine dikkat edelim. Yaptmz deer atamalar sonucu
kontroln bu zelliklerinin ilk deerleride otomatik olarak set edilmi olacaktr.

Kontroln arka plandaki kts ise aadaki gibi olacaktr.

<Kontrolum:TarihKontrolum ID="TarihKontrolum1"
runat="server" SeciliAy="2" SeciliGun="10" SeciliYil="2007">
</Kontrolum:TarihKontrolum>

Snf baznda kullandmz niteliklerden DefaultProperty, kontrol sayfaya srklenip brakldnda,


Vs.Net 2005 IDE' si ierisindeki zellikler penceresinde, hangi zelliin varsaylan olarak seili
olacan belirtmektedir. rneimizdeki TarihKontrolum bileeni iin varsaylan zellik SeciliGun'
dr.

www.bsenyurt.com Page 1298


Gelelim zellik baznda kullandmz niteliklere. Kontrolmzdeki zelliklerin hepsine yukarda
bahsettiimiz nitelikleri uygulayabiliriz. rnein SeciliGun iin aadaki rnek kod parasnda
tasarm penceresine etki edecek nitelikler eklenmitir.

[Browsable(true)]
[Description("Hangi Gn?")]
[Bindable(true)]
[Themeable(true)]
[Category("Tarih Degerleri")]
[DefaultValue("1")]
[Localizable(true)]
public string SeciliGun
{
get
{
if (ViewState["seciliGun"] != null)
return ViewState["seciliGun"].ToString();
else
return "";
}
set { ViewState["seciliGun"] = value; }
}

Temel olarak Browsable niteliini yazmak art deildir. Nitekim zelliklerin hepsi, tasarm
zamannda zellik penceresinde grnrler. Ancak baz zelliklerin burada deitirilmesini
istemediimiz vakkalar olursa, false olarak iaretlenebilir. DefaultValue zelliine her ne kadar
balang iin 1 deerini atam olsakta, ToolboxData nitelii ierisinde bu zellik iin yeni bir
deer verilmitir. Bunun doal sonucu olarak, DefaultValue zelliindeki deer yerine ToolboxData
ierisindeki zellik deeri, zellikler penceresinde grnecektir.Themeable nitelii, Asp.Net 2.0 ile
birlikte gelmi olan tema kavramna istinaden kullanlabilir. Eer false deeri atanrsa zelliimize
tema veya skin uygulanamayacaktr. Localizablezelliine true deerinin atanmas ile, SeciliGun
deerinin resource dosyalarnda grnmesi salanr. rnein tm zelliklerimizde bu nitelii true
olarak kullandmzda aadaki gibi bir resource dosyas retilebilir.

www.bsenyurt.com Page 1299


Categroy niteliini kullandmz takdirde, zelliklerin properties blmnde mantksal isim
balklar altnda yer almas salanabilir. rnein SeciliGun,SeciliAy, SeciliYil zelliklerini Tarih
Degerleri isimli bir grup altnda toplayabiliriz. Benzer bir ekilde, AyMetin, GunMetin ve YilMetin
zelliklerini Metinler adnda bir grup balnda toplayabiliriz. Sonu aadakine benzer olacaktr.

Grdnz gibi, gelitireceimiz kontrollerin tasarm zamanndaki davranlarn niteliklerimiz


yardmyla belirleyebilmekteyiz. Bu makalemizde web kontrol gelitirmekle ilgili olarak, state
ynetimini ViewState' ler yardmyla nasl yapabileceimizi, tasarm zamanndaki davranlar nasl
belirleyebileceimizi incelemeye altk. u ana kadar yaptklarmz ile ilgili olarak aklmzda
kalanlar ise aadaki maddeler ile zetleyebiliriz.

u Ana Kadar Hatrda Kalanlar

www.bsenyurt.com Page 1300


Bir web sunucu kontrolnn sayfann yklenii srasnda set edilen deerlerini korumak iin
zelliklerin ierisindeki verileri ViewState' ler ierisinde saklamak gerekir.

ViewState kullanmak, kontroln istemci tarafnda deiiklie urayacak deerlerini ele almak iin
yeterli deildir. Bu durumda iin ierisinde postback sonucu sunucuya gnderilecek datalarn ele
alnmas gibi artlar girmektedir.

Web sunucu kontrollerine tasarm zaman destei salanabilir. Bylece Vs.Net IDE' si ierisindeki
davran modelleri ele alnabilir.

Tasarm zaman davranlarn belirleyen nitelikleri Assembly, Class ve Property olmak zere toplam
seviyede belirleyebiliriz.

Bylece geldik bir makalemizin daha sonuna. Sonraki makalemizde Render metodu ile ilikili baka
dzenlemer yapacak ve PostBack olaylarn nasl ele alabileceimizi aratrmaya alacaz. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Web Server Control Yazmak - 1 ( 17.01.2007 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Gnmz program gelitirme ortamlarn ou, gelitiricilerin(developers) daha kullanc dostu (user
friendly) arabirimler tasarlayabilmeleri iin saysz kontrol iermektedir. zellikle Asp.Net
ortamndan Asp.Net 2.0 ortamna geildiinde, web tabanl uygulamalar gelitirirken
kullanabileceimiz kontrollerin says olduka artmtr.(70den fazla kontrol) Buna ramen var olan
web sunucu kontrollerinin ihtiyacmz karlamad durumlar olabilir. Hatta ihtiyacmz
karlayabilecek bir kontrol olmayabilir de. Bu gibi durumlarda gelitiriciler ya nc parti
bileenleri satn alma ve kullanma yolunu tercih ederler yada ilgili sunucu kontrollerini (web server
control) kendileri gelitirirler. Bu ilk makalemizde basit anlamda web sunucu kontrollerini nasl
gelitirebileceimizi incelemeye balayacaz.

Bir web sunucu kontroln sfrdan yazmadan nce, var olan web kontrollerinin ne ekilde
altklarn analiz etmekte fayda vardr. Web ortam sunucu tarafl ve istemci tarafl alabilen
kodlarn ierisinde yer ald bir teknolojidir. Asp.Net perspektifinden baktmzda ise ounlukla
sunucu tarafl kodlamadan ve kontrollerden bahsederiz. Hangi web teknolojisi olursa olsun
istemcilerin tarayc pencerelerinde elde ettikleri kt her zaman iin yorumlanabilir bir HTML kts
olacaktr. rnein aadaki ekran grntsnde yer alan web sunucu kontrollerini gz nne
alalm.

www.bsenyurt.com Page 1301


Sayfamzda Label, TextBox, DropDownList, Button, CheckBox, RadioButton gibi basit Asp.Net
sunucu kontrolleri yer almaktadr. Bu sayfa herhangibir tarayc penceresi zerinden talep
edildiinde ise aadaki gibi bir HTML kts elde edilir.

Grdnz gibi web sunucu kontrollerinin her birisi alma zamannda aslnda HTML ieriine
evrilirler. Bunu Render olarak da adlandrabiliriz. Dolaysyla kendi Asp.Net Web sunucu
kontrollerimizi yazarken dnmemiz gereken ilk konu, tasarladmz kontroln istemci tarafna
nasl aktarlacadr. Bir baka deyile istemci tarayc penceresinde gnderilecek HTML ieriinin
nasl olacadr. Buda yazdmz kontroln Html ktsnn tarafmzca oluturulmasna baldr.

Asp.Net platformunda her sunucu kontrol yle yada byle bir ekilde System.Web.UI isim alan
altnda yer alan Control snfndan tremektedir. Control snf zerinde gelitireceimiz bir snf
web sunucu kontrol olarak ele alnabilir. Aslnda var olan tm web sunucu kontrolleri Control
snfndan treyen WebControl snfndan trer. WebControl snfndan tretme yaparak kontrol
gelitirme ilemlerini ilerleyen makalelerimizde ele almaya alacaz. System.Web.UI isim alan
altnda yer alan Control snfnn u anda bizim iin en nemli metodu Render metodudur. Render
metodu parametre olarak HtmlTextWriter tipinden bir deiken almaktadr. Bu deiken
yardmyla kontroln baslaca sayfa zerine HTML taklarn (Html tags) yazdrabiliriz. Aslnda
HtmlTextWriter snf TextWriter isimli zet snftan (abstract class) tretilmi bir snftr.

zellikle windows tabanl uygulama gelitirenler DateTimePicker kontroln bilirler. Ancak bu


kontroln benzeri bile, Asp.Net zerinde yer almamaktadr. ok basit olarak byle bir web

www.bsenyurt.com Page 1302


kontroln gelitirmek istediimizi dnelim. Kendi web kontrollerimizi gelitirirken eer HTML
ktsnn nasl olacan tam olarak kestiremiyorsak, kontrolmzn ierisinde yer almasn
istediimiz elemanlar dier web sunucu kontrollerinden oluturarak retilen HTML ktsn gz
nne alabiliriz. Bu biraz hileli bir yol olsada balangta olaylar daha kolay alglayabilmemizi
salayacaktr. Tarih formatndaki bir kontrol temel olarak gn, ay ve yl gibi bilgileri tayabilir.
Bunlar birer DropDownList olarakda dnebiliriz. Bu listelerin banda ise birer Label ile global
halede getirilebilecek gn, ay, yl kelimeleride yer alabiliriz. (Global hale getirmekten kastmz ise
ieriin farkl dillere desteinin olmasdr. Yani localization) Tam olarak tasvir etmek istediimiz
bileen aadakine benzer olacaktr.

Burada kullanlan Label bileenleri Html ktsna birer span taks (span tag) ierisinde
alnmaktadr. DropDownList kontrolleri ise birer select elementi olarak geecektir. DropDownList
ierisindeki elerimiz ise, select elementinin ierisinde birer alt element olarak option taklar
arasnda gsterilecektir. yleyse istemci tarafna kartmamz gereken HTML ierii aa yukar
bellidir. Peki bu ierii kendi kontrolmz ierisinde nasl izdireceiz?

Her eyden nce temel olarak Control snfndan treyen bir tipe ihtiyacmz olduunu belirtmitik.
Eer bu tipi bir snf ktphanesi ierisinde (class library) ele alrsak, Visual Studio ierisindeki
ToolBox' a ekleyebilir ve baka web projeleri ierisindede kullanlmasn salayabiliriz. O halde bir
Class Library (snf ktphanesi) projesi aarak ie balayalm. Normal artlarda kendi web sunucu
kontrollerimizi barndracak ktphane tipi olarak Web Control Library tercih edebiliriz. Bu proje
tipi ierisinde bir web kontrol rnei, gerekli nitelikleri (attributes)
ve referanslar (rnein System.Web.dll gibi) ile birlikte hazr bir ablon olarak gelmektedir.
Ancak web kontrol gelitirme sanatn temelinden renmeye altmzdan, standard bir Class
Library zerinden devam etmek ok daha retici olacaktr. Bu nedenle makalemizde Web Control
Library seeneini u an iin kullanmayacaz.

Yazdmz web sunucu kontrollerini bir snf ktphanesi ierisinde tutarsak, Visual
Studio IDE' si ierisinde yer alan ToolBox blmne ekleyebilir ve baka web projeleri
ierisinden de kullanabiliriz. Hatta ayn solution ierisindeki web projelerinde ilgili
kontroller otomatik olarak ToolBox ierisinde grnecektir.

Snf ktphanemiz ierisinde TarihKontrolum isimli bir snf(class) gelitireceiz. Yanlz bu snfn
System.Web.UI isim alan ierisindeki Control snfndan tretilebilmesi iin, snf
ktphanemizin System.Web.dll assembly' na ak bir referansta bulunmas gerekmektedir.

Referansmz ekledikten sonra snfmz Control snfndan tretebiliriz. Eklenen referans, snfmz
ierisinde web ortamna (rnein ViewState' ler, post-back olaylar) mdahele etmemizide
salayacaktr.

www.bsenyurt.com Page 1303


using System;
using System.Web.UI;

namespace BenimWebKontrollerim
{
public class TarihKontrolum:Control
{
}
}

Tasarlamaya altmz web kontrolnn baz paralar otomatik olarak hem tasarm zamannda
(design time) hemde alma zamannda (run time) deitirilebilmelidir. Eer snfmz bu tip
deiebilir deerleri barndracaksa ve bunlarn desteini hem tasarm zamannda hem gelitirme
zamannda salayacaksa, nasl bir yeye ihtiyacmz olabilir? Cevap olduka basittir.
zellik (Property). O halde snfmz aadaki gibi gelitirelim.

using System;
using System.Web.UI;

namespace BenimWebKontrollerim
{
public class TarihKontrolum:Control
{
private string _gunMetin;
private string _yilMetin;
private string _ayMetin;

public string GunMetin


{
get { return _gunMetin; }

www.bsenyurt.com Page 1304


set { _gunMetin = value; }
}
public string AyMetin
{
get { return _ayMetin; }
set { _ayMetin = value; }
}
public string YilMetin
{
get { return _yilMetin; }
set { _yilMetin = value; }
}

protected override void Render(HtmlTextWriter writer)


{
// Gn yazsn tutacak Label iin Html tarafna bir span elementi atlr.
writer.Write("<span id='lblGun'>" + GunMetin + "</span>");
// iki boluk braklr.
writer.Write("&nbsp;&nbsp;");
// Gn deerlerini tutacak (1...31 e kadar) select elementi oluturulur.
writer.Write("<select name='Gun' id='Gun'>");
// Select elementi ierisinde, her gn iin bir option elementi oluturulur value ve text
deerleri i olarak set edilir.
for (int i = 1; i <= 31; i++)
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() +
"</option>");
// Alan Select taks kapatlr.
writer.Write("</select>");
// ki boluk braklr
writer.Write("&nbsp;&nbsp;");
// Ay metnini tayan Label kontrol iin span taks atlr.
writer.Write("<span id='lblAy'>" + AyMetin + "</span>");
// ki boluk braklr
writer.Write("&nbsp;&nbsp;");
// Aylar iin gerekli select elementi oluturulur.
writer.Write("<select name='Ay' id='Ay'>");
// Her bir Ay iin select elementi ierisine birer option elementi alr.
for (int i = 1; i <= 12; i++)
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
// select elementi kapatlr.
writer.Write("</select>");
// ki boluk braklr.
writer.Write("&nbsp;&nbsp;");
// Yil metni iin span elementi oluturulur.
writer.Write("<span id='lblYil'>" + YilMetin + "</span>");
// ki boluk braklr
writer.Write("&nbsp;&nbsp;");
// Yillar iin select elementi oluturulur
writer.Write("<select name='Yil' id='Yil'>");
// 1900 ile 2050 aras tarih aralndaki her bir yl iin select elementi ierisine birer option
elementi alr.
for (int i = 1950; i <= 2050; i++)
writer.Write("<option value='" + i.ToString() + "'>" + i.ToString() + "</option>");
// select elementi kapatlr.
writer.Write("</select>");
base.Render(writer);

www.bsenyurt.com Page 1305


}
}
}

Snfmzn belkide en can alc noktas Render metodunun ieriidir. Burada dikkat ederseniz,
kontrolmzn HTML ktsn HtmlTextWriter nesnesi yardmyla en bandan oluturuyoruz.
Label' larmz iin birer span ve liste kutularmz iinde birer select elementi. Bu noktadan sonra
snf ktphanemiz (class library) ierisinde gelitirdiimiz TarihKontrolum isimli bileenin,
herhangibir web projesindeki herhangibir sayfann tasarm annda ToolBox' a eklendiini grebiliriz.

Gelitirilen web sunucu kontrollerini ierisinde barndrdan ktphaneleri, private


assembly eklinde kullanabileceimiz gibi (yani web uygulamas ile birlikte tanacak
ekilde), shared (public) olarak GAC' a (Global Assembly Cache) atp kullanabilirizde. GAC
zerinde tutmamz halinde Assembly' n bir strong name' e sahip olmas gerektiini
unutmayalm.

imdi bu kontrol herhangibir web sayfas zerine srkleyip brakalm. Bu durumda sayfamzn
ekran grnts aadaki gibi olacaktr.

Sayfann kaynak tarafna getiimizde ise kontrol ierisinde izilen liste kutular veya balklarn hi
birisinin gzkmediini, bunun yerine asp.net sunucu kontrollerine benzer tek bir elementin
oluturulduunu grebiliriz. Bu nokta, kontrol gelitirme metodolojisinde bilgi saklama (informatin
hiding) olarak adlandrlmaktadr. yleki, gelitirdiimiz sunucu kontrolnn arka tarafnda olanlar
sayfa tasarmcsndan gizlenemitir. Bu sayfa tasarmclarnn ilgili kontrolleri daha kolay
kullanabilmesini ve kod karmaasndan uzaklalmasn salar. Dier yandan gelitiriciler
(developers) bizim kontrolmz treterek geniletebilirler.

www.bsenyurt.com Page 1306


Gelitiricilerin bizim yazdmz kontrolleride geniletebilmeleri iin kontrol ierisinde var
olan yelerin, virtual (sanal) olarak tanmlanmas dnlebilir. Bylece tretilen tipler
isterlerse bu yeleri override (ezip) ederek kendi istedikleri biimde almalarn
salayabilirler. Ltfen hatrlayalm, bu konular OOP (Object Oriented Programming -
Nesneye Dayal Programlama) temellerindendir.

Tekrar konumuza dnecek olursak.

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


Inherits="_Default" %>

<%@ Register Assembly="BenimWebKontrollerim"


Namespace="BenimWebKontrollerim" TagPrefix="cc1" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<cc1:tarihkontrolum id="TarihKontrolum1"
runat="server"></cc1:tarihkontrolum>
</form>
</body>
</html>

Sayfann arka planna baktmzda dikkati eken ilk noktalardan birisi BenimWebKontrollerim.dll'
ine ait referans bilgisinin Register direktifi ile sayfaya eklenmi oluudur. Register elementi
ierisinde yer alan TagPrefix nitelii, TarihKontrolum bileeninin sayfaya eklenmesi halinde
kullanlacak tak n ekini belirtmektedir. Hatrlayacanz gibi kontrol snfmz ierisine
GunMetin,AyMetin ve YilMetin isimli zellikler dahil etmitik. Bu zellikler, kontrolmz seildiinde
properties penceresinde aadaki gibi grnecektir.

Bu zelliklere rnek deerler atayp sayfamz tarayc penceresinde atmzda, kontrolmzn


aadaki ekran grntsnde olduu gibi eklendiini ve HTML ktsnn Render metodunda
tasarladmz ekilde retildiini grrz.

www.bsenyurt.com Page 1307


Sayfa kts;

alma zamannda oluturulan HTML kts ise aadakine benzer olacaktr.

Artk elimizde kendi yazdmz bir web sunucu kontrol var. Bunu elbetteki biraz daha fazla
gelitirmemiz gerekecek. rnein formumuz zerine bir button ekleyip sayfann istemciden sunucu
tarafna gitmesine neden olacak bir ilem yaparsak (post-back) liste kutularnn ieriinin
balang deerlerine set edildiini grrz.

Dikkat ettiyseniz deerleri deitirmemize ramen gn, ay ve yl deerleri ilk deerlerine set
edilmitir. Bunun sebebi son derece doaldr. Gelitirdiimiz web kontrol, kullanld web
sayfasnn bir parasdr. Sayfa ilk talep edildiinde oluturulur ve render edilen ierie HTML
ktlar dahil edilir. Bundan sonra zaten sunucu tarafnda, Asp.Net sayfasna ait nesne rnei yok

www.bsenyurt.com Page 1308


edilmektedir. Bu bir Asp.Net sayfasnn yaam dngsnn (life cycle) doal sonucudur.
Dolaysyla sayfa ierisindeki kontrollerde Dispose edilecektir. O halde ikinci talepte, yani post-back
ileminden sonra, ayn ilemler tekrarlanacaktr. Sayfaya ait nesne rnei ve ierideki tm nesne
rnekleri tekrardan oluturulacak ve zellikle kontrollerin ierisinde yer alan zellikler de ilk
deerlerine set edilecektir. Dolaysyla kontrolmzn, post-back ilemleri sonrasnda bir ekilde
istemcinin setii liste elerini hatrlamas ve ieride ilemesi gerekecektir. te bu kontrolmz
daha fazla gelitireceimiz (gelitirmemiz gerektii) anlamna gelmektedir. Dier taraftan,
gelitirdiimiz kontroln tasarm zamanndaki yeteneklerinide arttrabiliriz. Tm bu gerekenleri yaz
dizimizin ikinci makalesinde ele almaya alacaz.

Bu makalemizde bir web sunucu kontroln gelitirmek iin gereken ilk admlar attk. Yanmza kar
olarak kalanlar ksaca aada maddeler halinde bulabilirsiniz.

u Ana Kadar Hatrda Kalanlar

Kullanc tarafndan bir web kontrol gelitirmek nihayetinde, System.Web.UI.Control snfndan


bir snf tretmektir. (Sonradan bu ilem iin sadece WebControl snfn tercih edeceiz.)

zel olarak yazlacak bir web kontroln iki tarafl olarak dnmek gerekir. stemci tarafndan ve
sunucu tarafndan. stemci tarafnda dnlecek olanlar, kontroln retecei HTML ktsnn nasl
olmas gerektiidir. Sunucu tarafnda dnlmesi gerekenler ise, istemcide seilen verilerin nasl
hatrlanacan ve istemci iin gerekli HTML ieriinin nasl hazrlanacadr.

Kullanc tarafndan gelitirilen sunucu kontrolleri ayn zamanda, Html ktsnn hazrlanmas,
viewstate ve post-back ilemlerinin ele alnmas gibi kavramlarn, sayfa gelitiricisinden
soyutlanmasna yardmc olur. (information hiding)

Bir web sunucu kontroln, birden fazla web projesinde hatta Visual Studio IDE' si ierisinden
kullanabilmek iin bir class library ierisinde tutulmasnda fayda vardr. Ortak kullanm amacyla bu
ktphane GAC (Global Assembly Cache)zerinde de tutulabilir.

Gelitirilen web sunucu kontrolnn, tasarm veya alma zamannda deitirilebilecek yeleri var
ise bunlar birer zellik olarak tasarlamak gerekir.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Web Servislerinde SoapHeader ile


zelletirilmi Dorulama ( 10.01.2007 ) - Web
Service
Deerli Okurlarm Merhabalar,

Web servislerinde gvenlik sz konusu olduunda, gelitiricileri en ok zorlayan noktalardan birisi


grsel bir arabirimin olmaydr. Bu nedenle zellikle web tabanl uygulamalarda tercih edilen form
tabanl (form-based) veya windows tabanl (windows based) dorulama (authentication)
sistemlerini uygulamak biraz daha farkldr. Biz bu makalemizde form tabanl dorulama ve
yetkilendirme sistemininin iskeletini, web servisleri zerinde nasl gelitirebileceimizi incelemeye
alacaz.

www.bsenyurt.com Page 1309


Konuyu daha iyi anlamak iin vakkamz analiz edelim. Web servisi tarafnda yer alan baz
metodlarn istemciler tarafndan kullanlabilmesi iin ilgili kullanclarn dorulanmas gerektiini
dnelim. Byle bir durumda kullanclarn ilgili web metod arlarndan nce web servisi
tarafndan dorulanmas (authenticate) gerekecektir. Srf bu ama iin tasarlanm bir web metodu
gz nne alnabilir. Kullanclarn login metodu ile dorulanmasnn en byk amac, i yapan web
metodlarna yaplacak olan arlarda tekrar tekrar dorulama yaplmasnn da nne gemektir.
Peki bu nasl salanabilir? Eer kullancnn elinde bir gven belgesi (credential) olursa bu
ilevsellik ok kolay bir ekilde salanabilir. Login metodu ierisinde hazrlanacak olan bu gven
belgesini, web servisinin kendisine balanan istemcileri dorulamas halinde verecei bir bilet
olarakta dnebiliriz. Bilet bir kere oluturulduktan sonra istemciye gnderilecektir. Bu noktadan
sonra istemci uygulama,web servisi tarafndan kendisine verilen bu bilet ile web metodlarn
aracaktr. Bylece bir kere dorulanan kullancnn, bu ilemden sonra yapaca arlarda
tekrardan dorulanmasna gerek kalmayacaktr. Bu elbette bilet bilgisi korunduu srece geerli
olacaktr. Istemci uygulamann kapatlmas ve tekrar balatlmas halinde, web servisi tarafndan
yeni bir biletin hazrlanmas ve gnderilmesi gerekebilir.

Burada nemli olan bir sorun vardr. stemciler iin sunucu tarafnda oluturulan biletler, istemci
uygulama ve web servisi arasnda nasl tanacaktr? te burada web servisleri ile istemciler
arasnda hareket eden verinin tand Soap zarflar (Soap Envelope) devreye girmektedir.
Soap zarflarnn iki nemli paras vardr. Asl verinin tand gvde (Soap Body) ksm ve paket
ile birlikte tanabilecek ekstra bilgilerin yer ald balk (Soap Header) ksm. Soap zarfnn
balnda bilet bilgisini tayabiliriz. Bylece kullanc, web servisi tarafndan ilk dorulanndan
sonra Soap paketindeki balk bilgisi ile kendisine gelen bileti alabilir. Bundan sonra yapaca web
metodu arlarnda ise kendisine verilen bileti yine web servisine Soap balnda gnderecektir.

imdi gelin biraz daha teknik detaya inelim ve rnek bir uygulama zerinden hareket ederek form
tabanl dorulama iskeletini web servisleri iin oluturmaya alalm. Web servisi tarafnda
dnmemiz gereken ilk konu kullanc bilgilerini nerede saklayacamzdr. Kullanclarn sistem
tarafndan tannmas iin baz bilgilerinin herhangibir depolama alannda saklanmas gerekecektir.
Bu amala .Net 2.0 ile birlikte gelen Membership API' sini kullanabiliriz yada kendi
hazrlayacamz veri saklama ambarlarn gz nne alabiliriz. Bu ambarlar bir Access veritaban
hatta bir Xml dosyas bile olabilir. Ancak verilerin daha tutarl ve gvenli bir ekilde saklanmas
amacyla ilikisel veritaban (Relational Database Management System - RDMS) sistemlerinden
birisi olmas ok daha leklenebilir zmler elde etmemizi salayacaktr. Makalemize konu olan
rneimizde bu amala basit bir sql veritaban dosyas kullanyoruz.

Azondb.mdf veritaban dosyamzn ierisinde u an iin tek bir tablo yer almaktadr. Kullanicilar
isimli tablomuzun temel amac, dorulamas yaplacak olan yelere ait baz bilgileri saklamaktr.
rnein kullanclarn ad, mail adresi, ifresi gibi.

www.bsenyurt.com Page 1310


Tablomuzun veri yapsn olduka basit dnyoruz. Nitekim odaklanmamz gereken nokta tablo
yaplarndan ziyade web servisi zerinde gvenlii form tabanl sistem kurallarna gre tasarlamak.
Ama elbetteki rol ynetimininin (role management) var olduu, ifrelerin de ifrelenerek (en
azndan Hash algoritmas ile kartrlarak) tutulduu daha gl bir veri saklama ortam
dnlebilir. Var olan Membership API' si buna en gzel rnektir.

Gelelim web servisi tarafmza. Az ncede bahsettiimiz gibi, form tabanl dorulama sisteminde
iskeleti oluturan nemli noktalar, kullancnn sunucu tarafndan dorulanmas (authentication), bir
biletin oluturulmas ve bu biletin Soap balnda istemciye gnderilmesidir. ncelikle kullanc
bilgilerinden bazlarn web metodlar arasnda bulmamz salayacak bir snf tasarlayarak ie
balayalm.

public class Kullanici


{
private string _ad;
private string _email;
private string _biletNumarasi;

public string Ad
{
get { return _ad; }
}
public string Email
{
get { return _email; }
}
public string BiletNumarasi
{
get { return _biletNumarasi; }
}
public Kullanici(string kullaniciAdi,string email)

www.bsenyurt.com Page 1311


{
_ad = kullaniciAdi;
_email = email;
_biletNumarasi = Guid.NewGuid().ToString();
}
}

Kullanici isimli snfn en can alc noktas bir Global Unique Identifier (GUID) deerini
sunmasdr. Bu deer Kullanici isimli snfa ait bir nesne rneklendiinde yapc metod ierisinde
oluturulmaktadr. GUID deerleri web servisinin alt sistemde benzersiz olarak
oluturulduklarndan, her kullancnn ayr ayr ele alnmasn salayabiliriz. rneimizde, Kullanici
snfna ait nesne rneklerini Application nesnesinde tamay tercih edeceiz. Application nesnesi
web servisi uygulamas ierisinde heryerden eriilebilir bir nesnedir. Dolaysyla web metodlarmz
ierisinden Application nesnelerine kp gelen bilet numarasna ait bir Kullanici nesne rneinin
olup olmadn kontrol edebiliriz. Yani, dorulanan kullanclar web servisi tarafndan Application
nesnesinde tutup, istemci ile Soap balndan gelecek olan biletin numarasna gre kontrol
edebiliriz. Bylece web metodlar ierisinde eer istemcideki bilet numarasnn karl olan bir
kullanc var ise ilemlerin yaplmasn salayabiliriz. Ama ncesinde Soap zarfnn balnda
tanacak olan snfn tasarlanmas gerekmektedir.

public class Bilet:System.Web.Services.Protocols.SoapHeader


{
private string _biletNumarasi;

public string BiletNumarasi


{
get { return _biletNumarasi; }
set { _biletNumarasi = value; }
}

public Bilet(string numara)


{
_biletNumarasi = numara;
}

www.bsenyurt.com Page 1312


public Bilet()
{
}
}

Soap zarflarnn balk ksmnda bilgi tayabilmenin yolu SoapHeader tipinden tretilmi bir snf
yazlmasdr. Bu tretme sayesinde Bilet isimli snfa ait nesne rneklerini soap paketlerinde balk
ksmnda tayabilme imkanna sahip oluruz. Olusturulan bu snf, web servisini referans eden
istemci uygulamalarada gnderilecektir. Ayn zamanda Soap paketi ierisine seriletirilebilir olmas
gerekmektedir. Bu nedenlede varsaylan yapc metodu (default constructor) olmak
zorundadr. Dikkat ederseniz balkta tanacak olan bu snf sadece tek bir ye sunmaktadr.
BiletNumarasi. Bilet isimli snfn BiletNumarasi isimli zelliinin bir set blouna sahip olmas
nemlidir. Aksi halde istemci tarafndaki uygulama sisteme login olduktan sonra yapaca
arlarda bu bilgiyi tekrardan set edemez ve web servisi tarafna gnderemez. Gelelim web
servisimiz ierisinde neler yapacamza.

[WebService(Namespace = "http://tempuri.org/")]
[WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
public class UrunServisi : System.Web.Services.WebService
{
public Bilet _bilet;

[WebMethod(Description="Kullanc bileti oluturulmasn salar")]


[SoapHeader("_bilet", Direction=SoapHeaderDirection.Out)]
public void GirisYap(string kullaniciAdi, string sifre)
{
using(SqlConnection conn=new SqlConnection(@"data source=.\SQLEXPRESS;Integrated
Security=SSPI;AttachDBFilename=|DataDirectory|AzonDb.mdf;User Instance=true"))
{
SqlCommand cmd = new SqlCommand("Select KullaniciAdi,PostaAdresi From Kullanicilar
Where KullaniciAdi=@KullaniciAdi and Sifre=@Sifre", conn);
cmd.Parameters.AddWithValue("@KullaniciAdi", kullaniciAdi.ToString());
cmd.Parameters.AddWithValue("@Sifre", sifre.ToString());
conn.Open();
SqlDataReader dr=cmd.ExecuteReader();
if (dr.Read())
{
Kullanici kln = new Kullanici(dr["KullaniciAdi"].ToString(),
dr["PostaAdresi"].ToString());

www.bsenyurt.com Page 1313


Application[kln.BiletNumarasi] = kln;
_bilet = new Bilet(kln.BiletNumarasi);
}
else
throw new Exception("Geersiz kullanc");
}
}

private Kullanici KullaniciDogrula(string biletNumarasi)


{
Kullanici kln = (Kullanici)Application[biletNumarasi];
if (kln != null)
return kln;
else
throw new Exception("Geersiz bilet numaras");
}

[WebMethod(Description="Ortalama endeks hesaplamalar yaplr.")]


[SoapHeader("_bilet",Direction=SoapHeaderDirection.In)]
public double MaliyetHesapla(double parcaNo)
{
KullaniciDogrula(_bilet.BiletNumarasi);
return parcaNo*10;
}
public UrunServisi () {
}
}

Web servisimiz ierisinde GirisYap isimli bir metodumuz bulunmaktadr. Bu aslnda makalemizin
bandan beri belirttiimiz, kullanclarn dorulanmas salayan login metodudur. Parametre olarak
ald ve istemci uygulamadan gelen kullanc ad ve ifre bilgilerine gre dorulama ilemini
stlenir. Yanlz metodun yapt iki nemli atama vardr. Birincisinde, Kullanici snfna ait bir nesne
rneinin oluturulmas ve retilen GUID deerine gre Application nesnesine atanmas sz
konusudur.

Kullanici kln = new Kullanici(dr["KullaniciAdi"].ToString(), dr["PostaAdresi"].ToString());


Application[kln.BiletNumarasi] = kln;

Bylece kullanc eer dorulanrsa web servisi kendisine bal olan istemciye ait
bilgilere Application nesnesi zerinden bilet numarasini kullanarak eriebilecektir. kincisinde ise,
retilen bilet numarasna gre Bilet snfndan _bilet isimli nesne rnei oluturulur.

_bilet = new Bilet(kln.BiletNumarasi);

Dikkat ederseniz Bilet isimli snfa ait bu nesne rnei Soap balnda tanmaktadr. Ancak dikkat
edilmesi gereken bir nokta vardr. GirisYap isimli metod iin belirtilenSoapHeader nitelii
(attribute). Bu niteliin ilk parametresi ile, metod ierisinde oluturulan _bilet isimli nesne
rneinin Soap balnda tanaca belirtmektedir. kinci parametre ilede, bu bilginin web servisi
tarafndan istemciye gidecek olan soap paketlerindeki balk ieriine eklenecei belirtilmektedir.
Bu yn belirlemek iin SoapHeaderDirectionenum sabitinden faydalanlmaktadr.

www.bsenyurt.com Page 1314


KullaniciDogrula isimli metodumuz sadece bu servis snf ierisinde kullanlan bir yedir. Daryla
bir balants olmadndan private olarak tanmlanmtr. Grevi, metoda parametre olarak gelen
bilet numaras deerine sahip bir Application deikeninin olup olmadn tespit etmektir. Eer
yoksa bir istisna nesnesi ortama, daha dorusu istemci uygulamaya frlatlr. Metodun geriye
Kullanici snf tipinden bir deer dndrmesinin tek nedeni, bu metodu kullanan web
metodlarndan, ilgili ilemi gerekletiren kullancya ait baz temel bilgilere ulalabilmesini
salamaktr. Bu ounlukla o ilemi yapan kullanc iin loglama yaplmas istendii durumlarda
yada rolne veya yetkisine gre ilgili ilemi yapabilip yapamayacana karar verilmesi gibi
durumlarda kullanlabilir.

Gelelim i yapan web metodumuza. Metodun ne i yapt ok nemli deil u aamada. Dikkat
etmemiz gereken nokta, metodun hizmeti nasl verdii. MaliyetHesapla isimli metodumuzun
da SoapHeader nitelii (attribute) tanmlanmtr. GirisYap metodundakine gre tek fark yndr.
Dikkat ederseniz SoapDirection.In deeri kullanlmaktadr. Bu, ilk parametrede belirtilen _bilet
isimli nesne rneinin, istemci uygulamadan web servisine gelecek olan Soap paketi ierisindeki
balk bilgisinde yer alacan belirtir. Eer kullanc bu metodu armadan nce sisteme giri
yapmsa elinde bir bilet numaras vardr ve Soap paketi ile bunu web servisindeki ilgili metoda
ulatrabilir. Metod ierisinde KullaniciDogrula isimli metod arlr ve eer Application nesnesi
zerinden gelen bilet numarasna sahip bir nesne var ise sz konusu metod yrtlr. Ama byle
bir bilet numaras yoksa zaten istemciye KullaniciDogrula metodu ierisinden bir istisna
frlatlacaktr.

Artk istemci tarafnda bir test uygulamas yazarak sistemi snayabiliriz. Olay daha basit
dnebilmek iin bir Console uygulamas zerinden hareket edeceiz. Uygulamamza ncelikle
web servisimizin referansn eklememiz gerektiini unutmayalm.

Web referansnn eklenmesi ile birlikte istemci uygulama tarafnda Soap balnda tanabilecek
olan Bilet tipine ait bir snfta eklenecektir.

www.bsenyurt.com Page 1315


Dikkat ederseniz Bilet snfna ait nesne rneini elde etmemizi salayan bir zellikte (property)
UrunServisi isimli proxy snfmza dahil edilmitir. BiletValue zellii Soap balnda tanan Bilet
nesne rneini okuyabilmemizi hatta atama yapabilmemizi salar. Bu ksa bakn hemen ardndan
aadaki kod satrlarn Console uygulamamzn Main metodu ierisine yazarak rneimizi
gelitirmeye devam edelim.

static void Main(string[] args)


{
try
{
UrunWebSrv.UrunServisi urnSrv = new Istemci.UrunWebSrv.UrunServisi();
urnSrv.GirisYap("bsenyurt", "1234");
Console.WriteLine("Sistem tarafndan verilen unique Id \n
{0}",urnSrv.BiletValue.BiletNumarasi);
double sonuc=urnSrv.MaliyetHesapla(1000);
Console.WriteLine("Maliyet "+sonuc.ToString());
}
catch(Exception err)
{
Console.WriteLine(err.Message.ToString());
}
Console.ReadLine();
}

www.bsenyurt.com Page 1316


Dikkat ederseniz MaliyetHesapla isimli web metodumuzu altrmadan nce sisteme giri
yapyoruz. Bunun iin GirisYap metodunu aryoruz. rnek olmas asndan Kullanicilar
tablosunda bsenyurt isimli bir kullanci oluturduk ve 1234 ifresini verdik. ( ifrelerin bu ekilde
ak olarak gitmesi ve hatta tabloda bu ekilde ak olarak saklanmas elbette doru deil. Burada
gerekirse encryption mekanizmalarnda faydalanlmas ok daha gvenli bir sistem oluturulmasn
salayacaktr. Ancak byle bir durumda istemci tarafndaki uygulamayda bizim gelitirmemiz
gerekecektir ki bu da web servisi kullanmn anlamsz klmaktadr. zm olarak Remoting tercih
edilebilir yada WSE 3.0 ile birlikte gelen gvenlik sistemleri gz nne alnabilir.) Kullanc eer web
servisi tarafndan dorulanrsa, retilen bilet numarasn servise ait nesne rneinden BiletValue
isimli zellik yardmyla elde ebiliriz. Sonrasnda ise MaliyetHesapla isimli metodumuzu
armaktayz. Uygulamamz test ettiimizde aadakine benzer bir ekran grnts elde ederiz.

Eer program bir kere daha altrrsak farkl bir GUID deeri ile karlarz. Aadaki ekran
ktsnda olduu gibi.

Bu son derece doaldr. nk uygulama her altnda Login metodu devreye girmekte ve
kullancy bulup yeni bir GUID rettirmektedir. Dolaysyla sz konusu dorulama sistemi
uygulamann ak olmas halinde, birden fazla web metodu arldnda daha efektif ileyecektir.
Byle bir durumda login olunduktan sonra retilen GUID deeri, uygulamann devamndaki tm
web metod arlarnda ayn kalacaktr. Elbette sisteme giri yapamayan bir kullanc ile
karlaldnda GirisYap metodu, istemci tarafna bir istisna frlatacaktr. rnein var olmayan bir
kullanc ile console uygulamamz denediimizde aadaki gibi bir sonula karlaabiliriz.

Tasarlanan bu sistem her ne kadar kullanl grnsede baz dezavantajlar vardr. Hereyden nce
web servisinin alt sunucunun kmesi halinde tm Application nesneleri kaybolacaktr. Hatta
kmesi haricinde, web uygulamasnn herhangibir nedenle yeniden balatlmas halinde de ayn
durum sz konusudur. Buna sebep olarak yeniden derlemeyi (compiling) ya da yeniden
datmay (publishing) gsterebiliriz. Dolaysyla sisteme giri yapan kullanc bilgilerini daha
salam bir yerde saklamak isteyebiliriz. Bu durumda Application nesnesi yerine belki bir veritaban
tablosu gz nne alnabilir. Ayrca performans arttrmak amacyla ara
bellekleme (caching) tekniklerinden de yararlanlabilir. Sonu itibariye bu iyiletirmeler yaplsada
yaplmasada iskelet ayn kalmak zorundadr. Kullancy bir ekilde dorulamak (authenticat) ve
metod arlarndan tekrar kullanc bilgisi istememek iin bilet kullanmak akllca bir yoldur. Buna
birde rol tabanl yetkilendirme gibi zellikler eklendiinde form tabanl dorulama sisteminin iskeleti
tamamlanm olacaktr. Bu makalemizde web servislerinde, soap zerinden form tabanl dorulama
sistemini nasl gerekletirebileceimizi incelemeye altk. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 1317


Burak Selim ENYURT
selim@bsenyurt.com

Nasl Yaplr : zelletirilmi SiteMapProvider


Yazmak ( 29.12.2006 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Asp.Net 2.0 ile web uygulamalarn gelitirmek artk ok daha kolaylat. Bunun en byk
nedenlerinden biriside kontrol paneline gelen ok sayda bileen olmasdr. Her ne kadar bir
yazlmcnn hayatn kolaylatran yenilikler olsada zaman zaman var olan bu yaplar zelletirme
yoluna gitmek isteyebiliriz. Bugunk makalemizin konusunu oluturan SiteMapProvider bu durumda
ele alnabilecek yeniliklerden birisidir. Asp.Net 2.0 ile gelitirilen web uygulamalarnda site haritas
kartmak ve bunu ele alacak kontrollerle almak son derece kolaydr. Yeni gelen SiteMapPath,
Menu ve TreeView kontrolleri site haritasnn etkin bir ekilde kullanlmasn salayan
bileenlerdir. Bu kontroller sayesinde kullanclarn site ierisinde hareket etmesi, nerede olduklarn
grmesi son derece kolaylamtr. Aslnda olayn znde web uygulamasna dahil
edilen web.sitemap isimli dosya ve ierii yer almaktadr. Xml tabanl olan bu dosya siteMapNode
isimli elementlerden olumaktadr. Aada rnek bir web.sitemap dosya ierii yer almaktadr.

Sz konusu olan bu xml kaynan SiteMapPath kontrol dorudan kullanrken, Menu ve TreeView
kontrolleri SiteMapDataSource bileeni zerinden ele alrlar. Dikkat ederseniz siteMapNode
elementleri i-ie (nested) bir yapya sahiptir. Bu hiyerarik yap, doal olarak site ierisindeki
sayfalar ve aralarndaki balantlar tanmlar. Ayn zamanda ilgili sayfann yol(url), aklama
(description), balk (title) gibi bilgileride ilgili kontrollere siteMapNode elementleri ile
sunulmaktadr. Ne varki burada alan sistem tamamen Xml tabanl ak bir dosyaya bamldr.
Oysaki site haritasn, gelen kullanclarn rollerine gre deitireceimiz, buna bal olaraktanda
menlerde hangi linklerin gsterileceine karar vermek isteyeceimiz senaryolar sz konusu
olabilir. En basit anlamda site haritasn Xml kayna yerine rnein bir veritaban tablosundan
getirmek isteyebiliriz. te bu ve benzeri ihtiyalar bizim SiteMapProvider tipini zelletirmemize
neden olmaktadr. SiteMapProvider zelletirmesi iin StaticSiteMapProvider isimli abstract
snfndan tretme yapacamz bir tipi ele almamz gerekmektedir. Bu zelletirme ilemine
balamadan nce bizim iin gerekli n hazrlklar yapalm. Senaryomuz gerei site haritasn Sql
Server zerinden SiteMaps isimli bir tabloda tutacaz. Tablomuzu oluturmak iin gerekli sql kodu
aadaki gibidir.

www.bsenyurt.com Page 1318


USE [AdventureWorks]
GO
SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[SiteMaps](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Baslik] [nvarchar](50) NOT NULL,
[Aciklama] [nvarchar](50) NOT NULL,
[Url] [nvarchar](50) NOT NULL,
[Ust] [int] NULL,
CONSTRAINT [PK_SiteMaps] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

Tablomuzun kolonlar temel olarak site haritas ierisinde yer alacak her bir enin sunmas
gereken nitelikleri iermektedir. Baslik bilgisi ile bir sayfann navigasyon kontrollerinde gsterilecek
olan ismini, Aciklama alan ile istemci tarayc penceresinde kacak olan tip kutucuklarnda
gsterilecek ierii, Url ile ilgili eye tklandna gidilmesi gereken sayfann adresini belirtiyoruz.
Ama belkide en nemli ksm tablo ierisindeki satrlarn kime bal olduunu belirten Ust isimli
alandr. Bu alan sayesinde bu tablo zerinde self-referencing tipinden bir iliki tanmlanmaktadr.
Bu iliki sayesinde site ierisinde hangi sayfann(sayfalarn) kimlere bal olduu(bir baka deyile
hangi sayfann alt dal olduu) bilgisini elde edebiliriz. Ksacas bu tablonun tasarmndaki ama,
web.sitemap ierisinde Xml tabanl olarak oluturulan hiyerarinin gerekletirilmesidir. Tablomuzu
oluturduktan sonra rnek olmas asndan aadaki ekran grntsnde yer alan veriler ile
doldurabiliriz.

Site haritasna ait bilgileri tayan bu tablonun bilgilerine alma zamannda ihtiyacmz olacaktr.
Bu amala kod ierisinde SiteMaps tablosundan veri ekmek iin gerekli sorgu cmlesini
tutabileceimiz gibi bir sakl yordamdan da (stored procedure) faydalanabiliriz. Aadaki sakl
yordam bu amala tasarlanmtr ve alma zamannda site haritasnn bellee yklenmesi
amacyla kullanlacaktr.

USE AdventureWorks
GO

www.bsenyurt.com Page 1319


SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO

CREATE PROCEDURE SiteHaritasiCek


AS
BEGIN
SET NOCOUNT ON;
SELECT Id,Baslik,Aciklama,Url,Ust From SiteMaps
END
GO

Artk kod tarafnda neler yapacamza bakabiliriz. Her eyden nce var
olan SiteMapPath, Menu ve TreeView kontrollerinin bakaca SiteMapProvider nesnesini
deitirmek istiyoruz. Dolaysyla bu deiiklik iin uygulamann web.config dosyas ierisinde
varsaylan salaycsn aadaki gibi deitirmemiz gerekecektir.

<system.web>
<siteMap defaultProvider="SiteHaritaSaglayicisi">
<providers>
<clear/>
<add name="SiteHaritaSaglayicisi" type="SiteHaritaYoneticisi" baglantiBilgisi="Data
Source=localhost;Initial Catalog=AdventureWorks;Integrated
Security=SSPI"spAdi="SiteHaritasiCek"/>
</providers>
</siteMap>
...

providers isimli elementin niteliklerinden name ve type mutlaka yazlmak zorundadr. Type
niteliinde (attribute) zelletireceimiz SiteMapProvider tipini belirtmekteyiz. Name niteliinde
belirtilen deer ise zellikle, kullanlmas iin her
hangibir SiteMapDatasource istemeyen SiteMapPath kontrol iin nemlidir. Nitekim bu kontrol
varsaylan olarak sitede web.sitemap isimli bir dosyay aramaktadr. Ancak senaryomuzda kendi
SiteMapProvider tipimizi yazyoruz. Dolaysyla SiteMapPath kontrolne bunu bir ekilde
sylememiz gerekecektir. te bu noktada name niteliinin ierii nem kazanmaktadr.
baglantiBilgisi ve spAdi isimli nitelikler ise SiteHaritaYoneticisi isimli snfmz ierisinde yer
alan Initialize metodundan yakalayabileceimiz niteliklerdir. Burada ama, yazm olduumuz
salayc snfn, balant bilgisi ve sakl yordam adndan bamsz olacak ekilde kullanlabilmesini
salamaktr. Artk web uygulamamzda kullanacamz SiteMapPath, Menu ve TreeView kontrolleri
hangi Site Map salaycsna bakacan bilmektedir. Gelin imdi zelletirilmi site haritas snfmz
yazalm. Snfmz herhangibir web site uygulamasna dahil edebiliriz.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

www.bsenyurt.com Page 1320


public class SiteHaritaYoneticisi:StaticSiteMapProvider
{
private string _spAdi;
private string _baglantiBilgisi;
private bool _olusturuldu;
private SiteMapNode _rootNode;

public bool Olusturuldu


{
set {
_olusturuldu = value;
}
get {
return _olusturuldu;
}
}

/* eer _spAdi ve baglantiBilgisi deerleri siteMap providers boumundan alnmamlarsa


bunlarn snf ierisindeki deikenlere atanmas ilemlerini gerekletirir.*/
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection
attributes)
{
if (!Olusturuldu)
{
base.Initialize(name, attributes);

// NameValueCollection tipinden metoda gelen attributes isimli parametre zerinden, spAdi


ve baglantiBilgisi niteliklerinin deerleri alnr.
_spAdi = attributes["spAdi"];
_baglantiBilgisi = attributes["baglantiBilgisi"];

Olusturuldu = true;
}
}

protected override void Clear()


{
lock (this)
{
_rootNode = null;
base.Clear();
}
}

/* Site haritasn tayan _rootNode isimli SiteMapNode nesnesinin oluturulmasn salar. */


public override SiteMapNode BuildSiteMap()
{
lock (this)
{
// Eer _rootNode oluturulmamsa,
if (_rootNode == null)
{
// ncelikli olarak eskiden kalan elementler varsa bunlar koleksiyondan kart
Clear();
using (SqlConnection conn = new SqlConnection(_baglantiBilgisi))

www.bsenyurt.com Page 1321


{
SqlCommand cmd = new SqlCommand(_spAdi, conn);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataTable dtNodes = new DataTable();
// Tablo bilgisi DataTable ierisine alnr.
da.Fill(dtNodes);
// Ust alannn deeri Null olan alan yani site haritasnda en stte duran satr bilgisi
alnr.
DataRow drRoot = dtNodes.Select("Ust is null")[0];
// _rootNode oluturulur.
_rootNode = new SiteMapNode(this, drRoot["Url"].ToString(),
drRoot["Url"].ToString(), drRoot["Baslik"].ToString(), drRoot["Aciklama"].ToString());

// o anki node(boum)' un ID alann deeri alnr ve recursive (yinelemeli) alan


AltNodeEkle metodu tetiklenir.
string rootID = drRoot["ID"].ToString();
AltNodEkle(_rootNode, rootID, dtNodes);
}
}
return _rootNode;
}
}

/* Recursive (yinelemeli) olarak alan bu metod, site hiyerarisinin root node(boum)' undan
en alt node(boum)' una kadar dolamakla ve ilgili boumlar birbirlerinin altna eklemekle
grevlidir. */
private void AltNodEkle(SiteMapNode ustNod, string rootID, DataTable dt)
{
// Gelen satrn altndaki satrlar tespit etmek iin dataTable ierisinde select atlr.
DataRow[] altNodlar = dt.Select("Ust = " + rootID);
// Her bir alt satr dolalr
foreach (DataRow row in altNodlar)
{
// O anki node(boum) oluturulur ve yine o anki satrn ID deeri alnr.
SiteMapNode cocukNod = new SiteMapNode(this,row["Url"].ToString(),
row["Url"].ToString(),row["Baslik"].ToString(), row["Aciklama"].ToString());
string rowID = row["ID"].ToString();

// node(boum) st node(boum)' a eklenir.


AddNode(cocukNod, ustNod);
// Recursive metodumuz tekrardan o anki satr ve node(boum) iin altrlr.
AltNodEkle(cocukNod, rowID, dt);
}
}

// SiteMapNode' un elde edilmesini, bellekte oluturulmasn salar bir SiteMapNode referans


olarak geriye dndrlmesini salar.
protected override SiteMapNode GetRootNodeCore()
{
return BuildSiteMap();
}

// Bellekte oluturulan siteMapNode' un elde edilmesini salayan zellik. (Readonly)


public override SiteMapNode RootNode
{
get {

www.bsenyurt.com Page 1322


return BuildSiteMap();
}
}
}

SiteHaritaYoneticisi isimli snfmz StaticSiteMapProvider abstract snfndan tremitir. Aslnda


StaticSiteMapProvider snfda SiteMapProvider snfndan tremitir. StaticSiteMapProvider snf,
tredii SiteMapProvider snfnn biraz daha ufaltlm bir srmdr. Bu nedenle kendi
SiteMapProvider tiplerimizi gelitirirken ok fazla kod dnmemizi engelleyici nitelikte olduundan
tercih edilmektedir. yleki snfmzdan grdnz gibi bir ka temel ye ile istediimiz
zelletirilmi salayc snf yazabiliyoruz. Aadaki ekil sz konusu tipler arasndaki ilikisel
durumu daha net aklamaktadr.

Biz rnek snfmz ierisinde, st snflarda abstract olarak


tanmlanm BuildSiteMap ve GetRootNodeCore isimli metodlar eziyoruz. Bu metodlar snfn
can alc noktalardr. Grevleri ilgili kaynaktan bellee ekilen veriye gre oluturulan Root Node'
un (ki bu boumda hiyerarik olarak alt boumlar ile birlikte gelecektir) ilgili kontrollere verilmesini
salamaktr. Burada sz konusu olan kontrollerimiz ise SiteMapPath, Menu ve TreeView
kontrolleridir. Initialize metodu, alma zamannda BuildSiteMap ve GetRoodNodeCore yelerden
nce alt iin, balant bilgisinin ve sp adnn web.config dosyasndaki yerlerinden alnmalar
iin en ideal yerdir. Snfmz kullanacak olan web sitemizde aadaki sayfalarmzn yer aldn

www.bsenyurt.com Page 1323


dnebiliriz. Sayfalarmz tablomuzdaki bilgilere gre tasarlamamz nemlidir. Aksi takdirde krk
linkler ile karlabiliriz.

Tm sayfalarda navigasyon kontrollerimizi kolayca ele alabilmek iin bir web user control (kullanc
web kontrol) bileenini aadaki gibi gelitireceiz. Kullanc web kontrolmz ierisinde
SiteMapPath, Menu ve TreeView kontrollerimizi kullanacaz. Ancak dikkat etmemiz gereken baz
noktalar var. Bunlardan birisi SiteMapPath kontroln srkleyip braktmzda yazm olduumuz
SiteHaritaYoneticisi tipine balanmaddr. Bunu salamak iin SiteMapPath
bileenimizin SiteMapProvider zelliine SiteHaritaSaglayicisi provider deerini vermemiz
gerekmektedir. Bu provider web.config dosyasnda kullanlacak olan SiteHaritaYoneticisi tipini iaret
ettii iin SiteMapPathkontrolmzn veriyi nereden alaca belirlenmektedir.

<asp:SiteMapPath ID="SiteMapPath1" runat="server" Font-Names="Verdana" Font-Size="0.8em"


PathSeparator=" : " SiteMapProvider="SiteHaritaSaglayicisi">
<PathSeparatorStyle Font-Bold="True" ForeColor="#990000" />
<CurrentNodeStyle ForeColor="#333333" />
<NodeStyle Font-Bold="True" ForeColor="#990000" />
<RootNodeStyle Font-Bold="True" ForeColor="#FF8000" />
</asp:SiteMapPath>

Benzer problem TreeView kontrol iinde geerli olacaktr. Normal artlarda TreeView kontrol ve
Menu kontrollerini kullanrken bir SiteMapDataSource bileenine balamamz yeterlidir.
SiteMapDataSource bileeni otomatik olarak web.config dosyasndaki ayarlara bakacandan, ilgili
kontrollere site haritasn balamak iin hangi tipin ele alnmas gerektiini bilmektedir. Lakin
TreeView kontrol bu ayarlamalara ramen site haritas ierisindeki yeleri gsteremeyecektir. Bu
sorunu zmek iin veri balama ilemini (TreeNode DataBindings) tasarm tarafndan yada
kaynak kod tarafndan doru ekilde ayarlamak gerekmektedir.

www.bsenyurt.com Page 1324


<asp:TreeView ID="TreeView1" runat="server" DataSourceID="SiteMapDataSource1"
ImageSet="Arrows" ShowLines="True">
<ParentNodeStyle Font-Bold="False" />
<HoverNodeStyle Font-Underline="True" ForeColor="#5555DD" />
<SelectedNodeStyle Font-Underline="True" ForeColor="#5555DD" HorizontalPadding="0px"
VerticalPadding="0px" />
<NodeStyle Font-Names="Verdana" Font-Size="8pt" ForeColor="Black"
HorizontalPadding="5px" NodeSpacing="0px" VerticalPadding="0px" />
<DataBindings>
<asp:TreeNodeBinding DataMember="SiteMapNode" NavigateUrlField="Url"
SelectAction="Expand" TextField="Title" ToolTipField="Description" />
</DataBindings>
</asp:TreeView>

Burada dikkati eken noktalardan birisi TreeNodeBinding elementi


ierisinde NavigateUrlField, TextField, ToolTipField niteliklerinin baktklar alan adlardr. Bizim
tablomuzdaki alan adlar hatrlayacanz gibi, Baslik, Aciklama ve Url olarak isimlendirilmiti. Peki
nasl oluyorda bunlar birbirleriyle eleiyorlar? Bunu salayan elbetteki SiteMapNode snfnn

www.bsenyurt.com Page 1325


yapc metodudur. SiteHaritaYoneticisi snf ierisinde boumlar olutururken bu snfn yapc
metoduna o anki tablo satrndan ilgili deerler aktarlmaktadr. te elemenin gerekletii yer
burasdr. Aadaki ekran grntsnde yapc metodun alaca parametreler ak bir ekilde
grlmektedir.

Artk yapmamz gereken tm hazrl tamamlam durumdayz. Uygulamamz test edersek eer,
kontrollerimizin baarl bir ekilde ilgili tabloya balandn grebiliriz. rnein aadaki ekran
grntsnde Bayan Giyim sayfasna gidilmitir.

Grdnz gibi, Site haritasn Xml bamllndan kurtarma ansna sahibiz. Elbette yazlan bu
tip uygulamalarda performasda dnecek nitelikte tedbirler almak gerekebilir. rnein site
haritasn tutan SiteMapNode' un arabellee alnmas dnlerek daha hzl alan bir men
sistemi tasarlanabilir. Nitekim uygulamamzda sayfann istemciden sunucuya her postalannda,
sunucu tarafndan ilgili sakl yordam sayfann yaam dngs ierisinde altrlacaktr. te
buradaki performans kayplarnn nne gemek iin ara bellek sistemi (caching) dnlebilir.
Benzer ekilde ilgili snf ierisinde siteye dahil olan kullancnn yetkilerinin kontrol edilmesi ve
datann buna gre ekilerek ilgili boumlarn dzenlenmesi dnelebilir. Ancak k noktamz
yukarda bahsettiimiz gibidir. Bu makalemizde ksaca site haritamz nasl zelletirebileceimizi
grdk. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 1326


rnek uygulama iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Nasl Yaplr : Connected(Bal) Web Parts (


26.12.2006 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Web uygulamalarmzda kullanabileceimiz saysz sunucu tabanl kontrol vardr. Gelitirdiimiz


uygulamalarda baz durumlarda birden fazla kontroln kullanld web sayfalarmz sz konusu
olabilir. Bu tarz durumlarda kodlar merkeziletirmek, istenen kontrolleri tek bir noktadan
gncelleyebilmek amacyla kullanc web kontrollerine (web user control) bavurabilir yada kendi
web sunucu kontrollerimizi yazabiliriz. zellikle kendi web sunucu kontrollerimizi var olan bir
kontrolden tretme (inheritance) yardmyla gelitirebileceimiz gibi sfrdan da yazabiliriz. (Kendi
web kontrollerimizi oluturmak ile ilgili olarak ilerleyen zamanlarda bir makale hazrlamay
dnyorum.)

Asp.Net 2.0 mimarisi ile birlikte sayfaya bal olan kullanclara gre zelletirebileceimiz Web Part
kavram ile karlatk. Web Part kontrolleri birer sunucu kontrol olmakla birlikte, zelliklerini
kiiletirebilme ve farkl kullanclar iin farkl veriler tayabilme yeteneine sahip kontroller olarak
karmza kmaktadr. Aslnda SharePoint mimarisini kendi web uygulamalarmzda kullanabilme
amacyla tasarlanm kontrollerdir. rnein web part kontrolleri sayfa zerinde srkleme,
minimize etme gibi grsel ilemleri gerekletirebiliriz ki buda SharePoint tarz portal
uygulamalarnn en byk zelliklerindendir. Web Part kontrolleri, kiiselletirme
(Personalization) iinde nemli kabiliyetler sunmasna ramen baz noktalarda kullanm olduka
karmak olabilmektedir. rnein web part kontrolleri arasnda veri iletiiminde bulunmak bir baka
deyile, birbirleriyle haberleebilen web part kontrolleri gelitirmek. te bu makalemizde web part
kontrolleri aras balantlarn nasl salanabileceini adm adm incelemeye alacaz.

zellikle kendi gelitireceimiz Web Part kontrollerinde, kontroller arasnda bilgi tamak
isteyeceimiz durumlar sz konusu olabilir. Bu istek, var olan kontroller dnldnde ok da
zel bir konu deildir. Ama iin ierisine kiiselletirilebilir, bir Web Part Zone' dan dierine
srklenebilir, minimize edilebilir vb Web Part kontrolleri girdiinde farkl bir teknik kullanmak
gerekmektedir. rnein herhangibir veri ierii zerinde arama yapmamz salayacak bir web part
kontrolnn baka bir web part kontrolne aranacak deeri aktarmasn istediimizi dnelim.
Verinin aktarld Web Part kontrol zerinde de arama yaplan deere gre ilgili sonularn
gsterilmesini isteyebiliriz. Peki bu tarz bir ihtiya iin gerekenler nelerdir?

Kendi Web Part kontrollerimizden bahsettiimiz iin WebPart tipinden treyen snflar
gelitirmemiz gerekiyor. Bu web part kontrollerimizden birisi dier web part kontrol iin veri
salayc nitelik olucakken dieride bu veriyi tketici nitelikte olacaktr. Genellikle veriyi salayacak
olan web part kontrol Provider olarak adlandrlmaktadr. Provider Web Part kontrolnn
sunaca ierii kullanacak olan dier Web Part kontrolmz ise Consumer (tketici) olarak
adlandrlmaktadr. Provider grevini stlenen bir Web Part kontroln birden fazla Consumer
kullanabilir. Provider Web Part kontrolnn gnderecei veriyi, Consumer niteliinde olan bir Web
Part kontrolnn(lerinin) alabilmesi iin, Provider Web Part kontrolne bir arayz (interface)
uygulanmas gerekmektedir. Bu arayz(Interface), Provider Web Part kontrolnden Consumer
Web Part kontrolne nesne referans tanmasnda rol almaktadr. Bylece ilgili referans zerinden
Provider Web Part kontrol ile gelen veriyi tama ve Consumer Web Part kontrolnden(lerinden)
alma ansna sahip olabiliriz. Son olarak her iki web part kontrol arasnda arayz yardmyla
refarans tayabilmek iin balant noktalarna (Connection Part) ihtiyacmz olacaktr. Balant

www.bsenyurt.com Page 1327


noktalar aslnda zel nitelikler(attribute) ile imzalanm metodlardr. Aadaki ekilde ihtiyacmz
olanlar zetlenmeye allmtr.

Artk bir rnek zerinden adm adm ilerleyerek Web Part kontrolleri aras nasl veri
tayabileceimizi incelemeye balayabiliriz. lk olarak rnek bir senaryo gz nne alalm. Provider
(Salayc) grevini stlenecek kontrolmzde arama ilemi iin veri girilebilecek bir kutucuk
olduunu ve buraya bir rn ad yazlabileceini dnelim. ( rnlerimizi Sql Server 2005 ile gelen
AdventureWorks veritabanndaki Product tablosundan ekebiliriz. ) Bu noktadan sonra arama
szc Consumer grevini stlenecek olan Web Part kontrolne aktarlacak ve bulunan bilgiler bir
GridView kontrol ierisinde gsterilecektir. Senaryo gerei en az iki web part kontrolne
ihtiyacmz olacak. Bu kontrollerin en byk zellii WebPart snfndan treyecek olmalardr.
Bylece ilerine kiiselletirilebilir yeler dahil edebilir, ayn zamanda birbirlerine balayabiliriz.
Web Part kontrollerimizi ve aradaki balanty tesis etmekte kullanacamz arayz(interface)
tipimizi ayr bir ktphane (library) halinde tasarlarsak, Visual Studio.Net ToolBox' na ekleme ve
farkl web projelerinde kullanma ansna da sahip oluruz. Bu nedenle basit bir Web Control Library
projesi gelitirerek ie balayabiliriz. Yazacamz tipler aada yer almaktadr.

www.bsenyurt.com Page 1328


IcerikSaglayici ve IcerikKullanici isimli Web Part kontrollerimiz, WebPart abstract snfndan
tretilmitir. Bylece kiiselletirme gibi zelliklere sahip olabilirler. En nemliside birbirlerine
balanabilirler. IAnlasma isimli arayzmz, IcerikSaglayici' dan, IcerikKullanici kontrolne
aktarlacak olan veriyi basit bir zellik(property) olarak tanmlamaktadr. u anda bu veri bizim iin
ArananBilgi isimli zelliktir. Hatrlarsanz veri salayc Web Part kontrolnn, tanacak veriyi
ieren referans aktarabilecek bir arayz kullanmas gerektiinden bahsetmitik. te bu nedenle
IcerikSaglayici kontrolmze IAnlasma arayz uygulanmaktadr.

Web Part kontrollerimizdeki belkide en nemli yeler balant noktas (Connection


Point) metodlardr. IcerikSaglayici Web Part kontrolmzde bu grevi SaglayiciBaglantiNoktasi
isimli metodumuz stlenmektedir. IcerikKullanici Web Part kontrolmzde ise
TuketiciBaglantiNoktasi bu grevi stlenir. SaglayiciBaglantiNoktasi metodu geriye IAnlasma
arayznn tayaca bir referans gndermektedir. Sz konusu referans alma zamannda,
IcerikSaglayici kontrolnn nesne rneinden bakas deildir. Bu referans alacak olan
tketici(consumer) yemiz TuketiciBaglantiNoktasi ise, IAnlasma tipinden bir arayz parametre
olarak almaktadr. Dolaysyla alma zamannda bu iki metod birbirleri ile haberleme (u an iin
tek ynl bir haberleme sz konusudur) yeteneini kazanmaktadr. Tabiki bu yelerin, birbirlerine
ulaabilmelerini salamak iin ilgili niteliklerle (attributes) imzalanmalar ve Web Part' larn bir
birlerine ya dinamik olarak yada statik olarak balanmalar gerekecektir. Ama ncesinde kod
tarafnda yaptklarmza ksaca bakalm.

IAnlasma arayz (interface);

public interface IAnlasma


{

www.bsenyurt.com Page 1329


string ArananBilgi
{
get;
set;
}
}

IcerikSaglayici Web Part kontrol;

public class IcerikSaglayici:WebPart,IAnlasma


{
private string _urunAdi;
private TextBox _aramaAlani;
private Button _btnAra;

/* Web Part ierisindeki kontrolleri oluturmak iin CreateChildControls metodunu eziyoruz.*/


protected override void CreateChildControls()
{
// nce Web Part zerindeki kontrolleri temizleyelim.
Controls.Clear();

// Web Part kontrolnn balk bilgisini deitiriyoruz.


Title = "rn Arama";

// Aranacak bilginin girilecei TextBox kontroln tanmlayp Controls koleksiyonuna


ekliyoruz.
_aramaAlani = new TextBox();
Controls.Add(_aramaAlani);

// Arama emrini verecek olan Button kontrolmz oluturuyoruz.


_btnAra = new Button();
_btnAra.Text = "Bakacam rn";
_btnAra.BackColor = System.Drawing.Color.Gold;
_btnAra.BorderColor = System.Drawing.Color.Gray;
_btnAra.BorderStyle = BorderStyle.Dashed;
_btnAra.BorderWidth = 2;
_btnAra.Font.Bold = true;
// Anonymous(isimsiz) metod yardmyla Button' a basldnda yaplmas gerekenleri
belirtiyoruz.
_btnAra.Click += delegate(object sender, EventArgs e)
{
// TextBox' a girilen bilgiyi ArananBilgi isimli zellie atyoruz.
ArananBilgi = _aramaAlani.Text;
};
Controls.Add(_btnAra);
}

#region IAntlasmaYuzu Members

/* ArananBilgi isimli zellii kiiselletirilebilir olarak tanmlyoruz. Bylece siteye giren her farkl
kullanc iin farkl ekilde tutulabilecektir. */
[Personalizable( PersonalizationScope.User)]
public string ArananBilgi
{
get {
return _urunAdi;

www.bsenyurt.com Page 1330


}
set {
_urunAdi = value;
}
}

#endregion

// Balant noktamz ConnectionProvider nitelii ile belirtiyoruz.


[ConnectionProvider("Arama Balant Noktas","SaglayiciNokta")]
public IAnlasma SaglayiciBaglantiNoktasi()
{
return (IAnlasma)this; // O anki IcerikSaglayici nesne rneinin referansn IAnlasma
tipinden olacak ekilde geri dndryoruz.
}
}

IcerikKullanici Web Part kontrol;

public class IcerikKullanici : WebPart


{
private string _arananUrun;
private Label _lblGelenUrunAdi;
private GridView _grdUrunler;

// Balant noktas olmas iin ConnectionConsumer nitelii ile imzalyoruz.


[ConnectionConsumer("Tketici Balant Noktas","TuketiciNokta")]
public void TuketiciBaglantiNoktasi(IAnlasma anls)
{
_arananUrun= anls.ArananBilgi; // Salaycdan gelen referansn zerinden ArananBilgi
zelliinin deerini alyoruz.
CreateChildControls(); // Alnan deer gre web part zerindeki kontrollerin tekrardan
oluturulmasn salyoruz.
}

protected override void CreateChildControls()


{
Controls.Clear(); // nce kontrolleri kaldrp sahay temizliyoruz.

// Web Part' n balk bilgisini deitiriyoruz.


Title = "Arama Sonular";

// Aranan bilgiyi gsterecek Label kontroln oluturup Web Part' a ekliyoruz.


_lblGelenUrunAdi = new Label();
if (!String.IsNullOrEmpty(_arananUrun)) // Eer _arananUrun alannn deeri bo yada null
deilse eklemesini salyoruz
_lblGelenUrunAdi.Text = _arananUrun;
_lblGelenUrunAdi.ForeColor = System.Drawing.Color.Red;
_lblGelenUrunAdi.Font.Bold = true;
_lblGelenUrunAdi.Font.Size = 12;
Controls.Add(_lblGelenUrunAdi);

// Bir alt satra geme iin Literal kontrol kullanyoruz.


Literal ltr = new Literal();
ltr.Text = "<br/>";
Controls.Add(ltr);

www.bsenyurt.com Page 1331


// gelen arama bilgisine gre veri ekme ve GridView kontrolne balama ilemlerini
gerekletiriyoruz.
if (!String.IsNullOrEmpty(_arananUrun))
{
using (SqlConnection conn = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlDataAdapter da = new SqlDataAdapter("Select
ProductId,Name,ListPrice,SellStartDate From Production.Product Where Name Like '%" +
_arananUrun + "%'", conn);
DataTable dt = new DataTable();
da.Fill(dt);
_grdUrunler = new GridView();
_grdUrunler.DataSource = dt;
_grdUrunler.DataBind();
Controls.Add(_grdUrunler);
}
}
}
}

imdi gelitirmi olduumuz bu ktphaneyi herhangibi web uygulamasnda kullanmak zere


aadaki gibi ToolBox' a ekleyelim. Bunun iin ToolBox' ta Choose Items' a gememiz ve
assembly' mz bulup IcerikSaglayici ve IcerikKullanici kontrollerini sememiz yeterli olacaktr.
rnek olarak ben General sekmesi altna ekledim.

Assembly' n seildii iletiim kutusu;

www.bsenyurt.com Page 1332


ToolBox' n grnm;

Gelitirdiimiz kontroller birer Web Part kontroldr. Bu sebeptende ilgili web sayfasnda Web Part
Zone' lar ierisinde kullanlp birbirlerine balanabilmeleri iin statik veya dinamik balama
tekniklerinden birisini tercih etmemiz gerekmektedir. Dinamik balama tekniine gre, web part
kontrollerinin birbirlerine balanmasn sayfa zerinden gerekletirme imkanna sahip oluruz.
Bunun iin web sayfas zerinde bir ConnectionsZone olmas yeterlidir. Ayrca kullancnn
dinamik balama seeneini kullanmas halinde ilgili Web Part Zone' lar zerinden Connect Verb'
nn kullanlabilir olmas gerekecektir. Bu nedenlede sayfada yer
alan WebPartManager kontrolnn DisplayMode zelliinin ConnectDisplayMode olmas
gerekir. ounlukla Web Part kullanldnda, Display Mode' larn alma zamannda
deitirilebilmesi iin Menu kullanm tercih edilmektedir. Bizim amacmz sadece ConnectionsZone'
u kullanmak olduu iin, fazla uramadan sayfann Page_Load ksmnda aadaki kod
parasnda gsterildii gibi DisplayMode' u belirliyoruz.

protected void Page_Load(object sender, EventArgs e)


{
if(!Page.IsPostBack)
wpManager.DisplayMode = WebPartManager.ConnectDisplayMode;
}

Sayfamzn tasarmn ise aadaki gibi gelitirebiliriz.

www.bsenyurt.com Page 1333


Artk uygulamamz test edebiliriz. Salkl sonular alabilmek iin web uygulamasnda Form tabanl
gvenlik sistemi uygulanmtr. Ama hem Web Part kontrolleri aras bilgi tamak hemde bu Web
Part' larn giren kullanclara gre kiiselletirilebilmesini salamaktr. Biz dinamik balama tekniini
tercih ettiimiz iin ncelikli olarak kullanclarn ilgili Web Part kontrollerini birbirlerine balamalar
gerekecektir. rneimizde bu balant yn IcerikSaglayici kontrolden, IcerikKullanici kontrole
doru olmaldr. Bu sebepten alma zamannda IcerikSaglayici Web Part kontrolmzn
bulunduu Zone' da Connect men esi seilmelidir.

www.bsenyurt.com Page 1334


Connect linkine tkladmzda ConnectionsZone bileeni grnr hale gelecektir. Henz bir balant
tanmlamadmz iin No active connections mesajn almaktayz.

imdi Create a Connection to a Consumer linkine tklarsak, IcerikSaglayici Web Part


kontrolnden, IcerikKullanici Web Part kontrne doru bir balant tanmlamamz yeterli olacaktr.

Artk Web Part kontrollerimiz arasnda veri tayabiliriz. Aadaki Flash animasyonunda
uygulamann rnek almas gsterilmektedir. (Animasyonu izleyebilmek iin en azndan
sisteminizde Flash 6 Player' nn ykl olmas geremektedir.)

www.bsenyurt.com Page 1335


Buraksenyurt isimli kullanc sisteme girdikten sonra rn Arama balkl Web Part kontrolnden,
aramak istedii kelimeleri giriyor. Button kontrolne basldnda ise bulunan sonular Arama
Sonular balkl Web Part kontrolnde GridView nesnesinde gsteriliyor. u anda buradaki tm
ayarlar buraksenyurt kullancs iin kiiselletirilmitir. zellikle arama alan bilgisi
kiiselletirildiinden, buraksenyurt isimli kullanc sisteme tekrar girdiinde son arad rn bilgisi
ve sonular ile karlaacaktr. Dolaysyla farkl kullanclar iin farkl arama bilgisi ve sonular
tutulabilecektir.

rneimizde kullandmz dinamik balama teknii dnda, Web Part kontrollerini birbirlerine
statik olarakta balayabiliriz. Tek yapmamz gereken Web Part Manager elementi ieriini aadaki
gibi deitirmektir.

<asp:WebPartManager ID="wpManager" runat="server">


<StaticConnections>
<asp:WebPartConnection ID="StatikBaglayici" ProviderConnectionPointID="SaglayiciN
okta" ProviderID="IcerikSaglayici1" ConsumerConnectionPointID="TuketiciNokta"ConsumerI
D="IcerikKullanici1" />
</StaticConnections>
</asp:WebPartManager>

Dikkat ederseniz WebPartConnection elementi ierisinde icerik salayc ve tketici iin gerekli Id
tanmlamalar yaplmaktadr. ProviderConnectionPointID nitelii (attribute), IcerikSaglayici Web
Part kontrolndeki balant noktas metodunda yer alan ConnectionProvider niteliinin ikinci
parametresinin deeridir.

www.bsenyurt.com Page 1336


[ConnectionProvider("Arama Balant Noktas","SaglayiciNokta")]
public IAnlasma SaglayiciBaglantiNoktasi()
{

Benzer ekilde ConsumerConnectionPointID niteliinin deeride, IcerikKullanici Web Part


kontrolndeki balant noktas metodunda yer alan ConnectionConsumer niteliinin ikinci
parametresinin deeridir.

[ConnectionConsumer("Tketici Balant Noktas","TuketiciNokta")]


public void TuketiciBaglantiNoktasi(IAnlasma anls)
{

ProviderID ve ConsumerID niteliklerinin deerleri ise, ilgili Web Part kontrollerimizin ID


niteliklerinin deerleridir. Uygulamamz bu haliyle test ettiimizde sonularn deimediini
grrz. Tabiki test amacyla sayfadaki ConnectionsZone nesnesini kaldrmak ve Web Part
Manager kontrol iin DisplayMode zelliini set etmemek gerekmektedir.

Bu makalemizde kendi Web Part kontrollerimiz arasnda veri aktarm amacyla balantlarn
(Connections) nasl kurulabileceini incelemeye altk. Burada grdmz teknik sadece tek
ynl bir balama seenei sunmaktadr. Birde Consumer' dan Provider' a doru veri aktarmak
isteyebileceimiz vakkalar olduunu dnmek gerekir. Bu durumda iki ynl balantlar sz
konusu olacaktr. Bu konunun aratrmasnda siz deerli okurlarmza brakyorum. Bylece geldik
bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek uygulama iin tklayn. (nemli Not: Dosya boyutunun byk olmas nedeniyle,
kiiselletirme amacyla kullanlan ve App_Data klasrnde yer alan Aspnetdb.mdfveritaban
dosyas silinmitir. Test ederken ltfen Asp.Net Configuration Tool' unda ilgili veritabannn
oluturulmasn salaynz ve en azndan rnek iki kullancy sisteme dahil ediniz.)

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net 2.0 ve Client Script Callback (


17.12.2006 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Web sayfalarmzda karlatmz sorunlardan bir tanesi post-back hareketlerine neden olacak
davranlarn ok fazla olabilmesidir. Varsaylan olarak bir Button' n grevi sayfay istemciden
sunucuya ierii ile birlikte gndermektir. Dier yandan baz bileenlerin AutoPostback zelliklerine
true deeri atanarak istemci tarafndan sunucuya doru postalama ilemi yapmalar da
salanabilmektedir. Fakat baz durumlarda sayfann tamamn sunucuya doru postalamak
istemeyebiliriz. rnein il ve ile bilgilerini ayr ayr tutan DropDownList kontrollerinin olduu bir
senaryoda; bir il seildiinde buna bal ilelerin yklenmesi iin sayfannn tamamiyle sunucuya
gidip gelmesi gerekecektir. Byle bir durumda sayfann daha nceden istemci tarafna yklenmi
pek ok paras gereksiz yere tekrardan sunucu tarafndan istemciye doru gnderilecektir. Her ne
kadar arabellee (caching) alma gibi tekniklerle sunucudan istemciye gelecek olan cevabn daha da
hzlandrlmasn salayabilsekte, sayfann tamamnn postalanmasn engellemek ve sadece
gereken ksmlarnn gncellenmesi iin ilgili paralarn postalanmasn salayabilmek daha etkili bir

www.bsenyurt.com Page 1337


zmdr. Tahmin edeceiniz gibi bu yaklam modeli gnmzde Ajax veAtlas.Net gibi
teknolojik terimlerle karmza kmaktadr.

Biz bu makalemizde Asp.Net 2.0 zerinde istemci tarafndan geri bildirim (client script callback)
ilemlerinin kolay bir ekilde nasl yaplabileceini incelemeye alacaz. lk olarak alma
modelinden bahsedelim. Barol oyuncumuz ICallbackEventHandler arayzdr. Bu arayz ilgili
web sayfasna ait snfamza uygulamamz gerekmektedir. Uygulanan arayz beraberinde iki metod
sunmaktadr. Bu metodlar GetCallbackResult ve RaiseCallbackEvent yeleridir.
RaiseCallbackEvent metodu string tipinden bir parametre alr. Bu parametrenin rol olduka
nemlidir. Nitekim istemci tarafndan yada baka bir deyile tarayc tarafndan sunucuya doru
string tipte bir deer tanmas gerekmektedir. rnein illeri gsteren DropDownList kontrolnn
seilen deerinin string karl, parametre olarak istemci tarafna
gelebilir. GetCallbackResult metodu ise, geriye string tipinden bir deer dndrmektedir.
Dolaysyla bu deer istemci tarafndan ele alnacak bilgiyi iermektedir. rnein seilen ile bal
ileleri bu dn deeri olarak dnebiliriz. Buradaki tek problem, istemciden sunucuya gelen
yada sunucudan istemciye dnen bilgilerin string tabanl olmasdr. Bu sebepten istemci tarafndada
bir Javascriptkodunun GetCallbackResult metodundan dnen deeri ele alacak ekilde yazlm
olmas gerekecektir. Benzer ekilde sunucudan istemciye gnderilecek string bilgininde zel olarak
hazrlanmas gerekecektir. Nitekim istemci tarafndan ayrtrlarak kullanlmas sz konusu olabilir.
Bu gereksinimlerin karlanmasnn ardndan sunucu tarafnda yapmamz gereken tek ey,
istemcinin RaiseCallbackEvent metodunu nasl tetikleyeceini bildirmek olacaktr. Bu amalada
.Net' in sunuduu baz metodlardan faydalanabiliriz. Bu metodlar yardmyla sunucu tarafndan
istemci zerine javascript kodu eklemek gibi ilemleri gerekletirebilmekteyiz. Sonu olarak elde
edeceimiz mimari model aadaki ekildekine benzer olacaktr.

www.bsenyurt.com Page 1338


Dilerseniz bir rnek zerinden devam edelim. Senaryomuzda AdventureWorks veritabannda yer
alan ProductSubCategory ve ProductCategory tablolarn ele alacaz. lk olarak web sayfamz
aadakine benzer bir ekilde tasarlayarak ie koyulalm.

stemci Kategoriler' in tutulduu DropDownList bileeninden bir e setiinde sayfann tamam


sunucuya gnderilmeden, sadece bizim iin gerekli olan Alt Kategoriler gelecek ve ilgili
DropDownList bileenine dolacak. Aslnda Alt Kategorileri gsteren DropDownListe' e dolacan
sylemek ok doru bir yaklam deildir. Nitekim, istemci tarafnda var olan HTML ktsnda
DropDownList kontrol bir select taks olarak grnr. eleri ise ieride birer Option taks olarak
yer almaktadr.

Dolaysyla Alt Kategorileri doldurmak ile kastettiimiz; istemciye gelen string cevabn ierisindeki
alanlar ayrtrarak, ilgili select taks ierisine birer option taks olarak eklemektir. Tekrardan
rneimize dnebiliriz. lk olarak kategorileri ProductCategories tablosundan yklememiz
gerekmektedir. Kategorileri doldurmak iin SqlDataSource bileninden faydalanabiliriz. Select
sorgumuz ierisinde ProductCategoryID ve Name alanlarn ekiyoruz.

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


Inherits="_Default" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>Kategoriler<br />
<asp:DropDownList ID="ddlKategoriler" runat="server"
DataSourceID="dsKategoriler" DataTextField="Name" DataValueField="ProductCategoryID">
</asp:DropDownList>
<asp:SqlDataSource ID="dsKategoriler" runat="server" ConnectionString="<%$
ConnectionStrings:AdvConStr %>" SelectCommand="SELECT ProductCategoryID, Name FROM
Production.ProductCategory">

www.bsenyurt.com Page 1339


</asp:SqlDataSource>
Alt Kategoriler<br />
<asp:DropDownList ID="ddlAltKategoriler" runat="server">
</asp:DropDownList>
</div>
</form>
</body>
</html>

Bir sonraki admmz olarak sayfamza ICallbackEventHandler arayzn uygulamamz


gerekiyor. Default.aspx sayfamz iin sunucu tarafnda yazlacak olan kodlar aadaki gibi
olacaktr.

private string _kategoriId;

public string GetCallbackResult()


{
using(SqlConnection conn=new
SqlConnection(ConfigurationManager.ConnectionStrings["AdvConStr"].ConnectionString))
{
/* istemciden gelen CategoryId deerine gre SubCategory' ler ekilir ve bir StringBuilder
yardmyla bir dn bilgisi oluturulur. */
SqlCommand cmd = new SqlCommand("Select ProductSubCategoryID,Name From
Production.ProductSubCategory Where ProductCategoryId=@CatId", conn);
cmd.Parameters.AddWithValue("@CatId", _kategoriId);
conn.Open();
SqlDataReader dr = cmd.ExecuteReader();
StringBuilder builder = new StringBuilder();
while (dr.Read())
{
builder.Append(dr["ProductSubCategoryID"].ToString());
builder.Append("|"); // Field' lar birbirlerinden ayrabilmek iin tek pipe konulur.
builder.Append(dr["Name"].ToString());
builder.Append("||"); // satr sonlar iin ift Pipe konulur.
}
dr.Close();
return builder.ToString();
}
}

public void RaiseCallbackEvent(string eventArgument)


{
/* istemci tarafndan tetiklenen bu metoda gelen string parametre deerini alp sayfa
seviyesindeki bir deikene atyoruz. */
_kategoriId = eventArgument;
}

Burada GetCallbackResult metodundan geriye dndrdmz string bilgiyi oluturma eklimiz


eminimki dikkatinizi ekmitir. Bunun en byk nedeni az nce bahsettiimiz gibi DropDownList
kontrolnn istemci tarafnda bir select taksna dnmesi ve elemanlarnn birer option haline
gelmesidir. Sonu itibariyle istemci tarafndaki DropDownList kontrolnn Html ktsnn
tayabilecei deerler gz nne alndnda bunlar toplu bir halde tek bir string olarak
gndermek yeterli deildir. Gnderilen string bilginin istemci tarafndaki fonksiyon ierisinde
ayrtrlabilmesi gerekecektir ki gelen bilgileri ayrtrarak select taks ierisine birer option olarak
ekleyebilelim. Bu sebepten ProductSubCategoryId ve Name alanlarnn arasna | gelecek ve her bir

www.bsenyurt.com Page 1340


satrn sonundada || gelecek ekilde bir string oluturulmas tercih edilmitir. Elbette burada |
iaretini kullanmak zorunda deiliz. Bunun yerine yldz yada virgl gibi sembolllerde konulabilir.
Ancak elbette bu sembollerin okuduumuz alanlarn ierisinde yer almamasna dikkat etmeliyiz.
Byle bir durumda istemci tarafndaki fonksiyon, satrlar ve dolaysyla alanlar doru bir ekilde
ayrtramayacaktr.

Gelelim istemci tarafndaki fonksiyonumuza. Bu fonksiyonun temel


grevi, GetCallbackResult metodundan dnecek olan string bilgiyi ayrtrp ddlAltKategoriler
isimli dropdownList' in Html karl olan ieriine birer option eleman olarak olarak eklemek
olacaktr.

<script type="text/javascript" language="javascript">

function IstemciGeriBildirim(gelenBilgi,context)
{
/* nce fonksiyona gelen altKategiler stringinin ieriini tayacak DropDownList kontroln
istemci tarafnda yakalamlyz. */
var lstKategoriler=document.forms[0].elements['ddlAltKategoriler'];
lstKategoriler.innerHTML=""; // liste ierii temizlenir
// Gelen string bilgiyi || lara gre ayrtyoruz.
var satirlar=gelenBilgi.split('||');

// her bir satr dolayoruz.


for(var i=0;i<satirlar.length;++i)
{
// satrlar | iaretine gre ayrtryoruz. Bylece alanlar elde ediyoruz.
var alanlar=satirlar[i].split('|');

var altKategoriId=alanlar[0];
var altKategoriAdi=alanlar[1];

// Html tarafnda listemiz iin option elementini oluturuyoruz. Value olarak altKategoriId'
yi ierik olarakta altKategoriAdi' ni veriyoruz.
var oge=document.createElement('option',altKategoriId);
oge.innerHTML=altKategoriAdi;

// Oluturulan e listeye eklenir.


lstKategoriler.appendChild(oge);
}
}

</script>

Bu JavaScript fonksiyonu sunucudaki GetCallbackResult metodundan dnen string bilgiyi


ayrtrmak ve istemci tarafndaki liste kutusuna eklemekten sorumludur. Unutulmamaldr ki,
istemci tarafna gelen bilgiler HTML ieriidir. Dolaysla DropDownList' e eleman eklemek iin
ayrtrlan her bir enin birer option elementi olarak ele alnmas gerekmektedir. Yapmamz
gereken son bir ilem daha vardr. stemci tarafnda, Kategorilerin tutulduu liste kutusu zerinde
bir bir eden bir dierine geildiinde, sunucu tarafndaki ilgili metodlarn tetiklenmesi
gerekmektedir. Bunu gerekletirebilmek iin sayfann Page_Load olay metodu ierisine aadaki
kod satrlarn eklememiz yeterli olacaktr.

protected void Page_Load(object sender, EventArgs e)


{

www.bsenyurt.com Page 1341


string script=ClientScript.GetCallbackEventReference(this,
"document.all['ddlKategoriler'].value", "IstemciGeriBildirim", null);
ddlKategoriler.Attributes.Add("onChange", script);
}

GetCallbackEventReference isimli metod sayesinde istemci taraf iin gerekli olan script' lerin
otomatik olarak oluturulmasn salayabiliriz. Metoun ilk parametresi, client callback ileminin ele
alnaca nesneyi belirtmektedir. Uygulamamz gz nne alndnda bu nesne sayfann kendi
referansdr. kinci parametre istemci tarafndan sunucu tarafndakiRaiseCallbackEvent metoduna
gelecek olan parametredir ki bu senaryoda ddlKategoriler' de seili olan enin deeridir. nc
parametre ile istemci tarafnda, sunucudakiGetCallbackResult metodunun sonucunu ele alacak
olan JavaScript fonksiyonunun ad belirtilir. Son parametre istemci tarafndaki fonksiyona
geirlmesi gereken ekstra bilgiler var ise kullanlr. rneimizde byle bir ihtiyacmz olmad iin
son parametre deerini null olarak geiyoruz. Son olarak, scriptlerin hangi kontroln hangi nitelii
iin oluturulacan belirtiyoruz. rneimizde liste kutusunun onChange olay iin gerekli
JavaScript' lerin oluturulmasn belirtmekteyiz. (Aadaki grnty izleyebilmek iin en azndan
Flash 6.0 srm gerekmektedir. )

Grdnz gibi Kategorilerde deiiklik yaptmzda alt kategoriler listesi dolmakta, ancak
sayfann sunucuyu tamamiyle postalandna dair bir iaret grlmemektedir.

Client Script Callback mimarisi derinlemesine incelendiinde sayfann istemciden sunucuya doru
tamamen postalanmay, sayfaya ait baz olay metodlarn almad anlamna gelmez. Aslnda
sayfaya ait Page_Init, Page_Load ve Page_Unload gibi olaylar almaktadr. Bununla birlikte
rnein PreRender, Render gibi olaylar ve hatta post-back olaylarna ait metodlar
altrlmamaktadr. Dolaysyla ilgili sayfa iin, bir blm krplm bir yaam dngsnn sz
konusu olduunu ve altn syleyebiliriz.

Client Script Callback ile ilgili dikkat edilmesi gereken baz kstlamalarda vardr. Gnmzde
hemen her tarayc programn JavaScript destei vardr. Ancak baz tarayclarn Client Callback
destei olmayabilir. Hatta internet explorer bu sistemi gerekletirmek iin ActiveX kullanr ve
taraycnn ActiveX ayarlar gvenlik nedeniyle bilerek kapatlm olabilir. Bu gibi sebeplerden dolay
Client Callback mimarisi doru bir ekilde almayacaktr. stemcilerin kullandklar tarayc
programlarn ClientCallback desteinin olup olmadn renmek ve uygulamann ileyiini buna
gre deitirmek iin Request.Browser.SupportsCallback zelliini kullanabiliriz. Bu

www.bsenyurt.com Page 1342


makalemizde ksaca istemci tarafl callback modelinin, .Net zerinde nasl gerekletirilebileceini
incelemeye altk. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek uygulama iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

HTTPHandler ve HttpModule Kavramlar (


08.12.2006 ) - Asp.Net
Deerli Okurlarm Merhabalar,

oumuz herhangibir tarayc penceresinden bir AspNet sayfasn ardmzda resmin hep n
yznden bakarz. Oysaki resmin arka yznde dikkate deer bir mimari bulunmaktadr. Bu mimari
ierisinde yer alan nemli yaplardan ikisi, Http Pipeline' n bir paras olan Http Handler ve Http
Module kavramlardr. Bu makalemizde Http Handler ve Http Module kavramlarn ksaca
incelemeye ve tanmaya alacaz. HttpHandler ve HttpModule kavramlarn derinlemesine
incelemeden nce ie, bir web sayfasn talep ettiimizde web sunucusunun bu talebi nasl
deerlendirdiini ele almaya alarak balayalm. alma modelindeki barol
oyuncularmz ISS (Microsoft Internet Information Services), ASPNET_ISAPI, Asp.Net Work
Processor ve HTTPPipeLine dr.

Temel olarak IIS, web sunucusuna gelen html, aspx, asp, jsp vb talepleri karlayp cevaplamakla
ykml bir programdr. Talep edilen sayfalar farkl tipte olduundan yada farkl programalama
sistemlerince iletildiklerinden IIS, gelen talebi asl iletecek olan sisteme devretmek iin baz
durumlarda arada bir program arayzne ihtiya duyacaktr. Baz durumlarda diyoruz nk bir
HTML sayfas iin (yada bir resim dosyas vb...) .Net Framework ve benzeri ortamlara ihtiya
yoktur. Bunlar zaten dorudan karlanabilirler. Ancak rnein bir asp sayfasna gelen talep
iin asp.dll Isapi extension kullanlr. Bir Asp.Net sayfas sz konusu olduunda ise bu
extension AspNet_Isapi.dll ktphanesidir. AspNet_Isapi unmanaged (ynetimsiz) bir
ktphanedir. Dolaysyla ierisinde .Net Framework kodlar altrlmaz. Bunun yerine
AspNet_Isapi.dll gelen talepleri, Asp.Net Work Processor' a iletir. Asp.Net Work Processor ise, bu
talepleri ietilmek zere Http Module ve Http Handler' lara devreder. ok basit olarak
dndmzde alma eklini aadaki gibi dnebiliriz.

www.bsenyurt.com Page 1343


Burada Http Modules ve Http Handler ksmn biraz daha aklamakta fayda var. Asp.Net Runtime
gelen talepleri Http Module' ler zerinden geirerek ilgili HttpHandler' a devreder. lgili HttpHandler
diyoruz nk Asp.Net alma ortamna den her talep iin ele alnabilecek ayr ayr HttpHandler
tipleri mevcuttur. Sz gelimi web servisleri iin alan ayr bir HttpHandler varken web sayfalar
iin alan baka bir HttpHandler' vardr. Biz bir aspx sayfas iin gelen talebi gz nne
aldmzda ilgili HttpHandler' n yapt baz ilemler vardr. Bu ilemler srasnda sayfann bir
rnei (nesne olarak) zerindeki kontroller ile birlikte oluturulur. Bir baka deyile sayfann yaam
dngs alr. (PreInit -> Init -> Load -> Change/ Click -> PreRender -> UnLoad -> Dispose)
Nihayetinde bir HTML kts retilir. Bu HTML kts Http Module' ler zerinden geriye doru
Asp.Net Work Processor' a oradanda AspNet_Isapi' ye iletilir ve son olarak IIS zerinden talepte
bulunan istemciye gnderilir. Aslnda sistemimizde ykl olan pek ok HttpHandler ve HttpModule
tipi vardr. Bunlar root klasrdeki web.config dosyas ierisinde bulabiliriz. rnein makaleyi
yazdm sistemde ki root web.config dosyas D:\WINDOWS\Microsoft.NET\
Framework\v2.0.50727\CONFIG klasr altnda yer almaktadr. Root klasrde yer alan web.config,
bu makinedeki web uygulamlarnn konfigurasyon dosyalarnn kaltmsal olarak tredii dosyadr.
Bu dosya ierisinde yer alan HttpHandlers ve HttpModules sekmelerine baktmzda aadakine
benzer ktlar elde ederiz.

rnek httpHandlers elementi ve alt elementleri; (Burada ok daha fazla Handler tanm vardr.
rnek olmas asndan bir ka Handler gsterilmektedir.)

<httpHandlers>
<add path="trace.axd" verb="*" type="System.Web.Handlers.TraceHandler" validate="true"
/>
<add path="*.aspx" verb="*" type="System.Web.UI.PageHandlerFactory" validate="true"
/>
<add path="*.ashx" verb="*" type="System.Web.UI.SimpleHandlerFactory" validate="true"
/>
<add path="*.asmx" verb="*" type="System.Web.Services.

www.bsenyurt.com Page 1344


Protocols.WebServiceHandlerFactory, System.Web.Services, Version=2.0.0.0, Culture=neutral,
PublicKeyToken=b03f5f7f11d50a3a" validate="false" />
<add path="*.rem" verb="*" type="System.Runtime.Remoting.Channels.
Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false" />
<add path="*.soap" verb="*" type="System.Runtime.Remoting.Channels.
Http.HttpRemotingHandlerFactory, System.Runtime.Remoting, Version=2.0.0.0,
Culture=neutral, PublicKeyToken=b77a5c561934e089" validate="false" />
<add path="*.asax" verb="*" type="System.Web.HttpForbiddenHandler" validate="true" />
<add path="*.ascx" verb="*" type="System.Web.HttpForbiddenHandler" validate="true" />
<add path="*.master" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"
/>
<add path="*.skin" verb="*" type="System.Web.HttpForbiddenHandler" validate="true" />
<add path="*.sitemap" verb="*" type="System.Web.HttpForbiddenHandler"
validate="true" />
<add path="*.dll.config" verb="GET,HEAD" type="System.Web.StaticFileHandler"
validate="true" />
<add path="*.exe.config" verb="GET,HEAD" type="System.Web.StaticFileHandler"
validate="true" />
<add path="*.config" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"
/>
<add path="*.cs" verb="*" type="System.Web.HttpForbiddenHandler" validate="true" />
<add path="*.csproj" verb="*" type="System.Web.HttpForbiddenHandler" validate="true"
/>
<add path="*.resx" verb="*" type="System.Web.HttpForbiddenHandler" validate="true" />
<add path="*.mdb" verb="*" type="System.Web.HttpForbiddenHandler" validate="true" />
...dieleri
</httpHandlers>

HttpModules elementi ve alt elementlerinin ierii;

<httpModules>
<add name="OutputCache" type="System.Web.Caching.OutputCacheModule" />
<add name="Session" type="System.Web.SessionState.SessionStateModule" />
<add name="WindowsAuthentication"
type="System.Web.Security.WindowsAuthenticationModule" />
<add name="FormsAuthentication"
type="System.Web.Security.FormsAuthenticationModule" />
<add name="PassportAuthentication"
type="System.Web.Security.PassportAuthenticationModule" />
<add name="RoleManager" type="System.Web.Security.RoleManagerModule" />
<add name="UrlAuthorization" type="System.Web.Security.UrlAuthorizationModule" />
<add name="FileAuthorization" type="System.Web.Security.FileAuthorizationModule" />
<add name="AnonymousIdentification"
type="System.Web.Security.AnonymousIdentificationModule" />
<add name="Profile" type="System.Web.Profile.ProfileModule" />
<add name="ErrorHandlerModule" type="System.Web.Mobile.ErrorHandlerModule,
System.Web.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
<add name="ServiceModel" type="System.ServiceModel.Activation.HttpModule,
System.ServiceModel, Version=3.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</httpModules>

HttpHandler sekmesine baktmzda path ksmnda baz dosya uzantlar olduu grrz. Bunlarn
ou web uygulamalarn tasarlayanlara tandk gelecektir.

www.bsenyurt.com Page 1345


Uzant Tipi

sayfalara ait Trace bilgilerinin tutulduu


trace.axd
dosya

aspx Asp.Net web sayfalarmz (Web pages)

ascx Kullanc web kontrolleri (Web User Controls)

cs C# kaynak kod dosyalar (Source Files)

config Konfigurasyon dosyalar (Configuration Files)

asmx Web servisi dosyalar (Web Service Files)

csproj C# proje dosyalar (C# Projects Files)

Temalarda kullanlan skin dosyalar (Skin


skin
Files)

master Master Page dosyalar (Master Pages)

Bu elementlerin her biri iin birde verb nitelii (attribute) tanmlanmtr. Verb nitelii Http
protokolne gre bu elementler ierisinde belirtilen uzantya sahip kaynaklara gelebilecek olan
talep eitlerini snrlamak iin kullanlr. rnein bu nitelie Get, Head, Post gibi deerler bir
arada yada ayr ayr verilebilir. * olmas halinde tm Http isteklerinin geerli olaca
belirtilmektedir. HttpHandler ierisindeki elementler iinde belkide en nemli ksm type niteliinin
iaret ettii .Net tipidir. imdi u senaryoyu dnelim. Normal artlar altnda url zerinden bir cs
dosyasn talep ettiimizde aadakine benzer bir hata alrz. (Testi IIS zerinden yapabilmek iin
bilerek cs uzantl dosya ilgili virtual directory altna atlmtr. Aspx dosyas ile cs dosyalarnn IIS
altna atlmas, Vs.Net 2005 Copy Web Site datm modelinin varsaylan alma eklidir.)

Byle bir mesaj almamzn nedeni, cs uzantl dosyalara gelecek olan


arlarn HttpForbiddenHandler tipi tarafndan ele alnyor olmasdr. Bu handler hata

www.bsenyurt.com Page 1346


mesajndan grebileceimiz gibi ilgili dosyaya eriilmesini engellemektedir. Bu nedenle
HttpForbiddenHandler tarafndan ele alnabilen tm dosya tipleri iin yukardaki hata mesajn alrz.
Tam aksine aspx uzantl sayfalar PageHandlerFactory tipi tarafndan ele alnr. Ancak
PageHandlerFactory aslnda bir Http Handler deildir. Bunun yerine alma zamannda gerekli olan
HttpHandler' n retilmesini ve bunu bir arayz olarak (IHttpHandlerFactory) dndrlmesini
salayan fonksiyonellii ierir. Dolaysyla aspx uzantl sayfalar iin bu fabrika tipinin rettii
handler sunucu tarafl derleme ve sayfa nesne rnei retme ilemlerini stlenecektir.
PageHandlerFactory aslnda .Net 2.0 ile gelen ve Asp.Net 2.0 alma modelini destekleyen bir
tiptir. Aada bu snfn tredii IHttpHandlerFactory arayz yeleri ile birlikte grlmektedir.
Dikkat ederseniz GetHandler isimli ye metod, geriye IHttpHandlerFactory tipinden bir arayz
referans dndrmektedir ki bu referans alma zamannda gereki olan HttpHandler tipini
tayacaktr.

Benzer ekilde rnein web servislerine gelicek olan talepleride (asmx sayfalarna gelicek olan
talepleri) WebServiceHandlerFactory tipi stlenecektir. Bu Handlern sahip olduu
fonksiyonellikler arasnda gelen taleplerdeki Soap mesajlarn deserialize etmek, cevap (response)
olarakta tekrar seriletirilmi Soap paketkerini hazrlayp kar tarafa gndermek gibi grevler
saylabilir.

HttpModules ksmna baktmzda ise yine web uygulamalarmzda ska kullandmz baz
kavramlarn var olduunu grebiliriz. rnein Cache (ara bellee alma), Session, Authentication,
Role ynetimi vb. Buradan u sonu kartlabilir. HttpModules ierisinde tanmlanan elementlerde
belirtilen tipler bir web uygulamas iin ele alabileceimiz framework zelliklerini kullanabilmemizi
salar. rnein caching sistemini OutputCacheModule, Session sistemini SessionStateModule,
Windows tabanl dorulama sisteminiWindowsAuthenticationModule, Form tabanl dorulama
sistemini FormsAuthenticationModule vb... tipleri ele almaktadr. O halde bu noktada
HttpHandler ve HttpModule sekmesindeki elementler arasndaki ilikiyi daha kolay aklayabiliriz.
Bir sayfa talebi HttpHandler' a ulamadan nce HttpModule' lerden geer. HttpHandler gerekli Html
ktsn rettiinde ise sonular yine HttpModule' ler zerinden Asp.Net alma zaman motoruna
iletilir. Bylece bir sayfa iin gerekli olan ara bellee alma, bellekten Html ktsna dahil etme,
session bilgisini oluturma veya okuma, gvenlik dorulamalarn yapma gibi ilevsellikler ilgili
HttpModule' ler tarafndan hem taleplerde (request) hemde cevaplarda (response), ele alnabilirler.

www.bsenyurt.com Page 1347


ok dk bir ihtimallde olsa bazen kendi HttpHandler yada HttpModule' lerimizi yazmak
isteyebiliriz. rnein istemciden zel bir dosya uzants ve parametre ile gelecek olan bir resim
isteini, veritabanndan okuyup istemcilere html kts olarak gnderecek bir handler, yada bir cs
dosyasna gelecek talep sonras bu talebi istemciye metin formatnda dndrecek olan bir handler
gz nne alnabilir. Makalemizin bundan sonraki ksmlarnda kendi HttpHandler' larmz ve hatta
HttpModule' lerimizi nasl yazabileceimizi incelemeye alacaz. Her ne kadar kendi HttpHandler
veya HttpModule tiplerimizi oluturmak iin dnlebilecek senaryo says az olsada amacmz
temel olarak bunlar nasl yazabileceimizi ve Asp.Net alma ortam tarafndan nasl ele
alnabileceini incelemektir. Kendi HttpHandler tiplerimizi oluturabilmek iin ilk
olarak IHttpHandler arayzn (interface) implemente edecek olan bir snf yazmamz
gerekmektedir. lk olarak bu ve benzeri HttpHandler yada HttpModule' leri ierisinde barndracak
bir Class Library projesi oluturalm. Bylece bu HttpHandler veya HttpModule tiplerimizi baka
web uygulamalar iinde kullanabiliriz. ( Hatta bunu GAC (Global Assembly Cache) ierisine atarsak
her web uygulamasnn ortaklaa eriebilecei bir dll halinede getirmi oluruz.) Class Library
projesinde kullanacamz HttpHandler veya HttpModule tiplerimiz ierisinden gncel web
ieriklerine (Http Context) eriebilmek iin System.Web referansn aka eklememiz
gerekmektedir.

imdi bu snf ktphanesi ierisine IHttpHandler arayzn uygulayan bir snf dahil edelim.

www.bsenyurt.com Page 1348


IHttpHandler arayz, MyCustomHandler isimli snfmz ierisine iki ye dahil eder.
Bunlardan ProcessRequest isimli metod, gelen talepleri deerlendirebileceimiz yedir. Yani
talebe gre Html ieriini oluturabileceimiz bir baka deyile http isteini kendi istediimiz
ekilde ele alabileceimi yerdir. Dikkat ederseniz bu metod parametre olarak HttpContexttipinden
bir deiken almaktadr. Bu deiken sayesinde, Response, Request ve Server nesnelerine
eriebiliriz. Bu da gelen talepler HttpHandler ierisinde deerlendirebileceimiz anlamna
gelir. IsReusable zellii ise sadece okunabilir bir zelliktir ve ilgili HttpHandler nesne rneine ait
referansn baka talepler iinde kullanlp kullanlmayacan belirler. imdi kodumuzu aada
grld gibi biraz daha gelitirelim.

using System;
using System.Web;

namespace MyHandlers
{
public class MyCustomHandler:IHttpHandler
{
#region IHttpHandler Members
public bool IsReusable
{
get { return true; }
}

public void ProcessRequest(HttpContext context)


{
string isim = context.Request["Ad"];
context.Response.Write("<html><body>");
context.Response.Write("<b> Adm : " + isim + "</b><br/>");
context.Response.Write("</body></html>");

www.bsenyurt.com Page 1349


}
#endregion
}
}

Dikkat ederseniz ProcessRequest metodu ierisinde Request zerinden gelecek olan Ad isimli bir
parametreyi alyoruz ve basit olarak bir Html kts retiyoruz. retilen Html kts iin Response
nesnesini kullanmaktayz. Yazm olduumuz bu HttpHandler trnn bir web uygulamasnda,
rnein mypx uzantl dosyalar ele almasn istediimizi dnelim. ncelikle gelitirdiimiz snf
ktphanesini web projemize ekleyelim. lk aamada dosya tabanl (file based) bir web sitesi
gelitireceiz.

Bu nedenle ilk olarak web.config dosyas ierisinde mypx uzantl dosyalarn az nce yazdmz
snf ktphanesi (class library) ierisindeki MyCustomerHandler tipi tarafndan ele alnacan
belirtmemiz gerekiyor. Dolaysyla web.config ierisinde var olan HttpHandler sekmesindeki
elementler arasna yeni bir tanesini eklememiz gerekmektedir.

<system.web>
<httpHandlers>
<add path="*.mypx" verb="*" type="MyHandlers.MyCustomHandler,MyHandlers"
validate="true"/>
</httpHandlers>

Bylece mypx uzantl herhangibir istei MyCustomHandler isimli snfa ait nesne rnei
karlayacaktr. Burada path ksmna *.mypx yazdk. Bylece mypx uzantl herhangibir dosyaya
gelecek olan talebi, type parametresi ile belirtilen snfa devretmi oluyoruz. Durumu aadaki
grntde grld gibi test edebiliriz.

www.bsenyurt.com Page 1350


Dikkat ederseniz web sitemizde sayfam.mypx isimli bir dosya bulunmamktadr. Ancak bu dosyaya
Ad isimli parametreyide ieren bir talep geldiinde, MyCustomHandler tarafndan karlanmaktadr.
Sonu olarak MyCustomHandler' a ait ProcessRequest metodu arlm ve buna gre bir Html
kts retilmitir. rneimizi dorudan visual studio.net 2005 ierisinde F5 ile
altramayacamz farketmisinizdir. Nitekim elimizde sayfam.mypx dosyas zaten yok.
Dolaysyla testimizi yaparken tarayc zerinden manuel olarak Url girmemiz gerekmektedir. Dikkat
edilmesi gereken bir nokta gelitirilen bu web sitesi IIS altna datldnda ne olacadr. Nitekim
IIS' e bir ekilde mypx uzantl dosyalara gelecek olan taleplerin Asp.Net alma ortamna
devredilmesi gerektiini sylememiz gerekmektedir. IIS' e mypx uzantl dosyalar tantmadan
nce, bunu bildirmediimizde ne olacana bakmamzda fayda var. Bunun iin web sitemizi IIS
altnda yaymladmz dnelim. rnein MySite ismiyle yaynladmz farz edelim. Bu durumda
sayfam.mypx?Ad=burak isimli bir talepte bulunduumuzda aadaki ekran grntsnde yer alan
sonucu elde ederiz.

Bu hatann sebebi IIS' in mypx isimli uzantl dosyalar ne yapacan bilememesidir. Bunun iin IIS
zerinde mypx isimli dosyay tantmamz gerekmektedir. Bir baka deyile, mypx uzantl dosyalar
iin gelecek olan taleplerin AspNet_Isapi.dll' e devredilmesini sylemeliyiz. Bu amala, IIS
zerinden MySite isimli virtual directory' nin zelliklerine gidelim ve Directory ksmndan
Configuration sekmesini aalm.

www.bsenyurt.com Page 1351


Dikkat ederseniz burada siteye gelebilecek talepler ve bunlar deerlendirecek olan programlar ile
ilgili eletirmeler yaplmaktadr. (Mappings) Bizim tek yapmamz gereken aadaki gibi yeni bir
eletirme eklemektir.

www.bsenyurt.com Page 1352


Dikkat ederseniz executable ksmnda aspnet_isapi.dll' ini belirtiyoruz. Bylece extension ksmnda
belirtilen mypx isimli dosyalar iin gelicek olan talepler, aspnet_isapi.dll tarafndan ele alnabilecek.
Buradan da tahmin edeceiniz zere kendi yazdmz HttpHandler' a kadar gelicek. Check that file
exists (dosyann var olup olamadn kontrol et) seeneini kaldrmamzn nedeni ise olmayan bir
mypx sayfasna gelecek olan taleperi IIS' in geri evirmesini engellemektir. (Bu ayarlamalar IIS 5.1
zerinde yaplm olup IIS 6.0 iin baz farkllklar olabilir.) Artk talebimiz alacaktr. rnein bu
kez mypage.mypx?Ad=Selim talebinde bulunduumuzu dnelim. Aadaki sonucu elde
ederiz.

Gelelim kendi HttpModule' lerimizi nasl yazabileceimize. Yazmzn banda bahsettiimiz gibi
HttpModule' ler ile Http Handler' lar arasnda yakn bir iliki vardr. IIS tarafndan gelen her istek
ilgili HttpHandler' a iletilmeden nce baz HttpModule' ler zerinden geer. HttpHandler tarafndan
retilen Html ktlar ise ayn module' ler zerinden IIS' e doru gnderilirler. HttpModule' ler
ounlukla olay tabanl fonksiyonellikler ierir. rnein bir kullancnn dorulanmas srasnda veya
sonrasnda alacak olaylar WindowsAuthenticationModule tarafndan kontrol altna alnr. Biz kendi
HttpModule' lerimizi oluturduumuzda gelen taleplerde veya giden cevaplarda ele alnabilecek
module olaylarn zellitirme ansna sahip olabiliriz. Kendi HttpModule nesnelerimizi yazabilmek
iin IHttpModule arayznden tretilmi bir snf yazmamz gerekmektedir. Dilerseniz
makalemizde kullandmz MyHandlers isimli snf ktphanesi ierisine MyCustomHandler isimli bir
tipi aadaki gibi ekleyelim.

using System;
using System.Web;

namespace MyHandlers
{
class MyCustomModule:IHttpModule
{
#region IHttpModule Members
public void Dispose()
{
throw new Exception("The method or operation is not implemented.");
}

public void Init(HttpApplication context)


{
throw new Exception("The method or operation is not implemented.");
}
#endregion
}

www.bsenyurt.com Page 1353


}

IHttpHandler, uyguland tipe iki metod dahil eder. Init ve Dispose. Init
metodu HttpApplication tipinden bir parametre almaktadr ki bu parametre sayesinde var olan
HttpModule olaylarna mdahale etme, aktif Http ieriine ulama gibi imkanlara sahip olabiliriz.
Dispose metodunu ise, bu snfa ait nesne rnei yok edilmeden nce yapmak istediimiz kaynak
temizleme ilemleri iin kullanabiliriz. rnein Module ierisinden kullanlan unmanaged(managed)
kaynaklarn serbest braklmas iin ele alabiliriz. imdi modulmz ierisine biraz kod yazalm ve
sonularn incelemeye alalm.

using System;
using System.Web;

namespace MyHandlers
{
class MyCustomModule:IHttpModule
{
HttpContext m_Ctx=null;

public void Init(HttpApplication context)


{
m_Ctx = context.Context;
context.PreSendRequestContent+= new
EventHandler(context_PreSendRequestContent);
}

void context_PreSendRequestContent(object sender, EventArgs e)


{
m_Ctx.Response.Write("<!--Bu sayfa Z irketi tarafndan retilmitir...-->");
}

public void Dispose()


{
throw new Exception("The method or operation is not implemented.");
}
}
}

Bakn burada uygulama iin PreSendRequestContent isimli bir olay yklenmitir. Bu olay,
HttpHandler tarafndan retilen HTML ierii gnderilmeden nce alr. Bylece bu modl
kullanan bir uygulama ierisindeki her hangibir sayfa talebinde gnderilen Http ieriine "Bu sayfa
Z irketi tarafndan retilmitir..." cmlesi bir yorum taks (comment tag) olarak eklenecektir.
Yazdmz HttpModullerin ilgili web uygulamas ierisinde geerli olmasn salamak iin yine
web.config dosyasnda dzenleme yapmamz gerekmektedir. Bu amala, web.config dosyasna
aadaki gibi httpModules sekmesini dahil etmemiz ve yeni HttpModule' mz bildirmemiz yeterli
olacaktr.

<httpModules>
<add name="MyModule" type="MyHandlers.MyCustomModule,MyHandlers"/>
</httpModules>

Artk bu konfigurasyon ayarlarna sahip bir web uygulamasna gelecek her talep sonrasnda,
retilecek olan Html ierikleri iin yazm olduumuz modl devreye girecek ve ilgili olay metodu
alacaktr. Bunu test etmek amacyla herhangibir aspx sayfasn web uygulamamza dahil edelim

www.bsenyurt.com Page 1354


ve altralm. Elde edilen sayfann ieriine tarayc penceresinden baktmzda aadakine
benzer bir kt elde ederiz.

Dikkat ederseniz, ierie bir yorum satr eklenmitir. Bu bilgi mesaj aslnda web uygulamamza
gelecek her sayfa talebinde geerli olacaktr. Init metodu ierisinde yer alanHttpApplication nesne
rnei zerinden yazabileceimiz pek ok olay metodu vardr. Bunlardan bir ka ve ne ie
yaradklar aadaki tabloda listelenmitir.

Olay (Event) levi

BeginRequest Bir talep geldiinde tetiklenir.

EndRequest Cevap istemciye gnderilmeden hemen nce tetiklenir.

PreSendRequestHeaders stemciye HTTP Header gnderilmeden hemen nce tetiklenir.

PreSendRequestContent stemciye ierik gnderilmeden hemen nce tetiklenir.

Session gibi durum nesneleri (state objects) elde edilmeye hazr hale
AcquireRequestState
geldiinde tetiklenir.

AuthenticateRequest Kullanc dorulanmaya hazr hale geldiinde tetiklenir.

AuthorizeRequest Kullancnn yetkileri kontrol edilmeye hazr hale geldiinde tetiklenir.

www.bsenyurt.com Page 1355


Bu olaylar dnda ele alabileceimiz baka olaylarda vardr. rnein var olan dier HttpModule'
lerin ieriklerine erimek ve kullanmak isteyebiliriz. Sz gelimi, WindowsAuthenticationModule'
ele almak istersek aadaki gibi bir kod paras gelitirebiliriz.

using System;
using System.Web;
using System.Web.Security;

namespace MyHandlers
{
class MyCustomModule:IHttpModule
{
HttpContext m_Ctx=null;
WindowsAuthenticationModule authMod = null;

public void Init(HttpApplication context)


{
m_Ctx = context.Context;

authMod
= (WindowsAuthenticationModule)context.Modules["WindowsAuthentication"];
authMod.Authenticate +=
new WindowsAuthenticationEventHandler(authMod_Authenticate);
}

void authMod_Authenticate(object sender, WindowsAuthenticationEventArgs e)


{
m_Ctx.Response.Write("<!--" + e.User.Identity.Name + "-->");
}

public void Dispose()


{
throw new Exception("The method or operation is not implemented.");
}
}
}

Dikkat ederseniz, context nesnesi zerinden Modules isimli bir koleksiyona eriebilmekteyiz. Bu
koleksiyon ierisinde var olan tm HttpModule' ler yer almaktadr. Bunu debug mode' da iken
grebiliriz.

www.bsenyurt.com Page 1356


Dikkat ederseniz kendi gelitirdiimiz MyCustomModule isimli nesnemiz, web.config dosyasndaki
ismiyle (name niteliinde yazdmz MyModule) bu koleksiyon ierisinde grlmektedir. Kendi
HttpModule' lerimizi yazmak iin gerekli senaryolar dndmzde aklma ok fazla vakka
gelmeyebilir. Ama u rnekler fikir vermesi asndan ve denenmesi asndan yararl olabilir. Bir
web uygulamasna gelen her hangibir talepte authenticate olan kullanclarn log dosyalarna
kaydedilmesi ele alacak kendi HttpModule snfmz yazabiliriz. Talep edilen url bilgisi ok uzun
olduunda bunu ayrtrp (parse) baka ve daha ksa bir url olacak ekilde kullancya
gsterebilecek bir olay metodunu barndracak bir HttpModule yazabiliriz vb...

Bu makalemizde ksaca HttpHandler ve HttpModule kavramlarna deinmeye altk. Her ne kadar


kendi Handler yada Module' lerimizi yazmay pek tercih etmesekte, baz durumlarda Asp.Net
alma ortamn alt seviyede zelletirmek isteyebiliriz. Bu gibi
durumlarda IHttpHandler ve IHttpModule arayzlerinden treteceimiz tiplerden yararlanmamz
gerekmektedir. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye
dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net 2.0 Temelleri : Bir Web Sayfasnn


Anatomisi ( 30.11.2006 ) - Asp.Net
Deerli Okurlarm Merhabalar,

Bu makalemizde, bir web sayfasnn (.aspx uzantl dosyalar) anatomosini incelemeye alacak,
kaynak koddaki zel noktalar, in-line coding, code-behind modelini, yaam dngsn ve alma
zamannda olay balanmas gibi temel kavramlara deineceiz. Bylece basit olarak bir web
sayfasnn anatomisini renmek iin gerekli ip ularn deerlendirme frsatn bulmu olacaz. lk
olarak basit bir web sayfasn gz nne alarak balayalm.

www.bsenyurt.com Page 1357


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

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>

</div>
</form>
</body>
</html>

Bu sayfa zerinden konuulabileceimiz olduka fazla zellik bulunmaktadr. Yukardaki kod paras
Visual Studio.Net 2005 tarafndan retilen defualt.aspx isimli bir web sayfasnn ieriini
gstermektedir. Her web sayfas mutlaka Page direktifi ile balar. Page direktifinin sahip olduu
nitelikler sayfa iin gerekli olan alma zaman ve gelitirme zaman davranlarn belirleyen
deerler ierir. rnein CodeFile nitelii, bu sayfa iin alma zamannda deerlendirilecek ve
zellikle arka kodlarn (code-behind) tutulaca dosyann adn belirtir. Inherits isimli nitelik ile,
retilecek olan alma zaman sayfasnn hangi tipten tretilecei
sylenmektedir. Language nitelii bu sayfada C# dili ile gelitirme yaplacan vurgular.
Dikkatimizi eken bir dier nitelik olan AutoEventWireup' a ise makalemizin sonunda deineceiz.
Ama ncesinde sayfamza bir Button kontrol alp buna ait bir Click olay metodu yazalm. Web
sayfasna tasarm zamannda bir Button kontrol srklersek, ilgili kontroln form taks ierisine
alndn grrz. Eer Button kontrolmze ift tklarsak (yada, event' lerinden Click olayna ift
tklarsak), default.aspx.cs isimli code-behind dosyasnda, Button bileenine ait ilgili olay
metodunun otomatik olarak oluturulduunu grrz.

default.aspx ierisindeki deiiklik

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


<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/>
</div>
</form>

defaulf.aspx.cs

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


{
protected void Button1_Click(object sender, EventArgs e)
{
}
}

Burada en ok dikkat etmemiz gereken nokta, _Default snfnn Page' den tremesi ve partial bir
tip olmasdr. Bunun nemini ve oluturduu fark grmek iin ayn uygulamann Asp.Net 1.1

www.bsenyurt.com Page 1358


versiyonuna bakmamz gerekecektir. Aadaki kod paralar Visual Studio.Net 2003 ile
tasarlanmtr ve ayn senaryoyu ele almaktadr.

WebForm1.aspx

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false"


Inherits="HelloAspNet1.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<HTML>
<HEAD>
<title>WebForm1</title>

<meta name="GENERATOR" Content="Microsoft Visual Studio .NET 7.1">


<meta name="CODE_LANGUAGE" Content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
</HEAD>
<body MS_POSITIONING="GridLayout">
<form id="Form1" method="post" runat="server">
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>
</form>
</body>
</HTML>

WebForm1.aspx.cs code behind dosyas

public class WebForm1 : System.Web.UI.Page


{
protected System.Web.UI.WebControls.Button Button1;

private void Page_Load(object sender, System.EventArgs e)


{
}

#region Web Form Designer generated code


override protected void OnInit(EventArgs e)
{
InitializeComponent();
base.OnInit(e);
}

private void InitializeComponent()


{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
}
#endregion

private void Button1_Click(object sender, System.EventArgs e)


{
}
}

Grdnz gibi Asp.Net 1.1' de sayfaya bir kontrol eklendiinde, code-behind dosyas ierisinde
Asp.Net 2.0' dakine gre daha farkl ilemler yaplmaktadr. Hereyden nce Code-Behind

www.bsenyurt.com Page 1359


sayfamzda, Button1 adnda bir Button nesnesi tanmlanmtr. Oysaki Asp.Net 2.0 ile gelitirdiimiz
sayfa ierisinde bu tarz bir tanmlama sz konusu deildir.

protected System.Web.UI.WebControls.Button Button1;

Dier taraftan Button1 isimli nesne iin bir Click event' i Initialize Component metodu ierisinde
yklenmi ve Button1_Click isimli olay metoduna balanmtr. Initialize Component metodu
aslnda windows formlarnda da benzer bir grev stlenir. Yani form zerindeki kontrollerin
oluturulmas gerekli olaylarnn balanmas ve formun controls koleksiyonuna dahil edilmesi gibi.
Elbette web de durum biraz daha farkl olmasna ramen yinede kontrollerin oluturulmas gibi bir
durum sz konusudur. Asp.Net 1.1 bu ii gerekletirmek iin sayfann OnInit isimli olay metodunu
gz nne almaktadr.

this.Button1.Click += new System.EventHandler(this.Button1_Click);

Oysaki Asp.Net 2.0 mimarisinde her sayfann alma zamannda (run-time) derlenmesi (compile)
sz konusudur. Bu ilem nedeni ile, bir nesne ve olaylarna ait metodlar alma zamannda dll
retimi srasnda otomatik olarak birbirlerine balanrlar. Bu Asp.Net 2.0 ile web sayfalarna gelen
en nemli yeniliklerden birisidir. Dolaysyla, sayfa zerine yerletireceimiz bileenleri ayrca
tanmlamamza, bunalara ait olaylar yklemek iin temsilcilere kadar gitmemize gerek
kalmamaktadr. zellikle .Net 2.0 ile gelen tiplerin paralara ayrlabilmesinin (Partial Types Modeli)
bu yeni alma modelinde nemli bir yeri vardr. Bu alma sistemini daha net anlayabilmek
amacyla aadaki ekli gz nne alabiliriz.

www.bsenyurt.com Page 1360


Asp.Net 2.0 iin alma zamannda retilen paral bir snf sz konusudur. Bu snf var olan aspx
sayfasndan retilir ve code-behind dosyasnda yer alan snf ile birletirilir. Her iki snf partial
olarak tanmlanm olduundan aslnda ortada tek bir snf vardr. Sonu olarak retilen asl snf,
bileenlerinin tanmlamalarn, ilgili olaylar ile olan balantlarn vb... ieren bir yapya sahiptir. Bu
snfa ait nesne rnekleri istemciden gelen talepler sonras retilir, yaam dngsn geer ve
istemciye gnderilemek zere bir html ktsnn retilmesinde kullanlr.

Asp.Net 2.0' da sayfa zerindeki kontroller ve bu kontrollere ait olaylarn balanmas gibi
ilemler alma zamannda gerekletirilir. Bylece kod tarafnda olay ykleme ve kontrol
tanmlama gibi kodu kalabalklatran ilemlerden uzaklalabilinmektedir.

Gelelim web sayfalarnn anatomisindeki bir dier konuya. Kodlamay nerelerde yapabiliriz? Asp.Net
iki tr kodlama ekli sunmaktadr. Bunlardan birisi Inline-Coding dieri ise Code-
Behind modelidir. Inline-Coding modelinde, aspx sayfasnn kaynak ierii ile kod ksm ayn fiziki
dosya ierisinde yer alrlar. rnein aadaki kod parasnda Inline-Coding modeli
kullanlmaktadr.

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

www.bsenyurt.com Page 1361


Inherits="_Default" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"


"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<script runat="server">
protected void Button1_Click(object sender, EventArgs e)
{
}
</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/>
</div>
</form>
</body>
</html>

Inline coding modelinde dikkat ederseniz, sayfann kodlarn aspx sayfas ierisinde yer alan script
bloklar ierisinde yapmaktayz. Script blou ierisinde runat="server" niteliinin kullanlmasnn
en byk nedeni ise bu blok ierisinde altrlacak olan kodlarn sunucu tarafnda ele alnacak
olmasdr. Visual Studio.Net 2005 bir nceki srmne gre, Inline-Coding srasnda intelli-sense
iin tam destek vermektedir. Aadaki ekran ktsna dikkat ederseniz script blou ierisinde .net
tipleri iin intelli-sense zelliinin tam olarak altn grebiliriz.

Inline-Coding' in en nemli avantajlarndan birisi kaynak html ierii ile kodlarn tek ve ayn fiziki
dosya ierisinde yer almasdr. Bu sayfann datlmasn (deployement) son derece kolaylatrr.
Ayrca sayfann yeninden isimlendirilmesi baka bir kod sayfasna bamllk olmadndan daha
kolaydr.

www.bsenyurt.com Page 1362


Microsoft, kodlama ilemlerinde Code-Behind modelinin kullanlmasn nermektedir.

Gelelim Code-Behind modeline. Bu modelde, kodlarmz ierisinde barndrdan ayr bir fiziki dosya
sz konusdur. Aadaki kod parasnda bu model gsterilmektedir.

Aspx tarafnda

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


<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/>
</div>
</form>

Code Behind tarafnda

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


{
protected void Button1_Click(object sender, EventArgs e)
{
Response.Write("Deneme");
}
}

Code-Behind programlamann en nemli arts, kod taraf ile sunum tarafnn kesin olarak
birbirlerinden ayrlyor olmasdr. Bu nedenle grafik departman ile kodlamaclarn ayn sayfa
zerinde almalar ok daha kolay olabilmektedir.

Web sayfalarnn anatomisinde inceleyeceimiz bir dier konuda form taksnn grevidir. Bildiiniz
gibi bir istemci web sunucusu zerinden herhangibir sayfay ilk talep ettiinde, sunucu tarafnda bir
dizi ilem gerekletirilir.

Aslnda ilk talep Http protokolnn Get metoduna gre gerekleir. Talep edilen sayfa
sunucuda nce IIS tarafndan karlanr ve Asp.Net sayfas olup olmadna baklr. Eer
Asp.Net sayfas ise talep ASPNET_ISAPI.dll' ine devredilir. Bu dll, Asp.Net web
uygulamalarn altran ve yneten Asp.Net work processor ile IIS arasndaki iletiimi
salamakla grevlidir. AspNet Work Processor, talep edilen sayfann bulunduu web
uygulamasnn bir application domain ierisine yklenmesinden, CLR' a almasndan
sorumludur. Eer talep edilen sayfaya ait web uygulamas iin bir Application Domain
almamsa, Asp.Net Work Processor bu ilemide stlenir. Bu u anlamada gelir; eer
Application Domain ykl ise bu adm otomatikman atlanr.

Gelen talebe ait sayfann altrlmas, bellee alnmas, html ktsnn retilmesi gibi
ilemler HTTPPIPE ad verilen bir .Net snflar koleksiyonun sorumluluu altndadr. Tabi
talep edilen sayfaya ait bir dll daha nceden iletim sisteminin ilgili temp klasrlerine
atlmsa buradaki dll retme gibi ilemler otomatikman atlanr ve sayfann dorudan
altrlmasna geilir. Yani HTTPPIPE talep edilen ierik iin dll oluturma ileminide
kontrol altna alr. retilen kt istemcinin grmesi gereken ieriktir ve ayn yollar ile IIS'
e dnerek buradan istemciye gnderilir.

www.bsenyurt.com Page 1363


Talep sonras gerekleen arka plan ilemlerinin sonucunda ilgili sayfann HTML ktsnn istemciye
gnderildiini dnebiliriz. stemci bu sayfa zerinden gelen kontrollerde veri girileri yapabilir. Bu
veri girilerinden sonra sayfay tekrardan sunucuya gnderebilir-ki biz buna post-back ilemi
diyoruz. te sayfann ierisindeki veriler ile birlikte sunucuya gnderilmesi aamasnda standard
olarak HTTP protokolnn Post metodu kullanlr. Bu ilemde HTTP paketi ierisinde sunucuya
doru hareket edecek olan ierik, sayfadaki form taks ierisinde kullanlan elemanlar iin geerli
olacaktr. Ksacas, HTTP Post tekniine gre sayfa ierisindeki veriler istemciden sunucuya doru
HTTP paketi ierisinde gnderilirler. Oysaki HTTP protkolnn Get isimli bir baka metodu daha
vardr. Bu metoda gre form taks ierisindeki elemanlara ait ierik Url zerinden bir baka deyile
tarayc pencersinin adres satr zerinden sunucuya gnderilecektir. imdi bu durumu analiz etmek
iin default.aspx sayfamz aadaki gibi deitirelim.

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


Inherits="_Default" %>

<script runat="server">

protected void Button1_Click(object sender, EventArgs e)


{
Response.Write(txtAd.Text);
}

</script>

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server" method="get">
<div>
<asp:Button ID="Button1" runat="server" Text="Button" OnClick="Button1_Click"/>
<asp:TextBox ID="txtAd" runat="server" Text="Adnz" />
</div>
</form>
</body>
</html>

stemci bu sayfay talep ettikten sonra TextBox kontrolne veri girii yapp, sayfay tekrar
sunucuya gnderdiinde ViewState, TextBox ve Button nesnelerine ait ierikler url zerinden
sunucuya gnderilmektedir. Bunu aadaki ekran grntsnden ve Url satrndaki kod ksmndan
daha net grebilirsiniz.

http://localhost:1503/Anatomi/Default.aspx?__VIEWSTATE=%2FwEPDwUKMTM0MDE0NzQwOGRkc
cXHiCjUXf6SyoYO18eFOly9GKU%3D&Button1=Button&txtAd=Burak&__EVENTVALIDATION=%
2FwEWAwKYvOnjDAKM54rGBgKM%2B%2FaQCjAN0uAoGcNSpMV1ikOzE6pJ9Fnd

www.bsenyurt.com Page 1364


Dikkat ederseniz, TextBox kontrolnn ieriini Url ierisinde net olarak grebilmekteyiz. Http Get
modeline gre sayfa ieriklerini sunucuya gndermek ,zellikle bilgilerin ak olarak Url zerinden
gidiyor olmas ve tarayclarn Url zerinden gnderebilecekleri karakter saysnn bir snrnn olmas
gibi nedenlerden dolay ok tercih edilen bir yol deildir. Lakin, parametrik deerlerin Url satrndan
deitirilerek farkl sonularn elde edilebilmesi gibi bir imkanda sz konusudur ki gvenlik gz
nne alndnda bununda bir avantaj olmad dnlebilir.

Web sayfamza ait anatomide inceleyeceimiz bir dier nemli unsurda yaam dngleridir. Aslnda
her web sayfas sunucu tarafnda bir .Net snfdr. nk ieriklerinde baka snflara ait rnekler,
ye metodlar, olaylar, zellikler vb... vardr. Dahas her web sayfas sunucu tarafnda retilmekte
ve ilenmektedir. Yani istemciler bir web sayfasn talep ettiklerinde sunucunun yapaca i, talep
edilen sayfann rneini oluturmak ve yrtmek olacaktr. Dolaysyla bu sre srasnda her web
sayfasnn ele alnabilecek bir yaam dngs olduu sonucuna varabiliriz. Standard olarak bir web
sayfasnn retilmesi aamasndaki yaam dngsn tm ayrntlaryla izlemek istersek Trace
mekanizmasn kullanabiliriz. Trace konusuna detaya girmeyecek olsakta, yaam dngs
ierisindeki admlar grmemiz asndan bir rnek yapmamz gerektiini dnyorum. Trace' i
aktif hale getirmek iin Web.config dosyasna aadaki eleman eklememiz yeterli olacaktr.

Buna gre Trace bilgileri ilgili web uygulamasndaki her sayfann sonunda (pageOutput=true) ve
yanlzca sunucu bilgisayar zerindeki isteklerde (localOnly="true") grnecek ekilde aktif hale
getirilmektedir. imdi default.aspx sayfamz tarayc pencersinden talep edersek aadaki kty
elde ederiz.

www.bsenyurt.com Page 1365


Bu kty sayfamz ilk talep ettiimizde elde ederiz. Peki Button kontrolmze basp sayfay
istemciden sunucuya gnderdiimizde (post-back) yaam dngs nasl ileyecektir? Hereyden
nce sayfa zerindeki verilerin istemciden gelmesiyle birlikte post edilen datalarn ve viewstate
verilerinin ilendii baka olaylarda tetiklenecek ve iletilecektir. Bu durumda trace bilgilerimiz
aadaki gibi olacaktr.

www.bsenyurt.com Page 1366


Temel olarak buradaki olaylardan bazlarn sayfamz ierisinde ele alabilir ve sayfann yaam
dngs ierisinde kendi isteklerimizi kodlayarak yrtebiliriz. Bir web sayfasnn yaam
dngsnde ele alnabilecek olaylar daha basit olarak dndmzde aadaki sralamay ele
alabiliriz.

Page_PreInit
Page_Init
Page_Load
Button iin Click / Change Olay Metodlar (Eer tetiklenmiler ise)
Page_PreRender
Page_UnLoad
Dispose (Eer override edilmise)

www.bsenyurt.com Page 1367


Burada dikkat ederseniz Page_Load ve Page_PreRender olaylar arasnda sayfa zerindeki
bileenlere ait Click ve Change olaylarnn yer aldn grrz. Yukardaki Trace ktsnda bunlar
tam olarak gremesekte Button_Click olay metodu ierisine aadaki kodu yazarak izleme ansna
sahip olabiliriz.

Trace.Warn("Button Click olay metodu alyor..."); // Trace' e krmz renkte bilgi yazdryoruz.

Bu kodu altrdmzda Trace ktsnda aadaki grnty elde ederiz.

Buradaki ktnn Button kontrolne basp sayfay sunucuya gnderdikten sonra olutuuna dikkat
edelim.

Sonu olarak talep edilen her web sayfas, sunucu tarafnda bir nesne olarak retilir,
altrlr, HTML kts alnr ve yok edilir (Dispose).

Bu olaylar ierisinde zellikle dikkate deer olan iki tanesi vardr. Page_UnLoad ve Dispose.
Page_UnLoad sayfaya ait Html kts retildikten sonra alr. Bu nedenle burada HTML ktsna
mdahale etme ansmz artk kalamamaktadr. Dolaysyla, sayfa ierisinde kullanlan baka
managed kaynaklarn kapatlmas ve sisteme iade edilmesi iin ideal bir olay metodudur. Dier
taraftan Dispose metodu Page snf ierisinde override edildii takdirde, Unmanaged kaynaklarn
sisteme iade edilmesi iin biilmi kaftandr.

Yaam dngsnde yer alan baz olaylar kod tarafnda ele alabileceimizden bahsetmitik. Web
sayfasna ait olay metodlar ile (ki bunlarn yaam dngs ierisinde nemli bir rol vardr),

www.bsenyurt.com Page 1368


sayfann Page direktifinde yer alan AutoEventWireup niteliinin deeri arasnda nemli bir iliki
vardr. rnein aadaki kod parasn ele alalm.

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


Inherits="_Default" %>

<script runat="server">

protected void Page_PreInit(object sender,EventArgs e)


{
Response.Write("PreInit olay metodu alt...");
}

</script>

Default.aspx sayfasn altrdmzda PreInit isimli olay metodunun ilemediini grrz. Bunun
sebebi varsaylan olarak true deerine sahip olan AutoEventWireup zelliine false deerini
atamam olmamzdr. Buradan u sonuca varabiliriz. Sayfaya ait olay metodlarnn otomatik olarak
balanmasn salamak iin AutoEventWireup zelliinin deerinin true olmas gerekmektedir.
Nitekim bu deeri true yaptmzda PreInit olay metodunun altn grebiliriz.

Peki AutoEventWireup niteliine false deerinin atanabilmesinin nasl bir katma deeri olabilir.
Bunun iin aadaki kod parasn gz nne alabiliriz.

www.bsenyurt.com Page 1369


Bu kod parasna gre InitOncesi isimli olay metodumuz sayfann PreInit olay gerekletii zaman
altrlacak metod olacaktr. AutoEventWireup nitelii Asp.Net 1.1 versiyonunda varsaylan olaran
false deerine sahip olan bir niteliktir. Sayfa olaylarn kendi isimlendirdiimiz metodlar ile
ilikilendirmekten baka bir avantaj saladn dnmemiz ne yazkki pek mmkn deildir.

Grdnz gibi herhangibir tasarm olmayan hatta nemli bir i yapmayan bir web sayfas
zerinde konuulabilecek olduka fazla konu vardr. Bu makalemizde bir web sayfasnn anatomisini
ve gze arpan noktalarn incelemeye altk. Bylece geldik bir makalemizin daha sonuna. Bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Kullanc Web Kontrollerini Daha Etkin


Kullanmak ( 21.11.2006 ) - Asp.Net
Deerli Okurlarm Merhabalar,

Kullanc web kontrolleri (web user control) kendi ilerinde birden fazla kontrol barndrabilen
komposit tipteki grsel bileenlerdir. Asp.Net 1.0/1.1 den veri var olan kullanc web kontrollerini
ounlukla, birden fazla sayfada kullandmz durumlarda (hatta ayn sayfada bir ok yerde ayn
kontrol kmelerini kullanmak istediimizde) dnr ve gelitiririz. Bu kontroller tek bir yerde
durduklar iin gncelletirilmeleri halinde, kullanldklar tm sayfalara ilgili deiiklikler
yansyacaktr. Gncelleme kolayl, kullanc web kontrollerini tercih etmemizin en byk
nedenlerinden birisidir. Ancak bu kontroller bir adan bakldnda, herhangibir web sayfasna
eklenen web sunucu kontrollerinden (web server control) yada html sunucu kontrollerinden (html
server control) ok da farkl dnlmemelidir. Nasl ki bir web sunucu kontrolnn zellikleri
(properties) ve olaylar(events) oluyorsa bir web kullanc kontrolnnde zellikleri ve olaylar
olabilir. Nihayetinde, bir kullanc tanml web kontrol
aslnda System.Web.UI.UserControl snfndan trerler ve kullanld sayfann bir paras olarak
sunucu tarafnda nesne baznda ele alnrlar. Dolaysyla kullanldklar sayfada yakalanabilecek
olaylar ve kullanlabilecek zellikleri olabilir. Hatta bir web kontroln nasl dinamik olarak
oluturabiliyorsak bir kullanc web kontroln de dinamik olarak oluturabilir ve sayfann o anki
ieriine ekleyebiliriz. te bu makalemizde daha ok bu konular zerinde durmaya alacaz.
Temel olarak aadaki maddede duracaz.

zellik (Property) kullanm


Kullanc web kontrollerini dinamik oluturma
Olay (Event) kullanm

1. zellik (Property) Kullanm

Kullanc web kontrollerinin aslnda System.Web.UI.Control tipinden treyen snflar eklinde ifade
edilebileceinden bahsetmitik. Bu nedenle kullanc web kontrollerine zellik ekleyebiliriz. Bu
zellikler yardmyla rnein bir kullanc tanml kontrol ierisindeki bileenlerin baz zelliklerine
dardan eriebilir hatta deitirebiliriz. Dilerseniz rnek bir senaryo zerinden gidelim. Aadaki
ekran ktsna sahip olan bir web user control' mz olduunu dnelim.

www.bsenyurt.com Page 1370


AdresBilgisi.ascx;

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


Inherits="AdresBilgisi" %>
<table>
<tr>
<td >l</td>
<td ><asp:DropDownList ID="ddlIl" runat="server" ></asp:DropDownList></td>
</tr>
<tr>
<td >le</td>
<td ><asp:TextBox ID="txtIlce" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td >Cadde</td>
<td ><asp:TextBox ID="txtCadde" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td >Sokak</td>
<td ><asp:TextBox ID="txtSokak" runat="server"></asp:TextBox></td>
</tr>
<tr>
<td >Posta Kodu</td>
<td ><asp:TextBox ID="txtPostakodu" runat="server"></asp:TextBox></td>
</tr>
</table>

AdresBilgisi.ascx.cs;

public partial class AdresBilgisi : System.Web.UI.UserControl


{
protected void Page_Load(object sender, EventArgs e)
{
string[] iller = new string[] { "Istanbul", "Ankara", "Izmir" };
foreach (string il in iller)
ddlIl.Items.Add(il);
}
}

AdresBilgisi isimli kullanc tanml web kontrolmz ierisinde basit olarak l, le, Cadde, Sokak,
PostaKodu gibi bilgiler tutulmaktadr. Elbette burada sade dnmek zorunda olduumuzdan
kontrol mmkn olduunca basit tasarladk. Normal artlar altnda bu kontrole dorulama
(validation) bileenlerini ilave etmek, il ve ile gibi bilgileri bir birleri ile ilikili olacak ekilde gerekli

www.bsenyurt.com Page 1371


veri kmelerinden ekmek gibi ilemleri gz ard ediyoruz. Odaklanacamz nokta bu kontrol iin
kendi zelliklerimizi yazmak ve kullanmak olacak. imdi bu kontrollerden iki tanesini
kullanacamz aadaki ekran grntsne sahip bir web sayfas olduunu dnelim.

Aslnda senaryomuz olduka tandk gelecektir. Bir al veri sitesinde, teslimat adresi ve fatura
adresi bilgilerinin ayn olmas halinde ayn tipten iki web user control arasnda nasl iletiim
kuracaz. (ok doal olarak burada bir CheckBox kontrol kullanp teslima adresinin fatura adresi
olraakta kullanlacan belirtebilir ve ii tek bir kullanc tanml web kontrol ile halledebileceimizi
dnebiliriz. Ancak byle bir durumdada farkl bir Fatura adresi girilmesi mmkn
olmayacaktr.) te bu nokta bize web user control ierisindeki kontrollerin dardan eriebilir
olmasn salayacak zellikler gerekecektir. Bu amala, AdresBilgisi isimli kullanc tanml web
kontrollmze aadaki gibi zellikler eklememiz gerekecektir. zelliklerimiz kullanc web kontrol
ierisindeki bileenlerin Text, SelectedIndex gibi zelliklerinin deerlerini d ortama amaktan
sorumludur.

public int Il
{
get { return ddlIl.SelectedIndex; }
set { ddlIl.SelectedIndex = value; }
}
public string Ilce
{

www.bsenyurt.com Page 1372


get { return txtIlce.Text; }
set { txtIlce.Text = value; }
}
public string Cadde
{
get { return txtCadde.Text; }
set { txtCadde.Text = value; }
}
public string Sokak
{
get { return txtSokak.Text; }
set { txtSokak.Text = value; }
}
public string PostaKodu
{
get { return txtPostakodu.Text; }
set { txtPostakodu.Text = value; }
}

Artk AdresBilgisi kontrol ierisindeki yelere kod tarafnda eriebilir, dahada nemlisi
dndmz senaryoyu gerekleyebiliriz. Bunun iin tek yapmamz gereken default.aspx.cs
ierisinde aadaki kod parasn yazmaktr.

protected void btnAyniAdres_Click(object sender, EventArgs e)


{
AdresBilgisi2.Il = AdresBilgisi1.Il;
AdresBilgisi2.Ilce = AdresBilgisi1.Ilce;
AdresBilgisi2.Cadde = AdresBilgisi1.Cadde;
AdresBilgisi2.Sokak = AdresBilgisi1.Sokak;
AdresBilgisi2.PostaKodu = AdresBilgisi1.PostaKodu;
}

imdi rneimizi altralm ve Teslimat adresi bilgilerini girdikten sonra Fatura in Ayn Adresi
Kullan dmesine basalm.

lk Durum;

www.bsenyurt.com Page 1373


Dmeye basldktan sonra;

www.bsenyurt.com Page 1374


Sonuta, AdresBilgisi1 isimli kullanc web kontrol ierisindeki bileenlere ait deerler AdresBilgisi2
isimli kullanc web kontrol ierisinde bileenlere aynen gnderilmitir. Dolaysyla hem kullancy
ayn bilgileri girme zahmetinden kurtardk hemde ayn web user control' e ait birden fazla rnek
arasnda nasl veri transferi yapabileceimizi aydnlatm olduk. Gelelim ikinci konumuza.

2. Kullanc web kontrollerini dinamik oluturma

alma zamannda (run time) web kontrollerini dinamik olarak oluturmak hatta bunlar ayn event
metodlarna ynlendirmek zellikle portal tarz sistemlerde nemlidir. Benzer davran kullanc
web kontrolleri iinde gerekletirebiliriz. Burada dikkat edilmesi gereken husus, kullanc tanml
web kontrolnn ele alnaca sayfa ierisinde kayt edilerek (register) bildirilmesi gerektiidir.
Bunun iin Register direktifinden yararlanabiliriz. rnein AdresBilgisi.ascx kullanc tanml web
kontroln dinamik olarak default2.aspx isimli bir sayfada kullanmak istediimizi dnelim. lk
olarak Register direktifini aadaki gibi eklemeliyiz.

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


Inherits="Default2" %>
<%@ Register Src="~/AdresBilgisi.ascx" TagName="Adres" TagPrefix="adr" %>

Aslnda bir web user control herhangi bir sayfaya eklendii zaman, bu direktif otomatik olarak
eklenmektedir. Bizim u anki amacmz kontrolden bir ka tanesini dinamik olarak oluturup ilgili
web sayfasna eklemek olduundan kod tarafnda ilgili kontrol tipine eriebilmemiz gerekmektedir.

www.bsenyurt.com Page 1375


Bu nedenle ilgili web kullanc kontroln register ettik. Dinamik olarak gerekletirilecek ilemler
iin sayfann Page_Init olay metodunu tercih edebiliriz. (Bu olay metodu bir web sayfasnn yaam
dngsnde genellikle kontroln dinamik olarak oluturulmas istendii durumlarda tercih
edilmektedir. Elbetteki bu bir zorunluluk deildir. stenildiinde Page_PreInit yada Page_Load gibi
event metodlarnda dinamik kontrol oluturma amacyla gz nne alabiliriz.)

protected void Page_Init(object sender, EventArgs e)


{
AdresBilgisi kontrol1=(AdresBilgisi)LoadControl("AdresBilgisi.ascx");
AdresBilgisi kontrol2 = (AdresBilgisi)LoadControl("AdresBilgisi.ascx");

kontrol1.Ilce = "le giriniz...";


kontrol2.PostaKodu = "90000";

phKontroller.Controls.Add(kontrol1);
phKontroller.Controls.Add(kontrol2);
}

Dikkat ederseniz, AdresBilgisi isimli kullanc web kontrollerini ncelikle yklememiz gerekmektedir.
Bu ilem iin LoadControl metodu kullanlmtr. Bu metod o anki sayfaya (Page) ait bir
metoddur ve geriye Control tipinden bir nesne rnei dndrmektedir. Kontrol bu ekilde
ykledikten sonra hemen ilgili tayc nesneye eklemeyi tercih edebiliriz elbette. Ancak biz
kontrolmzn Ilce, PostaKodu gibi zelliklerinede kod ierisinde erimek istediimizden doru bir
tip dnmne ihtiyacmz vardr. Bu nedenle LoadControl ile elde edilen Control nesnesi
AdresBilgisi tipine cast operatr yardmyla dntrlmektedir. rneimizi altrdmzda
phKontroller isimli PlaceHolder bileeninin Controls koleksiyonuna, AdresBilgisi kontrollerinin
aadaki gibi eklendii gzlemlenebilir.

3. Olay (Event) Kullanm

www.bsenyurt.com Page 1376


Kullanc web kontrollerini, sradan bir web sunucu kontrol olarak dnmeye altmzda
olaylara sahip olabileceini de syleyebiliriz. rnein bir Button nesnesi bir web sayfasna
eklendiinde ve bu nesneye mouse ile basldnda Click event' i (eer yklenmi ise) aktif hale
gelir. Web tabanl uygulamalarn doas gerei bu olaya ilikin metodlar, her ne kadar sayfann
ierisindeki yeler olsalarda hemen altrlmazlar. Bunun sebebi, sunucu tarafnda ilgili web
sayfasnn nesnel olarak retilmesi srasnda alan yaam dngs (page life cycle) dr. stemci
aslnda bir dmeye bastnda, sayfa istemci tarayc penceresinden sunucuya doru ierii ile
birlikte gnderilir (Bu ilemi genellikle Postback olarak adlandryoruz). Bunun zerine sunucu
tarafnda gnderilen sayfann bir rnei oluturulur ve ok genel hatlar ile aadaki yaam
dngs alr.

Page_PreInit
Page_Init
Page_Load
Button iin Click / Change Olay Metodlar
Page_PreRender
Page_UnLoad

Peki biz kendi gelitirdiimiz kullanc web kontrollerine olay eklemek istersek ne olur. ncelikle
olarak sayfann yaam dngs aadakine benzer bir srada ileyecektir.

Aspx sayfas ilk talep edildiinde;

Default3.aspx Page_PreInit
Urun.ascx Init
Urun.ascx Init
Default3.aspx Page_Init
Default3.aspx Load
Urun.ascx Load
Urun.ascx Load
Urun.ascx UnLoad
Urun.ascx UnLoad
Default3.aspx Page_UnLoad

Sayfadaki Web User Control ierisinden bir olay tetiklendiinde;

Default3.aspx Page_PreInit
Urun.ascx Init
Urun.ascx Init
Default3.aspx Page_Init
Default3.aspx Load
Urun.ascx Load
Urun.ascx Load
Default3.aspx iinde alan web user control olay
Urun.ascx UnLoad
Urun.ascx UnLoad
Default3.aspx Page_UnLoad

Yaam dngsnn ileyiini ksaca inceledikten sonra kullanc web kontrolleri iin olaylar nasl
yazabileceimize bir bakalm. lk olarak, bir temsilci (delegate) tanmlanr. Temsilcinin amac, ilgili
olay tetiklendiinde devreye girecek olan olay metodunun yapsn tanmlamak ve alma
zamannda bu metodun adresini iaret etmektir. Sonrasnda ise bir event tanmlanr.
Tanmladmz event, user control' kullandmz sayfalarda ele alnabilecektir. Bir baka deyile,
kullanc web kontrol ierisinde tanmlanan olay gerekletiinde, sayfa ierisinde yazlan olay
metodu devreye girecektir. Genel olarak olay metodlar iki parametre ile alrlar. lk parametre

www.bsenyurt.com Page 1377


ounlukla olay meydana getiren nesneyi referans eder. kinci parametre ise, olay metoduna olay
ile ilgili bir takm bilgiler aktarabilir. rnein EventArgs gibi. Dolaysyla kendi parametre
snflarmz yazp, olay metodu ierisine bilgi tayabiliriz. imdi dilerseniz bu ilemleri bir senaryo
zerinden incelemeye alalm.

rnek senaryomuzda, Urun.ascx isimli bir web user control nesnemiz var. Bu nesne ierisinde
dinamik olarak oluturulan CheckBox kontrollerinde gnler tutulmakta. Kullanc rnlerin teslim
edilebilecei gnleri seebilmektedir. Kontrol zerinde yer alan dmeye basldnda ise,
SecilenleriAl isimli bir olay manual olarak tetiklenmektedir. nemli olan nokta, SecilenleriAl isimli
olayn kontroln kullanld sayfa ierisinde yakalanabilecei ve ele alnabileceidir. Bu kontrol
ierisinde tanmladmz temsilcimiz kendi ierisinde KontrolBilgileri isimli bir snf olay parametresi
olarak kullanmaktadr. Bir baka deyile KontrolBilgileri snfn EventArgs snf gibi dnebiliriz.
nce KontrolBilgileri snfn tasarlayarak ie balayalm.

public class KontrolBilgileri


{
private List<string> m_Kontroller;

public List<string> Kontroller


{
get { return m_Kontroller; }
}

public KontrolBilgileri(PlaceHolder ph)


{
m_Kontroller = new List<string>();
for (int i = 0; i < ph.Controls.Count; i++)
{
if (ph.Controls[i] is CheckBox)
{
CheckBox currentChk=ph.Controls[i] as CheckBox;
if (currentChk.Checked)
m_Kontroller.Add(currentChk.Text);
}
}
}
}

KontrolBilgileri snfnn grevi, olay metodu ierisine, kullanc web kontrolnde seili olan
CheckBox bileenlerinin Text bilgilerini string tipinden elemanlar tayan generic bir koleksiyon
eklinde dndrmektir. Olay iine bilgi tayacak snfmz tasarladktan sonra kullanc web
kontrolmz aadaki gibi gelitirebiliriz.

Urun.ascx;

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


%>
<asp:PlaceHolder ID="phGunler" runat="server"></asp:PlaceHolder>
<br />
<br />
<asp:Button ID="btnIsaretle" runat="server" Text="Isaretle" OnClick="btnIsaretle_Click" />

Urun.ascx.cs;

www.bsenyurt.com Page 1378


public partial class Urun : System.Web.UI.UserControl
{
public delegate void SecilenleriAlHandler(KontrolBilgileri args);
public event SecilenleriAlHandler SecilenleriAl;

protected void Page_Load(object sender, EventArgs args)


{
string[] gunler = new string[] { "Pazartesi", "Sal", "aramba", "Perembe", "Cuma",
"Cumartesi", "Pazar" };
foreach (string gun in gunler)
{
CheckBox chkBox = new CheckBox();
chkBox.ID = gun;
chkBox.Text = gun;
phGunler.Controls.Add(chkBox);
LiteralControl lc = new LiteralControl("<br/>");
phGunler.Controls.Add(lc);
}
}
protected void btnIsaretle_Click(object sender, EventArgs e)
{
if (SecilenleriAl != null)
SecilenleriAl(new KontrolBilgileri(phGunler));
}
}

Kontrolmzde, SecilenleriAlHandler isimli temsilci(delegate) ve SecilenleriAl isimli olay (event)


yesi yer almaktadr. btnIsaretle isimli dmemize ait Click olay metounda, SecilenleriAl isimli bir
olay kontrol kullanan bir sayfa tarafndan yklenmi ise manual olarak tetiklenmektedir. Bu u
anlama gelir. Eer kontrol kullandmz bir web sayfasnda, bu kontrole ait SecilenleriAl isimli bir
olay yklenmi ise, bununla ilikili olay metodu altrlacaktr. Bu amala default3.aspx isimli
rnek bir sayfada aadaki kodlar gelitirelim.

default3.aspx;

www.bsenyurt.com Page 1379


default3.aspx.cs;

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


{
protected void Secilenler(KontrolBilgileri kb)
{
for (int i = 0; i < kb.Kontroller.Count; i++)
Response.Write(kb.Kontroller[i]+"<br/>");
}
}

Uygulamamz altrdmzda, user control zerinde baz seenekleri iaretlediimizde ve dmeye


bastmzda o sayfa zerinde tanmladmz Secilenler isimli olay metodunun altn ve seilen
gnlerin ekrana yazldn grebiliriz.

www.bsenyurt.com Page 1380


Dikkat edilmesi gereken bir nokta vardr. ounlukla kontrolleri dinamik olarak oluturup bir web
sayfasna eklediimizde bu kontrollerin hepsini tek bir olay metoda ynlendirebiliriz. lgili olay
metodu ierisinde hangi kontrolden gelindiini anlamak iin ise genellike object tipinden gelen ve
ismi ounlukla sender olarak bilinen deikeni ilgili tipe cast ederiz. Benzer yapy Urun.ascx
kontrol iin dndmzde, SecilenleriAl isimli olay metoduna ayn ilevsellii salayacak
eklentiyi yapamz gerekecektir. Bunun iin temsilciyi, olay tetikleyen metoddaki ary ve snf
zerindeki kontrole ait olay metodunu aadaki gibi deitirmemiz yeterli olacaktr.

Urun.ascx.cs' de temsilci;

public delegate void SecilenleriAlHandler(object gonderen,KontrolBilgileri args);

Urun.ascx.cs' de olay tetikleyen button_Click metodu;

protected void btnIsaretle_Click(object sender, EventArgs e)


{
if (SecilenleriAl != null)
SecilenleriAl(this,new KontrolBilgileri(phGunler));
}

default3.aspx.cs' deki Secilenler olay metod;

protected void Secilenler(object sender,KontrolBilgileri kb)


{
for (int i = 0; i < kb.Kontroller.Count; i++)
Response.Write(kb.Kontroller[i]+"<br/>");
}

www.bsenyurt.com Page 1381


Bu deiiklik bize, kontrole ait olay metodu ierisinde hangi web kullanc kontrolnn tetiklendiini
alglama imkan verecektir. Bylece birden fazla web kullanc kontroln ayn olay metoduna
ynlendirdiimizde her birinin zelliklerini ve yelerini ayn metod ierisinde ele alabiliriz. rnein
Urun.ascx ierisinde gnler dnda ekstradan bilgi girilebilecek notlarn olduu bir TextBox
olduunu ve bu TextBox' n ieriine d ortamdan eriebilmemizi salayan read only bir zellik
eklediimizi dnelim.

public string Notlar


{
get{return txtNot.Text;}
}

Default3.aspx sayfasnda Urun.ascx kontrolnden rnein 2 tane olduunu ve bunlarn ayn olay
metoda ynlendirildiini gz nne. Bu durumda ilgili olay metodu ierisinde, hangi kontrol
tarafndan bir tetikleme olduunu tespit edebilir. nk artk olay tetikleyen nesneyi tayan bir
parametremiz vardr. Dolaysyla bu parametre zerinden ilgili Notlar zellie geebilir ve hangi
kontrolden gelindiyse onun notlarn alabiliriz.

protected void Secilenler(object sender,KontrolBilgileri kb)


{
Urun urn = (Urun)sender;
Response.Write(urn.Notlar + "<br/>");

for (int i = 0; i < kb.Kontroller.Count; i++)


Response.Write(kb.Kontroller[i]+"<br/>");
}

www.bsenyurt.com Page 1382


Bu makalemizde kullanc web kontrollerini daha etkin ekilde nasl kullanabileceimizi incelemeye
altk. Aslnda k noktamz bir web kullanc kontroln normal bir web sunucu kontrolne
benzer bir snf olarak dnmekti. Bu sayede kullanc web kontrollerine zellik, olay
ekleyebileceimizi ve dinamik olarak alma zamannda oluturabileceimizi grdk. Bylece
geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek kod iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

SqlCommandBuilder iin 4 Tavsiye ( 13.11.2006 )


- Ado.Net
Deerli Okurlarm Merhabalar,

SqlCommandBuilder snf zellikle balantsz katman (disconnected layer) modelinde ska


kullanlmaktadr. ounlukla, SqlDataAdapter tipine ait nesneler iin gerekli olan UpdateCommand,
InsertCommand ve DeleteCommand zelliklerine bal SqlCommand nesnelerini sfrdan
oluturmamak iin tercih edilebilir. Framework 1.1' de zellikle balantsz katman modeline ait bir
vakka olan Concurency Violation durumlarndaki yaklam nedeniyle (tm kolonlar where' e dahil
etmek) bazen tercih edilmemektedir. Ancak SqlCommandBuilder, Framework 2.0 ile birlikte
kendisine eklenen yeni yeler sayesinde daha da fonksiyonel hale gelmitir. Bununla birlikte
SqlCommandBuilder tipinin sadece balantsz katman (disconnected layer) modeli iin yazlm
olduunu dnmek hakszlk olacaktr. Nitekim katmanl mimaride veri eriim katman (data
access layer) ierisinde son derece kullanl olabilecek bir metodada sahiptir. te bu makalemizde
SqlCommandBuilder tipinin, .Net Framework 2.0 versiyonu ile birlikte glendirilmi olan
ynlendiren bahsetmeye alacaz. Temel olarak ileyeceimiz maddeler aadaki gibidir.

Stored Procedure' lerin parametrik yapsn alma zamannda bir SqlCommand nesnesine
aktarabilme
akma durumlar iin uygun olan yntemi ConflictOption zellii ile belirleyebilme
Update ilemleri srasnda sadece gncellenen parametreleri sql sunucusuna gnderebilme
SqlDataAdapter iin retilen sql komutlarnda kolon ad kullanlmasn tercih edebilme

imdi burada bahsettiimiz zellikleri incelemeye alalm. Ancak maddelerimizi incelemeden nce
senaryo olarak kullanacamz tablomuzu aadaki sql script yardmyla oluturalm. Personel isimli
tablomuz Sql Server 2005 zerinde AdventureWorks veritaban altnda yer alacaktr. Ancak
rneklerimiz iin dilerseniz siz kendi tablolarnzda kullanabilirsiniz.

USE [AdventureWorks]
GO

CREATE TABLE [dbo].[Personel](


[PersonelId] [int] IDENTITY(1,1) NOT NULL,
[Adi] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Soyadi] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Maasi] [money] NOT NULL,
[IseGirisTarihi] [datetime] NOT NULL,
[Departmani] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Durum] [timestamp] NOT NULL,

www.bsenyurt.com Page 1383


CONSTRAINT [PK_Personel] PRIMARY KEY CLUSTERED
(
[PersonelId] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

1. Stored Procedure' lerin parametrik yapsn alma zamannda bir SqlCommand


nesnesine aktarabilme

yle bir metod dnelim ki, sadece altraca sakl yordamn (stored procedure) adn, ve
saysn bilmemesine ramen parametrelerinin deerlerini alsn. Sonrada iaret ettii bu sakl
yordam yrtsn. Bu tam anlamyla veri eriim katmanlarnda kullanlabilecek bir metod tipidir. Bir
sakl yordam altrrken eer ald giri parametreleri (input parameter) varsa bunlar mutlaka
ilgili SqlCommand nesnesinin Parameters koleksiyonuna ayn adlarda olmak artyla eklememiz
gerekmektedir. imdi ilk olarak varsaylan haliyle byle bir ii nasl yapacamz dnmeye
alalm. Bu amala Personel tablomuza satr ekleyen aadaki gibi bir sakl yordammz olduunu
varsayalm.

CREATE PROCEDURE dbo.PersonelEkle


(
@Adi nvarchar(50)
,@Soyadi nvarchar(50)
,@Maasi money
,@IseGirisTarihi datetime
,@Departmani nvarchar(50)
)
AS
Insert into Personel (Adi,Soyadi,Maasi,IseGirisTarihi,Departmani)
Values (@Adi,@Soyadi,@Maasi,@IseGirisTarihi,@Departmani)
RETURN

Sakl yordammz be adet input parametresi almaktadr. Bu sp' yi altracak olan bir
SqlCommand nesnesi temel olarak aadaki kodda grld gibi kullanlacaktr. Dikkat ederseniz
sakl yordammz ierisindeki tm parametreler cmd isimli SqlCommand nesne rneinin
Parameters koleksiyonuna eklenmekte, eklenirkende metoda gelen deerlerini almaktadrlar.

class Komutlar
{
private string m_ConStr;

public Komutlar(string conStr)


{
m_ConStr = conStr;
}
public void PersonelEkle(string ad,string soyad,decimal maas,DateTime iseGiris,string
departman)
{
using (SqlConnection con = new SqlConnection(m_ConStr))
{
SqlCommand cmd = new SqlCommand("PersonelEkle", con);
cmd.CommandType = System.Data.CommandType.StoredProcedure;
cmd.Parameters.AddWithValue("@Adi",ad);
cmd.Parameters.AddWithValue("@Soyadi",soyad);
cmd.Parameters.AddWithValue("@Maasi",maas);
cmd.Parameters.AddWithValue("@IseGirisTarihi",iseGiris);

www.bsenyurt.com Page 1384


cmd.Parameters.AddWithValue("@Departmani",departman);
con.Open();
cmd.ExecuteNonQuery();
}
}
}
class Program
{
static void Main(string[] args)
{
Komutlar kmt = new Komutlar("data source=localhost;database=AdventureWorks;integrated
security=SSPI");
kmt.PersonelEkle("Hey", "Mayk", 1000, new DateTime(2001, 1, 1), "Spor
Arabalar");
}
}

Bu kod baarl bir ekilde alacaktr. Ancak dikkat ederseniz PersonelEkle metodu sadece
PersonelEkle sakl yordamn altrabilir. Dahas, metodun ierisindeki SqlCommand nesne
rneine ait parametre deerleri, aslnda metoda gelen parametrelerin deerleridir. Dolaysla
parametrelerin adlar hatta tipleri deiebilir. Bu tarz durumlarda srekli olarak kod zerinde
dzenlemeler yapmamz ve yeniden derlememiz yada baka bir yol dnmemiz gerekecektir.
Oysaki aadaki metod tam anlamyla her hangibir Sql sakl yordamnn her hangi sayda
parametresine hizmet edebilecek niteliktedir.

public void Execute(string spAdi, params object[] degerler)


{
using (SqlConnection conn = new SqlConnection(m_ConStr))
{
using (SqlCommand cmd = new SqlCommand(spAdi, conn))
{
cmd.CommandType = System.Data.CommandType.StoredProcedure;
conn.Open();
// DeriveParameters sadece Sp' lerde ie yarayan bir tekniktir.
SqlCommandBuilder.DeriveParameters(cmd);
for (int i = 1; i <= degerler.Length; i++)
cmd.Parameters[i].Value = degerler[i-1];
cmd.ExecuteNonQuery();
}
}
}

Metodumuz ilk parametre olarak altraca sakl yordamn adn alr. Daha sonra
ise params anahtar szcnden faydalanarak n sayda, object tipinden elemanlar tayan bir
diziyi parametre almaktadr. Metodumuz ierisinde yer alan SqlCommandBuilder snfnn
static DeriveParameters metodu ise, parametre olarak ald SqlCommand nesnesinin iaret
ettii sakl yordama gider, bu yordamn parametrelerini (ilk parametresi @RETURN_VALUE olacak
ekilde) alr ve ilgili komut nesnesinin Parameters koleksiyonuna ekler. Eer uygulamay debug
ederseniz aadaki ekran grntsnde olduu gibi sakl yordam parametrelerinin cmd nesnesine
eklendiini grebilirsiniz.

www.bsenyurt.com Page 1385


Execute metodumuzun bu versiyonunu aadaki gibi test edebiliriz.

Komutlar kmt = new Komutlar("data source=localhost;database=AdventureWorks;integrated


security=SSPI");
kmt.Execute("PersonelEkle","Hey", "Mayk", 1000, new DateTime(2001, 1, 1), "Spor
Arabalar");

Peki DeriveParameters metodu aslnda ne yapmaktadr. Sql Server Profiler yardmyla bu


uygulmann arka planda altrd sql kodlarn incelersek aadaki gibi bir ar ile karlarz.

www.bsenyurt.com Page 1386


Dikkat ederseniz sp_procedure_params_managed isimli bir sakl yordam, parametrelerini elde
etmek istediimi sakl yordamn adn parametre alarak altrlmaktadr. Bu ifadeyi Sql Server
2005 Management Studio zerinde altrrsak, aadaki gibi bir kt elde ederiz.

Sistem sp' lerinden olan sp_procedure_params_managed aslnda PersonelEkle isimli sakl


yordam ierisindeki tm parametreleri ve bu parametrelere ait detayl bilgileri bir tablo olarak
geriye dndrmektedir. Bu tabloda parametrelerin adlarndan tutunda veri tiplerine kadar, null
deer ierip iermekyeceklerinden tayacaklar veri uzunluuna kadar tm bilgiler yer almaktadr.
Bu tabloyu deerlendiren elbette SqlCommandBuilder nesnesinin kendisidir. Tablo ierisindeki
bilgilere gre ilgili SqlCommand nesnesinin parameters koleksiyonuna gerekli eklemeler yaplr.

OleDbCommandBuilder, OracleCommandBuilder, ODBCCommandBuilder snflard


a DeriveParameters metodunu destekler. Tek art, ilgili veri taban sisteminin sakl
yordama ait parametre yapsn getirebiliyor olmasdr. Unutmayalm; DeriveParameters
sadece sakl yordamlar iin geerlidir. Dz Sql sorgu cmlelerini ele alan komutlar iin
(parametrik bile olsalar) InvalidOperationException istisnas dndrmektedir.

2. akma durumlar iin uygun olan yntemi ConflictOption zellii ile belirleyebilme

Balantsz katman nesneleri ile alrken, bamz en ok artan konulardan biriside,


birbirlerinden habersiz olarak bir den fazla kullancnn ayn veri zerinde deiiklik yapmasdr.
Byle bir durumda son gncelleme kazansn (Last Wins) tekniini tercih edebilir yada
DbConcurrencyViolation istisnasn ele alabiliriz. (Konu hakknda detayl bilgi iin tklayn.) Hangi
teknii seersek, Update ve Delete sorgularnn where koullarnda deiiklik olacaktr.
SqlCommandBuilder snfna yeni katlan ConflictOptionszellii ile retilen komutlarn bizim
seeceimiz akma kuralna gre oluturulmas salanabilir. Last Wins teknii iin Where
kouluna, o tabloda yer alan Primary Key alann orjinal
deeri, DBConcurrencyViolation durumda ise tm alanlarn orjinal deerleri yada Id alan ile
birlikte varsa TimeStamp gibi alanlarn orjinal deeleri hesaba katlacaktr. imdi bu durumu analiz
edeceimiz rnek bir Windows uygulamasn aadaki gibi gelitirelim.

public partial class Form1 : Form


{
private SqlConnection conn;
private SqlDataAdapter daPersonel;

www.bsenyurt.com Page 1387


private DataTable dtPersonel;

public Form1()
{
InitializeComponent();
}
// DataAdapter hazrlanr.
private void PrepareDataAdapter()
{
conn = new SqlConnection("data source=localhost;database=AdventureWorks;integrated
security=SSPI");
daPersonel = new SqlDataAdapter("Select
PersonelId,Adi,Soyadi,Maasi,IseGirisTarihi,Departmani,Durum From Personel", conn);
}
/* SqlCommandBuilder hazrlanr ve Update, Delete, Insert komutlarn hazrlamas salanr.
Oluan komutlar bilgi amacyla StringBuilder kullanlarak bir RichTextBox kontrolne yazlr. */
private void PrepareCommands()
{
SqlCommandBuilder cmb = new SqlCommandBuilder(daPersonel);
ConflictOption selectedOption =
(ConflictOption)Enum.Parse(typeof(ConflictOption),
cmbConflictOptions.SelectedItem.ToString());
cmb.ConflictOption = selectedOption; // akma seenei belirlenir.
daPersonel.InsertCommand = cmb.GetInsertCommand();
daPersonel.UpdateCommand = cmb.GetUpdateCommand();
daPersonel.DeleteCommand = cmb.GetDeleteCommand();

StringBuilder builder = new StringBuilder();


builder.Append("Insert Command : \n");
builder.Append(daPersonel.InsertCommand.CommandText + "\n");
builder.Append("Update Command : \n");
builder.Append(daPersonel.UpdateCommand.CommandText + "\n");
builder.Append("Delete Command : \n");
builder.Append(daPersonel.DeleteCommand.CommandText + "\n");
txtCommands.Text = "";
txtCommands.Text = builder.ToString();
}
/* Select dmesine basldnda dataTable oluturulur, SqlDataAdapter tarafndan doldurulur ve
DataGridView kontrolne veri kayna olarak balanr. */
private void btnSelect_Click(object sender, EventArgs e)
{
dtPersonel = new DataTable();
daPersonel.Fill(dtPersonel);
grdPersonel.DataSource = dtPersonel;
grdPersonel.Columns.Remove("Durum"); // TimeStamp tipi alanlar DataGridView' da
problem kartt iin kartld.
}
/* Form yklenirken DataAdapter hazrlanr, ConflictOption iin enum sabiti zerinden alnan
deerleri ComboBox' a dolduran PrepareConflictOption metodu arlr.*/
private void Form1_Load(object sender, EventArgs e)
{
PrepareDataAdapter();
PrepareConflictOptions();
cmbConflictOptions.SelectedIndex = 0;
}
// ConflictOption enum sabiti ierisindeki deerleri ComboBox kontrolne doldurur.

www.bsenyurt.com Page 1388


private void PrepareConflictOptions()
{
string[] conflictOptions = Enum.GetNames(typeof(ConflictOption));
foreach (string option in conflictOptions)
cmbConflictOptions.Items.Add(option);
}
/* DataTable zerindeki deiiklikeri asl veri kaynana yazmadan nce SqlCommandBuilder
oluturulduu ve Delete, Update, Insert komutlarnn hazrland PrepareCommands metodunu
arr. */
private void btnUpdate_Click(object sender, EventArgs e)
{
PrepareCommands();
daPersonel.Update(dtPersonel);
}
}

Kod tarafnda bizim iin nemli olan ksm PrepareCommand metodu ierisinde yaptklarmzdr. Bu
metod ierisinde SqlDataAdapter nesnesi iin gerekli Update,Delete ve Insert komutlarn
oluturmaktayz. akma seeneini dikkat ederseniz ConflictOption enum sabiti zerinden
almaktayz. Uygulamada SqlDataAdapter iin gerekli komutlar oluturduktan sonra, Update
metodunu belirlediimiz akma seeneine gre hazrlanan komutlara gre yrtmekteyiz.
ConflictOption enum
sabiti CompareAllSearchableValues,CompareRowVersion ve OverwriteChanges olmak zere
deer alabilmektedir. Buna gre SqlCommandBuilder nesnesinin bu 3 seenek iin rettii
ktlar aadaki gibi olacaktr.

CompareAllSearchableValues iin;

Dikkat ederseniz Update ve Delete sorgularnda Where cmleciine TimeStamp tipindeki Durum
alan hari tm alanlar katlmtr.

www.bsenyurt.com Page 1389


CompareRowVersion iin;

Dikkat ederseniz Update ve Delete sorgularnda Where kouluna sadece Primary Key olan
PersonelId alan ve TimeStamp tipinden olan Durum alan katlmtr. Bu eit bir sorgu zellikle
DBConcurrency Violation durum iin idealdir.

CompareRowVersion zellikle DBConcurrencyViolation durumu iin biilmi kaftan gibi


gzksede, dier veri salayclar iin gelitirilmi CommandBuilder nesnelerinde ayn
geerlilik olmayabilir. Nitekim, Timestamp veri tr her veritaban sisteminde var
olan bir tr deildir. Bu tip veri trlerine sahip olmayan sistemlerde mecburen
DBConcurrencyViolation durumlarnn ele alnmasnda, where cmleciinden sonra
mmkn olan tm alanlarn hesaba katlmas gerekecektir. Bir baka
deyileCompareAllSearchableValues seenei seilecektir.

OverwriteChanges iin;

www.bsenyurt.com Page 1390


Dikkat ederseniz Update ve Delete sorgularna ait Where koullarna sadece Primary Key olan
PersonelId alan katlmtr. Dolaysyla Last Wins modeli geerlidir.

Grld gibi, SqlCommandBuilder snfna Framework 2.0 ile gelen ConflictOption zellii,
akma senaryolarna bal olarak uygun Delete ve Update komutlarnn hazrlanmasn
salamaktadr.

3. Update ilemleri srasnda sadece gncellenen parametreleri sql sunucusuna


gnderebilme

SqlDataAdapter balantsz katman nesnelerinde yaplan deiilikleri asl veri kaynana yazmak
zere Update metodunu kullanmaktadr. Balantsz katmandaki verilerde sadece deiiklie
uram alanlar update sorgularna dahil etmek istersek SqlCommandBuilder'
n SetAllValues isimli zelliine false deerini atamamz yeterli olacaktr. SetAllValues zellii
varsaylan olarak true deerine sahiptir. Yani bir satrdaki alanlarn bazlarnda deiiklik olmasada
update sorgusuna gnderilmektedir. Bu durumu Sql Server Profiler yardmyla kolayca analiz
edebiliriz. Ama ncesinde kodumuzda aadaki deiiklii yapalm.

private void PrepareCommands()


{
SqlCommandBuilder cmb = new SqlCommandBuilder(daPersonel);
ConflictOption selectedOption = (ConflictOption)Enum.Parse(typeof(ConflictOption),
cmbConflictOptions.SelectedItem.ToString());
cmb.ConflictOption = selectedOption;
cmb.SetAllValues = false;
daPersonel.InsertCommand = cmb.GetInsertCommand();
daPersonel.UpdateCommand = cmb.GetUpdateCommand();
daPersonel.DeleteCommand = cmb.GetDeleteCommand();
// dier kod satrlar
}

imdi Windows uygulamamz altrlalm ve satrlar zerinde, baz alanlarda (rnein sadece ad
alannda) deiiklik yapp Update metodunu altralm.

www.bsenyurt.com Page 1391


Update ilemini balattktan sonra Sql Server Profiler ile sql tarafna gnderilen update
sorgularna bakarsak aadaki sonular elde ederiz.

rnek olarak sadece PersonelId deeri 1 olan satrn Adi alann deitirdiimizden ve
SqlCommandBuilder nesne rneinde SetAllValues isimli zellie false deerini atadmzdan,
Update sorgusunda sadece Adi alan kullanlmtr. Ancak SetAllValues zelliini hi deitirmessek
yada bilinli olarak true deerini atarsak aadaki sonular elde ederiz.

Grdnz gibi bu kez Update sorgusunda btn alanlar kullanlmtr.

4. SqlDataAdapter iin retilen command' lerde kolon ad kullanlmasn tercih edebilme

u ana kadar incelediimiz maddelerde SqlCommandBuilder nesnesi, Update, Insert ve Delete


komutlarn hazrlarken parametre adlar olarak @P[Rakam] notasyonunu kullanmtr. Yine
Framework 2.0 ile gelen bir zellik sayesinde @P[KolonAd] notasyonunu kullanma ansnada
sahibiz. Bunun iin GetInsertCommand, GetUpdateCommand ve GetDeleteCommand isimli
metodlarn ar yklenmi versiyonunlarn kullanmamz gerekiyor.

www.bsenyurt.com Page 1392


// Insert versiyonu
public SqlCommand GetInsertCommand (bool useColumnsForParameterNames)

// Delete versiyonu
public SqlCommand GetDeleteCommand (bool useColumnsForParameterNames)

// Update versiyonu
public SqlCommand GetUpdateCommand (bool useColumnsForParameterNames)

Bu versiyon bool tipinden bir deer almakta olup, parametre adlarnda kolon isimlerinin gsterilip
gsterilmeyeceini belirtmektedir. rnek uygulamamzda basit olarak bu bool deikeni tutacak bir
CheckBox kontrol ele alyoruz. Metodumuzu ise aadaki gibi deitirmemiz yeterli olacaktr.

private void PrepareCommands()


{
SqlCommandBuilder cmb = new SqlCommandBuilder(daPersonel);
ConflictOption selectedOption = (ConflictOption)Enum.Parse(typeof(ConflictOption),
cmbConflictOptions.SelectedItem.ToString());
cmb.ConflictOption = selectedOption;
cmb.SetAllValues = false;
bool useParameterNames = chkUseParameter.Checked;

daPersonel.InsertCommand = cmb.GetInsertCommand(useParameterNames);
daPersonel.UpdateCommand = cmb.GetUpdateCommand(useParameterNames);
daPersonel.DeleteCommand = cmb.GetDeleteCommand(useParameterNames);
// dier kod satrlar
}

imdi uygulamamz yeniden altrp farkl akma tipleri iin oluan sorgulara bakarsak aadaki
sonular elde ederiz.

CompareAllSearchableValues iin;

CompareRowVersion iin;

www.bsenyurt.com Page 1393


OverwriteChanges iin;

Grdnz gibi parametre adlar artk kolon adlarndan oluturulmaktadr.

SqlCommandBuilder nesnesi Framework 2.0 daki ek fonksiyonellikleri ve zellikleri sayesinde artk


daha kullanl hale gelmitir. Dier CommandBuilder nesneleride benzer ilevsellikleri salamakla
birlikte, kullanlan veritaban sisteminin sahip olduu imkanlarda nemlidir. rnein
OleDbCommandBuilder snfnnda DeriveParameters metodu vardr ve bir OleDb kaynaklarndan sp
destei olmayan veritabanlarna balanabilmemiz de mmkndr. Sp destei olmad iin byle
bir durumda OleDbCommandBuilder' n DeriveParameters fonksiyonu bir ie yaramayacaktr. Dier
yandan zellikle balantsz katman nesneleri ile alrken eitli akma kritlerlerine gre
otomatik olarak sorgularn oluturulabilmesi nemli bir zellik olarak karmza kmaktadr.
Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek kod iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

C# Temelleri : Enum Sabitinin Bilinmeyen


Ynleri ( 30.10.2006 ) - C#
Deerli Okurlarm Merhabalar,

Enum sabitleri gelitirici dostu tipler olarak dnlebilir. ou zaman uygulamalarmz ierisinde
yer alan algoritmalarn baz durumlara gre farkl ekillerde hareket etmesi beklenir. Bu hareket

www.bsenyurt.com Page 1394


serbestliini salamann kolay yollarndan birisi, koullarn doru ekilde tespitinden sonra, uygun
bir biimde ele alnabilmesidir. Bu amala saysal deerler ile yaplan karlatrmalar son derece
yerinde olmaktadr. Ancak algortima ileyiini deitirmek iin saylar ele almak, eer bu
algoritmalar pek ok yerde kullanlacaksa eitli zorluklara neden olabilir. En azndan hangi saynn
ne anlama geldiini yada o say iin koulun nasl deitirilmesi gerektiini hatrlamak zor olabilir.
Neyseki enum sabitleri sayesinde, bu tip saylarn anlaml ekilde isimlendirilerek kullanlabilmesi
salanmtr.

Framework kendi ierisinde kulland pek ok yapda aktif olarak enum sabitlerine bavurmaktadr.
rnek olarak, DataReader' lar iin kullanlan CommandBehavior, DataTable ierisindeki satrlarn
durumuna ilikin bilgiler iin kullanlan DataRowState ve benzerleri gibi daha pek ok enum tipini
sayabiliriz. Built-in tipler dnda kendimizde enum sabitleri gelitirebiliriz ki buda iin en gzel
taraflarndan birisidir. Ne varki enum sabitlerini gelitirmek, sadece saylara anlaml isimler vermek
kadar sade bir konu deildir. te bu makalemizde enum konusunun derinlerine inmeye
alacaz. Temel olarak ele alacamz konular aadaki balklar altnda ilemeye alacaz.

Bir enum sabitine ait ieriin alma zamannda dinamik olarak elde edilmesi.
String bir verinin, bir enum sabiti ieriindeki karlnn elde edilmesi.
Enum sabitlerinin ieriinin ToString metodu ile farkl biimlerde elde edilmesi
Veyalanm (Ored) ieriklerin kullanm.
IsDefined metodu her zaman yeterli olmayabilir.

1. Bir enum sabitine ait ieriin alma zamannda dinamik olarak elde edilmesi.

Baz durumlarda enum sabitlerinin tm ieriinin alma zamannda bilinmesi ve kullancya


gsterilmesi gerekebilir. Sz gelimi, gelitirdiimiz bir grafik uygulama olduunu dnelim. Tual
zerine izilen resimlerin herhangibir ekilde saklandn ve zaman ierisinde her hangibir noktada
aldklarnda, son kaydedildikleri halleriyle kullancya sunulmak istendiklerini dnelim. izilen
ekiller ve bunlara ilikin lokasyon, derinlik, ller vb bilgileri saklamak iin seriletirme gibi
tekniklerden tutunda veritabanna kayt etme yada zel formatlar ile fiziki dosyalara aktarma gibi
pek ok yol tercih edilebilir. Lakin bu tip bir uygulamada ekranda olupta hatrlanmas gereken
ekilleri nerede saklarsak saklayalm nasl bir veri tipi ile saklayacamz nem kazanabilir.
izilebilecek olan ekilleri string olarak adlar ile tutmaktansa bunlara karlk gelen saysal
deerlerden faydalanmak ou zaman saklanacak ieriin boyutunu azaltabilir ve buda verinin
daha az yer tutmasn salayabilir.

izilebilecek ekil tiplerinin saysal olan karlklarnn sadece saklama amacyla ele alnmas
gzeldir. Peki gelitirici yada son kullanc bu saylar nasl anlayabilir? Enum sabitleri bu noktada
iimize yarayabilecek bir tiptir. Peki bu ekil tiplerinin kullanc tarafndan etkin bir ekilde
kullanlabilmesi iin ne yapabiliriz? te bu noktada System.Enumsnfnn
static GetNames metodu devreye girmektedir. GetNames metodu bir enum sabiti ierisindeki tm
deerlerin string formatndan bir dizi ile elde edilebilmesini salamaktadr. Aadaki windows
uygulamasnda eitli ekilleri bnyesinde barndran bir enum sabitinin ieriinin alma
zamannda farkl ekillerde elde edilii gsterilmeye allmaktadr. (Benzer istekler bir Web
uygulamasnda hatta bir web uygulamasnda da gz nne alnabilir.)

www.bsenyurt.com Page 1395


Uygulamada Sekil isimli kullanc tanml bir enum sabiti kullanlmaktadr. rnek olmas asndan
enum sabiti ierisindeki deerler ComboBox, ListBox kontrollerine birer e olarak eklenmi ayrca
her bir deer iin birer RadioButton kontrol dinamik olarak oluturulmutur. Enum sabiti ierii ve
uygulama kodumuz aadaki gibidir.

Sekil Enum sabitimiz ve ierii;

public enum Sekil


{
Kare, Dortgen, Daire, Elips, Cizgi, ParalelKenar, Altigen, Ucgen
}

Uygulama kodlarmz;

/* parametre olarak verilen Sekil enum tipi ierisindeki tm deerlerin adlar string dizisine alnr.*/
string[] sekilTipleri = Enum.GetNames(typeof(Sekil));
foreach (string sekilTipi in sekilTipleri)
{
// ComboBox kontrolne eklenir.
cmbSekiller.Items.Add(sekilTipi);
// ListBox kontrolne eklenir.
lstSekiller.Items.Add(sekilTipi);

// RadioButton haline getirilip FlowLayoutPanel kontrolne eklenir.


RadioButton rdbSekilTipi = new RadioButton();
rdbSekilTipi.Name = sekilTipi;
rdbSekilTipi.Text = sekilTipi;

www.bsenyurt.com Page 1396


grpSekiller.Controls.Add(rdbSekilTipi);
}

Tekrar etmek gerekirse nemli olan nokta, GetNames metodu ve metodun dndrd string
dizinin kullanl eklidir. Dikkat ederseniz metoda parametre olarak Sekil isimli enum sabitimizin
tipi (type) verilmitir. Burada dikkat edilmesi gereken bir nokta daha vardr. Kullanc ComboBox,
ListBox veya RadioButton kontollerinden birini setiinde, seilen bu bilginin enum sabitimiz
ierisindeki hangi deere karlk geldiini tespit etmek. te bu konuyu ikinci maddemizde
irdeleyeceiz.

2. String bir verinin, bir enum sabiti ieriindeki karlnn elde edilmesi.

Belkide ilk akla gelen yntem bir switch case yada oklu if kullanm olacaktr. Sz gelimi yukardaki
windows uygulamamzda kullancnn ComboBox, ListBox kontrolleri ile RadioButton kontrolnde
seebilecei bilginin enum tipi ierisinde karlk geldii deeri bulmaya alalm. Bu amala pekala
aadaki gibi bir metod yazabiliriz.

private Sekil SecilenSekil(string sekilAdi)


{
Sekil skl=0;
switch (sekilAdi)
{
case "Kare":
skl = Sekil.Kare;
break;
case "Dortgen":
skl = Sekil.Dortgen;
break;
case "Daire":
skl = Sekil.Daire;
break;
case "Elips":
skl = Sekil.Elips;
break;
case "Cizgi":
skl = Sekil.Cizgi;
break;
case "ParalelKenar":
skl = Sekil.ParalelKenar;
break;
case "Altigen":
skl = Sekil.Altigen;
break;
case "Ucgen":
skl = Sekil.Ucgen;
break;
}
return skl;
}

Ancak Enum snfnn tam bu ama iin kullanlabilecek ok daha etkili bir yesi vardr. Bu kadar
uzun bir kod yazmaktansa zellikle deer trlerinin vazgeilmez yelerinden birisi
olan Parse metodunun, Enum snf ierisine dahil edilmi versiyonunu aadaki gibi kullanabiliriz.

www.bsenyurt.com Page 1397


private Sekil SecilenSekil(string sekilAdi)
{
return (Sekil)Enum.Parse(typeof(Sekil), sekilAdi, true);
}

Parse metodu sayesinde ikinci parametrede verilen string bilgi, ilk parametre ile belirlenen Enum
tipi ierisinde aranr. Son parametre byk kk harf duyarllnn olup olmayacan belirlemek
amacyla kullanlan boolean bir deer almaktadr. Biz rneimizde true deerini verdik. Eer false
deerini verseydik rnein PARALELKENAR gibi bir bilgi iin alma
zamannda ArgumentException istisnasn alacaktk. Bunun nedeni elbetteki harf duyarlln
kapatm olmamz ve ParalelKenar ile PARALELKENAR bilgilerinin bu kritere gre eit olmamasdr.

Parse metodu sayesinde kullancnn setii bilgilerin, ilgili enum sabiti ierisindeki karlklarn
bulabilir ve saysal deerlerini elde edebiliriz. Aslnda bir enum sabiti ierisinde yer alan deerlerin
farkl formatta karlklar vardr. rnein bu deerlerin sadece string karlklar deil saysal
karlklarda vardr. te bu karlklar elde etmek amacyla ToString metoduna bir takm
parametreler verilir ki buda makalemizin 3nc maddesinin konusudur.

3. Enum sabitlerinin ieriinin ToString metodu ile farkl biimlerde elde edilmesi

Bir enum sabiti ierisindeki deerleri ToString metodu yardmyla farkl formatlarda elde edebiliriz.
Bu amala aadaki tabloda yer alan deerler kullanlr.

Parametre
levi
Deeri

G veya g Enum sabiti ierisindeki ilgili deeri genel(General) formatta yazar.

D veya d Enum sabiti ierisindeki ilgili deerin saysal(Decimal) karln yazar.

Enum sabiti ierisindeki ilgili deerin Hexadecimal (16l say sistemindeki)


X veya x
karln yazar.

FlagsAttribute' unun kullanlp kullanlmamasna gre ilgili enum sabiti deerinin


F veya f
string karln yazar.

rnein , bir oyunda oyuncularn aldklar puan gerei oynayabilecekleri seviyleri Yetki isimli enum
sabiti ile ele aldmz dnelim.

public enum Yetki


{
Caylak = 1
,Uzman = 2
,Profesyonel = 4
,Tecrubeli = 6 // Bu deer sonradan bamza i aabilir.
}

Buna gre bu enum sabiti ierisindeki her hangibir deeri ToString metodunun farkl versiyonlar ile
ekrana yazdrmaya altmzda aadaki sonular alrz.

www.bsenyurt.com Page 1398


static void Main(string[] args)
{
Yetki ytk;
// Tek bir enum deeri iin ToString() alma ekilleri
ytk = Yetki.Caylak;
EnumInfo(ytk);
}

private static void EnumInfo(Yetki ytk)


{
Console.WriteLine("------------------------------------");
Console.WriteLine("Varsaylan : " + ytk.ToString());
Console.WriteLine("General : " + ytk.ToString("G"));
Console.WriteLine("Flags : " + ytk.ToString("F"));
Console.WriteLine("Decimal : " + ytk.ToString("D"));
Console.WriteLine("Hexadecimal : " + ytk.ToString("X"));
}

4. Veyalanm ieriklerin kullanm

Baz durumlarda enum sabitleri ierisindeki deerlerin | iareti ile veyalandn grrz. rnein
CommandBehavior enum sabitini kullanrken SingleRow|CloseConnection ifadesi ile veya benzerleri
ile ok sk karlarz(kullanrz). Ayn durum kendi yazm olduumuz enum sabitleri iinde
geerlidir. Yetki enum sabitimizi gz nne alrsak eer, aadaki gibi bir kullanm sz konusu
olabilir. Dikkat ederseniz bit seviyesinde veya(OR) ilemi uygulanmaktadr.

Yetki ytk = Yetki.Profesyonel | Yetki.Uzman;

Burada ilgin olan bir durum vardr. O da Profesyonel ve Uzman deerlerinin saysal toplamlarnn 6
olmasdr. 6 deeri dikkat ederseniz Yetki enum sabiti ierisinde yer alan Tecrubeli' nin saysal
deerinede karlk gelmektedir. Bu nedenlede EnumInfo metoduna bu tip bir parametre
gnderildiinde aadaki ekran ktsnn elde edilmesi son derece doaldr. Ancak bu tip bir
kullanm tercih edilmemelidir. Yani veyalanm enum sabiti deerlerinin, baka bir enum sabitine
denk gelmesi istenen bir durum deildir.

Yetki isimli enum sabiti ierisinde yer alan saysal deerlere bakldnda, veyalanm olarak
mmkn olabilecek pek ok kombinasyon olaca kesindir. rnein aadaki tabloda olas bir ka
kombinasyon verilmektedir.

Caylak | Uzman 3

www.bsenyurt.com Page 1399


Caylak | Profesyonel 5

Caylak | Tecrubeli 7

Uzman | Profesyonel 6

Uzman | Tecrubeli 8

Caylak | Uzman | Profesyonel 7

Caylak | Uzman | Tecrubeli 9

Caylak | Uzman | Profesyonel | Tecrubeli 13

Ancak burada dikkat edilmesi gereken nemli bir husus vardr. Bunun iin, Enum sabiti ierisindeki
kombinasyonlarn program tarafndaki sonularna bakmamz gerekmektedir. rnein 3 ve 5
deerlerini veren kombinasyonlara bakalm.

EnumInfo(Yetki.Profesyonel | Yetki.Uzman);
EnumInfo(Yetki.Caylak | Yetki.Profesyonel);

Dikkat ederseniz ToString metodunun varsaylan ile G parametresi kullanlan versiyonlar saysal
deerlerin toplamn geriye dndrmtr. Sadece F parametresi kullanarak elde ettiimiz
sonularda ilgili deerlerin string karlklar, aralarna virgl konularak elde edilebilmitir. Eer
ToString() ve ToString("G") versiyonlarnnda benzer ekilde davranmasn istersek enum sabitimiz
zerinde Flags niteliini (attribute) uygulamamz gerekecektir.

[Flags]
public enum Yetki
{
Caylak = 1
,Uzman = 2
,Profesyonel = 4
,Tecrubeli = 6
}

Bu durumda ayn uygulamada aadaki sonular alrz.

www.bsenyurt.com Page 1400


Flags attribute' u ile ilgili bu ksa bilgi ardndan veyalanm enum sabitleri iin ele alacamz bir
dier kritik noktaya gelelim. zellikle enum sabiti ierisindeki eitli deerlerin birlikte veyalanarak
kombinasyonlar oluturulabildiini grdk. Peki bu kombinasyonlar gerektende doru saysal
deerleri mi retiyorlar? rnein bu maddenin banda Uzman | Profesyonel kombinasyonunun
Tecrubeli' nin saysal deerini rettiini grdk ve bunun istenmeyen bir durum olacan
vurguladk. Nitekim veyalanm ifadeler kullanlacaksa saysal deerlerin farkl veyalanm
kombinasyonlarda ok daha garip sonular retmesi muhtemeldir. Bu durumu analiz edebilmek iin
rnek uygulamamzda aadaki kod parasnda grlen kombinasyonlar deneyelim.

Console.WriteLine("\tCaylak");
EnumInfo(Yetki.Caylak);

Console.WriteLine("\tProfesyonel | Uzman");
EnumInfo(Yetki.Profesyonel | Yetki.Uzman);

Console.WriteLine("\tCaylak | Profesyonel");
EnumInfo(Yetki.Caylak | Yetki.Profesyonel);

Console.WriteLine("\tCaylak | Uzman");
EnumInfo(Yetki.Caylak | Yetki.Uzman);

Console.WriteLine("\tProfesyonel | Tecrubeli");
EnumInfo(Yetki.Profesyonel | Yetki.Tecrubeli);

Console.WriteLine("\tYetki.Caylak | Yetki.Uzman | Yetki.Tecrubeli");


EnumInfo(Yetki.Caylak | Yetki.Uzman | Yetki.Tecrubeli);

Console.WriteLine("\tYetki.Caylak | Yetki.Profesyonel | Yetki.Tecrubeli");


EnumInfo(Yetki.Caylak | Yetki.Profesyonel | Yetki.Tecrubeli);

Bu durumda ekran ktmz aadaki gibi olacaktr.

www.bsenyurt.com Page 1401


Grdnz gibi olduka ilgin sonular elde ettik. Pek ok kombinasyonda ne toplam saysal
deerleri ne de ToString ve ToString("G") metodlarnn sonular doru olarak gzkmemektedir. O
halde kombinasyonlarn doru sonular verebilmesini bir ekilde salamak gerekmektedir.
ounlukla bu durum iin enum sabiti ierisindeki herhangibir deikenin deerinin, kendisinden
nce gelen saysal deerlerin toplamndan en azndan bir fazla olmas tercih edilir. Dolaysyla enum
sabitimizi aadaki gibi deitirmek yerinde olacaktr.

[Flags]
public enum Yetki
{
Caylak = 1
,Uzman = 2
,Profesyonel = 4
,Tecrubeli = 8
}

Program tekrar altrdmzda aadaki ekran grntsnde yer alan sonular alrz.

www.bsenyurt.com Page 1402


Grdnz gibi bu sefer elde ettiimiz sonular ok daha tutarl ve dorudur. Kombinasyonlar
doru saysal karlklar retmi ve Flags attribute' u sayesinde ToString() ve ToString("G")
metodlar geriye dzgn kombinasyonlar dndrmtr. O halde enum sabitlerimiz ierisindeki
deerlerin veyalanm hallerine ihtiyacmz olucaksa, Flags niteliini kullanmakta ve saysal
deerleri bir ncekilerin toplamnn en az bir fazlas olacak ekilde belirlemekte fayda vardr.

5. IsDefined metodu her zaman yeterli olmayabilir.

IsDefined, her hangibir enum deikeninin ilgili enum sabiti ierisinde var olup olmadna dair bool
deer dndren bir zelliktir. Baz durumlarda parametrik bir bilginin, herhangibir enum sabiti
ierisinde var olup olmadn tespit etmek isteyebiliriz. Bu amala kendi switch..case yada if..else
yaplarmz kurabileceimiz gibi Enum snfna ait static IsDefinedmetodundan da faydalanabiliriz.
Ancak IsDefined metodu her zaman iin yeterli olmayacaktr. Neden yeterli olmayacan daha iyi
anlayabilmek iin bir rnek zerinden devam edelim. Parca isimli bir enum sabitimiz olduunu gz
nne alalm.

public enum Parca

www.bsenyurt.com Page 1403


{
Islemci=1
,Harddisk=2
,Ram=4
,EkranKarti=8
,SesKarti=16
}

Deneme olmas asndanda console uygulamas ierisinde aadaki kodlar ele alalm.

Console.WriteLine("Islemci var m ? "+Enum.IsDefined(typeof(Parca),"Islemci"));


Console.WriteLine("ISLEMCI var m ? " + Enum.IsDefined(typeof(Parca), "ISLEMCI"));
Console.WriteLine("SESKarti var m ? " + Enum.IsDefined(typeof(Parca), "SESKarti"));
Console.WriteLine("Parca.SesKarti var m ? " + Enum.IsDefined(typeof(Parca),
Parca.SesKarti));
Console.WriteLine("Parca.SesKarti|Parca.Ram|Parca.Islemci var m ? "
+ Enum.IsDefined(typeof(Parca),Parca.SesKarti| Parca.Ram| Parca.Islemci));
Console.WriteLine("1 var m ? " + Enum.IsDefined(typeof(Parca), 1));
Console.WriteLine("1|2 var m ? " + Enum.IsDefined(typeof(Parca), 3));

IsDefined metodu ilk parametre olarak kontrol ileminin yaplaca Enum sabitinin tipini almaktadr.
Bu amala typeof parametresi kullanlmtr. Ikinci parametre ise object tipinden olup aranan bilgiyi
temsil etmektedir. Uygulamay altrdmzda aadakine benzer bir ekran grnts elde
ederiz. imdi bu durumu analiz etmeye alalm.

Kod satrlarmzn ilkinde Islemci isimli string bilgiyi kontrol ediyoruz. Islemci deeri, enum
sabitimiz ierisinde gerektende vardr. Dolaysyla IsDefined metodu true deer dndrmtr.
Lakin burada case sensitive bir durum sz konusudur. Bu nedenle ISLEMCI ve SESKarti isimli
bilgiler iin IsDefined metodu false deerler dndrmektedir. 4nc olarak Parca.SesKarti bilgisi
IsDefined metodu ile kontrol edilmektedir. ok doaldrki Parca isimli enum sabitimiz ierisinde bu
deer zaten vardr. Bu nedenle true deeri dnmtr.

5nci kontrolde bir kombinasyon kullanlm ve SesKarti, Ram ve Islemci deerlerinin bir arada olup
olmamas durumu ele alnmtr. Her ne kadar bu deerler enum sabiti ierisinde yer alsada sonu
false deer dndrmtr. yleyse buna bir zm retilmesi gerekmektedir. zm zerinde
tartmadan nce 6nc ve 7nci arlarada gz atmakta fayda var. 6nc arda 1 saysal deerini
kontrol ediyoruz. Bu deerin karl Islemci olduu iin IsDefined metodu geriye true
dndrmektedir. Oysaki ayn durum 7nci kontrolde sz konusu deildir. Enum sabiti ierisinde
aka belirtilmi 3 saysal deerine sahip bir deiken olmamasna ramen Islemci ve HardDisk
deikenlerinin toplam 3' tr. Dolaysyla enum sabiti ierisinde 3' e karlk gelen bir kombinasyon
vardr ve fakat IsDefined metodu bunu analiz edememektedir. Bu tip durumlarda enum sabiti
ierisine aadaki gibi yeni bir deiken daha eklenir.

www.bsenyurt.com Page 1404


public enum Parca
{
Islemci=1
,Harddisk=2
,Ram=4
,EkranKarti=8
,SesKarti=16
,Hepsi=(Islemci|Harddisk|Ram|EkranKarti|SesKarti)
}

Ne yazkki bu deikenin eklenmesi IsDefined metodunun alma eklini etkilemez. Bu yzden


kendi kontrol metodunu yazmamz gerekmektedir. Bu amala aadakine benzer bir metod
gelitirilebilir.

static void Main(string[] args)


{
Console.WriteLine("Parca.SesKarti var m ? " + VarMi(Parca.SesKarti));
Console.WriteLine("Parca.SesKarti|Parca.Ram|Parca.Islemci var m ? " +VarMi(Parca.SesKarti |
Parca.Ram | Parca.Islemci));
}

static bool VarMi(Parca prc)


{
if((prc!=0)&&((Parca.Hepsi & prc)==prc))
return true;
else
return false;
}

Bu metod her ne kadar IsDefined metodunda olduu gibi object tipinden parametreler ile
almasada ierisinde yapt kontroller sayesinde eitli kombinasyonlara kar doru tepkiler
verebilecek ekilde tasarlanmtr. En nemli ksm VarMi metodu ierisindeki if kouludur. If koulu
ierisinde Parca.Hepsi ile metoda parametre olarak gelen Parca enum sabitinin ilgili deeri bit
seviyesinde and (ve) ilemine tabi tutulmaktadr. Bu ilemin sonucunun yine metoda gelen
parametre deerine eit olmas halinde true deeri dndrlmektedir. rnein Parca.SesKarti |
Parca.Ram | Parca.Islemci kombinasyonunu gz nne alalm. Burada bitsel seviyede veya ilemi
gereklemektedir ve sonuta retilen kt aadaki gibi olacaktr.

0001000
Parca.SesKarti 16
0

0000010
Parca.Ram 4
0

0000000
Parca.Islemci 1
1

Bit seviyesinde | islemi. (Veya)

0001010
Parca.SesKarti | Parca.Ram | Parca.Islemci 21
1

Metod ierisinde ise gelen bu deer Parca.Hepsi ile bitsel ve ilemine tabi tutulmaktadr.

Parca.SesKarti | Parca.Ram | Parca.Islemci 21 0001010

www.bsenyurt.com Page 1405


1

0001111
Parca.Hepsi 31
1

Bit seviyesinde & islemi. (Ve)

0001010
Parca.SesKarti | Parca.Ram | Parca.Islemci 21
1

Elde edilen sonuca bakldnda tekrar 21 deerini elde ettiimizi bir baka deyile metoda
parametre olarak gnderilen enum deerinin, Parca enum sabiti ierisinde yer alp almadn tespit
etmi oluyoruz. Her ne kadar kendi yazdmz VarMi metodu parametre olarak IsDefined' da
olduu gibi object tipiyle almyorsada istersek saysal deerlerede tepki verebilecek hale
getirebiliriz. Tek yapmamz gereken VarMi metodunu aadaki gibi ar yklemektir (overloading).

static bool VarMi(int prc)


{
if ((prc != 0) && (((int)Parca.Hepsi & prc) == prc))
return true;
else
return false;
}

Dikkat ederseniz bu sefer parametremiz integer tipindendir. Elbette kontrol ilemi srasnda
Parca.Hepsi enum deerinin saysal karln kullanmak zorundayz. Bu nedenle int cast
operatrn kullanyoruz. Sonular inceleyebilmek iin aadaki test kodlarn ele alabiliriz.

Console.WriteLine("Parca.SesKarti var m ? " + VarMi(1));


Console.WriteLine("Parca.SesKarti|Parca.Ram|Parca.Islemci var m ? " + VarMi(21));
Console.WriteLine("44 var m ? " + VarMi(44));

Uygulamamz bu haliyle altrdmzda aadaki sonular elde ederiz.

Dikkat ederseniz 44 deerinin enum sabiti ierisinde bir karl olmad iin metodumuz baarl
bir ekilde false deerini dndrmektedir. Dier taraftan Parca.SesKarti | Parca.Ram |
Parca.Islemci kombinasyonuda enum sabiti ierisinde yer ald iin metodumuz true deerini
geriye dndrmektedir.

Bu makalemizde enum sabitlerini biraz daha derinlemesine incelemeye altk. Var olan enum
sabitlerinin ieriinin alma zamanndan nasl elde edilebileceini, her hangibir string bilginin bir
enum sabiti ierisindeki karlnn Parse metodu ile nasl bulunabileceini grdk. Bunlarn
dnda, enum sabitlerinin ieriklerinin string olarak farkl formatlarda yazlmasn, Flag niteliinin
bu iteki yerine baktk. Son olarakta veyalanm (bitsel or ilemine tabi tutulmu enum
deerlerinin) ieriklerin kullanmn ve dikkat edilmesi gereken noktalar inceledik. Bylece geldik

www.bsenyurt.com Page 1406


bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek kod iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

C# 3.0 - lk Bakta XLINQ ( 22.10.2006 ) - C#


3.0
Deerli Okurlarm Merhabalar,

XLINQ (Xml Language Integrated Query) temel olarak LINQ modelinin Xml zerine
uyarlanabilmesini hedeflemektedir. Bildiiniz gibi LINQ projesi ile, IEnumerable<T> arayzn
uygulam .Net nesneleri zerinde dil ile tmletirilmi sorgulamalar gerekletirilebilmektedir.
Microsoft ayn sorgu yapsn, veritaban objelerinin programlama ortamnda nesnel olarak ifade
edilebildii varlklar(entities) zerinde kullanlabilmesini de DLINQ (Database Language Integrated
Query) ile salamaktadr. (DLINQ ile ilgili zet bilgileri bu makalemden bulabilirsiniz.) XLINQ ise,
yine dil tabanl sorgulama zelliklerini alp bunlarn XML verileri zerinden gerketirilebilmesini
salmayay amalamaktadr. Xml verilerinde dil tabanl sorgular yaplabilmesinin dnda, var olan
dkman nesne modeline (Document Object Model -DOM), XPath ve Xslt kavramlarna ek olacak
ekilde yeni fonksiyonelliklerde gelmektedir. rnein bir Xml verisini bellek zerinde oluturmak
iin XDocument isimli yeni bir tipin yapc metodlarndan faydalanabiliriz. Dahada ileri gidersek,
XLINQ ' yu DLINQ ile tmleik olacak ekilde kullanabiliriz. Bunun anlam, veritaban objelerinin
nesnel olarak ifade edildii varlklar LINQ ile sorgulayp, Xml formatnda sonu kmelerini alma
zamannda (runtime) elde edebileceimizdir. DLINQ' da olduu gibi, XLINQ' da kendi ierisinde C#
3.0' n yeniliklerini barndrmakta ve kullanmaktadr.

XLINQ ile ilgili denemeleri LINQ Preview ekini kullanarak Vs.Net 2005 zerinden
deneyebilirsiniz.

XLINQ iin gerekli tipler, System.Xml.XLinq isim alan altnda yer almaktadr. Bir Xml dkman
ve ierisinde yer alabilecek elemanlar gz nne alndnda bunlarn karlklarnn ynetimli kod
(managed code) tarafnda X harfi ile balayan tiplerle ifade edildiini grebiliriz. rnein Xml
elementlerini XElement tipi, nitelikleri (Attribute) XAttribute tipi karlamaktadr.
System.Xml.XLinq isim alannda (namespace) bu iki tipin dnda aadaki tabloda bir ksm verilen
dier ynetimli tiplerde yer almaktadr.

Tip Ad Xml Karl

Bir Xml dkman iermekle sorumludur. XDocument sayesinde sfrdan


XDocument Xml ierikleri bellek zerinde oluturulabilir, kaydedilebilir yada var olan bir
Xml ierii bellee yklenebilir.

Xml dkmanlarnda yer alan element' lerin ynetimli kod tarafndaki


XElement
karldr.

Xml dkmanlarnda yer alan niteliklerin (attribute) ynetimli kod


XAttribute
tarafndaki karldr.

www.bsenyurt.com Page 1407


Xml dkmanlarnda kullandmz yorum satrlarn ynetim kod tarafnda
XComment
kullanmamz salar.

Xml dkman ierisinde, node (boum) olarak ifade edilebilecek her


XNode
trden eleman ynetimli kod tarafnda ele alabilmek amacyla kullanlr.

Xml dkmanlarnn banda yer alan processing instruction' larn


managed tarafta ele alnabilmesini salar. Bu i iin XDecleration
XProcessingInstruction snfndanda yararlanlmaktadr. rnein Xml dkmanlar bana standard
olarak gelen versiyon numaras , encoding gibi bilgileri bu XDecleration
yardmyla kod tarafnda tanmlayabiliriz.

ounlukla CData (Character Data) blmlerinin yada birletirimi


XText
metinlerin ynetimli kod tarafnda ele alnabilmesi iin kullanlr.

Xml ierisinde yer alan isim alanlarnn ynetimli kod tarafnda ele
XNamespace
alnabilmesini salar.

XDocument ve XElement snflarnn tretildikleri abstract snftr. zellikle


XContainer Xml dkman zerinde sorgulamalar yapabilmek iin gerekli
fonksiyonelikleride salar.

DTD (Document Type Definitions) yapsnn ynetimli kod tarafndaki


XDocumentType
karldr.

LINQ iin gelitirilmi, geniletimi metodlar (extension


methods) barndran static snftr. Extension Methods kavram C# 3.0 ile
XElementSequence
birlikte gelmitir ve var olan framework tiplerine ek metodlar
yazlabilmesini salamaktadr.

Dilerseniz XLINQ ile gelitiricilerin hayatna girecek bir ka yenilii rnekler ile uygulayarak
makalemize devam edelim. lk olarak bir Xml verisinin bellek zerinde oluturulmas
srasndaXDocument tipinden nasl yararlanabileceimizi greceiz. Bu amala yeni bir LINQ
Console Application projesi oluturalm ve aadaki kod satrlarn yazalm.

using System;
using System.Collections.Generic;
using System.Text;
using System.Query;
using System.Xml.XLinq;
using System.Data.DLinq;

namespace UsingXLINQ
{
class Program
{
static void Main(string[] args)
{
#region Basit XLINQ Kullanm

XDocument xmlBook = new XDocument(


new XDeclaration("1.0", "utf-8", "yes")
, new XElement("Books"
, new XElement("Book",
new XAttribute("ID", 1000)
, new XElement("Name", new XText("Her Ynyle C#"))
, new XElement("ListPrice", new XText("50"))
)

www.bsenyurt.com Page 1408


, new XElement("Book",
new XAttribute("ID", 1001)
, new XElement("Name", new XText("C# CookBook"))
, new XElement("ListPrice", new XText("45"))
)
)
);

xmlBook.Save("BookWithXLinq.xml");

XElement element = XElement.Load("BookWithXLinq.xml");


Console.WriteLine(element.ToString());

#endregion
}
}
}

lk dikkatimizi eken sanyorumki XDocument nesnesinin oluturulu ekli olsa gerek. XDocument
nesnesine ait yapc metod bir Xml verisinin sfrdan oluturulabilmesini salayacak ekilde
tasarlanmtr. Dolaysyla yapc metodumuz ierisinde Xml verimiz iin gerekli elemanlar teker
teker oluturabiliriz. rneimizdeki XDocument nesne rneinin yapc metodu (constructor)
ierisinde ilk olarak her Xml ieriinin sahip olmas gereken processing instruction ksmn
oluturuyoruz. Bunu gerekletirmek iin XDeclaration snfn kullanmaktayz.

Her Xml verisinin bir root elementi olmas gerektiinden XElement snf ile ilk olarak Books isimli
boumu tanmlyoruz. Burada dikkat etmemiz gereken bir nokta var. XElement snfna ait yapc
metod (constructor) ierisinden yeni XElement yada XAttribute nesne rneklerini oluturabiliyoruz.
Dolaysyla hiyerarik olarak bir Xml veri aacn yapc metod ierisinde tek seferde
oluturabilmekteyiz. nk her elementin ierecei dier elementleri yapclar ierisinde
tanmlyoruz.

Oluturulan bu Xml ierii bellek zerinde yer alacaktr. Ancak dilersek bu ierii fiziki bir
kaynaada kaydedebiliriz. Bu amalada XDocument snfnn Save metodu kullanlr. Tam tersine,
fiziki bir Xml dosyasndan bir XElement tipi ierisine ykleme ilemide gerekletirebiliri.
rneimizde ierii bir XElement tipine yklemek amacyla yine XElement tipinin
static Load metodunu kullanyoruz. Aslnda bir xml ieriini fiziki bir dosyadan okumak veya
yazmak gibi ilemler zaten .Net ierisindeki bilinen Xml tiplerininde yapabilecei
fonksiyonelliklerdir. Ancak bir Xml ieriini yapc metod yardmyla tek seferde oluturabilme
yetenei XLINQ' nun vadettii yeniliklerden birisidir. Sonu itibariyle uygulamamz altrdmzda
aadaki ekran grntsn elde ederiz.

Bununla birlikte BookWithXLinq.xml isimli dosyannda aadaki gibi oluturulduunu grebiliriz.

www.bsenyurt.com Page 1409


Bellek zerinde XDocument ile oluturulan yada bir XElement tipi ierisine yklenen Xml verilerine
sonradan eleman eklemek var olan elemanlar deitirmek hatta silmek gibi ilemleride
gerekletirebiliriz. rnein aadaki kod parasnda bellee aldmz Xml ieriine yeni bir Book
eleman, alt elamanlar ile nitelii eklenmektedir.

XElement newBook = new XElement("Book",


new XAttribute("ID", 1005)
, new XElement("Name", new XText("Developing XLINQ"))
, new XElement("ListPrice", new XText("80"))
);
xmlBook.Element("Books").Add(newBook);

Console.WriteLine(xmlBook.ToString());

Books Xml ieriine yeni bir kitap eklemek iin XElement tipinden ve yapc metodundan
faydalanmaktayz. Dikkat ederseniz Book boumunu olutururken ierisine ID attribute' unu, Name
ve ListPrice elemanlar ile bunlarn ieriklerini eklemekteyiz. Text tabanl ieriin eklenebilmesi
iinde XText tipinden yararlanyoruz. Bu tarz bir kullanm grsel arabirime sahip windows veya
web tabanl uygulamalarda hatta mobil uygulamalarda olduka ie yarayacaktr. yleki Xml
verisinin deerleri kullanc tarafndan ele alnan bileenlerden seilerek elde edilebilir.

XElement tipi ile oluturulan Xml elemann var olan XDocument nesnesinin iaret ettii Xml
ieriine eklemek iin ise nce Books elemanna gidilmektedir. Bu amala Element metodu
kullanlm ve parametre olarak gidilecek elemann ad verilmitir ki buda root' tur. Element metodu
geriye bir XElement dndrmektedir. Yani alma zamannda Books root elemann iaret
etmektedir. Bunun arkasndan gelen Add metodu yardmyla, bir st satrda oluturulan yeni Book
eleman root elamnn ieriine dahil edilmektedir. Program bu haliyle altrdmzda aadaki
sonucu elde ederiz. Grdnz gibi yeni oluturduumuz eleman var olan Xml ieriinin sonuna
eklenmitir.

www.bsenyurt.com Page 1410


Gelelim dil tabanl sorgulama zelliklerinin XLINQ ierisindeki yerine. LINQ getirdii imkanlar
sayesinde veriler zerinde sorgulamalar yapmamz kolaylatracak yenilikler getirmektedir. Buna
gre zellikle Sql' den aina olduumuz select, where, orderby, from, sum gibi pek ok kavram,
IEnumerable<T> dan tremi .Net tiplerinin sunduu veriler zerinde, veritaban kaynaklarnn
nesnel karlklarnn sunulduu varlklar (entities) zerinde kullanabilmemiz mmkndr. Bu
yenilikler kendisini Xml verilerinin sorgulanmasnda da gstermektedir. rnein, aadaki gibi
rnek bir Xml ieriimiz olduunu dnelim.

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


<Personelimiz>
<Personel ID="1">
<SicilNo>190002</SicilNo>
<Ad>Burak Selim</Ad>
<Soyad>enyurt</Soyad>
<Maas>1000</Maas>
</Personel>
<Personel ID="2">
<SicilNo>1903402</SicilNo>
<Ad>Elma</Ad>
<Soyad>Soz</Soyad>
<Maas>5000</Maas>
</Personel>
<Personel ID="3">
<SicilNo>1401202</SicilNo>
<Ad>Kevn</Ad>
<Soyad>Dankin</Soyad>
<Maas>4500</Maas>
</Personel>
<Personel ID="4">
<SicilNo>230002</SicilNo>
<Ad>Carim Abdul</Ad>
<Soyad>Cabbar</Soyad>
<Maas>500</Maas>
</Personel>
<Personel ID="5">
<SicilNo>121302</SicilNo>
<Ad>Mayk</Ad>
<Soyad>Cordn</Soyad>
<Maas>2000</Maas>
</Personel>
</Personelimiz>

www.bsenyurt.com Page 1411


Personel.xml isimli dosyada tutulan bu ierikte bir Personelin ID, Sicil Numaras, Ad, Soyad, Maas
bilgileri tutulmaktadr. Bu Xml ieriini bellee alan bir uygulamada ok doal olarak baz
sorgulamalar yapmak isteyebiliriz. rnein maa belirli bir deerin zerinde olanlar bu Xml
dkman ierisinden ekmek istediimizi dnelim. Aadaki kod paras bu ilemin nasl
gerekletirilebileceini gstermektedir.

Console.WriteLine("Maa deeri ");


double maas=Convert.ToDouble(Console.ReadLine());

XDocument docPersonel=XDocument.Load("..\\..\\Personel.xml");

XElement elements=new XElement("PersonelListe",


from pers in docPersonel.Elements("Personelimiz").Elements("Personel")
where (double)pers.Element("Maas")>=maas select pers
);

Console.WriteLine(elements.ToString());

Kod ierisinde LINQ ifadesinin nasl kullanldna dikkat edelim. Uygulamamz kullancndan maa
bilgisini aldktan sonra ilk olarak Personel.xml isimli dosya ieriini bellee birXDocument nesnesi
yardmyla alyor. Sonrasnda ise docPersonel nesnesi zerinden bir LINQ sorgusu gerekletiriliyor
ve sonular bir XElement nesne rneinde tutulacak ekilde alnyor. Uygulama altrldnda ve
maa deeri olarak 2000 deeri girildiinde aadaki ekran grnts ile karlarz.

LINQ sorgusu, XElement tipine ait nesne rnei oluturulurken ikinci parametre ierisinde
kullanlmtr. Sql kullanclar iin from, where ve select gibi anahtar kelimelerinin yeri biraz tuhaf
gelebilir. Aslnda yukardaki ilemi Sql dilinde dndmzde, "Select * From Personel Where
Maas>=2000" gibi bir ifadeyi gz nne alabiliriz. LINQ da ise durum biraz daha farkl olmakla
birlikte olduka anlalr sorgular oluturulabilmektedir. Dolaysyla Xml verilerini LINQ' nun
salad btn imkanlar ile sorgulama ansna sahibiz. phesizki bu imkanlar, zellikle XPath ve
XQuery gibi sorgulama teknolojilerin zerine gelen olduka esnek ve gl bir yap olarak karmza
kmaktadr. in gzel yan burada ele aldmz LINQ sorgularnn anahtar kelimelerinin ve
kullanm standardlarnn , LINQ, XLINQ, DLINQ iin ayn olmasdr.

www.bsenyurt.com Page 1412


imdi XLINQ' nun DLINQ ile olan yakn ilikisine bir gz atalm. Bildiiniz gibi DLINQ mimarisinde,
veritaban nesnelerini uygulama tarafnda temsil ettiimiz objeler zerinde LINQ sorgular
altrabilmekteyiz. Yani bir veritaban tablosunu uygulama ortamnda nesnel olarak ifade eden bir
veri zerinde dil tabanl sorgular altrabilmekteyiz. XLINQ ilede, DLINQ nun sunduu varlklar
(entity) zerinde yapacamz LINQ sorgular sonucu elde edilen sonu kmelerini alma
zamannda Xml ierii haline getirebilme ansna sahibiz. Yani DLINQ ve XLINQ zelliklerini bir
arada ele alabiliriz. Bu konuyu daha net anlayabilmek iin Northwind veritabannn entity
karlklarn ele alacamz bir rnek ile devam edeceiz. LINQ Preview ile birlikte, DLINQ ierisinde
kullanlan varlklar(entities) yazmak yerine kolayca hazrlayabileceimiz bir ara (tool)
gelmektedir. SqlMetal isimli bu arac aadaki gibi komut satrndan altrabiliriz.

D:\Program Files\LINQ
Preview\Bin>sqlmetal /server:localhost /database:Northwind /code:NorthwindBase.cs

Bu durumda NorthwindBase.cs isimli bir snf oluturulacak ve bizim iin gerekli tm snflar bu
kaynak kod ierisine dahil edilecektir. SqlMetal arac yardmyla oluturulan bu snfn
ieriine Class Diagram yardmyla baktmzda aadaki ekran grntsne benzer bir ierik ile
karlarz.

Hatrlayacanz gibi DLINQ konusunu incelediimiz makalemizde yukardakine benzer bir yapy
kendimiz yazarak gelitirmeye almtk. SqlMetal arac yardmyla oluturulan NorthwindBase.cs
dosyasn uygulamamza ekledikten sonra aadaki kodlar yazalm.

www.bsenyurt.com Page 1413


Console.WriteLine("rn Fiyat ");
decimal fiyat=Convert.ToDecimal(Console.ReadLine());

Northwind nrth = new Northwind("data source=localhost;database=Northwind;integrated


security=SSPI");

XElement urunler =new XElement("Urunler",


from urn in nrth.Products where urn.UnitPrice> fiyat orderby urn.ProductName
select
new XElement("Urun",
new XAttribute("ID",urn.ProductID),
new XAttribute("Ad", urn.ProductName),
new XAttribute("BirimFiyat", urn.UnitPrice)
)
);

urunler.Save("Urunler.xml");
Console.WriteLine(urunler.ToString());

Uygulamamzda kullancndan bir fiyat bilgisi alyoruz. Sonrasnda ise Northwind snfmz balant
iin gerekli bilgi ile oluturuyoruz. Bu ilemin arkasnda Urunler isimli bir root eleman ierecek bir
XElement nesnesi rnekliyoruz ve ikinci parametre ierisinde yine dil tabanl bir sorgus cmlecii
kullanyoruz. Bu sefer Products tablosundan gelen (ki bu tablo Northwind snf ierisinde Products
isimli bir snfa karlk geliyor) verilerden, UnitPrice alan belli bir deerin zerinde olan satrlar
ProductName alanna gre sralayp ekiyoruz. ekilen verileri Urun isimli
bir XElement ierisinde XAttribute snf yardmyla nitelik olarak oluturuyoruz. Sonrasnda ise
deneme olmas amacyla elde edilen XElement' i fiziki bir dosyaya kaydediyor ve uygulama
ekranna basyoruz. Buna gre uygulama altnda aadaki ekran grntlerini elde ederiz.

retilen Xml dosyas ierii ise aadaki gibi olacaktr. Dikkat ederseniz, XElement snf ile
tanmladmz nesne rneinin sunduu Xml ieriinde ID, Ad, BirimFiyat isimli nitelikler

www.bsenyurt.com Page 1414


(attributes) deerlerini Products snfna ait ProductID, ProductName, UnitPrice zelliklerinden
alacak ekilde oluturulmu ve Urun isimli eleman (element) ierisinde toplanmlardr.

Grld gibi Xml dosyas ve ekran ktsnda UnitPrice alannn deeri 90 birimin zerinde olanlar
elde ettik. Burada nemli olan nokta, dil tabanl sorgulamay kullanarak, varlklar (entities)
zerinden bir sorgulama yapmamz ve sonular ekerken bunlar XElement, XAttribute gibi tipler
yardmyla bir Xml ieriine dntrmemizdir. Elde edilen bu Xml ierii platformlar arasnda
hareket edebilecek, fiziki kaynaklar zerine yazlabilecek, hatta uygulamalarn grsel bileenlerine
balanabilecek (rnein XmlDataSource yardmyla bir TreeView kontrolne yada bir GridView
kontrolne) hale getirilmektedir. XLINQ yukardaki rneklerde zerinde durmaya altmz
yenilikler dnda pek ok zellik daha iermektedir. Bunlar LINQ Preview yardmyla gelen
dkmantasyondan da bulabilirsiniz. zetle XLINQ, dil tabanl sorgular ve Xml ile ilgili yeni
fonksiyonellikleri biz gelitiricilerin kullanmna sunmay hedeflemektedir. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek kod iin tklayn.

www.bsenyurt.com Page 1415


Burak Selim ENYURT
selim@bsenyurt.com

C# Temelleri: 1!=1 Eitsizliinden GetHashCode'


a Uzun nce Bir Yol ( 11.10.2006 ) - C#
Deerli Okurlarm Merhabalar,

Eminimki makale bal size olduka ilgin gelmitir. Matematiksel olarak mmkn olmayan bu
durum .Net programlama ortamnda acaba gerekletirilebilir mi? Elbetteki matematiksel olarak
imkansz olan bu durumun programlama ortammz ierisinde gerekleebilir olmasda pek mantkl
deil. O halde makalemizin asl konusundan bahsedelim ve durumu akla kavuturalm. Bu
makalemizde .Net ierisinde yer alan veri tiplerinin(data types) nasl ve ne ekilde
karlatrlabileceklerini incelemeye alacaz. Bir baka deyile nesnelerin birbirleri arasndaki
eitliklerini mercek altna alacaz. .Net ierisinde nesnelerin ieriklerini karlatrmak adna pek
ok yntem bulunmaktadr. Bu anlamda makalemizin ekirdeini Object snfnn
static ReferneceEquals, Equals metodlar ile sanal(virtual- yani ezilebilir) Equals metodu
oluturmaktadr. Sonrasnda bu metodlara Object snfnn GetHashCode metodunun ezilmesini de
ekleyeceiz. Nitekim baz koullar bizi GetHashCode' a doru gtrecektir.

Bildiiniz gibi .Net ierisinde iki temel veri tr yer almaktadr. Bunlar Referans trleri (Reference
Types) ve Deer trleridir (Value Types). Referans ve Deer trlerinin bellek zerindeki farkl
tutulu ekilleri, bunlara ait nesne rneklerininde farkl ekillerde karlatrlabilecei sonucunu
dourmaktadr. Dolaysyla iki referans tipinin eitlii veya iki deer tipinin eitlii sz konusu
olduunda gz nne alnmas gereken modeller vardr. .Net ierisinde iki eit eitlik teorisi vardr.
Referans tabanl ve deer tabanl.

Referans tabanl eitlik modelinde, nesnelerin birbirlerine eit olmas iin, adreslerinin eit olmas
yeterlidir. Bu ounlukla nesne kimliinin (object identity) eit olmas olarakta belirtilir. Deer
tabanl eitlik modelinde ise nesnelerin sadece kimlikleri deil, ierikleride (contents) ele
alnmaktadr. .Net ierisinde yer alan tipler bu iki eitlik modelinden birisini tercih etmektedir.
rnein string snf referans tipi olmasna ramen deer tabanl eitlik modelini (value semantics
equality) tercih ederken, DataRowView snf referans tabanl eitlik modelini (reference semantics
equality) tercih etmektedir. Dolaysyla iki string deiken birbiriyle karlatrlrken sadece nesne
kimlikleri (object identity) deil, nesne ierikleride (contents) deerlendirilmektedir. DataRowView
snfna ait iki nesne rneinde ise sz konusu olan bu nesnelerin bellekte gsterdikleri adreslerin
eit olup olmaddr. Bu iki farkl eitlik modeli, kendi yazdmz tipler iinde bir takm n
hazrlklar gerektirebilir. rnein baz durumlarda yazdmz referans tipleri iin deer tabanl
eitlik modelini kullanmak isteyebiliriz. Yada bunun tam tersi bir durum sz konusu olabilir.

www.bsenyurt.com Page 1416


Yaygn Kurallar:

1 - ki referans tipi deiken ayn veriyi iaret ediyorlarsa eittirler.


2 - ki deer tr deiken ayn tipteyseler ve ierikleri ayn ise eittirler.

Bu yaygn kurallar elbetteki gelitirici tarafndan bozulabilir.

Object snfnn baz ye metodlar ile yukarda bahsettiimiz eitlik teorileri arasnda sk bir iliki
vardr. Object snf nesnelerin eit olup olmadklarn yukarda bahsedilen modellere gre kontrol
etmemizi salayan bir takm yeler ierir. Bu yelerden static olan ReferenceEquals ve Equals
metodlarnn davranlar deitirilemez. Ancak kendi tiplerimizin eitlik modellerini
deitirebilmemiz iin Object snf sanal (virtual) Equals metodunu iermektedir. imdi kod
yazarak eitlik modellerini biraz daha detaylandrmaya alalm. Aadaki rnek kod paras
makale balmz birazda aldatmaca ile gereklemektedir.

double deger_1 = 1;
double deger_2 = 1;
if (Object.ReferenceEquals(deger_1, deger_2))
Console.WriteLine("Eitler");
else
Console.WriteLine("Eit deiller");

Dikkat ederseniz deger_1 ve deger_2 double tipinden iki farkl deiken olmalarna ramen
ierikleri ayndr. Bu iin aka taraf olmakla birlikte byle bir sonu alnmas son derece doaldr.
Nitekim referans tabanl eitlik modelini kullanan ReferenceEquals metodunu kullanyoruz. Ancak
ayn kodu Equals metodu yardmyla altrrsak Eitler sonucunu alacamz kesindir ki buda
iimize su serpip 1==1 matematik sonucunu dorulamaktadr.

double deger_1 = 1;
double deger_2 = 1;
if (Object.Equals(deger_1, deger_2))
Console.WriteLine("Eitler");
else
Console.WriteLine("Eit deiller");

Equals metodunun bu sonucu vermesinin en byk nedeni ieride yapt karlatrma ilemleridir.
Equals metodu ilk olarak parametre olarak ald nesne rneklerinden herhangibirinin null olup
olmadna bakar. Byle bir durum varsa zaten eitlikten sz edilemez. (Tabiki her iki rnekte null
ieriine sahipse bu durumda nesne rneklerinin eit olduu kabul edilir.) Sonrasnda ise ==
operatr ile bu nesne rneklerinin kimliklerinin bir baka deyile bellekte iaret ettikleri veri

www.bsenyurt.com Page 1417


adreslerinin ayn olup olmadna bakar. Buda geerli deilse son olarak gelen nesne rneklerinden
ilkinin ezilmi olan Equals metodunu kullanarak ierik(content) kontrol yapar. erik ayn ise gelen
nesne rnekleri eittir.

Object snfnn static ReferenceEquals metodu ayn ierie sahip farkl deer tr
deikenleri iin her zaman false dndrecektir.

Bu teoriyi yukardaki double tipi ksmen karlamaktadr. Peki kendi deer trlerimiz sz konusu
olduunda da ReferenceEquals ayn davranm sergileyecektir? Hatta, Object snfnn static Equals
metodu nasl bir davran sergileyecektir? Aadaki kod parasnda bu durum irdelenmeye
allmaktadr.

public struct Personel


{
private double m_Maas;
private int m_TcNo;
private string m_Ad;

public Personel(int tcNo, string ad, double maas)


{
m_TcNo = tcNo;
m_Ad = ad;
m_Maas = maas;
}
}

class Program
{
static void Main(string[] args)
{
Personel prs1 = new Personel(1900, "Burak", 20);
Personel prs2 = new Personel(1900, "Burak", 20);

Console.Write("Reference Equals ile ");


if (Object.ReferenceEquals(prs1, prs2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");

Console.Write("Equals ile ");


if (Object.Equals(prs1, prs2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");
}
}

www.bsenyurt.com Page 1418


Grld gibi ReferenceEquals metodu kendi deer tiplerimiz iinde ayn davran
sergilemektedir. rneimizde gelitirdiimiz Personel yapsna ait nesne rnekleri ayn ierie sahip
olmalarna ramen bellek zerinde farkl adreslerde yer almaktadrlar ve bu nedenle nesne
kimlikleri ayn deildir. Dolaysyla ReferenceEquals metodunun tam olarak referans tabanl eitlik
modelini benimsediini ve ezilebilir bir versiyonu olmad iin bu davrannn deitirilemeyeceini
dnebiliriz. Tam tersine Equals metodu, ilgili yap deikenlerinin ieriklerini kyaslam ve ayn
olduklarna kanaat getirerek geriye true deer dndrmtr.

Peki referans trlerinde durum nedir? rnein ayn ierie sahip iki string' i yada kendi yazdmz
iki snfa ait nesne rneklerinden ayn ierie sahip olanlarn eitliklerini ReferenceEquals ile ve
Equals metodu ile test ettiimizde sonular ne olacaktr? Aadaki kod paralar bu durumu analiz
etmektedir. lk olarak kendi yazdmz Urun isimli bir snf iin ReferenceEquals ve Equals
davranlarna bakalm.

public class Urun


{
private int m_Id;
private string m_Ad;
private double m_Fiyat;

public Urun(int id, string ad, double fiyat)


{
m_Id = id;
m_Ad = ad;
m_Fiyat = fiyat;
}
}

class Program
{
static void Main(string[] args)
{
Urun urn1 = new Urun(1000, "Balata", 10);
Urun urn2 = new Urun(1000, "Balata", 10);

Console.Write("Reference Equals ile");


if (Object.ReferenceEquals(urn1, urn2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");

Console.Write("Equals ile ");


if (Object.Equals(urn1, urn2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");
}
}

www.bsenyurt.com Page 1419


Yukardaki kod parasnda kendi yazdmz Urun isimli referans tipine ait iki ayr rnek yer
almaktadr. Lakin bu iki rnein ierikleri ayndr. Ancak adresler farkl olduu iin ReferenceEquals
metodu karlatrmasnn sonucu false olarak dnmektedir ki byle olmas doaldr. Dier taraftan
Object snfnn static Equals metodu nesne ierikleri ayn olmasna ramen yine false cevabn
vermektedir. Oysaki Personel yapsn kullandmz rnekte sonu eit olduklar ynndedir. Byle
bir sonu almamzn en byk nedeni kendi yazdmz Urun snf iin Equals metodu yazmam
oluumuzdur. Bir baka deyile static Equals metodunun kendi ierisindeki son kontrol srasnda
yapt ii stlenecek ezilmi (override) bir Equals metodu, Urun snf ierisinde yer almamaktadr.
yleyse sonucun bu ekilde olmas son derece doaldr. Dolaysyla kendi snflarmz iin Object
snfnn sanal Equals metodunu ezmezsek, Object snfnn Static olan Equals metodu sz konusu
tip iin ierik kontrolde gerekletiremeyecektir. Bir baka deyile Object snfnn static Equals
metodu referans tipli eitlik modelini gereklemitir. Bunu test etmek iin makalemizin ilerleyen
ksmlarnda Urun snf ierisinde Equals metodunu ezeceiz.

Elbette gzden karlmamas gereken bir durum vardr. Urun snfna ait nesne rneklerinden urn1
ve urn2' yi birbirlerine atadktan sonra Equals ve ReferenceEquals metodlarn test edersek
aadaki ekran grntsndeki sonucu alrz.

Dikkat ederseniz her iki metodda true deerini dndrmektedir. Bu son derece doaldr nitekim
atama sonras referans tiplerinin ayn adresi iaret etmeleri salanmtr. Ayn adresler iaret
edildii iin, ieriklerde ayn kabul edilecektir. Buda metodlarn true deer dndrmesini
aklamaktadr. ( Atama sonras oluan durumu deer trleri iin dndmzde ise; Personel
yapmz kullandmz rnekte, prs1 nesne rneini prs2 nesne rneine atadmz takdirde
ReferenceEquals metodu false deer, Equals metodu ise true deer dndrecektir. )

Gelelim .Net ierisinde yer alan nceden tanml referans tiplerinden birisi olan string snfna.
Aadaki kod paras string snf iin geerli durumu analiz etmektedir.

string str1 = "Burak Selim enyurt";


string str2 = "Burak Selim enyurt";

Console.Write("Reference Equals ile");


if (Object.ReferenceEquals(str1, str2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");

Console.Write("Equals ile");
if (Object.Equals(str1, str2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");

www.bsenyurt.com Page 1420


Dikkat ederseniz string tipinden deikenler sz konusu olduunda ReferenceEquals metoduda,
Equals metoduda true deerini dndrmektedir. Hatta ilgin olan nokta str1 ve str2 deikenlerinin
birbirlerine atanmam dolaysyla referanslar eitlenmemi olmalarna ramen static
ReferenceEquals metodu true deeri dndrmtr. Oysaki bizim yazdmz Urun referans tipi iin
her ikiside false olarak dnmektedir. String deikenlerimiz iin Equals metodunun true deer
dndrmesinin en byk nedenlerinden birisi String snfnn kendi ierisinde Equals metodunu
yazm olmas ve kullanmasdr. Bu rneklerden u sonuca varabiliriz.

Kendi snflarmz yazdmz takdirde ieriklere gre eitlikleri kontrol etmek istiyorsak
(yani deer tabanl eitlik modelini uygulamak istiyorsak) Object snfnn sanal olan
Equals metodunu ezmemiz (override) gerekecektir.

Gelin, kendi yazdmz Urun snf ierisinde Equals metodunu ezelim ve Object snfnn static
Equals metodunun nasl bir davran sergileyeceine bakalm. Bu amala, Urun snfmz ierisinde
Equals metodunu aadaki gibi ezelim.

public override bool Equals(object obj)


{
Urun urn = (Urun)obj;
if ((urn.m_Id == this.m_Id) && (urn.m_Ad == this.m_Ad) && (urn.m_Fiyat == this.m_Fiyat))
return true;
else
return false;
}

Equals metodu dikkat ederseniz object tipinden bir parametre almaktadr. Bu parametreyi metod
ierisinde Urun tipine eviriyoruz. Snf ierisindeki alan deerleri ile gelen referansn deerlerini
karlatryoruz. Eet tm deerleri birbirlerine eitlerse geriye true deerini dndrerek
referanslarn eit olduuna karar veriyoruz. Ezmi olduumuz Equals metodu sonrasnda kodu
yeniden altrrsak artk Object snfnn Equals metodunun true deer dndrdn grrz.

Object snf ierisinde yer alan sanal(virtual) Equals metodunun ezilmesiyle artk Urun snfna ait
nesne rnei zerindende de Equals metodunu arabiliriz. .Net ierisinde yer alan pek ok tip
kendi ierisinde Object snfndan gelen Equals metodunu ezmi ve kendine gre dzenlemitir. Var
olan tm framework nesnelerinin Object snfndan tredii dnld takdirde, kendi tiplerimiz
zerinden yada var olan tipler zerinden Equals metodu arlabilir. rnein bir double tipi
zerinden Equals metodunu arlabileceimiz gibi kendi yazdmz bir snf zerinden de (eer
Equals metodunu ezdiysek) arabiliriz. Bu durumu analiz etmek iin console uygulamamzda
aadaki kod parasn deneyebiliriz.

if (urn1.Equals(urn2))
Console.WriteLine(" Eitler");
else
Console.WriteLine(" Eit deiller");

www.bsenyurt.com Page 1421


Urun snfmz ierisinde Equals metodunu override ettiimiz iin true deeri dnecektir ve ekrana
Eitler yazacaktr. Ancak Equals metodunu kendi snfmz ierisinde ezmemi olsaydk, metod
ars sonucu false deer dnecek ve ekrana eit deiller yazacakt. Tam bu nokta Equals
metodunu kendi tipimiz iin ezdiimizde derleme zamannda bir uyar aldmz grrrz. Uyarda,
snfmzn Object' ten gelen GetHashCode metodunu ezmesi(override) nerilmektedir.

Peki bu uyar niin verilmektedir? Neden Object snfnn GetHashCode metodunun ezilmediine dair
bir uyar alyoruz? Bunu anlayabilmek iin ncelikli olarak Object snfnn GetHashCode metodunun
grevinden bahsetmemiz gerekmektedir. GetHashCode metodu geriye hash algoritmasna gre
retilmi saysal bir deer dndrr. Bu saysal deer aslnda Hashtable ve Dictionary<> gibi
koleksiyonlarda nemli bir yere sahiptir.

Hashtable ve Dictionary<> gibi koleksiyonlar kendi ilerinde tuttuklar satrlar hash


deerlerine gre sralamaktadrlar. Hash algoritmasnn gc sayesinde bu koleksiyonlar
dierlerine gre daha hzl alabilmektedir.

Dilerseniz ilk olarak GetHashCode metodu tarafndan retilen hash deerlerini mercek altna
almaya alalm. Aadaki kod parasnda ierikleri ayn olan tipler iin hash deerleri
ekilmektedir.

string str1 = "Burak Selim enyurt";


string str2 = "Burak Selim enyurt";
Console.WriteLine("...String tipi iin Hashcode...\n");
Console.WriteLine("str1 iin Hash Deeri : {0} ",str1.GetHashCode().ToString());
Console.WriteLine("str2 iin Hash Deeri : {0} \n", str2.GetHashCode().ToString());

Urun urn1 = new Urun(1000, "Balata", 10);


Urun urn2 = new Urun(1000, "Balata", 10);
Console.WriteLine("...Urun Snf(Class) iin Hashcode...\n");

www.bsenyurt.com Page 1422


Console.WriteLine("urn1 iin Hash Deeri : {0} ", urn1.GetHashCode().ToString());
Console.WriteLine("urn2 iin Hash Deeri : {0} \n", urn2.GetHashCode().ToString());

Personel prs1 = new Personel(1900, "Burak", 20);


Personel prs2 = new Personel(1900, "Burak", 20);
Console.WriteLine("...Personel Yaps(Struct) iin Hashcode...\n");
Console.WriteLine("prs1 iin Hash Deeri : {0} ", prs1.GetHashCode().ToString());
Console.WriteLine("prs2 iin Hash Deeri : {0} \n", prs2.GetHashCode().ToString());

Kodu altrdmzda aadaki sonucu alrz.

Ekran grntsndende dikkat edeceiniz zere, string, ve Personel Yaps nesne rnekleri iin
retilen hash deerleri ayndr. lgin olan Urun snfna ait nesne rneklerinin ierikleri ayn
olmasna ramen retilen hash deerlerinin farkl oluudur. Oysaki iki nesne rnei eer deer tipi
modeline gre eit iseler ayn hash deerlerinden bahsediyor olmamz gerekmektedir.

ki nesnenin ierii deer tipi modeli gereince eitse, ayn hash deerlerinin retiliyor
olmas gerekmektedir. Buda zellikle deer tipinden eitlik modelini uygulayan tipler iin
GetHashCode metodunun ezilmesini gerektirir.

Nitekim String referans tr bu teoriyi dorulamaktadr. yleki string tipi kendi ieriinde deer
tipli eitlik modelini kullanmaktadr. Dolaysyla yukardaki rnekte yer alan str1 ve str2
deikenlerinin ayn hash kodlarn retmesi beklediimiz bir durumdur. imdilik, kendi yazm
olduumuz snflardaki bu durumu incelemeden nce yaplarda(structs) farkl ierikler olmas
halinde farkl hash deerleri alp alamayacamz kontrol etmemizde fayda var.

string str1 = "Burak Selim enyurt";


string str2 = "Burak S. enyurt";
// Dier kodlar

Personel prs1 = new Personel(1900, "Burak", 20);


Personel prs2 = new Personel(2000, "Burak", 20);
// Dier kodlar

www.bsenyurt.com Page 1423


Yukardaki kod parasn console uygulamamzda altrrsak aadaki ekran grntsnde yer
alan sonular elde ederiz.

Eminimki deiiklik dikkatinizi ekmitir. String deikenlerde yaplan deiiklik sonucu retilen
hash deerleri farkldr. Ancak yazm olduumuz Personel Yaps iin ierikte deiiklik (m_TcNo
alan deitirilmitir) yapm olsakta durum deimemitir. Hash deerleri ayn olarak retilmitir.
Oysaki normal artlarda bir Personelin TC Kimlik Numarasnn benzersiz olaca kesindir. Buna gre
hash algoritmasnn uygun ekilde davran gstermesi gerekmez mi? Aslnda bizi yanltan nokta
Personel yaps ierisinde yer alan alanlarn sralamasdr.

private double m_Maas;


private int m_TcNo;
private string m_Ad;

Dikkat ederseniz ilk alan m_Maas alandr. Oysaki rnek kodumuzda sadece m_TcNo alannn
deerini deitirdik. Peki dier alanlarn ayn kalmas artyla m_Maas alann deitirirsek ne olur?
rnein prs2 nesnesi iin bu deeri 21 yapalm, prs1 iin ise 20 olarak brakalm.

Personel prs1 = new Personel(1900, "Burak", 20);


Personel prs2 = new Personel(1900, "Burak", 21);

Grdnz gibi farkl bir hash deeri elde ettik. Buna gre zellikle kendi deer trlerimiz iin u
sonuca varabiliriz.

GetHashCode metodu kendi deer trlerimiz iin bir hash deeri retirken varsaylan
olarak sadece yap ierisindeki ilk alann deerini gz nne alr.

lk alann deil ama yap ierisindeki benzersiz alanlardan birisinin kesin olarak Hash retiminde
kullanlmasn salamak iin GetHashCode metodu ezilebilir. rneimizde Tc Kimlik Numarasnn
benzersiz olduu dnelecek olursa GetHashCode metodu ezilip ieride m_TcNo alan zerinden

www.bsenyurt.com Page 1424


bir Hash deeri rettirilebilir. Bu durumda yapmz ierisinde GetHashCode metodunu aadaki
ekilde ezme yoluna gidebiliriz.

public override int GetHashCode()


{
return m_TcNo.GetHashCode();
}

Uygulamay bu haliyle altracak olursak eer prs1 ve prs2 yap rnekleri iin geriye dnen hash
deerlerinin 1900 olacan grrz. Oysaki prs1 nesnesinin maa alanlarnn deerleri halen daha
farkldr. Yani bu iki nesne rnei u an iin eit deiller. Baka bir deyile ayn ierie sahip
deiller. Kurala greyse, iki nesne rnei ayn ierie sahip iseler ayn hash deerlerinin retilmesi
gerekmektedir. Bu nedenle daha etkili bir yol olmas asndan bu yap ierisindeki tm yelerin
string ieriklerini dndrecek bir ieriin zerinden Hash kod retimine gidebiliriz. Aadaki kod
parasnda bu ilem ele alnmaya allmtr.

public override string ToString()


{
return m_TcNo.ToString() + " " + m_Ad.ToString() + " " + m_Maas.ToString();
}
public override int GetHashCode()
{
return this.ToString().GetHashCode();
}

String metodu ierisinde yer alan kod ile, Personel yapsndaki tm alanlar iin ierisine katlm ve
bir GetHashCode deeri elde edilmitir.

imdi tekrar Urun snfmza dnelim. Hatrlayacanz gibi ayn ierie sahip olan urn1 ve urn2
nesneleri iin farkl hash deerleri retilmiti. Oysaki ayn hash deerlerinin retilmesi gerektiini
sylemitik. Buna gre, Personel yaps ierisinde kullandmz taktii Urun snfmz iinde ele
alabiliriz.

public override int GetHashCode()


{
return this.ToString().GetHashCode();
}
public override string ToString()
{
return m_Id.ToString() + " " + m_Ad + " " + m_Fiyat.ToString();
}

www.bsenyurt.com Page 1425


Grdnz gibi artk ayn ierie sahip olan Urun nesne rneklerimiz ayn hash deerlerini
retmektedirler. Object snfna ait sanal Equals metodunun ezilmesi ile GetHashCode metodunun
ezilmesi arasnda yakn bir iliki yer almaktadr. Makalemizde zerinde durmaya altmz konular
bir takm kurallarn domasna neden olmutur. Buna gre;

Equals metodu ezildii takdirde GetHashCode metoduda ezilmelidir.


== operatr ar yklendii takdirde Equals metoduda ezilmelidir ve her ikiside ayn
karlatrma algoritmasn iermelidir.
Eer karlatrma ilemleri iin IComperable arayz uygulandysa, Equals ezilmelidir ve
her ikisi iinde ayn eitlik algoritmalar kullanlmaldr.
Son olarak Equals, GetHashCode ve == operatrleri exception dndrmemelidir.

Bu kurallara dikkat edildii takdirde eitlik ilkelerinin salanmas daha kolay olacak ve Hashtable
yada Dictionary<> gibi hash kod tabanl alan algoritmalarn dzeni bozulmam olacaktr. Bir
baka deyile eitlikler zerinde tutarll salam oluruz. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

C# Temelleri : Referans Tipi Olmak ( 02.10.2006


) - C#
Deerli Okurlarm Merhabalar,

.Net zerinde kullanlabilen veri trleri (data types) referans trleri (reference types) ve deer
trleri (value types) olmak zere iki kategoriye ayrlmaktadr. Temel olarak deer trleri (value
types) fiziki bellein stack ad verilen blgesinde tutulur. Referans trleri ise, veriyi heap bellek
blgesinde tutarken, stack blgesinden verilerin adresini gsteren iaretiler kullanr. .Net
Framework ierisinde yer alan int, double, float, bool gibi ilkel tiplerin ou deer trleridir.
Gelitiriciler struct ve enum tiplerini kullanarak kendi deer trlerini tasarlayabilirler. Aslnda ilkel
deer trlerinin (int, double gibi) .Net Framework ierisinde karlk geldikleri struct ' lar vardr
(rnein int iin System.Int32). Bunlar ayn zaman Common Type System' in yeleridir. Referans
tipleri cephesine bakacak olursak; string ve object trleri nceden tanml olan referans tipleridir.
Gelitiriciler class, delegate gibi tipleri kullanarak kendi referans trlerini yazabilirler. Deer ve
referans trleri ile ilgili bu ksa aklamalardan sonra dilerseniz makalemizde ileyeceimiz konu
balklarna bir bakalm.

Referans tipleri aras atamalar sonras durumu.


Struct' lar ierisinde referans tipleri kullanlmas halinde, tipler aras atamalar sonras
durum.
Var olan referans trlerini klonlamak.
Referans trlerini metod parametrelerinde deer tr gibi kullanmak.

1. Referans tipleri aras atamalar sonras durumu.

www.bsenyurt.com Page 1426


Referans tipleri arasnda yaplan atamalar dikkat edilmesi gereken durumlardan birisidir. zellikle
atamalar sonras tip zerinde sahip olunan verilerde yaplacak deiiklikler dier nesne rneklerine
ait verileride dorudan etkileyecektir. Bu tamamyle referans tiplerinin bellek zerinde tutulu
ekliyle alakal bir durumdur. Bu durumu analiz etmek iin NoktaBilgisi isimli bir snf ele alalm.

class NoktaBilgisi
{
private string m_Aciklama;
public NoktaBilgisi(string aciklama)
{
m_Aciklama = aciklama;
}
public string Aciklama
{
get { return m_Aciklama; }
set { m_Aciklama = value; }
}
}

NoktaBilgisi isimli snfmz Aciklama isimli bir zellie ve bu zelliin kulland m_Aciklama isimli
alan set etmekte kullanlan bir yapc metoda sahiptir. Bu koddaki amacm ie yarar snftan ok
bir referans tipini ele almaya almaktr. Console uygulamamza ait kodlar aada olduu gibidir.
lk olarak NoktaBilgisi snfna ait nb1 isimli bir rnek oluturulmaktadr. Sonrasnda ise bu rnek
nb2 isimiyle tanmlanm bir NoktaBilgisi referansna eitlenmektedir. Bu eitleme ileminden sonra
nb2 isimli rnek zerinden Aciklama isimli zelliin deeri deitirilir. te her ey bu noktadan
sonra karr. Atama sonrasnda artk nesne rnekleri heap zerindeki ayn veri alanlarn iaret
ettiklerinden deiiklikler istenmeyen bir sonu dourabilir.

Console.WriteLine("\t Nokta 1 nesnesi oluturulur...");


NoktaBilgisi nb1 = new NoktaBilgisi("Nokta Aklamas");
Console.WriteLine("\t Nokta 2 nesnesi tanmlanr ve Nokta 1 nesnesi atanr...");
NoktaBilgisi nb2 = nb1;
Console.WriteLine("\t Nokta nesneleri iin Aklama bilgileri...");
Console.WriteLine("Nokta 1.Aklama ->"+nb1.Aciklama);
Console.WriteLine("Nokta 2.Aklama ->"+nb2.Aciklama);
Console.WriteLine("\t Nokta 2 nesnesi zerinde Aklama bilgisi deitirilir...");
nb2.Aciklama = "Yeni Aklama";
Console.WriteLine("\t Nokta nesneleri iin Aklama bilgileri son durum...");
Console.WriteLine("Nokta 1.Aklama ->"+nb1.Aciklama);
Console.WriteLine("Nokta 2.Aklama ->"+nb2.Aciklama);

Uygulamamz altrdmzda elde edeceimiz ekran grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 1427


Dikkat ederseniz atama ilemi sonrasnda nb2 nesne rnei zerinden yaplan deiiklik nb1 nesne
rneinin ieriinide dorudan etkilemitir. Bu referans tipleri iin zaten beklenen davrantr. Olay
aadaki ekilde grafiksel olarak ifade edilmeye allmtr.

Ne varki NoktaBilgisi isimli snfmz struct (yap) haline getirdiimizde (bunu class anahtar szc
yerine struct yazarak gerekletirebiliriz.) ok daha farkl bir sonula karlarz ve aadaki ekran
grntsn elde ederiz.

Yap kullanldnda atama sonras bellekte iki farkl NoktaBilgisi nesne rnei olumaktadr. Bu
nedenlede nb2 nesne rneine ait Aciklama alannda yaplan deiiklik nb1 nesnesini
etkilememitir. Olay aadaki ekilde grafiksel olarak ifade edilmeye allmtr.

Peki gelelim nemli soruya. Yaplar aras atama sonrasnda deiiklikler birbirlerini etkilemiyorlarsa,
bir struct ierisinde bir referans tr kullanldnda durum ne olacaktr? Bu soruyu 2nci madde
ierisinde incelemeye alalm.

www.bsenyurt.com Page 1428


2. Struct' lar ierisinde referans tipleri kullanlmas halinde, tipler aras atamalar sonras
durum.

Birinci maddedeki rneimizde, NoktaBilgisi snfn struct olarak kullandmzda, atama ilemi
sonrasnda stack bellek blgesinde farkl kopyalar oluturulduunu grmtk. Bu da kopyalanan
nesne rnekleri zerindeki deiikliklerin birbirlerini etkilemeyecei anlamna gelmekteydi. Ancak
yaplar (structs) ierisinde referans tiplerini kullanrsak durum biraz daha farkl olacaktr. Bunun iin
aadaki gibi bir yapmz (struct) olduunu dnelim.

struct Nokta
{
private int m_X;
private int m_Y;
private NoktaBilgisi m_bilgi;

public int X
{
get { return m_X; }
set { m_X = value; }
}

public int Y
{
get { return m_Y; }
set { m_Y = value; }
}

public NoktaBilgisi Bilgi


{
get { return m_bilgi; }
set { m_bilgi = value; }
}

public Nokta(string bilgi, int x, int y)


{
m_bilgi = new NoktaBilgisi(bilgi);
m_X = x;
m_Y = y;

www.bsenyurt.com Page 1429


}
public override string ToString()
{
return m_X.ToString() + " " + m_Y.ToString() + " " + m_bilgi.Aciklama;
}
}

Nokta isimli yapmz (struct) herhangibir noktaya ait x ve y koordinatlarn tutacak ve konumuza
rnek tekil etmesi asndan ierisinde NoktaBilgisi isimli snfmza ait referans tipini kullanacak
ekilde tasarlanmtr. imdi teorimize gemeden nce Nokta yapmz Console uygulamamz
ierisinde aadaki gibi kullanalm.

Console.WriteLine("\tNokta 1 oluturulur...");
Nokta nokta_1 = new Nokta("Balang Noktas", 10, 102);
Console.WriteLine("\tNokta 1 den Nokta 2' ye Atama yaplr...");
Nokta nokta_2 = nokta_1;
Console.WriteLine("\tNokta Nesne bilgileri...");
Console.WriteLine("Nokta 1 : \t" + nokta_1.ToString());
Console.WriteLine("Nokta 2 : \t" + nokta_2.ToString());
Console.WriteLine("\tNokta 2 iin alanlar deitirilir...");
nokta_2.Bilgi.Aciklama = "Yeni Aklama";
nokta_2.X = 18;
nokta_2.Y = 204;
Console.WriteLine("\tSon Durum");
Console.WriteLine("Nokta 1 : \t" + nokta_1.ToString());
Console.WriteLine("Nokta 2 : \t" + nokta_2.ToString());

Her zaman olduu gibi ilk olarak nokta_1 isimli bir yap nesnesi rneklenmekte ve sonrasnda
nokta_2 isimli bir yap tanmlamasna doru bir atama gerekletirilmektedir. Atama ilemi
sonrasnda ise nokta_2 zerindeki yelerde bir takm deiiklikler yapmaktayz. Burada zerinde
durmamz gereken nokta, NoktaBilgisi referansna ait Aciklama zellii zerinde yaplan
deiikliktir. Uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

Normal artlar altnda nokta_1 isimli yap rneini nokta_2 isimli yapya aktardmzda bellek
zerinde iki farkl deiken alan oluturulacaktr. Dolaysyla nokta_2 isimli nesne rnei zerinden
X ve Y alanlar iin yaptmz deiiklikerin nokta_1 nesne rneini etkilemeyecei ortadadr.
Ancak ayn davran biimi, ieride kullandmz NoktaBilgisi tipi iin geerli olmamtr. Bu durumu
aadaki grafik ile daha net canlandrabiliriz.

www.bsenyurt.com Page 1430


Olayn sebebi gayet aktr. ki yap rnei ierisindeki m_bilgi alanlar heap zerindeki ayn blgeyi
referans etmektedir. Bu atamann bir sonucu olarak karmza kmaktadr. zm olarak yapmza
IClonable arayzn uygulayabilir ve derin kopyalama (deep copy) tekniini kullanabiliriz.

3. Var olan referans trlerini klonlamak

Baz durumlarda referans trlerine ait bir nesne rneini o anki ieriiyle alp yeni bir nesne rnei
olarak kullanmak, baz deerlerini deitirmek ama bunlar yaparken atama srasnda kullanlan
dier nesneyi(nesneleri) etkilememek isteyebiliriz. Bir baka deyile bir referans trn klonlamak
isteyebiliriz. Bu tip ilemler iin .Net Framework ierisinde yer alan ICloneable isimli arayzn ilgili
snfa uyarlanmas gerekmektedir. Bu durumu daha iyi analiz edebilmek iin aadaki gibi bir
Dortgen snfmz olduunu dnelim.

public class Dortgen:ICloneable


{
private int m_En;
private int m_Boy;

public int En
{
get { return m_En; }
set { m_En = value; }
}

www.bsenyurt.com Page 1431


public int Boy
{
get { return m_Boy; }
set { m_Boy = value; }
}
public Dortgen(int en, int boy)
{
m_En = en;
m_Boy = boy;
}
public override string ToString()
{
return "En : " + m_En.ToString() + " Boy : " + m_Boy.ToString();
}
public object Clone()
{
return new Dortgen(this.m_En, this.m_Boy);
}
}

ICloneable arayz (interface) Clone isimli, parametre almayan ve geriye object tipinden deer
dndren bir metod tanmlar. Dortgen isimli snfmz ierisinde bu metodu kullanrken, o anki
m_En ve m_Boy deerlerini ele alarak yeni bir Dortgen nesne rneini geriye dndryoruz.
Dolaysyla alma zamannda, Dortgen snfna ait bir nesne rneini klonlama ansna sahip
oluyoruz. Aadaki kod parasnda bu ilemin nasl gerekletirilebilecei gsterilmektedir.

Console.WriteLine("\t Dortgen 1 nesnesi oluturulur...");


Dortgen drt1 = new Dortgen(10, 12);
Console.WriteLine("\t Dortgen 1 nesnesi Dortgen 2 nesnesine atanr...");
Dortgen drt2 = (Dortgen)drt1.Clone();
Console.WriteLine("\t Atama sonras bilgiler...");
Console.WriteLine("Dortgen 1 iin " + drt1.ToString());
Console.WriteLine("Dortgen 2 iin " + drt2.ToString());
Console.WriteLine("\t Dortgen 2 nesnesinin eni ve boyu deitirilir...");
drt2.En = 4;
drt2.Boy = 5;
Console.WriteLine("\t Dortgen 2 deiiklii sonras bilgiler...");
Console.WriteLine("Dortgen 1 iin " + drt1.ToString());
Console.WriteLine("Dortgen 2 iin " + drt2.ToString());

Uygulamamz altrdmzda aadaki sonucu alrz. Grdnz gibi klonlama ileminden


sonra, drt2 nesne rnei zerinde yaplan deiiklikler hi bir ekilde drt1 nesne rneini
etkilememitir.

www.bsenyurt.com Page 1432


Klonlama ilemi sonras bellekte oluan durumu aadaki grafikte olduu gibi dnebiliriz.

Dortgen snfmzn i yeleri deer trndendir. Bu sebepten dolay Clone metodu ierisinde
MemberwiseClone fonksiyonu kullanlaraktan da ayn etki salanabilir.

public object Clone()


{
return this.MemberwiseClone();
}

Ancak Dortgen snfnn baka referans tipleri ierdii ve kulland baz durumlarda
MemberwiseClone metodu tam bir klonlama ilemi gerekletiremeyebilir. Sz konusu durumu
analiz edebilmek iin Dortgen snf ierisinde, DortgenBilgi isimli bir referans tipi kullanacaz.

public class DortgenBilgi


{
private string m_Bilgi;
public string Bilgi
{
get { return m_Bilgi; }
set { m_Bilgi = value; }
}
public DortgenBilgi(string bilgi)
{
m_Bilgi = bilgi;
}
}

Dortgen snf ierisindede aadaki deiiklikleri yapalm.

public class Dortgen:ICloneable


{
private int m_En;
private int m_Boy;
public DortgenBilgi DortgenBilgisi=new DortgenBilgi("Drtgen");

public int En
{
get { return m_En; }
set { m_En = value; }

www.bsenyurt.com Page 1433


}
public int Boy
{
get { return m_Boy; }
set { m_Boy = value; }
}
public Dortgen(int en, int boy,string bilgi)
{
m_En = en;
m_Boy = boy;
DortgenBilgisi.Bilgi = bilgi;
}
public override string ToString()
{
return "En : " + m_En.ToString() + " Boy : " + m_Boy.ToString() + " " +
DortgenBilgisi.Bilgi ;
}
public object Clone()
{
return this.MemberwiseClone();
}
}

Dortgen snfmz ierisinde mzklk yapacak olan ve klonlama ileminde sorun kartacak olan ye
DortgenBilgi isimli alandr. Console uygulamamza ait kodlarmzda son olarak aadaki gibi
tamamlayalm. Bu sefer drt2 nesne rnei zerinden DortgenBilgisi referansna gidiyor ve Bilgi
isimli alann deerini deitiriyoruz. Yukardaki satrlarda Clone metodunu kullandmz iin
beklentimiz, Bilgi alanndaki deiikliin drt1 nesnesini etkilememesi olacaktr.

Console.WriteLine("\t Dortgen 1 nesnesi oluturulur...");


Dortgen drt1 = new Dortgen(10, 12,"Dikdrtgen");
Console.WriteLine("\t Dortgen 1 nesnesi Dortgen 2 nesnesine atanr...");
Dortgen drt2 = (Dortgen)drt1.Clone();
Console.WriteLine("\t Atama sonras bilgiler...");
Console.WriteLine("Dortgen 1 iin " + drt1.ToString());
Console.WriteLine("Dortgen 2 iin " + drt2.ToString());
Console.WriteLine("\t Dortgen 2 nesnesinin eni ve boyu deitirilir...");
drt2.En = 4;
drt2.Boy = 4;
drt2.DortgenBilgisi.Bilgi = "Kare";
Console.WriteLine("\t Dortgen 2 deiiklii sonras bilgiler...");
Console.WriteLine("Dortgen 1 iin " + drt1.ToString());
Console.WriteLine("Dortgen 2 iin " + drt2.ToString());

Oysaki uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

www.bsenyurt.com Page 1434


Grdnz gibi drt2 nesnesi zerinden DortgenBilgisi referansna ait Bilgi zelliinin deeri
deitirildiinde ayn etki drt1 iinde meydana gelmitir. Dolaysyla Clone metodu tam olarak
ilevini yerine getirmemitir. Bunun sebebi Clone metodu ierisinde kullanlan MemberwiseClone
metodunun referans tipi iin adres kopyalamas gerekletirmi olmasdr. zm olarak Clone
metodu ierisinde Dortgen snfna ait bir nesne rnei, o anki deerleri ile tekrardan rneklenip
geriye dndrlebilir.

return new Dortgen(this.m_En, this.m_Boy,this.DortgenBilgisi.Bilgi);

Uygulamay bu haliyle altrdmzda aadaki ekran grntsn elde ederiz. Grdnz gibi
bu sefer tam anlamyla bir derinlemesine kopylama ilemi gereklemitir. (Dortgen snf iin
kullandmz bu klonlama tekniini 2nci maddede kullandmz Nokta yaps iinde kullanabiliriz.)

Ayn etkiyi aadaki kod parasnda olduu gibide salayabiliriz. Bu tekniie gre,
MemberwiseClone metodu ile gncel Dortgen referansnn tm deer trleri salkl bir ekilde
alnmaktadr. Sonrasnda ise bir DortgenBilgi snfna ait nesne rnei oluturulmakta ve ierii
gncel Dortgen nesne rnei zerinden alnmaktadr ki burada sz konusu olan ierik Bilgi isimli
alandr. Son olarakta Dortgen snfna ait yeni nesne referans metoddan geriye dndrlmektedir.

Dortgen drt = (Dortgen)this.MemberwiseClone();


DortgenBilgi blg = new DortgenBilgi("");
blg.Bilgi = this.DortgenBilgisi.Bilgi;
drt.DortgenBilgisi = blg;
return drt;

4. Referans trlerini metod parametrelerinde deer tr gibi kullanmak.

Bildiiniz gibi deer trlerini (value types) metodlara referans tr olarak olarak geirebilmekteyiz.
Bunun iin ref ve out anahtar szcklerinden yararlanmaktayz. Lakin baz durumlarda referans
trlerini metodlara deer tr gibi geirmekde isteyebiliriz. Bu daha ok, metod ierisinde gelen

www.bsenyurt.com Page 1435


referans zerinde yaplacak deiikliklerin orjinal referans deitirmesini istemediimiz durumlarda
ie yarayacak bir yoldur. Konuyu daha net anlayabilmek iin NoktaBilgisi isimli snfmza ait
referans parametre olarak kullanan aadaki metoda sahip olduumuzu dnelim.

static void NoktaDegistir(NoktaBilgisi noktaBlg)


{
Console.WriteLine("\t Metod ierisi...Aklama deitirilir...");
noktaBlg.Aciklama = "Yeni Aklama";
}

NoktaDegistir isimli metodumuz NoktaBilgisi tipinden ald parametre zerinden Aciklama alannn
deerini deitirmektedir. Uygulamamza ait Main metodu ierisinde ise aadaki kodlar yazalm.

Console.WriteLine("\t NoktaBilgisi Oluturulur...");


NoktaBilgisi bilgi = new NoktaBilgisi("zel Mlk");
Console.WriteLine("Bilgi : " + bilgi.Aciklama);
Console.WriteLine("\t Metod arlr ve Bilgi nesnesi metoda aktarlr...");
NoktaDegistir(bilgi);
Console.WriteLine("Bilgi : " + bilgi.Aciklama);

Uygulamamz bu haliyle altrdmzda aadaki ekran grntsn elde ederiz. Grdnz


gibi metod ierisinde yaplan deiiklik otomatik olarak orjinal konumdaki nesne rneinide
etkilemitir.

imdi NoktaDegistir isimli metod ieriini aadaki gibi deitirelim.

static void NoktaDegistir(NoktaBilgisi noktaBlg)


{
noktaBlg = new NoktaBilgisi("Yeni Aklama");
// noktaBlg zerinden istenilen dier ilemler gerekletirilir.
}

Bu kez gelen parametreyi ieride bizzat rneklemekteyiz.(new ile yeni bir rneini
oluturmaktayz) Bu durumda uygulamamz yeninden altracak olursak NoktaDegistir metodu
ierisinde yaplan deiikliin Main metodu ierisinde yer alan NoktaBilgisi nesne rnei zerinde
bir etki yapmadn grebiliriz. Dolaysyla orjinal konumdaki nesne rneinin ieriini koruyabiliriz.

www.bsenyurt.com Page 1436


Bu makalemizde referans tiplerini daha yakndan incelemeye altk. Referans tipleri aras
atamalarn sonucundan yola karak, struct lar ierisinde referans trlerini kullanmamz halinde
neler olabileceine baktk. Ayrca bir referans tipinin tam bir kopyasnn nasl karlabileceini ve
bunu yaparkende ICloneable arayznn nasl kullanlabileceini incelemeye altk. Son olarakta
bir referans tipini herhangibir metoda bir deer tr olarak nasl alabileceimizi grdk. Bylece
geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

C# 3.0 - lk Bakta DLINQ ( 25.09.2006 ) - C#


3.0
Deerli Okurlarm Merhabalar,

Bildiiniz gibi uzun bir sredir Microsoft LINQ (.Net Language Integrated Query) adn verdii ve C#
3.0' n amac olan bir projeyi srdrmekte. Projenin en byk amac, zellikle veri zerinde
yaplabilecek sorgulama tekniklerinin dahada yaygnlatrlmas ve dil ortamna entegre
edilebilmesi. rnein LINQ sayesinde IEnumerable<T> arayzn (interface) uygulam herhanbir
tip (type) zerinde sql sorgularna benzer ifadeler kullanabilir ve alt kmeler ekebiliriz. LINQ' nun
bu zelliklerini kullanabilmek iin C# dilinin 3.0 versiyonunda pek ok yenilik bulunmaktadr.
rnein var anahtar szc ile, tip belirtmeden deiken tanmlayabilmek (var keyword), nesne
rneklerini olutururken yapc metodlara gerek kalmadan balang deerlerini belirleyebilmek
(object initializing), isimsiz tipler oluturabilmek (anonymous types) hatta lambda ( => ) isimli
yeni bir operatr sayesinde isimsiz metodlar bir adm ileriye gtrebilmek vb... mmkndr. Ancak
asl etki az ncede bahsettiimiz gibi LINQ ile gelmektedir.

LINQ' nun iki farkl uygulama alan daha vardr. Bunlar XLINQ - XML Store and Language
Integrated Query ve DLINQ - Database Language Integrated Queries' dur. XLINQ ile xml
verileri zerinde dil ile tmletirilmi sorgulama ifadeleri yazmak mmkn olabilmektedir. DLINQ
ise bugnk makalemizin asl konusudur. DLINQ ilikisel verilerin nesne olarak ifade edilebildii
ortamlar iin dil destekli sorgular kullanabilmemizi salamaktadr. Buna gre, bir veritabanna ait
herhangibir tabloyu uygulama tarafnda snf olarak temsil ettiimiz durumlarda (entity), bu
snflara ait rneklerin alma zamannda veritabanndan doldurulmasn salayabilir ve ilgili nesne
rnekleri zerinde LINQ ifadelerini kullanarak sorgular altrabiliriz. Bunun tersi durumda
geerlidir. Yani nesnelerin bellekte iaret ettikleri ierikte deiiklik yapp veritabanna doru
ynlendirilebilir. Konuyu daha iyi anlayabilmek iin bir rnek zerinden hareket edelim. Bu
rneimizde AdventureWorks ierisinde kendi oluturduumuz bir tabloyu ele alacaz.
Kullanacamz rnek tabloyu aadaki script yardmyla oluturabilirsiniz.

USE [AdventureWorks]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE TABLE [dbo].[Calisanlar](
[Id] [int] IDENTITY(1,1) NOT NULL,
[Ad] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,

www.bsenyurt.com Page 1437


[Soyad] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Maas] [money] NOT NULL,
[GirisTarihi] [datetime] NOT NULL,
[DogumTarihi] [datetime] NOT NULL,
[Unvan] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
[Departman] [nvarchar](50) COLLATE SQL_Latin1_General_CP1_CI_AS NOT NULL,
CONSTRAINT [PK_Calisanlar] PRIMARY KEY CLUSTERED
(
[Id] ASC
)WITH (PAD_INDEX = OFF, IGNORE_DUP_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]

DLINQ iin kilit nokta DataContext isimli snftr. DataContext snf alma zamannda, entity
snflar ile asl veri kaynann haberleebilmesine imkan tanr. ounlukla DLINQ uygulamalar
ierisinde, Strongly Typed DataContext snflar yer almaktadr. Bu snflar ilerinde, entity
snflarna ait generic tipler kullanr. DataContext zerinden tretme yardmyla oluturulan tipler
sayesinde LINQ ifadelerini nesne rnekleri zerinde altrabiliriz. Ayn zamanda nesne rnekleri
zerinde yaplacak deiiklikleri veritaban tarafna doru gnderebiliriz. Bu bilgilerden yola karak
hareket ettiimizde ilk yapmamz gereken aadaki gibi bir entity snf yazmak olacaktr. Bu snf
temel olarak Calisanlar tablosundaki her bir satr temsil edebilme yeteneine sahip olacak ekilde
tasarlanmaldr.

[Table(Name="Calisanlar")]
class Calisan
{
[Column(Name="Id",Id=true)]
public int Id;

[Column(Name="Ad")]
public string Adi;

[Column(Name="Soyad")]
public string Soyadi;

[Column(Name="Maas")]
public decimal Maasi;

[Column()]
public DateTime GirisTarihi;

[Column()]

www.bsenyurt.com Page 1438


public DateTime DogumTarihi;

[Column(Name="Unvan")]
public string Unvani;

[Column(Name="Departman")]
public string Departmani;
}

DLINQ bir snfn, nesne rnei olduunda veritabanndaki hangi tabloya karlk geldiini,
alanlarnn (fields) tablo zerindeki hangi kolonlara (columns) denk dtn ve temel
zelliklerinin neler olacan belirtmemize yarayan nitelikler(attributes) iermektedir. rnein
yazm olduumuz Calisan isimli snfn, veritabanndaki hangi tabloya karlk geldiini Table isimli
attribute yardmyla belirleyebiliriz. Buna gre Calisan isimli snfmz Calisanlar isimli tabloya ait
olacaktr.

Column, Table gibi nitelikler (attributes) ve biraz sonra greceimiz DataContext


snf, System.Data.DLinq isim alan (namespace) altnda yer almaktadr.

Benzer ekilde snf ierisinde tanml alanlarn, Calisanlar tablosu zerinde karlk geldikleri
kolonlar Column isimli nitelik (attribute) yardmyla belirlemekteyiz. Column nitelii yardmyla
eletirilecek kolon adnn ne olacan belirlemek dnda baka zellikleride ayarlayabiliriz. rnein
Id isimli alann ayn zamanda identity olacan Id zelliine true deeri atayarak belirlemekteyiz.
Benzer ekilde bir alann veri trnde DBType zellii ile Column nitelii ierisinde ayarlayabiliriz.
Aadaki ekilde Column nitelii ierisinde kullanabileceimiz dier zellikler grlmektedir.

Entity snfmzn ardndan Strongly Typed DataContext snfn yazmamz gerekmektedir. Bu tip
snflar genellikle bir veritaban ierisindeki tablolarn satrlarn temsil eden entity rneklerine ait
toplu veri kmelerini barndrmak ve ynetmek amacyla yazlmaktadr. Aadaki kod parasnda
yer alan AdventureWorks isimli snfn temel amac budur.

www.bsenyurt.com Page 1439


using System;
using System.Data.DLinq;

namespace UsingDLINQ
{
class AdventureWorks:DataContext
{
public Table<Calisan> SirketCalisanlari;

public AdventureWorks(string conStr)


: base(conStr)
{
}
}
}

AdventureWorks isimli snfmz DataContext' ten tretilmektedir. Yapc metodumuz ierisinde


dikkat edecek olursanz parametre olarak balant bilgisini alp DataContext snfnn ilgili yapc
metoduna (Constructor) gndermekteyiz. AdventureWorks isimli snfn bir dier nemli yesi
SirketCalisanlari' dir. Bu yenin tipi Table' dr. Table tipi burada generic' tir ve Calisan snf tipinden
rnekler barndrabilecei belirtilmektedir. yleyse biz SirketCalisanlari ile, Calisanlar tablosunun
tm satrlarn referans edebiliriz. imdi gelelim LINQ' yu iin ierisine katarak alma zamannda
Calisanlar isimli tablodan nasl sorgulama yapabileceimize. Bu amala oluturacamz LINQ
Preview Consoleuygulamas ierisinde aadaki kodlar yazmamz gerekiyor.

using System;
using System.Query;

namespace UsingDLINQ
{
class Program
{
static void Main(string[] args)
{
AdventureWorks adw = new AdventureWorks("data
source=localhost;database=AdventureWorks;integrated security=SSPI");

var calisanListesi=from clsn in adw.SirketCalisanlari select clsn;

foreach(var c in calisanListesi)
{
Console.Write(c.Id.ToString());
Console.Write("\t"+c.Adi+" ");
Console.Write(c.Soyadi);
Console.Write("\t"+c.Maasi.ToString());
Console.Write("\t"+c.DogumTarihi.ToString());
Console.WriteLine("\t"+c.Departmani.ToString());
}
}
}
}

Uygulamamz altrdmzda aadaki ekran grntsnde yer alan sonular elde ederiz.

www.bsenyurt.com Page 1440


Dikkat ederseniz burada C# 3.0 ile gelen bir ka yenilik yer almaktadr. Bunlardan birisi var
anahtar szcnn kullanlmasdr. Bildiiniz gibi var anahtar szc ile bir deikeni, tipini
belirtmeden tanmlayabilir ve kullanabiliriz. kinci nemli yenilik ise C# 3.0 ' n asl konusunu
oluturuan LINQ ifadelerinin kullanlmasdr. from anahtar szc ile balayan ifademizde
AdventureWorks snfna ait nesne rnei ierisinde yer alan Table tipindeki SirketCalisanlari nesne
rnei zerinden basit bir select sorgusu atlmaktadr. Burada yazm tarz T-Sql gz nne
alndnda biraz ters gelebilir. Ancak uygulamac gzyle baktmzda son derece mantlk bir
sorgu cmlesi ortaya kmaktadr. imdi sorgumuzu biraz deitirip aadaki hale getirelim.

var calisanListesi=from clsn in adw.SirketCalisanlari where clsn.Departmani=="Yazlm" select


clsn;

Bu durumda uygulamamz altrdmzda sadece yazlm departmanna ait alanlar elde


edebiliriz.

Sorgu ifadelerinin doru alabilmesi iin (rnein where anahtar szcn


kullanabilmek iin) System.Query isim alann uygulamamza dahil etmemiz
gerekmektedir.

Bu durumda sonu u ekilde olacaktr. imdi rneimizi biraz daha gelitirelim ve DLINQ
kullanarak ilikili verilerin nesnel bazda nasl sorgulanabileceini ele almaya alalm. Bu amala
Sql Server 2005 zerinde bizim emektar Northwind veritabann kullanacaz. Senaryo olarak
Categories ve Products tablolarnn birletirilmi hallerini (bir baka deyile join edilmi hallerini) ele
almaya alacaz. Yanlz bu kez bu birletirilmi veri kmesini kod tarafndaki katmanlarda ele
alacaz. Bizim iin gerekenler ncelikli olarak Categories ve Products tablolar iin birer entity
snf. Sonrasnda ise yazm olduumuz bu entity snflar ile asl tablolarmz arasndaki ilikiyi
salayacak DataContext' ten tremi bir snf. DataContext tipinden treteceimiz bu snf
ierisinde tablolar arasndaki ilikiyide nesnel bazda salamamz gerekecektir. Bunun
iinde Associationniteliinden ve EntitySet tipinden yararlanacaz. lk olarak entity snflarmz
aadaki gibi gelitirelim.

www.bsenyurt.com Page 1441


using System;
using System.Data.DLinq;

namespace UsingDLINQ
{
[Table(Name="Categories")]
class Kategori
{
[Column(Name="CategoryID",Id=true)]
public int KategoriId;

[Column(Name="CategoryName")]
public string KategoriAdi;

private EntitySet<Urun> m_urunDetay;

[Association(Storage="m_urunDetay",OtherKey="KategoriId")]
public EntitySet<Urun> UrunDetaylari
{
get { return m_urunDetay; }
set { m_urunDetay.Assign(value); }
}
}

[Table(Name="Products")]
class Urun
{
[Column(Name="ProductID",Id=true)]
public int UrunId;

[Column(Name="ProductName")]
public string UrunAdi;

[Column(Name="UnitPrice")]
public decimal BirimFiyat;

[Column(Name="CategoryID")]
public int KategoriId;

private EntityRef<Kategori> m_kategorisi;

[Association(Storage = "m_kategorisi", ThisKey = "KategoriId")]

www.bsenyurt.com Page 1442


public Kategori Kategorisi
{
get { return m_kategorisi.Entity; }
set { m_kategorisi.Entity = value; }
}
}
}

Buradaki kod parasnda, Kategori ve Urun snflar arasnda alma zamannda ifade edilebilecek
bire-ok (one-to-many) ilikide tanmlanmtr. Kategori snf ierisinde bu ii UrunDetaylari isimli
zellik gerekletirmektedir. zellie uygulanan Association isimli nitelik, bir kategoriye bal
rnlerin nerede saklanacan storage zellii yardmyla belirtmektedir. kinci parametremiz ise
bire-ok iliki iin gerekli anahtar(key) alan iaret eder ki buda ilgili kategorinin id deeri olacaktr.
imdide DataContext' ten trettiimiz Strongly Typed tipimizi yazalm.

using System;
using System.Data.DLinq;

namespace UsingDLINQ
{
class Northwind:DataContext
{
public Table<Kategori> Kategoriler;
public Table<Urun> Urunler;

public Northwind(string conStr)


: base(conStr)
{
}
}
}

Dilerseniz daha fazla detaya girmeden nesnel bazda ifade edebileceimiz bu ilikiyi LINQ zerinden
nasl kullanabileceimize bakalm. Bu amala programmza aadaki kod satrlarn ekleyelim.

Northwind nrth=new Northwind("data source=localhost;database=Northwind;integrated


security=SSPI");

var sonuclar = from urn in nrth.Urunler from ktg in nrth.Kategoriler where urn.KategoriId
== ktg.KategoriId select urn;

var altSonuclar=from snc in sonuclar where snc.KategoriId==2 select snc;

www.bsenyurt.com Page 1443


Console.WriteLine("\t Join zerinden Belirli Kategori Altnda Olanlar...");
Console.WriteLine();

foreach (Urun u in altSonuclar)


{
Console.WriteLine(u.KategoriId.ToString()+"\t"+u.Kategorisi.KategoriAdi+"\t"+u.UrunAdi+"\
t"+u.BirimFiyat.ToString());
}

Uygulamamz bu haliyle altrdmzda aadaki ekran grntsn elde ederiz. Grdnz


gibi KategoriId deeri 2 olan rnleri ekebilmekteyiz. Bu amala iki adet LINQ ifadesi
kullanlmtr. lk ifade aslnda Urunler ve Kategoriler isimli Table nesne rneklerine ait veri
kmelerini KategoriId alanlar zerinden birletiren ve T-Sql deki Join benzeri bir ilevsellii
salayan yapdadr. kinci LINQ ifadesinde ise bu Join yaps zerinden KategoriId' ye bir alt kme
ekilmektedir.

Yapm olduumuz rneklerdende anlayabileceiniz gibi DLINQ aslnda i katmannda yer alan
tiplerin zerinden T-Sql tarznda sorgularn yaplabilmesini salamaktadr. DLINQ ana konu olarak
LINQ ifadelerini kullandndan, alma zamannda bellek zerinde bulunan nesneler zerinde
istenilen sorgulamalar yaplabilir. DLINQ kendi ierisinde kayt dzenleme, transaction kullanm
gibi daha ileri seviye imkanlara da sahiptir. Bu konular ile ilgili daha detayl
bilgileri sitesinden bulabilirsiniz. Bu makalemizde ksaca DLINQ teknolojisine ksaca bakmaya ve
tanmaya altk. Makale ierisinde geen bilgilerin ounun C# 3.0 n son hali yaymlanana kadar
deiiklik gsterebileceini de gz nne almamz gerektiini unutmayalm. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

C# Temelleri : Static Olmak ( 14.09.2006 ) - C#


2.0
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1444


Static anahtar szc C# programlama dilinde st kapal yada ak bir biimde pek ok yerde
kullanlr. C# programlama dilini yeni renen birisi iin static anahtar szcnn kullanm
alanlarn bilmek nemlidir. te bu amala yola ktmz bu makalemizde, static kavramnn C#
programlama dilindeki yerini incelemeye alacaz. Static anahtar szcnn aadaki listede
olduu gibi eitli durumlarda kullanabiliriz.

Bir snf(class) ierisinde bulunan metodlar(methods) static olarak tanmlanabilir.


Bir snf(class) ierisinde bulunan alanlar (fields) static olarak tanmlanabilir.
Bir snfa ait static bir yapc metod (constructors) tanmlanabilir.
Deimezler (constants) bilinsiz olarak (implicit) static tanmlanmlardr.
Readonly referanslar aka belirtilmedike static deildirler.
C# 2.0 static snflara izin verir.

imdi tm bu maddeleri genileterek incelemeye alalm.

1 . Bir snf(class) ierisinde bulunan metodlar(methods) static olarak tanmlanabilir.

Static olarak tanmlanan bir metodun kullanlabilmesi iin tanmlanm olduu tipin nesne rneini
oluturmaya gerek yoktur. Bu durum ounlukla bir tipin asl i yapan fonksiyonelliklerin
kullanlabilmesi iin, tm nesneyi rneklemenin gereksiz olduu durumlarda ele alnr. rnein
aadaki kod parasn ele alalm. Bu kod parasnda basit olarak Matematik isimli snf ierisinde
tanmlanm Toplam isimli static bir metod yer almaktadr.

using System;

namespace StaticKavrami
{
class Matematik
{
public static double Toplam(double x, double y)
{
return x + y;
}
}
}

Burada tanml olan Toplam isimli static metodu kullanmak iin tek yaplmas
gereken SnfAd.StaticMetodAd notasyonunu kullanmak olacaktr.

www.bsenyurt.com Page 1445


using System;

namespace StaticKavrami
{
class Program
{
static void Main(string[] args)
{
double result = Matematik.Toplam(4, 5);
}
}
}

Grld gibi intelli-sense zellii Matematik isimli tip yazldktan sonra kullanlabilecek static
metodumuzu dorudan gstermektedir. .Net Framework ierisinde yukardaki rnekte bizim
tarafmzdan tanmlanm olan (user-defined) metod gibi yzlerce static metod mevcuttur. Bu
metodlarn kullanm amac ounlukla tanmlanm olduklar tipin nesne rneine ihtiya
duyulmayndan ileri gelmektedir. rnein Console uygulamalarn gelitirirken ok sk
kullandmz Console snfna ait WriteLine, ReadLine vb metodlar static olarak tanmlanmlardr.
Hatta bir console uygulamas gelitirdiimizde, programn giri noktas olan Main metodunun static
olarak tanmlandn farketmiizdir.

Static metodlarn kullanlmas srasnda dikkat edilmesi yada bilinmesi gerekin baz durumlar vardr.
ncelikli olarak, static olarak tanmlanm snf metodlarna static olmayan snf yeleride eriebilir.
rnein aadaki kod parasn gz nne alalm.

class Matematik
{
public static double Toplam(double x, double y)
{
return x + y;
}

public double Toplamlar(int ustSinir,double x,double y)


{
double sonuc=0;
for (int i = 0; i < ustSinir; i++)

www.bsenyurt.com Page 1446


sonuc+=Toplam(x,y);
return sonuc;
}
}

Bu kod parasnda static olmayan Toplamlar isimli Matematik snfna ait ye metod, static olan
Toplam metodunu kullanabilmektedir. Birde bunun tam tersi durumu gz nne almaya alalm.
Yani static bir metod ierisinden static olmayan bir metoda erimeye alalm. Aadaki
AltToplamlar isimli metod bu amala gelitirilmitir.

public static void AltToplamlar(int ustSinir, double x, double y)


{
Toplamlar(10, 4, 5);
}

Bu kod parasnda AltToplamlar isimli static metodumuz ierisinde, static olmayan Toplamlar isimli
metod arlmaktadr. Ancak bu metodu ieren uygulama kodu derleme zamannda An object
reference is required for the nonstatic field, method, or property
'StaticKavrami.Matematik.Toplamlar(int, double, double) hata mesajn verecektir. Eer
Visual Studio.Net kullanarak kodu yazyorsanz zaten AltToplamlar isimli metod ierisinden,
Toplamlar isimli metoda intelli-sense yardmyla bile eriemiyeceimizi grebilirsiniz.

Elbette burada ilgin bir durum daha vardr ki buda this anahtar szc kullanld takdirde
Toplamlar isimli static olmayan metodun eriilebilir gzkmesidir.

Bu tip bir eriim mmkn olmasna ramen uygulama kodu derleme zamannda 'this' is not valid
in a static property, static method, or static field initializer hatasn verecektir. Dolaysyla
static bir ye metodu ierisinde sadece static ye metodlar arlabilir. Yada baka bir deyile
static bir metod ierisinden static olmayan bir metodun arlamayacan syleyebiliriz.

2. Bir snf ierisinde bulunan alanlar (fields) static olarak tanmlanabilir.

www.bsenyurt.com Page 1447


Static metodlar gibi, bir snf ierisinde kullanlabilecek static alanlarda tanmlayabiliriz. Bir alann
static olarak tanmlanmas halinde bellek zerindeki yerleim eklide bilinmesi gereken noktalardan
bir tanesidir. Bunu daha iyi ifade edebilmek iin aadaki kod parasn gz nne alalm.

using System;

namespace StaticKavrami
{
class Matematik
{
public static double Pi = 3.14;
}
class Program
{
static void Main(string[] args)
{
Matematik mt1 = new Matematik();
Matematik mt2 = new Matematik();
Matematik mt3 = new Matematik();

Console.WriteLine(Matematik.Pi.ToString());
Console.WriteLine(Matematik.Pi.ToString());
Console.WriteLine(Matematik.Pi.ToString());
}
}
}

Matematik isimli snfmzda static olarak yer alan Pi isimli double tipinden bir deiken yer
almaktadr. Bu deikene dikkat ederseniz static metodlardakine benzer bir
ekilde SnfAd.DeikenAd notasyonu ile eriebilmekteyiz. Ancak burada asl nemli olan nokta
Matematik snfna ait 3 nesne rneinin oluturulmasna ve kullanlmasna ramen Pi deerinin hi
bir ekilde deimediidir.

te bu etkinin nedeni Pi deerinin static olarak tanmlanm oluudur. Dolaysyla Matematik


nesnelerinden ka tane oluturulursa oluturulsun hepsi ayn Pi deerine iaret etmektedir.
Aadaki grafikte bu durum sembolize edilmeye allmtr.

www.bsenyurt.com Page 1448


Static alanlar ile ilgili enteresan bir durum vardr. Bir static alann deeri alma zamannda
deitirilebilir ancak yapc metodlar iin ierisine girdiinde kodun tepkisi ok daha farkl olur.
Konuyu daha iyi anlamak iin Matematik snfmza static Pi deerini nesne rnei zerinden
deitirmemize yarayacak aadaki gibi bir metod ekleyelim.

public void PiDegistir(double pi)


{
Pi = pi;
}

Sonrasnda ise program kodlarmz aadaki gibi deitirelim.

static void Main(string[] args)


{
Matematik mt1 = new Matematik();
Matematik mt2 = new Matematik();
Console.WriteLine(Matematik.Pi.ToString());
Console.WriteLine(Matematik.Pi.ToString());
mt2.PiDegistir(3);
Matematik mt3 = new Matematik();
Matematik mt4 = new Matematik();
Console.WriteLine(Matematik.Pi.ToString());
Console.WriteLine(Matematik.Pi.ToString());
}

Tahmin edeceiniz gibi PiDegistir isimli metod mt2 isimli Matematik snfna ait nesne rnei
zerinden arldktan sonra, oluturulan mt3 ve mt4 isimli nesne rnekleri static Pi deikeninin
yeni deeri olan 3' e erieceklerdir.

www.bsenyurt.com Page 1449


Lakin iin ierisine bir yapc metodu katarsak durum biraz daha farkl bir hal alacaktr. Bu
deiiklie gre yukardaki kod parasn yeniden altrdmzda ilgin ama beklenen bir sonula
karlarz.

public Matematik()
{
Pi = 3.1415;
}

Bu durumda grld gibi tm rnekler iin Pi static deikeninin deeri 3.1415 olarak set
edilmektedir. Bunun sebebi son derece doaldr, nitekim yapc metod (constructor) her Matematik
nesne rnei oluturulurken altrldndan static deikenimizin deeride srekli olarak set
edilmektedir. te bu duruma zm olacak bir metod eidi daha vardr ; static yapc metod.
(static constructor method)

3 . Bir snfa ait static yapclar (constructors) tanmlanabilir.

Static yapc metod 2nci maddedeki son rnekte meydana gelen durum iin tam bir zm
olmaktadr. Static yapc metodu ounlukla bir snfn static deikenlerine ilk nesne rnei
oluturulduunda bir kereliine deer atmak iin kullanabiliriz. Bu bilgiler nda Matematik
snfmz aadaki gibi deitirelim ve static yapc metodumuz ierisinde static Pi deikeninin
deerini belirleyelim.

class Matematik
{
public static double Pi=3.14;

public void PiDegistir(double pi)


{
Pi = pi;
}
static Matematik()
{
Pi = 3.1415;
}
}

Burada dikkate deer bir nokta, Pi isimli static deiken tanmlanrken 3.14 deerini almasna
ramen, Matematik snfna ait ilk nesne rneinin oluturulmas ile birlikte Pi deerinin 3.1415
olarak ele alnmaya balanmasdr. Bunun sebebi static yapc metodun yapt deer atamasnn
geerli oluudur. imdi 2nci maddedeki Main metodundaki kodlarmz Matematik snfnn bu yeni
haline gre altrrsak, sistemin doru altn ve yapc metodlarn olumsuz etkisinin
gereklemediini grrz. Buradan karacamz en iyi sonu udur ki bir snfn static yelerinin
initialize edilecei en uygun yer static yapc metodudur.

www.bsenyurt.com Page 1450


Static yapc metoda ilikin dikkat edilmesi gereken bir takm kurallar da vardr. Bu kurallara gre;

Static yapc metod eriim belirleyicisi (access modifiers) kullanamaz.


Static yapc metod parametre alamazlar.
Static yapc metod snfa ait tm yapclardan nce alr.
Static yapc metod ka nesne rnei oluturulursa oluturulsun bir kere alr.
Bir snf sadece bir static yapc metod ierebilir.
Static yapc metod ya ilk nesne rnei oluturulduunda ya da ilk static snf yesi
arlmadan hemen nce yrtlr.

4. Deimezler (constants) bilinsiz olarak static tanmlanrlar.

Constant' lar uygulamann almas boyunca deimeyecek deerleri saklamak iin kullandmz
bir deiken eididir. Basit olarak deer trnden (value types) sabit bir deikeni aadaki gibi
tanmlayabiliriz.

public const double E = 2.7;

Her ne kadar aktrmasalarda const anahtar szc ile tanmlanan sabitler ayn zamanda static
davran gsterirler. Bunu hem Visual Studio.Net zerinde kod yazarken hemde ildasm ile
gelitirdiimiz tipin assembly' na ait metadata bilgisine bakarken grebiliriz.

Visual Studio.Net Ortamnda;

Ildasm (Intermediate Language DisAssembly) framework arac yardmyla assembly ierisine


baktmzda hem Matematik tipi zerinden hemde metaData ksmndan (Ctrl+M ile), E isimli sabit
deikenin static olarak tanmlandn grebiliriz. Bu da constant' larn aslnda isel olarak bilinsiz
bir ekilde (implicitly) static tanmlandnn kantdr.

www.bsenyurt.com Page 1451


Elbetteki sabitler bilinsiz (implicit) olarak static tanmlandklarndan, static anahtar szc
kullanldnda derleme zamannda hata mesaj alrz.

5. Readonly referanslar aka belirtilmedike static deildirler.

Constant' lar derleme zamannda (compile time) tanmlanan deikenler iin geerlidir. Bu
nedenlede sadece deer trlerine (value types) uygulanabilirler. Oysaki baz durumlarda sabit
olarak tanmladmz deikenlerin deerleri alma zamannda belirlenebilir. Bu nedenle referans
tiplerini sabit olarak kullanlabilmek iin readonly tanmlarz. rnein Matematik snfmzn readonly
versiyonunu kullanan aadaki Islemler isimli snf gz nne alalm.

class Islemler
{
public readonly Matematik mtIslemler;

public Islemler()
{
mtIslemler = new Matematik();
}
}

www.bsenyurt.com Page 1452


Readonly olarak tanmlanp sabit hale getirilen referans deikenlerinin constant' larda olduu gibi
alma zamannda static bir ye davran sergileyecei dnelebilir. Ancak aadaki ekran
grntsndende farkedeceiniz gibi bu mmkn deildir. Dikkat ederseniz intelli-sense zellii
readonly olarak tanmlanm mtIslemler isimli yeye,SnfAd.DeikenAd notasyonu ile
eriilmesine izin vermemektedir.

Dolaysyla readonly olarak tanmlanan referans trleri aka belirtilmedike static deildirler.
Dolaysyla mtIslemler isimli sabitimizi static olarak
tanmladmzda SnfAd.DeikenAd notasyonu ile erime imkanna sahip oluruz. Elbette
yukardaki kodu gz nne aldmzda, byle bir deiiklik bir static yapc metodunda
kullanlmasn gerektirecektir.

www.bsenyurt.com Page 1453


6. C# 2.0 static snflara izin verir.

C# 1.1 versiyonunda olmayan zelliklerden birisi bir snfn static olarak tanmlanamayyd. Oysaki
C# 2.0 ile static snflar tanmlayabilmekteyiz. Static snflarn belkide en nemli zellii sadece
static yeler ierebiliyor olmalardr. Static snflar ile ilgili daha detayl bilgiyi C# 2.0 ve Static
Snflar isimli makalemde bulabilirsiniz. Bylece geldik bir makalemizin daha sonuna. Bu
makalemizde static kavramnn C# dilindeki yerini incelemeye altk. Temel olarak static yelerin
metod ve alan baznda kullanln, static yapc metodu, sabit olarak tanmlanan deer veya
referans trlerindeki yerini incelemeye altk. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

XML Verilerini XSD ile Ynetimli Kod


zerinden Dorulamak ( 01.09.2006 ) - Xml
Deerli Okurlarm Merhabalar,

Xml ieriini kullandmz pek ok platformda, verinin belirli kurallara gre yazlm olmasn
istediimiz durumlar sz konusu olabilir. Bu durum zellikle, farkl platformlar arasnda tanacak
Xml tabanl verilerin ayn kurallar dizisine uygun olacak ekilde kullanlmas istendii durumlarda
karmza kmaktadr. Xml verilerinin belirli kurallara gre doruluunun tespitinde u anda DTD
(Document Type Definitions), XDR (Xml Data Reduced) ve XSD (Xml Schema
Definitions) gibi teknolojilerden yararlanlmaktadr. Bu teknolojiler yardmyla bir Xml verisi
ierisindeki elemanlar zerinde eitli kurallar tanmlayabiliriz. rnein tutulan veri tiplerini
snrlayabilir, Xml aacnn yapsn tanmlayabiliriz vb. Bylece verilerin tutarllnda salam
oluruz. Gnmzde, Xml verilerinin dorulanmas iin kullanlan en yaygn teknoloji XSD ' dir. XSD'
yi daha nceki trevi olan XDR' n mkemmelletirilmi hali olarakta dnebiliriz. Zaten WC3' da
XSD emalarnn kullanlmasn nermektedir. Biz bu makalemizde .Net tarafnda yer alan ynetimli
tipleri (Managed Types) kullanarak Xml verilerini XSD ile arptrarak dorulama ilemlerini nasl
yapabileceimizi incelemeye alacaz. lk olarak aadaki gibi bir Xml ieriimiz olduunu
dnelim.

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


<Dukkanim>
<Kitap ID="1000">
<Adi>Her Ynyle C#</Adi>
<Fiyat>Elli YTL</Fiyat>
<StokDurumu>40</StokDurumu>
<Yazarlar>
<Yazar>Sefer Algan</Yazar>
</Yazarlar>
<BasimTarihi>10/11/2003</BasimTarihi>
<Aciklama>C# ile ilgili yazlm en iyi Trke kaynaklardan birisidir. </Aciklama>
</Kitap>
<Kitap ID="1001">
<Adi>Kahraman Asker</Adi>
<Fiyat>30</Fiyat>
<StokDurumu>Bin Adet</StokDurumu>
<Yazarlar>
<Yazar>Anonim</Yazar>
</Yazarlar>

www.bsenyurt.com Page 1454


<BasimTarihi>10/11/2004</BasimTarihi>
<Aciklama>C# ile ilgili yazlm en iyi Trke kaynaklardan birisidir. </Aciklama>
</Kitap>
</Dukkanim>

Bu Xml ieriinde Kitaplar ile ilgili bir takm bilgileri tutmaktayz. rnein Kitabn adn, fiyatn,
stoktaki durumunu, basm tarihi vb. Bu Xml dkmann herhangibir tarayc yardmyla atmzda
gelitiriciler iin okunabilir ve anlalabilir bir ierik elde ederiz.

Lakin bu Xml ieriinin platformlar arasnda tandn ve ilendiini dndmzde hataya


neden olacak pek ok problemin olduunu grebiliriz. rnein Fiyat alanlarnda bir standart yoktur.
yleki ilk Kitap eleman (element) ierisinde Fiyat deeri Elli YTL olarak string bazl yazlmken,
ikinci Kitap elemanndaki Fiyat elemannn deeri 30 olarak saysal belirtilmitir. Baka bir deyile
Fiyat alannn aslnda uygun bir veri tipi olma zorunluu yoktur. Dolaysla bu Xml dkmann alp
fiyatlar zerinde saysal ilemler yapacak olan bir uygulama kodu sorunlar ile karlaacaktr.
Benzer durum StokDurumu eleman iinde geerlidir. Bu tip veri uyumazlklarn emalarda
yapacamz tanmlamalar ile dzeltebiliriz. Dier taraftan dikkat ederseniz her Kitap eleman
ierisinde Yazarlar isimli bir eleman bulunmaktadr ki bu elemanda en az bir Yazar elemann
iermelidir. Bu da bir kural olarak ema bilgisi ierisine alnabilir. XSD emalarn sfrdan
herhangibir editor kullanmadan yazmak her zaman keyfi verici bir i olmayabilir. Lakin Vs.Net 2003
srmnden bu yana, grsel olaraktan XSD emalarn kolayca hazrlayabilmemizi salayan bir
arabirim sunmaktadr. Buna gre yukardaki Xml dkmanmz iin aadaki gibi bir XSD emasn
kolayca hazrlayabiliriz. (XSD' nin renilebilecek daha ok zellii olduundan ve makalemizin
snrlarn atndan ok fazla derinine inmeyeceiz.)

www.bsenyurt.com Page 1455


<?xml version="1.0" encoding="utf-8"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="Dukkanim">
<xs:complexType>
<xs:sequence>
<xs:element name="Kitap" minOccurs="1" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="Adi" type="xs:string" minOccurs="1" maxOccurs="1"/>
<xs:element name="Fiyat" type="xs:double" minOccurs="1"
maxOccurs="1"/>
<xs:element name="StokDurumu" type="xs:integer" minOccurs="1"
maxOccurs="1"/>
<xs:element name="Yazarlar" minOccurs="1" maxOccurs="1">
<xs:complexType>
<xs:sequence>
<xs:element name="Yazar" type="xs:string" minOccurs="1"
maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="BasimTarihi" type="xs:dateTime" minOccurs="1"
maxOccurs="1" />
<xs:element name="Aciklama" type="xs:string" minOccurs="1"
maxOccurs="1" />
</xs:sequence>
<xs:attribute name="ID" type="xs:integer" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

lk olarak ema dosyamzda belirttiimiz kurallar ksaca incelemeye alalm. rnein Adi, Fiyat,
StokDurumu, Yazarlar, BasimTarihi, Aciklama gibi elemanlardan sadece ve yanlz bir adet
girilebilecei belirtilmektedir. Bu kural minOccurs ve maxOccurs isimli zellikler ile belirtiliyor.
Dolaysyla Yazarlar isimli elemanmz, kendi ierisinde en az bir olacak ekilde istenildii kadar
(unbounded sayesinde) Yazar eleman ierebilir. XSD dkmanmz ierisinde yer alan her eleman

www.bsenyurt.com Page 1456


(ve hatta ID isimli attribute-nitelik) iin ayr veri tipi tanmlamalar yaplmtr. rnein ID isimli
attribute (nitelik) integer tipinden olmaldr. Fiyat isimli elemanmz double trnden olmaldr vb.

Peki bu ve benzeri ema bilgisini(bilgilerini) kullanarak yazdmz Xml ieriini ynetimli kod
tarafndan (managed-code) nasl denetleyebiliriz? .Net 2.0 ierisinde bu tip ilemler iin getirilmi
yeni tipler vardr. Bunlar XmlReaderSettings, XmlSchemaSet isimli tiplerdir. Konuyu daha iyi
anlayabilmek iin rnek kodlar ile devam etmemizde fayda olduu kansndaym. Aadaki kod
parasnda bir Asp.Net formu zerinde, Dukkan.xml isimli Xml dkmannn Dukkan.xsd ismli xml
ema dkman ile dorulanmasnn nasl yaplabilecei gsterilmektedir.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Text;

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


{
StringBuilder hatalar;

protected void Page_Load(object sender, EventArgs e)


{
string xmlFile = Server.MapPath("Dukkan.xml");
string XSDFile =Server.MapPath( "Dukkan.XSD");
hatalar = new StringBuilder();

XmlReaderSettings xrs = new XmlReaderSettings();


xrs.ValidationEventHandler +=
new System.Xml.Schema.ValidationEventHandler(xrs_ValidationEventHandler);
xrs.Schemas.Add(null, XmlReader.Create(XSDFile));
xrs.ValidationType = ValidationType.Schema;
XmlReader reader = XmlReader.Create(xmlFile, xrs);
while (reader.Read())
{}
if (hatalar.ToString() == "")
Response.Write("Hata yok");
else
Response.Write(hatalar.ToString());
}

void xrs_ValidationEventHandler(object
sender, System.Xml.Schema.ValidationEventArgs e)
{
if (e.Severity == System.Xml.Schema.XmlSeverityType.Error)
hatalar.Append(e.Message+"<br><br>");
}
}

rneimizi altrdmzda aadaki ekran grntsnde yer alan hata mesajlarn elde ederiz.

www.bsenyurt.com Page 1457


Dikkat ederseniz XSD emasnda belirtilen kurallara uymayan durumlar iin eitli hata mesajlar
retilmi ve ekrana yazlmtr. Kodumuzdaki kilit nokta XmlReaderSettings isimli tipin
XmlReader tipi ile entegrasyonudur. XmlReaderSettings snfna ait tek olay(event)
olan ValidationEventHandler, dorulamas yaplan Xml dkman ierisinde meydana gelen
hatalar (errors) yada uyarlar(Warnings) sonucunda otomatik olarak tetiklenmektedir. Xml verisini
kontol etmek iin kullanlacak XSD emalar, XmlReaderSettings snfna Schemaszellii
yardmyla yklenir. Schemas zellii .Net 2.0 ile gelen yeni tiplerden birisi
olan XmlSchemaSet tipinden nesne rnekleri ile de alabilmektedir. Burada nemli olan
noktalardan birisi Schemas zelliinin aslnda bir koleksiyon sunmas ve Add metodu nedeni ile
XmlReaderSettings iin birden fazla ema bilgisinin bir arada tutulabilmesidir. yleki farkl xml isim
alanlarna ait farkl sayda ema bilgisini XmlReaderSettings tipleri ierisinde barndrabiliriz.
XmlReaderSettings snfna ait bir dier nemli ye ise ValidationTypezelliidir. Bu zellii
atadmz deer ile (ValidationType.Schema), XSD ema tipine gre dorulama yapacamz
belirtmi oluruz. Kodun ilerleyen ksmlarndaki admlarmzda ise XmlReader snfmza ait
nesnemizi Create isimli statik metod ile oluturmaktayz.

rnek kodumuzda XmlReader snfna ait nesne rnei ile okuma yapmak iin gerekli reader isimli
nesneyi olutururken static Create metodunun ilk parametresi olarak Xml dkmanmz, ikinci
parametresi olarakta dorulama ilemleri ile ilgili bilgileri ieren XmlReaderSettings nesne
rneimizi belirtmekteyiz. Bu ilemlerin ardndan tek yaplmas gereken XmlReader nesne rneinin
tad ierii ileri ynl okumaktr. Bu amala kullandmz while dngs ile Xml ieriinde ileri
ynl bo bir teleme gerekletirirken, XSD dosyamzn ierdii emada belirtilen kurallara
uymayan her noktada, ValidationEventHandler olay tetiklenir. Bizde bu olaya ilikin metodumuz
ierisinde dorulama sonucu ortaya kan hatalar, ValidationEventArgs tipi ile ele alabiliriz.
rnek olarak incelediimiz Xml dkmanmz aadaki gibi dzenlersek (yani ema hatalarn
ortadan kaldrrsak) uygulamamz dorulamay baarl bir ekilde geecektir.

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


<Dukkanim>
<Kitap ID="1000">
<Adi>Her Ynyle C#</Adi>
<Fiyat>50</Fiyat>
<StokDurumu>40</StokDurumu>
<Yazarlar>

www.bsenyurt.com Page 1458


<Yazar>Sefer Algan</Yazar>
</Yazarlar>
<BasimTarihi>2003-10-11T12:00:00</BasimTarihi>
<Aciklama>C# ile ilgili yazlm en iyi Trke kaynaklardan birisidir. </Aciklama>
</Kitap>
<Kitap ID="1001">
<Adi>Kahraman Asker</Adi>
<Fiyat>30</Fiyat>
<StokDurumu>1000</StokDurumu>
<Yazarlar>
<Yazar>Anonim</Yazar>
</Yazarlar>
<BasimTarihi>2004-10-11T12:00:00</BasimTarihi>
<Aciklama>C# ile ilgili yazlm en iyi Trke kaynaklardan birisidir. </Aciklama>
</Kitap>
</Dukkanim>

XSD ile dorulama ilemleri zellikle Xml verisi zerinde XmlDocument tipi ile alrken daha
byk nem tar. XmlDocument snf bildiiniz gibi bir Xml ieriini bellekteDOM (Document
Object Model) sistemine gre referans eder. Buda ilgili dkman zerinde ykleme zamannda bir
dorulama ileminin yaplmasn gerektirir. Eer bir Xml verisini, XmlDocument snfna ait nesneler
yardmyla ele alyorsak, dkman ierisine yaplacak mdahalelerinde belirleyeceimiz ema
kurallar erevesinde olmasn garanti etmek isteyebiliriz. Durumu daha iyi analiz etmek iin
aadaki kod parasn ele alalm.

string xmlFile = Server.MapPath("Dukkan.xml");


string XSDFile =Server.MapPath( "Dukkan.XSD");
hatalar = new StringBuilder();

XmlDocument doc = new XmlDocument();


doc.Load(xmlFile);
XmlElement currElement
=(XmlElement)doc.DocumentElement.SelectSingleNode("//Dukkanim/Kitap[@ID='1000']");
XmlNode newNode = doc.CreateNode(XmlNodeType.Element, "SayfaSayisi", null);
newNode.InnerText = "600";
currElement.AppendChild(newNode);

doc.Save(xmlFile);

rnek kodumuzda, XmlDocument snfna ait doc isimli nesne rneimizi Dukkan.xml dosyasna ait
xml ierii ile ykledikten sonra ID niteliinin deeri 1000 olan node (boum) ksmn elde
ediyoruz. Sonrasnda ise dkman zerinde yeni bir eleman (element) oluturuyoruz. Amacmz
oluturduumuz yeni eleman (element) 1000 ID numaral Kitap boumu altna eklemek. Bunun
iin SayfaSayisi isimli bu yeni xml elemanna bir deer atayp chile node olarak dkmandaki ilgili
boumun altna ekliyoruz. Bu aslnda XSD emasnda tanmlanmam bir eleman. Dolaysylada
eklenmemesi gereken bir eleman. Ancak XSD dorulamasn hesaba katmadmzdan bu yeni
eleman Xml ieriine gayet gzel bir ekilde eklenecektir. yleki rneimizi altrdmzda Xml
dkmanmzn ieriinin aadaki gibi deitiini grrz. Her nekadar Vs.Net 2005 IDE' si bizi bu
yeni eleman konusunda uyarsada, sonu olarak deiiklik kod tarafndan fiziki dosyaya
aktarlmtr.

www.bsenyurt.com Page 1459


O halde gelin XSD dorulamasn iin ierisine katp bu deiikliklerin yaplmasn engelleyelim.
Bunun iin yine XmlReaderSettings ve XmlReader snflarndan yararlanacaz. Ancak bu kez
XmlDocument ierisinde dorulama ilemini gerekletirmek iin,baka bir deyie bellekteki Xml
verisi zerinde dorulama yapabilmek iin, XmlNodeReader isimli snftan faydalanacaz. Bu
nedenle uygulama kodumuzu aadaki gibi deitirelim.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.Xml;
using System.Text;

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


{
StringBuilder hatalar;

protected void Page_Load(object sender, EventArgs e)


{
string xmlFile = Server.MapPath("Dukkan.xml");
string XSDFile =Server.MapPath( "Dukkan.XSD");

www.bsenyurt.com Page 1460


hatalar = new StringBuilder();

XmlDocument doc = new XmlDocument();


doc.Load(xmlFile);

XmlElement currElement
=(XmlElement)doc.DocumentElement.SelectSingleNode("//Dukkanim/Kitap[@ID='1000']");
XmlNode newNode = doc.CreateNode(XmlNodeType.Element, "SayfaSayisi", null);
newNode.InnerText = "600";
currElement.AppendChild(newNode);

XmlNodeReader nodeReader = new XmlNodeReader(doc);


XmlReaderSettings readerSettings = new XmlReaderSettings();
readerSettings.ValidationEventHandler+=new
System.Xml.Schema.ValidationEventHandler(readerSettings_ValidationEventHandler);
readerSettings.ValidationType= ValidationType.Schema;
readerSettings.Schemas.Add(null,XmlReader.Create(XSDFile));
XmlReader reader = XmlReader.Create(nodeReader, readerSettings);

while (reader.Read())
{}

if (hatalar.ToString() == "")
doc.Save(xmlFile);
else
Response.Write(hatalar.ToString()+"<b>Hatas Nedeniyle Xml Dkmannn yeni ierii
kayt edilememitir.</b>");

void readerSettings_ValidationEventHandler(object sender,


System.Xml.Schema.ValidationEventArgs e)
{
if (e.Severity == System.Xml.Schema.XmlSeverityType.Error)
hatalar.Append(e.Message + "<br><br>");
}
}

Dilerseniz uygulama kodumuzda neler yaptmza ksaca bakalm. Bu sefer XmlDocument snfna
ait doc isimli nesne rneinin iaret ettii bellek grntsn, ilgili XSD emas ile kontrol
edebilmek amacyla XmlNodeReader snfndan yardm alyoruz. Bu nedenle XmlNodeReader
snfmza ait nodeReader isimli nesne rneimizi doc parametresini vererek oluturuyoruz. Her
zamanki gibi, XSD ema dosyas (Dukkan.XSD) iin gerekli ayarlarn
tanaca XmlReaderSettings snfna ait nesne rneimizi oluturmaktayz. Burada dikkat
edilmesi gereken noktalar; dorulama tipi (ValidationType)seimi, dorulama srasnda hatalar
veya uyarlar sonras tetiklenecek olayn ve metodunun hazrlanmas (ValidationEventHandler)
ve XSD ema dosyasnn Schemas koleksiyonuna yklenii (Schemas.Add).

www.bsenyurt.com Page 1461


XSD dkmanmz ile doc isimli nesnemizin bellekte iaret ettii Xml ieriini arptrmak
dolaysyla ema denetimi altna dorulama kontrollerini yapmak iinse, yine XmlReader snf
nesne rneinden yararlanyoruz. Ancak bu sefer ilk parametremiz, XmlNodeReader snfmza ait
nodeReader isimli nesne rneimizdir. While dngs ile yaptmz bo teleme hareketi srasnda
da oluan hata mesajlarn topluyor ve hibir hata yok ise Xml dkmanmz son haliyle
kaydediyoruz (doc.Save). Aslnda dng ierisinde ilerlerken, XmlReader.Create metodunda
belirtiimiz kurallar uyguluyoruz. Yani XmlNodeReader' n tad ierik zerinde ilerlerken XSD yi
tayan XmlReaderSettings' teki kurallara gre dorulama kontrolleri gerekletiriyoruz. Bylece
geldik bir makalemizin daha sonuna. Bu makalemizde ksaca XSD emalarn, Xml dkmanlar ile
arptrarak yaplan dorulama ilemlerinde .Net ynetimli tiplerinin (managed code) nasl
kullanlabileceini incelemeye altk. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek Uygulama in Tklayn

Burak Selim ENYURT


selim@bsenyurt.com

lk Bakta .Net Resource Ynetimi ( 19.08.2006 )


- C# 2.0
Deerli Okurlarm Merhabalar,

Bir Assembly kendi ierisinde Resources ad verilen harici kaynaklar ile birlikte kullanlabilir.
Kaynaklar ounlukla bu assembly ierisindeki eitli tipler tarafndan kullanlan resim dosyalar
(gif,jpg,icon, bmp vb...) , metin dosyalar (text files), string bazl veriler yada wav uzantl ses
dosyalardr. rnein bir text dosya ieriini yada uygulamada kullanlan resim dosyalarna ait
binary ierikleri, assembly ierisine gmebiliriz (Embedding). Bunun bize salayaca en byk
avantaj, assembly' kaynaklar ile birlikte tek bir dosya halinde tayabilecek olmamzdr. zellikle
path (yol) baml dosya kaynaklarnda bu durum daha byk nem arz etmektedir. Nitekim
uygulama ierisinde resim, ses, metin dosyas gibi kaynaklarn kullanld yerlerde adres bilgisi
verilme zorunluluu ortadan kalkmaktadr. Bu da o adreste olmaypta eriilmek istenen bir kaynak
dosya var ise eer, oluacak istisnalarn (exceptions) bir nevi nne geilmesi anlamna
gelmektedir. Dier taraftan bu dosyalardan her hangibirinin istem d olarak silinmesi halindede
uygulama almaya devam edecektir. Nitekim kaynaklar assembly ierisine gmlm haldedir.
Resource (Kaynak) bilgilerini ynetimli kod (managed code) tarafnda oluturabilir hata var olan
kaynak dosya bilgilerine eriebiliriz. Bu ilemler iin System.Resources isim alan altnda yer alan
baz tipler kullanlmaktadr.

Resource (Kaynak) Ynetimi in Kullanlan Tipler

Assembly ierisine gmlm (embedded) kaynak verileri


ResourceManager
okuyabilmek iin kullanlr.

Resx uzantl ve Xml tabanl kaynak bilgi dosyalarna


ResXResourceWriter
yazma ilemi iin kullanlr.

Resx uzantl ve Xml tabanl kaynak bilgi dosyalarndan


ResXResourceReader
okuma ilemi iin kullanlr.

Dorudan Resource uzantl binary kaynak dosyalarna


ResourceWriter
yazma ilemi iin kullanlr.

ResourceReader Dorudan Resource uzantl binary kaynak dosyalarndan

www.bsenyurt.com Page 1462


okuma ilemi iin kullanlr.

Temel olarak bir assembly ierisine kaynak dosya dahil etmek iin aadaki sre takip edilir.

Resx uzantl dosyalar xml tabanldr. Bu dosyalar kaynak verileri anahtar-deer (key-value) iftleri
eklinde saklar. Xml tabanl olmalar nedeni ile gelitiriciler tarafndan kolayca okunabilir ve anlalr
bir ierik sunmaktadr. Resx dosyalar dorudan assembly ierisine dahil edilemezler. Assembly
ierisine dahil edilebilecek olan kaynaklar ikili formatta (binary) tutulanresources uzantl
dosyalardr. Resource uzantl dosyalar retmek iin Framework aralarndan
olan ResGen.exe (Resource Generator) 'den yararlanlmaktadr. retilen resource
dosyas csc (C#Compiler arac) yardmyla ilgili assembly' n ierisine dahil edilebilir. Bu ilem
srasnda csc aracnn /resource parametresi kullanlmaktadr. Bu sre Vs.Net 2005 IDE' si
ierisinde otomatik olarak gerekletirilmektedir.

lk olarak, resx uzantl dosyalarn kod tarafnda nasl oluturulabileceini incelemeye alalm.
Aadaki kod parasnda bir resx dosyas oluturulmakta ve parametre olarak verilen bir takm
bilgileri bu dosyaya dahil edecek kodlar iermektedir. (Bu kodun almas
iin System.Resources isim alannn eklenmi olmas gerekmektedir.)

ResXResourceWriter resxWriter = new ResXResourceWriter("KaynakResimler.resx");


resxWriter.AddResource("Generic", new Bitmap("generic.gif"));
resxWriter.Generate();
resxWriter.Close();

lk olarak ResxResourceWriter isimli snfa ait bir nesne rnei oluturuyoruz. Bu nesne rnei
parametre olarak resx uzantl dosyann adn alyor. AddResource isimli metod, belirtilen resx
dosyasna veri atmak iin kullanlmaktadr. Burada biz rnek olarak gif formatndaki bir resim
dosyasn kullanyoruz. Son olarak oluturulan bilgileri fiziki dosyaya aktarmak iin Generate isimli
metod arlmaktadr. Bu ilemler sonrasnda oluan resx dosyasn notepad yardmyla atmzda
aada bir paras grnen ierii elde ederiz. Dikkat ederseniz resim dosyamz, retilen Xml
dosyas ierisine binary seriletirilmi ve value isimli boumlar (nodes) arasna atlmtr.

www.bsenyurt.com Page 1463


imdi oluturulan bu resx dosyasnn assembly ierisine gmlmesini salayacak resource uzantl
karln oluturmalyz. Bu amala ResGen.exe aracn komut satrndan aada olduu gibi
kullanmamz gerekiyor.

resgen KaynakResimler.resx Kaynaklar.resources

Bu ilemin sonucunda Kaynaklar.resources isimli binary dosya oluur. Bu dosyay Vs.Net


ortamnda aarsak eer aadakine benzer bir kt elde ederiz. Ksaca resim dosyamza ait ierik
buraya dahil edilmitir.

Bir sonraki admz ise bu Resource dosyasn assembly' n ierisine dahil etmek olacaktr. Bu amala
csc.exe isimli C# assembly' lar retmemizi salayan Framework aracn komut satrndan
aadakine benzer bir ekilde kullanabiliriz.

csc /out:bin/debug/CreatingUsingResources.exe /target:winexe


/resource:bin/debug/Kaynaklar.resources /r:System.Drawing.dll *.cs

www.bsenyurt.com Page 1464


Bu ilem sonrasnda eer windows uygulamasna ait assembly ieriine ildasm( Intermediate
Language DisAssembler Tool) yardmyla bakacak olursak resource dosyasna ait referans
bilgisinin Manifest ieriine eklenmi olduunu grrz.

Programatik olarak, resx dosyasn oluturmadan dorudan resource dosyalarnda oluturabiliriz.


Bu amala ResourceWriter tipi kullanlr. Aadaki kod paras arada bir resx dosyas olmadan
dorudan resource dosyasna bir verinin (rnek olarak ayn resim dosyasn kullandk) nasl
yazlabileceini gstermektedir.

ResourceWriter writer = new ResourceWriter("Kaynaklar.resources");


writer.AddResource("Generic", "generic.gif");
writer.Generate();
writer.Close();

Bu kod satrnn almas sonrasnda Kaynaklar.resources dosyas dorudan elde edilecektir.


AddResource metodu ile bir nceki rneimizde kullandmz generic.gif isimli dosyay, resource
dosyamz ierisine alyoruz. ResxResourceWriter snfnda olduu gibi buradada dosyay reten
metod Generate isimli metodumuzdur. Son olarakta ResourceWriter nesne rneini kapatyoruz.
Komut satr aralar yardmyla yaplan bu ilemler Vs.Net 2005 IDE' si ierisinde elbetteki ok
daha kolay bir biimde yaplabilmektedir. imdi Vs.Net 2005 IDE' si ierisinde resource dosyalarn
en ksa ekilde nasl oluturabileceimizi adm adm incelemeye alalm. lk olarak projemize yeni
bir e (item) eklemeliyiz. Ekleyeceimiz bu ye resx uzantl bir dosya olacaktr.

kinci olarak oluturulan resx dosyasna istediimiz kaynaklar eklemeliyiz. Resim dosyalarn, ses
dosyalarn, metin dosyalarn vb...Bu ilemler srasnda srkle brak (drag-drop) ilemlerini
kullanabileceimiz gibi, dosya iin oluturulan menlerden de faydalanabiliriz. Add Resource
mensnden aadaki seenekler yardmyla kaynak verileri ekleyebiliriz. (zellikle Add Existing
File yardmyla var olan kaynak dosyalar seilerek eklenebilir.)

www.bsenyurt.com Page 1465


Bir Resource dosyas ierisindeki kaynak dosyalar veya ierii aada grld gibi ilgili menleri
kullanarak izleyebiliriz. Kaynak ekleme ilemleri iin burada srkle brak (drag-drop) seeneinede
sahibiz.

Yaplan ekleme ilemleri sonrasnda Solution Explorer' da Resources isimli bir klasr aldn
grebiliriz. Kaynak olarak eklediimiz tm dosyalar bu klasr altna otomatik olarak tanacaktr.
rneimizde iki resim dosyasn kaynak olarak eklediimizde Solution Explorer grnts
aadakine benzer olacaktr.

www.bsenyurt.com Page 1466


Peki bizim komut satr aralar ile retmeye altmz resource dosyas nerededir? Bu dosya
Vs.Net 2005 tarafndan obj klasr altndaki debug klasrne otomatik olarak atlmaktadr.
rneimizi gz nne alrsak eer bu dosya CreatingUsingResources. Kaynaklar.
resources ismi ile oluturulacaktr. u anda resoruce dosyamz ierisinde yer alan kaynaklar exe
uzantl assembly ierisine dahil edilmitir. Buda, uygulamamzn exe dosyasn alp baka bir
adreste (rnein baka bir makinede) altracak olursak, assembly ierisine gmlen kaynaklarn
kullanlabilecei anlamna gelmektedir. Assembly ierisine gmlen kaynak dosyalar ele alabilmek
iin ResourceManager snfndan yararlanabiliriz. Bu amala rnek uygulamamza aadaki kod
parasn eklediimizi dnelim.

ResourceManager resManager;
resManager=new
ResourceManager("CreatingUsingResources.Kaynaklar",Assembly.GetExecutingAssembly());
pbImage.Image=(Bitmap)resManager.GetObject("Istanbul_1");
resManager.ReleaseAllResources();

ResourceManger snfna ait nesne rnei oluturulurken, ilk parametre olarak resource dosyann
adn veriyoruz. kinci parametre ise bu resource dosyann gmld assembly' n addr. Ki bu da
zaten uygulamann alt assembly' dr. Daha sonra ierideki resim dosyalarndan herhangibirini
okuyabilmek iin GetObject metodunu kullanyoruz. Nitekim okuyacamz veri string bazl bir
ierik deil binary formattaki bir resim dosyasdr. Bu nedenle okunan nesne Bitmap tipine ak bir
ekilde dntrlm sonrasnda ise PictureBox kontrolnn image isimli zelliine dorudan set
edilmitir. Bu kodu ieren rnek uygulamamz altrdmzda aadaki gibi bir sonu elde
ederiz. (zellikle uygulamaya ait exe dosyasn bulunduu yerden alp tek bana baka bir yere
kopyalayarak altrmanz neririm. Resmin baarl bir ekilde okunabildiini greceksiniz.)

Yukardaki rneklerimizde kullandmz Resources dosyalarn veya Resx dosyalarn kod tarafnda
okumak istediimiz takdirde, ResxResourceReader yada ResourceReader snflarndan
yararlanabiliriz. rnein aadaki kod paras ile alma zamannda resources dosyas ierisindeki
anahtar deerleri elde edebiliriz.

ResourceReader reader = new


ResourceReader("..\\..\\obj\\debug\\CreatingUsingResources.Kaynaklar.Resources");
IDictionaryEnumerator numarator = reader.GetEnumerator();

www.bsenyurt.com Page 1467


while (numarator.MoveNext())
{
listBox1.Items.Add(numarator.Key.ToString());
}

Aadaki kod paras ise yukarda yaplan ilemin aynsn resx uzantl kaynak dosya iin
gerekletirmektedir.

ResXResourceReader resxReader = new ResXResourceReader("..\\..\\Kaynaklar.resx");


IDictionaryEnumerator numarator2 = reader.GetEnumerator();
while (numarator2.MoveNext())
{
listBox1.Items.Add(numarator2.Key.ToString());
}

Her iki kod ierisinde yer alan GetEnumerator isimli metod gerie IDictionaryEnumaretor trnden
bir interface referans dndrmektedir. Geriye dnen bu referans zerinden, bilinen while
iterasyonunu kullanarak anahat-deer (key-value) iftlerini elde edebiliriz. Ancak dikkat edecek
olursanz bu kodlarda resx ve resources uzantl dosyalarn adresleri kullanlmtr. Buda sadece exe
dosyasnn var olduu bir durumda ilgili kodlarn almayaca anlamna gelmektedir. Dolaysyla
ResourceWriter, ResourceReader, ResxResourceWriter, ResxResourceReader gibi snflar ounlukla
development srelerinde yada yaymlanan (publishing) assembly' n yannda resx ve resources
dosyalarnn tanmas halinde kullanlmas anlaml olan tiplerdir. Dier hallerde assembly' a dahil
edilen kaynak ieriklerini okumak iin ResourceManager tipinin kullanlmas arttr. Gelitirdiimiz
rnek kod paralarnda ounlukla resim dosyalarn kullandk. Bununla birlikte string bazl verileri,
byte dizilerini, wav uzantl ses dosyalarnda kullanabilirsiniz. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Cross-Page Postback Paradigmas ( 04.08.2006 )


- Asp.Net 2
Deerli Okurlarm Merhabalar,

Asp.Net 2.0 ile gelen en nemli yeniliklerden biriside Cross-Page Postback mimarisidir. Cross-Page
Postback, bir sayfann tm ierii ile baka bir sayfaya doru gnderilebilmesini salar. Bunu bir
asp.net sayfasnn kendi zerine deilde, hedef gsterilen bir sayfaya doru gnderilmesi olarakta
dnebiliriz. Bylece hedef sayfa ierisinden, kaynak sayfadaki (yada kaynak sayfalardaki)
verilere eriebilme imkan salanm olunur. Bu ayn zamanda sayfalar arasnda veri tamann
etkili yollarndan birisi olarak, web uygulamalarndaki yerini almtr. Cross-Page Postback olduka
gl bir yenilik olmasna karn kullanrken dikkat edilmesi gereken baz hususlar vardr. Bu
makelemizde dikkat edilmesi gereken noktalar rnekler zerinden incelemeye alacaz.
Aadaki tabloda Cross-Page Postback ilemi srasnda dikkat etmemiz gereken noktalar maddeler
halinde zetlenmeye allmtr.

Cross-Page Post Back Kullanrken

Cross-Page Postback ilemini yapabilen web tabanl bileenler


1 sadece IButtonControl arayzn (interface) uygulam web kontrolleridir. Bu nedenle hedef

www.bsenyurt.com Page 1468


sayfada Null Reference kontrol mutlaka yaplmaldr.

Cross-Page Postback ilemi srasnda, kaynak sayfaya(sayfalara) ait referans(referanslar)


kullanlmak istendiinde bu sayfaya(sayfalara) ait nesne rnei (rnekleri) oluturulur.
2 Dolaysyla bu kaynak sayfann yaam dngsnde (Web Page Life Cycle) yer alan olay
metodlarnda almas ama grmezden gelinmesi anlamna gelir.

Kaynak sayfada tanml herhangibir zellie hedef sayfa ierisinden eriebilmek iin, kaynak
3 snfa ait bir nesne rneine ihtiya vardr.

Birden fazla sayfadan tek bir sayfaya doru Cross-Page Postback ilemi yaplabilir. Ancak bu
4 durumda hedef sayfaya hangi sayfadan gelindiinin anlalmas kaynak sayfa kontrollerinin
doru bir ekilde tespit edilebilmesi iin arttr.

Kaynak sayfa eer dorulama kontrolleri (validation controls) ieriyorsa ve istemci tarafl
kontrol scriptleri (zellikle java script' ler) altrlamyorsa yada kapalysa, hedef sayfaya
5 yinede gei yaplabilir. Bu kaynak sayfaya ait dorulama ilemlerinin komple atlanmas
anlamna gelir.

Dilerseniz bu maddeleri teker teker incelemeye alalm.

Madde 1:

Web kontrollerinden olan Button, LinkButton ve ImageButton bileenleri, IButtonControl' den


tremilerdir. Bu sebepten dolay PostBackUrl isimli zellikleri vardr. PostBackUrl bildiiniz gibi,
Cross-Page Postback srasnda hedef olarak gidilecek url bilgisini iermektedir. Tipik olarak hedef
sayfa ierisinden kaynak sayfaya ait herhangibir kontroln ieriini almak (rnein kaynak
sayfadaki bir TextBox ierisine girilen bir deeri) iin FindControl metodu kullanlr. Lakin hedef
sayfaya gemek iin HyperLink yada Response.Redirect metodu gibi tekniklerde kullanlabilir. Bu
ise Cross-Page Postback olmamas anlamna gelmektedir.

Madde 1' i daha net anlayabilmek iin basit bir rnek gelitirelim. Kaynak1.aspx ve Hedef.aspx
isimli iki web sayfamz olduunu dnelim. Kaynak1.aspx sayfasndan, Hedef.aspx sayfasna gei
yapmak iin iki farkl teknik kullanyoruz. Birincisinde PostBackUrl zellikleri set edilmi olan
Button, LinkButton ve ImageButton kontrollerini ele alyoruz. Bu kontrollerin PostBackUrl
zelliklerine ilgili deerleri set ederekten Cross-Page Postback ilemini gerekletiriyoruz. Dier
seeneimizde ise Response.Redirect metodu ve HyperLink kontroln kullanarak hedef sayfaya bir
gei yapmaktayz.

Kaynak1.aspx;

www.bsenyurt.com Page 1469


<%@ Page Language="C#" AutoEventWireup="true" CodeFile="Kaynak1.aspx.cs"
Inherits="Kaynak1" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<strong>Gnderilecek Bilgi <br /></strong>
<asp:TextBox ID="txtInfo" runat="server"></asp:TextBox><br /><br />
<table border="1">
<tr>
<td><strong><span style="color: green; font-family: Verdana">PostBackUrl
ile</span></strong></td>
</tr>
<tr>
<td ><asp:Button ID="btnGoTarget"
runat="server" PostBackUrl="~/Hedef.aspx" Text="Hedefe Git" /><br/><br/>
<asp:LinkButton ID="lnkGoTarget"
runat="server" PostBackUrl="~/Hedef.aspx">Hedefe Git</asp:LinkButton><br /><br />
<asp:ImageButton ID="imbGoTarget" runat="server" Height="64px"
ImageAlign="Middle" ImageUrl="~/Beaver.bmp" PostBackUrl="~/Hedef.aspx" Width="64px"
/></td>
</tr>
<tr>
<td><strong><span style="color: red; font-family: Verdana">PostBackUrl
olmadan</span></strong></td>
</tr>
<tr>
<td><asp:Button ID="btnGoTarget2" runat="server" OnClick="btnGoTarget2_Click"
Text="Hedefe Git"/><br/><br />

www.bsenyurt.com Page 1470


<asp:HyperLink ID="hlGoTarget" runat="server" NavigateUrl="~/Hedef.aspx">Hedefe
Git</asp:HyperLink></td>
</tr>
</table>
</div>
</form>
</body>
</html>

Kaynak1.aspx.cs;

protected void btnGoTarget2_Click(object sender, EventArgs e)


{
Response.Redirect("~/Hedef.aspx");
}

Hedef.aspx.cs;

protected void Page_Load(object sender, EventArgs e)


{
Response.Write(((TextBox)PreviousPage.FindControl("txtInfo")).Text);
}

Uygulamay altrdktan sonra, HyperLink veya PostBackUrl zellii set edilmemi olan
kontrollerimizden herhangibiri zerinden hedef sayfaya gei yaptmzda aadaki hata mesaj ile
karlarz.

Bu hata mesajnn sebebi son derece aktr. Nitekim HyperLink kontrol yada Response.Redirect
metodu ile hedef sayfaya gei yapldndan PreviousPage referans null olarak gelmektedir. Yani
ortada bir Cross-Page Postback ilemi sz konusu deildir. Bu durum, hedef sayfaya ait Url
bilgisinin dorudan talep edilmesi halinde de geerlidir. yleyse, ilgili yerlerde PreviousPage tipinin
null olup olmad kontrol edilmeli ve ilemler buna gre yaplmaldr. zm olarak Hedef.aspx
sayfasnda aadaki kontrol yapmak yeterli olacaktr.

if (PreviousPage != null)
Response.Write(((TextBox)PreviousPage.FindControl("txtInfo")).Text);

Madde 2:

Bir Cross-Page Postback ilemi meydana geldiinde, hedef sayfada PreviousPage referansnn ilk
kullanld yer kaynak sayfaya ait bir nesne rneinin oluturulmasna yol aacaktr. Dolaysyla
kaynak sayfann yaam dngs ierisinde yer alan olaylardan, gelitirici tarafndan kodlanm

www.bsenyurt.com Page 1471


olanlar alacaktr. Ancak bu kodlar ve sonular grmezden gelinecektir. Bunu daha iyi
anlayabilmek iin Kaynak1.aspx.cs dosyasna aadaki eklemeleri yapalm.

private void Page_Init(object sender, EventArgs e)


{
Response.Write("Init metodu...");
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Write("Page Load metodu alyor...");
}
protected void btnGoTarget_Click(object sender, EventArgs e)
{
Response.Write("Go Target dmesine basld...");
}
private void Page_PreRender(object sender, System.EventArgs e)
{
Response.Write("PreRender alyor...");
}
private void Page_Unload(object sender, System.EventArgs e)
{
}

Kodu bu aamasndayken debug ederek izlersek aadaki ekilde anlatlmaya allan yolu
izlediini grebiliriz.

Grld gibi, kaynak sayfa yklendikten sonra PostBackUrl zellii set edilmi herhangibir
kontrole baslmas halinde kod ilk olarak Hedef sayfann yaam dngsnden iletilmeye
balanacaktr. Bu dng Hedef sayfaya aittir. Dolaysyla bir asp.net web sayfas iin geerli olan
yaam dngsndeki ileyi geerlidir. Ne varki, hedef sayfadaPreviousPage referans ile kaynak
sayfaya yaplacak ilk talepte, sunucu tarafnda Kaynak sayfaya ait nesne rneinin oluturulmas

www.bsenyurt.com Page 1472


ilemleri balayacaktr. Buda doal olarak Kaynak sayfann yaam dngsnn tekrar
tetiklenmesi, Init, Load, Click, PreRender ve Unload gibi olaylarn yeniden almas anlamna
gelmektedir. Bu sadece kaynak sayfaya ait nesne rneinin elde edilmesi srasnda olmas beklenen
bir prosedrdr. in ilgin yan, kaynak sayfaya ait nesne rneklenirken, buradaki kodlarn
grmezden gelinmesidir.

Bu maddeyi daha net anlayabilmek iin klasik bir Asp.Net sayfasnn yaam dngsn bilmekte
fayda vardr. Yukardaki ekil bunu gstermektedir. Burada grlen changed ve click olaylar
ounlukla Web kontrollerine ait olaylardr. Bir sayfa ilk yklendiinde Change ve Click olaylar
devreye girmez. Genellikle bir Asp.Net sayfas zerinde herhangibir ekilde PostBack ilemi
yapldnda var olan yaam dngs ierisinde srasyla Changed ve Click olaylarda eklenir.

Madde 3:

Baz durumlarda kaynak sayfadaki herhangibir public yeye, hedef sayfa zerinden erimek
isteyebiliriz. Byle bir durumda eer herhangibir ey belirtmessek PreviousPage tipi ilgili yelere
dorudan eriilmesi mmkn deildir. Bu ounlukla kaynak sayfaya ait snf ierisinde bir zellik
(property) tanmland zaman rastlanacak bir durumdur. lgili zellie eriebilmek iin ncelikle
kaynak sayfaya ait nesne rneinin hedef sayfada kullanlabilir olmas gerekmektedir. Durumu
daha iyi anlayabilmek iin ilk olarak kaynak sayfa snfmza bir zellik yazacaz. Daha sonra ise
PreviousPage yardmyla bu zellie hedef sayfa zerinden erimeye alacaz. rnei gelitirmek
iin Kaynak1.aspx.cs kodlarn aadaki gibi deitirelim.

Kaynak1.aspx.cs iin ek;

private DateTime _istekZamani;

public DateTime IstekZamani


{
get { return _istekZamani; }
}

Hedef.aspx.cs sayfasna ait Load metodu ierisinde IstekZamani isimli zellie erimeye
altmzda tasarm zamannda aadaki hata mesaj ile karlarz.

Sorun Kaynak1.aspx sayfasna ait arka plan snfnn nesne rneinin doru bir ekilde ele
alnmayndan kaynaklanmaktadr. zm olarak hedef sayfaya, kaynak sayfann tipini
sylememiz yeterli olacaktr. Bunun iin Hedef.aspx sayfasnda Page direktifinin hemen altna
aadaki gibi PreviousPageType direktifini eklememiz gerekmektedir.

www.bsenyurt.com Page 1473


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

Bu haliyle uygulamay derlediimizde hi bir sorunla karlamadan IstekZamani isimli zellie


eriebildiimizi grrz.

Madde 4 :

Cross-Page Postback ilemi zellikle sayfalar arasnda veri tama ilemleri arasnda nemli bir yere
sahiptir. Baz durumlarda hedef sayfaya birden fazla sayfadan Cross-Page Postback ilemi
gerekletirebiliriz. Ancak byle bir senaryoda, hedef sayfaya hangi tipten gelindiinin anlalmas
art olacaktr.

Senaryoyu daha net anlayabilmek iin rnek uygulamamza Kaynak2.aspx isimli yeni bir web
sayfas daha ekliyoruz. Bu sayfa da Hedef.aspx sayfasna doru post ilemini gerekletirebilecek
button kontrolleri iermektedir.

Kaynak2.aspx;

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


Inherits="Kaynak2" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<strong>Gnderilecek Bilgi<br /></strong>
<asp:TextBox ID="txtInfo2" runat="server"></asp:TextBox><br /><br />
<table border="1">
<tr>

www.bsenyurt.com Page 1474


<td><strong><span style="color: green; font-family: Verdana">PostBackUrl
ile</span></strong></td>
</tr>
<tr>
<td><asp:Button ID="btnGoTarget" runat="server"
OnClick="btnGoTarget_Click" PostBackUrl="~/Hedef.aspx"
Text="Hedefe Git" /></td>
</tr>
</table>
</div>
</form>
</body>
</html>

Bu sefer Kaynak2.aspx sayfasndaki TextBox kontrolnn adn Kaynak1.aspx' den farkl olarak
txtInfo2 olarak deitirdik. imdi uygulamamz test ettiimizde Kontrol1.aspx' den yaplan
geilerde bir problem olmadn ancak Kaynak2.aspx' ten yaplan geilerde aadaki istisna
mesajn aldmz grrz.

Bu son derece doaldr. Nitekim PreviousPage referansnn iaret ettii sayfada txtInfo isimli bir
kontrol bulunmamaktadr. Dahas bizim PreviousPage tipimiz u anda hangi sayfadan buraya
gelindiini de bilmemektedir. Madde 3 ' te yaptmz gibi PreviousPageType direktifini
kullanmay tercih edebiliriz. Ancak bu direktif sadece bir kez tanmlanabilmektedir. Dolaysyla
aadaki gibi bir kullanm geersizdir.

yleyse zm ? zm olarak, Reference direktifi kullanlabilir.

<%@ Reference Page="~/Kaynak1.aspx" %>


<%@ Reference Page="~/Kaynak2.aspx" %>

www.bsenyurt.com Page 1475


Elbette kod tarafnda da yaplmas gereken bir takm deiiklikler vardr. Reference direktifleri
sayesinde Hedef sayfada kullanlabilecek referans tiplerini bildirmi oluruz. Bu durumda Hedef
sayfada aadaki deiiklikleri yapmamz yeterli olacaktr.

if (PreviousPage != null)
{
if (PreviousPage is Kaynak1)
{
Kaynak1 kyn1 = PreviousPage as Kaynak1;
Response.Write(((TextBox)kyn1.FindControl("txtInfo")).Text);
}
if (PreviousPage is Kaynak2)
{
Kaynak2 kyn2 = PreviousPage as Kaynak2;
Response.Write(((TextBox)kyn2.FindControl("txtInfo2")).Text);
}
}
else
Response.Write("Cross-Page Postback ilemi yok...");

Bu durumda uygulama sorunsuz olarak alacaktr.

Madde 5:

Gelelim bir dier nemli konuya. Dorulama (Validation) ilemleri bildiiniz gibi istemci tarafndan
balar ve sunucu tarafnda tekrar edilir. Asp.Net 2.0' n kulland Validation Kontrolleri, hem
istemci tarafl script' leri hemde sunucu tarafl kodlar otomatik olarak hazrlamaktadr. Istemcilerin
script desteinin olmamas ihtimaline karlkta sunucu tarafnda mutlaka ve mutlaka dorulama
ilemleri yaplr. Dolaysla istemci tarafnda dorulama ilemleri baarl olsa dahi sunucu tarafnda
bu kontroller tekrar yaplacaktr. Ancak istemci tarafnda script desteinin olmamas halinde Cross-
Page postback ileminde yaanan bir problem vardr. Eer istemci taraf script destei kapal ise
kaynak sayfadaki dorulama ilemleri Cross-Page ilemi nedeni ile atlanmaktadr. Dilerseniz rnek
zerinden devam ederek konuyu daha net anlamaya alalm. Bu amala aadaki ekran
grntsne sahip Kaynak3.aspx isimli bir web sayfas oluturuyoruz.

Kaynak3.aspx;

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


Inherits="Kaynak3" %>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>

www.bsenyurt.com Page 1476


</head>
<body>
<form id="form1" runat="server">
<div>
<strong>
Email adresinizi girin : </strong>
<br />
<asp:TextBox ID="txtEmail" runat="server"></asp:TextBox>
<br />
<br />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
runat="server" ControlToValidate="txtEmail" ErrorMessage="Email
girmelisiniz." EnableClientScript="False"></asp:RequiredFieldValidator><br />
<asp:RegularExpressionValidator ID="RegularExpressionValidator1"
runat="server" ControlToValidate="txtEmail" ErrorMessage="Geersiz mail
adresi" ValidationExpression="\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-
.]\w+)*" EnableClientScript="False"></asp:RegularExpressionValidator><br />
<br />
<asp:Button ID="btnSend" runat="server"
Text="Hedef" PostBackUrl="~/Hedef2.aspx" /></div>
</form>
</body>
</html>

Dikkat ederseniz dorulama kontrollerinin script tarafnda JavaScript kodu


retmesini EnableClientScript zelliklerine false deerini atayarak nledik. Bu elbette teorimizin
ispatlanmas iin konulmu kk bir deiiklik. Senaryomuz gerei Hedef2.aspx isimli bir sayfaya
doru hareket ediyoruz. Eer textBox kontrolnn ieriini bo brakrsak veya geersiz bir mail
adresi yazarsak normal artlarda sayfann Cross-Page Postback ilemini gerekletirmemesini
bekleyebiliriz. Ne yazkki byle olmayacaktr. Sonu aadaki ekran grntsnde olduu gibidir.

Video' dan greceiniz gibi hi bir dorulama ilemi almadan hedef sayfaya geilebilmektedir. Bu
durumu nlemek iin kaynak sayfadan hedef sayfaya hareket etmeden nce Page snfnn IsValid
zellii kullanlarak dorulama ilemlerini yaptrmaya alabiliriz. Ancak Cross-Page Postback
srecinde meydana gelen yaam dngleri nedeni ile yine kontroller atlanacak ve hedef sayfaya
gidilecektir. zm olarak hedef sayfa ierisinde, kaynak sayfann geerli olup olmad kontrol
edilebilir ve gerekirse kullanc kaynak sayfaya geri gnderilebilir. Bunun iin Hedef2.aspx.cs
ierisindeki Load metodunu aadaki gibi kodlamak yeterli olacaktr.

www.bsenyurt.com Page 1477


protected void Page_Load(object sender, EventArgs e)
{
if (PreviousPage != null)
{
if (!PreviousPage.IsValid)
{
Response.Write("nceki Sayfada dorulanmam bilgiler var...");
}
}
}
protected void btnBack_Click(object sender, EventArgs e)
{
Response.Redirect("~/Kaynak3.aspx");
}

imdi tekrardan uygulamamz altralm.

Eminimki dikkatli gzlerden kamayacaktr. Kaynak sayfaya geri dndmzde TextBox


kontrolnn ierii boalmtr. Dahas alma esnasnda hi gremediimiz dorulama kontrolne
ait hata mesaj hi kmamtr. Oysaki normal bir PostBack ileminde (yani sayfann kendi zerine
gnderilmesinde) validation kontrolleri alacak, ilgili hata mesajlar grnecek ve TextBox gibi
dier baz kontrollerinde ierii kaybolmayacaktr. Oysaki Cross-Page Postback ilemi srasnda bu
avantaj kaybedilmektedir.

zm olarak kaynak sayfadaki verilerin hedef sayfaya bir ekilde tanmas ve dn ilemi
srasnda da ilgili kontrollere aktarlmas dnlebilir. Bu amala zelliklerden faydalanabiliriz.
Daha etkili bir zm olarak kaynak sayfa hedef sayfaya gitmeden dorulama kontrolleri yaplmas
yoluna gibilebilir. Ancak yukardaki madde 2' de grdmz gibi sayfalarn yaam dngsnden
dolay kaynak sayfadaki bu kodlar gz ard edilecektir. Dier taraftan her web sayfas bu rnekte
olduu gibi bir tek TextBox kontrolnde ibaret deildir. ok daha fazla kontroln ve dorulama
ileminin olduu bir sayfada sayfalar aras kontrol ieriklerini tayarak elde edilmeye allacak bir
zm can skc olabilir. Yinede, kaynak sayfaya tekrar geri dnldnde eer kontrollerin
ieriklerini yeniden doldurabilirsek sayfaya yeniden bir dorulama ilemi yaptrabilir ve gerekli
validator kontrollerinin hata mesajlarnn kmasn salayabiliriz. Bu durumu daha net
anlayabilmek iin kaynak3.aspx.cs ve hedef2.aspx.cs kodlarn aadaki gibi deitirelim. (Hedef2
ierisinde Kaynak3 referansn elde edebilmek iin PreviousPageType direktifi kullanlmtr.)

Hedef2.aspx.cs;

www.bsenyurt.com Page 1478


protected void Page_Load(object sender, EventArgs e)
{
if (PreviousPage != null)
{
if (!PreviousPage.IsValid)
{
Kaynak3 kyn3 = PreviousPage as Kaynak3;
Response.Redirect("~/Kaynak3.aspx?HatalarVar=1&email="+kyn3.Email);
}
}
}

Kaynak3.aspx.cs;

public string Email


{
get { return txtEmail.Text; }
}

protected void Page_Load(object sender, EventArgs e)


{
if (Request.QueryString["HatalarVar"] != null)
{
txtEmail.Text = Request.QueryString["email"].ToString();
Page.Validate();
}
}

Kod u ekilde almaktadr. Kullanc kaynak sayfada hatal bir veri girii yaptnda hedef sayfaya
yinede gidilir ve PreviousPage tipi zerinden hedef sayfa ierisinde dorulama ilemi yaplr. Eer
dorulama (Validation) baarsz ise, Kaynak3 ierisinde tanml EMail isimli zellik yardmyla
kaynak sayfadakiTextBox ierii alnr ve QueryString' e eklenerek geri gnderilir. Kaynak sayfann
Load metodunda ilgili QueryString parametreleri yakalanr ve ierik alnarak TextBox kontrolne
atanr. Son olarak kaynak sayfa ierisinde Validate metodu altrlarak dorulama ilemlerinin
yeniden yaplmas salanr ve bu sayede Validator kontrolne ait uygun hata mesajda ekranda
grnr. Sonucu grmek iin rneimizi tekrar altralm.

www.bsenyurt.com Page 1479


Yukardaki videodan grdnz gibi, client side validation script' ler kapalda olsa, Cross-Page
postback olduktan sonra kaynak sayfaya dnldnde hem kontroln eski ierii hemde validator
bileenin hata mesaj gsterilebilmektedir. Bu her ne kadar iyi bir zm gibi grnsede, sayfadaki
kontrol saysnn ve ierik uzunluklarnn ok daha fazla olduu hallerde bizi QueryString yerine
baka nesnelerden yararlanmaya zorlayacaktr. Bu anlamda rnein Session nesnesi ele alnabilir.
Bylece geldik bir makalemizin daha sonuna. Bu makalemizde Cross-Page Postback kullanrken
dikkat etmemiz gereken noktalar incelemeye altk. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Xml Web Servislerinde Etkili Caching Kullanm


( 28.07.2006 ) - Web Servisleri
Deerli Okurlarm Merhabalar,

n-bellekleme (Caching) ilemleri web uygulamalar iin ne kadar nemli ise Xml Web Servisleri
iinde ayn durum geerlidir. n-bellekleme sistemi sayesinde web uygulamalarnn kullancya
cevap verme srelerinin ksaltlmas hedeflenmitir. Bu da doal olarak uygulamann performansn
arttrc bir etkendir. Kaldki istekler nbellekten (cache) karland iin, arka tarafta yaplan pek
ok sre atlanmaktadr. Dolaysyla database ilemleri gibi maliyeti yksek olan srelerin belirli
kriterlere gre altrlmas ve kullancnn istedii sonularn en hzl ekilde verilebilmesi n-
bellekleme sisteminin getirilerinden sadece birisidir. Web servisleride, web uygulamalar gibi 80
numaral port zerinden hizmet verdiklerinden n-bellekleme yetilerine sahiptir. Web
uygulamarnda kullanlan n-bellekleme mant ile web servislerinde kullanlan birbirlerine olduka
yakndr. Ancak bir takm farkllklarda mevcuttur.

Bildiiniz gibi, web uygulamalarnda n-bellekleme (caching) sistemi Output Caching ve Data
Caching olmak zere iki ana kategoriye ayrlmaktadr. Bir web uygulamasnda Output Caching
sayfa baznda veya user control baznda kullanlabilir. Bylece bir web sayfasnn tamamnn yada
onun kk bir parasnn n-bellekte tutulmas salanabilir. Oysaki ayn durum Web Servislerinde
biraz daha farkldr. Nitekim, web servislerinin kullanc ile etkileimde olan bir arayz
bulunmamaktadr. Buda kontrol veya sayfa baznda n-bellekleme ileminin yaplamayaca
anlamna gelmektedir. Bir web servisi sz konusu olduunda n bellee (cache) alnabilecek olan
ierik bu servise ait metodlarn dndrecei sonu kmelerinden baka bir ey olmayacaktr.
Dolaysla web servislerinde metod baznda n-belleklemenin yaplabileceini syleyebiliriz. Bunun
dnda, web uygulamlarnda ska kullanlan Data Caching teknii web servisleri iinde geerlidir.
Kaldki Data Caching tekniinde kesin yaam sresi (absolute expire time), hareketli yaam
sresi (floating expire time), dosya veya tablo bamll (cache dependency) gibi
seeneklerde mevcuttur. Bu seenekler bir web servisi ierisinde etkin bir ekilde uygulandnda
kullanclara hzl cevap verebilmenin dnda, var olan sistem kaynaklarnda daha etkili
kullanabilme olanaklarna sahip oluruz. Bir web metodun dndrecei sonu kmesini n-bellee
tamak iin yaplmas gereken, WebMethod niteliini aadaki gibi CacheDuration zellii ile
kullanmaktr.

[WebMethod(CacheDuration = 180)]

www.bsenyurt.com Page 1480


Bu niteliin uyguland web metodun dndrecei sonular 180 saniye (3 dakika) sreyle n
bellekte tutulacaktr. Bu olduka kullanl bir zelliktir. Ancak asl dikkat edilmesi gereken nokta,
parametre baml dnlerin sz konusu olduu web metodlarnda ortaya kmaktadr. Nitekim
web metodlarnda parametreler sz konusu olduundan parametre deerleri iin ayr ayr n-
bellekleme ilemleri sz konusu olmaktadr. rnein, Sql Server 2005 zerinde yer alan rnek
AdventureWorks veritabanndanki Product tablosunun verilerini, ProductSubCategoryID deerine
gre farkl veri kmeleri eklinde sunabilecek bir web metodumuz olduunu dnelim. Normal bir
web uygulamasnda bu tip parametrik fonksiyonellikler sz konusu olduunda
genellikle OutputCache direktifinin VaryByParam niteliinden faydalanlr. Oysaki web servisi
metodlarnda bu tarz bir kullanm sz konusu deildir. Web servisleri parametre baml n-
bellekleme sz konusu olduunda daha aklc bir yaklam sergilyerek, metodun parametresine
(parametrelerine) gre farkl n-bellek alanlar oluturur. Bylece CacheDuration nitelii ile
belirtilen n-bellekleme sreleri ierisinde ayn parametrik deeri talep eden kulllanclar iin n-
bellekte tutulan o parametreye ait grntler cevap olarak istemcilere gnderilir. Bunu daha iyi
anlayabilmek iin aadaki kod parasn gz nne alalm.

[WebMethod(Description = "Alt kategoriye gre rnler", CacheDuration = 180)]


public DataSet GetProductsBySubCategory(int subCatId)
{
using (SqlConnection con = new SqlConnection("data
source=manchester;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd=new SqlCommand("Select
ProductID,Name,ListPrice,Size,StandardCost,ProductSubCategoryID From Production.Product
Where ProductSubCategoryID=@SubCatId",con);
cmd.Parameters.AddWithValue("@SubCatId",subCatId);
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
return ds;
}
}

Bu rnek web metodu, parametre olarak Product tablosundaki ProductSubCategoryID alan iin
kullanlacak bir parametre almaktadr. Talep edilen ieriin n bellekte tutulma sresi 180 saniye
(3 dakika) olarak belirtilmitir. imdi bu metoda belirli aralklar ile 4 farkl talep geldiini
dnelim. lk ve ikinci taleplerde srasyla subCatId parametresine 1 ve 5 deerlerinin aktarldn
dnelim. Yani iki farkl kullanc farkl zamanlarda belirtilen kategorilerdeki rnleri ekmek
istesin. lk talep sonrasnda, yukardaki web metodunda yer alan kodlar 1 deeri iin
altrlacaktr. Yani SqlConnection balants alacak, ilgili SqlCommand oluturulup bir
SqlDataAdapter yardmyla sonu kmesi bir DataSet nesnesine aktarlacak ve geriye dndrlerek
kullancya cevap verilecektir. te bu andan itibaren oluturulan sonu kmesi n belleede atlr
ve 180 saniye sreyle burada tutulur. Dolaysyla ayn subCatId deeri iin bu 180 saniyelik zaman
dilimi ierisinde gelecek olan herhanbir talep, yukardaki kodlar altrlmadan n-bellekte tutulan
veri ieriinden dndrlecektir. kinci ve farkl bir subCatId deeri iin gelen talep iinde ayn
sre sz konusu olacaktr ve n-bellekte ayr bir alan alarak ve CacheDuration sresi ierisinde
gelen taleplerin cevaplar buradan karlanacaktr. Aadaki izelgede bir zaman dilimi ierisinde iki
farkl subCatId iin gelen taleplerin n-bellekleme sistemince nasl ele alnaca gsterilmeye
allmtr.

www.bsenyurt.com Page 1481


zellikle parametre baml n-bellekleme ilemlerinde web servisleri iin dikkat edilmesi gereken
bir nokta vardr. Web servisi isteimiz dnda parametre baml n-bellekleme yapmaktadr. Bu
otomatik geliim zaman zaman iyi sonular versede baz durumlarda kullanlmamaldr. Otomatik
karar sistemi zellikle verinin ok yksek boyutlara erimedii hallerde olduka faydal bir
yntemdir. Ancak veri kmesinin boyutunun byk olmas, n-bellekte tutulan veri kmelerininde,
gelen saysz talep sonucu bellei inanlmaz derecede iirecei anlamna gelir. Bellekteki bu art
bir sre sonra her nekadar fiziki disk zerinden karlanabilecek olsada, performans olumsuz
etkiliyen ve sistem kaynaklarn tketen bir etkendir. Byle bir durumda n-bellekleme sisteminin
avantaj kaybedilip dezavantaja dnebilir. Sonu itibariye bir orta yolda hareket etmek ok daha
mantkl olabilir. Bu orta yol zellike web servislerinde yukardaki gibi parametreye baml sonu
kmeleri sz konusu olduunda ele alnan bir desen (pattern) iermektedir. Bu desene gre,
parametreye bal sonu kmelerinin ekildii asl veri seti n-bellekte tutulur. Kullancnn talepte
bulunduu veri ierii ise, n-bellekte tutulan bu ortak veri setinden ayrtrlarak ekilir. Bu, n-
bellekleme kapasitesini daha etkin kullanabilmemizi salarken, kullancnn isteklerini birazda olsa
hzl karlayabilecek bir model oluturabilmemizi salar. Aadaki ekil bu modeli zetlemeye
almaktadr.

www.bsenyurt.com Page 1482


Mavi izgiler 5 numaral ID deeri iin gelen ilk talepte yaplan ilemleri gstermektedir. Tm
Products seti veritabanndan ekilerek n-bellee atlr. Sonrasnda ise n-bellekteki veri seti
ierisinden, ProductSubCategoryID deeri 5 olan satrlar ayrtrlarak Client 1 isimli istemciye
gnderilir. Ayn ProductSubCategoryID deeri iin gelecek ikinci talepte ise artk n-bellekte
tutulmakta olan veri seti ierisinden ayrtrma ilemi yaplacaktr. Database' e tekrar gidilip veri
ekme ilemi gerekletirilmemektedir. Bu elbette veri setinin n-bellekte tutulduu sre ierisinde
bir talep geldiinde geerlidir. Aksi durumda yine veritabanndan ver ekme ve n-bellee alma
ilemi gerekletirilecektir.

Sz geen modelde Data Caching sistemi etkin olarak kullanlmaktadr. imdi yukardaki rnek
senaryomuzu bu modele gre yazmaya alalm. Hereyden nce Product tablosunun ieriini ilk
gelen talepten sonra belirli bir sre n bellekte tutacak bir metod yazmamz gerekiyor. Bu metod
web servisi ierisindeki dier metodlara hizmet vereceinden private olarak tanmlanabilir. Metodun
ierisinde, web servisindeki ilgili metoda(metodlara) gelen talepler iin n bellekte Product
tablosuna ait bir DataSet nesnesinin tutulup tutulmadna bakacaz. Bu kontrol ilemi
iin Cache snfndan yararlanabiliriz. Eer DataSet nesnemiz n bellekte ise, web metoduna gelen
parametre baml talep buradan karlanacak. Aksine ilgili veri seti n bellekte deil ise, nce
oluturulacak ardndan n-bellee atlacak ve son olarak yine ilgili web metoduna ilenmesi iin
devredilecek. Aadaki metodumuz bu ilemler iin tasarlanmtr.

private DataSet GetProducts()


{
if (Context.Cache["Products"] != null)
{
return (DataSet)Context.Cache["Products"];
}
else
{
SqlDataAdapter da = new SqlDataAdapter("Select

www.bsenyurt.com Page 1483


ProductID,Name,ListPrice,Size,StandardCost,ProductSubCategoryID From Production.Product",
"data source=manchester;database=AdventureWorks;integrated security=SSPI");
DataSet ds = new DataSet();
da.Fill(ds);
Context.Cache.Insert("Products", ds, null, DateTime.Now.AddMinutes(5),
TimeSpan.Zero);
return ds;
}
}

Burada Data Caching yaparken Absolute Time tekniini setik. Yani Products isimli, DataSet tayan
Cache nesnemiz oluturulup n bellee atldktan sonra 5 dakika sreyle burada tutulacaktr.
Elbette sahip olunan verinin ieriinin ne kadar sk deitiine gre bu sre gelitirici tarafndan
uzatlabilir yada ksaltlabilir. rnein ok sk deimeyen lke - ehir - le gibi bir ierik sunan
verilerde Cache sresi mmkn olduunca uzatlabilir.

Cache nesnesini bir web servisi metodu ierisinde kullanabilmek iin gncel talepleri tayan http
ieriini (HttpContext) ele almamz gerekmektedir. Bu ierii Context nesnesi yardmyla ele
alabiliriz. Products isimli, ieriinde DataSet nesne rnei tayan bir Cache nesnesinin tutulup
tutulmadn kontrol etmek iin ve eer byle bir nesne yok ise bunu oluturdukan sonra n-
bellee Cache snf yardmyla ekleyebilmek iin Context snfndan yararlanyoruz. Gelelim
istemcilere hizmete verecek olan parametre baml metodumuza. Bu metodun ieriinide
aadaki gibi tasarlayabiliriz.

[WebMethod(Description = "Alt kategoriye gre rnler")]


public DataSet GetProductsBySubCategory(int subCatId)
{
DataSet dsResult = GetProducts().Copy();
foreach (DataRow currRow in dsResult.Tables[0].Rows)
{
if ((currRow["ProductSubCategoryID"].ToString() == "") ||
(currRow["ProductSubCategoryID"] == null) ||
(Convert.ToInt32(currRow ["ProductSubCategoryID"]) != subCatId))
currRow.Delete();
}
dsResult.AcceptChanges();
return dsResult;
}

Buradaki ana fikir n bellekte tutulan veri seti ierisinden, kullancnn talep ettii parametre
deerine gre oluacak yeni bir veri setini kullancya gndermektir. Bunun iin, n-bellekten gelen
DataSet yapsn bozmayacak ekilde ele alnmaktadr. Bu sebeptende ncelikle ilgili DataSet' in bir
kopyas Copy metodu ile kartlr. Sonrasnda elde edilen kopya ierisinde dolalmakta ve
ProductSubCategoryID deeri bo veya null olanlar ile gelen subCatId deerine eit olmayanlar 0
indisli DataTable ierisinden kartlmaktadr. Bylece kullancya istedii veri setini gndermi
oluruz. Yukardaki teknii kullandnz takdirde eer web servisini altrr ve
GetProductsBySubCategory metodunu yrtrseniz, uygulamay debug ederken metodun
altrlmas sonrasnda dnecek olan veri setinin sadece parametre olarak gelen kategori bilgilerini
ierdiini kolayca tespit edebilirsiniz.

www.bsenyurt.com Page 1484


Peki bu ilemlerin bize kazandrd avantalar nelerdir? Her eyden nce farkl parametre deerleri
iin n bellekte farkl veri seti grntleri oluturmaktan kurtulmu oluyoruz. Bu sayede n bellein
optimize ediliinde nemli bir kazancmz olmaktadr. Dier taraftan tm parametre baml talepler
n bellekteki ayn veri setini kullandndan, veri ayrtrma ilemi iin veritabanna gidi geliler de
azaltlmaktadr. Bu gidi gelilerin (round-trips) azalmas, web servisinin sql sunucusunu ok fazla
sre ile megul etmesinin nlenmesi anlamna gelmektedir. Bu makalemizde web servislerinde
uygulanan n bellekleme tekniine farkl bir adan bakmaya altk. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net 2.0 zerinde Xslt Kullanm ( 20.07.2006


) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Xml (eXtensible Markup Language - geniletilebilir iaretleme dili), farkl platformlar arasnda
kolayca bilgi tanmasna izin veren, veri kmelerini kendi kurallarmzla oluturmamz salayan
nemli standartlardan birisidir. Lakin zaman zaman Xml dkmanlarn okumak ok kolay
olmamaktadr. En azndan oluturulan Xml dkmanlarnda tutulan ierii, son kullancya farkl
ekillerde gstermek ihtiyacn duyabiliriz. te bu noktada, var olan Xml verisinin farkl bir formata
dntrlebiliyor olmas gerekmektedir. XSLT(eXtensible Stylesheet Language
Transformation) standard tam bu noktada devreye girmektedir. Xslt herhangibir Xml ieriini

www.bsenyurt.com Page 1485


farkl bir Xml, Html, Csv (Comma Seperated Values) veya Text formatna dntrme ilemi ile
ilgili materyalleri salayan bir iaretleme dilidir.

Bu sayede verileri sakladmz bir Xml ieriini son kullancya daha uygun formatlarda sunabilme
imkann kazanm oluruz. Bu zellikle web tabanl sistemlerde son derece nemlidir. Dntrme
ilemi srasnda sradan bir tarayc kullanlabilecei gibi, .Net Framework ierisinde yer alan
tiplerdende (types) faydalanlabilir. Yani Xslt ile arptrlm bir Xml ieriine basit bir tarayc ile
bakabilir yada bu arptrma ilemini ynetimli kod (managed code) zerinden .Net Framework
tiplerini kullanarak gerekletirebiliriz. Xslt kendi ierisinde XPath dilini kullanmaktadr. Bu sayede
kaynak Xml dkman ierisinde eletirme yaparak, dntrme ilemini uygulayaca paralar
kolayca bulabilir. Xslt sadece Xml ieriini farkl formatta gstermekle kalmaz dnm ilemi
srasnda aadaki tabloda belirtilen ilemlerinde yaplabilmesini salar.

Xslt Dntrme Operasyonunda Yaplabilecek Baz lemler

Sralama ilemleri uygulatabilmek (Sorting).

Filtreleme ilemleri.

Koullu ayrtrmalar (if ve choose kullanm).

Parametre kullanm sayesinde farkl dntrme ilemlerinin


salanabilmesi.

Xslt dkman ierisinde harici kullanc tanml fonksiyonlar


arabilmek.

Xslt dkman ierisinde script altrabilmek.

Xslt' nin yukarda saylanlar haricinde de sahip olduu pek ok yetenek vardr elbette. Ancak bunlar
makalemizin konusunu u an iin amaktadr. Biz bu makalemizde temel olarak Xslt' yi tanyacak
ve .Net Framework 2.0 iinde etkin bir ekilde nasl kullanabileceimizi grmeye alacaz. lk
olarak aadaki rnek xml dkmann ele alalm.

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


<Muzikler>

www.bsenyurt.com Page 1486


<Muzik ID="1">
<Soyleyen>Coldplay</Soyleyen>
<AlbumAdi>X and Y</AlbumAdi>
<CikisTarihi>2005</CikisTarihi>
<Fiyat>28</Fiyat>
<Tip>CD</Tip>
</Muzik>
<Muzik ID="2">
<Soyleyen>Depeche Mode</Soyleyen>
<AlbumAdi>Playing The Angel</AlbumAdi>
<CikisTarihi>2005</CikisTarihi>
<Fiyat>25</Fiyat>
<Tip>CD</Tip>
</Muzik>
.
.
.
<Muzikler>

MuzikDukkanim.xml isimli fiziki dosyada tutulan bu ierikte Muzikler isimli root node (ana boum)
altnda Muzik isimli child node' lar (alt boumlar) yer almaktadr. Muzik boumu ierisinde ID isimli
bir attribute (nitelik) ve Soyleyen, AlbumAdi, CikisTarihi, Fiyat, Tip isimli alt boumlar yer
almaktadr. Bu dkman herhangibir tarayc zerinde aarsak aadakine benzer bir ekran
grnts elde ederiz.

Grdnz gibi bu Xml ierii her ne kadar bir gelitirici (developer) iin anlamlda olsa, son
kullanc iin ayn eyi sylemek pek doru olmayacaktr. Bu ierii rnein bir Html kts haline
getirebiliriz. Bylece son kullanc iin daha okunabilir bir yap salam oluruz. Xslt kendi ierisinde
Html taklarna izin verdii iin retilecek ktnn grsel formatn istediimiz gibi ayarlayabiliriz.
Aadaki rnek Xslt ierii bu amala yazlmtr.

www.bsenyurt.com Page 1487


XstlForHtml.xsl dkman ierii;

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


<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<html>
<body>
<h1>Mzik Dkkanm</h1>
<table border="1" borderColor="Black" cellpadding="0" cellspacing="0">
<tr bgcolor="#FFCC66">
<th>ID</th>
<th>Syleyen</th>
<th>Albm Ad</th>
<th>k Tarihi</th>
<th>Sat Fiyat</th>
<th>Cd/Dvd/Kaset</th>
</tr>
<xsl:for-each select="Muzikler/Muzik">
<tr>
<td>
<xsl:value-of select="@ID"/>
</td>
<td>
<font size="2" color="Blue">
<xsl:value-of select="Soyleyen"/>
</font>
</td>
<td>
<b>
<xsl:value-of select="AlbumAdi"/>
</b>
</td>
<td align="right">
<xsl:value-of select="CikisTarihi"/>
</td>
<td>
<b>
<xsl:value-of select="Fiyat * 1.5"/> Ytl
</b>
</td>
<td>
<xsl:value-of select="Tip"/>
</td>
</tr>
</xsl:for-each>
</table>
</body>
</html>
</xsl:template>

www.bsenyurt.com Page 1488


</xsl:stylesheet>

Bir Xslt ierii ilk zamanlarda gelitiricilere korkutucu gelebilir. Ancak adm adm incelendiinde son
derece kolay ve anlalrdr. Xslt dkmanlar mutlaka stylesheet eleman ile balar ve biterler. Bu
elemanda Xslt dkmannn standardlarnda yer alan isim alan (namespace) ve versiyon numaras
(version number) gibi bilgiler yer alr. Dkmanmzn ieriinde yer alan en nemli ksmlardan
birisi <xsl:template match="/"> boumudur. Xslt dkmanlarnn, kaynak olarak gsterildii
xml dkman zerinde dntrme ilemi yapabilmesi iin burada bir ablon (template)
eletirilmesinde bulunmas gerekir. Bu eletirme ileminde ilgili kmeyi seebilmek iin XPath
ifadeleri kullanlr. Dikkat ederseniz template elemannda (element) match deeri / olarak
belirlenmitir. Bu, Xslt' yi uygulanan Xml dkmanndaki tm boumlarn (nodes) dntrme
ileminde ele alnacan belirtir. Dntrme ileminin hangi yelere, nasl uygulanaca ve /
ablonuna uyan paralarn ktda nasl gzkeceine dair gerekli format ayarlar
ise template elemanna ait boum ierisinde yaplmaktadr.

Xslt dkmanmzda yer alan bir dier nemli eleman (element) <xsl:for-each
select="Muzikler/Muzik"> boumunda geen for-each ' tir. for-each eleman sayesinde select
niteliinde (attribute) belirtilen kme zerinde ileri ynl hareket edebiliriz. Dikkat ederseniz select
niteliinin deeri Muzikler/Muzik olarak belirlenmitir. Bu da tipik bir XPath ifadesidir. for-each
eleman programlamada kullandmz foreach dngsnden farkszdr. Bu eleman sayesinde
Muzikler isimli ana boum (root node) ierisindeki tm Muzik alt boumlarn (child nodes)
dolaacak bir ifade elde etmi oluruz.

Dikkat ederseniz Xslt dkman ierisinde yer yer Html taklar gemektedir. Eer Html' e aina
iseniz, burada bir tablo oluturulduunu, balklarnn, arka plan renginin vb. belirlendiini
grebilirsiniz. Peki ilgili Html tablosunun satrlarnda (TR) yer alan stunlar (TD) ierisine gelecek
olan deerleri bir Xml dkman ierisinden nasl almaktayz? Yani Xml ieriindeki hangi alanlarn
nereye geleceini nasl belirtebiliriz? Bunun iin Xslt' nin value-of elemanndan yararlanmaktayz.
rnein, <xsl:value-of select="Tip"/> boumu, Xslt dkmannn uyguland Xml ieriinde
yer alan Muzikler/Muzik boumu(node) altndaki Tip isimli alt boumun (child nodes) ieriini
bulunduu yere yazdracak ilevsellii salamaktadr. Gelelim yazm olduumuz bu Xslt
dkmannn ilgili Xml ieriine nasl uygulanacana. Bunun iin xml dkmanmzn bana xsl-
stylesheet ilemci direktifini (processing directive) uygulamamz gerekmektedir.

Bu ilemin ardndan MuzikDukkanim.xml dosyasn herhangibir tarayc penceresinde aarsak


aadakine benzer bir kt elde ederiz.

www.bsenyurt.com Page 1489


Grld zere son kullanc iin ok fazla anlam ifade etmeyen bir Xml ierii, Xslt kullanlarak
ok daha dzenli ve okunabilir bir Html formatna dntrlmtr. Xslt dntrme ilemi
srasnda kullanabileceimiz baka fonksiyonelliklerde vardr. rnein, sonu olarak elde ettiimiz
kmede sralama ilemleri yaptrabilir veya eitli koullar uygulatabiliriz. rnein,
MuzikDukkanim.xml dosyasnn ieriinde AlbumAdi alanna gre tersten sralatma yapmak iin Xslt
dkmanmzda sort elemann aadaki gibi kullanmamz yeterli olacaktr.

<xsl:for-each select="Muzikler/Muzik">
<xsl:sort select="AlbumAdi" order="descending" data-type="text"/>

Sort eleman (element) select nitelii(attribute) ile hangi alana gre sralama yaplacan
belirtmektedir. order niteliinde srlamann ynn belirtiyoruz (ki buradadescending ile tersten
sralama yapacamz belirttik). data-type nitelii ise sralama kriteri iin ele alnacak veri tipini
belirtiyor. AlbumAdi alan string bazl bir ierie sahip olduundan sralamannda karakter bazl
olmas, bir baka deyile text tipinde olmas gerekiyor. Eer saysal bir sralama sz konusu ise
data-type deerini number olarak belirtmemiz gerekecektir. Bu deiikliklerden sonra xml
dkmanmz yeniden bir tarayc penceresinde aarsak aadakine benzer bir ekran grnts
elde ederiz.

www.bsenyurt.com Page 1490


Sralama dnda karlatrma ifadelerinide ele alabiliriz. Bunun iin ounlukla Xslt'
nin if yada choose elemanlarndan faydalanlr. If elemann zellikle filtreleme yaparken
kullanabiliriz. Bu eleman ierisine dahil edilen value-of elemanlar belirtilen koula uyuyorsa kt
olarak elde edilebilir. rnein Xml ieriimizde Tip alannn deeri DVD olanlar listelemek
istediimizi dnelim. Bu durumda Xslt dkmanmzda for-each eleman ierisinde yer alan
value-of elemanlarn if elemanna ait boumlar (nodes) arasna almamz gerekecektir.

<xsl:for-each select="Muzikler/Muzik">
<xsl:sort select="AlbumAdi" order="descending" data-type="text"/>
<xsl:if test="Tip='DVD'">
<tr>
<td><xsl:value-of select="@ID"/></td>
<td><font size="2" color="Blue"><xsl:value-of select="Soyleyen"/></font></td>
<td><b><xsl:value-of select="AlbumAdi"/></b></td>
<td align="right"><xsl:value-of select="CikisTarihi"/></td>
<td><b><xsl:value-of select="Fiyat * 1.5"/> Ytl</b></td>
<td><xsl:value-of select="Tip"/></td>
</tr>
</xsl:if>
</xsl:for-each>

www.bsenyurt.com Page 1491


Dikkat ederseniz Tip alannda DVD yazan elemanlar elde ettik. If eleman bunu gerekletirebilmek
iin test isimli niteliini kullanmaktadr. Elbette burada mantksal operatorleri kullanarak oklu
karlatrmalarda yapabiliriz. rnein tipi Dvd veya Cd olanlar elde etmek istediimizde if
elemann u ekilde kullanabiliriz.

<xsl:if test="Tip='DVD' or Tip='CD' ">

If dnda kullanlabilecek karlatrma komutlarndan biriside choose elemandr. Choose aslnda


swicth-case' e benzeyen bir yapdadr. rnein Xml ieriimizde Sat Fiyat 35 Ytl' den kk
olanlarn arka plan rengini yeil, 35 Ytl ile 55 Ytl arasnda olanlarn arka plan rengini mavi ve kalan
ksma ait arka plan renklerinide krmz yapmak istediimizi dnelim. stelik bu ilemde sadece
Dvd ve Cd tiplerini ele almak istediimizi varsayalm. Bu durumda Xslt ieriimizde aadaki
deiiklikleri yapmamz yeterli olacaktr.

<xsl:for-each select="Muzikler/Muzik">
<xsl:sort select="AlbumAdi" order="descending" data-type="text"/>
<xsl:if test="Tip='DVD' or Tip='CD' ">
<tr>
<td><xsl:value-of select="@ID"/></td>
<td><font size="2" color="Blue"><xsl:value-of select="Soyleyen"/></font></td>
<td><b><xsl:value-of select="AlbumAdi"/></b></td>
<td align="right"><xsl:value-of select="CikisTarihi"/></td>
<xsl:choose>
<xsl:when test="Fiyat &gt;35 and Fiyat &lt;55">
<td bgColor="Blue"><font color="White" size="3"><b><xsl:value-of
select="Fiyat"/> ytl</b></font></td>
</xsl:when>
<xsl:when test="Fiyat &lt;35">
<td bgColor="Green"><font color="White" size="3"><b><xsl:value-of
select="Fiyat"/> ytl</b></font></td>
</xsl:when>
<xsl:otherwise>
<td bgColor="Red"><font color="White" size="3"><b><xsl:value-of
select="Fiyat"/> ytl</b></font></td>
</xsl:otherwise>
</xsl:choose>
<td><xsl:value-of select="Tip"/></td>
</tr>
</xsl:if>
</xsl:for-each>

www.bsenyurt.com Page 1492


Dikkat ederseniz choose eleman ierisinde when ve otherwise isimli iki alt eleman kullanlmtr.
When eleman if eleman gibi test isimli bir nitelie sahiptir ki buraya koulumuzu yazarz. (Choose
eleman ierisinde birden fazla when ifadesi kullanlabilir.) otherwise ise when elemannda belirtilen
koullara uymayan durumlarda devreye girmektedir.

u ana kadar gelitirdiimiz rneklerde Xslt uyguladmz Xml ieriini grmek iin, tarayc
pencersinde ilgili xml dosyasn ama yolunu setik. Lakin Asp.Net uygulamalarnda ok sk Xml
verileri ile almaktayz. Bu nedenle bir Xslt dkmann herhangibir Xml ieriine, ynetimli
kod(managed code) tarafnda da uyarlayabilmeliyiz. Framework bir Xml dkmann bir Xslt
dkman ile arptrmak iin pek ok kullanl tip iermektedir. Framework 1.1' de transform
ilemleri iin XslTransform tipi kullanlmaktayd. Bu tip Framework 2.0 iinde geerlidir. Ancak
modas gemi (obsolute) olarak kabul ediliyor ve yerine gelen
yeni XslCompiledTransform tipinin kullanlmas neriliyor. Kaynaklarda yeni gelen
XslCompiledTransform tipinin eskisine gre ok daha iyi bir performans salad sylenmekte.
Aadaki kod paras tipik olarak yukarda gerekletirdiimiz ilemlerin ynetimli (managed)
tarafta nasl yaplabileceini ieren basit bir kod paras sunmaktadr.

XslCompiledTransform xsltran = new XslCompiledTransform();


xsltran.Load(Server.MapPath("XsltForHtml.xsl"));
xsltran.Transform(Server.MapPath("MuzikDukkanim.xml"), null, Response.Output);

XslCompiledTransform tipinin iki nemli yesi Load ve Transform metodlardr. Load metodu
ile dntrme ileminde kullanlacak olan kaynak Xslt dkman belirtilir. Loadmetodunun alt
adet ar yklenmi (overload) versiyonu vardr. Yukardaki rnek kod parasnda Xsl dosyasnn
bulunduu yol(path) bilgisi kullanlmtr. Transform ilemleri srasnda eer performans nemli ise
Load ve Transform medorlarnda IXPathNavigable arayz (interface) tipinden parametre alan
versiyonlarnn kullanlmas nerilmektedir. Aadaki kod parasnda IXPathNavigable tipine
atanabilen XPathDocument referanslar kullanlmtr.

XslCompiledTransform xsltran = new XslCompiledTransform();


XPathDocument doc = new XPathDocument(Server.MapPath("MuzikDukkanim.xml"));
XPathDocument xslDoc = new XPathDocument(Server.MapPath("XsltForHtml.xsl"));
xsltran.Load(xslDoc);
xsltran.Transform(doc, null, Response.Output);

www.bsenyurt.com Page 1493


Hangi teknik kullanlrsa kullanlsn, dntrme ilemini Transform isimli metod
gerekletirmektedir. Transform metodunun ondrt farkl versiyonu bulunmaktadr. Bizim
kullandmz rneklerdeki versiyonlarda ilk parametre olarak dntrme ileminin uygulanaca
Xml dkman belirtilmektedir. kinci parametrede ise, ortamdan Xslt dkmanna gndereceimiz
eitli parametreler varsa bunlara ait bilgilere yer verilir. Biz u anki kod paramzda parametre
gndermediimizden buray null olarak belirttik. Son parametre ise dntrlen ktnn nereye
yaplacan belirtmektedir. Bizim rneimizde bu kt web sayfasnn html ieriine doru
yaplmaktadr ki bu parametre bir stream de alabilir. Bu da ktnn fiziki bir kaynaa doru
yaplabileceini gsterir. Yukardaki kod paralarndan herhangibirini rnek bir web uygulamasnda
kullandmzda aadakine benzer bir kty o anki gncel aspx sayfas zerinde elde edebiliriz.

Baz durumlarda Xslt dkman ierisinde deerini d ortamdan alacak parametreler kullanmak
isteyebiliriz. rnein gelitirdiimiz Xslt dosyasnda fiyat d ortamdan gelen deerden byk
olanlarn zerinde bir koul altrmak istediimizi dnelim. ncelikli olarak d ortamdan
gelecek olan parametreyi Xslt dkmanmza bildirmeli, onu ieride kullanmal ve daha sonra
ynetimli taraftan bu parametre deerini aktarmalyz. lk olarak ieride kullanacamz
parametreyi ekleyerek ie balayalm. Bunun iinparam elemanndan aadaki gibi
faydalanabiliriz.

Param elemanna ait name nitelii parametre adn belirtir. select niteliinde ise bu parametre iin
varsaylan bir deer kullanlr. Bu parametreyi rnek olarak when eleman ierisinde kullanabiliriz.

www.bsenyurt.com Page 1494


Peki bu parametreye ynetimli kod ierisinden nasl deer gndereceiz? Sz konusu parametre
XslCompiledTransform snfnn Transform metodu iin aslnda bir argmandr. Xslt dkman
ierisinde birden fazla parametre tanmlanm olabilir. Tm bu parametreler ve
deerleri XsltArgumentList isimli bir tip ile saklanrlar. Aadaki kod parasnda web sayfasndaki
bir TextBox kontrolnden alnan saysal deer, yukarda tanmlam olduumuz Price isimli
parametreye deer olarak aktarlmaktadr. Dikkat ederseniz XsltArgumentList tipine ait nesne
rneimize AddParam metodu ile Price parametresi eklenmi ve deeri verilmitir. Sonrasnda ise
Transform metodunun ikinci parametresine argList isimli nesnemiz bildirilmitir.

private void Parametric(decimal price)


{
XslCompiledTransform xsltran = new XslCompiledTransform();
xsltran.Load(Server.MapPath("XsltForHtml.xsl"));
XsltArgumentList argList = new XsltArgumentList();
argList.AddParam("Price", "", price);
xsltran.Transform(Server.MapPath("MuzikDukkanim.xml"), argList, Response.Output);
}

Baz durumlarda Xslt ierisinden d ortama parametre aktarp bir takm hesaplamalar yaptrmak
isteyebiliriz. Bu tipik olarak, Xslt dkman ierisinden dardaki bir metodu armak anlamna
gelmektedir. Dolaysyla, Xslt dkman ierisinde kapslleyemiyeceimiz bir takm kodlar, d
ortamda ele alabilir ve Xslt dkman ierisinden buraya parametre gnderebiliriz. lk olarak
aadaki gibi basit bir snf tasarlayalm.

public class PriceManager


{
public decimal LastPrice(string fiyat)
{
decimal fyt = Convert.ToDecimal(fiyat);
return fyt - 1;

www.bsenyurt.com Page 1495


}
}

Bu snf ierisinde yer alan LastPrice isimli metod bir parametre almaktadr. te biz bu
parametrenin deerini Xslt dkmanmz ierisinden gndereceiz. Bylece Xslt dkmannn ele
ald alan deerini ele alacak i mantn kendi yazdmz bir tip ierisine alm bulunuyoruz.
Metodun dn deeri ise, Xslt dkmannda bu metodu ardmz yerde kullanlabilecektir. Bu
aamadan sonra kodlarmzda aadaki gibi deitirmemiz gerekiyor.

XslCompiledTransform xsltran = new XslCompiledTransform();


XPathDocument doc = new XPathDocument(Server.MapPath("MuzikDukkanim.xml"));
XPathDocument xslDoc = new XPathDocument(Server.MapPath("XsltForHtml.xsl"));
XsltArgumentList argLst = new XsltArgumentList();
PriceManager tip = new PriceManager();
argLst.AddExtensionObject("urn:MyType", tip);
xsltran.Load(xslDoc);
xsltran.Transform(doc, argLst, Response.Output);

Burada yine barol oyuncumuz XsltArgumentList tipidir. Ancak bu sefer, Xslt dkmannn d
ortama gnderdii parametreyi ileyecek ve kullanacak bir nesne sz konusudur. Bu
sebepten AddExtensionObject metodu kullanlmtr. Bu metod ilk parametre olarak bir xml
namespace (isim alan) bilgisi almaktadr. kinci parametre ise, Xslt dkmannn kullanaca
tipe ait nesne rnei referansdr. Gelelim Xslt dkmanmza. Burada hereyden
nce urn:MyType isim alannn belirtilmesi gereklidir. Bunun iin stylesheet elemanna bir isim
alan bildirimini aadaki gibi eklememiz gerekecektir.

<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:MyType="urn:MyType">

Artk isim alann tanmladmza gre, Xslt dkmanmz ierisinde PriceManager tipine ait nesne
rneini ve ye metodunu arabilir ve parametre gnderebiliriz. Aadaki rnek kullanm bu iin
nasl yaplabileceini gstermektedir.

<xsl:when test="Fiyat &lt;=$Price">


<td bgColor="Green">
<font color="White" size="3"><b> <xsl:value-of select="MyType:LastPrice(Fiyat)"/>
ytl</b></font>
</td>
</xsl:when>

Dikkat ederseniz value-of eleman ierisinde yer alan select niteliinde metod ars yaplmtr.
MyType isim alan kod tarafnda tip isimli PriceManager snfna ait nesne rneini iaret
etmektedir. Dolaysya bu bilgi zerinden kolayca LastPrice metoduna eriilmi ve Fiyat isimli Xml
alannn deeri parametre olarak gnderilebilmitir. Elbetteki metodun dn deeri, select
elemannn bulunduu hcreye yazlacaktr.

www.bsenyurt.com Page 1496


Bu makalemizde ksaca Xslt' nin ne olduunu, ne ie yaradn, .Net Framework ierisinden nasl
kullanlabileceini ksaca incelemeye altk. Aslnda Xslt bal bana bir konudur ve ayrca zaman
ayrlmas gerekmektedir. Xml, Xslt, Xpath gibi popler konularn .Net ile olan ilikilerini daha iyi
anlayabilmek iin size Wrox' un Professional ASP.NET 2.0 XML (Programmer to
Programmer) kitabn tavsiye ederim. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Byk Nesneler(Large Objects) ile almak (


11.07.2006 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Veritaban programclnda zaman zaman byk nesneler (large objects) ile almak zorunda
kalabiliriz. Grnt, ses, resim, text dkman, altrlabilir uygulamalar gibi dosyalar bir
veritaban iin byk nesne (large objects) olabilecek kaynaklardr. Bu gibi dosyalarn veritaban
zerinde alanlar (fields) ierisinde saklanabilmesi baz zel veritaban trleri ile mmkn
olabilmektedir. Sql Server temel olarak byk nesneleri iki kategoriye ayrmaktadr. BLOBs ad
verilen ikili formatta byk nesneler (Binary Large Objects - BLOBs) ve karakter tabanl byk
nesneler (Character Large Objects - CLOBs). Bununla birlikte Sql Server 2005 ile byk
nesneleri saklamak iin gelen yeni veri trleride vardr. Bunlarda genel olarak deer trnden
byk nesneler (Value Types Large Objects - VTLOs) olarak adlandrlmaktadr. Aadaki
tabloda Sql Server 2000 ve 2005 srmlerinde geerli olan byk nesne trleri (Large Objects
Types) listelenmektedir.

Nesne eidi Sql Server 2000 Veri Tr Sql Server 2005 Veri Tr

image ( maksimum 2 Gb)


BLOBs (Binary Large Objects) image ( maksimum 2 Gb)
varbinary(max)

www.bsenyurt.com Page 1497


text (maksimum 2 Gb, non-
text (maksimum 2 Gb, non- unicode)
CLOBs (Character Large unicode) varchar(max)
Objects) ntext (maksimum 1 Gb, ntext (maksimum 1 Gb, unicode)
unicode) nvarchar(max)
xml

Tablodan grebileceiniz gibi Sql Server 2005 ile birlikte gelen yeni byk nesne (large object)
tr vardr. Varbinary(max) tr Sql Server 2000' deki image trnn benzeridir. Benzer
ekilde varchar(max) ve nvarchar(max) trleride srasyla text ve ntext veri trlerinin yeni
karlklardr. Sql Server 2005' in image, text, ntext gibi veri trlerini desteklemeye devam edecei
ancak yeni Sql srmlerinde artk bunlar kaldracana dair bir takm bilgiler mevcuttur. Bu
nedenle Sql Server 2005 zerinde yer verilen image, text ve ntext veri trlerinin geriye doru
uyumluluu salamak amacyla tutulduunu dnebiliriz. Yeni eklenen VTLOs' larn en byk
zelliklerinden birisi, byk nesne iin belirli bir boyut bildirilebilmesidir. Dolaysyla
varbinary(3000) gibi bir tanmlama yapabiliriz. Sz konusu yeni trleri birletirebilir (concatenate),
sorgulayabilir, hatta sp' lere parametre olarak geirebiliriz. Bu imkanlar dnldnde, VLTOs
eski byk nesne trlerine nazaran nemli avantajlar iermektedir.

Dikkat edersek, byk nesnelerin (large objects) kaplad alanlar 2 Gb seviyesine kadar
kmaktadr. Acaba bir veritaban sistemi ierisinde bu denli byk alanlar iin yer ayrlabilmesinin
avantajlar ve dezavantajlar neler olabilir? rnein bir elektronik ticaret sitesini gz nne alalm.
Kullancnn etkileimde bulunduu rnlere ait resim bilgileri ounlukla web sunucusu zerindeki
fiziki bir adreste tutulur. Sayfada resmin grnebilmesi ve en nemlisi bulunduu tablo satr ile
ilikilendirilmesi iin ounlukla resmin sanal yolu (virtual path) bir field ierisinde saklanr. Bu son
derece mantkldr. Nitekim bu tip sitelerde yer alan resimlerin boyutlar genellikle ok yer
tutmayacak ve tarayc pencerelerine hzla yklenebilecek seviyede olurlar. Bu adan bakldnda
resimleri bu ekilde yol bilgileri ile tutmak son derece mantkldr.

Lakin baz sistemlerde tutulan resim bilgileri ok yksek boyutlu olabilir ve ayn zamanda tutulan
ieriin gvenlii nem arz edebilir. rnein, yksek boyutlu ve ska deiebilen CAD izimlerinin
tutulduu bir sistem olduunu dnelim. Bu izimler sklkla gncelenebilecei gibi belirli kiisel
dnda grlmemesi istenebilir. Ayrca veritabann yedeinin alnd durumlarda CAD
izimlerininde veritaban ile birlikte tanmas zor olacandan, bu izimlerin satr dahilinde
tutulmas ve sz konusu tablo satrlar ierisinde tanabilir olmas nemli bir avantaj salayacaktr.
Her iki rnek senaryo gz nne alndnda dikkat edilmesi gereken bir takm ortak noktalar
olutuu aka gzlemlenebilir. nemli olan hususlar verinin tanma
kolayl, gvenlii ve nesnel olarak kaplad alan dr.

rnein belirli kullanclarn asla grmemesi gereken byk nesneler olduunu dnecek olursak,
bunlar veritaban sisteminin gvenliine emanet etmek son derece mantkl bir seim olacaktr.
Dier yandan byk nesneler veritabannn boyutunu arttracak ve eriim hzlarn eer kodlamada
eitli taktikler uygulamassak yavalatacaktr. Genellike 8000 byte' n zerine klmas halinde
byk nesneleri okurken veya veritabanna doru yazarken para para ilemek uygulama
performansn dorudan olumlu ynde etkileyecek bir zmdr. yleki ou istemci, ok yksek
kapasiteli nesneleri bellee almakta sorunlar ile karlaabilir.

zellikle boyutu 8000 byte' n zerinde olan byk nesneleri okurken veya yazarken
paral olarak ele almak uygulama performansn arttrc bir etkendir. Nitekim
uygulamann alt sistem her zaman ok yksek boyuta sahip nesneleri tayabilecek
kapasitede donanma sahip olamayabilir. Bu konu ile ilgili olarak resim dosyalarnn sql
server 2000 sisteminde nasl okunaca ve nasl yazlacana dair bilgi veren

www.bsenyurt.com Page 1498


makaleleri takip etmenizi neririm.

Microsoft.Net 2.0, Sql Server tablolar zerindeki byk nesneleri (large objects) ele alabilmek
iin SqlDataReader tipine iki yeni metod daha ilave etmitir. GetSqlBytes ve GetSqlCharsisimli
metodlar, bir tablo satrndaki herhangibir byk nesne (large object) alann okumak iin
gerekli stream' leri kolayca elde etmemizi salarlar. Biz bu makalemizde bir rnek zerinden
giderek Sql Server 2005 zerinde yeni veri trleri ile byk nesnelerin nasl saklanabileceini ve
okunabileceini ksaca incemeleye alacaz.

Okuma ilemlerini gerekletirirken SqlDataReader nesnesi bize etkin bir performans ve verim
sunmaktadr. SqlDataReader nesnesinin okuma ilemlerinde hzl olduunu zaten biliyoruz. Bununla
birlikte SqlCommand snfnn CommandBehaviour numaralandrcsnn (enum)
deerinin SequentialAccess olmas halinde, okunan satr ierisindeki byk nesnelerin (large
objects) bir akm (stream) zerinden ister para para ister tamamen okunabilmesi salanmaktadr
ki buda byk nesnelerin okunabilmesinin en hzl yoludur. Normal artlarda bir satrdan veri
okurken SequentialAccess davrannn verilmesi, byk nesne alanlar sz konusu olduunda ok
nemlidir. nk bir SqlDataReader nesne rnei alma zamannda genellikle select sorgusundan
dnen satrlar uygulamann alt sistemdeki bellee anlk olarak okur ve sonraki satrdan devam
eder. Dolaysyla byk nesne(large object) ieren bir satrn tamamn bellee almak performans
kaybna neden olabilir. SequentialAccess davran sayesinde, satrn tamamnn bellee alnmasnn
nne geilebilir. nk alanlarn ieriinin ardl olarak (sequential) okunabilmesine imkan
salanr.

Gelelim Framework 2.0 ile gelen yeni metodlar nasl kullanacamza. Aadaki ak emas tipik
olarak byk nesne (large object) ieren bir alann nasl okunabileceini zetlemektedir.

www.bsenyurt.com Page 1499


lk olarak yukardaki ak emasnda belirtilen byk nesne (large object) okuma ilemini basit bir
rnek kod zerinden incelemeye alalm. Senaryo olarak Sql Server 2005 ile birlikte gelen
Production isim alannda yer alan Product ve ProductPhoto tablolarn ele alacaz. Product
tablosunda rn bilgileri yer almaktadr. ProductPhoto tablosunda ise bu rnlere ilikin resim
bilgileri varbinary(Max) tipinden alanlarda saklanmaktadr.

Gelitireceimiz rnek bir windows uygulamas olacak. Uygulamamzn kodlarn aada


bulabilirsiniz.

Form1.cs iin nemli kod satrlar;

private LobsWorker wrk;

private void Form1_Load(object sender, EventArgs e)


{
wrk = new LobsWorker();
wrk.LoadProductInfos(grdProducts);
}

private void btnShowPicture_Click(object sender, EventArgs e)


{
if (grdProducts.SelectedRows.Count > 0)
{
int photoId = Convert.ToInt32(grdProducts["ProductPhotoID",
grdProducts.CurrentCell.RowIndex].Value);
wrk.ShowPicture(pcbProductPhoto, photoId);
}
}

leri yklenen LobsWorker snfmz;

using System;
using System.Data;
using System.Configuration;
using System.Data.SqlClient;
using System.Windows.Forms;
using System.IO;

namespace LOBs

www.bsenyurt.com Page 1500


{
class LobsWorker
{
SqlConnection _con;
SqlCommand _cmd;
SqlDataReader _dr;
SqlDataAdapter _da;

public void LoadProductInfos(DataGridView grid)


{
using (_con = new
SqlConnection(ConfigurationManager.ConnectionStrings["AdvConStr"].ConnectionString))
{
_cmd=new SqlCommand("SELECT Production.Product.ProductID,
Production.Product.Name, Production.Product.ListPrice,
Production.Product.StandardCost,Production.ProductProductPhoto.ProductPhotoID FROM
Production.Product INNER JOIN Production.ProductProductPhoto ON Production.Product.ProductID
= Production.ProductProductPhoto.ProductID Where Production.Product.Size is not Null",_con);
_da = new SqlDataAdapter(_cmd);
DataTable dt = new DataTable();
_da.Fill(dt);
grid.DataSource = dt;
}
}
public void ShowPicture(PictureBox pb, int photoId)
{
using (_con = new
SqlConnection(ConfigurationManager.ConnectionStrings["AdvConStr"].ConnectionString))
{
using (_cmd = new SqlCommand("Select
ProductPhotoID,LargePhotoFileName,LargePhoto From Production.ProductPhoto Where
ProductPhotoID=@PhotoID", _con))
{
_cmd.Parameters.AddWithValue("@PhotoID", photoId);
_con.Open();
_dr = _cmd.ExecuteReader(CommandBehavior.CloseConnection |
CommandBehavior.SequentialAccess);
if (_dr.Read())
{
pb.Image =
System.Drawing.Image.FromStream(_dr.GetSqlBytes(2).Stream);
}
_dr.Close();
}
}
}
}
}

www.bsenyurt.com Page 1501


Kullanc DataGridView kontrolden bir satr seip Resim Gster isimli dmeye tkladnda, seilen
satrdaki ProductPhotoID alannn deeri ele alnaraktan rn resmi bir PictureBox kontrolnde
gsterilmektedir. Yardmc snfmz olan LobsWorker ierisindeki en nemli ye ShowPicture isimli
metoddur. Bu metod parametre olarak resmin gsterilecei PictureBox bileeninin referansn ve
DataGridView kontrolnde seilen satrdaki ProductPhotoID alannn deerini almaktadr. Metod
ierisinde SqlDataReader snfna ait nesne rneinin ExecuteReader metodu altrldktan sonra
elde edilen satrdaki LargePhoto isimli alann deeri GetSqlBytes metodu ile alnmaktadr.
GetSqlBytes isimli metodun dndr referans tipinin Stream isimli bir zellii vardr. Dolaysyla
rn resmini gstermek iin tek yapmamz gereken elde edilen Stream' i PictureBox
kontrolnn Image isimli zelliine atamak olacaktr. Uygulamann bu haliyle rnek ktsn
aada grebilirsiniz.

Benzer sre dkman tipindeki kaynaklar iinde geerlidir. Tek fark GetSqlBytes metodu
yerine GetSqlChars metodunu kullanmak olacaktr. Ancak GetSqlChars' n Stream isimli bir zellii
yoktur. Bunun yerine dorudan string olarak ierii elde edebiliriz. Bununla birlikte GetSqlChars
metodu ile elde edilen ierii karakter dizisi eklinde ele almakta mmkn olabilir. Bylece okuma
ilemlerinin rnek olarak bir resim format iin nasl yaplabileceini ksaca incelemi olduk. Benzer
ilemleri ikili formatta kaydedilebilecek pek ok dosya iin yapabilirsiniz.

Gelelim yazma ilemlerine. Tipik olarak grnt, resim, ses veya dkman formatndaki kaynaklar
tablolar zerindeki ilgili alanlara yazmak iin aadaki ak emasndakine benzer bir yol
izleyebiliriz.

www.bsenyurt.com Page 1502


Yazma ileminide inceleyeceimiz basit bir rnek ile makalemize devam ediyoruz. erisinde bir
ehire ait resim ve tarihe bilgilerini ieren bir tablomuz olduunu dnelim. Tablomuzun yaps
aadaki ekilde grld gibi olacaktr. Dikkat ederseniz Resim, Tarihce alanlarnn veri tipleri
srasyla varbinary(Max) ve nvarchar(Max) olarak seilmitir.

rnek uygulamamzda LobsWorker snf ierisinde yer alan aadaki InsertCity isimli metodumuz,
seilen resim dosyas ve dkman bilgilerini (rnek olarak text format baz alnmtr) ele alarak
Sehirlerimiz isimli tabloya satr ekleme ilemini gerekletirmektedir.

public void InsertSehir(string sehir,string imagePath, string docPath)


{
using (_con = new
SqlConnection(ConfigurationManager.ConnectionStrings["AdvConStr"].ConnectionString))
{
using(_cmd=new SqlCommand("Insert into Sehirlerimiz (Sehir,Resim,Tarihce) Values
(@Sehir,@Resim,@Tarihce)",_con))
{

www.bsenyurt.com Page 1503


_cmd.Parameters.AddWithValue("@Sehir", sehir);
_cmd.Parameters.Add("@Resim", SqlDbType.VarBinary);
_cmd.Parameters.Add("@Tarihce", SqlDbType.NVarChar);

FileStream fsPic = new FileStream(imagePath,FileMode.Open,FileAccess.Read);


BinaryReader br = new BinaryReader(fsPic);
_cmd.Parameters["@Resim"].Value=br.ReadBytes((int)fsPic.Length);

FileStream fsDoc = new FileStream(docPath, FileMode.Open, FileAccess.Read);


StreamReader sr = new StreamReader(fsDoc);
_cmd.Parameters["@Tarihce"].Value = sr.ReadToEnd();

_con.Open();
_cmd.ExecuteNonQuery();
}
}
}

InsertCity metodunu inceleyecek olursak jpg uzantl resim dosyalarn varbinary(max) tipinden
olan @Resim isimli parametreye aktarrken bir BinaryReader snf nesne rneinden
yararlanyoruz. Nitekim varbinary(max) tipinin bekledii verinin byte dizisi eklinde olmas
gerekmektedir. Dier taraftan txt uzantl dkman dosyamz nvarchar(max) tipinden alana
eklemek iinse bu kez bir StreamReader snf nesne rneinden yararlanyoruz. Bu kez
aktarmamz gereken verinin string tipinden olmas yeterlidir. rneimizi denediimizde seilen
verilerin tabloya baarl bir ekilde eklenmi olduklarn grebiliriz.

www.bsenyurt.com Page 1504


Grld gibi yeni gelen metodlar, byk nesneler ile alrken olduka byk kolaylklar
getirmitir. Buna ramen 8000 byte snrn bizim iin nemli bir izgidir. Genellikle bu deeri aan
kaynaklar saklarken para para okuma ve yazma yntemleri tercih edilmelidir. Bu yntemlerden
biriside Sql Server zerinde UpdateText ve TextPtr anahtar szcklerinin kullanld tekniktir. Bu
teknii ilerleyen yazlarmzda (yada bir grsel dersimizde) incelemeye alacaz. Son olarak,
byk nesnelerin veritabannda saklanmasnn gvenlik, kontrol edilebilirlik ve
tanabilirlik asndan byk avantajlar saladn ancak optimum performans iin ekstra aba
gerektirdiinide gz ard etmemekte fayda olacan syleyelim. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

lk Bakta .Net Process Ynetimi ( 07.07.2006 ) -


Framework
Deerli Okurlarm Merhabalar,

Bir Windows uygulamasn altrdmzda iletim sistemi bellek zerinde sz konusu programn
alabilmesi iin bir Process aar. Bu Process ierisinde, uygulamann almas iin gerekli bellek
ayrma ilemleri, harici olarak kullanlan Module' ler (rnein baka Com nesneleri veya .net
assembly' lar gibi) ve process ii Thread' ler bulunur. ounlukla bir Process aldnda bu Process
ierisinde mutlaka bir main thread bulunur. Hatta basit bir Console uygulamasn altrdnzda
Main Thread dnda baka ayn Proces' e dahil baka Thread' ler ile de karlaabiliriz. Dolaysyla
uygulama iin alan Process' in birden fazla Thread ierecei durumlar sz konusu olabilir.
Literatrde multi-threading olarak geen bu olay, bir Process' in ierisinde i yapan e zamanl
paralarn olmas anlamna gelmektedir.

www.bsenyurt.com Page 1505


Yukardaki ekilde bir Process' in alma zamannda sahip olabilecei ierik ifade edilmeye
almaktadr. Buradaki bilgilerden yola karak bir Process' in en azndan bir Thread ierdiini,
bellek zerinde kulland ve ihtiya duyduu bilgileri veri olarak paylaml bir alanda tuttuunu ve
bellee yklenirken beraberinde ihtiya duyabilecei baka modulleride ierebileceini
syleyebiliriz. Burada yer alan TLS (Thread Local Storage) ksmn, bir Thread' in kendisi iin
sonradan hatrlamas gereken bilgileri tuttuu yer olarak dnebiliriz. Bu saklama alanlar
sayesinde Thread' lerin bir nceki konumlarnda sahip olduklar ierie eriebilmeleri ve kaldklar
yerden devam edebilmeleri mmkn olabilmektedir. te bu nedenle bu bilgiler zel olarak TLS
(Thread Local Storage) alannda tutulurlar. Tek ilemcili bir sistem gz nne alndnda TLS
alanlar son derece nemlidir. Ancak HyperThreading teknolojili veya birden fazla ilemciye sahip
sistemlerde durum daha farkl olabilir. Konumuz Thread' lerin almasn incelemek olmad iin
bu konuda ok fazla detaya girmeyeceiz.

.Net Framework yukardaki ekilde grlen yapdaki bilgileri alma zamannda elde edebilmemizi
salayan baz tipler (types) ierir. System.Diagnostics isim alannda bulunan bu tipler yardmyla
alma zamanda bir Process' e ait eitli bilgilerini elde edebiliriz. Dier taraftan dilersek alma
zamannda baka Process' leri altrabilir, var olanlar yok edebilir, baz Process' lere parametrik
bilgi aktarabilir ve hatta Process' lerden d ortama sunulan bir takm stream' leri okuyabiliriz.
Aadaki tabloda Process API' sini kullanarak yapabileceklerimizin bazlar maddeler halinde
belirtilmektedir.

Process ' ler ile ilgili Managed Code (Ynetimli Kod) Tarafnda Yapabileceklerimizden
Bazlar

Sistemde var olan Process' lerin bilgilerini alabiliriz. rnein Process' lerin adlarn, baladklar
1
sreleri, sistem tarafndan kendilerine verilen Identity deerlerini vb. gibi.

Bir Process' i kod ierisinden altrabiliriz. Bu ilemi yaparken altrlacak Process iin gerekli
2
balang bilgilerini syleyebilir. (Start ilemi)

Bir Process' i altrp kendi iinden d ortama sunduu verileri baka Process' ler ierisinde
3 yakalayabiliriz. zellike Main metodu ierisinden d ortama atlan stream' leri dier Process' ler
ierisinde yakalayabilmemiz mmkndr. (Yada tam dersi durumda sz konusudur.)

Bir Process' i altrmadan nce sz konusu Process iin gerekli parametreleri kod ierisinden
4 gnderebiliriz. rnein internet explorer iin bir Process aarken gezilecek URL bilgisini de
parametre olarak verebiliriz.

Bir Process' in , alma zamannda ierdii Thread' leri yakalayabilir ve bir takm bilgilerine
5
ulaabiliriz.

Bir Process' in bellee almas ile birlikte, sz konusu Process' e ilave olan ve almas srasnda
6
kullanlan module bilgilerini elde edebiliriz.

7 Bir Process' i istersek alma zamannda sonlandrabiliriz. (Kill ilemi)

Burada bahsedilenleri dahada geniletebiliriz. Bizim iin en nemli yardmc tip Process isimli
snftr. Process snfnn eitli static metodlar sayesinde o an almakta olan tm Process' leri
elde edebiliriz ; ayrca belirli bir Process' i sistem tarafndan verilen Identity deeri ile

www.bsenyurt.com Page 1506


veya Process ad ile balatabiliriz. Dilerseniz ilk rneimiz ile ie balayalm ve Process API' sini
daha detayl bir ekilde renmeye alalm. lk olarak sistem de yer alan Process' leri ve bunlara
ait bir takm bilgileri nasl elde edebileceimize bakacaz. Bunun iin aadaki kod parasn
herhangibir Console uygulamasnda denememiz yeterli olacaktr.

private static void ProcessInfos()


{
Process[] currentProcesses = Process.GetProcesses("manchester");
Console.WriteLine("Process Count {0}", currentProcesses.Length.ToString());
foreach (Process pro in currentProcesses)
{
try
{
Console.WriteLine("{0,6}, {1,20}, Balang : {2,6}, Thread Says {3,5}",
pro.Id.ToString(), pro.ProcessName, pro.StartTime.ToShortTimeString(),
pro.Threads.Count.ToString());
}
catch
{
continue;
}
}
}

Herhangibir sistemde o anda alan Process' leri elde edebilmek iin Process snfnn
static GetProcesses metodunu kullanrz. rneimizde bu metoda parametre olarak yerel makine
adn (local machine name) vermekteyiz. GetProcesses metodu geriye Process tipinden bir dizi
dndrmektedir. Bu dizinin herbir eleman Process tipinden olduu iin gncel Process' lere ait
eitli bilgileri elde edebiliriz. Tabi elde ettiimiz bu bilgiler ilgili Process' lere ait anlk verilerdir.
Dolaysyla Process' lerin son durumu hakkndaki bilgileri elde edebilmek iin srekli kontrol ilemi
gerektirecek kodlar yazlmas gerekebilir.(Bu tip bir dzenlemede Polling benzeri bir mantk sz
konusudur.) Biz rneimizde basit olarak her bir Process' in sistem tarafndan verilen Identity
deerini, adn, balad zaman ve ierdii Thread saysn ekrana yazdrmaktayz. ( Process snfn
ve yelerini kullanrken System.Diagnostics isim alann uygulamamza eklemeyi unutmamamlyz.
) Metodumuzu test ettiimiz rnek bir Console uygulamasnn kts aadakine benzer olacaktr.

www.bsenyurt.com Page 1507


Process snfnn baka static metodlarda vardr. rnein GetCurrentProcess metodu o an
almakta olan uygulamaya ait Process bilgisini elde etmenizi salar.GetProcessById static
metodu sistemdeki Identity deerine gre bir Process nesne rnei
retir. GetProcessesByName static metodu bir Process adn parametre olarak alarak, o anda bu
isim ile ak olan ka tane Process varsa bunlarn hepsini Process snf tipinden bir dizi olarak geri
dndrr. Son olarak static Start metodu ile, alma zamannda bir Process ierisinden baka
Process' leri altrabiliriz.

Process current = Process.GetCurrentProcess();


Console.WriteLine("{0,15} {1,15}","Id : ",current.Id.ToString());
Console.WriteLine("{0,15} {1,15}", "Start Time : ", current.StartTime.ToShortTimeString());
Console.WriteLine("{0,15} {1,15}","Process Name : ", current.ProcessName);
Console.WriteLine("{0,15} {1,15}", "Machine Name : ", current.MachineName);

Yukardaki kod parasnda o anda almakta olan uygulamaya ait Process bilgilerinden bazlar
ekrana yazdrlmaktadr. Burada rnek olarak bir ka Process bilgisini okuyoruz. Baz durumlarda
alma zamannda herhangibir uygulama adn ele alaraktan sz konusu program iin ak olan
Process' ler hakknda bilgi almak isteyebiliriz. ( rnein sistemde ak olan Visual Studio.Net IDE'
lerinin tamam hakknda bilgi almak gibi. ) Bu durumda Process snfnn
static GetProcessesByName metodunu kullanrz. Bu metod geriye Process snf tipinden bir dizi
dndrr. Metodun geriye dizi dndrmesinin sebebi, alma zamannda bir uygulamaya ait birden
fazla Process' in alm olabileceidir. Aadaki kod paras basit olarak alma zamannda
Windows iletim sisteminin bilinen programlarndan olan Notepad uygulamasna ait Process
bilgilerini vermektedir. Kod ierisinde, elde edilen dizinin uzunluuna baklarak sz konusu
uygulamaya ait ak Process' lerin olup olmadnn tespiti kolayca yaplabilir. Bu kontroln
yaplmasnn sebebi ak Process olmamas halinde, null referans olacandan uygulamann istem
d bir biimde sonlanabilecek olmasdr.

Process[] prcNotePad = Process.GetProcessesByName("Notepad");


if (prcNotePad.Length > 0)
{
for (int i = 0; i < prcNotePad.Length; i++)
{
Console.WriteLine("{0,15} {1,15}", "Id : ", prcNotePad[i].Id.ToString());
Console.WriteLine("{0,15} {1,15}", "Start Time :
", prcNotePad[i].StartTime.ToShortTimeString());
Console.WriteLine("{0,15} {1,15}", "Process Name : ", prcNotePad[i].ProcessName);
Console.WriteLine("{0,15} {1,15}", "Machine Name : ", prcNotePad[i].MachineName);
Console.WriteLine("----------------");
}
}

www.bsenyurt.com Page 1508


Sradaki rneimizde her hangibir .Net kodu ierisinden baka Process' leri nasl
altrabileceimizi greceimiz aadaki kod parasn ele alacaz. Kod ierisinden baka
Process' ler balatabilmek iin Process snfnn static Start metodunu kullanrz.

// Bilinen bir Windows uygulamas iin parametre destekli Process balatlr. Bir internet
explorer uygulamasnn alabilecei parametrelerden birisi Url bilgisidir.
Process.Start("iexplore", "http://www.bsenyurt.com");

// Start metodu parametre olarak ProcessStartInfo tipinden bir nesne rneide alabilir.
Aadaki kod satr Windows ' un Calculator uygulamasn altrmakta ve bir Process
amaktadr.
ProcessStartInfo startInfo = new ProcessStartInfo("calc");
Process.Start(startInfo);

// Herhangibir uygulamann path bilgisinden yararlanarak, sz konusu uygulama iin bir


Process balatlabilir.
Process.Start(@"D:\HaftaIci\ExceptionHandling\ExceptionHandling\bin\Debug\ExceptionHandling.e
xe");

Dikkat ederseniz bu kod parasndaki rneklerde farkl ekillerde Process balatma ilemleri ele
alnmtr. ounlukla Windows iletim sistemini gz nne aldnzda komut satrndan veya Start
mensnde yer alan Run seenei ile dorudan altrabileceiniz uygulamalar vardr. Bu nedenle
ayn uygulama adlarn exe uzantl veya uzantsz olabilecek ekilde kod ierisinde yazabilir ve ayr
Process' leri balatabiliriz. Start metodunun yukarda kullanlan versiyonlar dnda ele
alabileceiniz farkl ar yklenmi versiyonlarda vardr. rnein aadaki versiyonda dikkat
ederseniz Process' i amak iin UserName, Domain ve Password bilgileri gerekmektedir. Buna
gre bir uygulamay gerekli yetkileri bildirerektende balatabiliriz.

Makalemizin giri ksmnda alma zamanndaki Process' lerin beraberlerinde ykledikleri module'
ler olabileceinden bahsetmitik. Sonu itibariye bir .Net uygulamasnn varsaylan hali bellee
yklendii zaman, iletim sistemi tarafndan ilgili Process' e dahil edilen baz ek module' ler sz
konusu olabilir. Bu Module' ler ounlukla Com nesneleri, C tabanl sistem ktphaneleri
olabilecei gib baka .Net ktphaneleride (dll' ler) olabilir. Aadaki kod paras parametre olarak
verilen herhangibir uygulamann, iletim sistemi tarafndan alan Process' ine dahil olan Module'
lerine ilikin bir takm bilgiler vermektedir.

www.bsenyurt.com Page 1509


private static void LookingModules(Process currentProc)
{
ProcessModuleCollection modules = currentProc.Modules;
int totalSize = 0;
foreach (ProcessModule mdl in modules)
{
Console.WriteLine("{0,25} : {1,15} bytes", mdl.ModuleName,
mdl.ModuleMemorySize.ToString());
totalSize += mdl.ModuleMemorySize;
}
Console.WriteLine(totalSize.ToString() + " bytes");
Console.ReadLine();
}

Biz rneimizde, var olan uygulamaya ait Process nesne rneini ele aldk. Buna gre Process'
imize dahil olan dier Module' lerin isimlerini ve bellekte kapladklar alanlar grebiliriz. Dikkat
ederseniz Process snfnn Modules isimli zellii geriye her bir eleman ProcessModule snf
tipinden olan ProcessModuleCollection trnden bir koleksiyon rnei dndrmektedir.
ProcessModule tipini kullanarak bir Process ierisine dahil olan herhangibir Module hakknda
alma zaman bilgilerine ulaabiliriz.

alma zamannda Process' leri balatabileceimiz gibi onlar yok etmek isteyebiliriz de. Bunun iin
tek yapmamz gereken Process snfna ait Kill metodunu kullanmak olacaktr. Aadaki kod
paras ile alma zamannda sistemde var olan tm Internet Explorer uygulamalar (doal olarak
Process' leri) sonlandrlmaktadr. Bu ilemi gerekletirmek iin iexplore adn ieren Process' lerin
listesi GetProcessesByName metodu ile ekilmi ve elde edilen dizideki her bir Process tipi nesne
rnei iin Kill metodu arlmtr. Her zamanki gibi sz konusu uygulama iin sistemde ak
Process' ler olup olmadn kontrol etmek ve Kill ilemini bir try...catch blou altnda gvenli olarak
gerekletirmek alma zamannda oluabilecek istenmeyen hatalarn nne geilmesinde nemli
bir rol oynayacaktr.

Process[] prcs = Process.GetProcessesByName("iexplore");

www.bsenyurt.com Page 1510


if (prcs.Length > 0)
{
for (int i = 0; i < prcs.Length; i++)
{
try
{
prcs[i].Kill();
}
catch{}
}
}

Bazen bir Process ierisinden, baka Process' lerce d ortama aktarlan verileri okumak
isteyebiliriz. ounlukla string bazl stream' lerin bu ekilde d ortama aktarlmas halinde, Process
API' sini kullanarak her hangibir uygulama ierisinden bu ktlar yakalayabiliriz. Tabiki byle bir
ihtiyacn hangi durumlarda doabileceinide dnmek lazm. Aadaki rnekte, Support.exe adl
Console uygulamas d ortama bir string mesaj vermektedir. Bunun iin tipik olarak Console
snfnn WriteLine metodu kullanlmtr.(Consolo.out' ta kullanlabilinir.) rnek kod paramz ise,
Support.exe adl Console uygulamasn altrp bir Process ierisine dahil etmekte ve Support.exe
uygulamasnn d ortama verdii sonular bir Stream dahilinde kendi Process' i ierisine
almaktadr.

ProcessStartInfo strInfo = new ProcessStartInfo(@"D:\Vs2005Projects\C#


2.0\Support\Support\bin\Debug\Support.exe");
strInfo.UseShellExecute = false;
strInfo.RedirectStandardOutput = true;
Process pro=Process.Start(strInfo);
StreamReader reader = pro.StandardOutput;

//string okunan;
//while((okunan=reader.ReadLine())!=null)
//{
// Console.WriteLine(okunan);
//}

Console.WriteLine(reader.ReadToEnd());

Console.ReadLine();
pro.WaitForExit();

Kodumuzda ilk olarak ProcessStartInfo tipinden bir nesne rnei oluturuyor ve ilgili Process iin
bir takm zellikleri belirliyoruz. zellikle ProcessStartInfo' nun iaret ettii Support.exe isimli
uygulamadan d ortama aktarlan stream' i okuyabilmek
iin RedirectStandartOutput zelliine true deerini atam olmamz gerekmektedir. Bundan
sonrasnda ise Process' i balatyor ve StandartOutput zelliini kullanarak bir stream
yakalyoruz. Yakaladmz stream zerinden gelen veriyi kod ierisinde deiik ekillerde
okuyabiliriz. Kodumuzda bu iin iki farkl yapl yolunu gryorsunuz. Bir tanesi satr satr okuma
ilemini dieri ise tm string bilgiyi okuma ilemini gerekletiriyor. Kodumuzun sonunda dikkat
ederseniz WaitForExit metodunu aryoruz. Process snfnn WaitForExit isimli metodunu
kullanmamzn amac ise; ilgili harici uygulamann sonlanmasn beklemek. Bylece harici Process'

www.bsenyurt.com Page 1511


sonlandrlmadan, asl uygulamamzn sonlandrlmamasn salam oluyoruz. Dier Process
ierisinde alacak olan Console uygulamasna ait Main metodu kodu ise aadaki gibidir.

static void Main(string[] args)


{
Console.WriteLine("Dier Process' den Merhabalar.");
}

Uygulamann altrlmas sonucu;

Bir Process' den baka bir Process' e stream bazl veri ekmek dndan istenirse altrlacak
Process' e uygulama ierisinde yine stream bazl veri aktarmda gerekletirilebiliriz. Bu durumda
Process' in StandardInput zelliini ele almamz gerekecektir. StandardInput zellii,
StandardOutput zelliinin tersine stream ierisine veri yazabilmek iin bir StreamWriter nesne
rneini dndrr.

Son olarak bir Process' e dahil olan Thread' lerin nasl ele alnabileceini basit bir rnek ile
incelemeye alacaz. Aadaki kod parasnda Visual Studio.Net 2005 ortamna ait alma
zaman thread' lerine ilikin baz bilgilerin nasl elde edilebileceimizi gsteren rnek bir kod paras
bulunmaktadr.

Process[] currProc = Process.GetProcessesByName("devenv");


if (currProc.Length > 0)
{
ProcessThreadCollection currThreads = currProc[0].Threads;
foreach (ProcessThread trd in currThreads)
{
Console.WriteLine("{0,7} {1,15} {2,10} {3,15} ", trd.Id.ToString(),
trd.PriorityLevel.ToString(), trd.StartTime.ToString(),trd.ThreadState.ToString());
}
}

www.bsenyurt.com Page 1512


Bir Process' in ierisinde alan Thread' leri elde edebilmek iin Process snfna ait nesne rnei
zerinden Threads zellii arlr. Threads zellii geriyeProcessThreadCollection tipinden (bu
tip gvenli bir koleksiyondur) bir nesne rnei dndrr. Her bir eleman ProcessThread snf
tipinden olan bu koleksiyon yardmyla bir Process ierisinde yer alan tm Thread' leri elde
edebiliriz. rnek kodumuzda, elde edilen her bir Thread' in Id (Sistem tarafndan verilen
identity deeri), PriorityLevel (ncelik seviyesi), StartTime (Balang
zaman) ve ThreadState (Thread' in o anki durumu) bilgileri ekilmektedir.

Grld gibi .Net uygulamalar altrldklarnda iletim sistemi tarafndan alan Process' ler sz
konusudur. Biz bu Process' leri managed (ynetimli) taraftan kontrol edebiliriz. Gerekli Process
bilgilerinin alma zamannda elde edilebilmesi, istendiinde baka Process' lerin parametrik olarak
balatlabilmesi (ya da sonlandrlabilmesi) gibi imkanlara sahibiz. Hatta ok basit seviyede de olsa
Process' ler aras veri transferide yapabilmekteyiz. Bu makalemizde ok ksada olsa Process' lerin
ne olduunu ve managed (ynetimli) tarafta nasl ele alnabileceklerini incelemeye altk ve
bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Asp.Net 2.0 ile Configuration Management


(Konfigurasyon Ynetimi) ( 26.06.2006 ) -
Asp.Net 2
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1513


Asp.Net 2.0 zellikle Web.config dosyasn daha kolay ynetebilmek amacyla beraberinde bir
ynetim API' si ile birlikte gelmektedir. Configuration Management API olarak adlandrabileceimiz
bu yap sayesinde, web.config gibi konfigurasyon dosyalarn ve ieriini programatik olarak daha
etkin bir ekilde ynetebiliriz. Bildiiniz gibi web.config dosyas xml tabanl bir ierik sunmakla
birlikte entegre edildii web uygulamas iin gerekli temel bir takm ayalar ierir. (Elbette bir web
uygumas ierisinde yer alan alt klasrler iinde ayr web.config dosyalarnn ele alnabileceini
hatrlatmakta fayda var.) AppSettings, ConnectionStrings, Authentication, Authorization,
SessionState, Membership, Tracing, Pages gibi pek ok konu ile ilikili ksmlar bu ayarlar arasnda
dnebiliriz. Burada saym olduumuz tm ksmlar Configuration Management API ierisinde
birer tipe karlk gelmektedir. rnein Authentication ayarlar iin AuthenticationSection,
SessionState ayalar iin SessionStateSection gibi pek ok tip gelitirilmitir. Bu, ilgili ksmlarn
programatik olarak nesnel dzeyde kullanlabilmesi anlamna gelmektedir. Yani, Configuration
Management API' si sayesinde, web.config ierisinde yer alan herhangibir ksm (Section) nesne
rnei olarak kullanabilir, ieriini dzenleyebilir ve tekrardan kayt edebiliriz. te bu
makalemizde, basit olarak web.config ieriini programatik olarak nasl ele alabileceimizi
incelemeye alacaz.

Configuration Management API' si sadece web uygulamalarn esas almaz. Dier uygulamalar
(rnein Desktop) iin kullanlabilecek eitli uygulama dzeyindeki konfigurasyon dosyalarnda ele
alabiliriz. Temek olarak bir web.config dosyasn programatik seviyede Configuration snfna ait
bir nesne rnei ile ele alabiliriz. Configuration Management API' si ierisinde, Configuration tipini
elde edebilmemizi salayan iki temel snf vardr.
Bunlar ConfigurationManager ve WebConfigurationManager snflardr. ConfigurationManager
sadece web uygulamalarn deil dier platformlarda gz nne alr. WebConfigurationManager
snf ise zellikle web tabanl sistemler iin tasarlanm yeler ierir. ConfigurationManager
snf System.Configuration isim alannda, WebConfigurationManager snf
ise System.Web.Configuration isim alannda yer almaktadr. WebConfigurationManager tipinin
belkide en nemli yesi static OpenWebConfiguration metodudur. Bu metod sayesinde,
web.config dosyalarn herhangibir seviyede aabiliriz. Dier taraftan WebConfigurationManager
snf OpenMachineConfiguration isimli static bir ye metod daha ierir. Bu metod sayesinde de
tahmin edebileceiniz gibi, machine.config dosyasna eriilebilmektedir. Bu bizim makine
seviyesindeki bir takm ayarlar programatik olarak ele almamz salar. Aadaki tabloda bu
metodlara ilikin rnek bir takm senaryolar verilmitir.

rnek Metod levi

Gncel uyulamadaki
WebConfigurationManager.OpenWebConfiguration("~/") web.config dosyasn
alr.

ConfigMngAPI isimli
Web uygulamasna ait
WebConfigurationManager.OpenWebConfiguration("/ConfigMngAPI")
olan web.config
dosyasn aar.

ConfigMngAPI isimli
web uygulamasndaki
WebConfigurationManager.OpenWebConfiguration("/ConfigMngAPI/Admin") Admin klasr
altndaki web.config
dosyasn aar.

www.bsenyurt.com Page 1514


siteAdi ile belirtilen
web uygulamasndaki
web.config dosyasn
aalar. Bu metodun
WebConfigurationManager.OpenWebConfiguration("~/", "siteAdi") dier versiyonlar
kullanlarak ilgili
siteye username ve
password bilgiside
iletilebilinir.

Var olan web


uygulamasndaki
Admin klasrnde iin
WebConfigurationManager.OpenWebConfiguration("~/", null, "/Admin")
web.config' de
yazlm location
boumunu aar.

Framework altndaki
WebConfigurationManager.OpenMachineConfiguration() machine.config
dosyasn aar.

Tabloda belirtilen rnek kullanmlar oaltlabilir. Sonu itibariyle OpenWebConfiguration


metodunun alt farkl ar yklenmi versiyonu vardr. Buradaki nemli noktalardan biriside,
OpenWebConfiguration ve OpenMachineConfiguration gibi static metodlarn
geriye Configuration tipinden bir nesne rnei gnderiyor olulardr. Configuration snfna ait bu
nesne rnekleri sayesinde alan config uzantl dosya zerinde istediimiz ynetimsel ilemleri
(dzenleme, kaydetme, elde etme gibi) gerekletirebiliriz. imdi ilk olarak konfigurasyon
dosyalarnda ska kullandmz appSettings ve connectionStrings ksmlarn nasl
ynetebileceimizi greceiz. Bunun iin web.config dosyasndaki appSettings ve connectionStrings
ksmlarna aada grld gibi rnek bir ka veri gireceiz.

<appSettings>
<add key="mailGonderici" value="on"/>
<add key="varsayilanMail" value="admin@admin.com"/>
<add key="varsayilanHataSayfasi" value="hataSayfasi.aspx"/>
</appSettings>
<connectionStrings>
<add name="AdvConStr" connectionString="data
source=localhost;database=AdventureWorks;integrated security=SSPI"
providerName="System.Data.SqlClient"/>
<add name="NorthConStr" connectionString="data
source=localhost;database=Northwind;integrated security=SSPI"
providerName="System.Data.OleDb"/>
</connectionStrings>

Uygulama kodlarmz da aadaki kod parasnda olduu gibi dzenleyelim.

www.bsenyurt.com Page 1515


using System;
using System.Configuration;
using System.Web.Configuration;

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


{
// lk olarak bizim iin gerekli deikenleri tanmlyoruz.
private Configuration _config;
private AppSettingsSection _appSec;
private ConnectionStringsSection _conSec;

// Uygulamaya ait web.config dosyas ierii _config isimli Configuration tipine ait nesne
rneine alnr.
private void GetConfig()
{
if(_config==null)
_config = WebConfigurationManager.OpenWebConfiguration("/ConfigMngAPI");
}

// web.config dosyas ierisinden appSettings ksm ekilerek AppSettingsSection tipinden


_appSec isimli bir nesne rneine atanr.
private void GetAppSettingsSection()
{
if(_appSec==null)
_appSec = _config.AppSettings;
}

// web.config dosyasndan connectionStrings ksm ekilerek ConnectionStringsSection tipinden


_conSec isimli nesne rneine atlr.
private void GetConnectionSection()
{
if (_conSec == null)
_conSec = _config.ConnectionStrings;
}
// appSettings ksmndaki key bilgileri Settings zellii zerinden gidilen AllKeys zellii ile alnr
ve DropDownList kontrolne set edilir.
private void LoadAppSettings()
{
GetConfig();
GetAppSettingsSection();
ddlAppSettingsKeys.DataSource = _appSec.Settings.AllKeys;
ddlAppSettingsKeys.DataBind();
}

// connectionString sekmesindeki bilgileri tayan _conSec nesnesi kullanlarak Name alanlarn


ieren veri seti DropDownList kontrolne balanr.
private void LoadConSettings()
{
GetConfig();

www.bsenyurt.com Page 1516


GetConnectionSection();
ddlConnectionKeys.DataSource = _conSec.ConnectionStrings;
ddlConnectionKeys.DataTextField = "Name";
ddlConnectionKeys.DataValueField = "Name";
ddlConnectionKeys.DataBind();
}
// AppSettings ksmndaki key deerlerini gsteren DropDownList kontrolnde seilen anahtar
bilgisine gre Value deeri elde edilir.
private void GetAppSetInfo()
{
GetConfig();
GetAppSettingsSection();
txtAppSetValue.Text = _appSec.Settings[ddlAppSettingsKeys.SelectedValue].Value;
}

// DropDownList kontrolnden seilen name deerine gre, web.config dosyasndaki


connectionStrings sekmesinden ilgili connectionString, name ve providerName bilgileri ekilir.
private void GetConStrInfo()
{
GetConfig();
GetConnectionSection();
txtConStrValue.Text =
_conSec.ConnectionStrings[ddlConnectionKeys.SelectedValue].ConnectionString;
lblConStrName.Text =
_conSec.ConnectionStrings[ddlConnectionKeys.SelectedValue].Name;
lblProviderName.Text =
_conSec.ConnectionStrings[ddlConnectionKeys.SelectedValue].ProviderName;
}

protected void Page_Load(object sender, EventArgs e)


{
if (!Page.IsPostBack)
{
LoadAppSettings();
LoadConSettings();
GetAppSetInfo();
GetConStrInfo();
}
}
protected void ddlAppSettingsKeys_SelectedIndexChanged(object sender, EventArgs e)
{
GetAppSetInfo();
}
protected void ddlConnectionKeys_SelectedIndexChanged(object sender, EventArgs e)
{
GetConStrInfo();
}
}

www.bsenyurt.com Page 1517


Dikkat ederseniz web.config dosyas ierisindeki ksmlar ele almak iin elde edilen Configuration'
tipinden faydalanlmtr. zellikle appSettings ve connectionStrings sekmeleri ok sk
kullanldndan bunlara dorudan eriimi salayan zellikler mevcuttur. Bu zelliklerin geri dn
tiplerine dikkat ederseniz, AppSettingsSection veConfigurationStringsSection tipinden
olduklarn grebiliriz. Dolaysyla bu tipler zerinden de bizim iin gerekli temel bilgilere gei
yapabiliriz. rnein seilen balantya ait connectionString bilgisi, salayc ad (providerName)
vb... gibi. Uygulamamz bu haliyle ilk altrdmzda aadaki ekran grntsne benzer bir
sonu elde ederiz.

Elbette Configuration API' si ierisinde var olan web.config sekmelerine karlk gelen tipler
tanmlanmtr. Baka konfigurasyon bazl dosyalara ekleyeceimiz kendi sekmelerimizde elde
edebileceimiz teknikler mevcuttur. Bunun iin rnein GetSection metodundan yararlanabiliriz.
u anki rneimiz basit olarak web.config dosyas ierisinde yer alan bilinen ksmlardan,
ConnectionStrings ve AppSettings paralarna ait bilgileri okuyabilmemizi salamaktadr. Bir
sonraki admmzda ise bu bilgiler zerinde deiiklik yaparak tekrardan web.config dosyasna
yazma ilemini ele alacaz. Bunun iin uygulamamza aadaki metodlar eklememiz yeterli
olacaktr.

// lk olarak AppSettingsSection tipine ait nesne rnei zerinden DropDownList' ten seilen key
bilgisinin value zelliinin deeri TextBox' tan alnr. Burada kayt ilemini web.config zerinde
gerekletirilmesi iin mutlaka Configuration tipinen ait Save metodu arlmaldr.
protected void btnChangeAppSet_Click(object sender, EventArgs e)
{
GetConfig();
GetAppSettingsSection();
_appSec.Settings[ddlAppSettingsKeys.SelectedValue].Value = txtAppSetNewValue.Text;
_config.Save();
GetAppSetInfo();

www.bsenyurt.com Page 1518


}

// ConnectionString bilgisindede deiiklik yapmak iin ConnectionStringsSection tipinden


yararlanlr. Bu tipe ait nesne rnei yardmyla DropDownListe' ten seilen connectionString bilgisi
yakalanr ve ConnectionString zelliine yeni deeri atanr. Son olarak deiikliklerin web.config
dosyasna yanstlabilmesi iin Configuration tipine ait Save metodu altrlmaldr.
protected void btnChangeConStr_Click(object sender, EventArgs e)
{
GetConfig();
GetConnectionSection();
_conSec.ConnectionStrings[ddlConnectionKeys.SelectedValue].ConnectionString =
txtNewConStrValue.Text;
_config.Save();
GetConStrInfo();
}

Artk uygulamamzda yer alan web.config dosyas ierisindeki connectionStrings ve appSettings


sekmelerindeki verilerde deiiklik yapabiliriz. Buradaki hassas nokta eriilen bilgini deiiklie
uramasn takiben Configuration tipinin Save metodunun arlm olmasdr. Bylece, yaplan
deiiklikler kesin olarak Configuration tipine ait nesne rneinin o anda iaret ettii konfigurasyon
dosyasna (ki burada web.config dosyasdr) yazlmaktadr. (Not : Aadaki grnty
seyredebilmek iin taraycnzda Flash Player' n son srmnn olmas tavsiye edilir. Eer
sisteminizde XP Service Pack 2 yklyse ilgili uyary dikkate alp ierie izin vermelisiniz. (Allow
Blocked Content). Videoyu ynetmek iin sa tklayp kan meny kullanabilirsiniz. Video Boyu
130 kb.)

www.bsenyurt.com Page 1519


Yukardaki rneklerimizde ok bilinen appSettings ve connectionStrings ksmlarn ele aldk.
rnein sessionState ksmnda ele almak istediimizi dnelim. Byle bir durumda Configuration
tipi sessionState iin bir zellik sunmaz. Bunun yerine konfigurasyon dosyasndaki herhangibir
ksmn ieriini ConfigurationSection tipinden elde etmemizi ve uygun tipe dntrmemizi
salayan GetSection metodundan yararlanabiliriz. Aadaki kod paras bu ilemi nasl
yapacamz gstermektedir.

SessionStateSection _sesSec =
(SessionStateSection)_config.GetSection("system.web/sessionState");
lblSessionSecInfo.Text = "<b> Session Mode : </b> " + _sesSec.Mode.ToString() + "<br>" +
"<b>Cookieless : </b>" + _sesSec.Cookieless.ToString();

Burada sessionState ksmn ynetmemizi salayan SessionStateSection tipi mevcuttur. Yanlz


GetSection metodu geriye ConfigurationSection tipinden bir ye dndrd iin bunun ilgili
tiplere dntrlmesi (casting) gerekir. Bu yzden SessionStateSection tipine aka bir
dntrme ilemi uygulanmtr. Sonrasnda ise elde edilen _sesSec isimli tip yardmyla bir
sessionState sekmesi iin geerli standart niteliklere kolayca eriebiliriz. rnein Cookiless
zelliine yada Mode zelliine. Burada bir dier nemli noktada sessionState sekmesine nasl
eritiimizdir. Bu ksm web.config ierisinde system.web boumu ierisinde yer aldndan
system.web/sessionState ifadesi ile yakalanmaktadr.

www.bsenyurt.com Page 1520


Dilersek web.config ierisindeki ksmlar ifreli (encrypt) olarakta kayt edebilir hatta ifrelenmi
veriyi alma zamannda dzgn bir biimde okuyabiliriz. Bu ilemler iin var olan section tiplerinin
(AppSettingsSection, ConnectionStringsSection gibi) SectionInformation isimli
zelliklerinin ProtectSection isimli bir ye metodu kullanlr. ifrelenmi verileri zebilmek iin ise
SectionInformation isimli zelliinin UnprotectSection isimli ye metodundan yararlanabiliriz.
Konuyu daha iyi anlayabilmek iin aadaki rnek kod parasn ele alalm. Bu kod parasnda
web.config dosyas ierisindeki AppSettingsSection ve ConnectionStringsSection ksmlarnn
encrypt ve decrypt ilemleri iin gerekli dzenlemeler yer almaktadr.

// ConnectionStrings sekmesini varsaylan RSA sistemine gre ifreler. Bunun iin ilgili ksmn
SectionInformation zelliinin ProtectSection metodu kullanlr.
protected void btnProtectConn_Click(object sender, EventArgs e)
{
GetConfig();
GetConnectionSection();
if (!_conSec.SectionInformation.IsProtected)
{
_conSec.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
_config.Save();
}
else
Response.Write("ConnectionStrings zaten ifrelenmitir...");
}

// Bu kez ifrelenmi olan ConnectionStrings sekmesi zlerek web.config tekrar kaydedilir.


protected void btnUnprotectConn_Click(object sender, EventArgs e)
{
GetConfig();
GetConnectionSection();
if (_conSec.SectionInformation.IsProtected)
{
_conSec.SectionInformation.UnprotectSection();
_config.Save();
}
else
Response.Write("ConnectionStrings zaten ifresiz tutulmaktadr...");
}

// AppSettings sekmesini varsaylan RSA sistemine gre ifreler. Bunun iin ilgili ksmn
SectionInformation zelliinin ProtectSection metodu kullanlr.
protected void btnProtectAppSet_Click(object sender, EventArgs e)
{
GetConfig();
GetAppSettingsSection();

www.bsenyurt.com Page 1521


if (!_appSec.SectionInformation.IsProtected)
{
_appSec.SectionInformation.ProtectSection("RsaProtectedConfigurationProvider");
_config.Save();
}
else
Response.Write("AppSettings zaten ifrelidir...");
}
protected void btnUnprotectAppSet_Click(object sender, EventArgs e)
{
GetConfig();
GetAppSettingsSection();
if (_appSec.SectionInformation.IsProtected)
{
_appSec.SectionInformation.UnprotectSection();
_config.Save();
}
else
Response.Write("AppSettings zaten ifreli deil...");
}

Uygulamamz bu haliyle altrp rnein connectionStrings ve appSettings ksmlarn


ifrelediimizde web.config dosyasnn aadakine benzer bir yapya brndn grrz. Burada
Protect metodunda parametre olarak RsaProtectedConfigurationProvider kullanlmtr. Bu
provider seimi ile RSA algoritmasn baz alarak ifreleme ve zme ilemlerinin gerekletirilecei
belirtilmektedir. Elbetteki burada kendi zel koruma salayclarmz (Custom Protection Provider)
da kullanabiliriz.

www.bsenyurt.com Page 1522


Grld gibi connectionStrings ve appSettings ksmlar iin ifreleme ilemleri yaplm ve key,
value, name, providerName, connectionString gibi niteliklerin (attributes) ierii okunamaz hale
getirilmitir. Lakin, alma zamannda ConnectionStringsSection tipine ait nesne rnei
zerinden ilgili balant bilgilerini kolayca okuyabiliriz. Ayn durum appSettings ksm iinde
geerlidir. Dolaysyla buradaki ifreleme ilemleri sadece ve sadece web.config dosyasnn
dardan plak gzle okunmas srasnda nem kazanmaktadr. Web.config dosyasn istemcilerin
elde etmesi zaten pek mmkn deildir. Yine de web.config dosyasndaki baz hassas bilgileri
korumak adna yukardaki tekniklerden yararlanlabilinir.

Bazen konfigurasyon dosylarnda yer alan ksmlarn, Configuration API ierisinde karl olan
tipler olmayabilir. Bu ounlukla Asp.Net 1.1 den 2.0' a geirilen projelerde rastlanabilecek bir
durumdur. ( Dahas web.config dosyas darsnda kullandmz xml konfigurasyonlar varsa daha
geerli bir durumdur. ) Dolaysyla byle hallerde ilgili ksmlarn ham XML ieriini ele almak
gerekebilir. Eer ilgili ksmn Configuration API ierisinde yer alan bir karl yok ise
yine ConfigurationSection tipinden yararlanabiliriz. Temel olarak ConfigurationSection tipine ait
nesne rneklerini Configuration tipinin GetSection metodu ile elde edebilmekteyiz. Aadaki kod

www.bsenyurt.com Page 1523


paralar bu ilemin nasl gerekletirilebileceini gstermektedir. rnek olarak yine appSettings ve
connectionStrings paralarn ele alyoruz.

// AppSettings ksmnn ham XML ieriini elde etmek iin SectionInformation zelliinin
GetRawXml metodu kullanlr.
protected void btnGetAppSetRawXml_Click(object sender, EventArgs e)
{
GetConfig();
ConfigurationSection cfgSec = _config.GetSection("appSettings");
lblAppSetRawXml.Text = Server.HtmlEncode(cfgSec.SectionInformation.GetRawXml());
}
// ConnectionStrings ksmnn ham XML ieriini elde etmek iin SectionInformation zelliinin
GetRawXml metodu kullanlr.
protected void btnGetConStrRawXml_Click(object sender, EventArgs e)
{
GetConfig();
ConfigurationSection cfgSec = _config.GetSection("connectionStrings");
lblConStrRawXml.Text = Server.HtmlEncode(cfgSec.SectionInformation.GetRawXml());
}

Yanlz burada dikkat etmemiz gereken bir nokta vardr. O da GetSection metodunun mutlaka ve
mutlaka, ilgili ksmn web.config ierisindeki harf duyarl (case-sensitive) bilgisini almak
zorunda oluudur. rnein connectionStrings yerine ConnectionStrings yazdmzda alma
zamannda aadaki hata mesajn alrz.

Uygulamamz bu haliyle altrdmzda aadaki ekran grntsnde olduu gibi appSettings ve


connectionStrings sekmelerinin ham Xml ieriklerini elde edebileceimizi grrz.

www.bsenyurt.com Page 1524


IIS kendi ierisinde bir web uygulmasnn ayarlarn deitirmemizi salayacak bir ynetim konsolu
(management Console) ierir. Asp.Net Microsoft Management Console Snap-In' i sayesinde
web.config ierisindeki ayarlar grsel arabirimi kullanarak IIS zerinden de deitirebiliriz.

www.bsenyurt.com Page 1525


Bu konsol sayesinde aadaki resimden de grlebilecei gibi hemen hemen tm ksmlara
(sections) ait deiiklikleri kolayca gerekletirebilmekteyiz. Bu elbette IIS zerinde var olan bir
ynetimsel ara birimdir ve zaman zaman tercih edebiliriz. Ama zellikle kendi web
uygulamalarmz uzaktan ynetmek istediimiz durumlarda, yonetim (admin) sayfalarndan
web.config gibi dosyalara daha kolay ve gl bir ekilde de hkmedebilmeliyiz. Bu sebepten dolay
Configuration API' nin gelitirilmesi ve geniletilmesinin son derece isabetli olduu kansndaym.

www.bsenyurt.com Page 1526


Bu makalemizde temel olarak Asp.Net 2.0 ile gelen yeni konfigurasyon alt yapsn (Configuration
API) incelemeye altk. Eer bu API ierisindeki tipleri ve yelerini inceleyecek olursanz, aslnda
bir sistemin tm konfigurasyon ayarlarn ok kolay ve etkin bir ekilde programatik olarak
yapabileceimizi grrsnz. zellikle xml tabanl konfigurasyon ieriklerini her hangi bir ayrtrma
(parsing) ilemine gerek duymadan ynetebilecek tiplerle sahip olmak son derece etkili ve verimli
bir gelitirme ortam salayacaktr. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

.Net Remoting - SoapSuds ( 21.06.2006 ) -


Remoting
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1527


Remoting mimarisinde, istemci ve sunucu arasnda uzak nesneleri paylamann drt farkl yolu
vardr. stemcilerin tek amac sunucu zerinde yer alan uzak nesne referanslarn kullanabilmektir.
Bu adan bakldnda, istemci uygulamann uzak sunucu zerindeki nesne referanslarnn yapsn
bilmesi gerektii ortaya kmaktadr. Kullanlabilecek yollardan ilki uzak nesne snfnn bulunduu
paylaml bir assembly' tm istemci uygulamalara datmaktr. Bu istemci uygulamalar iin ekstra
kod yazmadan kolayca gerekletirilebilecek bir ilemdir. Lakin istemci uygulamalarda, uzak snfn
tm ieriinin yer ald bir assembly' da mevcuttur. Bu da ILDASM (Intermediate Dis-Assembler
Tool) ve baka nc parti aralar yardmyla i mantnn (business logic) istemci tarafndan
kolayca okunabilecei anlamna gelir. te bu dezavnataj nedeni ile zellikle gvenlik asndan
ou zaman bu teknik tercih edilmez.

kinci yntem ve belkide en popler olan, uzak snf modelinin tretildii bir interface tipini istemci
ve sunucu arasnda paylama sunmaktr. Yani istemci tarafnda sadece ve sadece uzak nesne
modelinin bilgisini tutan bir interface tipi yer alacaktr. Bu modele gre uzak sunucu zerindeki
uzak nesne referansna polimorfizm' in bir sonucu olarak interface tipi zerinden eriebilinir. Ama
daha da nemlisi istemci tarafnda, uzak nesne ierisindeki kodlarn kesinlikle grnmyor
oluudur. Bu da doal olarak i mantn istemciden gizleyen etkili bir tekniktir. .Net Remoting
uygulamalarn yazarken ounlukla interface kullanm tercih edilmektedir.

nc model abstract modeli ele alr ve zellikle nesne retiminin istemciden soyutlanmas sz
konusu ise Fabrika Tasarm Desenini (Factory Design Pattern) uygular. Bu model ierisinde,
interface modeline benzer olarak istemci tarafndan i mant ve zellikle uzak nesnenin retili
biimi soyutlanmaktadr. Ne yazkki bu modelin uygulanmas ou zaman kolay deildir. nk
daha ileri seviye kod yazmn gerektirmektedir. Bu modelin kullanlabilmesi iin abstract mimari,
tasarm desenleri gibi kavramlara aina olmak gerekir.

Drdnc ve son model ise istemci tarafndaki uygulamalarn, kullanmak istedikleri uzak nesneye
ait metadata bilgisini salayan SoapSuds aracn ele alr. Bu modelde, istemci tarafnda uzak
nesneye ait sadece tip ve ye bilgilerini ieren bir assembly sz konusudur. Yani istemci tarafnda
sadece uzak nesneye ait metadata bilgisi yer alr. Bu da elbetteki i mantn istemciden gizleyen
bir modeldir. Ancak zellikle interface ve abstract modelinin etklinlii nedeni ile SoapSuds modeli
deerini kaybetmektedir. Yinede SoapSuds modelini bilmekte yarar vardr. te bu makalemizde
SoapSuds modelini incelemeye alacaz. Bu modeller arasnda elbetteki bir takm avantaj ve
dezavantajlar sz konusudur. rnein interface , abstract veya soapSuds modelleri balantsz
almaya izin vermezler. Bunun en byk nedeni elbette i yapacak nesnel kodlarn istemci
tarafnda bulunmaydr. Bu tip bir ihtiyaca ancak ve ancak Paylaml Assembly modeli cevap
verecektir. Ancak .Net Remoting uygulamalarnn tasarm amac dnldnde bu son derece u
bir rnektir. Bahsedilen drt model arasndaki temel farkllklar ve birbirlerine olan stnlklerini
aadaki tabloda zet olarak bulabilirsiniz.

Model Dezavantajlar Avantajlar

Paylaml Assembly stemci tarafndan i mantnn Gelitirme kolayl. Balantl ve


(Shared Assembly) grlebilmesi. balantsz alma destei.

Balantl ve balantsz katman stemci tarafndan i mantnn


Interface
modeline cevap verememesi. gizlenmesi (security).

Balantl ve balantsz katman


mantnn gizlenmesi (security) ve
modeline cevap verememesi.
Abstract uzak nesne retim ilemlerinin
soyutlanmas.
Kodlamann zor oluu.

www.bsenyurt.com Page 1528


Balantl ve balantsz katman
modeline cevap verememesi.
mantnn istemci tarafndan
SoapSuds
gizlenmesi. (security).
Wrapped proxy seeneinde
sadece HTTP destei olmas.

SoapSuds modelinde, istemci tarafnda uzak nesneye ait metadata' y ieren bir assembly retimi
sz konusudur. Framework ile gelen SoapSuds aracnn en temel amac bu assembly' retmektir.
Burada retilen assembly aslnda fiziki bir proxy nesnesi grevini stlenir. Proxy' nin iki farkl
retili ekli vardr. Wrapped Proxy yada Non-Wrapped Proxy. Wrapped Proxy tipinde, sadece SOAP
ve HTTP protokol desteklenmektedir. Bunun dnda bu modeli uygularken istemci tarafnda
channel, port gibi konfigurasyon ayarlarnn yaplmasna gerek kalnmaz. nk bu tip bilgiler
WSDL talebi sonucu retilen Proxy Assembly' n ierisine kaydedilmektedir. Non-Wrapped Proxy
modeli ise hem HTTP hem de TCP protokolne destek verebilmektedir(Teorik Olarak). Non-
Wrapped Proxy modelinde,Wrapped Proxy Assembly' da yaplmayan konfigurasyon ayarlarnn da
yaplmas gerekir. Hangi tip olursa olsun sonu itibariyle SoapSuds modeli, istemcinin uzak nesneyi
kullanabilmesi iin gerekli bilgileri ieren bir metadata salar ve bunu kullanarak bir proxy
assembly retir. imdi dilerseniz SoapSuds modelini rnekler zerinde incelemeye alalm. lk
olarak rneklerimizde kullanacamz uzak nesneye ait snfmz ve sunucu uygulamamz
tasarlayarak ie balayacaz.

Uzak nesne snf kodlar;

namespace RemoteObjects
{
public class Matematik:MarshalByRefObject
{
public Matematik()
{
Console.WriteLine("Uzak nesne yapc metod arld...");
}
public double Toplam(double deger1, double deger2)
{
return deger1 + deger2;
}
}

www.bsenyurt.com Page 1529


}

Sunucu Uygulama;

class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("..\\..\\App.config",false);
Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
}
}

Sunucu Konfigurasyon bilgisi;

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


<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="Http Server" port="9800"/>
</channels>
<service>
<wellknown type="RemoteObjects.Matematik,RemoteObjects"
objectUri="Matematik.soap" mode="Singleton"/>
</service>
</application>
</system.runtime.remoting>
</configuration>

imdi ilk olarak SopaSuds aracn sunucu zerinde altryor ve Wrapped Proxy' mz retiyoruz.
Bunun iin Visual Studio.2005 Command Prompt' u kullanabiliriz. SoapSuds aracn kullanrken
Proxy Assembly' retebilmemiz iin Sunucu uygulamann mutlaka alyor olmas gerekmektedir.
Bu arada yazdmz komut satrndaki SOAP uzantsna ve WSDL (Web Service Description
Language) talebine dikkat edelim. Burada oa anahtar Output Assembly anlamna gelmektedir.

Komut : SoapSuds -url:http://manchester:9800/Matematik.soap?wsdl -oa:MatMetaData.dll

www.bsenyurt.com Page 1530


Komutu uygularken dikkat ederseniz ?wsdl taks kullanlyor. Bunun sebebi Metadata' nn SOAP
zerinden elde edilen WSDL dkmanna baklarak kartlmasdr. Eer tarayc penceresinden
http://manchester:9800/Matematik.soap?wsdl yazarsanz aadakine bezner bir ekran grnts
elde edersiniz. Bu web servislerinden aina olduumuz WSDL dkmandr.

Bu ilemin ardndan komutu altrdmz klasrde MatMetaData.dll isimli bir assembly


oluturulduunu grebiliriz. Bu Wrapped Proxy trndendir. imdi ILDASM arac yardmyla
MatMetaData.dll ve RemoteObjects.dll' lerini birbirleriyle karlatralm.

www.bsenyurt.com Page 1531


lk olarak ktlarn ayn olmad hemen gze arpmaktadr. SoapSuds rettii assembly ierisine
WSDL' i kullanarak uzak nesneye nasl erieceine dair bilgiler ieren ek yeler atmtr. Dahas
Matematik snf ierisindeki Constructor ve Toplam metodlarnn MsIL kodlarna bakacak olursak,
ye ii kodlarn yanstlmadn kolayca grebiliriz. Buda istemcinin, uzak nesne i mantna ait
kodlar asla gremeyecei anlamna gelmektedir.

MatMetaData.dll' i iindeki Matematik snf iin Constructor ierii;

.method public hidebysig specialname rtspecialname


instance void .ctor() cil managed
{
// Code size 28 (0x1c)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void
[System.Runtime.Remoting]System.Runtime.Remoting.Services.RemotingClientProxy::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldarg.0

www.bsenyurt.com Page 1532


IL_0009: ldarg.0
IL_000a: call instance class [mscorlib]System.Type [mscorlib]System.Object::GetType()
IL_000f: ldstr "http://manchester:9800/Matematik.soap"
IL_0014: call instance void
[System.Runtime.Remoting]System.Runtime.Remoting.Services.RemotingClientProxy::ConfigurePr
oxy(class [mscorlib]System.Type,
string)
IL_0019: nop
IL_001a: nop
IL_001b: ret
} // end of method Matematik::.ctor

RemoteObjects.dll iindeki Matematik snf iin Constructor ierii

.method public hidebysig specialname rtspecialname


instance void .ctor() cil managed
{
// Code size 21 (0x15)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [mscorlib]System.MarshalByRefObject::.ctor()
IL_0006: nop
IL_0007: nop
IL_0008: ldstr bytearray (55 00 7A 00 61 00 6B 00 20 00 6E 00 65 00 73 00 // U.z.a.k. .n.e.s.
6E 00 65 00 20 00 79 00 61 00 70 00 31 01 63 00 // n.e. .y.a.p.1.c.
31 01 20 00 6D 00 65 00 74 00 6F 00 64 00 20 00 // 1. .m.e.t.o.d. .
E7 00 61 00 1F 01 31 01 72 00 31 01 6C 00 64 00 // ..a...1.r.1.l.d.
31 01 2E 00 2E 00 2E 00 ) // 1.......
IL_000d: call void [mscorlib]System.Console::WriteLine(string)
IL_0012: nop
IL_0013: nop
IL_0014: ret
} // end of method Matematik::.ctor

MatMetData.dll iindeki Matematik snf iin Toplam metodu ierii;

.method public hidebysig instance float64


Toplam(float64 deger1,
float64 deger2) cil managed
{
.custom instance void [mscorlib]System.Runtime.Remoting.Metadata.SoapMethodAttribute::.ctor()
= ( 01 00 01 00 54 0E 0A 53 6F 61 70 41 63 74 69 6F // ....T..SoapActio
6E 55 68 74 74 70 3A 2F 2F 73 63 68 65 6D 61 73 // nUhttp://schemas
2E 6D 69 63 72 6F 73 6F 66 74 2E 63 6F 6D 2F 63 // .microsoft.com/c
6C 72 2F 6E 73 61 73 73 65 6D 2F 52 65 6D 6F 74 // lr/nsassem/Remot
65 4F 62 6A 65 63 74 73 2E 4D 61 74 65 6D 61 74 // eObjects.Matemat
69 6B 2F 52 65 6D 6F 74 65 4F 62 6A 65 63 74 73 // ik/RemoteObjects

www.bsenyurt.com Page 1533


23 54 6F 70 6C 61 6D ) // #Toplam
// Code size 24 (0x18)
.maxstack 3
.locals init ([0] float64 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.0
IL_0002: ldfld object
[System.Runtime.Remoting]System.Runtime.Remoting.Services.RemotingClientProxy::_tp
IL_0007: castclass RemoteObjects.Matematik
IL_000c: ldarg.1
IL_000d: ldarg.2
IL_000e: callvirt instance float64 RemoteObjects.Matematik::Toplam(float64,
float64)
IL_0013: stloc.0
IL_0014: br.s IL_0016
IL_0016: ldloc.0
IL_0017: ret
} // end of method Matematik::Toplam

RemoteObjects.dll iindeki Matematik snf iin Toplam metodu ierii;

.method public hidebysig instance float64


Toplam(float64 deger1,
float64 deger2) cil managed
{
// Code size 9 (0x9)
.maxstack 2
.locals init ([0] float64 CS$1$0000)
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: add
IL_0004: stloc.0
IL_0005: br.s IL_0007
IL_0007: ldloc.0
IL_0008: ret
} // end of method Matematik::Toplam

Dikkat ederseniz, retilen Wrapped Proxy ierisinde SOAP zerinden HTTP protokoln kullanarak
yaplacak ye arlar iin gerekli bilgiler yer almaktadr. imdi retilen bu Wrapped Proxy' rnek
bir istemcide kullanalm. ncelikle yapmamz gereken SoapSuds ile retilen Wrapped Proxy'
istemci uygulamamza referans etmek olacaktr.

www.bsenyurt.com Page 1534


stemci uygulama;

using System;
using System.Collections.Generic;
using System.Text;
using RemoteObjects;

namespace ClientApp
{
class Program
{
static void Main(string[] args)
{
Matematik mt = new Matematik();
Console.WriteLine(mt.Toplam(3, 4).ToString());
Console.ReadLine();
}
}
}

Burada dikkat ederseniz sradan istemci uygulamalarndaki remoting iin gerekli hi bir
konfigurasyon ayar yoktur. Oysaki kanal bilgisinin (channel) ya da SAO(Server Activated Object)
veya CAO (Client Activated Object) iin gerekli kayt ilemlerinin yaplm olmas gerekmektedir.
Bunlarn yaplmaynn nedeni, uzak nesneyi kullanabilmek iin gerekli eriim bilgilerinin,
SoapSuds ile retilen Wrapped Proxy ierisinde olmasdr. imdi remote uygulamamz test
edebiliriz. (Aadaki videoyu izleyebilmek iin Flash Player gereklidir.)

www.bsenyurt.com Page 1535


Grld gibi, istemci uygulama altnda sunucu zerinde Matematik snfna ait yapc metod
altrlmtr. Bu, istemcinin gerekten sunucu zerindeki bir referans kullandnn kantdr.
Dahas, sunucuyu altrmadan istemci uygulamay altrmay
denerseniz, "System.Net.Sockets.SocketException: No connection could be made becaus
e the target machine actively refused it" istisnasn alrsnz ki buda remote sistemin gerekten
tamaland anlamna gelir.

Gelelim Non-Wrapped Proxy modeline. Bu modelde, retilen assembly ierisinde sadece snfa ait
metadata bilgisi bulunur. Dolaysyla, Wrapped Proxy' lerde olduu gibi sadece HTTP protokolne
bal deildir. TCP protokolnde ele alabiliriz. Non-Wrapped Proxy kullanrken istemci tarafnda
gerekli konfigurasyon ayalar da yaplmaldr. Bu sayede sunucu zerinde meydana gelecek kanal
ve port deiikliklerini istemci tarafnada yanstabiliriz. Oysaki Wrapped proxy tipine gre SoapSuds
arac ile metadata' y ieren assembly' yeniden retmemiz ve datmamz gerekecektir. Yukardaki
rneimizi ele aldmzda, Non-Wrapped Proxy' imizi oluturmak iin SoapSuds aracn aadaki
ekilde kullanmamz yeterlidir. SoapSuds arac yardmyla Assembly' n retilebilmesi iin nceden
sunucu uygulamann alyor olmas gerektiini ltfen unutmaynz. Non-Wrapped Proxy retimi
iin SoapSuds aracnda -nowp anahtar kullanlr.

Komut : SoapSuds -nowp -url:http://localhost:9800/Matematik.soap?wsdl -


oa:MatMetaDataNoWp.dll

www.bsenyurt.com Page 1536


imdi oluan MatMetaDataNoWp.dll isimli assembly' mz yine ILDASM arac yardmyla inceleyelim.

Grld gibi tek fark Wrapped Proxy' de yer alan get_RemotingReference metodu ile
RemotingReference nesnesinin Non-Wrapped Proxy ierisinde olmaydr. Dolaysyla, istemci

www.bsenyurt.com Page 1537


tarafndaki uygulamamzda gerekli konfigurasyon ayarlarn yapmamz gerekecektir. Bu amala
istemci tarafna aadaki konfigurasyon dosyasn ekleyelim. Elbette type parametresini belirtirken
Assembly ad olarak oluturulan Non-Wrapped Proxy Assembly' nn adn vermemiz gerekecektir.

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


<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="Http Client"/>
</channels>
<client>
<wellknown type="RemoteObjects.Matematik,MatMetaDataNoWp"
url="http://manchester:9800/Matematik.soap"/>
</client>
</application>
</system.runtime.remoting>
</configuration>

Daha sonra ise, yeni proxy assembly' mzn dll dosyasn istemci uygulamamza referans etmemiz
gerekiyor. ( nceki rneimizde retilen Assembly' da ayn isim alann ve snf ierdiinden
karlk olmamas amacyla MatMetaData.dll referans bu rnek iin kaldrlmtr.)

imdi istemcimize ait kodlar aadaki gibi deitirelim.

RemotingConfiguration.Configure("..\\..\\App.config",false);
Matematik mt = new Matematik();
Console.WriteLine(mt.Toplam(3, 4).ToString());

Uygulamamz test ettiimizde remoting sisteminin baarl bir ekilde altn grebiliriz. Her
zamanki gibi uzaktan eriimi ispat etmek iin, sunucu uygulamay altrmadan istemci uygulamay
altrmanz neririm. Grld gibi SoapSuds modelinde Wrapped Proxy ya da Non-Wrapped
Proxy' lerin bir birlerine gre temel baz farkllklar bulunmaktadr. Son olarak SoapSuds arac
yardmyla uzak nesne snfna ait bir kaynak kodun istemci tarafna tanabileceinide berlirtmek
istiyorum. Bunun iin -gc (Generate Class) anahtarn kullanmak yeterlidir. rnein sunucu
uygulamamz alrken komut satrndan aadaki satr altralm.

Komut : SoapSuds -nowp -url:http://localhost:9800/Matematik.soap?wsdl -gc

www.bsenyurt.com Page 1538


Bunun sonucu olarak cs uzantl bir kaynak kod dosyas oluur. Dosyann ierii aadakine benzer
olacaktr.

using System;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Metadata;
using System.Runtime.Remoting.Metadata.W3cXsd2001;
using System.Runtime.InteropServices;
namespace RemoteObjects
{
[Serializable,
SoapType(XmlNamespace=@"http://schemas.microsoft.com/clr/nsassem/RemoteObjects/Remote
Objects%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull"
,
XmlTypeNamespace=@"http://schemas.microsoft.com/clr/nsassem/RemoteObjects/RemoteObject
s%2C%20Version%3D1.0.0.0%2C%20Culture%3Dneutral%2C%20PublicKeyToken%3Dnull")][Co
mVisible(true)]
public class Matematik : System.MarshalByRefObject
{
[SoapMethod(SoapAction=@"http://schemas.microsoft.com/clr/nsassem/Remote
Objects.Matematik/
RemoteObjects#Toplam")]
public Double Toplam(Double deger1, Double deger2)
{
return((Double) (Object) null);
}
}
}

Dolaysyla istemci tarafndan oluan bu isim alan ve ieriini dorudan kullanabilir yada bu kaynak
kod dosyasnda bir assembly retip onu kullanmay tercih edebiliriz. Tabi byle bir durumda aynen
Non-Wrapped Proxy modelinde olduu gibi istemci taraf iin gerekli konfigurasyon ayarlarnn
bildirilmesi gerekmektedir. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Profile API ile Personalization ( 02.06.2006 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Gnmz web uygulamalarnda, kullanc bazl kiiselletirme (personalization) olduka nemli ve


popler bir konudur. rnein, bir elektronik ticaret sitesini ziyaret ettiimizi dnelim. Bu site bir
sonraki ziyaretimizde, daha nceden bakm olduumuz rnler ile ilikili yeni nerilerde

www.bsenyurt.com Page 1539


bulunabilir. Bylece siteye giren kullanclar baka rnlere ynlendirebilir. Yeni nerilerin
sunulabilmesi, sitenin bizim alkanlkarmz takip etmesi ve kendisini buna gre deitirmesi
anlamna gelmektedir. Daha ak bir ekilde sylemek gerekirse bu site, yelerin zelliklerine gre
kiisellemektedir. Buna rnek olabilecek en gzel sitelerden birisi amazon.com' dur. Bir sitenin,
yelerinin isteklerine gre davran gstermesi iin kullanlan eitli teknikler vardr. Bunlardan
belkide en basiti ve ilkel olan Cookie kullanmdr. Cookie' ler istemci tarafl bilgi saklama amacyla
tercih edilirler. Ancak istemcilerin Cookie destei olmad durumlarda kiiselletirme
(personalization) mmkn olmayacaktr. Alternatif ve daha salkl bir yol olarak kullancya ilikin
bilgilerin kiiselletirme (personalization) amacyla veritaban sistemlerinde tutulmas ve sayfalar
aras geilerde de Session nesneleri yardmyla tanmas ok daha profesyonel bir yaklamdr.

Asp.Net 2.0, getirdii MemberShip Management (yelik Ynetimi) sistemi ierisine kiiselletirme
(personalization) ile ilikili bir takm yenilikler eklemitir. Bunlardan belkide en nemlisi Profile API'
dir. Dier kiiselletirme (personalization) ekli ise Web Part kullanmdr. Profile API yardmyla,
kullanc bazl kiiselletirilmi ayarlar MemberShip sistemine dahil edilip kullanlabilir. Bylece
siteye giren her ye iin farkl kiisel bilgiler tutulabilir ve sayfann o kullancya has olacak ekilde
deitirilmesi dinamik olarak salanabilir. Elbette kullanc iin geerli olan bu kiisel ayarlar yelik
sistemine ait tablolarda saklanmaldr. Aksi halde siteye giren kullanc ile kiiselletirilmi verilerin
entegrasyonu ok zor olacaktr.

Profile sisteminde veritaban tarafnda Sql Server 7, 2000 ve 2005 sistemleri kullanlabilecei gibi,
Custom Provider' lar yardmyla farkl depolama ortamlarda ele alnabilir. Profile API ye bazl
verileri sunucu zerinde tutmaktadr. Biz bu makalemizde Profile API' sini kullanarak basit olarak
kiiselletirme (personalization) ilemlerinin nasl yaplabileceini incelemeye alacaz. Profile
API' sini kullanrken, kiiselletirilecek bilgiler birer zellik olarak Web.Config dosyasna eklenirler.
Asp.Net 2.0 ' da Web.Config dosyasna eklenen yeni boumlardan birisi olan Profile boumu
sayesinde o site iin geerli tm kullanclara ait ortak profil deseneleri oluturulabilir. Profile
boumu ierisinde herhangibir bir ye iin kisel ayarlarn tutulabilecei zellik tanmlamalar yer
alr. Bu zellikler iinde Properties boumundan faydalanlr. Aadaki rnekte Web.config dosyas
ierisine dahil edilmi rnek Profile zelliklerini grebilirsiniz.

<system.web>
<profile>
<properties>
<add name="Kategorim"/>
<add name="KarsilamaMesajim"/>
<add name="SonGirisZamanim"/>
</properties>
</profile>

Bu profile bilgisine gre, sisteme giri yapan her kullanc iin Kategorim, KarsilamaMesajim ve
SonGirisZamanim isimli zelliklerde kiiye gre farkl deerler tutulabilecektir. Profile ierisinde
belirtilen zelliklerin kullanlabilmesi iin en azndan sitenin kullanc bazl alacak ekilde organize
edilmesi gerekir. Bu makale iin gelitirdiimiz rnekte, Sql Server 2005 Express Edition' kullanan
MemberShip sistemi almaktadr. Bylece, her bir kullancya zel profil deerlerini saklayabiliriz.
Bu deerler varsaylan olarak aspnet_Profile tablosunda saklanmaktadr. Profile iin tutulacak
zellikleri konfigurasyon dosyasna ekledikten sonra kod ierisinde Profile snfn kullanarak eitli
ilemleri gerekletirebiliriz. Web.Config dosyasnda, Profile boumu ierisindeki Properties boumu
altna eklenen her bir elemana Profile snf zerinden eriebiliriz.

www.bsenyurt.com Page 1540


ekildende grebileceiniz gibi, kod tarafnda Profile snf ve intelli-sense yardmyla, zellik olarak
eklediimiz tm elemanlara ulaabilmekteyiz. imdi basit olarak bu snf nasl kullanacamza bir
bakalm. rnek senaryo olarak default.aspx sayfamz aadaki gibi tasarlayalm.

ncelikli olarak sayfamzn alma eklinden ksaca bahsedelim. Uygulamamzda Form tabanl
dourlama kullandmz iin, default.aspx sayfasna gelinmeden nce isimsiz kullanclar
UserLogin.aspx sayfasna bir kere uramak zorundalar. Burada sisteme baarl bir ekilde Login
olan kullanclar default.aspx sayfasna geldiklerinde gncel profillerine ait zelliklere eriebilecek ve
deitirebilecekler. Bylece Web.Config dosyasndaProfile boumu ierisinde belirttiimiz
zelliklerin her birinin deerlerini her kullanc iin farkl ekillerde tutabileceiz. Yani kiiye gre
zelletirme yapm olacaz. Bunlar gerekletirebilmek iin kodumuzda aadaki deiiklikleri
yapalm.

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


{
protected void Page_Load(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
ProfileBilgisi();
}
}

www.bsenyurt.com Page 1541


private void ProfileBilgisi()
{
lblKategorim.Text = Profile.Kategorim;
lblMesajim.Text = Profile.KarsilamaMesajim;
lblSonGirisZamanim.Text = Profile.SonGirisZamanim;
}
protected void btnSaveProfile_Click(object sender, EventArgs e)
{
Profile.SonGirisZamanim = DateTime.Now.ToString();
Profile.KarsilamaMesajim = txtMesaj.Text;
Profile.Kategorim = ddlKategoriler.SelectedItem.Text;
Profile.Save();
ProfileBilgisi();
}
}

lk olarak sayfa yklenirken eer kullanc sisteme giri yapm ise ona ait Profile zelliklerinin
deerlerini alyor ve ekrandaki label kontrollerine yazdryoruz. Button kontrolne tklandnda ise
kullancnn girdii deerler, bu kullancya zel profile bilgileri olarak veritabanndaki aspnet_profile
tablosuna kaydediliyor.

Profile ierisinde tutulan zellik deerleri rnek Burak isimli kullanc iin aspnet_Profile isimli
tabloda aadaki ekilde grld gibi tutulur.

www.bsenyurt.com Page 1542


Kullancya ait Profile bilgisini oluturan zellikler ile bunlara karlk gelen deerlerin nasl
tutulduuna dikkat ediniz. Profile ierisinde tanmladmz tm zellikler PropertyNames alan
ierisinde tutulur. Bu zellikere karlk gelen deerler ise PropertyValueString alan ierisinde
tutulmaktadr. Burada 3 farkl kullanc iin 3 farkl Profile satr yer almaktadr. Profile ierisinde
tanmlam olduumuz zellikler u anda varsaylan olarak String tipindendirler. stersek burada
tutulacak zelliklerin tiplerinide aka syleyebilir ve hatta varsaylan deerlerinide ayarlayabiliriz.
zellikte tip gvenliini salamak asndan type niteliini kullanmakta fayda vardr. rneimizdeki
Profile bilgisini buna uygun olacak ekilde aadaki gibi dzenlediimizi dnelim.

<profile>
<properties>
<add name="Kategorim" type="System.String" defaultValue="Dvd"/>
<add name="KarsilamaMesajim" type="System.String" defaultValue="Kiisel Mesajnz"/>
<add name="SonGirisZamanim" type="System.DateTime"/>
<add name="ButonFontBuyuklugu" type="System.Int32" defaultValue="12"/>
</properties>
</profile>

Burada dikkat ederseniz iki yeni zellike daha ekledik. Bununla birlikte her zelliimiz iin geerli
olabilecek primitive tipleri ve varsaylan deerleri tanmladk. Uygulamamz bu haliyle
derlediimizde SonGirisZamanim zelliinin kullanld yerler iin hata mesajlar alrz.

Sebep son derece aktr. SonGirisZamanim isimli Profile zelliinin tipini DateTime olarak
belirttiimizden, bu zelliin kullanld yerlerde uygun tr dnmlerini yapmamz
gerekmektedir. Bu deiiklikler nda kodumuzu yeniden aadaki gibi dzenleyelim.

www.bsenyurt.com Page 1543


protected void Page_Load(object sender, EventArgs e)
{
if (User.Identity.IsAuthenticated)
{
ProfileBilgisi();
}
}

private void ProfileBilgisi()


{
lblKategorim.Text = Profile.Kategorim;
lblMesajim.Text = Profile.KarsilamaMesajim;
lblSonGirisZamanim.Text = Profile.SonGirisZamanim.ToLongDateString();
btnSaveProfile.Font.Size = Profile.ButonFontBuyuklugu;
}
protected void btnSaveProfile_Click(object sender, EventArgs e)
{
Profile.SonGirisZamanim = DateTime.Now;
Profile.KarsilamaMesajim = txtMesaj.Text;
Profile.Kategorim = ddlKategoriler.SelectedItem.Text;
Profile.Save();
ProfileBilgisi();
}

Elbette primitive tipleri kullanabileceimiz gibi, kendi yazm olduumuz tipleride kullanmak
isteyebiliriz. rnek olarak kullancnn site ierisinde gezdii sayfalara ilikin bilgileri
saklayabileceimiz bir snfmz olduunu dnelim.

public class UrlInfo


{
private string _sayfaAdi;
public string SayfaAdi
{

www.bsenyurt.com Page 1544


get { return _sayfaAdi; }
set { _sayfaAdi = value; }
}
private string _url;
public string Url
{
get { return _url; }
set { _url = value; }
}
private DateTime _sonGirisTarihi;
public DateTime SonGirisTarihi
{
get { return _sonGirisTarihi; }
set { _sonGirisTarihi = value; }
}
public UrlInfo()
{ }
public UrlInfo(string ad, string url, DateTime giris)
{
SayfaAdi = ad;
Url = url;
SonGirisTarihi = giris;
}
}

Bu snf Profile ierisinde bir zellik tipi olarak set etmek iin aadaki notasyonu kullanmamz
gerekmektedir.

<add name="SonSayfa" type="UrlInfo"/>

Bu noktadan sonra SonSayfa isimli Profile zelliini uygulamamz ierisinde istediimiz ekilde
kullanabiliriz. zelliin alaca deer tr artk UrlInfo' dur. rnein o anki kullancnn Profile
bilgisine yeni bir UrlInfo rnei eklemek iin aadaki kod satrna benzer bir ifade yazabiliriz.

Profile.SonSayfa = new UrlInfo("default", "default.aspx", DateTime.Now);

Dier taraftan SonSayfa zelliinin ieriini okurken, geri dnecek olan deerin tipi UrlInfo
olacandan, aadaki kod parasnda olduu gibi gncel kullancnn geerli olan UrlInfo yelerine
de eriebiliriz.

lblSonSayfa.Text = Profile.SonSayfa.SayfaAdi + " " +


Profile.SonSayfa.SonGirisTarihi.ToShortDateString();

Yanlz burada dikkat edilmesi gereken bir nokta vardr. u anda SonSayfa zelliinin aspnet_Profile
ierisinde nasl tutulduuna bakarsak Xml eklinde tutulduunu grrz.

www.bsenyurt.com Page 1545


Dilerseniz zelliin ieriini Binary formatnda tutarak daha az yer tutmasnda salayabilirsiniz.
Bunun iin Properties boumunda ilgili zellik iin serializeAs niteliini kullanmamz gerekmektedir.

<add name="SonSayfa" type="UrlInfo" serializeAs="Binary"/>

Lakin uygulamamz bu ekilde altrdmzda ve bir kullanc ile sisteme giri yaptmzda
aadaki istisna mesajn alrz.

Bunun sebebi ise, yazm olduumuz UrlInfo tipinin ikili formatta seriletirilebilir olarak
iaretlenmemesidir. Serializable niteliini (attribute) kullanarak bu hatann nne geebilir ve
tipimizi ikili formatta seriletirilerek ilgili alan ierisine alnmasn salayabiliriz.

[Serializable]
public class UrlInfo
{
...

Tipimizi seriletirilebilir olarak iaretledikten sonra uygulamamz sorunsuz bir ekilde alacaktr.
Elbette UrlInfo tipinin gncel kullanc iin geerli olan ierii artk tabloda, PropertyValuesString
alannda deil, PropertyValueBinary alannda saklanacaktr.

Profile API' si ile ilgili dikkat edilmesi gereken bir dier hususda, siteye giren isimsiz kullanclarn
nasl ele alnacadr. Siteye giren isimsiz kullanclar (anonymous users) iinde Profile bilgisi
tanmlanabilir. Baz alveri sitelerinde isimsiz kullanclar dahi sepete bir eyler ekleyebilmektedir.
Bu isimsiz kullancnn bir sonraki giriinde daha nceden oluturduu sepeti kullanabilmeside
kiiselletirme ile alakaldr. Aslnda isimsiz bir kullanc sisteme girdiinde onun iin bir benzersiz
bir id deeri retilir. Bu id deeri varsaylan olarak oturum aan kullancnn bilgisayarnda cookie
eklinde saklanr. Elbette cookie destei olmayan istemciler iin ayn Session modelinde olduu gibi
cookieless zm vardr. Bu yntemler sayesinde, bir siteye balanan her isimsiz kullanc iin ayr
ayr kiiselletirmeler yapabiliriz. Balamak iin ncelikli olarak Web.Config idosyas erisinden,
isimsiz kullanclar iin Profile kullanmn aktif hale getirmemiz gerekir. Varsaylan olarak bu zellik
kapaldr. nk, isimsiz kullanclar iin Profile kullanm zellikle veritaban kaynaklarn ve doal
olarakta web sunucusu kaynaklarn ok fazla harcayacaktr.

www.bsenyurt.com Page 1546


<anonymousIdentification enabled="True" cookieless="AutoDetect" />

Buradaki rnekte cookieless zelliine AutoDetect deeri atanmtr. Yani isimsiz kullanc iin
oluturulan id deerinin istemci bilgisayarnda Cookie eklinde mi, yoksa url ile birlikte tanacak
ekilde mi tutulacana Asp.Net karar verecektir. Cookieless niteliinin alabilecei dier deerler ise
UseCookies, UseUri ve UseDeviceProfile ' dir. Bylece artk sistem ierisinde isimsiz kullanclar iin
Profile bilgisinin kullanlabileceinide sylemi oluyoruz. Lakin var olan Profile zellikleri ierisinde
de hangilerinin isimsiz kullanclar iin geerli olacana karar vermemiz ve bunu belirtmemiz
gerekiyor. Bunun iin tek yapmamz gereken istediimiz zelliin allowAnonymous niteliine true
deerini atamak olacaktr.

<add name="SonSayfa" type="UrlInfo" serializeAs="Binary" allowAnonymous="true"/>

Grld gibi Asp.Net 2.0 kiiselletirme adna Framework Class Library ierisine olduka gl
bir tip atmtr. Profile tipinin yukarda deindiimiz zellikleri dnda daha pek ok kabiliyetide
elbette vardr. Bunlarn aratrlmasn siz deerli okurlarma brakyorum. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Native Web Services ( 22.05.2006 ) - Sql 2005


Deerli Okurlarm Merhabalar,

Sql Server 2005 ile gelen etkili zelliklerden biriside, doal xml web servisi (native xml web
services) desteinin bulunmasdr. Sql Server 2000 srmnde, web servisi desteini sunabilmek
iin SqlXml 3.0 ve IIS' in sunucu sistemde mutlaka ykl olmas gerekmektedir. Bununla birlikte
istemciler MDAC desteine sahip olmaldr. Oysaki Sql Server 2005 istemcilerden Http protokolne
gre gelecek SOAP uyumlu talepleri dorudan iletebilecek ekilde tasarlanmtr. Sistemde yer
alan Http dinleyici (Http Listener), istemcilerden gelecek olan talepleri dorudan Sql Server 2005
zerindeki EndPoint' lere iletmektedir. Dolaysyla sunucu sistem zerine IIS bulunma zorunluluu
ortadan kaldrlmtr.

Sql Server 2005, sakl yordamlarn (stored procedures) ve kullanc tanml fonksiyonlarn (User-
defined Functions) http zerinden SOAP uyumlu taleplere cevap verebilecek halde sunulmasn
salar. Bunun iinde Http veya Tcp protokolne gre alan EndPoint nesnelerinden yararlanr. Sql
Server 2005, http zerinden gelecek olan talepleri yine SOAP mesajlar eklinde
cevaplandrdndan, istemci her hangibir platform veya sistem olabilir. rnein bir Unix sistemi
yada Linux sistemi de Sql Server 2005 tarafndan sununlan bu servisleri kullanabilir. Biz bu
makalemizde adm adm Sql Server 2005 zerinden web servisi hizmetini nasl verebileceimizi
incelemeye alacaz. Sql Server 2005 zerinden herhangibir sakl yordam yada kullanc tanml
fonksiyonu web servisi kurallar ierisinde sunmann ve kullanmann yolu aadaki ekilde ksaca
tasvir edilmeye allmaktadr.

www.bsenyurt.com Page 1547


Buna gre ilk olarak web servisi zerinden hizmet verecek sakl yordam yada fonksiyon hazrlanr.
Hazrlanan bu fonksiyonun istemcilere cevap verebilmesi ve SOAP taleplerini uygun bir biimde ele
alabilmesi iin bir EndPoint nesnesi hazrlanr. Daha sonra istemci uygulama ilgili EndPoint iin
proxy snfn oluturur. Bildiiniz gibi .Net ile gelitirilen web servislerini, isteci tarafndaki
uygulamalarda kullanmann yollarndan birisi proxy nesnelerinden faydalanmaktr. Buna gre,
tketilmek (Consume) istenen web servisinin wsdl dkmanna gre istemci tarafnda bir proxy
snf oluturulur. Ayn durum, Sql Server 2005 zerinden sunulan EndPoint nesneleri iinde
geerlidir. Tabi istenirse, proxy nesnesi yardmyla deil SOAP taleplerini dorudan oluturacak ve
cevaplar deerlendirecek ekilde kodlama teknikleride kullanlabilir. Web servisinin kullanlabilmesi
iin gerekli admlarn tamamlanmasnn ardndan son olarak Sql Server 2005 tarafndaki EndPoint
tketilerek kullanlr.

Bu kadar teorik bilgiden sonra dilerseniz rnek bir senaryo zerinen hareket edelim. lk olarak ie
yarar bir sakl yordam (Stored Procedure) gelitireceiz. rnek olarak Sql Server 2005 ile standart
olarak yklenen AdventureWorks veritabann kullanacaz. Aadaki sql script ile Production isim
alanndaki Product tablosundan liste fiyat belirli bir deerin stnde olan rnlerin elde edilebildii
bir sakl yordam (stored procedure) oluturulmaktadr.

USE AdventureWorks
GO

CREATE PROCEDURE ListeFiyatinaGoreUrunler


@ListPrice float
AS
BEGIN
SELECT
ProductID
, Name
, ProductNumber
, MakeFlag
, StandardCost
, ListPrice
, SafetyStockLevel
FROM Production.Product
WHERE (ListPrice > @ListPrice)
END
GO

stemcilerin bu sakl yordama http zerinden talepte bulunup sonularn alabilmelerini salamak
iin ise Sql Server 2005 zerinde bir EndPoint oluturmamz gerektiinden daha ncesinde
bahsetmitik. Bu EndPoint nesnesini aadaki scriptte grld gibi oluturabiliriz. ( EndPoint
nesneleride dier ou veritaban nesnesi gibi Drop ve Alter gibi komutlar ile birlikte
kullanlabilmektedir. )

USE AdventureWorks
GO

CREATE ENDPOINT ListeFiyatinaGoreUrunlerEndPoint


STATE = STARTED
AS HTTP ( path = '/sql/ListeFiyatinaGoreUrunler', AUTHENTICATION = (INTEGRATED), PORTS =
(CLEAR) )

www.bsenyurt.com Page 1548


FOR SOAP(
WEBMETHOD 'ListeFiyatinaGoreUrunler' (NAME =
'AdventureWorks.dbo.ListeFiyatinaGoreUrunler',SCHEMA = STANDARD),
BATCHES = ENABLED,
WSDL = DEFAULT,
SCHEMA = STANDARD,
DATABASE = 'AdventureWorks',
NAMESPACE = 'http://tempUri.org/'
)
GO

Bylece sistemde http zerinden ListeFiyatinaGoreUrunler sakl yordamna (stored procedure)


gelecek talepleri karlayacak bir EndPoint nesnesi oluturmu oluyoruz. Artk istemciler bu
EndPoint' i http veya tcp zerinden arp sonularn alabilirler.

Windows XP Service Pack 2 ykl bir sistemde alyorsanz eer, EndPoint nesnesini
oluturbilmek iin World Wide Web Publishing servisini bu ilem srasndadurdurmamz
gerekebilir. Windows 2003 sistemlerinde ise buna gerek yoktur.

Gelitirdiimiz ListeFiyatinaGoreUrunlerEndPoint adl nesneyi ve Sql Server 2005 zerinde kaytl


dier EndPoint' leri grmek iin http_endpoints tablosundan yararlanabiliriz. Bu sistem tablosu
EndPoint' lere ait tm bilgileri tamaktadr.

EndPoint nesnesi oluturulurken pek ok anahtar kelime kullanlmaktadr. Temel ama EndPoint
nesnesinin hangi sakl yordam yada fonksiyonu, hangi iletiim protokolne gre sunacan
belirlemek ve dier konfigurasyon ayarlarn yapmaktr. Bu anahtar kelimeler hakknda birazda olsa
bilgi vermekte fayda olaca kansndaym.

Anahtar
levi
Szck

EndPoint iin balang durumunu belirtir. Started, Stoped veya Disabled olabilir.
Eer Stoped olarak ayarlanrsa, EndPoint' e erimek isteyen istemciler bir alma
State
zaman istisnas alrlar. Disabled olmas halinde ise EndPoint sistemde kalmaya
ancak gelen taleplere cevap vermemeye baalayacaktr.

Bu ksmda iletiim protokol tanmlanr ve bu protokol zerinden gerekli


Http / Tcp konfigurasyon ayarlar belirlenir. Http dnda tcp zerindende servis
verilebilmektedir.

www.bsenyurt.com Page 1549


Path EndPoint iin gerekli URL bilgisini tanmlar.

stemciler iin gvenlik dorulama modelini belirler. Basic, Digets, Ntlm, Kerberos,
Authentication
Integrated modlarndan birisi olabilir.

Clear olmas halinde http portu zerinden hizmet verilmesini salar. SSL olmas
Ports
halinde ise https zerinden hizmet verilir.

Site Servisin host edildii bilgisayarn addr.

Bu ksmda SOAP mesajna ynelik tanmlamalar yaplr ve servisin SOAP


Soap
protokoln kullanaca belirtilir.

Sakl yordamn yada kullanc tanml fonksiyonumuzun istemciler tarafndan


WebMethod
kullanlabilmesi iin gerekli metod ad tanmlamasdr.

Wsdl Wsdl desteini belirtir.

Database EndPoint' in yer ald veritaban adn belirtir.

Namespace SOAP mesajlar iin gerekli xml isim alann (xml namespace) tanmlar.

Artk EndPoint' imiz hazr olduuna gre bunu herhangibir istemci uygulama zerinde test
edebiliriz. Ancak teste balamadan nce basit olarak EndPoint' in alp almadn kontrol
edebiliriz. Yazdmz EndPoint' in kontrol ilemi iin tarayc penceresinde,
http://localhost/sql/ListeFiyatinaGoreUrunler?wsdl bilgisini yazmamz yeterlidir. Eer aadaki
ekran grntsnde olduu gibi wsdl dkmanna ulaabiliyorsak EndPoint' imiz baarl bir ekilde
alyor demektir.

www.bsenyurt.com Page 1550


imdi bu hizmeti gerek bir .Net uygulamasnda nasl kullanacamz incelemeye alalm. Web
servisi hizmetini hangi tip istemcide sunacamza bakmakszn dikkat etmemiz gereken nemli bir
nokta vardr. Yukardaki sakl yordamda (stored procedure) olduu gibi geriye bir sonu kmesi
dnyorsa, EndPoint bunu bir object dizisi eklinde dndrecektir. Bu yzden EndPoint zerinden
gelen veriyi tayan DataSet nesnesini bu object dizisi ierisinde yakalayp almamz gerekmektedir.
Biz rnek olarak bir Windows Uygulamasn ele alacaz. lk olarak servisimizi uygulamamza Add
Web Reference tekniine gre tantmamz gerekiyor.

Bu ilemin ardndan solution explorer' a bakacak olursak, web servisinin, proxy snfnn ve wsdl
dkmannn da eklenmi olduunu grrz.

www.bsenyurt.com Page 1551


Uygulama kodumuz ise aadaki gibidir.

private void button1_Click(object sender, EventArgs e)


{
UrunServis.ListeFiyatinaGoreUrunlerEndPoint srv = new
UrunServis.ListeFiyatinaGoreUrunlerEndPoint();
srv.Credentials = System.Net.CredentialCache.DefaultCredentials;
object[] sonuclar = srv.ListeFiyatinaGoreUrunler(Convert.ToDouble(txtFiyat.Text));

foreach (object guncelNesne in sonuclar)


{
if (guncelNesne.GetType().ToString() == "System.Data.DataSet")
grdUrunler.DataSource = ((DataSet)guncelNesne).Tables[0];
}
}

UrunServis referans ierisinde yer alan ListeFiyatinaGoreUrunlerEndPoint servisine eriirken


istemcinin ayn domain ierisinde olduunu dnerekten DefaultCredential uygulanmtr. Nitekim
EndPoint tanmlamamzda, authentication modu olaraktanda integrated seeneini kullanmtk.
Dier taraftan normal web servislerinin kullanmnda web metodlarnn dn tipi ne ise, proxy
nesneleri zerinden de ayn tipi alabilmekteyiz. Oysaki burada geriye object tipinden bir dizi
dnmektedir. Bu dizinin elemanlarna alma zamannda Visualizer yardmyla bakacak olursak
aadaki ekildende grebileceiniz gibi bir DataSet nesnesinin de var olduunu grrz.

www.bsenyurt.com Page 1552


Dolaysyla kodumuz ierisinde object dizisinin elemanlar arasnda dolap tipinin string karl,
DataSet' in Framework ierisindeki tam adna e den System.Data.DataSet ile karlatrlmas
gerekmektedir. Bu tespit yapldktan sonra, gncel object dizi eleman DataSet tipine
dntrlerek veri kayna olarak kullanlm ve form zerindeki gridView kontrolne bu veri
kmesi ierisindeki 0 indeksli DataTable balanmtr. Uygulamamz altrdmzda , Sql Server
2005 zerinden EndPoint' imize baarl bir ekilde eriebildiimizi grrz.

Grld gibi artk Sql Server 2005 zerinde sakl yordam (stored procedure) yada kullanc
tanml fonksiyonlar (user defined functions), http istemcilerine hizmet verecek ekilde web servisi
olarak sunmak olduka kolaydr. Tek yapmamz gereken EndPoint nesnelerini hazrlamak ve
istemcilerde tketmek olacaktr. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 1553


Burak Selim ENYURT
selim@bsenyurt.com

Custom Serialization ( 14.05.2006 ) - C# 2.0


Deerli Okurlarm Merhabalar,

Nesnelerin alma zamanndaki durumlarn alp herhangi bir kaynaa doru yazmak ve baka bir
zaman dilimi ierisinde bu kaynaktan ayn nesne durumunu elde etmek amacyla seriletirme
tekniklerinden ska faydalanlmaktadr. Biz bu makalemizde zel seriletirmeyi (Custom
Serialization), Framework 1.1' den itibaren incelemeye balayacak ve 2.0' da getirilen yeniliklere
deineceiz. Bazen seriletirme (Serialization) veya ters-seriletirme (Deserialization) ilemleri
srasnda, veriyi deitirmek isteyebiliriz. rnein seriletirilecek olan veriyi ilgili stream zerine
ifrelemek isteyebiliriz. Sz konusu stream bir a ortamnda, fiziki bir dosya veya bellek blgesi
olabilir. zellikle a zerinden harekete eden verilerin seriletirme ilemine tabi tutulduu
Remoting gibi mimarilerde ifreleme ilemi zaman zaman nem arz edebilir. Elbette ifreleme gibi
amalar dnda da baka nedenlerden dolay zel seriletirme ilemlerini gerekletirmek
isteyebiliriz.

Hangi nedenle olursa olsun zel seriletirme, kod tarafnda bir takm zel ilemleri gerektirir. zel
seriletirmeyi kavrayabilmek ve uygulayabilmek iin var olan seriletirme srelerini basitten
detaya kadar incelemek gerekir. Dilerseniz ilk olarak bir nesnenin seriletirme srecine ksaca bir
gz atalm.

ounlukla, seriletirmek veya ters-seriletirmek istediimiz verinin ierii Formatter' lar tarafndan
kullanlrlar. Seriletirme ilemi srasnda bu bilgiden yararlanlarak veri bir stream' e doru yazlr.
Ters-seriletirme ileminde ise stream' den okunan veri yine formatter nesnesi yardmyla orjinal
nesne zerine yklenir. Seriletirme ve ters-seriletirme ilemleri iin Framework 2.0' da getirilen
en byk yeniliklerden birisi, olaylarn ele alnabilecei metodlarn yazlabiliyor oluudur.
Framework 2.0 perspektifinden bakldnda bir nesnenin seriletirilmesi veya ters-seriletirilmesi
srasnda meydana gelen olaylar daha kolay ele alnabilmektedir.

www.bsenyurt.com Page 1554


ekilden de grebileceiniz gibi seriletirme sreci gerekleirken meydana gelen iki olay vardr.
Bunlardan ilki seriletirme ileminin gerekletii srada alan OnSerializing olaydr. Seriletirme
ilemi gerekletirildikten hemen sonra devreye giren olay ise OnSerialized' dir. Ters seriletirme
(Deserialization) ileminde de benzer bir durum sz konusudur. Ters seriletirmenin gerekletii
srada OnDeserializing olay ele alnabilir. Bu ilem bittikten hemen sonrasnda ise, eer snf
IDeserializationCallback arayzn uygulam ise OnDeserialization olay ncelikli olarak devreye
girecektir. Son olarakta OnDeserialized olay gerekleecektir. te Framework 2.0 bahsetmi
olduumuz seriletirme olaylarn daha iyi ele alabileceimiz yeni nitelikler sunmaktadr.

OnSerializing, OnSerialized, OnDeserializing, OnDeserialized olaylar sadece Binary


seriletirmede gerekleir. Soap formatnda yaplan seriletirmede sadece Serialization
olaylar meydana gelir.

Peki bahsetmi olduumuz bu olaylar nasl ele alacaz? Bunun iin Framework 2.0 ile birlikte
gelen yeni attribute (nitelik) larmz mevcuttur. Bu attribute' larn listesini ve ksa aklamalarn
aadaki tabloda bulabilirsiniz.

Attribute Ksa Aklama

OnSerializing Seriletirme ilemi srasndaki olay metodlarn niteler.

OnSerialized Seriletirme ilemi tamamlandktan sonraki olay metodlarn niteler.

OnDeserializing Ters-Seriletirme ilemi yapld sradaki olay metodlarn niteler.

Ters-Seriletirme ilemi tamamlandktan sonraki olay metodlarn


OnDeserialized
niteler.

www.bsenyurt.com Page 1555


Bu attribute' lar yardmyla bir metodu iaretlediimizde, seriletirme (ters-seriletirme) srasndaki
sreci ele alabiliriz. Framework 2.0 ile zel seriletirmeye getirilen yenilikleri ele almadan nce
Framework 1.1' de bu ii nasl gerekletirebileceimizi incelemekte fayda var. Eer bir snfa zel
seriletirme uygulamak istiyorsak ncelikle bu snfa ISerializable arayzn uygulamamz
gerekmektedir. Tabiki bu snfn Serializable nitelii ile iaretlenmi bir snf olmas gerektiide
unutulmamaldr. ISerializable arayznn sunduu GetObjectData metodu yardmyla, veri
ieriini zel seriletirme ilemine tabi tutabiliriz. Dier taraftan ters-seriletirme ilemi iin sz
konusu snfn mutlaka zel bir yapc metodu (constructor) kullanlmas arttr. Bu yapc metodun
parametrik yaps, ISerializable arayznden uygulanan GetObject metodunun parametrik yaps ile
ayn olmak zorundadr.

Konuyu daha iyi anlayabilmek iin basit bir rnek gelitirerek makalemize devam edelim.
rneimizde, Personel tipinden basit bir nesne rneinin binary formatta seriletirmesi ilemi ele
alnmaktadr. Lakin bu ilemde seriletirme yaparken nesnenin grafiini oluturan ierik Rijndael
algoritmasna gre ifrelenmektedir. Ters-seriletirme ilemi srasnda ise, ifrelenmi olan ierik
tekrar Personel tipi nesne rneine atanmaktadr. Uygulamamzda ifreleme ilemlerini ele alan
SifrelemeYoneticisi isimli snfmz temel olarak bizim iin gerekli encryption ve decryption
metodlarn salamaktadr. Personel isimli snfmz ise bir personel iin gerekli temel zellikleri
tayp zel seriletirme yeteneine sahip olacak ekilde tasarlanmtr. Dikkat edeceimiz en
nemli nokta, Personel isimli snfmzn uygulad GetObjectData metodu ve zel yapcsdr.

using System;
using System.IO;

www.bsenyurt.com Page 1556


using System.Text;
using System.Runtime.Serialization;
using System.Security.Cryptography;

namespace OzelSerilestirme
{
// Personel snfmn ikili seriletirmeye destek verebilmesi ve zel seriletirmeyi kullanabilmesi
iin Serializable niteliine mutlaka sahip olmas gerekir.
[Serializable]
class Personel:ISerializable
{
private int _id;

public int Id
{
get { return _id; }
set { _id = value; }
}
private string _ad;

public string Ad
{
get { return _ad; }
set { _ad = value; }
}
private DateTime _dogum;

public DateTime Dogum


{
get { return _dogum; }
set { _dogum = value; }
}
private double _maas;

public double Maas


{
get { return _maas; }
set { _maas = value; }
}

public override string ToString()


{
return Id.ToString() + " " + Ad + " " + Dogum.ToShortDateString() + " " +
Maas.ToString();
}

public Personel(int id, string ad, DateTime dogum, double maas)


{
Id = id;

www.bsenyurt.com Page 1557


Ad = ad;
Dogum = dogum;
Maas = maas;
}

#region Deserialization iin kullanlan zel constructor metodumuz

public Personel(SerializationInfo info, StreamingContext context)


{
// ifrelenmi veriler info nesnesi zerinden alnarak, zc nesnemize gnderilir. Elde
edilen sonular Personel nesnesinin alma zamanndaki rneinin ilgili alanlarna setlenir.
Id = Convert.ToInt32(SifrelemeYoneticisi.SifreCoz((byte[])info.GetValue("Identity",
typeof(object))));
Ad = SifrelemeYoneticisi.SifreCoz((byte[])info.GetValue("Name", typeof(object)));
Dogum =
Convert.ToDateTime(SifrelemeYoneticisi.SifreCoz((byte[])info.GetValue("BirthDate",
typeof(object))));
Maas = Convert.ToDouble(SifrelemeYoneticisi.SifreCoz((byte[])info.GetValue("Salary",
typeof(object))));
}

#endregion

#region ISerializable Members

public void GetObjectData(SerializationInfo info, StreamingContext context)


{
// ncelikle, Personel snfnn alma zamanndaki nesne rneinin sahip olduu zellik
deerleri ifreleme ileminden geirilir. Elde edilen byte dizileri ise info nesnesinin AddValue
metodu yardmyla, binary seriletirilmenin yapld stream' e doru yazlr.
byte[] sifrelenmisId = SifrelemeYoneticisi.Sifrele(Id.ToString());
byte[] sifrelenmisAd = SifrelemeYoneticisi.Sifrele(Ad);
byte[] sifrelenmisDogum = SifrelemeYoneticisi.Sifrele(Dogum.ToString());
byte[] sifrelenmisMaas = SifrelemeYoneticisi.Sifrele(Maas.ToString());

info.AddValue("Identity", sifrelenmisId);
info.AddValue("Name", sifrelenmisAd);
info.AddValue("BirthDate", sifrelenmisDogum);
info.AddValue("Salary", sifrelenmisMaas);
}

#endregion
}

// ifreleme ve zme ilemleri iin kullandmz snfmz, Rijndael algoritmasn temel alr.
class SifrelemeYoneticisi
{
private static byte[] Key = { 0x01, 0x06, 0x03, 0x07, 0x05, 0x06, 0x07, 0x11, 0x09, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };

www.bsenyurt.com Page 1558


private static byte[] IV = { 0x01, 0x06, 0x03, 0x07, 0x05, 0x06, 0x07, 0x11, 0x09, 0x10,
0x11, 0x12, 0x13, 0x14, 0x15, 0x16 };

public static byte[] Sifrele(string sifrelenecekVeri)


{
MemoryStream ms = new MemoryStream();
RijndaelManaged rm=new RijndaelManaged();
CryptoStream cs;
byte[] veri = Encoding.UTF8.GetBytes(sifrelenecekVeri);
cs = new CryptoStream(ms, rm.CreateEncryptor(Key, IV), CryptoStreamMode.Write);
cs.Write(veri, 0, veri.Length);
cs.Close();
ms.Close();
return ms.ToArray();
}

public static string SifreCoz(byte[] sifrelenmisVeri)


{
MemoryStream ms = new MemoryStream();
RijndaelManaged rm = new RijndaelManaged();
CryptoStream cs = new CryptoStream(ms, rm.CreateDecryptor(Key, IV),
CryptoStreamMode.Write);
cs.Write(sifrelenmisVeri, 0, sifrelenmisVeri.Length);
cs.Close();
ms.Close();
return Encoding.UTF8.GetString(ms.ToArray());
}
}
}

Uygulama kodumuz ise aadaki gibidir.

using System;
using System.IO;
using System.Text;
using System.Security.Cryptography;
using System.Runtime.Serialization.Formatters.Binary;
using OzelSerilestirme;

public class main


{
public static void Main(string[] args)
{
#region Binary seriletirme

BinaryFormatter bfYaz = new BinaryFormatter();


FileStream fsYaz = new FileStream("Personel.txt", FileMode.Create);
Personel pers = new Personel(1000, "Burak Selim enyurt", new DateTime(1976, 12, 4),

www.bsenyurt.com Page 1559


2000);
bfYaz.Serialize(fsYaz, pers);
fsYaz.Close();

#endregion

#region Binary ters-seriletirme

BinaryFormatter bfOku = new BinaryFormatter();


FileStream fsOku = new FileStream("Personel.txt", FileMode.Open);
Personel persOkunan = (Personel)bfOku.Deserialize(fsOku);
Console.WriteLine(persOkunan.ToString());
fsOku.Close();

#endregion
}
}

Uygulamamzda ilk olarak bir Personel tipi nesne rneini fiziki bir dosyaya ikili formatta
seriletirmekteyiz. Sonrasnda ise fiziki dosyadan okuduumuz veriyi yeni bir Personel tipi nesne
rneine tamaktayz. Buradaki ilemler aslnda normal bir seriletirme ileminden farksz. Ancak
Personel snfmz zel seriletirme ilemini uygulad iin arka planda verilerin ifrelenmesi ve
zmlenmesi sz konusu.

Uygulama altktan sonra seriletirilmi verimizi tutan dosyamzn ierii aadaki gibi olacaktr.
Grdnz gibi Id, Ad, Dogum ve Maas gibi bilgilerimiz ifrelenmitir. Geri, normal bir
seriletirme ilemi srasnda da binary formatn kullandmz iin veri ierii ok kolay okunamaz
haldedir. Ancak zellikle string bazl veriler okunabilir formatta olacaktr. Yinede biz, kullandmz
ifreleme anahtarna sahip olmayanlarn, nesneyi o anki ierii ile elde edememesini garanti altna
alm oluyoruz. Aadaki ilk ekran grntsnde Personel tipine ait nesne rneimizin ifrelenmi
halini grmektesiniz. kinci grntde ise normal ikili seriletirmenin etkisini grmekteyiz.

Eer ifreleme yapmassak;

Uygulamamz altrdmzda ifrelediimiz personel tipi nesne rneinin baarl bir ekilde
zlerek ters-seriletirilebildiini de grmekteyiz. Elbette burada rnek olmas asndan Rijndael

www.bsenyurt.com Page 1560


algoritmasn kullandk. Bunun yerine dier ifreleme algoritmalarnda kullanabiliriz. Sonuta
nemli olan seriletirme srecinde nerede neyi kullanacamz bilmektir.

Framework 2.0' da ncedende bahsettiimiz gibi, seriletirme ve ters-seriletirme srecindeki


olaylar ele alabilecek metodlar, eitli nitelikler yardmyla yazabilmekteyiz. Bununla ilgili
olaraktan Personel snfmzn yeni versiyonunu aadaki gibi yazacaz. Dikkat ederseniz bu sefer
zel bir constructor yazmadk veya GetObjectData metodunu kullanmadk. Dier taraftan snfmza
ISerializable arayznde uygulamadk. Framework 2.0 getirdii bu yeniliklerle birlikte,
ISerializable arayzne destek vermeye devam etmektedir. zellikle attribute' larn destekledii
metodlarn SerializationInfo tiplerini dorudan almamas nedeniyle, yukarda yazdmz ifreleme
rneini Framework 2.0' daki nitelikleri kullanacamz metodlar yardmyla yazmak gerekten
zordur.

[Serializable]
class Personel2
{
private int _id;

public int Id
{
get { return _id; }
set { _id = value; }
}
private string _ad;

public string Ad

www.bsenyurt.com Page 1561


{
get { return _ad; }
set { _ad = value; }
}
private DateTime _dogum;

public DateTime Dogum


{
get { return _dogum; }
set { _dogum = value; }
}
private double _maas;

public double Maas


{
get { return _maas; }
set { _maas = value; }
}

public override string ToString()


{
return Id.ToString() + " " + Ad + " " + Dogum.ToShortDateString() + " " + Maas.ToString();
}

public Personel2(int id, string ad, DateTime dogum, double maas)


{
Id = id;
Ad = ad;
Dogum = dogum;
Maas = maas;
}

[OnSerializing()]
protected void Serilestiriliyor(StreamingContext ctx)
{
Console.WriteLine("Seriletiriliyor...");
}

[OnSerialized()]
protected void Serilestirildi(StreamingContext ctx)
{
Console.WriteLine("Seriletirildi...");
}

[OnDeserializing()]
protected void TersSerilesitiriliyor(StreamingContext ctx)
{
Console.WriteLine("Ters seriletiriliyor...");
}

www.bsenyurt.com Page 1562


[OnDeserialized()]
protected void TersSerilestirildi(StreamingContext ctx)
{
Console.WriteLine("Ters Seriletirildi...");
}
}

Personel snfnn ikinci versiyonuna dikkat ederseniz yeni attribute' larmzn kullanld metodlarn
hepsinin ayn parametrik yapda olduunu grebilirsiniz. Metodlarmzn hepsi deer dnrmeyen
(void) ve sadece StreamingContext tipinden tek parametre alan modeldedir. Bu metodlar ierisinde
u an iin sadece seriletirme srecini takip etmekteyiz. Uygulamamz Personel2 tipine gre
gncellediimizde aadakine benzer bir ekran grnts alrz. Dikkat ederseniz, tm sreci
yakalayabilmekteyiz. Buda bize seirletirme sreci srasnda, d kaynaklar ile ilgili ilemler
yapabilmek iin uygun bir zemin hazrlamaktadr.

Framework 2.0 ile gelen belkide en nemli yenilik generic mimaridir. zellikle generic modelin
hemen her tipe uygulanabiliyor olmas dikkatleri seriletirilebilir tipler zerine de ekmektedir.
Dolaysyla zel seriletirme ilemini yaparken generic alanlar ele alabileceimizi syleyebiliriz.
Yanlz generic mimariyi kullandmz snflarda eer zel seriletirme yapyorsak dikkat etmemiz
gereken bir takm noktalar vardr. rnein aadaki snf ele alalm.

[Serializable()]
public class Personel3<G>:ISerializable

www.bsenyurt.com Page 1563


{
private G _eleman;
private string _ad;

public string Ad
{
get { return _ad; }
set { _ad = value; }
}

public G Eleman
{
get { return _eleman; }
set { _eleman = value; }
}

#region ISerializable Members

public void GetObjectData(SerializationInfo info, StreamingContext context)


{
info.AddValue("Eleman", _eleman);
info.AddValue("Ad", _ad);
}

#endregion

public Personel3(SerializationInfo info, StreamingContext context)


{
Ad = info.GetString("Ad");
Eleman = (G)info.GetValue("Eleman",typeof(G));
}

public Personel3(G eleman,string ad)


{
_eleman = eleman;
_ad = ad;
}

public override string ToString()


{
return _eleman.ToString()+" "+_ad.ToString();
}
}

Grld gibi zel seriletirmeye ihtiyacmz olduunda ele alabileceimiz teknikler ortadadr.
ifreleme ilemleri gibi, verinin dorudan deitirilmesi gerektii durumlarda ISerializable
arayzne ait yelerin kullanlmas ok daha doru olacaktr. Nitekim byle bir ihtiyata dorudan
sre ierisinde yer alan nesne deerlerini yakalayabilmek adna ele alnabilecek en uygun yol
budur. Bununla birlikte seriletirme sreci ierisinde farkl kaynaklara ynelik ilemler yaplmas

www.bsenyurt.com Page 1564


dnlyorsa Framework 2.0 ile birlikte gelen attribute' lardan yararlanlabilir. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

rnek kod iin tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Data Access Application Block Nedir? (.Net 2.0


iin) ( 05.05.2006 ) - EA
Deerli Okurlarm Merhabalar,

Microsoft tarafndan serbest olarak datlan Data Access Application Block (Veri Eriimi Uygulama
Blou) zellikle n katmanl mimarilerde, Data Access Layer (veri eriim katman) iin gerekli
ilevsellii salayan, performans ve bellek ynetimi konusunda iyi sonular veren bir Enterprise
Solution Pattern' dir. Bu block sayesinde, zellikle Business Layer (i katmanndaki) katmanndaki
iimiz olduka kolaylamaktadr. zellikle Sql sunucusu zerinde uzmanlam olan bu block' un
.Net 2.0 iin olan srm Ocak ay ierisinde yaynland. Data Access Application Block (Veri Eriimi
Uygulama Blou) ve dier Enterprise Solution Pattern' lerini bu adresten indirebilirsiniz. Data
Access Application Block (Veri Eriimi Uygulama Blou), dier blocklar gibi bir solution olarak
gelmektedir. Dolaysyla ilk kullanmndan nce mutlaka bu solution' ap derlememiz gerekir.
Bylece kullanlabilir assembly dosyalarmz (dll' leri) elde etmi oluruz. Bunun sonucu olarakta
herhangibir projede, Data Access Application Block (Veri Eriimi Uygulama Blou) iin oluturulan
assembly' mz referans edebilir ve kullanmaya balayabiliriz. Ayn uygulama mant dier block'
lar iinde geerlidir.

Data Access Application Block (Veri Eriimi Uygulama Blou)' unu ksaca inceleyeceimiz bu
makalede rneklere gemeden nce, Data Access Layer 'n (veri eriim katman) salad
avantajlardan ksaca bahsetmekte fayda olaca kansndaym. Katl mimariler, zellike Enterprise
Solution' larn olmazsa olmaz paralarndan birisidir. Temel olarak en basit mimari model
katmandan olumaktadr.

Bu modelde veri ile ilgili temel ilemleri stlenen bir veri eriim katman (Data Access Layer),
uygulamann mantn stlenen bir i katman (Business Layer) ve uygulama arabiriminin
tutulduu bir sunum katman (Presentation Layer) mevcuttur. Data Access Layer (veri eriim
katman) genellikle balant oluturma, sql komutlarn altrma gibi temel yaplar iin gerekli
kodlar, dier katmanlardan soyutlayan bir grev stlenir. Net tarafndan baktmzda, DataSet,
DataTable, Xml, DataReader gibi veri trlerini veya kendi veri trlerimizi geri dndren ilemler ve
daha bir ou Data Access Layer (veri eriim katman) ierisindeki metodlarda toplanmaktadr.
Eer elinizde hazr bulunan bir Data Access Layer (veri eriim katman) yoksa veya tembellik edip
yazmaya eniyorsanz (ya da var olan bir tanesini inceleyip en azndan vizyonunuzu gelitirmek
istiyorsanz), Data Access Application Block (Veri Eriimi Uygulama Blou) gerekten byk bir
frsattr. zelliklede cretsiz olarak datld dnlrse.

Normal artlar altnda zellikle Business () katmannda yer alan metodlarmz ierisinde, Data
Access Layer (veri eriim katman) ierisindeki metodlar sklkla kullanlmaktadr. rnein web

www.bsenyurt.com Page 1565


tabanl bir hizmet programn ele alalm ve sayfalar zerindeki GridView kontrollerinin doldurulmas
gibi temel bir ilem iin gerekli olan materyalleri dnelim. lk olarak Data Access Layer (veri
eriim katman) zerinde gerekli sorgular altrp geriye DataSet dndrecek ar yklenmi
(overload) metodlar yazlmas gerekir. Ar yklenmi bu versiyonlarda text bazl query
altracak, birden fazla sayda parametre alacak yada bir stored procedure' ele alacak hatta
bunlarn transaction bazl versiyonlarnda tutacak tipte seenekler yer alabilir. stelik bu metodun
kullanaca balant nesnesinide bilmesi, gerekirse oluturmas, amas ve hatta ii bitince bellek
ynetiminide gereletirerek kaynaklar en iyi ekilde idare etmesi beklenir. Sonu itibariyle
uygulamann i mantn kapsayan Business () katmannn, buradaki kod kalabalndan
etkilenmemesi amalanmaktadr. yleki veri eriim katman bir kez yazp pek ok projede
kullanlabilirken, i katman projeden projeye farkllk gsterecektir. te bu nedenle bu tip
karmak ve kendi ierisinde dallanarak modlleebilen ilemler, pek ok projede kullanlabilmeleri
amacyla Data Access Layer (veri eriim katman) ierisinde tutulurlar.

Data Access Application Block (Veri Eriimi Uygulama Blou)' un salad etkinlikleri grebilmek
amacyla aadaki kod parasn gz nne alabiliriz. Bu kod paras pek ok yerde kullanlabilecek
tipte bir metod olarak veri eriim katmannda yer alacak nitelikte bir yapya sahiptir.

using (SqlConnection con = new SqlConnection(conStr)


{
using (SqlCommand cmd = new SqlCommand(queryString, con))
{
SqlDataAdapter da = new SqlDataAdapter(cmd);
DataSet ds = new DataSet();
da.Fill(ds);
}
}

Kodumuz parametre olarak gelecek sorgunun sonularn bir DataSet ierisine aktarmaktayz. Bu
ilemi gerekletirmek iin ihtiyacmz olan tm materyal kod satrlarnda yer almaktadr. Balanty
oluturmak iin bir SqlConnection nesne rnei, komutu altrmak iin bir SqlCommand nesne
rnei ve bu komutu alp DataSet' i dolduran bir SqlDataAdapter nesne rnei. Aslnda yaplan i
son derece basittir. Bir sorgu sonucu elde edilen veri kmesinin DataSet nesne rneine
aktarlmas.

eitli uygulamlarn pek ok noktasnda belirli bir sorgu ve balant ile alp geriye DataSet
dndrecek metodlarmz olacaktr. Bunlar her seferinde tekrardan yazmak nesne ynelimli bir
dilin imkanlar gz nne alndnda doal olarak yanl olacaktr. Dolaysyla bu ve benzeri
ilevselliklere sahip kod paralar, bir katman dahilinde toplanabilir ve ynetimin daha kolay olmas
salanabilir. stelik bu, verileri hazrlamak iin kullanlan kod karmaasnnda dier katmanlardan
soyutlanmas anlamna gelmektedir. te bu nedenlede, uygulamalarn mant ile grsel
arabirimlerinden ayrtrlm ve temel olarak veri eriim tekniklerini ele alm bir katman sz
konusudur ki biz bunu Data Access Layer (veri eriim katman) olarak nitelendiriyoruz. Microsoft
buradaki ihtiyac ele alaraktan herkesin kolayca kullanabilecei bir veri eriim katman zm
retmitir. Data Access Application Block (Veri Eriimi Uygulama Blou).

Eer sisteminize Data Access Application Block (Veri Eriimi Uygulama Blou)' u baarl bir ekilde
yklediyseniz, kendi Data Access Layer (veri eriim katman) ktphanenize kolayca sahip

www.bsenyurt.com Page 1566


olmusunuz demektir. rnein yukardaki kodun yer ald bir Data Access Layer (veri eriim
katman) metodunun, Data Access Application Block (Veri Eriimi Uygulama Blou)' taki karln
ele almaya alalm. Ancak ncesinde, uygulamamza Data Access Application Block (Veri Eriimi
Uygulama Blou)' tan gerekli referanslar almamz gerekecektir. (Eer .Net 2.0 iin indirdiiniz
Enterprise Library' yi standart olarak kurduysanz, Enterprise Solution' unuzu derledikten sonra
oluan assembly' lara C:\Program Files\Microsoft Enterprise Library January 2006\bin klasrnden
eriebilirsiniz.)

Bu referanslar aldktan sonra yukardaki kod parasn aadaki haliyle yazabiliriz. nce bizim iin
gerekli referanslar;

using Microsoft.Practices.EnterpriseLibrary.Common;
using Microsoft.Practices.EnterpriseLibrary.Data.Sql;
using Microsoft.Practices.EnterpriseLibrary.Data;

Kodumuzun aynsn ve hatta daha iyisinide yapan Data Access Application Block (Veri Eriimi
Uygulama Blou) karlklar,

Database db = DatabaseFactory.CreateDatabase("conn");
db.ExecuteDataSet(CommandType.Text, "Select * From Production.Product");

Grld gibi Data Access Application Block (Veri Eriimi Uygulama Blou)' un kullanm son
derece kolay ve esnektir. Koda dikkat edecek olursanz, connection nesnesinin nasl
oluturulduunu, dataSet nesnesinin nasl doldurulduunu grmemekteyiz. Bu ilemler Data Access
Layer (veri eriim katman) ierisinde kapsllenerek bizden soyutlandrlm durumdalar. Benim en
ok beyendiim zelliklerden birisi, kilit nesnelerin oluturulmasnda eitli factory nesnelerinin
grev alyor olmas. rneimizde, Database nesnesini oluturmak iin DatabaseFactory isimli baka
bir fabrika nesnesi kullanlmtr. zellikle CreateDatabase metodunun bu versiyonu varsaylan
olarak uygulamann konfigurasyon dosyasna bakp uyun connectionString node' unu kullanmtr.

.Net 2.0 iin gelitirilen bu versiyonda nceki Enterprise Block' lara gre bir takm temel
farkllklarda mevcuttur. rnein, burada oluturduumuz Database nesne rneini eitli metodlar
yrtmek (execute) iin kullanmaktayz. Ancak bunu olutururken App.config dosyasnda
tuttuumuz connection string bilgisini dorudan kullanyoruz. Bu ve benzeri pek ok yenilik var.
Pek ok isim alan tamamen deimi ve daha iyi ayrtrlm durumda. Ama ilk gze arpanlar
arasnda Ado.Net 2.0 olan tam destek ve snflarn biraz daha derlenip bir nceki versiyona gre
karmaklktan uzaklatrlm olmas var.

www.bsenyurt.com Page 1567


App.config ierii;

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


<configuration>
<connectionStrings>
<add name="conn" connectionString="Data
source=manchester;database=AdventureWorks;integrated security=sspi"
providerName="System.Data.SqlClient"/>
</connectionStrings>
</configuration>

CreateDatabase static metodu konfigurasyon dosyas ierisindeki conn isimli anahtar nasl
bulacan bilmektedir. Biz bununla da uramamaktayz. Buda uygulamann yeniden derlemeye
gerek duymayacak teknikleri (ki burada xml tabanl bir konfigurasyon dosyas bunu karlyor)
kolayca uygulayabilecek bir katmana sahip olduu anlamna gelmektedir. imdi gelin baka bir
senaryoyu ele alalm. rnein, sistemde yer alan parametrik bir stored procedure' n sonularn
ortama bir DataReader vastasyla almak istediimiz bir ilevsellii Data Access Layer (veri eriim
katman) ierisine katmak istediimizi dnelim. Bu senaryo iin Sql Server 2005 zerinde,
AdventureWorks veritabannda yer alacak aada oluturma script' i verilen sp' yi kullanabiliriz.

Kullandmz Stored Procedure;

USE [AdventureWorks]
GO

SET ANSI_NULLS ON
GO
SET QUOTED_IDENTIFIER ON
GO
CREATE PROCEDURE [dbo].[GetStoreByPersonID]
(
@PersonID int
)
AS
SELECT * FROM Sales.Store WHERE SalesPersonID=@PersonID
RETURN

imdi bu sp' yi kullanacak rnek bir kod parasn kendi DAL' mz ierisinde aadaki gibi
yazdmz dnelim.

using (SqlConnection con = new SqlConnection(conStr))


{
using (SqlCommand cmd = new SqlCommand(queryStr, con))
{
cmd.CommandType = CommandType.StoredProcedure;
cmd.Parameters.AddWithValue(prmName, prmValue);
con.Open();
SqlDataReader dr = cmd.ExecuteReader();

www.bsenyurt.com Page 1568


}
}

Elbette buraki kod yazm ekli yazlmcdan yazlmcya farkllkta gsterebilir. Oysaki hangi yol ile
olursa olsun, Data Access Application Block (Veri Eriimi Uygulama Blou)' un sunduu izgi
bellidir. Bu da aslnda, byk apl projelerde farkl yazlmclarn ayn standart zerinde gelitirme
yapabilmesini olanakl klmaktadr. Dolaysyla tek yapmamz gereken eer bir stored procedure' ,
konfigurasyon dosyasnda tutulan bir balant bilgisi zerinden altrmak ve geriye bir DataReader
almak ise, Business () katmannda kullanacamz metod sadece aadaki iki satr kod parasn
ierecektir.

Database db = DatabaseFactory.CreateDatabase("conn");
db.ExecuteReader("GetStoreByPersonID", 277);

Grld gibi, ExecuteReader metodunun kullandmz versiyonunda ilk parametre olarak stored
procedure' n ad verilmitir. kinci parametre olarak ise, params anahtar szc kullanlarak n
sayda object tipinden deer girilebilmesi salanmtr. Buna gre ExecuteReader metodu gelen
deer saysna gre ieride parametre oluturacak ve sp' ye gnderecektir. (Bu ilemlerin Data
Access Application Block (Veri Eriimi Uygulama Blou) ierisindeki kodlarda nasl yapldn
grmek iin, ExecuteReader satrna Breakpoint koymanz ve F11 ile adm adm ilerlemenizi
neririm.) Bylece sadece iki kod satr ile ne kadar ok kod kalablndan soyutlandmz daha
kolay grebilir ve veri eriim katmannn faydalarn fark edebilirsiniz. te Data Access Layer (veri
eriim katman) ' n faydas burada bir kez daha ortaya kmaktadr. Tm kod kalabaln i
mantmzdan soyutlamtr. Ayrca ynetiminide kendi ierisinde gerekletirmektedir.

Baka bir rnek daha ele alalm. Bazen uygulamalarmz n-katl mimariye sahip olabilir. rnein
veritabanndaki eitli tiplerin snfsal karlnn tutulduu bir entity katmanmz olduunu
dnelim. Bu katmanda pekala veri eriim katmann aktif olarak kullanacaktr. rnein, Urun
isimli aadaki tipi ele alalm.

www.bsenyurt.com Page 1569


public class Urun
{
private int _id;
private string _ad;
private double _fiyat;

public int Id
{
get { return _id; }
set { _id = value; }
}
public string Ad
{
get { return _ad; }
set { _ad = value; }
}
public double Fiyat
{
get { return _fiyat; }
set { _fiyat = value; }
}
public Urun()
{
}
public void Load(int id)
{
Database db = DatabaseFactory.CreateDatabase("conn");
IDataReader dr = db.ExecuteReader("GetProductById", id);
dr.Read();
_id = Convert.ToInt32(dr["ProductID"]);
_ad = dr["Name"].ToString();
_fiyat = Convert.ToDouble(dr["StandardCost"]);
}
}

Bu kod parasnda rnek olarak Urun isimli bir entitiy' nin alma zamannda karlk gelecei
herhangibir veri satr iin yklenebilmesini (Load) salarken veri eriim katmanndan nasl
yararlanabildiimizi grmektesiniz.

Data Access Application Block (Veri Eriimi Uygulama Blou)' un sunduu imkanlara ait pek ok
rnek gelitirebiliriz. Bir dier rnek ile makalemize devam edelim. Web tabanl uygulamalarda veri
balama ilemleri srasnda Business () katmannn veri eriim katmanndan nasl
yararlanabileceini greceimiz bir rnee bakalm.

Business () snfmz;

public class OurLogic


{
private Database _db;
public OurLogic()
{
_db = DatabaseFactory.CreateDatabase("conn");
}

www.bsenyurt.com Page 1570


// rnleri parametre olarak gelen GridView kontrolne ykleyen i katman metodu.
public void BindProducts(GridView dg)
{
dg.DataSource = _db.ExecuteDataSet(CommandType.Text, "Select * From
Production.Product");
dg.DataBind();
}

// rn kategorilerini parametre olarak gelen DropDownList kontrolne balayan, ve value ile


text zelliklerinide ayarlayan bir i katman metodu. Burada ListControl kullanlmasnn tek sebebi,
sayfalarda yer alan DropDownList ve ListBox kontrollerine de destek verilmesini salamaktr. Bu
yine ListControl' un polimorfik yapsnn salad bir avantajdr.
public void BindPrdCategories(ListControl dl)
{
dl.DataSource=_db.ExecuteReader(CommandType.Text,"SELECT ProductCategoryID,
Name FROM Production.ProductCategory");
dl.DataValueField = "ProductCategoryID";
dl.DataTextField = "Name";
dl.DataBind();
}

// rnlerin saysn int tipinde dndren bir i katman metodu. Bu metodda generic bir yapda
kullanlabilir. Bylece presentation katmanndan arlrken herhangibir tipe karlk gelecek ekilde
ele alnabilir.
public int GetCategoryCount()
{
return (int)_db.ExecuteScalar(CommandType.Text,"SELECT COUNT(*) AS
CategoryCount FROM Production.ProductCategory");
}

// Urun entity tipini verilen id' ye gre ykleyen ve geri dndren bir i katman metodu.
public Urun GetUrun(int id)
{
Urun urn = new Urun();
urn.Load(id);
return urn;
}
}

imdi i katmannn basit olarak sunum katmanndan nasl kullanldna bakalm.

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


{
protected OurLogic _ol;

protected void Page_Load(object sender, EventArgs e)


{

www.bsenyurt.com Page 1571


_ol = new OurLogic();
}
protected void btnProducts_Click(object sender, EventArgs e)
{
_ol.BindProducts(grdProducts);
}
protected void btnCategories_Click(object sender, EventArgs e)
{
_ol.BindPrdCategories(ddlProductCategories);
}
protected void btnGetCount_Click(object sender, EventArgs e)
{
lblCatCount.Text=_ol.GetCategoryCount().ToString();
}
protected void btnGet_Click(object sender, EventArgs e)
{
Urun urn = _ol.GetUrun(Convert.ToInt32(txtId.Text));
lstLoad.Items.Add(urn.Ad);
lstLoad.Items.Add(urn.Fiyat.ToString());
}
}

Grld gibi Data Access Application Block (Veri Eriimi Uygulama Blou) sayesinde
uygulamalarmz gelitirirken sadece i katmann ve sunum katmann dnmemiz yeterli

www.bsenyurt.com Page 1572


olmaktadr. Bunun bir avantaj olup olmad dnlebilir. Sonu itibariyle yazlm mhendisliine
yeni balayan arkadalar iin, veri eriim katmannn nasl olduunun farkna varmak veya nasl
yazldn anlamak iin Data Access Application Block (Veri Eriimi Uygulama Blou)' u incelemek
bile vizyonumuzu gelitirecek nemli bir etkendir. zellikle kendi projelerimizde, projenin
bykl ile orantl olacak ekilde kendi veri eriim katmanlarmz yazmay tercih edebiliriz.
Ancak performans, bellek ynetimi, tutarllk gibi kriterlerin nemi gz nne alndnda, Data
Access Application Block (Veri Eriimi Uygulama Blou)' un en azndan incelenmesi gerektii
kansndaym. Bu makalemizde ksaca Microsoft' un cretsiz olarak sunduu enterprise zm
desenlerinden birisi olan Data Access Application Block (Veri Eriimi Uygulama Blou)' un ne
olduunu ve hangi amalar ile kullanlabildiini temel dzeyde incelemeye altk ve geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Sql 2005 XML Veri Tipini XSD ile Dorulamak (


21.04.2006 ) - Sql 2005
Deerli Okurlarm Merhabalar,

Sql Server 2005 ile birlikte gelen en byk yeniliklerden birisi, yeni XML veri tipidir. XML veri tipini
tablolarda alanlar, stored procedure' lerde ve fonksiyonlarda parametreler veya deikenler iin
kullanabilmekteyiz. Ancak asl iyi olan nokta, XML veri tipinden herhangibir ieriin, XSD emalar
yardmyla doruluunun kontrol altna alnabilmesidir. Bir XML emas ile ilikilendirilmi ve
doruluu bu ema bilgisinde verilen kriterlere gre salanacak olan XML verisine, trlendirilmi
XML (Typed XML) ad verilmektedir. (Tam kart olan Untyped XML verisi ise sadece well-formed
olarak tanmlanm XML ieriini iaret etmektedir.)

Typed XML verileri, alma zamannda Untyped XML verilerine gre daha yksek
performans salar. nk Untyped XML ieriinde, elementlere ve niteliklere ait veriler
string formatnda tutulmakta olup alma zamannda gereksiz yere tr dnmlerinin
olmasna neden olmaktadr. Oysaki Typed XML verisinin ieriinde yer alan element ve
niteliklerin veri trleri zaten emada belirtilen trlerden olmak zorunadr. Bu da alma
zamannda gereksiz tr dnmlerini engelleyerek yksek performans salamaktadr.

Peki Sql Server 2005 zerinde, zellikle bir tablo alannn veri tipini XML olarak belirttiimizde, bu
alann ieriini bir XML emas ile (XML Schema) nasl ilikilendirebiliriz. Hereyden nce, XML veri
tipi ile ilikili olan ema bilgilerinin nasl ve ne ekilde tutulduunu bilmekte fayda var. Sql Server
2005 zerinde bir XML emas ounlukla bir ema koleksiyonuna (Schema Collection) eklenerek
kullanlmaktadr. Dier taraftan sistemde yer alan bir ka tablo zerinde de, bu ema ierisinde yer
alan isim alanlarna (namespaces), elementlere (elements), niteliklere (attributes) vb... ait bilgiler
saklanmaktadr. Dolaysyla alma zamannda bir XML veri alannn ieriini kontrol etmek iin,
Sql Server 2005 sistemine kayt edilmi (register) ema koleksiyonlarndan faydalalanlmaktadr.
ncelikle bir ema bilgisini Sql Server 2005 sistemine nasl kayt edebileceimize bakalm. Elimizde
aadaki gibi bir ema olduunu dnelim. (Var olan bir XML dkmannn ema bilgisini Visual
Studio.Net ortamnda Create Schema seenei yardmylada oluturabilirsiniz. Ben aadaki rnek
emay bu teknik ile oluturdum ve Sql Server 2005 sistemine kayt edilebilecek hale getirdim.)

www.bsenyurt.com Page 1573


<?xml version="1.0" encoding="utf-16"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.bsenyurt.com/Kitaplar"
xmlns="http://www.bsenyurt.com/Kitaplar">
<xs:element name="Kitaplar">
<xs:complexType>
<xs:sequence>
<xs:element name="Kitap">
<xs:complexType>
<xs:sequence>
<xs:element name="Ad" type="xs:string" />
<xs:element name="Fiyat" type="xs:int" />
<xs:element name="Basim" type="xs:date" />
<xs:element name="Yazarlar">
<xs:complexType>
<xs:sequence>
<xs:element name="Yazar" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="ID" type="xs:unsignedShort" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>

Bu ema bilgisinde Kitaplar root elementi ierisinde yer alan Kitap elementi tipinden boumlar
(nodes) yer almaktadr. Her bir Kitap boumu ierisinde ID isimli ve unsignedShort tipinden
nitelikler (attributes) olmak zorundadr. Kitap boumlar (nodes) ierisinde string tipinden Ad,
integer tipinden Fiyat ve date veri tipinden Basim elementleri yer almaktadr. Ayrca her Kitap
boumu (node) ierisinde string tipinden Yazar elementlerini tayan, Yazarlar isimli alt boumlarda
(Childe Nodes) yer almaktadr. Ksacas aadaki rnek XML ieriine ait bir ema yaps sz
konusudur.

<Kitaplar>
<Kitap ID="1000">

www.bsenyurt.com Page 1574


<Ad>Her Ynyle C#</Ad>
<Fiyat>50</Fiyat>
<Basim>2001-01-01Z</Basim>
<Yazarlar>
<Yazar>Sefer Algan</Yazar>
</Yazarlar>
</Kitap>
</Kitaplar>

Yukardaki gibi bir ema(Schema) bilgisini sisteme kayt edebilmek iin Sql Server 2005 zerinde
aadaki sorgu cmlesini altrmamz gerekmektedir. Bu cmle ile yukardaki ema bilgisini
sisteme KitapSchema XML ema koleksiyonu olacak ekilde eklemekteyiz.

IF EXISTS (SELECT schema_id FROM sys.XML_schema_collections WHERE


name='KitapSchema')
BEGIN
RAISERROR('ema zaten var...',16,1)
END;

CREATE XML SCHEMA COLLECTION KitapSchema


AS
N'<?xml version="1.0" encoding="utf-16"?>
<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.bsenyurt.com/Kitaplar"xmlns="http://www.bsenyurt.com/Kit
aplar">
<xs:element name="Kitaplar">
<xs:complexType>
<xs:sequence>
<xs:element name="Kitap">
<xs:complexType>
<xs:sequence>
<xs:element name="Ad" type="xs:string" />
<xs:element name="Fiyat" type="xs:int" />
<xs:element name="Basim" type="xs:date" />
<xs:element name="Yazarlar">
<xs:complexType>
<xs:sequence>
<xs:element name="Yazar" type="xs:string" />
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="ID" type="xs:unsignedShort" use="required" />
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>

www.bsenyurt.com Page 1575


</xs:element>
</xs:schema>'

Bu sql cmlesini altrdmz takdirde, sistemde yer alan belirli tablolara emamz ile ilgili bilgiler
eklenecektir. Bunlarn bir ksmn grmek iin aadaki ekran grntsnde yer alan sorgular
altrabilirsiniz. Bu bilgiler grdnz gibi sistem tablolarnda tutulmaktadr. zetle emamzn
ierii ayrtrlarak tablolara datlmtr.

Dikkat ederseniz en tepede ema koleksiyonumuzun (KitapSchema) yer ald sistem tablosuna
bakyoruz. Burada ema koleksiyonumuz iin oluturulan xml_collection_id alannn, namespaces,
elements ve attributes sistem tablolarnda nasl yer aldna dikkat ediniz. Grdnz gibi,
emamz ierisindeki her bir ayrnt sistem tablolarna yazlmaktadr. zellikle namespaces sistem
tablosundaki isim alan bizim iin nemlidir. Buradaki isim alann, ema bilgisini uygulamak
istediimiz XML veri tiplerinde kullanacaz. Varsaylan olarak, Visual Studio.Net gibi bir ortamda
ema dosyanz hazrladysanz eer (ki ben byle yaptm) encoding formatnn utf-8 olduunu ve
buradaki gibi http://www.bsenyurt.com/Kitaplar adnda bir isim alannn eklenmedii grrsnz.
Burada Utf-8 formatn mutlaka Utf-16 olarak evirmeliyiz. Nitekim Sql Server 2005 zellikle ema

www.bsenyurt.com Page 1576


bilgilerinde sadece Utf-16 formatn desteklemektedir. Ayrca, Sql Server 2005 ierisindeki XML
verilerinin bu emay kullanabilmesi iinde, namespaces sistem tablosuna bir adn eklenmi olmas
gerekmektedir. Bu amalada ayrca bir xmlns' i eklememiz gerekti. Aksi takdirde, namespaces
sistem tablosunda name alan bo olan bir satr elde ederiz.

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


<xs:schema attributeFormDefault="unqualified" elementFormDefault="qualified"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.bsenyurt.com/Kitaplar"xmlns="http://www.bsenyurt.com/Kit
aplar">

Artk sistemde, KitapSchema isminde bir XML ema koleksiyonumuz mevcuttur. Sra geldi bunu
nasl kullanacamza. Sql Server 2005 Management Studio' da grsel olarak tablolar olutururken
alana ait veri tipini XML olarak setikten sonra bu alana ait zelliklerden Schema Collection'
kullanarak ema bilgisini ekleyebiliriz. rnein aadaki resimde grld gibi Kitap isimli alann
veri tipi XML olarak belirlenmitir. Daha sonra ise Schema Collection zelliinde bizim az nce
eklediimiz KitapSchema ema koleksiyonu seilmitir.

Benzer kurallar, tablomuzu sorgu cmlesi ile olutururken de geerlidir. rnein aadaki sql
cmlesinde, yukardaki tabloya ait script yer almaktadr. Grdnz gibi XML veri tipini belirlerken
ieriin dbo.KitapSchema nesnesi tarafnda denetlenecei belirtilmektedir.

CREATE TABLE dbo.BookBase


(
ID int IDENTITY(1,1) NOT NULL,
Kitap xml(CONTENT dbo.KitapSchema) NOT NULL,
CONSTRAINT PK_BookBase PRIMARY KEY CLUSTERED
(
ID ASC

www.bsenyurt.com Page 1577


)WITH (IGNORE_DUP_KEY = OFF) ON PRIMARY
)
ON PRIMARY

imdi gelin, Kitap alanmza rnek bir XML verisini eklemeye alalm. Elbette, eklenecek olan
verinin buraya konulabilmesi iin KitapSchema emasnn syledii kurallara uymas
beklenmektedir. Bunu salamak iin, eklemek istediimiz XML ieriinde mutlaka ve mutlaka XML
isim alanmz uygulanmaldr. Aksi takdirde aadaki gibi bir hata mesaj alrz.

Aadaki insert sorgusunda geerli bir veri girii yaplmaktadr.

INSERT INTO dbo.BookBase VALUES


(N'<Kitaplar xmlns="http://www.bsenyurt.com/Kitaplar">
<Kitap ID="1000">
<Ad>Her Ynyle C#</Ad>
<Fiyat>50</Fiyat>
<Basim>2001-01-01Z</Basim>
<Yazarlar>
<Yazar>Sefer Algan</Yazar>
</Yazarlar>
</Kitap>
</Kitaplar>')

imdi ema bilgimizin alp almadn kontrol edebileceimiz rnek bir insert sorgusu
altralm. rnein Basim elementine geerli olmayan bir tarih bilgisi girelim. Bu durumda,
alma zamannda bir istisna alrz ve satrn tabloya eklenmediini grrz.

www.bsenyurt.com Page 1578


Son olarak sistemde yer alan bir ema koleksiyonunu kaldrmak istediimizde her zamanki gibi
drop anahtar szcn aadaki gibi kullanmamz gerekecektir.

IF EXISTS (SELECT schema_id FROM sys.XML_schema_collections WHERE name='KitapSchema')


BEGIN
DROP XML SCHEMA COLLECTION KitapSchema
END;

Grld gibi, Sql Server 2005 zerinde yer alan XML tipindeki alanlarn bir ema yardmyla
kontrol son derece kolay ve etkilidir. alma zamannda salanan performansn yan sra, XML
ieriinin bizim belirleyeceimiz ema kurallarna uygun bir biimde dorulanmas olduka
nemlidir. Bylece geldik bir makalemizin daha sonuna bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Server Side SponsorShip ( 19.04.2006 ) -


Remoting
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde Remoting mimarisinde istemci tarafl destek modelini incelemeye
almtk. stemci tarafl destek modelinin en byk problemlerinden birisi, istemcilerin firewall
arkasnda olmas halinde ortaya kmaktadr. Bu engel, sunucularn istemcilere eriimini
kstlayacandan istemci tarafl destek modelinin almas garanti altna alnmam olabilir. Bu
nedenle, istemcilerin firewall arkasnda olup olmadklarnn bilinmedii durumlarda kesinlikle
sunucu tarafl destek (server side sponsorship) modeli kullanlmaldr. Bu makalemizde sunucu
tarafl destek modelinin ileyi eklinden bahsedecek ve rnek bir uygulama gelitireceiz.

www.bsenyurt.com Page 1579


lk olarak modelin teorisinden birazda olsa bahsetmekte fayda var. Sunucu tarafl destek
modelinde, uzak nesne haricinde bu nesnenin kiralama sresini kontrol eden ve gerektiinde
otomatik olarak uzatan bir destek nesnesi(Sponsor Object) vardr. Yanlz bu sponsor nesne sunucu
tarafnda olduu iin, istemci tarafndan bir ekilde arlabilmeli ve kullanlabilmelidir. Dolaysyla
uzak nesnenin kiralama sresini kontrol eden sponsor nesnemizde aslnda bir uzak nesnedir. Yani
MarshallByRefObject tipinden tretilmitir. Dier taraftan bu sponsor nesnenin, uzak nesne
referansna ait kiralama sresini, sunucu tarafnda kontrol edebilmesi iin ayrca ISponsor
arayznde uygulamas gerekmektedir. Bildiiniz gibi ISponsor arayznn salad Renewal
metodu ile kiralama sreleri uzatlabilir.

Peki istemci tarafndaki uygulamalar uzak nesnenin kiralama sresini kontrol eden bu sponsor
nesnesini nasl kullanmaldr? stemci, uzak nesnesine ait kiralama sresinin mrn kontrol
edecek uzak sponsor nesnesinide belirli aralklarla ele alabilmelidir. Bu amala, istemci uygulama
zerinde sadece uzak sponsor' u belirli periyotlarla kontrol eden ve ayr bir thread ierisinde
alacak baka bir snf daha gereklidir. Bu snf ierisinde belirli zaman aralklarnda, uzak sponsor
nesnesine ait herhangibir ye metod arlr. Buradaki ama, istemci tarafndan bir ekilde uzak
sponsor nesnesini aktif olarak tutmaktr. Nitekim, uzak nesne kiralama sresinin ynetecek olan
referans sunucu zerinde duran sponsor nesne referansdr.

Model biraz kark grnebilir. Ancak rneimizi gelitirirken ok daha net anlalabileceini
dnmekteyim. Dilerseniz hi vakit kaybetmeden rneimizi gelitirelim. e hem sunucu hemde
istemci uygulamamzn ortak olarak kullanaca class library' yi tasarlamakla balayalm. Bu
ktphane ierisinde, hem uzak nesnemiz, hem de uzak sponsor nesnemiz iin gerekli interface
tanmlamalarn yapacaz.

using System;
using System.Runtime.Remoting.Lifetime;

namespace RemoteFace
{
public interface IRemoteObject
{
double Toplam(double x, double y);
}

public interface ISponsorObject:ISponsor


{
void CanliKal();
}

www.bsenyurt.com Page 1580


}

IRemoteObject isimli arayzmz (interface), uzak nesnemiz iin gerekli prototipi sunmaktadr. Bu
ktphanede asl nemli olan arayz ise ISponsorObject arayzmzdr. Bu arayzm ayrca
ISponsor arayznden de trettik. Bylece sponsor nesnemizin hem ISponsorObject arayzn
uygulamasn hem de, kiralama ynetimi iin gerekli olan ve ISponsor arayznden gelen Renewal
metodunu uygulamasn salam olacaz. Burada zellikle interface' leri kullanmamzn nedeni
bildiiniz gibi, istemci uygulamann sunucu tarafndaki uzak nesnelerin salad metodlarda olacak
deiikliklerden etklilenmemesini salamaktr. yleki biz istemci tarafnda bu arayzleri kullanarak
uzak nesne ve sponsorumuza ait referanslar arabileceiz. Polimirfizim (Polymorphsym)
saolsun. Gelelim sunucu tarafna. Sunucu tarafmzdaki uygulamamzda uzak nesnemizi ve uzak
sponsor nesnemizi aadaki gibi oluturacaz.

Uzak Nesne Snfmz;

class RemoteObj:MarshalByRefObject,IRemoteObject
{
public RemoteObj()
{
Console.WriteLine("Uzak nesne rnei oluturuldu " + DateTime.Now.ToString());
}
#region IRemoteObject Members

public double Toplam(double x, double y)


{
return x + y;
}

#endregion
}

www.bsenyurt.com Page 1581


Uzak Sponsor Snfmz;

class ServerSponsor:MarshalByRefObject,ISponsorObject
{
public ServerSponsor()
{
Console.WriteLine("Uzak sponsor nesne oluturuldu " + DateTime.Now.ToString());
}

#region ISponsorObject Members

public void CanliKal()


{
Console.WriteLine("Canli kal metodu arld " + DateTime.Now.ToString());
}

#endregion

#region ISponsor Members

public TimeSpan Renewal(System.Runtime.Remoting.Lifetime.ILease lease)


{
Console.WriteLine("Uzak nesne iin kiralama sresi yenilendi " + DateTime.Now.ToString());
return TimeSpan.FromSeconds(6);
}

#endregion
}

Uzak nesne snfmzdan ziyade, uzak sponsor nesne snfmzn ileyii bizim iin ok daha
nemlidir. Dikkat ederseniz, sponsor snfmzn ierisinde bir i yapmayan CanliKal isimli bir metod
vardr. Bu metodu istemci tarafnda yer alan baka bir snfmz kullanacak. Bunu biraz sonra
aklamakta fayda var. Sponsor snfmzn Renewal metodu kiralama sresini 6 saniye kadar
uzatyor. Peki bu kimin kiralama sresi? te istemci tarafnda yer alacak kodlarmzda, bu sponsor
nesnesinin ele alaca Lease Manager' seerken, uzak nesnenin kiralama yneticisini ele alp
sponsor nesnemize gndereceiz. Bir baka deyile, uzak nesnemizin kiralama yneticisine,
sponsor nesnemizi register edeceiz. Bylece uzak nesnenin kiralama sresini, sunucu zerindeki
sponsor nesne rneimiz stlenmi olacak. Vakit kaybetmeden sunucu uygulamamzn kodlarn ve
konfigurasyon dosyasn aadaki gibi gelitirelim.

Server;

static void Main(string[] args)


{
RemotingConfiguration.Configure(@"..\\..\\ServerApp.config",true);
Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
}

www.bsenyurt.com Page 1582


ServerApp.config

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


<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="4378">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
<service>
<wellknown type="Server.RemoteObj,Server" objectUri="RemObj"
mode="Singleton"/>
<wellknown type="Server.ServerSponsor,Server" objectUri="RemSpn"
mode="Singleton"/>
</service>
<lifetime leaseTime="6" renewOnCallTime="2" leaseManagerPollTime="1"/>
</application>
</system.runtime.remoting>
</configuration>

Dikkat ederseniz, hem uzak nesnemiz hemde sponsor nesnemiz iin ayr ayr SAO (Server
Activated Object) tipinde ve Singleton modeline uygun tanmlamalar yapyoruz. Sunucu zerinde
alacak uzak nesnelerimiz iin geerli kiralama srelerinide lifetime boumunda (node)
belirtmekteyiz. Elbette, buradaki kiralama sreleri tm referanslar iin geerli olacaktr. Yani hem
uzak nesnemiz hemde sponsor nesnemiz iin. Dilerseniz bu referanslarn kiralama srelerini ayr
ayrda tanmlayabilirsiniz. Bunun iin tek yapmanz gereken InitializeLifetimeService metodunu
uzak nesne snflar ierisinde override etmektir.

Gelelim istemci tarafndaki kodlara. Sunucu tarafl sponsor kullanmna ait teoriden bahsederken,
istemci tarafnda sunucu zerindeki sponsor referansn dzenli olarak tetikleyecek bir snf
olacandan bahsetmitik. te bu snfmz istemci uygulamamzda aadaki gibi gelitireceiz.

PollingObject

www.bsenyurt.com Page 1583


class PollingObject
{
private bool _canliBirak;
private ISponsorObject _sponsorObject;

public bool CanliBirak


{
get { return _canliBirak; }
set { _canliBirak = value; }
}

public PollingObject(ISponsorObject sponsorObject)


{
_canliBirak = true;
_sponsorObject = sponsorObject;
Thread currTrd=new Thread(this.CanliTut);
currTrd.Start();
}

public void CanliTut()


{
while (CanliBirak)
{
_sponsorObject.CanliKal();
Thread.Sleep(2000);
}
}
}

PollingObject isimli snfmzn en byk zellii, rnei oluturulurken parametre olarak


ISponsorObject tipinden bir nesne almas. Bu alma zamannda bizim oluturacamz uzak
sponsor nesne rneimiz (ServerSponsor) olacaktr. Basit olarak yapc metod bu nesne rneini
kullanacak CanliTut isimli metodu, ayr bir thread ierisinde ve CanliBirak isimli zellik deeri true
olduu mddete, aracaktr. Bu metodun arlmas ile, istemci tarafndan kullanlan uzak
nesneye ait kiralama sresinin, sunucu zerindeki sponsor nesne rnei tarafndan kontrol altna
alnmas salanm olunur. leyii istemci uygulamamzn kodlar ok daha iyi anlatmaktadr.

Client

static void Main(string[] args)


{
RemotingConfiguration.Configure("..\\..\\ClientApp.config", true);

IRemoteObject remObj = (IRemoteObject)Activator.GetObject(typeof(IRemoteObject),


"tcp://manchester:4378/RemObj");

#region Server Side Sponsor Kullanlmaya Balanr

ISponsorObject spnObj = (ISponsorObject)Activator.GetObject(typeof(ISponsorObject),

www.bsenyurt.com Page 1584


"tcp://manchester:4378/RemSpn");

PollingObject pllObj = new PollingObject(spnObj);

ILease il = (ILease)((MarshalByRefObject)remObj).GetLifetimeService();
il.Register(spnObj);

#endregion

for (int i = 0; i < 8; i++)


{
Console.WriteLine(remObj.Toplam(i, i + 1).ToString());
System.Threading.Thread.Sleep(4000);
}
Console.WriteLine("Metodlar sonlandrld...");
il.Unregister(spnObj);
pllObj.CanliBirak = false;
Console.WriteLine("Program kapatmak iin bir tua basn...");
Console.ReadLine();
}

lk olarak uzak nesnemizi (RemoteObject) kullanabilmemizi salayacak IRemoteObject referans


elde edilir. Ardndan ayn yol ile ISponsorObject referans elde edilir. Sonrasnda ise PollingObject
tipimize ait bir nesne rneini oluturuyoruz. te bu andan itibaren, parametre olarak
gnderdiimiz spnObj arayz ile sunucu zerindeki sponsor nesne referansn kullanmaya
balyoruz. zleyen satrda, uzak nesne rneini referans eden remObj' nin kiralama yneticisini
ILease arayzne atyoruz. te can alc nokta buras. ILease referansna, sunucu zerinde yer
alan sponsor nesnemizi kayt ediyoruz. Dolaysyla, PollingObject ierisinde ayr bir i parac
olarak alan CanliTut isimli metod 2 saniyelik aralklarla uzak sponsor nesne referansnn CanliKal
metodunu armaya balyor. Bu arlar sonucu uzak nesnenin kiralama sreside, ILease
referansn unregister edip, CanliTut metodunun ileyiini CanliBirak isimli zellie false deerini
atayp kesinceye kadar, uzamaya devam ediyor. Ksacas, istemcinin kulland uzak nesnenin
kiralama sresinin ynetimini, sunucu zerinde yer alan ve istemci tarafndan belirli periyotlarla
kontrol edilen uzak sponsor nesne referansna devretmi oluyoruz. Uygulamamz test etmeden
nce, istemci tarafndaki konfigurasyon dosyasnda aadaki gibi oluturalm.

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


<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp">
<clientProviders>
<formatter ref="binary" />
</clientProviders>
</channel>
</channels>
<client>
<wellknown type="RemoteFace.IRemoteObject,RemoteFace"
url="tcp://manchester:4378/RemObj/"/>

www.bsenyurt.com Page 1585


<wellknown type="RemoteFace.ISponsorObject,RemoteFace"
url="tcp://manchester:4378/RemSpn/"/>
</client>
</application>
</system.runtime.remoting>
</configuration>

imdi olay iyice analiz edebilmek iin client tarafndaki kodlarmzda sponsor nesne ile ilgili olan
ksmlar kaldrp altracaz.

static void Main(string[] args)


{
RemotingConfiguration.Configure("..\\..\\ClientApp.config", true);

IRemoteObject remObj = (IRemoteObject)Activator.GetObject(typeof(IRemoteObject),


"tcp://manchester:4378/RemObj");

for (int i = 0; i < 8; i++)


{
Console.WriteLine(remObj.Toplam(i, i + 1).ToString());
System.Threading.Thread.Sleep(4000);
}
Console.WriteLine("Metodlar sonlandrld...");
Console.WriteLine("Program kapatmak iin bir tua basn...");
Console.ReadLine();
}

Kullandmz uzak nesne rneini SAO olarak Singleton modunda tasarlamtk. Bununla birlikte
uzak nesne iin varsaylan kiralama srelerinide belirtmitik. stemci taraf pe pee uzak nesne
metodlarn ardnda, her kiralama sresi sonlandktan sonra sunucu zerinde yeni bir
referansn oluturulmu olmas gerekmektedir. Yani yapc metodlarn birden fazla kez arlmas
durumu sz konusudur.

www.bsenyurt.com Page 1586


Grdnz gibi, uzak nesne rneine ait kiralama sreleri sona erdike yeni uzak nesne
referanslar sunucu zerinde oluturulmutur. Ancak Sponsor kodlarmz tekrardan uygulamaya
dahil edersek aadaki sonular elde ederiz.(Aadaki ekran grnts flash formatnda olup,
flash player yklemenizi gerektirebilir...)

www.bsenyurt.com Page 1587


Bu sefer, uzak nesne rneimize ait tek bir referans tm uygulama boyunca yaamaktadr. nk
uzak sponsorumuz kiralama srelerini otomatik olarak yenilemektedir. Sunucu tarafl destek
kontrol uygulan asndan zor grnsede istemci tarafl destek modelinin baz dezavantajlarn
ortadan kaldrmaktadr. rnein FireWall engellerini. Bu yzdende remoting uygulamalarnda ska
tercih edilen bir yntemdir. Bylece geldik bir makalemizin daha sonuna bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek kod iin tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Client Side SponshorShip ( 12.04.2006 ) -


Remoting
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1588


Son makalemizde, remoting uygulamalarnda uzak nesnelere ait kiralama srelerinin (Lease Time)
nasl ynetilebileceinden bahsetmitik. Bununla birlikte bir uzak nesnenin kiralama sresinin
sonlamasnn ardndan gelecek olan metod arlarnda istemcilerin olmayan bir referansa erimeye
altn ve bu nedenlede alma zaman istisnalar ile karlaabileceklerini grmtk. Bu
makalemizde, kiralama srelerini otomatik olarak uzatmak iin istemci tarafl destek modelinden
(Client Side sponsorShip) nasl yararlanabileceimizi incemeleye alacaz.

SponsorShip mimarisi temel olarak, uzak nesnelerin yaam srelerini otomatik olarak arttrmak iin
kullanlr. ki ekilde uygulanabilir. Bunlardan birisi istemci tarafnda dieri ise sunucu tarafnda
yaplabilen destekleme sistemidir. Her iki destek trnnde birbirlerine gre avantajlar ve
dezavantajlar vardr. stemci tarafl destek modelinde (Client Side Sponsorship), istemcinin
kulland uzak nesnenin kiralama yneticisi (Lease Manager) ile, ISponsor arayznden tretilen
bir snfn i birlii sz konusudur. Bu ibirliinin bir sonucu olarak, uzak nesneye ait referansn
yaam sresini doldurmas halinde, istemci tarafl sponsor otomatik olarak devreye girecek ve
kiralama sresini uzatacaktr. Bu modelin alabilmesi iin, sunucudan gelen geri
bildirimlerin(Callbacks) istemci tarafndan ele alnabilmesi gerekmektedir. Bu da istemcinin yeri
geldiinde sunucu isteklerini kabul eden bir davran sergilemesi demektir. te bu nedenle,
zellikle firewall gibi gveli sistemlerin arkasnda kalan istemcilere sunucunun eriememesi halinde
istemci tarafl destek modeli bir ie yaramayacaktr. Bu istemci tarafl destek sistemi asndan bir
dezavantaj olarak grlebilir.

Peki istemci tarafl modeli nasl uygulayacaz? Bunu anlamann en iyi yolu basit bir rnek
zerinden gitmek ile olacaktr. Teorik olarak yapmak istediimiz ey, istemcilerin kulland uzak
nesnelere ait kirlama srelerini otomatik olarak arttrabilmek ve bylece alma zamannda
meydana gelecek kayp referans arlarnn nne geebilmektir. lk olarak uzak nesnemizi
gelitirmekle ie balayalm. Uzak nesnemizin aada grlen modele sahip olduunu dnelim.

public class RemoteObj : MarshalByRefObject


{
public RemoteObj()
{
Console.WriteLine("Uzak nesne yapc metodu arld...");
}

public int GetTotal(int orderID)


{
return orderID * 100;
}
}

www.bsenyurt.com Page 1589


imdi vakit kaybetmeden sunucu uygulamamzda aadaki gibi gelitirelim.

static void Main(string[] args)


{
RemotingConfiguration.Configure("..\\..\\ServerApp.config",true);
Console.WriteLine("Sunucu dinlemede...Kapatmak iin bir tua basn...");
Console.ReadLine();
}

Sunucu uygulamamza ait remoting ayarlarn bir konfigurasyon dosyasnda tutacaz. Dikkat
ederseniz, kiralama sresini mmkn olduunca ksa tutmaya altk. Uzak nesneye ait bir
referans oluturulduktan sonra yaklak olarak 3 saniyelik bir mr olacaktr. Dier taraftan
remoting mimarimizi CAO (Client Activated Object) modelini baz alarak gelitirdik. Bu nedenle
istemci tarafnda bir uzak nesne rnei oluturulur oluturulmaz, sunucu zerinde bu nesneye bal
bir referans hemen oluturulacaktr.

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


<configuration>
<system.runtime.remoting>
<application>
<service>
<activated type="RemoteLib.RemoteObj,RemoteLib"/>
</service>
<lifetime leaseTime="3" renewOnCallTime="1" leaseManagerPollTime = "1"
/>
<channels>
<channel ref="tcp" port="4567">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

Bu konfigurasyon dosyasnda standart ayarlarn yannda zellikle channel boumu ierisinde yer
alan serverProviders ve clientProviders isimli alt boumlar hemen gze arpmaktadr. Bu alt
boumlar aynen istemci tarafndada kullanlmak zorundadr.

Konfigurasyon dosyasnda serverProviders ve clientProviders boumlarn kullanmassak


(ki istemci destek modelinde bunlar hem istemci hem sunucu konfigurasyon dosyalarnda
kullanmalyz) gvenlik ile ilgili bir alma zaman hatasn aadaki gibi alrz.

www.bsenyurt.com Page 1590


Gelelim istemci uygulamamza. stemci uygulamamz ilk olarak aadaki gibi herhangibir destek
nesnesi (sponsor object) olmadan gelitireceiz. stemci uygulamamz basit olarak, uzak nesneye
ait bir nesne rneini client activated object modelinde oluturmaktadr. Daha sonra istemci, uzak
nesne referansn kullanarak GetTotal isimli metodu arka arkaya 10 defa armaktadr. Bu metod
armlarnn her birinde istemci uygulama yaklak olarak 3 saniye sreyle uyutulmaktadr.
Dolaysyla bu gecikmeler, uzak referansn kiralama sresinin dolmasna ve bu sre dolmadan
metod armlarnn tamamlanamamasna neden olacaktr. te buda bizim sponsor ynetimine
gitmemizi salayacak etkendir.

static void Main(string[] args)


{
RemoteObj rm = null;

try
{
RemotingConfiguration.Configure("..\\..\\ClientApp.config", true);
rm = new RemoteObj();

for (int i = 0; i < 10; i++)


{
Console.WriteLine(i+"nci ar..."+rm.GetTotal(i).ToString());
System.Threading.Thread.Sleep(3000);
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
finally
{

}
Console.WriteLine("Program kapatmak iin bir tua basn...");
Console.ReadLine();
}

stemci uygulamamza ait konfigurasyon dosyas ise aadaki gibidir. Dikkat ederseniz, channel
bilgisinde tcp tipini ve 0 numaral bir portu hizmete sunduumuzu gryorsunuz. Port bilgisinin 0
olmas, bir sunucunun bu istemciye balanmaya almas srasnda, uygun olan bo portlardan
birinin sunucuya hizmet iin tahsis edilmesini salar. Burada byle bir channel tipi kullanmamzn
tek nedeni, istemcinin destek modelini kullanabilmesini salamaktr. Nitekim bu modelde, sunucu
uygulama, istemci tarafna geri bildirimlerde bulunabilmelidir. Buda istemcinin yeri geldiinde
sunucu gibi davranmasn gerektirir ki bu ancak uygun bir portun sunucuya verilmesi ile
gerekleebilir.

www.bsenyurt.com Page 1591


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.runtime.remoting>
<application>
<client url="tcp://manchester:4567">
<activated type="RemoteLib.RemoteObj,RemoteLib"/>
</client>
<channels>
<channel ref="tcp" port="0">
<serverProviders>
<formatter ref="binary" typeFilterLevel="Full"/>
</serverProviders>
<clientProviders>
<formatter ref="binary"/>
</clientProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

stemci uygulamamz bu haliyle test ettiimizde alma zamannda daha ikinci metod armna
geemeden aadaki ekranda grlen hata mesaj ile karlarz.

Bu hatann nedeni son derece aktr. Uzak nesneye ait referansn kiralama sresi (Lease Time)
dolduu iin istemci uygulamamz, alma zamannda olmayan bir referansa ait kayp metod
arlarnda bulunmaktadr. O halde artk, destek modelini kullanarak bu hatann nne nasl
geebileceimize bakabiliriz. lk olarak istemci tarafl destek mimarisini (Client Side SponsorShip)
kullandmz iin, istemci tarafnda bir takm deiiklikler yapmamz gerekecektir. Bunlardan
birincisi, sponsor hizmetini kullanacak olan bir snfn tasarlanmasdr. Bu snf aadaki gibi
gelitirdiimizi dnebiliriz.

www.bsenyurt.com Page 1592


class ClientSponsor : MarshalByRefObject, ISponsor
{
#region ISponsor Members

public TimeSpan Renewal(ILease lease)


{
Console.WriteLine("Sponsor sre yenileme metodu altrld.");
return TimeSpan.FromSeconds(5);
}

#endregion
}

Dikkat ederseniz, istemci tarafl bir sponsor nesnesi MarshalByRefObject ile ISponsor tiplerinden
trer. ISponsor tipi, Renewal isimli bir metod sunar. Bu metodun geri dn tipi TimeSpan
trnden bir sredir ve sponsor nesnesinin ilikilendirildii uzak nesne referansnn yeni kiralama
sresini belirtmektedir. Bu metod Lease Manager ile konuabilmek iin parametre olarak ILease
arayz tipinden bir nesneyi kullanr. rneimizde kiralama sresini 5 saniye kadar uzatyoruz.
Dolaysyla, uzak nesne refaransna ait kiralama sresinin sonlanmas halinde oluacak kayp metod
arlarnn da nne gemi oluyoruz. Ancak henz iimizi tamamlam deiliz. Yazm olduumuz
bu snfn grevini yerine getirebilmesi iin, alma zamannda gncel Lease Manager' a kayt
edilmesi (register) gerekmektedir. Kaydetme ileminin tam tersi olan unregister ilemi ise, sponsor
nesnesi ile Lease Manager' n ortakln kesen bir davran gsterir. stemci uygulamamzn client
side sponsor snfn kullanacak yeni hali aadaki gibi olmaldr.

static void Main(string[] args)


{
ILease il=null;
ClientSponsor cs=null;
RemoteObj rm = null;

try
{
RemotingConfiguration.Configure("..\\..\\ClientApp.config", true);
rm = new RemoteObj();

www.bsenyurt.com Page 1593


#region Sponsor register edilir.

il = (ILease)rm.GetLifetimeService();
cs = new ClientSponsor();
il.Register(cs);

#endregion

for (int i = 0; i < 10; i++)


{
Console.WriteLine(i+"nci ar..."+rm.GetTotal(i).ToString());
System.Threading.Thread.Sleep(3000);
}
}
catch (Exception err)
{
Console.WriteLine(err.Message);
}
finally
{
il.Unregister(cs);
}
Console.WriteLine("Program kapatmak iin bir tua basn...");
Console.ReadLine();
}

Sponsor snfmza ait nesne rneini alma zamannda, istemci tarafndan kullanlan uzak nesne
referansna ait Lease Manager ile ilikilendirebilmek iin yine gncel Life Time Servisini elde
etmemiz gerekir. Bunun sonucu olarak oluan ILease arayz tipini kullanarak sponsor nesnemizi
Lease Manager iin kayt edebiliriz.(Register) Uygulamamz imdi bu haliyle altracak olursak hi
bir problemle karlalmadn grrz. Dikkat ederseniz belirli zaman aralklarnda kiralama
sreleri sona ermeden otomatik olarak uzatlmaktadr.

www.bsenyurt.com Page 1594


Tm metodlar altrlmasn tamamladktan sonra, finally blou ierisinde sponsor snfmza ait
nesne rneide unregister edilerek Lease Manager ile olan ibirliine son verilmektedir. Grld
gibi istemci tarafl destek modeli ile, kiralama sreleri sona ermi olan referanslarn yol aaca
kayp metod armlarnn nne geebilir ve uygulamann devamlln salayabiliriz. stemci
tarafl bu modelin dnda bir de sunucu tarafl bir destek modeli olduundan bahsetmitik. (Server
Side Sponsorship) Bu modelide bir sonraki makalemizde incelemeye alacaz. Bylece geldik bir
makalemizin daha sonuna bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek kod iin tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

.Net Remoting - Lease Time (Kiralk Sre)


Ynetimi ( 06.04.2006 ) - Remoting
Deerli Okurlarm Merhabalar,

Remoting mimarisi gz nne alndnda dikkat ekici noktalardan bir tanesi, sunucu tarafnda
oluturulan uzak nesnelerin (remote object) yaam sreleridir. stemciler, uzak nesnelere ait
referanslar kullanrken bunlarn yaam srelerini sunucu tarafndaki konfigurasyon belirler. Bu
istemcilerin sunucu tarafndaki referanslara ait kaynaklara aka mdahale edememesinin de bir
sonucu olarak grlebilir. Sunucu tarafnda yaplan bu yaam srelerinin ynetimine ksaca Kiralk
Sre Ynetimi (Lease Time Management) denmektedir. Bu makalemizde ksaca bu konuyu
incelemeye alacaz.

www.bsenyurt.com Page 1595


Bir istemci, uzak nesneye ait bir referans oluturduunda sunucu tarafnda bu referans iin bir geri
saym sresi balatlr. Buna ounlukla Initial Lease Time (Balang Kiralama Sresi) denir. Bu
sre geriye doru hareket eder ve sunucu tarafnda alan Lease Manager yardmyla belirli
aralklarla (varsaylan olarak 10 saniyede 1) kontrol edilir. Eer bir referansn geriye doru ileyen
kiralama sresi sonlanrsa (ki bu o anki srenin 0 olmas anlamna gelir), garbage collector
tarafndan toplanlmak zere iaretlenir. te bu andan sonra istemci, ayn referansa ait bir yeyi
ardnda alma zamannda bir exception ile karlar. Bunun sebebi istemci tarafndan
oluturulan uzak nesnenin sunucu zerindeki kiralama sresinin sfrlanm bir baka deyile yaam
sresinin bitmi olmas ve bu nesneye ait referansn artk sunucuda bulunamaydr.

Balangta bir uzak nesnenin InitialLeaseTime sresi 300 saniyedir. Yani 5 dakika kiralama
sresi sz konusudur. stemcileri var olmayan bir referansa ait metodlar armalar halinde
karlaacaklar exception' lardan korumann eitli yollar vardr. Bunlardan birisi uzak nesneye
ait RenewOnCallTime zelliinin deeridir. Bu deere verilen sre, bir uzak nesne referansnn
Lease Time sresi dolmadan nce, istemci tarafndan gelebilecek bir metod armnn ele
alnmasnda nemli rol oynamaktadr. Bunu yle aklayabiliriz. Bir uzak nesnenin kiralama
sresinin 6 saniye olduunu ve RenewOnCallTime sresininde 2 saniye olduunu dnelim.
stemci uzak nesneye ait bir referans ilk oluturduunda, kiralama sresi geriye doru azalmaya
balayacaktr. Sunucu zerindeki gncel kiralama sresi (Current Lease Time) 2 saniyeye
geldiinde, eer istemci tarafndan bir metod ars daha yaplrsa, nesnenin kiralama sresi
otomatik olarak RenewOnCallTime' da belirtilen sreye ayarlanr. Bu durumda bu sre 2 saniye
olacaktr. RenewOnCallTime sresinin ileyiini rneklerimizde daha yakndan analiz edeceiz ve
daha kolay anlayacaz.

Uzak nesnelere ait referanslarn yaam srelerini istersek deitirebiliriz. Bunu gerekletirebilmek
iin uzak nesneye ait kaltm yolu ile gelen InitializeLifeTimeService isimli metodu override
(ezmek) etmemiz gerekecektir. Bu metod temel olarak uyguland tipe ait kiralama srelerinin
ynetiminin salanmasndan sorumludur. Buradaki ayarlamalar yardmyla bir uzak nesne
referansnn InitialLeaseTime ve RenewOnCallTime srelerini ayarlayabiliriz. Hatta referansn
sonsuza dek (elbetteki evre koullar uygun olduu srece) yaamasnda salayabiliriz.

Kiralama srelerinin (Lease Time) ynetimi sadece Client Activated Object' ler iin ve
Server Activated Object' lerdede sadece Singleton modeli iin geerlidir. Yani SingleCall
iin kiralama sreleri uygulanamaz. Nitekim SingleCall modelinde uzak nesne referanslar
metod armlarndan sonra zaten yok edilirler.

imdi kiralama srelerini ynetebileceimiz basit bir rnek ile konumuzun derinlerine inmeye
alalm. lk olarak RenewOnCallTime sresinin salad etkiyi incelemeye alacaz. Sunucu
tarafmzda yer alacak uzak nesne modelinde, kiralama srelerini yneteceiz ve ardndan istemci
tarafnda bu nesneye ait rneklemelerin ve ye armlarnn etkilerini incelemeye alacaz.
Model olarak iimizi kolaylatrmas asndan Client Activated Object tipinden uzak nesneler
kullanacaz. lk olarak uzak nesnemizi aadaki gibi oluturalm.

public class RemoteObj : MarshalByRefObject


{
public string Info(string prm)
{
return "Remote Metod " + prm;
}

public RemoteObj()
{

www.bsenyurt.com Page 1596


Console.WriteLine("Nesne oluturuldu...");
}

public override object InitializeLifetimeService()


{
ILease lease = (ILease)base.InitializeLifetimeService();
if (lease.CurrentState == LeaseState.Initial)
{
lease.InitialLeaseTime = TimeSpan.FromSeconds(6);
lease.RenewOnCallTime = TimeSpan.FromSeconds(2);
}
return lease;
}
}

Uzak nesnemizi incelediimizde bizim iin belkide en nemli metod override edilmi olan
InitializeLifeTimeService' dr. Peki bu ezme ilemi ile ne yapyoruz biz? Bu metod tam olarak
alma zamannda bir uzak nesnenin ilk oluturulduu srada, sadece o nesne rneine ait referans
iin geerli olacak kiralama srelerini belirlemektedir. rnein buradaki deerlere gre referans 6
saniye boyunca sunucu zerinde kiralanacaktr. Eer nesnenin mrnn bitmesine 2 saniye
kaldnda, bu son sre ierisinde de bir metod arm gerekleirse kiralama sresi
RenewOnCallTime' da belirtildii zere 2 saniyeye set edilecektir. Nesnemizin bu yaam sreleri ile
kullann incelemek amacyla sunucu ve istemci tarafndaki kodlarmz aadaki gibi gelitirelim.

Sunucu;

static void Main(string[] args)


{
TcpServerChannel srvC = new TcpServerChannel(4500);
ChannelServices.RegisterChannel(srvC,true);
RemotingConfiguration.RegisterActivatedServiceType(typeof(RemoteObj));
LifetimeServices.LeaseManagerPollTime=TimeSpan.FromSeconds(1);
Console.WriteLine("Server dinlemede...");
Console.ReadLine();
}

Sunucu tarafnda yer alan kodlarmzda, LeaseManager iin LeaseManagerPollTime sresini 1 saniye
olarak ayarlamaktayz. Bu, LeaseManager' n her bir saniyede, sunucu zerindeki uzak nesne
referanslarnn kiralama srelerini kontrol edecei anlamna gelmektedir.

stemci;

static void Main(string[] args)


{
try
{
TcpClientChannel cliC = new TcpClientChannel();
ChannelServices.RegisterChannel(cliC, true);

www.bsenyurt.com Page 1597


RemotingConfiguration.RegisterActivatedClientType(typeof(RemoteObj),
"tcp://manchester:4500/");
RemoteObj rmo = new RemoteObj();
for (int i = 1; i < 6; i++)
{
Console.WriteLine(rmo.Info("Test " + i.ToString()));
ILease currLease = (ILease)rmo.GetLifetimeService();
Console.WriteLine(currLease.CurrentLeaseTime.ToString());
System.Threading.Thread.Sleep(2000);
}
}
catch (System.Exception err)
{
Console.WriteLine(err.Message);
}
Console.ReadLine();
}

stemci tarafnda yaptklarmza gelince. Burada uzak nesneye ait rnek oluturulduktan sonra, bu
referansa ait Info isimli metod arka arkaya 6 kez altrlmaktadr. Her bir metod armndan
sonra uzak nesne referansnn sunucu zerinde kalan kiralama sresi mr istemci tarafndaki
Console penceresine yazlmaktadr. Daha sonrasnda ise process 2 saniye kadar uyutulur. imdi
uygulamann almasn izleyelim. (Aadaki video grnts flash formatnda olup bilgisayarnza
flash player kurmanz gerektirebilir.)

www.bsenyurt.com Page 1598


Burada dikkat ederseniz, metodun 3nc arlndan itibaren nesneye ait kiralama sresi hep 2
saniye olarak kalmtr. Bunun sebebi, 2nci artan sonra gelen 3nc metod arnn artk
RenewOnCallTime sresi snrlarna dahil olmasdr. Bu nedenle referansa ait kiralama sresi
sonraki armlarda srekli olarak 2 saniyeye set edilmitir. Bu sayede istemci 6 metod
armnda baarl bir ekilde yapabilmitir. Oysaki kiralama sreleri aslnda ok hassas dengeler
zerinde almaktadr. Yaplacak ufak hatalar istemcileri bana sorun aabilir. Bunu grmek iin
istemci tarafndaki bekleme sresini 4 saniyeye kartalm ve uygulamamz yeniden test
edelim.(Aadaki video grnts flash formatnda olup bilgisayarnza flash player kurmanz
gerektirebilir.)

Dikkat ederseniz, 3nc metod armnda uygulama bir istisna ile sonlanmaktadr. lk metod
armnda kiralama sresi yaklak olarak 6 saniye civarndadr. kinci arma geerken
uygulama 4 saniye duraksamtr. Bu nedenle kiralama sresi bu nesne rneimiz iin yaklak 2
saniyeye kadar inmitir. 3nc metod armnda nce istemci uygulama 4 saniye daha bekler.
Oysa bu sre ierisinde, uzak nesne referans kiralama mrn doldurduundan, garbage collector
tarafndan toplanlmak zere iartlenir. Dahas bu 4 saniyelik bekleme sresi ierisinde baka bir
metod arm olmadndan RenewOnCallTime sresinin snrlarda artk geerli deildir.
Dolaysyla istemci artk olmayan bir referansa arda bulunmaya almaktadr. Bunun doal
sonucu olarakta istemci uygulamada bir istisna oluacaktr. Dolaysyla alma zamannda bu gibi
durumlarn oluabileceini dnmek ve buna gre hareket etmekte fayda vardr. Dilerseniz, bir
uzak nesne referansnn mmkn olduunca uzun sre yaamasn isteyebilirsiniz. Buna genellikle
sonsuz kiralama sresi (infinity lease time) denir. Bunun iin tek yapmanz gereken uzak
nesnede ezdiimiz InitializeLifetimeService metodundan geriye null bir referans dndrmek
olacaktr.

public override object InitializeLifetimeService()


{

www.bsenyurt.com Page 1599


return null;
}

Bu durumda az nce duraklama sresi 4 saniye olan istemci uygulamay altrdmzda bir sorun
ile karlamadan tm metod arlarn sonulandrldn grrz. (Aadaki video grnts
flash formatnda olup bilgisayarnza flash player kurmanz gerektirebilir.)

Tabi burada istemci tarafnda dikkat edilmesi gereken bir husus vardr. Buda Infinity Lease Time
olmas durumunda, istemci zerinden o anki referansa ait CurrentLeaseTime sresinin
okunamayacadr. Buda alma zamannda istisnaya neden olacak bir durumdur.

Bir uzak nesneye ait kiralama srelerini sadece kod tarafnda deil xml tabanl konfigurasyon
dosyalarnda da tutabiliriz. Bildiiniz gibi, Remoting uygulamalarnn daha esnek olmas asndan
channel, port, type, objectUri gibi bir takm bilgileri konfigurasyon dosyalarnda tutmaktayz.
Dolaysyla sunucu uygulamamz iin gerekli konfigurasyon dosyasn aadaki gibi oluturabiliriz.

<configuration>
<system.runtime.remoting>
<application>
<channels>
<channel ref="tcp" port="4500" />
</channels>
<lifetime leaseTime="6" renewOnCallTime="2" leaseManagerPollTime = "1" />
<service>
<activated type="RemoteObjects.RemoteObj,RemoteObjects"/>

www.bsenyurt.com Page 1600


</service>
</application>
</system.runtime.remoting>
</configuration>

Kiralama srelerine ait bilgiler eer aksi belirtilmesse her zaman saniye cinsinden uzunluklar temsil
eder. Ancak farkl taklar kullanarak bu sre cinslerini deitirmemiz mmkndr. Bu deerleri
aadaki tabloda bulabilirsiniz.

Harf Anlam rnek

D Gn 3D (3 gn)

H Saat 2H (2 saat)

M Dakika 45M (45 dakika)

S Saniye 15 (15 saniye)

100 (100
MS Milisaniye
milisaniye)

zetlemek gerekirse, bir uzak nesnenin varsaylan kiralama sresini (lease time) deitirebilir ve
referanslarn yaam srelerini etkilyebiliriz. Bu makalemizde bunu gerekletirmek iin programatik
olarak ve konfigurasyon baznda kullanabileceimiz yollar inceledik. Bir sonraki makalemizde,
Sponsor tekniini incelemeye alacaz. Bylece geldik bir makalemizin daha sonuna bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek kod iin tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

.Net Remoting - Synchronous, Asynchronous,


OneWay ( 31.03.2006 ) - Remoting
Deerli Okurlarm Merhabalar,

Remoting gibi mimarilerde bazen istemcilerin (clients) ardklar uzak nesnelere (remote objects)
ait metodlarn dn sreleri uzun zaman alabilir. Bu gibi durumlarda istemci doal olarak, uzak
nesne zerinden ard metodun geri dnn beklemek durumunda kalr. Dolaysyla istemci
uygulamann, uzak nesne armna paralel olarak yrtebilecei ilemler var ise bunlarda askda
kalacaktr. Bunun deiik nedenleri olabilir. Gerektende ilemler uzun srebilir. rnein veritaban
bazl ilemlerin uzak sunucular zerinde gerekletii remoting uygulamalarnda ska rastlanabilen
bir durumdur. Varsaylan olarak istemci tarafnda eer hi bir zelletirme yaplmaz ise,

www.bsenyurt.com Page 1601


senkron(Synhronous) alan bir yap sz konusudur. Bu makalemizde Senkron model ile balayp,
Asenkron ve OneWay metod arm modellerini incelemeye alacaz.

Aadaki kod parasnda yer alan remoting uygulamas senkron yapya bir rnektir. Uzak
nesnemize ait snf modelinde ok basit bir metod yer almaktadr. Bu metodun geri dn sresini
arttrmak ve istemcinin durumunu analiz edebilmek iin Thread tipinin Sleep metodu ile uzak nesne
metodu ierisinde gncel i parac bir sre uyutulmutur.

stemci tarafnda asenkron(Asynchronous) veya tek yn (OneWay) iin bir zelletirme


yaplmamsa, uygulama Senkron (Synchronous) kurallar erevesinde iler.

Uzak nesneye ait interface modelimiz,

using System;

namespace RemoteLib
{
public interface IRLib
{
int GetTotal(int orderID);
}
}

Sunucu taraf uygulama kodlarmz,

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemoteLib;

namespace Server
{
// Uzak nesne tipimiz
public class OrderObj:MarshalByRefObject,IRLib
{

#region IRLib Members

public int GetTotal(int orderID)


{
Console.WriteLine("Metod arld...");
System.Threading.Thread.Sleep(4000);
return orderID;
}

www.bsenyurt.com Page 1602


#endregion
}

// Sunucu uygulama
class Program
{
static void Main(string[] args)
{
TcpServerChannel srvC = new TcpServerChannel(8777);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(OrderObj), "OrderObj",
WellKnownObjectMode.SingleCall);
Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
}
}
}

stemci taraf uygulama kodlarmz,

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Tcp;
using RemoteLib;

namespace Client
{
// stemci uygulama
class Program
{
static void Main(string[] args)
{
TcpClientChannel cliC = new TcpClientChannel();
IRLib rl = (IRLib)Activator.GetObject(typeof(IRLib), "tcp://manchester:8777/OrderObj");
Console.WriteLine(rl.GetTotal(1001).ToString());
Console.WriteLine("Metod sonras kodlar...");
Console.ReadLine();
}
}
}

Sunucu ve istemcinin almasna bakalm. (Aadaki video grnts flash player


gerektirmektedir.)

www.bsenyurt.com Page 1603


Aka grld gibi, istemci uzak nesneye ait GetTotal isimli metodu ardktan sonra, izleyen
kod satrna geebilmek iin, uzak nesne metodunun tamamlanmasn beklemek zorunda kalmtr.
Yaklak 4 saniyelik gecikmenin ardndan, istemci tarafnda izleyen kod satrlar iletilebilmitir. te
bu senkron eriim modelidir. Elbette bu modelin dezavantajl bir model olduu konusunda kesin
yargya varmak yanltr. Nitekim zaman zaman, istemci tarafnn izleyen kod satrlarnn ileyii,
uzak nesneden dnecek deerlere bal olabilir. Bu gibi durumlarda senkron model dna
kmamakta fayda vardr.

Senkron modelde, istemcinin uzak nesneden (remote object) dnecek olan sonular
beklemesi her zaman bir dezavantaj olarak grlmemelidir. ou zaman, uzak nesnenin
dndrd deerler, istemcinin izleyen kod satrlarnda kullanlacak tipte olabilir.

Gelelim asenkron (asynchronous) metod arm modeline. Eer Xml Web Servislerindeki asenkron
eriim modelini hatrlarsanz, proxy snf ierisinde Begin ve End kelimeleri ile balayan metodlar
yer aldn bilirsiniz. Bu metodlar yardmyla Web Metodlarna (Web Method) asenkron olarak
erimek mmkndr. Oysaki Remoting mimarisinde, yukardaki rnei gz nne aldmzda fiziki
bir proxy snf yer almamaktadr. Dolaysyla bizim istemci tarafnda, asenkron yrtme iin
gereken ilevleri bir temsilci (delegate) yardmyla baarmamz gerekecektir. Nitekim temsilci tipleri
yardmyla BeginInvoke ve EndInvoke metodlarna eriilebilmektedir. Asenkron eriim modelinde
pf nokta, uzak nesne zerinde yer alan ve asenkron olarak yrtlmek istenen metod modelinin,
istemci tarafnda bir temsilci (delegate) tipi yardmyla alma zamannda iaret edilecek olmasdr.
stemci tarafndaki bu temsilci tipini kullanarak BeginInvoke ve EndInvoke metodlarna arabilir
ve bylece uzak nesne metodunu asenkron olarak yrtebiliriz. Yine yukardaki rneimizi gz
nne alacak olursak yapmamz gereken deiiklikler istemci tarafndadr.

namespace Client
{
delegate int dlgGetTotal(int orID);

www.bsenyurt.com Page 1604


class Program
{
static void Main(string[] args)
{
TcpClientChannel cliC = new TcpClientChannel();
IRLib rl = (IRLib)Activator.GetObject(typeof(IRLib), "tcp://manchester:8777/OrderObj");
dlgGetTotal currGetTotal = new dlgGetTotal(rl.GetTotal);
IAsyncResult res=currGetTotal.BeginInvoke(1001, null, null);
Console.WriteLine("Metod sonras kodlar...");
Console.WriteLine(currGetTotal.EndInvoke(res).ToString());
Console.ReadLine();
}
}
}

Grld gibi ilk olarak, OrderObj isimli uzak nesnemize ait GetTotal metodunu, istemci tarafnda
iaret edebilecek bir temsilci tanmladk. alma zamannda bu temsilci tipine ait bir nesne rnei
yardmyla, istemcinin eritii o anki uzak nesne referans zerindeki asl GetTotal metodunu iaret
edebileceiz. Bunu salamak iin currGetTotal isimli delegate rneini nasl oluturduumuza
dikkat edin. Buradaki rl arayz rneinin ard GetTotal metodu, alma zamannda aktif olan
uzak nesne referansnn sahip olduu GetTotal metodudur.

dlgGetTotal currGetTotal = new dlgGetTotal(rl.GetTotal);

Artk bu noktadan itibaren BeginInvoke ve EndInvoke metodlarn arabiliriz. BeginInvoke metodu


bildiiniz gibi geriye IAsyncResult arayz tipinden bir nesne dndrr.

IAsyncResult res=currGetTotal.BeginInvoke(1001, null, null);

Bunu elde ettikten sonra, istemci tarafnda izleyen kod satrlar baarl bir ekilde alacaktr.
Hemen ardndan EndInvoke metodu arlp, ortamdaki IAsyncResult arayz nesnesi bu metoda
devredilerek asl sonular istemci tarafna alnr.

Console.WriteLine(currGetTotal.EndInvoke(res).ToString());

Burada sembolik olarak istemci tarafnda BeginInvoke operasyonundan sonra sadece tek satrlk
kod almaktadr. Bundan sonra hemen EndInvoke metodunu armaktayz. EndInvoke metodu,
eer sunucu tarafndaki uzak nesne metodu halen geriye bir sonu dndrmemi ise, bu sonu
gelene kadar da uygulamay duraksatacaktr. Bunu unutmamamz gerekir. Sunucu ve istemcinin
almasna bakalm. (Aadaki video grnts flash player gerektirmektedir.)

www.bsenyurt.com Page 1605


Asenkron eriim modelinde genellikle yukardaki kullanm tarz yerine Callback teknii kullanlr. Bu
teknie gre, uzak nesne metodu asenkron olarak almasn bitirdiinde, istemci tarafndaki
callback metodu otomatik olarak devreye girerek sonular uygulamaya devredecektir. imdi
yukardaki rneimizi buna gre deitirelim. Tek yapmamz gereken, BeginInvoke metodunda
Callback metodu ile ilgili parametreyi bildirmek olacaktr. Sz konusu parametre AsyncCallback
tipinden bir temsilci nesne rneidir. Bu temsilci nesne rnei, alma zamannda asenkron olarak
yryen metod ileyiini tamamlad anda devreye girecek olan geri bildirim metodunu iaret
etmektedir. Dolaysyla rneimizin kodlarn aadaki gibi deitirerek Callback tekniini
uygulayabiliriz.

namespace Client
{
delegate int dlgGetTotal(int orID);

class Program
{
static dlgGetTotal currGetTotal;

static void Main(string[] args)


{
TcpClientChannel cliC = new TcpClientChannel();
IRLib rl = (IRLib)Activator.GetObject(typeof(IRLib), "tcp://manchester:8777/OrderObj");
currGetTotal = new dlgGetTotal(rl.GetTotal);
AsyncCallback acb = new AsyncCallback(CallbackMetod);
IAsyncResult res = currGetTotal.BeginInvoke(1001, acb, null);
Console.WriteLine("Metod sonras kodlar...");
for (int i = 0; i < 8; i++)
{
System.Threading.Thread.Sleep(1000);

www.bsenyurt.com Page 1606


Console.Write("+");
}
Console.ReadLine();
}

static void CallbackMetod(IAsyncResult res)


{
if(res.IsCompleted)
Console.Write("Metod sonucu {0}",currGetTotal.EndInvoke(res).ToString());
}
}
}

AsyncCallback temsilci tipi, IAsyncResult arayz tipinden nesne rnekleri alan ve geriye deer
dndrmeyen metodlar iaret etmektedir. Biz uygulamamza bu amala CallbackMetod isimli bir
metod ekledik. Bu metod ierisinde, eer asenkron olarak yrtlen uzak nesne metodu ileyiini
tamamlamsa (ki bunu metoda parametre olarak gelen IAsyncResult nesne rneinin IsCompleted
zellii ile anlyoruz) sonular ortama aktarmak iin EndInvoke metodu arlr. Callback
metodunun devreye alnabilmesi iin BeginInvoke metoduna AsyncCallback temsilci tipine ait
rneimizi parametre olarak vermemiz gerekir. Sunucu ve istemcinin almasna
bakalm. (Aadaki video grnts flash player gerektirmektedir.)

Gelelim OneWay tekniine. OneWay tekniinde sadece geri dn tipi olmayan uzak nesne
metodlar sz konusu olabilir. Dahas OneWay nitelii (attribute) ile imzalanan bir metod, istemci
tarafndan altrldktan sonra unutulur.

www.bsenyurt.com Page 1607


OneWay niteliine sahip metodlar, at-unut fzeleri gibidir. stemci tarafnda arldktan
sonra istemci kodlar ileyiini srdrrken, OneWay metodu geriye hi bir bilgi vermez
ve sunucu tarafnda kendi bana ileyiini tamamlar.

Yani istemci tarafnda metod arm sonras kodlar ilerken, metodun bana ne geldiinden
istemcinin herhangibir ekilde haberi olmaz. Bu metod ierisinde meydana gelebilecek bir
istisnann, istemci tarafndan alglanmamas anlamna gelir. Bu nedenle OneWay metodlar
ounlukla sunucu tarafnda log tutma gibi istemci asndan nem arz etmeyen durumlarda,
asenkron ileyii gerekletirmek iin tercih edilebilir. Uzak nesnede yer alan bir metodun OneWay
davrann gsterebilmesi iin, OneWay nitelii (attribute) ile iaretlenmesi gerekir. Bizim
rneimizde bunu interface tarafnda yapmamz gerekecektir. OneWay nitelii,
System.Runtime.Remoting.Messaging isim alan altnda yer almaktadr. Bu nedenle interface' imizin
bulunduu class library uygulamasna System.Runtime.Remoting referansnda aka eklememiz
gerekiyor.

using System;
using System.Runtime.Remoting.Messaging;

namespace RemoteLib
{
public interface IRLib
{
int GetTotal(int orderID);
[OneWay]
void WriteLog(int orderID);
}
}

Bu deiiklikten sonra uzak nesnemizide interface' imizin yapsna uygun olarak dzenlememiz
gerekir. OrderObj snfmzn yeni halinde WriteLog isimli ek bir metod olmaldr. Bu metod
ierisinde basit olarak birer saniye aralklarla sunucu uygulamada mesaj yazdrlmaktadr. Burada
ama, istemcinin metodu armasn takiben, istemci uygulamann sonlanmas halinde sunucun bu
kodlar altrmaya devam edeceini ispatlamaktr.

public void WriteLog(int orderID)


{
for (int i = 0; i < 10; i++)
{
Console.WriteLine("Log bilgisi yazlyor...");
System.Threading.Thread.Sleep(1000);
}
}

imdi istemci tarafndaki kodlarmz aadaki gibi deitirelim.

static void Main(string[] args)


{

www.bsenyurt.com Page 1608


TcpClientChannel cliC = new TcpClientChannel();
IRLib rl = (IRLib)Activator.GetObject(typeof(IRLib), "tcp://manchester:8777/OrderObj");
rl.WriteLog(1901);
Console.WriteLine("Metod sonras kodlar...");
Console.WriteLine("Uygulamay durdurmak iin bir tua basn...");
Console.ReadLine();
}

Bu sefer uygulamay metodu ardktan sonra sonlandryoruz. Buna gre OneWay tipindeki
WriteLog isimli uzak nesne metodu, sunucu zerinde almasna devam edecektir. Oysaki metod
OneWay davran gstermeyecek ekilde ayarlansayd, metod almas bitene kadar istemci
bekleyecekti. Aadaki flash animasyonunda durumu daha iyi grebilirsiniz. (Aadaki video
grnts flash player gerektirmektedir.)

OneWay davran gsteren metodlarn bir dier sorunu ise exception olmas halinde ortaya kar.
rnein, OrderObj isimli uzak nesne snfmzn WriteLog isimli metodu ierisinde bir istisna durumu
olutuunu dnelim. Bu durumda istemci tarafnda alan metodu try...catch bloklar ile kontrol
etsek dahi istisnay yakalayamayz. Dahas bu istisna sunucu tarafnda oluarak metodun ileyiini
bozacaktr. Dolaysyla istemcinin hi bir ekilde bu istisnadan haberi olmayacaktr. Bu OneWay
davrann sergileyecek metodlarn kullanmn azaltan bir etkendir. Ksacas OneWay teknii her ne
kadar mkemmel bir asenkron modeli gibi grnsede, gerekten istemci asndan sonular nemli
olmayan durumlarda ele alnabilecek bir yaklamdr.

Bu makalemizde .Net Remoting iin geerli olan metod arma tekniklerini ksaca incelemeye
altk. Senkron mimarinin varsaylan tip olduunu, asenkron mimarinin avantajlarn ve OneWay
tekniinin dezavantajlarn irdelemeye altk. Grnen o ki, bu modellerden hangisinin
kullanlacana karar vermek iin gerekten ihtiyalar iyi tespit etmek gerekmektedir. Bylece
geldik bir makalemizin daha sonuna bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

www.bsenyurt.com Page 1609


Burak Selim ENYURT
selim@bsenyurt.com

.Net Remoting ve Event Mimarisi ( 26.03.2006 ) -


Remoting
Deerli Okurlarm Merhabalar,

Remoting mimarisinde temel ama, istemcilerin uzak nesnelere (remote objects) erimelerini
salamak ve bu nesneler zerindeki metodlar altrmaktr. .Net Remoting iin en ok kullanlan
model Marshall By Referance modelidir. Bu modelde istemciler uzak nesneler ile, sunucu zerinde
oluturulan uzak nesne referanslar yoluyla konuurlar. Ancak baz durumlarda, uzak nesnelerin yer
ald sunucu uygulamalar, istemciler zerinde yer alan metodlar altrmak isteyebilir. Byle bir
durumda roller sre ierisinde istemci ve sunucu arasnda deiime urar. Yani istemciler
sunucudaki uzak nesnelere eriebilirken, sunucuda istemciler zerindeki nesnelere eriebilmektedir.
Bu modelin gereklemesi iin zellikle olay gdml programlann can damar olan temsilci
(delegate) ve event (olay) tipleri kullanlmaktadr.

Teorik olarak bu yaklamda, istemciler uzak nesne iin geerli olan bir event' ykleyebilir ve uzak
nesneleri kullanan sunucuda tetiklenen olay sonras, istemci tarafnda yer alan olay metodlarn
altrabilir. Bu olayn gerekleebilmesi iin, uzak nesnenin istemci tarafndan yklenebilecek bir
event' a sahip olmas, ayrca olayn tetiklenmesi sonucu istemcideki uygun metodu iaret
edebilecek bir temsilci (delegate) tipininde var olmas gerekir. Dolaysyla sunucu tarafnda ve
istemci tarafnda olmas gerekenler belirlidir. Sunucu tarafnda, uzak nesne tipimiz, istemcideki olay
metodunu iaret edebilecek bir delegate tipimiz ve istemci tarafndan eriilebilecek bir event tipimiz
var olmaldr. stenirse, olay metodu iin bilgi tayacak baka bir tip daha sunucu tarafnda yer
alabilir. Bilgi tayacak bu tipi rnein bir windows uygulamasndaki button nesnesine tklandnda
devreye giren click olay metodunun EventArgs parametre tipine benzetebiliriz. stemci tarafnda
ise, uzak sunucunun herhangibir olay sonucu altraca olay metodunu ieren bir tip yer
almaldr.

Hem sunucunun hemde istemcinin karlkl olarak ilgili nesnelerini kullanabilmeleri iin,
bu nesnelerin MarshallByReference tipinden tretilmeleri arttr. Bu zaten Referans
tabanl remoting ilemlerin temel prensibidir.

Aadaki ekil sunucu ve istemci tarafnda yazmamz gereken tipleri zetlemektedir.

www.bsenyurt.com Page 1610


Gelelim mimarinin ileyi ekline. Uzak sunucu aktif olarak hizmet vermeye baladktan sonra,
istemciler uzak nesne referansn elde etmelidir. Burada uzak nesne referansnn elde edili ekli
nemlidir. Client Activated Object yada Server Activated Object mimarisine dayal bir yaklam
kullanlabilir ancak SAO mimarisinde yer alan SingleCall modelini stateless olduu iin kullanmak
alma zamannda istisnalara yol aar. Nitekim SingleCall modelinde istemcilerin altrd uzak
nesnelere ait referanslar sunucuda oluturulduktan sonra hemen kullanlr ve yok edilirler. O
yzden SAO modelinde srarc olunacaksa Singleton aktivasyon tipi kullanlmaldr. Biz rneimizde
Client Activated Object mimarisini kullanacaz.

Client Activated Object (CAO) mimarisinde, istemci uzak nesneye ait bir nesne rneini
oluturduu zaman, sunucu zerinde bu uzak nesneye ait bir referans hemen oluturulur.
Server Activated Object (SAO) modelinde ise sunucu zerindeki uzak nesneye ait
referansn oluturulmas iin istemci tarafnda uzak nesneye ait bir metodun arlmas
gerekir.

Uzak nesne referansnn sunucu tarafnda oluturulmasnn ardndan istemci, uzak nesne iin bir
olay (event) kaydeder ve hemen ardndan uzak nesne zerinde kaydettii olay ele alan bir metodu
tetikler. Uzak sunucuda yer alan bu metod ierisinde, o anki referans iin bir olayn yklenip
yklenmedii kontrol edilir. Eer olay yklenmise sunucu, istemci zerindeki ilgili olay metodunu
altrr ve varsa gerekli olay bilgilerini bu istemciye aktarr. imdi gelin bu bahsettiklerimizi
uygulama koduna dkelim. ncelikle uzak sunucu nesnemizin yer ald snf ktphanesini
tasarlamak ile ie balamalyz.

Sunucu, istemci zerindeki olay metodunu altrabilmek iin bir temsilci (delegate) tipi
kullanacaktr. Temsilcimizin iaret edecei metod modelinin aadaki gibi olduunu dnelim.
Burada, olay metoduna bilgi tamak amacyla, parametre olarak kendi tasarladmz
seriletirilebilir (ki remoting srasnda bu arttr) EventInfo tipini kullanmaktayz.

www.bsenyurt.com Page 1611


Temsilci tipimiz; dlg

public delegate void dlg(EventInfo eInfo);

Olay metodumuza bilgi tayacak tipimiz; EventInfo

[Serializable]
public class EventInfo
{
private string _info;

public string Info


{
get { return _info; }
set { _info = value; }
}
public EventInfo(string inf)
{
_info = inf;
}
}

Gelelim uzak nesnemize ait tipe. Uzak nesne snfmzn en nemli noktas bir event' a sahip olmas.
Bu event' i az nce tanmladmz temsilci yardmyla oluturuyouruz. Dier tarafan EventTrigger
isimli metodumuz ise, istemcilerin uzak nesne zerine kaydettikleri bir event olup olmadn
denetleyerek olay metodunu aryor.

www.bsenyurt.com Page 1612


Uzak nesnemize ait snf kodlarmz;RemObj

public class RemObj:MarshalByRefObject


{
public event dlg Click;

public RemObj()
{
Console.WriteLine("Uzak nesne iin rnek oluturuldu...");
}
public string RemMethod()
{
return "Uzak metod";
}
public void EventTrigger(string userName)
{
if (Click != null)
{
Console.WriteLine(userName + " sunucu zerinde olay
tetikledi..."+DateTime.Now.ToString());
System.Threading.Thread.Sleep(10000);
EventInfo ei = new EventInfo(DateTime.Now.ToString());
Click(ei);
}
}
}

Gelelim istemci tarafnda, sunucu tarafndan arlacak olay metodunun bulunduu tipe; ClientSide
isimli snfmz ierisinde sadece uzak nesnenin bulunduu sunucunun araca olay metodunu
tanmladk. Bu metodun yapsnn, istemcilerin eriecei sunuc zerindeki uzak nesnede tanml
delegate tipimizin belirttii ile ayn olduuna dikkat edin. Nitekim, uzak nesnedeki EventTrigger
metodu istemci tarafndan tetiklendiinde, buradaki kodlara gre Click(ei) isimli metod arm,
Click event' i ierisinde tanml delegate tipinin iaret ettii istemci zerindeki olay metodunu
altracaktr. Dier yandan snfmz yine MarshallByReference tipinden tretiyoruz. Nitekim
sunucu, uzak nesne olarak istemci tarafndaki bu tipin referanslarna ihtiya duyacaktr.

www.bsenyurt.com Page 1613


stemci tarafndaki uzak nesne tipine ait kodlarmz; ClientSide

public class ClientSide:MarshalByRefObject


{
public void EventMethod(EventInfo eInf)
{
Console.WriteLine(eInf.Info);
}
}

Artk sunucu ve istemci uygulamalarmz kodlayabiliriz. stemci ve sunucu tarafn basit Console
uygulamalar olarak tasarlayacaz. Remoting iin gerekli konfigurasyon ayarlarn ise xml bazl
config dosyalarnda tutacaz. nce sunucu tarafnn kodlarn ve konfigurasyon dosyasn
oluturmakla ie balayalm. Elbette hem sunucu hemde istemci tarafnda
System.Runtime.Remoting ve RemoteObjects assembly' mza ait referanslarmz eklememiz
gerekiyor.

Server uygulamamza ait kodlar; Server

using System;
using System.Runtime.Remoting;
using RemoteObject;

namespace Server
{
class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("..\\..\\ServerApp.config",false);
Console.WriteLine("Sunucu dinlemede...");
Console.WriteLine("-------------------");
Console.ReadLine();
}
}
}

Server uygulamamza ait konfigurasyon dosyas; ServerApp.config

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

www.bsenyurt.com Page 1614


<configuration>
<system.runtime.remoting>
<application>
<service>
<activated type="RemoteObject.RemObj,RemoteObject" />
</service>
<channels>
<channel ref="tcp" port="4567">
<serverProviders>
<provider ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

imdi konfigurasyon dosyamz zerinde biraz konualm. Server tarafnda CAO (Client Activated
Object) modelini desteklediimizi belirtiyoruz. Activated node' u ierisinde yer alan type nitelii
(attribute) deiken olarak Namespace.SnfAd,AssembleAd na gre gerekli bilgiyi almaktadr.
Bildiiniz gibi istemci tarafndada bu type bilgisi tanmlanacak ve istemciler sunucu zerindeki uzak
referanslar talep ederken bu bilgileri kullanacaktr. Ayrca, Tcp protokoln kullanacak kanal
bilgilerinide channels node' u altnda yer alan channel node' unda belirtmekteyiz. Gelelim istemci
tarafna;

stemci uygulamamza ait kodlar; Client

using System;
using System.Runtime.Remoting;
using RemoteObject;

namespace Client
{
class Program
{
static void Main(string[] args)
{
RemotingConfiguration.Configure("..\\..\\ClientApp.config",false);
RemObj ro = new RemObj();
ClientSide cs = new ClientSide();
ro.Click += new dlg(cs.EventMethod);
ro.EventTrigger("Burak");
Console.ReadLine();
}
}
}

www.bsenyurt.com Page 1615


stemci uygulamamzda uzak nesne(RemObj) ve istemci tarafndaki nesne(ClientSide) iin rnekler
oluturuluyor. Daha sonra uzak nesnemize Click event' ini kaydediyoruz(Register). Burada nemli
olan nokta event' imizi uzak nesneye kaydederken, uzak nesnenin zerinde Click olaynn
tetiklenmesi sonucu, istemci tarafnda altracak olan metodun(EventMethod) belirtilmesi.

ro.Click += new dlg(cs.EventMethod);

Bu ifade ile, uzak nesne zerinde Click olay tetiklendiinde (ki biz bunu uzak nesnenin
EventTrigger metodu ile canlandryoruz), istemci tarafndaki nesnemizin EventMethod' unu
altracamz belirtiyoruz.

stemci uygulamamza ait konfigursayon dosyas; ClientApp.config

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


<configuration>
<system.runtime.remoting>
<application>
<client url="tcp://localhost:4567/">
<activated type="RemoteObject.RemObj,RemoteObject" />
</client>
<channels>
<channel ref="tcp" port="0">
<serverProviders>
<provider ref="binary" typeFilterLevel="Full" />
</serverProviders>
</channel>
</channels>
</application>
</system.runtime.remoting>
</configuration>

stemci tarafndada channel bilgisi olarak sunucu tarafnda olduu gibi Tcp kanaln setik. Byle bir
seim yapmamzn nedeni hem sunucun hemde istemcinin birbirleri zerindeki nesnelerinin
referanslarn kullanacak uygun kanallara ihtiya olunmasdr. Normal artlar altnda sunucu
tarafnda Tcp Server (veya Http Server), istemci tarafnda ise Tcp Client (veya Http Client) kanallar
seilerek remoting ilemleri gerekletirilir. Ancak burada sunucu uygulama yeri geldii zaman
istemci gibi davranacaktr ve uzak metodu aracaktr ki sunucu asndan nemli olan uzak metod
bizim olay metodumuzdur.

Delegate tipinin seriletirilebilir olmas iin (remoting' i destekelemesi iin) xml


konfigurasyonunda serviceProvider ksm yer almaktadr.

Artk tek yapmamz gereken uygulamamz bu haliyle test etmek olacaktr. ncelikle istemci tarafn
altralm. Bunu yapmamzdaki ama alma zamannda aadaki ekranda grlen istisnay
almak.

www.bsenyurt.com Page 1616


Bu bizim iin, istemci tarafnn gerektende konfigurasyon dosyasnda belirtilen ayarlar ile bir uzak
sunucuya balanmaya altnn ve hakiki bir remoting ortamnn olutuunun gstergesidir. Bir
baka deyile RemObj snfna ait nesne rneini istemci kendi application domani' i ierisinde
oluturmamaktadr. Gerektende bu rnee ait referans sunucu tarafnda aramaktadr. Bunuda
grdkten sonra, artk remoting uygulamamz test edebiliriz. nce sunucu uygulamamz
altryoruz ardnan ise istemci uygulamamz. Sonuta, istemci sunucu zerindeki uzak nesneyi
kullanarak bir olay tetikliyor ve bunun karlnda sunucu uygulamada olay metodunu istemci
tarafnda yrtmeye balyor.

Aadaki Flash animasyonunda uygulamann canl olarak almasn grmektesiniz. (Not:


Sisteminizde Flash Player ykl deilse bu animasyonu gremeyebilirsiniz.)

Peki uygulamada neler oldu yle bir analiz etmeye alalm. ncelikle server uygulamamz
altrdk. Hemen ardndan istemci uygulamamz altrdk. stemci uygulamamz kodlar
ierisinde uzak nesne rnei oluturacak kod satr (RemObj ro=new RemObj(); satr) geildikten
sonra sunucu tarafnda yer alan uzak nesne (RemObj) snfna ait bir referans oluturuldu. Bunu
sunucu ekranna gelen mesajdan anlayabiliriz. Nitekim bu mesaj uzak nesnenin constructor
metodu ierisinde yazmtk. Bu ilemi takiben istemci tarafndan tetikleyici metod (EventTrigger)
arldktan sonra ise sunucu tarafnda, istemcinin olay tetikleme zaman yazld. Burada olay
daha iyi analiz etmek iin olay tetikleyici metodumuz ierisinde kodu 10 saniye kadar uyuttuk. Bu
sre sonunda sunucu uygulama, istemci tarafndaki olay metodunu (EventTrigger) altrd ve
istemci tarafnda o anki zaman ekrana geldi. Bylece remoting uygulamas iin geerli event
modelinin baarl bir ekilde altn ispat etmi oluyoruz.

www.bsenyurt.com Page 1617


Grdnz gibi remoting uygulamalarnda istemci tarafndan olay tetiklemek ve bu olay
karlnda sunucunun kendisine bal olan istemciler zerinde var olan olay metodlarn
altrabilmesini salamak mmkn. Bylece geldik bir makalemizin daha sonuna bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek uygulamal indirmek iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

.Net Remoting ve Factory Design Pattern (


18.03.2006 ) - Remoting
Deerli Okurlarm Merhabalar,

Factory Design Pattern (Fabrika Tasarm Deseni), istemcilerin ihtiya duyduu nesneleri oluturmak
iin zel bir nesnenin kullanld mimariyi ele alr. yleki bu tasarm deseninde istemcinin,
kullanaca asl nesnenin nasl retilecei hakknda herhangibir bilgiye sahibi olmas gerekmez. Bu
rnekleme iini stlenen fabrikann (Factory) kendisidir. Biz bu makalemizde, Factory Design
Pattern' in .Net Remoting ierisinde kullanln incelemeye alacaz. Makaleyi kolay takip
edebilmeniz asndan Remoting ile ilgili temel bilgilere aina olmanz nemlidir. Factory tasarm
deseninin 3 nemli paras vardr. Client, Factory ve Product.

www.bsenyurt.com Page 1618


stemcilerin (Clients) amac Product tipinden nesne rneklerini kullanmaktr. Bunun iin mutlaka ve
mutlaka Product tipinden nesne rneklerinin oluturumasna ihtiya vardr. stemci bu retim
ilemini dorudan deil, Factory nesne rnekleri zerinden yapar. Dolaysyla her hangibir Product
tipinin retilmesi aamasnda oluabilecek deiikliklerden sorumlu olan tip Factory nesnesi
olacaktr. Bu bir anlamda istemcilerin, ilgilendikleri Product nesnesinin nasl rneklendirildiklerini
bilmemesi anlamna gelir. Bunu soyutlama (abstraction) olarakta tanmlayabiliriz. Bu sebepten
dolay Factory tasarm deseni zellikle remoting uygulamalarnda ska kullanlmaktadr. nk
uzak nesnelerin (ki burada product nesnelerimiz olacak) oluturulmas (Creation) ksmnda zaman
ierisinde gncellemeler ve deiiklikler olabilir. te bu deiiklikleri ele alacak ve bu sorumluluu
tayacak olan ksm istemci deil Factory ' nin kendisi olacaktr.

Factory tasarm deseni, nesnelerin oluturulmas ile ilgilendiinden constructor metodlar


aktif ekilde kullanr. Bu nedenlerden dolay Creational Pattern' ler kategorisinde yer
almaktadr.

imdi dilerseniz konuyu daha fazla karmaklatrmadan teoriden uzaklaalm ve factory tasarm
desenini ele alabileceimiz bir rnek gelitirelim. Bu rneimizde istemciler, rn olarak
kullanacaklar nesne rnekleri zerinden uzak sunucuda yer alan bir veritabanna balanacaklar ve
kendileri iin gerekli bilgileri tedarik edecekler. Elbetteki, rnlerin oluturulmas ilevini tamamen
Factory nesnemize devredeceiz. lk olarak izleyeceimiz yoldan bahsedelim.

Gelitirme Admlarmz

Factory ve Product nesneleri iin gerekli abstract snflarmz public bir class library ierisinde
1-
olutururuz.

www.bsenyurt.com Page 1619


Server taraf iin gerekli abstract snflarmzdan tretilen Factory ve Product snflarmz
2-
yazarz.

3- Server tarafnda gerekli remoting kodlarn yazarz.

4- stemci tarafnda gerekli remoting kodlarn yazarz.

lk olarak abstract snflarmz yazmamz gerekiyor. Bunlar bir class library ierisinde tutmamzn
en nemli nedeni, hem server tarafnda hemde istemci tarafnda ihtiyacmzn olmas ve referans
olarak eklememiz gerektii. Bu nedenle nce bir class library projesi aalm ve aadaki abstract
snflarmz oluturalm.

Abstract snflar, normal snflar gibi yeler ierebilen, rneklendirilemeyen (instance


create edilemez) ve kendisinden treyen tiplerin mutlaka override etmesi gereken metod,
zellik gibi yelerin tanmlamalarn ieren (kod bloksuz halleri) tiplerdir.

namespace FactoryProductBase
{
public abstract class ProductBase : MarshalByRefObject
{
public abstract string GetContactInfo();
}

public abstract class FactoryBase : MarshalByRefObject


{
public abstract ProductBase CreateProduct(int ContactID);
}
}

www.bsenyurt.com Page 1620


imdi burada yaptklarmzdan ksaca bahsedelim. ncelikli olarak ProductBase abstract snfmz
yazdk. Bu snfmz herhangibir istemcinin asl olarak almak isteyecei nesnelerin uygulayaca
bir metod bildirimi iermekte. Amacmz bu abstract snf uygulayan bir Product tipi ile
AdventureWorks veritabannda yer alan Contact tablsoundan belirli bir ContactID' ye ait bilgileri
string formatta alabilmek. retimden sorumlu olan FactoryBase isimli abstract snfmz ise,
kendisini uygulayacak olan herhangibir Factory tipinin, Product retme iini nasl yapmas
gerektiini bildiren bir abstract metod ieriyor. Dikkat ederseniz bu abstract metodumuzun dn
tipi ProductBase' dir. Buda FactoryBase' den tremi bir snfn override edilecek olan CreateProduct
isimli metodunun, ProductBase tipinden tretilmi olan bir snfa ait nesne rneini dndrebilecei
anlamna gelmektedir. Bu ilikiyi sunucu tarafmzda alacak olan asl snflarmz yazarken
kullanacaz.

Her iki abstract snfnda, remoting ierisinde kullanlabilmesini salamak iin


MarshalByRefObject' dan tretildiine dikkat edin. MarshalByRefObject bildiiniz gibi,
istemcinin remote nesnenin referans ile alabilmesini salar.

Abstract snflarmz hazrladktan sonra sra geldi sunucu tarafn programlamaya. Sunucu
tarafnda, FactoryBase ve ProductBase snflarndan treyen tiplerimizi yazarak ie balayacaz.
Ama ncesinde, sunucu uygulamamz bir console application olarak aalm. Daha sonra ise,
System.Runtime.Remoting ve abstract snflarmz barndrdan Class Library' imizi bu uygulamaya
referans olarak ekleyelim.

imdi Factory ve Product snflarmz yazmamz gerekiyor.

www.bsenyurt.com Page 1621


public class Product : ProductBase
{
string _ContactInfo;

public Product(int ContactID)


{
_ContactInfo = "";
using (SqlConnection con = new SqlConnection("data
source=MANCHESTER;database=AdventureWorks;integrated security=SSPI"))
{
using(SqlCommand cmd=new SqlCommand("Select
ContactID,FirstName,MiddleName,LastName From Person.Contact
Where ContactID=@ContactID",con))
{
cmd.Parameters.Add("@ContactID", SqlDbType.Int);
cmd.Parameters["@ContactID"].Value = ContactID;
con.Open();
SqlDataReader dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
dr.Read();
StringBuilder sb = new StringBuilder(_ContactInfo);
sb.Append(dr["ContactID"] + " ");

www.bsenyurt.com Page 1622


sb.Append(dr["FirstName"] + " ");
sb.Append(dr["MiddleName"] + " ");
sb.Append(dr["LastName"] + " ");
dr.Close();
_ContactInfo = sb.ToString();
}
}
}

public override string GetContactInfo()


{
return _ContactInfo;
}
}

public class Factory : FactoryBase


{
public override ProductBase CreateProduct(int ContactID)
{
return new Product(ContactID);
}
}

Ksaca snflarmzn alma ekline bakalm. Factory snfmz FactoryBase abstract snfndan
tremitir. Bu nedenle CreateProduct isimli metodu override etmek zorundadr. CreateProduct
metodumuz dikkat ederseniz, ProductBase snfndan trettiimiz Product tipinden bir nesne
rneini geriye dndrmektedir. Burada elbeteki devreye Product snf ierisinde yazdmz yapc
metod (constructor) girer. Bu metod ierisinde ksaca veritaban balant ilemlerimizi yapp,
Contact tablosundan ContactID, FirstName, MiddleName ve LastName alanlarnn deerlerini
okuyup stringBuilder yardmyla snf ierisinde yer alan _ContactInfo isimli string' e aktarmaktayz.
Son olarak Factory tipimizin override ettii GetContactInfo isimli metodumuzda _ContactInfo
deikenimizin ieriini geriye dndrmekte. Sra geldi, server tarafnda remoting iin yapmamz
gereken ilemlere. Bunun iin server tarafmzdaki console uygulamamzn main metodunun
kodlarn aadaki gibi deitirmemiz gerekiyor.

static void Main(string[] args)


{
TcpServerChannel srvChannel = new TcpServerChannel(8000);
ChannelServices.RegisterChannel(srvChannel,true);
RemotingConfiguration.RegisterWellKnownServiceType(typeof(Factory), "Server/Factory",
WellKnownObjectMode.SingleCall);
Console.WriteLine("Sunucu dinlemede...");
Console.ReadLine();
}

lk olarak, Tcp protokol zerinden haberlemeyi tercih ettiimizden, istemciden gelecek talepleri
dinleyecek bir portu (rneimizde 8000 numaral port) kullanma amamz gerekiyor. Bu amala bir
TcpServerChannel nesnesi oluturduk ve bunu siteme register ettik. Sonrasnda ise SingelCall
tekniine gre (yani her istemci iin server tarafnda ayr birer remote object referans

www.bsenyurt.com Page 1623


oluturulmas), istemcilerin server ile iletiim kurabilecei URI bilgisini hazrlyoruz. Bunun iin bir
WellKnowServiceTypeEntry nesnesini, RemotingConfiguration.RegisterWellKnowServiceType
metodu ierisinde oluturduk. Dolaysyla sunucu tarafnda artk unu sylemi oluyuroz.
tcp://MANCHESTER:8000/Server/Factory adresini, istemcilerin kullanmna ayoruz. Bu URI
bilgisine gre istemciler MANCHESTER isimli sunucuya 8000 numaral porttan balanacak ve Server
isim alanndaki Factory isimli snfa ait nesne rneklerinin referanslar ile konuacak. Sunucu
tarafmzda hazrladktan sonra sra geldi istemci tarafndaki kodlar yazmaya. Yine server tarafna
benzer olarak istemci tarafndada bizim iin gerekli olan class library ve System.Runtime.Remoting
isim alanlarn aka eklememiz gerekiyor.

imdi istemci tarafmzdaki kodlar yazalm.

static void Main(string[] args)


{
TcpClientChannel clientChannel = new TcpClientChannel();
ChannelServices.RegisterChannel(clientChannel, true);

FactoryBase fb = (FactoryBase)Activator.GetObject(typeof(FactoryBase),
"tcp://MANCHESTER:8000/Server/Factory");
ProductBase pb = fb.CreateProduct(1);
Console.WriteLine(pb.GetContactInfo());
}

stemci tarafnda, sunucu taraf ile haberleebilmemiz iin bu kez bir TcpClientChannel nesnesine
ihtiyacmz var. Bizim iin burada nemli olan, server tarafndan bir FactoryBase tipinden nesne
rneine ait referans almak iin Activator snfnn GetObject static metodunu kullanyor oluumuz.
Bu metod sayesinde, server tarafndan FactoryBase tipinden bir referans kullanacamz sylemi
oluyoruz. Ancak dikkat edin sadece sylyoruz. Henz bu referans sunucudan istemciye alm
deiliz. Nitekim sunucu zerindeki referanslar, istemcide bir metod arm yapld zaman
oluturulmaktadr.

Sonrasnda ise, Product tipinden nesne rneimizin ilgili metodunu altrabilmek iin, elde
ettiimiz FactoryBase referansnn CretaeProduct isimli metodunu kullandk. Bylece sunucu
tarafndaki Product tipine eriip, 1 numaral Contact bilgisini istemci tarafna tayabiliyoruz. Burada
nemli olan nokta, Product tipine ait bir referans istemcinin dorudan create etmeyii. Bu ilemi
FactoryBase' in CreateProduct isimli metodu bizzat yapmakta. Dolaysyla Product tipine ait bir
referansn nasl oluturulduu, istemci tarafndan tamamen soyutlatrlm olmaktadr.

www.bsenyurt.com Page 1624


stemci tarafnda FactoryBase ve ProductBase abstract snflarn kullanmamza ramen,
sunucu tarafndaki Factory ve Product tiplerinin baz yelerini ele alabilmekteyiz. te bu
polimorfizm' in bir etkisidir. nk abstract tipler, kendilerinden treyen tiplere ait
referanslar tadklarnda, tremi tiplerin override edilmi yelerine eriebilirler.

Uygulamamz test etmek iin ncelikle server tarafn altrmal ve sunucuyu dinlemeye hazr hale
getirmeliyiz. Eer sisteminizde yk bir firewall var ise bu isteinizi onaylayp onaylamadnz
sorabilir. (rnein Xp iletim sisteminin Firewall program devreye gittiinde Unblock seeneini
iaretlemeniz lazm.) Burada ilemi onaylayp portumuzu remote iletiim iin amamz gerekiyor.
Sonrasnda ise istemci uygulamamz altrp sonular grebiliriz.

Remoting' in uyguland bu rnein baarl bir ekilde alp almadn kontrol etmek iin,
istemci uygulamanz sunucuyu altrmadan yrtmeyi deneyin. CreateProduct isimli metodun
arld yerde SocketException tipinden bir istisna alrz. Bunun sebebi, sunucu tarafnn
almyor oluu ve bu sebeple balant salanamasdr.

Bu makalemizde, Factory Design Pattern' in , gerek hayat uyarlamalarndan birisi olan .Net
Remoting' deki yerini incelemeye altk. Ksaca tekrar etmek gerekirse Factory deseni bir
istemcinin, kullanaca rnn oluturulmas sorumluluunu fabrikaya (Factory) devreden bir
mimari sunmaktadr. Bu da istemcinin, kullanaca rnn nasl oluturulacan bilmek zorunda
olmamas anlamna gelir. Dahas, rn tarafndaki nesnelerin oluturulmas srasndaki deiiklikler
istemciyi etkilemeyecektir. Bu sadece fabrika nesnelerinin bilmesi gereken bir durumdur. Bylece
uygulamalarn daha kolay geniletilebilmesi salanabilir. Tahmin edeceiniz gibi bir rnn
(Product) n oluturulmas srasndaki deiikliklerin sadece sunucu tarafnda yaplmas yeterli

www.bsenyurt.com Page 1625


olacaktr. nk istemci tarafnda bu tiplere ait referanslar yerine bu tiplerin tredii referanslar
yer almaktadr. Buda mimariyi en azndan rnlerin retili eklini tek bir merkezden
gdmleyebileceimiz anlamna gelir. Bylece geldik bir makalemizin daha sonuna bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek uygulamal indirmek iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Web Servisleri in Drt Pf Nokta ( 14.03.2006 )


- Web Servis
Deerli Okurlarm Merhabalar,

Web Servislerini yazmak ve kullanmak, ou zaman bir web service projesi oluturmak ve istemci
tarafnda Add Web Reference teknii ile oluturulan proxy snfn kullanmaktan ibaret basit bir
mimari olarak dnlr. Ancak sanlann aksine Web servislerinin yazlmasnda ve kullanlmasnda
dikkate deer eitli pf noktalar vardr. te bu makalemizde bu pf noktalardan drdn
maddeler halinde incelemeye alacaz.

1 - Bir web metodunun overload edilmesi (ar yklenmesi) standart bir metodun
overload edilmesinden daha farkldr.

rnek bir web servisinde aadaki gibi ar yklenmi (overload) iki web metodumuz olduunu
gz nne alalm. Bu metodlarn ar yklenmi olduklarn rahatlkla syleyebiliriz. Nitekim, her iki
metodunda imzalar farkldr. (Ar yklemede(Overloading) metod imzasnn, metodun ald
parametre says ve parametrelerin tiplerine bal olduunu anmsayalm.)

[WebMethod()]
public double Carp(double x,double y)
{
return x*y;
}

[WebMethod()]
public int Carp(int x,int y)
{
return x*y;
}

Normal artlar altnda bu metodlar alma zamannda bir problem olmadan yrtebilmemiz
gerekir. Ancak metodlar ieren herhangibir web servisini ardmzda, alma zamannda
aadaki ekran ile karlarz.

www.bsenyurt.com Page 1626


Sebep web servisinde yer alan SOAP mesajlarnn yaps ile ilgilidir. Ayn isimli metodlar SOAP
mesajlar ierisine ayn isimler ile gmlmeye alldndan ve birbirlerinden ayrt edilebilmeleri
iin xml ierisinde var olan bir overload mekanizmas olmadndan byle bir problem yaanmtr.
Bu sorunu zmek iin hata mesajnda belirtildii gibi WebMethod niteliinin
(attribute) MessageName zelliinden yararlanrz. Bu zellik ile her iki metodu birbirinden
benzersiz olacak ekilde ayrabiliriz. Bu nedenle yukardaki rnek kod parasnda yazdmz
metodlara ait WebMethod niteliklerini aadaki gibi yeniden dzenlemeliyiz.

[WebMethod(MessageName="CarpForDoubles")]
public double Carp(double x,double y)
{
return x*y;
}

[WebMethod(MessageName="CarpForIntegers")]
public int Carp(int x,int y)
{
return x*y;
}

Bu haliyle web servisi sorunsuz bir ekilde alacaktr. Deiikliin yapt etkileri kullandnz web
servisinin wsdl dkmannda daha rahat izleyebilirsiniz.

2 - Aralarnda kaltmsal iliki olan nesneler sz konusu olduunda, taban snfa (base
class) ait nesne rneklerinden oluan dizi tiplerinin dndrld web metodlarnda
uymamz gereken kurallar vardr.

ok basit olarak aralarnda kaltmsal iliki bulunan aadaki Sekil, Dortgen ve Ucgen snflarn gz
nne alalm. ekildende grlecei zere, Dortgen ve Ucgen snflar Sekil taban snfndan
treyen (derived) snflarmzdr.

www.bsenyurt.com Page 1627


Snflar;

public class Sekil


{
}
public class Dortgen:Sekil
{
}
public class Ucgen:Sekil
{
}

imdi bu ilikiyi kullanan aadaki gibi bir web metodumuz olduunu dnelim. Kaltmn bir
etkisi olarak , Sekil snfna ait bir nesne rnei, kendisinden treyen Dortgen ve Ucgen snf
tipinden nesne rneklerini tayabilmektedir. SekilleriAl isimli web metodumuz aslnda Sekil snf
tipinden bir diziyi geriye dndrmektedir. Ancak bu dizi kodlardanda grebileceiniz gibi Dortgen
ve Ucgen tipinden nesne rneklerini tamaktadr.

[WebMethod()]
public Sekil[] SekilleriAl()
{
Sekil[] sekiller=new Sekil[3];
sekiller[0]=new Dortgen();
sekiller[1]=new Ucgen();
sekiller[2]=new Dortgen();
return sekiller;
}

Bu web metodunu ardmzda alma zamannda bir istisna(excpetion) alrz. stisnann sebebi
son derece basittir. Web metodunun alma zamannda retecei ktya gre, web metodundan
mutlaka ve mutlaka Sekil tipinden elemanlar barndrdan bir dizi tipi dndrlecei
dnlmektedir. Bunu web servisimizin WSDL (Web Service Description Language) dkmannda
daha kolay grebiliriz.

www.bsenyurt.com Page 1628


Dikkat ederseniz, Web metodumuzun geri dndrecei tip ierisinde tanmlanan ArrayOfSekil
kompleks tipi (Complex Type), sadece Sekil tipinden deerler almaktadr. Dolaysyla Sekil tipinin,
Dortgen veya Ucgen tipinden nesne rneklerini barndrabileceini, dolaysyla ArrayOfSekil
kompleks tipinin yaps ierisinde bu tiplerinde yer alabileceini XML tarafnda sylememiz
gerekmektedir. te bu amala System.Xml.Serialization isim alannda yer
alan Xmlnclude niteliinden yararlanabiliriz. Web metodumuzu aadaki hali ile gncelleyelim.

[WebMethod()]
[XmlInclude(typeof(Dortgen))]
[XmlInclude(typeof(Ucgen))]
public Sekil[] SekilleriAl()
{
Sekil[] sekiller=new Sekil[3];
sekiller[0]=new Dortgen();
sekiller[1]=new Ucgen();
sekiller[2]=new Dortgen();
return sekiller;
}

imdi WSDL dkmanmza yeniden bakacak olursak ArrayOfSekil isimli kompleks tipin Dortgen ve
Ucgen tiplerinide barndrabilecek ekilde tanmlandn grrrz.

www.bsenyurt.com Page 1629


Dier taraftan web metodumuz artk baarl bir ekilde alacaktr.

3 - Web metodlarnda performans iin Caching kullanabiliriz.

Web uygulamalarn gelitirirken performans arttrc tedbirlerden birisi olarak caching


mekanizmalarna bavururuz. Dilersek bu teknii web servislerinde yer alan web metodlarn
dndrd sonular iinde uygulayabiliriz. Web metodlarn WebMethod niteliinin
(attribute) CacheDuration isimli zellii saniye cinsinden n bellekleme sresini belirtir. Bu zellik
yardmyla bir web metodun dndrecei sonular, web sunucusunun n belleine alabiliriz. Bu da
performans olarak web metodunu kullanan istemcilere hzl cevap dnmesi anlamna gelmektedir.
Nitekim cevaplar hazr olarak ara bellekte tutulan ktlardan dndrlr.

Basit olarak aadaki kod parasnda, Northwind veritabannda yer alan Order Details tablosundan
belirli bir OrderID' ye ait satrlar bir DataSet nesnesi ierisinde geri dndrlmektedir.
CacheDuration burada n bellekleme sresini 120 saniye olarak belirtmektedir. Buna gre yaplan
sorgu sonucu dndrlecek olan veri kmesi web sunucusunun n belleinde 120 saniye sreyle
tutulacaktr.

[WebMethod(CacheDuration=120)]
public DataSet GetOrderDetails(int OrderId)
{
using(SqlConnection con=new SqlConnection("data
source=LONDON;database=Northwind;integrated security=SSPI"))
{
using(SqlCommand cmd=new SqlCommand("Select
OrderID,ProductID,UnitPrice,Quantity,Discount From [Order Details] Where
OrderID=@OrderID",con))
{
cmd.Parameters.Add("@OrderID",SqlDbType.Int);
cmd.Parameters["@OrderID"].Value=OrderId;

www.bsenyurt.com Page 1630


SqlDataAdapter da=new SqlDataAdapter(cmd);
DataSet ds=new DataSet();
da.Fill(ds,"Siparisler");
return ds;
}
}
}

imdi bu web metodu barndrdan bir servisi kullanan basit bir console uygulamamz olduunuzu
dnelim. Console uygulamamzn kodlar aadaki gibidir.

static void Main(string[] args)


{
AltinSerivisi.AltinServis altin=new UsingCacheDuration.AltinSerivisi.AltinServis();
DataSet ds=altin.GetOrderDetails(10250);
foreach(DataRow dr in ds.Tables[0].Rows)
{
for(int i=0;i<ds.Tables[0].Columns.Count;i++)
{
Console.Write(dr[i].ToString()+" ");
}
Console.WriteLine();
}
}

lk olarak uygulamamz altralm ve elde ettiimiz deerlere bakalm. Daha sonra Order Details
tablosunda 10250 numaral siparie ait bilgilerde ufak bir deiiklik yapalm. rnein Quantity
deerini 10' dan 20' ye kartalm. 120 saniyelik sre dolmadan metodumuzu tekrar aracak
olursak, Quantity deerinin halen daha 10 olarak geldiini grrz. Bunun sebebi verinin o an iin
web servisinin bulunduu web sunucusunun n belleinden geliyor oluudur. Elbetteki 120
saniyelik bu nbellekleme sresi sonunda Quantity deerinin yenilendiini grebiliriz. n bellee
alma ilemi bu rnekte grld gibi sadece parametrik bazda deil, parametresiz web metodlar
iinde geerlidir.

4 - Web Servisi tarafnda security iin en basit haliyle Windows Authentication'


kullandmzda istemci tarafnda da yapmamz gerekenler vardr.

Web servisleri, web uygulamalarnda olduu gibi bir web sunucu zerinden yaymlanrlar. Bu
anlamda bakldnda bir web uygulamas iin sz konusu olan authentication seeneklerini, web
servisleri iinde ele alabiliriz. zellikle windows tabanl dorulama gz nne alndnda istemci
tarafnda alan uygulamalarn, gvenlik bilgilerini doru bir ekilde gnderebiliyor olmas gerekir.
lk olarak dorulama metodu Basic Authentication olarak ayarlanm bir web servisimiz olduunu
dnelim. IIS tarafnda ilgili web servisimiz iin gerekli gvenlik ayarlarnn aadaki ekilde
grld gibi olmas gerekmektedir.

www.bsenyurt.com Page 1631


imdi istemci tarafnda bu web servisini kullanacak olan uygulamamz gz nne alalm. Web
metodumuzu arabilmemiz iin ncelikle bu servise istemci tarafndan bir gvenlik belgesi
gndermemiz gerekir. (Credential) Bu gvenlik belgesini tayacak olan
tip ICredential arayzdr. stemci tarafnda bu bilgiyi hazrlayabilmek iin ICredential arayzn
(Interface) uygulayan NetworkCredential tipini kullanabiliriz. Aadaki kod parasnda
GoldServis isimli web servisimizdeki GetOrderDetails isimli metodu armadan nce, servisi
altrmak iin gerekli credential bilgisinin nasl eklendii gsterilmektedir.

AltinSerivisi.AltinServis altin=new UsingCacheDuration.AltinSerivisi.AltinServis();


System.Net.NetworkCredential credential=new
System.Net.NetworkCredential("admin","admin1234");
altin.Credentials=credential;
DataSet ds=altin.GetOrderDetails(10250);
foreach(DataRow dr in ds.Tables[0].Rows)
{
for(int i=0;i<ds.Tables[0].Columns.Count;i++)
{
Console.Write(dr[i].ToString()+" ");
}
Console.WriteLine();
}

Eer istemci uygulama doru ifre ve kullanc bilgisini gnderemez ise HTTP 401 : Access Denied
istisnasn alrz. Ancak doru gvenlik bilgilerinin gnderilmesi sonucunda web metodu baarl bir
ekilde altrlacaktr.

www.bsenyurt.com Page 1632


Bu makalemizde ksaca web servislerini kullanrken dikkate alabileceimiz bir ka noktaya deindik.
Ayn isimli ar yklenmi metodlarn kullanlma tarzn, web metodlardan geriye dnen kompleks
tiplerin ierisinde kaltm ilikisi olduu takdirde bunu Xml tarafnada bildirmemiz gerektiini,
performans iin caching' i kullanabileceimizi ve sunucu tarafnda bir authentication olmas halinde
istemci iin gerekli username ve password bilgilerinin nasl hazrlanp gnderilebileceini
incelemeye altk. Elbetteki web servisleri ile ilgili dikkate deer daha pek ok nokta var. rnein
SoapExtension yardmyla soap mesajlarnn ifrelenmesi gibi. Bu ve benzer dier konulara ilerki
makalelerimizde deinmeye alacaz. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

XPath ve .Net ( 04.03.2006 ) - Xml


Deerli Okurlarm Merhabalar,

XPath, XML dkmanlar zerinde basit tipte sorgulamalar yapmamza izin veren bir dildir. Yaps
gerei kullanld pek ok alan vardr. rnein XQuery iinde yada bir XSLT dkmannda bu dilin
izlerine rahatlkla rastlayabilirsiniz. Tam olarak yapt iin, XML dkman ierisinde lokasyon
aramak ve bulmak olduunu syleyebiliriz. XPath, herhangibir Xml verisi zerinde arama ve
konumlandrma ilemini gerekletirmek iin Document Object Model' i kullanlr. Yani, xml verisinin
bellekteki hiyerarik aa yapsn ele alr. Bunun iinde Xml verisinin yapsal (structural) metadata
bilgisine bakar. XPath bal bana bir dildir ve bu konu ile ilgili yazlm kitaplar vardr. ( Size eski
olmasna ramen Sams' n XPath Kick Start : Navigating XML with XPath 1.0 and 2.0 kitabn
tavsiye edebilirim.)

Biz bu makalemizde ok fazla detaya inmeyecek ve XPath' i .Net zerinde nasl kullanabileceimizi
basit olarak incelemeye alacaz. Konuyu iyi anlayabilmek amacylada XPath ile oluturulmu
eitli tipteki sorgular rnek bir xml dkman zerinde kullanacaz. rnein elimizde Kitaplara ait
yazar, isim, fiyat gibi bilgileri tutan bir Xml dkman olduunu dnelim. Aada bu amala
kullanabileceimiz Kitaplar.xml adl xml veri dosyasnn bir parasn gryorsunuz. (Xml dosyasn
ve rnek kodlar buradanindirebilirsiniz.)

www.bsenyurt.com Page 1633


Bu Xml verisini gz nne alacak olursak, XPath' in ilgili veri kmesini bellekte aa(tree) modeli
ekline tasvir edeceini ve buna gre yer belirleme ilemini gerekletireceini syleyebiliriz.
Kitaplar.xml dosyamzn ieriini ele aldmzda, XPath modeli, bellek zerinde aadaki ekile
benzer bir aa yapsn kullanacaktr. Bu hiyerarik yap zaten Document Object Model' in bir
uyarlamasdr.

www.bsenyurt.com Page 1634


Dikkat ederseniz Root element zerinden xml verisi ierisinde tm alt elementler bu elementlerin
var ise atrribute' lar ele alnmaktadr. Kitaplar.xml verisinin tamamn grafie sdrmamz zor
olacandan sadece bir ksm burada gsterilmetedir. te XPath, herhangibir kritere gre bir node
listesi, tek bir node veya deer (rnein toplam gibi) dndrmek iin bu aa yapsn kullanacaktr.
Bu modele gre XPath dili ile aadaki tabloda da belirtilen rnek sorgular oluturabiliriz.

XPath Sorgusu Anlam

Kitaplar ierisindeki her bir Kitap elementini, alt elemenetleri


Kitaplar/Kitap
ile birlikte elde etmemizi salar.

Kitaplar ierisindeki her bir Kitap elementinin ierdii ID


Kitaplar/Kitap/@ID
attribute' larnn tamamn geri dndrr.

Kitaplar iersinde Kitap element' lerinden, ID attribute' unun


Kitaplar/Kitap[@ID=1000]
deeri 1000 olan elementi (elementleri) elde etmemizi salar.

Kitaplar ierisinde Kitap element' lerinden Fiyat element' inin


Kitaplar/Kitap[Fiyat<=50]
deeri 50 veya daha az olanlar elde etmemizi salar.

Kitaplar/Kitap[Fiyat>50 and Kitaplar ierisinde, Kitap elementler' inden Fiyat elementinin


Fiyat<80] deeri 50 ile 80 arasnda olanlar elde etmemizi salar.

Toplam Kitap saysn verir. Bu tekil bir sonu deeri


count(/Kitaplar/Kitap) dndrr. stteki sorgularda olduu gibi bir node listesi
dndrmez.

Kitaplarn fiyatlarnn toplamn geriye dndrr. Yani Kitap


sum(/Kitaplar/Kitap/Fiyat) node' lar ierisindeki Fiyat node' larnn value zelliklerinin
deerlerinin toplamn verir.

Fiyat element' inin deeri 70' den yksek olan Kitap element'
sum(/Kitaplar/Kitap/Fiyat[.>70])
lerindeki Fiyat element' lerinin toplamn verir.

Fiyat element' inin deeri 70' den yksek olan Kitap element'
count(/Kitaplar/Kitap/Fiyat[.>70])
lerinin saysn verir.

Buradaki sorgularda ksaltmalar(abbreviation) kullanlmtr.(/ veya . gibi) Bunun birde ksaltma


kullanlmayan(unabbreviation) ekli vardr. Genellikle kslatmalarn yer ald kullanm ekli daha
yaygndr ve esnektir.

Gelelim yukardakine benzer XPath ifadelerini .Net zerinde nasl kullanacamza. Framework Class
Library aslnda tamamyla XPath mimarisini kullanmaya yarayan tipleri barndran
System.Xml.XPath isim alanna sahiptir. Buradaki temel snflar yardmyla XML dkmanlar
zerinde XPath ile arama ve yer belirleme ilemlerini gerekletirebiliriz. Bununla birlikte bir
XmlDocument nesnesinin SelectNodes veya SelectSingleNode gibi metodlarnda parametre
olarak XPath ifadelerini kullanabiliriz. Hangisini tercih edeceimiz, Xml dkman zerinde ne gibi

www.bsenyurt.com Page 1635


ilemler yapmak istediimize baldr. Eer Xml dkmannda belirli bir lokasyona eriip elde
ettiimiz node listelerinde deiiklikler yapmak istiyorsak XmlDocument snfnn SelectNodes veya
SelectSingleNode metodlarn tercih edebiliriz. Bununla birlikte sadece arama ve arama sonularn
gsterme amal uygulamalarda, XPath isim alannda yer alanXPathDocument gibi snflar
kullanmak performans ve hz asndan daha efektif sonular retecektir. Nitekim XPathDocument,
XPathNavigator ve XPathNodeIterator gibi snflar XmlDocument snfna gre daha performansldr.

Aadaki rnek Console uygulamasnda ok basit olarak XPathDocument snfndan yararlanlarak


fiyat 50 ile 80 arasnda olan kitaplara ilikin bilgiler xml verisi ierisinde bulunarak ekrana
yazdrlmaktadr. Ayrca, fiyat 70' den byk olan kitaplarn saysda ekrana farkl bir teknik ile
(Evaluate) yazdrlmaktadr.

using System;
using System.Xml;
using System.Xml.XPath;

namespace UsingXPathNavigator
{
class Class1
{
static void UsingXPath()
{
XPathDocument doc = new XPathDocument("..\\..\\Kitaplar.xml");
XPathNavigator navigator = doc.CreateNavigator();

XPathNodeIterator nodes = navigator.Select("Kitaplar/Kitap[Fiyat>50 and


Fiyat<80]");

while (nodes.MoveNext())
{
Console.WriteLine(nodes.Current.ToString());
}

Console.WriteLine("Toplam Kitap Sayisi (Fiyat>70)


"+navigator.Evaluate("count(/Kitaplar/Kitap/Fiyat[.>70])").ToString());
}

static void Main(string[] args)


{
UsingXPath();
}
}
}

Program altrdmzda aadakine benzer bir ekran grnts elde ederiz.

www.bsenyurt.com Page 1636


Dilerseniz ksaca kodlarmz inceleyelim ve ne yaptmz daha iyi anlamaya alalm.
XPathDocument snf, herhangibir Xml dkmann XPath dilini kullanarak sorgulayabilmemizi
salayan eitli fonksiyonelliklere ve zelliklere sahiptir. Aslnda XPath, Xml dkmanlarn DOM
(Document Object Model)' e uygun olan bir aa yaps eklinde inceler. Dolaysyla
XPathDocument snf xml verisini bu modele uygun bir bellek grntsn oluturmak amacyla
kullanlr. XPathDocument snfna ait bir nesne rnei ile bellee alnan aa modeli zerinde
hareket edebilmek iin, XPathNavigator snfna ait metodlar kullanlabilir. XPathNavigator,
abstract bir snf olduundan (yani nesne rnei oluturulamayan bir snf), XPathDocument
snfnn CreateNavigator metodu yardmyla oluturulur.

XPathNavigator snf iki nemli metod sunar. Bunlar Select ve Evaluate metodlardr. Select
metodu ounlukla geriye birden fazla sayda sonu dnecei zaman kullanlr. rneimizde olduu
gibi. Select metodu aslnda geriye XPathNodeIterator tipinden bir nesne rnei dndrmektedir.
Bu snf basit olarak, Select metodu sonucu elde edilen veri seti zerinde, ileri ynl hareket
etmemizi salar. Biz bu iterasyon ile Kitap node' larnn tm ieriini ekrana yazdryoruz. Ancak
grdnz gibi ekran kts okta mkemmel deil. Aadaki kod parasda, Kitap node' larnn
alt node' larndada ileri ynl hareket ediyor ve ieriin daha okunabilir olmasn salyoruz. yleki
XML dkmanmzda Kitap node' larnn alt node' larndan olan Yazarlar node' ununda alt node' lar
var. Bu yzden i ie 3 while iterasyonu yazmamz gerekiyor.

static void UsingXPathSecond()


{
XPathDocument doc = new XPathDocument("..\\..\\Kitaplar.xml");
XPathNavigator navigator = doc.CreateNavigator();

XPathNodeIterator nodes = navigator.Select("Kitaplar/Kitap[Fiyat>50 and Fiyat<80]");

// lk olarak sorgu sonucu elde edile fiyat 50 ile 80 arasndaki Kitap node' larnda hareket
ediyoruz.
while (nodes.MoveNext())
{
// Her bir Kitap elementinin alt node' larn alyoruz ve bu node' lar ierisinde ileri ynl
hareket ediyoruz.
XPathNodeIterator
childNodes=nodes.Current.SelectChildren(XPathNodeType.Element);
while(childNodes.MoveNext())
{
// Eer o anki alt node'un ad Yazarlar ise bu kez gncel Kitap node' unun altndaki
Yazarlar node' unun alt node' lar ierisinde ileri doru hareket ediyoruz. Eer gncel alt node
Yazarlar node' u deilse o node' un adn ve deerini yazdryoruz.
if(childNodes.Current.Name=="Yazarlar")
{
XPathNodeIterator
yazarlarNodes=childNodes.Current.SelectChildren(XPathNodeType.Element);

www.bsenyurt.com Page 1637


Console.Write("Yazar(lar) : ");
while(yazarlarNodes.MoveNext())
{
Console.Write(yazarlarNodes.Current.Value+", ");
}
Console.WriteLine();
}
else
{
Console.WriteLine(childNodes.Current.Name+":"+childNodes.Current.Value);
}
}
Console.WriteLine();
}
Console.WriteLine("Toplam Kitap Sayisi (Fiyat>70)
"+navigator.Evaluate("count(/Kitaplar/Kitap/Fiyat[.>70])").ToString());
}

XPathNavigator snfmzn yukardaki rneklerde kullandmz dier nemli fonksiyonelliinin


Evaluate metodu ile salandn sylemitik. Bu metod geriye object tipinden bir deer
dndrmektedir. Bu yzden rneimizde olduu gibi count ile hesaplanan tek bir deeri almak iin
birebirdir. Evaluate metodunu, Command snfnn ExecuteScalar metoduna benzetebilirisiniz. Her
ikiside bir veri seti zerinden geriye tek bir deer dndrmek amacyla kullanlr.

XPath dilini kullanabileceimiz tek tip XPatDocument snf ve bununla ilikili dier snflar deildir.
XPath dili ile yazlan sorgular XmlDocument snfna ait herhangibir nesne rnei iinde de
kullanabiliriz. XmlDocument snfnn SelectNodes ve SelectSingleNode isimli metodlar
parametre olarak XPath tipinden ifadelerde almaktadr. rnein aadaki kod parasnda
XmlDocument snfndan nesne rneimizin bellekte tuttuu xml verisi ierisinde Bill Evjen isimli
yazara ait Kitap node' larnn listesi elde edilmektedir. SelectNodes metodu ile bulunan node' lar
aldktan sonra bunlarn saysna bakaraktan st node' lara (parent node) nasl ktmza dikkat
edin.

static void UsingXmlDoc()

www.bsenyurt.com Page 1638


{
XmlDocument xmldoc = new XmlDocument();
xmldoc.Load("..\\..\\Kitaplar.xml");

XmlNodeList resultNodes = xmldoc.SelectNodes("/Kitaplar/Kitap/Yazarlar[Yazar='Bill


Evjen']");
XmlNode currNode;
XmlNode parentNode;

if(resultNodes.Count==1)
{
currNode=resultNodes[0];
parentNode=currNode.ParentNode;
Console.WriteLine(parentNode.InnerText);
}
else
{
foreach(XmlNode aNode in resultNodes)
{
parentNode=aNode.ParentNode;
Console.WriteLine(parentNode.InnerText);
}
}
}

static void Main(string[] args)


{
UsingXmlDoc();
}

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde XPath dili ile gelitirdiimiz sorgular
.Net snflar ile nasl kullanabileceimizi inceledik. zetlemek gerekirse, XPath modelinin sunduu
imkanlar kullanabileceimiz yerler XPathDocument snf ve XmlDocument snflardr. Her iki snf
ile XPath ifadelerini etkin bir ekilde kullanabiliyoruz. Bunlara ek olaraktan ileridede greceimiz
gibi XPath ifadelerini XQuery veya XSLT ierisinde de aktif olarak kullanmaktayz. Bu modelleri
daha sonraki yazlarmzda incelemeye alacaz. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 1639


Connection Pooling' in nemi ( 27.02.2006 ) -
Ado.Net 2
Deerli Okurlarm Merhabalar,

Connectilon Pooling veritaban programclnda, uygulamalarn performansn dorudan etkiliyen


unsurlardan birisidir. Balantlarn bir havuza atlarak buradan kullanlmalarn salamaktaki en
byk ama, ok sayda kullancnn bal olduu veri tabanl uygulamalarda, ayn zelliklere sahip
balant bilgilerinin defalarca oluturulmasnnn nne gemek bu sayede var olan ak
balantlarn kullanlabilmesini salamaktr. Temel mantk son derece basittir. Bir kullanc
uygulamas ierisinden bir verikaynana balanmak istediinde, geerli bir Connection nesnesi
oluturmak zorundadr. Bu Connection nesnesi eer ilk kez talep edilmise, veritaban tarafnda bir
balant havuzunun iine atlacaktr. Ki baka bir kullanc ayn veri kaynana ayn balant bilgisi
ile balanmak istediinde, havuzdaki balanty kullanabilecektir. Burada ayn balant bilgisine
bavuran birden fazla kullanc olduunu dndmzde bu mimarinin nemi ortaya kmaktadr.
zellikle web tabanl uygulamalarda bu fark byk performans kazanm anlamna gelmektedir. Biz
bu makalemizde Connection Pooling' in mimarisini incelemektense onu kullanrken dikkat etmemiz
gereken noktalara deineceiz. Ama hereyden nce connection pooling' i kullanmann faydasn
greceimiz basit bir rnek ile yola kmakta fayda olaca kansndaym. Bunun iin, Vs.2005' de
aadaki kodlara sahip basit bir console uygulamas yazarak ie balayalm.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace UsingPooling
{
class Program
{
static void Main(string[] args)
{
SqlConnection con = new SqlConnection("data
source=MANCHESTER;database=AdventureWorks;integrated security=SSPI;Pooling=false");
DateTime dtBaslangic = DateTime.Now;
for (int i = 0; i < 10000; i++)
{
con.Open();
con.Close();
}
DateTime dtBitis = DateTime.Now;
TimeSpan tsGecerSure = dtBitis - dtBaslangic;
Console.WriteLine("Geen sre {0} milisaniyedir.",
tsGecerSure.TotalMilliseconds.ToString());
}
}
}

www.bsenyurt.com Page 1640


ncelikle bu uygulamada ne yapyoruz ksaca bunu aklayalm. Uygulamamz Sql Server 2005
zerinde yer alan AdventureWorks isimli veritabanna, 10000 defa bir balant ap kapatyor.
Burada dng ierisinde gerekleen olaylar, sisteme balanan 10000 farkl kullancnn kod ksm
olarakta dnebilirisiniz. Ayn balant bilgisi iin defalarca ama ve kapatma ilemini yapyoruz ve
bu ilemler sonras oluan sre farkna bakyoruz. Burada balant bilgisine dikkat ederseniz
Pooling zelliinin bilerekten false olarak atandn grrsnz. Yani ilgili connection bilgisinin
herhangibir ekilde havuza atlmayacan (Connection Pool' da tutulmayacan) belirtmi
oluyoruz. Bu haliyle uygulamamz altrdmzda aadaki gibi (ya da kullandnz evresel
parametrelere gre bu sonuca yakn) bir sre fark elde ederiz.

Ancak Pooling=false zelliini kaldrrsak (ki varsaylan hali true' dur ve pooling' in aktif olmasn
salar) sre fark ok daha az olacaktr.

Grld gibi, her iki uygulamann alma sreleri arasnda belirgin ve ayn zamanda dikkate
deer bir zaman fark olumutur. Bu, Connection Pooling' in herhangibir Connection nesnesine ait
balant bilgisi ierisinde hi bir ey belirtilmesse zaten aktif olacana kredebileceimiz bir
durumdur. Ancak kodlama farklarndan dolay Pooling zaman zaman bamz derde sokabilir. Bizim
iin sanc yaratacak iki farkl durum vardr. imdi ksaca bu durumlar inceleyeceiz. lk olarak
aadaki kodlara sahip olan ve Vs.2005 zerinde gelitirilmi basit bir Windows Uygulamasn gz
nne alalm.

private void btnExecute_Click(object sender, EventArgs e)


{
try
{
SqlConnection con = new SqlConnection("data

www.bsenyurt.com Page 1641


source=MANCHESTER;database=AdventureWorks;integrated security=SSPI;Min Pool Size=10;Max
Pool Size=15");
SqlCommand cmd = new SqlCommand("SELECT Count(*) FROM Person.Contat", con);
con.Open();
int kontakSayisi=Convert.ToInt32(cmd.ExecuteScalar());
con.Close();
}
catch(Exception err)
{
lstExceptions.Items.Add(err.ToString());
}
}

Burada button kontrolne basldnda alan kodlarda, Person.Contat isimli tablodaki kayt saysn
renebileceimiz bir sorgunun altrlmasn gryoruz. Burada kod, try/catch blouna
alndndan, sql komutlarnn yrtlmesi yada balantnn almas srasnda oluacak hatalara
kar program koruma altna aldmz dnebiliriz. Ancak Contat(Contact olmas gerekirdir)
tablosu AdventureWorks isimli veritabannda mevcut deildir. Bu yzden kod alma zamannda
bir SqlException verecektir. Ancak bu kodu birden fazla sayda kullancnn tetiklediini dnrsek
(rneimizde butona defalarca basarak bu durumu canlandrabiliriz) bamza korkun iler
gelebilir. yleki, SqlCommand snfndan olan cmd nesnesi execute edilirken oluan hata, con
nesnesinin kapatlmasn engellemektedir. Bu sunucu zerindeki balant havuzunda ak kalan bir
balant demektir. Button kontrolmz tetiklendike, ak balant says artmaya ve bir sre
sonrada balant havuzundaki maksimum balant saysn amaya balayacaktr. Bu durum byle
devam ederekten sonuta uygulamann SqlException istisnasndan vazgeerek zaman amna bal
olaraktan InvalidOperationException istisnasn frlatmasna neden olacaktr. u aamada istisnann
tipinden ziyade ak kalan balantlar srekli olarak artmas ok tehlikeli bir durumdur. Aadaki
ekran grnts, yukardaki uygulamada button kontrolne defalarca baslaraktan elde edilmitir.

www.bsenyurt.com Page 1642


Bu grntde yer alan NumberOfReclaimedConnections sayac (Counter), .Net 2.0 ile birlikte gelen
yeni performans lm deerlerinden birisidir ve havuzda yer alpta kapatlamayan balant
saylarna ilikin bilgileri vermektedir. Grafiktende grlecei zere ak balantlar srekli
artmtr. Uygulama bunun sonucunda SqlException' dan karak zaman am (Timeout) nedeni ile
InvalidOperationException' a srklenmitir.

NumberOfReclaimedConnections, .Net 2.0 ile birlikte gelen Performans sayalarndan


(Performance Counter) birisidir. Bu saya .Net Data Provider For Sql Server performans
nesnesi (Performance Object) altnda yer almaktadr.

www.bsenyurt.com Page 1643


Aslnda hatann nedeni son derece basittir. Connection snfna ait nesne rneinin kapatlmas
garanti altna alnmamtr. Bu gerekten nemli bir hatadr. Bu durumu dzeltmek iin ya finally
blou eklenmeli ya da ilemler aadaki kod parasnda olduu gibi using bloklar ierisinde
gerekletirilmelidir. Nitekim using blou doal olaraktan kulland nesnenin dispose edilmesini
garanti altna alr.

private void btnExecute_Click(object sender, EventArgs e)


{
try
{
using (SqlConnection con = new SqlConnection("data
source=MANCHESTER;database=AdventureWorks;integrated security=SSPI;Min Pool Size=10;Max
Pool Size=15"))
{
using (SqlCommand cmd = new SqlCommand("SELECT Count(*) FROM Person.Contat",
con))
{
con.Open();
int kontakSayisi = Convert.ToInt32(cmd.ExecuteScalar());
}
}
}
catch (Exception err)
{
lstExceptions.Items.Add(err.ToString());
}
}

www.bsenyurt.com Page 1644


Grld gibi bu kez havuzda ak kalan hi bir balant yoktur. Bunu grmek iin uygulamay
test ettiimizde, yukardaki ekran grntsnde olduu gibi NumberOfRecalimedConnections
sayacnn (Counter) sfr olarak seyrettiini grrz. Dolaysyla uygulamadaki balantlar iin
maksimum havuz boyutunun almas ve nihayetinde InvalidOperationException istisnasna
srklenilmesi engellenmitir. Hereyden nemlisi ne kadar ok kullanc bu kodu altrrsa
altrsn, havuzda ak kalan herhangibir balant olmayacaktr. imdi gelelim connection pooling
ile ilgili dier nemli noktaya. Aadaki rnek console uygulamas bu durumu canlandrmak iin
gelitirilmitir.

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace Pooling_3
{
class Program
{
static void Main(string[] args)
{
try
{
for (int i = 1; i < 100; i++)

www.bsenyurt.com Page 1645


{
KontakSayisiniBul();
}
}
catch (SqlException err)
{
Console.WriteLine(err.Message.ToString());
}
Console.ReadLine();
}

private static void KontakSayisiniBul()


{
using (SqlConnection con = new SqlConnection("data
source=MANCHESTER;database=AdventureWorks;integrated security=SSPI;Min Pool Size=5;Max
Pool Size=15"))
{
SqlCommand cmd = new SqlCommand("Select Count(*) From Person.Contact", con);
con.Open();
int kontakSayisi = Convert.ToInt32(cmd.ExecuteScalar());
System.Threading.Thread.Sleep(1500);
}
}
}
}

Bu rnekte son derece anlamsz bir ekilde 100 defa Contact tablosundaki eleman saysn
hesaplatmaktayz. Bu ilemleri yaparken durumu daha iyi analiz edebilmek iinde kodu 1,5 saniye
kadar duraksatyoruz. Bu ilem sonradan Sql Server Servisini restart etmemizde bize zaman
kazandracaktr. Kodu, ayn ilemi sunucuya doru gerekletiren n sayda kullanc ekranna ait bir
uygulamann paras olarakta dnebiliriz. N sayda kullanc sunucuya balanp sorguyu
altrdklar srece, sunucunun bana eitli haller gelebilir. rnein, Sql Server Servisi bir
ekilde batan balatlm (Restart) olabilir. (Bu ounlukla sql sunucusunu barndran bilgisayarn
istem d restart olmas halinde gerekleebilecek bir durumdur.) Eer byle bir durum sz konusu
olursa, havuzda duran balant bilgileri servis yeniden alsa bile eriilemez hale gelecektir.
rneimizi altrdktan sonra Sql Server servisini batan balatacak olursak, servis durup yeniden
almaya baladnda ilgili uygulama ortama bir SqlException istisnas frlatacaktr.

www.bsenyurt.com Page 1646


Bu istisnann nedeni artk havuzda duran balant bilgilerinin yapsnn, servisin yeniden
balatlmas nedeni ile bozulmu olmasdr. Bu sorunu zebilmek iin yaplabileceklerden bir tanesi
ve en kolay, havuzdaki balantlar sfrlamak bir baka deyile havuzu boaltmaktr. Ado.Net 2.0'
da Connection snflarna bu ilemleri kolay bir ekilde yapabilmek iin iki yeni metod eklenmitir.
Bu metodlarn prototipleri aadaki gibidir.

Metod Ksa Aklama

public static void ClearAllPools () Havudaki tm balantlar boaltr.

public static void ClearPool (SqlConnection Parametre olarak verilen balantya ait
connection) havuzu boaltr.

Bu metodlarn uygulanmas halinde yukardaki alma zaman hatas ile baedebiliriz. Aslnda bu
metodlar, balant havuzunu boaltrken ilgili balant nesnelerini kapatmazlar. Sadece bunlarn
artk kullanlmayacan belirtirler. Yukardaki rnek uygulamamz aadaki gibi deitirmemiz
etkili bir alma zaman zm olacaktr.

try
{
for (int i = 1; i < 100; i++)

www.bsenyurt.com Page 1647


{
KontakSayisiniBul();
}
}
catch (SqlException err)
{
if (err.Number == 233)
{
SqlConnection.ClearAllPools();
}
}

Uygulamamz bu haliyle altrrsak alma zamannda herhangibir istisna almayz. Az nce


deindiimiz gibi bu sorunun daha zor olan ama daha gl olan bir zm daha vardr. Bu
Failover Partner ad verilen gene bir zmdr. Ksaca, sql sunucusunun yannda ayna(Mirror)
grevi gren bir sunucu ve birde tank(Witness) grevi gren baka bir sunucu vardr. Bu sistemin
konusu makalemizin snrlarn amaktadr. Bu konuya ilerleyen zamanlarda ayrca vakit ayrmay
dnyorum. Grld gibi balant havuzlarn kullanrken bamza gelebilecek iki nemli
tehlike zerinde durmaya altk. lki kesin olarak kapatlmayan balant nesnelerinin yol at
sorundu. Bunun zm iin en etkili yntem olarak using bloklarna bavurduk. Dier sorunumuz
ise, alma zamannda veritaban sunucusunun herhangibir neden ile sfrlanmasyd. Bu sorunu
ise, hata kodunu ele alp balany havuzlarn boaltarak zdk. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Mobil Uygulamalarda Http zerinden


Download ve Upload ( 21.02.2006 ) - Mobile.Net
Deerli Okurlarm Merhabalar,

Http protolok yardmyla internet zerinden sunuclar ve istemciler arasnda veri al veriinde
bulunmak mobil uygulamalarda ok ie yarayan bir tekniktir. zellikle binary (ikili) formatta veri
transferi iin, Http ektili ve verimli bir protokol hizmeti sunar. Bu makalemizde mobil uygulamalar
ile web sunucular arasnda veri transferi ilemlerini Http protokolne gre nasl yapabileceimizi
incelemeye alacaz.

Http protokol gerei uygulamalarda istekte (request) bulunan ve cevap (response) veren
taraflarn olmas sz konusudur. Bir kaynaa ynelik olarak gerekli isteklerde bulunmak ve bu
isteklere karlk gerekli cevaplar retmek iin FCL (Framework Class Library) ierisinde yer alan
HttpWebRequest ve HttpWebResponse snflarn kullanabiliriz. Bu snflar sadece Http protokoln
baz alarak almaktadrlar. HttpWebRequest snf yardmyla bir kaynaa Http protokol zerinden
istekte bulunabiliriz. Bu kaynak ounlukla uzak sunucuda yer alr. Benzer ekilde
HttpWebResponse snf yardmyla da istekte bulunduumuz kayanaa ynelik geri dnleri bir
baka deyileri cevaplar (response) ele alabiliriz. HttpWebRequest snf aslnda WebRequest
snfndan, HttpWebResponse snf ise WebResponse snfndan tremitir. WebResponse ve
WebRequest snflar web zerindeki eitli protokollere gre alabilecek snflar iin ortak
zellikleri bnyelerinde toplamaktadr.

www.bsenyurt.com Page 1648


WebRequest ve WebResponse snflar internet ortamnda request/response modeline
gre alacak mimarileri kullanabilmek iin vardr. zellikle Http protokoln kullanan bir
request/response modeli iin bu snflardan treyen HttpWebRequest ve
HttpWebResponse snflar kullanlr.

Biz rnek olarak bir mobil uygulmann ierisinde yer ald bir senaryoyu gz nne alacaz.
Diyelimki mobil cihazmz ile sokakta gezerken resimler ektik, ses ve grnt kaytlar yaptk.
Bunlar internet ortam zerinden bir web sunucusuna gndermek isteyebiliriz. (Upload ilemi)
Benzer olaraktan tersi durumda sz konusu olabilir. Ya da rnein bir polis olduumuzu ve
kolumuza bal mobil cihazdan su ileyen kiinin fotorafn aldmz dnelim. Bu fotoraf
mobil cihaz tayan tm polis, itfaiye, askeri, salk ekiplerince tek bir sunucu zerinde
ekilebilecek bir kaynak olabilir. (Download) Farkl senaryolar dnlebilir. Http modelinin baz
alnd request/response modeli burada bize mobil cihazlar ile sunucular arasnda iletiim
kurmamzn yollarndan sadece birisidir. Dolaysyla bu senaryolar iin farkl tekniklere ve
mimarilerede bavurabilirsiniz. Biz Http protokol yardmyla bunu nasl salayabileceimizi
inceleyeceiz.

lk olarak ie basit bir Smart Device Application uygulamas oluturmakla balayalm. Non-
Graphical Application tipinde basit bir uygulama gelitireceiz. Web sunucumuz tarafnda ise, IIS
altnda isimsiz kullanclarn (anonymous users) read ve write ilemleri yapmasna izin veren bir
virtual directory' miz (sanal klasrmz) olmaldr. Bu klasr biz, http zerinden mobil cihaza
gndereceimiz ve mobil cihazdan alacamz dosyalar tutacamz yer olarak kullanacaz. nk
istekte bulunacamz kaynaa http zerinden eriebilmemiz ve buradan okuma/yazma ilemlerini
yapabilmemiz gerekmektedir.

Web sunucusu tarafnda yaptmz bu ayarlardan sonra uygulama tarafndaki kodlarmza


geebiliriz. lk olarak Download ve Upload ilemleri srasnda izleyeceimiz prosedrleri ksaca
aklamaya alalm. Download ilemi iin ncelikle web sunucusundaki ilgili dosyaya bir istekte
(request) bulunmamz gerekecektir. Bu ii HttpWebRequest snfna ait bir nesne rnei yardmyla

www.bsenyurt.com Page 1649


gerekletirebiliriz. stekte bulunduumuz kaynaktan veri alabilmek iin ise, bir baka deyile web
sunucusu zerinde yer alan dosyay mobil cihazmza aktarabileceimiz bir stream oluturabilmek
iinse HttpWebResponse snfna ait nesne rneinden yararlanacaz. Her iki nesneyi kullanarak
sunucuda duran herhangibir formattaki dosyay bir stream zerinden mobil cihaza aktarmak iin ise
Binary seviyede okuma ve yazma ilemi yapacamz ilgili snflar kullanacaz. Burada ounlukla
binary(ikili) formatta okuma ilemi yapacamzdan BinaryWriter ve BinaryReader snflarna ait
nesne rneklerine ihtiyacmz olacaktr. BinaryWriter snfna ait nesne rneini mobil cihaz
zerindeki kaynaa binary formatta veri yazmak, BinaryReader snfna ait nesne rneimizi ise
istekte bulunduumuz kaynaktan veri okumak iin kullanacaz. lk olarak uygulamamza
System.Net ve System.IO isim alanlar ekleyelim. System.Net isim alanndan(namespace)
ihtiyacmz olan HttpWebRequest, HttpWebResponse, WebRequest ve WebResponse snflarn
alrken, System.IO isim alanndan da FileStream, BinaryWriter ve BinaryReader snflarn
aracaz.

using System;
using System.Data;
using System.IO;
using System.Net;

namespace UsingHttp
{
class Class1
{
static void DosyaIndir()
{
HttpWebRequest
request=(HttpWebRequest)WebRequest.Create("http://169.254.25.129/MobileFiles/Elvis.gif")
;
HttpWebResponse response=(HttpWebResponse)request.GetResponse();

BinaryReader reader=new BinaryReader(response.GetResponseStream());

FileStream localFile=new FileStream("Elvis.gif",FileMode.Create);


BinaryWriter writer=new BinaryWriter(localFile);

try
{
while(true)
{
writer.Write(reader.ReadByte());
}
}
catch
{
}
response.Close();
writer.Close();
}

static void Main(string[] args)


{

www.bsenyurt.com Page 1650


DosyaIndir();
}
}
}

imdi uygulama kodlarmz ksaca inceleyelim. DosyaIndir isimli metodumuzda ilk olarak
HttpWebRequest ve HttpWebResponse snflarna ait nesne rneklerimizi oluturuyoruz.
HttpWebRequest nesnemizi create etmek iin WebRequest snfnn static Create metodunu
kullanp, cast ilemi yaptmza dikkat edelim. Dikkat ederseniz Create static metodu parametre
olarak istekte bulunduumuz dosyann adresini alyor. Buradaki ip adresi aslnda bu uygulamada
kullandmz Pocket Pc 2003 Emulator' mzn iletiim kuraca web sunucusunun adresidir ve
sisteme ykl olan Microsoft LoopBack sanal network kartnn verdii bir deerdir.
HttpWebResponse snfmza ait nesne rneimizi olutururken ise talepte bulunduumuz
HttpWebRequest snfna ait nesne rneinin GetResponse isimli metodunu kullanyoruz. Bu metod
geriye WebResponse snf tipinden bir nesne rnei dndrdnden sonucu HttpWebRequest
tipine cast etmemiz gerekiyor. Artk web sunucu zerindeki MobileFiles klasrnde yer alan Elvis.gif
isimli resim dosyasna bir istekte bulunup cevap alabilecek ekilde gerekli kodlamalar yapm
olduk.

BinaryReader snfna ait nesne rneimizi, talepte bulunduumuz kaynaktan ikili formatta okuma
yapmak iin kullanyoruz. BinaryReader snfna ait nesne rneimiz parametre olarak bir stream
almaktadr. Bu stream ise, response nesnemizin GetResponseStream isimli metodu ile elde
edilmektedir. Daha sonra okuyacamz byte stream' ini mobil cihaz zerinde kaydedeceimiz
dosya iin gerekli ilemleri yapyoruz. Bir FileStream nesnesi ile nce bu dosyay mobil cihazn root
klasr altnda fiziki olarak oluturuyor ve ardndan bu dosyaya binary formatta yazacak olan
BinaryWriter snfna ait nesne rneimizi oluturuyoruz.

Yazma ilemi iin try,catch blou ierisinde yer alan basit bir sonsuz dng kullanyoruz. Bu dng
ierisinde response nesnesinin at stream zerinden okuma ilemi yapan reader nesnesini
kullanarak, mobil cihaz zerindeki fiziki dosyaya yazma ilemini BinaryWriter snfnn Write
metodunu kullanarak gerekletiriyoruz. imdi uygulamamz altrrsak web sunucumuzda yer
alan Elvis.gif isimli dosyann mobil cihaza indirilmi olduunu grrz. (Uygulamamz Pocket PC
2003 Emulator' zerinde test etmekteyiz.)

www.bsenyurt.com Page 1651


Sra geldi mobil cihazmz zerinden web sunucusuna binary formatta dosya gnderme ilemine.
Uygulamamzda rnek olarak DjBurak isimli gif formatnda bir dosya olduunu gz nne alacaz.
Bu dosya fiziki olarak mobil cihazmz zerinde projemizi deploy ettiimiz ilgili klasrde yer alacak.

Gelelim Upload ilevinin ana hatlarna. Bu kez HttpWebRequest snf barol stelenecek. Nitekim
dosya indirme ileminin tam tersini yapacaz. Yani ilk olarak web sunucusu zerinde yaratmak
istediimiz dosya iin bir HttpWebRequest nesne rnei oluturacaz. nemli olan nokta bu nesne
iin uygulanacak olan veri aktarm metodunun tipi. Biz upload ilemi yaptmzdan aslnda PUT
metodunu gerekletirmi oluyoruz. Bundan sonrasnda ise her zaman olduu gibi veri gnderme
ilemi iin bir stream' e ihtiyacmz olacak. Bu kez bu stream' in yn mobil cihazmzdan sunucuya
dorudur. Stream zerinden verileri gndermek iin ise, byte tipinde belirli boyuttaki dizileri
kullanp bir buffer alan oluturacaz. Bu buffer' daha sonra ilgili stream zerinden, web
sunucusuna doru aktaracaz. Buna gre DosyaGonder isimli metodumuzu aadaki gibi
yazabiliriz.

static void DosyaGonder()


{
HttpWebRequest
request=(HttpWebRequest)WebRequest.Create("http://169.254.25.129/MobileFiles/DjBurak.g
if");
request.Method="PUT";
request.AllowWriteStreamBuffering=true;
Stream str=request.GetRequestStream();
FileStream reader=new FileStream("\\Program Files\\UsingHttp\\DjBurak.gif",FileMode.Open);
byte[] byteArr=new byte[1024];
int readLength=reader.Read(byteArr,0,byteArr.Length);
while(readLength>0)
{
str.Write(byteArr,0,readLength);
readLength=reader.Read(byteArr,0,byteArr.Length);
}
reader.Close();
str.Close();
request.GetResponse();
}

lk olarak bir HttpWebRequest snfna ait bir nesne rneini oluturuyoruz. Bu kez WebRequest
snfmzn static Create metodu, mobil cihazdaki dosyann, web sunucusu zerinde hangi isimle
yazlacan belirtecek ekilde bir parametre alyor. Buna gre Upload ilemi baarl bir ekilde
gerekletirildiinde mobil cihazmzdaki dosyamz web sunucusundaki MobileFiles isimli klasre
DjBurak.gif isimli gif formatndaki resim dosyas olarak kaydedilecektir. Daha sonra request

www.bsenyurt.com Page 1652


nesnesimiz iin Http modelini belirtiyoruz. PUT, request nesnesinin uzak sunucuya veri
gndereceini belirtmi oluyor. Verileri 1024 byte' lk diziler halinde gndermeyi planladmzdan
kodlarmz buna gre tasarlyoruz. Oluturduumuz Stream nesnesi, request nesnesinin gsterdii
kaynaa doru veri aktarma iini stlenecek. Veri aktarmndan yararlanp web sunucus zerindeki
dosyamz oluturmak iin ise her zaman olduu gibi Stream snfmzn Write metodunu
kullanyoruz. Burada byte dizisinin boyutunu arttrarak buffer haline getirililen ve http zerinden
gnderilen paketlerin bykln ayarlayabilirisiniz. Uygulamamz altrdmzda mobil
cihazmz zerinde yer alan DjBurak.gif isimli dosyasnn web sunucusundaki MobileFiles isimli
klasr altnda oluturulduunu grebiliriz.

Bu makalemizde basit olarak mobil cihazlarda Http protokoln kullanarak uzak makineler
zerindeki kaynaklara eriimin nasl yaplabileceini incelemeye altk. Binary (ikili) formatta,
request/response modeline uygun ilemler gerekletirebileceimizi grdk. rnek olarak gif
formatndaki resim dosyalarn ele aldk. Ancak siz binary format kullandnz srece herhangibir
tipteki dosyayda bu ilem iin kullanabilirsiniz. Buna gre grntl bir ses dosyasndan tutunda
ifrelenmi bir text dosyasn dahi ift ynl olarak tayabilirisiniz. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek uygulama iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Sabit Deer Tipleri (Immutable Value Types)


Analizi ( 08.02.2006 ) - C#
Deerli Okurlarm Merhabalar,

Immutable (sabit) tipler basit olarak tanmlandktan sonra varlklar asla deimeyen trler olarak
nitelendirilebilirler. Sabit bir tipe ait bir nesne rneini oluturduunuzda, bu tipin ierii asla
deimez. Ancak bir tipin sabit olup olmayacana karar vermek gerekten zordur. Bu karar
mekanizmasnda, tipin sahip olduu veri ieriinin atomik (atomic) yaps olduka nemlidir.
Atomiklik, bir tipin sahip olduu verisel btnl oluturan her bir elemann aralarndaki iliki
olarak tanmlanabilir. Bu noktada bir tipin atomik olup olmamas, sabit bir tip haline getirilip
getirilmemesinde nemli bir karar mekanizmasdr.

Atomik yapy anlamak iin, bir tipin ierisinde yer alan alanlarn aralarndaki ilikiyi kavramamz
ok nemlidir. rnein, Muhendis isimli bir tipimiz olduunu dnelim. Tipimizin ID, Ad, Soyad,
Pozisyon gibi bilgileri bardndrdn gz nne alalm. Bir mhendisin irket iin geerli olan ID
bilgisi deiebilir. Ancak bu deiikliin Ad,Soyad veya Pozisyon alanlar zerinde herhangibir etkisi
yoktur. Benzer ekilde, bir mhendisin pozisyonuda deiebilir. Ancak bu deiikliin Id,Ad,Soyad
alanlar zerinde bir etkisi yoktur. Ksacas, Muhendis tipinin veri ieriini oluturan alanlarn
birbirleri zerinde her hangibir balayc etkisi yoktur. Bu nedenle Muhendis tipinin atomik olmayan

www.bsenyurt.com Page 1653


bir veri ierii sunduunu syleyebiliriz. Bu da ilgili tipin verileri arasnda tutarllk olmasn
gerektirmeyecek bir olgudur.

Bir tipin verisel ieriini oluturan alanarnn birbirleri zerinde herhangibir etkisi yok
ise, atomik olmayan bir yap sz konusudur.

imdi bir de Saat, Dakika ve Saniye bilgilerini barndrdan Zaman isimli baka bir nesne modelini
ele almaya alalm. Zaman tipi ierisinde yer alan Saat, Dakika ve Saniye alanlarnn
herhangibirinde yaplacak olan deiiklik, dierlerinide etkileyebilecek cinstendir. rnein saniyenin
60' dan byk olmas halinde, dakika alan zerindede gncelletirme yaplmas gerekir. Ayn
durum dakika alan zerinde yaplan deiiklikler iinde geerlidir. Dakikann 60' tan byk olmas
halinde bu kez saat alannn gncelletirilmesi gerekir. Dolaysyla, Zaman tipi ierisinde yer alan
alanlarn bir birlerini dorudan etkilediini syleyebiliriz. te bu etkileim nedeni ile Zaman tipinin
Atomik bir veri ierii sunduunu syleyebiliriz. yleki, verilerin tutarl olmas gerekmektedir.

Bir tipin verisel ieriini oluturan alanlarnn birbirleri zerinde etkisi var ise, atomik bir
yap sz konusudur.

Peki bir tipin ierisinde yer alan veriler arasndaki atomik yapnn sabit(Immutable) bir tip iin
nemi nedir? Hereyden nce, atomik veri yapsna sahip bir tip iin, alma zamannda nesne
rnei zerinde yaplacak her deiiklik nemlidir. Nitekim nesne rnei zerinden hareket
ettiimizde, her hangibir alann deerinin deitirilmesi, atomik zincir ierisinde yer alan dier
alanlarda etkileyebilir. Bu ise zellikle ok kanall uygulamalarda, farkl kullanclarn deiik
zamanlarda ayn nesne rneinin tutarsz farkl veri grntlerine bakmasna neden olabilir.
zellikle bu gibi durumlarda, tipin ieriinin referans yolu ilede etkilenmesine izin vermemeye
alrz. Bu amala kullanlabilecek en uygun tr struct tipidir. Durumu daha iyi analiz edebilmek
iin, Zaman isimli aadaki gibi bir yapmz (struct) olduunu dnelim.

www.bsenyurt.com Page 1654


struct Zaman
{
private int _Saat;
private int _Dakika;
private int _Saniye;

public int Saat


{
get { return _Saat; }
set { _Saat = value; }
}
public int Dakika
{
get { return _Dakika; }
set { _Dakika = value; }
}
public int Saniye
{
get { return _Saniye; }
set { _Saniye = value; }
}
}

Zaman isimli tipimize ait herhangibir nesne rneini alma zamannda aadaki gibi kullanmaya
altmz dnelim.

static void Main(string[] args)


{
Zaman zmn = new Zaman();
zmn.Saat = 12;
zmn.Dakika = 30;
zmn.Saniye = 56;

// Var olan nesne rnei zerinde deiiklik yaplyor.


zmn.Saniye = 64;

www.bsenyurt.com Page 1655


zmn.Dakika = 66;
}

Burada ilk olarak Zaman tipinden bir nesne rneini oluturuyoruz. Daha sonra var olan nesne
rnei zerindeki verilerde tip ierisindeki zelliklerimizi (properties) kullanarak deiiklikler
yapyoruz. te bu noktada verinin tutarlln farkl srelerdeki kullanclar iin bozmu oluyoruz.
Baka bir deyile, farkl kullanclarn farkl zamanlarda bu tipin farkl grntlerine bakabilecekleri
bir durumla kar karyayz. (Burada saniyenin veya dakikann 60' dan byk olmas sonras
yaplmas gerekenler ele alnmamtr.) zellikle zerinde durmamz gereken nokta Zaman tipine
ait nesne rneinin veri tutarllnn nasl korunabileceidir. ok kanall ortamlarda e zamanl
alan kullanclar asndan uygulamann almasnn deiik zamanlarnda Zaman nesnesinin
tutarlln korumak iin neler yaplabilir? Bunu salamann bir ka yolu olabilir. Ancak en garantisi
var olan yapmz, sabit bir deer tr (Immutable Value Type) haline getirmektir. Zaman yapmz
sabit deer tipi haline getirmek iin ilk olarak dardan zellikler vastasyla yaplan deer
atamalarn ortadan kaldrmamz ve kontrol tek bir noktada, dolaysyla bir yapc metod ierisinde
toplamamz gerekmektedir. Buna gre yapmz aadaki hale getirebiliriz.

struct Zaman
{
private readonly int _Saat;
private readonly int _Dakika;
private readonly int _Saniye;

public int Saat


{
get { return _Saat; }
}
public int Dakika
{
get { return _Dakika; }
}
public int Saniye
{
get { return _Saniye; }

www.bsenyurt.com Page 1656


}
public Zaman(int sa, int da, int sn)
{
_Saat = sa;
_Dakika = da;
_Saniye = sn;
ZamanKontrol();
}
private void ZamanKontrol()
{
// Artk srelerin kontrol ve deerlendirilmesi
}
}

Dikkat ederseniz, alanlarmz sadece okunabilir(read only) olarak tanmladk. Dier taraftan
zelliklerimize ait set bloklarn kaldrarak dardan deer atanmasn engelledik. Nesne alanlarna
deer atayabileceimiz en uygun yer olaraktanda ar yklenmi yapc metodumuzu kullandk.
ZamanKontrol isimli metodumuz artk sreleri hesap ederek alanlarn atomik yaps erevesinde
gerekli veri tutarlln salayacak kodlar iermektedir. Sonu itibariyle artk elimizde kullanl bir
sabit deer tr (Immutable Value Type) vardr. Artk Zaman yapsna ait bir nesne rneini
oluturduumuzda var olan nesne ieriini deitirebilmemizin tek yolu nesne rneini yeniden
oluturmaktr.

Zaman zmn = new Zaman(10, 12, 16);

// Var olan nesne rneinin ieriini ancak yeniden oluturarak deitirebiliriz.


// zmn.Saniye = 64;
// zmn.Dakika = 66;

zmn = new Zaman(4, 5, 6);

Burada ilk olarak Zaman yapsna ait bir nesne rnei oluturulmutur. Artk bu nesne var olan
sreler ierisinde tektir ve ierii sabittir. Dahas, ieriin veri tutarll bu nesne rneine bakan
herkes iin salanmtr. Eer, var olan ierik zerinde deiiklik yapmak istersek tek yolumuz
vardr ki buda nesneyi yeniden rneklendirmekten gemektedir.

Sabit deer trlerinde dikkat edilmesi gereken bir dier hususda ieride yer alan referans trl
alanlarn kontroldr. Nitekim referans trleri zerinde yaplan deiikliklerin etkileri, var olan
atomik yap ierisinde, tutarszlklara yol aarak veri btnln bozabilir. rnein, Zaman
yapsn bir dizi olarak baka bir sabit deer tipi ierisinde kullandmz dnelim. Diziler Array
snfndan gelen referans tipleridir. Bu tipe ait bir nesne rneinin her hangibir eleman zerinde
yaplacak deiiklikler, dizinin kullanld herhangibir tip ierisindede gerekleebilir. te bu
nedenle sabit deer trleri ierisinde zellikle diziler kullanldnda dikkat edilmesi gerekir. Bunu
daha iyi anlayabilmek iin aadaki rnei gz nne alalm. Burada SporcuListesi isimli sabit
deer trmz, ieride Zaman yaps tipinden (Zaman yapmzda sabit bir deer tipidir) bir diziyide
kullanmaktadr.

www.bsenyurt.com Page 1657


struct SporcuListesi
{
private readonly Zaman[] zamanlar;

public SporcuListesi(Zaman[] zmn)


{
zamanlar = zmn;
}
public IEnumerator ZamanListesi
{
get { return zamanlar.GetEnumerator(); }
}
}

Bu haliyle SporcuListesinin sahip olduu veri ieriinin tutarllnn garantiye alnm olduu
dnlebilir. Oysaki aadaki uygulama kodlar veri tutarlln kaybettiimizi gsteremektedir.
Zaman yapsn her ne kadar sabit deer tipi olarak tanmlam olsakta, SporcuListesi yapsnn
verisel btnl ve tutarll ieride bir referans tipi kullanlmasndan dolay bozulmutur.

static void Listele(SporcuListesi liste)


{
Console.WriteLine("---Var Zamanlar---");
IEnumerator numb = liste.ZamanListesi;
while (numb.MoveNext())
{
Zaman z = (Zaman)numb.Current;
Console.WriteLine(z.Saat + " " + z.Dakika + " " + z.Saniye);
}
}

static void Main(string[] args)


{
Zaman zmn1 = new Zaman(3, 42, 45);
Zaman zmn2 = new Zaman(3, 43, 31);
Zaman zmn3 = new Zaman(3, 56, 1);

Zaman[] zmn = new Zaman[] { zmn1, zmn2, zmn3 };

www.bsenyurt.com Page 1658


SporcuListesi liste = new SporcuListesi(zmn);
Listele(liste);
zmn[0] = new Zaman(0, 0, 0);
Listele(liste);
}

Uygulamay altrdmzda aadaki ekran grntsn elde ederiz. Dikkat ederseniz


SporcuListesi isimli yapya ait nesne rneimizi oluturduktan sonra, bu yap dnda bir yerde zmn
isimli dizinin ilk elamanna ait verilerde deiiklik yaplmtr. SporcuListesi isimli yapmza ait nesne
rnei oluturulduunda, zmn isimli dizinin referans, bu yapmz ierisindeki zamanlar isimli dizinin
referansyla eitlenmitir. Dolayslya SporcuListesi yapsna ait nesne rnei oluturulduktan sonra,
zmn dizisi ile SporcuListesi isimli snf ierisinde kullanlan zamanlar isimli dizi artk ayn referansa
sahiptir. Bu nedenle SporcuListesi yaps dnda zmn dizisi zerinde yaplan deiiklikler, zamanlar
isimli diziyide etkilyeceinden, sabit deer tr olarak tanmlanm SporcuListesi yapsnn verisel
tutarll bozulmutur.

Peki sorunu nasl zebiliriz? Bu sorunu amak iin, SporcuListesi isimli sabit deer tr ierisinde
Zaman tipi tabanl dizimizi kopyalama yolunu seebiliriz. SporcuListesi yapsnda, yapc
metodumuzu aadaki kod parasnda olduu gibi deitirdiimizi dnelim. Bu kez yapc
metodumuza parametre olarak gelen diziyi dorudan atamak yerine ieride nce zamanlar isimli
dizimizi gelen dizinin eleman saysn baz alarak oluturuyor ve gelen dizinin elemanlarn bu dizi
ierisine 0nc indeksten itibaren kopyalyoruz. Bylece SporcuListesi yapsn olutururken, ieride
kullanlan dizinin veri tutarlln salam oluyor bir baka deyile dardan yaplan deiikliklerin
etkisini ortadan kaldryoruz.

public SporcuListesi(Zaman[] zmn)


{
zamanlar = new Zaman[zmn.Length];
zmn.CopyTo(zamanlar, 0);
}

Uygulamamz tekrardan altrrsak, darda yaplan deiikliin bu kez sabit deer tipimiz
ierisinde etkili olmadn grrz.

www.bsenyurt.com Page 1659


Grld gibi bu kez uygulama kodu ierisinde zmn isimli dizideki deiikliimiz, SporcuListesi
rneindeki zamanlar isimli diziyi etkilememitir. Bylece geldik bir makalemizin daha sonuna. Bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Seriletirme (Serialization) in Pf Noktalar (


02.02.2006 ) - C#
Deerli Okurlarm Merhabalar,

Uygulamalarmzda kullandmz tipler (types) pek ok amala seriletirilirler (Serialization).


Framework Class Library ierisinde var olan pek ok tip seriletirilebilir (Serializable) halde
tasarlanmtr. Bizde ou zaman kendi yazm olduumuz tipleri seriletirme ihtiyac duyarz.
rnek olarak, XML Web Servislerinde istemci taleplerine gnderilecek olan nesnelerin, network
zerinde tayacamz paketlerin veya bir web uygulamasnda yer alan Session nesnelerinin
veritabannda saklanmas srasnda kullanlan tiplerin seriletirilmesini gz nne alabiliriz. Hangi
tr olursa olsun seriletirmede dikkat edilmesi gereken baz noktalar vardr. te bu gnk
makalemizde zellikle Binary ve SOAP formatl seriletirmelere ynelik pf noktalara deinmeye
alacaz.

Kendi yazm olduumuz bir tipi seriletirmek iin tek yapmamz


gereken Serializable niteliini(Attribute) kullanmaktr. Bu zaten bir tipin seriletirilebilmesi iin
gerekli kuraldr. Seriletirme doas gerei, tipin ierisinde yer alan alanlar(fields) ele alr ve bu
alanlarn deerlerini isimleri ile birlikte herhangibir stream' e yazabilir. Bu durumda, tip ierisinde
var olan alanlarn da seriletirilebilir olmalar gerekir.

Seriletirilen bir tipin var olan alanlarnn seriletirilebilir zellie sahip olmas, baka bir
deyile Serializable niteliini uygulam olmas gerekir.

Konuyu daha iyi anlayabilmek iin rnekler zerinden gitmeye alacaz. .Net Framework 2.0
zerinde bir Console uygulamasn ele alacaz. rnein RadyoKanal ve RadyoSahip isimli iki
snfmzn olduu bir rnei gz nne alalm. Bu rneimizde temel amacmz RadyoKanal snfna
ait bir nesne rneini SOAP formatnda serilitirmek ve DeSerialize ilemine tabi tutmak.

www.bsenyurt.com Page 1660


RadyoKanal snfmz;

using System;
using System.Runtime.Serialization;

namespace Serilestirme
{
[Serializable()]
public class RadyoKanal
{
private string _Frekans;
private string _KanalAdi;
private string _MuzikTuru;
private RadyoSahip _Sahip;

public RadyoKanal(string fre,string ad,string tur,RadyoSahip s)


{
_Frekans=fre;
_KanalAdi=ad;
_MuzikTuru=tur;
_Sahip=s;
}
public override string ToString()
{
return _Frekans + " " + _KanalAdi + " " + _MuzikTuru + " " + _Sahip.ToString();
}

www.bsenyurt.com Page 1661


}
}

RadyoSahip snfmz;

using System;

namespace Serilestirme
{
public class RadyoSahip
{
private string _AdSoyad;
private System.Int32 _VergiNo;

public RadyoSahip(string adS,System.Int32 vergiNo)


{
_AdSoyad=adS;
_VergiNo=vergiNo;
}
public override string ToString()
{
return _AdSoyad;
}
}
}

RadyoKanal snfmz seriletirilebilir bir tiptir. Bu snfa ait herhangibir nesne rneine Binary veya
SOAP formatnda seriletirme ilemini uyguladmzda ierdii tm alanlarda seriletirilme ilemine
tabi tutucaktr. RadyoKanal isimli snfmz ierisinde yer alan alanlarn tipleri u an iin string ve
RadyoSahip' tir. String tipi zaten seriletirilebilir bir snftr. Oysaki RadyoSahip isimli snfmzn u
aamada seriletirilme zellii yoktur. Eer yukardaki snflarmz adaki rnek uygulamada
olduu gibi kullanmaya kalkarsak alma zamanda istisna(Exception) alrz.

using System;
using System.IO;
using System.Runtime.Serialization.Formatters.Soap;

namespace Serilestirme
{
class Program
{
private static void Serialize()
{
FileStream fs=null;
try
{
RadyoKanal kanal=new RadyoKanal("999.00","BurkiFM","Alternative Rock",new

www.bsenyurt.com Page 1662


RadyoSahip("Burak Selim Senyurt",10000));
fs=new FileStream("Test.xml",FileMode.OpenOrCreate);
SoapFormatter bf=new SoapFormatter();
bf.Serialize(fs,kanal);
}
catch(Exception err)
{
Console.WriteLine(err.Message);
}
finally
{
fs.Close();
}
}

private static void DeSerialize()


{
FileStream fs=null;
try
{
fs=new FileStream("Test.xml",FileMode.Open);
SoapFormatter sf=new SoapFormatter();
RadyoKanal kanal=(RadyoKanal)sf.Deserialize(fs);
Console.WriteLine(kanal.ToString());
}
catch(Exception err)
{
Console.WriteLine(err.Message);
}
finally
{
fs.Close();
}
}

[STAThread]
static void Main(string[] args)
{
Serialize();
DeSerialize();
}
}
}

www.bsenyurt.com Page 1663


Uygulamamzda Soap formatnda serialize ve deserialize ilemlerini uygulamaktayz. Bu arada,
SoapFormatter' kullanabilmek iin bu snfa ait referans uygulamaya aka eklememiz gerektiini
hatrlatmak isterim. Gelelim hata mesajmza. Hata mesaj RadyoSahip isimli tipin seriletirilebilir
bir tip olarak iaretlenmemi olduunu ifade etmektedir. Dolaysyla tek yapmamz gereken,
RadyoSahip isimli snfmza da Serializable niteliini eklemek olacaktr.

[Serializable()]
public class RadyoSahip

Bu haliyle uygulamamz altrdmzda her hangibir problem ile karlamayz. Nesne rneimizi
xml uzants ile SOAP formatnda seriletirdiimizden Binary formata gre okunurluu daha
kolaydr. XML dkmanmza dikkat ederseniz, RadyoKanal ve RadyoSahip tipleri ayr node' lar
halinde ifade edilmi ve o anki nesne iin sahip olduklar alan deerleride bu node' lar ierisinde
ayrtrlmtr.

www.bsenyurt.com Page 1664


Kendi yazm olduumuz bir tipi seriletirilebilir olarak tanmlamassak, bu tipi kullanan
baka tiplerinde seriletirilmesini engellemi oluruz. Ancak bu sonu, yazdmz her tipin
seriletirilebilir olmas gerektii zorunluluunu dourmaz.

Gelelim bir dier nemli noktaya. Bazen tipimiz ierisinde yer alan filed(alan)' lardan bazlarnn
seriletirilme ilemine dahil edilmemesini isteriz. Bunun eitli sebepleri olabilir. lk akla gelen, bir
nesnenin gizli olan baz alansal bilgilerinin seriletirilmesinin nne gemektir. rnein seriletirilen
bir paketin network zerinde dolatn dnecek olursak, gereksiz bilgilerin bu pakette yer
almamasn isteyebiliriz.

Seriletirilen bir tip ierisinde, seriletirilme ilemine dahil edilmesini istemediimiz alanlar
iin NonSerialized niteliini kullanrz.

rnein, RadyoSahip isimli snfmz ierisinde yer alan _VergiNo isimli alanmzn seriletirme
ilemine dahil edilmemesini istediimizi dnelim. Tek yapmamz gereken NonSerialized niteliini
bu alana uygulamak olacaktr.

[NonSerialized()]
private System.Int32 _VergiNo;

Uygulamamz bu haliyle altrdmzda _VergiNo alannn seriletirme ilemine dahil edilmediini


grrz.

Eer seriletirme ilemi zerinde tam hakimiyet salamak


istiyorsak ISerializable arayzne(interface) bavurmamz gerekecektir. Burada sz konusu olan
hakimiyet seriletirme ilemi srasnda hangi alanlarn, hangi isimler ile ve hangi srada yazlaca
ve hatta farkl versiyonlara sahip tiplerin sz konusu olmas halinde seriletirme ilemlerinin
ynetilebilmesidir. RadyoKanal isimli snfmza ISerializable arayzn uyguladmz dnelim.
Bu arayz beraberinde sadece tek bir metodun uygulanma zorunluluunu getirmektedir. Bu
metod GetObjectData' dr.

using System;
using System.Runtime.Serialization;

www.bsenyurt.com Page 1665


namespace Serilestirme
{
[Serializable()]
public class RadyoKanal:ISerializable
{
// Dier yeler

#region ISerializable Members

public void GetObjectData(SerializationInfo info, StreamingContext context)


{
info.AddValue("Kanal Adi", _KanalAdi);
info.AddValue("Radyo Frekans", _Frekans);
info.AddValue("Muzik Turu", _MuzikTuru);
info.AddValue("Kanal Sahibi", _Sahip);
}

#endregion
}
}

GetObjectData metodu, snfa ait nesne rneinin seriletirilmesi ilemi srasnda devreye girer.
u aamada SerializationInfo tipinde olan info isimli parametre yardmyla seriletirme ierisinde
yer alacak anahtar-deer (key-value) iftlerini belirlemekteyiz. (Bildiiniz gibi, bir tipin seriletirilen
tm alanlar anahtar-deer iftleri esasna dayanlarak aktarlrlar.) Buna gre rnein RadyoKanal
isimli snfmzn herhangibir nesne rneinin o an sahip olduu _Frekans alannn deeri,
seriletirilen dosyada Radyo Frekans ismi ile tutulacaktr. Hatta dikkat ederseniz, ilk iki alann
yazl srasda deitirilmitir. yleki varsaylan seriletirme halinde, tip ierisindeki alanlarn dizili
sras dikkate alnmaktadr. Oysaki biz burada bu sralamay GetObjectData metodu ierisinde
belirleyebileceimizi grmekteyiz. Ne varki uygulamamz bu haliyle altrdmzda aadaki hata
mesajn alrz.

Aslnda seriletirme ileminde her hangibir problem yoktur. Bunu oluturulan xml dosyasnn
ieriine bakarak grebiliriz.

www.bsenyurt.com Page 1666


Sorun DeSerialize ilemi srasnda meydana gelmektedir. Bir snfa ISerializable arayzn
uyguladmzda, nesneye ait alanlarn eletirilme ilemlerini her iki yndede doru ve tutarl bir
biimde yapmamz gerekir. Yani snfmza deSerialize ilemi uyguland takdirde gereken
eletirme bilgisini de vermemiz gerekir. Bu amala genel bir desen kullanlr. Bu desene gre tipe
ait bir private constructor (yapc metod) aadaki kod parasnda olduu gibi kullanlmaldr.

private RadyoKanal(SerializationInfo info, StreamingContext ctx)


{
_Frekans = info.GetString("Radyo Frekans");
_KanalAdi = info.GetString("Kanal Adi");
_MuzikTuru = info.GetString("Muzik Turu");
_Sahip = (RadyoSahip)info.GetValue("Kanal Sahibi", typeof(RadyoSahip));
}

Burada dikkat edecek olursanz SerializationInfo tipine ait Get metodlarn kullanarak stream
ierisinde gelen anahtar-deer iftlerinin, RadyoKanal snf ierisinde denk geldii yeleri
belirlemekteyiz. Bu haliyle uygulamamz altrdmzda her hangibir problem ile karlamayz.

Seriletirilebilir bir snfa ISerializable arayzn (interface) uyguladmzda, deserialize


ilemininde baarl olmas iin tipe ait bir private constructor' n yazlmas ve ieride
seriletirilmi yelere deer atamasnn aka yaplmas gerekmektedir. Bu yapc metoda
DeSerialize Constructor ismini verebiliriz.

Elbetteki bir snfa ISerializable arayzn uyguladmzda, bu snftan treyecek snflar


yazarkende dikkat etmemiz gereken hususlar vardr. Eer taban snf (base class) seriletirilebilir
olarak tanmlarsak ve ISerializable arayzn uygularsak, ilk olarak treyen snflarn(derived
class) taban snf iindeki DeSerialize Constructor metoduna eriebilmelerini salamamz gerekir.
Bu nedenle temel snf ierisindeki DeSerialize Constructor metodunu protected eriim belirleyicisi
ile iaretleriz. Bu konuyu daha iyi anlayabilmek iin rneimize RadyoKanal snfndan treyen
RadyoPersonel isimli yeni bir snf ekleyelim.

www.bsenyurt.com Page 1667


[Serializable()]
class RadyoPersonel:RadyoKanal
{
private int _PersonelNo;
private string _PersonelAd;

public RadyoPersonel(int no, string ad)


{
_PersonelNo = no;
_PersonelAd = ad;
}
}

Bu kez uygulamamzda treyen snfmza ait bir nesne rneini seriletirmek istediimizi gz
nne alalm.

private static void Serialize()


{

www.bsenyurt.com Page 1668


FileStream fs=null;
try
{
//RadyoKanal kanal=new RadyoKanal("999.00","BurkiFM","Alternative Rock",new
RadyoSahip("Burak Selim Senyurt",10000));
RadyoPersonel rp = new RadyoPersonel(10001, "DJ Burak");
fs=new FileStream("Test.xml",FileMode.OpenOrCreate);
SoapFormatter bf=new SoapFormatter();
bf.Serialize(fs,rp);
}
catch(Exception err)
{
Console.WriteLine(err.Message);
}
finally
{
fs.Close();
}
}

private static void DeSerialize()


{
FileStream fs=null;
try
{
fs=new FileStream("Test.xml",FileMode.Open);
SoapFormatter sf=new SoapFormatter();
RadyoPersonel rp=(RadyoPersonel)sf.Deserialize(fs);
Console.WriteLine(rp.ToString());
}
catch(Exception err)
{
Console.WriteLine(err.Message);
}
finally
{
fs.Close();
}
}

Eer RadyoPersonel snfmz bu haldeyken uygulamamz altrrsak seriletirme ileminin


istediimiz gibi olmadn, hatta deserialize ilemi srasndada aadaki hata mesajn aldmz
grrz.

www.bsenyurt.com Page 1669


Bu hata mesajn ele almadan nce Xml dosyamza bakarsak, taban snfa ait yelerin null deerler
ile iaretlendiini, RadyoPersonel snfna ait hi bir yenin ise seriletirme ilemine dahil
edilmediini aka grebiliriz. Dolaysyla seriletirme ileminde de sre gelen bir problem sz
konusudur.

Burada problem udur. Taban snfmz olan RadyoKanal, ISerializable arayzn uygulam ve
seriletirme ilemi srasnda GetObjectData metodunu kullanarak yeleri stream ierisine
aktarmtr. Oysaki, ayn ilemin treyen snf tarafndanda yaplmas gerekmektedir.

ISerializable arayzn uygulam seriletirilebilir bir taban snftan tretme ilemi


yapldnda, treyen snfa ait nesne rneklerinin sahip olduu alanlarn baarl bir
ekilde seriletirilebilmesi iin, Temel snftaki GetObjectData prensibinin, treyen snf
ierisindede aka uygulanmas gerekir.

Bunu gerekletirmek iin taban snfa sanal bir metod (virtual method) ekleyebilir ve bunun
treyen snf ierisinde ezdirilmesini (override) salayabiliriz. lk olarak taban snfmza sanal
metodumuzu eklemeli ve bu metodu ISerializable arayznn uygulad GetObjectData metodu
ierisinde armalyz. Bu amala RadyoKanal snfmzda aadaki deiiklikleri yapmamz
gerekmektedir.

protected virtual void WriteData(SerializationInfo info, StreamingContext context)


{
}

public void GetObjectData(SerializationInfo info, StreamingContext context)


{
info.AddValue("Kanal Adi", _KanalAdi);
info.AddValue("Radyo Frekans", _Frekans);
info.AddValue("Muzik Turu", _MuzikTuru);
info.AddValue("Kanal Sahibi", _Sahip);
WriteData(info, context);

www.bsenyurt.com Page 1670


}

Dier yandan, treyen snfmz ierisinde bu sanal metodumuzu aadaki kod parasnda olduu
gibi ezmemiz gerekmektedir.

protected override void WriteData(System.Runtime.Serialization.SerializationInfo info,


System.Runtime.Serialization.StreamingContext context)
{
info.AddValue("Personel Numarasi", _PersonelNo);
info.AddValue("Personel Adi", _PersonelAd);
}

Bu haliyle uygulamamz altrdmzda yine yukardaki istisnay alrz. Ancak bu kez seriletirme
ileminde, treyen snfmza ait alanlarnda aktarldn grrz. Dolaysyla seriletirme ilemi
srasnda sre gelen problemi am durumdayz. Geriye DeSerialize ilemi srasnda oluan
problem kalmaktadr.

Tahmin edeceiniz gibi DeSerialize ilemi srasndaki problem, treyen snfn kendisine ait bir
DeSerialize Constructor metodu olmayndan kaynaklanmaktadr. Bu metod olmad iin
DeSerialize ilemi srasnda, hangi yeye hangi deerin hangi stream' den aktarlaca
bilinememektedir.

ISerializable arayzn uygulam seriletirilebilir bir taban snftan tretme ilemi


yapldnda, treyen snf iin DeSerialization ileminin baarl bir ekilde yaplabilmesi
iin, treyen snf ierisindede DeSerialize Constructor metodunun uygulanmas gerekir.

Bu problemi zmek iin, treyen snfmza aadaki constructor metodu eklememiz yeterli
olacaktr.

private RadyoPersonel(SerializationInfo info, StreamingContext context)


{
_PersonelNo = info.GetInt32("Personel Numarasi");
_PersonelAd = info.GetString("Personel Adi");
}

www.bsenyurt.com Page 1671


Uygulamamz bu haliyle baarl bir ekilde alacak ve hem Serialize hemde DeSerialize ilemlerini
baarl bir ekilde gerekletirecektir. RadyoKanal ve RadyoPersonel snflarnn son haline
aadaki UML emasndan daha kolay takip edebiliriz.

Bylece geldik bir makalemizin daha sonuna. Makalemiz boyunca gelitirdiimiz rnek
uygulamamzn son halini bu linkten indirebilirsiniz. Bir sonraki makalemizde grnceye dek,
hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Compact Framework zerinde RDA ile


Senkronizasyon ( 24.01.2006 ) - Mobile
Deerli Okurlarm Merhabalar,

Mobil uygulamalarda veri senkronizasyonu son derece nemlidir. rnein bir kurye firmasnn
datm elemann gz nne alalm. Mobil cihaz ile donatlm olan bu personelin grevi, kendisine

www.bsenyurt.com Page 1672


verilen teslimat bilgilerine gre, sipari sahiplerine rnlerini teslim etmektir. Her alma gnnn
banda, teslimat yapaca kiilerin bilgilerini ana sunuculardan mobil cihazna ykleyerek teslimat
iin hareket geen personel, tamamlanan teslimatlar annda veya belirli bir sre sonunda topluca
asl sunuculara gndererek gerekli gncelletirme ilemlerini yapar. Bu senaryo gerei personelin
teslimat bilgilerini dzenli olarak almas, tamamlanalar iaretlemesi ve son olarak bu bilgileri asl
sunucuya gndermesi gerekir.Bu noktada senaryonun iki ucunda yer alan sunucu ve mobil
tarafndaki veriler arasndaki gncellii eitli senkranizasyon mimarileri ile salayabiliriz.

Mobile uygulamalarda uzak sunucular (Server) zerindeki veriler ile yerel (Client/Mobil) veriler
arasndaki senkronizasyon ilemini iki farkl mimaride gerekletirebiliriz. Bunlardan birisi RDA
(Remote Data Access) dieri ise Merge Replication' dr. RDA kullanm Merge Replication' a
gre daha kolay olan bir mimaridir. Biz bu makalemizde RDA' y her ynyle incelemeye
alacaz. RDA mimarisi Sql Server 6.5 srm ve stn hedef almtr. RDA mimarisinde, mobil
platform ile uzak sunucu zerindeki veritaban arasnda senkronizasyon 3 teknikle salamaktr. Bu
teknikler Push, Pull ve SubmitSql teknikleridir. Bu tekniklere gemeden nce, RDA ' nn alma
ekli hakknda ksa bir bilgi vermekte fayda olaca dncesindeyim.

RDA mimarisinde istemci tarafnda yer alan Sql CE veritaban, Client Agent' kullanarak, sunucu
tarafndaki Sql Server CE Server Agent zerinden uzak Sql Server veritabanna eriebilir. Bu eriim
ift ynldr. stemci, sunucudan veri ekebilecei gibi, sunucuya veri gnderebilir. Hatta RDA
mimarisine zel olaraktan, sunucu zerinde dorudan sql ifadelerini altrabilir. Bu aslnda veri
gndermeye benzer bir ilemdir. Dier taraftan Push metodu ile, yerel veritabannda sadece
deiiklik yaplm satrlarn sunucuya gnderilmesi salanabilir. SubmitSql ile ise, dorudan
sunucu zerindeki verilerde deiiklik yaplmaktadr.

RDA mimarisinde ilemleri balatan her zaman mobil tarafndaki uygulamadr. Dier taraftan RDA,
HTTP zerinden IIS' i kullanarak Sql Server sunucularna gerekli yetkiler dahilinde eriebilir. RDA
mimarisini kullanabilmek iin sunucu tarafnda Sql Server CE Server Agent servisinin kurulu

www.bsenyurt.com Page 1673


olmas ve gerekli yaplandrma ayarlarnn oluturulmas gerekmektedir. Bu servis aslnda IIS
zerinde bulunan ve sscesa20.dll (Sql Server Compact Edition Server Agent 2.0) isimli IIS
API dll' ini kullanr. Sunucu zerinde alan bu servis, mobil tarafnda alanSql Server Client
Agent ile karlkl iletiimin salanmasnda nemli bir grev stlenmektedir. Dolayslay gerekli
senkronizasyonun salanmasnda nemli bir rol stlenir. Sql Server CE Server Agent' n sisteme
kurulmas bir takm basit ayarlamalar gerektirir. Bu ayarlamalarn nasl yapldna ilikin olarak
sevgili Tolga Gler' in daha nceki makalesindenyararlanabilirsiniz. Gerekli sistem entegrasyonu
salandktan sonra RDA ilemleri gerekletirilebilir.

RDA ilemleri iin ynetimli kod(Managed Code) tarafnda System.Data.SqlServerCe isim


alannda yer alan SqlCeRemoteDataAccess snf kullanlmaktadr. Bu snfa ait metodlar
kullanarak veri alma, veri ekme gibi ilemler gerekletirilebilir. Bu ilemler srasnda elbetteki
srekli bir balant gerekmektedir. Ancak bu sreklilik RDA mimarisinin srekli bir balant
gerektirdiini gstermez. Nitekim senkronizasyonun asl amalarndan biriside, aralnda belirli
aralklarla balant salanan yaplarda, istemci ve sunucu arasndaki veri btnln salamaktr.
Teorik olarak RDA mimarisine gre, veri aktarm srasnda balantnn kesildii durumlarda sistem,
balant tekrardan salayncaya kadar veri paketinin son gnderildii yeri aklnda tutar. Balant
tekrardan salanr salanmaz veriler kald yerden gnderilmeye devam eder.

RDA mimarisinde istemci tarafna veri ekmek iin Pull metodu, sunucu tarafna veri gndermek
iin Push metodu, sunucu zerinde dorudan sql cmlesi altrmak iin iseSubmitSql metodu
kullanlr. SqlCeRemoteDataAccess snfna ait olan bu metodlara ilikin temel zellikleri ve dikkat
edilmesi gereken noktalar yle sralayabiliriz.

Pull Push SubmitSql

LookUp tablolarn mobil tarafa Mobil tarafndan sunucuya veri


aktarlmasnda kullanlr.(Sadece gnderilmesinde bir baka
Dorudan sunucu zerinde sql
LookUp tablolar kullanlaca deyile var olan mobil bilgilerin
cmlesi altrabilir.
zaman Pull metodu ile sunucuda gncellenmesinde
gncelleme ilemi gerekmez.) kullanlr.

Pull ileminden nce mobil Pull metodu ile ekilen veriller Insert, Update, Delete ilemleri
tarafta yer alan ilgili tablo iin Tracking zellii aktif ise dnda geriye sonu kmesi
silinmelidir. Aksi durumda sadece deiiklikleri gndererek dndrmeyen sp' leride
istisna(Exception) alnr. kaynak kullanmn azaltr. altrabilir.

Sunucu tarafnda tracking


Eer Pull ile alnan tabloda ilemi yaplmayacandan,
gncelleme yaplacak ve Push ile gncelleme ileminden sonra Veri deiiklikleri dorudan
geri gnderiecek ise Tracking verilerin son hali iin tekrardan sunucu tarafnda yaplr.
zellii aktif hale getirilmelidir. Pull metodunu uygulamak
gerekebilir

Mobil tarafa alnacak her bir


tablo iin ayr ayr Pull metodlar
arlmaldr.

imdi RDA ilemlerini basit rnekler ile incelemeye alalm. ncelikle tm ilemlerimiz iin
SqlCERemoteDataAccess snfna ait nesne rneinin oluturulmas gerekmektedir. Bu nesne

www.bsenyurt.com Page 1674


rneinin InternetURL zellii ile, uzak sunucu zerinde sscesa20.dll dosyasn hizmete sunan
http adresi belirtilir. Bir baka deyile Sql Server CE Server Agent' a hangi adres ile eriilecei
belirtilmektedir. Bu mutlaka yaplmaldr.

RDA mimarisinde gvenlik IIS tarafnda ve Sql Server tarafnda nem kazanr. Eer Sql
Server CE Server Agent servisine erime ynetim olarak Anonymous Users gvenlii
seilmemi ise, belirli bir kullanc ad ve ifre ile balanabilmek
iin InternetLogin ve InternetPassword zellikleride set edilmelidir.

LocalConnectionString zellii ilede, mobil tarafnda kullanlacak olan balant bilgisi tanmlanr.
Bu balant bilgisi tipik olarak mobil cihaz zerindek Sql Server CE veritabanna balanmak iin
gereken balant bilgisidir. Buna gre SqlCERemoteDataAccess snfna ait bir nesne rneini
aadaki gibi oluturabiliriz.

private SqlCeRemoteDataAccess rda;

private void CreateRDAObject()


{
rda=new SqlCeRemoteDataAccess();
rda.InternetUrl="http://192.168.7.3/SQLCeRemote/sscesa20.dll";
rda.LocalConnectionString="Data Source=Ambar.sdf";
}

Bu rnek kod parasnda InternetURL bilgisinin ve LocalConnectionString bilgisinin nasl verildiine


dikkat edin. ( Buradaki sscesa20.dll' e ait url bilgisi ile yerele veritaban ad ver yolu kendi
sistemlerinizde daha farkl olabilir. )SqlCeRemoteDataAccess nesnesinin oluturulmasndan sonra,
Pull, Push ve SubmitSql metodlarn kullanabiliriz. Bu metodlar kullanmak iin, mutlaka uzak
sunucudaki veritabanna eriilecek balant bilgisi verilmelidir. Bu metodlarn rnek kullanmlarn
aadaki kod parasnda grebilirsiniz.

Pull;

private void Pull()


{
// Mobile taraftaki veritaban yok ise oluturulur. var ise silinip oluturulur.

rda.Pull("Musteriler","SELECT * From Customers","Provider=SqlOleDb;data


source=192.168.7.3;database=Northwind;uid=sa;password=1234",RdaTrackOption.TrackingOn);
rda.Dispose();
}

Pull metodunun uygulann grdnz yukardaki kod parasnda, ilk parametre ile mobile
tarafta yer alan veritabanndaki tablo ad belirtilir. kinci parametre uzak sunucudaki tablodan veri
ekmek iin altrlacak olan sql cmlesidir. nc parametrede ise, bu sorguyu altrabilmek
iin gerekli uzak sunucu balant bilgisi verilmektedir. ( Balant bilgisinin tanmlarken SqlOleDb
provider' nn setiimize dikkat edin.) Son olarak pull ileminden sonra eer gncelleme amacyla
Push ilemi uygulanacak ise, mobil tabloda olan deiikliklerin gnderilebilmesi amacyla izleme
zellii aktif hale getirilmitir.

www.bsenyurt.com Page 1675


Push;

private void Push()


{
// Mobile taraftaki veritaban zerinde eitli gncelleme ilemleri yaplr.

rda.Push("Musteriler","Provider=SqlOleDb;data
source=192.168.7.3;database=Northwind;uid=sa;password=1234",RdaBatchOption.BatchingOn);
rda.Dispose();
}

Push metodunun uygulann grdnz yukardaki kod parasnda, ilk parametre ile yerel tablo
belirtilir. Bu tablo, mobil cihaz zerinde yer alan veritaban uzarndaki tablo iaret edilir. kinci
parametre uzak sunucu zerindeki veritabanna eriebilmek iin gerekli balant bilgisini ierir. Son
parametre ise, tracking ilemi ile izlenen yerel tablo deiikliklerinin, sunucuya toplu olarak tek bir
transaction ierisinde gnderilip gnderilemiyeceini belirtmektedir.

SubmitSql;

private void SubmitSql()


{
rda.SubmitSql("Insert Into Personel (Ad,Maas) Values
('Burak',1000)","Provider=SqlOleDb;data
source=192.168.7.3;database=Northwind;uid=sa;password=1234");
rda.Dispose();
}

SubmitSql metodunun kullanln gsteren yukardaki rnek, balant bilgisi ile belirilenen uzak
veritaban zerinde basit bir insert ilemi gerekletirmektedir. Aadaki kod paras RDA
kullanmna ilikin genel bir rnei sunmaktadr. Bu rnekte, Northwind veritabannda yer alan
Region isimli tablodan Pull teknii ile veri ekilmesi, ekilen verinin Mobil form zerindeki bir
ListBox' a balanmas, belli bir satr zerinde gncelleme ileminin yaplarak Push metodu ile
sunucuya gnderilmesi ve dorudan sunucu zerinde rnek bir insert ileminin gerekletirilmesine
ilikin kodlamalar yaplmtr. Uygulamamz Pocket PC 2002(2003) Emulatorleri zerinde test
edilmi olan bir Smart Device Windows Applicationdr.

www.bsenyurt.com Page 1676


Uygulama Kodlarmz;

using System;
using System.Drawing;
using System.Collections;
using System.Windows.Forms;
using System.Data;
using System.Data.SqlServerCe;
using System.Data.Common;

namespace UsingRDA
{
public class Form1 : System.Windows.Forms.Form
{
private SqlCeRemoteDataAccess rda;
private System.Windows.Forms.ListBox lstRegions;
private System.Windows.Forms.Button btnPush;
private System.Windows.Forms.Button btnSubmitSql;
private SqlCeEngine cEngine;

private void CreateLocalDatabase()


{
// RDA Mimarisine zel olarak Pull ilemlerinden nce yerel veri taban dosyasnn silinmesi
gerekmektedir. Bu silme ilemi iin standart System.IO isim alannn File snfn kullanabiliriz.
if(System.IO.File.Exists("Ambar.sdf"))
{
System.IO.File.Delete("Ambar.sdf");
}
// Mobil taraftaki Sql Server Ce veritabann oluturmak iin System.Data.SqlServerCe isim
alannda yer alan SqlCeEngine snfn kullanyoruz. Bu snf ile var saylan olarak mobil cihazn root
klasrnde Ambar.sdf isimli veritaban dosyamz oluturmaktayz.
cEngine=new SqlCeEngine("data source=Ambar.sdf");

www.bsenyurt.com Page 1677


cEngine.CreateDatabase();
}

private void CreateRDAObject()


{
// SqlCeRemoteDataAccess nesnemizi oluturuyoruz. InternetURL zelliine Server Agen t'
n adresini, LocalConnectionString zelliine ise mobil veritabannn balant bilgisini veriyoruz.
rda=new SqlCeRemoteDataAccess();
rda.InternetUrl="http://192.168.7.3/CESrvAgent/sscesa20.dll";
rda.LocalConnectionString="Data Source=Ambar.sdf";
}

private void Pull()


{
CreateRDAObject();
// Pull ileminden nce mobil taraftaki veritabanmz silip(var ise) oluturuyoruz.
CreateLocalDatabase();
// Pull metodumuzu altryoruz.
rda.Pull("Bolgeler","SELECT RegionID,RegionDescription From
Region","Provider=SqlOleDb;data source=192.168.7.3;database=Northwind;uid=sa;passwor
d=1234",RdaTrackOption.TrackingOn);
// SqlCeRemoteDataAccess snfmza ait nesne rneimize ait bellek kaynan serbest
brakyoruz.
rda.Dispose();
}

private DataTable LoadToDataTable()


{
// Yerel veritabanna yklenen Regions tablosuna ait satrlar bir DataTable nesnesine
aktaryoruz. Burada amacmz gelen verileri Form zerindeki ListBox kontronde gstermek.
Bunun iin basit olarak SqlCeDataAdapter snfn kullanlyor.
DataTable dtRegion=new DataTable();
SqlCeDataAdapter daRegion=new SqlCeDataAdapter("Select
RegionID,RegionDescription From Bolgeler","data source=Ambar.sdf");
daRegion.Fill(dtRegion); // NOT : Fill ve dier SqlCeDataAdapter yelerini kullanabilmemiz
iin uygulamanza System.Data.Common isim alann aka referans etmemiz gerektiini
unutmaynz.
return dtRegion;
}

private void LocalChange()


{
// Ambar.sdf isimli yerel veritaban zerinden Bolgeler isimli tablodaki 2 numaral satrn
ieriini deitirecek bir update sorgusu altryoruz. Bu sorgu ile yaptmz yerel gncelleme
ilemini daha sonradan Push metodu ile sunucuyada gndereceiz.
SqlCeConnection conn=new SqlCeConnection("data source=Ambar.sdf");
SqlCeCommand cmdUpdate=new SqlCeCommand("UPDATE Bolgeler SET
RegionDescription='Western (Bat)' WHERE RegionID=2",conn);
try

www.bsenyurt.com Page 1678


{
conn.Open();
cmdUpdate.ExecuteNonQuery();
}
catch(SqlCeException excp)
{
MessageBox.Show(excp.Message.ToString());
}
finally
{
conn.Close();
}
}

private void Push()


{
CreateRDAObject();
// Simulasynon amacyla Yerel deiikliklerimizi yapyoruz.
LocalChange();
// Yerel olarak yaplan deiiklikleri uzak sunucu zerindeki veri kaynana aktaryoruz.
Bolgeler isimli yerel tablodan, yaplan deiiklikleri ki (sadece 2 numaral satra ait update ilemi
var), 192.168.7.3 ip adresindeki Northwind veritabanna aktaryoruz.
rda.Push("Bolgeler","Provider=SqlOleDb;data
source=192.168.7.3;database=Northwind;uid=sa;password=1234",RdaBatchOption.BatchingOn);
// SqlCeRemoteDataAccess snfmza ait nesne rneimize ait bellek kaynan serbest
brakyoruz.
rda.Dispose();
}

private void SubmitSql()


{
CreateRDAObject();
// Dorudan uzak sunucuya eriip, Region isimli tabloya yeni bir satr ekleyecek ekilde bir
sql sorgusunu uzak sunucu zerinde altryoruz.
rda.SubmitSql("Insert Into Region (RegionID,RegionDescription) Values
(5,'Marmara')","Provider=SqlOleDb;data
source=192.168.7.3;database=Northwind;uid=sa;password=1234");
// SqlCeRemoteDataAccess snfmza ait nesne rneimize ait bellek kaynan serbest
brakyoruz.
rda.Dispose();
}

private void BindToListBox()


{
lstRegions.DataSource=LoadToDataTable();
lstRegions.DisplayMember="RegionDescription";
lstRegions.ValueMember="RegionID";
}

www.bsenyurt.com Page 1679


private void Form1_Load(object sender, System.EventArgs e)
{
Pull();

// Pull metodu ile ektiimiz verileri yerel Sql Server Ce database' inden okuyup bir
DataTable' a aktardmz metodu kullanarak, listBox kontrolne balyoruz.
BindToListBox();
}

private void btnPush_Click(object sender, System.EventArgs e)


{
// nce yerel deiiklikleri sunucuya gnderiyoruz. Daha sonra sunucuda olan son hali
tekrardan mobil tarafa alyoruz.
Push();
Pull();
BindToListBox();
}

private void btnSubmitSql_Click(object sender, System.EventArgs e)


{
//nce dorudan uzak sunucu zerinde veri deiiklii yapyoruz. Sonra uzak sunucudan
son hali mobil tarafa alyoruz.
SubmitSql();
Pull();
BindToListBox();
}

// Form ile ilikili ilemler. Main, InitializeComponent vs...


}
}

rnek, RDA mimarisinin kolay anlalabilmesi amacyla ok fazla detay girmemitir. rnein,
try...catch ile exception ynetim mekanizmas daha da geniletilebilir, Region tablosuna girilecek
verilere ait bilgiler form zerindeki kontrollerden alnabilir...vb...

RDA mimarisinin uygulanna ilikin geni bir rnee ait Smart Device Application
Solution' buradan indirebilirsiniz.

Buraya kadar anlatklarmzdan yola karaktan RDA mimarisinin belirli avantajlarn ve


dezavantajlarn u ekilde sralayabiliriz.

Avantajlar DezAvantajlar

Sunucu tarafndaki veri kaynlar daha az Sunucu zerindeki deiiklikler izlenmemektedir.


kullanlr. (Bu fark zellikle Merge Replication Bunun yerine sadece istemci tarafndaki

www.bsenyurt.com Page 1680


mimarisine gre belirgin derecede azdr. deiikler izlenir.

Sql Server 6.5 ve zeri sql sistemlerini zellikle Pull ileminden nce istemci tarafndaki
destekler. (Sql CE zerindeki) tablolar silinmek zorundadr.

RDA iin gerekli sistem entegrasyonunun stemci tarafna alnacak her bir tablo iin ayr
yaplmas kolaydr. ayr Pulling ilemi gerektirir.

Bylece geldik bir makalemizin daha sonuna. zleyen makalelerimizde, Merge


Replication mimarisini incelemeye alacaz. Uygulanmas ve hazrl RDA mimarisine gre biraz
daha zor olan Merge Replication mimarisinin avantajlarn ve dezavantjlarn greceiz. Bu
makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Web Uygulamalarnda zel Dorulama


lemleri ( 14.01.2006 ) - Asp.Net
Deerli Okurlarm Merhabalar,

Web uygulamalarnda, kullanclarn girmi olduu verilerin istenen artlara gre doruluklarnn
kontrol edilmesi son derece nemlidir. Asp.Net ile gelitirilen web uygulamalarnda, kullanc
girilerinin kontrol iin ounlukla validation kontrolleri kullanlr. Validation bileenleri hem
istemci tarafnda hemde sunucu tarafndan veri kontrol ilemlerini gerekletirebilir. (Bu makaleyi
daha kolay takip edebilmeniz asndan var olan Validator kontrollerinin kullanmn bildiiniz
varsaylmaktadr.)

Temel olarak bir verinin doruluunun Validator bileenleri ile kontrol ilemi, eer istemci
script altrlmasna izin veriyorsa, nce istemci tarafnda client script' ler yolu ile
gerekletirilir. stemci tarafnda kontrol yaplsada, yaplmasada mutlaka ve mutlaka
server tarafnda da bir dorulama ilemi gerekletirilmektedir.

Temel dorulama ilemlerinde, girilen verinin belli bir formata uygun olup olmad (rnein geerli
bir mail adresi olup olmad), bo olup olmad, herhangibir deerden kk, byk, eit vb...
olup olmad ve benzeri durumlar kontrol edilir. Gerek udurki, var olan Validation kontrolleri ile
hemen hemen her tr dorulama ilemini gerekletirebiliriz. Ancak baz durumlarda veri zerinde
dorulama ilemleri iin zel algoritmalara ihtiyacm olabilir. rnein, girilen verinin uygun bir
kredi kart numaras olup olmadnn kontrol edilmesini salayan bir algoritmay, bir validation
kontol ierisinde kullanmak isteyebiliriz. Yada birden fazla dorulama ilemini bir arada sunmak
isteyebiliriz. te bu ve benzer durumlar iin Asp.Net, CustomValidator isimli bir bileen
iermektedir. Bu bileen yardmyla sunucu ve istemci tarafnda alacak zel kontrol
algoritmalarmz veya srelerimizi, eitli veri giri kontolleri ile ilikili olacak ekilde yazabiliriz.
Bu makalemizde, basit olarak Lhun algoritmas yardmyla kredi kart dorulama kriterini uygulayan
bir CustomValidator rnei gelitireceiz. Uygulamamz sadece Lhun Algoritma kontroln
yapacak.

www.bsenyurt.com Page 1681


CustomValidator kontrolmz kullanmaya balamadan nce, ksaca Lhun algoritmas hakknda da
bilgi vermekte fayda olaca kansndaym. Lhun algoritmas basit olarak kredi kart gibi saysal
ifadelerin doruluunu kontrol etmek amacyla kullanlan bir matematik algoritmasdr. Bu
algoritmaya "mod 10 algoritmas" da denmektedir. Basit olarak bir dizi matematiksel ilem ile,
verinin uygun bir kredi kart numaras olup olmad tespit edilir. Eer kredi kart numaras uygun
ise, sradaki dier ilemlere geilebilir.

Lhun algoritmas sadece girilen saysal ifadenin uygun bir kredi kart numaras olup
olmadn belirten bir model sunar. stemci tarafndan girilen kredi kart numarasnn
doru olmas sadece numarann dnya apnda kabul grm bir algoritma ile
dorulanabildiini gsterir. Oysaki, girilen kredi kart numarasnn geerlilik sresinin, kart
sahibinin isminin ve CVV2 gibi dier kriterlerin kontrolde gerekir ki bu tamamen ayr bir
sretir.

Ksaca Lhun algoritmas u ekilde alr.

1 - lk olarak kredi kart numarasnn en sa ikinci dijitinden balanarak srasyla sola doru
ilerlenir. (Kod yazlrken bunu gz ard edip soldan ikinci dijitten balayp ikier ikier de
atlayabiliriz. ) kier ikier atlanrken her bir dijitin iki kat hesap edilir. Elde edilen sonulardan
deeri 10 ve 10' dan byk olanlar var ise bunlarn basamaklar toplanr ve dier 10' dan kk
olan deerler eklenerek bir toplam deeri elde edilir.

2 - Daha sonra, iki kat alnan dijitlerin dnda kalan dijitler ele alnr ve bu dijitler bir birleriyle
toplanarak bir toplam deeri daha elde edilir.

3 - Son olarak 1nci ve 2nci ilemlerdeki toplamlarn toplam alnr ve sonucun 10 ile blnp
blnmediine (bir baka deyile mod 10' un sfr olup olmadna) baklr. Eer 10 ile tam
blnebiliyorsa bu say dizisi bir kredi kart numarasdr. Olay daha iyi anlamak iin rnek bir 16
haneli say dizisini ele alalm.

www.bsenyurt.com Page 1682


Burada 1234 5678 9876 5432 say dizisinin geerli bir kredi kart numaras olup olmadnn Lhun
algoritmasna gre nasl tespit edilebildiini grmektesiniz. Dikkat ederseniz sonu 10 ile tam
olarak blnemediinden say dizisi geerli bir kredi kart numarasn temsil etmemektedir. Sahip
olduunuz kredi kartlar zerinde yukardaki algoritmay deneyebilir ve sonularn irdeleyebilirsiniz.
unuda belirtmekte fayda vardr ki, dnya apnda kullanlan eitli tipte kredi kartlar mevcuttur.
rnein master card, visa gibi. Bunlarnda kendilerine has bir takm say dizisi kurallar vardr.
rnein bir master card' a ait kredi kart numarasnn ilk iki hanesi, 55 yada 50 olmak zorundadr.
Bu, kartn bir master card olduunun iaretidir. Konumuz validation ilemlerinin CustomValidator
kontrol ile nasl gerekletirilebileceini incelemek olduundan, Lhun algoritmas zerinde daha
fazla durmayacaz.

Gelelim bu algoritmay kullanacamz uygulama kodlarmza. CustomValidator kontrolmz sradan


bir Validator kontrolnden farkszdr. Sadece kontrol ileminin yaplaca olay metodlarn hem
client(istemci) tarafnda hem de sunucu(server) tarafnda kendimiz yazmamz gerekmektedir.
Elbette istemci tarafnda bir kontrol kodu yazmak zorunda deiliz. Ancak sunucu tarafnda mutlaka
yazmalyz. Aksi takdirde dorulama ilemlerini gerekletiremeyiz. Server tarafnda yazlan kodlar,
ServerValidate olay metodunda ele alnr. Client tarafnda yazlacak olan script kodlarn yer alaca
fonksiyon ise, ClientValidationFunciton zelliinde belirtiriz.

Normalde, dier Validator kontrolleri, client script zellikleri kapatlmad takdirde,


istemci tarafnda alacak script kodlarn otomatik olarak retmektedir. Ancak
CustomValidator kontrol sz konusu olduunda, istemci tarafnda alacak script
kodlarnda manuel olarak yazmamz gerekmektedir.

ServerValidate metodunun ServerValidateEventArgs parametresi, kontrol edilecek bileene ait


zelliin deerini temsil eder. rnein kredi kart numarasnn girilecei TextBox bileeninin, Text
zelliinin deerini bu parametrenin Value zellii ile metod ierisinde alabiliriz. Bu parametrik yap
client tarafnda alacak script metodu iinde geerlidir. Bizim rnek kodumuzda yapacamz
kontroller srasyla, girilen say dizisinin 16 haneli olduu, sadece saylardan olutuu ve Lhun
algoritmasn salayp salamaddr. Default.aspx sayfamzn tasarm aadaki gibi
olacaktr. (rneimiz Asp.Net 2.0 platformunda gelitirilmitir.)

CustomValidator bileenin ControlToValidate zellii, TextBox bileenine ayarlanmtr. Nitekim


dorulama ilemi iin TextBox kontrolmz ele alnacaktr. Son olarak, Kontrol balkl butonumuz
sadece sayfay postback etmek ve bu sayede server tarafndaki dorulama srecine geebilmek
amacyla kullanlmaktadr. Yani herhangibir kod iermemektedir. Sadece postback ilemini salar.
lk olarak ServerValidate olay metodunu aadaki gibi kodlayalm.

protected void custVldtr_ServerValidate(object source, ServerValidateEventArgs args)


{
#region Hane Says Kontrol

if (args.Value.Length != 16)
{

www.bsenyurt.com Page 1683


// Hata mesaj deitirilir.
custVldtr.ErrorMessage = "Kart numaras 16 haneli olmaldr.";
args.IsValid = false; // Validation ilemi geersizdir.
return; // Metoddan klr.
}

#endregion

#region Saysal deer kontrol

for (int i = 1; i < args.Value.Length; i++)


{
if (!char.IsDigit(args.Value[i]))
{
// Hata mesaj deitirilir.
custVldtr.ErrorMessage = "Sadece saysal deer girilmelidir.";
args.IsValid = false; // Validation ilemi geersizdir.
return; // Metoddan klr.
}
}

#endregion

#region Lhun Kontrol

List<int> kartNumarasi = new List<int>();


List<int> ciftKartNumaralari = new List<int>();
int toplam1=0,toplam2 = 0;

// TextBox' a girilen string formattaki kart numarasina ait say dizisinin her bir eleman List
tipinde int' deerler tutan generic kartNumarasi isimli koleksiyona aktarlr.
for (int i =0;i<args.Value.Length;i++)
{
kartNumarasi.Add(Convert.ToInt16(args.Value[i].ToString()));
}

// ilk olarak iki kat hesaplamas ve kan saylarn toplam ilemi yaplr.
for (int i =0; i <kartNumarasi.Count; i =i+ 2)
{
ciftKartNumaralari.Add(kartNumarasi[i] * 2);
}

for (int i = 0; i < ciftKartNumaralari.Count; i++)


{
if (ciftKartNumaralari[i] > 9)
{
string var = ciftKartNumaralari[i].ToString();
toplam1 += Convert.ToInt16(var[0].ToString()) + Convert.ToInt16(var[1].ToString());
}

www.bsenyurt.com Page 1684


else
{
toplam1 += ciftKartNumaralari[i];
}
}

// iki kat hesab dnda kalan elemanlarn toplam hesaplanr.


for (int i = 1; i < kartNumarasi.Count; i += 2)
{
toplam2 += kartNumarasi[i];
}

// Genel toplam alnr ve 10 ile tam blnp blnmediine baklr.


int toplam = toplam1 + toplam2;
if (toplam % 10 == 0)
{
args.IsValid = true; // hata mesaj dndrlmez. Validation ilemi geerlidir.
}
else
{
// Hata mesaj deitirilir.
custVldtr.ErrorMessage = "Geersiz kredi kart numaras girdiniz.";
args.IsValid = false; // Validation ilemi geersizdir.
}

#endregion
}

ServerValidate metodu geri dn deeri olmayan bir metoddur. ServerValidateEventArgs


parametresi sayesinde, ControlToValidate zellii ile balanan kontroln (ki burada TextBox
kontroldr) dorulama srecine girecek deerine eriilmektedir. Bu parametrenin IsValid zellii
bool tipinden bir zelliktir ve dorulama ileminin doruluunu belirtmektedir. True deerini ald
takdirde dorulama geerlidir. False deerinde ise dorulama ilemi geersizdir. Dorulama ilemi
geersiz olduu takdirde uygulama ileyiini durduracak ve hata mesaj ile kullanc
bilgilendirilecektir. Bu sayede izleyen srelerinde tutarlln salam oluruz. ServerValidate
metodumuz Server(sunucu) tarafnda almaktadr. Uygulamamz bu haliyle altrdmzda
aadaki Flash animasyonunda grlen sonular elde ederiz.

(Not : Aadaki grnty seyredebilmek iin taraycnzda Flash Player' n son srmnn olmas
tavsiye edilir. Eer sisteminizde XP Service Pack 2 yklyse ilgili uyary dikkate alp ierie izin
vermelisiniz. (Allow Blocked Content). Videoyu ynetmek iin sa tklayp kan meny
kullanabilirsiniz.)

www.bsenyurt.com Page 1685


Dikkat ederseniz, sayfa sunucuya geri gnderildikten sonra dorulama ilemi devreye girmektedir.
u anda client(istemci) taraf iin bir script kodu yazmadmzdan, normal dorulama srecine ait
olan istemci kontrol ksm otomatik olarak devre ddr. Oysaki ou zaman sunucuya geri
dnlmeden istemci tarafnda kontroller yapmak isteyebiliriz. Ancak .Net dorulama sistemi gz
nne alndnda istemci tarafnda herey doru olsa bile, sunucu tarafnda yinede dorulama
ilemi gerekletirilmektedir. O halde client(istemci) tarafnda yaplan dorulamann ne gibi bir
avantaj olabilir? stemci tarafnda yaplan dorulama ile, sunucuya gereksiz yere gidip gelme
ileminin nne gemi oluruz.

Hatrlatma; Dorulama sreci u ekilde iler.

www.bsenyurt.com Page 1686


imdi CustomValidator kontrolmz iin bir de client(istemci) script kodunu ekleyelim. Bu amala
javascript kullanmay setiimizi dnecek olursak tek yapmamz gereken aspx sayfamza
aadaki script kodlarn eklemek olacaktr.

<script type="text/javascript">
function ValidateCreditCard(sender,args)
{
if (args.Value.length != 16)
{
alert("Kart numaras 16 haneli olmaldr.");
args.IsValid = false;
return;
}

var rakamlar = '0123456789';

for (i=0; i<args.Value.length; i++)


{
if (rakamlar.indexOf(args.Value.charAt(i),0) == -1)
{
alert("Sadece saysal deerler girilebilir.");
args.IsValid=false;

www.bsenyurt.com Page 1687


return;
}
}

var toplam=0;
for (i=0; i < args.Value.length; i++)
{
var numara=args.Value.charAt(i);
if (i % 2 == 0)
numara=numara * 2;
if (numara > 9) numara=numara - 9;
toplam = toplam + parseInt(numara);
}
if(toplam % 10!=0)
{
alert("Geersiz kredi kart.");
args.IsValid=false;
return;
}
}
</script>

CustomValidator kontrolmzn aspx tarafndaki kodlar ise aadaki gibidir.

<asp:CustomValidator ID="custVldtr" runat="server" ControlToValidate="txtCreditCardNumber"


OnServerValidate=custVldtr_ServerValidate" ClientValidationFunction="ValidateCreditCard">
</asp:CustomValidator>

stemci tarafnda alan uygulamamz aadaki flash animasyonunda daha kolay izleyebilirsiniz.

(Not : Aadaki grnty seyredebilmek iin taraycnzda Flash Player' n son srmnn olmas
tavsiye edilir. Eer sisteminizde XP Service Pack 2 yklyse ilgili uyary dikkate alp ierie izin
vermelisiniz. (Allow Blocked Content). Videoyu ynetmek iin sa tklayp kan meny
kullanabilirsiniz.)

www.bsenyurt.com Page 1688


stemcilerin doas gerei, her zaman client tarafnda alacak script' lere izin verilmez. stemci
tarafnda alan dorulama script' leri, sunucuya doru yaplan gidi-geli ilemlerinin saysn
azaltan bir etkendir; ki buda a zerindeki gereksiz yk azaltr. Ancak baz istemcilerin, script
altrma izni olmadn iin, sunucu tarafnda dorulama ilemi yaplmas gereklilii sz
konusudur. Biz rneimizde CustomValidator kontrol iin hem istemci tarafnda hem de server
tarafnda dorulama ilemini uygulayabileceimiz iki metod kullandk. Bylece istemci izin veriyorsa
dorulamaya o tarafta yapp gereksiz a ykn azaltm olduk. zel algoritmalar ieren veya
birden fazla dorulama ilemini bir kontrol zerinde birletirmek istediimiz durumlarda
CustomValidator kontrol olduka iimize yaramaktadr. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Windows Uygulamalarnda Daha Kolay Thread


Ynetimi ( 05.01.2006 ) - .Net 2.0
Deerli Okurlarm Merhabalar,

Windows uygulamalarnda, arka planda alan i paralarnn (process) ok uzun srd durumlar
ile ska karlarz. Bu gibi durumlarda genellikle kullanc ekran (UI - User Interface) ksa
sreliine de olsa arka plan ilemleri tamamlanncaya kadar donar. Bunun nne gemek iin
Thread snflarn kullanabiliriz. Ancak .Net 2.0 ile birlikte windows uygulamalarnda arka planda
asenkron olarak altrlabilecek tipteki ilemleri kolayca
ynetebileceimiz BackgroundWorker isimli yeni bir grsel bileen gelmektedir. Bu makalemizde
bu bileen yardmyla, UI kitlenmelerine neden olacak tarzdaki sreleri nasl ynetebileceimizi
grmeye alacaz.

www.bsenyurt.com Page 1689


BackgroundWorker bileeni alma zamannda, asenkron olarak ilem yrtebilmemizi ve
bu sayede kullanc ekrannn gereksiz ekilde donmasn (freeze) engellemek amacyla
kolay ve gl bir sre ynetimi sunar.

Hereyden nce, bir windows uygulamasnda zellikle kullanc arayzn (user interface) uzun
sre duraksatabilecek, bir baka deyile kullancnn arabirim zerindeki herhangibir kontrol ile
etkileimini geici sre engelleyebilecek durumlarn neler olabileceini dnmekte fayda vardr.
Duraksatmaya neden olacak rnek durumlar aadaki tabloda verilmitir.

Ekran Donmalarna Neden Olabilecek Durumlar

Youn veritaban ilemleri. rnein CRUD ilemleri


srasnda.

Dosyalara ilikin download ve upload ilemlerinde.

Web servislerine ait metodlarn yrtlmesinde.

Resim dosyalarnn uygulama ortamna yklenmesinde.

BackgroundWorker bileeni, ilgili i parasn asenkron olarak yrtebilme ve anlk olarak durum
bilgisini verebilme (progress status) gibi imkanlar sunmaktadr. Bu nesneye ait 3 nemli olay
bulunmaktadr. Bunlar DoWork, ProgressChanged, RunWorkerCompleted olaylardr. DoWork
olay, asenkron olarak yrtlecek kodlarn yer ald ilemleri ele alr. Asenkron olarak yrtlen
ilemler almaya devam ederken, kullanc arayz(UI) herhangibir ekilde donmaz ve kullanc
aktivitelerine cevap vermeye devam eder. Yrtlen i paras sonlandnda ise,
RunWorkerCompleted olay tetiklenir. Bunu, asenkron olarak yrtlen sre sonlandnda
devreye giren callback metodu olarakta dnebilirsiniz. RunWorkerCompleted metodu sadece
ilemler tamamlandnda deil, iptal edildiinde (cancel) veya bir exception sonucu ilemler
kesildiinde de devreye girer. ProgressChanged olay ise, asenkron olarak yrtlen i parasnn
anlk durumunu bildirmek amacyla kullanlabilir.

BackgrounWorker bileeninin en nemli metodu RunWorkerAsync' dir. Bu metod, DoWork olayn


tetikleyerek, asenkron olarak yrtlmek istenen komutlarn devreye girmesini salamak gibi
nemli bir rolu stlenir. Dilersek RunWorkerAsync metodundan, DoWork olay metoduna ortam
parametresi tayabiliriz. Bu nemlidir nk ou zaman, asenkron yrtlecek i paralarna ait
kodlar, d parametreler bamldr. Benzer ekikde DoWork olayndan da ilemler bittiinde
tetiklenen RunWorkerCompleted olayna parametre aktarmn yapabiliriz. (rnein sre sona
erdiinde elde edilen sonularn aktarlmas gibi.)

Bileenin kullanmn daha kolay anlayabilmek iin basit bir rnek zerinden makalemize devam
edeceiz. Bir windows uygulamamz olduunu ve arka planda son derece uzun srebilecek bir
operasyonu gerekletirmeye altmz dnelim. rnein matematiksel bir uygulamada 1' den
1000' e kadar olan elemanlarn karelerinin toplamna ihtiyacmz olduunu dnelim.

zellikle Asenkron olarak yrtlecek bir veya daha fazla sql komutunun sz konusu
olduu veritaban operasyonlarnda bir windows uygulamas kullanlyor ise,
BackgroundWorker bileeni yerine, asenkron komut yrtme tekniklerinin (polling,

www.bsenyurt.com Page 1690


callback, wait modelleri) ele alnmas tercih edilmelidir. Nitekim BackgroundWorker nesne
rnekleri ile, sql komutlarnn asenkron ynetimi sanld kadar kolay deildir.

Konuyu en basit haliyle anlamak iin aadaki rnei gelitirelim. Windows uygulamamz aadaki
ekran grntsne sahip olan tek bir Form' dan olumaktadr. Hesapla balkl butona basldnda,
1' den 1000' e kadar olan saylarn karelerinin toplamnn bulunduu sre, arka planda
altrlmaktadr. ptal balkl button kontrolmz ise, almakta olan arka plan ilemini iptal
etmek iin kullanlr. Uygulamamzda bir adet TextBox ve ProgressBar kontrolmz yer alyor. Bu
kontrollerden TextBox kontrolmz, ilemler hesap edilirken kullancnn ekran ile etkileebildiini
gstermek amacyla kullanmaktayz. ProgressBar kontrolmz ise, arka planda yaplan
hesaplamann hangi konumda olduunu yzdesel olmamakla birlikte vurgulamaya almak iin
kullanyoruz. Elbette, 1' den 1000'e kadar olan saylarn karelerinin toplamn hesap etmek anlk bir
ilemdir. Biz sreci uzatmak iin kk bir hile yapacaz. Bu hilede amacmz sreci yeterince
uzatmak olduu iin, hesaplamar arasnda 10 milisaniyelik gecikme sreleri koyacaz.

Uygulama kodlarmz ve aklamalar aada yer almaktadr.

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.SqlClient;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace UsingBackGroundWorkerProcess
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

www.bsenyurt.com Page 1691


//Hesaplama ilemini yaptmz metod. ptal ilemini burada ele alabilmek iin DoWork
olayndan buraya DoWorkEventArgs parametresinide gnderiyoruz.
private double Compute(int endValue, DoWorkEventArgs e)
{
double Total = 0;
for (int i = 1; i <= endValue; i++)
{
// Eer iptal ilemi iin btnComputeCancel kontrolne baslmsa, BackgroundWorker
snfnn CancelAsync metodu altrlm demektir. Bu durumda, BackgroundWorker nesnesine bir
iptal talebi (Cancel Request) gider. Bu if yapsnda bunu kontrol ederek hesaplama ileminin iptalini
gerekletiriyoruz.
if (bgwProcess.CancellationPending == true)
{
e.Cancel = true;
}
else
{
// Hesaplama ileminden sonra, sreci biraz daha uzatabilmek iin arka planda
alan thread' imizi 10 milisanine kadar duraksatyoruz. Bu sadece olaylar izlemeyi kolaylatrmak
iin yaplm bir hile. Nitekim bize gerekten arka planda uzun sren bir ilem gerekiyor.
Total += i * i;
System.Threading.Thread.Sleep(10);
// ReportProgress metodu ile hesaplanan deeri, raporlama amac ile
ProgressChanged olayna gnderiyoruz.
bgwProcess.ReportProgress(i);
}
}
return Total;
}

// DoWork olaymz, hesaplamalarn arka planda yrtlmesini ve ilem sonucunun


DoWorkEventArgs parametresinin Result zelliine atanmasn salar. Sre sona erdiinde,
RunWorkerCompleted metodunda bu result zelliinin deerini alabiliriz.
private void bgwProcess_DoWork(object sender, DoWorkEventArgs e)
{
e.Result=Compute(Convert.ToInt32(e.Argument),e);
}

// RunWorkerCompleted olay, arka plan sreci tamamlandnda devreye girmektedir.


Burada basit olarak ileme ait iptal talebi (Cancel Request) olup olmad kontrol edilir ve yoksa
sonu kullancya bir MessageBox yardmyla bildirilir. Bu metodu asenkron olarak alan bir
ilemin tamamlanmas sonras devreye giren Callback metodu olarak dnebilirsiniz.
private void bgwProcess_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
MessageBox.Show("leminiz iptal edildi...");

www.bsenyurt.com Page 1692


pgbStatus.Value = 0;
txtFreeZone.Text = "";
}
else
{
MessageBox.Show(e.Result.ToString());
}
btnComputeCancel.Enabled = false;
btnComputeStart.Enabled = true;
}

private void btnCompute_Click(object sender, EventArgs e)


{
pgbStatus.Maximum = 1000;
pgbStatus.Minimum = 0;
pgbStatus.Value = 0;
// Hesaplama ileminin arka planda asenkron olarak yrtlmesini balatan metod arlr.
Dikkat ederseniz metodumuza birde parametrik deer gnderiyoruz.
bgwProcess.RunWorkerAsync(1000);
btnComputeCancel.Enabled = true;
btnComputeStart.Enabled = false;
}

private void btnComputeCancel_Click(object sender, EventArgs e)


{
// Arka planda yrtlen ileme, iptal talebini (cancel request) CancelAsync metodu ile
gndermekteyiz.
bgwProcess.CancelAsync();
btnComputeCancel.Enabled = false;
btnComputeStart.Enabled = true;
}

private void Form1_Load(object sender, EventArgs e)


{
btnComputeCancel.Enabled = false;
}

// Bu olay ile, anlk olarak arka planda devam eden ilemin hangi aamada olduunu ele
alabiliriz. lgili deeri ProgressChangedEventArgs parametresinin ProgressPercentage zellii ile
alyoruz. Bu deer aslnda Compute fonksiyonu ierisinde, ReportProgress metodu ile gnderdiimiz
deerin aynsdr. stenirse, burada bu deere gre yzdesel gsterimler de yaplabilir.
private void bgwProcess_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
pgbStatus.Value = e.ProgressPercentage;
}
}
}

www.bsenyurt.com Page 1693


Uygulamamz bu haliyle altrdmzda aadaki Flash videosunda grlen sonular elde ederiz.

(Not : Aadaki grnty seyredebilmek iin taraycnzda Flash Player' n son srmnn olmas
tavsiye edilir. Eer sisteminizde XP Service Pack 2 yklyse ilgili uyary dikkate alp ierie izin
vermelisiniz. (Allow Blocked Content). Videoyu ynetmek iin sa tklayp kan meny
kullanabilirsiniz.)

Grdnz gibi, Windows uygulamalarnda arka planda alacak ilemleri ynetmek iin
BackgroundWorker bileeni olduka byk kolaylklar salamaktadr. Aslnda u bir gerektir ki,
ayn ilevsellii Thread nesnelerini kullanaraktanda yapabilmekteyiz.

ok Kanall Programlama ve Threading hakknda daha fazla bilgi iin bkz; ok


Kanall(Multithread) Uygulamalar, Thread'leri Belli Sreler Boyunca Uyutmak ve
Yoketmek,Thread'lerde ncelik(Priority) Durumlar, e Yarar Bir MultiThreading(ok
Kanall) Uygulama rnei

Aslnda Windows uygulamalarn hedef alan bu gelimenin, thread ynetimini kolaylatrc bir
yenilik olduunu dnebiliriz. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Generic Mimaride Kstlamalarn(Costraints)


Kullanm ( 31.12.2005 ) - C# 2.0
Deerli Okurlarm Merhabalar,

Bu makalemizde .Net 2.0 ile birlikte gelen Generic mimarisinin uygulannda, kstlamalarn roln
basit rnekler ile incelemeye alacaz. Generic mimari her ne kadar tr bamsz algoritmalarn
gelitirilmesine izin versede, baz durumlarda eitli zorlamalarn uygulanmasnda gerektirir.
rnein generic olmas planlanan tiplerin sadece referans tipleri ile almasn isteyebiliriz. Generic
bir tipe her hangibir zorunluluk kuraln uygulayabilmek iin where anahtar szcn ieren bir ek
ifade kullanlr. Bu ifadeler 5 adettir ve aadaki tabloda gsterilmektedir.

www.bsenyurt.com Page 1694


Koul Syntax

Deer tipi olma zorunluluu where Tip : struct

Referans tipi olma


where Tip : class
zorunluluu

Constructor zorunluluu where Tip : new()

where Tip : <Temel


Treme zorunluluu
Snf>

Interface zorunluluu where Tip : <Interface>

lk olarak struct ve class zorunluluklarn incelemeye alacaz. Bu kstlamalar, Generic bir tip
ierisinde yer alan tiplerin deer tr veya referans trlerinden mutlaka ve sadece birisi olmasn
istediimiz durumlarda kullanrz. Generic' lik, uyguland tip iin tr bamszln ortaya koyan
bir yapdr. Generic mimari sayesinde bir tipin alma zamannda kullanaca yelerin trn
belirleyebiliriz. Ancak, hangi tr olursa olsun, ya deer tr ya da referans tr sz konusu
olacaktr. te kstlamalar kullanarak, generic mimari zerinde referans trm yoksa deer
trm olacan belirleyebiliriz. Konuyu daha iyi anlayabilmek iin u rnei gz nne alalm.
Bildiiniz gibi C# 2.0 beraberinde, Framework 1.1 ile gelen koleksiyonlarn generic karlklarn da
getirmitir. Generic koleksiyonlarlar alma zamannda sadece belirtilen trden nesneleri kullanr.
Doal olarka ya deer trlerini ya da referans trlerini kullanlar. Peki ya generic bir koleksiyonun
sadece deer trlerini tamasn istersek ne yapabiliriz. Bir ekilde T tipinin sadece deer tr
olmas zorunluluunu bildirmemiz gerekecektir. Aadaki emada BenimKoleksiyonum isimli zel
bir koleksiyon tanm yer almaktadr. BenimKoleksiyonum isimli generic snfmz ieride List
trnden bir generic koleksiyonu kullanmaktadr.

public class BenimKoleksiyonum<T> :IEnumerable<T>


{
private List<T> icListe = new List<T>();

public void Ekle(T urun)

www.bsenyurt.com Page 1695


{
icListe.Add(urun);
}

public T Oku(int indis)


{
return icListe[indis];
}

#region IEnumerable<T> Members

public IEnumerator<T> GetEnumerator()


{
return icListe.GetEnumerator() ;
}

#endregion

#region IEnumerable Members

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return icListe.GetEnumerator();
}

#endregion
}

Burada snfmz ierisinde yer alan icListe isimli List tipinden generic koleksiyonumuz, T trnden
elemanlar ile i yapacak ekilde tasarlanmtr. Ayn ekilde, Ekle, Oku ve GetEnumerator
metodunun bir versiyonuda sadece T tipinden elemanlar zerinde i yapmaktadr. imdi
BenimKoleksiyonum snfna ek olarak aada bilgileri verilen iki yapmz(struct) olduunu
dnelim.

Dvd.cs ve Kitap.cs;

www.bsenyurt.com Page 1696


struct Kitap
{
private string mBaslik;
private double mFiyat;

public Kitap(string baslik, double fiyat)


{
mBaslik = baslik;
mFiyat = fiyat;
}
public override string ToString()
{
return mBaslik + " " + mFiyat;
}
}

struct Dvd
{
private string mBaslik;
private double mFiyat;
private int mSure;

public Dvd(string baslik, double fiyat,int sure)


{
mBaslik = baslik;
mFiyat = fiyat;
mSure = sure;
}
public override string ToString()
{
return mBaslik + " " + mFiyat+" "+mSure;
}
}

Diyelimki BenimKoleksiyonum isimli snfn uygulama ierisinde sadec yukarda bilgileri verilen
Kitap, Dvd ve ileride bunlar gibi gelitirilebilecek baka struct' lar ile ilgili ilemler yapmasn
istiyoruz. Yani asla ve asla referans tiplerinin kullanmasn istemediimizi dnelim. Bu durumda
tek yapmamz gereken ey BenimKoleksiyonum isimli snfa bir generic Constraint uygulamaktr.

public class BenimKoleksiyonum<T> :IEnumerable<T> where T:struct

Nasl ki generic tipi deer trnden olmaya yukardaki sz dizimde olduu gibi zorlayabiliyorsak,
ayn ii referans trlerine zorlamak iinde yapabiliriz. Tek yapmamz gereken struct yerine class
anahtar szcn kullanmak olacaktr.

public class BenimKoleksiyonum<T> :IEnumerable<T> where T:class

Struct zorlamasn kullandmz takdirde eer ki, BenimKoleksiyonum snfn kod ierisinde
herhangibir referans tr ile kullanmaya alrsak (rnein string referans tr ile) derleme
zamannda aadaki hata mesajlarn alrz.

www.bsenyurt.com Page 1697


rneimizde kullandmz deer tr kstlamas her ne kadar koleksiyonun sadece struct' lar
kullanmasn salyorsada, eer sadece Kitap ve Dvd gibi kendi tanmladmz struct' larn
kullanlmasna bir zorunluluk getirmemektedir. Nitekim int, double gibi struct' larda
BenimKoleksiyonum ile birlikte kullanabilirsiniz. Bu noktada daha gl bir kstlama kullanmakta
fayda vardr. Tam olarak soy bamll kstlamas bu talebimizi karlar. Bu kstlamaya gre
generic olarak kullanlan trn belli bir tipten veya bu tipten treyen baka tip(tipler)den olmas
zorunluluu vardr. Dolaysyla, ister deer tr ister refarans tr olsun, belli bir tr veya bu
trden kaltmsal olarak treyen tiplerin kullanlmasn zorunlu hale getirebiliriz. Bu kstlamay
uygulamak iin aadaki sz dizimi kullanlr.

where Tip : <Temel Snf>

Bu kstlamay anlamak iin u rnei gz nne alalm. Otomobillere ait eitli rnleri nesneye
dayal mimari altnda tasarlamaya altmz dnelim. Her rn ayr bir snf olarak
tasarlayabiliriz. Lakin pek ok rnn ortak olan bir takm zellikleri ve ilevleride vardr. Bu tip
yeleri temel bir snfta toplayabiliriz. ok basit olarak aadaki snf diagramnda grlen bir rnek
gelitirelim. Burada Lastik ve Silecek isimli snflarmz, UrunTemel snfndan tremitir. UrunTemel
isimli snfmz tm rnler iin ortak olan rn kodu , fiyat ve ksa aklama bilgileri iin gerekli
zellikleri barndrmaktadr.

www.bsenyurt.com Page 1698


Yukardaki emada grlen UrunTemel, Lastik ve Silecek isimli snflarmza ait kod satrlarmz ise
aadaki gibidir.

UrunTemel.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingGenericConstrainst
{
public class UrunTemel
{
private int urunKodu;
private double urunFiyati;
private string urunBilgisi;

public UrunTemel(int kod,double fiyat,string bilgi)


{
urunKodu = kod;
urunFiyati = fiyat;

www.bsenyurt.com Page 1699


urunBilgisi = bilgi;
}

public int UrunKodu


{
get{return urunKodu;}
}
public double BirimFiyat
{
get{return urunFiyati;}
}

public string UrunTanimi


{
get{return urunBilgisi;}
}
}
}

Lastik.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingGenericConstrainst
{
public class Lastik : UrunTemel
{
private int capi;
private int genislik;
private string tipi;

public Lastik(int kodu, double fiyat, string bilgi)


: base(kodu, fiyat, bilgi)
{
}

public int Cap


{
get{return capi;}
set{capi = value;}
}

public int Genislik


{
get{return genislik;}
set{genislik = value;}

www.bsenyurt.com Page 1700


}

public string Tip


{
get{return tipi;}
set{tipi = value;}
}

public override string ToString()


{
return UrunKodu.ToString() + " " + BirimFiyat.ToString() + " " + UrunTanimi + " " +
Cap.ToString() + " " + Genislik.ToString() + Tip;
}
}
}

Silecek.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingGenericConstrainst
{
public class Silecek : UrunTemel
{
private int uzunluk;

public Silecek(int kodu, double fiyat, string bilgi)


: base(kodu, fiyat, bilgi)
{
}
public int Uzunluk
{
get{return uzunluk;}
set{uzunluk = value;}
}

public override string ToString()


{
return UrunKodu.ToString() + " " + BirimFiyat.ToString() + " " + UrunTanimi + " " +
Uzunluk.ToString();
}
}
}

www.bsenyurt.com Page 1701


imdi buradaki soy ilikisini kullanacak tipte bir ynetici snf gelitirdiimizi dnelim. Urunler
isimli bu snfmz deiik tipleri barndrabilecek bir generic koleksiyon ile birlikte kullanacaz.
Doal olarak, Urunler isimli snfmzda generic bir mimaride gelitireceiz. Urunler isimli snfmza
ait ema bilgisini ve kod satrlarn aadaki grafikte grebilirsiniz.

Urunler.cs

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingGenericConstrainst
{
public class Urunler<T> // where T : UrunTemel
{
private List<T> urunListe;

public Urunler()
{
urunListe = new List<T>();
}

public void Ekle(T uye)


{
urunListe.Add(uye);
}
public void Sil(T uye)
{
urunListe.Remove(uye);
}
public void Listele()
{
foreach (T uye in urunListe)
{
Console.WriteLine(uye.ToString());
}
}
}

www.bsenyurt.com Page 1702


}

imdi bu snflarmz Main metodumuzda aadaki kod satrlar ile kullanmaya alalm.

Urunler<Int16> urunler = new Urunler<short>();


urunler.Ekle(13);
urunler.Ekle(15);
urunler.Ekle(24);
urunler.Listele();

Uygulamamz bu haliyle altrdmzda her hangibir sorun ile karlamayz. Urunler isimli
snfmz Generic bir yapda olduundan Short veri trnden deikenleri ileyecek ekilde
tasarlayabiliriz. Fakat bu istediimiz bir kullanm ekli deildir. Nitekim biz Urunler isimli snfmzn
generic olmasn ama sadece Urun grubu ile ilgili trleri ilemesini istemekteyiz. Bu sebepten
yorumsal olarak yazdmz kstlama satrn kaldrmamz ve bu sayede Urunler snfn sadece
UrunTemel soyundan gelecek tiplerin kullanmna amamz gerekiyor. Uygulamamz yukardaki
kodlar ile brakp, kstlamamz devreye soktuumuzda, build ileminden sonra aadaki hata
mesajlar alrz.

Urunler isimli ilevsel snfmz, generic tip olarak sadece TemelUrun ve soyundan gelen snf nesne
rnekleri ile alabilecek ekilde kstlandrld iin bu hata mesajlar alnmtr. Ancak uygulama
kodlarmz aadaki gibi deitirdiimizde herhangibir problem ile karlamayz.

Urunler<UrunTemel> urunler = new Urunler<UrunTemel>();

Lastik lst = new Lastik(1000, 10, "Otomobil Lastii");


lst.Tip = "K Lastii";
lst.Cap = 185;
lst.Genislik = 75;

www.bsenyurt.com Page 1703


Silecek slc = new Silecek(1001, 5, "On silecek takimi");
slc.Uzunluk = 60;

urunler.Ekle(lst);
urunler.Ekle(slc);

urunler.Listele();

Generic kstlamalar ile ilgili olarak greceimiz bir dier modelde interface uygulama
zorunluluudur. Bu kurala gre, generic mimari iinde kullanlacak olan tr, koul olarak belirtilen
interface' i veya ondan treyenlerini mutlaka implemente etmi bir tip olmak zorundadr. rnein
aadaki mimariyi gz nne alalm. Bu rnekte bir veritaban sisteminde yer alan varlklar eitli
snflar ile temsil edilmeye allmtr. Bu varlklarn ortak zellii mutlaka ve mutlaka
IGenelVeriIslem isimli arayz uyguluyor olmalardr.

Bizim bu varlklar ynetecek bir snfmz var ise ve bu snf generic bir mimari ierisinde
kullanmak istiyorsak sadece IGenelVeriIslem arayzn ugulayan tiplerin kullanlmasn da garanti
edebiliriz. Tek yapmamz gereken ilgili ynetici snfmza arayz kstlamasn aadaki kod
satrlarnda grld gibi eklemek olacaktr.

class entYonetici<T> where T:IGenelVeriIslem


{
// rnek kod satrlar
}

www.bsenyurt.com Page 1704


Burada T tipinin mutlaka IGenelVeriIslem arayzn implemente etmi bir tr olmas zorunluluu
getirilmektedir. Bylece ynetici snfmz eitli tipleri kullanabiliyor olmakla birlikte u an iin
sadece ilgili arayz uygulayan varlk snflarna destek vermektedir.

Generic kstlamalar ile ilgili bir dier zellikte, varsaylan yapc metod olmas zorunluluudur. Buna
gre generic mimari ierisinde kullanlan bamsz trn mutlaka varsaylan yapc (default
constructor-parameterless constructor) metoda sahip olmas amalanmaktadr. Bunu daha iyi
anlayabilmek iin, varsaylan yapcs olmayan bir tipi, generic olarak kullanmaya almalyz.
Aadaki rnei gz nne alalm.

Bu rnekte, CDKoleksiyon basit olarak tasarlanm generic tipte bir koleksiyondur. Cd isimli
referans tipimizi pekala bu generic koleksiyon ierisinde kullanabiliriz. Lakin Cd isimli snfmzn
default constructor metodu mevcut deildir. Bunun yerine parametre alan overload edilmi bir
versiyonu kullanlmtr. CDKoleksiyon snfnn, tayaca generic tiplerin mutlaka ve mutlaka
varsaylan yapc metodlar iermesini isteyeceimiz durumlar sz konusu olabilir. Bu zorlamay
gerekletirmek iin tek yapmamz gereken new kstlamasn kullanmak olacaktr.

public class CDKoleksiyon<T> where T:new()


{
private List<T> icListe = new List<T>();

public void Ekle(T cd)


{
icListe.Add(cd);
}

public T Oku(int indis)


{
return icListe[indis];
}

www.bsenyurt.com Page 1705


}

public class Cd
{
private int BarkodNo;
public Cd(int id)
{
BarkodNo = id;
}
}

Uygulamada CDKoleksiyon snfna ait bir nesne rneini Cd tipini kullanacak ekilde oluturmaya
altmzda aadaki ekran grntsnde verilen hata mesajlarn alrz. Buna gre, generic tipin
mutlaka parametresiz bir constructor kullanmas gerektii derleme zamannda hata mesaj olarak
bildirilmektedir.

Dilersek generic kstlamalarn bir kan bir arada kullanabiliriz. rnein bir generic trn
hem belli bir tipten gelmesini hemde struct olmasn salayabiliriz. Bu kombinasyonlar
arttrmamz mmkndr. Buradaki tek art, eer varsaylan yapc kstlamasda var ise
new anahtarnn her zaman iin en sonda belirtilmesi gerekliliidir.

Bu sayede, zorlamalar kullanarak tip gvenliini daha belirleyici ekilde salam oluyoruz. Bu
makalemizde generic mimarinin nemli zelliklerinden birisi olan kstlamalar incelemeye altk.
Kstlamalar yardmyla tr bamszln kullanrken belirli artlarn salanmasn zorunlu hale
getirebileceimizi grdk. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

C# 2.0 ile Generic Delegates ( 21.11.2005 ) - C#


2.0
www.bsenyurt.com Page 1706
Deerli Okurlarm Merhabalar,

Bu makalemizde generic temsilcilerin (generic delegates) ne olduunu ve nasl kullanlabildiini


incelemeye alacaz. .Net 2.0 ile gelen en nemli yenelik generic mimarisidir. Generic mimarisi,
tr bamsz algoritmalar kurmamza imkan salayan gelimi bir yapdr. .Net 2.0' da snflar
(class), yaplar (struct), arayzleri (interface), metodlar (method), koleksiyonlar (collection) ve
temsilcileri (delegate) generic olarak oluturabilir ve kullanabiliriz. Bildiiniz gibi generic
mimarisinin salam olduu iki nemli zellik vardr. Bunlar tip gvenlii (type-safety) ve
performans artdr. zellikle performans ile kastedilen konu gereksiz boxing ve unboxing
ilemlerinin ortadan kaldrlabilmesidir. Generic mimarinin getirdii bu avantajlar delegate
(temsilci) tipi iinde kullanabilmekteyiz.

lk olarak generic temsilcilere neden ihtiyacmz olabileceini 1.1 versiyonundaki kullanmn gz


nne alarak irdelemeye alalm. Aadaki rnek uygulamada overload edilmi Toplam isimli iki
metod yer almaktadr. Bu iki metod farkl tipte parametreler almaktadr. Bunun yannda dn
tipleride farkldr. Bu metodlar temsilci nesneleri ile iaret etmek istediimizde iki ayr temsilci tipi
tanmlamamz gerekecektir. Nitekim temsilci tipi, tanmlam olduu desen ile(dn tipi ve metod
imzas) birebir uyumlu metodlar iaret edebilmektedir.

using System;

namespace UsingGenericDelegates
{
#region Temsilci tipleri tanmlanr

public delegate float TemsilciFloat(float a,float b);


public delegate int TemsilciInt(int a,int b);

#endregion

public class TemelAritmetik


{
public TemelAritmetik() {}

public float Toplam(float x,float y)


{
return x+y;
}

public int Toplam(int x,int y)


{
return x+y;
}
}
}

TemelAritmetik snfmza ait Toplam metodlarn alma zamannda belirlediimiz temsilci


nesneleri ile aadaki kod parasnda olduu gibi ilikilendirebiliriz.

using System;

www.bsenyurt.com Page 1707


namespace UsingGenericDelegates
{
class TestClass
{
[STAThread]
static void Main(string[] args)
{
TemelAritmetik ta=new TemelAritmetik();

#region Temsilciler Oluturulur

TemsilciInt tint=new TemsilciInt(ta.Toplam);


TemsilciFloat tFloat=new TemsilciFloat(ta.Toplam);

#endregion

int toplamInt=tint(1,2);
float toplamFloat=tFloat(1.2f,1.2f);

Console.WriteLine(toplamInt.ToString());
Console.WriteLine(toplamFloat.ToString());

}
}
}

Bu uygulama sorunsuz ekilde almaktadr. Ancak benzer ilevlere sahip olan yani int ve float
tipinden verileri toplayp bu trde geri dndren metodlar alma zamannda ilgili temsilci nesne
rnekleri ile iaret edebilmek iin iki ayr delegate tipi tanmlamamz gerekmitir. te .Net 2.0 ile
birlikte gelen generic mimarisi sayesinde tek bir temsilci tipi tanmn kullanarak birden fazla
metodu istenilen veri tipi iin kullanabiliriz. Baka bir deyile, yukardaki rnekte olduu gibi iki
farkl delegate tipi tanmlamak yerine generic yapda tek bir temsilci tipi (delegate type) tanmlayp,
bu tip zerinden alma zamannda uygun metodlar arabiliriz.

.Net 2.0 iin generic temsilci (generic delegate) tanmlamasnda da anahtar nokta, asal ayralar
(<>) arasna yazlan tr belirtme operatrdr. rnein, void dn tipine sahip ama parametre
tipleri belli olmayan (baka bir deyile alma zamannda belli olacak olan) bir temsilciyi aadaki
gibi tanmlayabiliriz.

public delegate void TemsilciX<T>(T deger);

Bu ifadede, TemsilciX isimli delegate tipinin alma zamannda geri dn tipi olmayan (void) ve
her hangibir tipte tek bir parametre alan metodlar iaret edebileceini sylemi oluyoruz.
rneimizde bu metod desenine uyan aadaki Yaricap fonksiyonumuzun olduunu dnelim.

public void Yaricap(double r)


{

www.bsenyurt.com Page 1708


Console.WriteLine("yarap ={0}", r);
}

Buna gre TemsilciX delegate tipini uygulamamzda aadaki gibi kullanabiliriz.

TemsilciX<double> tX = new TemsilciX<double>(ta.Yaricap); // Temsilci nesne rnei


oluturulur.
tX(1.3); // Temsilcimizin iaret ettii metod arlr.

Bu kod parasnda tX rneini olutururken, alma zamannda double tipinden parametre alacak
metodlar iaret edebileceini belirtmi oluyoruz. Dier yandan rnein, int tipinden bir parametre
alp void dn tipine sahip baka bir metodu iaret etmek istediimizde, TemsilciX deleagate tipini
buna gre tekrardan rneklendirebiliriz.

Bylece tek bir temsilci nesnesini kullanarak alma zamannda kendi belirlediimiz tipleri kullanan
metodlar iaret edebiliriz. Generic temsilcileri kullanarak, iaret edecekleri metodlarn dn
tiplerinin alma zamannda ne olacan da belirleyebiliriz. Makalemizin bandaki rnei dikkate
aldmzda Toplam metodunun her iki versiyonununda farkl tipten geri dn deerlerine sahip
olduunu grmekteyiz. Buna gre, generic temsilci tipimizi aadaki gibi tanmlayabiliriz. Bu sefer,
her metod iin ayr birer temsilci tipi tanmlamaktansa, tek bir generic temsilci tipi tanm iimizi
grecektir.

public delegate R Temsilci<T,R>(T deger1,T deger2);

Burada R harfi ile temsilcimizin alma zamannda iaret edecei metodun dn tipini belirtmi
oluruz. T harfi ilede, metodun alaca parametrelerin tipini belirliyoruz. Bu deiiklikeri gz nne
aldmzda, makalemizin bandaki rneimizi aadaki haliyle gncelleyebiliriz.

using System;

namespace UsingGenericDelegates
{
// Temsilci tipimiz tanmlanr.
public delegate R Temsilci<T, R>(T deger1, T deger2);

class TestClass
{
[STAThread]
static void Main(string[] args)

www.bsenyurt.com Page 1709


{
TemelAritmetik ta=new TemelAritmetik();

#region temsilcimize ait nesne rnekleri oluturuluyor

Temsilci<float, float> t1 = new Temsilci<float, float>(ta.Toplam);


Temsilci<int,int> t2=new Temsilci<int,int>(ta.Toplam);

#endregion

Console.WriteLine(t1(1.2f, 1.3f));
Console.WriteLine(t2(1,2));
}
}
}

Her ne kadar t1 ve t2 olmak zere TemelAritmetik snf ierisindeki Toplam metodlarnn her biri
iin ayr ayr iki delegate nesnesi rneklemi olsakta; bu nesne rneklerinin ait olduu delegate tipi
tektir. Uygulamay altrdmzda aadaki ekran grntsn elde ederiz.

Tek bir generic temsilci tipi ile, alma zamannda deiik dn tipi ve parametrelere
sahip metodlar iaret edebiliriz.

Temsilcilerin salam olduu tip gvenlii (type-safety) ve performans art gibi faydalar dnda
zellikle kendi tiplerimizi kullandmz takdirde devreye giren kstlamalar (constraints), delegate
tipleri iinde geerlidir. Bildiiniz gibi generic yaplarda Where anahtar szc yardmyla,
parametre tiplerine ilikin kesin baz kurallar koyabiliyoruz. rnein TemelAritmetik isimli
snfmzda aadaki gibi iki string tipte parametre alan bir metodumuz olduunu dnelim.

public string Toplam(string x, string y)


{
return x + y;
}

Byle bir durumda, Temsilci delegate tipimiz ile alma zamannda bu metodu aadaki kod
parasnda olduu gibi iaret edebiliriz.

Temsilci<string, string> t3 = new Temsilci<string, string>(ta.Toplam);


Console.WriteLine(t3("Burak", "Selim"));

www.bsenyurt.com Page 1710


Burada nemli olan nokta Toplam metodunun bu versiyonunun string tipinde, (bir baka deyile
referans tipinde) parametreler alyor oluudur. Oysaki biz temsilcimizin sadece deer trnde(value
types) parametreler alan metodlar iaret etmesini de isteyebiliriz. te byle bir sorunu, where
anahtar szc ile parametre tiplerine ynelik (veya dn tipine ynelik) kstlamalar girerek
aabiliriz. Dolaysyla Temsilci isimli delegate tipimizi aadaki gibi tanmlamamz yeterli olacaktr.

public delegate R Temsilci<T, R>(T deger1, T deger2) where T:struct where R:struct;

Burada where anahtar szcklerini kullanarak T ve R trlerinin mutlaka struct tipinde olmalar
gerektiini, bir baka deyile deer tr olmalar gerektiini belirtmi oluyoruz. Dolaysyla
uygulamamz bu haliyle derlemek istediimizde aadaki ekilde grld gibi, derleme zaman
hata mesajlarn alrz.

Yaptklarmz ksaca gzden geirecek olursak generic temsilcilerin salam olduu avantajlar u
ekilde sralayabiliriz.

Temsilci tiplerini tr bamsz olacak ekilde tanmlayabiliriz.

Where anahtar szcnn imkanlarndan faydalanarak temsilci tiplerine ait parametre ve dn


deerleri zerinde tip gvenliini (type-safety) daha st dzeyde salayabiliriz.

alma zamannda farkl parametre tiplerini kullanan uygun metodlar iin ayr ayr temsilci

www.bsenyurt.com Page 1711


tipleri tanmlamak zorunda kalmayz.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Kendi Referans Tiplerimizi Klonlamak (


14.11.2005 ) - C# 2.0
Deerli Okurlarm Merhabalar,

Bu makalemizde kendi yazm olduumuz referans tipleri arasnda yaplan atama ilemleri srasnda
yeden yeye (Member by member) kopyalamann nasl yaplabileceini incelemeye alacaz.
Bildiiniz gibi referans tipleri bellein heap bellek blgesinde tutulurlar. Bu tutulu yapsnn
zellikle referans tipleri arasnda yaplan atama ilemlerinde nemli bir etkisi vardr. ki referans
tipi arasnda bir atama ilemi sz konusu olduunda, aslnda bu referans tiplerinin heap bellek
blgesinde yer alan adresleri eitlenmektedir. Bu elemenin doal bir sonucu olaraktan da referans
tiplerinin her hangibirisinde yaplan deiiklik dierinide otomatikman etkileyecektir.

Ancak baz durumlarda, zellikle kendi yazdmz referans tiplerini kullanrken bu durumun tam
tersini isteyebiliriz. Yani kendi yazm olduumuz bir snfn iki nesne rnei arasnda yaptmz
atama ilemi sonras, bu referanslarn birbirini etkilemelerini istemeyebiliriz. Bu durumda yazm
olduumuz snfa IClonable arayzn uygulayarak referans tipinin klonlanmasn salayabiliriz.
Bu durumu analiz etmeden nce, referans tipleri arasnda yaplam atamann doal sonucunu
aadaki rnek ile incelemeye alalm. rneimizde bir drtgene ait kenar uzunluklarn tutacak
olan Dortgen isimli bir snf kullanacaz. Dortgen snfmzn UML emas ve kodlar aadaki
gibidir.

Dortgen.cs

public class Dortgen


{

www.bsenyurt.com Page 1712


private double kenarA;
private double kenarB;

public double A
{
get
{
return kenarA;
}
set
{
kenarA=value;
}
}

public double B
{
get
{
return kenarB;
}
set
{
kenarB=value;
}
}

public Dortgen()
{
kenarA=0;
kenarB=0;
}

public Dortgen(double aKenari,double bKenari)


{
kenarA=aKenari;
kenarB=bKenari;
}

public override string ToString()


{
string dortgenBilgi=kenarA.ToString()+" "+kenarB.ToString();
return dortgenBilgi;
}
}

imdi Dortgen snfnadan iki nesne rneini kullanacamz bir console uygulamsna ait Main
metodunda, aadaki kod satrlarn yazalm.

www.bsenyurt.com Page 1713


Dortgen drtgX=new Dortgen(10,20);
Console.WriteLine("X : "+drtgX.ToString());

Dortgen drtgY;
drtgY=drtgX; // referanslar eitlenir.
Console.WriteLine("Y : "+drtgY.ToString());

drtgY.A=30;
drtgY.B=40;

Console.WriteLine("Y : "+drtgY.ToString());
Console.WriteLine("X : "+drtgX.ToString());

Burada ilk olarak Dortgen snfna ait bir nesne rneini (drtgX) oluturuyor. Daha sonra ise drtgY
isimli bir nesne rnei oluturup bu rnee, drtgX nesnesini atyoruz. te bu noktada her iki nesne
rneinin referans adreslerini eitlemi oluyoruz. zleyen satrlarda bu kez drtgY nesnesi zerinden
A ve B zelliklerinin deerlerini deitiriyoruz. Az nce yaplan eletirme ilemi nedeniyle drtgY
nesnesi iin gerekletirilen deiiklikler drtgX nesnesi iinde sz konusu olacaktr. Dolaysyla
drtgX nesnesini ilk rneklerken belirlenen A ve B deikenlerinin deerlerini kaybetmi oluyoruz.

www.bsenyurt.com Page 1714


Referans tiplerinin bir birlerine atanmas ilemi sonras, bu tiplerin heap bellek
blgesindeki balang adresleri eitleneceinden, birisi ierisindeki varlklarda yaplacak
deiiklikler dierinede yansyacaktr.

Yukardaki rnek referans tipleri arasnda yaplan atamalarn bir eksiklik olduunu gstermez. Bu,
bellek sisteminin doal bir sonucudur. Dahas, referans tiplerinin bu ekilde tutulmasnn ve atama
ilemleri sonras adreslerin eitlenmesinin avantajl olduu durumlar da vardr. rnein n elemanl
bir diziyi, bir metoda parametre olarak geirmek istediinizde, dizinin metod blou iinde deer
trlerinde olduu gibi tekrardan rneklenmemesi, referans adreslerinin tanmas sayesinde
gerekleir. Bylece bellekte gereksiz yere ikinci bir dizi rnei yaratlmam olunur.

Elbetteki baz hallerde referans tiplerinin yeden-yeye (member by member) kopyalanmasn yani
ikinci bir adresleme ile yeni bir rnein oluturulmasn isteyebiliriz. te bunu gerekletirmek iin
var olan nesneyi atama ilemini yaparken klonlarz. Klonlama ileminin gerekletirilebilmesi iin,
yazm olduumuz snfa IClonable arayzn uygulamamz gerekir. Bu arayz sadece Clone isimli
tek bir metod iermektedir. Yukardaki rneimizde kullandmz Dortgen snfna IClonable
arayzn aadaki gibi uygulayabiliriz.

public class Dortgen:ICloneable


{
// Dier kodlar

#region ICloneable Members

public object Clone()


{
return new Dortgen(this.kenarA,this.kenarB);
}

#endregion
}

www.bsenyurt.com Page 1715


Elbette Clone metodunu atama ilemi srasnda aadaki kod parasnda olduu gibi kullanmamz
gerekir.

drtgY=(Dortgen)drtgX.Clone();

Clone metodu, Dortgen snfna ait yeni bir nesne rneini o an sahip olduu A ve B deerleri ile
geriye dndrr. Clone metodu varsaylan olarak Object tipinden deerler dndrd iin, drtgY
nesnesine yaplan atama ilemi srasnda tr dnm ilemi(casting) yaparak uygun tipe atama
yapmamz gerekmektedir. Bu ilem ile birlikte bellekte Dortgen snfna ait iki nesne rnei iin ayr
ayr adreslemeler sz konusu olacaktr. drgtX nesnesi var olan deerlerini korurken oluturulduu
sradaki adreste konulanmaya devam edecektir. drtgY nesnemiz ise drtgX nesnesinin o anki
ieriine sahip olmak zere, bellein farkl bir adres blgesinde yeniden rneklendirilecektir.
Durumu aadaki ekil ile daha kolay anlayabiliriz.

Uygulamay bu haliyle altrdmzda atama ilemi sonras drtgY nesnesi zerinden yaplan
deiikliklerin drtgX nesnesinin deerlerini etkilemediini grrz.

Ayn etkiyi u ekilde de yapabiliriz,

public object Clone()

www.bsenyurt.com Page 1716


{
return this.MemberwiseClone();
}

MemberwiseClone metodu Object snfna ait bir metoddur. Protected eriim belirleyicisine sahiptir
bu yzden tretme ilemi sz konusu olduunuda kullanlabilir. Ayrca override edilebilir bir metod
da deildir. MemberwiseClone metodu, kullanld snfn nesne rneinden bir kopya daha
oluturmaktr. Yukardaki rneimizi bu haliyle altrdmzda, atama sonras klonlama ileminin
baarl bir ekilde yapldn ve drtgY nesnesi zerinde yaplan deiikliklerin drtgX nesnesini
etkilemediini grrz.

Ancak MemberwiseClone metodunu kullanrken dikkat etmemiz gereken bir durum vardr.

MemberwiseClone metodu, klonlama ilemi srasnda nesnenin static olmayan tm


deer trlerini (value types) bit-bit kopyalar. Ancak ieride kullanlan referans tipi nesne
rnekleri varsa bunlarn adreslerini aynen yeni rnee geirir. Dolaysyla referans tipleri
aras yaplan atama ilemi sonras oluan ayn adresi gsterme atmas, dahili referans
tipi nesne rnekleri iinde geerli olur.

Bu durumda yeni nesne rneimiz ierisinde var olan bir referans tipi zerinde yaplacak bir
deiiklik, yine ilk nesne iindeki referans nesne rnei iinde geerli olacaktr. Bu dikkat edilmesi
gereken nemli bir durumdur. rnein Dortgen snfmz ierisinde kullanlacak yeni bir snfmz
olduunu varsayalm.

public class DortgenHesaplama


{
}

public class Dortgen:ICloneable


{
private double kenarA;
private double kenarB;
private DortgenHesaplama drgH=new DortgenHesaplama();

public double A
{
get { return kenarA; }
set { kenarA=value; }
}

www.bsenyurt.com Page 1717


public double B
{
get { return kenarB; }
set { kenarB=value; }
}
public DortgenHesaplama Hesaplama
{
get { return drgH; }
}
public Dortgen()
{
kenarA=0;
kenarB=0;
}

public Dortgen(double aKenari,double bKenari)


{
kenarA=aKenari;
kenarB=bKenari;
}

public override string ToString()


{
string dortgenBilgi=kenarA.ToString()+" "+kenarB.ToString();
return dortgenBilgi;
}

#region ICloneable Members

public object Clone()


{
return this.MemberwiseClone();
// return new Dortgen(this.kenarA,this.kenarB);
}

#endregion
}

Burada dikkat ederseniz, DortgenHesaplama isimli snfa ait bir nesne rneini Dortgen snf
ierisinde kullanmaktayz. Bu, Dortgen referans tipi ierisinde yer alan baka bir referans tipi nesne
rneidir. Atama ilemi sonras MemberwiseClone metodu DortgenHesaplama snfna ait nesne
rneinin sadece adresini kopyalayacaktr. Uygulamamzn kodlarn yukardaki Dortgen snfna
gre aadaki gibi deitirelim.

Dortgen drtgX=new Dortgen(10,20);


Dortgen drtgY;
drtgY=(Dortgen)drtgX.Clone();
drtgY.A=30;

www.bsenyurt.com Page 1718


drtgY.B=40;

bool refAdrEsitmi=object.ReferenceEquals(drtgX,drtgY);
Console.WriteLine("drtgX & drtgY referans adresleri eit mi ?"+refAdrEsitmi.ToString());

refAdrEsitmi=object.ReferenceEquals(drtgX.Hesaplama,drtgY.Hesaplama);
Console.WriteLine("drtgX.Hesaplama & drtgY.Hesaplama referans adresleri eit mi
?"+refAdrEsitmi.ToString());

ReferenceEquals parametre olarak ald nesne rneklerinin bellek referanslarnn ayn


olup olmadn kontrol ederek sonucu bool tipinden geriye dndren Object snfna ait
static bir metoddur.

Grld gibi drtgX ve drtgY nesnelerini Object snfnn ReferenceEquals metodu ile
karlatrdmzda, false deerini alyoruz. nk biz Dortgen snfmza IClonable arayzn ve
Clone metodu ierisinde MemberwiseClone fonksiyonunu uygulayarak, drtgX nesne rneini
klonluyoruz. Bu sebeple heap bellek blgesinde ayr bir Dortgen nesne rnei oluturuluyor.
Dolaysla adresler artk farkl olacandan ReferenceEquals metodu geriye false deer
dndrecektir. Ancak drtgX ve drtgY nesne rnekleri ierisinde yer alan DortgenHesaplama snfna
ait nesne rneklerinin referanslarn karlatrdmzda true deerinin dndn grmekteyiz.
Yani DortgenHesaplama snfna ait nesne rnekleri iin klonlama ilemi gereklememi bunun
yerine nesnelerin heap bellek blgesindeki adresleri eitlenmitir. Bu dikkat edilmesi gereken bir
durumdur ve snflarmz programlarken gerekli tedbirlerin alnmasn gerektirebilecek kadar
nemlidir. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0(Beta 2) - Connection String Security


(Balant Katar iin Gvenlik) ( 17.10.2005 ) -
Ado.Net 2
Deerli Okurlarm Merhabalar,

Gvenlik gnmz uygulamalarnda ok nemli bir yere sahiptir. zellikle veritaban kullanmn
ieren uygulamalarda gvenliin ayr bir nemi vardr. Veritabanna gnderilen sorgularn
korunmas, zellikle web servislerinden dnen veri kmelerinin etkin olarak ifrelenmesi gibi
durumlar sz konusudur. Gvenlik prosedr ierisinde yer alan unsurlardan biriside balant

www.bsenyurt.com Page 1719


bilgilerinin saklanmasdr. Biz bu makalemizde, .Net 2.0 ile birlikte gelen yeni tekniklerden birisine
deinerek, balant bilgisinin (ounlukla connection string olarakda ifade edebiliriz) kolay bir
ekilde nasl korunabileceini incelemeye alacaz.

Bildiiniz gibi, .Net tabanl uygulamalar zellikle XML tabanl konfigurasyon dosyalarn youn
olarak kullanr. Varsaylan olarak windows uygulamalarnda app.config veya web uygulamalarnda
yer alan web.config dosyalar, genel bilgilerin yer ald kaynaklardr. ounlukla proje genelinde
kullanlan balant bilgilerini bu dosyalarda key-value (anahtar-deer) iftleri eklinde tutmay
tercih ederiz. Aslnda balant katar(connection string) bilgilerini kod ierisinde de global seviyede
tanmlayp kullanabiliriz. Ancak bunun bir takm dezavantajlar vardr.

Balant katar gibi sonradan (zellikle rn canl yayna baladktan sonra) ska
deiebilecek bilgileri kod ierisinde (hard-coded) tutmak gvenlik ve ynetilebilirlik
asndan dezavantajlara sahiptir.

Birincisi, yazlan kodlar sonu olarak IL dilini kullandndan ters evrilerek aa kartlabilir.
(Disassembly aralar) Bu nedenle balant katar bilgiside renilebilinir. Dier yandan,
uygulamalar canl hayata getikten sonra, kullandklar veri taban sunucularnn ip bilgilerinin,
kullanc tanmlamalarnn ska deimesi nedeni ile balant katar bilgilerinin ska gncellenmesi
gerekebilir. te bu iki nedenden tr bu tip bilgiler xml tabanl konfigurasyon dosyalarnda, zel
ifreleme teknikleri ile tutulur.

Aadaki kod paralarnda bir web uygulamas ve bir console uygulamas iin kullandmz
standart konfigurasyon dosyalarnda yer alan balant katar tanmlamalarn ve bu balant
katarlar ierisindeki bilgilerin kullanmn gsteren iki rnek yer almaktadr.

Sradan bir console uygulamas iin app.config ierii;

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


<configuration>
<appSettings>
<add key="conStr" value="data source=localhost;database=AdventureWorks2000;user
id=sa;password="></add>
</appSettings>
</configuration>

conStr isimli anahtarn uygulama ierisinden kullanm;

using System;
using System.Data.SqlClient;

namespace UsingConnectionString
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
string

www.bsenyurt.com Page 1720


conStr=System.Configuration.ConfigurationSettings.AppSettings["conStr"].ToString();
using(SqlConnection con=new SqlConnection(conStr))
{
con.Open();
}
}
}
}

Bir web uygulamasnda web.config ierisinde balant katar (connection string) iin anahatar-deer
(key-value) kullanm.

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


<configuration>
<appSettings>
<add key="conStr" value="data source=localhost;database=AdventureWorks2000;user
id=sa;password="></add>
</appSettings>
<system.web>
<!-- Dier ayarlar-->
</system.web>
</configuration>

Web.Config ierisindeki balant katar bilgisinin default.aspx ierisinde kullanm;

private void Page_Load(object sender, System.EventArgs e)


{
string
conStr=System.Configuration.ConfigurationSettings.AppSettings["conStr"].ToString();
using(SqlConnection con=new SqlConnection(conStr))
{
con.Open();
}
}

Gelelim .Net 2.0' a. Yeni versiyonda zellikle balant katarlarna ynelik olarak gelitirilmi zel bir
gvenlik teknii mevcuttur. Bu tekniin kilit noktalar olarak, konfigurasyon ayarlarna eklenen iki
yeni nitelik sz konusudur.Bu nitelikler onfigurasyon protectedData ve protectedDataSections'
dr. ProtectedDataSections nitelii altnda sonradan ifrelenmesi dnlen anahatar bilgileri
tutulmaktadr. Balant katar iin kullanacamz anahtar bilgisini burada tutabiliriz. ProtectedData
ksmnda ise, ProtectedDataSections ierisinde yer alan anahtar bilgisini ifreleyecek (encryption)
ve deifre edecek (decryption) provider nesnesine ait bilgileri yer alr. u an
iin RSAProtectedConfigurationProvider veDPAPIProtectedConfigurationProvider adnda
iki adet ifreleme provider' mevcuttur. Bu providerlar, ilgili verinin ifrelenmesinden ve zellikle
alma zamannda kullanlrken deifre edilmesinden sorumludur. lk olarak configurasyon dosyas
ierisinde bu yaplar kullanarak gerekli dzenlemeleri yapmamz gerekmektedir.

.Net 2.0 iin bir console uygulamasna ait app.config konfigurasyon dosyasnn rnek ierii.

www.bsenyurt.com Page 1721


<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<connectionStrings>
<EncryptedData/>
</connectionStrings>

<protectedData>
<providers>
<add name="prvCon" type="System.Configuration.RsaProtectedConfigurationProvider
" keyContainerName="AnahtarDeger" useMachineContainer="true"/>
</providers>

<protectedDataSections>
<add name="connectionStrings" provider="prvCon" inheritedByChildren="false"/>
</protectedDataSections>

</protectedData>
</configuration>

Dikkat ederseniz protectedDataSections sekmesi, protectedData altnda yer alan bir blmdr.
Providers ksmnda, ifreleme ilemini yapacak olan tipe ait bilgiler yer almaktadr. Bu tipin takma
ad name zellii ile, tipin kendisi type zellii ile, kullanlacak ifreleme anahtarnn ad ise
keyContaionerName zellikleri ile tutulur. ProtectedDataSections ksmnda, ifrelenecek olan
anahtar bilgisi yer alr. Ancak dikkat ederseniz burada balant katarna ilikin herhangibir bilgi
yoktur. Sadece ifrelemeyi yapacak provider' n takma adn alan name zellii vardr. Bu zellik ile,
provider sekmesinde yer alan tipi iaret ederiz. Peki balant katarmz nerede yer almaktadr?

Dikkat ederseniz dosyann banda connectionStrings isimli taklar arasnda yer


alan EncryptedData isimli bir sekme yer almaktadr. ConnectionStrings konfigurasyon dosyalarna
eklenen yeni niteliklerden birisidir ve sadece balant katar bilgisi ile ilgilidir. Biz biraz sonra
yazacamz kodlar altrdmzda, balant katarmza ait bilgiler ifrelenerek bu ksm ierisine
eklenecektir. Bir baka deyile EncryptedData ksm ifrelenen verinin taycsdr. Burada dikkat
edilmesi gereken noktalardan birisi isim uyumluluudur. yleki connectionStrings taksnn ismi,
protectedDataSections ksmndaki anahtarn ismi ile ayn olmak zorundadr.

Balant katarnn connectionStrings isimli anahtara eklenmesi iin ekstra kod yazmamz
gerekmektedir. .Net 2.0' da System.Configuration isim alanna bir takm yeni snflar eklenmitir.
Biz bu snflar yardmyla, konfigurasyon dosyamza mdahale ederek, connectionStrings isimli
anahtara hem deer atamas yapabilir hemde ifreleme ilemini balatabiliriz. Bu amala aadaki
gibi bir kod yazmamz gerekmektedir. rnek olarak bir console uygulamas gz nne alnmtr.

using System;
using System.Configuration;
using System.Collections.Generic;
using System.Text;

namespace UsingAppSettings
{
class Program
{

www.bsenyurt.com Page 1722


static void Main(string[] args)
{
Configuration cnfg =
ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None, "");
cnfg.ConnectionStrings.ConnectionStrings.Add(new
ConnectionStringSettings("conStr","data source=localhost;database=AdventureWorks;integrated
security=SSPI"));
cnfg.Save();
}
}
}

ok fazla detaya girmeden yukardaki kodlar ile ne yaptmzdan ksaca bahsetmek istiyorum. lk
olarak bir configuration nesnesine atama yapyoruz. Bu atamadaConfigurationManager snfnn
statik OpenExeConfiguration metodunu kullanmaktayz. Bu metod aslnda belirtilen
configurasyon dosyasn bir Configuration nesnesi olarak atamak iin kullanlmaktadr. kinci
parametre konfigurasyon dosyasnn yolunu belirtir. Biz ayn uygulama ierisinde olduumuzdan
buray bo braktk. Daha sonra bu nesne zernde hareket ederek ConnectionStrings snfnn Add
metodunu aryor ve balant katarmz conStr ismi ile ilgili dosyaya ekliyoruz. Tabiki bu ekleme
ilemi srasnda provider' mz devreye giriyor ve bilgiyi ifreleyerek uygulamaya ait konfigurasyon
dosyasna yazyor. Son olarak Save metodu ile konfigurasyon dosyamz kaydediyoruz.

Normalde bu tip ilemleri 1.1 versiyonunda yapmak iin, yani xml tabanl konfigurasyon dosyasna
kod baznda mdahale etmek iin XmlDocument snfn kullanarak ayrtrma ilemlerini (parsing)
yapmamz gerekirdi. Yeni versiyonda grdnz gibi bu tarz ilemleri nesne baznda kolayca
yapabilmekteyiz.

Uygulamay denediim .Net 2.0 Beta versiyonunda, Configuration snfna eriebilmek


iin, System.Configuration isim alann projenin referanslarna Add Reference teknii ile
aka eklemem gerekti. Aksi takdirde, System.Configuration zerinden Configuration ve
ConfigurationManager gibi snflara direkt olarak eriilemiyor.

Yazdmz Console uygulamasn ilk altrdmzda konfigurasyon dosyalarnda her hangibir


deiiklik olmadn grrz. zellikle uygulamann debug klasrnde yer alan ve exe dosyamz ile
ayn isme sahip konfigurasyon dosyalarnda bir deiiklik olmayacaktr. Bunun sebebi, providern
ifreleme iin kullanaca bir anahtar deerin bulunmaydr. Hatrlarsanz provider
tanmnda keyContaionerName isimli bir zellik belirlemitik. KeyContainerName zelliine
atadmz AnahtarDeger , RS ifrelemesi iin gerekli anahtar kodu tamak iin kullanlacaktr. Peki
byle bir anahtar deerini nasl elde edebiliriz? Bunun iin aspnet_regiis aracn kullabiliriz.
Aadaki komut satr yardmyla bu ilemi gerekletirmekteyiz.

Bu ilemi yaptmz takdirde uygulamamzn exe kodunun bulunduu klasrde yer alan ayn isimli
konfigurasyon dosyas(UsingAppSettings.EXE.xml) ieriinin aadaki gibi yazldn grrz.

www.bsenyurt.com Page 1723


zellikle EncryptedData ve EncryptedKey ksmlarna dikkat ediniz.

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


<configuration>
<connectionStrings>
<EncryptedData Type="http://www.w3.org/2001/04/xmlenc#Element"
xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#tripledes-cbc" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<EncryptedKey Recipient="" xmlns="http://www.w3.org/2001/04/xmlenc#">
<EncryptionMethod Algorithm="http://www.w3.org/2001/04/xmlenc#rsa-1_5" />
<KeyInfo xmlns="http://www.w3.org/2000/09/xmldsig#">
<KeyName>Rsa Key</KeyName>
</KeyInfo>
<CipherData> <CipherValue>EIskDt2vsIN6xk5qC1S6slkWX97Ua28K
GGJTkHx500UsfMbed1TnZpQLYJaJW5XJXQPe
Y3IWm7iKdEZ+idx7THKlAx8eLf/HHDSi/HWp7sSJe6/4vcS6uQ+OyigdLpO6X3LEqoGYhwCNPoZq7e/e
B/P+w9pzLwivdczR1sOYMlQ=</CipherValue>
</CipherData>
</EncryptedKey>
</KeyInfo>
<CipherData> <CipherValue>fKJrwr1tdHNyVH9OYKlFeK7B7C1tzxp2ikrgu+KbCNBHM9fffF
Gt
EIRc9n0edC8poSskU7+APE18O6SRFqXD3OG0NX+9b65OIIHAXhEHdMYAbejU
VvqGoNw4xkisDfk/CgANrO9kST5f15g/0bH+5Cv83ptAV8mzIvzbvAzd+kpWdk
Q0T99jmiymcwqICBExmvUhT1wSUemYMC2Rzz3
JbJISvyqOZH9AYIxCesaeWwcyOvQfzLyHEw==</CipherValue>
</CipherData>
</EncryptedData>
</connectionStrings>
<protectedData>
<providers>
<add name="prvCon" type="System.Configuration.RsaProtectedConfigurationProvider"
keyContainerName="AnahtarDeger" useMachineContainer="true"/>
</providers>
<protectedDataSections>
<add name="connectionStrings" provider="prvCon" inheritedByChildren="false"/>
</protectedDataSections>
</protectedData>
</configuration>

Grdnz zere, ieride ifrelenmi bir takm veriler bulunmaktadr. Bu veriler aslnda,
programatik olarak atadmz balant katarna ilikin bilgilerdir. Peki bu bilgiyi uygulamamzda
nasl kullanabiliriz? ConfigurationManager snf yardmyla bu balant bilgisini kod ierisinden
okuyabilir ve ilgili balant nesneleri iin atayabiliriz. Aadaki rnek kod paras bu ilemin rnek
olarak nasl yaplabileceini gstermektedir.

www.bsenyurt.com Page 1724


string
conStr=ConfigurationManager.ConnectionStrings["conStr"].ConnectionString.ToString();
using (SqlConnection con = new SqlConnection(conStr))
{
// Bir takm kodlar
}

Yapm olduklarmz zetlersek; .Net 2.0, Configuration isim alan altnda yeni zelliklere sahip pek
ok tip sunmaktadr. Buradaki snflar ve konfigurasyon dosyalar iin gelitirilen yeni nitelikleri
kullanarak, config dosyalarnda tutulan balant katar bilgilerini yabanc gzlerden saklayabiliriz.
Elbetteki, kod ierisinde ConfigurationManager zerinde ilgili balant katar bilgisini okuyabilirsiniz.
Ancak herkesin grebildii config dosyalarndan balant katar bilgisini okuyamassnz. Tabi ne
yaparsanz yapn yinede gvenlii tam olarak salamak sz konusu olamaz. Her zaman iin en
azndan %1 ihtimal ile tm sistemler gvensidir. Bylece geldik bir makalemizin daha sonuna. Bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Constructor Initializers (Yapc Metod


Balatclar) Deyip Gemeyin ( 03.10.2005 ) - C#
Deerli Okurlarm Merhabalar,

Yapc metodlar nesne ynelimli programlamada ok byk neme sahiptir. Uygulamada


oluturduumuz her bir nesnenin en az bir yapc metodu (ki bu varsaylan yapc metodtur) vardr.
Kukusuz ki yapc metodlar (constructors), bir nesne rneinin kapslledii verilere balang
deerlerinin atanabilecei en elverili elemanlardr.

Yapclar, nesneleri balang konumlarna getirmek, bir baka deyile nesne ilk
oluturulduunda sahip olmas gereken deerleri belirlemek amacyla kullanrz.

Uygulamalarmzda ounlukla yapc metodlarn ar yklenmi versiyonlarna ihtiya duyarz. Bu


gereksinim genellikle, bir nesnenin verilerinin parametrik olarak birden fazla ekilde
balatlabilecei durumlarda olumaktadr. rnein veri ilemlerini stlenen bir snfn yapc
metodunda bu ilemler iin temel tekil edecek bir balant (connection) nesnesini oluturmaya
altmz dnelim. En az iki versiyon kullanabiliriz. Balant cmleciinin (Connection string)
parametrik olarak yapc metoda geirildii bir versiyon ve varsaylan balant cmleciinin
kullanlaca baka bir versiyon. Elbetteki ar yklenmi yapc metod versiyonlarn daha da
oaltabiliriz. Lakin burada dikkate deer bir durum vardr. O da ar yklenmi yapc metodlarn
ierideki deerlere atamalar nasl yapacadr. Genellikle burada iki tip versiyon kullanlr. Acem
programclarn ilk zamanlarda en ok kulland teknik balang deer atamalarnn her bir yapc
metod ierisinde ayr ayr yapld durumu kapsar. Dier teknik ise this anahtar szc
kullanlarak uygulanr ve deer atamalar merkezi bir yapc metod ierisine ynlendirilir.

Bu versiyonlar daha iyi kavrayabilmek amacyla basit bir rnek zerinde tartacaz. Farzedelim ki
Dortgenleri temsil edecek tipte bir snf tasarlyoruz. Drtgen tipinden nesneleri temsil edecek bu
snfn en azndan en ve boy gibi iki deeri kapslleyecei aikardr. Peki drtgen snfna ait nesne

www.bsenyurt.com Page 1725


rnekleri ka ekilde balatlabilir? Baka bir deyile bir Dortgen nesnesi oluturulduunda, en ve
boy deikenlerinin deerleri ka ekilde belirlenebilir? Bu soruya cevap ararken Dortgen snfmz
aadaki gibi tasarlayalm.

Snfmzn kodlarna gelince;

class Dortgen
{
private int m_AKenari;
private int m_BKenari;

public Dortgen() // Varsaylan yapc (default constructor)


{
m_AKenari=1;
m_BKenari=1;
}
public Dortgen(int akenari) // Kare olma durumu
{
m_AKenari=akenari;
m_BKenari=akenari;
}
public Dortgen(int akenari,int bkenari) // dikdrtgen olma durumu
{
m_AKenari=akenari;
m_BKenari=bkenari;
}
public double Alan()
{
return m_AKenari*m_BKenari;
}
}

Grdnz gibi son derece basit bir tasarmmz var. Her bir yapc metod ierisinde, Dortgen
snfnn kapslledii a ve b kenarlarna ait deerlere atamalar yapyoruz. Bu daha nceden de
vurguladmz gibi uygulamalarmzda ska kullandmz bir tekniktir. Aslnda durumu biraz daha
derinden incelemekte fayda var. Hemen ILDASM arac yardmyla, bu snf kullandmz her
hangibir uygulamann intermediate language (ara dil) kodlarna bakalm.

www.bsenyurt.com Page 1726


yapc metodumuzda kendi ilerinde ojbect tipinden bir nesne rneini oluturmaktadr. Aslnda
bu en tepedeki snf olan Object snfnn yapc metoduna bir ardr. Bu baka bir adan
bakldnda, Framework ierisinde yer alan nesne hiyerarisinin ve kaltmn (inheritance) bir
sonucudur. yleki, .net bnyesinde yer alan her nesne mutlaka en tepede yer alan Object
snfndan treyerek gelmektedir.

Bir yapc metodun IL kodu ierisinde, tredii temel snfa ait varsaylan yapc metodu
aryor olmas, kaltm (inheritance) iin nemli bir faktrdr. Bir treyen snf nesne
rnei oluturulduunda, ierideki kapsllenmi tiplere ilgili deerler atanmadan daha
nce, temel snfn yapcs (default constructor) arlr. Bu mekanizma, treyen snfa
ait nesne rnei oluturulurken, base anahtar szc yardmyla ortak deikenlere ait
deerlerin temel snfa(lara) kolayca aktarlabilmelerini salar.

www.bsenyurt.com Page 1727


Buradaki kodlama aslnda yapc metod balatclar (constructor initializers) kullanlarak daha sade
ve merkeziletirilmi bir hale getirilebilir. Merkeziletirilmeden kast, atamalarn tek bir yerde
toplanmasdr. Bunun en byk faydas kodun bakm ve onarm srasnda ortaya kar. Sonu
itibariyle yapc metodlarmzn ortak noktas, gelen parametreleri ayn ekilde atamaya
almalardr. Dolaysyla Dortgen snfn this anahtar szcn de kullanarak aadaki gibi de
gelitirebiliriz.

class Dortgen_ // :Dortgen_Taban


{
private int m_AKenari;
private int m_BKenari;

public Dortgen_():this(1,1)
{
}
public Dortgen_(int akenari):this(akenari,akenari)
{
}
public Dortgen_(int akenari,int bkenari)
{
m_AKenari=akenari;
m_BKenari=bkenari;
}
public double Alan()
{
return m_AKenari*m_BKenari;
}
}

Bu sefer Dortgen snfnn her bir yapc metodu aslnda en genel yapc metodu arp, this anahtar
szc yardmyla ortamdan gelen parametreleri tek bir noktaya aktarmaktadr. Bu teknik kod
okunurluunu daha da kolaylatrr. Ayrca, deer atamalarnn bakmn olumlu ynde etkiler.
nk her hangibir deiiklik iin tm yapc metodlar gezmektense, sadece atamalarn yapld
asl yapc metodu deitirmek ok daha aklc bir yoldur. Ancak her iki uygulama teknii arasndaki
farklar bunlar ile snrl deildir. Asl fark grebilmek iin yine IL kodlarna bakmamz gerekir.

www.bsenyurt.com Page 1728


Grdnz gibi bu sefer Object snfna ait varsaylan yapc metod sadece this anahtar szckleri
ile parametreleri ynlendirdiimiz merkezi yapc metod ierisinden arlmaktadr. Bu kodun
ierisinde alma zamannda object nesneleri iin tahsis edilecek bellek miktarn biraz da olsa
azaltan bir faktrdr. Tabi durumu bir de hz asndan incelemek gerekir. Her iki teknik
uygulanabilirlik, merkeziletirme, idareli bellek kullanm asndan olduka farkldr aslnda. Ama
aadaki rnek kodu uyguladmzda ok daha farkl bir sonucu elde edeceimizi grrz.

class TestUygulama
{
static void Main(string[] args)
{
DateTime dtSimdi;
TimeSpan fark;

#region birinci tip constructor kullanm (initializers ile)

www.bsenyurt.com Page 1729


dtSimdi=DateTime.Now;
for(int i=1;i<500000;i++)
{
Dortgen_ d1=new Dortgen_();
d1.Alan();
}
fark=DateTime.Now-dtSimdi;
Console.WriteLine("Birinci tip constructor kullanm {0} (Initializers
ile)",fark.TotalMilliseconds.ToString());

#endregion

#region ikinci tip constructor kullanm

dtSimdi=DateTime.Now;
for(int i=1;i<500000;i++)
{
Dortgen d2=new Dortgen();
d2.Alan();
}
fark=DateTime.Now-dtSimdi;
Console.WriteLine("kinci tip constructor kullanm {0} ",fark.TotalMilliseconds.ToString());

#endregion
}
}

Buradaki ilk dngmz, yapc balatclar (constructor initializers) kullanan Dortgen_ nesnesine ait
500000 nesne rneini oluturur ve alan hesab yapar. kinci dngmz ise, her bir deer
atamasnn kendi yapc metodu ierisinde yapld ilk tekniimizi kullanr. Uygulamay test
ettiimizde her iki dngnn tamamlanma sreleri arasnda belirgin bir fark vardr.

Sanlann aksine this kullanlan teknik, dierine gre daha yava almaktadr. Bu elbetteki gz
ard edilebilecek bir sre farkdr. Alternatif bir yntem olarak deer atamlarnn yapld ortak bir
metod, her bir constructor iinden ayr ayr arlabilir. Yani aadaki Dortgen_2 snfnn
kodlarnda olduu gibi.

public class Dortgen_2


{
private int m_AKenari;
private int m_BKenari;

www.bsenyurt.com Page 1730


public Dortgen_2()
{
Atama(1,1);
}
public Dortgen_2(int akenari)
{
Atama(akenari,akenari);
}
public Dortgen_2(int akenari,int bkenari)
{
Atama(akenari,bkenari);
}
public double Alan()
{
return m_AKenari*m_BKenari;
}
private void Atama(int akenari,int bkenari)
{
m_AKenari=akenari;
m_BKenari=bkenari;
}
}

Burada atama ilemleri sadece bu snf ierisinden eriilebilen (private) bir metod ile
salanmaktadr. Bu merkeziletirmeyi ve bakmn kolaylatrlabilmesini salar. Ancak this kullanm
terk edildii iin IL kodunda yine her bir yapc metod ierisinde, Object snfna ait varsaylan yapc
metodun arlmas durumu devam etmektedir.

www.bsenyurt.com Page 1731


Elbette bu artlar gz nne alndnda seim yapmak zorlamaktadr. Hangisi olursa olsun
alacaktr. Ancak ben performans asndan kayba neden olsa da, merkeziletirme, bakm ve
onarm kolayl salad dnldnde yapc balatclarn (constructor initializers) kullanmay
tercih ediyorum. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Boxing ve Unboxing Performans Kritii (


26.09.2005 ) - C#
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1732


Bundan yaklak olarak iki sene nce boxing ve unboxing kavramlar ile ilgili
bir makale (30.12.2003) yazmtm. Aradan uzun sre geti. Ancak boxing ve unboxing kavramlar
ile ilgili olarak halen daha dikkat edilmesi gereken hususlar var. Bunlardan bizim iin en nemlisi
elbetteki performans zerine etkileri. Uygulamalarmzda ok sk olarak farknda olmadan veya
farknda olaraktan boxing ve unboxing ilemlerinin yer ald kod paralarn kullanyoruz. Bildiiniz
gibi boxing, bir deer trnn, referans trn atanmas srasnda gerekleen ileme verilen
isimdir. Unboxing ise bunun tam tersi olmakta ve referans trnn tekrar deer trne
dntrlmesini kapsamaktadr. Hangisi olursa olsun, deer trlerinin tutulduu stack bellek
blgesi ile, referans trlerinin tutulduu heap bellek blgesi arasnda yer deitirme ve kopyalama
ilemleri sz konusudur.

ster boxing ister unboxing ilemi sz konusu olsun, bellek zerinde stack ve heap
blgeleri arasnda yeniden adresleme ve kopyalama ilemi sz konusudur.

te bu adresleme ve kopylama ilemlerinin uygulama ierisinde saysz defa tekrar ediyor olmas
performans olumsuz ynde etkileyen en nemli nedenlerden birisidir. Bunu daha iyi anlamadan
nce, boxing ve unboxing ilemlerini biraz daha alt seviyede incelemek gerekir. ok basit olarak
aadaki console uygulamasnn MSIL (Microsoft Intermediate Language) koduna bir gz atalm.

using System;

namespace InvestigateOfBoxingUnBoxing
{
class Class1
{
static void Main(string[] args)
{
int deger=25;
object obj=deger; // Boxing
int sonuc=(int)obj; // Unboxing
}
}
}

lk olarak integer tipinden bir deer trn, object tipinden bir referans trn atyoruz. Daha
sonra ise artk kutulanm (boxing ilemine tabi tutulmu) referans trnn deerini bilinli bir tip
dnm (explicitly cast) ilemi ile tekrar deer trnden bir deikene atyoruz. Bu kodun IL
kts aadaki gibi olacaktr.

.method private hidebysig static void Main(string[] args) cil managed


{
.entrypoint
// Code size 19 (0x13)
.maxstack 1
.locals init ([0] int32 deger,
[1] object obj,
[2] int32 sonuc)

www.bsenyurt.com Page 1733


IL_0000: ldc.i4.s 25
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: box [mscorlib]System.Int32
IL_0009: stloc.1
IL_000a: ldloc.1
IL_000b: unbox [mscorlib]System.Int32
IL_0010: ldind.i4
IL_0011: stloc.2
IL_0012: ret
} // end of method Class1::Main

Grdnz gibi, IL_0004 ve IL_000b segmentlerinde box ve unbox komutlar altrlarak


referans ve deer trleri aras bellek konumlandrma ve kopyalama ilemleri yaplmtr. Bunun
zaten byle olacan kodlarmzdan da biliyoruz. Peki IL kodunun bu ktsnn bizim iin
nemi nedir? Hereyden nce bunu aadaki masumane kod parasn ele alaraktan anlamaya
almakta fayda var.

using System;

namespace InvestigateOfBoxingUnBoxing
{
class BoxUnBox
{
public static void EkranaYaz(int yaricap,double pi)
{
double alan=yaricap*yaricap*pi;
Console.WriteLine("Yaricapi {0} olan dairenin alan = {1} dr.",yaricap,alan);
}
}
class Class1
{
static void Main(string[] args)
{
BoxUnBox.EkranaYaz(10,3.14);
}
}
}

Bu rnekte odaklanmamz gereken yer BoxUnBox snfmz ierisinde int tipinden yariap deerini
ve double tipinden pi deerini alan EkranaYaz isimli metodtur. Bu metod ierisinde standart olarak
alan hesabn yaptktan sonra sonular ekrana yazdrmak iin Console snfnn WriteLine metodunu
kullanyoruz. imdi uygulamann IL koduna tekrar bakalm. EkranaYaz metodunun ierisinde yer
alan aadaki satrlar bizim iin olduka nemlidir.

IL_000c: ldarg.0

www.bsenyurt.com Page 1734


IL_000d: box [mscorlib]System.Int32
IL_0012: ldloc.0
IL_0013: box [mscorlib]System.Double
IL_0018: call void [mscorlib]System.Console::WriteLine(string, object, object)

Grdnz gibi deer trlerimiz boxing ilemine tabi tutulmu ve WriteLine metoduna object
tipinden geirilmitir. Halbuki biz kodumuzda basit olarak sonular ekrana yazdrmaya alyoruz.
u noktada bellek zerinde, stack ve heap arasnda bir veri deitokuu olacan dnmeyebiliriz.
Ancak IL kodlarnn da syledii gibi box ve unbox komutlar arlmtr. Oysaki ayn kodu
aadaki stilde yazsaydk eer;

public static void EkranaYaz(int yaricap,double pi)


{
double alan=yaricap*yaricap*pi;
Console.WriteLine("Yaricapi {0} olan dairenin alan = {1}
dr.",yaricap.ToString(),alan.ToString());
}

bu durumda deer trlerimiz iin bir boxing ilemi uygulanmayacakt. Aslnda WriteLine metodunun
bekledii object trnden bir atama sz konusudur. Biz bunu daha parametreyi geirirken deer
trnn ToString() metodu ile salam oluyoruz. Dolaysyla, IL kodlarna tekrar bakacak olursak
box ve unbox komutarnn arlmadn, bir baka deyile boxing ve unboxing ilemlerinin
yaplmadn grrz.

IL_000c: ldarga.s yaricap


IL_000e: call instance string [mscorlib]System.Int32::ToString()
IL_0013: ldloca.s alan
IL_0015: call instance string [mscorlib]System.Double::ToString()
IL_001a: call void [mscorlib]System.Console::WriteLine(string, object, object)

Grdnz gibi her hangibir box komutu arlmamtr. yi herey hota, ayn sonular elde
ettiimiz her iki kod rneinden hangisini tercih etmeliyiz. Bu durumu analiz edebilmek iin
aadaki rnek uygulamay gz nne almakta fayda var. Amacmz boxing uyguland ve
uygulanmad durumlarda sresel farklar tespit ederek performans deerlendirmesi yapabilmek.

static void Main(string[] args)


{
#region Boxing ieren kod ksm
DateTime suAn=DateTime.Now;
for(int i=1;i<50000;i++)
{
double alan=i*i*3.14;
Console.WriteLine("Yaricapi {0} olan dairenin alan = {1} dr.",i,alan); // Boxing var...
}

www.bsenyurt.com Page 1735


TimeSpan tsBox=DateTime.Now-suAn;
#endregion

#region boxing iermeyen kod ksm


suAn=DateTime.Now;
for(int i=1;i<50000;i++)
{
double alan=i*i*3.14;
Console.WriteLine("Yaricapi {0} olan dairenin alan = {1}
dr.",i.ToString(),alan.ToString()); // Boxing yok...
}
TimeSpan tsNoBox=DateTime.Now-suAn;
#endregion

Console.WriteLine("------------");
Console.WriteLine("Boxing olduunda..."+tsBox.TotalMilliseconds.ToString());
Console.WriteLine("Boxing olmadnda..."+tsNoBox.TotalMilliseconds.ToString());
}

Uygulama kodumuz her ne kadar anlamsz grnse de sonu gerekten ok ilgintir. Uygulamann
tespit ettii sreler aslnda ortalama deerlerdir. Bu genellikle kullandnz makinenin donanmsal
yeteneklerine gre deiiklik gsterebilir. Ancak tabiki nemli olan hangisinin daha hzl olduudur.

Her iki region altndaki kodlarda ayn ii yapar. 50000 kez i deeri zerinden alan hesab yaparak,
sonular ekrana yazar. Ancak her iki teknik arasnda zellikle de WriteLine metodlar ierisinde az
nce bahsettiimiz ToString() kullanm fark vardr. lk region ierisindeki kodlarmzda ToString
metodunu kullanmadk. Bu sebeplede, deerler ekrana yazdrlmadan nce boxing ilemi sz
konusu olacaktr. Ancak ikinci region blgesindeki kodlarmzda yer alan WriteLine metodunda ise
deer trlerimiz iin ToString metodunu kullanyoruz. Sonuta sre fark nemsenecek derecede
yksektir. kinci teknik daha hzl sonu almamz salamtr. Her ne kadar yukardaki gibi bir
rnei pek kullanmayacak olsanzda, geni apl uygulamalar dnldnde gereksiz yere
yaplan boxing ve unboxing ilemleri, uygulamann genelinde nemli oranda performans ve hz
kaybna neden olabilir.

Boxing ve Unboxing ilemlerinin sk olarak grld dier bir durum ise koleksiyonlarn kullanld
uygulamalarda gze arpmaktadr. zellikle koleksiyonlara eleman aktarlrken veya koleksiyon
ierisindeki bir eleman okunurken boxing ve unboxing ilemleri ile karlalmaktadr. Burada
eleman saysnn ykselmesi, gerekleen boxing ve unboxing ilemlerinin saysn arttracaktr.
Dolaysyla stack ve heap arasndaki kopyalama ve yer deitirme ilemleride olduka
fazlalaacaktr ki bu da uygulamann yavalamasna neden olan bir faktrdr. Sz gelimi aadaki
rnek uygulamay gz nne alalm. Burada Urun isimli struct (yap) tipinden bir nesnemizi ilk nce
bir ArrayList koleksiyonunda, ardndan object tipinden bir dizide ve son olarakta kendi tipinden bir

www.bsenyurt.com Page 1736


dizide kullanyoruz.

using System;
using System.Collections;

namespace InvestigateOfBoxingUnBoxing
{
public struct Urun
{
private int m_Fiyat;
public int Fiyat
{
get
{
return m_Fiyat;
}
set
{
m_Fiyat=value;
}
}

public Urun(int fiyat)


{
m_Fiyat=fiyat;
}
}
class Class1
{
static void Main(string[] args)
{
#region ArrayList koleksiyonu kullanldnda
ArrayList alUrun=new ArrayList();
DateTime dtSuan=DateTime.Now;
for(int i=1;i<500000;i++)
{
alUrun.Add(new Urun(i*1000)); // boxing olacaktr
}
TimeSpan tsFark=DateTime.Now-dtSuan;
Console.WriteLine("ArrayList Kullanm........."+tsFark.TotalMilliseconds.ToString());
#endregion

#region object dizisi kullanldnda


object[] objUrunler=new object[500000];
dtSuan=DateTime.Now;
for(int i=1;i<500000;i++)
{
objUrunler[i]=new Urun(i*1000); // boxing olacaktr

www.bsenyurt.com Page 1737


}
tsFark=DateTime.Now-dtSuan;
Console.WriteLine("Object Dizisi Kullanm........."+tsFark.TotalMilliseconds.ToString());
#endregion

#region Struct tipinden bir dizi kullanldnda


Urun[] urunList=new Urun[500000];
dtSuan=DateTime.Now;
for(int i=1;i<500000;i++)
{
urunList[i]=new Urun(i*1000); // deer trne aktarma var. Yani boxing
yok...
}
tsFark=DateTime.Now-dtSuan;
Console.WriteLine("Struct Dizisi Kullanm........."+tsFark.TotalMilliseconds.ToString());
#endregion

}
}
}

Eer Main metodumuzun IL koduna bakacak olursak, ArrayList koleksiyonunu ve object dizisini
kullandmz dngler iin box komutunun arldn kolayca grebilirsiniz. Bunun sebebi struct
tipimizin deer tr olmasdr. ArrayList ve object dizilerimizin elemanlar ise object tipinden bir
baka deyile referans trndendir. Dolaysyla ArrayList' e ve object tipinden olan dizimize, Urun
isimli struct' mza ait nesne rneklerini eklemeye altmzda, deer trnden referans trne
gei (boxing) ilemi sz konusu olacaktr. Tahmin edeceiniz zere bu performans ve hz kaybna
neden olan bir durumdur.

www.bsenyurt.com Page 1738


yleki uygulamay altrdmzda Urun isimli struct tipinden dizinin kullanld dngnn,
dierlerine gre belirgin olarak daha hzl altn grebiliriz.

www.bsenyurt.com Page 1739


Elbette bu tip koleksiyonlar kullandnz durumlarda sadece Urun tipinden nesneler tanacak ise,
yine Urun tipinden bir nesne dizisini kullanmak en mantkl seimdir. Ama ou zaman kod
yazarken bu gibi durumlar gzden karrz. Burada belkide en byk problem elimizdekiler ile tam
olarak ne istediimizi bilemememizdir. Urun tipinden bir diziye ihtiyacm var ise bir koleksiyona
gerek var mdr? Yoksa bir koleksiyonun salad avantajlar kullanamyacam bir diziyi tercih
etmek iin performans ne kadar dnmeliyim? vb...Bu sorulara doru yantlar vererek en uygun
kullanm seebiliriz. Bu gibi kullanmlar uygulamann pek ok yerinde var olabilir. te bu sebepten
zellikle deer trlerini ve referans trlerini bir arada kullanrken boxing ve unboxing ilemlerini
minimize edecek tekniklere gidilirse performans olarak byk kazanmlar salanlabilir. lk
zamanlarda bunu amak iin IL kodu ile biraz daha fazla harneir olmamz gerekebilir. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Using fadesi ile Garanti Dispose ( 20.09.2005 ) -


C#
Deerli Okurlarm Merhabalar,

Bellek ynetimi zellikle byk apl projelerde performans kazanm asndan ok nemlidir.
Gnmz sistemlerinin yksek Ram kapasitesine sahip olduklar gz nne alndnda bu durum
ou zaman gz ard edilmektedir. Ancak saysz kullancnn baland sunucu(server) sistemleri
zerinde alan windows veya web servisleri gibi uygulamalar gz nne alndnda bellek
sorunlar ile her zaman iin karlalma olasl vardr.

Bildiiniz gibi .Net arlkl olarak ynetimli kodu (managed code) desteklemektedir. CLR (Common
Language RunTime - Ortak Dil alma Zaman), yazm olduumuz uygulamar altrmaktan,
kaynaklar ynetmekten ve sonlandrmaktan sorumlu bir ortam olarak bu ynetim iini stlenmitir.
CLR ierisinde istisna ynetimi, tip gvenlii gibi eitli kontrol ve ynetim mekanizmalar vardr.
Bunlardan belkide en nemlisi (uygulama gelitiricileri zellikle C++' tan gelenleri bir nebze olsun
rahatlatan) GC (Garbage Collector- p Toplayc) mekanizmasdr. GC, kapsama alan (scope)
dna kan referans tiplerinin bellekten atlmas grevini stlenir. Oysaki C++ ile gelitirilen
uygulamalarda, nesnelerin bellekten atlmas elle yaplmak zorundadr. Dolaysyla GC uygulama
gelitiricilere byk avantaj salar.

GC' nin salam olduu ynetim mekanizmas her ne kadar avantajl gzksede uygulamalarn
performans asndan dikkat edilmesi gereken bir nokta vardr. GC ileri biten referans trlerini
bellekten annda atmaz. Bu atlma sresi genelde belirsizdir ve nesnenin kendisinin bal olduu
baka referanslara veya nesnenin iinde bulunduu kapsama alannn (scope) yaam sresine gre
deimektedir. Bahsi geen sreler, zellikle birbirlerine bal referans trlerinin ok fazla sayda
kullanld sunucu uygulamalarnda bellein gereksiz yere ismesine neden olmaktadr. (Hatta ben
gelitirmi olduumuz bir projede OutOfMemoryException hatasn grebildiimi syleyebilirim.)
Aslnda bu durumu anlayabilmek iin bellek zerinde referans tiplerinin tutuluunu ve GC
tarafndan sistemden kaldrln ok basit seviyede dnmek gerekir. Aadaki senaryoda basit
olarak bu durum incelenmeye allmaktadr.

Bir uygulamamz olduunu ve uygulama kodlarnn alma zamannda 3 farkl nesneyi


oluturduunu dnelim. Bu nesne rnekleri bizim kendi oluturduumuz tiplere ait olabilecei
gibi FCL (Framework Class Library) ierisinde yer alan tiplerden de olabilir. Burada nemli olan
bunlarn referans trnden olmalar ve new operatr ile oluturulmalardr. Bildiiniz gibi referans
trleri bellein heap ad verilen blgesinde tutulmaktadr. Bu durumda bellein heap blgesindeki
yerleim aadakine benzer bir yapda farzedilebilir.

www.bsenyurt.com Page 1740


Burada nesnelerin arka arkaya dizildiini gryorsunuz. ou zaman uygulamalarmzda nesneler
ile iimiz bittiinde (zellikle kendi yazdmz snflara ait nesneler ile iimiz bittiinde ) bu nesneye
ait kaynaklar serbest brakmak amacyla null deer atamasna bavururuz. Nesne rneine null
deer atanmas aslnda o nesneye izleyen kod satrlarnda eriilememesini garanti eden bir
durumdur. Peki ya bu nesneye ait bellek kaynaklar gerekten ne zaman serbest kalacaktr.
Senaryomuza geri dnelim. Null deer atamas yaptmzda bellek grnmnde herhangibibir
deiiklik olmaz. Sadece Y Nesnesi artk eriilebilir konumda deildir nk onu iaret eden
adresleme artk mevcut deildir.

u noktada yeni bir nesne rneini daha oluturduumuzu dnelim. Aslnda oluturmaya
altmz dnrsek daha iyi olur. rnein Q nesnemizin aadaki gibi bellekte
konumlanacan farzedelim.

Burada Q nesnemizin boyutunun, bellein snrlarn atn temsil etmeye alyoruz. Bu


OutOfMemoryException' a yol aabilecek bir durumdur. Neyseki Garbage Collector (Artk Toplayc)
durum bu noktaya gelmeden nce devreye girererek managed code ierisinde almakta olan
referans trlerini gzden geirir ve uzun sredir kullanlmayan nesnelerin olup olmadn devaml
suretle kontrol eder. Bu senaryoya gre ilk yapaca i null atamas yaplm nesneyi bulmak ve
bellekteki adreslemeleri yeniden dzenleyerek yer tahsislerini kaydrmaktr. Sonu olarak bellein
yeni grnm aadaki gibi olacaktr.

Bu durum kapsama alanndan kan her nesne iin geerlidir. Ksacas,

GC, kapsama alan dna km olan nesnelere ait kaynaklar hemen serbest brakmaz.
Bu serbest brakma sresi genellikle belli deildir. Srenin belirsiz oluu ve gereksiz
nesneler toplanncaya kadar bellekte kalarak adres alan igal ediyor olmalar sistemin

www.bsenyurt.com Page 1741


yavalamasna neden olur.

Elbetteki GC' nin yapt ii kmseyemeyiz. Bellekteki kullanm d kalm nesnelerin bir
mekanizma sayesinde otomatik olarak sistemden kaldrlmas gerekten iimizi kolaylatrmaktadr.
Ancak yukardaki gibi bir senaryoyu gz nne aldmzda bellek zerindeki nesnelere ait yaplan
yer deitirmeler uygulamann yavalamasna neden olacaktr. te bu yzden kullandmz
nesneler ile ilgili iimiz bittiinde onlara ait bellek kaynaklarnn kesin olarak serbest braklmasn
salamak isteyebiliriz. Bu noktada IDisposable arayznden tremi nesnelerin Dispose metodlarn
kullanabiliriz. Dispose metodunda gerekli kodlamalar yaparak ilgili nesnenin annda bellekten
atlmasn salayabiliriz.

Bir nesne zerinde Dispose metodunu kullanabilmek iin, bu nesnenin IDisposable


arayzn mutlaka implemente etmesi gerekmektedir.

FCL ierisinde yer alan saysz nesne IDisposable arayzn uygulamaktadr. Bu nesneleri using
ifadesi ile veya try-catch-finally blounun uyguland desenler yardmyla bellekten daha ksa
srede atabiliriz. lk olarak try-catch-finally blou ile bu ii nasl gerekletirebileceimize bakalm.
Aadaki rnek kod paras, basit olarak bir referans tipinin ii bittiinde derhal bellekten
atlmasnn nasl salanacan gstermektedir.

using System;
using System.Data;
using System.Data.SqlClient;

namespace InvestigateForDispose
{
class AnaProgram
{
static void Main(string[] args)
{
SqlCommand cmd=null;
SqlConnection con=null;
try
{
con=new SqlConnection("data source=localhost;database=AdventureWorks2000;user
id=sa;password=");
cmd=new SqlCommand("SELECT TOP 1 * FROM Customer",con);
con.Open();
cmd.ExecuteNonQuery();
}
catch(SqlException exp)
{
Console.WriteLine(exp.Message);
}
finally
{
con.Dispose();

www.bsenyurt.com Page 1742


cmd.Dispose();
}
}
}
}

Finally bloklar try blounda yer alan kodlarda istisna frlatlmasna neden olacak hatalar olsa da
olmasa da devreye girer. Bu sebeple serbest braklacak nesneler iin Dispose metodlarn
aracamz en uygun yer finally bloklardr. Yukardaki rnekte yer alan SqlConnection ve
SqlCommand, IDisposable arayzn implemente eden snflardr. Bu sebepten Dispose metodlar
mevcuttur. Yukardaki desenin salad ilevselliin aynsn using ifadesi ile de gerekletirebiliriz.
Aadaki kod paras yukardaki rnein using ifadeleri ile nasl kodlandn gstermektedir.

using(SqlConnection con=new SqlConnection("data


source=localhost;database=AdventureWorks2000;user id=sa;password="))
{
using(SqlCommand cmd=new SqlCommand("SELECT TOP 1 * FROM Customer",con))
{
con.Open();
cmd.ExecuteNonQuery();
}
}

Using blounun yazm try-catch-finally desenine gre daha kolaydr. Aslnda Using blouda bir nevi
try-finally bloudur. Bu durumu daha iyi anlayabilmek iin using ifadesinin MSIL (Microsoft
Intermediate Language) koduna bakmakta fayda var. ILDASM arac ile uygulamamzn Main
metodundaki kodlara baktmzda aslnda Dispose ilemi iin try-finally bloklarnn uygulandn
grrz. Bir baka deyile using ifademiz IL kodu ierisinde try-finally blouna dntrlmtr.

.method private hidebysig static void Main(string[] args) cil managed


{
.entrypoint
// Code size 61 (0x3d)
.maxstack 3
.locals ([0] class [System.Data]System.Data.SqlClient.SqlConnection con,
[1] class [System.Data]System.Data.SqlClient.SqlCommand cmd)
IL_0000: ldstr "data source=localhost;database=AdventureWorks2000;"
+ "user id=sa;password="
IL_0005: newobj instance void
[System.Data]System.Data.SqlClient.SqlConnection::.ctor(string)
IL_000a: stloc.0
.try
{
IL_000b: ldstr "SELECT TOP 1 * FROM Customer"
IL_0010: ldloc.0
IL_0011: newobj instance void

www.bsenyurt.com Page 1743


[System.Data]System.Data.SqlClient.SqlCommand::.ctor(string,
class [System.Data]System.Data.SqlClient.SqlConnection)
IL_0016: stloc.1
.try
{
IL_0017: ldloc.0
IL_0018: callvirt instance void
[System.Data]System.Data.SqlClient.SqlConnection::Open()
IL_001d: ldloc.1
IL_001e: callvirt instance int32
[System.Data]System.Data.SqlClient.SqlCommand::ExecuteNonQuery()
IL_0023: pop
IL_0024: leave.s IL_0030
} // end .try
finally
{
IL_0026: ldloc.1
IL_0027: brfalse.s IL_002f
IL_0029: ldloc.1
IL_002a: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_002f: endfinally
} // end handler
IL_0030: leave.s IL_003c
} // end .try
finally
{
IL_0032: ldloc.0
IL_0033: brfalse.s IL_003b
IL_0035: ldloc.0
IL_0036: callvirt instance void [mscorlib]System.IDisposable::Dispose()
IL_003b: endfinally
} // end handler
IL_003c: ret
} // end of method AnaProgram::Main

Biz uygulamamzda i ie iki using blou kullandmzdan, uygulamann IL kodunda i ie gemi


iki try-finally blou yer almaktadr. Dikkat ettiyseniz finally bloklarnda SqlConnection ve
SqlCommand nesnelerine ait Dispose metodlar arlmtr. Eer IDisposable arayzn
implemente etmemi bir nesne rnei iin using veya try-catch-finally desenini kullanrsak derleme
zaman hatas alrz.

Using blou iin aadaki hata alnr.

www.bsenyurt.com Page 1744


Try-catch-finally deseninde de zaten Nesne zerinden eriebileceimiz bir Dispose metodu yoktur.

www.bsenyurt.com Page 1745


Aslnda bu gibi durumlarda using blounda kullanlacak nesnenin IDisposable arayzn uygulayp
uygulamadn bilmek ve buna gre davranmak olduka etkili bir yaklam olabilir.

Peki kendi snflarmza Dispose yeteneini nasl kazandrabiliriz? Bunun iin snfmza IDisposable
arayzn uygularz. IDisposable arayz sadece Dispose metoduna ilikin bir bildirim ierir. Snfn
Dispose metodunda managed ve unmanaged kaynaklar iin gerekli yoketme ilemlerini
gerekletirebiliriz.

class VeriYonetim:IDisposable
{
public VeriYonetim()
{}
public void Baglan()
{}

#region IDisposable Members

public void Dispose()


{
// Managed ve Unmanaged kaynaklarn serbest braklmas.
}

#endregion
}

www.bsenyurt.com Page 1746


class AnaProgram
{
static void Main(string[] args)
{
using(VeriYonetim vy=new VeriYonetim())
{
// Bir takm ilemler
}
}
}

Disposable nesnelerin kullanmnda dikkat edilmesi gereken bir nokta daha vardr. Baz durumlarda,
nesne rneklerimiz unmanaged (ynetilmeyen) referanslara sahip olabilirler. Bu tip unmanaged
referanslar sz konusu olduunda bunlarn ak bir ekilde sonlandrlmalar gerekir. Bu bir
nesnenin yaam dzeni ile ilgilidir. yleki bir nesne heap blgesinde geirdii zaman sresi
boyunca aadaki ekilde tasvir edilen evrelerden geer.

Her nesne nce oluturulur. ounlukla new operatr ile gerekletirilen bu ilemin ardndan
nesne uygulama ierisinde kullanlr. Kullanm sona erdiinde ve nesne scope (kapsama alan)
dna ktnda kullanlamaz hale gelir. Bu makalenin banda belirttiimiz gibi nesneye ait
kaynaklarn serbest braklmas anlamna gelmez. Sadece referans yok edilmitir. Daha sonra
nesnemiz sonlandrlabilir hale gelir ve nesne mr sonlandrlr. Sonlandrma ileminde genellikle
nesne ierisinde var olan unmanaged referanslarn bellekten atlmas ilemi gerekletirilir.
Nihayetinde sonlandrlm nesneye ait bellek blgeleri serbest braklr. te biz Dispose metodunu
ve SuppressFinalize metodunu kullanarak sonlandrma aamasn otomatik olarak atlayabilir ve
nesneye ait kaynaklarn iade edilmesini salayabiliriz.

www.bsenyurt.com Page 1747


Bir nesnenin referans ettii unmanaged kaynaklar yok etmek iin ya Dispose metodunun
ierii kullanlr ya da snfa ait destructor(yokedici) metod ierisinde bu yok etme ilemi
gerekletiriliz.

Peki byle bir imkan var ise neden sonlandrma sreci sz konusudur? Managed olarak
oluturulmu nesneler GC kontrolnde yok edilirler. Ancak ierisinde unmanaged referanslar var
ise, bu referanslarn aka yok edilmeleri bir baka deyile kaynaklarnn serbest braklmalar
gerekir. Oysaki GC bu ilemin nasl yaplabileceini tahmin edemez. Bu tarz durumlarda
unmanaged referanslara ait kaynaklar serbest brakmak iin nesnelerin destructor metodlarndan
faydalanlabilir. Dier yandan her nesne iin GC tarafndan ynetilen bir sonlandrma
kuyruu(finalizable queue) sz konusudur. Bu kuyruk finalize edilebilir nesneleri tutan bir
koleksiyondur. GC oluturulan nesneler iin buraya giri yapar ve nesne sonlandrma srecine
girdiinde ilgili sonlandrma ilemini uygulayaca nesne bilgilerini almak iin yine bu kuyruu
kullanr. Eer ki Dispose etmek istediimiz nesnenin unmanaged referanslar varsa bunlarda
dispose ilemi ile birlikte annda serbest brakmak iin GC snfnn SuppressFinalize metodu
kullanlabilir.

Bu koullar gz nne alndnda ounlukla kullanlan bir desen vardr. Bu desende hem
IDisposable arayz implemente edilir hemde snfa ait desctructor (yokedici) metod kullanlr.
Desctructor metodlar bildiiniz gibi nesne GC tarafndan yok edilmeden nce alan son metoddur.
Burada ounlukla unmanaged referanslarn serbest braklma ilemleri ele alnr. Sz konusu
desen aadaki yapya sahiptir.

class VeriYonetim:IDisposable
{
~VeriYonetim()
{
Dispose(false);
}

protected virtual void Dispose(bool disposeDurumu)


{
if(disposeDurumu==true)
{
// Managed kaynaklar iin Dispose metodu uygulanr.
}
// UnManaged kaynaklar temizlenir.
}

#region IDisposable Members

public void Dispose()


{
Dispose(true);
GC.SuppressFinalize(this);
}

#endregion

www.bsenyurt.com Page 1748


}

Bu desendeki yaklam ksaca udur; nesnemizi eer Dispose metodunu kullanarak arrsak bu
durumda overload ettiimiz ve sadece bu snftan treyen snflar tarafndan eriilip override
edilebilen Dispose metodu devreye girecektir. Bu metod ierisinde managed kodlarmz iin gerekli
temizleme ilemleri yaplr. Hemen ardndan da unmanaged kaynaklar silinir. Peki desctructor
metodu neden kullanyoruz?

Nesnemizin illede aka Dispose edilmesi gibi biri durum sz konusu deildir. Pekala, nesne doal
yollardan scope dna ktnda GC tarafndan serbest braklabilir. te bu serbest brakma
anndan hemen nce desctructor metodu devreye girmektedir. Desctructor metodumuzdan yine
overload ettiimi virtual Dispose metodumuzu arrz. Ancak bu kez managed kaynaklar zaten GC
tarafndan serbest braklacandan durumu mdahale etmeyiz. Bu yzden metoda parametre false
olarak gnderilir. Ancak yine de unmanaged kaynaklar bizim tarafmzdan serbest
braklacaktr. Son olarak Dipose metodumuzda kullandmz GC.SuppressFinalize metod arm
ile o anki nesneye ait sonlandrma kuyruundaki kaynaklarda serbest brakm oluruz. Bylece
geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

CallBack Teknii ile Asenkron Metod Yrtmek


( 09.09.2005 ) - C#
Deerli Okurlarm Merhabalar,

ou zaman projelerimizde, almakta olan uygulamalar uzun sreli olarak duraksatacak ilevlere
yer veririz. zellikle grsel tabanl uygulamalarda veritabanlarna ait kapsaml sorgularn yer ald
ilemlerde bu sorunla ska karlalmaktadr. En byk problem var saylan olarak kod satrlarnn
senkron hareket etmesidir. Yani kodlar sras geldike ileyen paralar btnnden olumaktadr.
Bu elbetteki uzun srecek bir sorgunun cevaplar alnmadan izleyen kod satrlarnn ilememesi
anlamna gelmektedir. Oysaki kodlar asenkron olarak altrma ansmzda mevcuttur. Eminim ki
Ado.Net 2.0' da asenkron metod yrtme tekniklerini veya asenkron web servisi uygulamalarnnn
nasl yazlacan duymusunuzdur. Temel prensib hepsi iin ayndr. Merkezde IAsyncResult
arayz tipinden bir nesnenin kullanld temsilci (delegate) tabanl modeller sz konusudur.

Bir temsilci her hangi bir metodun balan adresini iaret eden bir tip (type) tir. Metodlarn
balang adreslerini iaret eden bir temsilci alma zamannda polimorfik bir yapya sahiptir. Bu
sayede yeri geldii zaman kendi desenine uygun her hangi bir metodun yrtlmesini salayabilir.
te bu felsefeden yola karak alma zamannda asenkron olarak yrtlecek metodlarda
oluturulabilir. Bu noktada devreye IAsyncResult arayz (interface) girer. Temel olarak asenkron
olarak altrlmak istenen metod bir temsilci vastasyla yrrle sokulur. Bu anda ortama
IAsyncResult tipinden bir arayz nesnesi dner. Anlk olan bu ilem nedeni ile uygulamann geri
kalan kod satrlar duraksamadan ilemeye devam eder. Ancak bu srada ilgili temsilcinin balatt
ilemler ayr bir thread (i parac) ierisinde yrtlmeye devam etmektedir. Peki yrtlen
thread sonlandnda, retilen sonular ortama nasl alnacaktr? te burada eitli teknikler
kullanlabilir. Bizim bu makalede ileyeceimiz olan teknik Callback modelidir.

Hereyden nce asenkron yrtme tekniinin kalbi olan temsilcilerin MSIL (Microsoft Intermediate
Language) koduna bakmak ve anlamak gerekir. Sz gelimi aadaki gibi bir temsilci tipi
tanmladmz dnelim. Bu son derece yaln bir delegate tanmlamasdr.

www.bsenyurt.com Page 1749


public delegate void Temsilci();

Bu temsilciyi kullandmz her hangi bir uygulamaya ait assembly' ILDASM (Intermeidate
Language DisAssembly) arac yardmyla aarsak IL kodu ierisinde temsilci nesnemize ait iki
metod tanml olduunu grrz.

BeginInvoke ve EndInvoke metodlar tamamyla asenkron ilemler iin gelitirilmitir. BeginInvoke


metodu, temsilcimizin alma zamannda iaret ettii metodu yrrle sokmak ve o anda ortama
bir IAsyncResult arayz nesne rnei gndermek ile ykmldr. BeginInvoke metodu, temsilci
nesnesinin iaret etmi olduu metodu ayr bir thread ierisine atar. EndInvoke metodu ise dikkat
edecek olursanz parametre olarak IAsyncResult arayz tipinden bir nesne rneini alr. te bu
nesne, BeginInvoke ile balatlan process' ten sorumlu olan nesnedir. Dolaysyla EndInvoke
metodu ierisinden, asenkron metodun yer ald process' e ait sonular yakalanp ortama
aktarlabilir.

Callback modelinde BeginInvoke metodunun AsnycCallback temsilci tipinden olan parametresi


kullanlr. Bu nesne asenkron olarak altrlan metoda ait ilemler sonlandnda otomatik olarak
devreye girecek metodu iaret eden temsilci tipinden baka bir ey deildir. En genel kullanmda bu
AsyncCallback temsilcisi EndInvoke metodunu ieren baka bir metodu temsil eder.

Asenkron Callback modelinde, ilemlerin sonulanmasnn hemen ardndan devreye


girecek olan metod Callback metodu olarak adlandrlr. Bu metodu alma zamannda
iaret edebilmek iin zel AsyncCallback temsilci (delegate) tipinden faydalanlr.

imdi en basit haliyle Callback modelini masaya yatralm. Basit olarak aadaki Console
uygulamasn gelitireceiz.

using System;

namespace UsingAsyncCallback
{
public delegate void Temsilci();

www.bsenyurt.com Page 1750


class Yurutucu
{
public void Calistir(Temsilci t)
{
t.BeginInvoke(new AsyncCallback(SonuclariAl),t);
}

public void SonuclariAl(IAsyncResult ia)


{
Temsilci t=(Temsilci)ia.AsyncState;
t.EndInvoke(ia);
}

public void Islemler()


{
Console.WriteLine("Async yrtlecek metod");
}
}

class AnaProgram
{
[STAThread]
static void Main(string[] args)
{
Yurutucu yrtc=new Yurutucu();

#region Asenkron kullanldnda

Temsilci t=new Temsilci(yrtc.Islemler);


yrtc.Calistir(t);
Console.WriteLine("Dier kod satrlar...");

#endregion

#region Asenkron kullanlmadan

// yrtc.Metod();
// Console.WriteLine("Dier kod satrlar...");

#endregion

Console.ReadLine();
}
}
}

lk olarak Temsilci isimli bir delegate tipi tanmladk. Bu tip alma zamannda her hangi bir
parametre almayan ve geri dn tipi bulunmayan (void) metodlar iaret edebilecek cinstedir.
Asenkron ilemlerin toplu olarak yer ald Yurutucu isimli bir snfmz var. Bu snf ierisinde hem

www.bsenyurt.com Page 1751


asenkron metodun balatlmasn salayacaz, hem de ilmelerin sonlanmasnn ardndan devreye
girecek Callback metodumuzu ileteceiz.

Temsilcimizin BeginInvoke ve EndInvoke metodlarn altracak iki metodumuz var. Islemler isimli
metodumuz asenkron olarak yrtmeyi dndmz metod olacak. Calistir isimli metodumuz
Temsilci tipinden bir parametre almakta ve ieride bu nesne zerinden BeginInvoke metodunu
armaktadr. BeginInvoke metodumuzun AsyncCallback temsilcisi tipinden olan parametresi
Islemler isimli metodumuzu iaret edecek ekilde tanmlanmtr. Bu u anlama gelmektedir.
Calistir isimli metod uygulandnda BeginInvoke, temsilcinin iaret ettiim metodu asenkron olarak
yrrle sokacaktr. Asenkron olarak alan metod sonlandnda ise AsyncCallback nesnesinin
iaret ettii SonuclariAl isimli metod otomatik olarak devreye girecektir.

SonuclariAl isimli metodumuz geriye bir deer dndrmez ve sadece IAsyncResult arayz tipinden
bir parametre alr. Bunun sebebi AsyncCallback temsilcisinin bu tipteki metodlar iaret edebilecek
olmasdr. SonuclariAl isimli metodumuz ierisinde EndInvoke metodu ile asenkron ilemlerin
sonucu ortama alnmak istenmektedir. Bunu salayabilmek iin IAsyncResult tipinden parametre
Temsilci tipine dntrlr ki bu sayede temsilci zerinden BeginInvoke arlabilir. Bylece o ana
kadar alm olan ilemlerin sonucunu alabilecek konuma gelmi oluruz.

Model ilk bakta kark gzkebilir. Ancak temel noktalar anladnzda sorun kalmayacaktr. Biz
temsilcimizin BeginInvoke metodu ve EndInvoke metodunun olduunu biliyoruz. Bu metodlar
kullanrken AsyncCallback temsilci tipi ile Callback fonksiyonu olarak EndInvoke metodunu
ardmz bir metodu iaret ediyoruz. Burada dikkat etmemiz gereken AsyncCallback
temsilcisinin geri dn tipi olmayan ve IAsyncResult arayz tipinden nesneleri parametre olarak
alan metodlar iaret edebilecek olmasdr. Bundan sonra tek yapmamz gereken alma
zamannda temsilcimizi iaret edecei asenkron metodu gsterecek ekilde oluturmak ve
BeginInvoke yapsn barndrdan metodu yrrle sokmak. Uygulamamz yukardaki hali ile
altrdmzda aadakine benzer bir ekran grnts elde ederiz.

imdi burada anlamamz gereken nokta udur. Biz temsilcimiz ile iaret ettiimiz metodu
altrdktan sonra normal artlar altnda bu metod sonlanncaya kadar kodun beklemesi ve kod
tamamlandktan sonra kalan satrlarn ilemesi gerekirdi. Oysaki biz metodumuzu asenkron olarak
yrttmzden, temsilci nesnemizin iaret ettii metodu altrdmz kod satrndan sonraki
satrlar daha nceden alabilmitir. Bu ayrm anlamak ok nemlidir. Olay daha iyi
kavrayabilmek iin Main metodundaki kodlar aadaki gibi dzenleyelim.

Yurutucu yrtc=new Yurutucu();

#region Asenkron kullanldnda

// Temsilci t=new Temsilci(yrtc.Islemler);


// yrtc.Calistir(t);
// Console.WriteLine("Dier kod satrlar...");

#endregion

www.bsenyurt.com Page 1752


#region Asenkron kullanlmadan

yrtc.Islemler();
Console.WriteLine("Dier kod satrlar...");

#endregion

Console.ReadLine();

Uygulamay tekrar altrdmzda aadaki sonucu elde ederiz.

Grdnz gibi nce Islemler isimli metodumuz alt. Bu metodun almas bittikten sonra
kalan kod satrlarndan uygulama almaya devam etti. Bunun sebebi ileyiin senkron olarak
yrmesidir.

Callback modeli zellikle veri ekme ilemi uzun sren sorgularn yer ald uygulamalarda olduka
ie yaramaktadr. rnein AdventureWorks2000 veritaban zerinde aadaki gibi bir sorgunun
kullanld bir uygulama gelitirdiimizi dnelim.

SELECT * FROM Customer


INNER JOIN CustomerAddress ON Customer.CustomerID = CustomerAddress.CustomerID
INNER JOIN Address ON CustomerAddress.AddressID = Address.AddressID
INNER JOIN SalesPerson ON Customer.SalesPersonID = SalesPerson.SalesPersonID
INNER JOIN SalesPersonQuotaHistory ON SalesPerson.SalesPersonID =
SalesPersonQuotaHistory.SalesPersonID

Gerek hayatta bu ve bunun gibi daha ok zaman alacak sorgular ska kullanyoruz. Yukardaki
sorgu her ne kadar bizim iin pek bir ey ifade etmesede rnek uygulamamzda Callback modelini
nasl kullanacamza dair uygun bir gecikme sresi salayacak yapdadr. Uygulamamzn deseni
yukardaki ile neredeyse ayn olacak. Ancak bu kez nemli bir fark var. Bu da asenkron olarak
yrtlecek metodumuzun DataSet dndren ve string parametre alan bir yapda olmas.
Dolaysyla bu metodu iare edecek temsilci nesnemizde aadaki gibi olmaldr.

public delegate DataSet Temsilci(string sorguCumlesi);

Eer ILDASM arac ile bu temsilinin MSIL koduna bakacak olursak BeginInvoke ve EndInvoke
metodlarnn bir nceki rneimize nazaran biraz daha farkl oluturulduunu grrz.

www.bsenyurt.com Page 1753


Dikkat ederseniz temsilcimizin string parametresi BeginInvoke metodunun ilk parametresidir.
Ayrca temsilcimizin dn tipide EndInvoke metodunun dn tipi olmutur (DataSet) .

Asenkron yrtlecek olan metodlarmz geri dn tipine ve parametrelere sahip ise,


BeginInvoke ve EndInvoke metodlarda bu yapya gre ekillenecektir. EndInvoke
asenkron metodun dn tipinden deer dndrrken, BeginInvoke asenkron metodda
tanmlanan parametre says kadar parametreyi ek olarak alacaktr.

Dolaysyla hem altrc metodumuzu hem de Callback metodumuzu bu yapya uygun olarak
tasarlamalyz. te rnek kodlarmz.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;

namespace UsingAsyncCallback2
{
public delegate DataSet Temsilci(string sorguCumlesi);

class Yurutucu
{
public DataSet ds;

public void Baslat(Temsilci t,string sorgu)


{
t.BeginInvoke(sorgu,new AsyncCallback(Bitir),t);
}

www.bsenyurt.com Page 1754


public void Bitir(IAsyncResult ia)
{
Temsilci t=(Temsilci)ia.AsyncState;
ds=t.EndInvoke(ia);
Console.WriteLine(ds.Tables[0].Rows[1][5]+" "+ds.Tables[0].Rows[1][6]+"
"+ds.Tables[0].Rows[1][7]);
}

public DataSet SonuclariAl(string sorgu)


{
SqlConnection con=new SqlConnection("data
source=localhost;database=AdventureWorks2000;user id=sa");
SqlDataAdapter da=new SqlDataAdapter(sorgu,con);
DataSet dsSonucKumesi=new DataSet();
da.Fill(dsSonucKumesi);
return dsSonucKumesi;
}
}

class AnaProgram
{
[STAThread]
static void Main(string[] args)
{
Yurutucu yrtc=new Yurutucu();
string sorgu=@"SELECT * FROM Customer INNER JOIN CustomerAddress ON
Customer.CustomerID = CustomerAddress.CustomerID INNER JOIN Address ON
CustomerAddress.AddressID = Address.AddressID INNER JOIN SalesPerson ON
Customer.SalesPersonID = SalesPerson.SalesPersonID INNER JOIN SalesPersonQuotaHistory ON
SalesPerson.SalesPersonID = SalesPersonQuotaHistory.SalesPersonID";
Temsilci t=new Temsilci(yrtc.SonuclariAl);
yrtc.Baslat(t,sorgu);
for(int i=1;i<3000;i++)
{
Console.Write(".");
}
Console.ReadLine();
}
}
}

Uygulamamz altrdmzda yaklak olarak aadakine benzer bir grnt ile karlarz.

www.bsenyurt.com Page 1755


Dikkat ederseniz for dngs balamadan nce asenkron olarak yrtmek istediimiz metodumuz
olan SonuclarAl temsilci nesnemiz yardmyla altrlmtr. Bu ilemin ardndan BeginInvoke
metodumuz asenkron olarak alan SonuclariAl metodunu ayr bir i parasna bir IAsyncResult
arayz nesnesi sorumluluunda devretmitir. BeginInvoke metodunu altrdmzda Callback
metodumuzuda bildirdiimizden sorgu sonuland anda EndInvoke metodunun yer ald Bitir
isimli metod devreye girecektir. Bu metod ierisinde tamamlanan asenkron process' ten sorumlu
IAsyncResult nesne rnei kullanlarak Temsilci nesnemiz elde edilmi ve bu nesne zerinden
EndInvoke arlarak sorgu sonucu elde edilen DataSet alnmtr. Dikkat edin BeginInvoke
metodu geriye bir DataSet nesne rnei dndrmektedir. Son olarak rnek olmas asndan veri
kmesinin ilk satrna ait bir ka alan bilgisi ekrana yazdrlr.

Burada nemli olan nokta, metod almaya baladktan sonra, metodun ierdii sorgunun
sonlanmas beklenmeden for dngsnn devreye girmesidir. For dngs ileyiini srdrrken,
asenkron metodumuz tamamlandnda sonular ekrana yazdrlm ve for dngs kald yerden
ileyiine devam etmitir. te asenkron Callback modeli.

Callback modeli yardmyla asenkron ilemlerin gerekletirilmesi zellikle profesyonel


uygulamalarda byk nem arz etmektedir. zellikle uygulamalarn uzun sre duraksamasn
(donmasn) engelleyebileceimiz bir yoldur. Ancak asenkron modellerde birbirlerini etkileyebilecek
ilemler varsa dikkatli davranlmaldr. Aksi takdirde process' lerin sonsuz dnglere girerek asl
kalmasna neden olabiliriz.

Bylece geldik bir makalemizin daha sonuna bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek Kodlar in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Web Uygulamalarnda Custom Paging (


03.09.2005 ) - Asp.Net
www.bsenyurt.com Page 1756
Deerli Okurlarm Merhabalar,

Gelitirdiimiz web uygulamalarnda zellikle DataGrid kontrollerini kullandmzda sayfalama


ilemini ska kullanrz. Genellikle sayfalama ilemlerini var saylan hali ile kullanrz. Bu modele
gre grid zerinde sayfalama yapabilmek iin PageIndexChanged olayn ele almamz gerekir.
Burada grid kontrolne yeni sayfa numarasn DataGridPageChangedEventArgs parametresinin
NewPageIndex deeri ile verir ve bilgilerin tekrardan yklenmesini salayacak uygulama
kodlarmz yrtrz. Tipik olarak bu tarz bir kullanm aadaki kod parasnda olduu gibi
yaplmaktadr.

private void Doldur()


{
//Balantnn almas, verilerin ekilmesi ve ekilen verilerin DataGrid kontrolne balanmas
}

private void DataGrid1_PageIndexChanged(object source, DataGridPageChangedEventArgs e)


{
DataGrid1.CurrentPageIndex=e.NewPageIndex;
Doldur();
}

Buradaki yaklam gerekten ie yaramaktadr. Ancak aslnda performans asndan baz kayplar
sz konusudur. nk bu tip sayfalama tekniini kullanrken, sayfa linklerine her basmzda ilgili
veri kaynandaki tm veriler ekilmekte ve ekilen veri kmesi zerinde ilgili sayfaya
gidilmektedir. Bu elbetteki byk boyutlu veri kmeleri ile alrken dikkate alnmas gereken bir
durumdur. Nitekim performans olumsuz ynde etkileyecektir. Her ne kadar caching (tampon
bellee almak) teknikleri ile sorunun biraz olsun stesinden gelinebilecek olsa da daha etkili
zmler retebiliriz.

Byk boyutlu veri kmeleri ile alrken uygulanan varsaylan sayfalama teknii hz
kaybna neden olarak performans olumsuz ynde etkileyebilir.

te bu makalemizde zel sayfalama tekniklerinden bir tanesini incelemeye alacaz. Bu teknikte


yer alan paralardan en nemlisi ablon bir tablonun (temporary) kullanlmasdr. lk olarak asl veri
kmesini ele alacamz bir stored procedure (sakl yordam) gelitireceiz. Bu sakl yordammz
ierisinde asl veri kmesinin satrlarn alp temprary bir tabloya aktaracaz. Temporary
tablomuzun en byk zellii identity tipinde 1 den balayan ve 1' er artan bir alana sahip
olmasdr. Biz bu alann deerinden faydalanarak temp tablosu zerinde sayfalama ilemini
uygulayacaz. Buradaki ana fikiri daha iyi anlamak iin aadaki ekile bir gz atalm.

www.bsenyurt.com Page 1757


Senaryomuzda AdventureWorks2000 veritaban ierisinde yer alan Employee isimli tabloyu
kullanacaz. Bu tablo zerinde aadaki select sorgusu iin sayfalama ilemini gerekletireceiz.

SELECT EmployeeID,FirstName,LastName,NationalIDNumber,Title,BirthDate,EmailAddress FROM


Employee

Teorimizi ekil zerinden aklamaya alalm. nce bir temp tablosu oluturacaz. Temp
tablomuzun alanlar yukardaki select sorgusundaki alanlar karlayacak ekilde olacak. Bir de
ekstradan identity alanmz olacak. Sonra select sorgumuzdaki verileri, temp tablomuz ierisine
insert edeceiz. Ardndan temp tablomuz zerinden yeni bir select sorgusu altracaz. Ancak bu
sefer, Where koulumuz olacak ve burada identity alanmz iin bir aralk belirleyeceiz. te bu
aralk sayfann balang ve biti satrlarn belirleyerek istediimiz sayfaya ait verileri elde
etmemizi salayacak.

rnein, verilerimizi 5' er satrlk sayfalara blmek istediimizi dnelim. Bu durumda 2nci
sayfadaki ilk satrn id deerini Baslangic isimli formlmzden 6 olarak bulabiliriz. Yine 2nci
sayfann bitis satrnn deerinide Bitis isimli forml kullanarak 10 olarak bulabiliriz. Grdnz
gibi teori son derece basit. Sayfalamay gerekletirebilmek iin aslnda temp tablodaki identity
alanlarn kullanyoruz. Son olarak bu ilemlerin hepsini bir stored procedure(sakl yordam)
ierisinde barndrarak ilemlerin dorudan sql sunucusu zerinde ne hzl ekilde
gerekletirilmesini salyoruz. te sp kodlarmz.

CREATE PROCEDURE WorkSp_Paging

@SayfaNo INT,

www.bsenyurt.com Page 1758


@GosterilecekSatirSayisi INT

AS

DECLARE @BaslangicID AS INT


DECLARE @BitisID AS INT
DECLARE @SelectSorgusu AS NVARCHAR(255)

-- nce Temporary tablomuzu oluturuyoruz. ID alan nemli.


CREATE TABLE #TempOfEmployee
(
ID INT IDENTITY(1,1),
EmployeeID INT,
FirstName NVARCHAR(50),
LastName NVARCHAR(50),
NationalIDNumber NVARCHAR(15),
Title NVARCHAR(50),
BirthDate DATETIME,
EmailAddress NVARCHAR(50)
)

-- Employee tablosundaki verileri temporary tablomuza aktaryoruz.


SET @SelectSorgusu='SELECT
EmployeeID,FirstName,LastName,NationalIDNumber,Title,BirthDate,EmailAddress FROM Employee'
INSERT INTO #TempOfEmployee EXEC (@SelectSorgusu)

-- Balang ve biti satrlarnn ID alanlarnn deerlerini belirlemek iin formlasyonumuzu


kullanyoruz. SayfaNo ve GsterilecekSatirSayisi sp mize dardan gelen parametreler.
SET @BaslangicID=((@SayfaNo-1)*@GosterilecekSatirSayisi)
SET @BitisID=(@SayfaNo*@GosterilecekSatirSayisi)+1

-- Temporary tablomuz zerinden ilgili ID aralndaki veri setini ekiyoruz.


SELECT ID,EmployeeID,FirstName,LastName,NationalIDNumber,Title,BirthDate,EmailAddress
FROM #TempOfEmployee
WHERE ID>@BaslangicID AND ID<@BitisID

-- Son olarak sistemde bir karmakla yer vermemek iin temporary tablomuzu kaldryoruz.
DROP TABLE #TempOfEmployee
GO

imdi sp' mizi asp.net uygulamamzda kullanalm. zel sayfalama yaptmz iin artk
PageIndexChanged olayn kullanamayacaz. Dolaysyla sayfa linklerini manuel olarak
oluturmamz gerekiyor. Bu durumda DataGrid kontrolmze ait AllowPaging ve
AllowCustomPaging zelliklerinin deerlerini false olarak brakabiliriz. Eer sadece ilk, nceki,
sonraki, son tarznda linkler oluturacak isek iimiz kolay. lgili metodumuza sayfa numarasn ve
gstereceimiz satr saysn parametre olarak gndermemiz yeterli olacaktr. Ancak sayfa
numalarn link olarak sunmak istiyorsak biraz daha fazla abalamamz gerekecek. ncelikle asl ii
yapan metodumuzu aadaki gibi oluturalm. Bu metodumuzda tanmlam olduumuz sp' mizi bir
SqlCommand nesnesi yardmyla yrtyor ve elde ettiimiz sonu kmesini DataGrid

www.bsenyurt.com Page 1759


kontrolmze balyoruz.

private void Doldur(int sayfaNo,int gosterilecekSatirSayisi)


{
string sql=@"WorkSp_Paging";
cmd=new SqlCommand(sql,con);
cmd.CommandType=CommandType.StoredProcedure;
cmd.Parameters.Add("@SayfaNo",sayfaNo);
cmd.Parameters.Add("@GosterilecekSatirSayisi",gosterilecekSatirSayisi);
da=new SqlDataAdapter(cmd);
dt=new DataTable();
da.Fill(dt);
DataGrid1.DataSource=dt;
DataGrid1.DataBind();
}

imdi linklerimizi oluturalm. Burada kodlama teknii asndan tamamen serbestsiniz. Ben
aadaki gibi kodlamay tercih ettim. ncelikle Employee tablosundaki satr saysn buluyoruz.
Sonra sayfalarda gsterilecek satr says ile bunu oranlayarak sayfa saysn buluyoruz. Sayfa
saysn bulurken dikkat etmemiz gereken nokta artk satrlar iin sayfa numarasn bir arttrmamz
gerektiidir. Bunu tespit edebilmek iin toplam satr saysn sayfada gsterilecek satr saysna
blerken mod operatr (%) yardmyla kalan deeri hesaplyoruz. Eer kalan deer 0 ise problem
yok. Sayfa says tamdr. Ancak 0 deil ise bu durumda sayfa saysn bir arttrmalyz ki kalan
satrlarda en sondaki sayfada gsterebilelim.

Bu teknik yardmyla sayfa saysn tespit etmemizin ardndan her bir sayfa numaras iin birer
LinkButton kontrol oluturuyoruz. Bu kontrollerin Text ve ID zelliklerine ilgili sayfa numarasn
set ettikten sonra sayfadaki placeHolder kontrolne ekliyoruz. Ayrca LinkButton' lar arasnda birer
boluk olmasn salamak iin Label kontrollerini kullanabiliriz. imdi burada nemli olan nokta
LinkButton nesnelerinden birisine tklandnda ilgili sp' mizi altracak olan metodumuzu
arabilmek. Bunun iin her bir LinkButton nesnesini dng ierisinde olutururken ayn Click olay
metoduna ynlendiriyoruz. Bu olay metodu ierisinde yaptmz i ise ilgili LinkButton kontrolnn
ID deerini almak ve Doldur isimli metoda gndermek. Bylece ilgili linke tklandnda doruca sp'
miz altrlacak ve ilgili sayfaya ait veri seti ekrandaki grid kontrolmze dolacak.

private void SatirSayisiniBul()


{
cmd=new SqlCommand("SELECT COUNT(*) FROM Employee",con);
con.Open();
int toplamSatirSayisi=Convert.ToInt32(cmd.ExecuteScalar());
con.Close();
ViewState.Add("TSS",toplamSatirSayisi);
}

private void LinkleriOlustur(int gosterilecekSatirSayisi)


{
if(ViewState["TSS"]==null)
{

www.bsenyurt.com Page 1760


SatirSayisiniBul();
}

int kalanSatirSayisi=toplamSatirSayisi%gosterilecekSatirSayisi;
int sayfaSayisi;
if(kalanSatirSayisi==0)
sayfaSayisi=(toplamSatirSayisi/gosterilecekSatirSayisi);
else
sayfaSayisi=(toplamSatirSayisi/gosterilecekSatirSayisi)+1;

for(int i=1;i<sayfaSayisi;i++)
{
LinkButton link=new LinkButton();
Label lbl=new Label();

link.Text=i.ToString();
link.ID=i.ToString();
link.Click+=new EventHandler(link_Click);
lbl.Text=" ";
plhLinkler.Controls.Add(link);
plhLinkler.Controls.Add(lbl);
}
}

private void link_Click(object sender, EventArgs e)


{
LinkButton currLink=(LinkButton)sender;
int sayfaNo=Convert.ToInt16(currLink.ID);
Doldur(sayfaNo,5);
}

Son olarak sayfamz yklenirken Load olaynda olmasn istediimiz kodlarda aadaki gibi
ekleyelim.

private void Page_Load(object sender, System.EventArgs e)


{
con=new SqlConnection("data source=localhost;database=AdventureWorks2000;integrated
security=SSPI");
LinkleriOlustur(5);
if(!Page.IsPostBack)
{
Doldur(1,5);
}
}

Uygulamamz altracak olursak sayfalar arasnda baarl bir ekilde dolaabildiimizi grrz.
Grld gibi zel sayfalama ilemi biraz meakkatli bir yol gerektirse de performans asndan

www.bsenyurt.com Page 1761


olduka iyi verim sunacaktr. Buradaki performans farkn iyi anlayabilmek iin normal sayfalama ve
zel sayfalama tekniklerini iyice kavramak gerekir. Bir kere daha zetleyecek olursak, normal
sayfalama tekniinde her bir sayfada tm veri seti tekrardan ilgili balantsz katman kontrolne
doldurulmaktadr. Bizim kullandmz tekniktede dikkat ederseniz buna benzer bir yaklam sz
konusudur. nk bizde sp' miz ierisinde tm veri setini ekip bir temp tablo ierisine alyoruz.
Yanlz biz bu ilemi sql sunucusu zerinde gerekletiriyoruz. Oysaki normal sayfalamada hakikaten
tm veri kmesi balantsz katman nesnesine doldurulmaktadr. Bizim tekniimizde ise sadece
ilgili sayfadaki belirtilen satr says kadarlk bir veri seti balantsz katman nesnesine
doldurulmaktadr. te aradaki en byk fark budur. Ki bu fark bize performans salamaktadr. Bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Kodlar in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

Numaralandrclar Kullanmak in Bir Sebep ( 28.08.2005 ) - C#

Deerli Okurlarm Merhabalar,

Bildiiniz gibi numaralandrclar (enum sabitleride diyebiliriz) yardmyla saysal deerleri kod
ierisinde daha anlaml isimlendirmelerle ifade edebiliriz. Uygulama gelitirirken ounlukla
framework' n paras olan pek ok enum sabitini kullanmaktayz. rnein veritaban
uygulamalarnda ska kullandmz CommandBehavior, DataRowState, DataRowVersion sabitleri
gibi. Bu sistemin temel amac, bu tiplerin sahip olduklar deerlerin saysal karlklarna
ihtiyacmzn olmasdr. yle ki, uygulama ierisinde yer alan her hangi bir fonksiyonun davran
iin saysal bir karlatrma yapmamz gereken yerlerde, bu saysal deerin karl olan bir ismi
kullanmak ok daha mantkldr. Bu gelitirme asndan zaman kazandrc bir teknikten de tedir.
ou zaman projelerimizde kendi numaralandrc tiplerimizi tanmlama ihtiyac duyarz. te bu
gnk makalemizde bizi numaralandrc kullanmaya itecek bir nedeni incelemeye alacaz.

Numaralandrclar saysal deerleri anlaml isimler ile ifade etmemize yardmc olurken,
gerek kodlama zamannda gerekse gelitirme aamasnda programcya byk kolaylk ve
esneklik salarlar.

lk olarak numaralandrclar kullanmamz iin gerekli senaryomuzdan ksaca bahsedelim.


rneimizi bir web uygulamas olarak gelitireceiz. Bu web uygulmasnda AdventureWorks2000
(Sql Server 2000 Reporting Service ile birlikte gelen) isimli veritabannda yer alan Products ve
ProductSubCategory tablolarndan faydalanacaz. Temel olarak bir dataGrid kontrol zerinde veri
gsterme ve gncelleme ilemlerini ele alacaz. Uygulamamz en bandan itibaren tasarlayacaz.
lerleyen ksmlarnda ise numaralandrc ihtiyacmz kefedecek ve uygun zm yollarn
gelitirmeye alacaz. lk olarak uygulamamzn tablolar ile ilgili temel ilemlerini yapacak
yonetici snfn yazalm. DBYonetici snfmz u an iin sadece veri ekme ilemlerini stlenecek.
lerleyen ksmlarda dier baz ilevsellikleri de ekleyeceiz.

DBYonetici.cs

www.bsenyurt.com Page 1762


using System;
using System.Data;
using System.Data.SqlClient;

namespace UsingEnumerators
{
public class DBYoneticisi
{
private SqlConnection con;
private SqlDataAdapter da;

public DBYoneticisi()
{
con=new SqlConnection("data
source=localhost;database=AdventureWorks2000;integrated security=SSPI");
}

public DataSet SelectCategories()


{
DataSet resultSet=new DataSet();
string sql=@"SELECT ProductSubCategoryID, Name FROM ProductSubCategory Order By
ProductSubCategoryID";
da=new SqlDataAdapter(sql,con);
da.Fill(resultSet);
return resultSet;
}

public DataSet SelectProducts()


{
DataSet resultSet=new DataSet();
string sql=@"SELECT TOP 100 ProductID, Name, ProductNumber, StandardCost, ListPrice,
StandardCost / ListPrice * 100 AS IncRate, Class, DealerPrice, SellStartDate, Size,
Weight,ProductSubCategoryID, (SELECT Name FROM ProductSubCategory WHERE
ProductSubCategoryID = P.ProductSubCategoryID) AS ProductSubCategory FROM Product P
WHERE (StandardCost IS NOT NULL) AND (ListPrice IS NOT NULL) ORDER BY ProductID";
da=new SqlDataAdapter(sql,con);
da.Fill(resultSet);
return resultSet;
}
}
}

DBYonetici isimli snfmzdaki metodlardan ksaca bahsetmekte yarar var. Uygulamamzda


AdventureWorks2000 veritabannda yer alan Products isimli tabloyu kullanyoruz. Bu tablodaki bir
ka alan ele alacaz. Products tablosuna ilikin sorgumuza dikkat ederseniz, standart maliyet ile
liste fiyat arasndaki oran ifade eden ek bir alan olduunu farkedebilirsiniz. Biz bu alandaki deere
bakarak dataGrid' imiz zerinde renklendirme ilmelerini yapmaya alacaz.

www.bsenyurt.com Page 1763


SelectCategories isimli metodumuz ise rnlerimizin ait olabilecei kategorileri elde etmemizi
salyor. Aslnda bu metodu, dataGrid zerinde her hangibir satr iin gncelleme ilemi
yapacamz zaman, bir ListBox kontroln dinamik olarak doldurmak amacyla kullanacaz. imdi
DBYonetici snfmz web uygulamamzda kullanalm. lk olarak WebForm' umuz zerinde yer
alacak dataGrid kontrolmzn ieriini oluturacaz.

<asp:datagrid id="dgProducts" runat="server" Font-Size="Smaller" Font-Names="Verdana"


AutoGenerateColumns="False" DataKeyField="ProductID" AllowPaging="True">
<AlternatingItemStyle BackColor="LightSteelBlue"></AlternatingItemStyle>
<ItemStyle BackColor="White"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="Brown" BackColor="Gold"></HeaderStyle>
<Columns>
<asp:BoundColumn Visible="False" DataField="ProductID"></asp:BoundColumn>
<asp:TemplateColumn HeaderText="Urun Ad">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"Name")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtName" Runat="server" Width="100"
Text='<%#DataBinder.Eval(Container.DataItem,"Name")%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Urun Numaras">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"ProductNumber")%>
</ItemTemplate>
<EditItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"ProductNumber")%>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Maliyet">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"StandardCost","{0:C}")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtStandardCost" Runat="server" Width="100"
Text='<%#DataBinder.Eval(Container.DataItem,"StandardCost")%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Liste Fiyati">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"ListPrice","{0:C}")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtListPrice" Runat="server" Width="100"
Text='<%#DataBinder.Eval(Container.DataItem,"ListPrice")%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Artis Orani">

www.bsenyurt.com Page 1764


<ItemTemplate>
<asp:Label ID="lblIncRate" Runat="Server"
Text='<%#DataBinder.Eval(Container.DataItem,"IncRate","{0:F}")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"IncRate","{0:F}")%>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Alt Kategori ID" Visible="False">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"ProductSubCategoryID")%>
</ItemTemplate>
<EditItemTemplate>
<asp:Label ID="lblProductSubCategoryID"
Text='<%#DataBinder.Eval(Container.DataItem,"ProductSubCategoryID")%>'
runat="server"></asp:Label>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Alt Kategori">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"ProductSubCategory")%>
</ItemTemplate>
<EditItemTemplate>
<asp:DropDownList ID="lstProductSubCategory" runat="server" DataSource = "<%#
AltKategorileriAl() %>" DataTextField="Name" DataValueField="ProductSubCategoryID" />
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Boyutu">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"Size","{0:F}")%>
</ItemTemplate>
<EditItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"Size","{0:F}")%>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn HeaderText="Agirlik">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"Weight","{0:F}")%>
</ItemTemplate>
<EditItemTemplate>
<asp:TextBox ID="txtWeight" Runat="server" Width="100"
Text='<%#DataBinder.Eval(Container.DataItem,"Weight")%>'></asp:TextBox>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn>
<ItemTemplate>
<asp:Button id="btnDuzenle" CommandName="Duzenle" runat="server"
Text="Dzenle"></asp:Button>
</ItemTemplate>

www.bsenyurt.com Page 1765


<EditItemTemplate>
<asp:Button id="btnGuncelle" CommandName="Guncelle" runat="server"
Text="Gncelle"></asp:Button>
<asp:Button id="btnVazgec" CommandName="Vazgec" runat="server"
Text="Vazge"></asp:Button>
</EditItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn>
<ItemTemplate>
<asp:Button id="btnDelete" CommandName="Sil" runat="server"
Text="Sil"></asp:Button>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
<PagerStyle Mode="NumericPages"></PagerStyle>
</asp:datagrid>

u anda aklnzdan geenleri duyar gibiyim. Bu kadar uzun kodlardan sonra numarlandrclar
nerede kullanacamz merak ediyorsunuz. Ama biraz daha sabredelim. lk olarak yukardaki
dataGrid kontrolmz hakknda ksaca bilgi vermekte fayda var. DataGrid kontrolmz ekranda
Products tablosuna ait verileri gsterdii gibi, satrlar zerinde veri gncelleme ve silme ilemlerine
de izin verecek ekilde oluturuldu. Bu sebepten zerinde gncelleme yaplmasn istediimiz
alanlara ait EditItemTemplate ksmlarnda TextBox veya DropDownList gibi kontrollere yer verdik.
Konumuz dataGrid kontrolnn zelliklerini incelemek olmad iin ok fazla detaya girmiyorum.
imdi sayfamzn kodlarn yazalm.

private static DBYoneticisi yonetici;

private void Page_Load(object sender, System.EventArgs e)


{
yonetici=new DBYoneticisi();
}

private void btnYukle_Click(object sender, System.EventArgs e)


{
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
}

private void dgProducts_ItemDataBound(object sender, DataGridItemEventArgs e)


{
if((e.Item.ItemType==ListItemType.Item) ||
(e.Item.ItemType==ListItemType.AlternatingItem))
{
double incRate;
Label lbl=(Label)e.Item.Cells[5].Controls[1];
incRate=Convert.ToDouble(lbl.Text);
if(incRate>=100)

www.bsenyurt.com Page 1766


{
e.Item.Cells[5].BackColor=Color.Red;
e.Item.Cells[5].ForeColor=Color.White;
}
}
}

private void dgProducts_PageIndexChanged(object source, DataGridPageChangedEventArgs e)


{
dgProducts.CurrentPageIndex=e.NewPageIndex;
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
}

public DataSet AltKategorileriAl()


{
return yonetici.SelectCategories();
}

private void dgProducts_ItemCommand(object source, DataGridCommandEventArgs e)


{
switch (e.CommandName)
{
case "Duzenle":
dgProducts.EditItemIndex=e.Item.ItemIndex;
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
break;

case "Sil":
break;

case "Vazgec":
dgProducts.EditItemIndex=-1;
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
break;

default :
break;
}
}

Dilerseniz kodlarmzda neler yaptmza ksaca deinelim. Sayfamz yklenirken dataGrid


kontrol, Products tablosu iin altrdmz sorgudan dnen sonu kmesi ile dolduruluyor. Bu
srada dataGrid kontrolnn ItemDataBound olaynda her bir satr iin IncRate isimli alann deerini
kontrol ediyoruz. Bunun sonucuna gre eer art oran 100' den byk ise o hcreinin arka plan
rengini ve font rengini deitirerek kullancy uyaryoruz. Kullanc dataGrid kontrolnde sayfalama
ilemi yapabilir. Sayfalama ilemini salamak iin her zamanki gibi PageIndexChanged isimli olay

www.bsenyurt.com Page 1767


metodumuzu kullanyoruz. Her hangibir satr iin gncelleme ilemi ve silme ilemi de yapabilir.
Gncelleme ve Silme ilmeleri iin yine DataGrid kontrolmzn ItemCommand metodunu
kullanyoruz. Eer dzenleme modu seilirse bu durumda rnlerin dahil olduu kategorileri
listelemek iin DropDownList kontrolmz dolduran SelectProducts metodumuzu aryoruz.
Bylece sistemde kaytl olan rnlerin kullanc tarafndan bir combo kontrol ierisinden
seilebilmesini salam oluyoruz. Bu hzl aklamalardan sonra geldiimiz noktay aadaki
ekilden grebilirisiniz.

imdi bu uygulamada odaklanmamz gereken bir nokta var. O da, IncRate' in rengini belirlediimiz
ItemDataBound metodu. Gelin bu metodu mercek altna alalm.

private void dgProducts_ItemDataBound(object sender, DataGridItemEventArgs e)


{
if((e.Item.ItemType==ListItemType.Item) ||
(e.Item.ItemType==ListItemType.AlternatingItem))
{
double incRate;
Label lbl=(Label)e.Item.Cells[5].Controls[1];
incRate=Convert.ToDouble(lbl.Text);
if(incRate>=100)
{
e.Item.Cells[5].BackColor=Color.Red;

www.bsenyurt.com Page 1768


e.Item.Cells[5].ForeColor=Color.White;
}
}
}

Bu metodda dikkat ederseniz if dngmz ierisinde 5 numaral hcrenin ierisinde ki 1 numaral


kontrol ele alyoruz. Peki bu 5 numaral hcredeki 1 numaral kontrol' de neyin nesi oluyor.
Aslnda dataGrid nesnemizin aspx sayfasndaki kodlarn gz nne aldnzda 5 numaral hcrenin,
IncRate alanna ait hcre olduunu ve 1 numaral kontrolnde bu hcredeki Label kontrol
olduunu kolayca grebilirisiniz.

<asp:TemplateColumn HeaderText="Artis Orani">


<ItemTemplate>
<asp:Label ID="lblIncRate" Runat="Server"
Text='<%#DataBinder.Eval(Container.DataItem,"IncRate","{0:F}")%>'></asp:Label>
</ItemTemplate>
<EditItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"IncRate","{0:F}")%>
</EditItemTemplate>
</asp:TemplateColumn>

Herey buraya kadar gayet gzel. imdi default.aspx sayfamzda IncRate alann dataGrid
ierisinde kullandmz ItemTemplate taksnn hemen nne yeni bir tane daha ekleyelim. Bu
sefer query' den ektiimiz Class alann buraya ekliyoruz. Aynen aadaki kod parasnda olduu
gibi.

<asp:TemplateColumn HeaderText="Snf">
<ItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"Class","{0:F}")%>
</ItemTemplate>
<EditItemTemplate>
<%#DataBinder.Eval(Container.DataItem,"Class","{0:F}")%>
</EditItemTemplate>
</asp:TemplateColumn>

imdi uygulamamz tekrardan altralm. Bu sefer sizinde benim de beklediimiz gibi bir eylerin
yolunda gitmemesi gerekiyor. Aadaki ekran grnts korktuumuzun bamza geldii andr.

www.bsenyurt.com Page 1769


Hata gayet ak ve net. Artk 5 numaral hcremiz IncRate alanna ait hcre deil. Burada imdi
Class isimli alanmz yer almakta. Ayrca 5 numaral alandaki 1 numaral kontrolmzde bir Label
kontrol deil. Hatann nedenide doru hcre zerinde olmaymz. Daha da kts olabilir elbette.
Burada alma zamannda aldmz hata ile sorununun ne olduunu anlayabildik. Oysaki, yeni
eklediimiz hcre pekala saysal bir deer ieren bir Label kontrol tayabilirdi. Bu durumda
uygulama alacakt ama hatal sonular verecekti.

Peki ya zm? zm sonunda bu makalenin bandan beridir bahsetmeye altmz


numaralandrclardan geiyor. Sorgudan dnen alanlarn dataGrid' de denk geldii indeks
numaralarn temsil edecek bir numarlandrcmz olsayd daha iyi olmaz myd? En azndan yeni bir
hcre eklediimizde tek yapmamz gereken enum sabitimizde araya bir eleman daha eklemek
olacakt. nk kodun ka yerinde ayn numaral indeksi kullandmz bilemeyebilirdik. Her ne
kadar arama-bulma yntemi ile 5' lerin getii yerleri 6 yapabilecek olsakta bu hide profesyonelce
bir zm olmazd. te basit bir enum sabitini kullanarak ok daha profesyonel bir zm
retebilirdik.

Grdnz gibi enum sabitlerini kullanmak iin son derece gzel bir sebebimiz oldu. imdi bu
dncemizi uygulamamz ile btnletirmemiz gerekiyor. lk olarak yapmamz gereken enum
sabitimizi oluturmak. Eer bir solution ierisinde pek ok proje ile birlikte alyorsanz bu
durumda grid balklar gibi indekslere ait enum sabitlerini saklayabileceiniz genel bir katman dahi
oluturmay dnebilirsiniz. Bizim uygulamamz son derece kk olduundan geerli isim
alanmz altnda bir enum sabiti yapmamz yeterli olacaktr.

enum sabitimiz ProductsGridHeaders

namespace UsingEnumerators
{
enum ProductsGridHeaders
{
PRODUCTID,

www.bsenyurt.com Page 1770


NAME,
PRODUCTNUMBER,
STANDARDCOST,
LISTPRICE,
CLASS,
INCRATE,
PRODUCTSUBCATEGORYID,
PRODUCTSUBCATEGORY,
SIZE,
WEIGHT
}
}

te altn yumruu vurduumuz an. Artk tek yapmamz gereken, enum sabitimizi DataGrid
nesnemizin ItemDataBound olay metodunda aadaki gibi kullanmak.

Numaralandrc iindeki elemanlar isimlendirirken gerekten anlaml, bir eyleri


kulamza artran isimler vermeye zen gstermeliyiz.

private void dgProducts_ItemDataBound(object sender, DataGridItemEventArgs e)


{
if((e.Item.ItemType==ListItemType.Item) ||
(e.Item.ItemType==ListItemType.AlternatingItem))
{
double incRate;
Label lbl=(Label)e.Item.Cells[(int)ProductsGridHeaders.INCRATE].Controls[1];
incRate=Convert.ToDouble(lbl.Text);
if(incRate>=100)

www.bsenyurt.com Page 1771


{
e.Item.Cells[(int)ProductsGridHeaders.INCRATE].BackColor=Color.Red;
e.Item.Cells[(int)ProductsGridHeaders.INCRATE].ForeColor=Color.White;
}
}
}

Artk uygulamamz sorunsuz ekilde alacaktr ve istediimiz yeni satr dataGrid kontrolmze
ekleyebiliriz. Unutmamamz gereken tek ek, yeni bir satr eklendiinde bunu ilgili enum sabitinede
yanstmaktr. stelik kodun okunurluuda inanlmaz derecede kolaylamtr. Ancak elbette
ki kodumuzda enum sabitlerini kullanacamz tek yer buras deil.

rnein DropDownList kontrolmz doldurulduunda o an aktif olan satra ait rn kategori


adnnda seili olarak gelmesi gerekmektedir. u anki kodlarmza gre DropDownList kontrolmz
herhangibir satr edit modunda aldnda rnleri baarl bir ekilde listeliyor ama her zaman iin
ilk elemana konumlanyor. Bu problemi amak iin dzenleme moduna geildiinde DropDownList
kontrolnnn SelectedValue zelliini uygun deere (ki bu deer ProductSubCategoryId olacaktr)
atamamz yeterli olacaktr. Dolaysla dataGrid kontrolmzn ItemDataBound olay metodunda
aadaki dzenlemeyi yapmamz bu ihtiyacmz karlayacaktr. Artk kodu yazarken, hangi indisli
hcreyi dnmemize gerekte yoktur. nk numaralandrcmz anlaml isimleri ile bunu bize
sylemektedir.

if(e.Item.ItemType==ListItemType.EditItem)
{
Label
lblKatId=(Label)e.Item.Cells[(int)ProductsGridHeaders.PRODUCTSUBCATEGORYID].Controls[
1];
DropDownList
lstKategoriler=(DropDownList)e.Item.Cells[(int)ProductsGridHeaders.PRODUCTSUBCATEGOR
Y].Controls[1];
lstKategoriler.SelectedIndex=Convert.ToInt16(lblKatId.Text)-1;
}

Oluturduumuz enum sabiti zellikle gncellenecek satr iin yazacamz kod satrlarnda da ok
ie yarayacaktr. Son olarak gncelleme ilemimizi numaralandrcmz kullanarak nasl
gerekletirdiimizi grelim. Uygulamamza bu fonksiyonellii kazandrmak iin yine
ItemDataBound olay metodunu kullanacaz. Bu sefer CommandName zelliinin Guncelle deerini
almas halinde gerekletireceimiz ilemler var. Biz numaralandrcmz Kaydetme ileminin
gerekletirilecei metodu armadan nce, gridde seili olan satrdaki kontroller zerindeki
deerleri okuduumuz satrlarda kullanyoruz. rnein dataGrid kontrolnde Name alannn
gsterildii hcrede yer alan TextBox kontrolne girilen deeri almak iin, ProductsGridHeaders
numaralandrcsnn Name elemannn iaret ettii integer deere sahip olan hcredeki 1 numaral
kontrol ele alyoruz. Daha sonra bu kontrol bir TextBox nesnesine dntrerek gncel deerini
ilgili kaydetme ilemini gerekletirecek metodumuza tayoruz. Bu deer alma ilemini dier
kontrollerimiz iinde yapyoruz. Ancak nemli olan e parametresi zerinden dataGrid kontrolndeki
ilgili alanlara nasl eritiimiz. Yani numaralandrcmz nasl kullandmz.

private void Kaydet(DataGridCommandEventArgs e)

www.bsenyurt.com Page 1772


{
int productID=Convert.ToInt32(dgProducts.DataKeys[e.Item.ItemIndex]);
TextBox txtName=(TextBox)e.Item.Cells[(int)ProductsGridHeaders.NAME].Controls[1];
TextBox
txtStandardCost=(TextBox)e.Item.Cells[(int)ProductsGridHeaders.STANDARDCOST].Controls[
1];
TextBox
txtListPrice=(TextBox)e.Item.Cells[(int)ProductsGridHeaders.LISTPRICE].Controls[1];
TextBox txtWeight=(TextBox)e.Item.Cells[(int)ProductsGridHeaders.WEIGHT].Controls[1];
DropDownList
lstSubCategories=(DropDownList)e.Item.Cells[(int)ProductsGridHeaders.PRODUCTSUBCATEG
ORY].Controls[1];

string Name=txtName.Text;
double StandardCost=Convert.ToDouble(txtStandardCost.Text);
double ListPrice=Convert.ToDouble(txtListPrice.Text);
double Weight=Convert.ToDouble(txtWeight.Text);
int SCategoryID=Convert.ToInt16(lstSubCategories.SelectedValue);

yonetici.UpdateProducts(productID,Name,StandardCost,ListPrice,Weight,SCategoryID);
}

private void dgProducts_ItemCommand(object source, DataGridCommandEventArgs e)


{
switch (e.CommandName)
{
case "Duzenle":
dgProducts.EditItemIndex=e.Item.ItemIndex;
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
break;

case "Guncelle":
Kaydet(e);
dgProducts.EditItemIndex=-1;
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
break;

case "Sil":
break;

case "Vazgec":
dgProducts.EditItemIndex=-1;
dgProducts.DataSource=yonetici.SelectProducts();
dgProducts.DataBind();
break;

default :

www.bsenyurt.com Page 1773


break;
}
}

DbYoneticisi snfmzda gncelleme ilemini gerekletiren metodumuz ise aadaki gibidir.

public int UpdateProducts(int productID, string name, double standardCost, double listPrice, double
weight, int subCategoryID)
{
string sql=@"UPDATE Product SET Name=@Name,StandardCost=@StandardCost,
ListPrice=@ListPrice,Weight=@Weight, ProductSubCategoryID=@SubCategoryID WHERE
ProductID=@ProductID";
SqlCommand cmd=new SqlCommand(sql,con);
cmd.Parameters.Add("@Name",name);
cmd.Parameters.Add("@StandardCost",standardCost);
cmd.Parameters.Add("@ListPrice",listPrice);
cmd.Parameters.Add("@Weight",weight);
cmd.Parameters.Add("@SubCategoryID",subCategoryID);
cmd.Parameters.Add("@ProductID",productID);
con.Open();
int result=cmd.ExecuteNonQuery();
con.Close();
return result;
}

Grdnz gibi enum sabitlerini kullanarak kod gelitirmek daha da kolaylamaktadr. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

rnek Kodlar in Tklaynz.

Burak Selim ENYURT


selim@bsenyurt.com

SortedList ve Hashtable in 2 Basit neri (


06.08.2005 ) - C#
Deerli Okurlarm Merhabalar,

SortedList ve Hashtable koleksiyonlar, anahtar-deer (key-value) iftlerini esas alr. Hashtable


koleksiyonu zellikle sahip olduu elemanlar ile ilgili ilemlerde kulland hash algoritmal teknik
sayesinde en hzl alan koleksiyon olma zelliinide gsterir. Dier yandan SortedList anahtar-
deer iftlerinin, anahtar deerine gre her zaman sraland bir koleksiyon tipidir. Yani SortedList
koleksiyonuna eklediimiz elemanlarn srasna baklmakszn, yeniden yaplan bir sralama sz
konusudur. Bu avantajl bir durum olsa bile, zellikle SortedList' in ok daha yava alan bir
koleksiyon olmasna neden olmaktadr. Her iki koleksiyon hakknda sylenebilecek pek ok konu
vardr. Biz bu makalemizde zellikle dikkat etmemiz gereken 2 teori zerinde duracaz. lk
teorimiz ile ie balayalm.

www.bsenyurt.com Page 1774


Bir SortedList olutururken dorudan eleman eklemek yerine, elemanlar nce bir
Hashtable koleksiyonuna ekleyip, SortedList' i bu Hashtable zerinden
oluturmak daha hzldr.

Kulaa biraz galip geliyor deil mi? Bir SortedList koleksiyonunu anahtar-deer iftleri ile
doldururken dorudan SortedList' i kullanmak yerine bir Hashtable' n kullanlmas... Her ne kadar
ilgin gibi grnsede aadaki basit rnek ile bu durumu analiz edebiliriz.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

namespace UsingSortedList
{
class Tester
{
private SortedList sl;
private SqlConnection con;
private SqlCommand cmd;
private SqlDataReader dr;

private void Hazirla()


{
con = new SqlConnection("data source=BURAKS;database=AdventureWorks;integrated
security=SSPI");
cmd = new SqlCommand("SELECT NationalIDNumber,Title From
HumanResources.Employee", con);
}

public void Olustur()


{
sl = new SortedList();
con.Open();
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dr.Read())
{
sl[dr["NationalIDNumber"]] = dr["Title"];
}
dr.Close();
}

public void OlusturHt()


{
Hashtable ht = new Hashtable();

www.bsenyurt.com Page 1775


con.Open();
dr = cmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dr.Read())
{
ht[dr["NationalIDNumber"]] = dr["Title"];
}
sl = new SortedList(ht);
dr.Close();
}

public Tester()
{
Hazirla();
}
}

class Program
{
static void Main(string[] args)
{
Tester tester = new Tester();
DateTime dtBaslangic,dtBitis;
TimeSpan ts;

#region SortedList ile

dtBaslangic = DateTime.Now;
tester.Olustur();
dtBitis = DateTime.Now;
ts = dtBitis - dtBaslangic;
Console.WriteLine(ts.TotalMilliseconds);

#endregion

#region Hashtable ile

dtBaslangic = DateTime.Now;
tester.OlusturHt();
dtBitis = DateTime.Now;
ts = dtBitis - dtBaslangic;
Console.WriteLine(ts.TotalMilliseconds);

#endregion
}
}
}

rneimizde test ilemlerimiz iin Tester isimli bir snf kullanyoruz. Dier teorimiz iin de bu snf
kullanacaz. Snfmzda Sql Server 2005 zerinde yer alan AdventureWorks isimli veritabann

www.bsenyurt.com Page 1776


kullanacaz. Burada Employee isimli tabloyu gz nne alacaz. Amacmz bir Employee' un
NationalIDNumber alanlarn anahtar olarak, Title alanlarn ise deer olarak SortedList
koleksiyonumuza eklemek. Tablonun select edilen ieriine bakacak olursak NationalIDNumber
alanlarnn dzensiz(unsorted) srada olduunu grrz.

Elbetteki burada basit bir Order By ile NationalIDNumber alanna gre sralama yaptrabiliriz.
Ancak SortedList ile ilgili teorimize bakmak iin bize srasz(unsorted) ve benzersiz(unique)
anahtar(key) deerleri gerekiyor. Hazr elimizde var iken kullanmakta fayda var. lk metodumuz (
Olustur() metodu) anahtar-deer iftlerini SortedList' e dorudan ekliyor. kinci metodumuz
(Olusturht() metodu) ise anahtar-deer iftlerini nce bir Hashtable koleksiyonuna ekliyor ve daha
sonra SortedList koleksiyonunu aadaki yapc metod prototipi ile oluturuyor.

public SortedList(IDictionary d);

Hashtable koleksiyonu IDictionary arayzn implemente ettii iin, SortedList' imizi bu ekilde
oluturabilmemiz son derece doaldr. Uygulamay altrdmzda aadakine benzer bir sonu
elde ederiz.

www.bsenyurt.com Page 1777


Aslnda sonular milisaniye cinsinden olduu iin ok nemsiz grnebilir. Kald ki uygulamann ksa
sreli sonraki altrllarnda veritaban kaynaklarnn yeniden kullanmnnda etkisiyle bu sre
dahada aalara inecektir. Ancak gerek hayat problemlerinde ok daha fazla satra sahip
(ounlukla buradaki gibi 290 satrlk bir veri seti deil) tablolarda benzer ilemleri kullanabiliriz.
Sonu itibariyle teorik olarak bir SortedList koleksiyonunu olutururken bir Hashtable
koleksiyonundan yararlanmak performans olumlu ynde etkilemektedir. Gelelim ikinci dikkate
deer teoriye.

ster SortedList ister Hashtable olsun, anahtar-deer iftine sahip koleksiyonlarn


elemanlar arasnda ileri ynl iterasyon kullanrken DictionaryEntry nesneleri
zerinden hareket etmek, anahtarlar zerinden hareket etmekten daha hzldr.

Dictionary bazl bir koleksiyonda (ounlukla Hashtable ve SortedList) foreach dngsn


kullanarak yaptmz iterasyonlarda genellike kullandmz iki desen vardr. Bu desenlerden
birisinde Keys zellii kullanlr. Keys zellii ile koleksiyon ierisindeki her bir anahtar zerinde
ileri ynl hareket salanr. Bir anahtara karlk gelen deeri koleksiyon ierisinden almak iin,
gncel anahtar koleksiyonun indeksleyicisine parametre olarak verilir.

foreach (object anahtar in sl.Keys)


{
}

Dier yntemde ise DictionaryEntry nesneleri kullanlmaktadr ve deseni aadaki gibidir.


DictionaryEntry nesneleri o anki anahtar-deer iflerine eriebilmemizi salayan Key ve Value
zelliklerine sahiptir.

foreach (DictionaryEntry dicEnt in sl)


{
}

imdi bu teoriyi rneimizde uygulayarak oluan sre farklarn deerlendirmeye alalm. Tester
isimli snfmza aadaki iki metodu ekleyerek ie balyoruz.

public void Dolas_1()


{
OlusturHt();
foreach (object anahtar in sl.Keys)
{
object deger = sl[anahtar];
}
}

public void Dolas_2()


{

www.bsenyurt.com Page 1778


OlusturHt();
foreach (DictionaryEntry dicEnt in sl)
{
object deger = dicEnt.Value;
}
}

Metodlarmzda SortedList koleksiyonunu kullandk. lk metodumuzda deerlere erimek iin


indeksleyici zerinden anahtarlar kullanyoruz. Yani foreach dngmz koleksiyon iindeki her bir
anahtar iin teleme yapyor. kinci dngmz ise koleksiyon ierisindeki her bir DictionaryEntry
nesnesini ele alarak teleme yapyor. Her iki teknii kullanan kodlarmz ise Main metodumuza
aadaki gibi ekleyelim.

#region Key zerinden dng

dtBaslangic = DateTime.Now;
tester.Dolas_1();
dtBitis = DateTime.Now;
ts = dtBitis - dtBaslangic;
Console.WriteLine(ts.TotalMilliseconds);

#endregion

#region DictionaryEntry zerinden dng

dtBaslangic = DateTime.Now;
tester.Dolas_2();
dtBitis = DateTime.Now;
ts = dtBitis - dtBaslangic;
Console.WriteLine(ts.TotalMilliseconds);

#endregion

Uygulamamz altrdmzda aadakine benzer bir sonu elde ederiz.

Bu teori Hashtable koleksiyonlar iinde geerlidir. Her iki teoriyide incelediimiz rneklerin
dourduu sonular kullandnz sisteme nazaran grecelidir. Farkl sonuar oluabilir. zellikle
milisaniye cinsinden deerler sz konusu olduundan alma zamannda bu farklar ok nemsizdir.
Ancak yinede profesyonel stilde kod yazarken kullanabileceimiz tekniklerdir.

www.bsenyurt.com Page 1779


zetle SortedList koleksiyonunun kullanm amac elemanlarnn her zaman anahtarlarna gre sral
tutuluyor oluudur. Hashtable koleksiyonu ise elemanlarn ieride hash algoritmas ile oluturduu
indekslere gre tutar ve bulur. Hash algoritmasnn doas gerei Hashtable koleksiyonlar son
derece hzldr. Her iki koleksiyonunda ortak noktas IDictionary arayzlerini uygulam olmalar ve
bu sebepten DictionaryEntry tipinden nesneleri tamalardr. Bu yzden her iki koleksiyonda
bnyesinde key-value iftlerini barndrr. te bu ortak zelliklerden yola karaktan yukardaki iki
teori ortaya atlmtr. Biz de bu makalemizde bunlar incelemeye altk. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Tip Gvenli (Type Safety ) Koleksiyonlar


Oluturmak - 2 ( 31.07.2005 ) - C#
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde tip gvenli koleksiyon nesnelerimizi CollectionBase snf yardmyla nasl
oluturabileceimizi incelemitik. CollectionBase bize ArrayList benzeri koleksiyon snflarn yazma
frsat vermektedir. Dier yandan Hashtable koleksiyonunda olduu gibi key (anahtar) - value
(deer) iftlerinden oluacak tip gvenli bir koleksiyon snf yazmak isteyebiliriz. Bu durumda,
DictionaryBase snfndan yaralanabiliriz. DictionaryBase snfda CollectionBase snf gibi abstract
yapdadr. Yani kendisini rnekleyemeyiz. Temel olarak DictionaryBase key-value iftlerine sahip bir
koleksiyonun kullanmas gereken yeleri sunan arayzlerden tremitir. Yani IDictionary,
IEnumerable ve ICollection arayzlerini uyarlamaktadr. Dikkat ederseniz CollectionBase snfnnda
tredii IEnumerable ve ICollection arayzleri DictionaryBase iinde sz konusudur.

CollectionBase snf gerekli fonksiyonellii salamak iin nasl ki bir ArrayList koleksiyonunu
evreliyorsa (encapsulate), DictionaryBase snfda bir Hashtable koleksiyonunu evreler.
DictionaryBase snfnn protected zellikleri (Dictonary , InnerHashtable) yardmyla
oluturduumuz koleksiyon iindeki key-value iftlerine eriilebilir ve eleman ekleme, silme, arama

www.bsenyurt.com Page 1780


vb. gibi pek ok var olan aksiyonu gerekletirebiliriz. rneimizi incelediimizde DictionaryBase
yardmyla tip gvenli bir koleksiyon nesnesi oluturmann, CollectionBase kullanldnda
gerekletirilen uyarlama ile neredeyse ayn olduunu grecekseniz. Tek fark, ieride eriilen
nesnenin bir Dictionary nesnesi olmas ve key-value iftlerinin sz konusu olmasdr.

DictionaryBase snf key-value (anahtar - deer) iftlerinin kullanld Hashtable tipi


koleksiyon snflarn yazmamz ve kendi tip gvenliimizi oluturabilmemizi salar.

imdi gelin bir rnek zerinden bu konuyu incelemeye alalm. Bu sefer anahtar-deer iftleri
yapsna uygun bir koleksiyon nesnesi olarak ISBN numarasna sahip Kitaplar gz nne alacaz.
ISBN numaralar bizim iin key (anahtar) olacak. Bunun karlnda ise bir Kitap nesnesini
value(deer) olarak tutacaz. Bu elbette tipik olarak bir Hashtable koleksiyonu ile de yaplabilir.
Ancak bizim amacmz anahtarlarn(keys) mutlaka integer ve deerlerin (values) mutlaka Kitap
tipinden nesne rnekleri olmasdr. Normal bir Hashtable key-value iftlerini object tipinden tuttuu
iin, herhangibir tipi bu iftlere atayabiliriz. te burada tip gvenlii bizim esas olan amacmz
olmaktadr. Bu nedenlede DictionaryBase snf yardmyla kendi koleksiyon snfmz yazacaz. lk
olarak Kitap nesnemize ait snfmz oluturalm. Snfmzn basit yaps aadaki gibidir.

Snfmz kodlar;

using System;

namespace StrongCollections
{
public class Kitap
{
private int m_ISBN;
private string m_Baslik;
private int m_Fiyat;

public int ISBN


{
get{return m_ISBN;}
set{m_ISBN=value;}
}
public string Baslik
{
get{return m_Baslik;}
set{m_Baslik=value;}

www.bsenyurt.com Page 1781


}
public int Fiyat
{
get{return m_Fiyat;}
set{m_Fiyat=value;}
}
public Kitap(int isbn,string baslik,int fiyat)
{
m_ISBN=isbn;
m_Baslik=baslik;
m_Fiyat=fiyat;
}
public override string ToString()
{
return m_ISBN.ToString()+" "+m_Baslik+" "+m_Fiyat.ToString();
}
public Kitap()
{
}
}
}

imdi kendi tip gvenli koleksiyon snfmz yazalm. Snfmz DictionaryBase' den trettikten
sonra ieriden Dictionary zelliine erierek eleman ekleme, karma, arama, bulma gibi ilemleri
yapacamz metodlar ile bir indeksleyici ve anahtarlar(keys) zerinde teleme yapabileceimiz bir
numarator metod ekleyeceiz. Basit olarak snfmzn ierii aadaki gibi olacak.

Snf kodlarmz;

using System;
using System.Collections;

www.bsenyurt.com Page 1782


namespace StrongCollections
{
public class KitapKoleksiyon:DictionaryBase
{
public void Ekle(int isbn,Kitap kitap)
{
Dictionary.Add(isbn,kitap);
}
public void Cikart(int isbn)
{
Dictionary.Remove(isbn);
}
public bool Varmi(int isbn)
{
return Dictionary.Contains(isbn);
}
public Kitap Bul(int isbn)
{
return (Kitap)Dictionary[isbn];
}
public Kitap this[int isbn]
{
get{return (Kitap)Dictionary[isbn];}
set{Dictionary[isbn]=value;}
}
public IEnumerator NumaratorAl()
{
return Dictionary.Keys.GetEnumerator();
}
public KitapKoleksiyon()
{
}
}
}

Ekle metodumuz iki parametre almaktadr. Tahmin edeceiniz gibi ilk parametremiz Hashtable
koleksiyonu iin gerekli key (anahtar), ikinci parametremiz ise value(deer) dir. Bu metod
sayesinde, belli bir isbn numarasnn karl olarak bir Kitap nesne rneini koleksiyonumuza
eklemi oluruz. Cikart metodu, parametre olarak verilen isbn deerini Dictionary ierisinde bulur ve
listeden kartr. Varmi metodumuz geriye bool tipinden bir deer dndrr. Amac belirtilen isbn
deerinin koleksiyonda yer alp almadn belirlemektir. Bunun iin Dictionary zellii zerinden
Contains metodunu arrz.

Bul metodumuz ise, parametre olarak girilen isbn' i Dictionary zerinde arar ve sonucu geriye bir
Kitap nesne rnei eklinde dndrr. Bu dntrme gereklidir nk Dictionary geriye object
tipinden bir nesne rneini dndrecektir. Indeksleyicimizin indeks deerleri bu sefer key (anahtar)
lardr. Dikkat ederseniz tm metodlarmz int-Kitap tipinden anahtar-deer iftlerini kullanmaktadr.
Bylece aslnda tip gvenliinide salam oluyoruz. Son olarak eklediimiz NumaratorAl isimli
metodumuz Dictionary zerinde Key deerleri iin bir IEnumerator nesne rneini geriye

www.bsenyurt.com Page 1783


dndryor. Bunu alma zamannda koleksiyonumuz iindeki anahtarlar zerinden teleme
yaparak Kitap nesnelerini elde etmek iin kullanabiliriz. Ksacas bir listemele ilemi iin
kullanabiliriz. imdi koleksiyonumuzu kullanacamz bir rnek uygulama yazalm.

using System;
using System.Collections;

namespace StrongCollections
{
class Uygulama
{
static KitapKoleksiyon kitapCol;

static void Listele()


{
IEnumerator numarator=kitapCol.NumaratorAl();
while(numarator.MoveNext())
{
Console.WriteLine(kitapCol[Convert.ToInt32(numarator.Current)].ToString());
}
}

static void KoleksiyonOlustur()


{
kitapCol.Ekle(1000,new Kitap(1000,"Her Ynyle C#",1));
kitapCol.Ekle(1001,new Kitap(1001,"Thinking in C#",1));
kitapCol.Ekle(1002,new Kitap(1002,"Truva",1));
kitapCol.Ekle(1003,new Kitap(1003,"Java in a Nuthshell",1));
}

static void Main(string[] args)


{
// KitapKoleksiyon nesne rneimizi oluturuyoruz.
kitapCol=new KitapKoleksiyon();
// Koleksiyonumuza bir ka rnek Kitap elemann ekliyoruz.( key-value ifti olarak)
KoleksiyonOlustur();
// Koleksiyonumuzdaki elemanlar listeliyoruz.
Listele();
Console.WriteLine("-------------");
// Koleksiyonda belirtilen isbn deerine sahip Kitap nesnesi olup olmadna bakyoruz.
(Sonular bool tipinden)
Console.WriteLine("ISBN: 1000 var m? {0}",kitapCol.Varmi(1000));
Console.WriteLine("ISBN: 9999 var m? {0}",kitapCol.Varmi(9999));
Console.WriteLine("-------------");
// Koleksiyonumuzdan key deeri 1001 olan key-value iftini kartyoruz.
kitapCol.Cikart(1001);
Console.WriteLine("ISBN: 1001 kt");
// Koleksiyonumuzdaki elemanlarn son halini listeliyoruz. (Artk 1001 numaralar eleman
yok)

www.bsenyurt.com Page 1784


Listele();
Console.WriteLine("-------------");
// Koleksiyonumuzda 1003 isbn deerine sahip key-value iftini buluyoruz.
Kitap bulunanKitap=kitapCol.Bul(1003);
// Bulunan Kitap nesnesinin ieriini override ettiimiz ToString metodu ile ekrana
yazdryoruz.
Console.WriteLine(bulunanKitap.ToString());
}
}
}

Uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

Grld gibi KitapKoleksiyon isimli koleksiyonumuza eleman eklemek istediimizde bizden bir
key-value ifti beklenmektedir. yleki key integer tipinde, value ise Kitap tipinde olmak zorundadr.
Bunu tasarm zamannda koleksiyonumuza eleman eklerken kolayca grebiliriz.

te bu bizim iin tip gvenliini salamaktadr. nk KitapKoleksiyon tipinden nesne rneimize


int-Kitap tipi dnda bir anahtar-deer ifti ekleyemiz. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 1785


Tip Gvenli (Type Safety ) Koleksiyonlar
Oluturmak - 1 ( 23.07.2005 ) - C#
Deerli Okurlarm Merhabalar,

Tip gvenliini salamak her zaman iin nemli unsurlardan birisidir. Koleksiyon tabanl nesneleri
kullanrken ou zaman istediimiz tip gvenliini salayamayabiliriz. Buradaki en byk etken,
koleksiyon tabanl nesnelerin object tipinden referanslar tayor olmasdr. Bazen kendi
belirlediimiz tip dnda, baka her hangi bir tip barndrmasna izin vermek istemediimiz yapda
koleksiyon nesnelerine ihtiyacmz olur. Byle bir koleksiyon nesnesinin en byk avantaj az nce
bahsettiimiz tip gvenliini salamasdr.

C# 2.0 versiyonunda koleksiyon nesnelerine ilikin olarak tip gvenlii generic yaplar ile
kazandrlmtr. Peki 1.1 versiyonunda bu ileri nasl gerekletirebiliriz? ki alternatif yolumuz
vardr. Bunlardan birisi var olan bir koleksiyon nesnesini tretmektir. Dier yol ise CollectionBase
veya DictionaryBase tipinden tretme yaparak bir koleksiyon nesnesi tanmlamaktr. Biz bu
makalemizde CollectionBase snf yardmyla tip gvenli koleksiyon snflarn nasl
oluturabileceimizi inceleyeceiz. Bu snflar ayn zamanda strongly-typed collections (kuvvetle
trlendirimi koleksiyonlar) olarakta adlandrlmaktadr.

lk olarak CollectionBase snfn ksacada olsa tanmakta fayda var. CollectionBase snf abstract bir
snftr. Bu kendisine ait bir nesne rneinin oluturulamayaca anlamna gelmektedir. Ancak
CollectionBase snf IList, ICollection ve IEnumerable arayzlerini implemente etmektedir. Buda
tipik olarak bir koleksiyon nesnesi iin gerekli yeleri saladn gsterir. Aadaki ekilde grlen
YeniKoleksiyon strongly-typed koleksiyon snfmzdr. YeniKoleksiyn, CollectionBase snfndan
tretilmitir. CollectionBase snfmz ise bir koleksiyonun tamas gereken zellikleri sunan
yelerin bildirimini ieren temel arayzden tremektedir.

CollectionBase snf kendi ierisinde IList tipinden bir tip dndren protected yapda List isimli bir
zellie de sahiptir; ki bu zellik sayesinde CollectionBase snfndan treteceimiz snflar
ierisinden IList tipindeki koleksiyona eriebilir ve doal olarak ekleme, karma gibi temel

www.bsenyurt.com Page 1786


koleksiyon ilevselliklerini salayabiliriz. List zelliinin yan sra InnerList isimli zellik dorudan bir
ArrayList nesne referansna eriilmesini salar. Her iki zellikten de faydalanabilirsiniz. Biz bu
makalemizde List zellii yardmyla koleksiyon aktivitelerini salayacaz. imdi gelin kendi
strongly-typed koleksiyon snfmz yazalm. rneimizde bir Dvd' ye ait bilgileri barndran
nesneler dizisini tutacak ekilde bir koleksiyon tasarlayacaz. lk olarak bu koleksiyon ierisinde
tutmak istediinmiz Dvd nesnelerini temsil edecek snfmz gelitirelim. Dvd snfnn prototipi
aadaki ekilde olduu gibidir.

Dvd snfmz

using System;

namespace StrongCollections
{
public class Dvd
{
private string m_Baslik;
private int m_Fiyat;
private DateTime m_YapimYili;

public string Baslik


{
get{return m_Baslik;}
set{m_Baslik=value;}
}
public int Fiyat
{
get{return m_Fiyat;}
set{m_Fiyat=value;}
}
public DateTime YapimYili
{
get{return m_YapimYili;}
set{m_YapimYili=value;}
}
public Dvd(string baslik,int fiyat,DateTime yapimYili)
{
Baslik=baslik;
Fiyat=fiyat;
YapimYili=yapimYili;
}
public Dvd()

www.bsenyurt.com Page 1787


{
}
public override string ToString()
{
return this.Baslik+" "+this.Fiyat+" "+this.YapimYili.ToShortDateString();
}
}
}

DvdKoleksiyon snfmz ise yaps ierisinde bir koleksiyon iin ihtiya duyulabilecek bir iki metod
ierecek ekilde tasarlayacaz. Temel olarak bir Dvd nesnesini koleksiyona ekleme ve karma gibi
ilemleri stlenen metodlara sahip olacak. Ancak nemli bir zellik olarak koleksiyon ierisindeki
elemanlara indeksler zerinden eriebilmemizi salayacak bir indeksleyicide yer alacak. Koleksiyon
snfmzn yapsn aadaki ekilden daha net olarak grebilirsiniz.

DvdKoleksiyon snf

using System;
using System.Collections;

namespace StrongCollections
{
public class DvdKoleksiyon:CollectionBase
{
public void Ekle(Dvd dvd)
{
this.List.Add(dvd);
}
public void Cikart(Dvd dvd)
{
this.List.Remove(dvd);
}
public Dvd this[int indeks]

www.bsenyurt.com Page 1788


{
get{return (Dvd)this.List[indeks];}
set{this.List[indeks]=value;}
}
public void Cikart(int indeks)
{
this.List.RemoveAt(indeks);
}
public void Ekle(int indeks,Dvd dvd)
{
this.List.Insert(indeks,dvd);
}
public DvdKoleksiyon()
{
}
}
}

Ekle isimli metodumuzun iki versiyonu vardr. Bunlardan birisi koleksiyonun sonuna bir Dvd
nesnesini eklerken dieri, parametre olarak belirtilen indekse ekleme ilemini gerekletirir. Cikart
isimli metodumuzda iki versiyona sahiptir. Bunlardan birisi koleksiyondan parametre olarak ald
Dvd nesnesini kartrken, ikincisi belirtilen indeks zerindeki Dvd nesnesini koleksiyondan
kartmaktadr. Indeksleyicimiz ise, DvdKoleksiyonu ierisindeki Dvd tipinden nesnelere indeks
deerleri zerinden erimemizi salar.

Dikkat ederseniz tm bu yeler sadece ve sadece Dvd tipinden nesneler zerinden i yapmaktadr.
rnein koleksiyona nesne ekleme ve koleksiyondan nesne kartmak iin kullandmz metodlar
parametre olarak mutlaka bir Dvd nesne rneini referans ederler. Benzer ekilde
indeksleyicimizde sadece Dvd tipinden nesneler zerinden alr. imdi yazdmz koleksiyon
snfmz deneyeceimiz bir uygulama gelitirelim.

using System;
using System.Collections;

namespace StrongCollections
{
class Uygulama
{
static DvdKoleksiyon dvdCol;

static void Listele()


{
foreach(Dvd dvd in dvdCol)
{
Console.WriteLine(dvd.ToString());
}
Console.WriteLine("------------------------");
}

www.bsenyurt.com Page 1789


static void KoleksiyonOlustur()
{
dvdCol.Ekle(new Dvd("Gladiator",10,new DateTime(2000,1,1)));
dvdCol.Ekle(new Dvd("Star Wars 3",20,new DateTime(2005,1,4)));
dvdCol.Ekle(new Dvd("Crow",15,new DateTime(1997,3,9)));
}

static void Main(string[] args)


{
dvdCol=new DvdKoleksiyon();
KoleksiyonOlustur();

for(int i=0;i<dvdCol.Count;i++)
{
Console.WriteLine(dvdCol[i].ToString());
}
Console.WriteLine("--------------------");
dvdCol.Cikart(1);

Console.WriteLine("1 nolu eleman kartld...");


Listele();

// dvdCol.Ekle(123); // type - safety salanr.


}
}
}

Uygulamay altrdmzda aadaki sonucu elde ederiz.

Aslnda sanki normal bir koleksiyondan, rnein bir ArrayList ile yaptmz ilemlerden pek bir fark
yokmu gibi grnyor. Fark anlayabilmek iin yorum satrmz koda katarak uygulamay yeniden
derleyelim.

www.bsenyurt.com Page 1790


Burada problem Ekle metoduna saysal bir deerin parametre olarak girilmeye allmasdr.
DvdKoleksiyon snfmzn Ekle metodlarn ksaca bir hatrlarsak;

public void Ekle(Dvd dvd)


{
this.List.Add(dvd);
}
public void Ekle(int indeks,Dvd dvd)
{
this.List.Insert(indeks,dvd);
}

parametre olarak sadece Dvd tipinden nesneleri aldklarn grebiliriz. Bu nedenle kod derleme
zamannda hata vererek gelitiricinin alma zamannda bir hataya dmesini engellemitir. te
bu tip gvenliini salar. Benzer ekilde koleksiyondan okuduumuz bir Dvd nesnesini farkl bir
nesne tipine de atayamayz. rnein aadaki kod parasn gz nne alalm.

Kitap ktp=new Kitap();


ktp=(Kitap)dvdCol[0];

double dbl=(double)dvdCol[0];

Bu durumda derleme zamannda aadaki hata mesajlarn alrz.

www.bsenyurt.com Page 1791


Burada var olan bir tipe ve bizim yazdmz tipe atamalar yaplmaya allmtr. Ancak
koleksiyonumuz sadece Dvd tipinden nesne rneklerini geriye dndren bir indeksleyiciye sahiptir.
Bunu indeksleyiciyi kullanrken de grebilirsiniz.

Oysaki, bir ArrayList gz nne alndnda geriye dnen deer her zaman object tipinden olacaktr.

CollectionBase tipinden trettiimiz nesnelerde, koleksiyonda ilenecek olan nesne tipi ne


ise onu kullanmalyz. Bu tip gvenliini (type - safety ) salayabilmemizi olanakl klar.

CollectionBase' den trettiimiz snflarn salad tip gvenlii daha iyi anlayabilmek iin Dvd
nesnelerini tayacak bir ArrayList koleksiyonunun kullanld aadaki rnei gz nne almakta
fayda var.

ArrayList alDvd=new ArrayList();

alDvd.Add(new Dvd("Gladyatr",10,new DateTime(2000,1,1)));


alDvd.Add(new Dvd("Star vars 3",20,new DateTime(2005,1,4)));
alDvd.Add(new Dvd("krouv",15,new DateTime(1997,3,9)));
alDvd.Add(12);

foreach(Dvd dvd in alDvd)

www.bsenyurt.com Page 1792


{
Console.WriteLine(dvd.ToString());
}

Yazlan kod son derece masumane grnmektedir. stelik derleme zamannda hi bir hata mesaj
vermez. Yani alr bir koddur. Ancak uygulamay bu haliyle altrdmzda aadaki hata
mesajn alrz.

Sorun foreach dngsnde aka grlmektedir. foreach dngs sadece Dvd tipinden elemanlar
zerinde bir teleme gerekletirmek isterken koleksiyonun sonuna eklenen saysal deer bu
durumu bozmaktadr. Eer foreach dngsn terk edip aadaki gibi bir for dngsn tercih
ederseniz durum biraz daha ilgin bir hal alacaktr.

for(int i=0;i<alDvd.Count;i++)
{
Console.WriteLine(alDvd[i].ToString());
}

Kodda herhangibir derleme zaman hatas alnmaz. alma zamannda da bir hata alnmaz.
Uygulama baarl bir ekilde alr. Ancak bu kez de programn mantksal btnl bozulmutur.

te bu tip bir durumla karlatmzda gelitirici olarak tip gvenliini ve uygulamann mantksal
btnln korumak amacyla kendi koleksiyon snflarmz kullanmay tercih ederiz. Yazmzn
banda hatrlarsanz kendi yazacamz koleksiyon snflarn CollectionBase yoluyla veya
DictionaryBase yoluyla gelitirebildiimizi sylemitik. Bu makalemizde CollectionBase snf ile bu
ii nasl yapacamz grdk. Bir sonraki makalemizde ise DictionaryBase snfn inceleyemeye
alacaz. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 1793


Dizilere(Arrays) likin Basit neri (
14.07.2005 ) - C#
Deerli Okurlarm Merhabalar,

Hepimiz dizileri (Arrays) bilir ve kullanrz. Her ne kadar gnmzde koleksiyonlar, xml kaynaklar
ve tablo yaplar veri saklamak amacyla daha ok kullanlyor olsalar da, dizilerdende youn ekilde
yararlanmaktayz. rnein kendi tasarladmz bir snfa ait nesneler topluluunu pekala bir dizi
eklinde ifade edebilir hatta seriletirebiliriz (serializable). Lakin dizileri kullanrken tercih
edeceimiz ve bize performans asndan avantaj salayacak teknikleri ou zaman gz ard ederiz.
te bu makalemizde dizileri kullanrken iimize yarayacak performans kriterlerinden bahsedeceiz.

neri 1 ; Dizi elemanlar arasnda gezinirken kullanacamz for dngleri, foreach


dnglerine nazaran daha sratli alr.

ki dng yaps arasndaki fark daha net olarak grebilmek iin aadaki basit console
uygulamasn gz nne almakta fayda var. Uygulamamzda basit olarak double tipinden bir dizi
tanmlyoruz. Bu dizinin boyutunu dikkat ederseniz yksek verdik. Hem for dngsn hem de
foreach dngsn srasyla altyoruz. lk olarak for dngs ile indeksleyici operatrn
kullanarak dizimizin elemanlar zerinde ilerliyor ve bir toplam deeri alyoruz. Ayn ilemi daha
sonra bir foreach dngs ile gerekletiriyoruz. (Aldmz toplama ileminin bizim iin zel bir
nemi veua anlam yok.) Dnglerin alma srelerini yaklak olarak hesaplayabilmek amacyla
da TimeSpan ve DateTime snflarndan faydalanyoruz. Bu hesaplamalar bize yaklak olarak
dnglerin alma srelerini verecektir.

using System;

namespace UsingArrays
{
class DizilerTest
{
static void DiziTest_1()
{
double[] dizi=new double[50000000];
double toplam=0;

for(int i=0;i<dizi.Length;i++)
{
dizi[i]=i;
}

#region for dngs ile


DateTime dtBaslangic=DateTime.Now;
for(int i=0;i<dizi.Length;i++)
{
toplam+=dizi[i];

www.bsenyurt.com Page 1794


}
DateTime dtBitis=DateTime.Now;
TimeSpan tsFark=dtBitis-dtBaslangic;
Console.WriteLine(tsFark.TotalSeconds+" saniye...");
#endregion

#region foreach dngs ile


toplam=0;
dtBaslangic=DateTime.Now;
foreach(int i in dizi)
{
toplam+=i;
}
dtBitis=DateTime.Now;
tsFark=dtBitis-dtBaslangic;

Console.WriteLine(tsFark.TotalSeconds+" saniye...");
#endregion

Console.ReadLine();
}

static void Main(string[] args)


{
DiziTest_1();
}
}
}

Kodumuzu bu haliyle altrdmzda aadakine benzer bir ekran grnts elde ederiz. Ben
kendi test ortammda (windows 2000, 512 mb Ram, P4 2.4 ghz cpu tabanl bir pc) uygulamay iki
kez farkl zamanlarda altrdmda aadaki sonular aldm. Yaklak deerler olmasna ramen,
belirgin derecede fark olduu hemen gzlemlenmektedir. Tabiki uygulamann verdii sonular
sistemin o anki ilem younluuna gre deiiklik gsterebilir. Ancak sonu olarak for dngleri sz
konusu olan iterasyonu foreach dnglerine gre daha hzl tamamlamaktadr.

lk altrl;

kinci altrl;

www.bsenyurt.com Page 1795


Elbetteki dizimizdeki eleman saysnn azalmas halinde iki dngnn alma sreleri arasndaki
fark azalacaktr hatta bir birlerine daha da yaknlaacaktr. rnein dizimizi 10 milyon elemanl
olarak tanmlarsak uygulamann almasnn sonucu aadaki gibi olacaktr. Dnglerin alma
sreleri arasndaki fark azalm olmasna ramen yinede for dngs iterasyonu ok daha nce
tamamlamtr.

lk altrl;

kinci altrl;

Gelelim diziler ile ilgili ikinci nemli neriye. Bu neri, geriye dn deerleri dizi olan metodlar ile
ilgilidir.

neri 2 ; Metodlardan geriye dizi referanslar dnyorsa, dn deeri olmayacak


koullu durumlarda null deer yerine 0 elemanl bir dizinin dndrlmesi uygulamada
daha az kontrol yapmamz salar.

Bu neriyi anlayabilmek iin aadaki kod parasnda ye alan basiy console uygulamasn gz
nne alalm.

using System;

namespace UsingArrays
{
class DizilerTest
{
static double[] DiziTest_2(int elemanSayisi)
{
if (elemanSayisi <= 0)
{
return null;

www.bsenyurt.com Page 1796


}
else
{
return new double[elemanSayisi];
}
}

static void Main(string[] args)


{
double[] dizi;
dizi = DiziTest_2(-1);
for (int i = 0; i < dizi.Length; i++)
{
Console.WriteLine(dizi[i]);
}
}
}
}

Bu rnekte DiziTest_2 isimli metodumuz diziyi ieride oluturup referansn geri dndrmek zere
tasarlanmtr. Eer bu metoda aktardmz parametre deerimiz 0 veya negatif ise, metodumuz
geriye null deer dndrmektedir. Bu mmkndr nk diziler bildiiniz gibi referans trnden
elemanlardr. Ana kodumuzda ise for dngs yardmyla oluturulan dizinin elemanlar ekrana
yazdrlmaktadr. Uygulamamz bu haliyle derlediimizde aadaki ekran grntsnde olduu gibi
alma zamanndaNullReferenceException istisnas ile karlarz. Bu sonu for dngs yerine
foreach dngsn kullandmz takdirde de kanlmazdr.

Sorunu zebilmek iin dngnn altrlmasndan hemen nce dizi referansnn null olup
olmadnn kontroln yapmamz gerekir. Dolaysyla kodumuzu aadaki gibi dzenlemeliyiz.

double[] dizi;
dizi = DiziTest_2(-1);
if (dizi != null)
{
foreach (double eleman in dizi)
{
Console.WriteLine(eleman);
}
}

www.bsenyurt.com Page 1797


Ancak basit bir teknik ile bu kontrol atlayabiliriz. Tek yapmamz gereken DiziTest_2 isimli
metodumuzda null deer yerine 0 elemanl bir dizi referans dndrmek olacakr. Yani;

static double[] DiziTest_2(int elemanSayisi)


{
if (elemanSayisi <= 0)
{
return new double[0];
}
else
{
return new double[elemanSayisi];
}
}

Bu tekniin performans asndan kazanm olup olmad tartlacak bir konudur. Ancak bizi istisna
yakalama ve if kontrolnden kurtarmtr.

Diziler ile ilgili nc nerimiz ise zellikle iki boyutlu dizileri ilgilendirmektedir.

neri 3 ; ki boyutlu dizilerde i ie kullanlan dnglerde en dtan ie doru


gerekletirilen telemelerde, dizinin boyutlarndaki sraya gre ilem yaplmas
performans olumlu ynde etkiler.

Ne kastetmek istediimizi anlayabilmek iin aadaki kod parasnda verilen rnei gz nne
alalm.

static void DiziTest(int x)


{
int[,] dizi = new int[x, x];
DateTime dtBaslangic, dtBitis;
TimeSpan tsFark;

dtBaslangic = DateTime.Now;
for (int i = 0; i < x; i++)
for (int j = 0; j < x; j++)
dizi[i, j] = i + j;
dtBitis = DateTime.Now;
tsFark = dtBitis - dtBaslangic;
Console.WriteLine("Geen sre...{0} saniye.", tsFark.TotalSeconds);

dtBaslangic = DateTime.Now;
for (int i = 0; i < x; i++)
for (int j = 0; j < x; j++)
dizi[j, i] = i + j;

www.bsenyurt.com Page 1798


dtBitis = DateTime.Now;
tsFark = dtBitis - dtBaslangic;
Console.WriteLine("Geen sre...{0} saniye.", tsFark.TotalSeconds);
}

static void Main(string[] args)


{
for (int testSayisi = 0; testSayisi < 5; testSayisi++)
{
DiziTest(6000);
Console.WriteLine("-------------");
}
}

Bu kod parasnda, iki boyutlu bir diziye eleman atanlar iin iki adet i-ie gemi dng
kullandmz gryorsunuz. Bu dngler arasnda ki tek fark dizi elemanlarna eriim ekli. lk
dngde i,j sras kullanlrken ikinci dngmzde j,i sras kullanlyor. kinci i - ie dngmzde
aslnda i,j srasnda bir iterasyon yaplmasna ramen dizi elemanlarna j,i srasnda eriilmekte. Bu
hepimizin gzden karabilecei bir nokta. Dalgnlk sonucu dahi bu tarz bir kod satr yazma
ihtimalimiz var. Peki ya bu tarz bir yazmn sonular ne olabilir? Dnglerin almalarnn sonucu
ayn olsa da aadaki ekil aradaki fark aka ortaya koymaktadr. Sistemden siteme sreler fark
gsterebilir, ancak iki dng mekanizmasnn arasndaki sre fark ok ak ve belirgindir.

Elbette ayn durum boyutlar farkl bir dizi iinde geerlidir. rneimizdeki dng yaplarn
aadaki gibi deitirelim ve tekrar deneyelim.

static void DiziTest(int x,int y)


{
int[,] dizi = new int[x, y];
DateTime dtBaslangic, dtBitis;
TimeSpan tsFark;

dtBaslangic = DateTime.Now;
for (int i = 0; i < x; i++)

www.bsenyurt.com Page 1799


for (int j = 0; j < y; j++)
dizi[i, j] = i + j;
dtBitis = DateTime.Now;
tsFark = dtBitis - dtBaslangic;
Console.WriteLine("Geen sre...{0} saniye.", tsFark.TotalSeconds);

dtBaslangic = DateTime.Now;
for (int i = 0; i < y; i++)
for (int j = 0; j < x; j++)
dizi[j, i] = i + j;
dtBitis = DateTime.Now;
tsFark = dtBitis - dtBaslangic;
Console.WriteLine("Geen sre...{0} saniye.", tsFark.TotalSeconds);
}

static void Main(string[] args)


{
for (int testSayisi = 0; testSayisi < 5; testSayisi++)
{
DiziTest(6000,5000);
Console.WriteLine("-------------");
}
}

Bu kez sreler biraz daha uzam grnyor. zellikle ikinci i-ie dngde. Burada en byk
etkenlerden birisi x-y sras yerine y-x srasn tercih ediimizdir. Bunu yapmamzn sebebi tahmin
edeceiniz gibi IndexOutOfRangeException istisnasndan kurtulmaktr. Bu kk hileye ramen dizi
boyutlarna ters srada eriilmeye allmas, performans olumsuz ynde etkiler. Elbetteki
gelitirdiimiz uygulamalarda ou zaman bu tip ok boyutlu dngleri kullanmayabiliriz. O
sebepten her iki kullanmda derleme zaman hatas vermeyecei gibi dzgn bir biimde
alacaktr. zellikle kk boyutlu dizilerde bu farklar ok ama ok azdr. Yine de siz siz olun ve
profesyonel bir yazlm gelitirici olarak bu neriyi ve daha ncekilerini dikkate aln. Bylece geldik
bir makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

www.bsenyurt.com Page 1800


Burak Selim ENYURT
selim@bsenyurt.com

C# 2.0 in terasyon Yenilikleri ( 05.07.2005 ) -


C# 2
Deerli Okurlarm Merhabalar,

Bazen kendi yazm olduumuz tiplerin dizi bazl elemanlar olur. Uygulamalarmzda, bu elemanlar
arasnda, elamanlarn sahipi olan nesne rnei zerinden ileri ynl iterasyonlar kurmak
isteyebiliriz. Foreach dngleri belirtilen tip iin bu iterasyonu salayan bir mekanizmaya sahiptir.
Lakin kendi gelitirdiimiz tiplerin sahip olduklar elemanlar zerinde, bu tarz bir iterasyonu
uygulayabilmek iin bir numaratre ve uygulaycya ihtiyacmz vardr. Ksacas, tipimizin elemanlar
arasnda nasl teleme yaplabileceini sisteme retmemiz gerekmektedir. Bu ilevsellii
kazandrmak iin IEnumerable ve IEnumerator arayzlerini birlikte kullanrz.

Uygulamalarmzda klasik olarak kullandmz bir iterasyon teknii vardr. Bu teknie gre
iterasyon ierisinde kullanlacak olan elemanlar iin bir numaratr salanr. IEnumerable
arayznn salad GetEnumerator metodu geriye IEnumerator arayz tipinden bir nesne
rnei dndrmektedir ve bizim iin gerekli olan numaratrn kendisidir. IEnumerator ise
ounlukla dahili bir snfa (inner class) uygulanr ve iterasyon iin gerekli asl metodlar salar. Bu
metodlardan MoveNext bir sonraki elemann olup olmadn bool tipinden dndren bir ileve sahip
iken, Current metodu o anki eleman iterasyona devreder. Bu iki arayz kullanarak bir snf
iindeki elemanlar zerinde iterasyona izin verecek yapy kurmak biraz karmaktr. Aslnda teknik
son derece kolaydr sadece uygulanabilirlii ilk zamanlarda biraz kafa kartrcdr. lk olarak C#
1.1 iin bahsetmi olduumuz iterasyon tekniinin nasl gerekletirildiini inceleyeceimiz bir
rnek gelitirelim.

rneimizde her hangi bir ii simgeleyen bir snfmz olacak. Bu snfmzn modeli basit olarak
aadaki kod parasnda olduu gibidir. IsBilgisi isimli snfmz basit olarak bir iin adn ve
sorumlusuna ait bilgileri tutacak ekilde tasarlanmtr. e ait bilgileri tutan iki zellii ve ar
yklenmi(overload) bir yapc metodu(constructor) mevcuttur.

public class IsBilgisi


{
private string m_IsAdi;
private string m_IsSorumlu;
public string IsAdi
{
get
{
return m_IsAdi;
}
set
{
m_IsAdi=value;
}
}
public string IsSorumlu

www.bsenyurt.com Page 1801


{
get
{
return m_IsSorumlu;
}
set
{
m_IsSorumlu=value;
}
}

public IsBilgisi(string isAdi,string isSorumlu)


{
m_IsAdi=isAdi;
m_IsSorumlu=isSorumlu;
}
}

imdi IsBilgisi snf tipinden 3 eleman bnyesinde barndracak bir listeleme snf tasarlayacaz.
Amacmz IsBilgisi tipinden dizinin elemanlarna foreach dngsn kullanarak IsListesi nesnesi
zerinden eriebilmek. Yani aadaki kodun altrlmasn salamak istiyoruz. Burada dikkat
ederseniz foreach dngmz,"liste isimli IsListesi rneindeki her bir IsBilgisi tipinden nesne rnei
iin ilerle" gibisinden bir iterasyon gerekletirmektedir.

IsListesi liste=new IsListesi();


foreach(IsBilgisi i in liste)
{
Console.WriteLine(i.IsAdi+" "+i.IsSorumlu);
}

Normal artlarda eer IsListesi isimli snfmza IEnumerable ve IEnumerator arayzlerini


kullandmz iterasyon tekniini uygulamazsak bu kod derleme zamannda foreach dngsnn
uygulanamyacana dair hata mesaj verecektir. Yani IsListesi snfmzn kodunun balangta
aadaki gibi olduunu dnrsek;

public class IsListesi


{
static IsBilgisi[] Isler=new IsBilgisi[3];
private void ListeOlustur()
{
IsBilgisi is1=new IsBilgisi("Birinci i","Burak");
IsBilgisi is2=new IsBilgisi("kinci i","Jordan");
IsBilgisi is3=new IsBilgisi("nc i","Vader");
Isler[0]=is1;
Isler[1]=is2;
Isler[2]=is3;

www.bsenyurt.com Page 1802


}

public IsListesi()
{
ListeOlustur();
}
}

derleme zamannda aadaki hata mesajn alrz.

foreach statement cannot operate on variables of type


'Using_Iterators_CSharp_1.IsListesi' because 'Using_Iterators_CSharp_1.IsListesi' does
not contain a definition for 'GetEnumerator', or it is inaccessible

nk foreach dngsnn IsListesi snf iindeki IsBilgisi nesnelerine nasl eriecei ve onlar
zerinde ileri ynl nasl hareket edecei bilinmemektedir. Bu nedenle IsListesi snfmz aadaki
gibi oluturulmaldr. Buradaki amacmz C# 1.1 iin iterasyon tekniini incelemek olduundan ana
fikirde IsBilgisi snf tipinden 3 elemanl bir dizi kullanlmaktadr.

// Iterasyonu salayabilmek iin IEnumerable arayzn uyguluyoruz.


public class IsListesi:IEnumerable
{
// IsBilgisi tipinden nesne rneklerini tayacak dizimiz tanmlanyor.
static IsBilgisi[] Isler=new IsBilgisi[3];
// Isler isimli diziyi dolduracak basit bir metod.
private void ListeOlustur()
{
IsBilgisi is1=new IsBilgisi("Birinci i","Burak");
IsBilgisi is2=new IsBilgisi("kinci i","Jordan");
IsBilgisi is3=new IsBilgisi("nc i","Vader");
Isler[0]=is1;
Isler[1]=is2;
Isler[2]=is3;
}

public IsListesi()
{
// IsListesi nesne rneimiz oluturulurken Isler isimli dizimizde IsBilgisi tipinden elemanlar
ile dolduruluyor.
ListeOlustur();
}

#region IEnumerable Members

// GetEnumerator metodu IsListesi snfmzdaki Isler dizisinin elemanlarnda hareket

www.bsenyurt.com Page 1803


edebilmemiz iin gerekli numaratr nesne rneini geriye dndryor
public IEnumerator GetEnumerator()
{
return new Numarator();
}

#endregion

// Isler dizisindeki elemanlarda foreach dngsn kullanarak IsListesi snf zerinden ileri ynl
ve yanlz okunabilir iterasyon yapmamz salayacak inner class' mz olusturuyor ve bu snfa
IEnumerator arayzn uyguluyoruz.
private class Numarator:IEnumerator
{
// Dizideki eleman temsil edecek bir indeks deeri tanmlyoruz.
int indeks=-1;

#region IEnumerator Members

public void Reset()


{
indeks=-1;
}

// Gncel IsBilgisi elemann indeks deerini kullanarak Isler dizisi zerinden object tipinde
geriye dndren bir zellik. Dikkat ederseniz yanlzca get blou var. Bu nedenle foreach
dnglerinin salad iterasyon iinde elemanlar zerinde deiiklik yapamyoruz.
public object Current
{
get
{
return Isler[indeks];
}
}

// terasyonun devam edip etmemesine karar verebilmek iin, u anki elemandan sonra gelen
bir elemannn varl tespit edilmelidir. Bunu MoveNext metodu bool tipinden bir deer dndrerek
foreach mekanizmasna anlatr. Bizim kontrol etmemiz gereken gncel indeks deerinin Isler isimli
dizinin uzunluundan fazla olup olmaddr.
public bool MoveNext()
{
if(++indeks>=Isler.Length)
return false;
else
return true;
}

#endregion
}

www.bsenyurt.com Page 1804


}

imdi bu elemanlar kullanan basit bir console uygulmasn altrdmzda aadakine benzer bir
ekran grnts elde ederiz.

Her ne kadar uygulamamz istediimiz biimde alsada bizim iin bir takm zorluklar vardr. lki
kod yazmnn bir desen dahilinde de olsa uzun oluudur. kinci zorluk foreach dngs iinde
kullanlan elemanlar iin tip gvenliinin (type-safety) olmaydr. Dikkat ederseniz IEnumerator
arayznn salad Current isimli metodumuz object tipinden elemanlar geriye dndrmektedir.
Oysaki biz sadece IsBilgisi nesnesi tipinden elemanlar geriye dndrecek bir Current metodunu
pekala isteyebiliriz. Hatta bu bize tip gvenliinide salayacaktr.

te C# 2.0 hem uzun kod satrlarnn nne geen hem de tip gvenliini salayan yeni bir yap
getirmitir. Yapnn temelinde yine IEnumerable arayz yer almaktadr. Yeni generic tipleri
sayesinde, iterasyonun bizim belirttiimiz tiplere ynelik olarak gerekletirilebilecek olmasda
garanti altna alnmaktadr. Bu da aradmz tip gvenliini bize salar. Yukarda gelitirmi
olduumu yapy C# 2.0' da aadaki ekilde dzenleriz.

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingIterators
{
public class IsListesi:IEnumerable<IsBilgisi>
{
static IsBilgisi[] Isler = new IsBilgisi[3];
private void ListeOlustur()
{
IsBilgisi is1 = new IsBilgisi("Birinci i", "Burak");
IsBilgisi is2 = new IsBilgisi("kinci i", "Jordan");
IsBilgisi is3 = new IsBilgisi("nc i", "Vader");
Isler[0] = is1;
Isler[1] = is2;
Isler[2] = is3;
}

public IsListesi()
{
ListeOlustur();
}

www.bsenyurt.com Page 1805


#region IEnumerable<IsBilgisi> Members

IEnumerator<IsBilgisi> IEnumerable<IsBilgisi>.GetEnumerator()
{
yield return Isler[0];
yield return Isler[1];
yield return Isler[2];
}

#endregion

#region IEnumerable Members

System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
throw new Exception("The method or operation is not implemented.");
}

#endregion
}
}

Uygulama kodumuza ksaca bir gz gezdirirsek en byk yeniliklerden birisinin IEnumerable


arayznn uygulan srasnda ki generic tip tanmlamas olduunu farkedebiliriz.

public class IsListesi:IEnumerable<IsBilgisi>

Bu tanmlama ile basite, IsListesi nesnesinin uygulayaca IEnumerable arayznn, IsBilgisi


tipinden nesne rnekleri iin geerli olaca belirtilmektedir. Bu tahmin edebileceiniz gibi, tip
gvenlii dediimiz ihtiyac karlamaktadr (type safety).

Dier nemli bir deiiklik IEnumerator arayzn uygulam olduumuz her hangi bir dahili snfn
(inner class) burada yer almaydr. Son olarak yield anahtar szcnn kullanmda en byk
yeniliktir. yield anahtar szc C# 2.0 ile gelen yeni anahtar szcklerden birisidir.
IEnumerator<T> tipinden nesne rneini geri dndren metodumuz ierisinde kullanlmaktadr.

IEnumerator<IsBilgisi> IEnumerable<IsBilgisi>.GetEnumerator()
{
yield return Isler[0];
yield return Isler[1];
yield return Isler[2];
}

Dikkat ederseniz Isler isimli dizimizde yer alan her eleman iin yield return sz dizimi kullanlmtr.
Aslnda ayn ilevi aadaki kod ilede karlyabiliriz. stelik bu ok daha profesyonel bir

www.bsenyurt.com Page 1806


yaklamdr. Temel olarak anlamamz gereken yield return' n ilgili dizi iindeki her bir eleman iin
kullanlyor olmasdr.

IEnumerator<IsBilgisi> IEnumerable<IsBilgisi>.GetEnumerator()
{
for (int i = 0; i < Isler.Length; i++)
{
yield return Isler[i];
}
}

Ksacas artk yeni iterasyon modelimizde tek yapmamz gereken, foreach dngsne dahil olacak
elemanlarn ilgili numarator metodu iinde yield anahtar szc kullanlarak geri dndrlmesini
salamaktr. rnein aadaki kod parasnn ekran ktsn gz nne alalm.

IEnumerator<IsBilgisi> IEnumerable<IsBilgisi>.GetEnumerator()
{
yield return Isler[2];
yield return Isler[1];
}

Dikkat ederseniz foreach iterasyonumuz yield ile hangi elemanlar hangi srada dndrdysek ona
gre almtr.

Uygulamadaki geliimi bir de IL kodu asndan dnmek lazm. Aslnda temelde


numaralandrcnn kullanlmas iin gerekli olan IEnumerator bazl bir inner class yine
kullanlmaktadr. Bu sadece kod yazmnda yaplmamaktadr. yleki, C# 1.1 iin gelitirdiimiz
rnein IL koduna ilDasm arac ile bakarsak aadaki ekran grntsn yakalarz.

www.bsenyurt.com Page 1807


Dikkat ederseniz burada Numarator isimli dahili snfmz (inner class) ve ona IEnumerator arayz
vastasyla uyguladmz yeler grlmektedir. Birde C# 2.0 iin gelitirdiimiz rnein IL koduna
bir bakalm.

u anki beta versiyonuna gre IlDasm aracnn fiziki adresi \Program Files\Microsoft
Visual Studio 8\SDK\v2.0\Bin\ildasm.exe dr.

Dikkat ederseniz biz IEnumerator arayzn kullanarak bir dahili snf yazmam olsakta, IL
kodunun detaylarnda byle bir yapnn kullanld grlmektedir. Tabi burada bir nceki
versiyondan farkl olarak, generic tip uyarlamasda mevcuttur.

www.bsenyurt.com Page 1808


Artk uygulamamz iin aadaki kod parasn baarl bir ekilde altrabiliriz.

IsListesi isListesi = new IsListesi();


foreach (IsBilgisi i in isListesi)
{
Console.WriteLine(i.IsAdi + " " + i.IsSorumlu);
}

www.bsenyurt.com Page 1809


Grdnz gibi C# 2.0 ile iteratif ilemlerin alt yapsnn oluuturlmas C# 1.1 ' e gre daha az
kod yazarak kolayca gerekletirilebiliyor. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

C# 2.0 Covariance ve Contravariance Delegates (


30.06.2005 ) - C# 2
Deerli Okurlarm Merhabalar,

Bildiiniz gibi temsilciler (delegates) alma zamannda metodlarn balang adreslerini iaret
eden tiplerdir. Bu tipleri uygulamalarmzda tanmlarken alma zamannda iaret edebilecekleri
metodlarn geri dn tipi ve parametrik yaplarn bildirecek ekilde olutururuz. Ancak zellikle ,
C# 1.1 ortamnda temsilcilerin kullanmnda parametre ve dn tipileri asndan iki nemli
skntmz vardr. Bu skntlarn kaynanda birbirlerinden treyen yani aralarnda kaltmsal
(inheritance) ilikiler olan tipler yer alr.

Nitekim temsilciler C# 1.1 versiyonunda oluturulacaklar zaman, iaret edecekleri metodlar iin
kesin dn ve parametre tipi uyumluluunu ararlar. Dolaysla bu tiplerde kaltmsal ilikiler sz
konusu olduunda ortaya kan iki temel problem vardr. Bu iki temel sorunumuza bakmadan nce,
konunun odanda aralarnda kaltm ilikisi olan iki snf olduunu gz nne almalyz. rnein
Sekil ve Dortgen isimli iki snfmz olduunu ve Dortgen snfnn Sekil snfndan trediini
varsayalm. Bu snflarn sahip olduu ieriin bizim iin u aamada ok fazla nemi yoktur. lk
olarak covariance' la neden olan sorunu ele alalm. Aadaki uygulamamz dikkatle inceleyelim.

using System;

namespace UsingCovariance
{
public class Sekil
{
public Sekil()
{
}
}
public class Dortgen:Sekil
{
public Dortgen()
{

www.bsenyurt.com Page 1810


}
}

public delegate Sekil Temsilci();

class Class1
{
public static Sekil Metod_1()
{
return null;
}

public static Dortgen Metod_2()


{
return null;
}

[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new Temsilci(Metod_1);
temsilci=new Temsilci(Metod_2); // Derleme zaman hatas
}
}
}

Bu uygulamay derlediimizde,

temsilci=new Temsilci(Metod_2);

satr iin Method 'UsingCovariance.Class1.Metod_2()' does not match delegate


'UsingCovariance.Sekil UsingCovariance.Temsilci()' hatasn alrz. Peki burada sorun nedir?
Temsilci isimli delegate tipimiz, Sekil snfndan nesne rneklerini geriye dndren ve parametre
almayan metodlar iaret edebilecek ekilde tanmlanmtr . Bu durumda,

Temsilci temsilci=new Temsilci(Metod_1);

satr dzgn olarak alacaktr. Nitekim Metod_1 delegate tipimizin tanmlamalarna uyan tarzda
bir metoddur. Oysaki Metod_2 metodumuzun geriye dndrd deer Dortgen snf tipindendir.
Dolaysyla temsilci nesnemizin tanmlad bildirimin dnda bir dn tipininin dn sz
konusudur. Hatrlayn, temsilciler iaret edecekleri metodlar iin kesin dn tipi ve parametre tipi
uyumluluu ararlar. Oysaki Dortgen ve Sekil snf arasnda kaltmsal bir iliki sz konusudur ve bu
sebeple bu tarz bir kullanmn sorunsuz olarak alaca dnlmektedir. nk kaltmn doas
gerei bu Dortgen snfna ait nesne rnekleri Sekil snfna ait nesne rneklerine dntrlebilir.
Ancak temsilcimiz asndan bu kural ne yazk ki geerli deildir. Yani temsilcimiz belirtilen tipler
iin alma zamannda ok biimlilii destekleyememitir.

www.bsenyurt.com Page 1811


Peki bu sorunu nasl zebiliriz? Tek yapabileceimiz Dortgen snfna ait nesne rneklerini
dndren Metod_2 isimli metodumuzu iaret edecek yeni bir delegate nesnesini aadaki rnek
kod parasnda olduu gibi tanmlamak ve kullanmak olacaktr. Bu tahmin edeceiniz gibi hantal bir
zmdr. Bir birleri arasnda tr dnm yaplabilecek iki snf iin gereksiz yere iki ayr temsilci
tipi tanmlamak zorunda kalmz dahi istenmeyen bir durumdur.

public delegate Sekil Temsilci();


public delegate Dortgen Temsilci2();

class Class1
{
public static Sekil Metod_1()
{
return null;
}

public static Dortgen Metod_2()


{
return null;
}

[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new Temsilci(Metod_1);
Temsilci2 temsilci2i=new Temsilci2(Metod_2);
}
}

te C# 2.0' da, delegate tipi iin sz konusu olan bu sorun ortadan kaldrlmtr. Yukardaki
rneimizin aynsn C# 2.0' da yazdmz dnrsek her hangi bir derleme zaman hatas
almayz. Covariance' n desteklenebilmesi iin C# 2.0' a getirilen ekstra bir kodlama teknii yoktur.

www.bsenyurt.com Page 1812


Bu tamamen .net ekirdeinde delegate tipi zerinde yaplan bir dzenlemenin sonucudur.

Covariance, temsilcilerin alma zamannda iaret etmek istedii metodlarn,


aralarnda kaltmsal iliki olan dn tipleri arasndaki poliformik uyum
sorununu ortadan kaldran bir zellik olarak nitelendirilebilir.

Temsilci nesnelerimizin iaret edecei metodlarn dn tiplerinin kaltmsal ilikilere izin verecek
ekilde dzenlenmi olmas elbetteki alma zamannda bize byk bir esneklik getirmektedir.
Nitekim bu sayede birbirlerinden tremi n sayda snfa ait nesne rneklerinin dn tipi olarak
kullanld metodlar tek bir delegate nesnesi vastasyla alma zamannda iaret edebiliriz.

Gelelim contravariance durumuna. Bu kez kaltm ilikisine sahip olan snf rnekleri, temsilcilerin
iaret edecei metodlarn parametrik yaplar ierisinde kullanlmaktadr. Aadaki rnek kod
paras C# 1.1 iin bu durumu rneklemektedir.

using System;

namespace UsingContravariance

www.bsenyurt.com Page 1813


{
public class Sekil
{
public Sekil()
{
}
}
public class Dortgen:Sekil
{
public Dortgen()
{
}
}

public delegate int Temsilci(Dortgen dortgen);

class Class1
{
public static int Metod_1(Dortgen dortgen)
{
return 0;
}
public static int Metod_2(Sekil sekil)
{
return 0;
}

[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new Temsilci(Metod_1);
temsilci=new Temsilci(Metod_2); // Derleme zaman hatas
}
}
}

Bu kez delegate tipimiz geriye int tipinden deer dndren ve parametre olarak Dortgen snf
tipinden nesne rneklerini alan metodlar iaret edebilecek ekilde tanmlanmtr. Kodu
derlediimizde Method 'UsingContravariance.Class1. Metod_2(UsingContravariance.Sekil)' does not
match delegate 'int UsingContravariance.Temsilci(UsingContravariance .Dortgen)' hatasn alrz.
Yine delegate tipimiz burada parametrik imza uyumazlndan bahsetmektedir. Sorun,

temsilci=new Temsilci(Metod_2);

satrnda oluur. nk Metod_2 Dortgen snf tipinden bir nesne rneini parametre olarak
almaktansa Dortgen snfnn st snf olan Sekil snfndan bir nesne rneini parametre olarak
almaktadr. Buradaki problem tersi durum iinde sz konusudur. Yani temsilcimizi tanmlarken

www.bsenyurt.com Page 1814


metodun alaca parametrenin, treyen snf yerine temel snftan (base class) bir nesne rneini
kullanacak ekilde aadaki kod parasnda grld gibi tanmlandn dnrsek;

public delegate int Temsilci(Sekil sekil);

class Class1
{
public static int Metod_1(Dortgen dortgen)
{
return 0;
}
public static int Metod_2(Sekil sekil)
{
return 0;
}

[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new Temsilci(Metod_1); // Derleme zaman hatas
temsilci=new Temsilci(Metod_2);
}
}

bu sefer Metod_1 iin oluturulan temsilci isimli nesnemiz zerinden ayn hata mesajn alrz. Doal
olarak, metod parametlerinin st snftan veya treyen snftan olmas durumu deitirmeyecektir.

Contravariance, temsilcilerin alma zamannda iaret etmek istedii


metodlarn parametreleri arasnda kaltmsal ilikiye sahip tiplerin neden olduu
polimorfik uyum sorununu ortadan kaldran bir zellik olarak nitelendirilebilir.

Parametrelerin uyumsuzluunun neden olduu bu sorunu C# 1.1 ile zmek iin, covariance
tekniinde olduu gibi her bir metod iin ayr temsilci nesnelerini aadaki kod parasnda olduu
gibi tanmlamamz gerekecektir.

public delegate int Temsilci(Sekil sekil);


public delegate int Temsilci2(Dortgen dortgen);

class Class1
{
public static int Metod_1(Sekil sekil)
{
return 0;
}
public static int Metod_2(Dortgen Dortgen)

www.bsenyurt.com Page 1815


{
return 0;
}

[STAThread]
static void Main(string[] args)
{
Temsilci temsilci=new Temsilci(Metod_1);
Temsilci2 temsilci2=new Temsilci2(Metod_2);
}
}

Yukardaki rneimizi C# 2.0 ile derlediimizde ise her hangi bir sorun olmadn grrz.

Parametrelerin arasndaki kaltmsal iliki, alma zamannda temsilciler oluturulurken de


deerlendirilecek ve nesneler arasndaki tr dnm baarl bir ekilde parametrelerede
yansyacaktr. Bu covarince probleminde olduu gibi bize yine byk bir esneklik salar. Aralarnda
kaltmsal iliki olan n sayda snf nesne rneini kullanan metodlar tek bir temsilci nesnesi ile
alma zamannda iaret edebilme yetenei. Bylece geldik bir makalemizin daha sonuna, bir
sonraki makalemizde grnceye dek hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 1816


Burak Selim ENYURT
selim@bsenyurt.com

C# 2.0 ile Partial Types (Ksmi Tipler) (


27.06.2005 ) - C# 2
Deerli Okurlarm Merhabalar,

Visual Studio.Net ile windows veya web uygulamalar gelitirirken, kod yazlmas srasnda
karlatmz glklerden birisi, tasarm kodlar ile kendi yazm olduklarmzn i ie
gemeleridir. Bu zamanla kodun okunabilirliini zorlatran bir etmendir. Bunun windows
uygulamalarn veya asp.net uygulamalarn gelitirirken ska yaamaktayz. Bununla birlikte,
zellike soruce safe gibi ortamlarda farkl gelitiricilerin ayn snf kodlar zerinde e zamanl olarak
almas pek mmkn deildir. Visual Studio.2005 ile birlikte, snf (class), arayz(interface) ve
yap(struct) gibi tipleri mantksal olarak ayrtrabileceimiz ve farkl fiziki dosyalarda (veya ayn
fiziki dosya zerinde) tutabileceimiz yeni bir yap getirilmitir. Bu yapnn kilit noktas tiplerin
partial anahtar szc ile imzalanmasdr. Partial olarak tanmladmz tipleri farkl fiziki
dosyalarda (veya ayn fiziki dosya ierisinde) tutabiliriz. Burada nemli olan, alma zamannda
yazm olduumuz tipin mutlaka tek bir btn olarak ele alnyor olmasdr.

Partial tipler, bir tipin btnn oluturan soyutsal paralardr.

te bu makalemizde ksaca partial tiplerin nasl kullanldn incelemeye alacaz. imdi Visual
Studio.2005 ile gelitirdiimiz aadaki rnei gz nne alalm. Yeni atmz bir Console
uygulamasnda projemize ekilden de greceiniz gibi VeriYonetim.Ozellik ve VeriYonetim.Metod
adl iki kaynak kod dosyas ekledik.

ncelikle buradaki amacmzdan bahsedelim. Veritaban ile ilgili ynetim ilerini stlenecek bir snf
gelitirmek istiyoruz. Ancak bu snfn zelliklerini ve metodlarn ayr fiziki kaynak kod dosyalarnda
tutacaz. Bu mantksal ayrm yapmamzn eitli nedenleri olabilir. Gelitiricilerin ayn snfn eitli
mantksal paralar zerinde bamsz ama e zamanl olarak almalarn isteyebiliriz. ounlukla
en temel nedemiz snf btnn mantksal olarak ayrtrarak kodlamay kolaylatrmaktr. te bu
amala VeriYonetim isimli snfmzn bu ayr paralarn tutacak iki fiziki snf dosyasn projemize
ekledik. Bylece snfmz aslnda iki mantksal paraya blm olduk. lk parada sadece gerekli

www.bsenyurt.com Page 1817


zellik tanmalamalarn ikinci parada ise ilevsel metodlar barndracaz. Bylece kod gelitirme
safhasnda bu mantksal paralarn iki farkl dosyada tutulmasn salam oluyoruz.

Tasarm zamannda snfmz iki farkl paraya ayrm olsakta, kod gelitirme srasnda veya
alma zamannda tek bir tip olarak ele alnacaktr. Yani snfn btnl aslnda hi bir ekilde
bozulmamaktadr. Bu nemli bir noktadr. imdi ilk rneimizin kodlarna ksaca bakalm.

VeriYonetim.Ozellikler.cs;

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace PartialClasses
{
partial class VeriYonetim
{
private SqlConnection m_GuncelBaglanti;
private SqlCommand m_SqlKomutu;

public SqlConnection GuncelBaglanti


{

www.bsenyurt.com Page 1818


get { return m_GuncelBaglanti; }
set { m_GuncelBaglanti = value; }
}
public SqlCommand SqlKomutu
{
get { return m_SqlKomutu; }
set { m_SqlKomutu = value; }
}
}
}

VeriYonetim.Metodlar.cs;

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;

namespace PartialClasses
{
partial class VeriYonetim
{
public VeriYonetim(string baglanti)
{
m_GuncelBaglanti = new SqlConnection(baglanti);
}
public void KomutHazirla(string sorguCumlesi)
{
m_SqlKomutu = new SqlCommand(sorguCumlesi, GuncelBaglanti);
}
}
}

Uygulama ;

using System;
using System.Collections.Generic;
using System.Text;

namespace PartialClasses
{
class Program
{
static void Main(string[] args)
{

www.bsenyurt.com Page 1819


VeriYonetim yonetici = new VeriYonetim("data
source=localhost;database=AdventureWorks;integrated security=SSPI");
yonetici.KomutHazirla("SELECT * FROM Customers");
}
}
}

VeriYonetim isimli snfmz her iki kaynak kod dosyas ierisinde partial anahtar kelimesi ile
tanmlyoruz. Bylece nceden bahsetmi olduumuz mantksal ayrtrmay gerekletirmi olduk.
Eer MS ILDasm (Microsoft Intermediate Language DisAssembler) program yardmyla derlediimiz
uygulamamza gz atarsak ayr paralar halinde gelitirdiimiz VeriYonetim snfnn tek bir tip
olarak yazldn grrz.

Bizim partial snflar ierisine bldmz zellik, alan ve metodlar burada tek bir at altnda
toplanmtr. Partial snflar kullanrken elbetteki dikkat etmemiz gereken noktalar vardr. rnein
partial snflar ierisinde ayn elemanlar tanmlayamayz. Yukardaki rneimizde zellikleri
tuttuumuz snf paramza metodlar tuttuumuz snf parasnda olan constructor (yapc metod)
dan bir tane daha ekleyelim. zellikle ayn metod imzalarna sahip olmalarna dikkat edelim. Bu
durumda uygulamay derlemeye altmzda aadaki hata mesajn alrz.

www.bsenyurt.com Page 1820


Bu hata bize, partial class' larn asnda tek bir snf oluturan paralar olduunu ispat etmektedir.
Bu teoriden yola karaktan metodlarn ar yklenmi (overload) hallerini partial class' lar
ierisinde kullanabileceimizi syleyebiliriz. Bu sefer zellikleri tuttuumuz partial snfmz ierisine
VeriYonetim tipimiz iin varsaylan yapc metodu (default constructor) ekleyelim.

partial class VeriYonetim


{
public VeriYonetim()
{
m_GuncelBaglanti = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI");
}
// Dier kodlar
}

Bu durumda uygulamamz sorunsuz ekilde derlenecek ve alacaktr.

Partial snflar(classes) tanmlayabildiimiz gibi partial arayzler(interfaces)


veya yaplarda(structs) tanmlayabiliriz.

rnein, paralar aadaki ekilden de grld gibi iki farkl fiziki kaynak dosyada tutulacak
IVeriYonetim isimli bir arayz oluturmak istediimizi dnelim. IVeriYonetim.Metodlar.cs kaynak
kod dosyas ierisinde arayz uygulayacak olan tiplerin iermesi gereken metodlar bildireceimizi
farzedelim. IVeriYonetim.Ozellikler.cs kaynak kod dosyasnda ise, bu arayz uygulayacak tiplerin
iermesi gereken zellik bildirimlerini yapacamz varsayalm.

www.bsenyurt.com Page 1821


Tek yapmamz gereken arayzlerimizi mantksal olarak ayrtrmak ve partial anahtar kelimesini
kullanarak kodlamak olacaktr.

IVeriYonetim.Ozellikler.cs dosyas;

using System;
using System.Collections.Generic;
using System.Text;

namespace PartialClasses
{
partial interface IVeriYonetim
{
int MaasArtisOrani
{
get;
set;
}
}
}

IVeriYonetim.Metodlar.cs dosyas;

using System;
using System.Collections.Generic;
using System.Text;

namespace PartialClasses
{
partial interface IVeriYonetim
{
void Bilgilendir();
int PersonelSayisi(string sqlCumlesi);
}

www.bsenyurt.com Page 1822


}

Her iki interface tanmlamasda aslnda tek bir interface' in kendi kurduumuz mantksal mimari
erevesinde ayrlm soyut paralardr. Keza, IVeriYonetim isimli arayzmz her hangi bir snfa
uyguladmzda aadaki ekilden de grld gibi arayzmzn paralar deil btnl ele
alnacaktr.

Snflarda olduu gibi interface' ler iinde IL kodunun verdii grnm benzer olacaktr. Arayz
ilgili snfmza uyguladmzda partial blmlerde yer alan tm elemanlarn implementasyona dahil
edildiini grrz.

class VeriYoneticisi:IVeriYonetim
{

#region IVeriYonetim Members

// IVeriYonetim.Ozellikler.cs kaynak kod dosyas ierisindeki partial ksmdan gelen


yeler.
public void Bilgilendir()
{
//
}

public int PersonelSayisi(string sqlCumlesi)


{
//
}

// IVeriYonetim.Metodlar.cs kaynak kod dosyas iindeki partial ksmdan gelen


yeler.
public int MaasArtisOrani
{
get
{
//
}
set

www.bsenyurt.com Page 1823


{
//
}
}
#endregion
}

Tek bir at altnda toplanm kod ierisinde mantksal olarak ayr paralara blnm bir tek
arayz.

Partial ksmlarn, sturct' larda kullanl biimleride snflar ve arayzlerde olduu gibidir.

zellikle partial snflar iin bir takm kurallar vardr. Bu kurallara gre partial snflardan her hangi
biri abstract veya sealed olarak belirtilirse, sz konusu tipin tamam bu ekilde deerlendirilir.
rnein aadaki uygulamada partial snflarmzdan birisi sealed olarak tanmlanmtr. Bunun
doal sonucu olarak sz konusu olan tip sealed olarak ele alnr. Dolaysyla bu tipten her hangi bir
ekilde tretme ilemi gerekletirilemez. rnein aadaki kod derleme zamannda hataya yol
aacaktr.

sealed partial class Islemler


{
}
partial class Islemler
{
}
class AltIslemler : Islemler

www.bsenyurt.com Page 1824


{
}

Peki Partial snflar birden ok defa sealed tanmlarsak ne olur? rnein yukardaki kodumuzda
Islemler snfnn her iki parasnada sealed anahtar szcn uyguladmz dnelim.

sealed partial class Islemler


{
}
sealed partial class Islemler
{
}

Burada ki gibi bir kullanm tamamen geerlidir. Derleme zamannda her hangi bir hata alnmaz.
Parital tiplerin kullanm ile ilgili bir dier kstlamaya gre partial olarak imzalanm bir snf partial
olamayan bir snf olarak tekrardan yazamayz. Yani aadaki ekran grntsnde olduu gibi
Islemler isimli snf hem partial olarak hem de normal bir snf olarak tanmlayamayz. Byle bir
kullanm sonrasnda derleme zaman hatasn alrz.

Grld gibi snflarmz, arayzlerimizi veya yaplarmz partial olarak tanmlamak son derece
kolaydr. Tek yapmanz gereken partial anahtar szcn kullanmaktr. Asl zor olan, bu tipleri
blme ihtiyacn tespit edebilmek ve ne ekilde paralara ayrabileceimize karar vermektir. Yani bir
snf gelii gzel paralara blmektense bunun iin geerli bir sebep aramak son derece nemlidir.
Ayrca mantksal blmlemeyi ok iyi analiz etmemiz gerekir. Bu analizin en iyi zm sunabilmesi
ise sizlerin proje tecrbenize, planlama ve ngr yeteneklerinize baldr. Bylece geldik bir

www.bsenyurt.com Page 1825


makalemizin daha sonuna. Bir sonraki makalemizde grnceye dek hepinize mutlu gnler
dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

C# 2.0 ve Nullable Deer Tipleri ( 22.06.2005 ) -


C# 2
Deerli Okurlarm Merhabalar,

C# programlama dilinde bildiiniz gibi veri trlerini Referans Trleri(Reference Types) ve Deer
Trleri (Value Types) olmak zere iki ksma ayryoruz. Bu iki tr arasnda bellek zerinde fiziki
tutulu ekillerinden tutunda birbirleri arasndaki atamalara kadar pek ok farkllk vardr. Bu
farkllklardan birisi de, referans trlerinin null deerleri alabilmelerine karn, deer trlerinin ayn
zellie sahip olmaylardr. Bu durum zellikle veritaban tablolarnda null deer alabilen alanlarn,
dil ierisindeki tip karl deer trne denk dtnde baz zorluklar kartabilmektedir. te bu
makalemizde, C# 2.0 diliyle gelen yeni zelliklerden birisi olan Nullable Value Types (Null deer
alabilen deer trleri) ni incelemeye alacaz. Balang olarak C# 1.1 versiyonundaki durumu
analiz ederek ie balayalm. Aadaki kod parasnda bir referans trne ve bir de deer trne
null deerler atanmaya allmaktadr.

using System;

namespace ConsoleApplication2
{
class Class1
{
static void Main(string[] args)
{
string refTuru=null;
int degerTuru=null;
}
}
}

Bu uygulamay derlemeye altmzda Cannot convert null to 'int' because it is a value


type hatasn alrz. Ayn durumu kendi tanmladmz referans ve deer trleri iinde
gerekletirebiliriz. Aadaki kod parasnda bu durum rneklenmitir.

using System;

namespace ConsoleApplication2
{
class Kitap
{
}
struct Dvd

www.bsenyurt.com Page 1826


{
}
class Class1
{
static void Main(string[] args)
{
Kitap kitap=null;
Dvd dvd=null;
}
}
}

Bu kod parasndada ayn hatay alrz. nk struct' lar deer trdr ve bu sebeple null deerler
alamazlar. Oysaki ayn istisnai durum class gibi kendi tanmlam olduumuz referans trleri iin
geerli deildir. Peki deer trlerinin null deer ierme ihtiyac ne zaman doabilir? Bir veritaban
uygulamasn gz nne alalm. Bu tabloda int, double gibi deer trlerine karlk gelecek alanlarn
var olduunu dnelim. Veri girii srasnda bu int ve double deikenleri null olarak tabloya
aktarmak isteyebiliriz. Ya da tablodan veri ekerken, deer tr karl alanlarn null deer ierip
iermediini anlamak isteyebiliriz. te bu gibi durumlarda deer trlerinin null veriler ierebilecek
yapda olmas, kodumuzun leklenebilirliini arttracak bir yetkinlik olarak dnlebilir.
Veritabanlar iin geerli olan bu senaryoyu gz nne almadan nce C# 2.0 iin deer trlerinin
nasl null veriler tayabileceini incelemeye alalm. Deer trlerinin C# 2.0 iin iki versiyonu
vardr. Nullable deer trleri ve Non-Nullable deer trleri. Bir deer trnn null deerler ierecek
tipte olacan belirtmek iin ? tip belirleyicisi kullanlr.

using System;
using System.Collections.Generic;
using System.Text;

namespace TestOfNullableValues
{
class Program
{
static void Main(string[] args)
{
int? maas;
double? pi;
maas = null;
pi = null;
}
}
}

Yukardaki kod paras sorunsuz olarak derlenecek ve alacaktr. ? ile tanmlanan deer trleri
null veriler tayabilen deer tipindendir. Ayn durum kendi tanmladmz bir struct iinde
geerlidir. Aadaki kod parasnda Personel isimli struct' a null deer atamas yaplmtr.

struct Personel
{

www.bsenyurt.com Page 1827


}

class Program
{
static void Main(string[] args)
{
Personel? person = null;
}
}

Elbette referans trlerinde bu tarz bir kullanm geerli olmayacaktr. rnein aadaki kod
parasnda kendi tanmlam olduumuz bir snf nesnesine ve string trnden bir deikene ?
belirleyicisi vastasyla null deerler atanmaya allmtr.

Oysaki referans trleri zaten null deerler alabilmektedir.

Referans trlerine ? tip belirleyicisi uygulayarak null deer atamas yaplamaz.

? tip belirleyicisi aslnda tanmlanan deer trnn null veri tayabilecek baka bir versiyonunu
kullanlacan belirtmektedir. Bu yeni deer tr versiyonlar ise null verileri tayabilecek bir
yapda tasarlanmlardr. ? belirleyicisinin uyguland bir deer trnn null deerler ierip
iermediine HasValue zellii ilede baklabilmektedir. Bu zellik, ilgili deer tr null veri ierdii
srece false dndrecektir. rnein,

www.bsenyurt.com Page 1828


int? Yas;
Yas = null; // Yas deer trne null veri atanyor.
if (Yas.HasValue) // false dnecektir
{
Console.WriteLine("Yas null deil...");
}
else
{
Console.WriteLine("Yas null..."); // Bu satr iletilir.
}

C# 2.0 diline ? tip belirleyicisinden yola klaraktan yeni bir operatr eklenmitir. ?? operatr. Bu
operatr ksaca bir deer trnn ieriinin null olup olmamasna gre koullu olarak atama
yapmaktadr. Eer operatrde kullanlan null veri tayabilir deer trnn o anki deeri null ise,
koul olarak belirtilen deer ilgili deikene atanr. Aksi takdirde, deer trnn o anki verisi, ilgili
deikene atanr. Aadaki rnek kod parasnda bu operatrn kullanm ekli gsterilmeye
allmtr.

int? Yas; // null deer alabilecek bir deer tr tanmlanyor.

Yas = null; // null deer atamas


int yasi = Yas ?? 0; // Eer Yas null ise yasi alanna 0 atanr.
Console.WriteLine(yasi); // 0 yazar

Yas = 12;
yasi = Yas ?? 0; // Eer Yas null deil ise yasi alanna Yas' n o anki deeri atanr.
Console.WriteLine(yasi); // 12 yazar

lk kullanmda, Yas deer trnn sahip olduu veri null olarak belirlenmitir. ?? operatr bu
durumda yasi alanna 0 deerini atayacaktr. kinci kullanmda ise Yas deer trnn verisi 12
olarak belirlenmitir. Buna grede ?? operatr yasi deikenine 12 deerini (yani Yas nullable
deer trnn o anki verisini) atayacaktr. Burada dikkat ederseniz Yas null deer alabilen bir int
tipidir. Bununla birlikte ?? operatr ile yaplan veri atamas null deerler ieremiyen normal bir int
tipine doru yaplmaktadr. Burada sz konusu olan atama ilemini biraz irdelemekte fayda vardr.
Aadaki kod parasn ele alalm.

int? pi = 3;
int m_Pi;
m_Pi = pi;

Bu rnek derlenmeyecektir. Bunun sebebi ise null deer alabilen bir deer trn, normal bir deer
trne bilinsiz olarak atamaya almamzdr. Dolaysyla,

Nullable Deer trleri bilinsiz olarak normal deer trlerine dntrlemez.

www.bsenyurt.com Page 1829


Ancak aadaki kod parasnda grlen tr dnm ilemi geerlidir.

int? pi = 3;
int m_Pi;
m_Pi = (int)pi;

Elbette burada dikkat edilmesi gereken bir durum daha vardr. Eer o anki deeri null olan bir
deer trn normal bir deer trne bilinli olarak atamaya alrsak alma zamannda
InvalidOperationException hatas alrz.

Dolaysyla bu tip atamalarda ?? operatrn tercih etmek ok daha aklc bir yaklam olacaktr.
Nullable deer trlerine, normal deer trlerinin atanmasnda ise bilinsiz tr dnm de
geerlidir.

double e = 2.7;
double? E;
E = (double?)e; // Bilinli tr dnm
E = e; // Bilinsiz tr dnm

Yukardaki kod parasnda E null deerler tayabilen bir deer trdr. e ise normal deer trdr.

Normal deer trleri, nullable deer trlerine hem bilinli hem de bilinsiz
olarak dntrlebilir.

Makalemizin sonunda bir veritaban uygulamasnda null deerler alabilen deer trlerinin nasl
kullanlabildiini incelemeye alacaz. lk olarak C# 1.1 versiyonunda aadaki yapda bir
uygulama gelitirelim. Bu rneimizde, Sporculara ait bir takm temel bilgileri tutan bir tabloyu
kullanacaz. Tablomuzda tanml olan Sporcu, Boy ve Ya alanlar null deerler ierebilecek ekilde
yaplandrlmtr.

www.bsenyurt.com Page 1830


rnek olarakta aadaki iki satr verinin var olduunu dnelim. Dikkat ederseniz ikinci satrda
deer tr olarak ele alacamz alanlara <Null> deerler atanmtr.

Uygulama kodlarmz ise balang olarak aadaki gibidir. Basit olarak Sporcular temsil edecek bir
snf ve tablo zerindeki temel veritaban ilemlerini gerekletirecek bir katman snf yer
almaktadr. Katman snfmz u an iin sadece ve sadece Sporcu tablosundaki verileri okuyup, her
bir satr iin birer Sporcu nesnesi yaratan ve onun override edilmi ToString metodu ile bilgilerini
ekrana yazdran bir metoda sahiptir.

using System;
using System.Data;
using System.Data.SqlClient;

namespace TestNullableValues
{
class Sporcu
{
private int m_id;
private string m_sporcu;
private double m_boy;
private int m_kilo;
public Sporcu(int id,string sporcu,double boy,int kilo)
{
m_id=id;
m_sporcu=sporcu;
m_boy=boy;
m_kilo=kilo;
}
public override string ToString()
{
return m_id.ToString()+" "+m_sporcu+" "+m_boy.ToString()+" "+m_kilo.ToString();
}
}

class SporYonetim
{
SqlConnection con;
SqlCommand cmd;
SqlDataReader dr;

www.bsenyurt.com Page 1831


public SporYonetim()
{
con=new SqlConnection("data source=localhost;database=MyBase;user
id=sa;password=");
}

public void SporcuListesi()


{
cmd=new SqlCommand("Select ID,Sporcu,Boy,Kilo From Sporcular",con);
con.Open();
dr=cmd.ExecuteReader(CommandBehavior.CloseConnection);
while(dr.Read())
{
int id=(int)dr["ID"];
string sporcu=dr["Sporcu"].ToString();
double boy=(double)dr["Boy"];
int kilo=(int)dr["Kilo"];
Sporcu sprc=new Sporcu(id,sporcu,boy,kilo);
Console.WriteLine(sprc.ToString());
}
}
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
SporYonetim ynt=new SporYonetim();
ynt.SporcuListesi();
}
}
}

Bizim iin nemli olan nokta Boy ve Yas alanlarnn deererinin double ve int alanlara atld yerdir.
Uygulamamz bu haliyle altrdmzda aadaki hata mesajn alrz.

www.bsenyurt.com Page 1832


Sebep gayet net ve aktr. Deer trleri null veri ieremeyecei iin cast ilemleri alma
zamannda InvalidCastException tipinden bir istisna nesnesi frlatlmasna neden olmutur. Bu
sorunu amak iin kullanabileceimiz tekniklerden bir tanesi aadaki gibidir. dr ile okunan tablo
alanlar object tipinden geriye dndnden ve object tipide referans tr olduundan null deerler
ierebilir. Burada alann o anki verisinin null olup olmamasna gre uygun atamalar
gerekletirilmektedir.

double boy;
int kilo;
if(dr["Boy"]==System.DBNull.Value)
boy=0;
else
boy=(double)dr["Boy"];
if(dr["Kilo"]==System.DBNull.Value)
kilo=0;
else
kilo=(int)dr["Kilo"];
Sporcu sprc=new Sporcu(id,sporcu,boy,kilo);

Ayn rnei aadaki haliyle C# 2.0 versiyonunda daha farkl bir yaklam ile yazabiliriz. Bu kez,
Sporcu snfmzn yapc metodunda yer alan boy ve kilo parametleri ile private field olarak
tanmladmz m_Boy ve m_Kilo alanlarn null deer ierebilecek ekilde tanmlayarak ie
balayacaz. Yine SqlDataReader ile okuduumuz alanlarn null deer ierip iermediini kontrol
edeceiz. Ancak bu kez null deer ierseler dahi onlar taayabilecek deer trlerimiz elimizde

www.bsenyurt.com Page 1833


olacak. Bylece tablomuzda null deere sahip olan alanlarmz ekrana yazdrabileceiz.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Text;

namespace UsingNullableValues
{
class Sporcu
{
//Dier kod satrlar

// Snf ii bu iki alan null deerler tayabilecel tipten tanmladk.


private double? m_boy;
private int? m_kilo;

// Dier kod satrlar


}

class SporYonetim
{
// Dier kod satrlar

public void SporcuListesi()


{
// Dier kod satrlar
while (dr.Read())
{
// Dier kod satrlar

double? boy=null;
int? kilo=null;
if(dr["Boy"]!=System.DBNull.Value)
boy=(double)dr["Boy"];
if (dr["Kilo"] != System.DBNull.Value)
kilo = (int)dr["Kilo"];

// nullable deikenleri Sporcu snfnn yapc metoduna parametre olarak gnderiyoruz.


Sporcu sprc = new Sporcu(id, sporcu, boy, kilo);
Console.WriteLine(sprc.ToString());
}
}
}
class Program
{
static void Main(string[] args)

www.bsenyurt.com Page 1834


{
SporYonetim ynt = new SporYonetim();
ynt.SporcuListesi();
}
}
}

Uygulamamz bu haliyele altrdmzda tablodaki tm satrlarn ekrana yazdrldn grrz. C#


1.1 de gelitirdiimiz uygulama ile bu versiyon arasndaki en nemli fark, nullable deer trlerinin
kullanlarak null verilerin uygulama ierisinde kullanlabilmesidir. Bir sonraki makalemizde
grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

C# 2.0 ve Static Snflar ( 20.06.2005 ) - C# 2


Deerli Okurlarm Merhabalar,

ou zaman uygulamalarmzda, nesne rneinin oluturulmasna gerek duymayacamz yeleri


kullanmak isteriz. Bu amala static yeleri kullanrz. imdi bir de sadece static yelerden oluacak
bir snf tasarlamak istediimizi dnelim. C# programlama dilinin ilk versiyonunda bu tip bir snf
yazmak iin dikkat etmemiz gereken bir takm noktalar vardr. Static yeler kullanlabilmeleri iin
tanml olduklar snfn nesne rneine ihtiya duymazlar. Bu sebepten sadece static yeler
ierecek olan bir snfn rneklendirilememesi tercih edilecektir. rnein aadaki kod parasn
dikkate alalm. TemelAritmetik isimli snfmz Toplam isimli static bir metod iermektedir.

using System;

namespace UsingStaticClasses
{
public class TemelAritmetik
{
public static double Toplam(double deger1,double deger2)
{
return deger1+deger2;
}
}

class Class1
{
static void Main(string[] args)

www.bsenyurt.com Page 1835


{
double toplamSonuc=TemelAritmetik.Toplam(10,15);
Console.WriteLine(toplamSonuc);
}
}
}

Bu kod parasnda aada olduu gibi TemelAritmetik snfna ait bir nesne rnei tanmlayp
Toplam metodunu bu nesne rnei zerinden armaya almak derleme zamannda hataya
neden olacaktr. Az ncede belirttiimiz gibi, static yelere tanmlandklar snfa ait nesne rnekleri
zerinden eriilemezler.

TemelAritmetik temelAritmetik=new TemelAritmetik();


double toplamSonuc=temelAritmetik.Toplam(4,5);

Ancak yinede dikkat ederseniz TemelAritmetik snfna ait nesne rneini oluturabilmekteyiz. Bu
durumda ,ilk olarak static yelerle dolu bir snfn kesin olarak rneklendirilmesini nlemek
isteyeceizdir. Bu nedenle varsaylan yapc metodu (default constructor) private olarak
tanmlayarak bu durumun nne geebiliriz.

public class TemelAritmetik


{
// Varsaylan yapc private olduundan snfa ait nesne rnei oluturulamayacaktr.
private TemelAritmetik()
{
}

public static double Toplam(double deger1,double deger2)


{
return deger1+deger2;
}
}

Grld gibi artk TemelAritmetik snfna ait nesne rneklerinin retilmesinin nne getik. Ayn
ekilde varsaylan yapc metodun private olarak tanmlanmas bu snfta tretilme yaplmasnda
engellemektedir. Ancak bazen static yeler ieren snfmzn yapc metodu public veya protected
olarak tanmlanm olabilir. Bu durumda tretme ilemi gerekleebilecektir. rnein aadaki kod
parasn ele alalm.

using System;

namespace UsingStaticClasses
{
public class TemelAritmetik

www.bsenyurt.com Page 1836


{
public TemelAritmetik()
{
}

public static double Toplam(double deger1,double deger2)


{
return deger1+deger2;
}
}

public class AltAritmetik:TemelAritmetik


{
public void AltIslemler()
{
}
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
AltAritmetik altAritmetik=new AltAritmetik();
altAritmetik.AltIslemler();
double sonuc=AltAritmetik.Toplam(1,2);
}
}
}

Dolaysyla sadece static yeler ierecek bir snfn tretme ilemi iin kullanlmasnda bir ekilde
nlemek isteyebiliriz. Bu durumda sealed anahtar szc yardmyla, ilgili snfn tretme amacyla
kullanlamayacan belirtiriz.

public sealed class TemelAritmetik

Bu sadece static yeler ieren, tretilmeye izin vermeyen ve nesne rneini kesin olarak
oluturtmak istemediimiz bir snf iin acaba yeterli midir? sealed olarak tanmlanm snflar her
ne kadar tretme amacyla kullanlamasada, public eriim belirleyicisine sahip yapc metodlar
nedeni ile rneklendirilebilirler. Bize biraz daha zorlayc, kesin kurallar sunacak yeni bir yap C#
2.0 ile birlikte gelmektedir. C# 2.0 snflarn static olarak tanmlanabilmesine izin vermektedir.
Static snflar beraberinde bir takm kurallarda getirir. Aadaki kod paras C# 2.0 iin rnek bir
static snf tanmlamasn iermektedir.

using System;
using System.Collections.Generic;

www.bsenyurt.com Page 1837


using System.Text;

namespace UsingStaticClasses
{
public static class TemelAritmetik
{
public static double Toplam(double deger1,double deger2)
{
return deger1+deger2;
}
public static double pi = 3.14;
public static double PI
{
get
{
return pi;
}
set
{
pi = value;
}
}
}

class Program
{
static void Main(string[] args)
{
double sonuc=TemelAritmetik.Toplam(3, 5);
Console.WriteLine(sonuc);
Console.WriteLine(TemelAritmetik.pi);
TemelAritmetik.PI = 3;
Console.WriteLine(TemelAritmetik.PI);
}
}
}

rneimizde ieriinide static olarak tanmlanm metod, field ve zellik bulunan bir snf
grmektesiniz. Bu snfn bir nceki versiyona gre en nemli zellii static olarak tanmlanabiliyor
oluudur. Peki bu snfn static olarak tanmlanmasn getirdii kstlamalar nelerdir? lk olarak bu
snfa ait bir nesne rnei oluturmaya alalm.

TemelAritmetik ta;
TemelAritmetik tAritmetik = new TemelAritmetik();

www.bsenyurt.com Page 1838


Bu tip bir kod yazmna Visual Studio.2005 zaten intellisense zellii yardmyla izin vermeyecektir.
Lakin tAritmetik isimli nesne rneini new operatr ile oluturmaya altmzda TemelAritmetik
snfnn adnn listeye gelmediini grrz.

Dier yandan kodu derlediimizde aadaki hatalar alrz. Toplam 3 hatamz vardr. lk satr iin
verilen hatadan static olarak tanmlanm bir snfa ait nesne tanmlamas yapamadmz
anlayabiliriz. Dier yandan, ikinci satrda static snfa ait nesne rneinin oluturulamayaca ve
ayn zamanda tanmlanamayacana dair hata mesajlarn alrz.

Buradan u sonulara varabiliriz;

Static olarak tanmlanm snflara ait nesne rneklerini retemeyiz. Ayrca


static snflara ait nesne tanmlamalarn da yapamayz.

Static snflarn snrlamalar sadece bunlarla snrl deildir. imdi yukardaki static snfmza
aada olduu gibi static olmayan bir ka yeni ye daha ekleyelim.

public static class TemelAritmetik

www.bsenyurt.com Page 1839


{
public TemelAritmetik()
{
}
private int e;
protected void BilgiVer()
{
// Bir takm kodlar.
}

public static double Toplam(double deger1,double deger2)


{
return deger1+deger2;
}
public static double pi = 3.14;
public static double PI
{
get
{
return pi;
}
set
{
pi = value;
}
}
}

Kaynak kodumuzu derlediimizde 4 adet derleme zaman hatas alrz.

www.bsenyurt.com Page 1840


lk hatamz static snf ierisinde varsaylan yapc(default construcor) metod tanmlamaya
almaktr. Dilerseniz varsaylan yapc metodu ar ykleyerek baka versiyonlar ile de ayn
uygulamay derlemeyi deneyebilirsiniz. Sonu hep ayn olacaktr. Elbette doal olarak yapc
metodlar static olarak tanmlamaya alabiliriz ki bu zaten izin verilmeyen bir durumdur.

Static olarak tanmlanm snflar yapc metodlar (varsaylan yapc ve ar


yklenmi versiyonlar) ieremez.

Dier hatalarmz ise, static snf ierisinde static olmayan yeler tanmlamaya almamzdr.
Buradan da u sonuca varabiliriz.

Static olarak tanmlanm snflar sadece static yeler ierebilir.

www.bsenyurt.com Page 1841


ncelememiz gereken bir dier durum static snflarn tretilip tretilemiyeceidir. Aadaki kod
parasn gz nne alalm.

public static class TemelAritmetik


{
// Static snf kodlarmz
}

public class AltAritmetik : TemelAritmetik


{
}

Visual Studio.2005 her zamanki gibi bu tarz bir yazma zaten izin vermeyecektir. Ancak elimizin
altnda visual studio gibi bir gelitirme ortam olmadn ve notepad gibi bir editor yardmyla bu
kodu yazdmz dnecek olursak aadaki hata mesajn alrz.

Buradan varacamz sonu ise,

Static olarak tanmlanm snflardan baka snflar tretilemez.

www.bsenyurt.com Page 1842


Burada dikkate deer baka bir durum daha vardr. Static bir snftan baka bir snf tretemeyiz.
Peki static snf baka bir snftan tretebilir miyiz? Cevap basit;

Ancak bu durum static snflarnda mutlaka object snfndan tredii gereini deitirmez. Her ne
kadar static bir snf baka bir snftan tretemessekte onun object snfndan tredii kesindir.
Hata mesajmzda zaten bu durumu bize ispatlamaktadr. Bu noktada aklmza kurnazca bir teknik
gelebilir. Static bir snf baka bir static snftan tretmeyi deneyebiliriz. Bu tarz bir kodu
denediimizde aadaki hata mesajlarn alrz.

www.bsenyurt.com Page 1843


Buna gre u sonuca varabiliriz;

Static olarak tanmlanm snflardan baka static snflar da tretilemez.

Static olarak tanmlanm snflarn sadece static yeler ierecei kesin olmasna ramen, yelerinin
static anahtar szc ile tanmlanyor olmas biraz tuhaf bir durum olarak grlebilir. yleki
izlediim bir iki blog sitesinde bu durum biraz alayc ifadeler ile komik olarak ele alnm. Tabi u
anda test ettiimiz static class' larn beta 2 srmne ait olduu dnlecek olursa piyasaya
kacak olan srmde bu durum zerinde iyiletirmeler yaplabilir.

Durumu zetleyecek olursak, sadece static yeler iermesini dndmz,


rneklenmesini ve tretilmesini kesinlikle istemediimiz snflarn tanmlanabilmesi iin
static anahtar szcn snflar iin kullanabiliriz. Bu dndmz tasarm modelinin
uygulamamz iin yeterli olacaktr. Geldik bir makalemizin daha sonuna. Bu makalemizde C# 2.0' a
gelen yeni zelliklerden brisi olan static snflar incelemeye altk. Bir sonraki makalemizde
grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

www.bsenyurt.com Page 1844


C# 2.0 ve Anonymous (simsiz) Metodlar (
16.06.2005 ) - C# 2
Deerli Okurlarm Merhabalar,

simsiz metodlar bildiiniz gibi C# 2.0' a eklenmi olan yeni zelliklerden birisidir. Temeli C# dilinin
temsilci tipine dayanan bu yeni teknikte ama, temsilcileri iaret edecekleri metodlarn sahip
olduklar kod bloklar ile bir seferde tanmlayabilmektir. simsiz metodlar anlayabilmek iin
hereyden nce temsilcilerin (delegates) iyi kavranm olmas gerekmektedir. (n bilgi veya
hatrlatma asndan rnek makale ve video larmz incelemenizi neririm) Ksaca temsilciler,
alma zamannda metodlarn balang adreslerini iaret eden tip (type) lerdir. Temsilcilerin
herhangibir metodu alma zamannda iaret edebilmesinin yan sra bu metodu(metodlar)
arlabilmesi ve hatta parametreler gndererek dn deerleri vermesi gibi yetenekleride vardr.
Ama tm bu zellikleri arasnda en nemlisi, alma zamannda hangi metodu altracana karar
vermesidir.

Temsilciler (delegates), multithreading(ok kanall programlama) modelinde,


event-driven (olay gdml) programlamada, CallBack Modeli ile Asenkron
eriim tekniklerinde etkin olarak kullanlmaktadr.

C# 2.0 ile gelen isimsiz (anonymous) metodlar anlamak iin ncelikle C# dilinde bir temsilciyi nasl
kullandmza bakmamzda fayda var. Aadaki rnekte basit olarak bir temsilci tanmlanm ve
kullanlmtr. Bu temsilci iki adet double tipte parametre alan ve geriye double tipinden deerler
dndren metodlar iaret edebilecek ekilde tanmlanmtr. Dikkat ederseniz temsilci nesnemize
ait nesne rneimiz oluturulurken iaret edecei metod parametre olarak verilmektedir. Daha
sonra bu temsilci nesne rnei zerinden iaret edilen metod arlabilmektedir.

using System;

namespace DefiningDelegate
{
//Temsilcimiz iki adet double tipinden parametre alan ve geriye double tipinden deer dndren
metodlar iaret edebilecek.
public delegate double Temsilci(double pi,double r);

class Class1
{
[STAThread]
static void Main(string[] args)
{
// Temsilci nesnemiz oluturuluyor ve Alan isimli metodu iaret edecei syleniyor.
Temsilci t=new Temsilci(Alan);
// Temsilcimizin alma zamannda iaret ettii metod arlyor.
double daire_Alani=t(3.14,10);
Console.WriteLine(daire_Alani);
}

// Tanmladmz temsilci tarafndan iaret edilebilecek formatta bir metod bildirimi.

www.bsenyurt.com Page 1845


static double Alan(double pi_Degeri,double yaricap)
{
return pi_Degeri*(yaricap*yaricap);
}
}
}

C# 2.0 iin anonymous metodlar kullanarak yukardaki uygulamay aadaki kod parasnda
grld gibi yazabiliriz. Yeni versiyonda temsilci kullanmndaki tek fark temsilcinin iaret edecei
metod blounun, alma zamannda bu metodu aracak olan temsilci nesnesine eklenmi
oluudur. Buradan temsilcilerin inline (satr ii) kodlama yetenei kazanm olduklarn
syleyebiliriz.

simsiz(Anonymous) metodlar dardan parametre alabilirler ve geriye deer


dndrebiliriler.

C# 2.0 versiyonu

using System;
using System.Collections.Generic;
using System.Text;

namespace UsingAnonymousMethods
{
// Temsilcimizi tanmlyoruz.
public delegate double Temsilci(double a,double b);

class Program
{
static void Main(string[] args)
{
// Temsilcimizi hem oluturuyor hemde iaret edecei metod blounu anonymous olarak
tanmlyoruz.
Temsilci t = delegate(double pi,double r)
{
return pi * r*r;
};
// Temsilcimizi parametreler ile birlikte aryoruz ve dn deerini double tipinden bir
deikene atyoruz.
double alan = t(3.14, 10);
Console.WriteLine(alan);
}
}
}

www.bsenyurt.com Page 1846


Gelelim isimsiz metodlarn bir dier kullanm ekline. ok kanall (Multithreading) programlama
modelinde bildiiniz gibi ThreadStart isimli bir temsilci(delegate) tipi kullanlmaktadr. Bu temsilci
bir Thread nesne rneinin oluturulmas srasnda, yapc metod iin parametre olarak
kullanlmaktadr. C# 1.1 versiyonunda basit bir thread modeli aadaki kod parasnda olduu gibi
rneklenebilir. Ltfen temsilcilerin alma zamannda iaret edecekleri metodlar ile birlikte nasl
ilikilendirildiine dikkat edin.

using System;
using System.Threading;

namespace UsingThreading1
{
class Class1
{
//ThreadStart temsilcimiz alma zamannda ilgili process iindeki metodu temsil edecek.
static ThreadStart threadStart1;
static ThreadStart threadStart2;

// Thread nesnemiz parametre olarak ald ThreadStart temsilcisinin iaret ettiim metodun
ait olduu process iin gerekli ilemleri (start,abort,resume vb...) gerekletirecek.
static Thread thread1;
static Thread thread2;

// Thread iinde alacak metodlarmz.


static void Say1()
{
for(int i=0;i<100;i++)
{
Console.Write(i);
Thread.Sleep(100);
}
}

static void Say2()


{
for(int i=0;i<100;i++)
{
Console.WriteLine(i);
Thread.Sleep(150);
}
}

[STAThread]
static void Main(string[] args)
{
// ThreadStart temsilcilerimiz alma zamannda iaret edecekleri parametre olarak
alacak ekilde tanmlanyor.
threadStart1=new ThreadStart(Say1);
threadStart2=new ThreadStart(Say2);
// Thread nesnelerimiz ThreadStart temsilcilerinin parametre olarak alacak ekilde

www.bsenyurt.com Page 1847


tanmlanyor.
thread1=new Thread(threadStart1);
thread2=new Thread(threadStart2);
// Threadler altrlmaya balanyor.
thread1.Start();
thread2.Start();
}
}
}

imdi ayn rnein C# 2.0' da isimsiz metodlar yardmyla nasl yazlabileceine bakalm. Burada
dikkat ederseniz ThreadStart temsilcisi grlmemektedir. Bu elbetteki ThreadStart temsilcisinin
kullanlmad anlamna gelmemelidir. Aslnda bu tanmlama gizli olarak Thread snfna ait nesne
rnekleri oluturulurken yaplmaktadr. Yani alma zamannda Thread nesnesinin zaten bir
ThreadStart temsilci nesnesine ihtiyac olduu alma ortam tarafndan bilinmektedir. Dier
yandan kod yazm asndan bakldnda iki ilemin, (ThreadStart' n iaret edecei metodu
gsterecek ekilde rneklenmesi ve daha sonrada Thread nesnesinin oluuturulmas iin parametre
olarak kullanlmas) tek seferde yaplmaktadr.

C# 2.0 Versiyonu

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace UsingAnonymousMethods
{
class Program
{
// Thread ierisinde alacak metodumuz.
static void Say1()
{
for(int i=0;i<100;i++)
{
Console.Write(i);
Thread.Sleep(100);
}
}

static void Main(string[] args)


{
// lk Thread nesnemizi rneklerken ThreadStart temsilcisinin iaret edecei metodu
burada anonymous metod olarak tanmlyoruz.
Thread thread1=new Thread(delegate(){
Say1();
});
// Tanmladmz thread' i altryoruz.
thread1.Start();

www.bsenyurt.com Page 1848


// kinci Thread nesne rneimizi oluturuyoruz. Bu sefer thread1 nesnesinden farkl olarak
anonymous metodumuz ierisine direkt kodlar gmdk. thread1 nesnesinde ise kodlar ieren
metodu, anonymous metod bloumuz iine gmmtk.
Thread thread2 = new Thread(delegate(){
for (int i = 0; i < 100; i++)
{
Console.WriteLine(i);
Thread.Sleep(150);
}
});
thread2.Start();
}
}
}

Temsilcilerin kullanld dier bir tekniinde olay gdml (event-driven) programlama modeli
olduunu sylemitik. Bu modelde de Threading modeline benzer bir yap vardr. Her event (olay)
tanmlanrken bir temsilci kullanlr. Bu temsilci olay meydana geldiinde altrlacak olan metodu
alma zamannda iaret etmek ve armakla ykmldr. rnein aadaki kod parasnda bir
windows formu zerinde yer alan button kontrolnn Click olayna ilikin kodlar yer almaktadr. Bu
rneimizde, dikkat ederseniz button kontrolmze Click event' n ykleyebilmek iin
System.EventHandler temsilci tipi kullanlmaktadr. Bu temsilci, dier olay metodlarnda kullanlan
temsilciler gibi sistemde nceden tanmlanm halde yer almaktadr. InitializeComponent
metodunda button kontrolmze click olay yklenirken, hangi temsilcinin alma zamann hangi
metodu iaret edecei ve altracada bildirilir. Sonrasnda ise bu olay metodunun tanmlanmas
gerekmektedir.

public class Form1 : System.Windows.Forms.Form


{
private System.Windows.Forms.Button btnAksiyon;

// Dier kodlar

private void InitializeComponent()


{

// Dier Kodlar

this.btnAksiyon.Click += new System.EventHandler(this.btnAksiyon_Click);


}

// Dier Kodlar

private void btnAksiyon_Click(object sender, System.EventArgs e)


{
// Bir takm kodlar.

www.bsenyurt.com Page 1849


}
}

imdi ayn rnein C# 2.0' da isimsiz metodlar yardmyla nasl yazlabileceine bakalm.
Grld gibi System.EventHandler temsilcisi burada grlmemektedir. Aslnda tm isimsiz
metod modellerinde, temsilcilerden hangisi kullanlrsa kullanlsn (rnein System.EventHandler
veya ThreadStart gibi) bizim tek kullandmz delegate anahtar szc ile bir metod blounun
kombinasyonudur. Bu isimsiz metodlarn kullanmnn bir faydas olarakta grlebilir.

simsiz(Anonymous) metodlarda, kullanlan temsilcinin bilinmesine gerek


yoktur. delegate anahtar szc bu ii stlenir.

C# 2.0 Versiyonu

private void InitializeComponent()


{

// Dier kodlar

this.btnOnay.Click += delegate(object sender, System.EventArgs arg)


{
System.Windows.Forms.MessageBox.Show("Onay");
};

// Dier kodlar

simsiz metodlar uygulanlar asndan biraz kark grlebilir. En azndan alncaya kadar.
Ancak kavrandklarnda ok faydal olduklarn syleyebiliriz. Nitekim temsilci nesnelerimizin
tanmlamas gereken yerlerde direkt olarak kod bloklarn kullanmak olduka kullanl bir teknik
olarak karmza kmaktadr. Bu makalemizde C# 2.0 ile birlikte gelen isimsiz metod kavarmn,
her zaman iin iie olduu temsilciler ile birlikte incelemeye altk. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Operator Overloading (Operatrlerin Ar


Yklenmesi) ( 03.06.2005 ) - C#
Deerli Okurlarm Merhabalar,

Hepimiz uygulamalarmzda sklkla operatrleri kullanmaktayz. Matematiksel ilemlerde, koullu


ifadelerde,tip dntrme ilemlerinde vb...Ancak onlarn kendi yazdmz snflar iin zel

www.bsenyurt.com Page 1850


anlamlar ifade edecek ekilde yklenmesi ile pek az uramaktayz. Basit bir toplama operatrnn
bile, yeri geldiinde kendi snflarmza ait nesne rnekleri zerinde daha farkl davranlar
gsterecek ekilde yeniden yaplandrlmas son derece nemlidir. Bu ayn zamanda dilin salad
esneklii ve geniletilebilirliini de gzler nne sergilemektedir. te bu makalemizde, basit olarak
operatrlerin ar yklenmelerinin nasl gerekletirilebileceini rnek bir uygulama zerinden
incelemeye alacaz.

lk olarak senaryomuzdan ksaca bahsedelim. Uygulamamzda System.Drawing isim alann


kullanarak drtgen ve eliptik ekilleri izmemizi salayacak iki adet snfmz olacak. Bu snflarn
izim metodlarna baktmzda ortak parametreler ierdiklerini grrz. Bu nedenle bu ortak
parametreleri bir arada toplayacamz bir st snfda iin iine katarak ilgili ekil snflarn buradan
treteceiz. Amacmz kaltm kavram zerinde durmak deil. Bunu sadece kod okunabilirliini ve
nesnelerinin kullanlabilirliini kolaylatrmak amacyla gerekletiriyoruz. Peki bu snflarn yer
ald bir uygulamada hangi operatrleri ne amala ar ykleyebiliriz?

lk bata akla gelen eliptik bir eklin ierdii koordinat, boyut, renk gibi deerleri ile birlikte bir
drtgene evrilmesi olabilir. Burada drtgen tipinden bir nesne rneinin, bilinli (explicit) veya
bilinsiz (implicit) olarak eliptik bir nesne rneine dntrlmesi sz konusudur. Bunun iin cast
operatrn ar ykleyebiliriz. Dier taraftan, var olan drtgen veya eliptik nesnelerinin kendi
aralarnda toplama operatrleri ile toplanmas sonucu eitli kriterlere uyum salayacak yeni bir
drtgen veya elips nesnesini elde etmeyi dnebiliriz. rnein, iki kareyi toplayp, yeni boyutlar
bu iki karenin toplam kadar olan baka bir kare nesnesini izdirebiliriz. Bu ilevsellikte ancak ve
ancak toplama operatrnn burada sz konusu olan snflar iin ar yklenmesi ile mmkn
olabilir. imdi gelin uygulamamz gelitirmeye balayalm. Operatrlerin ar yklenmesini
aadaki grnme sahip bir windows uygulamasnda inceleyeceiz.

www.bsenyurt.com Page 1851


Uygulamay mmkn olduu kadar basit tasarlamaya altm. Amacmz operatrlerin ar
yklenmesini incelemek. Bu nedenle Macromedia Fireworks gibi bir grafik tasarm programn icat
etmeye almyoruz. Programmz temel olarak belirli renkte izgilere sahip olan drtgensel ve
eliptik ekilleri iziyor. Bir ekli izmek iin genilik ve yksekliini ilgili textBox kontrollerine
atadktan sonra mouse ile ekrann herhangibir yerine tklamanz yeterli olacaktr. Bununla birlikte
ie biraz renk katmak amac ile izgi renklerini seebiliyorsunuz. Mende bizim asl ilgilendiimiz iki
seenek var. Bunlardan birisi bir Elips nesnesini, Drtgen tipinden bir nesneye dntrerek ekrana
iziyor. Dier men seenei ilede iki Drtgen nesnesini toplayp sonucunu ekrana izdiriyoruz.
Makalenin ilerleyen safhalarnda iki eklin boyutsal bazda birbirlerine eit olup olmadn bildirecek
ekilde koul operatrlerini de ar ykleyeceiz. Nesneleri tutmak amacyla iki ArrayList
koleksiyonu kullanmay tercih ettim. Elbetteki siz bu program dahada gelitirmeli ve nesnelerin
daha esnek olarak tutulabilecei bir yapy kurgulamalsnz.

Gelelim uygulamamzdaki kritik snflara. Bu snflar, Dortgen, Elips ve TemelSekil snflardr.

Dortgen ve Elips snflar TemelSekil snfndan tretilmitir. Sebebi, Dortgen ve Elips snflarnn
izimi iin kullanlan metodlarn ayn tipte ve sayda parametre alyor olmalardr. Dolaysyla izim
iin gerekli materyalleri bir st snfta tutmak ve bunlara tek bir yerden eriebilmek amacya bu
tarz bir yap tercih edilmitir. Snflarmza ilikin balang kodlar aadaki gibidir.

Drtgen.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace UsingGDIWithOperatorOverloading
{
public class Dortgen:TemelSekil
{

www.bsenyurt.com Page 1852


public Dortgen(Panel aktifForm,Color color,int penSize,int x,int y,int width,int height)
{
base.m_X=x;
base.m_Y=y;
base.m_Width=width;
base.m_Height=height;
base.m_Color=color;
base.m_PenSize=penSize;
base.m_AktifForm=aktifForm;
}

public Dortgen()
{
}

public void Ciz()


{
Graphics cizici=m_AktifForm.CreateGraphics();
Pen kalem=new Pen(m_Color,m_PenSize);
cizici.DrawRectangle(kalem,m_X,m_Y,m_Width,m_Height);
}
}
}

Dortgen snfnda u an iin sadece Ciz isimli bir metodumuz var. Constructor metodumuz ald
parametreleri direkt olarak TemelSekil snfna gndermekte. Ciz metodu, Dortgen snfna ait nesne
rneini parametre olarak gelen alan zerinde izen ilevlere sahiptir. Dikkat ederseniz, drtgenin
izilecei yer, izgi kalnl, X ve Y koordinatlar, izgi rengi, eklin genilii ve ykseklii gibi
bilgiler parametrik olarak kullanlmaktadr. Elips snfda Dortgen snfna ok benzer bir yapdadr.

Elips.cs

using System;
using System.Drawing;
using System.Windows.Forms;

namespace UsingGDIWithOperatorOverloading
{
public class Elips:TemelSekil
{
public Elips(Panel aktifForm,Color color,int penSize,int x,int y,int width,int height)
{
base.m_X=x;
base.m_Y=y;
base.m_Width=width;
base.m_Height=height;
base.m_Color=color;
base.m_PenSize=penSize;
base.m_AktifForm=aktifForm;

www.bsenyurt.com Page 1853


}

public Elips()
{

public void Ciz()


{
Graphics cizici=m_AktifForm.CreateGraphics();
Pen kalem=new Pen(m_Color,m_PenSize);
cizici.DrawEllipse(kalem,m_X,m_Y,m_Width,m_Height);
}

public static Elips operator+(Elips k1,Elips k2)


{
int R=(k1.m_Color.R+k2.m_Color.R)%255;
int G=(k1.m_Color.B+k2.m_Color.B)%255;
int B=(k1.m_Color.G+k2.m_Color.G)%255;
Color c=Color.FromArgb(R,G,B);
Elips elips=new Elips(k1.m_AktifForm,c,k1.m_PenSize+k2.m_PenSize,
k1.m_X+k2.m_X,k1.m_Y+k2.m_Y,k1.m_Width+k2.m_Width,k1.m_Height+k2.m_Height);
return elips;
}
}
}

Son olarak TemelSekil.cs snfmz ise aadaki gibidir.

using System;
using System.Drawing;
using System.Windows.Forms;

namespace UsingGDIWithOperatorOverloading
{
public class TemelSekil
{
protected int m_X;
protected int m_Y;
protected int m_Width;
protected int m_Height;
protected Color m_Color;
protected int m_PenSize;
protected Panel m_AktifForm;

public int X
{
get

www.bsenyurt.com Page 1854


{
return m_X;
}
}
public int Y
{
get
{
return m_Y;
}
}
public int Width
{
get
{
return m_Width;
}
}
public int Height
{
get
{
return m_Height;
}
}
public Color Renk
{
get
{
return m_Color;
}
}
public Panel AktifForm
{
get
{
return m_AktifForm;
}
}

public int KalemUcu


{
get
{
return m_PenSize;
}
}
public TemelSekil()
{

www.bsenyurt.com Page 1855


}
}
}

imdi gelelim asl sorunumuza; bir Dortgen nesne rneini oluturmak son derece basittir.

Dortgen dortgen=new
Dortgen(this.pnlKaraTahta,Renk,2,Baslangic_X,Baslangic_Y,Genislik,Yukseklik);

Hatta bu nesneyi ekrana izdirmek artk ok daha kolaydr.

dortgen.Ciz();

Gel gelelim aadaki kod satrlarnn iletilmesi sonrasnda nasl bir sonu alacam mehuldr?

Dortgen dortgen1=new Dortgen(this.pnlKaraTahta,Color.Black,2,5,20,100,50);


Dortgen dortgen2=new Dortgen(this.pnlKaraTahta,Color.Yellow,2,10,40,75,80);
Dortgen d=dortgen1+dortgen2;
d.Ciz();

Bu haliyle uygulamamz derlediimizde aadaki hata mesajn alrz;

Operator '+' cannot be applied to operands of type


'UsingGDIWithOperatorOverloading.Dortgen' and
'UsingGDIWithOperatorOverloading.Dortgen'

Sebep gayet aktr. Dortgen snf toplam ileminin nasl yaplacan bilemez. Bunu gelitirici
olarak bizim ona retmemiz gerekmektedir. O halde gelin toplama ilemini bu snfa nasl
reteceimize bakalm. Hereyden nce operatrlerin ar yklenmesi ile ilgili olaraktan bir takm
kurallar vardr. Aslnda bu kurallar bizde tahmin edebiliriz.

Kural 1; operatrler, operatr metodlar yardmyla ar yklenirler. Bu sebepten bir


metod gvdeleri, parametreleri ve dn deerleri vardr.

Kural 2; operatr metodlar static olmaldr. Bunun sebebi operatr ilevsellii iin nesne
rneine ihtiya duyulmamasdr.

Kural 3; operatr metodlar operator anahtar kelimesini iermelidir. rnein: operator +


gibi.

Kural 4; elbette heryerden eriilebilmeleri gerektiinden public olmaldr.

Kural 5; operatrler doalar gerei en az bir operand ile alr. Dolaysyla ar


ykleyeceimiz operator metodlarn en az bir parametre almas arttr.

www.bsenyurt.com Page 1856


Bu kurallar dikkate aldmzda Dortgen snf iin toplama operatrn aadaki haliyle ar
ykleyebiliriz.

public static Dortgen operator+(Dortgen k1,Dortgen k2)


{
int R=(k1.m_Color.R+k2.m_Color.R)%255;
int G=(k1.m_Color.B+k2.m_Color.B)%255;
int B=(k1.m_Color.G+k2.m_Color.G)%255;
Color c=Color.FromArgb(R,G,B);
Dortgen Dortgen=new
Dortgen(k1.m_AktifForm,c,k1.m_PenSize+k2.m_PenSize,k1.m_X+k2.m_X,k1.m_Y+k2.m_Y,
k1.m_Width+k2.m_Width,k1.m_Height+k2.m_Height);
return Dortgen;
}

Dikkat ederseniz + operatrmze ilikin metodumuz, Dortgen tipinde iki nesne rneini alp
bunlar zerinde bir takm ilemler yaparak sonu olarak rettii Dortgen tipinden nesneyi geriye
dndrmektedir. Artk biraz nce hata veren kodlarmz imdi alacaktr. Asl uygulamamz
yrttmzde aadakine benzer bir sonu elde ederiz.

Toplama operatrne yaptmz yklemeyi dier operatrlere de yapabiliriz. Ancak ar


yklenecek operatrler arasnda zel neme sahip olanlar ve hatta ar ykleme yaplamyacak
olanlar da vardr. Szgelimi ekrandaki bir elips eklini drtgen tipine evirmek istediimizi
varsayalm. Burada bilinsiz olarak aadaki gibi bir atama yapmak isteyebiliriz.

www.bsenyurt.com Page 1857


Dortgen d=elipsOrnegi;

Dier yandan bilinli olarakta aadaki tarzda bir dnm de yapmak isteyebiliriz.

Dortgen d=(Dortgen)elipsOrnegi;

Dikkat ederseniz ilk rnekte bilinsiz, ikinci rnekte ise bilinli tr dnm sz konusudur.
Burada mevzu bahis olan dntrme ilemlerini ilgili snfa retebilmek iin yine operatr ar
yklemeden faydalanabiliriz. rnein aadaki metod bilinli olarak Dortgen tipine ait cast
operatrn ar yklemektedir.

public static explicit operator Dortgen(Elips elips)


{
TemelSekil ts=elips;
Dortgen Dortgen=new Dortgen(ts.AktifForm,ts.Renk,ts.KalemUcu,ts.X,ts.Y,ts.Width,ts.Height);
return Dortgen;
}

Metodumuzda dikkat eken en nemli nokta explicit anahtar szcdr. Bu Dortgen anahtar
szcnn cast operatr olarak kullanld durumlarda blok ierisindeki kod satrlarnn
altrlacan ifade etmektedir. Ayn ekilde bilinsiz tr dnmne izin verecek operatr
yklemelerini de yapabiliriz. Tek yapmamz gereken implicit anahtar szcn kullanmaktr.

public static implicit operator Dortgen(Elips elips)


{
TemelSekil ts=elips;
Dortgen Dortgen=new Dortgen(ts.AktifForm,ts.Renk,ts.KalemUcu,ts.X,ts.Y,ts.Width,ts.Height);
return Dortgen;
}

Elbette dntrme operatrlerinin ar yklenmesi ile ilgili olaraktan dikkat etmemiz gereken
nemli bir ayrnt vardr.

Hem implicit hem de explicit operatrlerini ayn anda ar ykleyemeyiz.

Ancak, sadece implicit operatrnn yklemesi ile, alma zamannda hem explicit hem de implicit
dnmlere izin vermi oluruz. Yani aadaki iki kod satrda baarl bir ekilde alacaktr.

Dortgen dortgen=elipsNesnesi1;
Dortgen dortgen2=(Dortgen)elipsNesnesi2;

www.bsenyurt.com Page 1858


Grld gibi operatrlerin ar yklenmesi son derece kolay. Bunlar kullandmz windows
uygulamasna ait kod satrlar ise aadaki gibidir.

private Color Renk;


private int Baslangic_X;
private int Baslangic_Y;
private int Genislik;
private int Yukseklik;
private ArrayList alDortgenler;
private ArrayList alElipsler;

private void menuElipsToDortgen_Click(object sender, System.EventArgs e)


{
if(alElipsler.Count>0)
{
Elips el=(Elips)alElipsler[0];
Dortgen dortgen=el;
dortgen.Ciz();
}
}

private void BaslangicAyarlari()


{
lblSecilenRenk.Text=Renk.Name;
lblRenk.BackColor=Renk;
}

private void btnRenkSec_Click(object sender, System.EventArgs e)


{
colors.ShowDialog();
Renk=colors.Color;
BaslangicAyarlari();
}

private void Form1_Load(object sender, System.EventArgs e)


{
Renk=Color.Black;
alDortgenler=new ArrayList();
alElipsler=new ArrayList();
BaslangicAyarlari();
}

private void pnlKaraTahta_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)


{
Baslangic_X=e.X;
Baslangic_Y=e.Y;
}

private void Ciz()

www.bsenyurt.com Page 1859


{
if(rdbDortgen.Checked==true)
{
Dortgen dortgen=new
Dortgen(this.pnlKaraTahta,Renk,2,Baslangic_X,Baslangic_Y,Genislik,Yukseklik);
dortgen.Ciz();
alDortgenler.Add(dortgen);
}
if(rdbElips.Checked==true)
{
Elips elips=new Elips(this.pnlKaraTahta,Renk,2,Baslangic_X,Baslangic_Y,Genislik,Yukseklik);
elips.Ciz();
alElipsler.Add(elips);
}
}

private void menuTopla_Click(object sender, System.EventArgs e)


{
if(alDortgenler.Count>=2)
{
Dortgen d1=(Dortgen)alDortgenler[0];
Dortgen d2=(Dortgen)alDortgenler[1];
Dortgen d3=d1+d2;
d3.Ciz();
}
}

private void menuTemizle_Click(object sender, System.EventArgs e)


{
this.Refresh();
Baslangic_X=0;
Baslangic_Y=0;
alDortgenler.Clear();
alElipsler.Clear();
}

private void pnlKaraTahta_DoubleClick(object sender, System.EventArgs e)


{
Genislik=Convert.ToInt32(txtGenislik.Text);
Yukseklik=Convert.ToInt32(txtYukseklik.Text);
Ciz();
}

private void menuKapat_Click(object sender, System.EventArgs e)


{
Close();
}

Dortgen snf ierisinde aritmetik operatrlerin ve dntrme operatrlerinin nasl ykleneceini


ksaca inceledik. Dilersek koullu ifadelerde kullanlan operatrleride ar ykleyebiliriz. rnein
== operatrn yeniden ykleyerek drtgen snfmz iin zel olarak kullanabiliriz.

www.bsenyurt.com Page 1860


== gibi karlatrma operatrlerinin ar yklenmesinde tek art, zt
operatrlerinde yklenme zorunluluunun olmasdr. rnein, == iin !=, < iin
> operatrnn ar yklenmesi gibi...

rneimiz ok basit olduundan genellikle koleksiyonlarda tuttuumuz ilk iki nesne zerinde ilem
yapyoruz. Yine bu tarz bir ilem yaptmz dnelim ve iki Dortgen nesnesinin boyutlarnn ayn
olmas halinde eit olduklarn gsterelim. Bunun iin Dortgen snfnda == ve != operatrlerini ayn
anda ar yklemeliyiz. Aadaki kodlarda Dortgen snfna bu ilevsellii nasl kazandrdmz
grebilirsiniz.

Dortgen.cs snfna eklenen operator metodlarmz;

public static bool operator==(Dortgen d1,Dortgen d2)


{
if((d1.Width==d2.Width)&&(d1.Height==d2.Height))
return true;
else
return false;
}

public static bool operator !=(Dortgen d1,Dortgen d2)


{
return !(d1==d2);
}

Operatrlerin uygulama ierisinde kullanm;

private void menuEsitmi_Click(object sender, System.EventArgs e)


{
Dortgen d1=(Dortgen)alDortgenler[0];
Dortgen d2=(Dortgen)alDortgenler[1];
if(d1==d2)
{
MessageBox.Show("Dortgenlerin boyutlar eit...");
}
if(d1!=d2)
{
MessageBox.Show("Drtgenlerin boyutlar eit deil...");
}
}

Eitlik kontrolnn sonucu;

www.bsenyurt.com Page 1861


Eit deildir kontrolnn sonucu;

Elbetteki ar ykleme yapamayacamz operatrlerde vardr.

www.bsenyurt.com Page 1862


=, . , ?:, ->, new, is, as, sizeof ,&&, ||, () operatrlerini ar yklememiz
yasaklanmtr.

Grld gibi nesnelerimiz iin, C# dilinde var olan operatrleri ar yklemek son derece
kolaydr. Dikkat etmemiz gereken bir takm kurallar vardr ki bunlar zamanla renilebilir.
Operatrlerin zellikle ar yklenmesine ihtiya duyulaca durumlar gz nne aldmzda,
grafik ve matematik uygulamalarnn st sralarda yer aldn grrz. rnein sevgili Sefer
ALGAN, Her Ynyle C# Kitabnda operatrlerin ar yklenmesi ile ilgili olaraktan Kompleks
saylar incelemitir. zetle operatrleri ar yklemek zellikle kendi oluturduumuz nesnelerin
esneklii asndan nemlidir. Bu makalemizde ilediimiz rnekte bahsedilen ar ykleme
ilemleri sadece Dortgen snf iin yaplmtr. Size tavsiyem Elips snf iinde benzer yklemeleri
yapmaya almanzdr.

Burak Selim ENYURT


selim@bsenyurt.com

Kendi stina Nesnelerimizi Kullanmak


(ApplicationException) ( 23.05.2005 ) - C#
Deerli Okurlarm Merhabalar,

stisna yakalama mekanizmas (Exception Handling) dotNet mimarisinde olduka nemli bir yere
sahiptir. Bu mekanizma sayesinde uygulamalarmzn kilitlenmesi ve istem d bir ekilde
sonlandrlmaya zorlanmasnn nne gemi oluruz. Framework ierisinde nceden tanmlanm
pek ok istisna snf mevcuttur. Bu snflar yardmyla, alma zamannda oluabilecek istisnai
durumlar kolayca tespit edilebilmektedir. Bylece uygulamalarn, CLR tarafndan denetlendii
srada ortama frlatlan istisnalar nedeniyle yn deitirebilmesi ve yaamn srdrebilmesi
salanm olmaktadr. Ancak baz durumlarda kendi istisna snflarmz yazma ihtiyac duyabiliriz.
Bunun pek ok nedeni olabilir. lk ve en temel nedeni, sistemde var olan istisna snflar dndaki
bir istisnay alma zamannda ele almak isteyiimizdir. te bu makalemizde bu ilevsellii nasl
gerekletirebileceimizi basit bir rnek zerinde incelemeye alacaz.

.Net Framework' te var olan istisna snflarnn tamam System.Exception snfndan dolayl bir
ekilde treyerek oluturulmulardr. Kendi istisna nesnelerimizi oluturabilmek ve yakalayabilmek
iin kullanacamz snflar System isim alannda yer alan ApplicationException snfndan tretiriz.
(Aslnda ApplicationException snfda Exception snfndan tremitir.) Bu sayede throw anahtar
szc vastasyla oluturduumuz istisna nesnelerinin ortama frlatlabilmesini salam oluruz.
Ortama frlatlan istisna nesnelerini uygun try...catch bloklarnda yakalayarak hem uygulamann
kmesini engellemi hem de kullanclarn anlaml mesajlar ile uyarlmasn salam oluruz.
ApplicatinException, kullanc tanml istisna snflarnn tipik Exception snflarnn sahip olduu
yelerini kullanabilmesini salar. Bu tabiki kaltmn bir sonucudur. Dier yandan
ApplicationException snf, kendisinden tretilen snfn bir istisna nesnesi olduunu ve throw
anahtar szc ile frlatlabileceini de belirtir.

Konuyu daha iyi anlayabilmek amacyla bir rnek zerinden gideceiz. Senaryomuzda aada
kodlar bulunan Kitap isimli snf kullanan bir uygulama yer alacak. Amacmz bu snf kullanrken
istisnaya neden olabilecek noktalar tespit etmek ve bu istisnalar ynetecek snf yazarak
uygulama ierisinden yn verebilmektir.

www.bsenyurt.com Page 1863


using System;

namespace KitapDukkani
{
public class Kitap
{
private string m_Kitap_Yazar;
private string m_Kitap_Baslik;
private double m_Kitap_Fiyat;
private DateTime m_Kitap_Basim;
private string m_Kitap_Kategori;

public string Yazar


{
get
{
return m_Kitap_Yazar;
}
set
{
m_Kitap_Yazar=value;
}
}
public string Baslik
{
get
{
return m_Kitap_Baslik;
}
set
{
m_Kitap_Baslik=value;
}
}
public double Fiyat
{
get
{
return m_Kitap_Fiyat;
}
set
{
m_Kitap_Fiyat=value;
}
}
public DateTime Basim
{
get
{

www.bsenyurt.com Page 1864


return m_Kitap_Basim;
}
set
{
m_Kitap_Basim=value;
}
}
public string Kategori
{
get
{
return m_Kitap_Kategori;
}
set
{
m_Kitap_Kategori=value;
}
}

public Kitap(string yazar,string baslik,double fiyat,DateTime basim,string kategori)


{
Yazar=yazar;
Baslik=baslik;
Fiyat=fiyat;
Basim=basim;
Kategori=kategori;
}

public Kitap()
{
}
}
}

Kitap snfmz tipik olarak bir kitabn temel zelliklerini sunan bir yapya sahiptir. Bu snf
kullanacak olan bir yazlm gelitiricinin dikkat edecei bir takm noktalar olacaktr. rnein, kitabn
fiyatnn negatif deer almamas , harf yada karakterlerden olumamas, basm tarihinin mutlaka
tarihsel formatta olmas gereklilii vb. Bunlar uygulamann almas esnasnda hataya neden
olabilecek durumlardr. Var olan istisna snflar yardmyla bu tip hatalar alma zamannda
bertaraf ederek uygulamann yaamna devam etmesini salayabiliriz. Bunun yannda bu snf
kullanacak olan yazlm gelitirici kullancnn hataya neden olacak girilerini engelleyecek tedbirleri
elbette gz nne alacaktr ve uygulayacaktr. rnein aadaki windows uygulamasnda kullanc
girilerinde oluabilecek veri girii hatalar ele alnmaya allmtr.

www.bsenyurt.com Page 1865


lk olarak alanlara girilecek olan karakter says snrlandrlarak ok uzun verilerin girilmeye
allmas engellenebilir. Tarih girilerinde oluabilecek hatalarn nne gemek bir windows
uygulamas iin son derece kolaydr. DateTimePicker bileeni bu kontrol bizim iin fazlasyla
salamaktadr. Kategori seiminde ise ComboBox bileeni kullanlabilir. Kategori veriside aslnda
belirli bir listeden alnmak zorundadr. Bu liste bir veritabanndan alnabilecei gibi, bir XML
dosyasndan da alnabililir vb...Bizim iin hataya neden olabilecek bir dier durumda Fiyat alanna
girilecek saysal deerin karakter olarak girilmeye allmasdr. Bunu engelleyebilmek iin sadece
saysal karakter giriine izin verecek bir metod kullanamz gerekir. Bunu gerekletirebileceimiz
en gzel yer ilgili TextBox kontrolnn KeyPress olay metodudur.

private void txtFiyat_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)


{
if (((int)e.KeyChar < 48 || (int)e.KeyChar > 57) && ((int)e.KeyChar!=8))
{
e.Handled=true;
}
}

Ama halen daha yazlm gelitiricinin bilmedii ve bu gibi durumlarda kullancnn uyarlmasn
istediimiz istisnai durumlar olabilir. rnein fiyat alanna her ne kadar negatif deer girilemiyecek
olsada, fiyat alanndaki gncel deer belli bir oranda azaltlmaya alldnda negatif deerin
oluabilecei grlebilir. rnein fiyat azaltm iin aadaki metodu uyguladmz varsayalm.

private void btnIndirim_Click(object sender, System.EventArgs e)


{
if(kitap!=null)
{
kitap.Fiyat-=10;
txtFiyat.Text=kitap.Fiyat.ToString();
}
}

Bu durumda ekran grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 1866


Grld gibi normal artlar altnda TextBox ierisine - karakterini basamasakta Kitap nesnemizi
oluturduktan sonra Fiyat zelliinin deerinde yapacamz 10 birimlik azaltmalar sonucu - deer
grnebilmektedir. Bu bir bug olarak deerlendirilebilse de nne gememiz gereken bir durumdur.
Dahas Kitap snfn kullanan yazlm gelitirici bu tip bir kontrol hi yapmayadabilir. te byle bir
durumda en azndan girilen deerin negatif olmas durumunda ortama bir istisnann frlatlmasn
salayabiliriz. Dier yandan girilen Fiyat deerinin belli bir deerin stnde olmamasn da
isteyebiliriz. te bu iki basit nedeni ele alarak kendi istisna snfmz yazabiliriz. lk bata
uygulamamzn Kitap nesnesi oluturan kodunu standart try...catch yapss iinde kullanamay
deneyelim.

private void btnOlustur_Click(object sender, System.EventArgs e)


{
try
{
kitap=new Kitap();
kitap.Baslik=txtBaslik.Text;
kitap.Yazar=txtYazar.Text;
kitap.Basim=dtpBasim.Value;
kitap.Fiyat=Convert.ToDouble(txtFiyat.Text);
kitap.Kategori=cmbKategori.SelectedText;
}
catch(System.Exception err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}

Bu haliyle uygulamay altrdmzda ve fiyat alan iin eksi deere getiimizde ortama herhangi
bir istisna nesnesinin frlatlmadn grrz. nk oluacak istisnai durum henz tarafmzdan
yaratlmamtr. Dolaysyla ApplicationException snfndan treteceimiz bir exception snf
yazmamz gerekmektedir. te bu amacmz salayan FiyatException isimli istisna snfmzn
kodlar;

using System;

namespace KitapDukkani

www.bsenyurt.com Page 1867


{
/// <summary>
/// Bir kitabn fiyat ile ilgili istisna snfdr.
/// </summary>
public class FiyatException:ApplicationException
{
/// <summary>
/// stisnaya neden olan fiyat deerini tutan zel field.
/// </summary>
private double m_Fiyat;
/// <summary>
/// stisna ile ilgili ksa aklama
/// </summary>
private string m_Mesaj;

/// <summary>
/// stisna nesnesi oluturulurken hataya neden olan fiyat deeri alnp m_Fiyat zel alanna
eitlenir.
/// </summary>
/// <param name="fiyat">stisnaya neden olan fiyat alannn deeridir.</param>
public FiyatException(double fiyat,string mesaj)
{
m_Fiyat=fiyat;
m_Mesaj=mesaj;
}

/// <summary>
/// ApplicationException snfndan gelen Message zellii override edilmitir. Geriye zel bir
hata mesaj dndrmektedir.
/// </summary>
public override string Message
{
get
{
return "Kitaba ait fiyat deeri "+m_Fiyat+"belirtilen kriterlere uygun deildir."+"
'"+m_Mesaj+"'";
}
}
}
}

Grld gibi kendi yazdmz istisna snflarnn normal bir snf yazmaktan hi bir fark yoktur.
Kendi yelerimizi ekleyebilir ve Exception snfndan devralnan Message, TargetSite,
InnerException gibi virtual zellikleri override edebiliriz. Snf tasarmn yaparken bu snfa ait
nesne rneklerinin ne amala kullanlacan belirlemeliyiz. FiyatException snfna ait bir nesne
rnei, herhangi bir Kitap nesnesinin fiyatnn baz kriterlere uymamas durumunda frlatlacaktr.

www.bsenyurt.com Page 1868


.Net iinde nceden tanmlanm olan istisna snflar Exception kelimesi ile
biterler. Kendi istisna snflarmzn isimlerinin de ayn ekilde yazlmas kod
standardizasyonu asndan nemlidir. rnein FiyatException gibi...

Dolaysyla kritere uymayacak Fiyat deerini tamas nemlidir. Ayrca kriterin eitliliine gre
kullancya verilmesi istenen mesaj ieriide bir field olarak saklanmaldr. Bu iki field' n alaca
deerleri ise constructor metodumuz ierisinde salayabiliriz. Oluturduumuz istisna nesnesinin
tipik bir Exception nesnesi gibi davranabilmesini salamak amacyla rnek olarak Message zellii
override edilmitir. FiyatException snf artk uygulama ierisinde yakalanabilecek tipik bir istisna
halini almtr. Ancak henz uygulanmamtr. Hereyden nce istisnann frlatlmasn istediimiz
yerlerde bunlar kodlamamz gerekecektir. Kitap nesnemizi gz nne aldmzda Fiyat zelliinin
deerinin verildii set blou bu i iin biilmi kaftandr. Buradaki kodlar aadaki gibi
dzenleyebiliriz.

public double Fiyat


{
get
{
return m_Kitap_Fiyat;
}
set
{
if(value>150)
throw new FiyatException(value,"Fiyat 150 YTL' den yksek olamaz");
if(value<0)
throw new FiyatException(value,"Fiyat negatif deer olamaz");
m_Kitap_Fiyat=value;
}
}

Fiyat zelliine deer atanrken eer girilen deer 0' dan kk ise buna uygun mesaja sahip bir
istisna nesnesi, Fiyat 150 YTL' den byk ise buna uygun mesaja sahip bir istisna nesnesi ortama
frlatlmaktadr. Bylece catch blounda FiyatException nesne rneklerini yakalayabiliriz. Kitap
snfnn yapc metodunda parametre zerinden, snf iindeki alanlara deer atamas
yaplmaktadr. Ancak burada da parametre deerlerini direkt olarak zelliklere atadmzda set
bloklar devreye girmektedir. Bu, Fiyat zelliinin deeri iin gerekli istisna kontroln yapc metod
ierisinde de gerekletirebilmemizi salar. Ksacas bir tala iki ku vurmu oluruz. Artk windows
uygulamamzdaki kodlar aadaki gibi dzenleyebiliriz.

private void btnOlustur_Click(object sender, System.EventArgs e)


{
try
{
kitap=new Kitap();
kitap.Baslik=txtBaslik.Text;
kitap.Yazar=txtYazar.Text;
kitap.Basim=dtpBasim.Value;
kitap.Fiyat=Convert.ToDouble(txtFiyat.Text);
kitap.Kategori=cmbKategori.SelectedText;

www.bsenyurt.com Page 1869


}
catch(FiyatException err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
catch(System.Exception err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}

rnein Kitap snfna ait nesne rneini olutururken Fiyat alannn deerini 175 olarak girelim.

Grld gibi oluturduumuz istisna snfna ait nesne rnei, Kitap nesnesi oluturulmaya
alldnda ortama frlatlmtr. Bir de Fiyat deerini 10' ar birim azalttmzda eksi deere
getiimiz bir metodumuz vard. Kitap nesnesinin istisnasz oluturup fiyatn negatif deere
ektiimizde uygulamann FiyatException istisnas nedeni ile kesilerek sonlandrldn grrz.

www.bsenyurt.com Page 1870


Uygulamann istisnay yakalayamamasnn sebebi fiyat azaltm yapan metodumuzun ilgili istisnay
yakalayacak bir try...catch yapsn kullanmaydr. ster kendi istisna nesnelerimiz olsun ister
sistemde var olan istisna nesneleri olsun, bunlarn yakalanarak uygulamann sonlandrlmadan
yaamaya devam edebilmesi iin uygun catch bloklar ile yakalanmalar arttr. Dolaysyla fiyat
arttrma ve azaltma metodlarmz aadaki gibi yenilememiz gerekmektedir.

private void btnIndirim_Click(object sender, System.EventArgs e)


{
try
{
if(kitap!=null)
{
kitap.Fiyat-=10;
txtFiyat.Text=kitap.Fiyat.ToString();
}
}
catch(FiyatException err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}

private void btnArttir_Click(object sender, System.EventArgs e)


{
try
{
if(kitap!=null)
{
kitap.Fiyat+=10;
txtFiyat.Text=kitap.Fiyat.ToString();

www.bsenyurt.com Page 1871


}
}
catch(FiyatException err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}
}

Artk Fiyat alan iin eksi deer olumamaktadr. Burada dikkat etmemiz gereken bir dier noktada
catch bloklarnda kendi tanmladmz istisna snflarn yakalayabilmek iin ilede o istisna snfna
ait nesne rneini belirtme zorunluluumuzun olmaydr. Yani

catch(FiyatException err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}

yerine,

catch(Exception err)
{
MessageBox.Show(err.Message,"Hata",MessageBoxButtons.OK,MessageBoxIcon.Error);
}

www.bsenyurt.com Page 1872


formunuda kullanabiliriz. Yine ayn istisna mesajlarn yakalayacazdr.

Grld gibi, uygulamalarmzda dndmz istisnai durumlar yakalayabilmemizi salayacak


snflar tasarlamak son derece kolaydr. nemli olan nokta, istisna nesnemizin gerekten gerekli
olup olmaddr. Eer byle bir gereklilik var ise ve kendi istisna snflarmz oluturduysak bunlara
ait nesne rneklerini uygun yerlerde ortama frlatmalyz. Son olarak frlattmz istisna
nesnelerimizi catch bloklar ile yakalayarak uygulamaya yn vermeliyiz. Bylece geldik bir
makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler
dilerim.

rnek uygulama iin tklayn.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve Data Provider-Independent


Mimari ( 24.04.2005 ) - Ado.Net 2
Deerli Okurlarm, Merhabalar.

Veritaban uygulamalarnda bamz artan noktalardan bir tanesi farkl tipte veritaban sistemleri
kullanan uygulamalarn gelitirilmesi srasnda ortaya kar. ou zaman gelitirdiimiz bir rn Sql
sunuclar zerinde yksek performans gsterecek ekilde almak zorunda iken, ayn rnn
Oracle zerinde altrlmas da istenebilir. Bu durumda ortak bir zm olarak OleDb isim alan
altndaki snflar kullanmak olduka mantkldr. nk OleDb zerinden her iki veri sunucusu iin
gerekli olan veri salayclarn kullanabiliriz. Dier yandan byle bir yol izlendiinde direkt olarak
OracleClient veya SqlClient isim alann kullanarak kazanlacak performans avantaj ortadan
kaybolacaktr. Peki .Net Framework iin gelitirilen baka bir veri salayc (data-provider) iin iine
girerse ne olacaktr. Bu durumda uygulama kodunda ilgili veri salaycsna destek verecek ekilde
dzenlemeler yapmamz gerekecektir. yleki, SqlClient isim alan iin gerekli Connection nesnesi
ile OracleClient isim alan iin gerekli Connection nesnelerinin isimleri farkldr. Ayn durum
Command nesnelerinden tutun da DataReader nesnelerine kadar geerlidir. te bu durum
kodlarmz her veri salayc iin ayr ekilde dzenlememizi gerektirebilir.

Dier yandan System.Data.Common isim alanndaki snflar kullanarak farkl veri salayclarna
destek verebilecek katmanlar gelitirebiliriz. Bu Ado.Net 1.1' de ok esnek olmayan bir mimari
zerinde gerekletirilmektedir. Oysa ki Ado.Net 2.0, System.Data.Common isim alanna bir takm
yeni zellikler eklemitir. Bu zellikler arasnda yeni eklenen iki snf byk neme sahiptir.
DbProviderFactories ve DbProviderFactory snflar. Ado.Net 2.0' da bu snflarn
System.Data.Common isim alanna eklenmelerinin en byk nedeni, ilgili sistemlerde ykl olan
veri salayclarnn renilebilmesi ve seilen herhangi bir veri salaycsna zel Command,
Connection, DataAdapter gibi veri zerinde i yapmamz salayacak snflarn tekil isimler altnda
rneklendirilebilmesidir. Yeni eklenen zelliklerin salad bu imkanlar sayesinde, gelitirilmi olan
bir rnn farkl veri salayclar iin destek verebilecek ekilde ina edilmesi daha da
kolaylatrlmtr. in gzel yan, bu mimarinin performans olarak asl veri salayclarna oranla
olduka iyi sonular veriyor olmasdr. te bu makalemizde System.Data.Common isim alanna
eklenen bu yeni snflar ile neler gerekletirebileceimizi incelemeye alacaz. Yeni eklenen
snflarn nemini daha iyi anlayabilmek iin aadaki ekli gz nne alabiliriz.

www.bsenyurt.com Page 1873


Aslnda uygulamamza katacamz veri salaycdan bamsz mimari iin, yukardaki yolu
izlememiz yeterli olacaktr. lk olarak sistemde ykl olan veri salayclarn elde edebiliriz. Ya da
bunun seimini kullancya brakabiliriz. Hangisinin kullanlacana biz, kullanc veya sistemin
kendisi karar verebilir. Son olarak seilen veri salayc zerinden gerekletireceimiz veritaban
ilemleri iin (rnein kaynaa balant amak, komut yrtmek gibi) gerekli olan reticiyi ( ki bu
DbProviderFactory snfdr )hazrlarz. Daha sonra bu yeni snf yardmyla gerekli olan nesneleri
retip kullanrz. Dilerseniz System.Data.Common isim alanna eklenen bu yeni iki snf incelemekle
ie balayalm.

ncelikle DbProviderFactories snfn ele alalm. Bu snf sistemde ykl olan veri salayclarn
elde etmemizi salayan GetFactoryClasses isimli static bir metoda sahiptir. Bu snfn dier bir
static metodu ise GetFactory' dir. GetFactory metodu geriye DbProviderFactory tipinden bir
nesne rneini dndrr. DbProviderFactory tipinden nesne rnekleri
yoluyla, DbConnection, DbCommand gibi nesneleri elde edebiliriz. Dolaysyla
DbProviderFactories snf yardmyla bir sistemdeki veri salayclarn elde edebilir ve seilen bir
veri salayacs iin gerekli nesneleri retmemizi salayacak DbProviderFactory snfn
rnekleyebiliriz. lk olarak aadaki kod parasn ele alalm.

using System.Data;
using System.Data.Common;

#endregion

namespace UsingDbProviderFactories

www.bsenyurt.com Page 1874


{
class Program
{
static void Main(string[] args)
{
DataTable dtProviders = new DataTable();
dtProviders = DbProviderFactories.GetFactoryClasses();
foreach (DataRow drProvider in dtProviders.Rows)
{
for (int i = 0; i < dtProviders.Columns.Count; i++)
{
Console.WriteLine(drProvider[i].ToString());
}
Console.WriteLine("----------");
}
Console.ReadLine();
}
}
}

Bu kod ile, sistemimizde ykl olan veri salayclarn elde etmi olduk. Dikkat ederseniz
GetFactoryClasses metodundan dnen deer DataTable tipinden bir nesne rneidir. Ayn rnei

www.bsenyurt.com Page 1875


bir windows uygulamasnda ele aldmzda bu geri dn tipinden yararlanarak sonular veri bal
kontroller zerinde (datagridview gibi) gsterebiliriz.

DataTable dtProviders = new DataTable();


dtProviders = DbProviderFactories.GetFactoryClasses();
grdProviders.DataSource=dtProviders;

Peki sistemdeki veri salayclarnn elde edilmesinin bize salayaca avantajlar neler olabilir?
Hereyden nce rnmzn yklendii sistemlerdeki veri salayclarn grmek ve bunlardan
seii olan ile uygulamay altrmak steyebiliriz. Byle bir durumda GetFactoryClasses metodu
iimizi olduka kolaylatracaktr. Dier yandan, rnmz sisteme yklerken kurulan herhangi bir
konfigurasyon ayar ile de bir veri salaycy seebiliriz. ounlukla bunu xml ierikli konfigrasyon
dosyalarnda belirtiriz. (rnein app.config dosyas iinde). Uygulamann hangi veri salaycsn
baz alarak devam edeceine bu dosyadaki ilgili konfigrasyon ayarndan karar verebiliriz. Elbette
byle bir durumda uygulamann yklendii sistemde seilen veri salaycsnn olup olmadna
bakmak iin yine yukardaki teknik ile elde edilen DataTable nesnesinden faydalanabiliriz. Bu
sayede sistemde ykl olmayan bir veri salaycs ile devam edilmesini de henz kurulum
aamasnda engellemi oluruz. Bunun sonrasnda kullancya kullanabilecei veri salayclar
alternatif olarak sunabiliriz ve uygun olan ile devam etmesini salayabiliriz. Gelelim,
DbProviderFactory snfna. Bu snf, veritabanna balant ama, sql komutu altrmak gibi
ilemleri yrtmemizi salayacak DbConnection, DbCommand gibi snflarn retilmesini salar. Bu
snfn prototipi aadaki gibidir.

public abstract class DbProviderFactory

Grld gibi DbProviderFactory abstract (soyut) bir snftr. Dolaysyla bu snfa ait bir nesne
rneini retemeyiz. Ancak DbProviderFactories snfmza ait olanGetFactory static metodu bizim
kullanabileceimiz bir DbProviderFactory nesnesini salayacaktr. GetFactory metodunun ar
yklenmi(overload) iki versiyonu vardr.

www.bsenyurt.com Page 1876


public static DbProviderFactory GetFactory(DataRow data-provider iin dataRow);
public static DbProviderFactory GetFactory(string data-provider iin invariant name);

Bu metodlardan ilki DataRow tipinden bir nesne rneini alr. Bu DataRow nesnesinin temsil ettii
satr aslnda DbProviderFactories snfnn GetFactoryClasses metodundan dnen DataTable
zerindeki satrlardan herhangi biridir. Dier yandan ikinci versiyonda string tipinden parametrenin
alaca deer, ilgili veri salaycsnn sistemdeki sabit addr (invariant-name).

DbProviderFactory fakto = DbProviderFactories.GetFactory("System.Data.SqlClient");

Elde ettiimiz DbProviderFactory nesnesi vastasyla artk veritaban uygulamamz iin gerekli
nesneleri rnekleyebiliriz. rnein aadaki kod paras ile bir DbConnection nesnesi elde
edilmektedir. DbConnection nesnesi tahmin edeceiniz gibi ilgili veri kaynana doru balant hatt
tesis etmemizi salar.

DbConnection, DbCommand, DbDataAdapter vb. abstract snflardr. Yani aslnda


bu snflara ait nesne rneklerini new operatr yardmyla oluturamayz. Bu
snflardan faydalanabilmek iin DbProviderFactories snfnn ilgili Create
metodlarn kullanrz.

Kod paramz;

DbProviderFactory fakto = DbProviderFactories.GetFactory("System.Data.SqlClient");


DbConnection con = fakto.CreateConnection();
con.ConnectionString="data source=localhost;database=AdventureWorks;integrated
security=SSPI";
con.Open();
con.Close();
Console.Read();
...

Bu kod parasnda SqlClient veri salaycsn kullanacak ekilde bir DbConnection nesnesi elde
edilmektedir. DbConnection nesnesini elde edebilmek iin DbProviderFactory snfna ait
CreateConnection metodu kullanlmaktadr. Ne yazk ki veri salayc bamsz mimarinin de iinden
u an iin kamayaca sorunlar var. Bunlardan birisi ConnectionString' in bir veri salaycdan
tekine farkllk gstermesidir. Yani Sql sunucularna SqlConnection nesnesi ile balant kurarken
kullandmz Connection String ifadesi, OleDbConnection iin olandan farkldr. Bu sorunu zmek
iin DbConnectionStringBuilder snf kullanlmaktadr. Bu snf bir connection string iine yazlan
zellikleri anahtar-deer (key-value) iftleri eklinde temsil eder. Bylece uygun Connection String
elde edilebilir. Ancak tabiki ncesinde seilen veri salaycsnn her durumda kontrol edilmesi
gerekecektir. Aadaki kod paras hem SqlClient hem de OleDb iin gerekli DbConnection
nesnesinin doru bir ekilde elde edilebilmesini salamaktadr. (Burada veri salaycsnn seimi
iin app.config dosyasn kullandmza dikkat edin.)

www.bsenyurt.com Page 1877


#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.Common;
using System.Configuration;

#endregion

namespace UsingDbProviderFactory
{
class Program
{
static void Main(string[] args)
{
DbProviderFactory fakto;
DbConnection con;
DbConnectionStringBuilder conStr = new DbConnectionStringBuilder();
string secilenProvider = ConfigurationSettings.AppSettings["ProviderTipi"];
fakto = DbProviderFactories.GetFactory(secilenProvider);
con = fakto.CreateConnection();
if (secilenProvider == "System.Data.SqlClient")
{
conStr.Add("data source", "localhost");
conStr.Add("database", "AdventureWorks");
conStr.Add("integrated security", "SSPI");
}
else if (secilenProvider == "System.Data.OleDb")
{
conStr.Add("Provider", "SqlOleDb");
conStr.Add("data source", "localhost");
conStr.Add("database", "AdventureWorks");
conStr.Add("integrated security", "SSPI");
}
else
{
Console.WriteLine("Doru provider seilmedi...");
}

www.bsenyurt.com Page 1878


con.ConnectionString = conStr.ConnectionString;
try
{
con.Open();
Console.WriteLine("Balant ald...");
Console.ReadLine();
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
finally
{
con.Close();
}
}
}
}

Uygulamamzda balang olarak veri salaycsn Sql sunucusuna direkt eriim salayan SqlClient
olarak belirledik. If koullarnda app.config dosyasna eklediimiz ProviderTipi anahtarnn deerine
bakarak uygun Connection String ifadesinin oluturulmasn salyoruz. Eer OleDb kaynan
kullanarak eriim salamak istersek tek yapmamz gereken app.config dosyasnda ProviderTipi
anahtarnn deerini System.Data.OleDb olarak deitirmek olacaktr.

Seilen veri salaycsnn (Data-Provider) ismi sistem de ykl olan sabit


ismidir. (Invariant Name)

Buradaki anahtarlarn deerlerinin sistemde tanml olan invariant-name deerleri olduunu


hatrlatalm. Aslnda sistemde ykl olan veri salayclarnn zellikleri elde edilirken
machine.config dosyasndaki ayarlara baklr. Eer
D:\WINDOWS\Microsoft.NET\Framework\v2.0.40607\CONFIG (Windows 2003 iin)
adresinden machine.config dosyasna baklrsa sistemde ykl olan veri salayclarnn
listesinin DbProviderFactories taksnda yer aldn grebiliriz. te veri salayclarnn sabit
isimleri buradan alnmaktadr.

www.bsenyurt.com Page 1879


DbConnection nesnesi gibi DbCommand nesneside veri salaycdan bamsz komut setlerinin
yrtlmesine imkan salamaktadr. Bir DbCommand nesnesinin oluturulu biimi DbConnection
nesnesinde olduu gibidir. Yani bu nesneyi elde edebilmek iin DbProviderFactory snfnn ilgili
Create metodunu aadaki gibi kullanrz.

DbProviderFactory fakto;
DbConnection con;
DbCommand cmd;
DbConnectionStringBuilder conStr = new DbConnectionStringBuilder();
string secilenProvider = ConfigurationSettings.AppSettings["ProviderTipi"];
fakto = DbProviderFactories.GetFactory(secilenProvider);
con = fakto.CreateConnection();
cmd = fakto.CreateCommand();
if (secilenProvider == "System.Data.SqlClient")
{
conStr.Add("data source", "localhost");
conStr.Add("database", "AdventureWorks");
conStr.Add("integrated security", "SSPI");
}

www.bsenyurt.com Page 1880


else if (secilenProvider == "System.Data.OleDb")
{
conStr.Add("Provider", "SqlOleDb");
conStr.Add("data source", "localhost");
conStr.Add("database", "AdventureWorks");
conStr.Add("integrated security", "SSPI");
}
else
{
Console.WriteLine("Doru provider seilmedi...");
}
con.ConnectionString = conStr.ConnectionString;
try
{
con.Open();
cmd.Connection = con;
cmd.CommandText = "INSERT INTO Personel (AD,SOYAD,MAIL) VALUES ('Burak
Selim','enyurt','selim@bsenyurt.com')";
int eklenen=cmd.ExecuteNonQuery();
Console.WriteLine("Balant ald...");
Console.WriteLine(eklenen + " SATIR EKLENDI");
Console.ReadLine();
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
finally
{
con.Close();
}

Grld gibi tek yapmamz gereken DbProviderFactory snfnn CreateCommand metodunu


kullanarak bir DbCommand nesnesini elde etmektir. Daha sonra bu komut nesnesinin kullanaca
sorgu ve balant her zamanki yntemlerimiz ile belirlenmitir. Elbetteki, DbConnection nesnesi
oluturulurken yaanan problemin benzeri burada da sz konusudur. Bu kez Command nesnelerinin
parametre isimlendirmeleri bir veri salaycdan tekine farkllk gstermektedir. rnein
SqlCommand nesnesinde kullanlan parametreler @ ile balarken, OleDbCommand nesnelerinde
sorgu cmleciindeki parametreler ? ile tanmlanmak zorundadr. Bu sorunu yine yukardaki if
yaps ile halledebiliriz. Sz konusu olan parametreleri DbParameter snf ile tanmlayabiliriz.
Dolaysyla yukardaki rnei aadaki gibi yazarsak parametre farklln bu rnekte geerli olan
veri salayclar iin zm oluruz.

static void Main(string[] args)


{
DbProviderFactory fakto;
DbConnection con;
DbCommand cmd;
DbParameter prmAd;

www.bsenyurt.com Page 1881


DbParameter prmSoyad;
DbParameter prmMail;
DbConnectionStringBuilder conStr = new DbConnectionStringBuilder();
string secilenProvider = ConfigurationSettings.AppSettings["ProviderTipi"];
string cmdQuery;
fakto = DbProviderFactories.GetFactory(secilenProvider);
con = fakto.CreateConnection();
cmd = fakto.CreateCommand();
prmAd = fakto.CreateParameter();
prmSoyad = fakto.CreateParameter();
prmMail = fakto.CreateParameter();
if (secilenProvider == "System.Data.SqlClient")
{
conStr.Add("data source", "localhost");
conStr.Add("database", "AdventureWorks");
conStr.Add("integrated security", "SSPI");
cmdQuery = "INSERT INTO Personel (AD,SOYAD,MAIL) VALUES (@AD,@SOYAD,@MAIL)";
prmAd.ParameterName = "@AD";
prmAd.DbType = DbType.String;
prmAd.Size = 50;
cmd.Parameters.Add(prmAd);
prmSoyad.ParameterName = "@SOYAD";
prmSoyad.DbType = DbType.String;
prmSoyad.Size = 50;
cmd.Parameters.Add(prmSoyad);
prmMail.ParameterName = "@MAIL";
prmMail.DbType = DbType.String;
prmMail.Size = 50;
cmd.Parameters.Add(prmMail);
cmd.Connection = con;
cmd.CommandText = cmdQuery;
}
else if (secilenProvider == "System.Data.OleDb")
{
conStr.Add("Provider", "SqlOleDb");
conStr.Add("data source", "localhost");
conStr.Add("database", "AdventureWorks");
conStr.Add("integrated security", "SSPI");
cmdQuery = "INSERT INTO Personel (AD,SOYAD,MAIL) VALUES (?,?,?)";
prmAd.DbType = DbType.String;
prmAd.Size = 50;
cmd.Parameters.Add(prmAd);
prmSoyad.DbType = DbType.String;
prmSoyad.Size = 50;
cmd.Parameters.Add(prmSoyad);
prmMail.DbType = DbType.String;
prmMail.Size = 50;
cmd.Parameters.Add(prmMail);
cmd.Connection = con;

www.bsenyurt.com Page 1882


cmd.CommandText = cmdQuery;
}
else
{
Console.WriteLine("Doru provider seilmedi...");
}
con.ConnectionString = conStr.ConnectionString;
try
{
con.Open();
prmAd.Value = "Burak Selim";
prmSoyad.Value = "enyurt";
prmMail.Value = "selim@bsenyurt.com";
int eklenen=cmd.ExecuteNonQuery();
Console.WriteLine("Balant ald...");
Console.WriteLine(eklenen + " SATIR EKLENDI");
Console.ReadLine();
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
finally
{
con.Close();
}
}

DbProviderFactory snf ayrca DbDataAdapter nesnelerini elde edebilmemizi


salayan CreatedDataAdapter isimli bir metoda sahiptir. Bu sayede balantsz katman nesneleri
ile veri kayna arasndaki veri tama ilemlerini gerekletirebileceimiz DataAdapter nesne
rneklerini veri salaycsndan bamsz olacak ekilde elde edebiliriz. Aadaki kod paras ile bu
ilemin nasl gerekletirilebileceini grmektesiniz. Bu rnekte kullancnn setii veri
salaycsnn sistemde ykl olup olmadnda kontrol ediyoruz. rneimizde veri salayclarn
OleDb ve SqlClient ile snrladk.

#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Drawing;
using System.Windows.Forms;

#endregion

namespace UsingDbDataAdapter

www.bsenyurt.com Page 1883


{
partial class Form1 : Form
{
private DbProviderFactory fakto;
private DbConnection con;
private DbConnectionStringBuilder conStr;
private DbCommand cmd;
private DbDataAdapter da;
private DataTable dt;

public Form1()
{
InitializeComponent();
}
private bool VeriSaglayiciKontrol(string invariantName)
{
int varmi = DbProviderFactories.GetFactoryClasses().Select("InvariantName='" +
invariantName + "'").Length;
if (varmi == 0)
return false;
else
return true;
}
private void DbConnectionOlustur(DbConnectionStringBuilder connectionString)
{
con = fakto.CreateConnection();
con.ConnectionString = connectionString.ConnectionString;
}
private void DbCommandOlustur(string sqlQuery)
{
cmd = fakto.CreateCommand();
cmd.Connection = con;
cmd.CommandText = sqlQuery;
}
private void FactoryOlustur(string veritabaniAdi)
{
if (radOleDb.Checked == true)
{
if (VeriSaglayiciKontrol("System.Data.OleDb"))
{
fakto = DbProviderFactories.GetFactory("System.Data.OleDb");
conStr = new DbConnectionStringBuilder();
conStr.Add("provider", "SqlOleDb");
conStr.Add("data source", "localhost");
conStr.Add("database", veritabaniAdi);
conStr.Add("integrated security", "SSPI");
DbConnectionOlustur(conStr);
}
}

www.bsenyurt.com Page 1884


if (radSql.Checked == true)
{
if (VeriSaglayiciKontrol("System.Data.SqlClient"))
{
fakto = DbProviderFactories.GetFactory("System.Data.SqlClient");
conStr = new DbConnectionStringBuilder();
conStr.Add("data source", "localhost");
conStr.Add("database", veritabaniAdi);
conStr.Add("integrated security", "SSPI");
DbConnectionOlustur(conStr);
}
}
}
private void DbDataAdapterOlustur()
{
da = fakto.CreateDataAdapter();
da.SelectCommand = cmd;
}
private void btnVeriCek_Click(object sender, EventArgs e)
{
FactoryOlustur("AdventureWorks");
DbCommandOlustur("SELECT TOP 5 FirstName,MiddleName,LastName FROM
Person.Contact");
DbDataAdapterOlustur();
dt = new DataTable();
da.Fill(dt);
grdVeriler.DataSource = dt;
}
}
}

www.bsenyurt.com Page 1885


Uygulamamz altrdmzda ister Sql veri salaycsn ister OleDb veri salaycsn seelim ayn
DbConnection, DbCommand ve DbDataAdapter nesneleri zerinden ilem yapyor olacaz. te bu
yeni mimarinin bize salad en byk avantajdr.

Son olarak bir DataReader nesnesini veri salaycdan bamsz mimaride nasl kullanabileceimizi
inceleyeceiz. Aslnda u an iin bu mimaride gelitirilmi bir DbDataReader snf yok. Bunun
yerine IDataReader arayzn kullanacaz. Dolaysyla arayz kullanacamz yere kadar
yaptmz ilemler yukardaki rnektekinden farksz olacak.

private void btnIDataReaderIleCek_Click(object sender, EventArgs e)


{
FactoryOlustur("AdventureWorks");
DbCommandOlustur("SELECT TOP 5 FirstName,MiddleName,LastName FROM Person.Contact");
using (con)
{
con.Open();
using (IDataReader dr = cmd.ExecuteReader())
{
while (dr.Read())
{
//bir takm okuma ilemleri.
}
}
}
}

Ado.Net 2.0 iin veri salaycdan bamsz mimariyi kullanmak olduka kolay ve yararl grnyor.
zellikle yeni eklenen snflar bu tarz yaplar oluturmamz son derece kolaylatrm. Burada
kafamz kurcalayan tek konu performans farkllklar. Microsoft kaynaklarna ve otoritelerine gre
ok byk performans kayplar olmad(olmayaca) syleniyor. Akas bu konunun ilerleyen
zamanlarda daha da netleecei grndeyim. Yine de yeni kolaylklarn zellikle farkl veri
sunucularna balanmamz gerektiren durumlarda ok baarl olacan syleyebilirim. Hereyden
nemlisi, hangi veri salaycs olursa olsun ayn DbConnection, DbCommand veya DbDataAdapater
nesnelerini kullanmak son derece byk bir avantajdr. Mimarinin u an iin sadece banda
olduumuzu dnyorum. System.Data.Common isim alanna katlacak daha bir ok zellik
olabilir. rnein buraya zel bir DbDataReader snfnn oluturulmas gibi. unu da hatrlatmakta
fayda var. Buradaki kod rnekleri ve kullanlan snflar, beta srmne aittir. rn piyasaya
ktnda bu snflarn isimlerinde veya kullanl ekillerinde deiiklikler olabilir. Bir sonraki
makalemizde grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Ado.Net 2.0' da Transaction Kavram (


17.04.2005 ) - Ado.Net 2
Deerli Okurlarm, Merhabalar.

www.bsenyurt.com Page 1886


Transaction kavram ve kullanm veritaban programclnn olmazsa olmaz temellerinden birisidir.
Veritabanna doru gerekletirilen ilemlerin tamamnn onaylanmas veya ilerinden birisinde
meydana gelecek bir istisna sonras o ana kadar yaplan tm ilerin geri alnmas veri btnln
korumak asndan son derece nemlidir. Ado.Net 1.0/1.1 iin transactionlarn kullanm, seilen
veri salaycsna gre farkl snflarn kullanlmasn gerektirir. rnein SqlClient isim alanndaki
snflar kullandnz bir veritaban uygulamanz var ise, SqlTransaction snfn kullanrsnz. Oysa
Ado.Net 2.0' da transaction mimarisi Ado.Net' ten ayrtrlm, bir baka deyile provider' lardan
bamsz hale getirilmitir. Aslnda en byk deiiklik transaction ilemlerinin artk
System.Transactions isim alan altnda yer alan snflar ile gerekletirilecek olmasdr. Bir dier
byk deiiklik transaction' larn yazm teknii ile ilgilidir. Ado.Net 2.0 da transaction oluturacak
ve kullanacak kodlar ok daha basit biimde yazabilirsiniz. Bunu ilerleyen paragraflarda sizde
greceksiniz.

Ado.Net 2.0' da transaction' larn kullanm ile ilgili belkide en nemli zellik datk (distributed)
transaction' larn uygulan biimidir. Normal artlarda Ado.Net 1.0/1.1 iin datk transaction' lar
kullanrken System.EnterpriseServices isim alann kullanan COM+ nesnelerini oluturur ve
ContextUtil snfna ait metodlar yardmyla datk transaction' lar kontrol altna alrz. (Detayl bilgi
iin tklayn.) Bu yap zellikle yazm ve oluturulmas itibariyle karmak olup kullanm da zor olan
bir yapdr. Oysa ki Ado.Net 2.0 olay ok daha akll bir ekilde ele alr. Ado.Net 2.0' a gre, iki tip
transaction olabilir. Tek veri kayna zerinde alan LightWeight Transaction' lar ve datk
transactionlar gibi davranan OleTx Transaction' lar. LightWeight Transaction' lar tek bir uygulama
alannda (application-domain) alan i paralardr. OleTx tipi Transaction' lar ise birden fazla
uygulama alannda (application-domain) veya ayn uygulama alannda iseler de farkl veri
kaynaklarn kullanan transaction' lar dr. Dolaysyla OleTx tipi transaction' lar Distributed
Transaction' lara benzetebiliriz. Ancak arada nemli farklarda vardr. lk olarak Ado.Net 1.0/1.1' de
tek veri kayna zerinde alan bir transaction' n nasl uygulandn hatrlayalm.

SqlConnection con = new SqlConnection(connectionString);


con.Open();
SqlCommand cmd = new SqlCommand(sqlSorgusu,con);
SqlTransaction trans;

trans = con.BeginTransaction();
cmd.Transaction = trans;
try
{
cmd.ExecuteNonQuery();
trans.Commit();
}
catch(Exception e)
{
trans.Rollback();
}
finally
{
con.Close();
}

Yukardaki rnekte yerel (local) makine zerinde tekil olarak alan bir transaction iin gerekli
kodlar yer almaktadr. Eer komutun altrlmas srasnda herhangi bir aksilik olursa, catch blou
devreye girer ve transaction geri ekilerek (RollBack) o ana kadar yaplm olan tm ilemler iptal
edilir. Tam tersine bir aksilik olmaz ise transaction nesnesinin Commit metodu kullanlarak ilemler

www.bsenyurt.com Page 1887


onaylanr ve veritabanna yazlr. Gelelim bu tarz bir rnein Ado.Net 2.0' da nasl
gerekletirileceine. Her eyden nce bu seferSystem.Transactions isim alann kullanmamz
gerekiyor. u anki versiyonda bu isim alann uygulamamza harici olarak referans etmemiz
gerekmekte.

Daha sonra ise aadaki kodlara sahip olan Console uygulamasn oluturalm.

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;
using System.Transactions;

#endregion

namespace Transactions
{
class Program
{
static void Main(string[] args)
{
using (TransactionScope tsScope = new TransactionScope())
{
using (SqlConnection con = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))

www.bsenyurt.com Page 1888


{
SqlCommand cmd = new SqlCommand("INSERT INTO Personel (AD,SOYAD,MAIL)
VALUES ('Burak Selim','ENYURT','selim@bsenyurt.com')", con);
con.Open();
cmd.ExecuteNonQuery();
tsScope.Complete();
}
}
}
}
}

Grld gibi Ado.Net 1.0/1.1' e gre olduka farkl bir yap


kullanlmtr. TransactionScope snfna ait nesne rnekleri kendisinden sonra alan balantlar
otomatik olarak bir transaction scope(faaliyet alan) ierisine alr. Buradaki temel mantk bir veya
daha fazla transaction' kullanacak olan bir scope (faaliyet alan) oluturmak ve hepsi iin gereki
bir takm zelliklerin ortak olarak belirlenmesini salamaktr. TransactionScope snfna ait nesne
rneklerini oluturabileceimiz pek ok ar yklenmi (overload) yapc (constructor) metod
mevcuttur. Bu yapc metotlar yardmyla, scope (faaliyet alan) iin pek ok zellik
tanmlayabilirisiniz. TransactionScope, IDisposablearayzn (interface) uygulayan bir snftr. Bir
TransactionScope nesnesi oluturululduunda ve bu nesnenin oluturduu faaliyet alanna ilk
transaction eklendiinde devam eden komutlara ilikin transaction' larda otomatik olarak var olan
bu scope (faaliyet alan) ierisinde gereklemektedir. Bu elbetteki varsaylan durumdur. Ancak
dilersenizTransactionScopeOption numaralandrcs (enumerator) yardmyla, yeni alan
transaction' larn var olan scope' a (faaliyet alanna) dahil edilip edilmeyeceini belirleyebilirsiniz.

Eer veritabanna doru alan komutlarda herhangi bir aksaklk olursa uygulama otomatik olarak
using blounu terk edecektir. Bu durumda son satrdaki Complete metodu arlabilir hale
gelecektir. Bu da transaction ierisindeki ilemlerin commit edilebilecei anlamna gelir. Bu yeni
teknik, eskisine gre zellikle kod yazmn hem kolaylatrm hem de profesyonelletirmitir.
Bununla birlikte var olan alkanlklarmzdan birisi meydana gelecek aksaklk nedeni ile kullancnn
bir istisna mekanizmas ile uyarlabilmesini salamak veya baka ilemleri yaptrmaktr. Dolaysyla
ayn rnei aadaki haliyle de yazabiliriz.

using (TransactionScope tsScope = new TransactionScope())


{
SqlConnection con = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI");
SqlCommand cmd = new SqlCommand("INSERT INTO Personel (AD,SOYAD,MAIL) VALUES
('Burak Selim','ENYURT','selim@bsenyurt.com')", con);
try
{
con.Open();
cmd.ExecuteNonQuery();
tsScope.Complete();
}
catch (TransactionException hata)
{
Console.WriteLine(hata.Message.ToString());
}

www.bsenyurt.com Page 1889


finally
{
con.Close();
}
}

Burada oluabilecek istisnay yakalamak istediimiz iin bir try-catch-finally blounu kullandk.
Ancak dikkat ederseniz TransactionScope nesnemiz yine using blou ierisinde kullanlmtr ve
transaction' commit etmek iin Complete metodu arlmtr. Her iki rnekte LightWeight
Transaction tipindedir. nk tek bir connection ve yine tek bir application domain mevcuttur.
Elbette birden fazla komutun yer ald transaction' larda ayn teknik kullanlarak oluturulabilir.
Ancak farkl veritabanlarna balanan aksiyonlar sz konusu ise Transaction' larn oluturulmas ve
arka planda gerekleen olaylar biraz farkldr. imdi bu durumu rneklemek iin aadaki Console
uygulamasn oluturalm.

using (TransactionScope tsScope = new TransactionScope())


{
using (SqlConnection conAdventureWorks = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmdAdvPersonel = new SqlCommand("INSERT INTO Personel
(AD,SOYAD,MAIL) VALUES ('Burak Selim','ENYURT','selim@bsenyurt.com')",
conAdventureWorks);
conAdventureWorks.Open();
cmdAdvPersonel.ExecuteNonQuery();
using (SqlConnection conNorthwind = new SqlConnection("data
source=localhost;database=Northwind;integrated security=SSPI"))
{
conNorthwind.Open();
SqlCommand cmdNrtPersonel = new SqlCommand("UPDATE Personel SET AD='Gustavo'
WHERE ID=1", conNorthwind);
cmdNrtPersonel.ExecuteNonQuery();
}
}
tsScope.Complete();
}

Grld gibi ilk yazdmz rnekten pek fark yok. Sadece i ie gemi (nested) bir yap var.
Ayn application domain' e ait iki farkl database balants ihtiyac olduu iin burada bir distributed
transaction kullanlmas gerekiyor. Normalde DTC (Distributed Transaction
Coordinator) kontrolnde ele alnacak bu transaction' lar oluturmak iin Ado.Net 1.0/1.1' de
baya uramamz gerekecekti. Oysa ki Ado.Net 2.0' da herhangi bir ey yapmamza gerek yok.
nk Ado.Net 2.0 otomatik olarak OleTx tipinde bir transaction oluturacaktr. Nasl m? Bunu
gzlemlemenin en iyi yolu, uygulama koduna breakpoint koymak ve Administrative Tool-
>Component Services' dan alacak olan transaction' lar izlemekle olacaktr. lk olarak
kodumuza bir breakpoint koyalm ve adm adm uygulamamzda ilerleyelim.

www.bsenyurt.com Page 1890


Sar noktaya gelinceye kadar ve conNorthwind isimli balant Open metodu ile alncaya kadar
aktif olan tek bir Connection nesnesi vardr. Buraya kadar transaction' mz LightWeight tipindedir.
Ancak ikinci balantda aldktan sonra bu balant TransactionScope nesnemize otomatik olarak
eklenecektir. te sar noktada iken Administrative Tool->Component Services' a
bakarsak, TransactionList ierisinde, DTC kontrol altnda kullanc tanml bir transaction' n
otomatik olarak aldn grrz.

Artk her iki connection zerinde alan komutlar DTC altnda oluturulan bu Connection' n
kontrol altndadr. lemler baarl bir ekilde tamamlanrsa TransactionScope nesnesine ait using
blounun sonundaki kod satr alacaktr. Yani Complete metodu yrtlecektir. Bu sayede
ilemler Commit edilir ve bylece tm ilemler onaylanarak veritabanlarna yazlr. Using bloundan
kldktan sonra ise, DTC kontrol altndaki bu transaction otomatik olarak kaldrlr. DTC kontrol
altnda oluturulan transaction' lar her zaman unique bir ID deerine sahip olur. Bylece sunucu
zerinde ayn anda alan birden fazla distributed transaction var ise, bunlarn birbirlerinden ayrt
edilmeleri ve uygun olan application domain' ler tarafndan ele alnmalar salanm olur.

www.bsenyurt.com Page 1891


TransactionScope nesnesinin belirledii scope (faaliyet alan) altnda alan transaction' lar bir
takm zelliklere sahiptir. rnein eskiden olduu gibi IsolationLevel deerleri veya TimeOut
sreleri vardr. Dilersek oluturulacak bir TransactionScope nesnesinin ilgili deerlerini nceden
manuel olarak ayarlayabilir bylece bu scope (faaliyet alan) iindeki transaction' larn ortak
zelliklerini belirleyebiliriz. Bunun iin TransactionOptions snfna ait nesne rnekleri kullanlr.

TransactionOptions trOptions = new TransactionOptions();


trOptions.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
trOptions.Timeout = new TimeSpan(0, 0, 30);
using (TransactionScope tsScope = new
TransactionScope(TransactionScopeOption.RequiresNew,trOptions))
{
using (SqlConnection con = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmd = new SqlCommand("INSERT INTO Personel (AD,SOYAD,MAIL) VALUES
('Burak Selim','ENYURT','selim@bsenyurt.com')", con);
con.Open();
cmd.ExecuteNonQuery();
tsScope.Complete();
}
}

Yukardaki rnekte, oluturulacak olan transaction' n izolasyon seviyesi ve zaman am sreleri


belirlenmi ve TransactionScope nesnemiz bu opsiyonlar erevesinde aadaki overload metot
versiyonu ile oluturulmutur.

TransactionScope tsScope = new


TransactionScope(TransactionScopeOption.RequiresNew,trOptions)

Burada ilk parametre birden fazla TransactionScope nesnesinin yer ald i ie gemi yaplarda
byk nem arzetmektedir. Bu seenek ile yeni alan transaction scope' un (faaliyet alannn) var
olan nceki bir transaction faaliyet alanna katlp katlmayaca gibi seenekler belirlenir. rnein
aadaki basit yapy ele alalm. Burada ilk using blou ile bir Transaction Scope oluturulur. kinci
using ifadesine gelindiinde yeni transaction scope' un nceki transaction scope' a ilave edilecei
TransactionScopeOption parametresi ile belirlenir. Nitekim Required deeri, yeni scope' u var olan
nceki scope' a ekler. Eer var olan bir scope yok ise yeni bir tane oluturur. Elbetteki burada akla
gelen soru scope iindeki transaction' larn kimin tarafndan onaylanacadr. Burada root scope kim
ise ona ait Complete metodu devreye girecektir.

using(TransactionScope faaliyetAlani1 = new TransactionScope())


{
...
using(TransactionScope faaliyetAlani2 = new
TransactionScope(TransactionScopeOption.Required))
{
...
}

www.bsenyurt.com Page 1892


}

imdi yukardaki nested scope yaps iine nc bir scope daha ilave edelim. Ancak yeni
TransactionScope iin TransactionScopeOption deerini RequiresNew olarak belirleyelim.

using(TransactionScope faaliyetAlani1 = new TransactionScope())


{
...
using(TransactionScope faaliyetAlani2 = new
TransactionScope(TransactionScopeOption.Required))
{
...
}
using(TransactionScope faaliyetAlani3 = new
TransactionScope(TransactionScopeOption.RequiresNew))
{
...
}
}

Bu durumda yapmz aadaki gibi olacaktr.

www.bsenyurt.com Page 1893


Dilersek transaction' lar aka(explicit) kendimizde manel olarak oluturabiliriz. u ana kadar
yaptmz rneklerde implicit bir yaklam izledik. Yani ilgili transaction ve bunlara ait kaynaklarn
otomatik olarak oluturulmasn saladk. rnein aadaki kodlarda transaction' lar manuel olarak
oluturulmutur. (rnek .Net 2.0 Beta srmnde denenmitir.)

ICommittableTransaction trans = Transaction.Create();


try
{
using (SqlConnection conNorthwind = new SqlConnection("data
source=localhost;database=Northwind;integrated security=SSPI"))
{
SqlCommand cmdInsert = new SqlCommand("INSERT INTO Personel (AD,SOYAD) VALUES
('Burak Selim','enyurt')", conNorthwind);
conNorthwind.Open();
conNorthwind.EnlistTransaction(trans);
cmdInsert.ExecuteNonQuery();
}
using (SqlConnection conAdv = new SqlConnection("data
source=localhost;database=AdventureWorks;integrated security=SSPI"))
{
SqlCommand cmdInsert = new SqlCommand("INSERT INTO Personel (AD,SOYAD,MAIL)
VALUES ('Cimi','Keri','cimi@keri.com')", conAdv);
conAdv.Open();
conAdv.EnlistTransaction(trans);
cmdInsert.ExecuteNonQuery();

www.bsenyurt.com Page 1894


}
trans.Commit();
}
catch
{
trans.Rollback();
}

ICommittableTransaction arayz bir Transaction Scope' un oluturulmasn salar. Bunun iin


Transaction snfna ait Create metodu kullanlr. Create metodu varsaylan ayarlar ile birlikte bir
Scope oluturacaktr. Eer bu Scope' a transaction' lar eklemek istersek, ilgili balantlar temsil
eden Connection nesnelerinin EnlistTransaction metodunu kullanrz. EnlistTransaction metodu
parametre olarak transaction Scope' u temsil eden ICommittableTransaction arayz tipinden
nesne rneini alr. Elbette arayze eklenen transaction' lara ait ilemlerin onaylanmasn salamak
iin arayze ait Commit metodu kullanlr. Tam tersine bir sorun kar ve veritabanna doru
yaplan ilemlerden birisi gerekletirilemez ise o ana kadar yaplan ilemlerin geri
alnmas ICommittableTransaction arayzne ait RollBack metodu ile salanm olur.

Bu makalemizde Transaction mimarisinin Ado.Net 2.0' daki yzn incelemeye altk. Grld
gibi kod yazmnn basitletirilmesinin yannda, zellikle EnterpriceServices bamllndan
kurtularak Distributed Transaction' larn otomatik hale getirilmesi ve Transaction Scope kavramnn
getirilmesi gze arpan nemli zellikler. Burada bahsedilen zellikler teorik olarak fazla bir
deiiklie uramayacaktr. Ancak baz yelerin isimlerin deiiklik beklenmektedir. rnein
ICommittableTransaction arayz yerine CommittableTransaction snfnn gelecei
dnlmektedir. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

DataReader Nesnelerini Kullanrken (


04.04.2005 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde Command nesnelerini kullanrken dikkat etmemiz gereken noktalara
deinmitik. Bu makalemizde ise DataReader nesnelerini kullanrken bizlere avantaj salayacak
tekniklere deinmeye alacaz. nceki makalemizde olduu gibi arlk olarak SqlDataReader
nesnesini ve Sql veritann kullanacaz. DataReader nesneleri bildiiniz gibi, balantl katman
(connected-layer) zerinde almaktadr. Grevleri veri kaynandan, uygulama ortamna doru
belli bir akm zerinden hareket edecek veri paralarnn tanmasn salamaktr. DataReader
nesneleri ile veri almak balantsz katman (disconnected-layer) nesnelerine veri ekmekten ok
daha hzldr. ounlukla DataReader nesnelerinin kullanlmasnn tercih edilecei durumlar vardr.
Uygulamalarmz gelitirirken ou zaman balantl katman ile balantsz katman nesneleri
arasnda seim yapmakta zorlanrz. Aadaki tablo "Ne zaman DataReader kullanrz?" sorusuna
k tutan noktalara deinmektedir.

Eer Windows veya Asp.Net uygulamas gelitiriyor ve birden fazla form(page) iin veri balama
(data-binding) gerekletirmiyorsanz,

www.bsenyurt.com Page 1895


Veriyi ara bellee alma (caching) ihtiyacnz yok ise.

Eer tablolarnz arasndaki ilikileri (relations) uygulamalarnzda kullanmyorsanz.

DataReader Kullanmay Tercih Edin.

Gelelim DataReader nesnelerini kullanrken dikkat edeceimiz altn noktalara. Bu teknikler


uygulamalarmzn performansn arttracak nitelikte olup aadaki tabloda belirtilmektedir.

DataReader nesnelerini kullanrken ak Connection' larn kapatlmasn unutmayn.

Sorgu sonucu sadece tek bir satr dnecei kesin ise SingleRow tekniini kullann.

Toplu sorgular (Batch Queries) iin Next Result tekniini kullann.

Binary veya Text bazl alan verilerini okurken SequentialAccess tekniini kullann.

imdi bu teknikleri birer birer inceleyelim.

Ak Connection' lar Kapatmay Unutmamak in

DataReader nesneleri ak ve geerli bir Connection nesnesine ihtiya duyarlar. Lakin ayn
Connection' kullanan DataReader nesneleri sz konusu ise, her bir DataReader' n kullanlabilmesi
iin bir nceki DataReader' n kulland Connection nesnesinin kapatlm olmas gerekir. (Bu ayn
Connection nesnesini kullanan DataReader' lar var ise geerlidir.) rnein aadaki uygulama
kodunu ele alalm;

using System;
using System.Data;
using System.Data.SqlClient;

namespace DataReaderDikkat
{
public class DbWork
{
private SqlConnection con;
private SqlDataReader dr;

/* CloseConnection kullanmna rnek metod.*/


public DbWork(string conStr)
{
con=new SqlConnection(conStr);
}

public SqlDataReader Results(string selectQuery)

www.bsenyurt.com Page 1896


{
SqlCommand cmd=new SqlCommand(selectQuery,con);
con.Open();
dr=cmd.ExecuteReader(); // Hatal kullanm.
return dr;
}
}
}

DbWork snfmz constructor metodunda bir SqlConnection nesnesi oluturur. Results isimli
metodumuz ise parametre olarak ald sorgu sonucu bir SqlDataReader nesnesi ile geri dndrr.
imdi bu snf kullanan aadaki uygulamamz ele alalm.

using System;
using System.Data;
using System.Data.SqlClient;

namespace DataReaderDikkat
{
class ClosingDataReader
{
[STAThread]
static void Main(string[] args)
{
DbWork worker=new DbWork("data source=BURKI;database=Northwind;integrated
security=SSPI");
#region CloseConnection Kullann.

SqlDataReader drOrders=worker.Results("SELECT TOP 10 * FROM Orders");


while(drOrders.Read())
{
Console.WriteLine(drOrders[0].ToString()+" "+drOrders[1].ToString());
}
drOrders.Close();
SqlDataReader drCustomers=worker.Results("SELECT TOP 10 * FROM Customers");
while(drCustomers.Read())
{
Console.WriteLine(drCustomers[0].ToString()+" "+drCustomers[1].ToString());
}
drCustomers.Close();
#endregion
}
}
}

Uygulamamz bu haliyle altrdmzda aadaki istisnay alrz.

www.bsenyurt.com Page 1897


Sebep ilk drOrders SqlDataReader nesnesinin kulland SqlConnection nesnesinin kapatlmam
olmas ve balantnn halen daha ak olarak kalmasdr. zellikle yukardaki gibi i nesneleri
zerinden yrtlen sorgularda Connection nesnelerinin otomatik olarak kapatlmasn salamak
iin CommandBehavior numaralandrcsnn CloseConnection deerini kullanmay unutmamak
gerekir. Dolaysyla DbWork snfmzdaki Results metodunu aadaki gibi dzenlersek istediimiz
sonucu elde eder ve istisnann stesinden geliriz.

public SqlDataReader Results(string selectQuery)


{
SqlCommand cmd=new SqlCommand(selectQuery,con);
con.Open();
dr=cmd.ExecuteReader(CommandBehavior.CloseConnection); // Doru Kullanm.
// dr=cmd.ExecuteReader(); // Hatal kullanm.
return dr;
}

www.bsenyurt.com Page 1898


Sorgu Sonucu Tek Bir Satr Dnd Kesin se

Baz durumlarda tablolardan dnen satr saysnn 1 olaca kesindir. Bu satrlar ounlukla belirli
key alan zerinden elde edilen parametrik sorgularn sonucudur. rnein, benzersiz deer alan
(unique), ve otomatik olarak artan alanlarn parametre olarak kullanld sorgular gz nne
alabiliriz. Bu tarz sorgularda, balantsz katman nesnelerini kullanmak gereksiz yere kaynak
tketimine neden olacaktr. Byle bir durumda DataReader nesneleri balantsz katman
nesnelerine oranla ok daha performansl ve hzl alacaktr. Burada nemli olan DataReader ile
dnen satr okumak iin ilgili Command nesnesinin ExecuteReader metoduna verilecek
CommandBehavior numaralandrcsnn deeridir. Aada bu tekniin kullanmna bir rnek
verilmitir. Veritaban ilemlerimizi topladmz DbWork snf basit olarak constructor metodu ile
bir SqlConnection nesnesi rneklendirir. GetRow metodumuz ise gelen sorguya ve parametre
deerine gre bulunan satr okuyacak bir SqlDataReader nesnesini geriye dndrr.

using System;
using System.Data;
using System.Data.SqlClient;

namespace DataReaderDikkat
{
public class DbWork
{
private SqlConnection con;
private SqlDataReader dr;

/* CloseConnection kullanmna rnek metod.*/


public DbWork(string conStr)
{
con=new SqlConnection(conStr);
}

public SqlDataReader GetRow(string FindQuery,int orderID)


{
SqlCommand cmd=new SqlCommand(FindQuery,con);
cmd.Parameters.Add("@OrderID",SqlDbType.Int);
cmd.Parameters["@OrderID"].Value=orderID;
con.Open();
dr=cmd.ExecuteReader((CommandBehavior)40);
return dr;
}
}
}

Burada ExecuteReader metodunun kullanlna dikkatinizi ekerim. CommandBehavior


numaralandrcsnn alaca deerlerin saysal karlklar vardr. SingleRow deerinin integer
karl 8, CloseConnection numaralandrcsnn integer karl ise 32' dir. Dolaysyla
(CommandBehavior)40, oluturulan SqlDataReader nesnesine sadece tek bir satr dndreceini ve
SqlDataReader nesnesi kapatldnda SqlConnection nesnesinin de otomatik olarak kapatlacan
belirtir. Gelelim ana program kodlarmza;

www.bsenyurt.com Page 1899


using System;
using System.Data;
using System.Data.SqlClient;

namespace DataReaderDikkat
{
class ClosingDataReader
{
[STAThread]
static void Main(string[] args)
{
DbWork worker=new DbWork("data source=BURKI;database=Northwind;integrated
security=SSPI");

#region SingleRow Kullann.


SqlDataReader drFind=worker.GetRow("SELECT * FROM Orders WHERE
OrderID=@OrderID",10248);
drFind.Read();
Console.WriteLine("BULUNAN SATIR "+drFind[0].ToString());
drFind.Close();

drFind=worker.GetRow("SELECT * FROM Orders WHERE OrderID=@OrderID",10249);


drFind.Read();
Console.WriteLine("BULUNAN SATIR "+drFind[0].ToString());
drFind.Close();
#endregion
}
}
}

Toplu Sorgula in DataReader Kullann

zellikle birden fazla sonu kmesini (result set) almak istiyorsanz ve DataReader kullanmaya
karar verdiyseniz en uygun yntem NextResult metodunun uygulanmasdr. Gerek u ki, byle bir
durumda birden fazla DataReader nesnesi pe pee altrlabilir. Ayn bu makalemizdeki ilk
rneimizde olduu gibi. Eer bu tarz sonu kmelerini gerekten arka arkaya alyorsak ve ayn
Connection' kullanyorsak, birden fazla DataReader nesnesi kullandmz iin ayn Connection'
kullanyor olsakta veritabanna doru birden fazla sayda tur atm oluruz. nk her bir
DataReader nesnesinden sonradan gelen DataReader nesnelerinin ayn Connection' kullanmalarna
imkan salamamz iin ilgili Connection' lar kapatmak gibi bir zorunluluumuz vardr. Oysaki bu
sorgular Batch Query olarak hazrlarsak tek bir DataReader nesnesi ve tek bir Connection ile daha
hzl sonu elde edebiliriz. Ayn aadaki rnekte olduu gibi. DbWork snfmza bu sefer, Batch
Query altracak bir metot ekledik. Metodumuz gelen string dizisi iindeki sorgu cmlelerini alp

www.bsenyurt.com Page 1900


bir StringBuilder yardmyla birletiriyor. Bu ilemin sonucu olarak "sorgu cmlesi 1;sorgu cmlesi
2;sorgu cmlesi 3;" tarznda bir query string' i oluturuyoruz ki bu bizim Batch Qeury' mizdir. Daha
sonra ilgili sorgu topluluunu altracak bir SqlCommand nesnesi oluturuyor ve bu komutu
yrterek elde ettiimiz SqlDataReader nesnesini geriye dndryoruz.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Text;

namespace DataReaderDikkat
{
public class DbWork
{
private SqlConnection con;
private SqlDataReader dr;

/* CloseConnection kullanmna rnek metod.*/


public DbWork(string conStr)
{
con=new SqlConnection(conStr);
}

public SqlDataReader BatchResults(string[] sorgular)


{
StringBuilder sbSorgular=new StringBuilder();
for(int i=0;i<sorgular.Length;i++)
{
sbSorgular.Append(sorgular[i]+";");
}
SqlCommand cmd=new SqlCommand(sbSorgular.ToString(),con);
con.Open();
SqlDataReader dr=cmd.ExecuteReader(CommandBehavior.CloseConnection);
return dr;
}
}
}

Gelelim uygulama kodlarmza;

using System;
using System.Data;
using System.Data.SqlClient;

namespace DataReaderDikkat
{
class ClosingDataReader
{

www.bsenyurt.com Page 1901


[STAThread]
static void Main(string[] args)
{
DbWork worker=new DbWork("data source=BURKI;database=Northwind;integrated
security=SSPI");

#region BatchQuery' lerde


string[] sorguKumesi={"SELECT TOP 5 * FROM Orders","SELECT TOP 5 * FROM
Customers","SELECT TOP 5 * FROM [Order Details]"};
SqlDataReader drToplu=worker.BatchResults(sorguKumesi);
do
{
while(drToplu.Read())
{
Console.WriteLine(drToplu[0].ToString()+" "+drToplu[1].ToString());
}
Console.WriteLine("------------");
}while(drToplu.NextResult());
drToplu.Close();
#endregion
}
}
}

Binary ve Text Tipindeki Alanlar Okurken

Baz tablolar ierisinde text veya binary tabanl alanlar tutarz. rnein resim dosyalarnn
tablolarda binary olarak saklanmas veya makalelerin html verisinin text tipli alanlar olarak
saklanmas gibi. zellikle bu tarz alanlar okurken DataReader nesnelerini kullanyorsak,
SequentialAccess tekniini kullanmak bize avantaj salayabilir. yle ki bu teknii uyguladmzda
ilgili satrn tamam okunacana bunun yerine bir stream oluturulur. Siz bu stream' i kullanarak

www.bsenyurt.com Page 1902


ilgili alana ait binary yada text veriyi okursunuz. rnein aadaki kodlar ile Northwind database'
inde yer alan Categories tablosundaki Text tipindeki Description alannn ilk 150 karakteri
okunmaktadr.

public SqlDataReader ReadText(string Query)


{
SqlCommand cmd=new SqlCommand(Query,con);
con.Open();
dr=cmd.ExecuteReader((CommandBehavior)48); // Bu kez hem SequentialAccess hem de
CloseConnection seili.
return dr;
}

Metodumuzun kullanl ise aadaki gibi olacaktr.

SqlDataReader drText=worker.ReadText("SELECT CategoryName,Description,Picture FROM


Categories");
char[] tampon=new char[150];
while(drText.Read())
{
drText.GetChars(1,0,tampon,0,150);
for(int i=0;i<150;i++)
{
Console.Write(tampon[i].ToString());
}
Console.WriteLine();
}

Bu makalemizde DataReader nesnelerini kullanrken dikkat edeceimiz ve bize avantaj salayacak


teknikleri incelemeye altk. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler
dilerim.

rnek iin tklayn.

www.bsenyurt.com Page 1903


Burak Selim ENYURT
selim@bsenyurt.com

Command Nesnelerine Dikkat! ( 27.03.2005 ) -


Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Command nesnelerini kullanrken performans arttrc, kod okunurluunu


kolaylatrc, gvenlik riskini azaltc etkenler zerinde duracaz ve bu kazanmlar iin gerekli
teknikleri greceiz. rneklerimizi SqlCommand snfna ait nesneler zerinden gelitireceiz.
Bildiiniz gibi Command nesneleri yardmyla veritabanna doru yrtmek istediimiz sorgular
altrmaktayz. Bu sorgular basit Select, Insert, Update, Delete sorgular olabilecei gibi sakl
yordamlar (Stored Procedures) veya tablolarda olabilir. Command nesneleri ayrca dier Ado.Net
nesnelerinin iletilmelerinde de etkin rol oynamaktadr. rnein balantsz katman (disconnected
layer) nesnelerinin doldurulmas veya gncellenmesi iin kullanlan DataAdapter nesneleri
veya balantl katman (connected layer) zerinde alan DataReader nesneleri gibi. Dolaysyla
Command nesnelerine baml olarak alan programlarn performans, gvenlik ve kod okunurluu
ynnden uygulamas tavsiye edilen baz teknikler vardr. Command nesnelerinin hazrlan ve
kullanlmas srasnda dikkat etmemiz gereken noktalar aadaki drt madde ile zetlenmitir.

SqlCommand Nesneleri in Pozitif Yaklamlar

Parametrik sorgularn kullanm.

Sorgularn yeniden kullanm iin hazrlanmas (Prepare Teknii)

En etkin constructor ile nesne rneinin oluturulmas.

Tek deerlik dnler iin ExecuteScalar metodunun tercih edilmesi.

imdi bu maddelerimizi tek tek incelemeye balayalm.

Parametrik Sorgularn Kullanm.

Parametrik sorgular dier trlerine gre daha hzl alr. Ayrca Sql Injection' a kar daha yksek
gvenlik salar. Son olarak, parametrik sorgularda rnein string deerler iin tek trnak kullanma
zorunluluunda kalmazsnz ki bu kodunuzun okunulabilirliini arttrr. rnein aadaki kod
parasn inceleyelim. Bu rneimizde tabloya veri girii iin INSERT sorgusu kullanlyor.
Sorgumuza ait Sql cmleciine dikkat edecek olursanz TextBox kontrollerinden deerler almakta.
fade okunurluk asndan olduka zorlayc. Ayrca tek trnak kullanlmas gerektiinden yazmnda
byk dikkat gerektiriyor.

SqlConnection con=new SqlConnection("data source=BURKI;database=Work;integrated


security=SSPI");

www.bsenyurt.com Page 1904


string insertText="INSERT INTO Maaslar (ADSOYAD,DOGUMTARIHI,MAAS) VALUES
('"+txtADSOYAD.Text.ToString()+"','"+txtDOGUMTARIHI.Text.ToString()+"',"+txtMAAS.Text.ToStri
ng()+")";
SqlCommand cmd=new SqlCommand(insertText,con);
con.Open();
cmd.ExecuteNonQuery();
con.Close();

Oysaki bu tip bir kullanm yerine sorguya giren d deerleri parametrik olarak tanmlamak ok
daha avantajldr. Srat, kolay okunurluk, tek trnak' dan bamsz olmak. Ayn kod parasn imdi
aadaki gibi deitirelim. Bu sefer sorgumuza alacamz deerleri SqlCommand nesnesine birer
parametre olarak ekledik. ADSOYAD alanmz nvarchar, DOGUMTARIHI alanmz DateTime, MAAS
alanmz ise Money tipindedir. Bu nedenle parametrelerde uygun SqlDbType deerlerini setik.
Daha sonra parametrelerimiz iin gerekli deerlerimizi Form zerindeki kontrollerimizden alyor.
Dikkat ederseniz textBox kontrollerinden veri alrken herhangi bir tr dnm ilemi
uygulamadk.

/* Connection oluturulur. */
SqlConnection con=new SqlConnection("data source=BURKI;database=Work;integrated
security=SSPI");
/* Sorgu cmlecii oluturulur.*/
string insertText="INSERT INTO Maaslar (ADSOYAD,DOGUMTARIHI,MAAS) VALUES
(@ADSOYAD,@DOGUMTARIHI,@MAAS)";
/* Command nesnesi oluturulur */
SqlCommand cmd=new SqlCommand(insertText,con);
/* Komut iin gerekli parametreler tanmlanr. */
cmd.Parameters.Add("@ADSOYAD",SqlDbType.NVarChar,50);
cmd.Parameters.Add("@DOGUMTARIHI",SqlDbType.DateTime);
cmd.Parameters.Add("@MAAS",SqlDbType.Money);
/* Parametre deerleri verilir. */
cmd.Parameters["@ADSOYAD"].Value=txtADSOYAD.Text;
cmd.Parameters["@DOGUMTARIHI"].Value=txtDOGUMTARIHI.Text;
cmd.Parameters["@MAAS"].Value=txtMAAS.Text;
/* Balant alr komut altrlr ve balant kapatlr. */
con.Open();
cmd.ExecuteNonQuery();
con.Close();

Sorgularn Yeniden Kullanm iin Hazrlanmas (Prepare Teknii)

Stored Procedure' lerin hzl olmalarnn en byk nedeni sql sorgularna ait planlarnn ara bellekte
tutulmasdr. Ayn ilevsellii uygulamalarmzda sk kullanlan sorgu cmleleri iinde
gerekleyebiliriz. Bunun iin SqlCommand nesnesinin Prepare metodu kullanlr. Bu metod
yardmyla ilgili sql sorgusuna ait plann Sql sunucusu iin ara bellekte tutulmas salanm olur.
Bylece sorgunun ilk altrlndan sonraki yrtmelerin daha hzl olmas salanm olur.
Aadaki kod parasn ele alalm. Bu sefer arka arkaya 3 satr girii ilemini gerekletiriyoruz.

SqlConnection con=new SqlConnection("data source=BURKI;database=Work;integrated

www.bsenyurt.com Page 1905


security=SSPI");
string insertText="INSERT INTO Maaslar (ADSOYAD,DOGUMTARIHI,MAAS) VALUES
(@ADSOYAD,@DOGUMTARIHI,@MAAS)"; con.Open();
SqlCommand cmd=new SqlCommand(insertText,con);
cmd.Parameters.Add("@ADSOYAD",SqlDbType.NVarChar,50);
cmd.Parameters.Add("@DOGUMTARIHI",SqlDbType.DateTime);
cmd.Parameters.Add("@MAAS",SqlDbType.Money);
// lk veri girii
cmd.Parameters["@ADSOYAD"].Value="Burak";
cmd.Parameters["@DOGUMTARIHI"].Value="12.04.1976";
cmd.Parameters["@MAAS"].Value=1000;
cmd.ExecuteNonQuery();

// kinci veri girii


cmd.Parameters["@ADSOYAD"].Value="Bili";
cmd.Parameters["@DOGUMTARIHI"].Value="10.04.1965";
cmd.ExecuteNonQuery();

// nc veri girii
cmd.Parameters["@ADSOYAD"].Value="Ali";
cmd.Parameters["@DOGUMTARIHI"].Value="09.04.1980";
cmd.ExecuteNonQuery();
con.Close();

Bu tarz bir kullanm yerine, aadaki kullanm zellikle a ortamnda iletilecek olan
sorgulamalarda daha yksek performans salayacaktr. Tek yapmamz gereken SqlCommand
nesnesini ilk kez Execute edilmeden nce Prepare metodu ile Sql Sunucusu iin ara bellee
aldrmaktr. Yani;

SqlConnection con=new SqlConnection("data source=BURKI;database=Work;integrated


security=SSPI");
string insertText="INSERT INTO Maaslar (ADSOYAD,DOGUMTARIHI,MAAS) VALUES
(@ADSOYAD,@DOGUMTARIHI,@MAAS)"; con.Open();
SqlCommand cmd=new SqlCommand(insertText,con);
cmd.Parameters.Add("@ADSOYAD",SqlDbType.NVarChar,50);
cmd.Parameters.Add("@DOGUMTARIHI",SqlDbType.DateTime);
cmd.Parameters.Add("@MAAS",SqlDbType.Money);
// lk veri girii
cmd.Parameters["@ADSOYAD"].Value="Burak";
cmd.Parameters["@DOGUMTARIHI"].Value="12.04.1976";
cmd.Parameters["@MAAS"].Value=1000;
cmd.Prepare();
cmd.ExecuteNonQuery();

// kinci veri girii


cmd.Parameters["@ADSOYAD"].Value="Bili";
cmd.Parameters["@DOGUMTARIHI"].Value="10.04.1965";
cmd.ExecuteNonQuery();

www.bsenyurt.com Page 1906


// nc veri girii
cmd.Parameters["@ADSOYAD"].Value="Ali";
cmd.Parameters["@DOGUMTARIHI"].Value="09.04.1980";
cmd.ExecuteNonQuery();
con.Close();

En Etkin Constructor ile Nesne rneinin Oluturulmas.

Bir SqlCommand nesnesinin oluturulmas srasnda kullanlacak Constructor metodun seimi


zellikle kod okunurluu asndan nemlidir. rnein aadaki kod kullanmn ele alalm.

// ConnectionString tanmlanr.
string conStr="data source=BURKI;database=Work;integrated security=SSPI";
// Select sorgu cmlesi tanmlanr.
string selectText="SELECT * FROM Ogrenciler";
// SqlConnection nesnesi oluturulur.
SqlConnection con=new SqlConnection();
// SqlConnection nesnesi iin Connection String atanr.
con.ConnectionString=conStr;
// Connection alr.
con.Open();
// Yeni bir SqlTransaction nesnesi balatlr.
SqlTransaction trans=con.BeginTransaction();
// SqlCommand nesnesi tanmlanr.
SqlCommand cmd=new SqlCommand();
// SqlCommand nesnesinin kullanaca SqlConnection belirlenir.
cmd.Connection=con;
// SqlCommand nesnesinin kullanaca SqlTransaction belirlenir.
cmd.Transaction=trans;
// SqlCommand nesnesinin yrtecei sorgu cmlesi belirlenir.
cmd.CommandText=selectText;

Bu kod aadaki gibi daha etkin bir biimde yazlabilir.

// ConnectionString tanmlanr.
string conStr="data source=BURKI;database=Work;integrated security=SSPI";
// Select sorgu cmlesi tanmlanr.
string selectText="SELECT * FROM Ogrenciler";
// SqlConnection nesnesi oluturulur ve alr.
SqlConnection con=new SqlConnection(conStr);
con.Open();
// Yeni bir SqlTransaction nesnesi balatlr.
SqlTransaction trans=con.BeginTransaction();
// SqlCommand nesnesi tanmlanr.
SqlCommand cmd=new SqlCommand(selectText,con,trans);

www.bsenyurt.com Page 1907


Tek Deerlik Dnler iin ExecuteScalar Metodunun Tercih Edilmesi.

Bazen sorgularmzda Aggregate fonksiyonlarn kullanrz. rnein bir tablodaki satr saysnn
renilmesi iin Count fonksiyonunun kullanlmas veya belli bir alandaki deerlerin ortalamasnn
hesaplanmas iin AVG (ortalama) fonksiyonu vb. Aggregate fonksiyonlarnn kullanld
durumlarda iki alternatifimiz vardr. Bu alternatiflerden birisi aadaki gibi SqlDataReader
nesnesinin ilgili SqlCommand nesnesi ile birlikte kullanlmasdr.

// ConnectionString tanmlanr.
string conStr="data source=BURKI;database=Work;integrated security=SSPI";
// Select sorgu cmlesi tanmlanr.
string selectText="SELECT COUNT(*) FROM Ogrenciler";
// SqlConnection nesnesi oluturulur ve alr.
SqlConnection con=new SqlConnection(conStr);
con.Open();
// SqlCommand nesnesi tanmlanr.
SqlCommand cmd=new SqlCommand(selectText,con);
// SqlDataReader nesnesi satr saysn almak amacyla oluturulur.
SqlDataReader dr=cmd.ExecuteReader(CommandBehavior.SingleResult);
// Elde edilen sonu okunur.
dr.Read();
// Hcre deeri ekrana yazdrlr.
Console.WriteLine("renci says "+dr[0].ToString());
// SqlDataReader ve SqlConnection kaynaklar kapatlr.
dr.Close();
con.Close();

Bu teknikte aggregate fonksiyonun altrlmasndan dnen deeri elde edebilmek iin


SqlDataReader nesnesi kullanlmtr. Ancak SqlCommand nesnesinin bu i iin tasarlanm olan
ExecuteScalar metodu yukardaki teknie gre daha yksek bir performans salamaktadr. nk
altrlmas srasnda bir SqlDataReader nesnesine ihtiya duymaz. Bu da SqlDataReader
nesnesinin kullanmak iin harcad sistem kaynaklarnn var olmamas anlamna gelmektedir.
Dolaysyla yukardaki rnekteki kodlar aadaki gibi kullanmak daha etkilidir.

// ConnectionString tanmlanr.
string conStr="data source=BURKI;database=Work;integrated security=SSPI";
// Select sorgu cmlesi tanmlanr.
string selectText="SELECT COUNT(*) FROM Ogrenciler";
// SqlConnection nesnesi oluturulur ve alr.
SqlConnection con=new SqlConnection(conStr);
con.Open();
// SqlCommand nesnesi tanmlanr ve ExecuteScalar ile sonu annda elde edilir.
SqlCommand cmd=new SqlCommand(selectText,con);
Console.WriteLine("Satr says "+cmd.ExecuteScalar().ToString());

Bu makalemizde, Command nesnelerini kullanrken bize performans, hz, gvenlik kod okunurluu
asndan avantajlar salayacak teknikleri incelemeye altk. Bir sonraki makalemizde grmek
dileiyle hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 1908


Burak Selim ENYURT
selim@bsenyurt.com

Self Referencing Relations ve


Recursive(Yinelemeli) Metodlar ( 14.03.2005 ) -
Ado.Net
oumuz altmz projelerde mdr,mdr yardmcs gibi ast st ilikisine sahip olan
organizasyonel yaplarla karlamzdr. rnein iletmelerin Genel Mdr den balayarak en alt
kademedeki personele kadar inen organizasyonel yaplar gibi. Burada sz konusu olan ilikiler
ounlukla pozisyonel bazdadr. Yani ok sayda personel birbirlerine pozisyonel bazda bamldr
ve bu bamllk en st pozisyondan en alt pozisyona kadar herkesi kapsar. Bu tarz bir sistemin
uygulama ortamnda canlandrlabilmesi iin pozisyonel ilikileri ifade edebilecek tablo yaplarna
bavurulur. zellikle pozisyonlar arasndaki ilikiyi kendi ierisinde referans edebilen tablolar bu
tarz ihtiyalarn karlanmas iin biilmi kaftandr. rnein aadaki tabloyu gz nne alalm.

Tabloda, X irketinin alan personelleri arasndaki pozisyonel hiyerariyi temsil eden bir yap
kullanlmtr. Dikkat edilecek olursa, her satrn Amiri alannn deeri yine tablo iinde yer alan bir
PersonelNo alann iaret etmektedir. Bu iliki Self Referencing Relations olarak adlandrlr. Elbette
bu tarz bir sistemde hiyerarinin nereden baladnn bir ekilde bilinmesi gerekir. nk tepeden
aaya doru inmek iin en st birimin dierlerinden tamamen benzersiz bir ekilde ifade
edilmesine ihtiya vardr. Buradaki gibi Amiri alannn deeri Null olan bir satr kimseye bal
deildir. Ancak kendisine bal olan bir organizasyonel hiyerari sz konusudur. te bunu
salayabilmek iin en tepede yer alacak satrn Amiri field nn deeri Null olarak belirlenmitir.
Tabloyu daha yakndan analiz edecek olursak aadaki hiyerarik yapnn oluturulabileceini
kolayca grrz.

www.bsenyurt.com Page 1909


te bu makalemizde yukarda grm olduumuz hiyerarik yapy bir TreeView kontrolnde nasl
ifade edebileceimizi incelemeye alacaz. Burada anahtar noktalar,Self Referencing
Relations oluturmak ve bu ilikileri Recursive (Yinelemeli) bir Metod ile uygulayabilmektir.
ncelikle Self Referencing Relation tablomuz zerinde grmeye alalm. rnein 5 numaral
PersonelNo deerine sahip satrmz ele alalm. Bu satrn Amiri field nn deeri 2 dir. Yani
organizasyonel yapda, 5 numaral satr aslnda 2 numaral satrn altnda yer almaktadr. Kald ki, 2
numaral satrda 1 numaral satrn altndadr. Bu ekilde tm satrlarn birbirleri ile olan
balantlarn tespit edebiliriz.

Self Referencing Relation zelliini salayan tablolarda bir satr(satrlarn) bal olduu
satrn yine bu tabloda var olmasn salamak veri tutarll (consistency) asndan
nemlidir.

Buradaki ilikiyi uygulamalarmzda tanmlamak iin DataRelation nesnelerini kullanabiliriz.


rnein;

DataRelation dr=new

www.bsenyurt.com Page 1910


DataRelation("self",ds.Tables[0].Columns["PersonelNo"],ds.Tables[0].Columns["Amiri"],false);

Bizim iin ikinci nemli nokta bu ilikiyi kullanacak olan Recursive(Yinelemeli) bir metodun
gelitirilmesidir. Yinelemeli metodumuzu gelitirirken tablo ierisindeki her bir satr ele alacak ve
bu satrlarn var ise alt satrlarna da bakacak bir algoritmay gz nne almamz gerekiyor.
rnein aadaki Console uygulamasn ele alalm.

class Worker
{
SqlConnection con=new SqlConnection("data source=BURKI;database=Veritabanim;integrated
security=SSPI");
SqlDataAdapter da;
DataSet ds;
DataRelation dr;

public void Baglan()


{
if(con.State==ConnectionState.Closed)
con.Open();
}

public void VeriCek()


{
da=new SqlDataAdapter("SELECT * FROM Kadro",con);
ds=new DataSet();
da.Fill(ds);
dr=new
DataRelation("self",ds.Tables[0].Columns["PersonelNo"],ds.Tables[0].Columns["Amiri"],false);
ds.Relations.Add(dr);
}
//Recursive metodumuz.
public void DetayiniAl(DataRow dr,string giris)
{
Console.WriteLine(giris+dr["Personel"].ToString());
foreach(DataRow drChild in dr.GetChildRows("self"))
{
DetayiniAl(drChild,giris+"...");
}
}

public void AgacOlustur()


{
foreach(DataRow dr in ds.Tables[0].Rows)
{
if(dr.IsNull("Amiri"))
{
DetayiniAl(dr,"");
}

www.bsenyurt.com Page 1911


}
}
}

class Class1
{
[STAThread]
static void Main(string[] args)
{
Worker wrk=new Worker();
wrk.Baglan();
wrk.VeriCek();
wrk.AgacOlustur();
}
}

Bu uygulamada basit olarak tablomuzdaki verileri ekiyor ve organizasyonel yapy hiyerarik


olarak elde ediyoruz. Aacmz oluturduumuz AgacOlustur metodu, DataTable ierisindeki tm
satrlar gezen bir foreach dngsn kullanyor. Hereyden nce bizim en tepedeki satr bir baka
deyile en stteki pozisyonu bulmamz gerekiyor. Tablo yapmzdan Amiri alannn deeri Null olan
satrn hiyerarinin tepesinde olmas gerektiini biliyoruz. Bu nedenle if koulu ile bu alan
buluyoruz. Ardndan bulduumuz satr DetayiniAl isimli Recursive(Yinelemeli) metodumuza
gnderiyoruz. Yinelemeli metodumuz gelen DataRow nesnesinin Child satrlarn gezen baka bir
foreach dngs kullanyor. Eer Child satrlar var ise yinelemeli metodumuz tekrardan arlyor.
Bu ilem tm satrlarn okunmas bitene kadar devam edecektir. Sonu itibariyle Console
uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

Gelelim, Windows uygulamamzda bu hiyerariyi nasl ekillendirebileceimize. zleyeceimiz yol


Console uygulamamzdaki ile tamamen ayndr. Tek fark bu kez bir DataRow a bal alt satrlar
alrken yinelemeli metodumuza parent node un (ki burada bir TreeNode nesnesidir) geiriliidir.
rnek uygulamay aada bulabilirsiniz. (Uygulamann almasn daha iyi anlayabilmek iin Trace
etmenizi neririm.) Burada zellike, child satrlarn hangi TreeNode nesnesine eklenmesi
gerektiinin tespiti son derece nemlidir. Dikkat ederseniz AgacOlustur metodumuzda ilk olarak
Amiri alannn deeri Null olan satr temsil edecek bir TreeNode nesnesi oluturulmu ve TreeView
kontrolne eklenmitir. Daha sonra yinelemeli metodumuza bu TreeNode ve o anki DataRow
nesneleri gnderilmitir. Bylece DetayiniAl metodu ierisinde child satrlarn hangi TreeNode
ierisine alnaca tespit edilebilir.

www.bsenyurt.com Page 1912


TreeView kullanm;

SqlConnection con=new SqlConnection("data source=BURKI;database=Veritabanim;integrated


security=SSPI");
SqlDataAdapter da;
DataSet ds;
DataRelation dr;

private void Baglan()


{
if(con.State==ConnectionState.Closed)
con.Open();
}

private void VeriCek()


{
da=new SqlDataAdapter("SELECT * FROM Kadro",con);
ds=new DataSet();
da.Fill(ds);
dr=new
DataRelation("self",ds.Tables[0].Columns["PersonelNo"],ds.Tables[0].Columns["Amiri"],false);
ds.Relations.Add(dr);
}

private void DetayiniAl(DataRow dr,TreeNode t)


{
foreach(DataRow drChild in dr.GetChildRows("self"))
{
TreeNode tnChild=new TreeNode(drChild["Personel"].ToString());
t.Nodes.Add(tnChild);
DetayiniAl(drChild,tnChild);
}
}

private void AgacOlustur()


{
foreach(DataRow dr in ds.Tables[0].Rows)
{
if(dr.IsNull("Amiri"))
{
TreeNode tn=new TreeNode(dr["Personel"].ToString());
treeView1.Nodes.Add(tn);
DetayiniAl(dr,tn);
}
}
}

private void Form1_Load(object sender, System.EventArgs e)


{

www.bsenyurt.com Page 1913


Baglan();
VeriCek();
AgacOlustur();
}

Uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

Bu makalemizde kendi satrlarn iaret eden satrlarn var olduu ilikileri tayan tablolarda, satr
arasndaki hiyerarik yapnn Recursive(Yinelemeli) metodlar ile uygulama ortamna nasl
aktarlabileceini incelemeye altk. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

rnek kodlar iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Balantsz Katmanda Concurrency Violation


Durumu ( 06.03.2005 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Balantsz katman nesneleri ile alrken karlaabileceimiz problemlerden bir tanesi gncelleme
ilemleri srasnda oluabilecek DBConcurrencyException istisnasdr. Bu makalemizde, bu hatann
frlatl nedenini inceleyecek ve alabileceimiz tedbirleri ele almaya alacaz. ncelikle istisnann
ne olduunu anlamak ile ie balayalm. Bir DataAdapter nesnesine ait Update metodu gncelleme
ilemleri iin Optimistic(iyimser) yaklam kullanan sql sorgularn altryorsa

www.bsenyurt.com Page 1914


DBConcurrencyException istisnasnn ortama frlatlmas, baka bir deyile Concurrency Violation
(e zamanl uyumsuzluk) durumunun olumas son derece doaldr.

Optimistic yaklam modeli, Pessimistic yaklam modelinin aksine


gncellenecek satrlar kilitlemez. Buda sunucunun kilit ama, takip ve kapatma
gibi ilemleri yapmamas dolaysyla performansnn artmas anlamna gelir.
zellikle balantsz katman mimarisinde kullanlan optimistic yaklam
modelinde tek sorun, gncelleme ilemlerini gerekletiren kullanclarn bu
ileri birbirlerinden habersiz ekilde yapmalar sonucu ortaya kabilecek
durumlardr.

rnein belli bir satra ait verileri gncellemek iin kullanabileceimiz aadaki Sql sorgusunu ele
alalm.

UPDATE MAILS SET AD=@AD,SOYAD=@SOYAD,EMAIL=@EMAIL WHERE ID=@ORGID AND


AD=@ORGAD AND SOYAD=@ORGSOYAD AND EMAIL=@ORGEMAIL

Sorgumuz basite, MAILS isimli veritabanndaki AD, SOYAD ve EMAIL alanlarnn deerlerini
gncellemektedir. Bunu yaparkende optimistic (iyimser) yaklamn kullanr. Bu nedenle, Where
koulunda tabloya ait primary key alan (ID) dahil olmak zere tm alanlar kullanlmaktadr.
Bylece tm alanlarn eletirme iin kullanld bir sorgu ortaya kar.

Optimistic yaklamda ele alnan yukardaki sorgu modeli iin Sql Server ve benzeri
veritaban sistemlerinde daha etkili yntemlerde vardr. rnein Sql
zerindetimestamp tipinden (yada uniqueIdentifier tipinden) alanlar kullanlabilir.
Timestamp trnden olan alanlar satr zerinde yaplacak herhangibir gncelleme ileme
sonrasnda sistem tarafndan otomatik olarak benzersiz bir karakter dizisi ile deitirilen
alanlardr. Bylece yukardaki sorgunun yapt iin aynsn aadaki gibide yapabiliriz.
(Buradaki Kontrol alan tipi timestamp tipindendir.

Update Mails Set Ad=@Ad,Soyad=@Soyad,Email=@Email Where


Id=@OrgId And Kontrol=@Kontrol

Bu ifadenin bize salad en byk avantaj elbetteki n sayda alan ieren bir tabloda
where ifadesinden sonra sadece iki alan kontrol ile (primary key ve timestamp alan)
Concurrency Violation durumunu irdeleyebilecek olmamzdr. Biz makalemizde daha uzun
olan yolu incelemeye alacaz. Lakin gerek hayat
modellerinde timestamp veyauniqueidentifier ve benzeri tipten alanlarn karlatrma
ilemi iin ele alnmas daha doru ve gl bir yaklam olacaktr.

Byle bir sorgunun neden olaca istisnai durumu anlayabilmek iin aadaki senaryoyu gz nne
almakta fayda olaca inancndaym. Senaryomuzda en az iki kullanc rol almaktadr. Bu
kullanclarmza A ve B takma isimlerini verdiimizi dnelim. Her iki kullancda database' den
MAILS tablosundaki verileri balantsz katmana DataAdapter snfna ait nesne rnei vastasyla
almaktadr.

www.bsenyurt.com Page 1915


A ve B verileri ektikten sonra, A kullancs herhangibir satr zerinde gncelleme ilemini uygular.
Bu durumda DataAdapter nesnesinin UpdateCommand zelliine karlk gelen SqlCommand
nesnesi, yukarda yazdmz sorguyu altracaktr. Bu sorguda, satrlarn orjinal deerleri ile
veritabanndaki halleri ayn olacandan gncelleme ilemi baarl bir ekilde gerekletirilecektir.
Lakin B kullancs u anda, A' nn gncellemi olduu veri kmesinin eski haline bakmaktadr. Eer
B kullancs, A kullancsnn biraz nce gncellemi olduu satr tekrar gncellemek isterse ne
olacaktr? te bu durumda, sorgu iindeki where kouluna giren alan deerlerinin balantsz
katmandaki orjinal halleri (yani DataRowVersion numaralandrcs tipinden Original olan
deerleri), veritabanndaki tabloda az nce gncelletirilmi olan alanlara ait yeni deerler ile
elemeyeceinden ilgili satr bulunamayacaktr. Bu da B kullancsnn satr update edememesine
neden olur. Bu noktada CLR, DbConcurrencyException trnden bir istisnay process iine
frlatacaktr. Dilerseniz bu hatay basit bir uygulama yardmyla elde etmeye alalm.
Uygulamamz imdilik sadece Update ilevini ele alacaktr. lk olarak basit bir windows uygulamas
aarak aadakine benzer bir form ekran oluturalm.

www.bsenyurt.com Page 1916


Uygulamamz aadaki field yapsna sahip olan ve Sql sunucusu zerinde barndrdmz MAILS
tablosunu kullanacaktr. Tablomuzdaki ID alan otomatik artan bir primary key olarak
tanmlanmtr.

imdide uygulama kodlarmz yazalm.

SqlConnection con;
SqlDataAdapter da;
DataSet ds;

/* SqlConnection nesnemizi oluturduumuz metodumuz. Bu metotda balant bilgisini App.Config


dosyasnda tuttuumuz connectionString isimli key' e ait value zelliinden alyoruz.*/
private void BaglantiHazirla()
{
try
{
con=new SqlConnection(ConfigurationSettings.AppSettings["connectionString"].ToString());
}
catch(SqlException hata)
{
MessageBox.Show(hata.Message);
}
}

/* Verileri ykleyen metodumuz parametre olarak ald string bilgiyi kullanan bir SqlDataAdapter
nesnesi oluturuyor. Daha sonra bu nesne yardmyla DataSet' imiz dolduruluyor. Son olarak
DataSet iindeki tablomuza ait primary key kolonu belirleniyor.*/
private void VerileriYukle(string sorguCumlesi)

www.bsenyurt.com Page 1917


{
BaglantiHazirla();
da=new SqlDataAdapter(sorguCumlesi,con);
ds=new DataSet();
da.Fill(ds);
ds.Tables[0].PrimaryKey=new DataColumn[]{ds.Tables[0].Columns["ID"]};
}

/* Veri ek balkl butona tklandnda, MAILS tablosundaki tm verileri ekeceimiz sorguyu


altracak VerileriYukle metodunu aryor ve sonu kmesini DataGrid kontrolmze balyoruz.
Ardndan eer SqlConnection nesnemiz ak ise kapatyoruz.*/
private void btnVeriCek_Click(object sender, System.EventArgs e)
{
VerileriYukle("SELECT * FROM MAILS");
dgVeriler.DataSource=ds.Tables[0];
if(con.State==ConnectionState.Open)
{
con.Close();
}
}

/* VeriGncelle metodu Update sorgusunu bizim tanmladmz SqlDataAdapter nesnesini


kullanarak gncelleme ilemini gerekletiriyor.*/
private void VeriGuncelle()
{
try
{
string guncellemeCumlesi="UPDATE MAILS SET
AD=@AD,SOYAD=@SOYAD,EMAIL=@EMAIL WHERE ID=@ORGID AND AD=@ORGAD AND
SOYAD=@ORGSOYAD AND EMAIL=@ORGEMAIL";
// Timestamp alan olduunda : Update Mails Set Ad=@Ad,Soyad=@Soyad,Email=@Email
Where Id=@ORGID AND KONTROL=@KONTROL
SqlCommand cmdUpdate=new SqlCommand(guncellemeCumlesi,con);
/* Sorgumuz iin gerekli parametreleri ekliyoruz. Parametre adlarn, veri tiplerini, boyutlarn
ve DataTable daki hangi alan source olarak alacaklarn belirliyoruz.*/
cmdUpdate.Parameters.Add("@AD",SqlDbType.NVarChar,50,"AD");
cmdUpdate.Parameters.Add("@SOYAD",SqlDbType.NVarChar,50,"SOYAD");
cmdUpdate.Parameters.Add("@EMAIL",SqlDbType.NVarChar,50,"EMAIL");

/* WHERE koulunda kullanlan parametreleri giriyoruz. Burada parametre deerlerimiz field'


larn orjinal deerleri olacak. Bunu salamak iin SourceVersion zelliine DataRowVersion
numaralandrcsnn Original deerini atyoruz.*/
cmdUpdate.Parameters.Add("@ORGID",SqlDbType.NVarChar,50,"ID");
cmdUpdate.Parameters["@ORGID"].SourceVersion=DataRowVersion.Original;
cmdUpdate.Parameters.Add("@ORGAD",SqlDbType.NVarChar,50,"AD");
cmdUpdate.Parameters["@ORGAD"].SourceVersion=DataRowVersion.Original;
cmdUpdate.Parameters.Add("@ORGSOYAD",SqlDbType.NVarChar,50,"SOYAD");
cmdUpdate.Parameters["@ORGSOYAD"].SourceVersion=DataRowVersion.Original;
cmdUpdate.Parameters.Add("@ORGEMAIL",SqlDbType.NVarChar,50,"EMAIL");

www.bsenyurt.com Page 1918


cmdUpdate.Parameters["@ORGEMAIL"].SourceVersion=DataRowVersion.Original;
// Where cmleciinden timestamp veya uniqueIdentifier kullanldnda yukarudaki parametre
tanmlamalar yerine sadece Kontrol alan iin tek bir parametre tanmlamasnn yaplmas yeterli
olacaktr.
// cmdUpdate.Parameters.Add("@KONTROL",SqlDbType.Timestamp,8,"KONTROL");
// cmdUpdate.Parameters["@KONTROL"].SourceVersion=DataRowVersion.Original;

da.UpdateCommand=cmdUpdate;

/* Son olarak Update metodunu altryoruz.*/


da.Update(ds);
}
catch(SqlException hata)
{
MessageBox.Show(hata.Message);
}
}

private void btnGuncelle_Click(object sender, System.EventArgs e)


{
VeriGuncelle();
}

Uygulamamzdan iki tane altrdmz ve rnein AD alan A ve SOYAD alan B olan satrlarn
deerlerini srasyla AL ile VEL olarak deitirdiimizi dnelim. Eer Gncelle butonuna tklarsak
ilemin baarl bir ekilde gerekletirildiini grrz.

www.bsenyurt.com Page 1919


imdi ikinci kullancmz ayn satrn verilerini deitirsin ve yine Gncelle butonuna bassn. Bu
durumda aadaki gibi bir istisna mesajn alrz.

www.bsenyurt.com Page 1920


Grld gibi ikinci kullanc update ilemini gerekletirmeye altnda Concurrency Violation
(e zamanl uyumsuzluk) durumu oluacaktr. Bu belirleyici olarak DBConcurrencyException
trnden bir istisnadr. Peki oluan bu istisnai durumun stesinden nasl gelebiliriz? lk akla gelen
yntem, istisna yakalandnda kullanclarn verilerin en gncel hallerini elde etmeleri konusunda
uyarlmalarn salamak olacaktr. Ancak balantsz katman zerinde alrken, ikinci kullanclar
bu rnekte olduu gibi tek bir satr gncellemek dnda yeni satr girileri, satr silmeler ve hatta
baka satr gncellemeleri gibi birden fazla sayda ilemi gerekletirmi olabilirler. Eer
gncelleme yaplan kod satrlarn istisna yakalama mekanizmalar ile izlemez ve
DbConcurrencyException hatasn yakalamazsak, kullancnn o ana kadar yapt tm deiiklikler
uygulamann istem d sonlanmas nedeni ile kaybolacaktr. Bu elbetteki istenen bir durum
deildir. Alternatif bir yol olarak, DataAdapter
nesnesininContinueUpdateOnError zelliine true deeri verilebilir. Bu durumda Update ilemi
srasnda oluacak olan hatalar gz ard edilecektir. Yani Concurrency' ye neden olan satrlar var
ise, bunlarn oluturduklar istisnalar ortama frlatlmayacaktr. rneimize bu durumu simle
edebileceimiz bir checkBox kontrol koyalm. Kullanc bu kutucuu iaretler ise update ilemi
srasnda oluacak olan Concurrency Violation (e zamanl uyumsuzluk) istisnas grmezden
gelinecektir. lgili metodumuza ait kodlarmz aadaki gibi deitirelim.

private void btnGuncelle_Click(object sender, System.EventArgs e)


{

www.bsenyurt.com Page 1921


if(chkContinueUpdateOnError.Checked==true)
{
da.ContinueUpdateOnError=true;
VeriGuncelle();
}
else if(chkContinueUpdateOnError.Checked==false)
{
da.ContinueUpdateOnError=false;
VeriGuncelle();
}
}

imdi, yine Concurrency olayna neden olacak ekilde deiiklikler yapalm. Yani her iki
kullancmzda verileri ektikten sonra, birinci kullancmz belli bir satr gncellesin. Ardndan ikinci
kullancmz ayn satr tekrar gncellemeye alsn. Bu durumda her hangibir istisna frlatlmaz ve
uygulama istem d bir ekilde sonlanmaz. Dahas, ikinci kullancnn yapt baka deiiklikler
eer var ise veritabanna baarl bir ekilde yanstlr. Ancak halen daha sorunlu olan satra ait
kullanc yeterli bilgiye sahip deildir. (Her ne kadar DataGrid bunu nlem iaretleriyle belirtsede
baka kontroller iin bu zellii salayamayabiliriz.) rnein kullancy hangi satrlarn Concurrency
Violation (e zamanl uyumsuzluk) istisnasna neden olduu konusunda daha detayl bir ekilde
uyarabiliriz. Burada DBConcurrencyException snfnn prototipi aadaki gibi olan Row zellii
iimize yarayabilir.

public DataRow Row {get; set;}

Bu zellik geriye hataya neden olan satr iaret edebilecek bir DataRow nesne rnei dndrr.
Bylece ilgili satra ait detayl bilgilere ulaabiliriz. Ancak, istisnai durum Concurrency' e neden olan
ilk satr grldnde devreye girmektedir. Dolaysyla ikinci kullancnn elinde Concurrency
istisnasna neden olacak birden fazla satr varsa tm bu satrlar yakalamak iin alternatif bir yol
uygulamamz gerekmektedir. Ado.Net mimarisinde yer alan DataSet, DataTable ve DataRow
snflarnn HasErrors zellikleri bu noktada bizim iimize yarayabilir.

public bool HasErrors {get;}

Bu zellik bool tipinden olup, herhangibir hata var ise geriye true deerini dndrecektir.
Concurrency durumunu bu hatalar arasnda sayabiliriz. imdi uygulama kodlarmza aadaki
metodu ekleyelim.

private void SonHaliAl()


{
string satirBilgi;
if(ds.Tables[0].HasErrors)
{
foreach(DataRow dr in ds.Tables[0].Rows)
{
if(dr.HasErrors)
{
satirBilgi=dr["AD"].ToString()+" "+dr["SOYAD"].ToString()+" Bakas tarafndan

www.bsenyurt.com Page 1922


deitirilmi. Satrn son halini elde etmek ister misiniz?";
if(MessageBox.Show(satirBilgi,"Son hali
al",MessageBoxButtons.YesNo,MessageBoxIcon.Question)==DialogResult.Yes)
{
SqlCommand cmdSonHaliAl=new SqlCommand("SELECT * FROM MAILS WHERE
ID="+(int)dr["ID"],con);
if(con.State==ConnectionState.Closed)
{
con.Open();
}
SqlDataReader
drGuncelSatir=cmdSonHaliAl.ExecuteReader(CommandBehavior.SingleRow);
drGuncelSatir.Read();
dr.BeginEdit();
dr["ID"]=drGuncelSatir["ID"];
dr["AD"]=drGuncelSatir["AD"];
dr["SOYAD"]=drGuncelSatir["SOYAD"];
dr["EMAIL"]=drGuncelSatir["EMAIL"];
// Timestamp veya uniqueIdentifier tipinden bir alan kullandysak (rneimizdeki
KONTROL alan gibi) onuda gncellememiz gerekir.
// dr["KONTROL"]=drGuncelSatir["KONTROL"];
dr.EndEdit();
con.Close();
}
}
}
ds.Tables[0].AcceptChanges();
}
}

Bu metod ile ilk olarak dataTable' n HasErrors zelliine bakyoruz. Eer bir hata var ise, her bir
satr taramaya balyoruz. Her bir satrn HasErrors zelliinin deerine bakarak hatal satrlar, bir
baka deyile Concurrency Violation (e zamanl uyumsuzluk)' a neden olanlar buluyoruz. Sonra,
hatal satrn primary key olduunu bildiimiz ID deerini kullanarak ilgili satrn birinci kullanc
tarafndan gncellenmi olan halini ekiyoruz. Bunu yaparkende SqlCommand ve SqlDataReader
nesnelerimizi kullanyoruz. Burada ID alan primary key olduundan ve benzersiz olarak satrlar
iaret edebildiinden tek satr dneceinden eminiz. Bu
nedenle CommandBehavior numaralandrcsnn SingleRowdeerini kullandk. Bu bize
performans asndan ekstra zaman kazandracaktr. Ardndan Concurrency Violation (e zamanl
uyumsuzluk) iinde kalan satrn alanlarna ait deerleri, asl veritabanndan ektiklerimiz ile
deitiriyoruz. te bu noktadan sonra eer kullanc tekrarda ayn satrlar update eder ise hi bir
problem ile karlamayacaktr. Nitekim, satrlarn DataRowVersion.Original deerleri
veritabanndaki en gncel halleri ile deitirilmi olacaktr. Dilersek, ikinci kullancnn o ana kadar
yapm olduu ve Concurrency Violation (e zamanl uyumsuzluk) altnda kalan deiikliklerin
tekrardan yazlmasn salayabiliriz. Tek yapmamz gereken Concurrency Violation (e zamanl
uyumsuzluk)' de kalan alanlarn o anki deerlerini bir ekilde saklamak, alanlarn gncel hallerini
ekerek orjinal deerleri yeni hallerine set etmek ve son olarak sakladmz alan deerlerini
tekrardan veritabanna gndermektir. Yazdmz SonHaliAl isimli metodu catch blou ierisinde
armaktayz. Nitekim Concurrency Violation (e zamanl uyumsuzluk) durumlar ancak
SqlDataAdapter nesnemizin Update metodunu ardktan sonra ortaya kan istisna ierisinde ele
alnabilir.

www.bsenyurt.com Page 1923


private void VeriGuncelle()
{
try
{
// dier kod satrlar
da.Update(ds);
}
catch(DBConcurrencyException)
{
SonHaliAl();
}
}

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde ksaca balantsz katmanda
meydana gelebilecek e zamanl akmalar nasl ele alabileceimizi incelemeye altk. Bir sonraki
makalemizde grnceye dek hoakaln.

Burak Selim ENYURT


selim@bsenyurt.com

RijndaelManaged Vastasyla
Encryption(ifreleme) ve Decryption(Deifre) (
23.02.2005 ) - Framework
Deerli Okurlarm, Merhabalar

Bu makalemizde, Rijndael Algoritmasn kullanan Managed tiplerden RijndaelManaged snf ile


ifreleme (encryption) ve deifre etme (decryption) ilemelerinin nasl gerekletirilebileceini
incelemeye alacaz. Konu ile ilgili rneklerimize gemeden nce .Net Framework ierisinde yer
alan Cryptography mimarisinde ksaca bahsetmekte yarar olduunu dnyorum. Aadaki ekil,
.Net Framework te System.Securtiy.Cryptograhpy isim alannda yer alan ifreleme hiyerarisini
gstermektedir. Framework mimarisinde ifreleme sistemi ilk olarak ana katmandan oluur. lk
katmanda taban snflar (base classes) yer alr. Bunlar SymmetricAlgorithm, AsymmetricAlgorithm
ve HashAlgorithm snflardr. Bu snflar kendisinden treyen ikinci katman snflar iin temel ve
ortak ifreleme zelliklerini ierirler.

www.bsenyurt.com Page 1924


SymmetricAlgorithm snfn kullanan ifreleme mekanizmalarnda herhangi bir anahtar ile
ifrelenen veriler, deifre edilmek istendiklerinde yine ayn anahtar kullanrlar. Bu zellikle internet
gibi herkesin kullanmna ak olan ortamlarda gvenlik asndan tehlike yaratabilir. Nitekim
anahtarn herhangi bir ekilde ele geirilmesi, ifrelenen verinin zlmesi iin yeterli olacaktr.
Dier yandan bu teknie gre gelitirilen algoritmalar hzl ve performansl alrlar.

SymmetricAlgorithm katmanndan treyen Encryption snflar ile uygulanan


ifreleme algoritmalarnda veriyi ifrelerken kullandmz key(anahtar) ve
IV(vektr) deerleri, ayn veriyi deifre ederken de gereklidir.

SymmetricAlgorithm yapsn kullanan ifreleme mimarilerinin neden olduu gvenlik sorununun


zm iin AsymmetrciAlgorithm taban snf (base class) gelitirilmitir. Bu mekanizmada veri

www.bsenyurt.com Page 1925


ifrelenecei zaman public bir anahtar kullanlr. Bu anahtarn herhangi bir ekilde ele geirilmesi,
verinin deifre edilebilmesi iin yeterli deildir. Nitekim verinin deifre (decryption) edilebilmesi iin
kar tarafn private bir anahtara gereksinimi vardr. Bu avantajnn yannda AsymmetricAlgroithm
mekanizmas SymmetricAlgorithm mekanizmasna gre daha yava almaktadr.

AsymmetricAlgorithm katmanndan treyen Encryption snflar ile uygulanan


ifreleme (encryption) algoritmalarnda veriyi ifrelerken public bir key
kullanrken, deifre (decryption) ilemi srasnda farkl olan private key
kullanlr.

Birinci katmanda yer alan taban snflar, abstract niteliktedir. Dolaysyla kendisinden treyen
ifreleme snflarnn iermesi ve uygulamas zorunlu olan yeler ierirler. Bildiiniz gibi abstract
snflardan nesne rnekleri retilemez. Ancak taban snflarn static Create metotlar yardmyla bu
snflar da ifreleme mekanizmalarnda kullanabiliriz. kinci katmanda yer alan snflar ise, zellikle
belirli ifrelme algoritmalarn iaret ederler. rnein bu gn ileyeceimiz Rijndael algoritmas 256
bitlik bir anahtar (key) ile ifreleme (deifre etme) salar. Buradaki snflar, taban snflardan (base
classes) tremitir ve abstract snflardr.

Asl ifreleme metotlarn ve yelerini bizim iin kullanl hale getiren snflar nc katmanda yer
alrlar. Burada dikkat edecek olursanz baz snflar ServiceProvider kelimesi ile biterler. Bu snflar
Windows un CryptoApi ktphanesini kullanan snflardr. Dier yandan Managed kelimesi ieren
snflar (rnein RijndaelManaged) zellikle .net iin gelitirilmi ynetimsel uyarlamalardr
(Managed Implementations). Buradaki snflar sealed olarak tanmlanmtr. Yani kendilerinden
tretme yaplamaz. Buna ramen eer istersek ikinci veya birinci katman snflarn kullanarak
kendi ifreleme algoritma snflarmz veya uyarlamalarmz gelitirebiliriz. Peki bir veri kmesini
ifrelemek iin yukardaki katmanlar ve ieriklerini nasl kullanabiliriz. Bu makalemizde biz rnek
olarak Rijndael algoritmasn kullanan iki rnek gelitireceiz. .Net ierisinde verileri ifrelemek iin
izleyeceimiz yolda anahtar nokta CryptoStream snfdr. Bu snfa ait nesne rnekleri yardmyla
verileri stream bazl olarak, istenen algoritmaya gre ifreleyebilir ya da deifre edebiliriz.
CryptoStream snfndan bir nesne rneini aadaki yapc metot (constructor) yardmyla
oluturabiliriz.

public CryptoStream(Stream stream, ICryptoTransform transform, CryptoStreamMode mode);

Bu metodun ilk parametresine dikkat edecek olursanz bir Stream nesnesidir. CryptoStream snf
ifrelenecek veya deifre edilecek verilerin ilenmesi srasnda Stream nesnelerini kullanlr.
Dolaysyla bellek zerinde tutulan verileri, fiziki dosyalarda tutulan verileri veya network zerinden
akan verileri ilgili stream nesneleri yardmyla (MemoryStream, FileStream, NetworkStream vb...)
CrpytoStream snfna ait bir nesne rneine aktarabiliriz. kinci parametre ise Stream zerindeki
verinin hangi algoritma ile ifreleneceini (deifre edileceini) belirlemek zere kullanlr. Bu
parametre ICryptoTransform ara yz tipinden bir nesne rneidir. nc parametre ise Stream e
yazma veya stream den okuma yaplacan belirtir. Stream zerindeki veriyi ifreleyeceimiz
zaman nc parametre Write deerini alrken, deifre ilemlerinde Read deerini alr. Kark gibi
grnmesine ramen rneklerimizden de greceiniz gibi, ifreleme(deifre etme) ilemleri
sanld kadar zor deildir. Dilerseniz vakit kaybetmeden rneklerimize geelim. lk rneimizde
metin tabanl bir dosya ieriini FileStream nesnesinden faydalanarak okuyor ve CyrptoStream
snfna ait nesne rnei yardmyla ifreleyerek bir dosyaya yazyoruz. Daha sona ise ifrelenen bu
dosyay tekrardan zyoruz.

using System;
using System.IO;

www.bsenyurt.com Page 1926


using System.Security.Cryptography;

namespace CryptoStreamS1
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
#region Dosya ifrelemesi (Rijndael algoritmas ile)

// lk olarak ifrelemek istediimiz dosya iin bir stream oluturuyoruz.


FileStream fs=new
FileStream(@"SifreliDosya.txt",FileMode.OpenOrCreate,FileAccess.Write);

/* Kullanacamz ifreleme algoritmasn uygulatabileceimiz managed Rijndael snfna ait


nesne rneimizi tanmlyoruz. ifreleme algoritmas olarak Rijndael tekniini kullanyoruz. */
RijndaelManaged rm=new RijndaelManaged();
rm.GenerateKey(); // Aalgoritma iin gerekli Key retiliyor.

/* imdi algoritma iin gerekli key ve vektr deerlerini retiyoruz. Burada kullanlan
ifreleme algoritmas simetrik yapda olduundan ifrelenen verinin alabilmesi iin (decrypting)
ayn key ve vektr deerine ihtiyacmz var. Bu nedenle bunlar bir byte dizisinde tutuyoruz.*/

// Elde ettiimiz key deerini bir byte dizisine aktaryoruz.


byte[] k=new byte[rm.Key.Length];
for(int i=0;i<rm.Key.Length;i++)
{
Console.Write(rm.Key[i]);
k[i]=rm.Key[i];
}

Console.WriteLine();

rm.GenerateIV(); // Algoritma iin gerekli IV vektr deeri retiliyor.


byte[] v=new byte[rm.IV.Length];

// Elde ettiimiz Vektr deerini bir byte dizisine aktaryoruz.


for(int i=0;i<rm.IV.Length;i++)
{
Console.Write(rm.IV[i]);
v[i]=rm.IV[i];
}

Console.WriteLine();

/* Belirlediimiz ifreleme algoritmasn kullanarak, stream zerinde ifrelemeyi yapacak


CryptoStream nesnemizi oluturuyoruz. ifrelemeyi oluturmak iin RijndaelManaged snfndan
rneklendirdiimiz nesnemizin CreateEncyrptor metodunu kullanyoruz. Oluturulan ifreli

www.bsenyurt.com Page 1927


dkman ilgili stream e yazmak istediimizdenCryptoStreamMode olarak Write deerini
seiyoruz.*/
CryptoStream cs=new CryptoStream(fs,rm.CreateEncryptor(),CryptoStreamMode.Write);

/*imdi ifrelenecek olan byte dizisini almak zere dosyamz iin bir akm oluturuyoruz.
Nitekim CryptoStream in aada kullanlan ar yklenmi versiyonu ilk parametre olarak
ifrelenecek veri yapsn bir byte dizisi halinde alyor.*/
FileStream fs2=new FileStream(@"Dosya.txt",FileMode.Open);
// dosyann ieriini byte dizisine aktaryoruz.
byte[] veriler=new byte[fs2.Length];
fs2.Read(veriler,0,(int)fs2.Length);

// CryptoStream snfnn write metodu ile dosya.txt yi okuduumuz byte dizisinin ieriini
fs2 ile belirttiimiz stream e yazyoruz.
cs.Write(veriler,0,veriler.Length);
fs2.Close();
cs.Close();
#endregion

#region ifrelenmi dosyann rnek olarak ilk satrnn decrypt edilerek okunmas.

/* Bu kez ilemleri tersten yapyoruz. lk olarak ifrelenmi ve decrypt edilmek istenen


stream nesnesinin oluturuyoruz. Ardndan bu stream deki veriye Rijndael alogirtmasn
uygulayarak Decrypting yapyoruz. */
FileStream fsSifreliDosya=new
FileStream(@"SifreliDosya.txt",FileMode.Open,FileAccess.Read);
RijndaelManaged rm2=new RijndaelManaged();
//simetrik algoritma kullandmz iin decrypting iinde ayn key ve vektr deerlerini
kullanmamz gerekiyor.
rm2.Key=k;
rm2.IV=v;
CryptoStream cs2=new
CryptoStream(fsSifreliDosya,rm2.CreateDecryptor(),CryptoStreamMode.Read);
StreamReader sr=new StreamReader(cs2);
string satir=sr.ReadLine();
Console.WriteLine(satir);
#endregion
}
}
}

Uygulamay altrdmzda orijinal ierikli dosyann aadaki gibi ifrelendiini grrz.

www.bsenyurt.com Page 1928


kinci rneimizde ise, MemoryStream nesnesinden yararlanacaz. Bu kez, bir veri tablosundan
ektiimiz belli bir alan bellek zerinden ifreliyor ve daha sonra ifrelenen verinin orijinal ieriini
elde edecek ekilde deifre ilemini uyguluyoruz.

using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Security.Cryptography;

namespace CryptoStreamS2
{
class Kriptografi2
{
[STAThread]
static void Main(string[] args)
{
#region verinin ifrelenmesi
/* ncelikle ifrelemek istediimiz veriyi elde ediyoruz. rnek olarak SQL Sunucusundaki
Ogrenciler tablosundan belirli bir alan aldk. */
SqlConnection con=new SqlConnection("data source=BURKI;database=Work;integrated
security=SSPI");
SqlCommand cmd=new SqlCommand("SELECT AD FROM Ogrenciler WHERE
OGRENCINO=1",con);
con.Open();
string sifrelenecekVeri=cmd.ExecuteScalar().ToString();
con.Close();

www.bsenyurt.com Page 1929


/* ifrelenecek verinin hereyden nce bir byte dizisi olarak ele alnmas gerekiyor.*/
byte[] sv=new byte[sifrelenecekVeri.Length];
for(int i=0;i<sv.Length;i++)
{
sv[i]=(byte)sifrelenecekVeri[i];
}

/* ifrelenecek veriyi bellee yazacaz. Bu nedenle MemoryStream snf tipinden bir


nesne rnei oluturduk*/
MemoryStream ms=new MemoryStream();
/* ifreleme algoritmas olarak Rijnadel tekniini salayan Managed nesne rneimizi
oluturuyoruz.*/
System.Security.Cryptography.RijndaelManaged rm=new RijndaelManaged();

/* ifreleme iin gerekli anahtar ve vektr deerlerini elde ediyoruz.*/


rm.GenerateKey();
rm.GenerateIV();

/* RijndaelManaged nesnesi tarafndan retilen anahtar ve vektr deerlerini byte


dizilerine alyoruz. Nitekim kar tarafn ifrelenen veriyi zebilmesi iin bu anahtar ve vektr
deerlerinin aynlarna ihtiyalar olacaktr.*/
byte[] anahtar=rm.Key;
byte[] vektor=rm.IV;

/* Veriyi belirttiimiz algoritmaya gre ifreleyerek parametre olarak verilen stream e ki


burada MemoryStream e yazmak iin CryptoStream snfmzdan nesne rneimizi oluturuyoruz.*/
CryptoStream cs=new
CryptoStream(ms,rm.CreateEncryptor(anahtar,vektor),CryptoStreamMode.Write);
/* Veriyi ifreleyerek bellee yazyoruz. Bandan sonuna kadar.*/
cs.Write(sv,0,sv.Length);
cs.FlushFinalBlock();

Console.Write("Verinin ifrelenen hali ");


byte[] icerik=ms.ToArray(); /* Bellee yazdmz ifrelenmi veriyi bir byte dizisine alarak
okuyor ve ekrana yazdryoruz.*/
for(int i=0;i<icerik.Length;i++)
{
Console.Write((char)icerik[i]);
}
Console.WriteLine();
#endregion

#region ifrelenen verinin zmlenmesi


/* Bellekte tutulan icerik deerini yani ifrelenmi olan veriyi parametre alan stream
nesnemizi oluuturuyoruz.*/
MemoryStream msCoz=new MemoryStream(icerik);
RijndaelManaged rmCoz=new RijndaelManaged(); // Rijndael algoritmasn kullanarak
ifrelenen veriyi zecek olan provider nesnemizi tanmlyoruz.*/
/* SymmetricAlgorithm sz konusu olduundan RijndaelManaged snfna ait nesne

www.bsenyurt.com Page 1930


rneinin decryption ilemi iin encrypt te kullanlan key ve IV deerlerine ihtiyacm var.*/
rmCoz.Key=anahtar;
rmCoz.IV=vektor;
/* Bu kez CryptoStream nesnemiz stream den okuduu veri zerinde Decypting ilemini
gerekletirecek. Bu nedenle Rijndael nesne rneimizin CreateDecryptor metodunu
aryoruz.*/
CryptoStream csCoz=new
CryptoStream(msCoz,rmCoz.CreateDecryptor(anahtar,vektor),CryptoStreamMode.Read);
byte[] cozulen=new byte[ms.Length]; // zlen veriyi tutacak bir byte dizisi
oluturuyoruz.
csCoz.Read(cozulen,0,icerik.Length); // ifrelenen veriyi zmleyerek okuyoruz.
Console.Write("ifrelenen verinin zlm hali ");
/* zmlenmi veriyi son olarak ekrana yazdryoruz.*/
for(int i=0;i<cozulen.Length;i++)
{
Console.Write((char)cozulen[i]);
}
Console.ReadLine();
#endregion
}
}
}

Uygulamamz arka arkaya altrdmzda aadakine benzer sonular alrz. Dikkat ederseniz
deifre edilen veri her seferinde ayn olmasna ramen, ifrelenen veri ierii bir birlerinden
farkldr.

Bu makalemizde ksaca Rijndael algoritmasn kullanan RijndaelManaged snf ile ifreleme ve


deifre ilemlerini incelemeye altk. lerleyen makalelerimizde, AsymmetricAlgorithm tekniininin

www.bsenyurt.com Page 1931


nasl uygulanabileceini incelemeye alacaz. Bir sonraki makalemizde grnceye dek hepinize
mutlu gnler dilerim.

rnek kodlar iin tklayn.

Burak Selim ENYURT


selim@bsenyurt.com

Caching Mekanizmasn Anlamak - 2 (


07.02.2005 ) - Asp.Net
Deerli Okurlarm, Merhabalar

Hatrlayacanz gibi bir nceki makalemizde, web uygulamalarnda caching mekanizmasn


incelemeye balam ve ara bellee alma tekniklerinden Output Cache yapsn incelemitik. Output
Cache tekniinde bir sayfann tamamnn HTML ierii ara bellee alnmaktayd. Oysa ou zaman
sayfamzda yer alan belirli veri kmelerinin ara bellekte tutulmasn isteyebiliriz. rnein, bir
alveri sitesinin pek ok ksm dinamik olarak deiebilirken sat yaplan rnlerin yer ald
kategori listeleri ok sk deimez. Hatta uzun sreler boyunca ayn kalabilirler. te byle bir
durumda sayfann tamamn ara bellee almak yerine sadece kategori listesini sunan veri kmesini
ara bellee almak daha mantkldr. Data Caching olarak adlandrlan bu teknikte ounlukla veri
kmeleri ara bellee alnr. Data Caching tekniinde verileri ara bellee almak
iinSystem.Web.Caching isim alannda yer alan Cache snf ve yeleri kullanlmaktadr.

Cache snf sealed tipinde olup kendisinden tretme yaplmasna izin vermez. Bununla
birlikte, her bir Application Domain iin yanlz bir Cache nesne rnei oluturulur ve
kullanlr.

Cache snfna bir veri kmesini eklemek bu veriyi ara bellee almak demektir. Bunun iin aadaki
4 ar yklenmi prototipe sahip olan ve bize pek ok imkan salayanInsert metodunu
kullanabiliriz.

public void Insert(string key,object value);

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

public void Insert(string key,object value,CacheDependency dependencies,DateTime absoluteExpi


ration,TimeSpan slidingExpiration);

public void Insert(string key, object value, CacheDependency dependencies, DateTime absoluteE
xpiration,TimeSpan slidingExpiration, CacheItemPriority priority, CacheItemRemovedCallbackonR
emoveCallback);

Insert metodu ara bellee alnan veri kmesinin durumuna ilikin olarak eitli imkanlar sunar.
rnein veri kmesinin ara bellekte ne kadar sre ile tutulaca veya ne kadar sre bu veriye

www.bsenyurt.com Page 1932


eriilmez ise ara bellekten silineceinin belirlenmesi vb...imdi bu imkanlar test etmeden nce
basit olarak bir veri kmesini Cache nesnesine nasl ekleyeceimizi inceleyeceiz.

private SqlConnection con;


private SqlCommand cmd;
private SqlDataAdapter da;
private DataTable dt;

/*Categories tablosundan CategoryName alannn deerlerini alyoruz ve bir DataTable nesnesine


aktaryoruz.*/
private void KategorileriAl()
{
con=new SqlConnection("data source=BURKI;initial catalog=Northwind;integrated
security=SSPI");
cmd=new SqlCommand("SELECT DISTINCT CategoryName FROM Categories",con);
da=new SqlDataAdapter(cmd);
dt=new DataTable();
da.Fill(dt);
}

private void Page_Load(object sender, System.EventArgs e)


{
//Gncel saat bilgisini label kontrolne yazdryoruz.
Label1.Text=DateTime.Now.ToLongTimeString();
/*Eer ara bellekte kategori isimli Cache nesnesinin ierii null ise bu durumda verileri ekiyoruz
ve DataTable ieriini ara bellee Cache snfnn Insert metodu ile alyoruz.*/
if(Cache["kategori"]==null)
{
KategorileriAl();
Cache.Insert("kategori",dt,null,DateTime.Now.AddMinutes(5),Cache.NoSlidingExpir
ation); /* Veriler 5 dakika sreyle ara bellekte saklanacak daha sonra ise silinecektir.*/
}
/*DataGrid kontrolne veri kayna olarak ara bellekteki kategori isimli Cache nesnesinin
ieriini veriyoruz. Bunu yaparken uygun tre dntrme ilemini yapyoruz.*/
DataGrid1.DataSource=(DataTable)Cache["kategori"];
DataGrid1.DataBind();
}

Uygulamamzda, Northwind veritabannda yer alan Categories isimli tablodan CategoryName


deerlerini ekiyoruz ve elde ettiimiz DataTable nesnesini 5 dakika sreyle ara bellekte tutumak
zere Insert metodu ile Cache nesnesine ekliyoruz. Uygulamay ilk altrmzda aadaki ekran
grntsn elde ederiz.

www.bsenyurt.com Page 1933


Sayfay yenilediimizde veya baka bir tarayc penceresinde tekrardan talep ettiimizde srenin
dzenli olarak deitiini grrz. imdi 5 dakika dolmadan tablodaki verilerde, rnein Beverages
alannn deerini [Beverages] olarak deitirdiimizi dnelim.

Daha sonra sayfay tekrar aralm.

www.bsenyurt.com Page 1934


Grld gibi Beverages deerini deitirmemize ramen yaplan deiiklikler uygulamamza
yansmamtr. Bu, verinin ara bellekten Cache nesnesi vastasyla ekildiinin bir ispatdr. Veri ara
bellee alndktan 5 dakika sonra ayn sayfa tekrar talep edilir ise bu kez verinin gncel hali ekrana
gelecektir. Burada veriyi Cache nesnesine alrken kullandmz Insert metodunda Absolute
Expiration (Tam Sre Sonu) zaman belirlenmitir. Bu sre, verinin ara bellekten kesin olarak ne
zaman atlacan sylemektedir. Bununla birlikte dilersek ara bellekte bulunan veri kmesine olan
eriim sklna gre bir Sliding Expiration ( Kayan Sre Sonu ) sreside belirleyebiliriz. Buna
gre,

Ara bellekteki verilere belirtilen Sliding Expiration ile belirtilen sre zarfnda eriilmez
ise bu sre sonunda bellekten atlrlar. Eer sre zarf iinde ara bellekteki verilere srekli
eriiliyorsa Sliding Expiration sresi gese dahi veriler ara bellekten atlmaz ve
durumlarn korurlar.

Srekli bellekte kalmak deyimi tabiki sistem kaynaklar azalp ara bellek verileri otomatik olarak
atlnca veya web sunucusu herhangibir neden ile restart olunca geerli deildir. imdi dilerseniz
Sliding Expiration durumunu incelemeye alalm. Bunun iin tek yapmamz gereken rneimizdeki
Insert metodunu aadaki ile deitirmek olacaktr.

Cache.Insert("kategori",dt,null,Cache.NoAbsoluteExpiration,TimeSpan.FromMinutes(3));

Olay daha iyi anlayabilmek iin aadaki ekli inceleyebiliriz.

www.bsenyurt.com Page 1935


Sayfa ilk talep edilip veriler ara bellea alndnda, Sliding Expiration sresinin 5 dakika ilerisini
gsterecek ekilde ayarlandn dnelim. Bu sre dolmadan nce ara bellekteki veri tekrardan
talep edilirse, Cache nesnesinin ieriinin boaltlma sresi ekilden de grld gibi ilerki bir
zamana (o anki andan 5 dakika sonrasna) sarkacaktr.

Insert metodunun parametrelerine dikkat edecek olursanz, ara bellekteki verilerin


durumlarnn CacheDependency snfna ait nesne rnekleri ile baka bir nesneye bal
olabileceini grrsnz. Bu bamllkta ounlukla fiziki dosyalar gz nne alnr. rnein, bir
XML dosyasndaki veriyi ara bellee alarak kullandmz dnelim. Bu veriler pekala gncel haber
balklarn veya bir alveri sitesindeki rnlerin kategorilerini gsterebilir. XML dosyasnda
meydana gelecek olan gncellemeleri annda ara bellee yanstmak iin, Cache nesnesini bu XML
dosyasna baml hale getirebiliriz. imdi bunun nasl yaplabileceini incelemeye alalm.
Yukarda gelitirdiimiz rneimizdeki kodlarmz aadaki gibi deitirelim.

Kategoriler.xml dosyasnn ierii;

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


<Kategoriler>
<Tipi>Muzik CD</Tipi>
<Tipi>Kitap</Tipi>
<Tipi>Film DVD</Tipi>
<Tipi>Muzik DVD</Tipi>
<Tipi>Elektronik Eyalar</Tipi>
<Tipi>Bilgisayar</Tipi>
<Tipi>Laptop</Tipi>
</Kategoriler>

default.aspx

private SqlConnection con;


private SqlCommand cmd;
private SqlDataAdapter da;
private DataTable dt;
private DataSet ds;

www.bsenyurt.com Page 1936


/*KategoriAlXML metodu Kategoriler.xml dosyas iinden verileri alr ve DataSet e ykler.*/
private void KategoriAlXML()
{
ds=new DataSet();
ds.ReadXml(Server.MapPath("Kategoriler.xml"));
}

private void Page_Load(object sender, System.EventArgs e)


{
//Gncel saat bilgisini label kontrolne yazdiriyoruz.
Label1.Text=DateTime.Now.ToLongTimeString();
if(Cache["kategori"]==null)
{
KategoriAlXML();
/* Cache nesnesine DataSet ierisindeki xml dosyasndan okunan ierie ait veri kmesi
yklenir. Bu ykleme ilemi yaplrken bir CacheDependency nesnesi ile Cache nesnesinin ieriinin
gncellii belirtilen XML dosyasna balanr.*/
Cache.Insert("kategori",ds.Tables[0],new
CacheDependency(Server.MapPath("Kategoriler.xml")));
}
/*DataGrid kontrolne veri kaynagi olarak ara bellekteki kategori isimli Cache nesnesinin
ierigini veriyoruz. Bunu yaparken uygun tre dnstrme islemini yapiyoruz.*/
DataGrid1.DataSource=(DataTable)Cache["kategori"];
DataGrid1.DataBind();
}

Burada, Cache nesnesinin ieriinin durumunu xml dosyamza balayabilmek iin


CacheDependency snfna ait bir nesne rnei oluturulmutur. Burada CacheDependency snfna
ait nesne rnei oluturulurken yapc metoda xml dosyasnn sanal adresi atanmtr.

new CacheDependency(Server.MapPath("Kategoriler.xml"))

Uygulamamz altrdmzda ilk olarak aadaki ekran grntsn elde ederiz.

www.bsenyurt.com Page 1937


imdi Kategoriler.xml dosyasnn ieriinde deiiklik yapalm ve bu deiiklikleri kaydedelim.
rnein aadaki gibi bir ka elemann bilgisini detirip yeni bir eleman ekleyelim.

Bu deiikliklerden sonra sayfay tekrardan talep edersek, Cache nesnesinin ierdii verilerin son
yaplan gncellemelere gre yenilendiini grrz. Cache nesnesindeki veriyi bir dosyaya
yukardaki gibi baml hale getirdiimizde, sayfaya yaplan her talepde dosyann ieriinin deiip
deimedii kontrol edilir. Eer bir deiiklik var ise, Cache nesnesinin ierdii veri ara bellekten
atlr. Biz uygulamamzda Cache nesnesini null olup olmadna gre ykleme yaptmz iin
dosyadaki gncelleme sonucu verinin bu son halini ara bellee alm ve DataGrid ieriini yenilemi
oluruz.

www.bsenyurt.com Page 1938


Asp.Net 2.0 da bir Cache nesnesinin dorudan Sql Server zerindeki bir tabloya baml
hale getirilebilmesi ve dolaysyla veritaban iindeki bir tabloda meydan gelecek
deiiklilerin Cache nesnesine annda yanstlabilmesi iinde SqlCacheDependency snfna
ait nesne rneklerinin kullanlabilecei ngrlmektedir. (* Bu durumu gelecek grsel
derslerimizden birisinde incelemeye alacaz.)

Cache nesnelerinin bellekten atlmas zamana, dosyaya balanabilecei gibi, sistem kaynaklarnn
azalmas durumunda da gerekleen bir olaydr. Sistem kaynaklarnn azalmas ve ara bellekteki
nesnelerin atlmas gerektii durumlarda Cache nesnelerinin sahip olduu ncelikler gz nne
alnr. Her ne sebep ile olursa olsun bir Cache nesnesinin ierii ara bellekten atldnda otomatik
olarak almasn istediimiz metodlar bildirebiliriz. Yani CallBack metod tekniini Cache nesneleri
iinde kullanabiliriz. rnein ara bellekte tutulan bir nesnenin zaman amna uramas nedeni ile
silindiinde otomatik olarak callback metodu devreye girerek gncel halinin tekrardan ara bellee
alnmas salanabilir. Ya da Cache nesnesi Remove metodu ile aka ara bellekten atld
durumlarda CallBack metodlarn altrabiliriz. Burada bir CallBack metodunun arlabilmesi
iin,CacheItemRemovedReason temsilcisi (delegate) tipinden bir nesne rneinden faydalanlr.
CacheItemRemovedReason temsilcisi aadaki prototipe uyan metodlar iaret edebilir.

public delegate void CacheItemRemovedCallback(string anahtar,object deger,


CacheItemRemovedReason sebep);

anahtar parametresi Cache nesnesinin key deerine karlk gelir. deger parametresi ise ilgili Cache
nesnesinin tad veriye sahiptir. Son parametre
ise CacheItemRemovedReasonnumaralandrcs (enum sabiti) tipinden bir deerdir ve CallBack
metodunun arlma nedenini bir baka deyile Cache nesnesinin hangi sebepten dolay ara
bellekten atldnn belirlenmesinde kullanlr. CacheItemRemovedReason numaralandrcsnn
sahip olduu deerler aadaki tabloda belirtilmektedir.

www.bsenyurt.com Page 1939


CacheItemRemovedReason Numaralandrc Aklama
Deeri

DependencyChanged Herhangibir bamllk nedeni ile Cache


nesnesinin ierii ara bellekten atlmtr.
rnein Cache nesnesine baladmz XML
dosyasnda yaplan bir deiiklik buna neden
olabilir.

Expired Cache nesnesinin ierii zaman amlar nedeni


ile ara bellekten atlmtr.

Removed Cache nesnesinin ierii Remove metodu ile


aka ara bellekten atlmtr. Yani programatik
olarak Cache nesnesinin Remove metodu ilgili
eye uygulanmtr.

Underused Sistem kaynaklarnn azalmas sonucunda web


sunucusu, Cache nesnelerinin ieriini sahip
olduklar nem sralarna gre ara bellekten
atmaya balamtr.

imdi CallBack tekniinin nasl uygulandn basit bir rnek ile incelemeye alalm.

private CacheItemRemovedCallback delCallBack=null;


private SqlConnection con;
private SqlCommand cmd;
private SqlDataAdapter da;
private DataTable dt;
private static string m_Sebep;
private static bool m_Durum=false;

private void KategorileriAl()


{
con=new SqlConnection("data source=BURKI;initial catalog=Northwind;integrated
security=SSPI");
cmd=new SqlCommand("SELECT DISTINCT CategoryName FROM Categories",con);
da=new SqlDataAdapter(cmd);
dt=new DataTable();
da.Fill(dt);
}

private void GeriBildirimMetodu(string anahtar,object deger,CacheItemRemovedReason


sebep)
{
m_Sebep=sebep.ToString();
m_Durum=true;

www.bsenyurt.com Page 1940


}
private void btnRemove_Click(object sender, System.EventArgs e)
{
if(Cache["Nesne1"]!=null)
{
Cache.Remove("Nesne1");
}
}
private void btnCacheEkle_Click(object sender, System.EventArgs e)
{
delCallBack=new CacheItemRemovedCallback(this.GeriBildirimMetodu);
if(Cache["Nesne1"]==null)
{
KategorileriAl();
Cache.Insert("Nesne1",dt,null,DateTime.Now.AddSeconds(10),Cache.NoSlidingExpiration,Cac
heItemPriority.High,delCallBack);
m_Durum=false;
}
}
private void WebForm1_PreRender(object sender, System.EventArgs e)
{
DataGrid1.DataSource=Cache["Nesne1"];
DataGrid1.DataBind();
if(m_Durum)
lblDurum.Text=m_Sebep;
else
lblDurum.Text="";
}

Yukardaki rnekte, Cache nesnesine DataTable ieriini eklerken Insert metodunun aadaki
versiyonu kullanlmtr.

Cache.Insert("Nesne1",dt,null,DateTime.Now.AddSeconds(10),Cache.NoSlidingExpiration,CacheIte
mPriority.High,delCallBack);

Burada delCallBack, CallBack metodumuz olan GeriBildirimMetodunu iaret


eden CacheItemRemovedCallback tipindeki temsilcimidir. Kullanc Remove ilemini
gerekletirdiinde veya Cache nesnesi zaman am nedeni ile ara bellekten atldnda, geri
bildirim metodu alacaktr. rneimizi altrdmzda ve 10 saniyelik zaman am sresi
dolmadan Ekle ve daha sonra kart balkl butonlara tkladmzda aadaki ekran grntsn
elde ederiz.

www.bsenyurt.com Page 1941


Eer 10 saniye sresi dolduktan sonra kart balkl butona basarsak Remove metodu
altrlmayacak ancak geri bildirim metodumuz alarak nesnenin ara bellekten atlma nedeni
Expired olarak deiecektir.

CallBack tekniinin uygulann daha iyi kavrayabilmek iin, rnekleri debug modunda altrp
breakpoint ler vastsayla kodlar izlemenizi neririm. Bylece geldik bir makalemizin daha sonuna.
Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

rnek uygulama iin tklayn.

Burak Selim ENYURT

selim@bsenyurt.com

Caching Mekanizmasn Anlamak - 1 (


21.01.2005 ) - Asp.Net
Deerli Okurlarm, Merhabalar.

Bu makalemiz ile birlikte, web sayfalarnn istemcilere daha hzl bir ekilde ulatrlmasnda
kullanlan tekniklerden birisi olan Caching (Ara Bellee Alma) mekanizmasn incelemeye
balyacaz. Akllca kullanld takdirde web uygulamalarnda istemcilere nazaran greceli olarak
performans artna neden olan Caching (Ara Bellee Alma) mekanizmas, teorik olarak bir web
sayfasnn tamamnn ya da bir parasnn ara bellee alnarak belli bir sre boyunca burada
tutulmas prensibini temel alarak alr. Asp.Net uygulamalar sz konusu olduunda bir sayfann
tamamn, belli bir veri kmesini veya sayfa zerindeki herhangibir kontrol ara bellee alabiliriz.
Buna gre Asp.Net uygulamalarndaki Caching (Ara Bellee Alma) mekanizmas aadaki farkl
teknii destekler.

Asp.Net Uygulamalar in Caching (Ara Bellee Alma)


Teknikleri

www.bsenyurt.com Page 1942


1 - Output Caching ( ktnn Ara Bellee Alnmas )

2 - Data Caching ( Verilerin Ara Bellee Alnmas )

3 - Fragment Caching ( Paralarn Ara Bellee Alnmas )

Output Caching tekniinde, bir aspx sayfasnn tm ierii ara bellee alnr ve belirli bir sre
boyunca burada tutulur. Bu mekanizmann alma biimini aadaki ekil ile daha kolay
irdeleyebiliriz. Bu alma sistemi temel olarak dier Caching mekanizmalarnda da ayn ekilde
ilemektedir. Deien sadece ara bellee alnan HTML grntsnn ierii olacaktr.

lk olarak, birinci istemci web sunucusundan bir aspx sayfasn talep eder. Web sunucusu sayfann
ilikili kodlarn altrarak bir kt retir ve bu sayfa iin Output Caching (ktnn Ara Bellee
Alnmas) aktif ise retilen HTML sonularn istemciye gnderir. Hemen ardndan gnderilen HTML
ieriini belirtilen sre boyunca(duration) tutmak zere sunucu zerindeki ara bellee alr.

imdi ikinci bir istemcinin devamllk sresi (Duration) ierisindeyken ayn sayfay sunucudan talep
ettiini dnelim. Bu durumda web sunucusu, talep edilen sayfann Cache (Ara Bellek) zerinde
olup olmadna bakar. Eer ikinci kullanc talebini, Devamllk Sresi (Duration) ierisindeki bir
zaman diliminde iletmi ise, web sunucusu istemciye sayfann ara bellekteki hazr halini gnderir.
Dolaysyla sayfann retilmesinde altrlan arka plan kodlarnn hi biri tekrardan yrtlmez. Bu
elbetteki ikinci kullancnn talep ettii sayfa iin daha ksa srede cevap almasn salar.

www.bsenyurt.com Page 1943


Output Caching mekanizmasn bir aspx sayfasna uygulayabilmek iin tek yaplmas gereken
OutputCache direktifinin sayfann aspx kodlarnn olduu ksma eklemek yeterlidir.

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

Burada, Duration zellii ile sayfann ilk talep ediliinden sonra 300 saniye (5 dakika) sre ile ara
bellekte tutulacan bildirmi oluyoruz. VaryByName parametresini daha sonra inceleyeceiz.

imdi dilerseniz, ksa bir rnek ile Output Caching mekanizmasnn etkilerini incelemeye alalm.
Basit bir web uygulamas gelitireceiz. Bu uygulamada, Sql Sunucusunda yer alan Pubs isimli veri
tabanndaki Authors isimli tabloya ait verileri bir DataGrid kontrol ierisine aktaracaz.

default.aspx sayfamzn kodlar;

private void Baglan()


{
con=new SqlConnection("data source=localhost;initial catalog=pubs;integrated
security=SSPI");
cmd=new SqlCommand("SELECT * FROM authors",con);
con.Open();
}
private void Doldur()
{
dr=cmd.ExecuteReader(CommandBehavior.CloseConnection);
dgVeriler.DataSource=dr;
dgVeriler.DataBind();
dr.Close();
}

private void Page_Load(object sender, System.EventArgs e)


{
Baglan();
Doldur();
}

Uygulama altnda ve default.aspx sayfasnn kts retildiinde bu sayfann son halinin bir
kopyasda ara bellee alnr. Yeni koypa ara bellekte 300 saniye (5 dakika ) boyunca kalacaktr.
Ayn sayfay baka bir tarayc' da atmzda ya da ayn tarayc penceresinde iken ileri geri
gittiimizde sayfann ara bellekte bulunan halini elde ederiz. Ancak bu rnekte dikkat edilmesi
gereken bir nokta vardr. Bu durumu simule etmek iin sayfay refresh edelim. Bu durumda
sayfann ierii aadakine benzer olacaktr.

www.bsenyurt.com Page 1944


Daha sonra Duration sresi dolmadan nce ilk satrn deerini Sql Sunucusu zerinden deitirelim.
Bu durumda sayfada Output Caching uygulanmam olsayd, sayfay bir sonraki talep ediimizde
Load metodu alacak ve tablonun en gncel hali kullancya sunulacakt. Oysaki imdi sayfay
talep ettiimizde, yaplan deiikliin grnmediini farkederiz.

Deiiklik;

Yeni bir tarayc ile ayn sayfay talep ettiimizde;

Bu ileyi bazen byk bir risk olabilir. rnein, sayfann daha dinamik olduu durumlarda ve hatta
olay metodlarna cevap vermesi gerektii durumlarda sayfann tamamnn ara bellee alnmas,
aslnda istemcilere sayfann en gncel halinin gnderilmesi demek deildir. Bu gibi durumlarda
ounlukla ya veri kmelerinin ya da sayfa zerindeki belirli ksmlarn (kontrollerin) ara bellee
alnmas teknii tercih edilir. Bu teknikleri bir sonraki makalemizde inceleyeceiz.

Bir sayfann tamamn ara bellee aldmzda, sayfann arabellekte yer alacak birden fazla
kopyasna ihtiya duyduumuz durumlar sz konusu olabilir. ounlukla QueryString kullanm
srasnda baka sayfalara eitli parametreleri ve deerlerini gndeririz. te VaryByParam zellii
sayesinde sayfann, gnderdiimiz her parametre iin ayr ayr veya sadece belirli parametreler iin
ayr ayr kopyalarn ara bellekte tutabiliriz.

www.bsenyurt.com Page 1945


Bu durumu daha yakndan inceleyebilmek iin pubs veritabanndaki titles tablosunu kullancamz
bir nrek gelitirelim. Uygulamann default.aspx sayfasnda bu kez titles tablosunda yer alan her bir
satr iin title alannn deerlerini gstereceiz. Kullanc her hangibir bala tkladnda bu kitap
ile ilgili detayl bilgilerin olduu baka bir sayfaya(detay.aspx) gidecek. Detay sayfas kitabn
Primary Key deerini (title_id) QueryString parametresi olarak alacak. Bu durumda, detay sayfas
iin ara bellee alma ilemini gerekletirebiliriz. Konuyu daha iyi anlayabilmek iin rnek
zerinden adm adm gidelim. lk olarak ana sayfamzn (default.aspx) aspx ieriini aadaki gibi
deitirmeliyiz.

<asp:DataGrid id="dgVeriler" style="Z-INDEX: 101; LEFT: 56px; POSITION: absolute; TOP: 88px"
runat="server" AutoGenerateColumns="False" Height="160px" Width="264px"
BorderColor="#DEBA84" BorderStyle="None" BorderWidth="1px" CellSpacing="2"
BackColor="#DEBA84" CellPadding="3">
<FooterStyle ForeColor="#8C4510" BackColor="#F7DFB5"></FooterStyle>
<SelectedItemStyle Font-Bold="True" ForeColor="White"
BackColor="#738A9C"></SelectedItemStyle>
<ItemStyle ForeColor="#8C4510" BackColor="#FFF7E7"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#A55129"></HeaderStyle>
<PagerStyle HorizontalAlign="Center" ForeColor="#8C4510"
Mode="NumericPages"></PagerStyle>
<Columns>
<asp:HyperLinkColumn DataNavigateUrlField="title_id"
DataNavigateUrlFormatString="Detay.aspx?title_id={0}" DataTextField="title"
HeaderText="Balk"></asp:HyperLinkColumn>
</Columns>
</asp:DataGrid>

Bu deiiklik sayesinde, dataGrid kontrolmzden Detay.aspx sayfasna title_id alannn deerini


parametre olarak gnderebileceiz. imdi Detay.aspx sayfamnn kodlarn aadaki gibi
gelitirelim.

private void Baglan(string Id)


{
con=new SqlConnection("data source=localhost;initial catalog=pubs;integrated
security=SSPI");
cmd=new SqlCommand("SELECT title_id,title,price,pubdate FROM titles WHERE
title_id='"+Id+"'",con);
con.Open();
}
private void Doldur()
{
dr=cmd.ExecuteReader(CommandBehavior.CloseConnection);
dgDetaylar.DataSource=dr;
dgDetaylar.DataBind();
dr.Close();
}

private void Page_Load(object sender, System.EventArgs e)


{

www.bsenyurt.com Page 1946


string id=Request.Params["title_id"].ToString();
Baglan(id);
Doldur();
}

Burada ara bellee alma ilemini Detay.aspx sayfas zerinde uyguluyoruz. nk detay.aspx,
dinamik olarak ierii gelen parametre deerine gre deien bir sayfadr. Biz gelen parametre
deerine gre retilen sayfalarn html ktlarn ara bellee almak istiyoruz. te bunun iin yine
aspx kodlarnn bana OutputCache direktifini aadaki gibi eklememiz gerekiyor.

<%@ OutputCache Duration="300" VaryByParam="title_id"%>

Bylece detay.aspx sayfas her altrldnda gelen title_id deeri baz alnarak ara bellekte 300
saniye sreyle duracak olan html ktlarnn oluturulmasna imkan salyoruz. Olay u ekilde
irdelersek daha anlalr olacaktr;

Parametre tabanl OutputCache ilemi

stemci title_id deeri BU1032 olan satr detay.aspx


sayfasndan ister. Bu durumda detay.aspx sayfasnn ierii detay.aspx in A koypas oluturulur.
ara bellee alnr. Bu sayfay A olarak dnelim.

Baka bir stemci title_id deeri MC2222 olan sayfay talep


eder. Bu durumda detay.aspx sayfasnn yeni halinin kopyas detay.aspx in B koypas oluturulur.
ara bellee alnr.

Baka bir stemci title_id deeri MC2222 olan sayfay talep


eder. Eer duration sresi dolmadysa talep edilen bu detay.aspx in var olan B kopyas
sayfann kts ara bellekte zaten olduundan istemciye dner.
direkt olarak bu kt gnderilir.

Baka bir stemci title_id deeri BU1032 olan sayfay talep


eder. Eer duration sresi dolmadysa talep edilen bu detay.aspx in var olan A kopyas
sayfann kts ara bellekte zaten olduundan istemciye dner.
direkt olarak bu kt gnderilir.

* Duration sreleri dolduunda ise gelen talebe gre ara bellekteki sayfa ktlar tekrardan
oluturulur.

Grld gibi VaryByParam zellii ile, bir sayfann kendisine QeuryString ile gelen
parametrelerinin deerine gre farkl ara bellek grntlerini elde edebilmekteyiz. Baz durumlarda
talep edilen sayfaya birden fazla parametre gnderildii veya hi parametre gnderilmeden
arldda olur. Bu durumu karlamak iin VaryByParam zelliine * deerini atayabiliriz.

<%@ OutputCache Duration="300" VaryByParam="*" %>

www.bsenyurt.com Page 1947


Her ne kadar bir sayfann Output Cache teknii ile ara bellee alnmas avantajl grnsede,
zellikle olay kodlamal sayfalarn ileyiinde bu kullanm sorunlara yol aabilir. Her eyden nce
sayfa iinde postback' e neden olan kodlamalar var ise, sayfa ilk arldktan sonra ara bellee
alnacandan bu kod satrlar duration sresi sonlanana kadar yrtlmeyecektir. Dier yandan
zaman zaman, sayfalarmzn ierii dinamik olarak deimek zorunda kalabilir. Bu gibi durumlarda
da sayfann tamamnn ara bellee alnmas iyi bir yntem deildir. zm, sayfann belirli
paralarnn veya sayfadaki herhangibir veri kmesinin(kmelerinin) ara bellee alnmasdr. Data
Caching ve Fragment Caching tekniklerini bir sonraki makalemizde inceleyeceiz. Tekrardan
grnceye dek hepinize mutlu gnler dilerim.

rnek uygulama iin tklayn.

Burak Selim ENYURT

selim@bsenyurt.com

Derinlemesine Session Kullanm - 2 ( 08.01.2005


) - Asp.Net
Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde hatrlayacanz gibi, Session nesnelerinin kullanmn incelemeye


balamtk. Bu makalemizde ise, Session nesnelerinin nerelerde saklanabildiine deinmeye
alacaz. Varsaylan olarak Session nesneleri In-Proc (ilem ii) modunda saklanrlar. Yani web
sayfasnn alt asp.net work process' in iinde, dolaysyla bu ilerin alt web
sunucularndaki bellek alanlarnda tutulurlar. Bu zellikle Session nesnelerine bilgi yazma ve
okumada nemli bir avantajdr. Nitekim, eriim dorudan ram zerindeki blgelere doru olduu
iin dier bahsedeceimiz modlara nazaran greceli olarak olduka hzl bir eriim sz konusudur.
Lakin, web sunucusunun bana bir ey gelmesi halinde (rnein sunucunun bir anda restart olmas
gibi) bellekte tutulan tm Session nesneleri bir anda kaybedilir. Bu da ok sayda kullancnn at
oturumlara ait bilgilerin tamamnn kaybolmas anlamna gelmektedir. Bunu basit bir rnek ile
gsterebiliriz. Aadaki web uygulmasnda, Session nesnesine bir deer atanmaktadr. Session' n
time-out sresi varsaylan halinde (Yani 20 dakika olarak) braklmtr.

default.aspx kodlar ve Form' un ekran grnts;

private void Page_Load(object sender, System.EventArgs e)


{
if(Session["Bilgi"]!=null)
{
Label1.Text=Session["Bilgi"].ToString();
}
}
private void btnEkle_Click(object sender, System.EventArgs e)
{
Session["Bilgi"]="Deneme";
Label1.Text=Session["Bilgi"].ToString();
}

www.bsenyurt.com Page 1948


WebForm2.aspx kodlar ve Form' un ekran grnts;

private void Page_Load(object sender, System.EventArgs e)


{
if(Session["Bilgi"]!=null)
Label1.Text=Session["Bilgi"].ToString();
}

Bu rnei altrdmzda, default.aspx sayfasnda Ekle butonuna basarsak Session nesnemize


Deneme bilgisi eklenecektir. Eer WebForm2.aspx sayfasna geersek, Session bilgisinin Label
kontrolne yazldn grrz.

www.bsenyurt.com Page 1949


imdi web uygulamamza ait Global.asax dosyasnda herhangibir deiiklik yapp uygulamamz
yeniden derleyelim. Ben rnek olarak pek bir anlam ifade etmeyen bir yorum satr girdim ve
uygulamay yeniden derledim. Tabi bunu yaparken, web taraycmzda sayfalarmz ak halde
bulunmaldr.

protected void Application_Start(Object sender, EventArgs e)


{
//YORUM SATIRIDIR.
}

imdi linklerimize tklayarak sayfalar arasnda tekrar gezindiimizde, henz time-out sresi
dolmam olan Session nesnelerinin kaybedildiini ve Label kontrollerinde Session nesnesine ait
ieriin yazmadn grrz. Ksacas, In-Proc modunda olan (Yani ilem ii - In Process) Session
nesneleri kaybedilmitir. Elbetteki Session nesnelerinin bu ekilde kaybolmas dnda da
oluabilecek istisnalar vardr. rnein sunucunun istem d bir ekilde kapanmas gibi.

Asp.Net ile birlikte durum ynetiminde (state management), Session nesnelerinin saklanabilmesi
iin iki teknik daha gelitirilmitir. Bu teknikler yardmyla, durum nesnelerinin yukardaki gibi
nedenlerden tr kaybolmalarnn nne geilebilmektedir. Bu tekniklerden bir tanesi Session
nesnelerinin bir Sql Veritabannda tutulduu SQLServer modu, dieri ise Session
nesnelerinin ASP.NET State Service Windows Servisinde tutulduu StateServer modudur. lk
olarak SQLServer modunu inceleyeceiz.

SQLServer modunda, Session nesnesine ait tm bilgiler bir Sql Sunucusunda bu i iin zel olarak
hazrlanm bir veritabannda tutulmaktadrlar. Bylece, Session nesnelerine ait ierik, istenen sre
kadar (aylarca bile olabilir) fiziki bir disk blgesinde saklanabilmektedir. Bu ayrca, veritabannn
baka bir sunucuda konulandrlmasyla, Web iftliklerinin (Web Farms) yapsna uygun bir
oluumada imkan tanr. Bylece, Web Sunucusunda oluabilecek aksaklklardan doacak sorunlar
Sql Sunucusunu etkilemeyecek, dolaysyla Session' lar korunmu olacaktr. Elbette bu sistemin de
dezavantaj vardr.

Session nesnelerini ayr bir sunucudaki veri tabannda tutmak her ne kadar gvenlik ve
tutarllk asndan yksek performans salasada, bilgilere eriimin In-Proc moda
gre daha yava olmasnada neden olur. Bu elbetteki verinin okunmas veya yazlmas
iin srekli veritabanna doru atlan turlarn bir sonucudur.

SQLServer modunda kullanlan ASPState isimli veritabannda Session nesnelerinin yazlma, silinme
gibi ilemleri iin kullanlan stored procedure' ler yer alr. Session nesnelerine ait asl ierik ise
tempdb isimli veritabannda yer alan tablolarda tutulmaktadr. Microsoft .NET Framework bu
veritabann ve ieriini kurmak iin gerekli Sql kodlarn ieren script dosyalarn ierir. Windows XP
sistemlerinde bu dosyaya
(InstallSqlState.sql) D:\WINDOWS\Microsoft.NET\Framework\v1.1.4322\ adresinden
ulaabilirsiniz. Bu sql script dosyasn Sql Query Analyzer ile altrdmzda, Sql
Sunucusunda ASPState isimli bir veritaban oluturulduunu grrz. Ayrca Session nesnelerini
tutacak olan tablolarda tempdbveritaban ierisine eklenirler.

www.bsenyurt.com Page 1950


Burada bizi asl ilgilendiren ksm, tempdb veritabannda
oluturulan ASPStateTempSessions isimli tablodur. Nitekim bu tablo Session verilerini saklamak
zere kullanlmaktadr. Tablonun yaps aadaki ekilde grld gibidir.

Dikkat edecek olursanz, SessionId isimli alan tablonun Primary Key alandr. Bu alanda, web
sunucu tarafndan otomatik olarak oluturulan ASP.NET_SessionId deeri tutulmaktadr. Bunun
dnda Session' n yaratld tarih, oturumun sona erecei sre bilgisi gibi veriler dnda Session
nesnesinin ieriinin saklanaca iki nemli alan daha vardr.
Bunlar SessionItemShort ve SessionItemLong alanlardr. Her iki alandan hangisinin

www.bsenyurt.com Page 1951


kullanlaca, Session nesnesine atanan verinin byklne gre belirlenmektedir. te bu noktada
karmza nemli bir sorun kar.

Bir DataSet ieriini Session nesnesine aktardmzda, SessionItemShort veya


SessionItemLong alanlarndan hangisi kullanlrsa kullanlsn, Session nesnesinin ierdii
veri nasl olurda tek bir alan ierisine sdrlabilir?

te burada bir nceki makalemizde bahsettiimiz gibi Session nesnesinin tayaca verinin
seriletirilebilir olmas gereklilii ortaya kmaktadr. Bylece ister binary olarak ister XML olarak
DataSet nesnesinin ierii seriletirilebilir ve tek bir alan ierisine yazlp okunabilir. Bu elbetteki
Session ile tamak istediimiz her nesne rnei iin geerli bir durumdur. (rnein kendi
yazdmz bir snf iin.)

Out-of-Proc (lem d) modlarda, Session nesnesine atanan nesnelerin mutlaka


seriletirilebilir (Serializable) olmalar gerekmektedir.

imdi basit olarak yukarda ilediimiz rneimizde kullandmz Session


nesnesini, SQLServer modunda saklayalm. Varsaylan olarak, Session nesneleri In-Proc modda
tutulduklarndan web.config dosyasnda yer alan sessionState boumunun standart ierii
aadaki gibidir.

<sessionState
mode="InProc"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="false"
timeout="20"
/>

Mode zelliinin deeri varsaylan olarak InProc' tur. Yani, Session nesneleri ilem iinde
tutulmaktadr. Session bilgilerini veritabanna yazabilmek iin sessionState boumunu aadaki
gibi dzenlememiz yeterli olacaktr.

<sessionState
mode="SQLServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;user id=sa;password=123456"
cookieless="false"
timeout="20"
/>

Burada dikkat etmemiz gereken en nemli nokta, sqlConnectionString zelliinin ald balant
cmleciidir. Bu zellikte, sql sunucusunun bulunduu lokasyon data source ile belirtilmektedir.
Varsaylan olarak Sql sunucusunun localhost zerinde bulunduu dnldnden bu deer
127.0.0.1 ip deerini alr. Ancak Web iftlii (Web-Farm) gibi sistemlerde eer Sql Sunucusunun
bulunduu adres farkl ise data source deerini bu adrese gre ayarlamamz gerekecektir. Dier

www.bsenyurt.com Page 1952


taraftan, Ado.Net' te olduu gibi balantnn yaplaca veritaban adnn burada belirtilmesine
gerek yoktur. Bunun sebebi SQLServer modunda Session nesnelerinin nereye yazlacaklarnn zaten
belli olmasdr. Bir dier husus ise, mutlaka ve mutlaka balanty belli bir kullanc ad ve ifresi
zerinden yapmamzn gvenlik asndan daha salkl olacadr.

unu da hatrlatmakta fayda var. InstallSqlState script' i her ne kadar session ynetimi iin gerekli
veritaban dzenlemelerini yapsada, ASPNET kullancsna ASPState veritabanndaki stored
procedure' leri altrma ve tempdb iindeki ASPStateTempSessions ile ASPStateTempApplications
tablolar iin gerekli Select, Insert, Update, Delete komutlarn yrtebilme izinlerini vermemiz
gerekiyor.

Aksi takdirde ASPNET kullancsnn bu sp ve sql komutlarn altrma yetkisi olmayacandan web
uygulamamzda aadakine benzer trden hata sayfalar ile karlaabiliriz.

www.bsenyurt.com Page 1953


Gerekli izinleride verdikten sonra artk uygulamamz altrabiliriz. Uygulamamz altrdmz
srada eer Sql Profiler ile arka planda olanlar izlersek hemen bir sp' nin altrldn ve sp' ye
parametre olarak bir GUID' in aktarldn grrz. Buradaki GUID, web sunucusu tarafndan
retilen ASP.NET_SessionId' den baka bir ey deildir. Session nesnesi ilk kez yaratldndan
ilgili tabloya INSERT ilemini uygulayan bir sp almaktadr.

Tam bu noktada ASPStateTempSessions tablomuza bakacak olursak, yukardaki sp'ye aktarlan Id'
deerini SessionId alanna alm yeni bir satr oluturulduunu grrz.

Elbetteki bu noktada, Session' mza henz bir bilgi aktarmadmz iin tabloda yer alan ilgili
alanlara herhangibir bilgi yazlmamtr. default.aspx sayfasnda ekle butonuna basarsak, baka bir
sp' nin bu kez var olan SessionId' li satr gncellemek zere altrldn ve parametre olarakta
encrypt edilmi Session ieriinin gnderildiini grrz.

www.bsenyurt.com Page 1954


Dolaysyla Session ierii tabloda yer alan ilgili satra (ASP.NET_SessionId deerine sahip olan
satr) yazlm olacaktr. Eer makalemizin bandaki rneimizde yaptmz gibi, Global.asax
dosyasnda bir deiiklik yapp uygulamay yeniden derleyip time-out sresinden nce Session' lar
okumak istersek, Session' lara ait deerlerin kaybolmadn kolayca tespit edebiliriz. Session' larn
yaam sreleri dolduunda otomatik olarak silindiklerini biliyoruz. InstallSqlState script' i ayrca
zaman amna uram Session' larn otomatik olarak kaldrlmas iin gerekli bir job nesnesinide
sql sunucusuna ykler. (Job nesnesinin alabilmesi iin Sql Server Agent servisinin alyor
olmas gerekmektedir.)

imdi aadaki rnei inceleyelim. Bu rneimizde, Session nesnesine bizim tanmladmz bir
nesne rneini aktaryoruz.

Personel isimli snfmz;

public class Personel


{
private string mAd;
private string mSoyad;

public string Ad
{
get
{
return mAd;
}
set
{
mAd=value;
}
}

public string Soyad


{
get

www.bsenyurt.com Page 1955


{
return mSoyad;
}
set
{
mSoyad=value;
}
}

public Personel(string ad,string soyad)


{
mAd=ad;
mSoyad=soyad;
}

public Personel()
{

}
}

default.aspx;

private Personel pOku;

private void Page_Load(object sender, System.EventArgs e)


{

if(Session["Eleman"]!=null)
{
pOku=new Personel();
pOku=(Personel)Session["Eleman"];
Label1.Text=pOku.Ad+" "+pOku.Soyad;
}
}

private void btnEkle_Click(object sender, System.EventArgs e)


{
Personel p1=new Personel("Burak Selim","enyurt");
Session["Eleman"]=p1;
}

WebForm2.aspx

private Personel pOku;

private void Page_Load(object sender, System.EventArgs e)

www.bsenyurt.com Page 1956


{
if(Session["Eleman"]!=null)
{
pOku=new Personel();
pOku=(Personel)Session["Eleman"];
Label1.Text=pOku.Ad+" "+pOku.Soyad;
}
}

default.aspx sayfasnda Session nesnemize Personel snfndan p1 isimli nesne rneimizi


aktaryorz. Her iki sayfada da Session nesnesinin ieriini okurken, Personel snfndan bir nesne
rneine aka bir dntrme ilemi yaptmza dikkat edelim. nk Session nesnesi, kendisine
atanan verileri object tipinde tamaktadr. imdi default.aspx sayfamz tarayc penceresinde aar
ve Ekle butonuna basarsak aadaki hata mesajn alrz.

Sorun gayet aktr. Personel snfmzn seriletirilebilir bir nesne olmas gerekmektedir. Bu nedenle
Personel snfmza Serializable niteliini (Attribute) eklememiz gerekiyor.

[Serializable]
public class Personel
{
.
.
.

imdi Ekle butonuna tekrardan basarsak ve sayfalar arasnda gezersek, Personel snfna ait nesne
rneinin baarl bir ekilde tandn grrz.

Session nesnelerini ilem dndan saklayabileceimiz bir dier seenekte ASP.NET State
Service isimli windows servisinin kullanlmasdr. Bu kullanmda ounlukla, State Service baka
bir sunucu zerinde altrlr ve dier web sunucular tarafndan ortaklaa kullanlr. Dolaysyla,
alan Asp.Net work processor' dan ayr process' ler sz konusudur. Bu ayr process' ler State
Server zerinde konulandrlr.

www.bsenyurt.com Page 1957


Session nesnelerini ASP.NET State Service ile kontrol edebilmek iin ncelikle bu servisin
altrlmas gerekir.

Servisin altrlmasnn ardndan Web.config dosyasnda da sessionState boumunun zelliklerini


aadaki gibi deitirmeliyiz.

<sessionState
mode="StateServer"
stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;integrated security=SSPI"
cookieless="false"
timeout="20"
/>

StateServer modunda, State Server olarak kullanlacak sunucunun tcpip adresi ve


ilgili port numaras stateConnectionString zelliinde belirleniz. Biz burada local makineyi
kullanyoruz. Buradaki 42424 port numaras, ASP.NET State Service servisinin kulland
varsaylan port numarasdr. Dilersek bu numaray deitirmemiz mmkn. Bunun iin,sistemdeki
registery ayarlarna inmemiz gerekiyor. Hot Key Local
Machine sekmesinde \System\CurrentControlSet\Services\aspnet_state\P
arameters\ altndaki Port elemannn deerini deitirmemiz yeterlidir.

www.bsenyurt.com Page 1958


Bu deiikliklerden sonra Session nesnelerini ASP.NET State Service' n kontrol altnda tutulmak
zere kullanabiliriz. Bu servis yardmyla tuttuumuz Session nesneleri iin deseriletirilebilme
art aranmaktadr, bunuda hatrlatalm.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Derinlemesine Session Kullanm - 1 ( 31.12.2004


) - Asp.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Asp.Net sunucularnda durum ynetimi (state management) amacyla kullanlan


Session nesnesini detayl bir ekilde incelemeye balyacaz. Bildiiniz gibi, web anatomisinde
durum ynetimi bal bana bir terminolojidir. Web sitelerinin yer ald web sunucularnn istemci
makinelerde durum ynetme yeteneine sahip olamamalar sonucu, belli bir kullancya ait bilgilerin
sayfalar arasnda korunmas veya tanabilmesi iin deiik teknikler gelitirilmitir. Session
kullanm bu tekniklerden birisidir. ncelikle Session kavramnn ne olduunu ve ne iin
kullanldn kavramaya alalm.

Bir kullanc, bir web sunucusundan herhangibir sayfa talep ettiinde, web sunucusu bu kullanc
iin kendi sistemi zerinde veya yardmc bir sunucuda (web farm' lar gz nne alndnda) bir
oturum balatr. te Session nesneleri yardmyla kullancya ait olan bu oturum boyunca sayfalar
arasnda bilgi tama ilemini gerekletirebiliriz. Session kullanmna verilebilecek en gzel ve
klasik rnek, kullanclarnn al veri sepetleri ile birlikte site iindeki sayfalar boyunca
gezinebilmeleridir. Burada temel fikir kullancnn sahip olduu sepete ait bilgileri site ierisinde yer
alan sayfalar boyunca tayabilmektir. Biz bu amala Session nesnelerini kullanabilir ve kullancnn
oturumu sonlanncaya kadar sayfalar arasnda veri tayabiliriz. Elbette balayan bir oturum
mutlaka bir ekilde sonlandrlr. Bir oturum temel olarak aadaki nedenlerden dolay sonlanabilir?

Oturum Sonlanmasna Neden Olacak Etmenler

Varsaylan olarak sunucu zerinde alan her bir oturum 20


dakikalk zaman am sresine sahiptir. Sitemizi ziyaret eden
Oturumun zaman amna kullanclarn Session verileri ile ne kadar sre durabilecekleri
uramas. (Timeout) gz nne alnarak bu sre daha da drlebilir veya
arttrlabilir. Srede yaplan ayarlamalar kesinlikle sunucuya ait
bellek tketimini etkileyecektir.

www.bsenyurt.com Page 1959


Bir web sunucusu kullancnn taraycsn kapatp
kapatmadn anlayamaz. Onun yerine barndrd sayfalara
Kullancnn tarayc penceresini
yaplan arlar tespit eder. Dolaysyla bir kullanc ak bir
kapatmas veya sayfaya yeni bir
oturuma sahip iken taraycsn kapattnda veya yeni bir
tarayc penceresi aarak
tarayc penceresi atnda ayn sayfaya yeni bir oturum iinde
ulamas.
balanr. Bunun sebebi sunucunun rettii ASP.NET_SessionId'
lerin her bir istekte yeniden oluturulmasdr.

Oturum kapatlmaya Session nesnesine Abondon metodu uygulanarak oturumlar


zorlandnda. iptal edilebilir.

Bir sunucunun yeniden balatlmas eer SessionId deerleri


ilem iinde (yani asp.net work processor' un at i
paralarnda) tutuluyorsa otomatik olarak kaybedilecektir.
Sunucu yeniden balatldnda.
Ancak SessionId lerin bir Sql sunucusunda database' de veya
StateServer isimli windows servisinde tutulmas salanarak bu
kayplarn nne geilebilir.

Gelelim Session nesnelerinin sunucu tarafndan doru istemciler ile nasl eletirilebildiine. Web
sunucusundan bir sayfa talep edildiinde (1) Asp.Net Work Processor bu istemci iin otomatik
olarak benzersiz bir tanmlama (Unique Identity) deeri retir (2). Bu 120 bitlik bir saydr ve zel
bir algoritma yardmyla sunucu zerinde oluturulur. Daha sonra bu talep karlnda sunucu,
oluturduu ASP.NET_SessionId deerini istemci bilgisayara gnderir (3). Bu ASP.NET_SessionId
deerinin istemci zerinde tutuluu varsaylan olarak bir erez (Cookie) vastasyla salanr (4).
Ayn deer Sunucu zerinde de yer almaktadr (4). Bu noktadan itibaren istemci, kendisine ait
oturumu sunucu zerinde bir ekilde sonlanncaya kadar, site ierisinde bu ASP.NET_SessionId
deeri ile tannr. Dolaysyla artk sunucu, oturum sahibinin kim olduunu bilmektedir.

Tanma; Sunucular oturum sahiplerini tanyabilmek iin, zel bir algoritma ile
oluturduklar 120 bitlik benzersiz bir tanmlayc deer kullanrlar. ASP.NET_SessionId.

Ancak burada istisnai bir durum vardr. Her istemci cookie' leri desteklemez. Bu durumda yaplacak
ufak bir ayarlama ile ASP.NET_SessionId deerinin url' ye eklenmesi salanr. Bunu ilerleyen
safhalarda inceleyeceiz. Aadaki ekil basit olarak bir SessionId deerinin nasl oluturulduunu
betimlemektedir. Bu varsaylan, yani Cookie destei veren tarayclar iin geerli olan senaryodur.

www.bsenyurt.com Page 1960


Session nesnesine atanan veriler web sunucusu zerindeki bellekte tutulmaktadr. Bu bilgiler asla
istemci bilgisayara gnderilmezler. Bu da gvenlik asndan nemli bir avantajdr.

Gvenlik; Session nesnelerine ait veriler Sunucu zerindeki bellek alanlarnda tutulur ve
asla istemcilere gnderilmez.

Burada dikkat etmemiz gereken nemli bir husus vardr. Session bilgilerinin sunucu belleinde
(varsaylan olarak budur) tutulmas. Bir Session nesnesinin en byk zelliklerinden birisi
seriletirilebilir (Serializable) nesneleri tayabilme zelliine sahip olmasdr. Yani, bir Session
nesnesi yardmyla kullancnn oturumu boyunca bir DataSet nesnesini sayfalar arasnda
dolatrabiliriz. Peki burada dikkat etmemiz gereken nokta nedir? Sorun DataSet gibi bir nesnenin
tek bana alt bir bilgisayar iin bile fazla bellek alan harcamasdr. Yani, sunucuya balanan
her bir kullanc iin oturum sresi boyunca DataSet nesne rneklerinin tanmas sunucu
kaynaklarn ciddi lde azaltr. Bellekte meydana gelen bu azalma elbetteki web sunucusunun
performansn olumsuz ynde etkileyecektir.

Performans; Bir web uygulamasnda Session nesnelerinin DataSet nesne rnekleri


tadn varsayarsak, N sayda kullancnn balanmas, sunucu belleinde N sayda
DataSet nesne rneinin oluturulmas anlamna gelmektedir.

Peki zm olarak ne retebiliriz? lk olarak nbellekleme tekniklerini kullanabiliriz. Ya da


Seriletirilebilir nesneleri rneklendiren snflar kendimiz yazarz. Tabi byle bir durumda
yazacamz snflarnda seriletirilebilir olmas bir baka deyile seriletirmeye izin veren nitelikleri
(Attribute) kullanmas gerekecektir. Bu konuyu ilerleyen makalelerimizde incelemeye alacaz.
Elbetteki bir Session sadece seriletirilebilir nesneleri deil her tipte .NET nesne rneini
saklayabilir.

www.bsenyurt.com Page 1961


Bu ksa aklamalardan sonra dilerseniz, Session nesnelerinin nasl oluturulduuna ve
kullanldna kod ksmndan basit bir rnel ile bakmaya alalm. Aadaki uygulamada,
default.aspx, sayfa2.aspx ve sayfa3.aspx isimli 3 adet web sayfamz var. Biz default.aspx ierisinde
kullancdan isim ve soyisim bilgisini alyor ve bunu Session nesnemizde tutuyoruz. Daha sonra
sayfa2.aspx ve sayfa3.aspx ierisinden bu session deerlerini okuyup ekrana yazdryoruz.
Default.aspx ilk aldnda, retilen ASP.NET_SessionId deerini de Session nesnesinin SessionId
zellii ile elde ediyoruz. rnek uygulamay bu linkten indirebilirsiniz.

//default.aspx
private void btnEkle_Click(object sender, System.EventArgs e)
{
Session["Kimlik"]=txtBilgi.Text; //Session' a deer atyoruz.
}

//sayfa2.aspx
private void Page_Load(object sender, System.EventArgs e)
{
lblAdSoyad.Text=Session["Kimlik"].ToString(); //Session deerini okuyoruz.
}

//sayfa3.aspx
private void Page_Load(object sender, System.EventArgs e)
{
lblAdSoyad.Text=Session["Kimlik"].ToString(); //Session deerini okuyoruz.
}

www.bsenyurt.com Page 1962


Yukardaki rnek Session kullanmnn en basit halidir.

Oturum ynetiminde iimize yarayacak iki olay vardr. Session_Start ve Session_End olaylar. Bir
istemci bir web sunucusunda bir oturum balattnda uygulamaya ait global.asax dosyasnda yer
alan Session_Start olay alr. Oturum herhangibir neden ile sonlandnda ise yine global.asax
dosyasndaki Session_End olay alr. Bu olaylar yardmyla, uygulamanzda oturum halinde
bulunan kullanc, saysn bir baka deyile sayfadaki ziyareti saysn renebilirsiniz. rnein az
nceki uygulamamz ele alalm ve Global.asax dosyasnda aadaki deiiklikleri yapalm.
Uygulamamzdaki default.aspx sayfasnda da aktif ziyareti saysn gstermek iin bir label
kullanacaz.

www.bsenyurt.com Page 1963


protected void Session_Start(Object sender, EventArgs e)
{
/*Uygulama seviyesinde bir deiken kullanmak istediimizden Application nesnesini kullandk.
Eer ilk kez oturum alyor ise varsaylan deeri 1 olarak ayarlyoruz. lk kez almyorsa var olan
deeri 1 arttryoruz.*/
if((int)Application["ToplamZiyaretci"]==0)
Application["ToplamZiyaretci"]=1;
else
{
int deger=(int)Application["ToplamZiyaretci"];
deger+=1;
Application["ToplamZiyaretci"]=deger;
}
}

protected void Session_End(Object sender, EventArgs e)


{
/* Oturum kapatldnda devereye giren bu olayda, uygulama seviyesindeki Application
nesnesinde saklanan deerini 1 azaltyoruz. Bylece online ziyareti saysn 1 azaltm oluyoruz.*/
int deger=(int)Application["ToplamZiyaretci"];
deger-=1;
Application["ToplamZiyaretci"]=deger;
}

Kodda dikkat ederseniz Application nesnesinin deerini deger isimli deikene alrken (int) tr
dntrme operatrn kullandk. Bunun sebebi, Application nesnesininde Session nesnesi gibi
verileri object tipinde saklyor olmasdr. Dolaysyla Session veya Application nesnelerinin
deerlerini okurken uygun tr dnmlerini aka yapmamz gerekiyor.

Artk tek yapmamz gereken Application nesnesinin deerini okumak ve label kontrolmze
yazdrmak.

private void Page_Load(object sender, System.EventArgs e)


{
Session["Kimlik"]=txtBilgi.Text;
lblZiyaretciSayisi.Text=Application["ToplamZiyaretci"].ToString();
}

Bundan sonra uygulamamza her yeni oturum amzda, Session_Start devreye girecek ve
kullanc saysn otomatik olarak 1 arttracaktr. Session'lar sonlandnda ise 1 eksileceklerdir.
Bunu daha iyi kavrayabilmek iin oturumlarn timeout sresini 1 dakikaya indirelim. Session
nesnesinin TimeOut zelliine 1 deerini atayarak bunu salayabiliriz.

Session.Timeout=1;

imdi pe pee tarayc pencereleri ap uygulamamzn olduu default.aspx sayfasn aralm.

www.bsenyurt.com Page 1964


Burada da grld gibi, Session_Start olay baarl bir ekilde alarak Application nesnesinin
ToplamZiyaretci elemannn deerini srekli olarak 1 arttrmtr. Lakin biz Session Timeout sresini
1 dakika yaptmz iin 1 dakika sonra Session nesnesinin deerinin null olmas gerekmektedir. Bu
sreyi bekledikten sonra yeni bir tarayc penceresi ap sayfamza girmek istersek aadaki ekran
grnts ile karlarz. Grld gibi ToplamZiyaretci deeri balang deerine atanmtr.

Burada dier bir durum daha vardr. Diyelim ki Timeout sresini 10 dakika yaptk. Uygulama
altrld ve bir ka oturum ald. Sonra ise, 10 dakika dolmadan nce Timeout sresini 1 dakika
yaptk. Ardndan yeni oturumlar atk. Son oturum andan 1 dakika getikten sonra, nceden
yaam sreleri 10 dakika iken alan oturumlar durumlarn korumaya devam ederler.

Bazen istemci tarayclar Cookie desteine sahip deildir veya bu zellikleri bilerek kapatlmtr.
Peki byle bir durumda istemci bilgisayar, sunucuda kendisi iin alan oturum ile nasl

www.bsenyurt.com Page 1965


eletirilebilir? Bu sorunun zm ASP.NET_SessionId deerinin site iinde hareket edilen
sayfalarn linklerine eklenmesidir. Asp.Net bunu bizim iin otomatik olarak yapmaktadr. Tek
yapmamz gereken web.config dosyasnda sessionState elemannda, Cookieless zelliine true
deerini atamaktr.

<sessionState
mode="InProc" stateConnectionString="tcpip=127.0.0.1:42424"
sqlConnectionString="data source=127.0.0.1;Trusted_Connection=yes"
cookieless="true"
timeout="20"
/>

Eer uygulamamz bu haliyle denersek sayfalar arasnda gezinirken url bilgilerinin aadaki gibi
deitiini grrz. Grld gibi ASP.NET_SessionId deeri otomatik olarak relative url bilgisinin
nne eklenmitir.

default.aspx iin;

Eer bu sayfadan dier sayfalara gei yapar isek, oluturulan ASP.NET_SessionId deerinin bu
sayfalarn url bilgisine de eklendiini dolaysyla Session' n korunduunu grrz.

Ancak burada dikkat etmemiz gereken nemli bir nokta vardr. Linkler arasnda ASP.NET_SessionId
deerinin url bilgisi ile aktarlabilmesini istiyorsak relative linkleri kullanmak zorundayz. Yani
Sayfa2 balkl LinkLabel nesnesinin NavigateUrl zelliinin deerine, sayfa2.aspx (default.aspx ile

www.bsenyurt.com Page 1966


ayn lokasyonda olduu iin) deerini vermemiz gerekir. Eer buraya
http://localhost/SessionSample1/Sayfa2.aspx gibi bir tam yol linki verirsek; bu linke tkladmzda
default.aspx' teki oturum yok saylacak ve yeni bir oturum almaya allacaktr.

Grld gibi default.aspx sayfasn atmzda oluan ASP.NET_SessionId deeri ile, buradan
Sayfa2.aspx' e gittiimizde URL bilgisine eklenen ASP.NET_SessionId deerinden farkldr. Dahas
burada, Sayfa2.aspx iin yeni bir oturum sz konusu olduundan, default.aspx iinde oluturulan
Session["Kimlik"] bilgisine buradan eriilemiyecektir. Bunun sonucuda da var olmayan bir nesneye
erimek istediimizden hata almaktayz.

Bu makalemizde Session nesnesine ksaca deinmeye altk. zleyen makalemizde, Session


nesnesi ile ilgili daha farkl konulara gz atmaya alacaz. Bu konular arasnda
ASP.NET_SessionId deerlerinin bir sql sunucusunda veya StateServer servisinde tutulmas da yer
almaktadr. Tekrardan grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net ile Sql Server Full-Text Searching (Tm


Metinde Arama) Kullanm ( 18.12.2004 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

www.bsenyurt.com Page 1967


Bu makalemizde, Sql sunucu zerindeki tablolarda text tabanl arama ilemlerinin, Full-Text
Searching (Tm Metinde Arama) servisi yardmyla nasl gerekletirildiini incelemeye alacaz.
Konunun pekimesi asndan basit bir web uygulmas ile de bu hizmeti kullanp text tabanl arama
ilemlerini irdelemeye alacaz. zellikle dikkatinizi ekmitir ki, internette yer alan pek ok
arama motoru aradmz kelimelerin getii web sayfalarn bulup bize getirir. ounlukla arama
motoruna kaytl web sayfasnn ieriinde yaplan text tabanl aramalar da Full-Text Searching
(Tm Metinde Arama) hizmetinden faydalanlr. Bu tip bir arama genellikle alanlar ierisinde ok
geni text tabanl ierie sahip olan tablolar zerinde yaplmaktadr. Sql sunucusu, 7.0
versiyonundan itibaren bu hizmeti vermeye balamtr. Elbetteki arama ileminin
gerekletirilebilmesi iin Full-Text Searching (Tm Metinde Arama) servisinin Sql sunucusunda
ykl olmas gerekmektedir.

Dilerseniz hi vakit kaybetmeden bir tablo iin Full-Text Index' in nasl oluturulacana ksaca
bakalm. ncelikle, Full-Text Indeksleme yapacamz tablonun adna enterprise manager' dan sa
tklayoruz ve aadaki gibi Define Full-Text Indexing On a Table' seiyoruz. Bu ileme
balamadan nce tablomuzda bir primary key alan olmas gerektiinide belirtelim. Nitekim
indeksleme ilemlerinde bu alan, sonularn dndrlmesinde anahtar alan olarak kullanlmaktadr.

Bu ilemin ardndan karmza kan sihirbazdaki admlar birer birer ilemeye balyoruz. Az ncede
belirttiim gibi bu ilk olarak tablomuzdaki primary alan iin bir index seiliyor.

www.bsenyurt.com Page 1968


Bu ilemin ardndan, hangi kolonlarda arama yaplacan belirtiyoruz. Full-Text aramalar
ounlukla uzun text verilerin tutulduu alanlarda kullanlr. rnein tablomuzdaki Icerik alan
makalelere ait Html ierii barndrdan ntext veri tipindedir. Burada sadece karakter ierikli veya
binary ierikli aramalara msade eden alanlarn grndn syleyelim. Yani primary key olan
alanlar veya tarih formatndaki alanlar burada grnmez. Nitekim bu yapdaki alanlarda Full-Text
Indexing yaplmas ok da anlaml deildir. Artk Full-Text Searching (Tm Metinde Arama)
ilemimiz semi olduumuz alanlar zerinde yaplabilecektir.

www.bsenyurt.com Page 1969


Sradaki admda ise, arama ilemi iin gerekli katalog tanmlanr. Yani Full-Text Indexing aslnda bir
katalogda tutulmaktadr. Dolaysyla bizim gerekletireceimiz arama ilemleride bu katalou
kullanacaktr. Kataloglar standart olarak d:\Program Files\Microsoft SQL Server\MSSQL\ftdata\
fiziki adresinde tutulur.

www.bsenyurt.com Page 1970


Daha sonraki admlarda ise kataloun belirli periyotlarda tekrardan doldurulmasn salayacak
Schedule (Takvim) ayarlarnda yapabiliriz. Bu ve izleyen admlar getikten sonra tek yapmamz
gereken kataloun doldurulmas ilemidir. Bunun iinde, iki seeneimiz var. Birisi Start Full
Population. Bu seenek ile katalog batan itibaren indekslenerek oluturulur. Bir dier
seeneimiz ise Start Incremental Population dr. Bu seenek sayesinde sadece tablonun eski
hali ile yeni hali arasndaki farklar indeksleme ilemine katlarak katalog gncellenir. Bu daha
nceden kataloglanm indeksler iin geerli bir seenektir. u an iin biz katalou yeni
oluturduumuzdan Start Full Population seeneini kullanacaz.

Bu ilemlerin ardnan dikkat ederseniz, tablomuzun yer ald database iinde, Full-Text
Catalog sekmesinde tanmladmz kataloun oluturulduunu grrsnz.

www.bsenyurt.com Page 1971


Eer tabloda oluan gncellemelerden sonra katalog bilgisinin otomatik olarak yenilenmesini
istiyorsak bu durumda Change Tracking zelliin aktif hale getirmeliyiz. Bununla birlikte katalog
gncelleme ileminin arka planda yaplmasn salamak iin Update Index in
Background seeneini aktif hale getirmeliyiz. Bylece, tablomuza yeni satrlar eklendiinde, Full-
Text Searching (Tm Metinde Arama) ilemi iin kullanlan katalog bilgilerinin otomatik olarak
yenilenmesini salam oluruz.

www.bsenyurt.com Page 1972


Artk tek yapmamz gereken Full-Text Searching (Tm Metinde Arama) ilemini kullanmak. Bunun
iin T-SQL' de bir ka komut var. Bunlardan ikisi, prototipleri aadaki gibi
olanFREETEXT ve FREETEXTTABLE anahtar szckleridir.

FREETEXT ( Arama Yaplacak Alan , 'Aranacak Kelime' )

FREETEXTTABLE ( Tablo Adi , Arama Yaplacak Alan , 'Aranacak Kelime' )

Her iki anahtar szckte, belli bir alan zerinde Full-Text Searching (Tm Metinde Arama) ilemini
gerekletirmemizi salar. Ancak FreeTextTable sonular farkl bir tablo ile geri dndrr. Bu
tabloda Rank ve Key isimli iki alan vardr. Key alan, arama ileminin yapld catalog
oluturulurken kullanlan primary key deerlerini alr. Rank alan ise, aranan kelimelerin bulunduu
satrlar arasnda bir derecelendirme yaplmasna imkan tanr.

Bu derecelendirme sayesinde aranan kelimenin daha ok getii satrlardan, az getii


satrlara doru (yada aranan kelimenin en uygun olarak eletirilebildii alanlardan en az
eletirildii alanlara doru) sralanm bir tablo grnts elde etmemiz mmkndr.

lk olarak Query Analyzer yardmyla bu sorgularn altrlmasn inceleyelim.

Burada grld gibi, FREETEXT anahtar szc, Icerik isimli alanda overload anahtar
kelimesinin getii satrlarn olduu sonu kmesini elde etmemizi salamtr.

www.bsenyurt.com Page 1973


FreeTextTable anahtar sznn kullanm ise biraz daha karmaktr. Burada arama sonucu
oluan tabloya ait verileri aramann yapld tablo ile birletirebilmek amacyla Join teknii
kullanlmtr. Join tekniinde arama ileminde elde edilen tablonun KEY alan ile Makale isimli
tablonun primary key alan olan ID alanlar eletirilmitir. Bu sorgu sonucunda RANK alanna gre
tersten sral bir veri kmesi elde ederiz. Kmeyi Rank alanna gre tersten sraladmz takdirde,
aranan kelimenin en uygun artlarda eletirildii satrlar en ste gelmi olacaktr.

imdi Full-Text Searching (Tm Metinde Arama) ilemini bir asp.net uygulamasnda kullanalm. Bu
uygulamada basit olarak bir arama ilemi sonucunda elde edilecek sonular bir DataGrid
kontrolnde gsterilecektir. Amacmz bir kelimeyi makalelerin ieriinde aramak ve bulunan
sonular kullancya sunmak. Gerekletireceimiz uygulamada aranan kelimenin girilecei
TextBox' ta oluturulabilecek Sql Injection' larn nne gemek amacyla bir Stored
Procedure kullanacaz. ncelikle sp' mizi aadaki gibi oluturalm.

CREATE PROCEDURE dbo.sp_AraBul


(
@Aranan nvarchar(255)
)
AS

SELECT A.*,M.Konu,M.Tarih,M.[ID] FROM Makale AS M


INNER JOIN
FREETEXTTABLE(Makale,Icerik,@Aranan) AS A
ON M.[ID]=A.[KEY]
ORDER BY A.RANK DESC

RETURN

Sp' miz dardan aranan kelimeyi parametre olarak alacak ve sonular arld ortama
dndrecek. imdide asp.net sayfamz aadaki ekilde oluturalm.

www.bsenyurt.com Page 1974


Yanlz burada amacmz sadece aranan kelimenin getii makaleleri bulmak deil. Ayn zamanda
bulunan makalelerin olduu sayfalara link vermek. Bu nedenle dataGrid kontrolmzn ieriini
aadaki gibi oluturmamz gerekiyor.

<asp:DataGrid id="dgSonuclar" style="Z-INDEX: 105; LEFT: 48px; POSITION: absolute; TOP:


120px" runat="server" AutoGenerateColumns="False">
<AlternatingItemStyle BackColor="#FFE0C0"></AlternatingItemStyle>
<ItemStyle ForeColor="Black" BackColor="#CCCCCC"></ItemStyle>
<Columns>
<asp:HyperLinkColumn DataNavigateUrlField="ID" DataNavigateUrlFormatString="Mak
aleGoster.aspx?ID={0}" DataTextField="Konu" HeaderText="Makale
Konusu"></asp:HyperLinkColumn>
<asp:BoundColumn DataField="Tarih" SortExpression="Tarih" ReadOnly="True"
HeaderText="Yayin Tarihi" DataFormatString="{0:dd-MM-yy}"></asp:BoundColumn>
</Columns>
</asp:DataGrid>

imdide uygulama kodlarmz yazalm.

private SqlConnection con;


private SqlCommand cmd;
private SqlDataAdapter da;
private DataTable dt;

private void BaslangicAyarlari()


{
con=new SqlConnection("data source=localhost;initial catalog=bsenyurt;integrated
security=SSPI");
cmd=new SqlCommand("sp_AraBul",con);
cmd.CommandType=CommandType.StoredProcedure;
cmd.Parameters.Add("@Aranan",SqlDbType.NVarChar,255);

www.bsenyurt.com Page 1975


da=new SqlDataAdapter(cmd);
dt=new DataTable();
}
private void Page_Load(object sender, System.EventArgs e)
{
BaslangicAyarlari();
}

private void btnBul_Click(object sender, System.EventArgs e)


{
cmd.Parameters["@Aranan"].Value=txtArananKelime.Text;
try
{
if(con.State==ConnectionState.Closed)
con.Open();
da.Fill(dt);
dgSonuclar.DataSource=dt;
dgSonuclar.DataBind();
}
catch(SqlException hata)
{
Label1.Text=hata.Message.ToString();
}
finally
{
if(con.State==ConnectionState.Open)
con.Close();
}
}

Uygulamamz altrdmzda aadaki sonucu elde ederiz.

www.bsenyurt.com Page 1976


Full-Text Searching (Tm Metinde Arama) tekniinde sadece tek bir kelime zerinden arama
yapmak zorunda deiliz. rnein "Matematik Mhendisi" kelimelerinin ardk olarak getii
yerleride kolayca bulabiliriz. Tabi byle bir arama sonucunda "Matematik Mhendisi" kelimesi ile
bire bir eleen metinlerin bulunduu satrlar ile "mhendisi" kelimesinin olduu ama "Matematik"
kelimesinin olmad satrlarda elde edilcektir.

Dier yandan ierik alannda hem overload kelimesi hemde interface kelimesi geen makaleleri
bulmak istediimiz bir rnek ile karlarsak ne yaparz? te byle bir durumda And, Or gibi
mantksal operatorlerin sunduu imkanlardan faydalanmamz gerekecektir. Bunun iin Full-Text
Searching (Tm Metinde Arama) ilemlerinde kullanabileceimiz iki yeni sql anahtar szc
vardr. Bunlar CONTAINS ve CONTAINSTABLE anahtar szckleridir. Bu
ifadelerde AND, OR, NEAR, * gibi mantksal operatorler kullanlarak arama ilemleri daha detayl
bir ekilde gerekletirilebilir. rnein aadaki sorgu, overload ve interface kelimelerinin bir arada
getii alanlar arar.

SELECT A.*,M.Konu,M.[ID] FROM Makale AS M INNER JOIN


CONTAINSTABLE(Makale,Icerik,'overload AND interface') AS A ON M.[ID]=A.[KEY]
ORDER BY A.RANK DESC

Dier yandan ayn aramay overload veya interface kelimelerinden herhangibirinin getii alanlar
zerinde de aadaki sorgu ile gerekletirebiliriz. Tek yapmamz gereken aranan kelimeler arasna
Or operatorunu koymak olacaktr.

www.bsenyurt.com Page 1977


And ve Or operatrleri dnda kullanabileceimiz bir dier kullanl operatrde, * asteriks
karakteridir. rnein,

SELECT A.*,M.Konu,M.[ID] FROM Makale AS M INNER JOIN


CONTAINSTABLE(Makale,Icerik,' "Datarela*" ') AS A ON M.[ID]=A.[KEY]
ORDER BY A.RANK DESC

sorgusu yardmyla Datarela ile balayan szckleri ieren alanlarn olduu veri kmesini elde
edebiliriz. CONTAINS ve CONTAINSTABLE aramalarnda kullanabileceimiz dier operatrler iin
Sql Help' e bakabilirsiniz. Bu makalemizde Full-Text Searching (Tm Metinde Arama) ilemlerinin
nasl yapldn incelemeye altk. Umuyorum ki yararl bir makale olmutur. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Oyun Programlamaya Giri (Matrisler


Yardmyla arpma Kontrol) ( 04.12.2004 ) -
C#
Deerli Okurlarm Merhabalar,

www.bsenyurt.com Page 1978


Hafta sonu evde bilgisayarm banda internette gezinirken, tarihi oyunlarn anlatld bir site ile
karlatm. Aslnda zaten eski oyunlar aratryordum. Amacm bu oyunlara, oyun oynamak
isteyen bir ocuk gz ile deil, onlarn yaplarn ve ekirdeklerini anlamaya alacak bir yazlmc
gzyle bakabilmekti. Sonuta, iimdeki ocuk ar basp bir ka tanesini saatlerce
oynadm. Aralarnda en ok houma gidenlerden birisi PackMan' di. Packman, dorusal dzlemde 4
yne hareket edebilen bir kahramand. Yolda kendisini rastgele konumlardan gelerek yakalamaya
alan bceklerden kayor ve bulduu meyveleri yiyerekte puanlar topluyordu. Tam oyunu
bitirmeme az kalmtki hi beklenmedik bir ekilde bceklerden birisi tarafndan yendim. Aslnda
ekrana bir sre donuk gzler ile bakmtm. Nitekim, oyunu oynarken aklma geen gn okuduum
Oyun Programlama kitab gelmiti.

Kitabn bir blmnde, ekranda yer alan ayn boyutlu nesnelerin arpmalarnn kontrolnde iki
boyutlu bir matris dizisinden faydalanlyordu. O anda, arpma tekniklerinin farkl bir teoremini
Packman'a benzeyecek bir oyun ile inceleyebileceimi dndm. Her ne kadar amacm tmyle
bir oyunu yazmak olmasada en azndan Packman' imi ekrandaki duvarlarn iinden geirmeyecek
ekilde hareket ettirmek istiyordum.

Teori gayet basitti. lk olarak oyun sahasn, eit boyutlu karelere blecektim. Bu karelerin boyutlar
oyundaki nesnelerin evresini saran hayali karelerinki ile ayn olacakt. Bylece bir kare iinde her
zaman tek bir oyun eleman tam olarak sm bulunacakt. Daha sonra ekrandaki elemanlar iki
boyutlu bir matris dizisi iinde bir ekilde konumlandracaktm. Son olarak, kahramann her
hareketinde yne bal olaraktan nceki veya sonraki kare alanlarn kontrol edecek ve orada bir
Duvar nesnesi var ise arpma olduunu belirterek o yne olan hareketi kesecektim.

Teoremin kilit noktas, oyun alanndaki karelerde bulunan elemanlar, iki


boyutlu bir Matris dizisi ierisinde temsil edebilmekti.

lk olarak aadaki gibi bir oyun alann dndm.

www.bsenyurt.com Page 1979


ekil 1. Oyun Sahas.

ncelikle, Duvar, Muz ve kahramanmz Packo' ya ait imajlar tasvir ettim. Bunlarn her birisi 20
piksel X 20 Piksel boyutlarndaki bir karenin i kenarlarna teer olacak byklkteydiler. Daha
sonra, oyun saham 20 Piksel X 20 Piksel' lik kareler ile doldurdum. Dolaysyla artk elimde, 20' ye
20' lik bir Matris vard. Bu Matris yardmyla ekrandaki her bir elemann konumunu bilebilirdim. Tek
yapmam gerken Matrisin ilgili elemanna, orada duran nesneyi temsil edecek saysal bir deer
vermekti. rnein u anki haliyle, Packo' nun Matris' deki konumunu aadaki gibi ifade
edebilirdim.

Matris[5,8]=1;

Bu durumda, Packo' nun saa doru olan hareketinde herhangibir duvara arpp arpmadn
kontrol etmek iin, Y deerinin 1 fazlasna bakmak yeterli olacakt.

Yani;

eer Matris[5,8+1]=2 ise (ki Duvarlarda 2 says ile ifade edebilirdim.)


arpma var, Saa gitme.
eer Matris[5,8+1]=3 ise (ki Muzlar 3 ile ifade edebilirdim.)
Saa git, Matris[5,9] daki Muzu ekrandan sil, Puan arttr.
eer Matris[5,8+1]=0 ise (ne duvar ne de Muz var ise.)
arpma yoktur. Yola devam et.

Bu kontrol Packo' nun yapaca dorusal her hareket iin uygulayabilirdim. Bylece ,

Hareket ynne gre bir sonraki admda yer alan elemanlar Matris dizisi iinde
bularak arpma kontroln gerekletirebilirdim.

Teoremi kafamda pekitirdikten sonra, sra bunu uygulamaya dkmeye gelmiti. Elbetteki bir
Windows uygulamas iin byle bir teoremi aratrmaya alrken bir takm zorluklar ile
karlaabilirdim. rnein, oyun baladnda Duvarlarn, Muzlarn ve Packonun rastgele ekrana
konumlandrlmas. Ekranda piksel baznda tutulan karesel alanlarn, Matris dizisi ierisinde nasl
indislendirilebilecei. yle ya, 400 piksel' e 400 piksel' lik bir Form alann, 400*400 elemanl bir
Matris dizisinde aynen uygulamak gereksiz yere hafza tketimine neden olurdu. Ya da, ekrandaki
bir Muz' un stnden geildiinde o resmin nasl kaldrlaca. Bu gibi pek ok sorunu nceden
dnmek ve uygulamay ona gre planlamak gerekiyordu. Bu amala nce dndm ve sonra
aadaki kodlar gelitirdim.

Konumlandrma ilemleri iin kullandm snf,

using System;

namespace Packo
{
/* Bu sinif yardimiyla oyun alaninda kullandigimiz nesnelerin X ve Y koordinatlari ve duvar
sayilari iin rastgele degerler rettiriyoruz. Ekranimizi 20' ye 20'e lik karelere ayirdigimiz iin
random sinifinin Next metodunu buna uygun sekilde agiriyoruz. */

www.bsenyurt.com Page 1980


public class Konumlandir
{
private int X,Y,duvarSayisi;
System.Random r;

public Konumlandir()
{
r=new Random();
}

/* X koordinatlari iin (herhangibir oyun elemaninin Left zelliginin degeri iin) bir zellik
tanimliyoruz. Bu zellik Read-Only formatindadir. */
public int YerlestirX
{
get
{
X=r.Next(1,20)*20; /* Oyun alani 400 piksele 400 piksel boyutunda oldugu iin, 1 ile
20 arasindaki rakami 20 kat sayisi ile arpiyoruz.*/
return X;
}
}

/* Y koordinatlari iin (herhangibir oyun elemaninin Top zelliginin degeri iin) bir zellik
tanimliyoruz. Bu zellik Read-Only formatindadir. */
public int YerlestirY
{
get
{
Y=r.Next(1,20)*20;
return Y;
}
}
/* Ekrana 10 ile 30 arasinda restgele bir degerde Duvarlar koymak iin bu zelligi
kullaniyoruz. Bu zellik Read-Only formatindadir. */
public int DuvarSayisi
{
get
{
duvarSayisi=r.Next(10,30);
return duvarSayisi;
}
}
}
}

Ana program;

Konumlandir k;

www.bsenyurt.com Page 1981


/* Ekrani 20*20 lik bir matris ile ele alacagiz. */
int[,] Matris=new int[20,20];

/* Matristeki her bir elemanin hangi oyun nesnesini (duvar,kahramanimiz packocuk ve Muz) temsil
ettigini daha kolay kontrol edebilmek iin sayisal degerleri bir enum sabiti ile anlamlandiriyoruz.*/
enum AlanSahibi
{
Pakocuk=1,
Duvar=2,
Muz=3
}

/* Ekrana duvar elemani, rastgele koordinatlara gelecek sekilde ekleniyor.*/


private void DuvarEkle()
{
/*Bir PictureBox nesnesi tanimlaniyor.*/
PictureBox pb=new PictureBox();
/*Nesnemizin ierecegi resim ykleniyor. */
pb.Image=System.Drawing.Image.FromFile("duvar.jpg");
/*Nesnemizin ekrandaki yerlesimi iin gerekli koordinat ayarlamalari yapiliyor.*/
pb.Top=k.YerlestirY;
pb.Left=k.YerlestirX;
/* Duvarin ekrandaki piksel bazli koordinatlarini Matrisimizdeki elemanlar ile uyusturabilmek iin
20 ile blyoruz. Matrisin bu elemanina Duvar enum sabitinin degerinin veriyoruz.*/
Matris[pb.Left/20,pb.Top/20]=(int)AlanSahibi.Duvar;
/* Nesnemizin boyutlari belirleniyor.*/
pb.Width=20;
pb.Height=20;
pb.SizeMode=PictureBoxSizeMode.StretchImage;
/* Nesnemiz formumuzun Controls koleksiyonuna ekleniyor.*/
this.Controls.Add(pb);
}

/* Ekrana bir Muz elemani, rastgele koordinatlara gelecek sekilde yerlestiriliyor.*/


private void MuzEkle()
{
/*Muz nesnesinin zerinden geildiinde onu ekrandan kaldrabilmek iin kontroln adn bilmem
gerekiyor.Bunun iin MuzEkle metodunun adn bulunduu koordinata gre tanmlyoruz.*/
string ad;
PictureBox pb=new PictureBox();
pb.Image=System.Drawing.Image.FromFile("muz.jpg");
pb.Top=k.YerlestirY;
pb.Left=k.YerlestirX;
Matris[pb.Left/20,pb.Top/20]=(int)AlanSahibi.Muz;
ad="MUZ_"+Convert.ToString((pb.Left/20))+"_"+Convert.ToString((pb.Top/20));
pb.Name=ad;
pb.Width=20;
pb.Height=20;

www.bsenyurt.com Page 1982


pb.SizeMode=PictureBoxSizeMode.StretchImage;
this.Controls.Add(pb);
}

/* Kahramanimiz Packo' nun ekrandaki konumu, Matris dizisindeki yeri ve saga veya sola bakacagi
resmi belirleniyor. Ayrica, ekrana DuvarSayisi kadar Duvar ve Muz elemanlari ekleniyor.*/
private void Baslat()
{
/* Rastegele X,Y ve duvar sayilari iin kullandigimi Konumlandir sinifina ait bir nesne rnegi
olusturuluyor.*/
k=new Konumlandir();
resPacko.Left=k.YerlestirX;
resPacko.Top=k.YerlestirY;
Matris[resPacko.Left/20,resPacko.Top/20]=(int)AlanSahibi.Pakocuk;
/*Egere resPacko ekranin sol yarim kresinde ise, Sola bakan resmi gsteriliyor.*/
if(resPacko.Left<200)
resPacko.Image=System.Drawing.Image.FromFile("packoSol.jpg");
/*Egere resPacko ekranin sag yarim kresinde ise, Saga bakan resmi gsteriliyor.*/
if(resPacko.Left>200)
resPacko.Image=System.Drawing.Image.FromFile("packoSag.jpg");
resPacko.Visible=true;
for(int i=1;i<k.DuvarSayisi;i++)
{
DuvarEkle();
MuzEkle();
}
}

int carpismaDurumu=0;

/* Eer stnden getiimiz nesne Muz ise onu ekrandan kaldryoruz. Bunu yaparken Form
zerindeki kontrollerde gezinip, kontroln adn buluyor ve Remove metodunu aryoruz.*/
private void MuzYokEt(int X,int Y)
{
/*nce Matirsimizin X,Y elemannn Muz olup olmadna bakyoruz.*/
if(Matris[X,Y]==(int)AlanSahibi.Muz)
{
/*Eer Muz ise dizinin bu elemannn deerini 0 yapyoruz. Bylece Muz nesnemizi diziden
karm oluyoruz.*/
Matris[X,Y]=0;
/* Daha sonra PictureBox' mzn adn tedarik ediyoruz. */
string muzX=X.ToString();
string muzY=Y.ToString();
string KontrolAdi="MUZ_"+muzX+"_"+muzY;
/*Dng ile, Form iindeki tm kontroller arasnda geziniyoruz.*/
for(int i=0;i<this.Controls.Count;i++)
{
/*Eer gncel kontroln ad, bizim Muz nesnemizinki ile ayn ise, bu PictureBox'
Formumuzdan kartyoruz.*/

www.bsenyurt.com Page 1983


if(this.Controls[i].Name.ToString()==KontrolAdi)
{
this.Controls.Remove(this.Controls[i]);
}
}
}
}

/* arpisma kontrolnn yapildigi metod. Bu metod Packo' nun X, Y koordinatlari ile hareket ettigi
yn (saga,sola,yukariya,asagiya) parametre olarak aliyor. Aldigi X,Y koordinatlari ve yne gre,
bir sonraki kare alaninda bir Duvar nesnesi olup olmadigina bakiyor.*/
private void CarpismaKontrol(int X,int Y,char Yon)
{
/*Eger sola hareket ediyorsak ve Matrisimizin [X indisinin 1 nceki elemani,Y] AlanSahibi.Duvar
enum sabitinin degerine esit ise arpisma vardir. */
if(Yon=='A')
{
int alanSahibi=Matris[X-1,Y];
if(alanSahibi==(int)AlanSahibi.Duvar)
carpismaDurumu=1;
else
carpismaDurumu=0;
MuzYokEt(X,Y);
}
/*Eger saga hareket ediyorsak ve Matrisimizin [X indisinin 1 sonraki elemani,Y]
AlanSahibi.Duvar enum sabitinin degerine esit ise arpisma vardir. */
if(Yon=='D')
{
int alanSahibi=Matris[X+1,Y];
if(alanSahibi==(int)AlanSahibi.Duvar)
carpismaDurumu=1;
else
carpismaDurumu=0;
MuzYokEt(X,Y);
}
/*Eger asagi hareket ediyorsak ve Matrisimizin [X,Y indisinin 1 sonraki elemani]
AlanSahibi.Duvar enum sabitinin degerine esit ise arpisma vardir. */
if(Yon=='S')
{
int alanSahibi=Matris[X,Y+1];
if(alanSahibi==(int)AlanSahibi.Duvar)
carpismaDurumu=1;
else
carpismaDurumu=0;
MuzYokEt(X,Y);
}
/*Eger yukari hareket ediyorsak ve Matrisimizin [X,Y indisinin 1 nceki elemani] AlanSahibi.Duvar
enum sabitinin degerine esit ise arpisma vardir. */
if(Yon=='W')

www.bsenyurt.com Page 1984


{
int alanSahibi=Matris[X,Y-1];
if(alanSahibi==(int)AlanSahibi.Duvar)
carpismaDurumu=1;
else
carpismaDurumu=0;
MuzYokEt(X,Y);
}
}

/*Form zerinde A (sol), S (asagi), D (saga), W (yukari) tuslarina basildika arpisma kontrol
yapiliyor. Eger arpisma var ise, belirtilen yndeki dogrusal harekete (20 piksellik teleme) izin
verilmiyor. Aksi halde harekete devam ediliyor.*/
private void frmPacko_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
int x=resPacko.Left/20;
int y=resPacko.Top/20;

if(e.KeyChar==(Char)Keys.A)
{
resPacko.Image=System.Drawing.Image.FromFile("packoSol.jpg");
CarpismaKontrol(x,y,'A');
if(carpismaDurumu==1)
MessageBox.Show("DUVARA ARPTIN");
else
resPacko.Left-=20;
}
if(e.KeyChar==(Char)Keys.D)
{
resPacko.Image=System.Drawing.Image.FromFile("packoSag.jpg");
CarpismaKontrol(x,y,'D');
if(carpismaDurumu==1)
MessageBox.Show("DUVARA ARPTIN");
else
resPacko.Left+=20;
}
if(e.KeyChar==(Char)Keys.S)
{
resPacko.Image=System.Drawing.Image.FromFile("packoAsagi.jpg");
CarpismaKontrol(x,y,'S');
if(carpismaDurumu==1)
MessageBox.Show("DUVARA ARPTIN");
else
resPacko.Top+=20;
}
if(e.KeyChar==(Char)Keys.W)
{
resPacko.Image=System.Drawing.Image.FromFile("packoYukari.jpg");
CarpismaKontrol(x,y,'W');

www.bsenyurt.com Page 1985


if(carpismaDurumu==1)
MessageBox.Show("DUVARA ARPTIN");
else
resPacko.Top-=20;
}
}

/*Oyunu kapatmak ve baslatmak kullandigimiz menleri ContextMenu ierisinde kullaniyoruz.*/


private void menuItem3_Click(object sender, System.EventArgs e)
{
Close();
}

private void menuItem1_Click(object sender, System.EventArgs e)


{
Baslat();
}

/* Kontrol amaciyla, Matris dizisinin degerlerini Text tabanli bir dosyaya da yazabiliyoruz.*/
private void menuItem4_Click(object sender, System.EventArgs e)
{
System.IO.FileStream fs=new
System.IO.FileStream("kontrol.txt",System.IO.FileMode.OpenOrCreate,System.IO.FileAccess.Write
);
System.IO.StreamWriter sw=new System.IO.StreamWriter(fs);
for(int i=0;i<20;i++)
{
for(int j=0;j<20;j++)
{
sw.Write("{0,2},{1,2}={2,3}",i,j,Matris[i,j]);
}
sw.WriteLine();
}
sw.Flush();
sw.Close();
fs.Close();
}

Kodlar her ne kadar uzun grnsede programn tek yapt, Packo' yu duvarlarn iinden
geirmeden hareket ettirmek ve yolda grd Muz' lar toplamasn salamak. rnein,
uygulamay altrdmzda bir duvara hangi ynden gelirsek gelelim, Matris dizimiz iinde Packo'
dan sonraki elemanlar kontrol edilecek ve duvara arplp arplmadna baklacaktr.

www.bsenyurt.com Page 1986


ekil 2. Duvara arp.

Dier yandan, eer Packo bir Muz zerinden geerse, bu Muz nesnesini temsil eden PictureBox
Form zerinden kaldrlacak, ayn zamanda Matris dizimizdeki ilgili Muz elemann deeride
sfrlanacaktr.

ekil 3. Packo Muzlar Yiyebiliyor.

www.bsenyurt.com Page 1987


Grld gibi, Matris teknii ile eit karelere blnm sahalardaki nesnelerin birbirleri ile olan
arpmalarn kontrol edebilmek son derece basit. Bu minik program elbetteki balang
aamasnda. rnein, her muz yiyiinden sonra puanlama sistemi olmas, duvarlarn seri olacak
ekilde ekrana dizilmesi, Packo dnda hareket eden ve Packo' yu yemeye alan bceklerin farkl
hareketleri vs... Bu ksmlarn gelitirilmesinide siz deerli okurlarma brakyorum. Uygulamaya
kald yerden devam edebilirsiniz. rnek uygulamay indirmek iin ltfen tklayn. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Oyun Programlamaya Giri (arpma


Teknikleri - 3) ( 19.11.2004 ) - C#
Deerli Okurlarm Merhabalar,

Getiimiz hafta boyunca, Oyun Programcl ile ilgili olaraktan aldm kitaplar frsat bulduka
okumaya ve almaya devam ettim. Konular o kadar heyecanl ve srkleyici ki aratrmak iin
zaman kavram anlmasz hale geliyor. yleki, dn gece sabaha kar saat 03:00 sularnda kat
kalem ile bouuyor ve arpma Tekniklerinden birisinin daha matematiksel modelinin C# ile nasl
uygulanabileceini aratryordum. Sonu olarak ie bir ka saatlik uykuyla gitmek zorunda kaldm.
Ancak buna ramen tm gn dintim. nk, arpma tekniklerinden birisini daha renmitim.
Sra anlatmaya gelmiti. te bugnk makalemizde 3nc arpma tekniini incelemeye
alacaz.

Oyun programclnda nemli bir yere sahip olan arpma tekniklerinde, bu makaleye gelinceye
kadar iki ana konuyu inceleme frsat bulduk. lk olarak iki drtgensel nesnenin bir birleriyle olan
arpmalarn inceledik. Daha sonraki makalemizde ise, eski dostumuz Pisagor' u anp, iki dairesel
nesnenin birbirleriyle olan arpmalarn aratrdk. Srada bu iki durumun kombinasyonu var. Yani,
bir drtgen ile dairesel bir nesnenin birbirleriyle olan arpmalarnn tespit edilmesi. Bu teknikte
yine Pisagor teroeminden yararlanacaz. Ancak dikkat etmemiz gereken nemli koordinat noktalar
var. Bu durumu daha iyi analiz etmek iin aadaki ekli gz nne alalm.

www.bsenyurt.com Page 1988


ekil 1. Drt Blge.

Bu teoride, drtgenin dairesel nesneye gre olan konumlarn ele almamz gerekiyor. Bu da bizim,
drtgen nesnesine ait olan maksimum ve minimum snr noktalarn bilmemiz gerektiini
gstermektedir. Buna gre, drtgensel nesnenin ke noktalarnn x ve y koordinatlar ele alnr.
Ksaca, oluturacamz pisagor geni iin bu maksimum ve minimum x, y koordinatlarn
bilmemiz gerekiyor. arpma teoremine gelince;

Drtgenin dairesel nesneye en yakn olan ke noktalarndan yola klarak


oluturulan dik gene ait hipotens deeri, dairesel nesnenin yarapndan
kk ise arpma vardr.

imdi buradaki drt blgeyi ksaca inceleyelim. rnek olarak 4nc blgeyi aadaki ekilde
olduu gibi ele alabiliriz. Esasen tm blgelerde, drtgensel nesneye ait minX,maxX,minY ve maxY
koordinatlar byk neme sahiptir. rnein PRO genini gz nne aldmzda, kenarlarn
uzunluklarn bulabilmek iin R noktasnn koordinatlarndan yararlanlmaktadr. R noktasna dikkat
edecek olursanz, drtgenin en uzak X ve en uzak Y deerlerine sahip olduunu grrsnz.
Dolaysyla biz, PO uzakln bulmak istiyorsak, Ox deerinden RmaxX deerini kartmamz
gerekecektir. Ayn durum RP kenarnn boyunu bulurken de geerlidir. Bu durumda, Oy deerinden
RmaxY deerini kartrz. Burada drtgenin drdnc blgeye dtn anlamak iin dairenin x,y
koordinatlar ile R noktasnn koordinatlar karlatrlr. Burada dikkat etmemiz gereken husus, R
noktasnn koordiantlarn drtenin daireye olan konumuna gre deieceidir.

www.bsenyurt.com Page 1989


ekil 2. Drdnc blge iin durum.

Bu anlattklarm size biraz karmak geldiyse sk durun. Dier blgelerin grafiksel ifadeleride
aada yer almaktadr. Dikkat edecek olursanz, R noktasnn koordinatlar her blge iin farkldr.
Buda gene ait dik kenarlar hesaplanrken uygun R noktas koordinatlarn kullanmamz
gerektiini, baka bir deyile programlama algoritmasnda, sz konusu blgeleri if koullar ile
tespit ederek gelitirmemiz gerektiini gsterir.

www.bsenyurt.com Page 1990


ekil 3. nc blge iin durum.

www.bsenyurt.com Page 1991


ekil 4. Birinci blge iin durum.

www.bsenyurt.com Page 1992


ekil 5. kinci blge iin durum.

imdi sra geldi bu teoremi C# kodlar ile gerekletirmeye. Bu amala aadaki ekran
grntsne sahip basit bir windows uygulamas gelitirdim. Her zamanki gibi ilemleri
kolaylatrmak amacyla, dairesel nesneyi sabit tutup, drtgensel nesneyi A,S,D,W tular ile
hareket ettiriyorum. Bizim iin nemli olan ksmlar, 4 durumdada geerli olan gene ait dik
kenarlarn FarkX ve FarkY eklinde hesap edilmeleri ve buradan yola klarak hipotens
deerlerinin bulunmas. Son olarak bu hipotens deerini, dairenin yarap ile karlatrp
arpma olup olmadn inceliyoruz.

www.bsenyurt.com Page 1993


ekil 6. Uygulama formu.

imdi gelelim uygulama kodlarmza.

/*global degiskenlerimizi tanimliyoruz. */


float Daire_X,Daire_Y,Dortgen_X,Dortgen_Y,Daire_R;
float Dortgen_MinX,Dortgen_MaxX,Dortgen_MinY,Dortgen_MaxY;
double Hipotenus,FarkX,FarkY;

/*Daire iin X,Y koordinatlar, yarap Drtgen iin ise X,Y, minimum ve maksimum X,Y
koordinatlar hesaplanyor.*/
private void Hesapla()
{
Daire_R=Daire.Width/2;
Daire_X=Daire.Left+Daire_R;
Daire_Y=Daire.Top+Daire_R;

Dortgen_X=Dortgen.Left+Dortgen.Width/2;
Dortgen_Y=Dortgen.Top+Dortgen.Height/2;
Dortgen_MinX=Dortgen.Left;
Dortgen_MaxX=Dortgen.Left+Dortgen.Width;
Dortgen_MinY=Dortgen.Top;
Dortgen_MaxY=Dortgen.Top+Dortgen.Height;

/*Burada temel olarak, drtgenin hangi blgelere denk dtne bakarak dik gene ait FarkX
ve FarkY deerlerini hesap ediyoruz.*/
if(Daire_Y<Dortgen_MinY)
{
FarkY=Daire_Y-Dortgen_MinY;

www.bsenyurt.com Page 1994


}
if(Daire_Y>Dortgen_MaxY)
{
FarkY=Daire_Y-Dortgen_MaxY;
}
if(Daire_X>Dortgen_MaxX)
{
FarkX=Daire_X-Dortgen_MaxX;
}
if(Daire_X<Dortgen_MinX)
{
FarkX=Daire_X-Dortgen_MinX;
}
/*Dik gene ait hipotens buluyoruz.*/
Hipotenus=Math.Sqrt((FarkX*FarkX)+(FarkY*FarkY));
}

/* lmleri ekrana yazdirmak iin string deger dndren bir metod hazirliyoruz.*/
private string Olcumler()
{
string olcum="Daire iin X:"+Daire_X.ToString();
olcum+=" Y:"+Daire_Y.ToString();
olcum+=" R:"+Daire_R.ToString();
olcum+=" | Dortgen in X:"+Dortgen_X.ToString();
olcum+=" Y:"+Dortgen_Y.ToString();
olcum+=" | Dortgen in MinX:"+Dortgen_MinX;
olcum+=" | Dortgen in MaxX:"+Dortgen_MaxX;
olcum+=" | Dortgen in MinY:"+Dortgen_MinY;
olcum+=" | Dortgen in MaxY:"+Dortgen_MaxY;
olcum+=" | Hipotens:"+Hipotenus.ToString();
return olcum;
}
/* Form zerinde A,S,D,W tuslarina basildiginda, Dortgen isimli pictureBox' in hareket etmesini
sagliyoruz.*/
private void frmCollision2_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if(e.KeyChar==(Char)Keys.A)
{
Dortgen.Left-=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
if(e.KeyChar==(Char)Keys.D)
{
Dortgen.Left+=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
if(e.KeyChar==(Char)Keys.S)

www.bsenyurt.com Page 1995


{
Dortgen.Top+=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
if(e.KeyChar==(Char)Keys.W)
{
Dortgen.Top-=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
Kontrol();
}

/* arpisma kontrolmz yapiyoruz. */


private void Kontrol()
{
if(Hipotenus<Daire_R)
{
this.Text="";
this.Text+=" |!!! ARPISMA VAR !!!| ";
}
else
this.Text="";
}

Kodlarmz son derece ak ve kolay. Uygulamamz altrdmzda, arpma teorimizin baarl


bir ekilde altn grrz.

www.bsenyurt.com Page 1996


ekil 7. arpma durumu.

Grld gibi artk oyun programlamada nemli noktalardan birisi olan arpma teorilerinde
baya bir yol aldk. Ancak her zaman bu teknikleri kullanmayacaz. rnein zaman zaman,
ekrann eit karelere blndn (ayn kareli defterler gibi) ve nesnelerin bu kareler zerindeki
konumlarna gre arpp arpmadklarnn belirlendiini rendim. nmzdeki hafta byk bir
ihtimalle bu konuyu incelemeye alacam. Kaynaklardan incelediim kadar ile bu karelere blme
teknii tam anlamyla PackMan tarz oyunlara ynelik gelitirilmi bir model. in iine bu kez
matris dizileri girecek. Bakalm bamza neler gelicek. Tekrardan grnceye dek hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Oyun Programlamaya Giri (arpma


Teknikleri - 2) ( 12.11.2004 ) - C#
Deerli Okurlarm Merhabalar,

Hatrlayacanz gibi bir nceki makalemizde, Oyun Programclna girmek adna arpma
tekniklerini incelemeye balam ve drtgenlerin arpmalarn ele almtk. Bugnk makalemizde
ise, dairesel ekillerin birbirleri ile olan arpmalarn incelemeye alacaz. Dairesel ekillerin
arpmasna verilebilecek en gzel rnek, kaynaklardan edindiim bilgiye gre Bilardo oyunlardr.
Burada gerekten de mkemmel dairelerin birbirleriyle olan arpmalar sz konusudur. unuda
hatrlatmakta fayda var. u an iin teorilerimizi iki boyutlu uzayda inceliyoruz. Elbetteki iin iin
boyutlu cisimler girdiinde kullanacamz algoritmalar ve teknikler birazda olsa farkllk
gsterecektir. nk uzay boyutunda X ve Y koordinatlarna ek olarak Z koordinatlarda iin iine
girecektir. Bu da iki boyutlu bir sistemde Bilardo oyunun tasarlanmasnn 3 boyutlu sistemdekine
gre daha kolay olduunu gstermektedir.

Dairesel nesnelerin arpmalarn belirlemek iin eski dostumuz Pisagor Teoreminden


faydalanacaz. Burada ana fikir, dairelerin merkezlerinin birbirlerine olan dorusal uzaklklar ile
yaraplarnn toplamlarnn karlatrlmasdr. Eer, dairelerin merkezleri aras dorusal uzaklk,
dairelerin yaraplar toplamndan kk ise, dairelerin st ste geldiklerinden dolaysyla
arptklarndan sz edebiliriz. Olay aadaki ekil ile ele almaya alalm.

www.bsenyurt.com Page 1997


ekil 1. Dairelerin arpmas.

Burada bizim iin anahtar ekil, dairelerin merkezleri arasnda oluan BMA dik genidir. Biz bu
gen yardmyla, A ve B noktalar arasndaki mesafeyi, baka bir deyile BMA geninin
hipotensn bulabiliriz. Bu bizim iin en kilit noktadr. Sonrasnda ise, bu mesafeyi Ra ve Rb
yaraplarnn toplam ile karlatrmamz yeterli olacaktr. Dolaysyla arpma formlmz
aadaki gibi olmaldr.

ekil 2. arpma Teorimiz.

Grld gibi yapmamz gereken, X ve Y koordinatlar arasndaki mesafelerden yararlanarak,


genin hiptonesn (yani iki daire merkezi arasndaki dorusal uzakl) bulmak ve bulduumuz
deeri, yaraplarn toplam ile karlatrmaktr. imdi dilerseniz, bu teoriyi C# ile gelitirilmi bir
windows uygulamasnda nasl simule edeceimize bakalm. Gelitireceimiz uygulama her zamanki
gibi basit ve anlamsz olacak. Ancak amacmz, yukardaki teoremi uygulamak ve sonularn
grmek. Bu amala aadaki ekran grntsne ait bir windows uygulamas gelitirdim.

www.bsenyurt.com Page 1998


ekil 3. Uygulama tasarmmz.

Kodlarmz ise aadaki gibi olacaktr.

/*global deikenlerimizi tanmlyoruz. */


float Top1_X,Top1_Y,Top2_X,Top2_Y,Top1_R,Top2_R;
double Hipotenus,YaricapToplam;

/*X,Y Koordinatlari ile yariaplar belirleniyor.*/


private void Hesapla()
{
Top1_R=Top1.Width/2;
Top1_X=Top1.Left+Top1_R;
Top1_Y=Top1.Top+Top1_R;

Top2_R=Top2.Width/2;
Top2_X=Top2.Left+Top2_R;
Top2_Y=Top2.Top+Top2_R;

float Fark_X=Math.Abs(Top1_X-Top2_X);
float Fark_Y=Math.Abs(Top1_Y-Top2_Y);

Hipotenus=Math.Sqrt((Fark_X*Fark_X)+(Fark_Y*Fark_Y));

YaricapToplam=Top1_R+Top2_R;
}

/* lmleri ekrana yazdrmak iin string deer dndren bir metod hazrlyoruz.*/
private string Olcumler()
{
string olcum="Top 1 iin X:"+Top1_X.ToString();
olcum+=" Y:"+Top1_Y.ToString();
olcum+=" R:"+Top1_R.ToString();
olcum+=" | Top 2 iin X:"+Top2_X.ToString();

www.bsenyurt.com Page 1999


olcum+=" Y:"+Top2_Y.ToString();
olcum+=" R:"+Top2_R.ToString();
olcum+=" | Hipotens:"+Hipotenus.ToString();
return olcum;
}

private void frmCollision2_Load(object sender, System.EventArgs e)


{
Hesapla();
lblOlcumler.Text=Olcumler();
}

/* Form zerinde A,S,D,W tularna basldnda, Top2 isimli pictureBox' n hareket etmesini
salyoruz.*/
private void frmCollision2_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if(e.KeyChar==(Char)Keys.A)
{
Top2.Left-=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
if(e.KeyChar==(Char)Keys.D)
{
Top2.Left+=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
if(e.KeyChar==(Char)Keys.S)
{
Top2.Top+=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
if(e.KeyChar==(Char)Keys.W)
{
Top2.Top-=1;
Hesapla();
lblOlcumler.Text=Olcumler();
}
Kontrol();
}

/* arpma kontrolmz yapyoruz. */


private void Kontrol()
{
if(Hipotenus<YaricapToplam)
{
this.Text="";

www.bsenyurt.com Page 2000


this.Text+=" |!!! ARPISMA VAR !!!| ";
}
else
this.Text="";
}

Kodlarmz son derece ak. Dikkat etmemiz gereken noktalardan birisi, Top1 ve Top2 isimli
nesnelerin X ve Y koordinatlarnn bulunmasdr. Burada Left ve Top zelliklerinin yansra daire
merkezlerini tam olarak bulabilmek iin, Width veya Height (daire olduklarndan X veya Y' ye
eklenecek mesafelerin Width veya Height ile hesaplanmas farketmez) deerlerinden birisinide gz
nne almamz gerekir. Yani aadaki kodlarda olduu gibi;

Top1_R=Top1.Width/2;
Top1_X=Top1.Left+Top1_R;
Top1_Y=Top1.Top+Top1_R;

Top2_R=Top2.Width/2;
Top2_X=Top2.Left+Top2_R;
Top2_Y=Top2.Top+Top2_R;

Bunun dnda Hipotens hesaplamasnda elbetteki karekk almak iin Math snfnn Sqrt
fonksiyonundan yaralanmaktayz.

Hipotenus=Math.Sqrt((Fark_X*Fark_X)+(Fark_Y*Fark_Y));

Uygulamamz altrdmzda, Top2 isimli nesneyi herhangibir ynden Top1 isimli nesne stne
getirirsek arpmann meydana geldiini kolayca tespit edebiliriz.

ekil 4. arpmann alma zamannda tespit edilmesi.

arpmalar ile ilgili bir dier nemli durumda, drtgenler ile dairelerin arpmalarnn nasl tespit
edilebileceidir. Bu kez, daire merkez nesne olarak dnlr ve drtgenin daireye olan en yakn

www.bsenyurt.com Page 2001


ve en uzak noktalar deerlendirilerek arpmann olup olmadna baklr. Bu teoriyide bir sonraki
makalemizde incelemeye alacaz. Tekrardan grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Oyun Programlamaya Giri (arpma


Teknikleri - 1) ( 06.11.2004 ) - C#
Deerli Okurlarm Merhabalar,

Yaklak bir ay kadar nce evde dinlenirken, u ana kadar yaptm ileri ve projeleri dndm.
Kesin olarak unu syliyebilirim ki, profesyonel anlamda ilgilendiim ve kullandm tek dil C# idi.
C# dilini kullanarak, .Net platformu altnda veritaban arlkl olmak zere eitli almalar
yaptm. Ancak bir sre sonra farkettim ki, bir Matematik Mhendisi olarak lisans eitimim srasnda
grdm o devasa cebir problemleri, teorem ispatlar hi bir zaman iin iine girmemiti.
Matematiin belkide ok az olmakla birlikte drt ileminin ve bir takm algoritmalar iin gerekli
iteratif ifadelerinin yer ald uygulamalar dnda, onu ok youn ekilde kullanmamtm.

Belki finansal veya istatistiki bir projede youn olarak ekonomi teoremlerini ve bunlara bal olarak
matematiksel denklemleri kullanmak gerekmekteydi ancak ok youn bir ekilde bunlar
kurcalamamtm. Dndke, gnmz dnyasnda artk algoritmalar ile, matematik ile uraan
yazlmclarn azald kansna vardm. Hepimizde matematik temeli var. Hepimiz bu konuda eitli
snavlardan getik. Ama sonu itibariyle ok az projede, daha nceden grdmz esiz
teoremleri kullandk. O dakikalarda neden bu yne eilmiyorum, biraz elenceli hatta matematik
ykl almalara el atmyorum diye dnmeye baladm. Derken zm son derece elenceli
ama bir o kadarda nemli bir sahada buldum. Oyun Programcl.

oumuz, yazlm gelitirirken bir gn byk bir oyunu yazan ekibin iinde olmay, onun
gelitiricilerinden birisi olarak anlmay hayal etmiizdir. Bu ok almay ve birazda zeki olmay
gerektiren bir kiilik ister. Kendi kendime dnrken, elbette gnmzn popler oyunlarndan
birisini yazan herhangibir ekipte olabilmek iin ok erken olduunu zaten biliyordum. Ama en
azndan bir oyun iin gerekli en temel bileene biraz da olsa ainalm vard. Matematik. Oyun
programlama ierisinde, oyun motorlarnn gelitirilmesinden aksiyonlarn uygulanna, yapay zeka
taktiklerinden stratejik karar mekanizmalarna kadar her aamada Matematiksel algoritmalarn yer
aldn gayet iyi biliyordum. Benim iin bunlar renmeye almak, uygulamak ve denemek,
benim iin heyecan verici olacakt. Dier taraftan eski Matematik gnlerimi hatrlam bir baka
deyile saksy biraz daha altrm olacaktm.

Byk bir hevesle bir taslak plan hazrladm ve ie koyuldum. Bana ncelikle oyun
programlamadaki temel teknikleri balang seviyesinden itibaren anlatacak ve yeri geldiinde de
uzmanlk seviyesine kadar kartacak kitaplar gerekliydi. Hemen Amazon.com' da ksa bir
aratrmadan sonra aadaki kitaplarn siparilerini verdim.

Oyun Programlama le lgili Kaynak Kitaplar

www.bsenyurt.com Page 2002


Beginning .Net Game Programming in C#
APress
David Weller, Alexandre Santos Lobao, Elen Hatton
414 Sayfa
Amazon Fiyat : 30.59$

C# and Game Programming: A Beginner's Guide


AK Peters Ltd.
Salvatore A. Buono
592 Sayfa
Amazon Fiyat : 39$

Beginning C# Game Programming (Game Development)


Muska & Lipman/Premier-Trade
Ron Penten
344 Sayfa
Amazon Fiyat : 20.39$

Managed DirectX 9 Kick Start : Graphics and Game Programming


Sams
Tom Miller
432 Sayfa
Amazon Fiyat : 23.79 $

Bu anlattm olaylar yaklak bir ay kadar nce gerekleti. u anda bu kitaplarda az da olsa
ilerlemi durumdaym. nann sevgili okurlarm bu ie giritiim iin ok ama ok memnunum. Biraz
matematik, biraz teori biraz pratik derken bir eyler kapmaya baladm bile. Hereyden nce ilk
konularda, eski dostumuz Hipotens' grmek bile son derece gzeldi. Konular anlamaya
baladma gre imdi tek yapmam gereken rendiklerimi uygulayarak pekitirmek ve sizler ile
paylamak. Artk bu kadar laf kalabalndan sonra, bu makalemizin konusunada deinme zaman
geldi.

Bu gn, oyun programlamann nemli temellerden birisi olan arpma (Collision) tekniklerine giri
yapacaz. Bir oyunda, bir birinden bamsz elerin bir birleriyle arpmalar zerinde
duracamz asl konu olacak. Bir sava oyununda taraflarn bir birlerine kar yaptklar hamleler
sonucu kimin kime vurduunu tespit etmek, vurularn ynne veya iddetine gre, darbeyi alan
nesnelerin ne tr hareketlerde bulunacana karar vermek asdndan arpma teknikleri

www.bsenyurt.com Page 2003


gerekten nemlidir. Bu teknikler bir ka tanedir. Bu gn ben sizlere, 2 boyutlu koordinat
sisteminde drtgensel ekillerin arpmalarnn nasl tespit edilebileceini anlatmaya alacam.

Dortgenlerin baz alnd bu teknikte ama, objeleri iine alan ve snrlayan


drtgensel alanlarn birbirleri stne gelip gelmediklerinin tespit
edilebilmesidir.

ncelikle durumu analiz edebilmek amacyla aadaki ekli gz nne alalm.

ekil 1. Senaryo.

Senaryo gerei, kpek bal ve yar arabas nesnelerimizin hareketli olduklarn dnelim.
Burada, yar arabas ve kpek bal aslnda ekranda piksel olarak yer kaplamaktadr. Bu iki piksel
topluluunun arpp arpmadklarn test edebilmek iin kullanlabilecek en basit teknik,
nesnelerin evresini saran drtgenlerin bir birleri stne gelip gelmediklerini tespit etmektir. Bu
nedenle, senaryomuzda yar arabmz A isimli, kpek balmz ise B isimli drtgenler ile
evrelediimizi dnelim. te bu noktadan sonra iin iine biraz matematik girecek.

Eer bu iki nesnenin X koordinatlar arasndaki fark, geniliklerinin yarlarnn


toplamndan kk ise ve iki nesnenin Y koordinatlar arasndaki fark,
yksekliklerinin yarlarnn toplamndan kk ise, bu iki drtgen st ste
gelmi dolaysyla arpma (Collision) gereklemi demektir.

Bunun matematiksel olarak aadaki ekil ile daha iyi anlayabiliriz.

www.bsenyurt.com Page 2004


ekil 2. Koordinat, genilik ve ykseklik lleri.

Burada, her iki drtgenin ekrann sol st kesine olan uzaklklar ve genilik ile ykseklikleri
belirtilmektedir. Elbette bir nesnenin X koordinat uygulamada bu nesnenin Left zelliinin
deerine, Y koordinat ise Top zelliinin deerine iaret etmektedir. Ayn ekilde genilik iin
Width, ykseklik iin ise Height zelliklerinden yararlanlacaktr. Yukarda bahsettiimiz arpma
koulunun matematiksel ifadesi ise aadaki gibi olacaktr.

ekil 3. arpma (Collision) koullar.

Dikkat edecek olursanz eitsizliklerin sol taraflarndaki ifadelerde mutlak deer sz konusudur. Bu
nedenle Math snfnn Abs isimli metodu iimize ok yarayacaktr. Bu ifadedeki her iki eitsizliinde
gereklemesi halinde, drtgenlerin st ste geldiklerinden, dolaysyla arptklarndan sz
edebiliriz. Bu teorimin gerekliini kontrol etmenin en gzel yolu uygulama zerinde olacaktr. Bu
amala aadaki gibi basit bir windows uygulamas oluturdum.

www.bsenyurt.com Page 2005


ekil 4. Uygulama.

Bu uygulamada, A isimli drtgen nesnesini klavyedeki A,S,D,E tular ile hareket ettirebileceiz.
Bizim buradaki amacmz, arpma olduu takdirde bunun gerekleip gereklemediini tespit
edebilmek. Bu amala, nesnelerin ekrandaki koordinatlarnda izlediimiz label nesnelerimiz var.
Gelelim uygulamamzn kodlarna.

private void Yaz()


{
lblXA.Text=A.Left.ToString();
lblYA.Text=A.Top.ToString();
lblWidthA.Text=Convert.ToString((A.Width/2));
lblHeightA.Text=Convert.ToString((A.Height/2));

lblXB.Text=B.Left.ToString();
lblYB.Text=B.Top.ToString();
lblWidthB.Text=Convert.ToString((B.Width/2));
lblHeightB.Text=Convert.ToString((B.Height/2));
}

www.bsenyurt.com Page 2006


private void frmCarpisma_Load(object sender, System.EventArgs e)
{
Yaz();
}

/* arpma Kontrolnn gerekletirildii metod */


private bool CarpismaKontrol()
{
float mutlakX=Math.Abs((A.Left+(A.Width/2))-(B.Left+(B.Width/2)));
float mutlakY=Math.Abs((A.Top+(A.Height/2))-(B.Top+(B.Height/2)));

float farkGenislik=(A.Width/2)+(B.Width/2);
float farkYukselik=(A.Height/2)+(B.Height/2);

if((farkGenislik>mutlakX)&&(farkYukselik>mutlakY))
{
return true;
}
else
return false;
}
}
private void frmCarpisma_KeyPress(object sender, System.Windows.Forms.KeyPressEventArgs e)
{
if(e.KeyChar==(Char)Keys.D)
{
A.Left+=10;
}
if(e.KeyChar==(Char)Keys.A)
{
A.Left-=10;
}
if(e.KeyChar==(Char)Keys.W)
{
A.Top-=10;
}
if(e.KeyChar==(Char)Keys.S)
{
A.Top+=10;
}

Yaz();
if(CarpismaKontrol())
{
lblCarpismaKontrol.Text="arpisma var...";
}
else
{
lblCarpismaKontrol.Text="";

www.bsenyurt.com Page 2007


}
}

Uygulamada dikkat ederseniz, teoremi aadaki kod satrlarndaki gibi uyguladk.

float mutlakX=Math.Abs((A.Left+(A.Width/2))-(B.Left+(B.Width/2)));/* X koordinatlar aras farkn


mutlak deeri. */
float mutlakY=Math.Abs((A.Top+(A.Height/2))-(B.Top+(B.Height/2)));/* Y koordinatlar aras
farkn mutlak deeri . */

float farkGenislik=(A.Width/2)+(B.Width/2); /*Geniliklerin yarlarnn toplam.*/


float farkYukselik=(A.Height/2)+(B.Height/2); /* Yksekliklerin yarlarnn toplam. */

if((farkGenislik>mutlakX)&&(farkYukselik>mutlakY)) /* Eer koul doru ise arpma vardr. */


{
return true;
}
else
return false;
}

imdi uygulamamz test edelim. A, S, D, W tular ile (bunlara basarken Caps Lock ak olmal) A
isimli buton kontrolmz 10' ar birim hareket ettirebilmekteyiz. Eer kutular stste getirirsek
arpma teoreminin baarl bir ekilde gerekletiini grrz.

www.bsenyurt.com Page 2008


ekil 5. arpma gerekleti.

Bu teknik en basit arpma modelidir. Nesnelerin drtgenler ierisinde dnlmesi araba eklinde
olduu gibi, bolua denk den alanlarnda hesaba katlmasna neden olmaktadr. Ancak i
dairesel nesnelerin arpmasna geldiinde (rnein tenis toplarnn raketler arpmas) hatta, daire
ve karesel nesnelerin arpmasna geldiinde dahada karmaklamaktadr.

Artk ilerleyen zamanlarda bu teoremleri incelemeye alacam. rendikede siz deerli


okurlarma aktaracam. Artk 24 blmm srer bir tetris oyunu yazmamz, 24 ay m srer
bilemiyorum. En azndan daha nceden bildiim hatta mutlaka bildiim ama farkna varamadm
algoritmalar renmek beni olduka memnun etti. Umuyorum ki sizlerde bu yaz dizisinden honut
kalrsnz. Tekrar grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve SqlDependency Snf Yardmyla


Query Notification ( 26.10.2004 ) - Ado.Net 2
www.bsenyurt.com Page 2009
Deerli Okurlarm Merhabalar,

ou zaman istemci uygulamalarda, kullancya sunduumuz verilerin yer ald tablolarda baka
kullanclar tarafndan gerekletirilen deiikliklerin annda grnmesini isteriz. SqlDependency
snf sayesinde artk, bir veritabannda meydana gelen deiiklikleri (u an iin Sql Server ve
Yukon) annda yakalayabilme ansna sahibiz. te bugnk makalemizde aslnda son derece derin
ve geni bir konu olan Sql Server Notification meselesini ok basit bir rnek ve Ado.Net 2.0 ile
gelen yeni snflardan birisi olan SqlDependency yardmyla incelemeye alacaz. lk olarak u
soruyu dnelim.

Sunucu zerinde ne gibi gelimeler


olduunda annda haberdar olmak
isteyebiliriz?

Verilerde meydana gelebilecek deiikler; bir


baka deyile yeni satrlarn eklenmesi, satrlarn
silinmesi veya gncellenmesi.

Tablo zerinde Drop, Alter veya Delete


ilemlerinin uygulanmas.

Sql sunucusunun yeniden balatlmas.

Sql sunucusu zerinde hatalar olumas


nedeniyle sunucunun ileyiinin durmas.

te bu gibi durumlarda, istemci uygulamalarn meydana gelecek olan deiikliklerden annda


haberdar olmasn isteyebiliriz. Bu durum zellikle, balantsz katman nesnelerinin kullanld
uygulamalarda byk nem kazanmaktadr. Peki bu annda haber bildirilmesini nasl salayabiliriz?
Bunun iin kullanlan mimari kabaca aadaki ekilde olduu gibidir.

www.bsenyurt.com Page 2010


ekil 1. Mimari.

Dilerseniz ksaca mimarinin ileyiinden ve bileenlerinden bahsedelim. SqlDependency snf, bir


SqlCommand ile ilikilendirilerek kullanlr ve isel olarak bir SqlNotificationRequest nesnesinide
barndrr. (Bu snfi ilerleyen makalelerimizde incelemeye alacaz.) SqlCommand snfnn
Notification ilemine uyan bir Select sorgusu iermesi gerekir. yleki bu Select sorgusu u anki
versiyonlar itibariyle aadaki gibi olamaz.

Select * From Tablo

Select sorgusunda talep edilen alan isimleri aka belirtilmelidir. Bununla birlikte, Tablo' nun
sahibide yani yaratcsda aka belirtilmelidir. Yani ancak aadaki gibi bir sql ifadesi Notification
desteini salayabilir.

Select Ad,Soyad From dbo.Tablo

Belirtilen Sql ifadesi altrldnda, SqlDependency nesnesi ilgili SqlCommand nesnesi iin
sunucuda bir Notification alacan sql sunucusuna bildirir. Sql sunucusu bu mesaj zerine ilgili sql
komutunu altrr ve Notification nesnesini sunucuya register eder. Bu bize, altrlan sql
sorgusunun sunucaya ekstradan bir takm bilgiler daha gnderdiini gstermektedir. Bu bilgiler
ounlukla, kayd tutulacak Notification ile ilgilidir ve SqlDependency snfnn ilgili yapc metodlar
yardmyla ayarlanabilir.

Notification nesnesi, sunucuya kayt edildikten sonra, komutun almas ile elde edilen sonular n
bellee alnr ve ilgili Notification nesneside Server Service Broker Queue tarafndan kuyrua atlr.
Buradaki n bellekleme ilemi aslnda bir temp tablosunun oluturulmasndan baka bir ey
deildir. Bu noktadan itibaren Sql sunucusu, ilgili satr kmesini izlemeye balar. Eer satr kmesi
zerinde yukarda bahsettiimiz durumlardan birisi nedeni ile deiiklikler olursa,

www.bsenyurt.com Page 2011


sp_DispatcherProc sistem prosedr yardmyla istemci uygulamann SqlDependency snfna ait
olan OnChange olayna bilgi mesaj gider.

Mimari her ne kadar kark gibi grnsede, uygulanabilirlii son derece kolay ve basittir. Bu
amala olay daha iyi irdeleyebilmek iin aadaki Windows uygulamasn gz nne alalm.

ekil 2. Windows Uygulamamz

#region Using directives

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Windows.Forms;
using System.Data.SqlClient;

#endregion

namespace NotifySample
{
partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
SqlConnection con;
SqlCommand cmd;
SqlDependency dep;
SqlDataAdapter da;
DataTable dt;

www.bsenyurt.com Page 2012


private void btnVeriCek_Click(object sender, EventArgs e)
{
con = new SqlConnection("data source=localhost;initial catalog=Dukkan;integrated
security=SSPI");
con.Open();
cmd = new SqlCommand("Select DetayID,PersonelID,Ad,Soyad,Mail From
dbo.PersonelDetay", con);
dep = new SqlDependency(cmd);
SqlDependency.Start("data source=localhost;initial catalog=Dukkan;integrated
security=SSPI");
dep.OnChange+=new OnChangeEventHandler(dep_OnChange);
da = new SqlDataAdapter(cmd);
dt = new DataTable();
da.Fill(dt);
dgVeriler.DataSource = dt;
}

void dep_OnChange(object sender, SqlNotificationEventArgs e)


{
MessageBox.Show("YENI VERILER EKLENDI...TAZELEME YAPIN");
}
}
}

Uygulamamz, Yukon zerinde Dukkan isimle veritabannda yer alan PersonelDetay isimli tabloya
ait verileri kullanmaktadr. Kullanc Veri ek balkl butona bastnda ilgili tabloya ait tm satrlar
DataGridView kontrolne yklenmektedir. imdi gelelim, burada nemli olan kod satrlarna. Dikkat
ederseniz, SqlDependency snfna ait nesne rneimizi aadaki kod satr ile oluturuyoruz.
Bylece ilgili komut iin Notification servisinin kullanlacan belirtmi oluyoruz.

dep = new SqlDependency(cmd);

Bu arada Select sorgumuzun kurallara uygun bir yapda olduuna dikkat edelim. Yani, alan adlarn
ve tablonun sahibini aka belirtiyoruz. Daha sonra ise, SqlDependency snfmza OnChange
olayn aadaki kod satr ile ekliyoruz.

dep.OnChange+=new OnChangeEventHandler(dep_OnChange);

Bu olayn bizim iin byk bir nemi var. Nitekim, sunucu zerinde n belleklenen veri kmesinde
deiiklikler olduunda, sql sunucusu tarafndan uygulmaya bir Notification mesaj gnderilecektir.
te bu mesajn ele alnaca olay SqlDependency snfna ait OnChange' dr. Bu olayn prototipi
aadaki gibidir.

public event OnChangeEventHandler OnChange;

www.bsenyurt.com Page 2013


Grdnz gibi bu olay OnChangeEventHandler temsilcisinin tanmlad metodlar altrabilir.
OnChangeEventHandler temsilcisinin prototipi ise aadaki gibidir.

public sealed delegate void OnChangeEventHandler( object sender, SqlNotificationEventArgs e );

Bu temsilcinin iaret edecei metodlara ait ikinci parametre SqlNotificationEventArgs snf tipinden
olup olduka nemlidir. Nitekim bu parametre yardmyla, gelen bildirinin hangi olaya istinaden
olutuunu ayrt edebilir ve ilemlerimize yn verebiliriz. Bu snfda detayl bir ekilde ilerleyen
makalelerimizde inceleyeceiz. Olay metodumuzda ise basit olarak herhangibir Notification mesaj
alndnda bir MessageBox' n kmasn salyoruz.

void dep_OnChange(object sender, SqlNotificationEventArgs e)


{
MessageBox.Show("YENI VERILER EKLENDI...TAZELEME YAPIN");
}

imdi uygulamamz altralm ve verileri ekelim. Yazdmz kodlar gerei, Sql suncusu zerinde
Select sorgumuza istinaden bir Notification nesnesi register edilecektir. imdi biz bu noktada
dorudan Yukon zerinden yeni bir satr gireceiz. (Aslnda ayn uygulamann baka bir rneinden
veya baka bir uygulamadanda bu tablo zerinde deiiklikler yapabiliriz) Bunu uygulamamz
alyorken yapacaz.

ekil 3. Yukon zerinden tablomuza yeni bir satr ekliyoruz.

Bu ilemi gerekletirdiimiz anda, uygulamamza bir bildiri mesaj iletilir ve tabloda deiiklik
olduu sylenir. Bunun sonucu olarakta, SqlDependency nesnemiz ile ilikilendirdiimiz OnChange
olay aktif hale gelecektir. Sonu aadaki gibi olacaktr. Yeni satr eklenir eklenmez uygulama
OnChange olayn altracaktr.

www.bsenyurt.com Page 2014


ekil 4. Notification mesaj uygulamaya gnderildi.

Dolaysyla biz, veri ekme ilemimizi bu olay ierisine alarak istemci uygulamann daima gncel
veriler ile konumasn salayabiliriz. SqlDependency snfnn pek ok yesi ve nemli zellii
vardr. Bir sonraki makalemizde, bu snf daha detayl bir ekilde incelemeye alrken,
gerekleen deiikliin tipine gre nasl hareket edebileceimizide greceiz. Tekrardan
grnceye dek salcakla kaln.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve Sql Komutlarn Asenkron


Olarak Yrtmek - 3 ( 22.10.2004 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Hatlayacanz gibi, Asenkron eriim teknikleri ile ilgili nceki makalelerimizde Polling ve Callback
modellerini incelemitik. Bu makalemizde ise, Wait modelini incelemeye alacaz. Wait modeli,
dier asenkron sql komutu yrtme tekniklerine gre biraz daha farkl bir ileyie sahiptir. Bu
model, baz durumlarda asenkron olarak alan sql komutlar tamamlanncaya kadar uygulamay
bekletmek istediimiz durumlarda kullanlmaktadr. WaitHandle modeli aslnda birden fazla sunucu
zerinde alacak farkl sorgular sz konusu olduunda ie yarayacak etkili bir tekniktir. Dier
taraftan e zamanl alan sorgu sonularnn uygulamamn kalannda etkili olduu durumlarda da
tercih edilmelidir. Wait modeli u an iin 3 teknik ile gerekletirilmektedir. Dilerseniz bu tekniklerin
ne olduklarn ve nasl uygulandklarn ksaca inceleyelim.

www.bsenyurt.com Page 2015


ekil 1. Wait Modelleri.

Wait Modellerini en kolay haliyle anlayabilmek iin ie, WaitOne modeli ile balamakta fayda vardr.
WaitOne modeli, sadece tek bir sql komutu iin uygulamann bekletilmesini salar. Ne kastettiimi
anlamak iin aadaki rneimizi dikkatle inceleyelim.

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Threading;

#endregion

namespace WaitModeli
{
class Program
{
static void Main(string[] args)
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;async=true");
SqlCommand cmd = new SqlCommand("WAITFOR DELAY '0:0:5';UPDATE
Production.Product SET ListPrice=ListPrice*1.15", con);

con.Open();
IAsyncResult res1 = cmd.BeginExecuteNonQuery(); //Komutu asenkron olarak
altr.

WaitHandle wh1 = res1.AsyncWaitHandle; // WaitHandle nesnesini al.


Console.WriteLine("Herhangibir islem"); // Bu aralkta e zamanl kodlar alr.

wh1.WaitOne(); // Eer komut tamamlanmamsa bekle.


int sonucUpdate = cmd.EndExecuteNonQuery(res1); // Komut ileyiini tamamlad
sonular al.
con.Close();
Console.WriteLine(sonucUpdate.ToString() + " SATIR GUNCELLENDI");

www.bsenyurt.com Page 2016


Console.ReadLine();
}
}
}

Bu rnek console uygulamasnda, Yukon zerinde yer alan AdventureWorks veritabanndaki


Product isimli tabloda gncelleme ilemi gerekletiren bir komut sz konusudur. Senaryonun daha
gereki olmas iin sql zerinde WaitFor ile ilemi 5 saniye ge balatyoruz. Biz komutu asenkron
olarak yrtmek istiyoruz. Lakin komutun sonularn almadan nce bir takm kod satrlarnnda
altrlmasn istiyoruz. Buraya kadar her ey normal. Ancak e zamanl yryen kod satrlarndan
sonrada, eer ilenen komut halen daha tamamlanmamsa, o komut tamamlanncaya kadar
gncel uygulamann duraksamasn ve baka bir ilem yapmamasn istiyoruz. te bu gibi tek
komutlara wait modelini uygulamak istediimizde, WaitHandle snfnn statik metodlarndan olan
WaitOne' kullanmaktayz.

Uygulama kodlarmz inceldiimizde ilk olarak asenkron olarak almasn istediimiz komuta ait
Begin metodlarndan birisini kullanarak IAsyncResult arayz tipinden bir nesne rneini elde
ediyoruz.

IAsyncResult res1 = cmd.BeginExecuteNonQuery();

Daha sonra ise, bu arayz nesnesinin AsyncWaitHandle zellii ile bir WaitHandle nesnesi
oluturuyoruz.

WaitHandle wh1 = res1.AsyncWaitHandle;

Bu WaitHandle nesnesinin elde edilii srasnda ve sonrasndaki uygulama satrlar sql komutumuz
ile ezamanl olarak yrtlmektedir. Biz WaitHandle nesnemizin WaitOne metodunu
uyguladmzda, alan sql komutunun tamamlandna dair bir sinyal WaitHandle nesnesine
gelinceye kadar aktif thread' in duraksatlmasn salam oluyoruz.

wh1.WaitOne();

Gelelim, WaitAll tekniine. WaitAll ise, birden fazla sql komutunun asenkron olarak alt
durumlarda devreye giren ve tm komutlar baarl bir ekilde tamamlanncaya kadar aktif
uygulamay duraksatan bir tekniktir. Bu sefer, WaitHandle nesneleri her bir komut iin ayr ayr
tanmlanmaldr. Dolaysyla bize WaitHandle tipinden bir dizi gerekmektedir. Aadaki rnek
uygulama, WaitAll tekniinin nasl uygulandn gstermektedir.

SqlConnection con1 = new SqlConnection("data source=localhost;initial


catalog=AdventureWorks;integrated security=SSPI;async=true");
SqlConnection con2 = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;async=true");
SqlConnection con3 = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;async=true");
SqlCommand cmd1 = new SqlCommand("WAITFOR DELAY '0:0:4';UPDATE Production.Product SET
ListPrice=ListPrice*1.15", con1);

www.bsenyurt.com Page 2017


SqlCommand cmd2 = new SqlCommand("WAITFOR DELAY '0:0:5';UPDATE Production.Product SET
ListPrice=ListPrice*1.20", con2);
SqlCommand cmd3 = new SqlCommand("WAITFOR DELAY '0:0:2';UPDATE Production.Product SET
ListPrice=ListPrice*1.45", con3);

con1.Open();
IAsyncResult res1 = cmd1.BeginExecuteNonQuery();
con2.Open();
IAsyncResult res2 = cmd2.BeginExecuteNonQuery();
con3.Open();
IAsyncResult res3 = cmd3.BeginExecuteNonQuery();

WaitHandle[] wh = new WaitHandle[3];


wh[0] = res1.AsyncWaitHandle;
wh[1] = res2.AsyncWaitHandle;
wh[2] = res3.AsyncWaitHandle;

Console.WriteLine("Burada bir eyler yaplr...");


for (int i = 1; i < 100; i++)
{
Console.Write(i.ToString()+" ");
}
Console.WriteLine();

WaitHandle.WaitAll(wh);
int sonucGuncel1 = cmd1.EndExecuteNonQuery(res1);
con1.Close();
int sonucGuncel2 = cmd2.EndExecuteNonQuery(res2);
con2.Close();
int sonucGuncel3 = cmd3.EndExecuteNonQuery(res3);
con3.Close();
Console.WriteLine(sonucGuncel1 + " SATIR GUNCELLENDI");
Console.WriteLine(sonucGuncel2 + " SATIR GUNCELLENDI");
Console.WriteLine(sonucGuncel3 + " SATIR GUNCELLENDI");
Console.ReadLine();

Burada grld gibi, adet sql komutumuz var. Her ne kadar anlamsz olsalarda sonuta
amacmz Wait modelinin nasl ilediini anlamaktr. WaitHandle dizisi iindeki her eleman, bu
elemanlar ile ilikili komutlara ait IAsyncResult nesnelerinin AsyncWaitHandle zellikleri yardmyla
oluturulur. Bu esnada, sql komutlar asenkron olarak yrtlmektedir. Dolaysyla WaitHandle
snfnn WaitAll metodunu altrdmz satra kadar olan kodlar, komutlar ile birlikte e zamanl
olarak yrmektedir. WaitAll metodunun olduu satra gelindiinde, uygulama alan komutlarn
hepsi tamamlanm olmak artyla yoluna devam eder. Bir baka deyile, eer bu satra
gelindiinde halen daha tamamlanmam komutlar varsa, varsaylan timeout sresi doluncaya
kadar bu komutlarnda tamamlanmas beklenir.

Wait modelindeki son teknik ise, WaitAny yapsdr. Bu teknik bir ncekilere nazaran biraz daha
karmaktr. WaitAny tekniinde, asenkron olarak yrtlen komutlar srasyla tamamlanncaya
kadar uygulama bekletilir. Burada sralamay belirten WaitAny metodudur. Nitekim, ileyii nce
tamamlanan metodun WaitHandle nesnesi dierlerine gre daha ncelikli olarak sinyal alacak ve

www.bsenyurt.com Page 2018


sonular ortama aktarlacaktr. WaitAny tekniinde iin ilgin ve bir o kadarda nemli olan yan,
WaitAny metodunun geriye integer olarak dndrd deerin kullanlmasnda yatmaktadr. Bu
deer aslnda, WaitHandle dizisi iindeki indeksi iaret etmektedir. Yani, WaitAny metodu ile aktif
olarak alnan WaitHandle eer tamamlanmsa, metodun geriye dndrecei deer bu komuta bal
WaitHandle elemannn dizi ierisindeki indeksidir.

Buna gre, WaitAny tekniinin, WaitHandle dizisi iindeki tm elemanlar ileyen bir dng
ierisinde kullanlmas ve bu metodun dndrd deerlerinde dizi indeksleri ile burada
karlatrlmas gerekmektedir. Her ne kadar kark bir teknikmi gibi grnsede, aadaki kod
blounu incelediimizde olay ok daha kolay anlayabileceimize inanyorum.

SqlConnection con1 = new SqlConnection("data source=Manchester;initial


catalog=AdventureWorks;integrated security=SSPI;async=true");
SqlConnection con2 = new SqlConnection("data source=Manchester;initial
catalog=AdventureWorks;integrated security=SSPI;async=true");
SqlCommand cmd = new SqlCommand("WAITFOR DELAY '0:0:5';UPDATE Production.Product SET
ListPrice=ListPrice*1.15", con1);
SqlCommand cmd2 = new SqlCommand("WAITFOR DELAY '0:0:3';UPDATE Production.Product SET
ListPrice=ListPrice*1.20", con2);

con1.Open();
IAsyncResult res1 = cmd.BeginExecuteNonQuery();
con2.Open();
IAsyncResult res2 = cmd2.BeginExecuteNonQuery();

WaitHandle[] wh = new WaitHandle[2];


wh[0] = res1.AsyncWaitHandle;
wh[1] = res2.AsyncWaitHandle;
for (int i = 0; i < 2; i++)
{
int iIndis = WaitHandle.WaitAny(wh);
if (iIndis == 0)
{
int result=cmd.EndExecuteNonQuery(res1);
con1.Close();
Console.WriteLine(iIndis.ToString()+" tamamland." +result.ToString());
}
if (iIndis == 1)
{
int result = cmd2.EndExecuteNonQuery(res2);
con2.Close();
Console.WriteLine(iIndis.ToString() + " tamamland." + result.ToString());
}
}

Dilerseniz bu kod parasn inceleyelim. WaitHandle dizimizi, iki sql komut iin gerekli olan
WaitHandle nesnelerini tutmak zere kullanlyoruz. Bu dizi iin gerekli WaitHandle nesnelerini elde
edebilmek amacylada, IAsyncResult arayzne ait AsyncWaitHandle zelliini kullanmaktayz.
Buraya kadar herey anlalr. Asl nemli olan atmz for dngsdr. Bu dng, WaitHandle
dizisinin eleman says kadar iterasyon yapmaktadr. Dng ierisinde,

www.bsenyurt.com Page 2019


int iIndis = WaitHandle.WaitAny(wh);

satr ile, dizi iindeki WaitHandle nesnelerinden her hangibirinin ilgili komutun bittiine dair bir
sinyal alp almadna baklr. Eer byle ise, komut ileyiini tamamlam demektir. Bu durumda
WaitAny metodu geriye integer bir deer dndrr. Elbetteki ileyen sql komutlarndan her hangibir
tamamlanmam ise, uygulama bu satrda bu komutlardan herhangibiri tamamlanncaya ve ilgili
WaitHandle nesnesine sinyal gnderilinceye kadar duraksar. Dnen integer deer, WaitAny
metodunun yaps gerei, WaitHandle dizisi iindeki ilgili WaitHandle nesnesinin indeks deerini
iaret eder. Bu nedenle uygulama bir sonraki satra getiinde if kouluna girer ve burada hangi
komutun tamamland WaitAny metodundan dnen integer deer yardmyla belirlenir. Tabiki
tamamlanan komuta uygun olan Begin metoduda bu if dngs iinde altrlr.

Daha sonra ise, dng ikinci iterasyondan ileyiine devam eder. Bu kez halen daha almakta
olan dier sql komutlarna ait WaitHandle nesnelerinin bir sinyal alp almadna baklr. Yine, ilk
iterasyonda olduu gibi nce tamamlanan komuta ait WaitHandle nesnesi gerekli sinyali alr ve
geriye dizi iindeki indeks deerini dndrr. Ardndan tekrar if koullar uygulanr ve gerekli
sonular elde edilir. Bu ileyi dng iindeki tm WaitHandle nesneleri ilikili olduklar komutlarn
tamamlandna dair sinyaller alncaya, dolaysyla komutlar ileyiini bitirinceye kadar devam eder.

Grld gibi Wait modeli ierdii teknikler itibariyle biraz karktr. Ancak ilerleyen zamanlarda,
Ado.Net 2.0' n son srmnde bu tekniklerin ok daha kullanl hale geleceine inanyorum. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Xml Web Servisleri - 5 (Mimarinin Temelleri -


DISCO) ( 07.10.2004 ) - Web Servis
Deerli Okurlarm, Merhabalar.

Disco, Microsoft tarafndan gelitirilmi bir keif mekanizmasdr. Web servislerinin kullanlmas ile
ilgili en nemli sorun, istemci uygulamalar gelitiren yazlmclarn, ne tip web servisleri
olduundan ve bunlar nasl kullanacandan haberdar olamamasdr. Bu amala, web servislerini
yaynlayanlar, bu servislere ait eriim bilgilerini e-mail veya baka iletiim yollar ile, istemcileri
gelitiren yazlm tarafna gnderebilirler. Ancak Microsoft bu iin daha kolay yaplabilmesini
salamak amacyla, web servislerinin kefedilmelerine kolaylk getiren teknikler gelitirmitir. Bu
tekniklerden birisi, disco tekniidir. Disco tekniinin kilit noktas, disco uzantl XML tabanl
dosyalardr. Daha nceki makalelerimizde, Visual Studio.Net ile gelitirdiimiz istemci uygulamay
gz nne aldmzda, GeoMat.disco isimli bir dosyannda yer aldn grrz.

www.bsenyurt.com Page 2020


ekil 1. Disco Dosyamz.

Bu dosyann ierii XML tabanl olup aadaki gibidir.

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


<discovery xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.xmlsoap.org/disco/">
<contractRef ref="http://localhost/GeoWebServis/GeoMat.asmx?wsdl" docRef="http://localhos
t/GeoWebServis/GeoMat.asmx" xmlns="http://schemas.xmlsoap.org/disco/scl/" />
<soap address="http://localhost/GeoWebServis/GeoMat.asmx" xmlns:q1="http://ilk/servis/"
binding="q1:Geometrik_x0020_HesaplamalarSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/" /></discovery>

Bu dkman, kullanlan web servisine nasl eriileceine ve zellikle wsdl dkmannn nasl
isteneceine dair nemli bilgileri barndrr. <contactRef boumunda yer alan ref nitelii ile wsdl
dkmanna eriim ekli belirtilir. Ayn boumda, docRef nitelii ile web servisine ait asmx uzantl
dosyann bulunduu url bilgisine yer verilmektedir. Bununla birlikte, <soap boumunda, soap
mesajlamas iin kullanlan isim alanlarnn tanmlamalar yer almaktadr.

Bu bilgilere sahip olan bir disco dkman sayesinde, kullanlmak istenen web servisine nasl
eriilecei bilinebilir. Disco uzantl bu XML dosyalarnn, web servislerinin kefine asl katks, .net
framework ile gelen disco aracnn kullanmnda olmaktadr. Bu durumu daha iyi anlayabilmek iin
u senaryoyu gz nne almakta yarar var; bir ok web servisi barndrdan bir web sitemiz
olduunu dnelim. Web servisleri, IIS gibi sunucularda gelitirildiklerinden, yazlm olan web
servislerinin sayfamz kullanan istemcilere yaynlamak isteriz. Baka bir deyile web
servislerimizden haberdar olunmasn isteriz. Disco tekniini bu yaynlama ilemi iin kullanabiliriz.
lk olarak, gelitirdiimiz tm web servisleri iin birer disco dkman oluturmalyz. Daha sonra
sitemizin al sayfasnda ufak bir deiiklik ile bu disco dkmanlarna disco arac yardmyla
eriilmesini salamalyz. Bu noktadan sonra, istemci uygulamalar gelitirecek olan yazlmclarn
tek yapmas gereken, balang sayfamzn bulunduu url bilgisini parametre olarak disco aracna
bildirmek olacaktr. imdi bu senaryoyu geree evirecek bir alma yapalm.

rnein yerel sunucumuzda (localhost) iki web servisimiz olduunu dnelim. u aamada bu
servislerin nasl yazldnn fazla bir nemi yoktur. imdi bu servislere ait disco dkmanlarn
oluturmamz gerekiyor. Bir disco dkmann herhangibir metin editrnde yazabiliriz. Ancak XML
ieriini oluturmak zor gelebilir. Bunun iin, Asp.Net in imkanlarndan faydalanabiliriz. Asp.Net bir
web servisine ait disco dosyasn talep ettiimizde bu dosyay browser da otomatik olarak

www.bsenyurt.com Page 2021


retecektir. Bu bir web servisi iin wsdl dkmannn istenme ekli ile ayn prensiplere dayanr ve
aadaki gibi gerekletirilir.

http://localhost/GeoWebServis/GeoMat.asmx?disco

Browser da yazdmz bu url den sonra web servisimize ait disco dkman bilgilerini aadaki gibi
elde ederiz.

ekil 2. Disco bilgilerinin tarayc penceresinden elde edilmesi.

imdi tek yapmamz gereken bu XML ieriini disco uzantl bir dosya halinde, localhost a yani
inetpub\wwwroot\ klasr altna kopyalamak olacaktr. Burada dikkat etmemiz gereken bir nokta
vardr. Browser dan elde ettiimiz xml ieriini bir disco dosyasna kopylarken iaretlerini
kaldrmay unutmamalyz. Aksi takdirde disco aracn kullanrken hata mesajlar ile karlarz.
rneimizde bu ilk disco dkmann localhost a GeoMat.disco ismi ile kaydedelim. Ayn ilemi
sunucumuzda yer alan tm web servisleri iin gerekletirebiliriz. Bu ilemlerin ardndan, localhost
un al sayfas olan localstart.asp dosyasn herhangibir editor de aalm. Burada Head taglar
arasna aadaki ekelemeleri yapmamz gerekiyor.

<head>
<link type='text/xml' rel='alternate' href='GeoMat.disco'/>

imdi burada ufak bir ilem daha yapmamz gerekiyor. Head tagnda yer alan bu satrdan sadece
bir tane tanmlayabiliriz. Normalde aadaki gibi bir tanmlama yapldnda, belirtilen iki disco
dosyasnnda ele alnaca ve istemcide altrlan disco arac sayesinde indirilebileceini
dnebiliriz.

<link type='text/xml' rel='alternate' href='GeoMat.disco'/>


<link type='text/xml' rel='alternate' href='PerSor.disco'/>

Ancak sanlann aksine, disco arac belirtilen sayfadaki link taglarndan sadece ilkini altrr ve bu
link ile belirtilen disco dkmann ve buna bal wsdl dkmann indirir. Bu sorunu halletmek iin,

www.bsenyurt.com Page 2022


ilk olarak belirttiimiz GeoMat.disco dosyasnda <discoveryRef boumunu ref nitelii ile birlikte
eklememiz yeterli olacaktr.

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


<discovery xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://schemas.xmlsoap.org/disco/">
<discoveryRef ref="PerSor.disco"/>
<contractRef ref="http://localhost/GeoWebServis/GeoMat.asmx?wsdl"
docRef="http://localhost/GeoWebServis/GeoMat.asmx"
xmlns="http://schemas.xmlsoap.org/disco/scl/" />
<soap address="http://localhost/GeoWebServis/GeoMat.asmx" xmlns:q1="http://ilk/servis/"
binding="q1:Geometrik_x0020_HesaplamalarSoap"
xmlns="http://schemas.xmlsoap.org/disco/soap/" />
</discovery>

DiscoveryRef boumu ile, GeoMat. disco dosyasnn referans edebilecei baka disco dosyalarn
belirtmi oluruz. Dolaysyla, balang sayfasnn bulunduu adres, disco arac iin parametre
olduunda, bu adresteki link tagnda yer alan disco dosyasnn yannda bu dosyann referans ettii
dier disco dkmanlarda ele alnabilecektir. Akas kk bir hile yapm oluyoruz. imdi tek
yapmamz gereken istemci bilgisayarn komut satrnda aadaki ifadeyi altrmak olacaktr.

D:\disco /out:deneme http://localhost/

ekil 3. Yerel sunucudaki disco ve wsdl dkmanlarnn elde edilmesi.

Bu ilemin ardndan, deneme isimli klasre bakldnda, GeoMat ve PerSor web servislerini
kullanabilmemiz iin gerekli proxy snflarn oluturmakta kullanacamz wsdl dkmanlarnn
disco dkmanlar ile birlikte indirildiini ve kayt edildiini grrz.

www.bsenyurt.com Page 2023


ekil 4. ndirilen disco ve wsdl dkmanlar.

Artk bu noktadan sonra yapmamz gerekenler sadece wsdl dkmanlar yardmyla proxy snfmz
oluturmak ve kullanmak olacaktr. Bir sonraki makalemizde grnceye dek hepinize mutlu
gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Xml Web Servisleri - 4 ( Mimarinin Temelleri -


WSDL) ( 02.10.2004 ) - Web Servis
Deerli Okurlarm, Merhabalar.

stemciler, web servisleri ile aralarndaki iletiimi, altklar makinede oluturulan proxy nesneleri
yardmyla gerekletirir. Bu, istemci uygulamann, web servisine ait yelerin farknda olmasn
gerektiren bir durumdur. Nitekim proxy nesnesini oluturan snf, web servisindeki public arayze
gre tasarlanr. Dolaysyla, istemci uygulamann kulland web servisine ait bilgileri bir ekilde
temin etmesi gerekmektedir. Visual Studio.Net ortamnda gelitirdiimiz istemci uygulamada,
projeye web servisinin referans olarak eklenmesi sonucu oluturulan baz dosyalar olduundan
bahsetmitik. Disco uzantl bir dosya, wsdl uzantl bir dosya ve proxy snfmza ait cs uzantl
dosya.

ekil 1. Istemci uygulamada oluturulan dosyalar.

www.bsenyurt.com Page 2024


Proxy snf ile wsdl dosyas arasnda sk bir iliki vardr. Visual Studio.Net ortamn gz nne
aldmzda, istemci uygulamaya Add Web Reference ile var olan bir web servisinin eklenmesi
durumunda ilk olarak .net, bu servisten wsdl uzantl bir dkman talep edicektir. WSDL (Web
Service Description Language - Web Servisleri Tanmlama Dili) ile oluturulan bu dkman XML
tabanl olup, web servisinin herkese ak olan yeleri, baka bir deyile arayz hakknda
tanmlamalara sahiptir. Talep edilen wsdl belgesi istemci uygulamaya indirilir. ndirilen dkman
yardmyla, istemcilerin web servisleri ile haberlemelerini kolaylatracak proxy snf oluturulur.

WSDL dkmanlar XML tabanl olmalar nedeni ile, her trl platforma indirilebilirler. XML tabanl
olup web servisinin yaps hakknda tanmlamalara sahip olduklarndan, indirilme sreleri ok uzun
deildir. Bir wsdl dkman istemci uygulamaya, web servisi ilk kez referans edildiinde indirilir.
Elbetteki web servisinde yaplacak gncellemelerin, istemci bilgisayar zerindede gerekletirilmesi
durumunda bu wsdl dkman tekrardan istemci bilgisayara indirilecektir.

ekil 2. WSDL Dkmannn Web Servislerinin Kullanmndaki Yeri.

Gelitirdiimiz istemci uygulamaya ait wsdl dkman aadaki gibidir.

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

<definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:s0="http://ilk/servis/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" targetNamespace="http://ilk/servis/"
xmlns="http://schemas.xmlsoap.org/wsdl/">

<types>

<s:schema elementFormDefault="qualified" targetNamespace="http://ilk/servis/">

<s:element name="DaireAlan">

www.bsenyurt.com Page 2025


<s:complexType>

<s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="r" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

<s:element name="DaireAlanResponse">

<s:complexType>

<s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="DaireAlanResult" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

<s:element name="DaireCevre">

<s:complexType>

<s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="r" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

<s:element name="DaireCevreResponse">

<s:complexType>

<s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="DaireCevreResult" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

<s:element name="DaireCevreDizi">

www.bsenyurt.com Page 2026


<s:complexType>

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="r" type="s0:ArrayOfDouble" />

</s:sequence>

</s:complexType>

</s:element>

<s:complexType name="ArrayOfDouble">

<s:sequence>

<s:element minOccurs="0" maxOccurs="unbounded" name="double" type="s:double" />

</s:sequence>

</s:complexType>

<s:element name="DaireCevreDiziResponse">

<s:complexType>

<s:sequence>

<s:element minOccurs="0" maxOccurs="1" name="DaireCevreDiziResult"


type="s0:ArrayOfDouble" />

</s:sequence>

</s:complexType>

</s:element>

</s:schema>

</types>

<message name="DaireAlanSoapIn">

<part name="parameters" element="s0:DaireAlan" />

</message>

<message name="DaireAlanSoapOut">

<part name="parameters" element="s0:DaireAlanResponse" />

</message>

<message name="DaireCevreSoapIn">

<part name="parameters" element="s0:DaireCevre" />

www.bsenyurt.com Page 2027


</message>

<message name="DaireCevreSoapOut">

<part name="parameters" element="s0:DaireCevreResponse" />

</message>

<message name="DaireCevreDiziSoapIn">

<part name="parameters" element="s0:DaireCevreDizi" />

</message>

<message name="DaireCevreDiziSoapOut">

<part name="parameters" element="s0:DaireCevreDiziResponse" />

</message>

<portType name="Geometrik_x0020_HesaplamalarSoap">

<operation name="DaireAlan">

<documentation>Daire Alan Hesabi Yapar</documentation>

<input message="s0:DaireAlanSoapIn" />

<output message="s0:DaireAlanSoapOut" />

</operation>

<operation name="DaireCevre">

<documentation>Daire evre Hesabi Yapar.</documentation>

<input message="s0:DaireCevreSoapIn" />

<output message="s0:DaireCevreSoapOut" />

</operation>

<operation name="DaireCevreDizi">

<documentation>Daire Cevre Hesabini Dizi Elamanlarina Uygular.</documentation>

<input message="s0:DaireCevreDiziSoapIn" />

<output message="s0:DaireCevreDiziSoapOut" />

</operation>

</portType>

<binding name="Geometrik_x0020_HesaplamalarSoap"
type="s0:Geometrik_x0020_HesaplamalarSoap">

www.bsenyurt.com Page 2028


<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />

<operation name="DaireAlan">

<soap:operation soapAction="http://ilk/servis/DaireAlan" style="document" />

<input>

<soap:body use="literal" />

</input>

<output>

<soap:body use="literal" />

</output>

</operation>

<operation name="DaireCevre">

<soap:operation soapAction="http://ilk/servis/DaireCevre" style="document" />

<input>

<soap:body use="literal" />

</input>

<output>

<soap:body use="literal" />

</output>

</operation>

<operation name="DaireCevreDizi">

<soap:operation soapAction="http://ilk/servis/DaireCevreDizi" style="document" />

<input>

<soap:body use="literal" />

</input>

<output>

<soap:body use="literal" />

</output>

</operation>

www.bsenyurt.com Page 2029


</binding>

<service name="Geometrik_x0020_Hesaplamalar">

<documentation>Geometrik Hesaplamalar zerine Metodlar Ierir. Ucgen, Dortgen gibi sekillere


ynelik alan ve evre hesaplamalari.</documentation>

<port name="Geometrik_x0020_HesaplamalarSoap"
binding="s0:Geometrik_x0020_HesaplamalarSoap">

<soap:address location="http://localhost/GeoWebServis/GeoMat.asmx" />

</port>

</service>
</definitions>

Bu wsdl dkman, gelitirdiimiz servise ait tm bilgileri ieririr. Hangi metodlarn kullanlabilecei,
bu metodlarn ne eit parametreler ald ve geriye ne tr deerleri nasl dndrd gibi bilgileri
sunar. Temel olarak bir WSDL dkman 5 ana ksmdan oluur.

ekil 3. Bir WSDL dkmann temel ksmlar.

Types ksmnda, web servisi ile ilikili SOAP mesajlarnda tanacak parametre ve geri dn
deerlerine ait ema elemanlar tanmlanr. rnein,

<s:element name="DaireAlan">

- <s:complexType>

- <s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="r" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

www.bsenyurt.com Page 2030


elamannda, DaireAlan isimli parametrenin double tipinden ve r isminde olduu belirtilmektedir.
Ayn ekilde geri dndrelecek deer ise, DaireAlanRespone elaman olarak tanmlanmtr.

<s:element name="DaireAlanResponse">

- <s:complexType>

- <s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="DaireAlanResult" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

Message ksmnda, web servisinin kabul edecei ve geri dndrecei mesajlara ait zet bilgiler yer
alr.

+ <message name="DaireAlanSoapIn">

<part name="parameters" element="s0:DaireAlan" />

</message>

+ <message name="DaireAlanSoapOut">

<part name="parameters" element="s0:DaireAlanResponse" />

</message>

+ <message name="DaireCevreSoapIn">

<part name="parameters" element="s0:DaireCevre" />

</message>

+ <message name="DaireCevreSoapOut">

<part name="parameters" element="s0:DaireCevreResponse" />

</message>

+ <message name="DaireCevreDiziSoapIn">

<part name="parameters" element="s0:DaireCevreDizi" />

</message>

+ <message name="DaireCevreDiziSoapOut">

www.bsenyurt.com Page 2031


Grld gibi, her SOAP mesaj iin In ve Out takl mesaj elemanlar mevcuttur. Buradaki
mesajlar, belirledikleri metod iin input ve output parametrelerini tanmlarlar. Bir baka deyile,
SOAP mesajlar iine konan ve SOAP mesajlar ile geri dnen parametreler tanmlanmaktadr.

-<message name="DaireAlanSoapIn">

<part name="parameters" element="s0:DaireAlan" />

</message>

- <message name="DaireAlanSoapOut">

<part name="parameters" element="s0:DaireAlanResponse" />

</message>

rnein burada, DaireAlan metodu iin oluturulan SOAP Mesajlarnn, iki tr tanmlanmtr. Web
servisine gidecek olan SOAP mesajlar, DaireAlan eleman tipinden parametre alacaktr. DaireAlan
elemannn types ksmnda tanmlanm olduuna dikkat edelim. Ayn ekilde, istemciye dnecek
olan SOAP mesajda, DaireAlanResponse eleman tipinden bir parametre ile gelecektir.

PortType ksmnda ise, her bir web servisi metodu iin birer operasyon tanmlamas yaplr. Bu
sayede, proxy nesnesi zerindeki bir metod ile web servisi zerinde kullanlabilir arlar
gerekletirilebilecektir. Baka bir deyile, web servisi zerinden gerekletirilebilecek
operasyonlarn tanmlamalar yaplmaktadr. Operasyon isimleri, burada grld gibi web
servisindeki metod isimleri ile ayndr. Buradaki eleman isimleri ile fiziki metodlar binding ksmnda
eletirilecektir.

- <portType name="Geometrik_x0020_HesaplamalarSoap">

- <operation name="DaireAlan">

<documentation>Daire Alan Hesabi Yapar</documentation>

<input message="s0:DaireAlanSoapIn" />

<output message="s0:DaireAlanSoapOut" />

</operation>

- <operation name="DaireCevre">

<documentation>>Daire evre Hesabi Yapar.</documentation>

<input message="s0:DaireCevreSoapIn" />

<output message="s0:DaireCevreSoapOut" />

</operation>

- <operation name="DaireCevreDizi">

<documentation>Daire Cevre Hesabini Dizi Elamanlarina Uygular.</documentation>

www.bsenyurt.com Page 2032


<input message="s0:DaireCevreDiziSoapIn" />

<output message="s0:DaireCevreDiziSoapOut" />

</operation>

</portType>

DaireAlan operasyonunu ele alalm. Bu operasyon gerekletiinde, SOAP mesajlarnn nasl bir
formatta olaca, baka bir deyile hangi tipte ve isimde elemanlar alaca, input message ve
output message elemanlarnn karlk geldii message elemanlarnda belirtilmitir. Message
elemanlar ise, bu mesajlarn tayaca parametrelerin tipini tanmlar. Bu tipler ise, types ksmnda
belirtilmitir.

Binding ksmnda, WSDL dkmanndaki her bir operasyon iin, bu operasyona web servisinde
karlk gelecek metod tanmlamalar yaplr. Bir baka deyile her bir operation eleman iin fiziki
olarak metod adresleri belirlenir. Bu adresler iin kullanlacak operasyonlar belirli olduu iin, bu
operasyonlara bal mesajlarda, fiziki adreslere balanm olur.

<binding name="Geometrik_x0020_HesaplamalarSoap"
type="s0:Geometrik_x0020_HesaplamalarSoap">

<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />

- <operation name="DaireAlan">

<soap:operation soapAction="http://ilk/servis/DaireAlan" style="document" />

- <input>

<soap:body use="literal" />

</input>

- <output>

<soap:body use="literal" />

</output>

</operation>

rnein, DaireAlan metoduna ilikin operation eleman, soapAction anahtar kelimesini takip eden
ksmda web servisinin isim alan ve metodu ile oluturulmu url ye balanmtr. Son olarak
service ksmnda ise, tanmlanan port larn gerekte fiziki olarak hangi adrese bakaca tanmlanr.

- <service name="Geometrik_x0020_Hesaplamalar">

<documentation>Geometrik Hesaplamalar zerine Metodlar Ierir. Ucgen, Dortgen gibi sekillere


ynelik alan ve evre hesaplamalari.</documentation>

- <port name="Geometrik_x0020_HesaplamalarSoap"

www.bsenyurt.com Page 2033


binding="s0:Geometrik_x0020_HesaplamalarSoap">

<soap:address location="http://localhost/geowebservis/geomat.asmx" />

</port>

</service>

WSDL dkmannn ierii karmak gibi grnsede, aslnda bu ieriin oluturulmas ile fazla
uramayz. Bir web servisi kullancs, Visual Studio.Net ortamn kullanmasa dahi, bu web
servisine ait WSDL dkmann yazmak zorunda deildir. Sonu olarak WSDL dkman, web
servisinden aadaki gibi bir url ile talep edilebilir.

http://localhost/geowebservis/geomat.asmx?wsdl

Bu url nin almas sonucunda, yazdmz web servisi iin otomatik olarak bir wsdl dkman
retilecektir. Peki elimizde Visual Studio.Net gibi bir gelitirme ortam yok ise, bu WSDL
dkmann kullanarak bir proxy snfn nasl oluturabiliriz? Bunun iin, .Net frameworkte yer alan
wsdl aracn kullanmamz yeterlidir.

Buraya kadar ilediklerimiz ile, bir web servisini kullanmak iin, bu web servisinin modelini istemci
bilgisayarda oluturacak bir proxy snfna ihtiyacmz olduunu biliyoruz. Bununla birlikte, bu proxy
nesnesini oluturmak iin, istemcinin web servisine ait wsdl dkmann talep ettiinide biliyoruz.
Her ne kadar Visual Studio.Net gibi bir grsel gelitirme ortamnda, web servisine ait referans
bilgisini istemci uygulamaya bir ka basit admda ekleyerek, proxy nesnesinin veri modelini
kapslleyecek snf oluturmak kolay olsada, bu ii .net framework ile gelen Wsdl arac yardmyla
da gerekletirebiliriz. Sonu olarak, her zaman elimizin altnda Visual Studio.Net gibi profesyonel
bir yazlm gelitirme platformu olmayabilir.

Wsdl arac .Net Framework ile birlikte standart olarak gelen bir aratr. Grevi, istemci uygulamalar
iin proxy nesnelerine veri modeli salayacak proxy snflarn oluturmaktr. Wsdl aracnn eitli
kullanm versiyonlar vardr. Bunlardan en ok kullanlan, web servisine ait asmx dosyasnn tam
url bilgisini parametre olarak alan aadaki yntemdir.

Wsdl url/<web servisi ad>.asmx

imdi, gelitirmi olduumuz web servisine ait bir proxy snfn wsdl arac ile nasl
oluturabileceimize bakalm. Bunun iin komut satrnda aadaki sz dizimini kullanmamz yeterli
olacaktr.

www.bsenyurt.com Page 2034


ekil 4. WSDL Aracnn kullanlmas.

Wsdl aracnn bu ekildeki kullanmnda dikkat etmemiz gereken tek nokta, web servisine ait url
bilgisinin tam olarak girilmesidir. Bu ilemin sonucunda, wsdl aracn altrdmz klasrde,
parametre olarak verilen web servise ait bir snf dosyas oluturulduunu grrz. Bu dosya, proxy
snfmza ait veri modelini kapslleyen bir yapda tekil edilmitir. Dosyann ad varsaylan olarak,
web servisini oluturduumuz snf dosyas iindeki, WebServices niteliindeki Name zelliininin
deerinden alnmtr.

ekil 5. Proxy snfmz.

stemci uygulamamz web servisi ile bu proxy snfndan rneklenecek nesneler zerinden
konuabilecektir. Wsdl arac, bir web servisi iin bir proxy snfn olutururken, ilk olarak servisten
wsdl dkmann talep eder. Bu ilem sonucunda istemci bilgisayara indirilen wsdl dkmanndaki
XML bilgilerinden yararlanlarak, wsdl arac uygun snf kodlarn otomatik olarak oluturur.
Oluturulan proxy snfna ait kodlar aadaki gibidir.

using System.Diagnostics;
using System.Xml.Serialization;
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;

[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="Geometrik HesaplamalarSoap",
Namespace="http://ilk/servis/")]
public class GeometrikHesaplamalar : System.Web.Services.Protocols.SoapHttpClientProtocol
{
public GeometrikHesaplamalar()
{
this.Url = "http://localhost/GeoWebServis/GeoMat.asmx";
}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ilk/servis/DaireAlan",
RequestNamespace="http://ilk/servis/", ResponseNamespace="http://ilk/servis/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public System.Double DaireAlan(System.Double r)
{
object[] results = this.Invoke("DaireAlan", new object[] {r});
return ((System.Double)(results[0]));
}

public System.IAsyncResult BeginDaireAlan(System.Double r, System.AsyncCallback callback,


object asyncState)
{
return this.BeginInvoke("DaireAlan", new object[] {r}, callback, asyncState);
}

www.bsenyurt.com Page 2035


public System.Double EndDaireAlan(System.IAsyncResult asyncResult)
{
object[] results = this.EndInvoke(asyncResult);
return ((System.Double)(results[0]));
}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ilk/servis/DaireCevre",
RequestNamespace="http://ilk/servis/", ResponseNamespace="http://ilk/servis/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public System.Double DaireCevre(System.Double r)
{
object[] results = this.Invoke("DaireCevre", new object[] {r});
return ((System.Double)(results[0]));
}

public System.IAsyncResult BeginDaireCevre(System.Double r, System.AsyncCallback callback,


object asyncState)
{
return this.BeginInvoke("DaireCevre", new object[] {r}, callback, asyncState);
}

public System.Double EndDaireCevre(System.IAsyncResult asyncResult)


{
object[] results = this.EndInvoke(asyncResult);
return ((System.Double)(results[0]));
}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ilk/servis/DaireCevreDiz
i", RequestNamespace="http://ilk/servis/", ResponseNamespace="http://ilk/servis/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public System.Double[] DaireCevreDizi(System.Double[] r)
{
object[] results = this.Invoke("DaireCevreDizi", new object[] {r});
return ((System.Double[])(results[0]));
}

public System.IAsyncResult BeginDaireCevreDizi(System.Double[] r, System.AsyncCallback


callback, object asyncState)
{
return this.BeginInvoke("DaireCevreDizi", new object[] {r}, callback, asyncState);
}

public System.Double[] EndDaireCevreDizi(System.IAsyncResult asyncResult)


{
object[] results = this.EndInvoke(asyncResult);
return ((System.Double[])(results[0]));
}
}

Gelelim, bu snf herhangibir uygulamada nasl kullanacamza. Artk elimizde bir proxy snf
olduu iin bu snftan faydalanarak herhangibir uygulamadan web servisine ait metodlara eriebilir
ve sonular deerlendirebiliriz. Bunu iin ilk olarak proxy snfmza ait bir dll oluturalm. Bu
sayede proxy snfn temsil edecek bir assemblya sahip olmu olacaz. Bylecede, herhangibir

www.bsenyurt.com Page 2036


platformdaki programda bu dll dosyasn kullanarak web servisimiz ile konuabileceiz. Bunun iin
komut satrndan aadaki satr altrmamz yeterli olacaktr.

ekil 6. Proxy snfmz iin dll' in oluturulmas.

imdi bu snf kullanacamz bir Console uygulamas gelitirebiliriz. Bunun iin aadaki kod
satrlarn ierecek bir snf dosyasn proxy snfmza ait dll ile ayn klasr altnda oluturalm.

using System;
using System.Web;
using System.Web.Services;
public class Uygulama
{
public static void Main(String[] args)
{
GeometrikHesaplamalar hesap=new GeometrikHesaplamalar();
double alan;
Console.WriteLine("YARICAP ");
double yariCap=Convert.ToDouble(Console.ReadLine());
alan=hesap.DaireAlan(yariCap);
Console.WriteLine("ALAN = {0}",alan);
}
}

Burada dikkat edilecek olursa, proxy snfmza ait bir nesne rneini oluturu eklimiz, Visual
Studio.Net ile gelitirdiimiz nceki istemci uygulamamzdaki ile ayndr. Bu benzerlik tesadfi
olmamakla birlikte, web servislerini kullanacak tm .net uygulamalar iin geerlidir. Kodlarn
yazm, kullanlan programlama diline gre deiebilir olmasna ramen teknik olarak yaplan i,
wsdl arac ile oluturulan proxy snfna ait bir nesne rneinin oluturulmasdr. rneklendirme
ilemini izleyen satrlarda rnek olmas asndan, web servisimizdeki DaireAlan metodu arlm
ve bu metodun sonucu ekrana yazdrlmtr. Son aamada, bu snf dosyamz aadaki ekilde
olduu gibi derlememiz gerekecektir.

www.bsenyurt.com Page 2037


ekil 7. Uygulamann almas sonucu.

Bu ilemlerin sonucunda uygulamamzn bulunduu klasrdeki dosyalar aadaki gibi olacaktr.

ekil 8. Dosyalar.

imdi uygulamamz komut satrndan altralm. Ekrandan bir yarap deeri girmemiz istenir.
Girdiimiz deer, proxy snfndan rneklediimiz nesne araclyla Soap mesaj olarak kodlanarak
web servisine iletilir. Web servisi mesaj zer, parametreyi alr ve ilgili metodu altrr.
Sonu(lar), Soap mesaj olarak kodlanarak, istemciye gnderilir. stemci uygulamaya ait proxy
snfnca zlen mesajdan sonu(lar) alnr ve konsol ekranna yazdrlr.

Son olarak Wsdl aracnn kullanmna ilikin dier tekniklere bir gz atalm. Proxy snfmzn ismini
kendimiz belirlemek istersek aadaki rnekte grlen komut satrn kullanrz.

Wsdl /out:ProxyAdi.cs http://localhost/geowebservis/geomat.asmx

Baz durumlarda, web servisinin bulunduu sunucuya giri izni gerekebilir. Bunun iin wsdl aracn
aadaki gibi, domain ad, kullanc ad ve ifre parametreleri ile birlikte kullanrz.

Wsdl http://localhost/geowebservis/geomat.asmx /domain:BURKI /username:Admin


/password:Password

Bir web servisinin url bilgisini kullanarak proxy snfn oluturabileceimiz gibi, fiziki yol bilgisi ile
birlikte var olan wsdl belgesini kullanarakta bu snf oluturabiliriz.

Wsdl d:\inetpub\wwwroot\geowebservis\geomat.wsdl

Bir proxy snfna ait kodlar, standart olarak C# dili baz alnarak oluturulur. Eer dier .net
dillerinden birisi ile oluturulmasn istersek aadaki gibi bir komut satrn kullanrz.

www.bsenyurt.com Page 2038


Wsdl /language:VB http://localhost/geowebservis/geomat.asmx

Bir proxy snfn, web servisine ait bir disco dkman yardmylada oluturabiliriz. Peki disco ad
verilen discovery(keif) dosyalarnn web servisleri-istemci sistemindeki yeri nedir? Bu konuyuda
bir sonraki makalemizde incelemeye alacaz. Tekrardan grnceye dek, hepinize mutlu
gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Xml Web Servisleri - 3 ( Mimarinin Temelleri -


SOAP) ( 01.10.2004 ) - Web Servis
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Xml Web Servislerinin mimarisine daha yaknda bakmaya alacak ve SOAP
(Simple Object Access Protocol) ' ksaca tanmaya alacaz.

Bir web servisinin, istemci uygulamalar tarafndan nasl kullanlabildiini anlamak, web servislerinin
mimarisini iyi bilmekle mmkndr. Mimariyi kolay bir ekilde anlayabilmek iin, daha nceki
makalemizde gelitirdiimiz web servisi ve istemci uygulamay gz nne alacaz. Hereyden nce
gelitirdiimiz web servisi local olarak test edilebilen ve tarayc zerinde alabilen bir asmx
dosyasndan ve buna bal Code-Behind dosyasndan olumaktadr. Web servisini test etmek iin,
web servisinin bulunduu adresteki asmx uzantl dosyay, tarayc penceresinden altrmak
yeterlidir. Bunun sonucunda, tarayc penceresinde bu web servisi hakkndaki bilgilere ulaabilir ve
ierdii metodlar grebiliriz.

Ancak burada yer alan Service Description balants bize baka bir olanak daha salamaktadr. Bu
balant yardmyla web servisimizin tm ieriini anlatan bir WSDL dkmanna eriebiliriz. WSDL
dkmannn en nemli yan, XML tabanl bir ierie sahip olmasdr. Dier yandan bu dkman,
web servisinde kullanlabilecek tm metodlara, parametrelere ve dn deerlerine ilikin bilgileri
iermektedir.

Peki bu WSDL dkman ne iin oluturulur? te bu noktada istemci uygulamaya bir gz atmakta
fayda vardr. stemci uygulamann web servisini kullanabilmesi iin, ilk nce web servisinin
bulunduu adrese bavurmas gerekir. Bu bavurunun ardndan web servisine ait referans istemci
uygulamaya eklediimizde, bir takm yeni dosyalarnda uygulamaya eklendiini grrz. Bu
dosyalardan belkide en nemli olan Reference.cs isimli dosyadr. Gelitirdiimiz uygulama ele
alndnda Reference.cs dosyasnn ierii aadaki gibi olacaktr.

using System.Diagnostics;
using System.Xml.Serializationg
using System;
using System.Web.Services.Protocols;
using System.ComponentModel;
using System.Web.Services;

www.bsenyurt.com Page 2039


[System.Diagnostics.DebuggerStepThroughAttribute()]
[System.ComponentModel.DesignerCategoryAttribute("code")]
[System.Web.Services.WebServiceBindingAttribute(Name="Geometrik HesaplamalarSoap",
Namespace="http://ilk/servis/")]
public class GeometrikHesaplamalar : System.Web.Services.Protocols.SoapHttpClientProtocol
{
public GeometrikHesaplamalar()
{
this.Url = "http://localhost/GeoWebServis/GeoMat.asmx";
}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ilk/servis/DaireAlan",
RequestNamespace="http://ilk/servis/", ResponseNamespace="http://ilk/servis/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public System.Double DaireAlan(System.Double r)
{
object[] results = this.Invoke("DaireAlan", new object[]{r});
return ((System.Double)(results[0]));
}

public System.IAsyncResult BeginDaireAlan(System.Double r, System.AsyncCallback callback,


object asyncState)
{
return this.BeginInvoke("DaireAlan", new object[] {r}, callback, asyncState);
}

public System.Double EndDaireAlan(System.IAsyncResult asyncResult)


{
object[] results = this.EndInvoke(asyncResult);
return ((System.Double)(results[0]));
}

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://ilk/servis/DaireCevre",
RequestNamespace="http://ilk/servis/", ResponseNamespace="http://ilk/servis/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]
public System.Double DaireCevre(System.Double r)
{
object[] results = this.Invoke("DaireCevre", new object[] {r});
return ((System.Double)(results[0]));
}

public System.IAsyncResult BeginDaireCevre(System.Double r, System.AsyncCallback callback,


object asyncState)
{
return this.BeginInvoke("DaireCevre", new object[] {r}, callback, asyncState);
}

www.bsenyurt.com Page 2040


public System.Double EndDaireCevre(System.IAsyncResult asyncResult)
{
object[] results = this.EndInvoke(asyncResult);
return ((System.Double)(results[0]));
}
}

Visual Studio.NET tarafndan otomatik olarak oluturulan bu dosyada dikkat ekici noktalar vardr.
Hereyden nce, karmzda, web servisimizin bir grnts yer almaktadr. Web servisimizde
yazdmz metodlar kullandklar parametreler ve daha baka bilgiler. Ancak nemli olan bu dosya
sayesinde, istemci uygulamann artk web servisine ait bir nesne rneini oluturup kullanabilecek
olmasdr. Dolaysyla, istemci uygulamamza web servisimize ait referans eklediimizde, istemci
uygulamda bu servise ait bir nesne yaps oluturulabilmitir. Bu sayede aadaki gibi bir bildirim
geerli hale gelir.

localhost.GeometrikHesaplamalar gh=new Istemci.localhost.GeometrikHesaplamalar();

Dahas, bu nesne zerinden, web servisindeki metodlar ayn isimler ile kullanabiliriz.

lblAlan.Text=gh.DaireAlan(r).ToString();
lblCevre.Text=gh.DaireCevre(r).ToString();

Olaya daha detayl bakldnda, Reference.cs nin aslnda, istemci ve web servisi arasndaki
haberlemeyi salayacak bir Proxy nesnesini oluturmak amacyla kullanldn syleyebiliriz.
Dolaysyla, istemci uygulama bu servisi kullanmak istediinde, yani bu servis zerinden bir metodu
armak istediinde, bu talebi proxy nesnesinden ister. Proxy nesnesi ise bu talebi , web servisine
iletir. Web servisi gelen talebi deerlendirir ve rettii cevab yine istemci uygulamadaki proxy
nesnesine gnderir. Proxy nesneside sonular, uygulama ortamna iletir.

www.bsenyurt.com Page 2041


ekil 1. Proxy Nesnesini ve SOAP' n Xml Web Servisi Mimarisindeki yeri.

Dier bir sorun, proxy nesnesine gelen taleplerin, web servisine giderken hi bir engel ile
karlamadan nasl hareket edecei ve geri geleceidir. stemci uygulama, proxy nesnesinde
normal olarak talepte bulunur ve cevaplar alr. Buradaki iliki normal olarak bir nesne.metod
ilikisidir. Ancak proxy nesnesi bu mesajlar, esnek, kolay okunabilir, herhangibir engele
taklmayacak bir hale getirmek durumundadr. Bu i iin XML tabanl bir bilgi ak biilmi
kaftandr. Yinede hareket edecek mesajlarn uygun bir formasyonda tanmalar ve web servisinin
anlayabilecei bir dilde ifade edilebilmeleri daha dorudur. Bu noktada SOAP (Simple Object
Access Protocol Basit Nesne Eriim Antlamas) devreye girer.

Web servislerinin kullanlmasnda, web servisleri ve istemciler arasndaki haberlemenin belirli


standartlar erevesinde gelitirilmesi ok nemlidir. SOAP (Simple Access Object Protocol) ite bu
noktada devreye giren ve web servisi-istemci sisteminin en nemli ksmn oluturan bir yap
tadr. SOAP, web servisleri ve istemciler arasnda gidip gelecek mesajlarn, XML tabanl olarak
belirlendii standartlara uygun formatta tanmasn salayan bir protokoldr. ounlukla HTTP
zerinde alan SOAP, FTP ve SMTP gidi dier iletiim protokolleri zerinden de kullanlabilir.

SOAP protokol, web servisleri ile istemciler arasnda gerekletirilen veri alveriinde, karlkl
olarak akcak mesajlarn nasl ve ne ekilde paketleneceini yada baka bir deyile bilgilerin nasl
kapslleneceini belirtir. SOAP, znde XML tabanl mesajlarn oluturulmasn belirtir. Bu nedenle
SOAP protokoln uygulayan mesajlar (ki bunlar SOAP Mesaj olarak adlandrlr), herhangibir a
ortamnda hi bir sorunla karlamadan uzak makineler arasnda iletilebilirler. SOAP protokol, 4
temel zerine ina edilmitir.

www.bsenyurt.com Page 2042


ekil 2. SOAP Protokolnn Temelleri.

SOAP protokolnn dayand bu temel kurallar ierisinde en nemlisi Envelope ksmdr. Bir SOAP
mesaj mutlaka bir zarf olarak tekil edilmeli ve Zarf kurallarna gre tasarlanmaldr. Dier
temellerin uygulanmas zorunlu deildir. Veri kodlama kurallar, zellikle seriletirilen nesneler iin
bir model sunar. Baka bir deyile, tanmlanm veri tiplerinin uygulama iin kullanlma kurallarna
karar verir. Bu katmandaki kurallarn uygulanmas opsiyoneldir. Mesaj deiim modeli, web servisi
ile istemciler arasnda dei toku edilen mesajlar iin bir istek/cevap deseni tanmlar. SOAP,
Remote Procedure Call tip mekanizmasn esas alan bir veri dei toku desenini kullansada bu bir
zorunluluk deildir. Mesaj deiim modelide opsiyoneldir. Veri balama kurallar ile, SOAPn iletiim
protokollerinin birbirlerine nasl balanacana dair tanmlamalar ierir. Veri balama kurallarda
opsiyoneldir.

Ksaca SOAP protokol, mutlaka iletiimsel mesajlarn SOAP Zarf kurallarna uygun bir biimde
tasarlanmasn zorunlu klar. SOAP mesajlarnn zarf kurallarna uygun bir biimde tasarlanmas iin
aadaki ekilde belirtilen format kullanlr. Burada bir SOAP zarfnn temel yaps belirtilmitir.

ekil 3. SOAP Zarfnn Temel Yaps.

SOAP Zarflar bir SOAP mesajnn balk ve gvde olmak zere iki ana ksmdan olumas
gerektiini belirtir. En nemli ksm gvdedir. Burada, yaplan metod armlarna ilikin bilgiler ile
ar sonucu istemcilere gnderilecek cevaplara ait xml tabanl bilgiler yer alr.

SOAP mesajlarn anlamann en iyi yolu, onlar gerek bir uygulamada takip etmektir. Bu amala,
gelitirmi olduumuz Web servisini ve istemci uygulamamz kullanacaz. stemci ve web servisi
arasnda hareket eden SOAP mesajlarn takip edebilmek amacyla Microsoft firmasnn
sunduu SOAP Tookit aracn kullanabiliriz. Bu arac bugn
itibariylehttp://download.microsoft.com/download/2/e/0/2e068a11-9ef7-45f5-820f-
89573d7c4939/soapsdk.exe adresinden temin edebilirsiniz. SOAP mesajlarn takip edebilmek
amacyla istemci uygulamamzda ufak bir deiiklik yapmamz gerekiyor. Bunun iin istemci

www.bsenyurt.com Page 2043


uygulamda, web servisine ait proxy nesnesinin snf dosyas ierisinde (reference.cs) yer alan,

this.Url = "http://localhost/GeoWebServis/GeoMat.asmx";

satrn

this.Url = "http://localhost:8080/GeoWebServis/GeoMat.asmx";

eklinde deitirmeliyiz. imdi SOAP Toolkit 3.0 ile yklenen Trace Utility aracn altralm.
Ardndan Trace Utility aracnda, New mensnden, Formatted Trace i seelim.

ekil 4. Yeni bir Trace ayoruz.

Karmza kacak olan aadaki pencereyi bu hali ile brakalm.

ekil 5. Trace Setup.

Ardndan istemci uygulamamz altralm ve web servisimizi kullanalm. Tekrardan Trace Utility
penceremize dnelim. Aadaki ekran grnts elde ederiz. Grld gibi, trace utility arac,
web servisimiz ile istemci uygulamamz arasndaki SOAP mesajlarn yakalamtr. Burada iki mesaj
sekmesi grnmektedir. Bunlarn herbiri web servisimizdeki bir metoda karlk gelmektedir.

www.bsenyurt.com Page 2044


ekil 6. SOAP Mesajlar.

rnein Message #1 sekmesini inceleyelim. steki XML bilgisi, istemcinin web servisine gnderdii
talebi (Request) gstermektedir. Alttaki mesaj ise, web servisinden istemciye gelen cevab
(Response) gsterir. stemcinin talebini incelediimizde aadaki XML dkmann elde ederiz.

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


- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <DaireAlan xmlns="http://ilk/servis/">
<r>10</r>
</DaireAlan>
</soap:Body>
</soap:Envelope>

Burada istemciden web servisine giden SOAP mesaj grlmektedir. Grld gibi mesaj
<soap:Envelope tag ile balamaktadr. Soap mesajmzn gvdesi ise <soap:Body> tag ile balar.
Burada istemci tarafndan arlan metodun ismi ve bu metoda gnderilen parametre deeri yer
almaktadr. Ayrca metodun hangi isim alan iinde yer aldda belirtilmitir. Bu isim alannn web
servisin ierisindeki WebService nitelii ile belirttiimiz isim alan olduuna dikkat ediniz. Soap
mesajmzn balk ksm ise, HTTP Header sekmesinde grlebilir. Buradaki XML satrlar ierisinde
en nemlisi <soapaction> tagnn olduu satrdr.

www.bsenyurt.com Page 2045


<soapaction>"http://ilk/servis/DaireAlan"</soapaction>

Soapaction tag, kullanlan web servisinde belirtmi olduumuz xml isim alannn sonuna web
servisinde yer alan metodun ismi eklenerek oluturulmutur. Burada, Soap mesajnn web servisi
tarafndan zmlenmesi srasnda, karlk gelecek isim alannn (WebService sekmesinde
belirttiimiz) ve bu isim alan iinden arlan metodun (WebMethod nitelii ile belirttiimiz)
tanmlamalar yer alr. Bylece web servisi gelen soap mesajna karlk gelen metodu bulup
altrabilir. Gelelim web servisinden istemciye dnen SOAP Mesajna.

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


- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <DaireAlanResponse xmlns="http://ilk/servis/">
<DaireAlanResult>314</DaireAlanResult>
</DaireAlanResponse>
</soap:Body>
</soap:Envelope>

Grld gibi, web servisinden istemciye dnen Soap mesajnda en dikkat ekici nokta Response
ve Result anahtar kelimeleridir. stemci tarafndan zllecek olan bu Soap mesaj, istemci
tarafndan metodun arld satra dnecek geri dn deerlerini ierir. Yine buradaki gvdede
yer alan metod tanmnda kullanlan isim alan ile (xmlns="http://ilk/servis/), istemciye ait proxy
nesnesini oluturan snf ierisindeki WebService niteliinde kullanlan isim alannn ayn olduuna
dikkat edelim.

[System.Web.Services.WebServiceBindingAttribute(Name="Geometrik HesaplamalarSoap",
Namespace="http://ilk/servis/")]

Burada grld gibi SOAP mesajlarmz tek parametre alan metodlar ve tek sonu ieren geri
dn deerlerini istemci ve web servisi arasnda belirli bir standart dahilinde tamaktadr. Dier
yandan, zellikle deiken sayda parametre alan ve geriye dizi veya veri kmesi dndrebilen
SOAP mesajlarda mmkndr. Bu durumu analiz edebilmek amacyla web servisimize parametre
olarak bir dizi alan ve geriye bu dizinin ilenmi halini dndrecek bir metod ilave edelim.

[WebMethod(Description="Daire Cevre Hesabini Dizi Elamanlarina Uygular.")]

public double[] DaireCevreDizi( double[] r)

int eleman_Sayisi=r.Length;

double[] dizi=new double[eleman_Sayisi];

for(int i=0;i<eleman_Sayisi;i++)

dizi[i]=r[i]*pi*2;

www.bsenyurt.com Page 2046


}

return dizi;
}

Bu web metodumuz, istemciden double trnden bir dizi alacak ve bu dizideki elemanlara evre
hesaplamas ilemlerini uygulayacak. Sonular ise yine bir dizi eklinde istemci bilgisayara geri
dndrlecek. stemci uygulamamzda bu yeni metodu test edebilmemiz iin, proxy nesnesinin,
web servisinin yeni versiyonuna uygun bir ekilde gncellenmesi gerekir. Bunun iin, istemci
uygulamada Solution Explorer penceresinde, Web References sekemsinde localhost esine sa
tklayarak alan menden, Update Web Reference i sememiz yeterli olacaktr.

ekil 7. Xml Web Servisini Gncellemek.

Bu durumda, istemci uygulamamz web servisimiz iin oluturduu proxy nesnesini yeniliklere gre
gncelleyecektir. Aksi takdirde web servisimize eklediimiz metodu kullanamayz. Bu ilemlerin
ardndan, istemci uygulamamza aadaki kod satrlarn ilave edelim.

double[] dizi=new double[3];

dizi[0]=1;

dizi[1]=2;

dizi[2]=3;

double[] diziSonuc=new double[3];

diziSonuc=gh.DaireCevreDizi(dizi);

www.bsenyurt.com Page 2047


foreach(double eleman in diziSonuc)

lblDizi.Text+=eleman.ToString()+" ";
}

Burada yaptmz, 3 elemanl double trnden bir dizi tanmlamak ve bu diziye atadmz
elemanlar, web servisimizdeki metodumuza parametre olarak gnderip sonular bir label
kontrolnde yazdrmak. Bizim iin nemli olan kodlarn yazl tarzndan ok, web servisine bir
dizinin gnderilmesi, orada ilenmesi ve sonularn geri gelmesi srasnda, SOAP mesajlarnn ne
ekilde oluacadr.

imdi Trace Utility den SOAP mesajlarn yenide inceleyelim. Yerel makinede altmz ve
proxy nesnemizide gncellediimiz iin, proxy snfndaki localhost tanmlamasn tekrardan
localhost:8080 olarak deitirmemiz, SOAP mesajlarn Trace Utility araclyla yakalayabilmemiz
asndan gerekli olabilir. SOAP Toolkit Trace Utility aracyla, SOAP mesajlarna baktmzda,
istemciden web servisine DaireCevreDizi metodu iin giden XML tabanl bilgilerin aadaki ekilde
oluturulduunu grrz.

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


- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <DaireCevreDizi xmlns="http://ilk/servis/">
- <r>
<double>1</double>
<double>2</double>
<double>3</double>
</r>
</DaireCevreDizi>
</soap:Body>
</soap:Envelope>

Grld gibi web metoda gnderdiimiz dizi elemanlar double XML veri tipinden elemanlar
olarak SOAP mesajnn gvdesine katlmtr. Ayn ekilde web servisinden geri dnen mesaja
baktmzda aadaki sonucu elde ederiz.

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


- <soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <soap:Body>
- <DaireCevreDiziResponse xmlns="http://ilk/servis/">
- <DaireCevreDiziResult>
<double>6.28</double>
<double>12.56</double>
<double>18.84</double>
</DaireCevreDiziResult>
</DaireCevreDiziResponse>
</soap:Body>
</soap:Envelope>

www.bsenyurt.com Page 2048


Sonular yine double XML veri tipi eleman olarak geri dndrlmtr. u ana kadar yaptmz
rneklerde, istemci uygulamann web servisindeki snf ve metodlar bir proxy nesnesi yardmyla
nasl kullandna ahit olduk. Peki istemci bir uygulama, kendisine web referans olarak ekledii
web servisine dair bir proxy nesnesini nasl oluturabildi? Bu sorunun cevabn Web Servislerinin
SOAP tan sonra olmassa olmaz materyali olan WSDL verebilir. WSDL konusunu bir sonraki
makalemizde incelemeye alacaz. Tekrarda grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT


selim@bsenyurt.com

Xml Web Servislerine Giri - 2 ( 30.09.2004 ) -


Web Servis
Deerli Okurlarm, Merhabalar.

Bu makalemizde, bir Xml Web Servisinin Visual Studio ile nasl oluturulabileceini
ve bir web sayfas zerinden nasl arlp kullanlabileceini incelemeye
alacaz. Visual Studio.Net ortamnda bir web servisi gelitirmek iin, ilk olarak
New Project blmnden, ASP.NET Web Service ablonu seilir. Visual Studio.Net,
yerel makinede bu web servisi iin gerekli fiziki ve sanal klasrleri, otomatik olarak
oluturacaktr. Notepad editornde yazdmz rnein aynsn, Visual Studio.Net
ortamnda gerekletireceimizden, proje ismi olarak GeoWebServis' i kullanalm.
Bu ayn zamanda web servisimizin varsaylan isim alan (default namespace )
olacaktr.

ekil 1. Yeni bir Web Servis projesinin eklenmesi.

www.bsenyurt.com Page 2049


Bu ilemin ardndan Visual Studio.Net, web servisimiz iin gerekli dosyalar oluturur. Varsaylan
olarak servisimiz, Service1.asmx adn alacaktr. Bununla birlikte, bu servise ait Code-Behind
dosyasnn kodlarda Visual Studio.Net tarafndan otomatik olarak hazrlanr. Visual Studio.Net,
servisin kullanmna rnek tekil edicek bir metodu da yorum satrlar halinde sunmaktadr. (
HelloWorld() metodu )

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
namespace GeoWebServis
{
public class Service1 : System.Web.Services.WebService
{
public Service1()
{
InitializeComponent();
}
#region Component Designer generated code
private IContainer components = null;
private void InitializeComponent()
{

}
protected override void Dispose( bool disposing )
{
if(disposing && components != null)
{
components.Dispose();
}
base.Dispose(disposing);
}
#endregion

// [WebMethod]
// public string HelloWorld()
// {
// return "Hello World";
// }
}
}
}

lk olarak, servisimizin adn deitireceiz. Bunun iin ncelikle, Solution Explorer ksmnda,
Service1.asmx dosyasnn ismini, GeoMat.asmx olarak deitirelim.

www.bsenyurt.com Page 2050


ekil 2. Service isminin deitirilmesi.

imdi ise, daha nce Notepad uygulamamzda yazdmz kodlar buradaki GeoMat.asmx.cs Code-
Behind dosyamz iinde aynen yazyoruz.

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Web;
using System.Web.Services;
namespace GeoWebServis
{
[WebService(Namespace="http://ilk/servis/",Description="Geometrik Hesaplamalar
zerine Metodlar erir. Ucgen, Dortgen gibi ekillere ynelik alan ve evre
hesaplamalar.",Name="Geometrik Hesaplamalar")]
public class TemelIsler : System.Web.Services.WebService
{
private const double pi=3.14;
[WebMethod(Description="Daire Alan Hesab Yapar")]
public double DaireAlan( double r)
{
return (r*r)*pi;
}
[WebMethod(Description="Daire evre Hesab Yapar.")]
public double DaireCevre( double r)
{
return 2*pi*r;
}

www.bsenyurt.com Page 2051


}
}

Projemizi derlediimizde, Visual Studio.Net, web servisimizin Code-Behind dosyasn kullanarak,


servisimiz iin gerekli dll dosyasn otomatik olarak bin klasr ierisinde oluturacaktr. Hazr olan
web servisini test etmek iin, projeyi altrmamz (Run) yeterlidir.

Bir web servisi uygulamas elbette tek bana bir anlam ifade etmez. Web servisleri, ancak
istemciler tarafndan kullanldklar takdirde anlam kazanacaktr. Bir web servisinin, herhangibir
istemci uygulamada kullanlabilmesi yzeysel olarak bakldnda ok karmak deildir. stemcinin
hereyden nce, web servisinin yer ald adrese (URL) bir referansta bulunmas gerekir. Bu
referansn geerli olmas halinde, bir sonraki admda istemci uygulamann servisin sahip olduu
yetenekleri bilmesi gerekmektedir. Bu mimarinin ileyiini ilerleyen makalelerimizde daha
derinlemesine incelemeden nce basit olarak gelitirdiimiz web servisini bir istemci uygulamada
nasl kullanacamz grelim.

stemci uygulamamz imdilik Visual Studio.Net ortamnda gelitireceiz. Mimarinin temellerini


daha iyi kavradktan sonra bu iin komut satr aralar ile nasl gerekletirildiini daha iyi
anlayacaz. imdi, Visual Studio.Net ortamnda bir uygulama oluturalm. Bu uygulama bir
Windows uygulamas, bir Asp.net uygulamas olabilecei gibi bir Mobil uygulamada olabilir. imdi,
New Project blmnden, Asp.Net Web Application tipini seelim ve uygulamamz Istemci ismi ile
oluturalm.

ekil 3. Yeni bir web uygulamasnn almas.

Srada bir web servisini uygulamamza ekleyeceimiz en nemli ksm var. Bunun iin Solution
Explorer da projemize sa tklyor ve alan menden Add Web Reference esini tklyoruz.

www.bsenyurt.com Page 2052


ekil 4. Web servisi iin gerekli referansn eklenmesi.

Bu ilem sonucunda ekrana, web servisini ekleyebilmemiz iin bir ka yntem sunan Add Web
Reference dialog penceresi gelecektir.

ekil 5. Web servisinin aranmas.

www.bsenyurt.com Page 2053


Servisimizi, yerel makinede gelitirdiimiz iin, Web services on the local machine balantsna
tklamamz halinde, localhost ta yer alan kullanlabilir tm web servislerinin listesini elde ederiz. Bu
linke tkladmzda, gelitirmi olduumuz Web Servisini ve bu servise ulaabileceimiz adresi elde
ederiz.

ekil 6. Yerel sunucuda bulunan web servisi.

GeoMat isimli balantya tkladmzda, web servisine ait bilgilerin yer ald ve web servisini test
edebilmemizi salyan pencere ile karlarz. Hatrlatmak gerekirse, burada yer alan servise ve
metodlara ait temel bilgiler WebService ve WebMethod nitelikleri sayesinde gerekletirilmitir.

ekil 7. Servisimizin saladklarna baklmas.

www.bsenyurt.com Page 2054


Artk web servisimizi bulduumuza ve ne tr ilemler gerekletirebildiini rendiimize,
dolaysyla servisi kefettiimize ( Discovery) gre, bu servisi uygulamamza Add
Reference butonuna tklayarak ekleyebiliriz. Bu ilemin ardndan, Visual Studio.Net uygulamaya
baz yeni dosyalar ekleyecektir.

ekil 8. Servisimiz ile birlikte oluturulan ek dosyalar.

Tm bu dosyalar Web References sekmesinin altnda yer almaktadr. Bu dosyalarn ne ie


yaradn ve ne amala oluturululduunu incelemeden nce, projemize eklediimiz web servisini
uygulama ierisinde nasl kullanacamz grelim. Bu amala basit Web Form umuzu aadaki gibi
tasarlayalm.

ekil 9. Web sayfamz.

imdi, Hesapla balkl butona basldnda meydana gelecek ilemleri kodlayacaz. Burada, web
servisimizindeki Alan ve Cevre isimli metodlar aracak ve bu metodlara parametre olarak
TextBox metin kutusu kontrolne girilen deeri gndereceiz. Daha sonra Web Servisimiz bu metin
kutusundaki deeri ilgili metodlarda altracak ve ilemlerin sonucu olarak metodlardan dnen

www.bsenyurt.com Page 2055


deerleri, web sayfamza gnderecek. Bunu gerekletirebilmek iin tek yapmamz gereken
aadaki kodlar yazmak.

private void btnHesapla_Click(object sender, System.EventArgs e)


{
double r=Convert.ToDouble(txtYaricap.Text);
localhost.GeometrikHesaplamalar gh=new
Istemci.localhost.GeometrikHesaplamalar();
lblAlan.Text=gh.DaireAlan(r).ToString();
lblCevre.Text=gh.DaireCevre(r).ToString();
}

Burada belkide en nemli ksm, Web Servisimizde yer alan GemotrikHesaplamalar isimli snfa ait
bir nesne rneinin aadaki kod satr ile oluturulmasdr.

localhost.GeometrikHesaplamalar gh=new Istemci.localhost.GeometrikHesaplamalar();

Web servisimizdeki metodlara ite bu nesne vastasyla erimekteyiz.

lblAlan.Text=gh.DaireAlan(r).ToString();
lblCevre.Text=gh.DaireCevre(r).ToString();

Burada kullanlan web servisinin, global seviyedeki bir ada yer aldn dnrsek, servis iindeki
snfa ait nesnenin istemci makinede nasl rneklenebildiini anlamak nemlidir. Nitekim snfa ait
nesne rneininin oluturulabilmesi, istemci makinede de, bu snfn olmasn gerektirir. Bu
Remoting teknolojisinden gelen bir zelliktir. Bir Remoting uygulamasnda, uzak hizmetleri
salayan nesne modelleri (dll dosyalar), bu hizmetleri kullanmak isteyen makinelere kopyalanr ve
uygulamalara referans olarak belirtilir. Oysaki web servislerinde durum farkldr. Web servisimize
ait snf, istemci uygulamaya kopyalamadk. Peki nasl oldu da bu servis snf, istemci uygulamada
kullanlabildi. te WSDL (Web Services Description Language) bu noktada devreye girerek bize
yardmc olmaktadr. Mimarinin daha derinlerine girerek bu konuyu net bir ekilde kavramadan
nce uygulamamzn nasl altna bakalm. Bunun iin projeyi Run edelim ve metin kutusuna bir
yarap deeri girelim. Sonu aadaki gibi olacaktr.

ekil 10. Web servisinin altrlmas sonucu.

Artk web servisimizi kullanan bir istemci uygulamamz var. Peki gerekte, kamera arkasnda
olanlar neler. Nasl oluyorda, web servisini kullanmak istediimizde, (bu servis dnyann baka
ucundaki bir makinede olsa bile) bu servise ait bir nesne rneini istemci uygulamada
oluturabiliyoruz? Hatta bu nesne nasl oluyorda, web servisindeki metodlar biliyor ve onlar

www.bsenyurt.com Page 2056


parametreleri ile birlikte arabiliyor? te tm bu sorularn cevab iin ncelikle mimariye daha
derinlemesine bakmamz gerekiyor. Web servislerinin mimarisini ilerleyen makalelerimizde
incelemeye alacaz. Tekrar grnceye dek hepinize mutlu gnler.

Burak Selim ENYURT


selim@bsenyurt.com

Xml Web Servislerine Giri - 1 ( 29.09.2004 ) -


Web Servis
Bu makalemizde, ksaca bir XML Web Servisinin ne olduuna, ne ie yaradna deinecek ve basit
bir Xml Web Servisinin notepad ile nasl oluturulabileceini incelemeye alacaz.

Bir Web Servisi, uzak istemcilerin bavuruda bulunduu eitli ilevsel metod armlarn
bardndrdan, ok ynl ve merkeziletirilmi bir nitedir. Bir web servisi, ok sayda istemci
tarafndan eriilebilen bir yapya sahiptir. Onu dier datk nesne modellerinden farkl klan sahip
olduu alt yap sistemi sayesinde, platform bamsz uygulanabilirlii salamasdr. Web
servislerinin gelitirilmesinde en byk etken, zellikle bir merkezdeki uygulamalar zerinde, ortak
amalar gerekletiren ilevselliklere sahip nesnelerin, gelitirildikleri an iletiim protokol gibi
kstlamalarn varldr.

Bir web servisi, standart olarak HTML iletiim protokol zerinden veri alveriine izin veren bir
yapdadr. HTML tabanl bu sistemin bilgi otoban XML temelleri zerine dayandrlmtr. XML' in
bizlere salad esneklik, kolay gelitirilebilirlik zelliklerinin yan sra, salam olduu global
standartlar, platform bamsz veri transferi kavramn dahada gelitirmitir. Web servislerinin
kullanlmasnda yatan en byk kavram xml tabanl veri aknn belirli standartlar dahilinde
gerekletirilmesidir. Bu, web servislerinin platform bamsz olarak herhangibir ate duvarna
(Firewall) yakalanmadan istemciler ile haberleebilmesini salar.

www.bsenyurt.com Page 2057


ekil 1. XML Web Servisleri Neyi fade Eder?

Bir web servisi, tek bana bir anlam ifade etmez. Web servisini kullanan istemcilerin de olmas
gerekir. stemciler internet ortamnda olabilecei gibi, altmz irketin network sisteminde yada
evimizdeki makinenin yerel sunucusu zerinde olabilir. Bir istemci, bir web servisini kullanmak
istediinde tek yapmas gereken, bu web servisi ile konuabilecek ortak bir takm standartlar
uygulamaktr. XML tabanl bu standartlar sayesinde istemciler, web servisine ulaabilir, bu servis
zerinden metodlar arabilir, bu metodlara parametreler gnderebilir ve metodlardan dnen
deerleri rnein veri kmelerini elde edebilir.

Web servislerinin kullanmna verilebilecek en gzel rnek, hava durumuna ilikin bilgilerinin en
gncel halleriyle, eitli platformlarda alan istemcilere sunulduu bir sistem olabilir. Hava
durumuna ilikin eitli bilgileri bir veri kmesi halinde tedarik eden merkezi web servisine
istemciler, bir web sayfasndan, bir windows yada java uygulmasndan, bir mobil uygulamadan
veya baka bir platformdan kolayca eriebilir. Web servisleri merkezi uygulamalar olduklarndan,
verilerdeki deiiklikler bu servisleri kullanan tm uygulamalar iin de e zamanl ve e gncellikte
olacaktr. Web servisleri ve bu servisleri kullanan istemciler arasndaki ilikiler, yzeysel olarak
bakldnda aadaki ekilde grld gibi deerlendirilebilir.

www.bsenyurt.com Page 2058


ekil 2. En basit haliyle Xml Web Servislerinin hayatmzdaki yeri.

Web servislerinin, onlar kullanan istemciler ile arasndaki iliki, phesiz ki bu ekilde grnd
kadar basit deildir. Hereyden nce, web servislerini kullanacak istemciler ile arada kurulucak
ilikinin belli standartlara dayandrlmas gerekir. Her ne kadar, web servisleri HTML zerinden
gidecek XML veri paralarn kullanyor olsada bunlarn, istemcilerin ileyebilecei ve anlayabilecei
bir hale getirilmeleri gerekir. Bu noktada devreye Web Servisleri iin nemli ve gerekli temellerden
birisi olan SOAP (Simple Object Access Protocol - Basit Nesne Eriim Antlamas ) girer.

Bir istemci, kullanaca web servisine ait bir takm bilgilere sahip olmak zorundadr. stemci bu
bilgileri kullanarak web servisinden SOAP protokolne uygun olarak hazrlanan XML mesajn
gnderir. Kodlanarak (Encoding) gnderilen bu mesaj, Web Servisi tarafndan zlr (Decoding) ,
gerekli parametreler ve metod arm bilgileri eliinde bir takm ilemler gerekletirir. Bu
ilemler sonrasnda Web Servisi, istemciye dndrecei cevap bilgileri iin yine SOAP protokolne
uygun XML mesajlarn oluturur. Bu mesajlar HTTP zerinden istemci uygulamaya ular, burada
zlr ve deerlendirilir.

Elbette ekildeki senaryoda yer alan istemci sistemler bunlar ile snrl deildir. ok eitli
platformlar da web servislerini kullanabilir. Web servisinin nnde alan bir Firewall (Ate Duvar)
olmas bilgilerin kolayca tanabilmesini engellemez. nk mesajlar, istemciler ve web servisleri
arasnda XML tabanl bilgi paracklar eklinde tanmaktadr.

stemcilerin kullanacaklar web servisindeki bilgileri nceden bilmeleri gerekir. WSDL (Web Services
Description Language - Web Servisleri Tanmlama Dili ) bu noktada devreye giren bir dier
nemli unsurdur. stemci uygulamalar WSDL yardmyla, kullanacaklar web servisine ait bilgileri
nceden tedarik ederler. Bu istemcinin web servisi zerindeki bir web metodunun varlndan
haberdar olmas, onu nasl kullanacan bilmesi anlamna gelmektedir. Web servislerinin mimarisini

www.bsenyurt.com Page 2059


daha derin ve detayl bir ekilde incelemeden nce, ilk Web Servisi uygulamamz yazmaya
balyoruz.

Bir Web Servisini oluturmak iin, Notepad gibi basit bir metin editorunu kullanabileceimiz gibi,
Visual Studio.NET gibi ileri seviyede bir yazlm gelitirme platformunuda kullanabiliriz. lk nce
Notepad zerinden bir web servisinin nasl yazlacan greceiz. Bir web servisi her eyden nce,
intranet veya internet zerinde yer alan bir sunucuda konulandrlmaldr. Yerel bir makinede bu i
iin, IIS (Internet Information Services) kullanlabilir. Bu nedenle ilk olarak, web servisimizi
barndrcak sanal bir klasr oluturmakla ie balamalyz. Windows XP iletim sistemine sahip bir
bilgisayarda, IIS altnda sanal klasrmz oluturabilmek iin Start mens, Administrative Tool,
Internet Informatin Services ksmna girelim.

ekil 3. IIS

Ardndan Default Web Site (yada web sunucusunun ad) ksmnda sa men tuuna basp New
ksmndan Virtual Directory' yi seelim.

ekil 4. Virtual Directory.

Karmza kacak olan sihirbazda Alias ksmna Geometri girelim. Klasrmz ise,
C:\Inetpub\wwwroot\Geometri olarak oluturalm. Buradaki admlar tamamladktan sonra, web
servisimizi bu klasr altnda oluturabiliriz. Web servisleri, asmx uzantl dosyalar olarak
oluturulurlar. Bu nedenle, asmx uzantl dosyamz, yerel web sunucumuzda oluturduumuz sanal
klasrn iaret ettii fiziki klasrde aadaki kodlar ile hazrlayalm.

<% @ WebService Language="C#" CodeBehind="GeoMat.asmx.cs"


class="GeoWebServis.TemelIsler" %>

Hazrladmz bu dosyay, GeoMat.asmx uzants ile kaydedelim. Kodlarda grld gibi, web
servisimizin asl ilevselliini, GeoMat.asmx.cs isimli Code-Behind dosyasnda gerekletireceiz.
Burada kullanacamz programlama dilinide Language zelliine C# deerini atayarak belirledik.
Ancak en nemlisi kaydedilen bu asmx dosyasnn bir web servisi olarak deerlendirileceini
belirten WebService anahtar szcnn kullanlmasdr. imdi Code-Behind dosyamz oluturalm.

www.bsenyurt.com Page 2060


using System;
using System.Web;
using System.Web.Services;

namespace GeoWebServis
{

[WebService(Namespace="http://ilk/servis/",Description="Geometrik Hesaplamalar zerine


Metodlar erir. Ucgen, Dortgen gibi ekillere ynelik alan ve evre
hesaplamalar.",Name="Geometrik Hesaplamalar")]
public class TemelIsler : System.Web.Services.WebService
{
private const double pi=3.14;

[WebMethod(Description="Daire Alan Hesab Yapar")]


public double DaireAlan( double r)
{
return (r*r)*pi;
}

[WebMethod(Description="Daire evre Hesab Yapar.")]


public double DaireCevre( double r)
{
return 2*pi*r;
}
}
}

Yazdmz bu dosyay GeoMat.asmx.cs ismi ile asmx dosyamzn bulunduu klasre kayt edelim.
Kodlar ksaca incelediimizde ilk olarak, keli parantezler ierisindeki ifadeler dikkatimizi
ekmektedir. Bu ifadeler birer nitelik (attribute) olup, web servisindeki snf ve metodlara ilikin bir
takm bilgileri, bu servisi kullanacak olan istemcilere salarlar.

rnein WebService niteliinde, Namespace zellii ile, bu servisin tanmn ierecek XML
dkmannda kullanlacak Namespace' i belirtmi oluruz. Description zellii ile, web servisindeki
bu snfn neler yaptn zetleyen ksa bilgileri belirleriz. Name zellii ilede, bu snfa bir isim
vermi oluruz. Bu bilgiler zellikle web servisini kefettiimizde (Discovery) , olduka ie
yaramaktadr. WebService niteliine benzer olarak WebMethod nitelii, izleyen metodun bir web
servisi metodu olduunu belirtmek iin kullanlr. Burada iki web servisi metodumuz yer almaktadr.
Her birinin ne i yaptna dair ksa bilgileride WebMethod niteliinin Description zellii ile
belirtebiliriz.

Burada kullandmz isim alan ve snf adlarnn, asmx dosyasnda belirtiimiz class
tanmlamalarndaki ile ayn olduuna dikkat edelim. Bir web servisi yazdmzda, bu web servisini
oluturacak olan snfn, System.Web.Services.WebService isim alanndan tretilmesi gerekir.
Yazm olduumuz bu web servisi temel olarak iki metoda sahiptir ve bu metodlarn herbiri double
trnden birer parametre alarak, yine double trnden sonular retmekte ve metodun arld
yere dndrmektedirler. Burada kullanlan parametreler istemci bilgisayarlarn, web servisindeki
ilgili metodlar armlar srasnda kullanlr. Dn deerleri ise, ilgili metodlar aran istemcilere
gnderilir.

www.bsenyurt.com Page 2061


Web servisimize ait asmx dosyamz ve Code-Behind dosyamz oluturduktan sonra, Code-Behind
dosyamz dll ktphanesi olarak derleyip, bin isimli bir klasr ierisine koymalyz. Bu amala
komut satrndan aadaki komutu vererek, Code-Behind dosyamz bir snf ktphanesi olacak
ekilde csc yardmyla derliyoruz.

csc /target:library GeoMat.asmx.cs

Oluturulan dll dosyasn asmx dosyamzn blunduu klasr altndaki bin isimli bir klasr ierisine
tadktan sonra web servisimize herhangibir taraycdan rahatlkla eriebiliriz. Bunun iin, Internet
Explorer penceresinde adres satrna

http://localhost/Geometri/GeoMat.asmx

url bilgisini yazmamz yeterli olucaktr. Bu ilem sonrasnda web servisimizin alr hali aadaki
gibi olacaktr.

ekil 5. Xml Web Servisinin taraycdan talep edilmesinin sonucu.

Grld gibi asmx uzantl dosyamz kullanarak, gelitirmi olduumuz web servisine ait bilgilere
eritik. Burada yazlan bilgilerin, WebService ve WebMethod niteliklerinde belirtmi olduumuz
deerlerin ayns olduu dikkatinizi ekmitir. Dilersek bu pencerede servisimizi deniyebiliriz. Web
servisimizde gelitirdiimiz metodlara ait linklerden hernangibirisine tkladmzda, bu metodu
armamz iin kullanabileceimiz bir sayfa ile karlarz.

www.bsenyurt.com Page 2062


ekil 6. Bir Web Metodunun arlmas.

Bu ekranda, value ile belirtilen bir metin kutusu olduuna dikkat edin. Bu metin kutusu
metodumuzun dardan ald double tipten parametreye istinaden oluturulmutur. Buraya bir
deer girerek metodun arlmasn salayabiliriz. Bu durumda metodun altrlmas sonucu elde
edilecek sonu(lar) bir XML bilgisi eklinde elde edilecek ve tarayc penceresinde aada olduu
gibi grnecektir.

Web servisimizin ana sayfasnda Service Description isimli bir balant vardr. Bu balantya
tkladmzda aadaki gibi uzun bir XML bilgisi elde ederiz.

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

- <definitions xmlns:http="http://schemas.xmlsoap.org/wsdl/http/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:s0="http://ilk/servis/"
xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
targetNamespace="http://ilk/servis/" xmlns="http://schemas.xmlsoap.org/wsdl/">

- <types>

- <s:schema elementFormDefault="qualified" targetNamespace="http://ilk/servis/">

- <s:element name="DaireAlan">

- <s:complexType>

www.bsenyurt.com Page 2063


- <s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="r" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

- <s:element name="DaireAlanResponse">

- <s:complexType>

- <s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="DaireAlanResult" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

- <s:element name="DaireCevre">

- <s:complexType>

- <s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="r" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

- <s:element name="DaireCevreResponse">

- <s:complexType>

- <s:sequence>

<s:element minOccurs="1" maxOccurs="1" name="DaireCevreResult" type="s:double" />

</s:sequence>

</s:complexType>

</s:element>

www.bsenyurt.com Page 2064


</s:schema>

</types>

- <message name="DaireAlanSoapIn">

<part name="parameters" element="s0:DaireAlan" />

</message>

- <message name="DaireAlanSoapOut">

<part name="parameters" element="s0:DaireAlanResponse" />

</message>

- <message name="DaireCevreSoapIn">

<part name="parameters" element="s0:DaireCevre" />

</message>

- <message name="DaireCevreSoapOut">

<part name="parameters" element="s0:DaireCevreResponse" />

</message>

- <portType name="Geometrik_x0020_HesaplamalarSoap">

- <operation name="DaireAlan">

<documentation>Daire Alan Hesabi Yapar</documentation>

<input message="s0:DaireAlanSoapIn" />

<output message="s0:DaireAlanSoapOut" />

</operation>

- <operation name="DaireCevre">

<documentation>Daire evre Hesabi Yapar.</documentation>

<input message="s0:DaireCevreSoapIn" />

<output message="s0:DaireCevreSoapOut" />

</operation>

</portType>
- <binding name="Geometrik_x0020_HesaplamalarSoap"

www.bsenyurt.com Page 2065


type="s0:Geometrik_x0020_HesaplamalarSoap">

<soap:binding transport="http://schemas.xmlsoap.org/soap/http" style="document" />

- <operation name="DaireAlan">

<soap:operation soapAction="http://ilk/servis/DaireAlan" style="document" />

- <input>

<soap:body use="literal" />

</input>

- <output>

<soap:body use="literal" />

</output>

</operation>

- <operation name="DaireCevre">

<soap:operation soapAction="http://ilk/servis/DaireCevre" style="document" />

- <input>

<soap:body use="literal" />

</input>

- <output>

<soap:body use="literal" />

</output>

</operation>

</binding>

- <service name="Geometrik_x0020_Hesaplamalar">

<documentation>Geometrik Hesaplamalar zerine Metodlar Ierir. Ucgen, Dortgen gibi sekillere


ynelik alan ve evre hesaplamalari.</documentation>

- <port name="Geometrik_x0020_HesaplamalarSoap"
binding="s0:Geometrik_x0020_HesaplamalarSoap">

<soap:address location="http://localhost/Geometri/GeoMat.asmx" />

www.bsenyurt.com Page 2066


</port>

</service>

</definitions>

Burada grld gibi bir XML belgesine neden ihtiyacmz olabilir? Dikkat edilecek olursa, bu XML
belgesinde, Web Servisimize ait bir takm bilgiler yer almaktadr. rnein, Metodlara ilikin
parametre bilgileri veya WebService ve WebMethod niteliklerinde belirttiimiz tanmlamalar gibi.
te istemci bilgisayarlar bu XML ktsn kullanarak, iletiim kuracaklar web servsileri hakknda
bilgi sahibi olurlar. Ancak burada asl nemli olan nokta, Service Description balantsnn,
aadaki ekilde oluudur. Bu aslnda, bir istemcinin, herhangibir web servisi hakkndaki bilgilere
nasl ulaabileceini gstermektedir.

http://localhost/Geometri/GeoMat.asmx?WSDL

Bir Web Servisini Visual Studio.NET ortamnda gelitirmek, u ana kadar yaptklarmzdan pek farkl
deildir. Ancak Visual Studio.Net ortamnn salad avantajlar nedeniyle ok daha kolaydr. Bir
sonraki makalemizde bir web servisinin Visual Studio.Net ortamnda nasl gelitirileceini ve bu web
servisine eriecek bir istemcinin nasl yazlacan incelemeye alacaz. Hepinize mutlu gnler
dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve Sql Komutlarn Asenkron


Olarak Yrtmek - 2 ( 25.09.2004 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Hatrlayacanz gibi bir nceki makalemizde, sql komutlarnn asenkron olarak yrtlmesi iin
kullanlan tekniklerden birisi olan polling modelini incelemitik. Polling modeli basit olmakla birlikte,
i yk fazla olan hacimli sql komutlarnn asenkron olarak altrlmasnda ok fazla tercih
edilmemelidir. Bu tip sorgularn yer ald asenkron yrtmelerde, CallBack veya Wait modellerini
kullanmak verimlii arttrc etkenlerdir. Bu makalemizde CallBack modelini ksaca incelemeye
alacaz.

CallBack modeli anafikir olarak, asenkron olarak alan sql komutlarnn ileyilerinin sona erdii
noktalarda yrrle giren metodlar bnyesinde barndran bir tekniktir. Bu teknie gre,
asenkron olarak yrtlecek sql komutlarn tayan SqlCommand nesneleri yine bilinen Begin...
metodlar ile altrlrlar. Ancak bu kez, SqlCommand nesnesine ait Begin metodlarnn aadaki
tabloda belirtilen ar yklenmi versiyonlar kullanlr.

CallBack modelinde kullanlan SqlCommand.Begin... metodlar

public IAsyncResult BeginExecuteNonQuery ( AsyncCallback callback, object stateObjcet


);

www.bsenyurt.com Page 2067


public IAsyncResult BeginExecuteReader ( AsyncCallback callback, object stateObjcet );

public IAsyncResult BeginExecuteXmlReader ( AsyncCallback callback, object stateObjcet );

Burada grld gibi her metod da, iki parametre almaktadr. lk parametre AsyncCallback
temsilcisi tipindendir. Bu parametre yardmyla, yrtlecek olan sql komutlar tamamlandnda
altrlacak olan metod iaret edilir. Bu, static olan, void geri dn deerine sahip ve yanlzca
IAsyncResult tipinde bir nesne rneini parametre olarak alan bir metod olmaldr. Bir baka deyile
Begin metodu ile altrlan sql sorgular sonlandnda hangi metodun altrlaca buradaki
temsilci (delegate) yardmyla belirlenmi olunur.

kinci parametre ise kullanc tarafndan belirtilebilen object tipinden bir nesnedir. ounlukla,
CallBack metodu iine, asenkron olarak alan sql komutunun sahibi olan SqlCommand nesnelerini
aktarmak amacyla kullanlmaktadr. Polling modelinde olduu gibi burada da Begin metodlarnn
geriye dn deerleri, alan asenkron sorgudan sorumlu olan IAsyncResult arayz tipinden
nesne rnekleridir.

Bu ksa aklamalardan sonra dilerseniz, CallBack modelinin nasl uygulandn gsteren basit bir
rnek gelitirelim. Bu amala Visual Studio.Net 2005' te aadaki kodlara sahip olan bir Console
uygulamas oluturalm.

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

#endregion

namespace CallBackModel
{
class Program
{
public static void Main(string[] args)
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;MultipleActiveResultSets=true;async=true");
con.Open();
SqlCommand cmd = new SqlCommand("UPDATE Production.Product SET
ListPrice=ListPrice*1.15", con);
SqlCommand cmd2 = new SqlCommand("SELECT * From Person.Address", con);
IAsyncResult res = cmd.BeginExecuteNonQuery(new AsyncCallback(UPDATE_OK), cmd);
IAsyncResult res2 = cmd2.BeginExecuteReader(new AsyncCallback(SELECT_OK), cmd2);
Console.WriteLine("SORGULAR ALIIYOR...");
Console.ReadLine();
con.Close();
}

www.bsenyurt.com Page 2068


public static void UPDATE_OK(IAsyncResult r)
{
SqlCommand komut = (SqlCommand)r.AsyncState;
int sonuc=komut.EndExecuteNonQuery(r);
Console.WriteLine(sonuc + " SATIR GNCELLEND...");
}

public static void SELECT_OK(IAsyncResult r)


{
SqlCommand komut = (SqlCommand)r.AsyncState;
SqlDataReader dr = komut.EndExecuteReader(r);
dr.Read();
Console.WriteLine(dr[1] + " " + dr[2]);
}
}
}

Uygulamay altrmadan nce ksaca neler yaptmza daha yaknda bakmakta fayda var. Bu
rneimizde, Yukon zerinde yer alan AdventureWorks veritabanna balandk. Amacmz iki sql
sorgusunu asenkron olarak altrmak ve bu sorgular ilerken uygulama ortamnda izleyen kod
satrlarn yrtlebilmesini salamak. SqlCommand nesnelerimizide yarattktan sonra sra bu
komutlar ilgili Begin... metodlar ile altrmaya geliyor.

IAsyncResult res = cmd.BeginExecuteNonQuery(new AsyncCallback(UPDATE_OK), cmd);


IAsyncResult res2 = cmd2.BeginExecuteReader(new AsyncCallback(SELECT_OK), cmd2);

Burada bizim iin en nemli noktalar parametrelerdir. Her iki metodun ilk parametresi aslnda
AsyncCallback temsilcisi tipindendir. Nitekim;

new AsyncCallback(UPDATE_OK)

tanmlamas ile aslnda UPDATE_OK isimli metodu iaret eden AsyncCallback tipinden bir temsilci
tanmlam olunmaktadr. Bu temsilcinin yapt i sadece, IAsyncResult nesne rneinin
sorumluluunda olan sql komutlarnn yrtl tamamlandnda, derhal altrlacak olan
metodun hangi metod olacana karar vermektir.

kinci paramtremiz ise, Begin metodunun sahibi olan SqlCommand nesnesidir. Bu nesneye,
UPDATE_OK metodu iinden eriilebiliriz. Eer byle bir eriim sz konusu olmasayd, CallBack
metodunun iinden sql sorgusunun sahibi olan SqlCommand nesnesine erimekte sorunlar
yaayabilirdik. Nitekim CallBack metodu dikkat edeceiniz gibi static olmak zorundadr ve static bir
metod iinde static olmayan yeler erimekte sorun yaamaktayzdr. Tm bunlar AsyncCallback
temsilcisinin iaret edebilecei metodun yaps ile ilgilidir.

public static void UPDATE_OK(IAsyncResult r)


{
SqlCommand komut = (SqlCommand)r.AsyncState;
int sonuc=komut.EndExecuteNonQuery(r);

www.bsenyurt.com Page 2069


Console.WriteLine(sonuc + " SATIR GNCELLEND...");
}

Bu metod dikkat edecek olursanz, IAsyncResult tipinden bir nesneyi parametre olarak almaktadr.
Buraya geirilen bu parametre, Begin metodu ile oluturulan IAsyncResult nesne rneidir.
Dolaysyla, sql komutunun ileyii tamamlandnda devreye girecek olan bu metod iinden,
IAsyncResult nesne rnei yardmyla sonu kmelerini elde edebilmemiz mmkn olabilmektedir.
Bir baka deyile, End... metodunu buraya aktarlan IAsyncResult nesne rnei zerinden
arabiliriz. Dier yandan, sql komutunun sahibi olan SqlCommand nesnesini metod iinde
kullanabilmek iin,

SqlCommand komut = (SqlCommand)r.AsyncState;

satr kullanlmtr. Bu satrda dikkat ederseniz, IAsyncResult nesnesinin AsyncState zelliinden


yararlanlmtr. Bu zellik, asenkron yrtme operasyonunda grev olan SqlCommand nesnesini
elde etmemizi salar. Tabiki zelliin tanmlan gerei, geri dn deeri object tipinde
olduundan burada bir cast ilemi uygulanmtr. Yani object nesneyi SqlCommand tipine
evirmemiz gerekmektedir.

Son admda ise, EndExecuteNonQuery metodu arlarak, sql komutunun sonular elde edilmitir.
Bu metod iin kullanlan desen yaps CallBack metodu olan SELECT_OK iinde geerlidir.
Uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

ekil 1. Uygulamann almas sonucu.

Dikkat edecek olursanz, biz CallBack tekniini uygulamaya baladmz Begin... arlarndan
sonraki kodlar, sql sorgularmzn tamamlanmasndan nce almtr.

Bu modeli, bir nceki makalemizde incelediimiz polling modeli ile karlatrdmzda ilk gze
arpan, srekli olarak bir kontrol yapmaymzdr. Hatrlayacanz gibi polling modelinde,
IAsyncResult nesnesinin IsCompleted zellii ile, alan sql sorgularnn tamamlanp
tamamlanmad kontrol edilmektedir. Bu her ne kadar basit ve fazla zaman almayan sorgular iin
kullanl olsada, daha byk lekli sorgularda, alan asenkron prosesin srekli olarak kontrol
edilmeye allmas ok anlaml olmayacak ve en nemlisi zaman kaybnda neden olacaktr. Bu
nedenlede bu tip youn sorgularda genellikle CallBack veya Wait modellerinden birisi tercih edilir.
CallBack modelinin anatomisini zihnimizde daha iyi canlandrabilmek amacyla aadaki ekli de
gz nne alabiliriz.

www.bsenyurt.com Page 2070


ekil 2. CallBack modelinin anatomisi.

Grld gibi aslnda, asenkron olarak alacak sql sorgular tamamlandnda devreye giren
CallBack metodlar, uygulama ortamndaki satrlardan tamamen bamsz olarak alan yaplardr.
Sql komutlar sonlandnda annda devreye girerek sonularn elde edilebilmesini salayan ve
hatta baka ilemlerin gerekletirilebilecei kod bloklarn kapsllememize imkan vermektedirler.
CallBack yapsnn biraz daha gelimi bir versiyonu olan Wait modelide asenkron sql komutlar
yrtlmesinde kullanlan tekniklerdendir. Bir sonraki makalemizde bu konuya deinmeye
alacaz. Tekrar grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve Sql Komutlarn Asenkron


Olarak Yrtmek - 1 ( 23.09.2004 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Bir nceki makalemizde MARS etkisini incelemi ve ayn balant zerinden birden fazla sayda
sonu kmesine nasl eriebileceimizi grmtk. Her ne kadar, ayn anda birden fazla sonu
kmesine eriebilsekte, halen daha MARS modeli, sql komutlar ile e zamanl alan kodlar ve
asenkron yrtlebilen dier sql komutlar iin yeterli deildir. Ado.Net 2.0 ile, sql komutlarn
asenkron olarak yrtebileceimiz bir takm yeni yeler gelmektedir. Bu yeler sayesinde, sql
komutlarn asenkron olarakaltrabilir ve hatta, dier kod satrlarnnda e zamanl olarak

www.bsenyurt.com Page 2071


ileyebilmesini salayabiliriz. Bu ileri gerekletirebilecek yeler u an iin sadece SqlClient
snfnda yer almaktadr. Ancak .Net Framework 2.0' n final srmnde bu yelerin, dier Ado.Net
isim alanlarnada yerletirileceklerini dnyorum.

Asenkron komut yrtmenin mant, asenkron metodlarn altrlmasna ok benzer. Nitekim


burada da, balatlan bir prosesi kontrol etmemize imkan salayan IAsyncResult arayznne ait
bir nesne rnei anahtar grevini oynamaktadr. Asenkron sql komutlarn yrtmek iin,
SqlCommand snfna aadaki tabloda yer alan alt adet yeni metod ilave edilmitir.

SqlCommand snf iin


Asenkron komut yrtme
metodlar

BeginExecuteNonQuery

BeginExecuteReader

BeginExecuteXmlReader

EndExecuteNonQuery

EndExecuteReader

EndExecuteXmlReader

Begin ile balayan tm metodlar, geriye IAsyncResult arayz tipinden bir nesne rnei
dndrrler. Programn almas esnasnda, bu tipe ait zellikler kullanlarak alan sql
komutlarna ait proseslerin durumlar kontrol edilebilir ve tamamlanp tamamlanmadklar renilir.
Elbetteki, almas tamamlanan bir sql komut metodunun geriye sonular dndrebilmesi iin,
End ile balayan uygun metodun altrlmas ve bu metoda ilgili prosese ait IAsyncResult nesne
rneinin parametre olarak gnderilmesi gerekmektedir. Temel olarak bu, Asenkron Sql
Komutlarnn altrlmasnn ana mantdr. Bununla birlikte Ado.Net 2.0, asenkron sql
komutlarnn yrtlebilmesi iin 3 deiik model sunmaktadr.

ekil 1. Asenkron Yrtme Modelleri.

Biz bugnk makalemizde, Pooling Modelini incelemeye alacaz. Bu modelde genellikle,


IAsyncResult tipinden nesne rnei ile sahip olunan prosesin tamamlanp tamamlanmad srekli
olarak kontrol edilir. Yani, Begin ile balayan herhangibir metoddan sonra bu metodun ierdii Sql

www.bsenyurt.com Page 2072


komutu yrtlrken, elde edilen IAsyncResult tipi nesne rneine ait IsCompleted zelliine
baklarak prosesin tamamlanp tamamlanmad aratrlr. Bu aratrma ilemi srekli tekrar
ettiinden altrlan sql komutlar tamamlanncaya kadar, bu aralklarda baka ilemler
gerekletirilebilir veya baka sql komutlar yrtlebilir. Dier taraftan bu kontrol ilemi zorunlu
deildir. Nitekim biz bu kontrol yapmasakta, Begin ve End komutlar arasndaki bloklarn
altrlmas salanabilir. Ancak burada ana fikir, uzun srebilecek sql komutlarnn asenkron
olarak almalar halinde zaman kaybnn nne geebilmek, uygulamann ileyiinin kesilmesini
nlemek ve bu zaman aralnda baka kodlar ve baka kullanc aktivitelerini baarl bir ekilde
icra edebilmektir. imdi dilerseniz Pooling modelinin en basit haliyle uygulann incelemek
amacyla, Visual Studio.Net 2005 ortamnda aadaki kodlara sahip basit bir Console uygulamas
gelitirelim.

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

#endregion

namespace PoolingModeli
{
class Program
{
static void Main(string[] args)
{
try
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;Asynchronous Processing=true");
SqlCommand cmd = new SqlCommand("UPDATE Production.Product SET
ListPrice=ListPrice+100", con);
con.Open();
IAsyncResult res = cmd.BeginExecuteNonQuery();

int i = 0;
while (!res.IsCompleted)
{
Console.WriteLine("LEM DEVAM EDYOR "+i);
i += 1;
}

int sonuc = cmd.EndExecuteNonQuery(res);


Console.WriteLine(sonuc + " SATIR GNCELLEND...");
Console.ReadLine();
con.Close();
}
catch (Exception hata)

www.bsenyurt.com Page 2073


{
Console.WriteLine(hata.Message);
Console.ReadLine();
}
}
}
}

imdi kodlarmzda ne yaptmza yaknda bakalm. lk olarak, aadaki satr ile yeni bir
SqlConnection nesnesi yaratyoruz.

SqlConnection con = new SqlConnection("data source=localhost;initial


catalog=AdventureWorks;integrated security=SSPI;Asynchronous Processing=true");

Burada, standart Sql Connection ifademizdekilerinin aksine, ekstradan bir terim


kullandk.Asynchronous Processing terimi, alan balantnn asenkron eriimlere izin verip
vermeyeceini belirler. Varsaylan deeri false' tur ve Asenkron komut yrtmelerine izin vermez.
Bu nedenle burada true deerini aka atyoruz. Eer bu balant zelliini belirtmessek, alma
zamannda aadaki istisnay alrz.

ekil 2. Balantnn Asenkron yrtmelere izin vermemesi halinde.

Daha sonra ise, SqlCommand nesnemizi oluturuyoruz. SqlCommand nesnemiz, AdventureWorks


veritabannda yer alan Product isimli tablodaki ListPrice deerini 100 birim arttran bir Update
sorgusuna sahip. Bu tablo Yukon kurulduunda 504 satr veri iermektedir. Haliyle biraz zaman
alabilecek bir gncelleme ilemi sz konusu. Ancak biz istiyoruz ki, bu gncelleme komutu
yrtlrken uygulama ortamnda baka eylerde yapabilelim. En azndan uygulama bloke
olmadan basit bir takm ilemleri gereketirebilme amacndayz. Bu amala ilk olarak sql
komutumuzu BeginExecuteNonQuery metodu ile altryoruz ve hemen ortama bir IAsyncResult
tipi nesnenin dnmesini salyoruz.

IAsyncResult res = cmd.BeginExecuteNonQuery();

u aamada, alan komuta ait proses res isimli IAsyncResult tipinden nesne rneinin
sorumluluu altnda. Biz bu rneimizde pooling modelini kullandmz iin, e zamanl olarak
altrmak istediimiz kodlarmz bir while dngs ierisine alabiliriz. Bu while dngs her bir
iterasyonunda, IAsyncResult nesnesinin o an sahip olduu prosesin tamamlanp tamamlanmadn
kontrol ediyor olacaktr. Bunun iinde, IsCompleted zelliinin deerine baklyor. Eer dnen deer
false ise, ilemin tamamlanmad anlalyor ve dng iindeki kodlar yrtlyor.

while (!res.IsCompleted)
{
Console.WriteLine("LEM DEVAM EDYOR "+i);

www.bsenyurt.com Page 2074


i += 1;
}

Sql komutunun yrtlmesi tamamlandnda, IAsyncResult nesnemizin IsCompleted zellii true


deerini dndrecektir. Dolaysyla dngden klm olunacak ve bir sonraki satra gelinecektir.
Gerekletirdiimiz asenkron ileyii aadaki ekil ile kafamzda daha kolay canlandrabileceimizi
dnyorum.

ekil 3. Pooling Modelinde leyi Tarz.

Tabiki, dng ierisinde yer alan ilemlerin daha uzun srede gereklemesi gibi bir durum ilede
karlaabiliriz. Byle bir durumda, IAsyncResult nesnesine ait proses tamamlanm olsa bile, dier
ilemler devam ettii iin bu ilemler sonlanana kadar uygulama donacaktr.

int sonuc = cmd.EndExecuteNonQuery(res);

Bu satrda ise, EndExecuteNonQuery metoduna ytlen sql komutuna ait prosesi temsil eden
IAsyncResult nesnemiz parametre olarak gnderiliyor. Bylece, tamamlanan proses sonucu elde
edilen deer (ExecuteNonQuery' nin integer bir deer dndrdn, yani sql sorusundan
etkilenen satr saysn verdiini belirtelim.) uygulama ortamna aktarlyor. Uygulamamz
altrdmzda aadaki ekran grntsn elde ederiz.

www.bsenyurt.com Page 2075


ekil 4. Uygulamann almas sonucu.

Elbetteki, bu rneimizde olduu gibi bir while dngsn kullanmak zorunda deiliz. Sonu
olarak, IAsyncResult nesnesi, End metodlar ile ortama iade edilinceye kadar yer alan tm satrlar
alacaktr. Dier taraftan, ayn anda birden fazla sql komutunun asenkron olarak altrlmasnda
salayabiliriz. Dilerseniz pooling modelinin, birden fazla Sql komutunun yrtlebilmesi iin nasl
kullanlabileceini bir rnek ile inceleyelim. Bu amala, Console uygulamamzdaki kodlarmz
aadaki hale getirelim.

try
{
/* Balantmz olutururken Asynchronous Processing zelliine true deerini vermeyi ihmal
etmiyoruz.*/
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;MultipleActiveResultSets=true;Asynchronous
Processing=true");

/* SqlCommand nesnelerimizi oluturuyoruz. lki bir tablo zerinde gncelleme yaparken,


ikincisi bir View nesnesinde veri ekiyor.*/
SqlCommand cmd = new SqlCommand("UPDATE Production.Product SET
ListPrice=ListPrice+10", con);
SqlCommand cmd2 = new SqlCommand("SELECT * FROM Sales.vStore", con);
con.Open(); // Balantmz ayoruz.
IAsyncResult res = cmd.BeginExecuteNonQuery();
IAsyncResult res2 = cmd2.BeginExecuteReader();

//Bu aralktaki satrlar bloke olmadan alr.


/* Dng her iki sql komutuda tamamlanncaya kadar alacaktr. Eer bunlardan her hangibir
nce biterseki yle olacaktr, dieride sonlanncaya kadar dng ierisindeki kodlar iletilmeye
devam eder.*/

www.bsenyurt.com Page 2076


while ((!res2.IsCompleted)||(!res.IsCompleted))
{
/* Eer Update komutu tamamlanm ise, o anki milisaniye ile birlikte ekrana RES BITTI
yazdrr. Eer ilem tamamlanmamsa, RES ISLEMINE DEVAM EDIYOR tekstini ve o anki
milisaniyeyi yazar.*/
if (res.IsCompleted)
{
Console.WriteLine("RES BITTI ");
Console.WriteLine(DateTime.Now.TimeOfDay.Milliseconds.ToString());
}
else
{
Console.WriteLine("RES ISLEMINE DEVAM EDIYOR " +
DateTime.Now.TimeOfDay.Milliseconds.ToString());
}
/* Eer Select komutu tamamlanm ise, o anki milisaniye ile birlikte ekrana RES2 BITTI
yazdrr. Eer ilem tamamlanmamsa, RES2 ISLEMINE DEVAM EDIYOR tekstini ve o anki
milisaniyeyi yazar.*/
if (res2.IsCompleted)
{
Console.WriteLine("RES2 BITTI ");
Console.WriteLine(DateTime.Now.TimeOfDay.Milliseconds.ToString());
}
else
{
Console.WriteLine("RES2 ISLEMINE DEVAM EDIYOR " +
DateTime.Now.TimeOfDay.Milliseconds.ToString());
}
}
/* Update sorgusunun sonularn ilgil IAsyncResult nesnesini parametre olarak vererek integer
bir deikene atyoruz. Burada EndExecuteNonQuery metodu aynen ExecuteNonQuery metodunda
olduu gibi geriye , sorgudan etkilenen satr saysn dndrecektir. */
int sonuc = cmd.EndExecuteNonQuery(res);
Console.WriteLine(sonuc + " SATIR GNCELLEND...");

/* Select sorgusu ile elde edilen kayt kmesini ortama almak iin, EndExecuteReader metoduna
res2 isimli IAsyncResult nesne rneini parametre olarak gnderiyoruz ve bu kmedeki ilk satra
ait 0nc ve 1nci alanlarn deerlerini ekrana yazdryoruz.*/
SqlDataReader dr = cmd2.EndExecuteReader(res2);
dr.Read();
Console.WriteLine(dr[0] + " " + dr[1]);
dr.Close(); // SqlDataReader nesnemizi kapatyoruz.
Console.ReadLine();
con.Close(); // Balantmz kapatyoruz.
}
catch (Exception hata)
{
Console.WriteLine(hata.Message);
Console.ReadLine();

www.bsenyurt.com Page 2077


}

Bu rnekte, iki sql komutunu asenkron olarak altrmaktayz. Yrtlecek her iki komut iinde
birer IAsyncResult tipinden nesne rnei oluturuyoruz. Bu andan itibaren, uygulamada farkl
ilemler yapabiliriz. Biz burada, while dngsn her iki IAsyncResult nesne rneinin temsil ettii
proseslerde alan sql komutlar sonlanncaya kadar altrmaktayz. Yrtlen komutlar
ileyilerini bitirdiklerinde, kullandklar IAsyncResult nesne rnekleri yardmyla asl sonular
ortama alyoruz. Sonu itibariyle, alan sql komutlar asenkron olarak yrtlmekte ve almalar
esnasnda programn bloke olmas nlenmektedir. Aadaki ekran grntsnden de dikkat
edeceiniz gibi, daha ksa sren UPDATE ilemi tamamlandktan sonra, dier komut bitene dek
dng devam etmitir.

ekil 5. Uygulamann almas sonucu.

Bu makalemizde Asenkron Sql Komutlarn Yrtlmesi konusuna ksaca deinerek


kullanabileceimiz tekniklerden birisi olan Pooling Modelini inceledik. Pooling modeli aslnda, ok
byk boyutlu sorgular ieren sql komutlarnn asenkron olarak yrtlmesinde ok faydal bir
teknik deildir. Bunun yerine daha gelimi olan dier modellerden CallBack Modeli veya Wait

www.bsenyurt.com Page 2078


Modeli yararlanlabilir. Bir sonraki makalemizde, CallBack modelini incelemeye alacaz. Tekrar
grnceye dek hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ile Mars' a Ayak Basyoruz (


20.09.2004 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, MARS (Multiple Active Results Sets) kavramn incelemeye alacaz. MARS
kavram Ado.Net 2.0 mimarisine monte edilmi yeni bir yapdr. Bu yapnn bize salad
avantajlar anlayabilmek iin, Ado.Net 1.0/1.1 srmlerinin kabiliyetlerine ve kstlamalarna ksaca
bir gz atmak gerekmektedir.

Editrn Notu : Final srmnde, ConnectionString katar ierisinde MultipleActiveResultSets=true


kullanlmamas halinde, MARS etkisi grlmemektedir. Varsaylan olarak MultipleActiveResultSets zelliinin
deeri false' dur. MARS teknii, MultipleActiveResultSets deeri aka true' ya set edildii takdirde
almaktadr.

Ado.Net' in nceki srmlerinde, zellikle veri kmelerini uygulama ortamna ekmek istediimizde
kullanabileceimiz iki temel teknik vardr. Birincisi, balantsz katmana veri alabilmek iin
DataAdapter, DataTable, DataSet gibi nesnelerin kullanlmasdr. kincisi ise, daha sratli veri
ekmemizi salayan ve veri kaynana olan balantnn sql komutunun ileyii boyunca ak
olmasn gerektiren, DataReader nesnelerinin kullanld tekniktir.

Bu tekniklerin hangisi kullanlrsa kullanlsn zellikle ayn balant zerinden e zamanl olarak
yrtlen sql komutlarnn altrlmasna izin veren bir yap yoktur. Yani, veri kaynandan bir
DataReader nesnesi ile veri ekerken, ayn ak balant zerinden gncelleme, ekleme, silme gibi
ilemleri ieren sql komutlarn altramayz. te bu imkanszl gidermek amacyla Ado.Net
mimarisi iine MARS, Asenkron Komut Yrtme ve ObjectSpace gibi yeni ve kkl deiiklikler
eklenmitir. Biz bu gnk makalemizde, ayn ak balant zerinden birden fazla kayt kmesini
uygulama ortamna ekmemize ve onlara erimemize imkan salayan MARS (Multiple Active
Results Sets) yapsn tanmaya alacaz.

MARS, zellikle ayn ak balant zerinden birden fazla satr kmesini elde edebileceimiz sql
komutlarnn e zamanl olarak altrlmasna imkan verir. rnein Ado.Net' in eski srmlerinde
u senaryoyu gz nne alalm; ayn veri kaynanda yer alan ve ayn balant zerinden
erieceimiz kayt kmesi olsun. Bu kayt kmelerini 3 farkl SqlDataReader nesnesi ile ortama
ekmek istediimizi dnelim. Bu ilemi simle edebilmek iin VS.NET 2003' de basit bir Console
uygulamas gelitireceiz. Uygulamamzn kodlar aadaki gibi olacaktr.

using System;
using System.Data.SqlClient;
using System.Data;

namespace MultipleReader

www.bsenyurt.com Page 2079


{
class AdoNet1nokta1de
{
[STAThread]
static void Main(string[] args)
{
try
{
SqlConnection con=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=SSPI");

SqlDataReader dr1;
SqlDataReader dr2;
SqlDataReader dr3;

SqlCommand cmd1=new SqlCommand("SELECT * FROM Customers",con);


SqlCommand cmd2=new SqlCommand("SELECT * FROM Orders",con);
SqlCommand cmd3=new SqlCommand("SELECT * FROM [Order Details]",con);

con.Open();

dr1=cmd1.ExecuteReader();
dr2=cmd2.ExecuteReader();
dr3=cmd3.ExecuteReader();

con.Close();
}
catch(Exception hata)
{
Console.WriteLine(hata.Message);
}
}
}
}

Uygulamamz altrdmzda alma zamannda bir istisnann frlatldn grrz.

ekil 1. Ado.Net 1.0./1.1' deki durum.

Sorun udur ki, ilk altrlan SqlDataReader nesnesini kapatmadan dierlerini altrmamz da
mmkn deildir. Nitekim SqlDataReader nesnesi, altrd Sql komutunu ile verileri ekebilmek
iin ilgili balantnn kendisi iin tahsis edilmesini ve ii bitene kadar da bakalar tarafndan
kullanlmamasn gerektirir. Bu, tamamyla Ado.Net' in mimarisinden kaynaklanan bir glktr.
Bununla birlikte, akla yle bir zm yolu gelebilir. Her bir SqlDataReader nesnesini kendi
SqlConnection havuzu iinde altrmak. Yani yukardaki kodu aadaki gibi yazmak.

www.bsenyurt.com Page 2080


SqlConnection con1=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=SSPI");
SqlConnection con2=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=SSPI");
SqlConnection con3=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=SSPI");
SqlDataReader dr1;
SqlDataReader dr2;
SqlDataReader dr3;

SqlCommand cmd1=new SqlCommand("SELECT * FROM Customers",con1);


SqlCommand cmd2=new SqlCommand("SELECT * FROM Orders",con2);
SqlCommand cmd3=new SqlCommand("SELECT * FROM [Order Details]",con3);

con1.Open();
con2.Open();
con3.Open();

dr1=cmd1.ExecuteReader();
dr2=cmd2.ExecuteReader();
dr3=cmd3.ExecuteReader();

con1.Close();
con2.Close();
con3.Close();

Bu haliyle uygulama alacak ve herhangibir hata mesaj yada istisna vermeyecektir. Uygulanan
bu teknik her ne kadar zmm gibi grnsede, gereksiz yere kaynak tketimine neden
olmaktadr. Nitekim ayn balant iin kez SqlConnection nesnesi rneklendirilmi ve sql
sunucuna adet ayr isimli ama ayn zellikte balant hatt tesis edilmitir. Dahas bu teknik
kullanld takdirde her alan Sql komutunun ileyii sonlanana kadar, bir sonraki sql komutuna
geilemiyecektir. Bunu zmek iinde, bu veri ekme ilemlerini ayr metodlar halinde tanmlayp
ok-kanall (multi-threading) programlama tekniklerini uygulayabiliriz. Ancak bu yaklamlar
elbetteki ok verimli yada leklenebilir deildir.

zm, .Net mimarlar tarafndan Ado.Net 2.0' a yerletirilmitir ve MARS olarak adlandrlmtr.
imdi ilk yazdmz uygulamay birde .Net framework 2.0 ortamnda gelitirelim. Kodlarmz hi
deitirmeyeceiz. Bu kez Yukon zerinde yer alan AdventureWorks isimli veritabanndaki iki
tabloya ayn ak balant zerinden ayn zamanda erimeye alacaz. te kodlarmz,

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data.SqlClient;
using System.Data;

#endregion

www.bsenyurt.com Page 2081


namespace MarsEtkisi
{
class Program
{
static void Main(string[] args)
{
try
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI");

SqlCommand cmd1 = new SqlCommand("SELECT TOP 10 * FROM Person.address",


con);
SqlCommand cmd2 = new SqlCommand("SELECT TOP 3 * FROM Person.contact", con);

SqlDataReader dr1;
SqlDataReader dr2;

con.Open();

dr1 = cmd1.ExecuteReader();
dr2 = cmd2.ExecuteReader();

while (dr1.Read())
{
Console.WriteLine(dr1["AddressLine1"]);
}
Console.WriteLine("-------------");
while (dr2.Read())
{
Console.WriteLine(dr2["FirstName"]);
}

con.Close();
Console.WriteLine("-------------");
Console.ReadLine();
}
catch (SqlException hata)
{
Console.WriteLine(hata.Message);
}
}
}
}

Uygulamay bu haliyle altrdmzda aadaki ekran grntsn elde ederiz. Grld gibi,
SqlDataReader nesneleri, dierinin kapatlmasna gerek duymadan veri kaynandan veri
ekebilmitir.

www.bsenyurt.com Page 2082


ekil 2. MARS Etkisi.

Bu rnek basit olarak MARS kavramn aklamaktadr. Olay daha iyi kavrayabilmek amacyla
aadaki ekildende faydalanabiliriz.

ekil 3. MARS (Multiple Active Results Sets)

ekildende grlebilecei gibi, bir veritabannda yer alan eitli saydaki tabloya ait veri kmelerini
ayn uygulama ortamna, farkl ama tek bir ortak balanty kullanan DataReader nesneleri
yardmyla eriebilmemiz mmkndr.

imdi dilerseniz, MARS etkisini daha iyi grebileceimiz baka bir rnei gz nne alalm. Bu kez
bir birleriyle bire-ok ilikisi olan iki tabloyu ele alacaz. Bu tablolara ait verileri uygulama

www.bsenyurt.com Page 2083


ortamna yine DataReader nesneleri yardmyla ekeceiz. Ancak iin ilgin yan, bir DataReader
nesnesi alrken ve satrlar arasnda iterasyon yaparken, dierine parametre gndererek her bir
satr iin dier DataReader' nda altrlmasnn salanm olacadr. Bu rnei gerekletirmek
iin aadaki kodlar yazarak, Visual Studio.Net 2005' de basit bir Console uygulamas gelitirelim.

static void Main(string[] args)


{
try
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=Dukkan;integrated security=SSPI");

SqlCommand cmd1 = new SqlCommand("SELECT * FROM DepartmanSinif", con);


SqlCommand cmd2 = new SqlCommand("SELECT * FROM PersonelDetay WHERE
PersonelID=@PersonelID", con);
cmd2.Parameters.Add("@PersonelID", SqlDbType.Int);

SqlDataReader dr1;
SqlDataReader dr2;

con.Open();
dr1 = cmd1.ExecuteReader();
while (dr1.Read())
{
Console.WriteLine(dr1["Departman"]);
Console.WriteLine(" ALTINDAKI ELEMANLARI....");
cmd2.Parameters["@PersonelID"].Value = dr1["PersonelID"];
dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
Console.WriteLine(dr2["Ad"]+" "+dr2["Soyad"]+" "+dr2["Mail"]);
}
dr2.Close();
Console.WriteLine("------------");
}

con.Close();
Console.ReadLine();
}
catch (Exception hata)
{
Console.WriteLine(hata.Message);
Console.ReadLine();
}
}

Uygulamamz altrdmzda ilikili tablolara ait verilerin ekrana yazdrldn grrz.

www.bsenyurt.com Page 2084


ekil 4. MARS Etkisi sayesinde iie alan SqlDataReader' lar.

rneimizde, SqlDataReader nesnelerini kullanarak Yukon sunucusu zerinde yer alan ilikili iki
tabloya ait verileri console uygulamasndan ekrana yazdrmaktayz. dr1 isimli SqlDataReader
nesnesi yardmyla DepartmanSinif isimli master tablodan satrlar bir while dngs ile
okumaktayz. Bu dngnn ierisinde ceyran eden olaylar ise bizim iin MARS etkisinin gcn bir
kere daha gstermektedir. Nitekim, dr1 nesnesi ile master tablodan her bir satr okunduunda bu
satra ait olan PersonelID alannn deeri, baka bir komuta parametre olarak gitmekte ve en
nemliside bu komutu bir SqlDataReader nesnesi, dieri halen daha akken yrterek uygulama
ortamna sonu kmesini dndrmektedir. Ayn kod mantn Ado.Net 1.1 verisyonunda Sql 2000
sunucusu zerinde gereketirmeye altmz aadaki rnei gz nne aldmzda ise;

try
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=SSPI");

SqlCommand cmd1 = new SqlCommand("SELECT * FROM Orders", con);


SqlCommand cmd2 = new SqlCommand("SELECT * FROM [Order Details] WHERE
OrderID=@OrderID", con);
cmd2.Parameters.Add("@OrderID", SqlDbType.Int);

SqlDataReader dr1;
SqlDataReader dr2;

con.Open();
dr1 = cmd1.ExecuteReader();
while (dr1.Read())
{
Console.WriteLine(dr1["OrderDate"]);
Console.WriteLine(" ALTINDAKI ELEMANLARI....");
cmd2.Parameters["@OrderID"].Value = dr1["OrderID"];
dr2 = cmd2.ExecuteReader();
while (dr2.Read())
{
Console.WriteLine(dr2["ProductID"]+" "+dr2["UnitPrice"]+" "+dr2["Quantity"]);
}

www.bsenyurt.com Page 2085


dr2.Close();
Console.WriteLine("------------");
}

con.Close();
Console.ReadLine();
}
catch (Exception hata)
{
Console.WriteLine(hata.Message);
Console.ReadLine();
}

Bu kez Ado.Net 1.1' in mimarisi bu tarz bir ileme izin vermeyecek ve while dngs iinden elde
edilen ilk tablo satrndan sonra, ikinci SqlDataReader nesnesi yrtlmeye alldnda, halen
almakta olan SqlDataReader' n ilemini sonlandrmas gerektiini syleyecektir.

ekil 5. Ado.Net 1.1'deki durum.

Grld gibi, MARS yaps var olan snflarn kabiliyetlerini arttrarak ayn ak balant zerinden
birden fazla sayda kayt kmesine eriebilme imkanna sahip olmamz salamtr. in gzel yan
MARS etkisini uygulamalarmza yanstabilmek iin, snflarmza has eitli ayarlamalar
yapamamza gerek olmaydr. Aynen Ado.Net 1.1 uygulamalar yazar gibi yazabiliriz kodlarmz.
Elbetteki bu mimari deiiklikler sayesinde Ado.Net snflarnn imkan ve kabiliyetleri nemli
derecede artmtr. Ado.Net 2.0 ile gelen tek yenilik MASR deildir. Bunun yannda, ayn anda
birden fazla sql komutunu altrmamza yarayan asenkron komut yrtme teknikleride
eklenmitir. Bu konuyuda bir sonraki makalemizde incelemeye alacaz. Hepinize mutlu gnler
dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve Toplu Gncelleme lemleri


(Batch-Updates) ( 18.09.2004 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Toplu gncelletirme ilemleri, birden fazla sql ifadesinin (insert,update,delete,select gibi) arka
arkaya gelecek ekilde ancak tek bir seferde altrlmasn baz alan bir tekniktir. Ado.Net 2.0 ile,
toplu gncelletirme ilemlerine daha fazla fonksiyonellik kazandrlmtr. Bu koul elbetteki toplu
gncelletirme ilemlerini destekeleyen veritaban sunucular zerinde geerli olmaktadr. u an
iin, ynetimsel kodda yer alan Oracle ve Sql nesnelerinin destekledii bu fonksiyonellii kazanmak

www.bsenyurt.com Page 2086


iin aada prototipi verilen ve SqlDataAdapter yada OracleDataAdapter snflarna ait olan,
UpdateBatchSize zellii kullanlmaktadr.

public override int UpdateBatchSize {get;set;}

Bu zellik bir anlamda, DataAdapter nesnesinin Update komutu ile veritabanna doru yaplacak
gncelleme ilemlerinin toplu olarak hangi periyotta gerekletirileceini belirtir. rnein, 1
varsaylan deeridir ve her bir gncelleme ileminin (insert,update veya delete) her satr iin ayr
ayr yaplacan belirtir. Daha derin dnecek olursa, rnein Sql Sunucusunda yer alan
sp_executesql stored procedure' nn her bir satr iin birer kez ilgili komutu (Insert gibi)
altracan belirtir.

Dier yandan, bu zellie 0 deerini verdiimizde tm gncelleme ilemleri tek bir seferde
gerekletirilir. Bir baka deyile veritabanna doru n sayda gncelleme ilemi varsa, Sql
Sunucusunda yer alan sp_executesql stored procedure' bu n saydaki ilemleri ieren toplu bir
komut kmesini tek bir seferde altrlacaktr. Ayrca UpdateBatchSize zelliine 0 ve 1 haricinde
verilecek olan pozitif deerler, her bir toplu gncelletirme ileminin ka i komut iereceini
belirtmektedir. Konuyu daha kolay bir ekilde anlayabilmek iin basit bir Console uygulmas
gelitirelim.

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

#endregion

namespace BatchUpdates
{
class Program
{
static void Main(string[] args)
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI");
SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM MailList", con);
DataTable dt = new DataTable();
da.Fill(dt);

DataRow dr;
for (int i = 1; i <= 5; i++)
{
dr = dt.NewRow();
dr["AD"] = "AD_" + i.ToString();
dr["SOYAD"] = "SOYAD_" + i.ToString();
dr["MAIL"] = "MAIL_" + i.ToString();
dt.Rows.Add(dr);

www.bsenyurt.com Page 2087


}
da.UpdateBatchSize = 1;
SqlCommandBuilder cm = new SqlCommandBuilder(da);
da.Update(dt);
Console.WriteLine("LEMLERN SONU");
Console.ReadLine();
}
}
}

Bu uygulamada Ado.Net 1.1 ile yapabildiimiz ilemlerden farkl bir ey yoktur. Yukon zerinde yer
alan MailList tablomuza SqlDataAdapter nesnesi vastasyla 5 adet satr giriyoruz. Bizim iin nemli
olan UpdateBatchSize deerinin 1 olarak belirtilmesidir. Uygulamamz altrmadan nce, Sql
Profiler aracn kullanarak yeni bir Trace balatalm ve Sql Sunucumuzda gerekleen ilemleri
izlemeye alalm. Trace' imiz alrken uygulmamamz yrtecek olursak, Sql Sunucusu zerinde
aadaki olaylarn gerekletirildiini grrz.

ekil 1. UpdateBatchSize deeri 1 olduunda.

Dikkat edecek olursanz, sp_executesql stored procedure' girilen her satr iin insert komutunu
birer kez altrmtr. Bunun nedeni UpdateBatchSize zelliinin 1 deerine sahip olmasdr. Eer
bu deeri 0 yapp tekrar altrrsak, bu takdirde ka satr girersek girerlim tm satrlar iin geerli

www.bsenyurt.com Page 2088


olan insert komutlar tek bir toplu-komut olarak ilenecek ve tek bir seferde altrlacaktr. rnek
olarak, dngmzn deerini 20 satr insert edilecek ekilde ayarladmz dnrsek,
UpdateBatchSize zelliine 0 deerini vermek ile, 20 satr iin parametre alacak tek bir stored
procedure' arm oluruz. Uygulamamzda bu kez tm satrlar update ettiimizi dnelim ve
UpdateBatchSize zelliine 0 deerini verelim.

for (int i = 0; i < dt.Rows.Count; i++)


{
dr = dt.Rows[i];
dr["AD"] ="_DEGISTI";
}

da.UpdateBatchSize = 0;

imdi Sql Profiler' da Trace' imizdeki ilemlere bakacak olursa, ka satr gncellenmi ise her bir
satr iin yaplan update ilemlerinin tek bir toplu-komut kmesinde gerekletirildiini grrz.

ekil 2. UpdateBatchSize zelliine 0 deeri verildiinde.

www.bsenyurt.com Page 2089


Elbette daha nceden bahsettiimiz gibi UpdateBatchSize zelliine 0 ve 1 haricinde pozitif
deerlerde verebiliriz. Bu durumda toplu-komut kmeleri belirtilen say kadar i komut ierecektir.
rneimizde, UpdateBatchSize deerini 7 yaparsak, her bir sp_executesql arsnda, isel olarak 7
satrlk ilem ieren toplu-komut kmeleri olduunu grrz.

da.UpdateBatchSize = 7;

ekil 3. UpdateBatchSize deerini pozitif her hangibir say olarak belirlediimizde.

rneklerdende grld gibi, Ado.Net 2.0 toplu-komut gncelleme ilemlerine daha fazla
fonkisyonellik katmak amacyla kullanl bir zellik kazanmtr. Baz durumlarda, gncelleme
ilemlerinin balantsz katmandan, veritabanna doru olan hareketlerinde toplu olarak yaplmas
network trafiini olumlu ynde etkileyecek bir gelimedir. nk, tm gncelleme hareketleri iin
veritabanna doru sadece tek bir tur atlacaktr. Elbetteki devasa boyutlara sahip olan veri
kaynaklar zerinde yaplacak byk apl gncelleme ilemlerinde, toplu-komut kmelerini belirli
saylarda komut ierecek ekilde ayarlamakta performans asndan olumlu bir etki yaratacaktr.

Bu makalemizde, ksaca toplu-gncelletirme (Batch-Update) ilemlerine deinmeye altk.


lerleyen makalelerimizde, Ado.Net 2.0' n yeni zelliklerine bakmaya devam edeceiz. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 2090


Burak Selim ENYURT

selim@bsenyurt.com

Ado.Net 2.0 ve Bulk-Data Kopyalama


Mekanizmas ( 17.09.2004 ) - Ado.Net 2
Deerli Okurlarm Merhabalar,

Sql Server'da bir veritaban tablosundan, baka bir hedef tabloya veri tama ilemi bulk-data
kopyalama olarak adlandrlr. Veritaban yneticileri ounlukla bu operasyonu gerekletirmek
amacyla, BCP ad verilen komut satr aracn kullanrlar. Burada ama, kaynak tablodaki satrlarn
veya bir satr kmesinin farkl konumda olabilecek bir tabloya tanmasdr. Hedef tablo ayn
veritabannda olabilecei gibi, dier bir sql sunucusu zerindeki baka bir veritabannda da yer
alabilir. Ado.Net 2.0' da SqlClient isim alanna eklenen yeni snflar yardmyla bu ilemleri ynetimli
kodda (managed-code) gerekletirme imkanna da artk sahibiz. Bu makalemizde, bu ilemleri
gerekletirmek iin kullanabileceimiz yeni Ado.Net 2.0 snflarn incelemeye alacaz.

Bulk-Data kopyalama ilemi iin Ado.Net 2.0 ile gelen en nemli snf, SqlClient isim alannda yer
alan SqlBulkCopy snfdr. Bu snfa ait nesne rnekleri yardmyla, kaynak tablodan hedef tabloya
veri transferi ilemleri kolayca gerekletirilebilir. Bu ilemler srasnda SqlBulkCopy nesne
rnekleri, tama ilemini varsaylan olarak at bir transaction ierisinde gerekletirmektedir.
Yani, hedef tabloya yaplan tama ilemleri srasnda oluabilecek olan hatalar sonrasnda,
transaction ilemi iptal edilerek roll-back operasyonu gerekleir ve hedef tabloya o ana kadar
girilen satrlar geri alnr.

Burada nemli olan noktalardan birisi, kaynak ve hedef tablolarn ayn ema yapsna sahip
olmalarnn nemli olmaydr. Yani, ayn alan adlar, eit alan saylar ve ayn alan sralar olmak
zorunda deildir. Nitekim, hedef tablo ile kaynak tablo arasnda alan elemelerinde uyumsuzluk
olabilir. rnein, alan adlar ve saylar birbirinden farkl olabilir. te bu durumda, kaynak ve hedef
tablodaki alanlar birbirleriyle eletirmekte kullanlan SqlBulkCopyColumnMapping snfna ait
nesne rnekleri kullanlr. Bu snf yardmyla kaynak ve hedef alanlarn kolayca eletirilmesi
salanm olur. Bulk-Data kopylama ilemi iin nemli olan bir dier snf ise,
SqlBulkCopyColumnMappingCollection' dr. Bu snf ise, tahmin edeceiniz gibi
SqlBulkCopyColumnMapping snf trnden nesne rneklerinin bir koleksiyonunu ifade etmektedir.

Bulk-Data kopyalama operasyonunda, kaynak veriler iin yine SqlClient isim alanndaki standart
nesneler kullanlabilir. Esasen bu tip bir operasyonda, kaynak verileri herhangibir SqlDataReader
nesnesinden, bir DataTable' dan veya bir DataRow dizisinden alabiliriz. Hatta bir Xml dkmannda
kaynak olarak kullanabiliriz. Bylece ynetimsel koda kazandrlan bu imkanlar ile veri tama
ilemi iin byk esneklik kazanm olmaktayz.

www.bsenyurt.com Page 2091


ekil 1. SqlBulkCopy Snfnn alma ekli.

Bulk-Data kopylama ileminin daha kolay anlalabilmesi iin elbette rnekler ile olay incelememiz
daha faydal olacaktr. imdi aadaki basit Console uygulamasn gz nne alalm.

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Data.SqlClient;

#endregion

namespace BulkCopy
{
class Program
{
static void Main(string[] args)
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI;MultipleActiveResultSets=true");

/*Hedef tablodaki satrlar nlem olarak siliyoruz.*/


SqlCommand cmd = new SqlCommand("DELETE FROM YEDEK_MailList", con);
con.Open();
cmd.ExecuteNonQuery();

/* Kaynak tablodan verileri SqlDataReader yardmyla ekiyoruz.*/


SqlCommand cmdCek = new SqlCommand("SELECT * FROM MailList", con);
SqlDataReader dr;

www.bsenyurt.com Page 2092


dr = cmdCek.ExecuteReader();

/*SqlBulkCopy nesnemizi hedef balanty belirterek oluturuyoruz.*/


SqlBulkCopy bc = new SqlBulkCopy(con);

/* Hedef tabloyu belirtiyoruz.*/


bc.DestinationTableName = "YEDEK_MailList";

/*WriteToServer metodu ile SqlDataReader' dan okuduumuz satrlar, hedefe insert


ediyoruz.*/
bc.WriteToServer(dr);

/* Nesneleri kapatyoruz.*/
bc.Close();
dr.Close();
con.Close();
}
}
}

rneimizi incelemeden nce, Yukon sunucumuz zerinde, AdventureWorks veritaban altnda


MailList ve YEDEK_MailList isimli iki tablomuz olduunu ve bu tablolarn ema yaplarnn
birbirleriyle tamamen ayn olduklarn belirtelim.

ekil 2. Her iki tablonunda ema yaps ayndr.

Burada gerekletirdiimiz operasyon, bulk-data kopyalama ileminin en basit halidir. imdi neler
yaptmza biraz daha yakndan bakalm. lk olarak Yukon sunucumuzdaki AdventureWorks
veritabanna bir balant atk. Daha sonra, tedbir olarak YEDEK_MailList tablosundaki tm satrlar
sildik. Nitekim byle bir ilem yapmasaydk YEDEK_MailList tablosuna tanan satrlar srekli arka
arkaya eklenecekti. Daha sonra ise, klasik olarak kaynak tablomuzdan verileri bir SqlDataReader
nesnesi yardmyla ektik. Bizi asl ilgilendiren ksm aadaki kod satrlarnn yer ald ksmdr.

www.bsenyurt.com Page 2093


SqlBulkCopy bc = new SqlBulkCopy(con);

bc.DestinationTableName = "YEDEK_MailList";

bc.WriteToServer(dr);

Burada ilk satrda, SqlBulkCopy nesnemizi o anki geerli SqlConnection nesnesi ile oluturuyoruz.
Yapc metoda ait parametre hedef balanty temsil etmektedir. Nitekim, hedef tablomuz ayn
sunucuda olmayabilir. Ya da, ayn veritaban zerinde olmayabilir. Bu nedenle burada balanty
dikkatli semek gerekmektedir. Sonraki satrda ise, tama ileminin hedef alnd tablo,
SqlBulkCopy nesnemize DestinationTableName zellii ile bildirilir. Buradaki tablo, SqlBulkCopy
nesnesi rneklendirilirken parametre olarak verdiimiz SqlConnection nesnesinin belirttii balant
zerinde aranr. Son satrmzda ise, WriteToServer metodu kullanlmtr. Bu metoda da parametre
olarak, kaynak tabloya ait veri kmesini tayan SqlDataReader nesnesi verilmitir. Bylece
WriteToServer metodu, SqlDataReader nesnesi ile MailList tablosundan okuduumuz satrlar,
SqlBulkCopy nesnesi oluturulurken belirtilen balant zerindeki hedef tabloya yazmaktadr.

rnei altrdmzda, kaynak verilerin hedef tabloya tandn grrz. Burada enteresan bir
nokta vardr. Bu ilemi st ste bir ka kez uyguladmzda, hedef tablodaki ID alannn
deerlerinin srekli olarak arttn grrz. yleki kaynak tablomuzda 1,2,3 olarak giden ID alan
deerleri, uygulama bir ka kez altrldktan sonra hedef tabloda aadaki gibi olabilir.

ekil 3. ID alannn durumu.

Her ne kadar biz ID alann her iki tabloda otomatik olarak artan identity deeri ile belirtsekte,
Bulk-Data kopyalama ileminde, ID deerlerinin bozulmadan hedef tabloya yanstlabilmeside
mmkndr. Bunun iin, SqlBulkCopy nesnemizin bir dier yapc metodunu kullanrz.

public SqlBulkCopy(connectionString, SqlBulkCopyOptions copyOptions);

Bu yapc metod SqlBulkCopyOptions numaralandrcs trnden bir parametre daha alr. Bu


numaralandrcnn alabilecei deerler unlardr.

SqlBulkCopyOptions Numaralandrc
Aklamas
Deeri

CheckConstraints Hedef tablodaki kstlamalar var ise bunlar gz nne


alnarak veri girii gerekleir.

Default Varsaylan deerler kullanlr.

www.bsenyurt.com Page 2094


KeepIdentity Kaynak tablodaki identity deerleri hedef tablodada
korunur. Yani deitirilmeden eklenir.

KeepNulls Null deerlerin hedef tabloya korunarak geirilmesini


salar.

TableLock Bulk-Data kopylama ilemi srasnda tabloya kilit


koyar.

Bizim rneimizde kullanmamz gereken deer, KeepIdentity' dir. imdi kodumuzdaki SqlBulkCopy
nesnemizin yapc metodunu aadaki parametreleri ile aralm.

SqlBulkCopy bc = new SqlBulkCopy("data source=localhost;initial


catalog=AdventureWorks;integrated security=SSPI", SqlBulkCopyOptions.KeepIdentity);

Uygulamamz imdi tekrar altracak olursak, hedef tablomuz olan YEDEK_MailList iindeki ID
alanlarnn deerlerinin, kaynak tablodaki ile ayn olduunu bir baka deyile korunduunu grrz.
Uygulamamz bir ka sefer st ste altrsakta sonu ncekinde olduu gibi deimeyecek ve
kaynak tablodaki ID alanlarnn deerleri hedef tabloya korunarak geecektir.

Veri tamalarndaki dier bir noktada, null deerlerin hedef tabloya tanmasdr. Dikkat edecek
olursanz, SqlBulkCopyOptions numaralandrcs Null deerlerin hedef tabloya korunarak
geirilmesini salayan KeepNulls deerine sahiptir. Bu zellii daha iyi anlayabilmek amacyla hedef
tablomuzda ufak bir deiiklik yapalm. MAIL alannn null deer ierebildiini biliyoruz. Hedef
tablomuzda bu alan iin bir default deer verelim.

ekil 4. Default Deer belirledik.

www.bsenyurt.com Page 2095


imdi bu koullarda MailList isimli kaynak tablomuzda yeni bir satr oluturalm ancak MAIL alann
null olarak brakalm. Uygulamay altrdmzda, bu satrn null deerinin hedef tabloya
tanmadn ve hedef tabloya "MAIL TANIMLI DEGIL" deerinin yazldn grrz.

ekil 5. Null deer tanmad.

Ancak SqlBulkCopy nesnemizi aadaki gibi oluturduumuzda, null deerin hedef tablodaki alana
tandn grrz.

SqlBulkCopy bc = new SqlBulkCopy("data source=localhost;initial


catalog=AdventureWorks;integrated security=SSPI", SqlBulkCopyOptions.KeepNulls);

imdiye kadar ki kodlarmzda, SqlBulkCopy nesnesi iin iki yapc metod kullandk. SqlBulkCopy
nesnelerini oluturabileceimiz yapc metodlarn tamam aadaki tabloda yer almaktadr.

Name Description

SqlBulkCopy (SqlConnection) Hedef balanty bir SqlConnection nesnesi belirtir.

SqlBulkCopy (String) Hedef balant iin SqlConnection String kullanlr.

SqlBulkCopy (String, SqlBulkCopyOptions) Hedef balanty string bilgisi olarak alr ve


SqlBulkCopy nesnesini, SqlBulkCopyOptions
numaralandrcs ile bertilen artlara gre oluturulur.

SqlBulkCopy (SqlConnection, SqlBulkCopy nesnesini hedef balantda,


SqlBulkCopyOptions, SqlTransaction) SqlBulkCopyOptions ile belirtilen artlarda,
SqlTransaction nesnesi ile belirtilen Transaction iinde
oluturur.

Bulk-Data kopyalama ilemini asl gerekletiren WriteToServer metodununda eitli ar


yklenmi (overload) verisyonlar vardr. Bu versiyonlar aadaki tabloda olduu gibidir.

Overload Versiyonu Aklamas

SqlBulkCopy.WriteToServer (DataRow[]) Bir DataRow dizisini hedef tabloya tar.

www.bsenyurt.com Page 2096


SqlBulkCopy.WriteToServer (DataTable) Bir DataTable' hedef tabloya tar.

SqlBulkCopy.WriteToServer (IDataReader) Bir SqlDataReader' dan okuduu veri kmesini


hedef tabloya tar.

SqlBulkCopy.WriteToServer (DataTable, Bir DataTable' dan DataRowState


DataRowState) numaralandrcsn belirttii kriterlere uyan
satrlarn, hedef tabloya tar.

Grdnz gibi, WriteToServer metodunu etkili versiyonlar vardr. rnein, bir DataTable
zerinde sadece deitirilmi olan satrlarn hedef tabloya yazlmasn salayabiliriz. Bunun iin tek
yapmamz gereken, DataRowState numaralandrcsnn Modified deerini kullanmak olacaktr.
Bildiiniz gibi DataRowState numaralandrcs, Modified, Unchanged, Inserted ve Deleted
deerlerinden birisini alabilir. Bu durumu dilerseniz bir rnek zerinde inceleyelim.

static void Main(string[] args)


{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI");
/*Hedef tablodaki satrlar nlem olarak siliyoruz.*/
SqlCommand cmd = new SqlCommand("DELETE FROM YEDEK_MailList", con);
con.Open();
cmd.ExecuteNonQuery();

SqlDataAdapter da = new SqlDataAdapter("SELECT * FROM MailList", con);


DataTable dt = new DataTable();
da.Fill(dt);
DataRow drYeni;
drYeni = dt.NewRow();
drYeni["ID"] = "10";
drYeni["AD"] = "Maykl";
drYeni["SOYAD"] = "Cordn";
drYeni["MAIL"] = "michael@jordan.com";
dt.Rows.Add(drYeni);

drYeni = dt.NewRow();
drYeni["ID"] = "11";
drYeni["AD"] = "Kerim Abdul";
drYeni["SOYAD"] = "Cabbar";
drYeni["MAIL"] = "nba@nba.com";
dt.Rows.Add(drYeni);

/*SqlBulkCopy nesnemizi hedef balanty belirterek oluturuyoruz.*/


SqlBulkCopy bc = new SqlBulkCopy("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI",SqlBulkCopyOptions.KeepIdentity);
/* Hedef tabloyu belirtiyoruz.*/
bc.DestinationTableName = "YEDEK_MailList";
/*WriteToServer metodu ile DataTable iinde sadece yeni eklenmi olan satrlar, hedef tabloya

www.bsenyurt.com Page 2097


yazdryoruz.*/
bc.WriteToServer(dt, DataRowState.Added);

/* Nesneleri kapatyoruz.*/
bc.Close();
con.Close();
}

Bu kodda grdnz gibi, MailList tablomuzun ieriini balantsz katman nesnelerinden birisi
olan DataTable' a aktardk. Daha sonra ise basit bir ekilde iki adet satr ekledik. Bu satrlar yeni
eklendikleri iin, DataRowState deerleri Added olarak belirlenmitir. SqlBulkCopy nesnemizin
WriteToServer metodunu uygularken,

bc.WriteToServer(dt, DataRowState.Added);

ikinci parametreye DataRowState.Added deerini verdik. Bylece hedef tabloya, dataTable


nesnesinin sahip olduu veri kmesinden sadece yeni eklenen satrlar yazlacaktr. Uygulamamz
altrdmzda YEDEK_MailList tablomuzun aadaki satrlara sahip olduunu grrz. Bu satrlar
uygulamada eklenen satrlardr.

ekil 5. Sadece DataTable' a eklenen satrlarn hedef tabloya aktarlmas sonucu.

Grld gibi SqlBulkCopy nesnesi sayesinde, verilerin baka tablolara aktarlmas son derece
kolaydr. Bununla birlikte, bu teknii yedekleme ilemleri iin sklkla kullanabiliriz. Hereyden nce,
var olan bir tablonun tm satrlarn, satrlarn belirli bir kmesini, yada son kullanc tarafndan
balantsz katmanda yeni eklenmi, silinmi, gncellenmi satrlarn tamamn baka bir hedef
tabloya kolayca aktarabilme yeteneine sahip olmu oluyoruz.

u ana kadar gerekletirdiimiz rnekler, ayn SqlConnection' kullamaktadr. Oysaki gerek


hayatta bu tip tama ilemlerini, farkl sunucularda yer alan farkl tablolara doru gerekletirmek
isteyebiliriz. Bununla birlikte, hedef tablomuz nerede olursa olsun farkl bir ema yapsnada sahip
olabilir. Byle bir durumda zellikle alanlarn doru ve uygun bir ekilde eletirilmesi nem
kazanmaktadr. imdi bu durumu incelemek amacyla ncelikle, YEDEK_MailList tablomuzu farkl
alan isimleri ve sralama ile ayn sunucuda bulunan farkl bir veritaban altna koyalm.

www.bsenyurt.com Page 2098


ekil 7. YEDEK_MailList Tablomuz.

Bu sefer tablomuzu hem farkl bir veritaban altna koyduk, hemde ema yapsn biraz daha
deitirdik. Hereyden nemlisi, alan adlarn, sralarn deitirdik. Bununla birlikte fazladan bir
alanmz(AccountStatus) daha mevcuttur. Bu nedenle, kaynak ve hedef tablolardaki alanlar
birbirleriyle eletirmemiz gerekmektedir. te bu amala, kodlarmzda
SqlBulkCopyColumnMapping snfna ait nesne rneklerini kullanmalyz. imdi uygulama
kodlarmz aadaki gibi deitirelim.

static void Main(string[] args)


{
try
{
SqlConnection con = new SqlConnection("data source=localhost;initial
catalog=Dukkan;integrated security=SSPI");
/*Hedef tablodaki satrlar nlem olarak siliyoruz.*/
SqlCommand cmd = new SqlCommand("DELETE FROM YEDEK_MailList", con);
con.Open();
cmd.ExecuteNonQuery();
con.Close();

/* Kaynak tablodan verileri SqlDataReader yardmyla ekiyoruz.*/


SqlConnection con1 = new SqlConnection("data source=localhost;initial
catalog=AdventureWorks;integrated security=SSPI");
SqlCommand cmdCek = new SqlCommand("SELECT * FROM MailList",con1);
SqlDataReader dr;
con1.Open();
dr = cmdCek.ExecuteReader();

/*SqlBulkCopy nesnemizi hedef balanty belirterek oluturuyoruz.*/


SqlBulkCopy bc = new SqlBulkCopy("data source=localhost;initial catalog=Dukkan;integrated
security=SSPI", SqlBulkCopyOptions.KeepIdentity);
/* Hedef tabloyu belirtiyoruz.*/
bc.DestinationTableName = "YEDEK_MailList";

www.bsenyurt.com Page 2099


/* Kaynak ve Hedef tablolarn alanlar eletiriliyor.*/
SqlBulkCopyColumnMapping cm1 = new SqlBulkCopyColumnMapping("ID",
"UserID");
SqlBulkCopyColumnMapping cm2 = new SqlBulkCopyColumnMapping("AD", "UserName");
SqlBulkCopyColumnMapping cm3 = new SqlBulkCopyColumnMapping("SOYAD",
"UserLastName");
SqlBulkCopyColumnMapping cm4 = new SqlBulkCopyColumnMapping("MAIL", "MailAddress");
/* Eletirmeler iin oluturulan SqlBulkCopyColumnMapping nesneleri, SqlBulkCopy
nesnemizin ColumnMappings koleksiyonuna ekleniyor.*/
bc.ColumnMappings.Add(cm1);
bc.ColumnMappings.Add(cm2);
bc.ColumnMappings.Add(cm3);
bc.ColumnMappings.Add(cm4);

/*WriteToServer metodu ile SqlDataReader' dan okuduumuz satrlar, hedefe insert


ediyoruz.*/
bc.WriteToServer(dr);

/* Nesneleri kapatyoruz.*/
bc.Close();
dr.Close();
con1.Close();
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}

Burada bizim iin nemli olan, kaynak ve hedef tablolardaki alan eletirmesini nasl
bildirdiimizdir. Bunun iin, aadaki rnek sz dizimini kullandk.

SqlBulkCopyColumnMapping cm1 = new SqlBulkCopyColumnMapping("ID", "UserID");

rneimizde, SqlBulkCopyColumnMapping snfnn aadaki prototipe sahip olan yapcsn


kullandk.

public SqlBulkCopyColumnMapping(string sourceColumn, string destinationColumn);

Bu yapc haricinde kullanabileceimiz dier yapclarda aadaki tabloda yer almaktadr.

Yapc Metod Aklama

SqlBulkCopyColumnMapping ()

www.bsenyurt.com Page 2100


SqlBulkCopyColumnMapping (Int32, Int32) Kaynak ve Hedef alanlarn indeksini alr.

SqlBulkCopyColumnMapping (Int32, Kaynak alann indeksini, hedef alann ismini alr.


String)

SqlBulkCopyColumnMapping (String, Kaynak alann ismini, hedef alann indeksini alr.


Int32)

SqlBulkCopyColumnMapping nesnelerimizi yarattktan sonra bu nesnelerin, SqlBulkCopy


nesnemizin ilgili ColumnMappings koleksiyonuna eklenmesi gerekmektedir. Bunun iin Add
metodunu kullandk. Bylece SqlBulkCopy nesnemiz, kaynak tablodaki hangi alann, hedef
tablodaki hangi alana denk geleceini bilmektedir. Ayn rnei, aadaki kodlar ilede
gerekletirebiliriz.

bc.ColumnMappings.Add("ID", "UserID");
bc.ColumnMappings.Add("AD", "UserName");
bc.ColumnMappings.Add("SOYAD", "UserLastName");
bc.ColumnMappings.Add("MAIL", "MailAddress");

Burada daha ksa bir zm uygulanmtr. Bu sefer dorudan ColumnMappings zelliinin Add
metodu kullanlarak, ilgili alan eletirmeleri SqlBulkCopy nesnesine eklenmitir. Bir
SqlBulkCopyColumnMapping nesnesinin oluturulmasnda kullanlan ar yklenmi yapclardaki
parametreler buradaki Add metodu iinde geerlidir. Yani dilersek, Add metodunda alanlarn indeks
deerlerinide kullanabiliriz. rneimizi altrdmzda, kaynak tablodaki satrlarn yeni tablomuza
baarl bir ekilde eklendiini grrz.

ekil 8. Alanlarn eletirilmesi sonucu.

SqlBulkCopy snfnn SqlRowsCopied isimli tek bir olay vardr. Bu olay, SqlBulkCopy snfnn
NotifyAfter zelliine verilen deeri baz alr ve bu deeri kullanarak Bulk-Data kopyalama ilemleri
srasnda periyodik olarak alr. Yani, eer biz NotifyAfter zelliine 20 deerini atarsak,
kaynaktan hedefe tanan her 20 satrda bir SqlRowsCopied olay alacaktr. Bu olayn prototipi
aadaki gibidir.

public event SqlRowsCopiedEventHandler SqlRowsCopied;

Olayn gereklemesi sonucu altrlacak metodu, SqlRowsCopiedEventHandler delegesi aadaki


gibi tanmlar.

www.bsenyurt.com Page 2101


public sealed delegate void SqlRowsCopiedEventHandler(object sender, SqlRowsCopiedEventArgs
e);

imdi rneimizdeki SqlBulkCopy nesnesi iin SqlRowsCopied olayn kullanalm.

static void Main(string[] args)


{
try
{
.
.
.
SqlBulkCopy bc = new SqlBulkCopy("data source=localhost;initial catalog=Dukkan;integrated
security=SSPI", SqlBulkCopyOptions.KeepIdentity);
bc.DestinationTableName = "YEDEK_MailList";
bc.ColumnMappings.Add("ID", "UserID");
bc.ColumnMappings.Add("AD", "UserName");
bc.ColumnMappings.Add("SOYAD", "UserLastName");
bc.ColumnMappings.Add("MAIL", "MailAddress");

bc.NotifyAfter = 1;
bc.SqlRowsCopied+=new SqlRowsCopiedEventHandler(bc_SqlRowsCopied);
bc.WriteToServer(dr);
.
.
.
}
catch (SqlException ex)
{
Console.WriteLine(ex.Message);
Console.ReadLine();
}
}

static void bc_SqlRowsCopied(object sender, SqlRowsCopiedEventArgs e)


{
Console.WriteLine("U ANA KADAR "+e.RowsCopied.ToString() + " SATIR TAINDI...");
}

Burada, SqlBulkCopy nesnemize SqlRowsCopied olayn ekledikten sonra bu olayn gereklemesi


sonucu altrlacak olan bc_SqlRowsCopied metodunda, o ana kadar tanm olan satr saysn
ekrana yazdryoruz. NotifyAfter zelliine 1 deerini atadmz iin, olay metodumuz her bir satr
hedef tabloya baarl bir ekilde tandktan sonra tetiklenecektir. Sonu aadaki gibi olur.

www.bsenyurt.com Page 2102


ekil 9. SqlRowsCopied olaynn ilenmesi sonucu.

Bu makalemizde, Ado.Net 2.0 ile gelen yeni kabiliyetlerden birisine deinmeye altk. lerleyen
makalelerimizde Ado.Net 2.0' n yeni zelliklerini incelemeye devam edeceiz. Hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 ve ObjectDataSource Kontrol (


14.09.2004 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde ObjectDataSource bileenini incelemeye alacaz. ObjectDataSource bileeni


Asp.Net 2.0 ile gelen yeni bileenlerden birisidir. Grevi, 3 katl mimarinin uygulanmas halinde,
verikayna ile sunum katmannda yer alan veri bal kontroller arasndaki veri alveriinin, i
katman zerindeki herhangibir nesne yardmyla gerekletirilebilmesini salamaktr. Baka bir
deyile, veri-bal kontroller ile, i katmannda yer alan i nesnesi arasndaki iletiimi
salamaktadr.

ekil 1. ObjectDataSource bileenin 3 katl mimarideki rol.

rneimizi incelediimizde ObjectDataSource nesnesinin 3 katl mimarideki yerini daha kolay


anlama frsat bulacaz. imdi u senaryoyo gz nne alalm. Web sitemizdeki veri bal

www.bsenyurt.com Page 2103


kontrollerin herhangibir veri kaynandan veri ekmek, veri eklemek, veri silmek ve veri
gncellemek gibi ilemler iin bir snf ve metodlarn kullandn dnelim. te bu snfn
salam olduu fonksiyonellikleri, sunum katmannda yer alan veri-bal kontroller ile kolayca
gerekletirebilmek amacyla ObjectDataSource nesnesini kullanabiliriz. rnek olarak, Personel ile
ilgili kaytlar tutan bir access tablomuz olduunu dnelim. Amacmz ilk olarak, bu tablodaki
verileri alp getirecek ve yeni bir satr veri girilmesini salayacak bir metoda sahip olan bir snf
yazmak olsun. Bunun iin aadaki kodlara sahip bir snf gelitirelim.

using System;
using System.Data;
using System.Data.OleDb;
using System.Web;

public class IsNesnesi


{
public DataSet VerileriAl()
{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;data
source=" + HttpContext.Current.Server.MapPath("~/Data/Veriler.mdb"));
OleDbDataAdapter da = new OleDbDataAdapter("Select * From Personel", con);
DataSet ds = new DataSet();
da.Fill(ds);
return ds;
}
public int VeriGir(string ad, string soyad, string mail, string departman, DateTime giris)
{
OleDbConnection con = new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;data
source=" + HttpContext.Current.Server.MapPath("~/Data/Veriler.mdb"));
OleDbCommand cmd = new OleDbCommand("Insert Into Personel
(PerAd,PerSoyad,Departman,Mail,GirisTarihi) Values ('" + ad + "','" + soyad + "','" + departman +
"','" + mail + "','" + giris + "')", con);
con.Open();
int sonuc = cmd.ExecuteNonQuery();
con.Close();
return sonuc;
}
public IsNesnesi()
{
}
}

VerileriAl isimli metodumuz, Veriler isimli Access veritabanna balanarak burada yer alan Personel
isimli tablodan tm satrlar alyor ve bu satrlar ykledii DataSet nesnesini geri dndryor.
VeriGir isimli metodumuz ise, parametreler alarak, tablomuza yeni bir satr ekliyor ve
OleDbCommand nesnesinin ExecuteNonQuery metodunun altrlmas sonucu dnen integer
deeri arld yere aktaryor. imdi bu snfmz kullanacak bir web uygulamas ina edelim.
Web sitemizde, i nesnemize ait IsNesnesi snfn Code klasrmzn altna yerletireceiz.
Bununla birlikte, veritabanmzda yine Data klasr altna kopyalayalm.

www.bsenyurt.com Page 2104


ekil 2. Uygulama yapmz.

Bu n hazrlklardan sonra, default.aspx sayfamzda aadaki kontrolleri barndracak ekilde


oluturalm.

ekil 3. default.aspx sayfamzn yaps.

Burada i nesnesi ile formda yer alan bal kontroller arasndaki ilikiyi salamak zere bir
ObjectDataSource nesnemiz yer almaktadr. lk nce, ObjectDataSource bileenimizin aspx
kodlarn aadaki gibi tamamlayalm.

www.bsenyurt.com Page 2105


<asp:ObjectDataSource ID="ObjectDataSource1" Runat="server" TypeName="IsNesnesi"
SelectMethod="VerileriAl" InsertMethod="VeriGir">
<InsertParameters>
<asp:Parameter Name="ad"></asp:Parameter>
<asp:Parameter Name="soyad"></asp:Parameter>
<asp:Parameter Name="mail"></asp:Parameter>
<asp:Parameter Name="departman"></asp:Parameter>
<asp:Parameter Name="giris" Type="DateTime"></asp:Parameter>
</InsertParameters>
</asp:ObjectDataSource>

ObjectDataSource bileenimizin baarl bir ekilde ileyebilmesi iin en nemli gereklilikler, select,
insert, update ve delete ilemleri iin i nesnesi zerindeki hangi metodlarn kullanacann
bildirilmesidir. Biz rneimizde ye alan i nesnesine ait snf ierisinde, veri ekmek ve veri girii
iin iki metod tanmladk. ObjectDataSource bileeninin SelectMethod ve InsertMethod zelliklerine,
ilgili Select ve Insert ilevlerini gerekletiren i nesnesi metodlarnn adlarn aktaryoruz. Artk
ObjectDataSource ile veriye balanacak olan nesneler, veri ekmek ve veri girii iin burada
belirtilen metodlar kullanacaklardr. Tabiki, ObjectDataSource' un bu bilgiler dnda ilgili metodlar
iieren snf hakknda da bilgiye sahip olmas gerekir. te bunun iinde, TypeName zelliine ilgili i
nesnesinin snf ad atanr.

unu hemen belirtelim ki, burada tanmladmz snf baka bir isim alan altnda olabilir. Bu
durumda, bu snfa tam olarak ulalacak tip bilgisinin TypeName zelliinde belirtilmesi gerekir.
rnein, snfmz IsKatmani isimli bir isim alannda bulunuyorsa bu durumda TypeName zelliine
IsKatmani.IsNesnesi deeri girilmelidir.

Dier DataSource bileenlerinde olduu gibi, Insert, Update ve Delete gibi ilemler parametreler
yolu ile gerekletirilmektedir. Bizimde burada, Insert metodumuzda kullandmz baz
parametreler mevcuttur. te bu parametreleri temsil etmesi iin, ObjectDataSource kontrolnn
InsertParameters koleksiyonu kullanlmtr. Delete ve Update ilemlerinde de DeleteParameters ve
UpdateParameters koleksiyonlar kullanlr.

Gelelim, formumuzda yer alan veri bal kontrollere. Veri ekme ilemi sonrasnda, tablomuzda yer
alan satrlar GridView kontrolnde gstermek istediimiz iin, GridView kontrolne ait aspx
kodlarn aadaki gibi yazmalyz.

<asp:GridView ID="GridView1" Runat="server" DataSourceID="ObjectDataSource1"


AutoGenerateColumns="false">
<Columns>
<asp:BoundField DataField="PerAd" HeaderText="Personel Ad"></asp:BoundField>
<asp:BoundField DataField="PerSoyad" HeaderText="Personel Soyad"></asp:BoundField>
<asp:BoundField DataField="Departman" HeaderText="Departman"></asp:BoundField>
<asp:BoundField DataField="GirisTarihi" DataFormatString="{0:dd.mm.yyyy}"
HeaderText="e Balama Tarihi"></asp:BoundField>
<asp:BoundField DataField="Mail" HeaderText="Mail Adresi"></asp:BoundField>
</Columns>
</asp:GridView>

GridView kontrolmzde DataSourceID zelliine ObjectDataSource bileenimizin ID deerini


atamak ile, alma zamannda GridView kontrolnde, ObjectDataSource' un i nesnesi zerinden

www.bsenyurt.com Page 2106


altrd Select metodundan dnen DataSet' e ait satrlarn gsterilmesini salam oluyoruz.
Eer sayfamz bu haliyle altracak olursak aadaki ekran grntsn elde ederiz.

ekil 4. Select metodunun almas sonucu.

Gelelim Insert ilevinin nasl gerekletirileceine. Yeni bir satr eklemek iin Ekle balkl button
kontrolmze bir ka satr kod yazacaz.

void btnEkle_Click(object sender, EventArgs e)


{
ObjectDataSource1.InsertParameters["ad"].DefaultValue = txtAd.Text;
ObjectDataSource1.InsertParameters["soyad"].DefaultValue = txtSoyad.Text;
ObjectDataSource1.InsertParameters["mail"].DefaultValue = txtMail.Text;
ObjectDataSource1.InsertParameters["departman"].DefaultValue = txtDepartman.Text;
ObjectDataSource1.InsertParameters["giris"].DefaultValue = txtGiris.Text;
ObjectDataSource1.Insert();
}

ObjectDataSource kontrolmz, i nesnesi zerindeki Insert ilevini gerekletirecek metodu


bilmektedir. Ayrca, bu metoda gndermesi gereken parametrelerin ne olacanda bilir. Bununla
birlikte, Insert ilevini gerekletirecek olan i nesnesi metodu iin gerekli parametre deerlerinin
bir ekilde gnderilmesi gerekmektedir. Bu amala, ObjectDataSource nesnesinin InsertParameters
koleksiyonundaki her bir parametreye gerekli deerler gnderilir. Daha sonra ise bu parametrelerin
deerleri, i nesnesindeki metod iinde var olan karlklarna gnderilir. Bu gnderme emrini ise
Insert metodu verir. Baka bir deyile, Insert metodu, ObjectDataSource kontrolnn
InsertParameters koleksiyonunda yer alan parametre deerlerini, i nesnesi zerindeki ilgili metoda
gnderir ve bu metodu altrr. Tabi burada ObjectDataSource bileenindeki InsertParameters
koleksiyonunda yer alan parametrelerinin Name zelliklerinin deerlerinin, i nesnesindeki VeriGir

www.bsenyurt.com Page 2107


metodundaki parametre isimleri ile ayn olduunda dikkat etmemiz gerekmektedir. Sonu olarak
veri giri ilemi gereklemi olur. imdi uygulamamz denersek, yeni satrlar ekleyebildiimizi
grrz.

ekil 5. Yeni satr eklemeden nce.

www.bsenyurt.com Page 2108


ekil 6. Yeni satr girildikten sonra.

Insert ileminde dikkat ederseniz, TextBox kontrollerine girdiimiz deerleri InsertParameters


koleksiyonundaki ilgili parametrelere aktardk. Dilersek, parametre deerlerinin aktarmn ilgili
kontroller zerinden dorudanda gerekletirebiliriz. Bunun iin, InsertParameters koleksiyonunda
Parameter nesneleri yerine, ilgil parametre deerini tayan kontrol temsil edecek
ControlParameter nesneleri kullanlr.

<asp:ObjectDataSource ID="ObjectDataSource1" Runat="server" TypeName="IsNesnesi"


SelectMethod="VerileriAl" InsertMethod="VeriGir">
<InsertParameters>
<asp:ControlParameter ControlID="txtAd" PropertyName="Text"
Name="ad"></asp:ControlParameter>
<asp:ControlParameter ControlID="txtSoyad" PropertyName="Text"
Name="soyad"></asp:ControlParameter>
<asp:ControlParameter ControlID="txtMail" PropertyName="Text"
Name="mail"></asp:ControlParameter>
<asp:ControlParameter ControlID="txtDepartman" PropertyName="Text"
Name="departman"></asp:ControlParameter>
<asp:ControlParameter ControlID="txtGiris" PropertyName="Text" Type="DateTime"
Name="giris"></asp:ControlParameter>
</InsertParameters>
</asp:ObjectDataSource>

Dikkat edecek olursanz, ControlID ile hangi kontroln kullanaca, PropertyName zellii ilede bu
kontroln hangi zelliinin deerinin alnaca belirtilir. Name zellii ise, i nesnesindeki ilgili insert
metodunda kullanlacak parametreyi iaret etmektedir ve i nesnesindeki metod parametresindeki
isim ile ayndr. Bu durumda, insert ilevini gerekletirebilmek iin tek yapmamz gereken
ObjectDataSource bileenine ait Insert metodunu armak olacaktr. Insert metodu altrldnda
ObjectDataSource bileeni, InsertParameters koleksiyonunda belirtilen kontroller zerindeki
deerleri alp ilgili insert metoduna gndermektedir.

void btnEkle_Click(object sender, EventArgs e)


{
ObjectDataSource1.Insert();
}

Delete ve Update ilevleride Insert ilevine benzer ekilde gerekletirilir. Bu kez,


ObjectDataSource bileeni iin DeleteCommand ve UpdateCommand zellikleri bildirilir ve ilgili
parametre koleksiyonlar eklenir. Bu makalemizde ksaca ObjectDataSource bileenini incelemeye
altk. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2109


Asp.Net 2.0 ve Master Page Kavram (
10.09.2004 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, Master Pages kavramna giri yapacak ve web uygulamalarnn gelitirmesinde


yaammza getirdii kolaylklar incelemeye alacaz. Internet sitelerini gz nne aldmzda,
siteye ait sayfalarn sklkla ayn ablonlar kullandn grrz. zellike, header, footer,
navigasyon ve advertisement alanlar, ounlukla siteye ait tm sayfalarda ayn yerlerde kullanlr.
Bu, siteye ait sayfalarn standart olarak ayn grnmde olmasn salamakla kalmaz, deien
ieriinde ortak bir ablon zerinde durmasna imkan tanr. Peki Asp.Net 2.0' n bu kullanm iin
getirdii yaklama gelene kadar, sayfalarda ortak olarak kullanlan ve tasarmsal olarak sayfa
koordinatlarnda ayn yerlerde yer alan bu unsurlar hangi teknikler ile oluturulmutur?

Html' in ilk zamanlarnda, bu tarz ilemleri gerekletirmek iin, ortak olan alanlar kopyalanarak
dier sayfalara yaptrlrd. Yada, ana ablonu ihtiva eden bir sayfadan dier sayfalar "save as"
metodu ile oluturulur ve ierikleri deitirilirdi. Bu tekniin en byk handikap, ablondaki
herhangibir deiikliin dier sayfalara yanstlmas srasnda ortaya kmaktadr. Nitekim 100' lerce
alt sayfaya ayn ablonu uygulamsak bu gerekten byk bir problemdir.

zm Asp ile gelmitir. Asp, include taklarn kullanarak, sayfalarda tekrar eden ieriklerin
kolayca kullanlabilmesini ve deiikliklerin tm sayfalarda grnebilmesini salamtr. Ancak
elbetteki include taksnnda bir takm sorunlar vardr. Bunlardan birisi, tasarm zamannda include
taksnn iaret ettii ieriin grnememesidir. Dolaysyla sayfann btnn nasl grndn
inceleyebilmek iin mutlaka altrmak gerekmektedir. Dier yandan, include teknii taklar
zerine kurulu olduundan, zellikle ak unutulan taklar sayfalarda istenmeyen Html ktlarnn
olumasna yol amaktadr.

Asp.Net, bu tip ortak ieriklerin kullanlmasna daha gl ve etkin bir yaklam getirmitir. User
Controls. Kullanc tanml kontroller, normal aspx ieriine sahip olabilmekte ve .net mimarisinin
gl zelliklerini kullanabilmektedir. Her ne kadar etkili bir teknik olsada, user control' ler iinde
tek bir sorun ne kmaktadr. Tasarm zamannda, user control ieriinin grlememesi.

Asp.Net 2.0, Master Page yaklam ile, yukarda bahsedilen dezavantajlar ortadan kaldrmay
baarmtr. Bir Master Page, uyguland dier aspx sayfalarnn nasl grnmesi gerektiine karar
veren bir ablona gibidir. Ancak, salad ContentPlaceHolder bileeni sayesinde, Master Page' leri
uygulayan dier aspx sayfalarnn, istenilen ierie sahip olmasnda salamaktadr. En gzel yan
ise, normal bir aspx sayfas gibi tasarlanabilmesi, yani html, image, server control gibi yeleri
ierebilmesidir. Bunlara ek olarak, olay gdml programlama modelinide destekler. Dolaysyla bir
Master Page aslnda bir aspx sayfasndan farkszdr.

Ancak asl fark, bir Master Page bir aspx sayfasna uygulandnda ortaya kar. Master Page' i
uygulayan bir aspx sayfas taraycda aldnda taraycya gelen sayfa, Master Page ile aspx
sayfasnn birletirilmesi sonucu ortaya kan baka bir aspx sayfasdr. Bu, .net framework' n
getirdii partial class teknii sayesinde gerekleebilmektedir. Bunun, Master Page' i uygulayan
aspx sayfalarna getirdii deiik kodlama etkileride vardr.

www.bsenyurt.com Page 2110


ekil 1. Master Page ve aspx sayfalarnn ortak alma mimarisi.

Bu ksa aklamalardan sonra, Master Page' lerin ne olduunu ve nasl kullanldklarn anlamak
amacyla basit bir rnek gelitirelim. lk olarak, Visual Studio.Net 2005' te bir web sitesi aalm.
Sitemize Master Page eklemek iin tek yapmamz gereken, Solution' mza sa tklamak ve Add
New Item' den gelen pencerede, Master Page tipini semektir. Master Page' ler master uzantl
dosyalardr.

ekil 2. Solution' a Master Page eklenmesi

Bu ilemin ardndan Master Page' in standart olarak aadaki gibi oluturulduunu grrz.

www.bsenyurt.com Page 2111


ekil 3. Varsaylan Master Page.

te burada ContentPlaceHolder1 bileenimiz, bu Master Page' i uygulayacak olan sayfalarn


serbeste eriebilecekleri ve ierik oluturabilecekleri alanlar tanmlamaktadr. Elbetteki bir Master
Page' in bu ekilde olmas beklenemez. Bu nedenle Master Page' imizi aadaki ekran
grntsnde olduu gibi tasarlayabiliriz. Dikkat edecek olursanz, Master Page' lerde, normal aspx
sayfalar gibi tasarlanabilirler. Bir baka deyile, Html kodlar, aspx bileenleri vb. ierebilirler.

ekil 4. Master Page sayfamznn tasarm.

Burada standart olarak bir web sayfasnn tasarlanmasndan farkl bir ilem yaplmamtr. En
nemli nokta Master Page' i uygulayacak sayfalarn ieriklerini yazabilecekleri ContentPlaceHolder
bileeninin kullanlmasdr. Dilersek bir Master Page iinde, birden fazla ContentPlaceHolder
bileeninede yer verebiliriz. Master Page' in aspx kodlarna baktmzda normal aspx sayfalarna
gre en nemli deiik page direktifi yerine master direktifinin kullanlmasdr. Master direktifi
sayfann bir Master Page olduunu belirtmektedir.

www.bsenyurt.com Page 2112


<%@ Master Language="C#" CompileWith="AnaSablon.master.cs"
ClassName="AnaSablon_master" %>

ContentPlaceHolder bileeni ise,

<asp:ContentPlaceHolder ID="ContentPlaceHolder1" Runat="server"></asp:ContentPlaceHolder>

aspx kodlar ile tanmlanr. Sayfann dikkate deer bir zelliide, form taklarn iermesidir. Nitekim
biraz sonra greceimiz gibi bunun, Master Page' i uygulayan aspx sayfalarna etkisi vardr. imdi
dilerseniz, yeni bir aspx sayfasna oluturduumuz Master Page' i nasl uygulayacamza bir
bakalm. ncelikle, Add New Item iletiim kutusunu aalm ve dosya tipi olarak Web Form' u
seelim. Ardndan, sayfamza uygulamak istediimiz Master Page' i seebilmek amacyla, Select
Master Page kutucuunu iaretleyelim.

ekil 5. Yeni bir web formun Master Page tabanl oluturulmas.

Bu durumda Add buttonuna bastmzda, sayfamza uygulamak istediimiz Master Page' i


seeceimiz iletiim kutusu ekrana gelecektir.

www.bsenyurt.com Page 2113


ekil 6. Master Page' in seilmesi.

Bu admda tamamladmzda, default.aspx sayfamz aadaki gibi oluturulacaktr. Dikkat edecek


olursanz, sadece Master Page' deki ContentPlaceHolder bileeninin bulunduu alan dzenlenebilir
yapdadr. Dier ksmlar iin dzenleme ve deiitirme gibi ilemleri gerekletirme imkanmz
yoktur. Bu sayede web formunun, Master Page' in izin verdii grnmde olmas ve kendisine
ayrlan alanda istedii ierii oluturmasna izni verilmi olunur.

ekil 7. Master Page' in bir web formuna uygulanmas sonucu.

Bu noktada, web formumuzun aspx kodlarna bakcak olursak sadece tek bir satrn olduunu
grrz.

<%@ Page Language="C#" MasterPageFile="~/AnaSablon.master"


CompileWith="Default.aspx.cs" ClassName="Default_aspx" Title="Untitled Page" %>

Bu tek satr aslnda ok ey ifade etmektedir. Hereyden nce, MasterPageFile zellii, sayfaya
uygulanan Master Page' in yolunu belirtir. Bu, formun bir Master Page' i uyguladn baka bir
deyile master page' den tretilerek retildiini gsterir. Kendi snf ve code-behind dosyas vardr.

www.bsenyurt.com Page 2114


Eer sayfadaki Content alan ierisinde dzenleme yapmak istersek bunu u an iin
gerekletiremediimizi grrz. Bunu salayabilmek iin, Master Page' de yer alan
ContentPlaceHolder bileeninin, bu sayfada bir Content bileeni ile eletirilmesi gerekmektedir.
Bunun iin, web formumuza aadaki aspx kodlarn yazmamz yeterli olacaktr. Content
bileeninin, ContentPlaceHolderID zellii, uygulanan Master Page' deki hangi ContentPlaceHolder
bileenini eletireceini belirtmektedir. Bu zelliin deeri, birden falza ContentPlaceHolder' n,
Master Page' i uygulayan sayfalarda eletirilmesinde nem kazanr.

<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="server">


</asp:Content>

Artk, ierii istediimiz gibi deitirebiliriz. Sunucu elemanlar, html kodlar, resimler vesaire.
rnein, bir Access tablosundan buradaki Content alan iindeki bir GridView bileenini dolduralm.

ekil 8. Content alann bir aspx sayfas dzenlermicesine kullanabiliriz.

Sayfamzn kodlarna bakacak olursak.

<%@ Page Language="C#" MasterPageFile="~/AnaSablon.master"


CompileWith="Default.aspx.cs" ClassName="Default_aspx" Title="Untitled Page" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="server">
<b>Mail Listemize Son ye Olan Okurlar&nbsp;</b>
<asp:AccessDataSource ID="AccessDataSource1"
Runat="server" DataFile="~/Data/veriler.mdb" SelectCommand="SELECT [ID], [Ad], [Soyad],
[Mail] FROM [MailListesi]">
</asp:AccessDataSource>
<asp:GridView ID="GridView1" Runat="server" ForeColor="Black" BorderWidth="1px"
BorderColor="Tan"

www.bsenyurt.com Page 2115


BackColor="LightGoldenrodYellow" DataSourceID="AccessDataSource1" DataKeyNames="ID"
AutoGenerateColumns="False" GridLines="None" CellPadding="2"
AutoGenerateEditButton="True">
<FooterStyle BackColor="Tan"></FooterStyle>
<PagerStyle ForeColor="DarkSlateBlue" HorizontalAlign="Center"
BackColor="PaleGoldenrod"></PagerStyle>
<HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
<AlternatingRowStyle BackColor="PaleGoldenrod"></AlternatingRowStyle>
<Columns>
<asp:BoundField ReadOnly="True" HeaderText="ID" InsertVisible="False"
DataField="ID"
SortExpression="ID"></asp:BoundField>
<asp:BoundField HeaderText="Ad" DataField="Ad"
SortExpression="Ad"></asp:BoundField>
<asp:BoundField HeaderText="Soyad" DataField="Soyad"
SortExpression="Soyad"></asp:BoundField>
<asp:BoundField HeaderText="Mail" DataField="Mail"
SortExpression="Mail"></asp:BoundField>
</Columns>
<SelectedRowStyle ForeColor="GhostWhite"
BackColor="DarkSlateBlue"></SelectedRowStyle>
</asp:GridView>&nbsp;
</asp:Content>

Dikkat edecek olursanz, eklemi olduumu tm kontroller ve dier ierik, Content bileenimize ait
taklar ierisinde yer almaktadr. Dier taraftan Content taklar dnda herhangibir ierik
oluturmamz salayacak bileenleri kullanma imkanmz yoktur. Bir dier nemli zellikte, ieriin
herhangibir form taks ierisinde yer almyor oluudur. Bunun sebebi, form taksnn zaten Master
Page' de uygulanm olmasdr. Dolaysyla web formumuz, Master Page' den kaltmsal olarak
tretildii iin form taklarnn burada kullanlmasna gerek yoktur.

Oluan default.aspx sayfas aslnda, Master Page' deki ContentPlaceHolder alannn ierik eklenmi
halidir. Bunun anlam, alma zamannda ieriin yer ald default.aspx sayfas ile
AnaSablon.Master sayfasnn birletirilerek yeni bir default.aspx sayfasnn oluturulmas ve son
kullancya sunulmasdr. Eer uygulamamz altracak olursak taraycmzda aadaki ekran
grntsn elde ederiz.

www.bsenyurt.com Page 2116


ekil 9. default.aspx' in alan hali.

Dilersek, bir web uygulamas ierisinde birden fazla Master Page tanmlayabilir ve istediimiz
sayfalara uygulayabiliriz. rnein, uygulamamza AnaSablon2.Master isimli aadaki form yapsna
sahip yeni bir Master Page eklediimizi farz edelim.

www.bsenyurt.com Page 2117


ekil 10. AnaSablon2.Master

Bu Master Page' i baka bir sayfaya kolayca uygulayabiliriz. rnein Kitap.aspx isimli bir web formu
oluturalm ve formumuzu AnaSablon2.master' dan tretelim. Bylece, uygulamamz ierisinde iki
farkl Master Page yapsn kullanan sayfalara izin vermi oluyoruz.

www.bsenyurt.com Page 2118


ekil 11. Bir uygulamada farkl Master Page' lerin kullanlmas.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde ksaca, Master Page' lerin,
uygulandklar aspx sayfalar ile kombine bir ekilde nasl altklarn incelemeye altk. Bir
sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 DetailsView Kontrol ile


Insert,Update,Delete ( 08.09.2004 ) - Asp.Net 2
www.bsenyurt.com Page 2119
Deerli Okurlarm Merhabalar,

Bu makalemizde, Whidbey ile gelen yeni kontrollerden birisi olan DetailsView bileeni ile, satr
ekleme, silme ve gncelleme gibi ilemlerin nasl yapldn incelemeye alacaz. Bununla birlikte
ncesinde, DetailsView kontroln genel hatlar ile ksaca aratracaz. DetailsView kontrol,
Asp.Net 2.0' a eklenen yeni data-bound kontrollerinden birisidir. Bu kontroln en byk zellii, t
zamannda sadece bir satr verinin gsterilmesini salamasdr. Bu noktada GridView kontrolnden
ayrlmasna ramen, bir veri kmesi zerinden navigasyon linkleri yardmyla hareket edilmesinede
izin verir. Konuyu daha iyi anlayabilmek iin, bir nceki makalemizde yer alan Access
veritabanmz kullanacamz bir rnek gelitireceiz. Bu rneimizde de, Access veri kaynamza
balanmak ve Select, Insert, Update, Delete ilemlerini gerekletirebilmek amacyla bir
AccessDataSource bileeni kullanacaz. Bu bileenimizi aadaki aspx kodlar ile oluturalm.

<asp:AccessDataSource ID="AccessDataSource1" Runat="server" DataFile="Data/veriler.mdb"


SelectCommand="Select * From MailListesi" InsertCommand="Insert Into MailListesi
(Ad,Soyad,Mail) Values (@Ad,@Soyad,@Mail)" UpdateCommand="Update MailListesi Set
Ad=@Ad,Soyad=@Soyad,Mail=@Mail Where ID=@ID" DeleteCommand="Delete From MailListesi
Where ID=@ID">
<InsertParameters>
<asp:Parameter Name="Ad"></asp:Parameter>
<asp:Parameter Name="Soyad"></asp:Parameter>
<asp:Parameter Name="Mail"></asp:Parameter>
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="Ad"></asp:Parameter>
<asp:Parameter Name="Soyad"></asp:Parameter>
<asp:Parameter Name="Mail"></asp:Parameter>
<asp:Parameter Name="ID"></asp:Parameter>
</UpdateParameters>
<DeleteParameters>
<asp:Parameter Name="ID"></asp:Parameter>
</DeleteParameters>
</asp:AccessDataSource>

AccessDataSource kontrolmz, balanaca veri bileeni zerinde, Select, Update, Insert ve


Delete ilemlerinin gerekletirilebilmesini salamak amacyla, SelectCommand, InsertCommand,
DeleteCommand ve UpdateCommand zelliklerini kullanmaktadr. zellikle veri girii, gncelleme
ve silme ilemleri iin kullanlan sorgular, parametreler iermektedir. Bu parametreleri, hangi
komut iin kullanacak isek, o komuta ait parametre koleksiyonuna birer Parameter nesnesi olarak
eklemeliyiz. Bu nedenle, InsertParameters, UpdateParameters ve DeleteParameters koleksiyonlar
kullanlmtr. Bunun dnda, AccessDataSource kontrolmzn, hangi access veritabanna
balanacan, DataFile zelliine atadmz dosya yol bilgisi ile belirliyoruz. Gelelim, DetailsView
kontrolmze. lk aamada bu kontrolmz aadaki aspx kodlar ile oluturalm.

<asp:DetailsView ID="DetailsView1" Runat="server" DataSourceID="AccessDataSource1"


AllowPaging="True" PagerSettings-Mode="NextPreviousFirstLast"
AutoGenerateInsertButton="True" AutoGenerateEditButton="True"
AutoGenerateDeleteButton="True" Font-Names="Verdana" Font-Size="X-Small"
DataKeyNames="ID">
</asp:DetailsView>

www.bsenyurt.com Page 2120


DetailsView kontrolmzn, DataSourceID zelliine atadmz bileen ad ile, hangi veri kaynan
ve sql sorgularn kullanacan belirliyoruz. AllowPaging zellii, her nekadar GridView' daki
sayfalama zelliini artrsada burada sayfa numaras yerine, satr numaralarn temsil
etmektedir. Yani n sayda kayd olan bir veri kmesi iin, n adet sayfa numaras yer alacaktr.
nk DetailsView bileeni, bir anda yanlz bir satr ekranda gstermektedir. Bununla birlikte,
sayfalama gsteriminin ne ekilde olacan belirtmek amacyla, PagerSettings-Mode zellii
kullanlmtr. Burada verdiimiz deer haricinde atayabileceimiz dier deerlerde unlardr.

ekil 1. PagerSettings-Mode deerleri.

AutoGenerateInsertButton zellii bileende satr ekleme iin gerekli linkerlin gsterilmesini salar.
Benzer ekilde, AutoGenerateEditButton zelliide, dzenleme linklerinin gsterilmesini salar. Son
olarak AutoGenerateDeleteButton zelliide Delete linkinin gsterilmesini salamaktadr. Elbette
bileenimiz iin kilit noktalardan biriside, DataKeyNames zelliine atanan Field deeridir. Bu
deer, nceki makalelerimizdende hatrlayacanz gibi, Update ve Delete sorgular (hatta baz
durumlarda Select sorgusu) iinde kullanlacak Primary Key alann ifade etmektedir. Nitekim, tek
bir satr zerinde yaplacak gncelleme ve silme ilemleri, o satrn benzersiz bir numara ile ifade
edilebilmesi halinde baarya ulaacaktr. te bu noktada primary key alanlar byk nem kazanr.
Sayfamz bu haliyle altrdmz takdirde aadaki ekran grntsn elde ederiz.

ekil 2. Uygulamann almas sonucu.

Grld gibi, bir anda sayfada sadece tek bir satra ait veriler grlmektedir. Veri kmesinin
Select sorgusu ile elde edilen satrlar arasnda gezebilmek iin, Navigasyon linkeri kullanlr. Burada
standart olarak bileenimiz, Select sorgusuna gre tm Field' lar getirmitir. Ancak dilersek sadece
belirli Field' larn kontrolmzde grnmesini salayabiliriz. Nasl ki, GridView kontrolnde bu i iin
kullandmz Columns koleksiyonu varsa, DetailsView bilenindede ayn ii yapan Fields
koleksiyonu vardr. Elbette koleksiyon isminin Fields olmas tesadfi deildir. Nitekim, DetailsView
bileeni, satrlarn Field baznda gsterir. Oysa GridView kme baznda ve stunlar esas alarak
gstermektedir. Dolaysyla bileenimizin aspx kodlarn aadaki gibi dzenleyerek sadece belirli
field' larn grnmesini salayabiliriz.

www.bsenyurt.com Page 2121


<asp:DetailsView ID="DetailsView1" Runat="server" DataSourceID="AccessDataSource1"
AllowPaging="True" PagerSettings-Mode="NextPreviousFirstLast"
AutoGenerateInsertButton="True" AutoGenerateEditButton="True"
AutoGenerateDeleteButton="True" Font-Names="Verdana" Font-Size="X-Small"
DataKeyNames="ID" AutoGenerateRows="false">
<Fields>
<asp:BoundField DataField="Ad" HeaderText="Ad"></asp:BoundField>
<asp:BoundField DataField="Soyad" HeaderText="Soyad"></asp:BoundField>
<asp:BoundField DataField="Mail" HeaderText="Mail Adresi"></asp:BoundField>
</Fields>
</asp:DetailsView>

Bu haliyle sayfamz atmzda, aadaki ekran grntsn elde ederiz. Dikkat edecek olursanz
sadece Ad,Soyad ve Mail alanlar grnmektedir.

ekil 3. Kendi belirlediimiz alanlarn gsterilmesi.

Burada, AutoGenerateRows zelliine dikkat etmenizi istiyorum. Bu zellie false deerini


vermeseydik eer, Select sorgusundan alnan tm alanlar gsterilecek ve sonrada bizim
belirlediimiz alanlar ekrana gelecekti. Aadaki ekilde grld gibi.

www.bsenyurt.com Page 2122


ekil 4. AutoGenerateRows zelliine false deeri vermeseydik.

Artk bilenimiz yardmyla, satr ekleme, silme ve gncelleme ilemlerini kolayca


gerekletirebiliriz. Son olarak, sayfamzn kodlarn aadaki hale getirerek sayfamz ve en
enmlisi DetalisView bileenimizi biraz makyajlayalm.

<%@ Page Language="C#" CompileWith="Default.aspx.cs" ClassName="Default_aspx" %>


<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:AccessDataSource ID="AccessDataSource1" Runat="server"
DataFile="Data/veriler.mdb" SelectCommand="Select * From MailListesi" InsertCommand="Insert
Into MailListesi (Ad,Soyad,Mail) Values (@Ad,@Soyad,@Mail)" UpdateCommand="Update
MailListesi Set Ad=@Ad,Soyad=@Soyad,Mail=@Mail Where ID=@ID" DeleteCommand="Delete
From MailListesi Where ID=@ID">
<InsertParameters>
<asp:Parameter Name="Ad"></asp:Parameter>
<asp:Parameter Name="Soyad"></asp:Parameter>
<asp:Parameter Name="Mail"></asp:Parameter>
</InsertParameters>
<UpdateParameters>
<asp:Parameter Name="Ad"></asp:Parameter>
<asp:Parameter Name="Soyad"></asp:Parameter>
<asp:Parameter Name="Mail"></asp:Parameter>
<asp:Parameter Name="ID"></asp:Parameter>
</UpdateParameters>
<DeleteParameters>
<asp:Parameter Name="ID"></asp:Parameter>
</DeleteParameters>
</asp:AccessDataSource><br />
<span style="font-size: 24pt; color: #663333; font-family: Agency FB"><b>Mail Listesi<br
/>
</b></span>
<asp:DetailsView ID="DetailsView1" Runat="server" DataSourceID="AccessDataSource1"
AllowPaging="True" PagerSettings-Mode="NextPreviousFirstLast"
AutoGenerateInsertButton="True" AutoGenerateEditButton="True"
AutoGenerateDeleteButton="True" Font-Names="Verdana" Font-Size="X-Small"
DataKeyNames="ID" CellPadding="4" BorderColor="#DEDFDE" GridLines="Vertical"
BorderWidth="1px" ForeColor="Black" BackColor="White" AutoGenerateRows="False"
BorderStyle="None">
<FooterStyle BackColor="#CCCC99"></FooterStyle>
<RowStyle BackColor="#F7F7DE"></RowStyle>
<PagerStyle ForeColor="Black" HorizontalAlign="Right"
BackColor="#F7F7DE"></PagerStyle>

www.bsenyurt.com Page 2123


<Fields>
<asp:BoundField DataField="Ad" HeaderText="Ad"></asp:BoundField>
<asp:BoundField DataField="Soyad" HeaderText="Soyad"></asp:BoundField>
<asp:BoundField DataField="Mail" HeaderText="Mail Adresi"></asp:BoundField>
</Fields>
<HeaderStyle ForeColor="White" Font-Bold="True"
BackColor="#6B696B"></HeaderStyle>
<EditRowStyle ForeColor="White" Font-Bold="True"
BackColor="#CE5D5A"></EditRowStyle>
<AlternatingRowStyle BackColor="White"></AlternatingRowStyle>
</asp:DetailsView>
</div>
</form>
</body>
</html>

ekil 5. DetailsView bileenin makyajlanm hali ve New linkine tklandnda.

rnek olarak, Yeni bir satr girdiimizde, bu satrn baarl bir ekilde veri kayanana eklendiini
grrz. rnein, aadaki kayt bilgisini Insert linki ile eklediimizi dnelim.

ekil 6. Yeni satr verisi.

Insert linkine bastktan sonra, tekrar son satra gidersek, yeni satrmzn baarl bir ekilde
eklendiini ve en nemliside, Access tablosundaki otomatik olarak artan ID deerinin, baarl bir
ekilde oluturulduunu grrz. Tekrar hatrlatmakta fayda var, burada yaptmz veri girii
dorudan, tabloyada yanstlacaktr.

www.bsenyurt.com Page 2124


ekil 7. Eklenen satr.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 GridView Kontrolnde


Update,Delete lemleri ( 07.09.2004 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, Asp.Net 2.0 ile gelen yeni kontrollerden birisi olan GridView kontrol zerinde,
veri gncelleme ve veri silme gibi ilemlerin nasl yaplacan incelemeye alacaz. Asp.Net 2.0
ve dolaysyla Framework 2.0, zellikle veri bal kontrollerde, yazlm gelitiricilerin sklkla
yaptklar rutin ilemlerin dahada kolaylatrlmasna izin veren mimari yaklamlar
benimsemektedir. Bu makalemize konu olan GridView kontrol internet sayfalarnda verilerin eski
DataGrid kontrolnde olduu gibi zgara formatnda grnmesini salar. Bununla birlikte GridView
kontrol zerinde sayfalama ve sralama gibi ilemleri yapmak eskiye nazaran ok daha kolaydr.
te GridView kontrolnn yazlm gelitirici dostu olan yapsnn bir dier kolaylda, satrlar
zerinde gncelleme ve silme ilmelerine getirdii yeniliklerde gizlidir.

Bu makalemizde gelitireceimiz rneimizde, bir Access veri kaynana balanacamz bir web
sayfamz olacak. Bu sayfada kullancamz GridView kontroln veri gncelleme ve silme ilemleri
iin kullanacaz. Bu rnei gelitirebilmemiz iin, GridView kontroln Access veritabanmza
balayacak bir DataSource kontrolne ihtiyacmz var. Access veritabanlarna balanmak ve ilgili
veritaban zerindeki tablolarda ilem yapabilmek iin, .net Framework 2.0 ile gelen yeni
nesnelerden birisi olan AccessDataSource kontroln kullanacaz. Veritabanmz Access ile
gelitirilmi olup MailListesi isimli aadaki Field yapsna sahip bir tabloyu barndrmaktadr.

ekil 1. Access tablomuzun field yaps.

www.bsenyurt.com Page 2125


Oluturduumuz bu tabloyu, web sitemiz iin standart olarak alan Data klasr altna kopyalaym.

ekil 2. Veritabanmz Data klasr altna koyalm.

Sra geldi default.aspx sayfamz tasarlamaya. ncelikli olarak, AccessDataSource kontrolmz


aadaki aspx kodlar ile sayfaya ekleyelim.

<asp:AccessDataSource ID="AccessDataSource1" Runat="server" DataFile="~/Data/veriler.mdb"


SelectCommand="SELECT * FROM [MailListesi]" UpdateCommand="UPDATE [MailListesi] SET
Ad=@AD,Soyad=@SOYAD,Mail=@MAIL WHERE ID=@ID">
<UpdateParameters>
<asp:Parameter Name="AD"></asp:Parameter>
<asp:Parameter Name="SOYAD"></asp:Parameter>
<asp:Parameter Name="MAIL"></asp:Parameter>
<asp:Parameter Name="ID"></asp:Parameter>
</UpdateParameters>
</asp:AccessDataSource>

Burada dikkat ederseniz, SelectCommand zellii dnda, dikkati eken bir dier zellik
UpdateCommand' dr. UpdateCommand zellii, satrlardaki deiikliklerin veri kaynana
yanstlmasnda kullanlacak Sql sorgusunu iermektedir. Bu sql sorgusu dikkat edecek olursanz,
eitli parametrelere sahiptir. Dikkate deer dier bir noktada, parametre bildirimlerinin,
Framework 1.0/1.1' de olan, OleDbCommand kontrollerindeki gibi, ? (soru iareti) olmaydr. Bu
noktada, Sql sunucular zerinde altrlan parametreli sorgulardaki yapnn (@Parametre_ad
yaps) aynsnn Access kaynaklar iinde kullanlabildiini ve bylece ortak bir standardn
oluturulmu olduunuda belirtelim.

UpdateCommand zelliindeki Sql sorgusunda yer alan parametreler, AccessDataSource


kontrolnn UpdateParameters koleksiyonunda birer Parameter nesnesi olarak tanmlanrlar.
Basite burada parametrelerimizin isimlerini Name zellikleri ile belirledik. DataSource bileenleri
iin, SelectCommand ve UpdateCommand komutlar dnda kullanlabilecek dier komutlarda,
DeleteCommand ve InsertCommand' dir. Bunlarn herbirinin parametre koleksiyonlar farkldr. Yani
DeleteCommand iin parametre koleksiyonu DeleteParameters iken, InsertCommand iin
InsertParameters' dr.

www.bsenyurt.com Page 2126


ekil 3. DataSource' lar iin geerli dier parametre koleksiyonlar.

AccessDataSource bileenimiz artk veri ekmek ve gncellemek iin hazrdr. Srada, GridView
kontrolmz, bu veri kaynana gre dzenlemek var. Bunun iin, GridView kontrolmz
aadaki aspx kodlar ile oluturmamz yeterli olacaktr.

<asp:GridView ID="GridView1" Runat="server"


DataSourceID="AccessDataSource1" DataKeyNames="ID" AutoGenerateColumns="False">
<Columns>
<asp:CommandField ShowEditButton="true"></asp:CommandField>
<asp:BoundField ReadOnly="True" HeaderText="ID" InsertVisible="False" DataField="ID"
SortExpression="ID"></asp:BoundField>
<asp:BoundField HeaderText="Ad" DataField="Ad" SortExpression="Ad"></asp:BoundField>
<asp:BoundField HeaderText="Soyad" DataField="Soyad"
SortExpression="Soyad"></asp:BoundField>
<asp:BoundField HeaderText="Mail" DataField="Mail"
SortExpression="Mail"></asp:BoundField>
</Columns>
</asp:GridView>

u aamada bizim iin en nemli zellik, DataKeyNames' dir. Bu zellik, GridView kontrolnde
zerindeki satrlarda yaplan veri deiiklikleri sonucu, gncelleme ilemlerinin hangi primary key
alan zerinden yaplacan belirtmektedir. Nitekim, Sql sorgumuza dikkat edecek olursanz,
gncelleme ileminin hangi alan iin yaplacan belirleyebilmek amacyla, primary key olan ID
alan kullanlmtr.

UPDATE [MailListesi] SET Ad=@AD,Soyad=@SOYAD,Mail=@MAIL WHERE ID=@ID

Bu sebeple, GridView kontrol, Update butonuna basldnda, DataKeyNames zelliindeki field


alannn deerini, seili olan satr zerinden AccessDataSource kontrolndeki UpdateCommand
sorgusuna gnderecektir. Dier nemli ye ise, CommandField kontroldr. Bu kontrol, satr
zerinde hangi ilemin yaplaca ile ilgili link (button) kontrollerinin gsterilmesi iin
kullanlmaktadr. Burada ShowEditButton zelliine true deerini vererek, ilgili satr iin Edit,
Update ve Cancel linklerinin gsterilmesini salam olduk. Artk web formumuza son halini
verebiliriz.

www.bsenyurt.com Page 2127


ekil 4. default.aspx sayfamzn grnm.

imdi sayfamz tarayc penceresinde aar ve herhangibir satrda edit linkine tklayacak olursak,
aadaki grnm elde ederiz.

ekil 5. Edit linkine tklandnda.

Grld gibi, ilgili satra ait alanlarda TextBox kutucuklar veri girii iin hazr beklemektedir. Bu
noktada Update linkine tklarsak, seili satrn ID deeri ile birlikte dier alanlarn gncel ierikleri,
AccessDataSource kontrolnn UpdateCommand zelliinde kullanlan Sql sorgusuna parametre
olarak gnderilirler. Ardndan gncelleme ilemi yaplr ve GridView kontrol gncel ierii ile
grntlenir. rnein, "Burak S." deerini "Burak Selim" yapp Update linkine bastmzda
aadaki ekran grntsn elde ederiz.

www.bsenyurt.com Page 2128


ekil 5. Gncelleme ilemi sonras.

Tahmin edin, Delete ilemini nasl gerekletireceiz. Uygulayacamz mantk aslnda, Update
ilemi iin uygulanan ile ayn olacaktr. lk olarak AccessDataSource kontrolmzde,
DeleteCommand zelliini tanmlamal ve geerli bir Delete sql sorgusu girmeliyiz. Ardndan bu Sql
sorgusunda kullanacamz ID alan iin bir parametre ekelemeliyiz. Yani AccessDataSource
kontrolmz aadaki hale getirmeliyiz.

<asp:AccessDataSource ID="AccessDataSource1" Runat="server" DataFile="~/Data/veriler.mdb"


SelectCommand="SELECT * FROM [MailListesi]" UpdateCommand="UPDATE [MailListesi] SET
Ad=@AD,Soyad=@SOYAD,Mail=@MAIL WHERE ID=@ID" DeleteCommand="DELETE FROM
[MailListesi] WHERE ID=@ID">
<UpdateParameters>
<asp:Parameter Name="AD"></asp:Parameter>
<asp:Parameter Name="SOYAD"></asp:Parameter>
<asp:Parameter Name="MAIL"></asp:Parameter>
<asp:Parameter Name="ID"></asp:Parameter>
</UpdateParameters>
<DeleteParameters>
<asp:Parameter Name="ID"></asp:Parameter>
</DeleteParameters>

Tabi GridView kontrolmzde de Delete ilemi iin gerekli linki (button' u) gstermeliyiz. Bu
amalada, GridView kontrolnn CommandField bileeninin ShowDeleteButton zelliinin deerini
true yapmalyz.

<asp:CommandField ShowDeleteButton="true" ShowEditButton="true"></asp:CommandField>

Bu deiikliklerden sonra sayfamz altrdmzda aadaki ekran grntsn elde ederiz.

www.bsenyurt.com Page 2129


ekil 7. Delete linkinin eklenmesi.

Eer Delete linki ile bir satr silecek olursak, ilgili satrn ID deeri, AccessDataSource
kontrolndeki, DeleteCommand zelliine parametre olarak gidecek ve Sql sorgusu altrlarak
ilgili satr silinecektir. rnek olarak, 1 ID deerine sahip satr sildiimizde, aadaki ekran
grntsn elde ederiz.

ekil 8. Satr silindikten sonra.

Bununla birlikte unutulmamas gereken nemli bir nokta vardr. Buradaki tm ilemler veri
tablosuna dorudan yanstlr. Dolaysyla, satr sildiimizde(gncellediimizde), AccessDataSource
bunu kesinlikle, asl tabloyada yanstacaktr. Nitekim son ilemden sonra, tablomuza bakacak
olursak ID deeri 1 olan satrn artk olmadn grebiliriz.

ekil 9. Satr kesin olarak silinir.

Gelitirdiimiz rnei biraz makyajlamaya ne dersiniz? rnein, Update, Edit, Cancel ve Delete
kelimeleri yerine Trke bir eyler ksa ve bunlar Link yerine button olsa fena olmazd deil mi?
Bunun iin tek yapmamz gereken aadaki aspx kodlar ile, GridView kontrolmz
gncellemektir. Dikkat edecek olursanz, her bir kontroln sonu Text kelimesi ile biten bir zellii

www.bsenyurt.com Page 2130


vardr. rnein Delete butonu iin DeleteText. Dolaysyla bunlar deiitirerek ekranda
grnmesini istediimiz metini belirtebiliriz. Ayrca, linklerimizi button haline getirmek iin,
ButtonType zelliine Button deerini atadk.

<asp:CommandField ButtonType="Button" CancelText="ptal" EditText="Dzenle" DeleteText


="Sil" UpdateText="Gncelle" ShowDeleteButton="true"
ShowEditButton="true"></asp:CommandField>

ekil 10. Trke buttonlar.

Sayfamzn son olarak makyajlanm hali ve ilgili aspx kodlar aadaki gibidir.

www.bsenyurt.com Page 2131


ekil 11. Sayfamzn biraz daha makyajl hali.

<%@ Page Language="C#" CompileWith="Default.aspx.cs" ClassName="Default_aspx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"


"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:AccessDataSource ID="AccessDataSource1" Runat="server"
DataFile="~/Data/veriler.mdb"
SelectCommand="SELECT * FROM [MailListesi]" UpdateCommand="UPDATE [MailListesi] SET
Ad=@AD,Soyad=@SOYAD,Mail=@MAIL WHERE ID=@ID" DeleteCommand="DELETE FROM
[MailListesi] WHERE ID=@ID">
<UpdateParameters>
<asp:Parameter Name="AD"></asp:Parameter>

www.bsenyurt.com Page 2132


<asp:Parameter Name="SOYAD"></asp:Parameter>
<asp:Parameter Name="MAIL"></asp:Parameter>
<asp:Parameter Name="ID"></asp:Parameter>
</UpdateParameters>
<DeleteParameters>
<asp:Parameter Name="ID"></asp:Parameter>
</DeleteParameters>
</asp:AccessDataSource><br/>
<b><span style="font-size: 24pt; color: #cc0000; font-family: Agency FB">Mail
Listesi</span></b>
<asp:GridView ID="GridView1" Runat="server" DataSourceID="AccessDataSource1"
DataKeyNames="ID" AutoGenerateColumns="False" BorderWidth="1px" BackColor="White"
GridLines="Vertical" CellPadding="4" BorderStyle="None" BorderColor="#DEDFDE"
ForeColor="Black" AllowSorting="True" AllowPaging="True">
<FooterStyle BackColor="#CCCC99"></FooterStyle>
<PagerStyle ForeColor="Black" HorizontalAlign="Right"
BackColor="#F7F7DE"></PagerStyle>
<HeaderStyle ForeColor="White" Font-Bold="True"
BackColor="#6B696B"></HeaderStyle>
<AlternatingRowStyle BackColor="White"></AlternatingRowStyle>
<Columns>
<asp:CommandField ButtonType="Button" CancelText="ptal"
EditText="D&#252;zenle" DeleteText="Sil"
UpdateText="G&#252;ncelle" ShowDeleteButton="True"
ShowEditButton="True"></asp:CommandField>
<asp:BoundField ReadOnly="True" HeaderText="ID" InsertVisible="False"
DataField="ID"
SortExpression="ID"></asp:BoundField>
<asp:BoundField HeaderText="Ad" DataField="Ad"
SortExpression="Ad"></asp:BoundField>
<asp:BoundField HeaderText="Soyad" DataField="Soyad"
SortExpression="Soyad"></asp:BoundField>
<asp:BoundField HeaderText="Mail" DataField="Mail"
SortExpression="Mail"></asp:BoundField>
</Columns>
<SelectedRowStyle ForeColor="White" Font-Bold="True"
BackColor="#CE5D5A"></SelectedRowStyle>
<RowStyle BackColor="#F7F7DE"></RowStyle>
</asp:GridView>
</div>
</form>
</body>
</html>

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

www.bsenyurt.com Page 2133


selim@bsenyurt.com

Asp.Net 2.0 ve TreeView Kontrol ( 06.09.2004 )


- Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, Asp.Net 2.0 ile birlikte gelen yeni kontrollerden birisi olan TreeView kontrol ile,
zellikle Xml tabanl veri kaynaklarna ait bilgilerin, internet ortamnda hiyerarik bir yapda nasl
gsterilebileceini incelemeye alacaz. Bir nceki makalemizden hatrlayacanz gibi, site iinde
son kullancya akll navigasyon hizmeti sunabilmek iin sitemap dosyalarndan
faydalanabileceimizi ve bu dosyalara ait Xml ieriinin, SiteMapPath kontrol ile sayfalarmzda
gsterilebileceinden bahsetmi ve basit bir rnek gelitirmitik. Benzer ilevsellie TreeView
kontrol yardmyla daha kuvvetli bir biimde sahip olabiliriz.

TreeView kontrol, Xml tabanl veri kaynaklarn kullanr. Bu anlamda, hiyerarik verilerin zellikle
aa yaps eklinde ifade edilmesinde kullanlmaktadr. imdi bir nceki makalemizde
gelitirdiimiz rnee TreeView kontroln ekleyerek, sitemap ileminin nasl yaplacan
incelemeye alalm. ncelikle, formumuza bir TreeView kontrol ve birde SiteMapDataSource
kontrol ekleyeceiz. TreeView kontrolnn nemli bir zellii mutlaka bir veri kaynana
balanmas gerekliliidir. Oysaki SiteMapPath kontrol doal olarak, site iin oluturulan sitemap
dosyasna dorudan balanabilmektedir. Fakat TreeView kontrol Xml tabanl verilere
balanbilirliinin gcn yanstabilmek iin, DataSource kontrollerinden birisini kullanmak
zorundadr. Bizim burada kullanacamz SiteMapDataSource basit bir ekilde, sitenin sitemap
dosyasna balanr ve Xml tabanl ieriin node seviyesinde, TreeView kontrol ile
ilikilendirilmesini salar. lk olarak bu kontrolleri geen rneimizdeki default.aspx sayfasna
aadaki tarzda yerletirelim.

ekil 1. Form Tasarmmz.

www.bsenyurt.com Page 2134


Formumuzu yukardaki gibi tasarladktan sonra tek yapmamz gereken, TreeView kontrolne veri
kaynan bildirmek olacaktr. Burada veri kaynamz SiteMapDataSource kontrol olduu iin,
TreeView kontrolnn DataSourceID zelliine, bu kontroln ID deerini atamamz yeterlidir. Bu
atamayda yaptmz takdirde aspx kodlarmz aadaki gibi olacaktr.

<asp:TreeView ID="TreeView1"
Runat="server" DataSourceID="SiteMapDataSource1"></asp:TreeView>
<asp:SiteMapDataSource ID="SiteMapDataSource1" Runat="server" />

Ayrca, tasarm ekranmzda aadaki grnm alacaktr.

ekil 2. TreeView, SiteMapDataSource kontrolne balandktan sonra.

Grld gibi, sitemap dosyasnn Xml ierii, SiteMapDataSource kontrol yardmyla, TreeView
kontrolne balanmtr. Bylece hiyerarik yapnn aa grnm elde edilmitir. Bu noktada,
aa grnmnn temel yapta olan node kavramndan bahsetmekte yarar olacan
dnyorum. TreeView kontrolnn ifade ettii aa yapsnda, "Azon Kitap Cd Dvd" eleman, root
node olarak adlandrlr. Root Node, baka alt node' lar ierebilen ve hiyeraride en st srada yer
alan node olarak deerlendirilir. Bununla birlikte bir TreeView kontrol birden fazla Root Node
ierebilmektedir. Root Node altnda yer alabilecek 3 tip node daha vardr. Bunlar Parent, Child ve
Leaf Node' lardr. Bir Parent Node, Child Node' lar ierir ve root node altnda yer alr. Dier
taraftan, herhangibir Child Node iermeyen node' lar Leaf Node olarak adlandrlr. Node' larn
mantn okuyarak anlamak her nekadar kark grnsede, aadaki ekil bu konuyu daha net bir
ekilde aklamaktadr.

www.bsenyurt.com Page 2135


ekil 3. Node Kavram.

Tabi burada dikkat edecek olursanz, rnein "CD ler" node' u Parent Node olmakla birlikte, Root
Node' un Child Node' u olarakta deerlendirilir. Benzer ekilde, "Film CD'leri" node'u "CD ler" node'
unun Child Node' u olmakla birlikte, baka alt node' lar iermedii iin ayn zamanda bir Leaf Node'
dur. Node' lar ile ilgili bu ksa aklamalardan sonra, uygulamamz gelitirmeye devam edelim.
TreeView kontrol, kullancya grsel adan eitli imkanlarda beraberinde getirmektedir. rnein
MSDN' de kullanlan aa yapsnn formatn TreeView kontrolnze uygulayabilirsiniz. Ya da,
aadaki ekran grntsn veren, News formatnda kullanabilirsiniz. Bunun iin tek yapmanz
gereken, TreeView kontrolnn Auto Format zelliklerini, nceden tanmlanm formatlardan birini
seerek tamamlamaktr.

ekil 4. nceden tanmlanm News formatnn TreeView kontrolne uygulanmasnn sonucu.

Dilerseniz sayfamz altralm ve TreeView kontrolnn bize nasl bir imkan saladna bakalm.
Sayfamz altrdmzda tarayc penceresinde TreeView kontrolnn, sitemap dosyasnn
ieriini, aa yaps eklinde aadaki ekilde olduu gibi gsterdiini grrz.

www.bsenyurt.com Page 2136


ekil 5. Sayfamz altnda.

in en gzel yan, node' lardan birisine tkladmzda, sitemap dosyasnda o node iin belirtilen
link' e baka bir deyile sayfaya gidebilmemizdir. rnein, Muzik Cd' leri sayfasna tkladmzda,
MuzikCd.aspx sayfasna gideriz. Dolaysyla TreeView kontroln, onu sitemap dosyasna balayan
SiteMapDataSource kontrol ile birlikte bir kullanc tanml kontrol olarak gelitirmemiz halinde,
sitemizin tm sayfalarnda son derece etkin ve k bir navigasyon sistemine sahip olabiliriz.

TreeView kontrolnn bu kullanm dnda daha pek ok tarz uygulan vardr. ncedende
sylediimiz gibi, bir TreeView kontrol mutlaka suretle bir veri kmesine balanr. Az nceki
rneimizde, bu veri kayna, sitemap dosyamzd ve buraya balanmak iin SiteMapDataSource
kontroln kullanmtk. Dilersek bir TreeView kontroln,bir Xml dosyasnada balayabiliriz.
rnein aadaki Xml dosyasn gz nne alalm. (Bu dosyay, Veriler.xml adyla Solution' mza
ekledik.)

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


<Manav>
<Meyve Kategori="Elma">
<Miktar Deger="1 Kilo"></Miktar>
<Miktar Deger="2 Kilo"></Miktar>
<Miktar Deger="3 Kilo"></Miktar>

www.bsenyurt.com Page 2137


</Meyve>
<Meyve Kategori="Kiraz">
<Miktar Deger="1 Kilo"></Miktar>
<Miktar Deger="2 Kilo"></Miktar>
</Meyve>
<Meyve Kategori="Karpuz">
<Miktar Deger="5 Kilo"></Miktar>
<Miktar Deger="5 - 10 Kilo"></Miktar>
<Miktar Deger="2 - 5 Kilo"></Miktar>
</Meyve>
<Meyve Kategori="Limon">
<Miktar Deger="3 Tane"></Miktar>
<Miktar Deger="10 Tane"></Miktar>
<Miktar Deger="10-> Tane"></Miktar>
</Meyve>
</Manav>

Bu Xml dosyasn,TreeView kontrolmze balayabilmemiz iin, bir XmlDataSource kontroln


kullanmamz gerekiyor. XmlDataSource kontrolmzn, bu Xml dosyasna iaret edebilmesi iin tek
yapmamz gereken, DataFile zelliine ilgili Xml dosyasnn adresini belirtmek olacaktr. Bunun iin
aspx kodlarmz aadaki gibi gelitirmemiz yeterli olacaktr.

<asp:XmlDataSource ID="XmlDataSource1" Runat="server" DataFile="Veriler.xml">


</asp:XmlDataSource>

imdi, bu XmlDataSource nesnesini kullarak, veriler.xml dosyasna balanacak ve ieriini


gsterecek bir TreeView kontroln sayfamza ekleyelim. Bu kez, SiteMapDataSource kontrolnde
olduu gibi, TreeView kontrolnn DataSourceID zelliine, XmlDataSource kontrolnn ID
deerini atamamz tek bana yeterli olmayacaktr. Nitekim, Xml dosyasndaki node' lar, TreeView
kontrolne bind etmemiz gerekmektedir. Bunun iin, TreeView kontrolnn <DataBindings> taks
kullanlr. Bu tak altnda, her bir node iin gerekli olan TreeNodeBinding aspx nesneleri
tanmlanmaldr. Bu bilgileri gz nne alrsak, TreeView kontrolmz ve XmlDataSource
kontrolmz aadaki aspx kodlar ile oluturmamz gerekmektedir.

<asp:TreeView ID="trvManav" Runat="server" DataSourceID="XmlDataSource1">


<DataBindings>
<asp:TreeNodeBinding DataMember="Manav" Text="Manav"
Value="Manav"></asp:TreeNodeBinding>
<asp:TreeNodeBinding
DataMember="Meyve" TextField="Kategori"></asp:TreeNodeBinding>
<asp:TreeNodeBinding DataMember="Miktar" TextField="Deger"></asp:TreeNodeBinding>
</DataBindings>
</asp:TreeView>

<asp:XmlDataSource ID="XmlDataSource1" Runat="server" DataFile="Veriler.xml">


</asp:XmlDataSource>

www.bsenyurt.com Page 2138


Burada bizim iin nemli olan zellikler, TreeNodeBinding kontrolne ait olan, DataMember ve
TextField zellikleridir. imdi, TreeView kontrolmze yine otomatik formatlardan birisini (rnein
MSDN) uygulayalm ve sayfamz taraycda aalm.

ekil 6. TreeView kontroln Xml dosyasna, XmlDataSource kontrol ile baladmzda.

Elbette, bu TreeView yapsn daha etkin bir ekilde kullanma sunabiliriz. rnein, kullanc burada
yer alan Leaf Node' lardan seim yapabilir. Bunun iin, TreeView kontrolnn, Leaf Node' larna
CheckBox koymamz salayacak bir zellii vardr.

ekil 7. ShowCheckBoxes zellii.

ShowCheckBoxes zellii ile, TreeView kontrolnn hangi node' larnda CheckBox gsterileceini
belirtebiliriz. Biz bu rneimizde leaf seeneini iaretleyelim. Bylece, kullancnn hangi meyveden
ka kilo (adet) almak isteyeceini iaretleyebilecei kutucuklarmz olacaktr. Kullancnn,
iaretledii kutucuklar elde edebilmek ve bir label kontrolnde gsterebilmek amacylada,
rneimizi aadaki ekilde olduu gibi gelitirelim.

www.bsenyurt.com Page 2139


ekil 8. Formun son hali.

Kullanc, sayfada "Gzden Geir" balkl button kontrolne tkladnda, TreeView kontrolne
iaretlemi olduu miktarlar ve bu miktarlarn yer ald Parent Node' lar lblSecilenler isimli Label
kontrolne yazdrlacak. Bu ilemi gerekletirmek iin, Button' umuzun Click olayna aadaki
kodlar yazmamz yeterli olacaktr.

void btnGozdenGecir_Click(object sender, EventArgs e)


{
string secilenler="";
if (trvManav.CheckedNodes.Count > 0)
{
foreach (TreeNode tn in trvManav.CheckedNodes)
{
secilenler += tn.Parent.Text+" "+tn.Text+"|";
}

lblSecilenler.Text = secilenler;
}
else
{
lblSecilenler.Text = " Manavdan bir ey almadnz...";
}

www.bsenyurt.com Page 2140


}

TreeView kontrolnn CheckedNodes zellii TreeNodeCollections koleksiyonu tipinden deer


dndrmektedir ve iaretlenmi olan node' lar kmesini temsil etmektedir. Dolaysyla if
kontrolnde, Count zellii ile, kullancnn herhangibir node' u iaretleyip iaretlemedii, baka bir
deyile CheckBox kutucuklarn seip semediine baklmaktadr. Eer seilmi node' lar var ise, bu
node' lar arasnda gezinmek iin, foreach dngs kullanlarak CheckNodes koleksiyonundaki her
bir TreeNode eleman ele alnr. TreeNode elemanlar bu dngde, Leaf Node' larmzdan
iaretlenmi olanlarna iaret etmektedir. Dolaysyla, o anki TreeNode nesnesinin Parent zellii,
Parent Node' u iaret eder. Uygulamamz altrp aadaki gibi bir ka seim yaptmz takdirde,
Label kontrolmzn seili olan Leaf Node' lar ve bu node'larn Parent Node' lar ile doldurulduunu
grrz.

ekil 9. Sayfamz altnda.

Bylece geldik bir makalemizin daha sonuna. lerleyen makalelerimizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 ve Temalar (Themes) ( 03.09.2004 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Bir internet sitesini nemli klan zellikler, sayfalarnn font, renk, nesne yerleimleri ile kontrollere
ait grsel zellikleri asndan birbirleriyle olan uyumluluklardr. Bu anlamda, ou zaman sayfalara
CSS stilleri uygulanr ve web uygulamasndaki tm grsel elerin ayn font, renk vb zelliklere

www.bsenyurt.com Page 2141


sahip olmas salanr. Asp.Net 2.0, bu tarz stillerin eitli seviyelerde uygulanmasn salayacak
yeni bir zellik salamaktadr. Themes (Temalar). te bu makalemizde, Asp.Net 2.0'da yer alan
temalarn, hangi seviyelere, nasl ve ne ekilde uygulanabileceini incelemeye alacaz.

Bir tema, aslnda iletim sistemlerinde uygulanan temalardan ok da farkl deildir. Pek oumuz
kulland iletim sistemine temalar uygulamtr. Uygulanan temalar, ounlukla sistemdeki font
zelliklerini, pencerelere ait eitli renkleri, duvar katlarn, sembolleri vb eleri grsel adan
belirli bir standarta gre deitirirler. Ancak internet projelerinin tasarlanmas sz konusu
olduunda, temalarn uygulanaca seviyeler kavram ncelikli olarak devreye girmektedir. Asp.Net
2.0 ile, makine seviyesinde, web uygulamas seviyesinde, sayfa seviyesinde ve sunucu kontrol
seviyesinde temalar uygulanabilmektedir.

ekil 1 Tema Seviyeleri.

Biz bu makalemizde, temalarn bu seviyelere nasl uygulandn incelemek amacyla, basit bir tema
oluturacak ve bu temay eitli seviyelere uygulayarak sonularn incelemeye alacaz. Bu
amala ilk olarak bir web uygulmas aalm. Bu web uygulamamzn default.aspx sayfasn
aadaki ekran grntsne sahip olacak ekilde oluturalm. Bu sayfada bir ka sunucu
kontroln kullanacaz.

www.bsenyurt.com Page 2142


ekil 2. Sayfamzn Varsaylan Hali.

Eer sayfamz bu haliyle taraycda aarsak aadaki ekran grntsn elde ederiz.

ekil 3. Sayfamzn ilk halinin taraycadaki grnts.

imdi uygulamamza bir tema ekleyeceiz. Bunun iin ncelikle solution' mza Theme isimli bir
folder eklememiz gerekiyor. Bu klasr, bir nceki makalemizde bahsetmi olduumuz Code klasr
gibi, solution iin zel anlam ifade eden bir yapya sahiptir. Nitekim bu klasr altna, uygulamaya
ait font, renk gibi stillerin nasl olacan belirten css dosyalar ve sunucu kontrollerine ait grsel
ayarlarn yapld skin dosyalar ile eitli resimler eklenebilir. Theme klasrn oluturduktan
sonra kullanacamz tema iin bir isim belirlemeli ve bu isimle yeni bir alt klasr amalyz. Artk
skin ve css dosyalarmz bu klasr altnda oluturabiliriz. Bylece, uygulamamzda oluturduumuz
alt klasr ismindeki temay uygulayabiliriz. Klasr yapmz aadaki ekildeki gibi olmaldr. Bu
hiyerarik dzen ayn zamanda, bir solution iin birden fazla tema oluturulabileceinide
gstermektedir.

ekil 4. Temamz iin uygulamamz gereken klasr hiyerarisi.

imdi sunucu kontrollerimizin nasl grneceini belirleyeceimiz zellikleri tayacak bir skin
dosyas oluturacaz. Bu dosyamz Temam klasr altnda gelitireceiz. Skinler zelikle temalar
iin tasarlanm tipteki dosyalardr. Ancak, Asp.Net 2.0' n Beta srmnde bu dosya tipi

www.bsenyurt.com Page 2143


tanmlanmamtr. Dolaysyla, klasrmz altnda Add New Item seenei ile skin eklemek
istiyorsak, Text File tipini sememiz ve dosya ismimizin uzants skin olacak ekilde belirtmemiz
gerekmektedir.

ekil 5. Skin eklenmesi.

Bir skin dosyas, aslnda sunucu kontrollerinin grsel adan zelletirilmi halini ierir. Dolaysyla,
bir web uygulamasna bir temann uygulanmas sonucu, bu uygulamdaki sunucu kontrolleri iin skin
dosyalar ierisindeki sunucu kontrollerinin grsel zellikleri uygulanr. Bunu aadaki kod
satrlarndan daha iyi anlayabiliriz. Aadaki kod satrlar, Gorsel.skin dosyamza ait olup eitli
sunucu kontrollerine grsel adan zenginlik katacak zelliklere sahiptir.

<asp:Label Runat="server" Font-Bold="False" Font-Names="Forte" Font-Size="Large"


ForeColor="Red"></asp:Label>
<asp:TextBox Runat="server" Font-Names="Verdana" Font-Size="Small" ForeColor="#C000C0"
BackColor="#FFC080" BorderColor="#C00000" BorderStyle="Solid" BorderWidth="2px"
></asp:TextBox>
<asp:Button Runat="server" Font-Bold="True" ForeColor="White" BackColor="OrangeRed"
BorderColor="#C04000" BorderStyle="Solid" BorderWidth="3px" />
<asp:DropDownList Runat="server" Font-Names="Bookman Old Style" Font-Size="Small"
BackColor="#FFE0C0" Font-Italic="True"></asp:DropDownList>
<asp:ListBox Runat="server" Width="100px" Height="70px" Font-Bold="True" ForeColor="Gold"
BackColor="SteelBlue"></asp:ListBox>

Bu kodlara dikkatlice bakacak olursanz, Label, Button, TextBox, DropDownList, ListBox gibi
kontrollerin eitli font, renk zellikleri ile tanmlanm olduklarn greceksiniz. te bu noktadan
sonra, her hangibir tema seviyesinde, Temam temasn uygularsak, sunucu kontrolleri burada
belirtilen grsel zelliklere sahip olacaktr. Bu dosyann oluturulmas ile birlikte ilk temamz
hazrlam oluyoruz. imdi bu temann, bahsetmi olduumuz seviyeler iin nasl uygulanacan
inceleyelim.

ncelikle sayfa seviyesinde bu temay default.aspx iin nasl uygulayacamza bakalm. Bunun iin,
default.aspx sayfasnn, page direktifine ait, Theme zelliinden yararlanacaz. Tek yapmamz

www.bsenyurt.com Page 2144


gereken, theme zelliine, oluturduumuz temann bulunduu klasrn ismini atamak olacaktr.
(Dolaysyla temann ismini.)

<%@ Page Language="C#" CompileWith="Default.aspx.cs"


ClassName="Default_aspx" Theme="Temam" %>

imdi default.aspx sayfamzn taraycdaki grnmne tekrar bakacak olursak, aadaki ekran
grntsn elde ederiz.

ekil 6. Temamzn sayfaya uygulanm hali.

Grld gibi, default.aspx altnda, page direktifindeki theme zelliinin sahip olduu deerin
belirttii klasr, web uygulamasnn Themes klasr altnda aranm ve bulunduktan sonra, ilgili
skin dosyasndaki kontrollere ait font ve renk zellikleri yklenmitir. Bu rneimizde temamz, web
sayfas seviyesindedir. Yani, uygulamamza aadaki ekran grntsne sahip ikinci bir form
eklediimizde, page direktifinin theme zelliine temamz atamadmz srece, sunucu
kontrollerinin varsaylan grnmlerine sahip olduunu farkederiz.

ekil 7. Theme zellii ayarlanmam sayfann tasarm hali.

www.bsenyurt.com Page 2145


ekil 8. Theme zellii ayarlanmam sayfann alan hali.

Bu durumda karmza yle bir soru kar. Temalarmz, web uygulamasnn ierdii tm sayfalara
uygulamak istersek ne olacak? te bu sorunun cevab her zaman olduu gibi, uygulamann
tamamna ait ayarlamalar yapabileceimiz web.config dosyas ile ilgilidir. Sorunun zm iin,
web.config dosyasna pages taksn aadaki syntax' ile eklememiz gerekir.

<system.web>
<pages theme="Temam"></pages>
.
.
.
</system.web>

Bylece, web uygulamasndaki tm sayfalarn, Temam isimli temay uygulamasn salam oluruz.
Baka bir deyile web uygulamas seviyesinde tema uygulatm oluruz. Bu noktadan sonra
default2.aspx sayfamzn almasna bakarsak, sunucu kontrollerinin temay uyguladn grrz.

ekil 9. Uygulama seviyesinde tema kullanlmasnn sonucu.

Dier bir seviye olarakta, makine seviyesinin olduundan bahsetmitik. Makine seviyesinde yaplan
tema uyarlamalar, sistemde gelitirilen tm web uygulamalarna, bu uygulamalardaki tm web
sayfalarna ve bu sayfalardaki tm sunucu kontrollerine uygulanmaktadr. Makine seviyesinde tema
uyarlamasn gerekletirmek iin, windows 2000 iletim sistemleri iin
C:\WINNT\Microsoft.NET\Framework\v2.0.40607\CONFIG adresinde yer alan machine.config

www.bsenyurt.com Page 2146


dosyasnda yine pages taksndaki theme zelliini aadaki syntax' ta olduu gibi ayarlamamz
gerekmektedir.

<pages theme="Temam">
.
.
.
</pages>

Ancak burada dikkat etmemiz gereken zel bir nokta vardr. Machine.config doysasna ekelenen
temann(temalarn) sistemdeki tm web uygulamalarna uyarlanabilmesi iin
C:\Inetpub\wwwroot\aspnet_client\system_web\2_0_40607 \Themes adresi altnda oluturulmas
veya var olan temalarn buraya kopyalanmas gerekmektedir. Temam isimli klasrmz ierii ile
birlikte buraya kopyalarsak ve machine.config' de yukarda bahsettiimiz ayarlamay yaparsak,
sistemdeki tm web uygulamalarnn bu temay uyguladn grrz.

ekil 10. Temamz global kullanma atmz klasr.

Temalar ile ilgili nemli bir dier noktada, st seviyedeki temalarn geersiz klnmas ilemidir.
Makine seviyesinde tema uyguladmz dnrsek, herhangibir web uygulamasnda bu temay
uygulamak istemiyebiliriz. Bu durumda tek yapmamz gereken, web.config dosyasndaki page
taksnn theme zelliine ya baka bir temay atamak yada bo brakmak olacaktr.

<pages theme=""></pages>

Bylece web uygulamas, makine seviyesinde belirtilen temay geersiz klacaktr. Eer sayfa
seviyesinde, uygulama seviyesindeki yada makine seviyesindeki bir temay geersiz klmak
istersek, bu kez ilgili sayfann page direktifindeki theme zelliinde ya baka bir temay belirtmemiz
yada EnableTheming zelliine false deerini vermemiz gerekecektir.

<%@ Page Language="C#" EnableTheming="false"%>

EnableTheming zellii, sunucu kontrolleri iinde geerlidir. Dolaysyla, bir temay uygulayan bir
web sayfasndaki herhangibir kontrol iin tema zelliklerini geersiz klabiliriz. Bunun iin tek
yapmamz gerken sunucu kontrolnn EnableTheming zelliine false deerini atamaktr. rnein,
gelitirdiimiz web uygulmasndaki Temam temasn gz nne alalm. Eer button kontrolnn
EnableTheming zelliini false yaparsak sayfamz altrdmzda aadaki ekran grntsnn
olutuunu ve Button kontrolne tema zelliklerinin uygulanmadn grrz.

<asp:Button ID="Button1" Runat="server" Text="Gster" EnableTheming="false"/>

www.bsenyurt.com Page 2147


ekil 11. Bir kontrol iin temann geersiz klnmas.

Bylece Asp.Net 2.0 ile gelen tema tekniinin nasl kullanldn ksaca incelemi olduk. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 iin Site Map Kullanm ( 03.09.2004


) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, web sitelerinde zellikle sayfalar arasndaki hareketlerde, kullanclarn nerede


olduklarn bilmelerine yardmc olan site haritalar zerinde duracaz. Bununla birlikte, site
haritalarnn Asp.Net 2.0' daki kullanm yollarndan birisini salayan SiteMapPath sunucu kontroln
ksaca incelemeye alacaz.

Internet sitelerinin ou, pek ok web sayfasndan oluur. Bu sayfalar arasnda her zaman iin bir
iliki ve hiyerari sz konusudur. Dolaysyla kullanclar, internet sitelerine ait sayfalarda
gezinirken, onlara sitenin neresinde olduklarn gstermek ve bulunduklar sayfaya nereden
geldiklerini belirtmek, sitenin mantksal ve anlamsam btnl asndan olduka nemlidir. Bu
tarz bir kolayl kullanclara salayabilmek amacyla eitli yollar kullanabiliriz. Kullanc tanml
kontroller gelitirebilir, programatik olarak gelitirimi teknikler uygulayabiliriz. Ancak Asp.net 2.0,
bu tip navigasyon izleme ilemleri iin, Xml tabanl, esnek ve daha pratik bir yol sunmaktadr. Bu
teknikteki anahtar noktalar, Site Map dosyas ile, SiteMapPath sunucu kontroldr. Olay daha iyi
anlayabilmek amacyla aadaki hiyerarik dzene sahip bir internet sitemizin olduunu
varsayalm.

www.bsenyurt.com Page 2148


ekil 1. Site Haritamz.

Burada grld gibi ana sayfamz dallanarak eitli alt sayfalara doru ilerlenmektedir. imdi,
Film Dvdsi sayfamzda olduumuzu dnelim. Burada kullancya, nerede olduu gstermek, son
kullanc asndan olduka deerli bir bilgidir. Heleki web sitemiz yzlerce sayfa ieriyoru ve
sayfalarn ou 3 yada daha fazla alt sayfaya mantki olarak balanyorsa ok daha nemlidir.
Ayrca, kullancnn bu sayfaya geldii sayfalarada gitmesini kolayca salayacak linklerin olmasda
tercih nedenidir. te bu tip ilemleri gerekletirmek iin, ekilsel olarak ifade ettiimiz bu haritay,
Xml ortamna tamamz gerekmektedir. Bu i iin kullanlan Site Map tipindeki dosyalar, Asp.Net
2.0 iin gelitirilmi zel nitelikli dosyalar olup tamamyla, site haritalama ilemlerine hizmet
etmektedir. imdi ncelikli olarak yukardaki hiyerariye sahip sitemizi Visual Studio.Net 2005
ortamnda oluturalm. Her sayfamz aadaki isimler ile Solution' mza ekleyelim.

www.bsenyurt.com Page 2149


ekil 2. Azon internet sitemizin sayfalar.

Sradaki ilemimiz web.sitemap dosyasn oluturmak olacaktr. Bunun iin Solution Explorer' da
sa tklayp Add New Item' i setikten sonra aadaki ekilde grld gibi Site Map dosya tipini
iaretlemeliyiz.

ekil 3. Site Map dosyamz oluturuyoruz.

Gelelim dosyamzn ieriine. Bu dosya Xml tabanl bir dosya olup, siteMapNode taklarndan
olumaktadr. SiteMap taks altnda yer alan, siteMapNode taklar, site haritasndaki sayfalar
eitli zellikleri ile birlikte belirtmektedir. Harita hiyerarisine gre derinlerdeki sayfalara inilmek
istendiinde i ie geen siteMapNode taklar kullanlmaldr. siteMapNode taklar temel olarak, url,
description, title olmak zere 3 nemli zellik ierir. Title ile sayfann bal, description ile sayfaya

www.bsenyurt.com Page 2150


ait aklama ve url zellii ilede sayfann adresi belirtilmektedir. imdi, oluturduumuz
web.sitemap dosyasna aadaki Xml ieriini yazalm.

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


<siteMap>

<siteMapNode url="default.aspx" title="Azon Kitap Cd Dvd" description="En iyi Kitaplar, Cdler,


Dvdler bu siteden alnr.">
<siteMapNode url="kitap.aspx" title="Kitaplar" description="Bilgisayar, hukuk ve tp
kitaplar">
<siteMapNode url="IngilizceBilgisayar.aspx" title="Ingilizce Bilgisayar Kitaplar"
description="Ingilizce Bilgisayar Kitaplar. Onlardan iyisi yok."/>
<siteMapNode url="TurkceBilgisayar.aspx" title="Trke Bilgisayar Kitaplar"
description="Trke Bilgisayar Kitaplar Zengin Arivimiz ile Karnzda."/>
<siteMapNode url="Hukuk.aspx" title="Hukuk Kitaplar" description="Hukuu
renebileceiniz en iyi kitaplar."/>
<siteMapNode url="Tip.aspx" title="Tp Kitaplar" description="Tp akaya gelmez. En iyi
tp kitaplarn bizden aln."/>
</siteMapNode>

<siteMapNode url="cd.aspx" title="CD ler" description="Film ve Mzik Cd' leri.">


<siteMapNode url="MuzikCd.aspx" title="Mzik Cd' leri." description="Harika gruplar,
harika albmler."/>
<siteMapNode url="FilmCd.aspx" title="Film Cd' leri." description="En gzel filmler."/>
</siteMapNode>

<siteMapNode url="dvd.aspx" title="DVD ler" description="Film ve Mzik DVD' leri.">


<siteMapNode url="MuzikDvd.aspx" title="Mzik DVD' leri." description="Harika gruplar,
harika albmler."/>
<siteMapNode url="FilmDvd.aspx" title="Film DVD' leri." description="En gzel filmler
oklu dil destekleri ve mkemmel grnt kaliteleriye Dvdlerde."/>
</siteMapNode>

<siteMapNode url="sitehakkinda.aspx" title="Site Hakknda" description="Kimiz ve size ne


salyoruz."/>

</siteMapNode>

</siteMap>

Artk elimizde site haritamzn xml ierii mevcuttur. imdi bu Xml ieriini kullanacak olan sunucu
kontrolmze bakalm. SiteMapPath sunucu kontrol, bu xml ieriine bakarak site haritasn
deerlendirir ve son kullancya akll navigasyon izleme yeteneini salar.

www.bsenyurt.com Page 2151


ekil 4. SiteMapPath sunucu kontrol.

imdi, toolbox' taki navigation sekmesinde yer alan SiteMapPath sunucu kontrollerini rnek olarak
TrkceBilgisayar.aspx sayfasna brakalm.

ekil 5. Sunucu kontrolnn sayfaya eklenmesi sonras.

Grld gibi, site haritamzdaki hiyarerik dzene gre bu sayfaya hangi sayfalardan gelindii
aka grlmektedir. Eer bu noktada, TurkceBilgisayar.aspx sayfasn altracak olursak,
"Kitaplar" ve "Azon Kitap Cd Dvd" linkleri ile, site haritasndaki st sayfalara klabileceimizide
grrz. Dilersek, SiteMapPath sunucu kontrolne hazr grsel formatlardan birisinide uygulayarak
makyajlayabiliriz. Bunun iin kontroln sanda kan ok iaretinden sonra yer alan Auto Format
seeneine basmamz ve herhangibir format (rnein Colorful) sememiz yeterlidir.

ekil 6. Auto Format seenei.

ekil 7. Colorful seenei.

www.bsenyurt.com Page 2152


Bu makyajlama ilemi sonras, SiteMapPath kontrolnn aspx sayfasndaki ierii aadaki gibi
olacaktr.

<asp:SiteMapPath ID="SiteMapPath1" Runat="server" Font-Size="0.8em" Font-Names="Verdana"


PathSeparator=" : ">
<PathSeparatorStyle Font-Bold="True" ForeColor="#990000"></PathSeparatorStyle>
<CurrentNodeStyle ForeColor="#333333"></CurrentNodeStyle>
<NodeStyle Font-Bold="True" ForeColor="#990000"></NodeStyle>
<RootNodeStyle Font-Bold="True" ForeColor="#FF8000"></RootNodeStyle>
</asp:SiteMapPath>

Burada nemli olan zelliklerden birisi, SiteMapPath sunucu kontrolne ait, PathSeperator' dr. Bu
zellik ile, sayfalar arasndaki ayra iareti belirtilmektedir. Burada st ste iki nokta kullanlmtr.
PathSeparatorStyle taks ise, ayra iaretinin font ve renk zelliklerini belirlemekte kullanlr.
CurrentNodeStyle , kullancnn o an bulunduu sayfay belirten node' un font ve renk zelliklerini
belirlerken, NodeStyle st nodelara ait ve RootNodeStyle ana sayfaya ait font ve renk zelliklerini
belirler.

imdi, bu sayfaya uyguladmz SiteMapPath sunucu kontrolln kopyalayalm ve dier


sayfalarmza yaptralm. rnek olarak bu kezde, MuzikDvd.aspx sayfamz altralm. Bu sayfay
altrdmzda ekran grnts aadaki gibi olacaktr.

ekil 8. MuzikDvd sayfamz.

Grld gibi, Xml ieriinde belirttiimiz description deeri burada ilgili sayfa iin bir ipucu
kutucuu olarak ekrana kmtr. Dier taraftan, alt izili linklere tklayarak st sayfalara hareket
edebiliriz. rnein, Dvd ler linkine tkladmzda, Dvd.aspx sayfasna gideriz.

ekil 9. Dvd.aspx sayfasna getik.

www.bsenyurt.com Page 2153


SiteMapPath sunucu kontrol iin enmli olan zelliklerden biriside, PathDirection' dr. Bu zellik,
kontrol zerindeki hiyerarinin root' tan current'a yada tam tersi istikamette olup olmayacan
belirtlir. Varsaylan olarak bir SiteMapPath kontrolnn yn, root' tan current' a dorudur. Eer
yn ters evirmek istersek, sunucu kontrolne ait kodu aadaki gibi deitirmemiz gerekir.

<asp:SiteMapPath ID="SiteMapPath1" Runat="server" Font-Size="0.8em" Font-Names="Verdana"


PathSeparator=" : " PathDirection="CurrentToRoot">

Bu durumda, sunucu kontrolmz aadaki gibi grnecektir.

ekil 10. PathDirection zellii CurrentToRoot yapldnda.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde, TreeView kontrol
yardmyla navigasyon ilemlerinin nasl yapldn incelemeye alacaz. imdilik hoakaln.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 ile Veri Kmelerinde Sayfalama


lemleri ( 01.09.2004 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, Asp.Net 2.0 ile gelitirilen sayfalarda, veri kmeleri zerinde sayfalama
ilemlerinin nasl yapldn incelemeye alacaz. Sayfalama ilemleri, zellikle internet(intranet)
uygulamalarnda yaygn ekilde kullanlan bir tekniktir. Burada, veri kmesine ati olan satrlar,
DataGrid gibi bir kontrolde gsterilirken, sayfalara ayrlrlar. Bylece veri kmesine ait satrlar
arasnda toplu gei yapmamza imkan salayan, navigasyon seeneklerine sahip olmu oluruz.

Asp.Net 2.0 iinde ayn imkanlar ve kabiliyetler sz konusudur. Ancak uygulan ekli ve kullanlan
bileenler ok daha farkldr. Hereyden nce, Asp.Net 1.0/1.1 de izlenen yollara nazaran, daha
ksa ve etkili bir teknik gelitirilmitir. Asp.Net' in ilk srmleri ile gelitirilen uygulamalarda,
sayfalama ilemlerinin gerekletirilmesi iin DataGrid kontrollerinde ekstradan olay prosedr
kodlamamz gerekmektedir. Bu bizim iin fazla maliyettir. Nitekim zaman kaybettirici bir ilemdir.
Ne demek istediimi ve Asp.Net 2.0' da hangi noktaya geldiimizi grmek iin Visual Studio.Net
2003 ile gelitirilen aadaki internet sayfasna bir gz atalm.

<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=windows-1252">

www.bsenyurt.com Page 2154


<title>New Page 1</title>
</head>
<body>
<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false"
Inherits="Sayfalama.WebForm1" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<title>WebForm1</title>
<form id="Form1" method="post" runat="server">
<asp:DataGrid id="DataGrid1" runat="server" AllowPaging="True">
<PagerStyle Mode="NumericPages"></PagerStyle>
</asp:DataGrid>
</form>
</body>
</html>

Bu aspx sayfasnda, DataGrid kontrol zerinde sayfalama ilemini gerekletirebilmek iin


AllowPaging zelliine true deeri atanmtr. Bununla birlikte sayfalamann saysal olarak
gerekletirilmesi iin PagerStyle taks eklenmi ve bu taknn Mode zelliine NumericPages deeri
atanmtr. Code-Behind kodlarmza bakacak olursak, benzer uygulamalarda da muhtemelen
aadaki kod satrlarnda kullanlan tarzda bir veri elde edili yntemi uygulandn grrz.

<%@ Page language="c#" Codebehind="WebForm1.aspx.cs" AutoEventWireup="false"


Inherits="Sayfalama.WebForm1" %> private void veriAl()
{
SqlConnection con=new SqlConnection("data source=localhost;initial catalog=pubs;integrated
security=SSPI");
SqlCommand cmd=new SqlCommand("Select au_lname,au_fname,address From authors",con);
SqlDataAdapter da=new SqlDataAdapter(cmd);
DataTable dtYazarlar=new DataTable();
da.Fill(dtYazarlar);
DataGrid1.DataSource=dtYazarlar;
DataGrid1.DataBind();
}
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack)
{
veriAl();
}
}

private void DataGrid1_PageIndexChanged(object source,


System.Web.UI.WebControls.DataGridPageChangedEventArgs e)
{
DataGrid1.CurrentPageIndex=e.NewPageIndex;
veriAl();
}

www.bsenyurt.com Page 2155


Sayfamz bu haliyle altrdmzda, veri kmesi ierisinde sayfalama ilemlerinin
gerekletirilebildiini grrz. Elde ettiimiz kme, sayfalara ayrlarak, DataGrid kontrolnde
gsterilecektir. Yaptmz ilem aslnda basittir ancak uzundur. ncelikle bir SqlConnection
kontrol ile veri kaynana bir balant hatt ekilir. Ardndan, ilgili veri kmesini elde
edebileceimiz, Select sorgusunu tayan bir SqlCommand nesnesi oluturulur. SqlCommand
nesnesini kullanacak olan bir SqlDataAdapter ise, balantsz katmandaki DataTable nesnesini veri
kmesi ile doldurmaktadr. Ardndan elde edilen DataTable bileeni DataGrid kontrolne balanr ve
DataGrid kontrol iin DataBind metod altrlr. Tm bu ilemlerin yannda sayfann PostBack
olmas durumunda kaybolacak paging zelliinin nne gemek iin, Load olaynda, IsPostBack
kontrol yaplr. Ayrca, DataGrid kontrolnde, sayfalama ilemi sonras oluan sayfa numaras
linklerine basldnda, veri kmesinin ilgili parseline gidebilmek iin, DataGrid1_PageIndexChanged
olay metoduda kodlanmtr. Bu yol her nekadar bir sre Asp.Net ilee uygulama gelitiren biris iin
anlalr ve kolay gzksede, takdir edersinizki uzun ve ayn zamanda verimsiz bir yapdadr.
Hereyden nce, ok fazla kaynak tketimi sz konusudur.

ekil 1. Asp.Net 1.1 Sayfalam ilemi.

Burada takip ettiimiz yolu dncek olursak, aslnda gereksiz yere bir ka adm ilem yaptmz
ve bir ka nesne kaynan gereksiz yere harcadmz dnebiliriz. Bu teknik dnda,
SqlDataReader nesnesini kullanacamz baka bir yol daha gelitirebilirdik. Ancak hangi yol
seilirse seilsin, her ikiside uygulama gelitiricinin bir ka satrda olsa fazladan kod yazmasn ve
baz pf noktalara (DataGrid1_PageIndexChanged olay metodu gibi) dikkat etmesini
gerektirecektir. Bu elbetteki uygulama gelitiricinin artan tecrbesi ile nemsiz hale gelebilir. Ancak
ilerin dahada ksaltlarak yaplabileceide gerektir. te Microsoft mimarlar, bu eksikliin farkna
varm olacaklarki, Asp.Net 2.0' da, sayfalama ilemine farkl bir yakam ve uygulama teknii
getirmiler. Hereyden nce, DataSource kavramn kullanan Framework 2.0 iin, sayfalama
ilemlerini gerekletirmek, Asp.Net 1.0/1.1 srmlerine gre hem daha kolay hemde daha
profesyonel bir anlaya sahip. Bu yeni teknik sayesinde, uygulama gelitiricinin verimliliinin daha
da artaca kansndaym. imdi dilerseniz, Asp.Net 2.0' daki duruma bir gz atalm. Bu kez aspx
sayfamzn kodlarn aadaki gibi oluturacaz.

<%@ Page Language="C#" CompileWith="Sayfalama.aspx.cs" ClassName="Sayfalama_aspx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"


"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<div>

www.bsenyurt.com Page 2156


<asp:GridView ID="GridView1" Runat="server" AllowPaging="True"
DataSourceID="sqlKaynak">
</asp:GridView>
<asp:SqlDataSource runat="Server" ProviderName="System.Data.SqlClient"
ConnectionString="data source=.;initial catalog=AdventureWorks;integrated security=true"
SelectCommand="SELECT [EmployeeID],[Gender],[HireDate] FROM
[AdventureWorks].[HumanResources].[Employee]" ID="sqlKaynak"></asp:SqlDataSource>

</div>
</form>
</body>
</html>

Bu kodlara sahip Asp.Net 2.0 sayfamz altrdmzda aadaki gibi bir ekran grnts elde
ederiz.

ekil 2. Asp.Net 2.0 iin sayfalama ilemi.

Burada dikkat edecek olursanz tek satr uygulama kodu yazlmamtr. Bunun yerine tm ilemler,
GridView ve SqlDataSource Asp.Net kontrolleri ile gerekletirilmitir. Bu kontroller, Asp.Net 2.0 ile
gelen saysz yeni bileenden sadece ikisidir. GridView kontrolmzn en nemli zellii, kendisine
veri kayna olarak bir SqlDataSource nesnesini bildiren DataSourceID zelliidir. Bu zellik ile, veri
kmesini ala belirttii veri kaynandan ekecek olan SqlDataSource kontrolnn ID deeri
belirtilir.

<asp:GridView ID="GridView1" Runat="server" AllowPaging="True" DataSourceID="sqlKaynak">


</asp:GridView>

SqlDataSource bileenimiz, uygulama gelitiricisinin verimliliini arttran yenilikler ieririr. Asp.Net


1.1 ile yazdmz bir nceki rnein aksine, burada veri kaynana balanma, veri kmesini ekme
ve bunlar ilgili kontrol ile ilikilendirme ilemleri tek bir bileen ierisindeki zellikle yardmyla

www.bsenyurt.com Page 2157


gerekletirilebilmektedir. Bu noktada kontrol her nekadar DataAdapter' andrsada ok daha farkl
olduunu ProviderName zelliine bakarak bile anlayabiliriz.

<asp:SqlDataSource runat="Server" ProviderName="System.Data.SqlClient"


ConnectionString="data source=.;initial catalog=AdventureWorks;integrated security=true"
SelectCommand="SELECT [EmployeeID],[Gender],[HireDate] FROM
[AdventureWorks].[HumanResources].[Employee]" ID="sqlKaynak"></asp:SqlDataSource>

SqlDataSource kontrol ile, burada rnek olarak, Yukon (Sql Server 2005) zerinde yer alan
AdventureWorks veritabanndaki Employee tablosuna balanlmtr. ProviderName zellii, hangi
veri salaycnn kullanlacan belirtir. Biz burada doal sql motorunu kullanmak istediimizden,
System.Data.SqlClient snfn kullandk. ConnectionString ile tahmin edeceiniz gibi, veri kaynana
bir balant hatt tahsis etmekteyiz. SelectCommand zellii ilede, altrmak istediimiz Select
sorgusunu tanmlyoruz. SqlDataSource kontrol burada GridView kontrol ile beraber
almaktadr. Dolaysyla, sayfalama ilemini gerekletirmek iin, GridView kontrolnn
AllowPaging zelliine true deerini atamamz ve kullanlcak DataSource bileenini belirtmemiz
yeterlidir.

Bylece geldik bir makalemizin daha sonuna. Bu makalemizde ksaca Asp.Net 2.0 iin sayfalama
ilemlerinin nasl gerekletirilebildiini incelemeye altk. Bir sonraki makalemizde grmek
dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 ve Code Klasr ( 01.09.2004 ) -


Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, Asp.Net 2.0 ile gelen tanmlanm klasrlerden (defined folders), Code
klasrnn nasl kullanldn incelemeye alacaz. Asp.Net 1.0/1.1 ile uygulama gelitirirken,
solution iindeki herey bir dll iinde (assembly) toplanr. Asp.Net 2.0 ise, dosya tabanl (file-
based) yaklam ad verilen yeni bir teknik kullanr. Bu teknie gre, solution, dosyalar ve klasrler
sisteminden olumaktadr. Bu sistemin faydas, otomatik derleme zelliine sahip olmasdr. Yani,
solution ierisine herhangibir dosya eklenmesi halinde (rnein bir snf), Visual Studio.Net 2005 bu
dosyay otomatik olarak derler ve solution' n her zaman dinamik olarak gncel kalmasn salar.
Bir baka deyile yeni eklenen dosya iin, solution' n batan derlenmesi gerekmez. Bu yzden,
Asp.Net 2.0 ile uygulama gelitirirken ilk dikkati eken unsur, oluturulan sanal klasr altnda
eskiden olduu gibi bin klasrnn ve bir dll dosyasnn olmaydr.

Asp.Net 2.0 ile gelitirilen bu yeni teknikte, eitli nceden tanmlanm (predefined folders) zel
klasr seenekleri mevcuttur. Bunlardan biriside Code klasrdr. Code klasr, snf dosyalarmz,
web servisleri iin kullanlan wsdl dosyalarmz, trlendirilmi dataset' ler (typed datasets) iin
kullanlan xml emalar ve Data Component' ler tipindeki dosyalar barndrlabilir. Code klasr
ierisine konulan bu dosyalar, Visual Studio.Net 2005 ortamnda otomatik olarak tannr. Ayrca,
Visual Studio.Net 2005, bu dosyalar kullanarak, snflara derler, proxy snflarn veya trlendirilmi
veri snflarn oluturur. Bu yapy aadaki ekil ile daha kolay anlayabiliriz.

www.bsenyurt.com Page 2158


ekil 1. Genel yap.

Dilerseniz konuyu daha iyi anlayabilmek amacyla basit bir rnek gelitirelim. Bunun iin Visual
Studio.Net 2005' de yeni bir Web Site ayoruz. Daha sonra Solution Explorer' da solution' mz
zerine sa tklyor ve New Folder seeneine basarak, yeni bir klasr oluturuyoruz. Klasrmze
Code ismini verdiimizde, eklinin normal klasrlerden biraz daha farkl olduunu hemen
farkedebiliriz. Nitekim Code klasrnn Solution iin zel bir anlam vardr.

ekil 2. Code klasrnn eklenmesi.

www.bsenyurt.com Page 2159


imdi default.aspx form' unuda aadaki gibi oluturalm. Bu web sayfasnda basit olarak, yarap
verilen bir dairenin alan hesap edilecek. Bu hesaplama ilemini yapan metodumuzu barndracak
bir snfmz olacak ve bu snfmz, Code klasr ierisinde yer alacak.

ekil 3. Form tasarmmz.

imdi, Code klasrnde sa tklayalm ve Add New Item' i seelim. Karmza aadaki dialog
penceresi kacaktr.

ekil 4. Code klasr iin yeni bir e eklemek.

Bu dialog pencersinde, Code klasrne ekleyebileceimiz dosya tipleri yer almaktadr. Biz class
tipini seeceiz. AlanHesap.cs dosyamzn kodlar aada grld gibidir.

using System;

public class AlanHesap

www.bsenyurt.com Page 2160


{
public AlanHesap()
{

}
public double DaireAlan(double yaricap)
{
return 3.14 * (yaricap * yaricap);
}
}

Bu noktadan sonra, solution' mz hi derlemeden, AlanHesap snfmz kullanabilir, bu snftan


nesne rnekleri yaratabilir daha da nemlisi intelli-sense zelliinden derhal faydalanabiliriz.

ekil 5. Intelli-Sense zellii.

Bu noktadan sonra, uygulamamz oluturduumuz klasre bakarsak aadaki yapda olduunu


farkederiz. Dikkat edecek olursanz Asp.Net 1.0/1.1' deki gibi kalabalk bir topluluk yoktur. En
nemlisi Bin klasrn veya tm uygulamann tiplerine ait manifesto bilgilerini ve kodlar barndran
bir dll grememekteyiz.

ekil 6. Klasr Azl.

Code klasr iin dikkat edilecek noktalardan birisi, buradaki dosyalarn tamamnn single assembly
olarak ele alnmalardr. Yani, bu klasr altndaki tm dosyalar ayn dil ile yazlm olmaldr.
Nitekim, klasrmze vb.net ile yazlm aadaki class dosyasn eklediimizi dnelim.

Imports Microsoft.VisualBasic

Public Class VbSinif

www.bsenyurt.com Page 2161


Public Function Deneme(ByVal yaricap As String) As String
Return (yaricap)
End Function

End Class

Bu durumda solution' derlediimizde aadaki derleme zaman hata mesajn alrz.

ekil 7. Hata Mesaj.

Peki zm nedir? Byk apl projelerde, farkl .net dilleri kullanlarak gelitirilen snflarn ayn
solution ierisinde kullanlmas iin ne yapabiliriz? Bunun iin, ncelikle Code klasr iinde her bir
dile ynelik olarak ayr klasrler amamz gerekir. Aadaki ekilde olduu gibi.

ekil 8. Farkl diller iin farkl klasrler.

Buradaki alt klasrleri isimlendirmek iin belirli bir kural yoktur. Ancak buradaki isimlendirmelerin
aynsn Web.Config dosyasndaki <compilation> node' unda kullanmamz gerekmektedir. Nitekim,
otomatik olarak yaplan nceden derleme ilemlerinde, hangi alt klasrlerin kullanlacann sitenin
konfigurasyon ayarlarna yanstlmas gereklidir. Bunun iin Web.Config dosyasndaki,

<compilation debug="true">

</compilation>

ksmn aadaki ile deitirmemiz yeterli olacaktr.

<compilation debug="true">

www.bsenyurt.com Page 2162


<codeSubDirectories>
<add directoryName ="CSharp"/>
<add directoryName ="VbDotNet"/>
</codeSubDirectories>
</compilation>

imdi bu ilemlerin ardndan default.aspx sayfasna getiimizde, vb.net ile yazdmz snfa
eriebildiimizi ve kullanabildiimizi grrz.

ekil 9. Farkl dil ile yazlm snfa eriim.

imdi kodumuzu aadaki gibi gelitirelim ve sayfamz altralm.

void btnHesapla_Click(object sender, EventArgs e)


{
AlanHesap ah = new AlanHesap();
lblSonuc.Text = ah.DaireAlan(Convert.ToDouble(txtYaricap.Text)).ToString();

VbSinif s = new VbSinif();


string deger = s.Deneme(txtYaricap.Text.ToString());
lblDeger.Text = deger;
}

www.bsenyurt.com Page 2163


ekil 10. Farkl dil ile yazlm snflar bir arada alyor.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Asp.Net 2.0 ile Cross-Page Posting (


31.08.2004 ) - Asp.Net 2
Deerli Okurlarm Merhabalar,

Bu makalemizde, Asp.Net 2.0 (Asp.Net Whidbey) ile, baka sayfalara veri postalama ilemlerinin
nasl ele alndn ve uygulandn incelemeye alacaz. Bildiiniz gibi, Asp.Net 1.0 / 1.1 ile
gelen yeniliklerden en nemlisi, sayfalarn kendi kendilerine form verilerini postalayabilme
kabiliyetleridir. yleki, Asp.Net ile gelitirilen web sayfalar aslnda birer snf nesnesi olduklarndan,
sayfa zerindeki form kontrollerine ve deerlerine kolayca eriilebilmektedir. Ancak baz
zamanlarda, sayfalarmzda yer alan form verilerini baka sayfalara gndermek isteyedebiliriz. te
Cross-Page Posting olarak adlandrlan bu ilemlerin, Asp.Net 2.0 ile gerekletirilmesi hem daha
kolay hemde daha etkili hale getirilmitir.

rneklerimizi gelitirdiimizde bu konuyu ok daha iyi anlayabileceinize inanyorum. Hi vakit


kaybetmeden rneimizi gelitirmeye balayalm. Bu rnek uygulamamz, Visual Studio.Net' in
2005 srmnn Beta versiyonu ile gelitireceiz. rneimizde, basit olarak iki web sayfas
kullanacaz. ncelikle yerel sunucumuzda bir web sitesi oluturalm. Bunun iin, File mensnden,
New alt mensn ve buradan da Web Site ksmn seiyoruz.

www.bsenyurt.com Page 2164


ekil 1. Yeni bir Web Site ayoruz.

Ardndan, karmza kacak dialog penceresinden, Asp.Net Web Site' seelim ve localhost altnda
CrossPosting isimli sanal klasrmzn adn girelim.

ekil 2. Web Site'mz oluturuyoruz.

Bu ilemin ardndan, Visual Studio.Net standart olarak default.aspx isimli sayfamz oluturur. Bu
sayfamz aadaki ekilde olduu gibi oluturalm.

www.bsenyurt.com Page 2165


ekil 3. Form tasarmmz.

Sayfamzn kodlanmasna gemeden nce, aspx sayfamzn ieriine bir gz atalm. Nitekim burada
nemli olan btnDiger ID deerine sahip button kontrolmzn taklar arasndaki ieriktir. Biz
burada ufak bir deiiklik yapacaz. nce kodlarmzn balang haline bakalm.

<%@ Page Language="C#" CompileWith="Default.aspx.cs" ClassName="Default_aspx" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"


"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >


<head runat="server">
<title>Untitled Page</title>
</head>
<body>
<form id="form1" runat="server">
<asp:Label ID="Label1" Runat="server" Text="Rumuzunuz" Width="86px" Height="19px"
Font-Bold="True"></asp:Label><span style="font-size: 10pt; font-family: Verdana"> </span>
<asp:TextBox ID="TextBox1" Runat="server"></asp:TextBox><br />
<span style="font-size: 10pt; font-family: Verdana"></span>
<asp:Label ID="Label2" Runat="server" Text="Ya Aralnz" Font-
Bold="True"></asp:Label><span
style="font-size: 10pt; font-family: Verdana"> </span>
<asp:DropDownList ID="DropDownList1" Runat="server" Width="71px" Height="22px">
<asp:ListItem>20-25</asp:ListItem>
<asp:ListItem>25-30</asp:ListItem>
<asp:ListItem>30-35</asp:ListItem>
</asp:DropDownList><span style="font-size: 10pt; font-family: Verdana">
<br />
<br />
</span>
<asp:Button ID="btnBuras" Runat="server" Text="Buras" /><span style="font-size: 10pt;
font-family: Verdana">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>
<asp:Button ID="btnDiger" Runat="server" Text="Diger" Width="58px" Height="24px"

www.bsenyurt.com Page 2166


/><span
style="font-size: 10pt; font-family: Verdana">
<br />
<br />
<br />
</span>
<asp:Label ID="lblKim" Runat="server" Width="270px" Height="19px"
BorderColor="#FFC0C0"
BorderWidth="1px" Font-Bold="True"></asp:Label><span style="font-size: 10pt; font-family:
Verdana">
</span>
</form>
</body>
</html>

Burada btnDiger, ID deerine sahip button kontrolmzn olduu satr aadaki gibi deitirelim.

<asp:Button ID="btnDiger" PostBackUrl="Diger.aspx" Runat="server" Text="Diger"


Width="58px" Height="24px" />

te Asp.Net 2.0 ile gelen ilk yeniliklerden birisi. PostBackUrl zellii. Bu Url, button kontrolne
basldnda, Form zerindeki verilerin belirtilen url' deki sayfaya gnderilmesini salamaktadr.
leyi ekli son derece etkilidir. imdi Solution Explorer' dan Add New Item ile, Diger.aspx isimli
sayfamzda uygulamamza ekleyelim. Ardndan, default.aspx sayfamzn Code-Behind kodlarn da
aadaki gibi gelitirelim.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Default_aspx


{
void btnBuras_Click(object sender, EventArgs e)
{
lblKim.Text = TextBox1.Text + DropDownList1.SelectedItem.Text;
}
}

Burada yaptmz deiik bir olay yok. Sadece, TextBox1 kontrolne girilen ve DropDownList1
kontrolnde seilen deerleri, Label kontrolne yazdrdk. te bu, Asp.Net 1.0/1.1 srmnden
bildiimiz, sayfann kendi kendine verileri postalamas ilemidir. Asp.Net 2.0 ile gelen yeni

www.bsenyurt.com Page 2167


teknikleri ise, Diger.aspx sayfasnda kullanacaz. Bunun iin Diger.aspx sayfamza bir Label
kontrol yerletirelim ve ardndan, sayfamza ait kodlar aadaki gibi dzenleyelim.

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Diger_aspx


{
void Page_Load(object sender, EventArgs e)
{
TextBox tbRumuz = (TextBox)PreviousPage.FindControl("TextBox1");
DropDownList lstYas = (DropDownList)PreviousPage.FindControl("DropDownList1");

lblDurum.Text = tbRumuz.Text + lstYas.SelectedItem.Text;


}
}

Dikkat edecek olursanz burada son derece gl bir teknik kullanlmaktadr. Bir adet TextBox ve
bir adette DropDownList kontrol tanmlanm ve oluturulmutur. TextBox kontrolmz
olutururken, PreviousPage snfnn FindControl metodu ile, bu sayfaya Post ilemi ile form verisi
gnderen sayfadaki TextBox1 kontrol bulunmaktadr. Bu ilem, bulunan kontroln TextBox
kontrol olarak cast edilmesi ile tamamlanr. Dolaysyla, Diger.aspx sayfamzn Page_Load olay
metodunda, elimizde bir adet TextBox kontrol olacaktr. Bu TextBox kontrol aslnda, default.aspx
sayfasndan gelen kontroldr. Bylece, default.aspx sayfasndaki TextBox1 kontrolnn deerine
ve zelliklerine bu snf ierisinden (Diger.aspx sayfasndan) kolayca eriebiliriz. Ayn teknik,
DropDownList kontrolmz iinde geerlidir. te Asp.Net 2.0, baka sayfalara form verisi
gnderme ilemlerinde bylesine gl bir teknik ile gelmektedir.

Uygulamamz altrdmzda ve Buras balkl butona tkladmzda basite sayfa kendi


kendisine postalama ilemini uygular. (Postback).

www.bsenyurt.com Page 2168


ekil 4. Postback.

Diger balkl button kontrolne bastmzda ise, Diger.aspx isimli sayfaya gidilir. Bu sayfann
Page_Load olay metodu alr ve burada ilgili TextBox ve DropDownList kontrolleri, default.aspx'
ten gelen kontroller baz alnarak oluturulur. Sonu olarak, default.aspx sayfasndaki kontroller
zerinde yer alan veriler kolayca elde edilir ve bu sayadaki Label kontrolne ierikleri yazdrlr.

ekil 5. Cross-Page Posting

Cross-Page Posting ileminde elbette sorun yaratabilecek durumlarda sz konusudur. Bunlarn en


nemlisi, bir kullancnn, default.aspx altrlmadan nce diger.aspx sayfasna ulamaya
almasdr. Byle bir durumda, default.aspx daha nceden altrlmad iin, buradaki kontroller
oluturulmam olacaktr. Dolaysyla, diger.aspx sayfasnda, PreviousPage snfna ait metodlar, var
olmayan kontrolleri bulmaya alacak ve referanslar oluturulamayacaktr. Kullanclarn byle bir
giriimde bulunmas sonucunda aadaki gibi bir hata mesaj ile karlalr.

www.bsenyurt.com Page 2169


ekil 6. Oluan Hata.

zm gayet basittir. Bu sayfa altrldnda, bu sayfaya baka bir sayfadan form bilgisinin
gnderilip gnderilmedii renilmelidir. Bunun iin, Page snfnn IsCrossPagePostBack isimli
zelliinden yararlanlr. Bu zellik, aslnda IsPostBack zellii gibi alr. Sadece, baka bir
sayfann mevcut sayfaya veri postalayp postalamadn kontrol eden ve boolean deer dndren
bir yapdadr. Prototipi aadaki gibidir.

public bool IsCrossPagePostBack {get;}

Dolaysyla, diger.aspx sayfamzn arka kodlarn aadaki gibi deitirmemiz sorunun giderilmesini
salayacaktr.

public partial class Diger_aspx


{
void Page_Load(object sender, EventArgs e)
{
if (PreviousPage!=null && PreviousPage.IsCrossPagePostBack)
{
TextBox tbRumuz = (TextBox)PreviousPage.FindControl("TextBox1");
DropDownList lstYas = (DropDownList)PreviousPage.FindControl("DropDownList1");

lblDurum.Text = tbRumuz.Text + lstYas.SelectedItem.Text;


}
else
{
Response.Redirect("default.aspx");
}
}
}

Bylece, eer kullanclar direkt olarak diger.aspx sayfasn altrrlarsa, nceden gelen bir Cross-
Page Posting ilemi olmadndan, else bloundaki kod satr alacak ve default.aspx sayfasna
gidilecektir.

Bu makalemizde, Asp.Net 2.0 ile gelen yeniliklerden birisine deinmeye altk. Elbette u an iin,
Asp.Net 2.0 henz beta aamasnda. Yani yazlan kodlar ve kullanlan teknikler deiebilir hatta
bazen kaynaklarn aksine almayabilir. Bunlardan da haberdar olduka sizleri bilgilendirmeye
alacaz. Bylece geldik bir makalemizin daha sonuna. lerleyen makalelerimizde grmek
dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Localization (Yerelletirme) 2 - Dil Destei (


07.08.2004 ) - C#
www.bsenyurt.com Page 2170
Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde hatrlayacanz gibi, .net ile gelitirilen uygulamalarn belirli kltrler iin
nasl yerelletirilebileceini incelemeye balamtk. lk blmde, belirli bir kltrn daha ok
saysal, tarihsel ve sralama formatlar zerinde durduk. Bu blmde ise, yerelletirmede daha da
nemli olan bir konuya, uygulamalarn farkl dillere gre destek vermesine deineceiz.

Bir .net uygulamasnn farkl dillere destek vermesindeki anahtar nokta, Resource dosyalarnn
etkin bir ekilde kullanlmasnda yatmaktadr. rnein, uygulamamzn arayznn Trke olarak
oluturulduunu dnelim. Bu uygulamaya ait arayzdeki metinleri, baka bir dilde sunabilmek
iin, ilgili kelimelerin dier dildeki karlklarnn bir ekilde assembly tarafndan bilinmesi gerekir.
Sadece bilinmesi elbette yeterli deildir. Ayrca, alan proses iin, arayz kltrnnde istenen
dile ayarlanmas gerekmektedir.

imdi dilerseniz bu ilemlerin nasl gerekletirilebildiini basit bir uygulama zerinde anlamaya
alalm. Uygulamamz aadaki form grntsne sahip bir windows uygulamas olacak. u anda
form zerindeki tm metinler Trke. Biz uygulamamz, ngilizce, Franszca ve Almanca dillerine
destek verecek hale getireceiz.

ekil 1. Uygulama Form Tasarmmz.

lk olarak Resource dosyalarn oluturacaz. Bu dosyalar, birer szlk olarak dnebiliriz.


Resource dosyalar XML tabanl dosyalar olup, temelde verileri anahtar yada isim (key - name) -
deer (value) iftleri eklinde tutmaktadrlar. Bu adan bakldklarnda bunlar Hash Tablolarna
benzetebiliriz. Dolaysyla, uygulamamza dil destei salamak istiyorsak, ortak isimler (names)
belirleyip, ilgili dil iin uygun deerleri atayacamz dosyalar oluturmamz gerekecektir. Yani
Trke iin bir tane, ngilizce iin bir tane, Almanca iin bir tane ve Franszca iin bir tane. Bir
Resource dosyasn Vs.Net ortamnda uygulamaya eklemek iin projeye sa tklayp Add New Item
iletiim kutusuna girmemiz ve Assembly Resource File dosya tipini sememiz yeterlidir. Burada
nemli olan Resource dosyasnn isimlendirili eklidir.

www.bsenyurt.com Page 2171


ekil 2. Resource Dosyasnn Eklenmesi.

Dikkat edecek olursanz dosyamz isimlendiriken tr-TR taksn kullandk. Bu Trke dilini konuan
lkemizi temsil eden belirleyici bir kltr kodudur. Dosyann bu ekilde isimlendirilmesinin sebebi,
alma zamannda, seilen kltre gre hangi Resource dosyasndaki kelimelerin ykleneceinin
belirlenebilmesidir. Bunu kodlarmz yazdmzda daha net bir ekilde aklamaya alacam.
imdi dosyamzn name ve value deerlerini girelim.

ekil 3. Resource1.tr-TR.resx dosyasnn ierii.

Artk tek yapmamz gereken, dier diller iinde gerekli olan resx dosyalarn oluturmak. Bu
dosyalarda, name yada key deerlerimiz Trke olacak. Ancak karlklar olan kelimeler value
deeri olarak belirlenecek. rnein, Franszca iin aadaki bilgiler girilecek.

www.bsenyurt.com Page 2172


ekil 4. fr-Fr kltr iin dil bilgilerinin Resource dosyasna girilmesi.

Sonu olarak, projemizde aadaki Resource dosyalarnn oluturulmas gerekmektedir. Bu sayede,


uygulamamz dnyann neresinde olursa olsun, kaynak dosyalarda belirtilen dillere ve kltrlere
destek verebilecektir. Elbette, her resx dosyasnda name alanlarna yazlan Trke kelimelerin dier
dildeki karlklar value alanna girilecektir.

ekil 5. Resx dosyalarmz.

imdi uygulama kodlarmz yazmaya balayalm. Uygulamamz iin, yerelletirme sz konusu


olduundan, System.Globalization isim alann ve proses iin kltrel zellikleri ve dil zelliklerini
belirleyeceimizden System.Threading isim alanlarn ilk olarak eklemeliyiz. Bunlarn yannda,
assembly iindeki Resource dosyalarn ynetebilmemiz iin, ResourceManager snfndan bir
nesneye ihtiyacmz olacaktr. Bu nesne iinde, System.Resources isim alann uygulamamza
eklemeliyiz. te kodlarmz,

private void Doldur()


{
this.textBox1.Text=DateTime.Today.ToLongDateString();
this.textBox2.Text=DateTime.Now.ToLongTimeString();
double sayi=121345.4565;
this.textBox3.Text=sayi.ToString();
}
private void Form1_Load(object sender, System.EventArgs e)
{
Doldur();
}

www.bsenyurt.com Page 2173


private void button1_Click(object sender, System.EventArgs e)
{
if(comboBox1.SelectedItem.ToString()=="USA")
{
Thread.CurrentThread.CurrentUICulture=new CultureInfo("en-US");
Thread.CurrentThread.CurrentCulture=new CultureInfo("en-US");
}
else if(comboBox1.SelectedItem.ToString()=="Trkiye")
{
Thread.CurrentThread.CurrentUICulture=new CultureInfo("tr-TR");
Thread.CurrentThread.CurrentCulture=new CultureInfo("tr-TR");
}
else if(comboBox1.SelectedItem.ToString()=="Franais")
{
Thread.CurrentThread.CurrentUICulture=new CultureInfo("fr-FR");
Thread.CurrentThread.CurrentCulture=new CultureInfo("fr-FR");
}
else if(comboBox1.SelectedItem.ToString()=="Deutschland")
{
Thread.CurrentThread.CurrentUICulture=new CultureInfo("de-DE");
Thread.CurrentThread.CurrentCulture=new CultureInfo("de-DE");
}

ResourceManager resM=new
ResourceManager("Languages.Resource1",Type.GetType("Languages.Form1").Assembly);
this.Text=resM.GetString("Trke Dil");
this.lblDil.Text=resM.GetString("Dil");
this.lblParasal.Text=resM.GetString("Parasal");
this.lblSaat.Text=resM.GetString("Saat");
this.lblTarih.Text=resM.GetString("Tarih");
this.button1.Text=resM.GetString("Gster");
Doldur();
}

Kullanc comboBox1 kontrolnden bir dil setiinde, ncelikle uygulamann arayznn hangi dili
kullanaca CurrentUICulture zellii ile belirlenmektedir. te bu noktada, resource dosyalarmz
isimlendirilirken neden kltr kodlarnn kullanld dahada belirginlemektedir. Nitekim, bu zellik,
CultureInfo trnden bir nesne alr. Bu nesne belirli bir kltr iin oluturulmaktadr. Bu kltrn
kodu, uygulama tarafndan Resource dosyalarnn isimlerinde aranr. Yani kullanc USA' i
setiinde, uygulama arayz iin en-US kltr kodu belirlenir. Dolaysyla, ResourceManager
nesnesi, bu kltr kodunu ieren Resource dosyasn kullanmaya balayacaktr.

If koullarnda, sonraki hamlede, gncel proses' deki saysal,tarihsel vb... formatlar iin gerekli
kltr kodu, CurrentCulture zelliine, ilgili kltr iin bir CultureInfo nesnesi atanarak
gerekletirilir. Bizim iin nemli olan bir dier noktada, ResourceManager nesnesinin oluturulu
eklidir.

ResourceManager resM=new

www.bsenyurt.com Page 2174


ResourceManager("Languages.Resource1",Type.GetType("Languages.Form1").Assembly);

Burada ilk parametre, Resource dosyalarnn ana adn iaret etmektedir. Ana admz rnein
Resource1.tr-TR.resx dosyasnn baz aldmzda, belirleyici kltr koduna kadar olan ksmdaki
dosya addr. kinci parametre ise, Reflection zelliklerini kullanr ve gncel assembly' n tipini alr.
Artk elimizde, resource' lar ynetebileceimiz bir nesne vardr. Tek yapmamz gereken, uygulama
arayzndeki text' lere, ResourceManager nesnesinin GetString metodu ile, name (key) alanlarnn
karl olan deerlerin (value) atanmasdr. Bunun iin, ResourceManager snfnn GetString
metodunu kullandk.

imdi akla u soru gelebilir. ResourceManager hangi resx dosyasn, dolaysyla hangi dili
kullanacan nereden bilecek. te bunu salayan, az nce bahsettiimiz CurrentThread snfnn
CurrentUICulture zelliidir. Bu zellie atadmz belirleyici kod burada devreye girerek,
ResourceManager' a hangi resx dosyasn kullanmas gerektiini sylemektedir. Bu aklamalardan
sonra dilerseniz, uygulamamz derleyip altralm. Her hangibir dili setiimizde, hem formatlarn
hemde arayzdeki metinlerin ilgili dile gre deitiini grrz. te arayzdeki metinlerin seilen
dildeki karlklar, oluturduumuz resx dosyalarndan, ResourceManager snfnn GetString
metodu ile alnmaktadr.

ekil 6. Almanca.

ekil 7. ngilizce.

www.bsenyurt.com Page 2175


ekil 8. Franszca

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

rnek uygulama iin tklayn

Burak Selim ENYURT

selim@bsenyurt.com

Localization (Yerelletirme) - 1 ( 05.08.2004 ) -


C#
Deerli Okurlarm, Merhabalar.

Dnya apnda yada baka bir deyile global apta uygulamalar gelitirilirken karlalabilecek
zorluklardan birisi, uygulamann farkl kltr ve dil seeneklerine gre alabilecek ekilde
tasarlanmasdr. Eski programlama dilleri gz nne alndnda, zellikle farkl dil destei
salayacak uygulamalarn gelitirilmesi tam anlamyla bir kabus olmutur. Sz gelimi 2 dile destek
verecek bir uygulama gelitirilmek istendiinde, her iki dil iinde farkl uygulama kodlar yazlmas
gerekirdi. Byle bir durumda, uygulamann piyasaya srlmesinden sonra yaplacak gncelleme
paketleri iinde ayn durum sz konusuydu. Dahas, 3nc bir dilin desteinin salanmas iin, ayn
projenin bu kezde bu dil iin gelitirilmesi gerekmekteydi. Dil eitliliinin yan sra, ayn dili
konuan fakat farkl takvimler, farkl parasal formatlar, farkl saysal formatlar hatta farkl
sralamalar kullanan kltrler iin iine sokulduunda durum tam anlamyla bir paradoks haline
gelmektedir.

Peki Microsoft .Net ile bu soruna nasl bir zm getirmektedir? te bu gnk makalemizin konusu
budur. Microsoft .Net platformu iinde gelitirdiimiz zmlerin (solutions), eitli dillere veya
kltrlere destek verebilmesini salamak amacyla, ncekilerine nazaran ok daha mantkl ve
verimli bir teknik uygulanr. Bu teknikte, uygulama kodu bir kez yazlr. Bu uygulamann dil destei
ve kltr destei vermesi iin ise, framework iinde yer alan System.Globalization isim alanndaki
snflardan ve resource files dediimiz kaynak dosyalarndan yararlanlr. Bir baka deyile, bir
uygulamann yerelletirilmesi yani dil destei ve kltrel destein salamas iin, uygulama kodlar
ile destek birimleri birbirinden ayr tutulmutur. Bylece, bir uygulamay n sayda kltr iin
yerelletirmek mmkn olmaktadr.

www.bsenyurt.com Page 2176


Bu teorik bilgiler ilk okunduunda akla karmak gelebilir. Olay daha iyi anlayabilmek iin,
yeryznde yer alan toplumlarn birbirlerinden farkllamasna neden olan kltrel zellikleri
kefetmek gerekmektedir. Dnyamz konuulan ana dillere gre eitli blgelere ayrlmtr. Bu
diller, bir toplumun doal kltrn (Neutral Culture) temsil eder. Yada baka bir deyile doal
kltrler dillere gre kategorize edilir. rnein ngilizce, Almanca, Franszca, talyanca dilleri doal
kltrleri (Neutral Cultures) yanstmaktadr. Bununla birlikte, eitli dillere destek verecek evirisel
uygulamalarda, doal kltrlerin bilinmesi yeterli iken, parasal ilemlerin, saysal ilemlerin,
tarihsel ilemlerin, sralamalarn vb... yer ald daha belirleyici yerelletirme ilemlerinde, dile bal
doal kltr bilgileri yeterli deildir. rnein, ngilizce konuan pek ok alt kltr vardr. ngiltere,
Amerika, Kanada, Avusturalya vb... Bu lkelerin her biri ngilizce konumakla birlikte, farkl kltr
zelliklerine sahip olabilirler. rnein kullandklar para birimi farkll, zip kodlarn farkll, saysal
ifadelerdeki nokta ve virgl kullanmlarnn farkllklar vb... Dolaysyla bir uygulamay, belirli bir
kltr iin zelletirecek isek, Specific Culture denilen alt kltr bilgilerinden yararlanmamz
gerekmektedir.

Tabiki kltr bilgilerinin belirli bir standart erevesinde ifade edilmesi ve kresel apta kabul
grmesi olduka nemlidir. Microsof bunun iin, IETF tarafndan belirlenmi RFC 1766 standardn
kullanr. Bu standarda gre, her doal kltr ve bu doal kltre bal alt kltrler ikier
karakterden oluan ksaltma kodlar ile ifade edilirler. Tabiki bir doal kltr birden fazla alt kltre
ve bu alt kltrlerde baka alt kltrlere sahip olabilirler. Konuyu aadaki rnek ekil daha iyi
ifade edecektir.

www.bsenyurt.com Page 2177


ekil 1. Franszca nn alt kltrleri.

rnein Fransca dili bir doal kltr olarak ele alndnda, dnya zerinde Franszca' y konuan
blgelerde bu kltrn alt kltrlerini oluturur. fr-FR Fransa'y, fr-BE Belikay fr-LU Lksemburg'
u temsil eden belirleyici kltr kodlardr. Peki uygulamalarmzda bu kltr kodlarn nasl
kullanabiliriz? Bunun iin System.Globalization isim alanndaki CultureInfo ve RegionInfo snflarn
kullanabiliriz. CultureInfo snf yardmyla belilri bir kltre ait bilgilere sahip oluruz. RegionInfo
snf ilede, belirli bir blgeye ait bilgilere ularz. rnein para birimi ve metrik sistemin kullanlp
kullanlmad gibi bilgiler RegionInfo snfn ilgilendirirken, takvim bilgisi, doal ad gibi bilgilerde
CultureInfo snfn ilgilendirir. in zel yan, bir uygulamann kullanc arayzndeki yerel kriterleri
deitirmek istediimizde, uygulamann alt thread nesnesine ait metodlar kullanamamzn
yeterli olacadr. Tabiki burada bahsi geen proses, belirtilen bir kltr bilgisine yani CultureInfo
nesnesine gre ayarland takdirde, programn yerelletirilmesi gerekletirilmi olacaktr.

imdi bu bahsettiklerimizi daha iyi anlayabileceimiz basit bir uygulama gelitirmeye allm. Bu
uygulamamzda, kabul gren standartlar iindeki tm kltrlere ait kodlar listeleyeceimiz bir
treeView kontrol kullacaz. Her hangibir kltr seildiinde bu kltre ait bilgiler ekrandaki
kontrollere dolacak. Ayrca, tarih, saat ve parasal bilgi veren textBox' larmzda rnek deerler
tutacak ve bu bilgilerin seilen kltrn belirttii zelliklere gre gsterilmesi salanacak. ncelikle
Vs.Net iinde aadaki forma grntsne sahip olan bir windows uygulamas oluturalm.

ekil 2. Form tasarmmz.

Gelelim uygulama kodlarmza. Her eyden nce System.Globalization isim alann uygulamamza
using anahtar kelimesi ile eklemeliyiz. Nitekim kullacanamz CultureInfo ve RegionInfo snflar bu
isim alan iinde yer almaktadr. Kulturler balkl butona bastmzda, Microsoft' un kulland

www.bsenyurt.com Page 2178


standart iindeki tm kltr kodlarnn listesini almak ve bunlar treeView kontrolnde aa yaps
eklinde hiyerarik bir dzende gstermek istiyoruz. te Kulturler balkl butona ait kodlarmz.

private void btnKulturler_Click(object sender, System.EventArgs e)


{
CultureInfo[] kulturDizi=CultureInfo.GetCultures(CultureTypes.AllCultures);

TreeNode[] nodes=new TreeNode[kulturDizi.Length];

int i=0;
TreeNode parent=null;

foreach(CultureInfo kulturBilgi in kulturDizi)


{
nodes[i]=new TreeNode();
nodes[i].Text=kulturBilgi.DisplayName;
nodes[i].Tag=kulturBilgi;

if(kulturBilgi.IsNeutralCulture)
{
parent=nodes[i];
treeView1.Nodes.Add(nodes[i]);
}
else if(kulturBilgi.ThreeLetterISOLanguageName==CultureInfo.InvariantCulture.
ThreeLetterISOLanguageName)
{
treeView1.Nodes.Add(nodes[i]);
}
else
{
parent.Nodes.Add(nodes[i]);
}
}
}

ncelike, var olan kltrleri elde etmek iin CultureInfo snfna ait GetCultures metodunu
kullandk. Bu metoda parametre olarak, CultureTypes.AllCultures deerini verdik. Metodumuz bu
parametre deeri dnda aadaki deerleride alabilmektedir.

CultureTypes Aklama
Numaralandrc Deeri

AllCultures Tm kltrleri listeler.

InstalledWin32Cultures Windows sistemlerinde kullanlan kltrleri


listeler.

NeutralCultures Sadece dille ilikilendirilmi doal kltrleri

www.bsenyurt.com Page 2179


listeler.

SpecificCultures Belirleyici kltrleri listeler.

Bundan sonraki kod satlarnda treeView kontrolmz doldurmak iin gerekli ilemler yaplmtr.
Dikkat etmemiz gereken noktalar, foreach dngs iindeki if koullardr. Buradaki ilk koulda
CultureInfo nesnesinin doal bir kltr olup olmadna baklr. Dier koulda ise kltrn invariant
culture olup olmad koulu deerlendirilir. Invariant kultrler, gerek kltrlerden bamsz olan
yaplardr. imdi uygulamamzn dier kodlarn oluturalm.

private void Temizle()


{
for(int i=0;i<this.Controls.Count;i++)
{
if(this.Controls[i] is TextBox)
{
this.Controls[i].Text="";
}
}
}
private void treeView1_AfterSelect(object sender, System.Windows.Forms.TreeViewEventArgs e)
{

Temizle();
CultureInfo guncelKultur=(CultureInfo)treeView1.SelectedNode.Tag;
txtName.Text=guncelKultur.Name;
txtNativeName.Text=guncelKultur.NativeName;
txtEnglishName.Text=guncelKultur.EnglishName;

if(!guncelKultur.IsNeutralCulture)
{
RegionInfo bolgeBilgisi=new RegionInfo(guncelKultur.LCID);
txtCurrency.Text=bolgeBilgisi.CurrencySymbol;
txtRegion.Text=bolgeBilgisi.DisplayName;
txtMetric.Text=bolgeBilgisi.IsMetric.ToString();

Thread.CurrentThread.CurrentCulture=guncelKultur;
double sayi=4587512.451;
txtNumber.Text=sayi.ToString("N");

txtDate.Text=DateTime.Today.ToString("D");

txtTime.Text=DateTime.Now.ToString("T");
}
}

TreeView kontrolnde her hangibir e seildiinde bu eye ait bilgiler, textBox kontrollerine
doldurulur. Eer seilen e doal bir kltr deilse, yani belirleyici kltr ise, bu kltrn

www.bsenyurt.com Page 2180


bulunduu lke veya blgeye ait bilgilere ulamak iin RegionInfo snfna ait bir nesne kullanlr. Bu
nesnenin berlileyici bir kltre ait olarak oluturulmas srasnda, belirleyici kltr temsil eden bir
deer kullanlr. Bu deer, CultureInfo snfnn LCID zellii ile elde edilen benzersiz bir
belirleyicidir. RegionInfo nesnesi yardmyla, belirleyici kltrn bulunduu blgeye has para birimi,
bu blgede metrik sistemin kullanlp kullanlmadna dair belirleyici bilgiler elde edilir. Gelelim iin
en nemli ksmna. Yani uygulamann seilen kltre gre yerelletirildii (Localization) ksma.

Thread.CurrentThread.CurrentCulture=guncelKultur;

Bu kod satr ile, alan proses iin kltr deeri, seilen kltre gre ayarlanmtr. Dolaysyla bu
kod satrn izleyen satrlardaki saysal deer, tarih ve zaman formatlar, seilen kltre gre ekrana
gelecektir. te uygulamamz basit bir ekilde yerelletirme ilemini gerekletirmitir. imdi
uygulamamz altralm ve sonular gzlemleyelim. Program ilk altrdmzda ve Kulturler
balkl butona tkladmzda aadaki ekran grntsn elde ederiz.

ekil 3. Tm Kltrler.

rnein German doal kltrn seelim. Bu durumda Almanca dilini konuan alt kltrler
grnecek ve Almanca doal kltrne ait kltr kodu, doal ad ve ingilizce ad bilgileri elde
edilecektir.

www.bsenyurt.com Page 2181


ekil 4. Almacan (German) Doal Kltr.

imdi belirleyici kltrlerden birini seelim. rnein Avusturya alt kltrn. Bu durumda bu
kltre ait yerel bilgiler ekrana gelecek ve uygulama bu noktadan sonra, Avusturya' ya ait yerel
bilgilere gre saylar formatlayacak, tarihleri gsterecek vb... ilemleri gerekletirecektir.

ekil 5. Avusturya Kltrne ait zellikler.

imdi daha u bir rnek gsterelim. rnein uygulamamzn Suudi Arabistan kltrne gre
yerelletirilmek istendiini farzedelim. Bu durumda ilk akla gelen arap takviminin farklldr.

www.bsenyurt.com Page 2182


ekil 6. Arabistanda durum dahada kark.

Bylece bir uygulamann, belirli bir kltre gre yerelletirilmesini grm olduk. Dier taraftan,
uygulamamzn farkl dillere gre destek vermesinide isteyebiliriz. te bu noktada devreye
Resource Files (Kaynak Dosyalar) girmektedir. Bu konuyu ise bir sonraki makalemizde incelemeye
alacaz. Hepinize mutlu gnler dilerim.

rnek uygulama iin tklayn

Burak Selim ENYURT

selim@bsenyurt.com

Identity Deerlerinin alma Zamannda Elde


Edilmesi ( 29.07.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, veritabanlarnda otomatik olarak artan identity alanlarnn deerlerinin, alma


zamannda uygulama ortamlarna nasl yanstlabileceini incelemeye alacaz. ounlukla,
tablolarmzda yer alan satrlarn birbirlerinden kolayca ayrt edilebilmelerini salamak iin, primary
key alanlarn kullanrz. Genellikle bu alanlar otomatik olarak artan saysal deerler zerinde
yaplandrrz. rnek olarak aadaki tabloyu gz nne aldmzda, PersonelID alannn 1 saysal
deerinden balayarak 1'er artan ve primary key zelliine sahip olduunu grrz.

www.bsenyurt.com Page 2183


ekil 1. PersonelID alannn zellikleri

Bu alann deeri, tablonun bulunduu sql sunucusu tarafndan otomatik olarak arttrlmaktadr.
Buraya kadar her ey zaten bildiimiz olaylardr. Sorun, bir uygulamada bu tabloya yeni bir alan
eklendiinde, o an veritaban tarafndan otomatik olarak arttrlan alann deerinin ortama
yanstlmasnda ortaya kmaktadr. Nitekim bu alann yeni oluan deerini elde etmek iin, ilgili
satrn uygulama ortamna yeniden ekilmesi gerekmektedir. Bu ise zellikle tabloya ait tm
satrlarn ekildii durumlarda gereksiz zaman kaybnn yaanmasna neden olmaktadr. Oysaki
uygulayacamz basit kodlamalar ile, yeni eklenen satrlara ait otomatik artan deerleri uygulama
ortamna, minimum eforu sarfederek kolaylkla alabiliriz. Sorunu daha iyi anlayabilmek amacyla
basit bir windows uygulamas gelitirelim. Form grntmz aadakine benzer olmaldr.

ekil 2. Uygulama Formumuz.

www.bsenyurt.com Page 2184


Uygulamamz basit olarak, Sql sunucusunda yer alan Northwind veritabanndaki Personel tablosuna
ait verileri ekmekte ve yeni satrlar eklenmesine izin vermektedir. Uygulamamza ait ilk kodlar ise
aadaki gibidir.

SqlConnection con;
SqlDataAdapter da;
DataTable dt;

private void btnVeriCek_Click(object sender, System.EventArgs e)


{
con=new SqlConnection("data source=localhost;initial catalog=Northwind;integrated
security=SSPI");
da=new SqlDataAdapter("SELECT * FROM PERSONEL",con);
dt=new DataTable("Personel");
da.Fill(dt);
dataGrid1.DataSource=dt;
}

private void btnEkle_Click(object sender, System.EventArgs e)


{
DataRow dr;
dr=dt.NewRow();
dr[1]=txtPersonelAd.Text;
dr[2]=txtPersonelSoyad.Text;
dr[3]=txtSaatUcreti.Text;
dr[4]=txtCalismaSuresi.Text;
dt.Rows.Add(dr);

SqlCommandBuilder cmb=new SqlCommandBuilder(da);


da.Update(dt);
}

imdi uygulamamz altralm, Veri ek balkl butona basalm ve dataGrid kontrolmzn


Personel verileri ile dolduunu grelim. Yeni bir personel kayd girdiimizde ve bu bilgileri Ekle
butonuna basarak veritabanna gnderdiimizde ekran grntmzn aadaki gibi olutuunu
farkederiz.

www.bsenyurt.com Page 2185


ekil 3. Yeni satr eklenii ve Identity alannn deeri.

Dikkat edilecek olursa, yeni satrmz balantsz katman nesnemiz olan DataTable' n Rows
koleksiyonuna ve ayrca sql sunucusu zerindeki Personel tablosuna baarl bir ekilde eklenmitir.
Sorun udurki, Veri ek butonuna basmadmz ve Personel tablosuna ait verileri DataTable
nesnesine tekrardan doldurmadmz srece, PersonelID alannn veritaban tarafndan otomatik
olarak atanan deerini gremeyiz. Oysaki byle bir deer, gerek bazl bir projede baka bir ilem
iin veri olarak kullanlmak istenebilir. rnein, bir call center' daki operatr, mterisi iin yeni
at bir dosyaya ait Identity deerini, dosya referans numaras olarak vermek durumunda olabilir.
Kaldki, eklediimiz satr iin geerli olan Identity deeri otomatik olarak oluturulmutur. Ancak
balantsz katman nesnesinin henz bundan haberi yoktur. Bu noktada program sonlandrmadan
Vs.Net ortamnda, Personel tablosu bilgilerine bakldnda, sql sorgusunu yeniden execute edersek
Identity deerinin oluturulmu olduunu gzlemleriz.

ekil 4. Identity deeri.

te makalemize konu olan sorun bu alann deerinin, satr veritabanna eklendii zaman nasl
uygulama ortamna alnacadr. ki alternatif zm yolumuz vardr. Bunlardan birincisi,
SqlDataAdapter snfnn RowUpdated olaynn kullanlmasdr. Dier alternatif yol ise, yeni identity
deerini uygulama ortamna ekebileceimiz bir Stored Procedure yardmyla, satr ekleme

www.bsenyurt.com Page 2186


ileminin yaplmasdr. Hangi yolu seersek seelim ikiside ortak bir anahtar szc
kullanmaktadr. Bu anahtar szck sql' e ait olan @@IDENTITY 'dir. Bu anahtar sck, eklenen
satra ait, veritaban tarafndan otomatik olarak retilen identity deerini temsil etmektedir. lk
olarak RowUpdated olay ile bu iin nasl salanacana bakalm. Tek yapmamz gereken
SqlDataAdapter nesnemize, RowUpdated olayn eklemek ve bu olay metodunu kodlamaktr.

private void btnVeriCek_Click(object sender, System.EventArgs e)


{
.
.
.
da.RowUpdated+=new SqlRowUpdatedEventHandler(da_RowUpdated);
}

private void btnEkle_Click(object sender, System.EventArgs e)


{
.
.
.
}

private void da_RowUpdated(object sender, SqlRowUpdatedEventArgs e)


{
SqlCommand cmd=new SqlCommand("SELECT @@IDENTITY",con);
if((e.Status==UpdateStatus.Continue) && (e.StatementType==StatementType.Insert))
{
e.Row["PersonelID"]=cmd.ExecuteScalar();
e.Row.AcceptChanges();
}
}

Burada RowUpdated metodunda, veritabanna yeni bir satr eklendiinde, @@IDENTITY deerini
alacak sorguyu altran bir SqlCommand nesnesi kullanlmaktadr. Bylece, balantsz katmana
ait yeni eklenen satrn ilgili alanna ( yani PersonelID alanna ), sorgunun sonucunu alabiliriz.
Uygulamamz bu haliyle altrdmzda ve yeni bir satr eklediimizde, PersonelID alan iin
veritaban tarafndan retilen otomatik deerinde, uygulama ortamna alndn gzlemleriz.

www.bsenyurt.com Page 2187


ekil 5. Identity deerinin elde edilmesi.

Gelelim ikinci yola. kinci yolumuz ise, ekleme ileminin bir Stored Procedure yardmyla
yaplmasdr. Bu Stored Procedure, ekleme ilemini yaparken, @@IDENTITY deerinide ortama bir
Output parametresi vastasyla gnderecektir. Bu amala Personel tablomuz iin aadaki Stored
Procedure' oluturalm.

ALTER PROCEDURE dbo.PersonelEkle


(
@PersonelID int OUTPUT,
@PersonelAd varchar(50),
@PersonelSoyad varchar(50),
@SaatUcreti decimal,
@CalismaSuresi decimal
)
AS
INSERT INTO Personel (PersonelAd,PersonelSoyad,SaatUcreti,CalismaSuresi) VALUES
(@PersonelAd,@PersonelSoyad,@SaatUcreti,@CalismaSuresi)

SELECT @PersonelID=@@IDENTITY

RETURN

Bu Stored Procedure' de en nemli nokta Select sorgusunda @@IDENTITY deerinin, bir Output
parametresine aktarlm olmasdr. Bu sayede, SP' yi altrdmzda, veri taban tarafndan
oluturulan otomatik deeri, uygulama ortammzda elde edebiliriz. Tek yapmamz gereken
aadaki kodlar yazmaktr.

private void btnSPileEkle_Click(object sender, System.EventArgs e)


{

www.bsenyurt.com Page 2188


SqlCommand cmd=new SqlCommand("dbo.PersonelEkle",con);
cmd.CommandType=CommandType.StoredProcedure;

cmd.Parameters.Add("@PersonelID",SqlDbType.Int);
cmd.Parameters.Add("@PersonelAd",SqlDbType.VarChar,50);
cmd.Parameters.Add("@PersonelSoyad",SqlDbType.VarChar,50);
cmd.Parameters.Add("@SaatUcreti",SqlDbType.Decimal);
cmd.Parameters.Add("@CalismaSuresi",SqlDbType.Decimal);

cmd.Parameters["@PersonelID"].Direction=ParameterDirection.Output;

cmd.Parameters["@PersonelAd"].Value=txtPersonelAd.Text.ToString();
cmd.Parameters["@PersonelSoyad"].Value=txtPersonelSoyad.Text.ToString();
cmd.Parameters["@SaatUcreti"].Value=Convert.ToDecimal(txtSaatUcreti.Text);
cmd.Parameters["@CalismaSuresi"].Value=Convert.ToDecimal(txtCalismaSuresi.Text);

con.Open();
cmd.ExecuteNonQuery();

/* Yeni satr DataTable' mzada ekliyoruz.*/


DataRow dr;
dr=dt.NewRow();
dr[0]=cmd.Parameters["@PersonelID"].Value; /* Veritabannda henz oluturulan otomatik
deeri alp, satrn PersonelID alanna aktaryoruz.*/
dr[1]=txtPersonelAd.Text;
dr[2]=txtPersonelSoyad.Text;
dr[3]=txtSaatUcreti.Text;
dr[4]=txtCalismaSuresi.Text;
dt.Rows.Add(dr);
dt.AcceptChanges();
}

Uygulamamz bu haliyle altrdmzda yeni ekelenen satr iin, veritaban tarafndan otomatik
olarak arttrlan identity deerinin kolayca elde edilebildiini grrz.

www.bsenyurt.com Page 2189


ekil 6. SP ile Identity deerinin elde edilmesi.

Gelelim bu iki seenekten hangisinin tercih edileceine. Microsoft' un bu konuda yapt testlere
gre, Stored Procedure yardmyla Identity deerlerinin elde edilmesi, RowUpdated olaynn
kullanld teknie nazaran daha performansl ve verimli. Dolaysyla SP kullanmn tercih etmek
daha doru bir seenek gibi gzkmektedir. Bir baka konu ise, Access tipi tablolar iin ayn
senaryonun nasl ileyeceidir. Access tipi tablolarda, Output parametresi desteklenmediinden, SP
kullanm ile identity deerinin elde edilmesi gereklemeyecektir. Bu nedenle tek seenek,
RowUpdated olaynda @@IDENTITY deerinin elde edilmesidir. Bylece geldik bir makalemizin
daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinizde mutlu gnler dilerim.

rnek uygulama iin tklayn

Burak Selim ENYURT

selim@bsenyurt.com

CurrencyManager ile Navigasyon ve Temel Satr


lemleri ( 27.07.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, CurrencyManager snf yardmyla, balantsz katman nesnelerinin iaret ettii


bellek blgelerindeki veri satrlar arasnda navigasyon, satr ekleme, satr silme ve satr
gncelleme ilemlerinin nasl gerekletirildiini incelemeye alacaz.

Genellikle bir veritaban uygulamasn gz nne aldmzda, var olan satrlar arasnda ileri ve geri
ynl hareketler sklkla kullanlan ilemler arasnda yer almaktadr. Bir windows uygulamasnda,
balantsz katman nesnelerinin sahip olduu veri kmelerini, form zerinde yer alan eitli
kontroller yardmyla kullancya sunarz. Ancak zaman zaman, bu veri kmesi iinde hareket
ederken, veriye bal kontrollerinde gncel satra ait alan bilgilerini gstermesini isteriz. Form

www.bsenyurt.com Page 2190


zerine yerletirilen kontrollerin her biri, bu eit navigasyon ilemlerine izin veren
CurrencyManager isimli nesne rneklerine sahiptir. Dolaysyla navigasyon ilemlerinin bal
kontrollere yansmas iin, bal kontrollere ait CurrencyManager nesnelerinin ilgili zelliklerinin
kullanlmas yeterlidir.

Bir windows uygulamasn dndmzde, Form zerinde yer alan bal kontrollerinin tmnn
ayn navigasyon hareketlerine izin vermesini istememiz son derece doaldr. Bu zaten arzu edilen
durumdur. Windows Form' larnn BindingContext zellii sayesinde, bal kontrollerin sahip olduu
CurrencyManager nesne rneklerini ynetebiliriz. Bu ynetim imkan, satrlar arasnda navigasyon,
yeni kayt ekleme, silme veya gncelletirme gibi ilemleri yapabilme imkanna sahip olmamz
salamaktadr. Konuyu ok yzeysel olarak anlattmz bu ksa aklamalardan sonra, olay daha
iyi ve net bir ekilde simle edebilmek amacyla aadaki Form grntsne sahip Windows
Uygulamasn tasarlayarak ilemlerimize balayalm.

ekil 1. Form tasarmmz.

Bu windows uygulamasnda, Sql sunucusunda yer alan Northwind veritabannda yer alan Personel
tablosuna ait veriler gsterilecektir. Balang olarak, uygulama kodlarmz aadaki gibidir.

SqlConnection con;
SqlDataAdapter da;
DataTable dt;

private void Bagla()


{
lblPersonelID.DataBindings.Add("Text",dt,"PersonelID");
txtPersonelAd.DataBindings.Add("Text",dt,"PersonelAd");
txtPersonelSoyad.DataBindings.Add("Text",dt,"PersonelSoyad");
txtSaatUcreti.DataBindings.Add("Text",dt,"SaatUcreti");
txtCalismaSuresi.DataBindings.Add("Text",dt,"CalismaSuresi");
}

private void Form1_Load(object sender, System.EventArgs e)


{
con=new SqlConnection("data source=localhost;initial catalog=Northwind;integrated
security=SSPI");

www.bsenyurt.com Page 2191


da=new SqlDataAdapter("SELECT * FROM PERSONEL",con);
dt=new DataTable("Personel");
da.Fill(dt);
Bagla();
}

Uygulama kodlarmza ksaca baktmzda, Sql sunucusuna balanarak Northwind veritabanndaki


Personel tablosuna ait tm satrlar, bir DataTable' a aktardmz ve Form zerindeki kontrolleride
bu veri kaynana baladmz grrz. Kontrollerimizi, tablonun ilgili alanlarna balarken
DataBindings zelliinin Add metodundan yararlanmaktayz.

Add metodu ilk parametre olarak, veri kaynandaki ilgili verinin, kontroln hangi zelliine
balanacan belirtir. kinci parametrede bu ilk parametredeki zellik iin hangi veri kaynann
kullanlaca belirtilir. Son olarak nc parametrede ise, ilk parametrede belirtilen kontrol
zelliine, ikinci parametredeki veri kaynann hangi alannn balanaca belirlenir. Bylece,
DataTable nesnemizin bellekte iaret ettii blgedeki satrlara ait alanlar, Form zerindeki
kontrollere balanm olacaktr. Uygulamamz bu haliyle derleyip altrdmzda, veri
kmesindeki ilk satra ait bilgilerin Form zerindeki kontrollere eklendiini grrz.

ekil 2. Uygulamann almas.

imdi ilk yapmak istediimiz, veri kmesindeki satrlar arasnda hareket edebilme imakanna sahip
olmaktr. u aamda 4 temel hareketimiz olabilir. Sonraki satra gei, nceki satra gei, son
satra gei ve ilk satra gei. Bu ilemleri gerekletirebilmek iin, Form' umuza ait
BindingContext zelliini kullanacaz. imdi formumuza 4 adet button kontrol ekleyelim ve
uygulama kodlarmz aadaki ekilde gelitirelim.

SqlConnection con;
SqlDataAdapter da;
DataTable dt;
CurrencyManager cm;

private void Bagla()


{
lblPersonelID.DataBindings.Add("Text",dt,"PersonelID");

www.bsenyurt.com Page 2192


txtPersonelAd.DataBindings.Add("Text",dt,"PersonelAd");
txtPersonelSoyad.DataBindings.Add("Text",dt,"PersonelSoyad");
txtSaatUcreti.DataBindings.Add("Text",dt,"SaatUcreti");
txtCalismaSuresi.DataBindings.Add("Text",dt,"CalismaSuresi");
}

private void Form1_Load(object sender, System.EventArgs e)


{
con=new SqlConnection("data source=localhost;initial catalog=Northwind;integrated
security=SSPI");
da=new SqlDataAdapter("SELECT * FROM PERSONEL",con);
dt=new DataTable("Personel");
da.Fill(dt);
Bagla();
cm=(CurrencyManager)this.BindingContext[dt];
lblPozisyon.Text="Guncel Pozisyon ------> "+Convert.ToString(cm.Position+1);
}

private void btnIlkSatiraGotur_Click(object sender, System.EventArgs e)


{
cm.Position=0;
lblPozisyon.Text="Guncel Pozisyon ------> "+Convert.ToString(cm.Position+1);
}

private void btnOncekiSatiraGotur_Click(object sender, System.EventArgs e)


{
cm.Position--;
lblPozisyon.Text="Guncel Pozisyon ------> "+Convert.ToString(cm.Position+1);
}

private void btnSonrakiSatiraGotur_Click(object sender, System.EventArgs e)


{
cm.Position++;
lblPozisyon.Text="Guncel Pozisyon ------> "+Convert.ToString(cm.Position+1);
}

private void btnSonSatiraGotur_Click(object sender, System.EventArgs e)


{
cm.Position=dt.Rows.Count-1;
lblPozisyon.Text="Guncel Pozisyon ------> "+Convert.ToString(cm.Position+1);
}

Uygulama kodlarmzda en nemli nokta, Form zerindeki kontrollerin sahip olduklar


CurrencyManager nesnelerini elde edebilmek iin, Form' a ait BindingContext zelliinden
yararlanmamzdr.

cm=(CurrencyManager)this.BindingContext[dt];

www.bsenyurt.com Page 2193


Bu satr ile, DataTable veri kaynana iin bir CurrencyManager nesnesi oluturulur. Artk
navigasyon ilemi iin tek yapmamz gereken, CurrencyManager snfna ait Position zelliinin
kullanlmasdr. Bu zelliin deimesi durumunda, Form zerinde yer alan ve DataTable' a ait veri
kaynana bal olan tm kontrollerin ierii gncel satra ait verileri gsterecek ekilde
deiecektir. rnein, bir satr ileri gitmek iin Position zelliinin deerini 1 arttrmamz yeterli
olurken, son satra gitmek iin, veri kaynann sahip olduu toplam satr saysn 1 eksiltiriz.

cm.Position++;
.
.
.
cm.Position=dt.Rows.Count-1;

Uygulamamz altrdmzda, satrlar arasnda istediimiz ekilde gezebildiimizi grrz.

ekil 3. Navigasyon.

CurrencyManager snf yardmyla yapabileceklerimiz sadece Navigasyon ilemleri ile snrl deildir.
Ayrca, satr ekleme, satr silme veya satr gncelletirme gibi temel tablo ilemlerinide
gerekletirebiliriz. Yeni bir satr eklemek iin CurrencyManager snfna ait, aada prototipi
verilen AddNew metodunu kullanrz.

public override void AddNew();

Uygulamamzda yeni bir satr eklemek iin ncelikle aadaki kodlar yazalm.

private void Temizle()


{
lblPersonelID.Text="";

for(int i=0;i<this.Controls.Count;i++)
{
if(this.Controls[i] is TextBox)

www.bsenyurt.com Page 2194


{
this.Controls[i].Text="";
}
}
}

private void btnYeniSatirEkler_Click(object sender, System.EventArgs e)


{
cm.AddNew();
Temizle();
}

private void btnVeritabaninaYaz_Click(object sender, System.EventArgs e)


{
SqlCommandBuilder cmb=new SqlCommandBuilder(da);
da.Update(dt);
}

Burada, nemli olan AddNew metodunun kullanlndan sonra, alan yeni satrn o anki veri
kmesinde yerini almas iin ileri veya geri ynl bir hareket yaplmasnn yeterli olduudur.
Elbette, CurrencyManager yardmyla, gncel veri kmesine eklenen satrlarn veritabannada
yanstlabilmesi iin, SqlDataAdapter nesnemize ait Update metodunun altrlmas gerekmektedir.
Gncel satrlar zerinde deiiklik yapldnda bu deiikliklerin onaylanabilmesi ve veri kmesine
yansyabilmesi iin ya satrlar arasnda hareket edilmesi yada aada prototipi verilen
EndCurrentEdit metodunun uygulanmas gerekir.

public override void EndCurrentEdit();

Veri kmesinden herhangibir satr silmek istediimizde ise, aadaki prototipe sahip olan
RemoveAt metodunu kullanabiliriz.

public override void RemoveAt( int index);

Bu metod parametre olarak, silinecek satrn indeksini almaldr. Satr gncelleme ve silme ilemleri
iin ilgili kodlarmz ise aadaki gibidir.

private void btnDegisiklikleriKaydet_Click(object sender, System.EventArgs e)


{
if(MessageBox.Show("Deiiklikler kaydedilsin mi?", "Deiiklik" ,
MessageBoxButtons.OKCancel, MessageBoxIcon.Question )==DialogResult.OK)
{
cm.EndCurrentEdit();
}
else
{
cm.CancelCurrentEdit();
}

www.bsenyurt.com Page 2195


}

private void btnGuncelSatiriSil_Click(object sender, System.EventArgs e)


{
cm.RemoveAt(cm.Position);
}

Elbette yaptmz satr ekleme, gncelleme ilemlerini iptal etmek istersek, prototipi aadaki gibi
olan CancelCurrentEdit metodunu kullanabiliriz. Bu metod ile o anda yaplan yeni satr ekleme veya
gncelleme ileminin oluturduu deiiklii geri alabiliriz. Tabiki satrdaki deiiklik EndCurrentEdit
metodu ile yada navigasyon hareketi ile onaylanmadysa. Bu durum sadece satr silme ilemi iin
geerli deildir. Dolaysyla satr silindiinde, CancelCurrentEdit bu ilemi geri almaz.

public override void CancelCurrentEdit();

CurrencyManager snfnn iimize yarayacak bir ka olayda vardr. Bunlardan birisi


PositionChanged olaydr. Bu olay gncel satr pozisyonu deitiinde almaktadr.
Uygulamamzdaki pozisyon bilgisini lblPozisyon kontrolnde gstermek iin kullandmz kod
satrn bu olay iine yerletirebiliriz. Elbette ncelikle, CurrencyManager nesnemiz iin aadaki
kod satr ile, PositionChanged olayn eklememiz gerekmektedir.

cm.PositionChanged+=new EventHandler(cm_PositionChanged);
.
.
.
private void cm_PositionChanged(object sender, EventArgs e)
{
lblPozisyon.Text="Guncel Pozisyon ------> "+Convert.ToString(cm.Position+1);
}

Bu makalemiz ile, CurrencyManager snfnn temel metodlarn ve zelliklerini inceleyerek, veri


kmeleri zerinde navigasyon, ekleme, gncelleme ve silme ilemlerinin nasl yapldn
renmeye altk. Umuyorum ki faydal bilgiler verebilmiimdir. Bir sonraki makalemizde
grnceye dek hepinize mutlu gnler dilerim.

rnek uygulama iin tklayn

Burak Selim ENYURT

selim@bsenyurt.com

NET Remoting' i Kavramak - 3 ( 22.07.2004 ) -


Remoting
Deerli Okurlarm, Merhabalar.

www.bsenyurt.com Page 2196


Bu makalemizde, uzak nesneler zerindeki metodlara asenkron olarak nasl eriebileceimizi ksaca
incelemeye alacaz. Remoting ile ilgili bir nceki makalemizde, ok basit haliyle uzak nesnelerin,
istemciler tarafndan nasl kullanlabildiini incelemitik. Gelitirmi olduumuz rnekte, uzak nesne
zerindeki metoda senkron olarak erimekteydik. Yani, uzak nesnedeki metodun ileyii bitene
kadar, istemci uygulama ksa srelide olsa duraksyordu. Ancak baz zamanlarda, uzak nesneler
zerinde ileyecek olan metodlar, belirli bir sre zarfnda gerekleebilecek uzunlukta ilemlere
sahip olabilirler. Byle bir durumda istemci uygulamalar, metodlarn geri dn deerlerini
beklemek zorunda kalabilirler. Oysaki, uzak nesneye ait metodlar bir yandan alrken, dier
yandanda istemci uygulamadaki izleyen kod satrlarnn e zamanl olarak almas istenebilir.
Bunu salamak iin, uzak nesne metodlarna asenkron olarak eriilir.

Uzak nesne metodlarna asenkron olarak eriim, istemci uygulamalar iin olduka kullanldr.
Elbette baz durumlarda senkron eriim tercih edilir. yleki, uzak nesneye ait metodun sonucu veya
sonular, istemci uygulamada izleyen kod satrlarnda kullanlyor olabilir veya uzak nesne
metodunun sonucu, istemci uygulama iindeki baka metodlara parametre olarak gnderiliyor
olabilir vb... Elbette byle bir durumda, uzak nesne zerindeki metoda asenkron olarak erimek
ok mantkl deildir. Nitekim, uzak nesne metodunun sonucunun veya sonularnn etkiledii baka
ilemler sz konusudur.

Bu ksa aklamalardan sonra, asenkron eriim iin gerekli olan temel unsurlardanda ksaca
bahsedelim. Uzak nesne zerindeki metodlarn asenkron olarak arlmas, normal bir
uygulamadaki metodlarn asenkron olarak arlmasndan ok da farkl deildir. rnein aadaki
console uygulamasn ele alalm. Bu uygulamada basit olarak Hesapla isimli metoda asenkron
eriim gerekletirilmitir.

using System;
using System.Threading;

namespace istemciUygulama
{
public class Sinif
{
public double Hesapla(double a,double b)
{
Thread.Sleep(3500);
return(a*a+b*b);
}
}

public class istemci


{
private delegate double Temsilci(double d1,double d2);

public static void Main(string[] args)


{
Sinif nesne=new Sinif();
Temsilci t=new Temsilci(nesne.Hesapla);
IAsyncResult res=t.BeginInvoke(4,5,null,null);
Console.WriteLine("Uygulama alyor...");
res.AsyncWaitHandle.WaitOne();
if(res.IsCompleted)
{

www.bsenyurt.com Page 2197


double sonuc=t.EndInvoke(res);
Console.WriteLine(sonuc);
}
Console.ReadLine();
}
}
}

Bu uygulamay derleyip altrdmzda acaba tam olarak neler olmaktadr? Hesapla isimli
metodumuz double tipinden iki parametre alan ve yine double tipinden deer dndren bir yapya
sahiptir. Bu metod ierisinde, Thread snfnn sleep metodu kullanlm ve uygulama yaklak
olarak 3.5 saniye sre ile duraksatlmtr. Burada ama uzun sren bir metod ileyii
gerekletirmektir. Metoda asenkron eriimin salanabilmesi iin, bir delegate nesnesi
kullanlmaktadr. ncelikle delegate nesnemiz tanmlanr.

private delegate double Temsilci(double d1,double d2);

Delegate nesnesinin metod imzasnn, Hesapla metodu ile ayn olduuna ve tipininde, Hesapla
metodunun geri dn deeri tipi ile ayn olduuna dikkat edelim. Gelelim Main metodu ierisindeki
kodlara. ncelikle,

Temsilci t=new Temsilci(nesne.Hesapla);

satrlar ile delegate nesnemiz oluturulmaktadr. Artk t isimli temsilcimiz, nesne snfna ait
Hesapla metodunun bellekteki balang adresini temsil etmektedir. te bu admdan sonraki
ilemler nemlidir ve asenkeron eriim tekniinin uygulann iermektedir.

IAsyncResult res=t.BeginInvoke(4,5,null,null);

Satr ile, delegate nesnesi iin BeginInvoke metodu arlmaktadr. Bu metod grld gibi 4
parametre almtr. lk iki parametre, temsilcinin iaret ettii metodun kullanaca iki parametrenin
deerini belirtmektedir. Sonraki parametreler ise null olarak braklmtr. Burada olan olay udur. t
isimli temsilcinin iaret ettii metod 4 ile 5 deerlerini parametre alarak almaya balamtr.
Lakin, bir metod armndan sonra uygulamann izleyen kod satrlarn devam ettirebilmesi iin,
metodun ileyiini tamamlam olmas gerekir. Ancak burada, BeginInvoke ile Hesapla metodu
altrlm ve annda ortama IAsyncResult arayz trnden bir nesne dndrlmtr. Nitekim
BeginInvoke metodunun geri dn deeri IAsyncResult arayz tipinden bir nesne rneidir.
Dolaysyla izleyen satrlardaki kodlar iletilebilecektir. Bunun sonucu olarak ekrana "Uygulama
alyor..." ifadesi yazlr. Bu noktadan sonra uygulamada istenilen ilemler yaplabilir.

Tabiki temsilcimizin altrd metodun sonucunun bir ekilde alnmas gerekir. lk yaplacak ilem,
IAsyncResult arayznden nesne rneinin IsCompleted zelliinin deerine bakmak olacaktr. Bu
deer true ise, asenkron metodun ileyii tamamlanm demektir. Bu durumda, asenkron olarak
alan metodun geri dn deerini alabilmek iin, t temsilcisinin EndInvoke metodu, uygulama
ortamnda o anda var olan IAsyncResult arayz nesne rnei res parametresi ile arlr. Sonu
olarak, asenkron metodun almasnn sonucu rettii deer elde edilir. Tm bu ilemler iin
aadaki kod satrlar iletilmitir.

www.bsenyurt.com Page 2198


res.AsyncWaitHandle.WaitOne();
if(res.IsCompleted)
{
double sonuc=t.EndInvoke(res);
Console.WriteLine(sonuc);
}
Console.ReadLine();

Burada ilk satr ile, IAsyncResult arayz nesnesinin, alan asenkron metodun ileyiini
tamamlamasn beklemesi sylenmitir. Bu kod satrnn yazlmasnn amac udur. Asenkron
metodun altrlmaya balamasndan sonra, uygulamada izleyen kod satrlar bu rnekte olduu
gibi oktan tamamlanm ancak halen daha asenkron metodun ileyii bitmemi olabilir. Bu
durumda if dngs gereklemeyecei iin metodun geri dn deeride alnamyacaktr. Bu satr
ile, asnekron metodun ileyiinin tamamlanmas garanti altna alnm olur. Uygulamann bu ksmn
aadaki gibi daha ksa bir ekildede yazabiliriz.

double sonuc=t.EndInvoke(res);
Console.WriteLine(sonuc);
Console.ReadLine();

Burada direkt olarak EndInvoke metodu arlm ve asenkron metodun dn deeri alnmtr.
Eer bu noktada, asenkron metod halen daha tamamlanmam ise, tamamlanncaya kadar beklenir
ve uygulama bu cevap gelinceye kadar duraksar.

Burada kullandmz basit rnekteki teknik, uzak nesnelerin kullanld Remoting uygulamalar
iinde geerlidir. Yine temsilciler, IAsyncResult arayz, BeginInvoke ve EndInvoke metodlar bizim
anahtar yelerimiz olacaklardr. Remoting uygulamalarnda, uzak nesneye ait metodlarn asenkron
olarak nasl arldn incelemeden nce, getiimiz Remoting Makalesindeki UzakNesne.cs
snfmza aadaki gibi yeni bir metod ekleyelim.

public double Alan(double yaricap)


{
Thread.Sleep(1500);
return (yaricap*3.14)/2;
}

imdi UzakNesne.cs dosyamz yine aadaki komut satr ile derleyerek dll dosyamz oluturalm.

www.bsenyurt.com Page 2199


Gelitirdiimiz istemci uygulamann bulunduu klasre UzakNesne.dll dosyamz kopyalayalm ve
istemci snfmzn kodlarnda aadaki gibi yazalm. Bu rneimizde, metodumuza senkron teknii
ile erimekteyiz. Amacmz uzak nesne metoduna senkron olarak yani varsaylan yaps ile
eritiimizde, uygulamann alma eklini inceleyebilmek.

using System;
using System.Runtime.Remoting;

namespace istemciUygulama
{
public class istemci
{
public static void Main(string[] args)
{
RemotingConfiguration.Configure("istemci.config");
UzakNesne.Musteriler m=new UzakNesne.Musteriler();
double alani=m.Alan(3);
for(int i=1;i<=200;i++)
{
Console.Write(i.ToString()+" ");
}
Console.WriteLine("----");
Console.WriteLine(alani);
Console.WriteLine("Metodlarin Isleyisi Bitti");
Console.ReadLine();
}
}
}

www.bsenyurt.com Page 2200


Remoting uygulamamz bu haliyle denemek iin nce sunucu uygulamamz altralm ve
sunucuya gelecek olan istemci taleplerini dinlemeye balayalm. Daha sonra ise, istemci
uygulamamz altralm. Bu admlardan sonra aadakine benzer ekran grnts ile karlarz.

Bu ekran grntsn aklamadan anlamaya almak bizim iin yanltc olacaktr. stemci
uygulama altktan yaklak 2 saniye kadar sonra bu ekran grnts komple oluacaktr. Yani for
dngsndeki kod satrlar, uzak nesne zerindeki metodumuzun ileyii bitmeden ekrana
yazlmayacaktr. Doal olarak, uzak nesnedeki Alan metodunun istemci uygulamaya deer
dndrmesiyle birlikte, for dngsndeki ileyi de ekrana yansyacak ve tm bu ilemler konsol
penceresinde ayn zamanda gerekleecektir.

Oysaki uzak nesnemiz zerindeki Alan metodunu asenkron olarak arsaydk, ncelikle dng
iindeki kod satrlar alarak ekrana 1 den 500' e kadar olan saylar yazlacak ve bu ilemlerin
ardndan uzak nesnedeki metodun sonucu ekrana yazlacakt. Dolaysyla uzak nesnedeki Alan
metodu altrldktan sonra, istemcideki izleyen kod satrlar e zamanl olarak yrtlebilecekti.
te bunu gerekletirebilmek iin, istemci uygulamamz aadaki haliyle dzenlememiz ve uzak
nesne metoduna asenkron olarak erimemiz gerekmektedir.

using System;
using System.Runtime.Remoting;

namespace istemciUygulama
{
public class istemci
{
private delegate double Temsilci(double d);

public static void Main(string[] args)


{
RemotingConfiguration.Configure("istemci.config");
UzakNesne.Musteriler m=new UzakNesne.Musteriler();
Temsilci t=new Temsilci(m.Alan);
IAsyncResult res=t.BeginInvoke(3,null,null);
for(int i=1;i<=500;i++)

www.bsenyurt.com Page 2201


{
Console.Write(i.ToString()+" ");
}
Console.WriteLine("----");
double alani=t.EndInvoke(res);
Console.WriteLine(alani);
Console.WriteLine("Metodlarin Isleyisi Bitti");
Console.ReadLine();
}
}
}

imdi sunucuyu altrp, sonrada istemciyi altrdmzda sonu olarak yine ayn ekran
grntsn elde ettiimizi grrz. Ancak bu kez dng, asenkron metodun ileyii ile birlikte
alm ve 1' den 500' e kadar olan saylarn konsol penceresine yazlmasnn ardndan ksa bir
sre sonrada asenkron metodun sonucu ekrana yazlmtr. leyi teknii ilk bata incelediimiz
rnekteki ile ayndr. Bu kez sadece, temsilcimizi olutururken, iaret edecei metod olarak, istemci
uygulamann alt klasrdeki dll iinde bulunan uzak nesne snf rneine ait metod belirtilmitir.
Tabiki bu metodun uzak nesnedeki rneinin altrlmas, konfigurasyon dosyasndaki kanal
ayarlamalar sonucu ilgili kanal nesneleri zerinden gereklemektedir. Bylece, bir Remoting
uygulamasnda, uzak nesneler zerindeki metodlarn asenkron olarak nasl altrlabileceini en
temel hatlar ile ve yzeysel olarak incelemi olduk. Bir sonraki makalemizde grnceye dek
hepinize mutlu gnler dilerim.

rnek kodlar iin tklayn.

Burak Selim ENYURT

selim@bsenyurt.com

Transaction' larda DeadLock Kavram (


07.07.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, e zamanl olarak alan Transaction' larda meydana gelebilecek DeadLock


durumunu incelemeye alacaz. ncelikle DeadLock teriminin ne olduunu anlamaya alalm.
DeadLock, ayn zamanl alan Transaction' larn, belirlir satr(lar) kilitlemeleri sonucunda ortaya
kabilecek bir durumdur. DeadLock terimini kavrayabilmenin en iyi yolu aadaki gibi
geliebilecek bir senaryoyu zihnimizde canlandrmakla mmkndr. Bu senaryoda sz konusu olan
iki tablomuz mevcuttur. Bu tablolar Sql sunucusunda Northwind veritaban altnda oluturulmu
olup Field(alan) yaplar aadaki gibidir.

www.bsenyurt.com Page 2202


ekil 1. Musteriler Tablosu.

ekil 2. Personel Tablosu.

imdi senaryomuzu tasarlayalarak DeadLock kavramn anlamaya alalm. Her iki tabloyu ayr
ayr kullanan ve e zamanl olarak alan iki Transaction' mz olduunu dnelim. Burada nemli
olan bu iki Transaction' n ayn anda alyor olmalardr.

DeadLock Senaryosu

1nci
Transaction 1 balatlr.
Adm

2nci
Transaction 2 balatlr.
Adm

3nc
Transaction 1 Personel tablosunda PersonelID deeri 78 olan satr kitler ve gnceller.
Adm

4nc Transaction 2 Musterilre tablosunda MusteriID deeri 1000 olan satr kitler ve
Adm gnceller.

Transaction 1 Musteriler tablosundaki MusteriID deeri 1000 olan satr gncellemek


5inci ister. Ancak, Transaction 2 bu satr kitlediinden, varsaylan Lock TimeOut sresi
Adm kadar bu kilidin almasn bekler. Bu sre sonuna kadar Transaction 2' nin ilemlerini
onaylamas veya geri almas beklenir.

Transaction 2 Personel tablosundaki PersonelID deeri 78 olan satr gncellemek ister.


6nc Ancak bu durumda, Transaction 1 bu satr kitlediinden yine varsaylan Lock TimeOut
Adm sresi kadar bu kilidin almasn bekler. Bu sre sonuna kadar Transaction 1' in
ilemlerini onaylamas veya geri almas beklenir.

Bizim iin nemli olan admlar, 5inci ve 6nc admlardr. Nitekim bu admlar e zamanl olarak
gerekletirildiklerinden, iki Transaction da birbirinin kilitlerinin almasn beklemek durumundadr.
te bu noktada DeadLock oluur. Nitekim sreler sona erinceye kadar herhangibir Transaciton
sahip olduu ilemleri ne onaylam (Commit) nede geri almtr (RollBack).Dolaysyla Transaction'
lardan birisi, varsaylan olarakta Sql sunucusuna gre en maliyetli olan otomatik olarak RollBack
edilecektir. Bu durumda bu Transaction' a ait kilitler ortadan kalktndan kalan Transaction' a ait
gncelleme ilemi tamamlanr. Ancak .net ile yazlan uygulamalarda DeadLock olutuunda,
Transaction' lardan birisi geri alnmakla kalmaz ayn zamanda ortama bir istisna frlatlr. Dolaysyla

www.bsenyurt.com Page 2203


DeadLock durumunda bu istisnannda ele alnmas gerekirki, DeadLock sonucu almaya devam
eden Transaction ilemleri onaylanabilsin.

DeadLock olumas durumunda, birbirlerini bekleyen Transaction' larda, bekleme srelerini


ayarlayabilir ve hangi Transaction' n daha nce RollBack edilmesi gerektiine karar verebiliriz.
Bunun iin, T-Sql' in LOCK_TIMEOUT ve DEADLOCK_PRIORITY anahtar szckleri kullanlr. Bir
Transaction' n baka bir Transaction' da oluan kilidi ne kadar sre ile beklemesi gerektiini
belirtmek iin aadaki gibi bir sql cmlecii kullanlr.

SET LOCK_TIMEOUT 3000

Burada LOCK_TIMEOUT deeri 3 saniye (3000 milisaniye) olarak belirtilmitir. Dier yandan, bir
Transaction iin DeadLock nceliini aadaki gibi bir sql cmlecii ile belirtebiliriz.

SET DEADLOCK_PRIORITY LOW

Bu sql cmleciini kullanan komutun alt Transaction, DeadLock olumas durumunda, ilk
olarak RollBack edilecek Transaction olacaktr. DEADLOCK_PRIORITY anahtar szcnn
alabilecei dier deerde NORMAL dir. Bu durumda, Transaction' lardan en maliyetli olan RollBack
edilir. DEADLOCK_PRIORITY iin varsaylan deer NORMAL olarak belirlenmitir. imdi dilerseniz
DeadLock olumasn daha iyi izleyebileceimiz bir rnek gelitirmeye alalm. Bu durumu simule
edebilmek iin, ayn anda alan Transaction i paralarna ihtiyacmz olacak. Yani DeadLock
senaryosunda belirtmi olduumuz gncelleme ilemlerinin ayn zamanda alyor olmas gerekli.
Bunu salayabilmek iin bu gncelleme ilemlerini birer Thread iinde altracaz. Uygulamamz
basit bir Console Application olacak. imdi aadaki uygulama kodlarn oluturalm.

using System;
using System.Data;
using System.Data.SqlClient;
using System.Threading;

namespace DeadLockTest
{
class Deadlock
{
/* Iki ayri Transaction iin iki ayri SqlConnection nesnesi olusturuyoruz. Bununla birlikte, iki
Transaction iindeki komutlari icra edecek iki adet SqlCommand nesnesi ve Transactionlar iinde iki
adet SqlTransaction nesnesi tanimliyoruz.*/
public static SqlConnection conT1 =new
SqlConnection("server=localhost;database=Northwind;integrated security=SSPI");
public static SqlConnection conT2 =new
SqlConnection("server=localhost;database=Northwind;uid=sa;integrated security=SSPI");
public static SqlCommand cmdT1;
public static SqlCommand cmdT2;
public static SqlTransaction T1;
public static SqlTransaction T2;

/* Bu metod, Personel tablosunda gncelleme islemini yapiyor. Komut, conT1 SqlConnection'


i zerinden, T1 isimli SqlTransaction' da alisacak sekilde olusturuluyor. Sonra bu komut

www.bsenyurt.com Page 2204


yrtlyor. Metod deadlock senaryomuzun 3nc adimini gereklestiriyor.*/
public static void GuncellePersonelT1()
{
Console.WriteLine("PersonelID=78 olan satirdaki PersonelAd alaninin degeri DENEME
yapiliyor...");
cmdT1=new SqlCommand("UPDATE Personel SET PersonelAd = 'DENEME' WHERE
PersonelID = 78", conT1,T1);
int sonuc = cmdT1.ExecuteNonQuery();
Console.WriteLine(sonuc+" guncellendi. PersonelAd = DENEME yapildi.");
}

/* Bu metod ile DeadLock senaryomuzun 4nc adimi gereklestiriliyor.*/


public static void GuncelleMusterilerT2()
{
Console.WriteLine("MusteriID=1000 olan satirdaki MusteriMail alaninin degeri
DENEME@DENEME.COM yapiliyor...");
cmdT2=new SqlCommand("UPDATE Musteriler SET MusteriMail =
'DENEME@DENEME.COM' WHERE MusteriID = 1000",conT2,T2);
int sonuc = cmdT2.ExecuteNonQuery();
Console.WriteLine(sonuc+" guncellendi. MusteriMail = DENEME@DENEME.COM yapildi.");
}

/* Bu metod ile DeadLock senaryomuzun 5nci adimi gereklestiriliyor.*/


public static void GuncelleMusterilerT1()
{
Console.WriteLine("MusteriID=1000 olan satirdaki MusteriMail alaninin degeri
MAIL@MAIL.COM yapiliyor...");
cmdT1 =new SqlCommand("UPDATE Musteriler SET MusteriMail = 'MAIL@MAIL.COM'
WHERE MusteriID = 1000",conT1,T1);
int sonuc = cmdT1.ExecuteNonQuery();
Console.WriteLine(sonuc+" guncellendi. MusteriMail = MAIL@MAIL.COM yapildi.");
}

/* Bu metod ilede DeadLock senaryomuzun 6nci adimi gereklestiriliyor.*/


public static void GuncellePersonelT2()
{
Console.WriteLine("PersonelID=78 olan satirdaki PersonelAd alaninin degeri ISIM
yapiliyor...");
cmdT2=new SqlCommand("UPDATE Personel SET PersonelAd = 'ISIM' WHERE PersonelID
= 78", conT2,T2);
int sonuc = cmdT2.ExecuteNonQuery();
Console.WriteLine(sonuc+" guncellendi. PersonelAd = ISIM yapildi.");
}

public static void Main()


{
/* Baglantimiz ailiyor ve ilk transaction baslatiliyor. Ardinan bu Transaction iin
LOCK_TIMEOUT degeri belirlenerek, kilitlerin ne kadar sre ile beklenecegini belirten sql komutu
alistiriliyor. Sre olarak 3 saniye veriliyor.*/

www.bsenyurt.com Page 2205


conT1.Open();
T1 = conT1.BeginTransaction();
cmdT1 = conT1.CreateCommand();
cmdT1.Transaction = T1;
cmdT1.CommandText = "SET LOCK_TIMEOUT 3000";
cmdT1.ExecuteNonQuery();

/* Ikinci transaction iin gerekli baglanti ailiyor, transaction baslatiliyor ve


LOCK_TIMEOUT sresi 3 saniye olarak belirleniyor.*/
conT2.Open();
T2 = conT2.BeginTransaction();
cmdT2 = conT2.CreateCommand();
cmdT2.Transaction = T2;
cmdT2.CommandText = "SET LOCK_TIMEOUT 3000";
cmdT2.ExecuteNonQuery();

/* Izleyen sql cmlecigi ile, DeadLock_Priority degeri LOW olarak belirleniyor. Yani, bir
deadLock olusmasi durumunda, cmdT2 nin iinde alistigi Transaction RollBack edilecektir.*/
cmdT2.CommandText = "SET DEADLOCK_PRIORITY LOW";
cmdT2.ExecuteNonQuery();

/*DeadLock senaryomuzdaki update ilemelerini gerekletirecek olan metodlarmz iin


Thread nesneleri oluturuluyor ve daha sonra bu Thread'ler balatlyor.*/
Thread Thread1 = new Thread(new ThreadStart(GuncellePersonelT1));
Thread Thread2 = new Thread(new ThreadStart(GuncelleMusterilerT2));
Thread Thread3 = new Thread(new ThreadStart(GuncelleMusterilerT1));
Thread Thread4 = new Thread(new ThreadStart(GuncellePersonelT2));

Thread1.Start();
Thread2.Start();
Thread3.Start();
Thread4.Start();

Console.ReadLine();
}
}
}

www.bsenyurt.com Page 2206


ekil 3. Programn almasnn Sonucu.

Uygulamay altrdmzda, ilk Thread ve ikinci Thread' ler iinde yrtlen update ilemlerinin
gerekletirildiini grrz. Daha sonra nc Thread iin gncelleme ilemi yaplrken, bu Thread'
in alt Transaction 3 saniye sreyle dier Transaction' daki kilidin almasn bekleyecektir. Sre
sonunda kilit halen daha almam olacandan (ki kilidin almas Commit veya RollBack ilemini
gerektirir. ) DEADLOCK_PRIORITY deeri LOW olarak belirlenen ikinci Transaction RollBack
edilecektir. Bununla birlikte SqlException trnden bir istisna da ortama frlatlr. Bu istisnada bir
DeadLock olutuu ve prosesler iinde alan Transaction' lardan birisininde kurban edilecei
belirtilir. Elbette burada istisnay kontrol etmediimiz iin her iki Transaction iindeki ilemler
RollBack edilecektir. Ana amacmz, DeadLock senaryosunun ne zaman gerekleecei ve neler
olacadr. Bylece DeadLock durumunun nasl olutuunu ve nelere yol atn ok ksa ve basit
olarak incelemeye altk. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler
dilerim.

rnek Uygulama in Tklayn.

Burak Selim ENYURT

selim@bsenyurt.com

NET Remoting' i Kavramak - 2 ( 03.07.2004 ) -


Remoting
Deerli Okurlarm, Merhabalar.

Bu makalemizde, daha nceden deinmi olduumuz .net remoting ile ilgili olarak ok basit bir
rnek gelitirmeye alacaz. Remoting' de ama, istemcilerin uzak nesnelere ait yelere
eriebilmelerini ve kullanabilmelerini salamaktr. Dolaysyla, remoting sistemi sz konusu
olduunda, remote object, server channels ve client channels kavramlar nem kazanr. Olaya bu
adan baktmzda ilk olarak bir remote object (uzak nesne) gelitirmemiz gerektii ortadadr.
Daha sonra, bu nesneyi kullanmak isteyecek istemcileri dinleyecek bir server programn yazmamz
gerekir. Bu server program aslnda, remote object' i barndran (host) bir hizmet program
olacaktr. stemcilerin tek yapmas gereken uzak nesneye ait bir rnei, altklar sistemde
kullanarak bir proxy nesnesi oluturmak ve bu nesne zerinden server programa istekte bulunarak

www.bsenyurt.com Page 2207


ilgili uzak nesneye ait metodlar altrmaktr. te bu noktada server ve client uygulamalardaki
channel nesneleri nem kazanr.

Biz bugnk rneimizde, TCP protokol zerinden haberleen bir remoting uygulamas
gelitirmeye alacaz. ncelikle ie, remote object (uzak nesne) snfn tasarlayarak balayalm.
Konuyu daha net anlayabilmek iin, uygulamalarmz editornde gelitireceiz. imdi aadaki
kodlardan oluan, UzakNesne.cs kod dosyasn oluturalm.

using System;
using System.Data;
using System.Data.SqlClient;

namespace UzakNesne
{
public class Musteriler:System.MarshalByRefObject
{
public string MusteriBul(string CustID)
{

SqlConnection con=new SqlConnection("data source=localhost;initial


catalog=Northwind;integrated security=SSPI");
SqlCommand cmd=new SqlCommand("SELECT * FROM Customers WHERE
CustomerID='"+CustID+"'",con);
con.Open();
SqlDataReader dr=cmd.ExecuteReader();
dr.Read();
string Bulunan=dr["CompanyName"]+" "+dr["ContactName"]+" "+dr["Phone"];
con.Close();
return Bulunan;

}
}
}

Burada grld gibi remote object (uzak nesne) snf iin en nemli unsur, bu snfn
System.MarshalByRefObject snfndan tretilmi olmasdr. Normal artlarda gelitirdiimiz bu
nesneye, bulunduu sistemin application domain' i ierisinden direkt olarak eriebiliri. Ancak, bu
nesnenin application domain' in dndaki bir domainden kullanlabilmesini salamak yani remoting
desteini vermek iin MarshalByRefObject snfndan tretmemiz gerekmektedir. Bu sayede istemci
uygulama, bu nesneye ait proxy nesnesi zerinden mesaj gnderebilecek ve alabilecektir. imdi
gelitirdiimiz bu assembly' bir dll olarak aadaki gibi derleyeylim.

Artk uzak nesnemizede sahip olduumuza gre, bu nesneyi kullanacak istemcileri takip edecek, bir
baka deyile dinleyecek (listening) bir server (sunucu) uygulamas yazabiliriz. Bir sunucu

www.bsenyurt.com Page 2208


uygulamas iin en nemli unsurlar, dinleme ilemi iin hangi kanaln, hangi ayarlar ile kullanlaca
ve remote object (uzak nesne) snfna ait bilgilerin ne olduundan olumaktadr. Server (sunucu)
iin gerekli bu bilgileri uygulama ierisinden programatik olarak belirleyeceimiz gibi, xml tabanl
bir konfigurasyon dosyas yardmylada tanmlayabiliriz. XML tabanl konfigurasyon dosyasnn,
programatik olan teknie gre en byk avantaj, kanal ve remote object (uzak nesne) ile ilgili
dzenlemelerde, kodun yeniden derlenmesine gerek kalnmamasdr. Bir konfigurasyon dosyas,
config uzantldr. Bu makalemizde kullancamz Server (sunucu) uygulamaya ait konfigurasyon
dosyas Sunucu.config isminde olup, aadaki satrlardan olumaktadr.

<configuration>
<system.runtime.remoting>
<application name="MusteriUygulama">
<service>
<wellknown mode="SingleCall" type="UzakNesne.Musteriler,UzakNesne"
objectUri="UzakNesne"/>
</service>
<channels>
<channel ref="tcp server" port="1000"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>

imdi bu xml dosyasnn ieriini ksaca incelemeye alalm. ncelikle ana eleman
<configuration> dr. Burada server (sunucu) uygulamasna ait remote object (uzak nesne) ve
channel (kanal) ayarlamalar mutlaka, <system.runtime.remoting> eleman iinde yaplmaldr.
<application> eleman iinde name zellii ile server (sunucu) uygulamamzn adn belirtiyoruz.

Asl nemli olan iki eleman <application> eleman altnda yer alan <service> ve <channels>
elemanlardr. <service> eleman altnda <wellknown eleman ile, remote object' e ait bilgiler
belirtilir. mode niteliinde, SingleCall ile, sunucu tarafl etkinletirme teknii belirtilmektedir. Bu
anlamda SingleCall ile, istemci tarafndan yaplan her metod arsna karlk birer sunucu nesnesi
rnei oluturulmas salanmaktadr. Dier alternatif ise, Singleton tekniidir ki bu teknie gre
sunucu nesneyi kullanan ka istemci olursa olsun, her bir istemcinin metod armlar sunucu
tarafndaki tek bir nesne rnei tarafndan ynetilmektedir.

type niteliinde remote object (uzak nesne) iin, bu tipin hangi isim alan ve snfa ait olduu
belirtilir. type niteliindeki ikinci parametre ise, uzak nesnenin bulunduu assembly' n addr.
objectUri ile, istemcilerin uzak nesne iin kullanacaklar endpoint (son nokta) ismi belirtilmektedir.
<channel elemannda, hangi protokol zerinden ve hangi port' tan dinleme yaplaca belirtilir.
Burada sistemdeki machine.config dosyasnda daha nceden tanmlanm olan tcp server
protokolnn, 1000 numaral portu kullanaca belirtilmitir. Machine.config
dosyasn D:\WINDOWS\Microsoft.NET\Framework\vx.x.xxxx\CONFIG klasrnde bulabilirsiniz. Bu
dosyada <channels> eleman altnda nceden tanmlanm remoting protokolleri yer almaktadr.

<channels>
<channel id="http" type="System.Runtime.Remoting.Channels.Http.HttpChannel,
System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
<channel id="http client" type="System.Runtime.Remoting.Channels.Http.HttpClientChannel,
System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral,

www.bsenyurt.com Page 2209


PublicKeyToken=b77a5c561934e089" />
<channel id="http server"
type="System.Runtime.Remoting.Channels.Http.HttpServerChannel, System.Runtime.Remoting,
Version=1.0.5000.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<channel id="tcp" type="System.Runtime.Remoting.Channels.Tcp.TcpChannel,
System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
<channel id="tcp client" type="System.Runtime.Remoting.Channels.Tcp.TcpClientChannel,
System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
<channel id="tcp server" type="System.Runtime.Remoting.Channels.Tcp.TcpServerChannel,
System.Runtime.Remoting, Version=1.0.5000.0, Culture=neutral,
PublicKeyToken=b77a5c561934e089" />
</channels>

Burada Machine.config iindeki tcp server protokolne ait tanmlamada,


System.Runtime.Remoting.Channels.Tcp. TcpServerChannel tipininde belirtildiine dikkat edelim.
Konfigurasyon dosyasnn hazrlanmas ile birlikte, artk sunucu uygulamamz yazabiliriz. Sunucu
uygulama, bu konfigurasyon dosyasn kullanarak, belirtilen protokol ve port zerinden istemci
taleplerini (mesajlarn) dinlemeye alacak ve gelen bu talepleri, yine konfigurasyon dosyasnda
belirtilen uzak nesneye ait rnee ynlendirecektir. Nesneden dnen cevaplarda, yine bu
konfigurasyon dosyasnda belirtilen protokol ve port ile istemcilere gnderilecektir. Gelelim
server(sunucu) uygulamamzn kodlarna.

using System;
using System.Runtime.Remoting;

namespace Sunucu
{
public class SunucuDinler
{
public static void Main(string[] args)
{
RemotingConfiguration.Configure("Sunucu.config");
Console.WriteLine("Dinlemeye baslandi...ikmak iin bir tusa basin");
Console.ReadLine();
}
}
}

Burada grld gibi, sunucu uygulamamz konfigurasyon dosyasndaki bilgilere


RemotingConfiguration snfnn Configure metodu ile ulamaktadr. zleyen satrlardaki WriteLine
ve ReadLine metodlar ile, uygulamann biz son verene kadar 1000 nolu Tcp Server portunu
dinlemesi salanmtr. imdi yazdmz bu uygulamay exe olarak derleyelim.

www.bsenyurt.com Page 2210


Bu ilemlerin ardndan, sunucu nesnemizin, sunucu uygulamamzn ve konfigurasyon dosyamzn
ayn klasrde olmalarna dikkat edelim.

Artk sunucu tarafndaki ilemlerimizi bitirmi olduk. imdi sunucu tarafndaki nesneyi kullanacak
istemci uygulamay tasarlayalm. Elbetteki, istemci uygulamada, mesajlarn Tcp protokoln baz
alarak bir kanal zerinden gndermek zorundadr. nk sunucu uygulama Tcp protokoln baz
alarak dinleme gerekletirecektir. Bunu salamak iin ncelikle, istemci tarafnda, client channel
(istemci kanal) nesnesine ihtiyacmz vardr. lave olarak, kullanacamz uzak nesneninde bir
koypasn, istemci uygulamann assembly'nn bulunduu klasre koymamz gerekiyor. Bir istemci
uygulama iin nemli olan unsurlar, kanal nesnesi ayarlar ve uzak nesneye ait ayarlardr. Bu
ayarlamalar programatik olarak yapabileceimiz gibi bir konfigurasyon dosyasnda da yapabiliriz.
Bu amala ncelikle aadaki istemci.config dosyasn oluturalm.

<configuration>
<system.runtime.remoting>
<application name="Istemci">
<client>
<wellknown type="UzakNesne.Musteriler,UzakNesne"
url="tcp://localhost:1000/UzakNesne"/>
</client>
<channels>
<channel ref="tcp client"/>
</channels>
</application>
</system.runtime.remoting>
</configuration>

<wellknown elemannda proxy nesnesi ile iletiim kuracak uzak nesneye ait bilgiler yer almaktadr.
zel olarak, uzak nesnenin tam olarak adresi url bilgisinde belirtilmitir. Bu url bilgisi, istemci
uygulamadaki proxy nesnesinin mesajlamak amacyla kullanaca kar nesne adresini tam olarak
belirtmektedir. <channels> elemannda ise, client channel nesnesi belirtilmitir. Bu nesne yine ref

www.bsenyurt.com Page 2211


nitelii ile, sistemde machine.config dosyasnda daha nceden tanmlanm tcp client niteliini
referans etmektedir. Artk istemci uygulamamzda yazabiliriz.

using System;
using System.Runtime.Remoting;

namespace istemciUygulama
{
public class istemci
{
public static void Main(string[] args)
{
RemotingConfiguration.Configure("istemci.config");
UzakNesne.Musteriler m=new UzakNesne.Musteriler();
string sonuc=m.MusteriBul("ALFKI");
Console.WriteLine(sonuc);
Console.ReadLine();
}
}
}

Grld gibi istemci uygulamada, konfigurasyon ayarlarn almak iin RemotingConfiguration


snfnn Configure metodunu kullanr. Bundan sonra tek yaplan uzak nesne rneini oluturmak ve
ilgili metodu armaktr. Yazdmz bu istemci.cs dosyasn aadaki ekilde derleyeylim.

Burada dikkat edilecek olursa, uzaknesne.dll dosyas assembly'a referans olarak bildirilmitir.
Dolaysyla, uzaknesne.dll' inin bir kopyasnn istemci uygulamann bulunduu klasrde olmas
gerektiine dikkat etmeliyiz.

imdi remoting sistemimizi bir test edelim. ncelikle sunucu uygulamamz, istemcilerden gelecek
talepleri dinlemek amacyla balatmamz gerekiyor.

www.bsenyurt.com Page 2212


Bu ilemin ardndan istemci uygulamamzda altralm. Sonular aadaki gibi olacak ve sql
sunucusunda yer alan Northwind veritabanndaki Customers tablosundaki CustomerID deeri ALFKI
alan satr bilgileri elde edilecektir.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Transaction' larda Izolasyon Seviyeleri -2


(IsolationLevel Numaralandrcs) ( 28.06.2004 )
- Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Sql izolasyon seviyelerinin, .net uygulamalarnda nasl kullanldn incelemeye


alacaz. Bir nceki makalemizde, izolasyon seviyeleri iin sz konusu olabilecek 3 problemi ele
almtk. Bu olas problemler phantoms, non-repeatable read ve dirty read durumlardr. E zamanl
olarak alan Transaction' larda meydana gelebilecek bu problemleri, IsolationLevel
numaralandrcs yardmyla kontrol altna alabiliriz. Bu numaralandrcnn alabilecei deerler ve
bu deerlerin izin verdii(vermedii) durumlar aadaki tabloda yer almaktadr.

Olas Problemler

www.bsenyurt.com Page 2213


IsolationLevel Non-
Numaralandrc Deeri Phantoms Repeatable Dirty-Read
Read

Chaos SqlServer tarafndan desteklenmez.

ReadCommitted

ReadUncommitted

RepeatableRead

Serializable

Unspecified SqlServer tarafndan desteklenmez.

Grld gibi IsolationLevel numaralandrcsnn alabilecei deerler alt adettir. Chaos ve


Unspecified numaralandrc deerleri sql server tarafndan desteklenmemektedir. Bununla birlikte,
bir Transaction snfnn IsolationLevel zelliinin varsaylan deeri ReadCommitted olarak
belirtilmitir. Bu tablonun okunuuna gelince. rnein, RepeatableRead deerini ele alalm. Bir
uygulamada, Transaction nesnesine izolasyon seviyesi olarak bu deer atand takdirde, e
zamanl olarak alan Transaction' lar arasnda sadece Phantoms durumuna izin verilir. Dolaysyla,
Non-repeatable Read ve Dirty-Read durumlarna izin verilmez. Burada tm olas problemlere izin
veren IsolationLevel numaralandrc deeri ReadUncommitted deeridir. Aksine, Serializable deeri
Transaction' lar arasnda doabilecek bu problemlerin hi birisinin olmasna izin vermez.

imdi dilerseniz, bu deerlerin ayn zamanda alan Transaction' lar zerindeki etkilerini rnek
uygulamamz zerinde incelemeye alalm. Bu makalemizde yine bir nceki makalemizde
gelitirdiimiz uygulamay rnek olarak kullanabiliriz. Bu kez formumuza izolasyon seviyelerini
alma zamannda belirlememize yarayacak 4 adet RadioButton kontrol yerletirdik. Formumuzun
grnts aadaki gibi olacaktr.

www.bsenyurt.com Page 2214


Elbette, gerek uygulamalarda burada olduu gibi izolasyon seviyelerinin alma zamannda bu
ekilde belirlenmesi pek doru olmayabilir. Ancak u an iin amacmz, bu izolasyon seviyelerinde
ayn anda alan Transaction' larda nelerin olup nelerin olmadn kontrol edebilmektir. Uygulama
kodlarmz ise, aada olduu gibidir.

SqlConnection con;
SqlTransaction trans;
SqlDataAdapter da;

private void btnBegin_Click(object sender, System.EventArgs e)


{
if(con.State==ConnectionState.Closed)
{
con.Open();
}
if(this.rdbReadCommited.Checked==true)
{
trans=con.BeginTransaction(IsolationLevel.ReadCommitted);
}
else if(this.rdbReadUncommited.Checked==true)
{
trans=con.BeginTransaction(IsolationLevel.ReadUncommitted);
}
else if(this.rdbRepeatableRead.Checked==true)
{
trans=con.BeginTransaction(IsolationLevel.RepeatableRead);
}
else if(this.rdbSerializable.Checked==true)
{

www.bsenyurt.com Page 2215


trans=con.BeginTransaction(IsolationLevel.Serializable);
}

lblDurum.Text=trans.IsolationLevel.ToString();
}

private void Form1_Load(object sender, System.EventArgs e)


{
con=new SqlConnection("data source=localhost;database=Northwind;integrated
security=SSPI");
}

private void btnCommit_Click(object sender, System.EventArgs e)


{
trans.Commit();
}

private void btnRollBack_Click(object sender, System.EventArgs e)


{
trans.Rollback();
}

private void btnBak_Click(object sender, System.EventArgs e)


{
try
{
SqlCommand cmdBak=new SqlCommand("SELECT * FROM Personel",con);
cmdBak.Transaction=trans;
da=new SqlDataAdapter(cmdBak);
DataTable dt=new DataTable();
da.Fill(dt);
dataGrid1.DataSource=dt;
}
catch(SqlException hata)
{
MessageBox.Show(hata.Message.ToString());
}
}

private void btnEkle_Click(object sender, System.EventArgs e)


{
SqlCommand cmdGir=new SqlCommand("INSERT INTO Personel (ISIM,SOYISIM) VALUES
('"+txtIsim.Text+"','"+txtSoyisim.Text+"')",con);
cmdGir.Transaction=trans;
int sonuc=cmdGir.ExecuteNonQuery();
MessageBox.Show(sonuc+" SATIR GIRILDI");
}

private void btnGuncelle_Click(object sender, System.EventArgs e)

www.bsenyurt.com Page 2216


{
SqlCommand cmdGuncelle=new SqlCommand("UPDATE Personel
SET ISIM='"+txtIsim.Text+"', SOYISIM='"+txtSoyisim.Text+"' WHERE ID="+txtID.Text,con);
cmdGuncelle.Transaction=trans;
int sonuc=cmdGuncelle.ExecuteNonQuery();
MessageBox.Show(sonuc+" SATIR GUNCELLENDI");
}

private void btnBakID_Click(object sender, System.EventArgs e)


{
try
{
SqlCommand cmd=new SqlCommand("SELECT ISIM,SOYISIM FROM Personel WHERE
ID="+txtID.Text,con);
cmd.Transaction=trans;
da=new SqlDataAdapter(cmd);
DataTable dt=new DataTable();
da.Fill(dt);
dataGrid1.DataSource=dt;
}
catch(SqlException hata)
{
MessageBox.Show(hata.Message.ToString());
}
}

Kodumuzdaki en nemli nokta, balatlacak Transaction' lar iin IsolationLevel deerlerinin


belirlenmesidir. Bu amala, SqlConnection snfnn, BeginTransaction metodunun aadaki
prototipi kullanlmaktadr. Bu prototipte BeginTransaction metodu, parametre olarak IsolationLevel
numaralandrcs trnden bir deer alr. Bylece belirtilen balant iin alacak Transaction, bu
parametrede belirtilen izolasyon seviyesini kullanarak alacaktr.

public SqlTransaction BeginTransaction(IsolationLevel iso);

imdi ilk olarak IsolationLevel zelliinin varsaylan deeri olan ReadCommitted deerinden ie
balayalm. ReadCommitted deeri, Phantoms ve Non-Repeatable Read durumlarna izin verirken,
Dirty-Read durumuna izin vermez. imdi rnek uygumamamzdan iki adet altralm ve aadaki
tabloda yer alan hareketleri srasyla uygulayalm. Elbette tm rneklerimizde ilk olarak Balat
balkl butona basarak Transaction' larn balamasn salamalyz.

IsolationLevel.ReadCommitted

Transaction 1 Transaction 2
Phantoms
Veri eker. (Bak balkl button)

www.bsenyurt.com Page 2217


Veri eker. (Bak balkl button)

Yeni satr ekler. (Ekle balkl button)

Transaction onaylanr. Commit (Onayla


balkl button)

Tekrardan Veri eker. Phantoms


durumu oluur.

www.bsenyurt.com Page 2218


imdide, Non-Repeatable Read durumunu inceleyelim. Bunun iinde, yine ayn uygulamadan iki
tane balatabilir yada halen alan uygulamalarda ak kalan Transaction' lar onaylayarak yeni
batan oluturabilirsiniz. Bu kez aadaki tabloda izleyen admlar gerekletireceiz.

IsolationLevel.ReadCommitted

Transaction 1 Transaction 2
Non-

www.bsenyurt.com Page 2219


Repeatable Belirli bir satr veri ekilir. (rnein
Read ID=58)

Ayn satr ekilir. (ID=58)

Bu satrdaki verilerde deiiklikler yaplr.

Transaction onaylanr. Commit.

Ayn satra tekrar baklr. Non-


Repeatable Read durumu oluur.

www.bsenyurt.com Page 2220


ReadCommitted seviyesi ile ilgili olarak son durum ise Dirty Read durumudur. Bu izolasyon
seviyesi, Dirty Read durumlarnn olumasna izin vermez. Hatrlayacanz gibi bu durumda, e
zamanl olarak alan Transaction' larda herhangibir Commit ilemi olmadan sz konusu olan
problemler yer almaktadr. imdi bu durumu incelemek iin aadaki tabloda yer alan ilemleri
gerekletirelim.

IsolationLevel.ReadCommitted

Dirty Transaction 1 Transaction 2

www.bsenyurt.com Page 2221


Read Belirli bir satr veri ekilir. (rnein
ID=73)

Ayn satr ekilir. (ID=73)

Bu satrdaki verilerde deiiklikler yaplr.


Ancak Transaction Commit edilmez.

Ayn satra tekrar baklmak istenir. Hata


Oluur.

Grld gibi, aadaki hata bildirisi alma zamannda oluur.

Dolaysyla unu syleyebiliriz. ReadCommitted deerine sahip Transaction' lardan herhangibiri


ierisinde yaplan gncelleme, silme veya ekleme gibi ilemlerin, dier Transaction tarafndan
grlebilmesi iin, bu deiiklikleri ieren Transaction' n Commit edilmesi veya RollBack edilmesi
gerekmektedir. Bu nedenle, ReadCommitted deeri, Dirty Read durumuna izin vermez.

Gelelim, ReadUncommitted deerine. Bu deerin ReadCommitted deerinden tek fark Dirty Read
durumuna izin vermesidir. Bu durumu analiz etmek iin, aadaki tablodaki ilemleri srasyla
uygulayalm. (Transaction' lar Balat balkl Button ile balatmadan nce, ReadUncommitted
RadioButton kontrolnn seili olmasna dikkat edelim.)

IsolationLevel.ReadUncommitted

Transaction 1 Transaction 2

Belirli bir satr veri ekilir. (rnein


ID=70)
Dirty
Read
Ayn satr ekilir. (ID=70)

Bu satrdaki verilerde deiiklikler yaplr.


Ancak Transaction Commit edilmez.

www.bsenyurt.com Page 2222


Ayn satra tekrar baklmak istenir.
(ID=70) Meydana gelen yeni
deiiklikler grlr.

Yaplan ilemler geri alnr. RollBack.

Bu Transaction' da gereklememi
deiiklikler grnmeye devam eder.
Dirty Read durumu.

Dolaysyla ReadUncommitted deerinin en nemli zellii, Dirty Read durumuna neden olacak
ilemlere izin vermesidir. Baka bir deyile, alan iki Transaction' dan herhangibirinde yaplan
deiikliklerin dier Transaction tarafndan grlmesi iin, ilemlerin mutlaka Commit edilmesi veya
RollBack edilmesi gerekmez.

Srada, RepeatableRead deeri var. Bu deeride ReadCommitted ile kyaslayarak anlamaya


almak daha mantkldr. RepeatableRead deeri, sadece phantoms durumlarna izin verir. Dier
durumlarn olumas halinde, yine zaman am nedeniyle bir SqlException istisnas firlatlr.
IsolationLevel' larn belirlenmesi ile ilgili nemli olan bir dier deerde Serializable deeridir. Bu
deer, Phantoms, Non-Repeatable Read ve Dirty Read durumlarndan herhangibirisinin olumasna
izin vermez. rnein aadaki tabloda yer alan ilemleri yapmaya altmz dnelim.

IsolationLevel.Serializable

Transaction 1 Transaction 2

Tablodan veriler ekilir.

Phantoms Tablodan veriler ekilir.

Yeni bir satr eklenmeye allr. Ancak buna


izin verilmez. nk satrlar, Serializable
deeri nedeniyle dier Transaction tarafndan
kilitlenmitir.

Dolaysyla Serializable deerinin e zamanl Transaction' lar iin sadece veri bakmaya izin verdiini
syleyebiliriz. Baka bir deyile, ayn anda alan iki Transaction' dan herhangibiri, Transaction'
lardan dieri ak olduu srece veri girii, dzenlemesi veya silme ilemlerini yapamaz. Bylece
Sql Server zerinde alan e zamanl Transaction' lar iin var olabilecek sorunlar deerlendiren
izolasyon seviyelerini ksaca grm olduk. lerleyen makalelerimizde, Sql Server kilitlerinin
Ado.Net iindeki yerini incelemeye alacaz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2223


Transaction' larda Izolasyon Seviyeleri (Isolation
Level) - 1 ( 19.06.2004 ) - Ado.Net
"Felakete maruz kalmadan nce, olaslklar iyi bilmek gerekir."

Deerli Okurlarm, Merhabalar.

Bu makalemizde, Transaction' larda kullanlan izolasyon seviyelerini incelemeye balayacaz.


Izolasyon seviyeleri, ezamanl olarak alan Transaction' larn birbirlerini nasl etkilemesi
gerektiini belirtmekte kullanlr. Yani bir baka deyile, bir Transaction iinde meydana gelen
deiikliklerin, baka e zamanl Transactionlar tarafndan nasl ele alnmas gerektiini
belirlememize olanak salar. Izolasyon seviylerini anlamann en iyi yolu, e zamanl olarak alan
Transaction' larda meydana gelebilecek sorunlar iyi anlamaktan geer.

Ezamanl olarak alan iki Transaction gz nne alndnda, oluabilecek durumlar tanedir.
Phantoms, Non-Repeatable Read, Dirty Read. Her bir durumun, alan Transaction' lara etkisi
farkldr. imdi bu problemleri incelemeye alalm. Bu amala basit bir windows uygulamas
gelitireceiz. Uygulamamz, Sql sunucusu zerinde alan veritaban zerinde ekleme,
gncelleme, veri ekme gibi ilemler yapacak. Tm bu ilemleri birer Transaction ierisinde
gerekletireceiz. Sonu olarak, ayn anda bu uygulamalardan iki proses altrp, bahsettiimiz
problemleri simle etmeyi deneyeceiz. ncelikle, Visual Studio.Net ortamnda bir windows
uygulamasn aadakine benzer forma sahip olacak ekilde oluturalm.

ekil 1. Form Tasarmmz.

Sra geldi uygulama kodlarmz yazmaya.

www.bsenyurt.com Page 2224


SqlConnection con;
SqlTransaction trans;
SqlDataAdapter da;

private void btnBegin_Click(object sender, System.EventArgs e)


{
if(con.State==ConnectionState.Closed)
{
con.Open();
}
trans=con.BeginTransaction();
}

private void Form1_Load(object sender, System.EventArgs e)


{
con=new SqlConnection("data source=localhost;database=Northwind;integrated
security=SSPI");
}

private void btnCommit_Click(object sender, System.EventArgs e)


{
trans.Commit();
}

private void btnRollBack_Click(object sender, System.EventArgs e)


{
trans.Rollback();
}

private void btnBak_Click(object sender, System.EventArgs e)


{
SqlCommand cmdBak=new SqlCommand("SELECT * FROM Personel",con);
cmdBak.Transaction=trans;
da=new SqlDataAdapter(cmdBak);
DataTable dt=new DataTable();
da.Fill(dt);
dataGrid1.DataSource=dt;
}

private void btnEkle_Click(object sender, System.EventArgs e)


{
SqlCommand cmdGir=new SqlCommand("INSERT INTO Personel (ISIM,SOYISIM) VALUES
('"+txtIsim.Text+"','"+txtSoyisim.Text+"')",con);
cmdGir.Transaction=trans;
int sonuc=cmdGir.ExecuteNonQuery();
MessageBox.Show(sonuc+" SATIR GIRILDI");
}

private void btnGuncelle_Click(object sender, System.EventArgs e)

www.bsenyurt.com Page 2225


{
SqlCommand cmdGuncelle=new SqlCommand("UPDATE Personel SET
ISIM='"+txtIsim.Text+"', SOYISIM='"+txtSoyisim.Text+"' WHERE ID="+txtID.Text,con);
cmdGuncelle.Transaction=trans;
int sonuc=cmdGuncelle.ExecuteNonQuery();
MessageBox.Show(sonuc+" SATIR GUNCELLENDI");
}

private void btnBakID_Click(object sender, System.EventArgs e)


{
SqlCommand cmd=new SqlCommand("SELECT ISIM,SOYISIM FROM Personel WHERE
ID="+txtID.Text,con);
cmd.Transaction=trans;
da=new SqlDataAdapter(cmd);
DataTable dt=new DataTable();
da.Fill(dt);
dataGrid1.DataSource=dt;
}

Kodlarmzda zel olarak yaptmz bir ey yok. Ado.Net'i kullanarak, bizim iin gerekli satrlar
oluturduk. u an iin odaklanmamz gereken, e zamanl Transaction' lar arasndaki problemlerin
irdelenmesi.

Phantoms;

ki Transaction olduunu ve bunlarn e zamanl olarak altn dnelim. Transaction1, veri


tabanndan herhangibir tabloya ait belirli bir veri kmesini ekmi olsun. Ayn veri kmesine
Transaction2' ninde baktn dnelim. Transaction2, tabloya yeni satrlar girsin ve Transaction'
onaylansn(Commit). Bu noktadan sonra, halen daha alan Transaction1, ayn veri kmesini
tekrardan Transaction ierisinde talep ettiinde, yeni eklenmi satrlar olduunu grecektir. Bu
satrlar, hayalet olarak dnlr ve bu nedele Phantom olarak adlandrlr. nk, Transaction1
ilemini sonlandrmadan veri kmesinin yeni bir ekline sahip olmutur. Yeni eklenen satrlar onun
iin bir anda ortaya kan hayalet satrlar gibidir. imdi dilerseniz, bu olay simle etmeye alalm.
ncelikle, gelitirdiimiz uygulamadan iki adet altrmamz gerekiyor. Sonra bu uygulamalardan
Balat balkl butonlara tklayarak Transaction' larmz altrmalyz. Artk elimizde alan iki e
zamanl Transaction var. imdi, yukarda bahsettiimiz senaryoyu uygulayalm. nce Transaction'
lardan birisi ile veri ekelim.

www.bsenyurt.com Page 2226


ekil 2. Transaction1 veri ekiyor.

Ardndan dier uygulamada alan Transaction zerinden yeni bir ka kayt girelim ve bu
Transaction' Commit edelim.

www.bsenyurt.com Page 2227


ekil 3. Ezamanl alan Transaction2 yeni satr girdi ve ilem onayland (Commit).

imdi almaya devam eden yani ak olan Transaction'n olduu uygulamaya geelim ve veri
kmesini yeniden Bak isimli butona tklayarak isteyelim.

ekil 4. Transaction1 iin, Phantom Satrlar Olutu.

te burada oluan Ahmet Nacarolu satr hayalet satrdr. Bu durumun meydana gelmesi iin, giri
ilemlerini yapan Transaction' n onaylanm olmas gerektiini hatrlatmak isterim. Aksi takdirde,
dier Transaction ile veriler ekilmek istendiinde, belirli bir sre dier Transaction'n bu ilemleri
tamamlayp(Commit) tamamlamyaca(Rollback) beklenir ve bu sre sonunda bekelenen olmassa
uygulama bir istisna frlatr. (Bu nedenle, Transaction2' de girdiimiz satrlardan sonra, Onayla
balkl butona basmay unutmayalm.)

Non-Repeatable Reads;

Yine iki e zamanl alan Transaction' mz olduunu dnelim. Transaction' lardan birisi yine veri
ekmi olsun. zellikle ektii belirli bir satr olabilir. Dier Transaction' da bu belirli satr veya
bakalarn gncellesin ve ilemi onaylansn (Commit). te bu noktadan sonra, dier almakta
olan Transaction ayn satrlara yeniden baktnda verilerin deimi olduunu grecektir. te bu
satrlardaki ani ve bilinmeyen deiiklikler nedeni ile, bu durum Non-Repeatable Read olarak
adlandrlmtr. imdi bu durumu simle edebilmek iin, yine uygulamamzdan iki tane altralm
ve Transaction' larmz balatalm. lk Transaction ile okuduumuz verilerden belirli bir satr
zerinde, ikinci Transaction'da deiiklik yapalm ve bu Transaction' onaylayalm(Commit).

www.bsenyurt.com Page 2228


ekil 5. Transaction2' de Transaction1' de aynen grnen satrlardan birisinde gncelleme yapld.

imdi bu Transaction' onaylayalm ve dier Transaction' da verileri tekrardan ekelim. Bu


durumda, ID deeri 58 olan satrn verilerinin deimi olduunu grlr.

www.bsenyurt.com Page 2229


ekil 6. Transaction1 iin NonRepeatable-Read durumu.

Dirty Reads;

Bu durum Phantoms ve Non-Repeatable Read durumlarna gre biraz daha farkldr. E zamanl
olarak alan Transaction' lardan birisi, dierinin okuduu ayn veriler zerinde deiiklik yapar.
Aynen Non-Repeatable Read' e neden olan durumda olduu gibi. Ancak nemli bir fark vardr.
Deiiklik yapan Transaction Commit edilmeden, dier Transaction ayn satrlar tekrar okur ve
deiiklikleri grr. Bu andan sonra, deiiklikleri yapan Transaction yapt gncellemeleri
RollBack ile geri alr. te bu noktada, verileri okuyan Transaction' da geri alnm (RollBack) yani
veri tabanna yanstlmam deiiklikler halen daha var olacaktr ki aslnda bu deiiklikler mevcut
deildir. te bu durum Dirty-Reads olarak adlandrlr. imdi bu durumu simle etmeye alalm.
Ancak burada sz konusu olan Transaction' lar e zamanl almakla birlikte, birisi Commit veya
RollBack edilmeden dierininde veri ekme gibi ilemleri yapabilmesine izin veren yapdadrlar. O
nedenle bir sonraki makalede zerinde duracamz IsolationLevel numaralandrcs trnden bir
deer ile Transaction' lar altrmamz lazm. Bu amala aadaki satr;

trans=con.BeginTransaction();

aadaki ile deitirelim.

trans=con.BeginTransaction(IsolationLevel.ReadUncommitted);

u aamada bunun ne anlama geldiinin ok nemi yok. Bunu ve dier numaralandrc deerlerinin
etkilerini bir sonraki makalemizde incelemeye alacaz. imdi yine iki uygulamamz ayn anda
altralm ve Transaction' larmz balatalm. nce Transaction1 iin verileri ekelim.
Transaction2' de belli bir satr zerinde deiikliklik yapalm.

www.bsenyurt.com Page 2230


ekil 7. Ezamanl alan Transaction2' de belirli bir satr zerinde gncelleme yapld.

imdi Transaction1 iinde, verileri tekrardan ekelim. Bu durumda Transaction2 ile, ID deeri 70
olan satr zerinde yaplm olan deiiklii grrz.

ekil 8. Transaction1 verileri tekrardan ekiyor ve deiiklikleri gryor.

imdi Transaction2' de yaptmz gncelleme ilemini geri alalm. te bu durumda, Transaction1


iinde, Transaction2 tarafndan satrn gncellenmi fakat onaylanmam, daha da nemlisi geri
alnm hali kalr. te bu durum Dirty Reads olarak adlandrlmaktadr. Bu durum ile ilgili olarak
alnabilecek tedbirler, IsolationLevel numaralandrcs ile belirlenir. Bu numaralandrcy ve
kullanm ekillerini bir sonraki makalemizde incelemeye alacaz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Transaction' larda SavePoint Kullanm (


15.06.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Ado.Net ile gerekletirilen transaction ilemlerinde, sql' de yer alan SavePoint'
lerin nasl uygulandn incelemeye alacaz. Sql' de transaction ilemlerinde, her bir i
parasndan sonra gelinen noktann birer SavePoint olarak kaydedilmesi sk rastlanan bir tekniktir.
Bir transaction birden fazla i parasna sahiptir. Her bir i parasnn baarl olmas halinde, tm
bu ilemler onaylanarak (commit) kesin olarak veritabanna yanstlr. Dier yandan, i paralarnn

www.bsenyurt.com Page 2231


herhangibirisinde meydana gelebilecek bir aksaklk sonucu transaction RollBack ilemini uygular ve
tm ilemler yaplmam saylarak veritaban, transaction balamadan hemen nceki haline getirilir.

Ancak ou zaman transaction bloklar ierisine aldmz i paralar, ok fazla sayda olup,
herhangibir noktada meydana gelebilecek RollBack ilemi sonucu o ana kadar yaplan tm
ilemlerin geersiz saylmas istenen bir durum olmayabilir. te byle bir durumda, baarl bir
ekilde gerekleen ilerden sonraki kod satrlarna dnmek daha mantkl bir yaklamdr. Elbette
bu durum havale, eft gibi bankaclk ilerini kapsayan transaction' larda tercih edilmemelidir.

SavePoint' lerin alma mantnda, transaction iindeki belirli noktalarn iaretlenmesi


yatmaktadr. Bu durumda, RollBack ilemi sz konusu olduunda, bu iaretlenmi noktalardan
birisine dnlebilme imkanna sahip olunur. te Sql transaction' larndaki bu teknii, .net ile
gelitirdiimiz uygulamalarda da simule edebilmek iin, Transaction snflarnn aada
SqlTransaction snf iin prototipi verilen Save metodu kullanlr.

public void Save(string savePointName);

Bu metod parametre olarak, SavePoint' in ismini belirten string trde bir deer alr. SavePoint
olarak kaydedilmi bir noktaya RollBack ilemi ile geri dnebilmek iin, RollBack metodunun
aadaki prototipi kullanlr.

public void Rollback(string transactionName);

Burada, RollBack metoduna, parametre olarak string trden SavePoint' in ad verilir. Burada nemli
olan, RollBack ile herhangibir SavePoint' e dnlmesinden sonra eer Commit ilemi uygulanrsa,
SavePoint' e kadar yaplan i paralarnn kesin olarak veritabanna yanstlacadr. imdi
SavePoint kullanmna ilikin olarak basit bir rnek gelitirelim. rnek windows uygulmasnda, 3 i
paras ieren bir transaction kullanacaz. Bu transaction ileminde, SavePoint' lere yer verecek ve
bu noktalarn veritabanna olan etkisini basite incelemeye alacaz. Bu amala aadaki form
grnmne benzer bir windows uygulmas tasarlayarak ie balayalm.

www.bsenyurt.com Page 2232


ekil 1. Form Tasarmmz.

imdi uygulama kodlarmz gelitirelim.

/* SqlConnection ve SqlTransaction nesnelerimizi tanmlyoruz.*/


SqlConnection con;
SqlTransaction trans;

private void frmMain_Load(object sender, System.EventArgs e)


{
/* Uygulamamz yklenirken, SqlConnection nesnemizi oluturuyoruz. Yerel sql sunucusunda yer
alan, Northwind veritabanna balant salayacaz.*/
con = new SqlConnection("data source=localhost;initial catalog=Northwind;integrated
security=SSPI");
}

private void btnBegin_Click(object sender, System.EventArgs e)


{
/* Kullanc transaction' balatyor. nce balantmz alr daha sonra SqlConnection
nesnemizin BeginTransaction metod ile, transaction' mz bu balant iin balatlr. Ardndan al
ilemi listBox kontrolne yazlr.*/
con.Open();
trans=con.BeginTransaction();
listBox1.Items.Add("Transaction basladi...");

www.bsenyurt.com Page 2233


}

private void btnEkle1_Click(object sender, System.EventArgs e)


{
/*Burada transaction' mz iinde altrlacak bir i paras uygulanyor. Bu i parasnda,
Personel isimli tabloya veri girii yaplmakta.*/
SqlCommand cmd=new SqlCommand("INSERT INTO Personel (ISIM,SOYISIM) VALUES
('BURAK','SENYURT')",con);
cmd.Transaction=trans; /* SqlCommand iin transaction nesnesi belirtilir.*/
try
{
int sonuc=cmd.ExecuteNonQuery(); /* Komutumuz altrlr.*/
trans.Save("Insert_1"); /*Transaction' mz iinde bu noktada bir SavePoint oluturulur.*/
listBox1.Items.Add(sonuc+" Kayit eklendi. SavePoint=Insert_1"); /* Durum listBox'a
yazlr.*/
}
catch
{
listBox1.Items.Add("HATA...");
trans.Rollback(); /* Bir hata oluursa ilk hale dnlr.*/
}
}

private void btnEkle2_Click(object sender, System.EventArgs e)


{
/*Burada transaction' mz iinde altrlacak bir i paras uygulanyor. Bu i parasnda, Per
isimli tabloya veri girii yaplmakta. Ancak tablomuzun ismi Personel olmal ve Per isimli bir
tablomuzda yok. Bu nedenle burada bir hata oluacaktr. te bu hata sonucu transaction'mz
RollBack ilemi ile Insert_1 isimli SavePoint noktasna dner.*/
SqlCommand cmd=new SqlCommand("INSERT INTO Per (ISIM,SOYISIM) VALUES
('SEFER','ALGAN')",con);
cmd.Transaction=trans;
try
{
int sonuc=cmd.ExecuteNonQuery();
trans.Save("Insert_2");/* Insert_2 isminde bir SavePoint oluturulur.*/
listBox1.Items.Add(sonuc+" Kayit eklendi. SavePoint=Insert_2");
}
catch
{
listBox1.Items.Add("HATA...DONUS-->Insert_1");
trans.Rollback("Insert_1"); /* Insert_1 isimli SavePoint noktasna dnlr.*/
}
}

private void btnSil_Click(object sender, System.EventArgs e)


{
/*Personel tablosundan ID alannn deeri 1 olan satr silecek komutu ieren bir i paras
uygulanyor. Ancak ID=1 olan bir satr yok ise bir istisna oluacaktr. Bu durumda RollBack ilemi

www.bsenyurt.com Page 2234


ile, Insert_2 isimli SavePoint noktasna dnlr. */
SqlCommand cmd=new SqlCommand("DELETE FROM Personel WHERE ID=1",con);
cmd.Transaction=trans;
try
{
int sonuc=cmd.ExecuteNonQuery();
listBox1.Items.Add(sonuc+" Kayit silindi.");
}
catch
{
listBox1.Items.Add("HATA...DONUS-->Insert_2");
trans.Rollback("Insert_2"); /* Insert_2 SavePoint noktasna dnlr.*/
}
}

private void btnCommit_Click_1(object sender, System.EventArgs e)


{
/* Transaction onaylanr. Eer transaction herhangibir SavePoint' te ise, o noktaya kadar olan
tm ilemler onaylanr. */
trans.Commit();
listBox1.Items.Add("Islemler Onaylandi...");
if(con.State==ConnectionState.Open)
{
con.Close();
}
}

Burada dikkat edilecek olursa, ikinci Insert ileminde yanl bir tablo ismi verilmitir. Ayrca silme
ilemi iin kullandmz sql cmleciinde, ID alannn deerinin 1 olmas garanti deildir. te
buralarda, istisnalar frlayacaktr. Ancak catch bloklarnda bu istisnalar yakandktan sonra RollBack
ilemi ile daha nceden kaydedilen belirli bir SavePoint' e dnlmektedir. te bu noktalardan sonra
Commit ilemini uygularsak, bu SavePoint' lere kadar olan tm i paralar onaynalacak ve
veritabanna yanstlacaktr. Bu durumu aadaki ekil ile daha kolay anlayabiliriz.

www.bsenyurt.com Page 2235


ekil 2. SavePoint Kullanm

imdi bu durumu analiz etmek iin uygulamamz altralm.

ekil 3. Ekle 2 ileminde hata.

www.bsenyurt.com Page 2236


nce Ekle 1 balkl butona basarak ilk Insert ilemimizi altralm. Daha sonra Ekle 2 balkl
butona tklayarak ikinci insert ilemini altralm. Burada Per isimli tablo olmad iin bir istisna
oluacaktr. Bu durumda Catch bloundaki RollBack metodu ile transaction Insert_1 isimli
SavePoint'e dner. Eer bu anda Onayla balkl butona tklar ve transaction' onaylarsak (Commit)
tablomuzun grnmnn aadaki gibi olduunu farkederiz. (Tablonun ilk hali hi bir kayt
iermemektedir.)

ekil 4. Insert_1 SavePoint'inden Sonra Commit Sonucu Tablonun Durumu.

Grld gibi, Insert_1 SavePoint' ine kadar olan ilemler (ki burada sadece ilk Insert komutu
oluyor) veritabanna yanstlmtr. imdi kodumuzdaki ikinci insert ifadesinde yer alan Per isimli
tablo adn dzeltelim ve bunu Personel yapalm. Bu durumda ikinci Insert ilemimizde geerli
olacaktr. Ancak halen Delete ileminde problem kmas olasdr. Nitekim, tablomuzda yeni
girdiimiz ilk satrn ID deeri 51' dir. Identity olarak tanmlanan bu alann 1 deerine sahip olmas
u anki artlarda imkanszdr. Dolaysyla Delete ileminde yine bir istisna frlayacak ve bu kez,
Insert_2 isimli SavePoint' e dnlecektir. imdi bu son durumu analiz etmek iin uygulamz
dzenleyelim ve tekrar altralm.

ekil 5. Delete ileminde meydana gelen istisna sonras Commit ilemi uygulanrsa.

nce, Baslat balkl butona tklayarak Transaction' mz balatalm. Ardndan srasyla Ekle 1, Ekle
2 ve Sil balkl butonlara tklayalm. Bu ilemler sonucunda Delete ileminde ID'si 1 olan satr
olmadndan bir istisna oluacak ve transaction'mz RollBack metodu ile, Insert_2 olarak

www.bsenyurt.com Page 2237


isimlendirdiimiz SavePoint' e dnecektir. Bu noktada Onayla balkl butona tklarsak, Commit
ilemi sonucu Insert_2 noktasna kadar olan iki Insert ilemimizde onaylanacak ve veri tablosuna
yanstlacaktr.

ekil 6. Delete ilemindeki istisna sonras Commit uygulandnda, tablonun son hali.

Bu makalemizde, Sql SavePoint' lerinin Ado.Net iindeki transaction' larda nasl kullanldn
incelemeye altk. Gelitirdiimiz rnek, sadece SavePoint' lerin kullanmn inceleme amacnda
olduundan, farkl trden hatalara aktr. Ancak nemli olan, SavePoint'lerin bir transaction
nesnesi iin nasl kayt edildikleri ve RollBack ilemleri sonucu bu noktalara nasl dnlebildiidir.
Ayrca, bu tip RollBack ilmeleri sonrasnda verilen Commit emirlerinin verileri gerek anlamda nasl
etkilediinede dikkat etmek gerekir. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

XML Rapor Web Servisleri ( 10.06.2004 ) - Web


Servis
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Crystal Report'larn birer web servisi olarak nasl yaynlanacaklarn ve istemciler
tarafndan kullanlacaklarn ksaca incelemeye alacaz. Hepimizin bildii gibi Web Servislerinin
gnmz teknolojilerine getirdii en byk yenilik, merkeziletirilmi metodlarn, herhangibir
platformda yer alan saysz istemci tarafndan, hi bir engele yada kstlamaya taklmadan kolayca
arlabilmeleri ve sonularn ayn yollar ile kolayca sorunsuz elde edilebilmeleridir. yleki, web
servislerinin XML tabanl olarak, SOAP protokolnn belirledii kriterlerde HTTP gibi basit iletiim
protokolleri zerinden anlamay desteklemesi, onlarn esnek, genileyebilir, kolay eriilebilir ve
popler olmalarn salamtr.

te web servislerinin sunmu olduu bu imkanlardan, gelitirmi olduumuz Crsytal Report'larnda


faydalanmalarn salayabiliriz. ounlukla, mterilerimizin yada firmamz ile birlikte alan
tedarikilerimizin, ortak bir noktadan, Crystal Report olarak hazrladmz esnek ve gl
raporlara, her platformdan sorunsuz ulalabilmeleri amacyla web servisi tabanl raporlar gelitirilir.

XML Rapor Web Servislerinin gelitirilmesi iki aamal bir ilemden ibarettir. lk olarak, rapor
dosyamz baz alcak bir web servisinin gelitirilemesi gerekir. Bu raporu kullanmak iin ise,
standart bir web servisinin kullanlmasnda uygulanan prosedrler iletilir. Yani, web servisine ait
referans, uygulamaya eklenir. Sonrasnda ise, eer uygulamay Visual Studio.Net ile gelitirdiysek,
web servisimiz iin uygulamamzda bir proxy nesnesi, bu servisin istemci uygulamaya indirilen wsdl
dkman vastasyla otomatik olarak oluturulur. Sonrasnda, istemci uygulamamz ile web
servisimiz arasndaki mesajlamalar SOAP protokolnn belirledii tipte bu proxy nesnesi
yardmyla gerekletirilir. Dolaysyla, gelitireceimiz istemci uygulamada, bu proxy snfna ait
nesne rneini kullanmamz gerekecektir.

www.bsenyurt.com Page 2238


Laf fazla uzatmadan XML Rapor Web Servislerinin gelitirilmesi ile ie balyalm. Bu amala ilk
olarak Visual Studio.Net ortamnda bir Asp.Net Web Uygulamas aalm. Bu noktada
uygulamamza, Solution Explorer'dan sa tklayarak atmz menden Add Exsiting Item ile daha
nceden gelitirmi olduumuz herhangibir rpt uzantl rapor dosyasn ilave edelim. (Bu noktada
asl amacmz rapor dosyasnn nasl oluturulduu olmad iin, bu konunun stnde fazla
durmayacam.)

Ben uygulamamda rnek olarak, daha nceden gelitirdiim ok basit bir rapor dosyasn
kullandm. Bu rapor, Sql Server sunucusunda yer alan Northwind veritabanndaki Customers
tablosuna ait bir ka veriden olumakta. Bizim iin asl nemli olan ksm, bu raporun, bir web
servisi olarak yaynlanmak istenmesidir. te bu amala raporumuza sa tklyor ve kan menden
Publish As Web Service seeneini iaretliyoruz.

ekil 1: Raporun Web Servisi Olarak Yaynlanmas.

Bu ilemin ardndan raporumuz iin, asmx uzantl web servisi dosyamzn oluturulduunu grrz.

www.bsenyurt.com Page 2239


ekil 2: Raporumuzun Web Servisi Haline Getirilmesi.

Dilersek bu sayfay web browser'dan altrarak raporumuz ile ilgili olarak neler yapabileceimi
grebiliriz. Artk elimizde, raporumuzu kullanmak isteyen istemcilere sunabileceimiz bir web
servisimiz var. Son adm olarak uygulamamz derleyelim. imdi bu XML Rapor Web Servisini
kullanmak isteyen istemcileri nasl gelitireceimize bakalm. Bunun iin rnek olarak bir Asp.Net
web uygulamas aalm. Bu uygulamaya web servisinden elde edeceimiz raporu gsterecek olan
bir Cyrstal Report Viewer nesnesini ekleyelim. Sayfamz aadakine benzer bir yapda olabilir.

ekil 3: stemci Asp.Net sayfasnn tasarm grnm.

Tanmlanm olan bir web servisini, bir istemciye eklemek iin, Add Web Reference seeneini
kullanrz. Bu durum, elbetteki XML Rapor Web Servisleri iinde geerlidir.

ekil 4. XML Rapor Web Servisinin stemci Uygulamaya Refernas Edilmesi.

Buradab karmza aadaki pencere gelicektir. Biz yerel makinede altmz ve web
servisimizide localhost'umuzda gelitirdiimiz iin, kullanlabilir web servislerini renmek amacyla
getirilen listeden, Web services on the local machine linkini seebiliriz.

www.bsenyurt.com Page 2240


ekil 5. Kullanlabilir web servislerinin renilmesi.

Bu linki setiimiz takdirde sistemde kullanabileceimiz web servisleri ekrana gelicektir. Bu


servislerden bir taneside, gelitirmi olduumuz XML Rapor Web Servisidir. Bu raporu seerek, web
servisine ait referans uygulamamza ekleyelim.

ekil 6. XML Rapor Web Servisimizin Seilmesi

XML Rapor Web Servisimizin seilip, istemci uygulamamza eklenmesi ile birlikte, vs.net bu web
servisine ait wsdl dosyasn talep eder. Wsdl dkman web servisinin public arayznn bir
grntsn xml formatnda istemci uygulamada kullanabilmemizi salar. Bu ilemin ardndan,
istemci uygulamada XML Rapor Web Servisimize ait Wsdl dkmanda otomatik olarak oluturulur.
Bu dkman yardmyla da, web servisimiz ile aramzdaki ilikiyi nesnesel bazda
gerekletirebilmemizi salayan proxy snfmz oluturulacaktr. Bu durumda Solution Explorer' da
projemizin son halinin aadaki gibi olduunu grrz.

www.bsenyurt.com Page 2241


ekil 7. Proxy Snfmz Oluturulur.

Artk tek yapmamz gereken, XML Rapor Web Servisimizden elde edeceimiz raporun ieriini,
Crystal Report Viewer nesnemizde gstermek. Bunun iin aadaki basit kod satrlarn
uygulamamza eklememiz yeterli olucaktr.

private void btnRaporla_Click(object sender, System.EventArgs e)


{
/* ncelikle proxy snfmza ait bir nesne rneini oluturuyoruz. */
localhost.MusteriRaporlariService rapor=new RaporIstemci.localhost.MusteriRaporlariService();
this.CrystalReportViewer1.ReportSource=rapor; // Web sayfamzdaki CrystalReportViewer
nesnemize rapor kayna olarak, proxy nesnemizi atyoruz. */
this.CrystalReportViewer1.DataBind(); /* Nesnemizi gelen rapor verilerine balyoruz.*/
}

Burada olanlar ksaca zetlemek gerekirse; ncelikle XML Rapor Web Servisimizin istemci
uygulama iin oluturulan proxy snfndan bir nesne rnekledik. Bylece, istemcimizdeki Crystal
Rapor nesnemiz, bu proxy snfndan elde edilen verileri gsterecek. Elbetteki proxy nesnemizde bu
verileri, XML Rapor Web Servisimizden almakta. Web sayfamz altrp, buton kontrolmze
tkladmzda aadakine benzer bir sayfa ile karlarz.

www.bsenyurt.com Page 2242


ekil 8. Raporun Elde Edilmesi.

Bu makalemizde en basit haliyle, XML Rapor Web Servislerinin nasl oluturulduunu ve


kullanldn incelemeye altk. Grld gibi kilit nokta, raporun web servisi olarak
yaynlanmasdr. (Publish As Web Service) Dier taraftan geri kalan btn ilemler web servislerinin
istemcilerde kullanlmasndaki teknikler ile ayndr. lerleyen makalelerimizde grmek dileiyle
hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

.NET Remoting'i Kavramak ( 22.05.2004 ) -


Remoting
Deerli Okurlarm, Merhabalar.

Bu makalemizde, .net remoting sistemini anlamaya alacak ve .net remoting sistemini oluturan
temel yaplar zerinde duracaz. ncelikle .net remoting' in ne olduunu ve ne ie yaradn
tanmlamakla ie ballaym. Remoting sistemi, ksaca, farkl platformlarda alan uygulamalar
arasnda veri alveriine imkan salayan bir sistemdir. Bu tanmda sz konusu olan platformlar
farkl iletim sistemlerinin yer ald farkl ve birbirlerinden habersiz proseslerde alan
uygulamalar ierebilir. Olayn en kilit noktasda, farkl sistemlerin veri alveriinde
bulunabilmelerinin salanmasdr.

Konuyu daha iyi irdeleyebilmek amacyla, Microsoft tarafndan belirtilen u rnei gz nne
alabiliriz. Bir pocket pc aygtnda, Windows CE iletim sistem zerinde, C# dili ile yazlm bir
uygulamamz olduunu dnelim. Bu uygulama herhangibir paras olmad bir ada yer alan bir
uygulamann ilgili metodlarn aryor olsun. Uzak network zerinde kurulu olan bu uygulama,

www.bsenyurt.com Page 2243


Windows 2000 iletim sisteminde alan VB ile yazlm ve baka bir sql sunucusunda yer alan bir
takm bilgileri tedarik eden bir yapya sahip olabilir. te .net remoting ile bu iki farkl uzak nesne
arasnda kolayca iletiim kurabilir ve veri alveriini salayabiliriz.

Remoting sisteminin bize vadettii aslnda, herhangibir zamanda, yerde ve aygt zerinden bilgi
eriimine izin verilebilmesidir. Bu aadaki ekilde daha anlalr bir biimde ifade edilmeye
allmtr.

ekil 1. NET Remoting Sisteminde Temel Ama

Gelelim .net remoting sisteminin temel olarak nasl altna ve nelere ihtiya duyduuna.
ncelikli olarak sistemde uzak snrlarda yer alan nesnelerin olduunu syleyebiliriz. Bu nesneler
arasnda meydana getirilecek iletiim, .net remoting alt yapsnda yer alan bir takm yeler ile
salanacak. Hereyden nce, uzak nesneler arasnda hareket edicek mesajlarn tanmas ilemi ile,
iletiim kanallarnn (Communication Channels) ilgilendiini syleyebiliriz. Uzak nesneler arasndaki
tm mesajlar bu kanal nesneleri yardmyla tanacak, kodlanacak (encoding) ve zlecektir
(decoding) . Kodlamaktan kastmz, uzak nesneler arasnda tanacak mesajlarn, kullanlan iletiim
protokolnn tipine gre belli bir formatta seriletirilmesi (serialization)dir. Dier yandan kodlanan
bu mesajn ayn kurallar evresinde dier uzak nesne tarafndan zmlenmesi (decoding)
gerekecektir. Zaten aradaki mesajlarn yaygn iletiim protokolleri zerinden gerekletirilmesi,
remoting'in en temel zelliklerinden birisidir.

Bir iletiim kanal nesnesi yardmyla tanan mesajlar, doal .net serletirici formatlar (binary,
soap) kullanlarak, kodlanr ve zlrler. Bir uzak nesne, baka bir uzak nesneye mesaj
gnderdiinde, bu mesaj, kullanlan kanal nesnelerinin esas ald protokoller erevesinde
seriletirilerek binary yada xml formatna dntrlr. Mesaj alan uzak nesne ise, seriletirilmi
bu mesaj uygun protokol tabanl .net seriletirme formatlarn kullanarak aar ve kullanr.
Seriletirme amacyla kullanlan iki kodlama eidi vardr.

www.bsenyurt.com Page 2244


ekil 2. Seriletirme Seenekleri

Gelelim dier nemli bir konuya. Uzak nesneler nasl kullanlacak. zellikle server (Sunucu) nitelikli
merkezi nesnelere, client (istemci) uygulamalardan nasl eriilebilecek. Bunun iin uzak nesnelere
ait referanslara ihtiyacmz olucaktr. Ancak burada karmza adresleme sorunu kacaktr. Nitekim,
herhangibir proses iinde alan bir nesne iin, uzak nesnelerin alt prosesler anlaml deildir.
Bu sorunun almasnda kullanlabilecek ilk yol sunucu nesnesinin, istemcilere kopyalanmasdr. Bu
durumda istemci uygulama, sunucu nesnesinin bir rneine ihtiya duyduunda bunu local olarak
kullanabilecektir.

Ancak kopylama ynteminin bir takm dezavantajlar vardr. Hereyden nce ok sayda metod
ieren byk boyutlu nesnelerin kopylanmas verimlilik ve performans asndan negatif bir etki
yaratacaktr. Bununla birlikte, istemci uygulamalar, server nesnelerinin sadece belirli metodlarn
kullanyor olabilirler. Buda nesnenin tamammn kopyalanmasnn anlamsz olmasna neden olan bir
dier durumdur. Bir dier dezavantaj ise, server nesnesinin bulunduu sistemdeki fiziki adreslere
referanslar ierebiliecek olmasdr. rnein dosya sistemine bavuruda bulunan nesneleri
barndran server nesneleri sz konusu olabilir. Byle bir durumda elbetteki kopyalama sonucu bu
referanslar yitirilecek ve istemci tarafndan kullanlamyacaktr. Son olarak, server nesnesinin
kopyalanmasnn, istemci kaynaklarn harcadn syleyebiliriz.

Bu dezavantajlar gz nne alndnda bize baka bir yntem gerekmektedir. Bu teknikte, server
nesnelerini kullanmak iin, bu nesnelere referansta bulunan proxy nesneleri kullanlr. stemci
uygulama, bir uzak nesneye ihtiya duyduunda, bu talebini proxy nesnesine iletecektir. Proxy
nesnesi ise, .net remoting'in salam olduu imkanlar dahilinde, ilgili uzak nesnesin ilgili yesinin
referansna bavuracak, bu metodu altracak ve dnen sonular yine proxy nesnesi araclyla,
istemci uygulamaya ulatracaktr. Bu konuyu aadaki ekil ile daha net bir biimde zihnimizde
canlandrabiliriz.

ekil 3. Proxy Nesnesinin Kullanlmas

Remoting sisteminde kullanlan nesnelerin kopyalanabilmesi veya refarans olarak deerlendirilmesi,


remoting nesnelerinin iki temel kategoriye ayrlmalarna neden olmutur. Remotable nesneler ve
NonRemotable nesneler. Remotable nesneler, Baka uygulamalarca kopyalanma veya referans
teknii ile eriilebilen nesnelerdir. NonRemotable nesneler ise, dier uygulamalar tarafndan
eriilemiyen nesnelerdir. ounlukla byk boyutlu, ok sayda metod ieren veya local olarak fiziki
adres referanslarna ihtiya duyan uzak nesnelerin, nonRemotable olarak belirtilmesi sk grlen bir
tekniktir. Peki bu durumda bu nesneleri kullanmak isteyen uzak uygulamalar nasl bir yol izleyebilir
? te bu noktada, nonRemotable nesnelerin, istemcilere alabilecek olan blmleri iin remotable
nesneler kullanlr.

www.bsenyurt.com Page 2245


Dier yandan remotable nesneler, kopylama veya referans tamaya imkan veren uzak nesnelerdir.
Burada ise karmza iki eit remotable nesne oluumu kar. Marshall By Value tipi remotable
nesneler ve Marshall by Reference tipi remotable nesneler. Bu kategorilendirme ekilsel olarak
aadaki gibidir.

ekil 4. Uzak Nesnelerin Temel Kategorilendirilmesi.

zellikle remotable nesneler iin yaplan ayrm kullanm asndan ok nemlidir. Marshall By Value
olarak belirlenmi remotable nesneler, bir istemci tarafndan talep edildiklerinde, zellikle bu
nesnenin herhangibir metodu istemci tarafndan arldnda, .net remoting sistemi bu nesnenin
bir kopyasn oluturur ve bu kopyay iletim kanal nesneleri yardmyla seriletirerek, ary yapan
istemciye gnderir. stemci tarafnda yer alan, .net remoting sistemi ise bu kopyay zmler ve bir
nesnenin bir kopyasn istemci makinede oluturur. Nesnenin, istemciye kopyalanabilmesi iin
seriletirme ilemi uygulanr. Burada nemli olan nokta, seriletirmenin otomatik olarak
gerekletirilebilmesi iin, nesneye ISerializable arayznn uygulanmasdr. Nesnelerin,
istemcilere bu yolla tanmas zellikle istemciler asndan ilem zamann ksaltc bir etken olarak
karmza kmaktadr. Nitekim istemcinin talep ettii metodlara, artk istemcideki uzak nesnenin
kopyas zerinden eriilmektedir.

Marshall By Reference nesneleri ise, istemci uygulamalar iin bu sistemlerde birer proxy nesnesi
eklinde oluturulur. Bu proxy nesnesi, asl uzak nesneye ilikin referanslar ieren metadata
bilgilerine sahiptir. Uzak nesnenin herhangibir metodu arldnda, proxy nesnesi ilgili metodun
referans ile hareket eder ve bir takm bilgileri sunucuya gnderir. Sunucu gelen bilgi paketini
zmledikten sonra ilgili parametreleri deerlendirerek talep edilen metodu altrr ve bunun
sonucu olarak geri dn deerlerini istemci makinedeki proxy nesnesine gnderir. Sonular
istemciye bu proxy nesnesi yardmyla gnderilecektir.

Bir uzak nesnenin herhangibir metodunun arlmasnda veya uzak nesneye ait bir rnein
istemcide new anahtar szc ile oluturulmaya allmasnda, uzak nesnenin davran biimi ve
aktifletirilmesi nem kazanr. Nitekim uzak nesnenin aktif hale gelmesi iki teknik ile
gerekletirilebilmektedir.

www.bsenyurt.com Page 2246


ekil 5. Nesne Etkinletirme.

ncelikle sunucu tarafl etkinletirmeden bahsedelim. Bu etkinletirme tekniinde, istemci


tarafndan sunucu nesnesinin bir metodu arldnda, sunucu tarafndan bu nesneye ait bir rnek
oluturulur. Daha sonrada bu nesne rneinin proxy nesnesi, istemci tarafnda oluturulur. Burada
dikkat ekici nokta nesne rneinin, new anahtar szc ile deil, sunucu nesneye ait bir metod
arldnda oluturuluyor olmasdr.

Bu etkinletirme tekniine rnek olarak unu gsterebiliriz. Devlet dairelerindeki sunuculara bal
brolar olduunu dnelim. Sunucu nesnemiz, bu brolara, vergi numarasna gre kontrol ve
kimlik bilgisi deerlerini gnderiyor olsun. Bu rnekte bro istemcilerinin, sunucuya srekli bal
olduklarn dnelim. stemci, bir vergi numarasn kontrol etmek istediinde, sunucu nesnesindeki
ilgili metodu aracaktr. te bu noktada sunucu tarafl etkinletirme devereye girerek, metod
armna karlk sunucu nesnesinin rneini oluturur.

Dier yandan sunucu tarafl etkinletirmede, Singleton ve SingleCall teknikleri kullanmaktadr.


Singleton tekniine gre etkinletirmede, sunucu nesneyi kullanan ka istemci olursa olsun, her bir
istemcinin metod armlar sunucu tarafndaki tek bir nesne rnei tarafndan ynetilmektedir.
SingleCall tekniinde ise, istemci tarafndan yaplan her metod arsna karlk birer sunucu
nesnesi rnei oluturulacaktr.

stemci tarafl etkinletirmeye gelince. Bu kez sunucu tarafl etkinletirmenin aksine, new anahtar
szc ile bir sunucu nesne rnei istemci uygulamada oluturulduunda, sunucu zerinde
sunucu nesnesinin rnei oluturulacaktr. Bu tip kullanma rnek olarak chat uygulamalarn
gsterebiliriz.

Remoting sisteminde uzak nesneler dnda en nemli unsur mesajlar tayan kanal nesneleridir.
(Channels) Kanal nesneleri uzak bilgisayarlarda yer alan uzak nesneler arasndaki haberlemede rol
oynayan kilit nesnelerdir. Aradaki iletiimi salamak iin kullanlan kanal nesneleri, bu iletiim
zerinden mesajlarn gnderilmesi, tanmas ve alnmas gibi ilemlerden sorumludurlar. Bildiiniz
gibi kanal nesnelerinin tad mesajlar HTTP veya TCP protokolleri erevesinde hareket ederler.
Bir kanal nesnesi yardmyla, uzak kanallara mesaj gnderebilir yada uzak kanallardan gelen
arlar dinleyebiliriz.

Bir uzak nesne, baka bir uzak nesneye mesaj gnderdiinde, kanal nesneleri devreye girerek bu
mesaj binary veya xml formatnda seriletirir. Mesaj yani ary alan uzak nesne ise, bu mesajn
ieriini, buradaki kanaln mesaj binary veya xml formattan zmlemesi ile okuyabilir. Remoting
sisteminde kullanlan kanallara ilikin snflar ve arayzler System.Runtime.Remoting.Channels isim
alannda yer almaktadr.

www.bsenyurt.com Page 2247


Temelde btn kanal nesneleri IChannels arayzn uygulamaktadr. Kanal nesneleri iletiimde
oynayacaklar role gre kategorilendirilirler. Eer kanal nesnesi arlar dinlemek amacyla
kullanlacaksa, alc (receiver) veya server (sunucu) olarak adlandrlrlar. Bununla birlikte, mesaj
gndericek olan kanal nesneleri sender (gnderici) veya client (istemci) olarak adlandrlrlar.

ekil 6. Kanallar.

Receiver kanallar, IChannelSender arayzn uygulayan kanallardr. Kullandklar protokollere gre


HttpClientChannel ve TcpClientChannel snflarndan oluturulurlar. Dier yandan Sender kanallar,
IChannelReceiver arayzn uygulayan TcpServerChannel ve HttpServerChannel nesneleridir.
Dier nemli iki kanal nesnesi ise HttpChannel ve TcpChannel nesneleridir.

imdi dilerseniz bu kanallarn .net remoting sisteminde oynadklar rolleri ksaca incelemeye
alalm. Burada nemli olan, mesajlamann gerekletirilecei protokoldr. Nitekim HTTP
protokoln kullanacaksak buna uygun kanal nesnelerini kullanmal, TCP protokoln
kullanacaksakta buna uygun kanal nesnelerini kullanmalyz. Eer HTTP protokol kullanlacaksa,
System.Runtime.Remoting.Channels.Http isim alannda yer alan kanal snflarn kullanrz.

ekil 7. Http Kanallar.

stemciden, uzak nesnelere mesaj gndermek iin HttpClientChannel snfna ait nesne rnekleri
kullanlr. Dier taraftan, istemcilerden gelicek arlar dinleyecek kanal nesneleri ise,
HttpServerChannel snfndan rneklenir. HttpClient snfna ait nesne rnekleri ise mesaj almak ve
mesaj gndermek iin kullanlrlar. HttpClientChannel nesne rnekleri oluturulurken, bu kanaln
kullanaca bir port numarasn zellikle belirtmemiz gerekmez. Remoting sistemi o an iin
kullanlabilen serbest portlardan birisini bu kanal nesnesi iin tahsis edecektir. Dier yandan
arlar dinlemek amacyla tanmlanan bir HttpServerChannel kanal nesnesinin belirli bir port
numaras zerinden oluturulmas gerekmektedir. ayet o an iin kullanmda olan bir port
belirlenirse alma zamannda istisna alrz. Bununla birlikte HttpServerChannel nesnesinin yapc
metoduna 0 deerini gndererek, port seme insiyatifini otomatik olarak .net remoting sistemine
brakabiliriz.

Http kanallar SoapFormatter snfn kullanarak, mesajlar xml formatnda seriletirirler. Bununka
birlikte, TCP protokoln kullanan kanal nesneleri ise, seriletirme ilemini binary olarak yapar ve
bunun iinde BinaryFormatter snfn kullanrlar. TCP protokoln taban alan kanal nesneleri,
System.Runtime.Remoting.Channels.Tcp isim alannda yer alan snflardan rneklenirler.

www.bsenyurt.com Page 2248


ekil 8. Tcp Kanallar.

Tcp isim alannda yer alan snflar, Http'dekiler ile ayn ilevlere sahiptirler. Tek fark, kullanlan
seriletirme ileminin farkl oluudur. Her iki isim alan iinde, oluturulan kanal nesne rneklerinin
ChannelServices snfnda yer alan static RegisterChannel metodu ile sisteme kayt edilmeleri
gerekmektedir.(Registiration)

Kanallalarn kullanmnda dikkat edilmesi gereken en nemli nokta, uzak nesnelerin ayn protokol
destekleyen kanallar kullanmalarnn gerekli olduudur. rnein, istemcilerden gelen arlar
dinlemek amacyla Http protokoln taban alan kanal nesneleri kullanlyorsa, istemcilerdede mesaj
gndermek iin Http protokoln taban alan kanal nesneleri kullanlmaldr. Nitekim farkl protokol
tabanl kanallarn kullanlmasnda istisnalar alrz. Bunun sebebi, farkl protokol kullanmnn sonucu
olarak kodlama ve zmleme ilemlerinin farkl seriletirme teknikleri ierisinde yaplyor
olmasdr. Http ve Tcp kanallar arasndaki farklar u ekilde zetleyebiliriz.

1 Http kanal nesneleri Http protokoln, Tcp kanal nesneleri ise Tcp protokoln kullanr.

Seriletirme ileminde, Http kanal nesneleri SoapFormatter snfn kullanrken, Tcp kanal
2
nesneleri BinaryFormatter snfn kullanr.

Http kanal nesneleri iin seriletirme xml tabanl yaplrken, Tcp kanal nesneleri iin
3
seriletirme binary formatta yaplr.

Bu makalemiz ile .net remoting sisteminin temel yaptalarn tanmaya altk. Bir sonraki
makalemizde, en basit anlamda bir remoting uygulamasnn nasl yapldn incelemeye alacak
ve teoride anlattklarmzn programatik olarak nasl yazlacan greceiz. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Windows Servislerinin Kontrol - 2 ( Sistemdeki


Servislerin Kontrol Edilmesi ) ( 12.05.2004 ) -
Win Servis
Deerli Okurlarm, Merhabalar.

www.bsenyurt.com Page 2249


Bu makalemizde, sistemde yer alan windows servislerini bir windows uygulamasndan nasl elde
edebileceimizi ve nasl kontrol edebileceimizi incelemeye alacaz. nceki makalelerimizden
hatrlayacanz gibi, sistemde yer alan servislerimiz, System.ServiceProcess isim alannda yer alan
ServiceController snf nesneleri ile temsil edilmektedir. Eer sistemde yer alan servisleri elde
etmek istersek, aada ar yklenmi iki prototipi olan, GetServices metodunu kullanabiliriz.

GetServices Metodu Prototipleri Aklamas

Bu prototip ile, local makinede yer alan


public static ServiceController[] GetServices();
servisler elde edilir.

public static ServiceController[] Bu prototipte, parametre olarak verilen makine


GetServices(string); bilgisine ait servisler elde edilir.

Burada grld gibi, GetServices metodu ServiceController snf trnden bir diziyi geri
dndrr. Ayrca bu metod static bir metod oluduundan, dorudan ServiceController snf
zerinden herhangibir nesne rneine gerek duymadan arlabilir. Aada rnek olarak
sistemdeki servislerin elde edili teknii gsterilmektedir.

ServiceController[] svc;
svc=ServiceController.GetServices();

Elde edilen servislerin herbiri birer ServiceController nesnesi olarak, ele alnr. Elde ettiimiz
servislerin zerinde bildiiniz gibi, bir servisin temel davranlar olan
Start,Stop,Pause,Contiune,ExecuteCommand vb.larn aada prototipi verilen metodlar yardmyla
gerekletirebilmekteyiz.

Metod Prototip Aklama

public void Start();


Start Servisi altrr.
public void Start(string[]);

Stop public void Stop(); Servisi durdurur.

alan servisi
Pause public void Pause();
duraklatr.

Duraklatlm
servisin almasna
Contiune public void Continue();
devam etmesini
salar.

Servisin
ExecuteCommand public void ExecuteCommand(int command); OnCustomCommand
metodunu altrr.

www.bsenyurt.com Page 2250


Birazdan gelitireceimiz rnek uygulamada, sistedemki servisler zerinde yukarda bahsettiimiz
metodlar kullanarak, servislerin kontroln gerekletirmeye alacaz. Burada dikkat edilmesi
gereken bir ka nokta vardr. ncelikle bir servis balatlacaksa, bu servisin o an almyor olmas
baka bir deyile Stopped konumunda olmas gerekmektedir. Ayn durum bir servisi durdururkende
geerlidir. Byle bir durumdada, Stop edilecek servisin, Running konumunda olmas gerekmektedir.
te bu nedenlerden dolay, sistemdeki servislerin almaya balamas veya alanlarn
durdurulmas gibi hallerde, servisin o anki durumunu kontrol etmemiz gerekmektedir. Bu amala
ServiceController snfnn aada prototipi verilen Status zelliini kullanrz.

public ServiceControllerStatus Status {get;}

Burada grld gibi Status zellii ServiceControllerStatus numaralandrcs trnden deerler


alabilmektedir. Bu numaralandrcnn alaca deerler servisin o anki durumu hakknda bilgi
vermektedir. Status zellii sadece get blouna sahip olduundan, yanlzca servisin o anki durumu
hakknda bilgi vermektedir. ServiceControllerStatus numaralandrcsnn alabilecei deerler
aadaki tabloda belirtilmektedir.

ServiceControllerStatus Deeri Aklama

ContinuePending Duraksatlan servis devam ettirilmeyi


beklerken.

Paused Servis duraksatldnda.

PausePending Servis duraksatlmay beklerken.

Running Servis alrken.

StartPending Servis altrlmay beklerken.

Stopped Servis durdurulduunda.

StopPending Servis durdurulmay beklerken.

Burada en ok kafa kartrc haller Pending halleridir. Bunu daha iyi anlamak iin rnek olarak
StopPending durumunu aadaki ekil zerinden incelemeye alalm.

www.bsenyurt.com Page 2251


ekil 1. Pending Durumlar.

Burada grld gibi alan bir servise, Stop emri verildiinde, bu servisin durumu Stopped
oluncaya kadar geen srede, servis StopPending durumundadr. Ayn mantk, StartPending,
PausePending ve ContinuePending durumlar iinde geerlidir. Pending durumlarn daha ok, bu
zaman srelerinin tamamlanp verilen emrin baarl bir ekilde uygulandnn izlenmesinde
kullanbiliriz. Bu amala, ServiceController snf bize, aada prototipleri verilen WaitForStatus
metodunu sunmaktadr. Bu metod, parametre olarak ald ServiceControllerStatus deeri
salanncaya kadar uygulamay duraksatmaktadr.

Prototipler Aklama

Servisin
ServiceControllerStatus
public voidWaitForStatus(ServiceControllerStatusdesiredStatus); numaralandrcs ile belirtilen
duruma gemesi iin,
uygulamay bekletir.

Servisin
ServiceControllerStatus
public void WaitForStatus(
numaralandrcs ile belirtilen
ServiceControllerStatus desiredStatus,
duruma gemesi iin,
TimeSpan timeout
TimeSpan ile belirtilen sre
);
kadar uygulamann
beklemesini salar.

Biz uygulamamzda WaitForStatus metodunu, bir servise Start,Stop,Pause ve Continue emirlerini


verdiimizde, pending ilemlerinin sona ermesi ile birlikte servisin baarl bir ekilde istenen
konuma getiini anlamak amacyla kullancaz. Bu aslnda SCM yardmyla bir servisin
durdurulmas veya balatlmasnda oluan bekleme ilemi ile alakal bir durumdur. rnein,

www.bsenyurt.com Page 2252


ekil 2. Servisin altrlmas srasndaki bekleme ilemi.

SCM yardmyla bir servisi altrdmzda (Start) yukardaki gibi bir pencere ile karlarz.
Burada servis, StartPending konumundadr. Servis almaya baladnda yani Running konumuna
geldiinde, artk StartPending konumundan kar. Lakin bu sre zarfnda SCM uygulamasnn bir
sre duraksadn grrz. Bu duraksama servis Running halini alncaya kadar srer. te bunu
salayan aslnda WaitForStatus mekanizmasndan baka bir ey deildir. Bu sayede servis Running
moduna getiinde, gncelenen listede servisin durumu Running olarak yazacaktr. Eer
WaitForStatus teknii kullanlmam olsayd, bu durumda servis Start edildiinde ve liste
gncellendiinde ilk aamada Servisin durumu StartPending olucak ve ancak sonraki liste
gncellemesinde Running yazacakt. Bizde uygulamamzda WaitForStatus metodunu bu amala
kullanacaz. Yani servis kesin olarak istediimiz duruma ulatnda, listemizi gncelliyeceiz.

ServiceController snf iin kullanlacak dier nemli bir zellikte CanPauseAndContinue zelliidir.
Baz servislerin bu zellik deeri false olduu iin, bu servislerin Pause ve Continue emirlerine
cevap vermesi olanakszdr. te uygulamamzda bizde bir servisin bu durumunu kontrol edicek ve
ona gre Pause ve Continue emirlerine izin vereceiz. CanPauseAndContinue zelliinin prototipi
aadaki gibidir.

public bool CanPauseAndContinue {get;}

ServiceController snf iin kullanabilceimiz dier nemli bir zellik ise, bir servisin bal olduu
dier servislerin listesini elde etmemizi salyan, ServicesDependOn zelliidir. Prototipi aadaki
gibi olan bu zellik ile, bir servisin almas iin gerekli olan dier servislerin listesini elde
edebiliriz.

public ServiceController[] ServicesDependedOn {get;}

Prototipten de grld gibi bu zellik, ServiceController snf trnden bir dizi geriye
dndrmektedir. Dolaysyla bu zellik yardmyla sistemdeki servislerin bal olduklar servisleride
elde etme imkanna sahibiz.

imdi dilerseniz buraya kadar ilediimiz yanlar ile, ServiceController snfn kullandmz bir
rnek gelitirmeye alalm. Bu rneimizde, sistemimizdeki servislerin listesini elde edeceiz.
Setiimiz bir servis zerinde Start, Stop, Pause, Continue gibi emirleri yerine getireceiz ve bir
servise bal olan servislerin listesine bakabileceiz. Bu amala ncelikle aadakine benzer bir
windows uygulama formu oluturarak ie balayalm.

www.bsenyurt.com Page 2253


ekil 3. Uygulamamzn Form Grnts.

imdide program kodlarmz oluturalm.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;
using System.ServiceProcess; /* ServiceController snfn kullanabilmek iin bu isim alann
ekliyoruz.*/

namespace ServisBakim
{
public class Form1 : System.Windows.Forms.Form
{
.

.
/* Sistemde ykl olan servislerin listesini elde edeceimiz bir metod gelitiriyoruz. Bu
metodu hem servis listesini alrken hemde bir servis ile ilgili Start,Stop,Pause,Continue emirleri
verildikten sonra, ListView kontrolndeki listeyi gncel tutmak amacyla kullanacaz.*/
private void ServisListeGuncelle()
{
ServiceController[] svc; /*ServiceController snfndan bir dizi tanmlyoruz.*/
svc=ServiceController.GetServices(); /* Bu diziye ServiceController snfnn static
GetServices metodu yardmyla sistemde ykl olan servisleri birer ServiceController nesnesi olarak
aktaryoruz.*/

www.bsenyurt.com Page 2254


lvServisler.Items.Clear(); /* ListView kontrolmzn ieriini temizliyoruz.*/
/* Elde ettiimiz servisler arasnda gezinmek iin, Servis says kadar telenecek bir for
dngs oluturuyoruz. Servis saysn ise, svc isimli ServiceController tipinden dizimizin Length
zellii ile elde ediyoruz.*/
for(int i=0;i<svc.Length;i++)
{
lvServisler.Items.Add(svc[i].ServiceName.ToString()); /* ListView kontrolndeki ilk
eye yani ServisAd ksmna i indisli ServiceController tipinden svc nesnesinin ismini ekliyoruz.
Bunun iin ServiceName zelliini kullanyoruz.*/
lvServisler.Items[i].SubItems.Add(svc[i].Status.ToString()); /*ListView kontrolndeki
alt eye, servisimizin durumunu Status zellii yardmyla ekliyoruz.*/
}
}

private void btnServisAl_Click(object sender, System.EventArgs e)


{
ServisListeGuncelle();
}

private void btnStart_Click(object sender, System.EventArgs e)


{
/* ncelikle balatmak istediimiz servis bilgisini ListView kontrolnden almalyz. Bunun
iin ListView kontrolnn FocusedItem zelliini kullanyoruz. Bylece kullancnn ListView'da
setii servisin adn elde edebiliriz.*/
string servis;
servis=lvServisler.FocusedItem.Text;
/*Seilen servis adn ele alarak bir ServiceController nesnesi oluturuyoruz.*/
ServiceController curSer=new ServiceController(servis);
/* Servis balatma ilemini eer seilen servisin durumu Stopped ise
gerekletirebilmeliyiz. Bu amala, nce seilen servise ait ServiceController nesnesinin Status
zelliine bakyoruz. Deerin Stopped olup olmadn denetlerken ServiceControllerStatus
numaralandrcsn kullanyoruz.*/
if(curSer.Status==ServiceControllerStatus.Stopped)
{
curSer.Start(); /* Servisi altryoruz.*/
curSer.WaitForStatus(ServiceControllerStatus.Running); /* Servisimiz Running
konumunu alncaya dek bir sre uygulamay bekletiyoruz ve bu ilemin ardndan servislerin listesini
gncelliyoruz. Eer WaitForStatus metodunu kullanmassak, servis listesini gncellediimizde, ilgili
servis iin StartPending konumu yazlcaktr.*/
ServisListeGuncelle();
}
else /* Servis zaten alyorsa yani durumu(Status) Running ise bunu kullancya
belirtiyoruz.*/
{
MessageBox.Show(curSer.ServiceName.ToString()+" ZATEN CALISIYOR");
}
}

private void btnStop_Click(object sender, System.EventArgs e)


{
/* Bir servisi durdurmak iin yapacamz ilemler, balatmak iin yapacaklarmz ile ayn.
Sadece bu kez, servisin Running konumunda olup olmadn denetliyor ve yleyse, Stop komutunu
veriyoruz.*/
string servis;
servis=lvServisler.FocusedItem.Text;

www.bsenyurt.com Page 2255


ServiceController curSer=new ServiceController(servis);
if(curSer.Status==ServiceControllerStatus.Running)
{
curSer.Stop(); /* Servis durduruluyor. */
curSer.WaitForStatus(ServiceControllerStatus.Stopped);
ServisListeGuncelle();
}
else
{
MessageBox.Show(curSer.ServiceName.ToString()+" ZATEN CALISMIYOR");
}
}

private void btnPause_Click(object sender, System.EventArgs e)


{
/* Bir servisi duraksatacamz zaman, bu servisin, CanPauseAndContinue zelliinin
deeri nem kazanr. Eer bu deer false ise, servis zerinde Pause veya Continue emirlerini
uygulayamayz. Bu nedenle burada ilgili servise ati CanPauseAndContinue zelliinin deeri kontrol
edilir ve ona gre Pause emri verilir.*/
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
if(curSer.CanPauseAndContinue==true) /* CanPauseAndContinue true ise, Pause ilemini
uygulama hakkna sahibiz.*/
{
if(curSer.Status!=ServiceControllerStatus.Paused) /* Servis eer Paused konumunda
deilse Pause emri uygulanr. Bir baka deyile servis alr durumdaysa.*/
{
curSer.Pause(); /* Servis duraksatlyor.*/
curSer.WaitForStatus(ServiceControllerStatus.Paused); /* Servisin Paused konumuna
gemesi iin bekleniyor. */
ServisListeGuncelle();
}
}
else
{
MessageBox.Show("SERVISIN PAUSE&CONTINUE YETKISI YOK");
}
}

private void btnContinue_Click(object sender, System.EventArgs e)


{
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
if(curSer.CanPauseAndContinue==true) /* CanPauseAndContinue true ise, Continue
ilemini uygulama hakkna sahibiz.*/
{
if(curSer.Status==ServiceControllerStatus.Paused) /* ServiceControllerStatus eer
Paused konumunda ise Continue ilemi uygulanr.*/
{
curSer.Continue(); /* Duraksatlan servis almasna devam ediyor. */
curSer.WaitForStatus(ServiceControllerStatus.Running); /* Servisin Running
konumuna gemesi iin bekleniyor. */
ServisListeGuncelle();
}

www.bsenyurt.com Page 2256


}
else
{
MessageBox.Show("SERVISIN PAUSE&CONTINUE YETKISI YOK");
}
}

private void btnBagliServisler_Click(object sender, System.EventArgs e)


{
string servis;
servis=lvServisler.FocusedItem.Text;
ServiceController curSer=new ServiceController(servis);
ServiceController[] bagliServisler=curSer.ServicesDependedOn; /* Bir servise bal
servislerin listesini elde etmek iin, gncel ServiceController nesnesinin, ServiceDependedOn
zellii kullanlr. */

lbBagliServisler.Items.Clear();
/* Bal servisler arasnda gezinmek iin foreach dngsn kullanyoruz.*/
foreach(ServiceController sc in bagliServisler)
{
lbBagliServisler.Items.Add(sc.ServiceName.ToString());
}
}
}
}

Uygulamamz altralm , sistemdeki servisleri elde edelim ve rnein Stopped konumunda olan
servislerden Alerter servisini altrp, bu servise bal servis(ler) varsa bunlarn listesini tedarik
edelim.

ekil 4. Alerter Servisi Stopped konumunda.

www.bsenyurt.com Page 2257


ekil 5. Alerter servisi altrld ve bal olan servis elde edildi.

Gelitirmi olduumuz uygulamada olaabilecek pek ok hata var. rnein listede hi bir servis
seili deilken oluabilecek istisnalar gibi. Bu tarz istisnalarn ele alnmasn siz deerli okurlarma
brakyorum. Bylece geldik bir makalemizin daha sonuna. lerleyen makalelerimizde grmek
dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Windows Servislerinin Kontrol -1 ( 05.05.2004 )


- Win Servis
Deerli Okurlarm, Merhabalar.

Bu makalemizde, windows servislerinin, bir windows uygulamasndan nasl kontrol edilebileceini


incelemeye alacaz. Bir nceki makalemizde, windows servislerinin nasl oluturulduunu ve
sisteme nasl yklendiklerini incelemitik. Oluturduumuz windows servislerini(sistemdeki
windows servislerini), SCM yardmyla ynetibilmekteyiz. Ancak dilersek, bu ynetimi
programlarmz iindende gerekletirebiliriz. Bunu salayabilmek iin, System.ServiceProcess isim
alannda yer alan ServiceController snfn ve yelerini kullanmaktayz.

ServiceController snf ile windows servislerine balanabilir ve onlar kontrol edebiliriz. rnein
servisleri balatabilir, durdurabilir veya sistemdeki servisleri elde edebiliriz. Bu ve benzeri olanaklar
dnda SCM ile yapamyacamz bir olayda gerekletirebiliriz. Bu olay windows servislerinin
OnCustomCommand metodu zerinde ilemektedir. Bir windows servisinin OnCustomCommand
metodu sayesinde servisimize standart ilevselliklerinin haricinde yeni ilevsellikler kazandrabiliriz.
Prototipi aadaki gibi olan OnCustomCommand metodu integer tipinden bir parametre
almaktadr.

www.bsenyurt.com Page 2258


protected virtual void OnCustomCommand(int command);

OnCustomCommand metodunu herhangibir windows uygulamasndan arabilmek iin,


ServiceController snfnn ExecuteMethod metodu kullanlr. Integer tipindeki parametre 128 ile 256
arasnda saysal deerler alr. Metoda gnderilen parametre deerine gre, OnCustomCommand
metodunun farkl ilevsellikleri yerine getirmesini salayabiliriz. ServiceController snf ile
yapabileceklerimiz aadaki ekilde ksaca zetlenmitir.

ekil 1. ServiceController Snf le Yapabileceklerimiz.

Servislerimizi programatik olarak nasl kontrol edebileceimize gemeden nce, konumuz ile ilgili
basit bir windows servisi yazarak ie balayalm. Bu servisimizde, kendi oluturacamz bir Event
Log ierisinde, sistemdeki srclerinin bo alan kapasitelerine ait bilgileri tutacaz. Bu amalada,
servisimize bir Performance Counter ekleyeceiz. Ayrca servisimize bir timer kontrol koyacak ve
bu kontrol ile belirli periyotlarda servisin, bo alan bilgilerini kontrol etmesini ve belli bir serviyenin
altna inilirse Event Log'umuza bunu bir uyar simgesi ile birlikte yazmasn salayacaz.

Bununla birlikte, OnCustomCommand metodunu uygulamamzdan altracak ve gnderdiimiz


parametre deerine gre servisin deiik ilevleri yerine getirmesini saayacaz. rnein
kullancnn bo alan kontrol sresini ve alt snr deerlerini programatik olarak belirleyebilmesini ve
servisteki ilgili deerleri buna gre deitirebilmesini salayacaz. Elbette bu deiiklikler servisin
alma sresi boyunca geerli olucaktr.

imdi dilerseniz servisimi oluturalm. ncelikle vs.net ortamnda, yeni bir windows service projesi
ayoruz. Projemizin ad, BosAlanTakip olsun. Ardndan servisimizin zelliklerinden adn ve servise
ait kodlarda yer alan Service1'i , BosAlanTakipServis olarak deitirelim. Bununla birlikte Soluiton
Explorer'da Service1.cs kod dosyamzn adnda BosAlanTakipServis.cs olarak deitirelim. Sonraki
admmz ise, servisin zelliklerinden AutoLog zelliine false deerini atamak. Nitekim biz bu
servisimizde kendi yazacamz Event Log'u kullanmak istiyoruz.

www.bsenyurt.com Page 2259


ekil 2. Servisimizin zelliklerinin belirlenmesi.

Servisimizin kodlarn yazmadan nce, Custom Event Log'umuzu ekleyeceiz. Bunun iin,
Components sekmesinden EventLog nesnesini servisimizin tasarm ekranna srklyoruz.

ekil 3. EventLog nesnesi.

imdi EventLog nesnemizin zelliklerini belirleyelim.

www.bsenyurt.com Page 2260


ekil 4. EventLog nesnemizin zellikleri.

Artk log bilgilerini, servisimize eklediimiz eventLog1 nesnesini kullanararak oluturacaz. Srada
servisimize bir Performance Counter nesnesi eklemek var. Servislerimizde kullanabileceimiz
Performance Counter elerini, Solution Explorer pencersinde yer alan Performance Counter
sekmesinden izleyebiliriz. Sistemde ykl olan pek ok Performance Counter vardr.

ekil 5. Sistemdeki Performance Counter'lardan bazlar.

Biz bu rneimizde, LogicalDisk sekmesinde yer alan Free MegaBytes esini kullancaz. Bu saya
yardmyla, servisimizden, sistemdeki bir hardisk'in bo alan bilgilerini elde edebileceiz. Bu amala
buradaki C: srcsn servisimiz zerine srklyoruz.

www.bsenyurt.com Page 2261


ekil 6. Kullancamz Performance Counter esi.

Dier ihtiyacmz olan nesne bir Timer. Bunun iin yine Components sekmesinden Timer nesnesini ,
servisimizin tasarm ekranna srklememiz yeterli. Daha sonra Timer nesnesinin interval
zelliinin deerini 600000 olarak deitirelim. Bu yaklak olarak 10 dakikada (1000 milisaniye *
10 dakika * 60 saniye) bir, Timer nesnesinin Elapsed olaynn altrllacan belirtmektedir. Biz
bu olay ierisinden C srcsndeki bo alan miktarn kontrol etmeyi planlyoruz. Elbette sreyi
balangta 10 dakika olarak belirlememize ramen gelitireceimiz windows uygulamasnda bu
srenin kullanc tarafndan deitirilebilmesini salyacaz. Bu ayarlamalarn ardndan servisimiz
iin gerekli kodlar yazmaya geebiliriz.

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.ServiceProcess;

namespace BosAlanTakip
{
public class BosAlanTakipServis : System.ServiceProcess.ServiceBase
{
...
private long BosMiktar;
private long Sinir;

www.bsenyurt.com Page 2262


/* Servisimiz altrldnda(start),durdurulduunda(stop), duraksatldnda(pause) ve
yeniden altrldnda(continue) , zaman bilgisini ve performanceCounter1 nesnesinin RawValue
zelliini kullanarak C srcsndeki bo alan miktarn, oluturduumuz Event Log'a WriteEntry
metodu ile yazyoruz. Servisin durum bilgisini ise metoda gnderdiimiz string trnden parametre
ile elde ediyoruz.*/
private void Bilgilendir(string durum)
{
eventLog1.WriteEntry(durum+" "+DateTime.Now.ToShortDateString()+ "
C:"+performanceCounter1.RawValue.ToString()+" mb");
}
protected override void OnStart(string[] args)
{
Bilgilendir("START");
BosMiktar=performanceCounter1.RawValue; /* Servis altrldnda, C srcsndeki
bo alan miktarn, BosMiktar isimli long trnden deikenimize aktaryoruz.
performanceCounter'mzn RawValue zellii burada setiimiz saya kriteri gerei sonucu
megabyte cinsinden dndrmektedir.*/
Sinir=3300; // Yaklak olarak 3.3 GB.
timer1.Enabled=true; // Timer nesnemizi altryoruz.
}
protected override void OnStop()
{
Bilgilendir("STOP");
}
protected override void OnPause()
{
Bilgilendir("PAUSE");
}
protected override void OnContinue()
{
Bilgilendir("CONTINUE");
}
/* zel komutumuzu yazyoruz. */
protected override void OnCustomCommand(int command)
{
/* if koullarnda OnCustomCommand'a gnderilecek parametre deerine gre, bo alan
uyars iin gerekli alt snr deeri belirleniyor. Ayrca, timer nesnemizin interval deeride gelen
parametre deerine gre belirleniyor ve bylece timer nesnesinin Elapsed olaynn alma aral
belirlenmi oluyor.*/
if(command==200)
{
Sinir=3000; // Yaklak olarak 3gb.
}
else if(command==201)
{
Sinir=2000; // Yaklak olarak 2gb.
}
else if(command==202)

www.bsenyurt.com Page 2263


{
Sinir=4000; // Yaklak olarak 4gb.
}
else if(command==203)
{
timer1.Enabled=false;
timer1.Interval=1800000; // 30 dakikada bir.
timer1.Enabled=true;
}
else if(command==204)
{
timer1.Enabled=false;
timer1.Interval=3600000; // Saatte bir.
timer1.Enabled=true;
}
else if(command==205)
{
timer1.Enabled=false;
timer1.Interval=3000; // 3 Saniyede bir.
timer1.Enabled=true;
}
}
private void timer1_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
if(BosMiktar<=Sinir)
{
/* Eer C srcsndeki bo alan mikar Sinir deikeninin sahip olduu deerin altna
derse, bu bilgi Event Log'umuza bir warning singesi ile birlikte eklenecek. */
string bilgi=DateTime.Now.ToShortDateString()+ " C: Surucusu Bos Alan :
"+performanceCounter1.RawValue.ToString();
eventLog1.WriteEntry(bilgi,EventLogEntryType.Warning);
}
else
{
Bilgilendir("");
}
}
}
}

Servisimizin kodlarnda bylece hazrlam olduk. imdi servisimiz iin gerekli olan installer'larmz
servisimizin tasarm ekrannda sa tula atmz menden, Add Installer esini seerek
ekleyelim. nce ServiceInstaller1'in zelliklerinden Display Name zelliinin deerini, Bos Alan
Takip olarak deitirelim. Bylece servisimizin, services sekmesinde grnen ismini belirlemi
oluruz. Ardndan ServiceProcessInstaller1 nesnemizin, Account zelliinin deerini, LocalSystem
olarak deitirelim. Bylece sistemi aan herkes bu servisi kullanabilecek.

Dier yandan oluturduumuz Custom Event Log iinde bir installer oluturmamz gerekiyor ki
installUtil tool'u ile servisimizi sisteme kurduumuzda, sistedeki Event Log'lar ierisine,
oluturduumuz Custom Event Log'da kurulabilsin. Bu amala, eventLog1 nesnemiz zerinde sa

www.bsenyurt.com Page 2264


tua basp kan menden Add Installer' seiyoruz. Bu sayede, Event Log'umuz iin, bir adet
eventLogInstaller'n oluturulduunu grrz. Bu iemlerin ardndan windows servis uygulamamz
derleyelim ve servisimizi sisteme ykleyebilmek iin installUtil, vs.net tool'unu aadaki gibi
kullanalm.

installUtil BosAlanTakip.exe

Bu ilemlerin ardndan servisimiz baar ile yklendiyse, server explorer'daki services sekmesinde
grnecektir. Servisimizi bu aamada denemek amac ile, balatp durdurmay deneyelim. Ancak
bu noktada servisimizin pause ve continue olaylarnn geersiz olduunu grrz. Bunun sebebi,
servisimizin OnPauseContinue zelliinin deerinin false olmasdr. imdi bu deeri true yapalm.
Servis uygulamamz tekrar derleyelim. Ardndan servisimizi sisteme yeniden ykleyelim. imdi
server explorer'dan servisimizi altrp deneyelim.

ekil 7. Servisin alan Hali.

Ben servisi test etmek iin, C srcsndeki bo alan biraz daha drdm. Grld gibi servis
baarl bir ekilde alyor. u an iin her 10 dakikada bir timer nesnesinin Elapsed olay devreye
giriyor ve C srcsndeki bo alan miktarnn 3.3 gb'n altna dp dmedii kontrol ediliyor.
Servisimiz bunu tespit ettii anlarda Event Log'umuza bir uyar iareti ekleyecektir.

imdi yazm olduumuz bu servisi baka bir windows uygulamas ierisinden nasl
ynetebileceimizi incelemeye balayalm. Burada bizim iin anahtar nokta, windows
uygulamamzda, System.ServiceProcess isim alann kullanmak. Oluturmu olduumuz servise ait
OnCustomCommand metodunu altrmak iin, bu isim alannda yer alan ServiceController snfnn
ExecuteCommand metodunu kullanacaz. ncelikle aadaki gibi bir form tasarlayarak ie
balayalm.

www.bsenyurt.com Page 2265


ekil 8. Form Tasarmmz.

imdi ServiceProcess isim alann kullanabilmek iin Add Referance ksmndan uygulamamza
eklememiz gerekiyor.

ekil 9. System.ServiceProcess isim alannn uygulamaya eklenmesi.

ncelikle servisimizi temsil edicek ServiceController snf trnden bir nesne oluturacaz.
ServiceController snfndan nesnemizi olutururken aada prototipi verilen yapc metodu
kullanyoruz. Bu yapc, servisin tam adn parametre olarak string trnden almaktadr.

www.bsenyurt.com Page 2266


public ServiceController(string serviceName);

ServiceController snfna ait nesne rneini kullanarak servisimize ilikin pek ok bilgiyi elde
edebiliriz. rnein, servisin grnen adn DisplayName zellii ile , servisin alt makine adn
MachineName zellii ile elde edebiliriz. ServiceController snfnn yeleri yardmyla sistemimizde
kurulu olan servislere ait pek ok bilgiyi temin edebiliriz. Bu konuyu bir sonraki makalemizde
incelemeye alacaz. imdi dilerseniz servisimizi kontrol ediceimiz ksa windows uygulamamzn
kodlarn yazalm.

ServiceController sc; /* Servisimizi kontrol edicek olan ServiceController snf nesnemiz


tanmlanyor.*/

private void Form1_Load(object sender, System.EventArgs e)


{
sc=new ServiceController("BosAlanTakipServis"); /* ServiceController nesnemiz, kullanmak
istediimiz servisin adn parametre olarak almak suretiyle oluturuluyor.*/
lblServisAdi.Text=sc.DisplayName.ToString()+"/"+sc.MachineName.ToString(); /* Servisimizin ,
sistemdeki services ksmnda grnen ismi ve zerinde alt makine ad elde ediliyor ve label
kontrolmze ekleniyor.*/
}

private void btnPeriyod_Click(object sender, System.EventArgs e)


{
if(lbPeriyod.SelectedIndex==0)
{
sc.ExecuteCommand(203); /* Servisimizdeki OnCustomCommand metodu altrlyor ve bu
metoda parametre deeri olarak 203 gnderiliyor. Artk servisimiz, 203 parametre deerine gre
bir takm ilevler gerekletirecek. 203 deeri karlnda servisimizdeki OnCustomCommand
metodu, log tutma sresini yarm saat olarak belirleyecektir.*/
}
else if(lbPeriyod.SelectedIndex==1)
{
sc.ExecuteCommand(204);
}
else if(lbPeriyod.SelectedIndex==2)
{
sc.ExecuteCommand(205);
}
}

private void btnAltSinirAyarla_Click(object sender, System.EventArgs e)


{
if(lbAltSinir.SelectedIndex==0)
{
sc.ExecuteCommand(201);
}
else if(lbAltSinir.SelectedIndex==1)
{
sc.ExecuteCommand(200);

www.bsenyurt.com Page 2267


}
else if(lbAltSinir.SelectedIndex==2)
{
sc.ExecuteCommand(202);
}
}

imdi uygulamamz altralm ve ilk olarak sreyi 3 saniyede 1 seerek Event Log'larn tutuluunu
izleyelim. Windows uygulamamz balatmadan nce servisimizi manuel olarak balatmay
unutmayalm. Dier yandan bunu dilersek SCM yardmyla otomatik hale getirebilir ve sistem
aldnda servisin otomatik olarak balatlmasn salayabiliriz. Event Log sresini 3 saniye olarak
belirleyip Ayarla balkl butona tkladmzda, servisimizi temsil eden ServiceController nesnesinin
ExecuteCommand metodu devreye girerek, ListBox'tan seilen enin indeksine gre bir deeri,
temsil ettii servis iindeki OnCustomCommand metoduna parametre olarak gnderir. Bunun
sonucu olarak Event Log'umuzda 3 saniyede bir durum bilgisinin yazlyor olmas gerekir.

ekil 10. Servisin Event Log tutma sresinin ayarlanmas.

Grld gibi servisimiz bu yeni ayarlamadan sonra, kendi oluturduumuz Event Log'a 3
saniyede 1 bilgi yazmaktadr. Servisimizde, C srcs iin belli bir miktar kapasitenin altna
dldnde, Event Log'a yazlan mesaj bir uyar simgesi ile birlikte yazlyor. u an iin, belirtilen
kapasitenin altnda olduumuzdan warning simgesi , servisin timer nesnesinin elapsed olaynda
deerlendiriliyor ve Event Log'umuza yazlyor. imdi bu kapasiteyi 2 GB yapalm ve durumu
gzlemleyelim.

ekil 11. Alt Sinir deerinin deitirilmesi.

Grld gibi, servisimizin alt snra gre Event Log'larn simgesini belirleyen davrann
deitirmeyi baardk. Bu ilemi ExecuteCommand metodu ile servisimizdeki OnCustomCommand'a
gnderdiimiz parametrenin deerini ele alarak gerekletirdik.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde sistemimizde yer alan
servisleri, ServiceController snfndaki metod ve zellikler ile nasl kontrol edebileceimizi
incelemeye alacaz. Bu makalede grnceye dek hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 2268


Burak Selim ENYURT

selim@bsenyurt.com

Windows Servislerine Giri ( 29.04.2004 ) - Win


Servis
Deerli Okurlarm, Merhabalar.

Bu makalemizde windows servislerine ksa bir giri yapcak ve en basit haliye bir windows
servisinin, .net ortamnda nasl oluturulacan incelemeye alacaz. ncelikle Windows Service
nedir, ne amalarla kullanlr bunu irdelemeye alak daha sonra windows servislerinin mimarisini
ksaca inceleyeceiz.

Windows servisleri, iletim sisteminde arka planda alan, kullanc ile etkiliimde bulunduu
herhangibir arayze sahip olmayan, kaynaklarn izlenmesi, system olaylarnn log olarak tutulmas,
network eriimlerinin izlenmesi, veritabanlar zerindeki transaction'larn izlenmesi, sistem
performansna ati bilgilerin toplanmas, sistem hatalarnn (system exceptions) , baarsz program
denemelerin (failure) vb. gibi geri plan ilemlerinin takip edilmesinde kullanlan, sisteme kayt
edilmi (register), altrlabilir nesnelerdir.

Aslnda, windows NT,2000,XP yada 2003 kullancs iseniz, windows servisleri ile mutlaka
ilgilenmisinizdir. Sistemlerimizde alan pek ok servis vardr. Bu servislerin neler olduuna,
Administrative Tool blmnde Services ksmndan bakabiliriz. rnein aada XP Professional
sisteminde ykl olan rnek servisler yer almaktadr.

ekil 1. Win XP iin rnek Windows Servisleri

www.bsenyurt.com Page 2269


te biz, .net snflarn kullanarak, burada yer alacak windows servisleri yazma imkanna sahibiz.
Windows Servislerinin mimari yaps aadaki ekilde grld gibidir.

ekil 2. Windows Servis Mimarisi

Mimariden ksaca bahsetmek gerekirse; Service Application (Servis Uygulamas) , istenilen


fonksiyonelliklere sahip bir veya daha fazla windows servisini ieren bir uygulamadr. Servis Kontrol
Uygulamas (Service Controller Application) ise, servislerin davranlarn kontrol eden bir
uygulamadr. Son olarak, SCM, sistemde ykl olan servislerin kontrol edilmesini salayan bir
windows aracdr. Dolaysyla biz, bir windows servis uygulamas yazarken, bunun ierisine birden
fazla servis koyabiliriz. Bu servis uygulamas ve baka servis uygulamalarnn davranlarn servis
kontrol uygulamalar yardm ile kontrol edebiliriz. Dier yandan, yazm olduumuz tm servis
uygulamalar ile birlikte sistemdeki servisleri, SCM araclyla ynetebiliriz.

.Net Framework, windows servislerini oluturabilmemiz iin gerekli snflar ieren


System.ServiceProcess isim alanna (namespace) sahiptir. Bu isim alanndaki snflar kullanarak,
bir servisi oluturabilir, sisteme ykleyebilir, yrtebilir ve kontrol edebiliriz. Aadaki ekil, basit
olarak, ServiceProcess isim alanndaki snflar ile yapabileceklerimizi temsil etmektedir.

ekil 3. System.ServiceProcess isim alanndaki snflar ile yapabileceklerimiz.

Buradaki snflar yardm ile bir windows servisi oluturmak istediimizde izlememiz gereken bir yol
vardr. ncelikle, servisi oluturmamz gerekir (Create) . Bunun iin ServiceBase snfn kullanrz.
ServiceBase snfnda yer alan metodlar yardmyla, bir windows servisini oluturabiliriz. Oluturulan
bu servisin daha sonra, kullanlabilmesi iin sisteme install edilmesi ve register olmas
gerekmektedir. Bu noktada devreye ServiceInstaller ve ServiceProcessInstaller snflar girer. Bir
windows servis uygulamasn install etmeden nce, bu servis iin bir i parac(process)
oluturulmal ve yklenmelidir. te bu noktada devreye ServiceProcessInstaller girer.
ServiceInstaller ve ServiceProcessInstaller snflar aslnda bir servisin sisteme yklenebilmesi iin

www.bsenyurt.com Page 2270


gerekli metodlar otomatik olarak salarlar. Ancak bu snflarn uyguland bir windows servis
uygulamasnn tam olarak sisteme yklenmesi ve Services ksmnda grlebilmesi iin, InstallUtil
isimli .net arac kullanlr ve oluturulan windows servis uygulamas sisteme yklenir.

Sisteme yklenmi olan servislerin kontrol edilebilmesi amacyla, ServiceController snfndaki


metodlar kullanabiliriz. Yani, bir servisin Start, Stop, Pause, Continue gibi dabranlarn kontrol
edebiliriz. Bu amala SCM aracn kullanabileceimiz gibi, ServiceController snfndaki metodlarda
kullanabilir ve bylece herhangibir uygulamdan bir servisi balatabilir, durdurabilir vb. ilemlerini
gerekletirebiliriz.

Bir windows servisinin oluturulmas, sisteme yklenmesi , yrtlmesi ve kontrol edilmesi her
nekadar kark grnsede, vs.net burada gereksinimin duyduumuz ilemlerin ounu bizim iin
otomatik olarak yapmaktadr. Windows servislerinin oluturulmasnda kullanlan
System.ServiceProcess isim alannn yannda, servislerin durumunun izlenebilmesi, eitli
performans kriterlerinin servis ierisinden kontrol edilebilmesi, sisteme ait loglarn servis ierisinde
kullanlabilmesi gibi ilemleri gerekletirebileceimiz snflar ieren System.Diagnostics isim
alanda vardr.

ekil 4. System.Diagnostics isim alan snflar.

Bir windows servis uygulamas ile normal bir vs.net uygulamas arasnda belirgin farkllklar vardr.
Hereyden nce bir windows servis uygulamasnn kullanlabilmesi iin, sisteme install edilmesi ve
register olmas gereklidir. Dier nemli bir farkta, bir windows servis uygulamas arka planda
alrken, bu servisin almas ile ilgili oluabilecek hatalardr. Normal bir windows uygulamasnda
hatalar sistem tarafndan kullancya bir mesaj kutusu ile gsterilebilir yada program ierisindeki
hata kontrol mekanizmalar sayesinde grsel olarak izlenebilir. Oysa bir windows servis uygulamas
alrken meydana gelen hatalar, event log olarak sistemde tutulurlar.

Windows servisleri ile ilgili bu ksa bilgilerin ardndan, dilerseniz birlikte basit bir windows servis
uygulamas gelitirelim. Bunun iin ilk yapmamz gereken vs.net ortamnda, bir windows service
applicaiton projesi amaktr.

www.bsenyurt.com Page 2271


ekil 5. Windows Servis Uygulamas Amak.

Bu ilemi gerekletirdiimizde, vs.net herhangibir kullanc arayz olmayan bir proje


oluturacaktr.

ekil 6 . Windows Servis Uygulamas ilk oluturulduunda ekrann grnm.

Servis uygulamasn gelitirmek iin yazacamz kodlara gemek iin, to switch to code windows
linkine tklamamz gerekiyor. Bu durumda vs.net tarafndan otomatik olarak oluturulmu kodlar
grrz. lk dikkat ekici nokta, Service1 isimli snfn ServiceBase snfndan tretilmi olmasdr.

public class Service1 : System.ServiceProcess.ServiceBase

www.bsenyurt.com Page 2272


ServiceBase snf OnStart, OnStop, OnPause, OnContinue gibi bir takm metodlar ieren bir snftr.
Bir windows servisi oluturulurken bu servis snfnn, ServiceBase snfndan tretilmesinin sebebi,
bahsetmi olduumuz metodlarn, servis snf ierisinde override edilmeleridir. Bir servis SCM
tarafndan yada windows iinden balatldnda, servisin balatldnda dair start mesaj gelir. te
bu noktada servisin OnStart metodundaki kodlar devreye girer. Ayn durum benzer ekilde, OnStop
olay iinde geerlidir. Tm bu metodlar ve baka yeler temel snf olan ServiceBase snf
ierisinde toplanmtr. Bunun sonucu olarak, bir snf servis olarak tanmlamsak, ServiceBase
snfndan tretir bylece servis balatldnda, durdurulduunda vb. olaylarda yaplmasn
istediimiz ilemleri, treyen snfta bu davranlarn tetikledii, OnStart, OnStop gibi metodlar
override ederek gerekletirebiliriz.

Sonu itibariyle vs.net, bir servis uygulamas oluturduumuzda, buradaki varsaylan servisi,
ServiceBase snfndan tretir ve otomatik olarak OnStart ve OnStop metodlarn aadaki ekilde
ekler.

protected override void OnStart(string[] args)


{

protected override void OnStop()


{

Peki bu metodlar ne zaman ve ne ekilde alr. Bir windows servisinin, normal windows
uygulamalarnda olduu gibi destekledii olaylar vardr. Windows servisleri 4 olay destekler. Bir
windows servisinde meydana gelen olaylarn alma ekli aadaki ekildeki gibidir.

www.bsenyurt.com Page 2273


ekil 7. Servis Olaylarnn Ele Aln Mekanizmas.

Buradan grld gibi, sistemde, yazm olduumuz windows servisi ile ilgili olarak 4 olay
meydana gelebilir. Bunlar Start, Stop, Pause ve Continue olaylardr. Bir servis SCM tarafndan
balatldnda bu servis iin Start olay meydana gelir. Daha sonra SCM, servisin iinde bulunduu
Servis Uygulamasna Start komutunu gnderir. Buna karlk servis uygulamas iindeki ilgili servis
bu Start komutunu alr ve karlnda, OnStart metodunda yazan kodlar altrr.

Dier yandan bir servis durdurulduunda, Stop olay meydana gelir. Ancak bu noktada SCM Start
tekniinden farkl olarak hareket eder. SCM nce oluan olayn sonucunda ilgili servis uygulamas
iindeki servisin, CanStop zelliine bakar. CanStop zellii true veya false deer alabilen bir
zelliktir ve servisin durdurulup durdurulamyacan dolaysyla, bir Stop olay meydana geldiinde,
servise ati OnStop metodunun altrlp altrlamyacan belirtir. SCM bu nedenle Stop olay
meydana geldiinde ilk olarak bu zellii kontrol eder. Eer zellik deeri true ise, servise Stop
komutunu gnderir ve sonu olarak OnStop metodundaki kodlar altrlr.

Stop tekniinde gerekleen zellik kontrol ilemi, Pause ve Continue olaylar iinde geerlidir. Bu
kez SCM, servisin CanPauseAndContinue zelliinin boolean deerine bakar. Eer bu deer true
ise, servise Pause komutunu veya Continue komutunu gnderir ve bunlara bal olan OnPause ve
OnContinue metodlarndaki kodlarn altrlmasn salar. Pause olay bir servis duraklatldnda
oluur. Continue olay ise, pause konumunda olan bir servis tekrar almasna devam etmeye
baladnda oluur.

Bir dier nemli nokta oluturulan service1 isimli snfn main metodundaki kodlardr.

static void Main()

www.bsenyurt.com Page 2274


{
System.ServiceProcess.ServiceBase[] ServicesToRun;
ServicesToRun = new System.ServiceProcess.ServiceBase[] { new Service1() };
System.ServiceProcess.ServiceBase.Run(ServicesToRun);
}

Burada grld gibi ServiceBase snf tipinden bir nesne dizisi tanmlanm ve varsaylan olarak
bu nesne dizisinin ilk eleman Service1 ismi ile oluturulmutur. Bu aslnda bir servis uygulamasnn
birden fazla windows servisini ierebileceinide gstermektedir. Burada ServiceBase snf tipinden
bir nesne dizisinin tanmlanmasnn nedenide budur. Zaten oluturduumuz Service1 snf,
ServiceBase snfndan tretildii iin ve sahip olduu temel snf metodlarda bu treyen snf
ierisinde override edildii iin, polimorfizmin bir gerei olarak, servis nesnelerini bir ServiceBase
tipinden dizide tutmak son derece mantkl ve kullanldr.

Son satra gelince. ServiceBase snfnn Run metodu, parametre olarak ald serviseleri, SCM
tarafndan balatlm iseler, bellee yklemekle grevli bir metoddur. Elbette servislerin bellee
Run metodu ile yklenebilmesi iin, ncelikle Start komutu ile balatlmalar gerekmektedir.
ServiceBase.Run metodu aslnda normal bir windows uygulamasndaki Application.Run metodu ile
ayn ilevsellii gsterir.

u ana kadar oluturduklarmz ile bir servisin omurgasn meydana kardk. Ancak halen
servisimiz herhangibir ilem yapmamakta. Oysaki bir servis ile, rnein, sistemdeki aygt
srclerine ait olay log'larn, dk bellek kullanm sonucu yazlm veya donanm ekipmanlarnda
meydana gelebilecek hata (error), istisna(exception), warning(uyar) gibi bilgilere ait log'lar
izleyebiliriz.

imdi dilerseniz ilk yazdmz servis ile Uygulama Log'larnn (Application Log) nasl tutulduunu
incelemeye alalm. Aslnda bizim izleyebileceimiz tip log vardr. Bunlar, System Log'lar,
Application Log'lar ve Security Log'lardr.

ekil 8. Olay Log'larnn Trleri.

Normal artlar altnda, vs.net ortamnda bir windows servis ilk kez oluturulduunda, servise ait
AutoLog zellii deeri true olarak gelir. Bu durumda Start,Stop,Pause ve Continue olaylar
meydana geldiinde, servis sisteme kurulduunda veya sistemden kaldrldnda, servis
uygulamasna ait loglar, Application Log'a otomatik olarak yazlrlar. Biz bu uygulamamzda kendi
zel loglarmz tutmak istediimizden bu zelliin deerini false olarak belirliyoruz.

www.bsenyurt.com Page 2275


Kendi olay loglarmz yazabilmemiz iin, EventLog nesnelerine ihtiyacmz vardr. EventLog
nesneleri System.Diagnostics isim alannda yer alan EventLog snf ile temsil edilirler. Bu nedenle
uygulamzda ncelikle bir EventLog nesne rnei oluturmalyz.

private System.Diagnostics.EventLog OlayLog;

Bir EventLog nesnesi oluturduktan sonra, bu nesne zerinden CreateEventSource metodunu


kullanarak servisimiz iin bir event log oluturabiliriz. Buna ilikin kodlar OnStart metodu iine
yazarsak, servis balatldnda oluturduumuz log bilgilerininde otomatik olarak yazlmasn
salam oluruz.

protected override void OnStart(string[] args)


{
OlayLog=new EventLog(); /* EventLog nesnemizi olusturuyoruz.*/

if(!System.Diagnostics.EventLog.SourceExists("Kaynak"))
{
System.Diagnostics.EventLog.CreateEventSource("Kaynak","Log Deneme"); /* Ilk parametre
ile, Log Deneme ismi altinda tutulacak Log bilgilerinin kaynak ismi belirleniyor. Daha sonra bu
kaynak ismi OlayLog isimli nesnemizin Source zelligine ataniyor.*/
}
OlayLog.Source="Kaynak";
OlayLog.WriteEntry("Servisimiz baslatildi...",EventLogEntryType.Information); /* Log olarak ilk
parametrede belirtilen mesaj yazilir. Log'un tipi ise ikinci parametrede grldg gibi
Information'dir.*/
}

Bu ilemlerin ardndan servisimiz iin basit bir grevide eklemi olduk. imdi srada bu servisin
sisteme yklenmesi var. Bunun iin, daha nceden bahsettiimiz gibi,
ServiceProcess.ServiceInstaller ve ServiceProcess.ServiceProcessInstaller snflarn kullanmamz
gerekiyor. Servis uygulamamz iin bir tane ServiceProcessInstaller snf nesne rneine ve
servis uygulamas iindeki her bir servis iinde ayr ayr olamak zere birer ServiceInstaller nesne
rneine ihtiyacmz var. Bu nesne rneklerini yazm olduumuz servis uygulamasna kolayca
ekleyebiliriz. Bunun iin, servisimizin tasarm penceresinde sa tua basyor ve Add Installer
seeneini tklyoruz.

www.bsenyurt.com Page 2276


ekil 9. Add Installer.

Bunun sonucu olarak vs.net, uygulamamza gerekli installer snflarn ykler.

ekil 10. Installer nesne rneklerinin yklenmesi.

Bunun sonucu olarak aada grlen snf uygulamamza otomatik olarak eklenir. Bu aamada
buradaki kodlar ile fazla ilgilenmiyeceiz.

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration.Install;

namespace OrnekServis
{
[RunInstaller(true)]
public class ProjectInstaller : System.Configuration.Install.Installer
{
private System.ServiceProcess.ServiceProcessInstaller serviceProcessInstaller1;
private System.ServiceProcess.ServiceInstaller serviceInstaller1;
private System.ComponentModel.Container components = null;

public ProjectInstaller()
{
InitializeComponent();
}
protected override void Dispose( bool disposing )
{

www.bsenyurt.com Page 2277


if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
private void InitializeComponent()
{
this.serviceProcessInstaller1 = new System.ServiceProcess.ServiceProcessInstaller();
this.serviceInstaller1 = new System.ServiceProcess.ServiceInstaller();
this.serviceProcessInstaller1.Password = null;
this.serviceProcessInstaller1.Username = null;
this.serviceInstaller1.ServiceName = "Service1";
this.Installers.AddRange(new System.Configuration.Install.Installer[]
{this.serviceProcessInstaller1,this.serviceInstaller1});

}
}
}

Ancak servisimizin, Sistemdeki service listesinde nasl grneceini belirlemek iin, ServiceInstaller
nesne rneinin, Display Name zelliini deitirebiliriz.

ekil 11. Servisimizin grnen adn deitiriyoruz.

Dier taraftan yapmamz gereken bir ilem daha var. ServiceProcessInstaller nesne rneinin
Account zelliinin deerini belirlemeliyiz. Bu zellik aadaki ekilde grlen deerlerden birisini
alr.

www.bsenyurt.com Page 2278


ekil 12. Account zelliinin Alabilecei Deerler.

Biz bu uygulama iin LocalSystem deerini veriyoruz. Bu, Servis Uygulamamzn sisteme
yklenirken, sistemdeki kullanclarn zel haklara sahip olmasn gerektirmez. Dolaysyla sisteme
giren her kullancnn servisi ykleme hakk vardr. Eer User seeneini kullanrsak, servisin
sisteme yklenebilmesi iin geerli bir kullanc ad ve parolann girilmesi gerekmektedir.

Artk yazm olduumuz servis uygulams iin installer'larda oluturduumuza gre uygulamamz
derleyip, sisteme InstallUtil arac ile ykleyebilir ve register edebiliriz. Bunun iin, servis
uygulamamzn exe dosyas ile, InstallUtil aracn aadaki gibi kullanrz.

www.bsenyurt.com Page 2279


ekil 13. InstallUtil arac yardmyla bir servisin sisteme yklenmesi.

te InstallUtil arac servisimizi sisteme yklerken, servis uygulamamza eklediimiz


ServiceProcessInstaller ve ServiceInstaller snflarn kullanr. Bu ilemin ardndan vs.net ortamnda,
Server Explorer'dan servislere baktmzda, AServis isimli servisimizin yklendiini ancak henz
altrlmadn grrz.

ekil 14. Servis sisteme yklendi.

Eer servisin otomatik olarak balatlmasn istiyorsak, ServiceInstaller nesnesinin StartType


zelliini Automatic olarak ayarlamamz yeterli olucaktr.

www.bsenyurt.com Page 2280


ekil 15. Servisin Balatlma eklinin Belirlenmesi.

stersek servisimizi, yine Server Explorer'dan servis adna sa tklayp alan menden start
komutuna basarak altrabiliriz. Servisimizi altrdktan sonra, yine Server Explorer
pencersinden Event Logs sekmesine bakarsak, bahsetmi olduumuz olay loglar haricinde kendi
yapm olduumuz olay logununda eklendiini grrz.

ekil 16. Servisin almasnn sonucu.

Burada grld gibi Log Deneme ismi ile belirttiimiz Event Log oluturulmu, Source olarak
belirttiimiz Kaynak nesnesi oluturulmu ve OnStart metoduna yazdmz kodlar yardmyla,
mesaj bilgimiz information(bilgi) olarak yazlmtr. Buraya kadar anlattklarmz ile bir windows
servisinin nasl yazldn ve sisteme yklendiini en temek hatlar ile grm olduk. lerleyen
makalelerimizde, windows servisleri ile ilgili daha farkl uygulamlar gelitirmeye alacaz.
Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Single File Assembly ve Multiple-File Assembly


Kavramlar ( 27.04.2004 ) - Framework
www.bsenyurt.com Page 2281
Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde, assembly'lar eriilebilirliklerine gre zel (private) ve paylatrlm


(shared) olmak zere iki kategoriye ayrabileceimizi incelemitik. Assembly'lar ayrca, tek dosya
(single file) ve oklu dosya (multiple-file) olmak zere iki farkl kategoriye daha ayrabiliriz. Bu
makelemizde assembly'larn bu tiplerini incelemeye alacaz.

ounlukla .net ile uygulama gelitirirken, gerekletirmi olduumuz uygulamalar tek bir
assembly' dan oluurlar. Bu varsaylan olarakta byledir. te bu assembly' lar single file (tek
dosya) assembly olarak adlandrlr. Bir multiple-file assembly uygulamas ise, birden fazla
assembly'dan oluabilir. yleki tm bu assembly'lar farkl .net dillerince yazlm uygulama
paralar olabilir. Tm bunlarn bir araya getirilerek PE(portable executable) olarak kullanlacak teki
bir assembly altnda birletirilmesi ile, multiple-file assembly mimarisi elde edilmi olur.

rnein, vb.net module'lerinden, J# ktphanelerinden oluan bir uygulamada, giri noktasna


sahip olan uygulamann (yani Main metodunu ieren uygulamann) C# ile yazlm olduunu ve bu
dosyadan dier module ve ktphanelere ait elemanlarn kullanldn dnelim. Burada
PE(portable executable)'a ati manifesto bilgisi, giri noktasna sahip olan assembly iin
oluturulacaktr. Bir assembly manifesto' su, uygulamann bavurduu dier assembly'lara ait
bilgileri, assembly'da kullanlan tr bilgilerini, assembly'a ait dosyalara ait bilgileri, izin bilgilerini
vb. ierir. Dolaysyla mutliple-file assmebly' a ait manifesto ierisinde, multiple-file assembly'
oluturan dier module'lere, ktphanelere ait bilgilerde yer alcaktr. Bylece yaln bir tabirle
elimizde, bir ka .net dili ile yazlm paralardan oluan ve tek bir assembly altnda birletirilen bir
uygulama olucaktr. Bu bizim, farkl .net dilleri ile yazlm uygulama paralarn tek bir assembly
altnda birletirerek kullanabilmemizi ve uygulamamz yaplandrabilmemizi salar.

rnekler zerinden gittiimizde bu konuyu daha iyi kavrayacanz dnyorum. lk olarak ok


basit bir single-file assembly oluturacak ve yapsn, .net aralarndan ildasm (Intermediate
Language DisAssembly) ile inceleyeceiz. Aada C# dili ile yazlm basit bir assembly
gryorsunuz.

using System;

public class Giris


{
public static void Main(string[] args)
{
int a,b;
a=5;
b=6;
int sonuc=Topla(a,b);

Console.WriteLine("Single File Assembly");


Console.WriteLine("Toplam {0}",sonuc.ToString());
}

public static int Topla(int birinci,int ikinci)


{
return birinci+ikinci;
}
}

www.bsenyurt.com Page 2282


Bu kodu aadaki ekilde grld gibi derlediimizde, Merhaba.exe assembly'nn
oluturulduunu grrz. Bu assembly'mz bir Main metodu ierdiinden ve biz bu assembly' exe
olarak derleyip ortaya bir PE karttmzdan,bu assemble'a ait manifesto bilgileride buna gre
olucaktr.

ekil 1. Single Assembly

imdi ildasm aracn kullanarak, oluturmu olduumuz bu assembly'n ieriine bakalm.

ekil 2. Giris.exe assembly'nn ierii.

www.bsenyurt.com Page 2283


Burada grld gibi, assembly'mza ait manifesto bilgisinde PE olduuna dair en byk iareti
gsteren entry point bilgisinin yer ald Main metodu grlmektedir. Daha nceden belirtiimiz gibi
bu manifesto ierisinde, Merhaba.exe assembly'nn kulland baka assembly'lara ait referans
bilgileri, assembly'a ait module bilgisi, hashcode bilgiler vb. bulunur. Tm bu manifesto bilgileri
metadata verisi olarak Merhaba.exe assembly' ierisinde tutulmaktadr. Bu assembly bir
PE(portable executable) olduu iin single assembly olarak deerlendirilir. Merhaba.exe
assembly'mzn manifesto bilgileri aadaki gibidir.

.assembly extern mscorlib


{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.ver 1:0:3300:0
}
.assembly Merhaba
{
// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool,
// bool) = ( 01 00 00 01 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.module Merhaba.exe
// MVID: {C9BE521B-50BF-49DE-A9F9-F6EDB3D31941}
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
// Image base: 0x07000000

Ancak bu assembly'n bir single-file assembly olduunun en byk kant Main metoduna ait IL
kodlarnda yazmaktadr.

www.bsenyurt.com Page 2284


ekil 3. Single-File Assembly Kant.

Her .net assembly'nda olduu gibi burada da manifestomuz, standart olarak, mscorelib
ktphanesine bir bavuru ile balamaktadr. Daha sonra assembly'a ait bilgiler balar. Bir single
assembly bu manifesto bilgileri dnda elbette uygulama kodlarnn MSIL karlklarnda
iermektedir. Bir single file assembly'n temel yaps aadaki gibidir.

ekil 4. Single-File Assembly'larn genel yaps.

www.bsenyurt.com Page 2285


Gelelim, multiple-file assembly'lara. Bu assembly trnn anlamann en iyi yolu konuyu bir senaryo
zerinde dnmektir. Uygulamamzn, vb.net ile yazlm bir module', J# ile yazlm bir
ktphanesi olduunu farzedelim. Biz bu kaynaklardaki snflar asl uygulamamzda yani PE olucak
assembly'mzda kullanmaya alacaz. ncelikle ie, vb.net module'n oluturmak ile
balayalm.

namespace vbdotnet
public class vbselam
public shared sub Selam()
System.Console.WriteLine("Selam, buras VB.NET module")
end sub
end class
end namespace

imdi bu vb.net kod dosyasn bir netmodule dosyas olarak derleyeceiz. Bunun iin aadaki
teknii uygulayacaz.

ekil 5. vb.net module

Ltfen, net module dosyasn vbc derleyici arac ile nasl oluturduumuza dikkat edelim. Bu
module, vb.net kodlar ile yazlm olup herhangibir giri noktas iermemektedir. Bu nedenle bu
assembly aslnda bir PE deildir. Tamamyle baka bir PE assembly'nn kullanabilmesi iin
gelitirilmitir. Bunu yazlm ekibinizin vb.net programclarnn gelitirmi olduu bir module olarak
dnebilirsiniz. Bizim amacmzda, bu module' asl PE assembly'mz ierisinde kullanmak ve bir
multiple-assembly meydana getirmektir. imdide J# kodlarndan oluan bir ktphane gelitirelim.

import System;

package Araclar

www.bsenyurt.com Page 2286


{
public class jsharpselam
{
public static function Selam()
{
System.Console.WriteLine("Selam, burasi JSharp ekibi");
}
}
}

ekil 6. J# ile yazlm ktphanemiz.

Sra geldi tm bu assembly'lar kullancak olan assembly'mz yazmaya. Bu , C# ile yazlm bir
assembly olucak ve ayn zamanda, yukarda yazm olduumuz vb.net module'n ve j#
ktphanesini kullanacak.

using System;
using Araclar;

public class Temel


{
public static void Main(string[] args)
{
System.Console.WriteLine("Ana uygulama");
jsharpselam.Selam();
vbdotnet.vbselam.Selam();
}

www.bsenyurt.com Page 2287


}

Kodumuzda, vb.net module' iindeki Selam ve j# ile yazlm ktphane iindeki Selam
metodlarna eriiyoruz. imdi yapmamz gereken ilem bu assembly' bir netmodule olarak
derlemek ve ardndan tm assembly'lar tek bir assembly altnda birletirmek. PE olucak olan
assembly'mz netmodule haline getirmek iin aadaki kod satrn kullanacaz.

ekil 7. PE uygulamamzn netmodule olarak oluturulmas.

Bu komut satrnda, PE olucak assembly'mz netmodule haline getirirken, kullandmz j#


ktphanesini nasl referans ettiimize ayrca vb.net module'n nasl eklediimize dikkat edelim.
Sra, tm bu assembly'lar tek bir at altnda toplayp multiple-assembly'mz oluturmaya geldi.
Bu ii gerekletirmek amacyla, AL (assembly linker) aracn kullanacaz. Bu ara yardmyla,
yazm olduumuz assembly'da tek bir assembly iinde toplayacak ve multiple-assembly
yapmz gerekletirmi olucaz.

www.bsenyurt.com Page 2288


ekil 8. al (assembly linker) yardmyla multiple-assembly atsnn oluturulmas.

Burada dikkat etmemiz gereken nokta main parametresi ile bildirdiimiz yerdir. Burada, PE'mzn
almaya balyaca yerin, Temel isimli assembly'mz iindeki Main yordam olduunu belirtmi
oluyoruz. Elbette main parametresi, herhangibir assembly iindeki Main yordamn belirtmek
zorundadr. PE dosyamza ayrca, dier kullanaca assembly'larda balam olduk. imdi
Uygulama.exe assembly'mzn yapsn ildasm ile yakndan inceleyelim.

ncelikle ilk dikkati eken nokta, entry point'in eklenmi olmasdr. Yazm olduumuz dier
assembly'lardan ne vb.net module assembly'mz ne j# kodlu ktphane assembly'mz nede PE'
mz oluturan C# netmodule assembly'mz (Main metodunu iermesine ramen) herhangibir
entry point iermemekteydi. Ancak al (assembly linker) arac ile tm bu assembly'lar tek bir
assembly altnda birletirirken, entry point'imizde Temel.netmodule assembly' iindeki Main
yordam olarak iaretlemi olduk.

www.bsenyurt.com Page 2289


ekil 9. PE olan assembly'mzn ierii.

Gelelim ierie. lk dikkat eken nokta dier assembly'larn bavuru bilgilerinin eklenmi olmasdr.
Bavurularn olduu assembly'lar extern anahtar kelimesini ieren satrlardr. Extern anahtar
kelimesi, bu assembly'larn PE tarafndan eriilen ve kullanlan assembly'lar olduunu gsterir.
Bunun dndaki tm satrlar ve bilgileri ile birlikte bu assembly aslnda bir single-file assembly'dan
farkszdr. Ancak kulland dier assembly'lar dnldnde ortaya bir multiple-file assembly
kmtr.

.module extern Temel.netmodule


.assembly extern mscorlib
{
.publickeytoken = (B7 7A 5C 56 19 34 E0 89 ) // .z\V.4..
.hash = (4E FE C2 93 5B 46 10 72 20 30 9A 9C 31 21 D0 2F // N...[F.r 0..1!./
9B 84 AF 0E )
.ver 1:0:3300:0
}
.assembly extern Microsoft.VisualBasic
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 7:0:3300:0
}
.assembly extern jsharpselam
{
.hash = (FA 10 B8 EE 98 5A F7 81 4F 0D 91 80 38 9D FB 78 // .....Z..O...8..x
04 14 A0 83 )
.ver 0:0:0:0
}
.assembly Uygulama
{

www.bsenyurt.com Page 2290


// --- The following custom attribute is added automatically, do not uncomment -------
// .custom instance void [mscorlib]System.Diagnostics.DebuggableAttribute::.ctor(bool,
// bool) = ( 01 00 00 01 00 00 )
.hash algorithm 0x00008004
.ver 0:0:0:0
}
.file vbselam.netmodule
.hash = (85 65 08 DF 98 6C 95 7F 61 47 8F 6C 02 DA 04 64 // .e...l..aG.l...d
B6 AC A2 F9 )
.file Temel.netmodule
.hash = (89 B4 FA 26 C6 7C 59 23 DB 92 6F 3A 29 5E 31 C7 // ...&.|Y#..o:)^1.
E7 37 35 AF ) // .75.
.class extern public vbdotnet.vbselam
{
.file vbselam.netmodule
.class 0x02000002
}
.class extern public Temel
{
.file Temel.netmodule
.class 0x02000002
}
.module Uygulama.exe
// MVID: {2F568429-2D83-4AA8-9558-46FB59574BBB}
.imagebase 0x00400000
.subsystem 0x00000003
.file alignment 512
.corflags 0x00000001
// Image base: 0x07000000

Uygulamamz altrdmzda aadaki sonucu elde ederiz.

ekil 10. Uygulamann almasnn sonucu.

Bylece geldik bir makalemizin daha sonuna. Umuyorum ki assembly'lar bu ynleri ile incelemek
siz deerli okurlarmzn iine yaryordur. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

www.bsenyurt.com Page 2291


selim@bsenyurt.com

Private Assembly ve Shared Assembly Kavram (


22.04.2004 ) - Framework
Deerli Okurlarm, Merhabalar.

Bu makalemizde, .NET'in temellerinden olan Assembly kavramnn nemli bir blm olan Global
Assembly Cache'i incelemeye alacaz. Net dilinde, assembly'lar private (zel) ve shared
(paylaml) olmak zere iki kategoriye ayrabiliriz. Private assembly'lar oluturulduklarnda,
altrlabilmeleri iin, uygulama ile ayn klasr altnda yer almaldrlar. Sz gelimi aadaki gibi bir
assembly'a sahip olduumuzu dnelim.

using System;

namespace PriAsm
{
public class Hesap
{
public double Topla(double a,double b)
{
return a+b;
}
}
}

Visual Studio.Net ortamnda bir class library olarak oluturduumuz bu assembly derlendiinde,
PriAsm.dll dosyasnn oluturulduunu grrz.

ekil 1. Assembly dosyamz.

imdi, oluturulan bu assembly iindeki Hesap isimli snfmz, baka bir klasrde yer alan bir
uygulama ierisinde kullanmak istediimizi dnelim. Bu durumda, PriAsm.dll dosyamz,
kullanmak istediimiz uygulamann klasrne kopyalamamz yeterli olucaktr. rnein aadaki
uygulamay gz nne alalm.

using System;
using PriAsm;

namespace Ornek
{
class Class1
{

www.bsenyurt.com Page 2292


static void Main(string[] args)
{

}
}
}

Bu Console uygulamasn derlemeye altmzda, "The type or namespace name 'PriAsm'


could not be found (are you missing a using directive or an assembly
reference?)" hatasn alrz. Bu hatay almamz son derece doaldr. nk PriAsm.dll
assembly'mz private bir assembly'dr. Bunun doal sonucu uygulamamzn bu assembly hakknda
hi bir bilgiye sahip olmamasdr. Uygulamamza, PriAsm.dll assembly'nn referans edilmesi
gerekmektedir. ncelikle, PriAsm.dll dosyasn, uygulamamzn assembly'nn bulunduu klasre
kopylamamz gerekir.

ekil 2. PriAsm.dll ile uygulama assemble' ayn yerde olmal.

Daha sonra ise uygulamamza PriAsm.dll assembly'n referans etmemiz gerekir. Bu amala
solution explorer'da assembly ismine sa tklanr ve Add Reference seilir.

www.bsenyurt.com Page 2293


ekil 3. Add Reference.

Karmza gelen Add Reference penceresinden, Projects ksmna geilir.

ekil 4. Projects

Burada Browse seenei ile, PriAsm.dll assembly'nn bulunduu klasre gidilir ve bu dll dosyas
seilerek referans ekleme ilemi tamamlanm olur.

www.bsenyurt.com Page 2294


ekil 5. Referansn eklenmesi.

Bu noktadan sonra Solution Explorer penceresine baktmzda, PriAsm isim alannn eklenmi
olduunu grrz.

ekil 6. PriAsm eklenmi durumda.

Artk uygulamamzda bu assembly iindeki snflar kolayca kullanabiliriz. Aadaki basit rnekte
bunu grebiliriz.

using System;
using PriAsm;

www.bsenyurt.com Page 2295


namespace Ornek
{
class Class1
{
static void Main(string[] args)
{
Hesap h=new Hesap();
double sonuc=h.Topla(4,5);
Console.WriteLine(sonuc.ToString());
}
}
}

Private assembly'lar bu ekilde kullanmak her zaman tercih edilen bir yol deildir. Nitekim,
PriAsm.dll assembly'nn eriebilmek bu dll'in, uygulamann assembly' ile ayn klasrde olmas
gerekmektedir. (Nitekim, PriAsm.dll assembly'nn uygulamann debug klasrnden baka bir yere
tanmas, uygulamann derleme zamannda hata vermesine yol aar. nk belirtilen adresteki
referans dosyas yerinde deildir. ) Buna karlk olarak bazen, oluturduumuz assembly'a birden
fazla uygulamann ayn yerden erimesini isteyebiliriz. te bu durumda devreye Global Assembly
Cahce girmektedir. GAC .NET uygulamalar tarafndan paylalan bileenlerin yer ald bir veri
deposudur. Birden fazla uygulamann ortak olarak kullanaca assembly'lar sistemdeki Global
Assembly Cache 'e yklenerek paylalm(shared) assembly'lar oluturabiliriz. GAC 'da tutulan
assembly'larn grntsne, bir Win XP sisteminde C:\WINDOWS\assembly klasrnden
ulaabiliriz. Burada yer alan assembly'lar, C# kodu ilk olarak yrtldnde annda derlenir ve
GAC nbelleinde tutulurlar.

ekil 7. GAC Assembly'lar.

Burada dikkat edicek olursanz rnein, System.Data Assembly'ndan iki adet bulunmaktadr. Bu iki
assembly'n sistemde sorunsuz bir ekilde almas, assembly'larn kimliklerinin farkll sayesinde
mmkn olmaktadr. Bu farkll yaratan GAC iine kurulan her bir assembly'n farkl strong
name'lere sahip olmasdr. Bir strong name, bir assembly'n ad, versiyon numaras, dil bilgileri,
dijital imzalar ve public anahtar deeri bilgilerinden oluur. rnein System.Data assembly'nn iki
versiyonu arasndaki farklar aadaki ekilde grld gibidir.

www.bsenyurt.com Page 2296


ekil 8. Farkllklar.

Bir assembly'n yukarda bahsedilen bilgileri AssemblyInfo isimli dosyada tutulmaktadr.imdi


dilerseniz gelitirmi olduumuz PriAsm.dll assembly'n GAC'e nasl kayt edeceimizi incelemeye
alalm. lk olarak bize bu assembly' sistem iin benzersiz (unique) yapacak bir strong name
gerekli. Bir strong name retmek iin, .Net FrameWork'un sn.exe tool'unu kullanabiliriz.

www.bsenyurt.com Page 2297


ekil 9. Strong Name'in oluturulmas.

Bu ilemin ardndan oluan Anahtar.sif isimli dosyay, assembly'mza bildirmemiz gerekiyor. Bunun
iin AssemblyInfo dosyasndaki AssemblyKeyFile niteliini kullanacaz. (Burada dosya uzantsnn
sif olmasnn zel bir nedeni yok. Ben sifre'nin sif'ini kullandm. Sonu olarak dosya binary
yazlaca iin herhangibir format verilebilir.)

[assembly: AssemblyKeyFile("D:\\vssamples\\PriAsm\\bin\\debug\\Anahtar.sif")]

Artk assembly'mz bir strong name'e sahip. Dolaysyla GAC iindeki assembly'lardan ve sonradan
gelibilecek olan assembly'lardan tamamyle farkl bir yapya brnd. Artk oluturduumuz bu
assembly' GAC'e alabiliriz. Bunu iki yolla gerekletirebiliriz. lk olarak, .Net Framework'n
GACUtil.exe tool'unu bu i iin kullanabiliriz.

ekil 10. Assembly'n GAC'e kurulmas.

Bu ilemin ardndan GAC klasrne baktmzda, PriAsm assembly'mzn eklenmi olduunu


grrz.

ekil 11. Assembly'n GAC'e eklenmesi.

Dier yandan ayn ilemi, PriAsm.dll dosyasn bu klasre srkleyerekte gerekletirebiliriz. Artk
bu noktadan itibaren, PriAsm assembly'na ve iindeki snflara, herhangibir .net uygulamasndan
kolayca eriebiliriz. rnein, herhangibir .net uygulamasndan PriAsm assembly'na ulamak iin
tek yapmamz gereken assembly' uygulamamza ayn private assembly'larda olduu gibi referans
etmektir. Fakat bu sefer, PriAsm.dll assembly'n uygulamamzn PE(Portable Executable)
dosyasnn bulunduu debug klasrne almak gibi bir zorunluluumuz yoktur. nk, programn ilk
derleniinde, PriAsm.dll, GAC'e alnr ve burada tutulur. Dolaysyla aadaki rnek kodlarn yer

www.bsenyurt.com Page 2298


ald Console Uygulamasnn bulunduu debug klasrne PriAsm.dll dosyasnn yklenmesi
gerekmez.

using System;
using PriAsm;
namespace ConsoleApplication3
{
class Class1
{
static void Main(string[] args)
{
Hesap h=new Hesap();
double sonuc=h.Topla(1,2);
}
}
}

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

likiler ve Hesaplanm Alanlarn Bir Arada


Kulllanlmas ( 08.04.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde aralarnda bire-ok (one-to-many) iliki olan tablolar iin hesaplanm alanlarn,
(yani DataColumn snfnn Expression zellii ile oluturduumuz stunlarn) tablolar arasndaki
ilikiler ile nasl bir arada kullanlabileceini incelemeye alacaz. Burada bir arada kullanmdan
kastm, rnek olarak; ebevyn (parent) tabloda fiziki olarak var olmayan ancak uygulamann
almas srasnda oluturulacak bir stundan, detay tablosundaki ilikili alanlar zerinden toplam,
ortalama, miktar gibi Aggregate ifadelerinin altrlmasndan ve sonularn yine parent tabloya
yanstlmasndan bahsediyorum.

Konumuzun ana problemini daha iyi anlamak iin u rnei gz nnde bulunduralm. Internet
zerinden ticaret yapan sitemizde kullanclarn temel bilgileri ile, vermi olduklar sipari bilgilerinin
ayr iki tabloda tutulduunu ve bu tablolar arasnda bire-ok iliki olduunu varsayalm. Kendimize
ait ynetici ekranlarnda, her bir ye iin, bu gne kadar vermi olduu siparilerin toplam saysn
ve bu siparilerin hepsine demi olduu toplam tutarlar anlk olarak grmek istediimizi
varsayalm. Burada bize, ebevyn tabloda bir hesaplanm alan gerekmektedir. Ancak hesaplanm
alan deerleri, detay tablosundaki veriler zerinden gerekletirilmek zorundadr. te bu noktada
devreye iki tablo arasnda tanmlam olduumuz bire-ok iliki girer.

Problemi ve ne yapmak istediimizi ksaca anlattktan sonra dilerseniz bunu gerek bir uygulama
zerinde incelemeye balayalm. Bu uygulamada, web sitesi yeleri iin tasarlanm olan Uyeler
tablosu ve bu yelerin satn alm bilgilerini tutan Siparisler isimli tablolara bir windows uygulamas

www.bsenyurt.com Page 2299


zerinden erimek istediimizi varsayalm. Tablolarmzn sahip olaca alanlar ve aralarndaki iliki
aadaki ekilde yer almaktadr.

ekil 1. Tablolarmzn Yaps ve Aralarndaki Bire-ok liki.

Bu iki tabloyu gz nne aldmzda, bir yeye ait birden fazla sipariin olabileceini grrz.
Uygulamamz bittiinde, DataGrid nesnemizde, her bir yenin bu gne kadar vermi olduu
siparilerin toplam saysn ve demi olduu toplam miktarlar gsterecek iki yeni stunumuz
olucak. Hi vakit kaybetmeden uygulamamzn kodlarn yazmaya balayalm. nce, aadaki gibi
bir Form tasarlayalm.

ekil 2. Form Tasarmmz.

Uygulamamzn kodlarna gelince.

SqlConnection con;
SqlDataAdapter da;
DataTable dtUyeler;
DataTable dtSiparisleri;
DataSet ds;

private void btnGetir_Click(object sender, System.EventArgs e)


{
/* Sql sunucumuza olan balantmz oluturuluyor. */
con=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=SSPI");

www.bsenyurt.com Page 2300


ds=new DataSet(); /* DataSet nesnemiz oluturuluyor. */

/* nce, Uyeler tablomuzdaki verileri alyor , dtUyeler DataTable'na yklyor ve oluan veri
kmesini temsil eden bu DataTable nesnesinide DataSet nesnemizin tables koleksiyonuna
ekliyoruz.*/
da=new SqlDataAdapter("Select * From Uyeler",con);
dtUyeler=new DataTable();
da.Fill(dtUyeler);
ds.Tables.Add(dtUyeler);

/* Ayn ilemi Siparisleri tablosu iin yapyoruz.*/


da=new SqlDataAdapter("Select * From Siparisleri",con);
dtSiparisleri=new DataTable();
da.Fill(dtSiparisleri);
ds.Tables.Add(dtSiparisleri);

/* Uyeler tablosundan Siparisleri tablosuna olan (dolaysyla dtUyeler DataTable nesnesinin


bellekte iaret ettii blgedeki veri satrlarndan, dtSiparisleri dataTable nesnesinin bellekte temsil
ettii blgedeki veri kmesine olan) bire-ok ilikiyi tanmlyoruz. */
ds.Relations.Add("Uyeler_Siparisleri",dtUyeler.Columns["UyeID"],dtSiparisleri.Columns["UyeID"]
,false);

dtSiparisleri.Columns.Add("ToplamTutar",typeof(Decimal),"Miktar*BirimFiyat");/* Bu satr ile,


dtSiparisleri tablomuzda, her bir satr iin Miktar ve BirimFiyat alanlarnn deerlerini arpyoruz.
kan sonular ToplamTutar isimli yeni tanmladmz bir alana iinde tutacak ekilde dtSiparisler
DataTable nesnesinin Columns koleksiyonuna ekliyoruz. */

dtUyeler.Columns.Add("Siparis Sayisi",typeof(int),"COUNT(Child.UyeID)");/* Burada ise,


dtUyeler tablosunda Siparis Sayisi isimli yeni bir alan oluturuyoruz. Bu alan, ilikili tablo olan
detay tablosundaki UyeId alanlarnn saysn COUNT ile hesaplyor. Ancak bunu yaparken Child
nesnesini kullanyor. Nitekim burada Child nesnesi, Uyeler tablosundaki her bir uyenin, Siparisleri
tablosunda karlk gelen satrlarn temsil ediyor. */

dtUyeler.Columns.Add("Toplam deme",typeof(Decimal),"SUM(Child.ToplamTutar)");/* Burada


ise, Child nesnesini kullanarak, var olan iliki zerinden, Siparisleri tablosuna gidiyor ve her bir ye
iin, az nce hesapladmz ToplamTutar alanlarnn toplamn SUM aggregate fonksiyonu ile
hesaplyoruz. Sonularn ise, Toplam deme isimli yeni bir alan olarak Uyeler tablomuza
ekliyoruz.*/

dgUyeler.DataSource=ds.Tables[0];
}

Uygulamamzda Child isimli nesneyi nasl kullandmza ve bu sayede, iki tablo arasndaki iliki
yardmyla, child tablodaki veriler zerindeki hesaplamalar bir btn halinde, parent tabloya
hesaplanm alan olarak nasl eklediimize ltfen dikkat ediniz. Uygulamamz altrdmzda
aadaki sonucu elde ederiz. Grdnz gibi her bir ye iin, yaplm olan toplam siparis
saysna ve demi olduklar toplam miktarlara ulaabildik.

www.bsenyurt.com Page 2301


ekil 3. Uygulamann almasnn Sonucu.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataRelation Snf ve oa-ok (Many-to-


many) likiler ( 01.04.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, DataRelation snf yardmyla, veritabanlarndaki many-to-many(oa-ok)


ilikilerin, balantsz katmanda nasl kullanlabildiini incelemeye alacaz. likisel veri taban
modelinde, tablolar aras ilikilerde ounlukla bire-ok(one-to-many) ilikilere rastlarz. Ancak
azda olsa, oa-ok ilikilerin kullanld durumlarda sz konusudur. Bu ilikiye rnek olarak
ounlukla, Sql sunucusunda yer alan Pubs veritabanndaki Authors ve Titles tablolar gsterilir. Bu
iki tablo arasndaki iliki yledir; bir yazara ait birden fazla kitap titles tablosunda yer alabilir. Ayn
ekilde, bir kitap birden fazla yazar tarafndan kaleme alnm olabilir. Bu bahsedilen iki ilikide ayr
ayr bire-ok ilikilerdir. Yani bir yazarn birden fazla kitab yazm olmas bire ok iliki olarak
dnlebilirken, bir kitabn birden fazla yazara ait olmasda bire-ok iliki olarak gzlemlenebilir.

Ancak, bu iki tablo arasnda ilikiyi bu ekilde yanstmamz mmkn deildir. Nitekim, bire-ok
ilikilerde, ok ilikiyi temsil eden tablodaki yabanc anahtar(foreign key), ebeveyn(parent) tabloda
unique zellikte bir alana ihtiya duyar. Dolaysyla iki ynl ilikinin olduu authors ve titles gibi
tablolar iin bu tarz bir ilikiyi oluturmak biraz daha farkldr. Bunun iin nc bir tablo kullanlr
ve bu tabloda, her iki tablonun primary key alanlarna yer verilir. Aadaki ekil, pubs
veritabannda yer alan authors ve titles tablolar iin oa-ok ilikiyi salayacak bu tarz bir
tablonun yapsn ve aralarndaki ilikiyi gstermektedir.

www.bsenyurt.com Page 2302


ekil 1. titleauthor tablosu yardmyla oa-ok ilikinin tanmlanmas.

Authors tablosunda yer alan her au_id alan, titleauthors tablosunda yer alr. Ayn durum titles
tablosundaki title_id alan iinde geerlidir. Bylece, author ve titles tablolar arasndaki oa-ok
iliki, titleauthor tablosu zerinden gerekletirilebilmektedir.

imdi dilerseniz, kendimiz oa-ok ilikiye sahip iki tablo ve bu tablolarn arasndaki ilikiyi
gerekletirecek nc bir ara tabloy oluturalm. rnek olarak, byk bir yazlm irketindeki
proje elemanlarn ve gerekletirilen projeleri ele alabiliriz. Bir proje mhendisi pek ok proje
gerekletirebilecei gibi, yaplan, halen allan veya planlanan projelerde birden fazla proje
mhendiside grev alabilir. te bu oa-ok iliki iin gsterebileceimiz gzel bir rnektir. Bu
amala sql sunucumuzda aadaki yaplara sahip tablolar oluturalm.

www.bsenyurt.com Page 2303


ekil 2. Projedeki mhendislere ait genel bilgileri tayan Muhendisler tablosu.

www.bsenyurt.com Page 2304


ekil 3. Projelere ait yzeysel bilgileri tutacak olan Projeler tablosu.

Son olarakta oka-ok ilikiyi tayacak ara tablomuz.

www.bsenyurt.com Page 2305


ekil 4. MuhendisProje Tablomuz oka-ok ilikiyi tayacak.

MuhendisProje tablosunu oluturduumuzda, Muhendisler tablosundan bu tabloya bire-ok iliki ve


yine Projeler tablosundan bu tabloya bire-ok ilikileri aadaki gibi oluturmamzda gerekiyor.

ekil 5. MuhendisProje tablosu zerinden gerekletirilen oka-ok iliki.

Gelelim iin .net ksmna. Tasarladmz bu yapy uygulamalarmzda kullanabilmek iin, zellikle
balantsz katman nesneleri zerinde kullanabilmek iin DataRelation snfn kullanmamz
gerekiyor. Yukardaki ilemler ile sql sunucumuzda oluturduumuz dzenin aynsn ,
sistemimizdeki balantsz katman uygulamasnda gerekletirmek istediimiz senaryoyu gz
nne alalm.

ncelikle, sahip olduumuz tabloyuda bir DataSet nesnesine aktarmamz gerekiyor. Daha sonra,
sql sunucusundaki bu tablolar arasndaki ilikileri, DataSet ierisindeki tablolarmz arasndada
gerekletirmemiz gerekli. te bu noktada DataRelation snf devreye giriyor. nce, Muhendisler
tablosundan, MuhendisProje tablosuna olan bire-ok ilikiyi oluturuyoruz. Ardndan ise, Projeler

www.bsenyurt.com Page 2306


tablosundan, MuhendisProje tablosuna olan bire-ok ilikiyi tasarlyoruz. Bu ilikilerin DataRelation
nesneleri olarak tanmlanmasnn ardndan, DataSet snfnn DataRelation nesnelerini tayan
Relations koleksiyonunada eklenmeleri gerekiyor. te bu son adm ile birlikte, veritaban
sunucusundaki oa-ok ilikinin aynsn balantsz katman nesnemiz olan DataSet zerinde de
gerekletirmi oluyoruz.

Dilerseniz, yukarda zetlediimiz iin uygulamada nasl gerekletirilebileceini incelemeye


alalm. Bunu iin bir windows uygulamas gelitirebiliriz. Bu uygulamada bir proje mhendisi
seildiinde, bu mhendisin yer ald projeleri ve bu projelerdeki ekip arkadalarn gsterecek
olan bir uygulama gelitirelim. Bu amala aadakine benzer tarzda bir form hazrlayalm.

ekil 6. Form Tasarmmz.

Sra geldi uygulamamzn kodlarn yazmaya. Uygulamay iki ksmda yazarsak daha kolay anlalr
olucaktr. ncelikle, bir mhendisi setiimizde bu mhendisin grev ald projeleri elde
edebileceimiz kodu uygulamamza ekleyelim. Bu aamada uygulamamzn kodlar aadaki gibi
olacaktr.

SqlConnection con;
SqlDataAdapter da;
DataSet ds;
DataTable dtMuhendisler;
DataTable dtProjeler;
DataTable dtMuhendisProje;

private void Form1_Load(object sender, System.EventArgs e)


{
/* Sql sunucumuza bir balant ayoruz. */
con=new SqlConnection("Data source=localhost;initial catalog=Friends;integrated
security=SSPI");

/* Mhendisler, MuhendisProje ve Projeler tablolarn referans edicek DataTable nesneleri ile bu


DataTable nesnelerini bnyesinde barndracak DataSet nesnemizi oluturuyoruz.*/
DataSet ds=new DataSet();
dtMuhendisler=new DataTable();

www.bsenyurt.com Page 2307


dtProjeler=new DataTable();
dtMuhendisProje=new DataTable();

/* SqlDataAdapter nesnemiz ile ilk aamada, Muhendisler tablosundaki bilgileri alyor ve


dtMuhendisler DataTable nesnesine yklyoruz. */
da=new SqlDataAdapter("Select * From Muhendisler",con);
da.Fill(dtMuhendisler);
/* Tanmladmz primaryKey alann, listBox kontrolndeki bir Muhendisi setiimizde bu
Muhendise ait satr bulucak Find metodunda kullanabilmek iin, PersonelID zerinden
oluturuyoruz. */
dtMuhendisler.PrimaryKey=new DataColumn[]{dtMuhendisler.Columns["PersonelID"]};
/* dtMuhendisler DataTable nesnesini, DataSet in Tables koleksiyonuna ekliyoruz. */
ds.Tables.Add(dtMuhendisler);

/* imdi Projeler tablosundaki verileri, dtProjeler DataTable nesnesine ekliyor ve bu


dataTable'da DataSet nesnemizin Tables koleksiyonuna ekliyoruz.*/
da=new SqlDataAdapter("Select * From Projeler",con);
da.Fill(dtProjeler);
ds.Tables.Add(dtProjeler);

/* Sra MuhendisProje tablosundaki verilerin eklenmesinde. */


da=new SqlDataAdapter("Select * From MuhendisProje",con);
da.Fill(dtMuhendisProje);
ds.Tables.Add(dtMuhendisProje);

/* imdi iin nemli ksm. Muhendisler tablosundan MuhendisProje tablosuna olan bire-ok
ilikiyi DataSet nesnemizin Relations koleksiyonuna bir DataRelation nesnesi olarak ekliyoruz.*/
ds.Relations.Add("Muhendis_MuhendisProje",dtMuhendisler.Columns["PersonelID"],dtMuhendisP
roje.Columns["PersonelID"],false);

/* Burada ise, Projeler tablosunda, MuhendisProje tablosuna olan bire-ok ilikiyi tanmlyor ve
DataSet nesnemizin Relations koleksiyonuna DataRelation olarak ekliyoruz.*/
ds.Relations.Add("Projeler_MuhendisProje",dtProjeler.Columns["ProjeID"],dtMuhendisProje.Colu
mns["ProjeID"],false);

/* lbMuhendisler ListBox kontrolnn dtMusteriler DataTable'ndaki verileri gstereceini


belirtiyoruz.*/
lbMuhendisler.DataSource=dtMuhendisler;
/* Buradaki satrlarda, Form zerindeki lbMuhendisler ListBox kontrol iin, Muhendislerin
adlarn gsterecek DisplayMember ve her bir mhendisin PersonelID alannn deerini indis olarak
alcak ValueMember zelliklerini belirliyoruz.*/
lbMuhendisler.DisplayMember=dtMuhendisler.Columns["Ad"].ToString();
lbMuhendisler.ValueMember=dtMuhendisler.Columns["PersonelID"].ToString();
}

private void btnGetir_Click(object sender, System.EventArgs e)


{
lbProjeler.Items.Clear();

www.bsenyurt.com Page 2308


/* ncelikle lbMuhendisler ListBox kontrolnden seilen Mhendise ait PersonelID alannn
deerini alyor ve DataTable snfnn Rows koleksiyonunun Find metodu yardmyla bu PrimaryKey
deerini ieren satr dtMuhendisler tablosundan buluyor ve DataRow nesnesine aktaryoruz.*/
DataRow dr;
dr=dtMuhendisler.Rows.Find(lbMuhendisler.SelectedValue);

/* Foreach dngsnde ilk aamada, seilen Muhendisin ocuk satrlarn(child rows)


MuhendisPersonel tablosundan alyoruz. Bir veya birden fazla satr geldiini dnrsek her bir
satr iinde, Projeler ve MuhendisProje tablolar arasndaki ilikiyi kullanarak, GetParentRow metodu
yardmyla, Mhendislerin alt Projelere ait satrlar elde ediyoruz. Sonrada bu satrlardaki
ProjeAdi alann deerini lbPorjeler isimli ListBox kontrolmze ekliyoruz.*/
foreach(DataRow drProjeNo in dr.GetChildRows("Muhendis_MuhendisProje"))
{
DataRow drProje=drProjeNo.GetParentRow("Projeler_MuhendisProje");
lbProjeler.Items.Add(drProje["ProjeAdi"]);
}
}

Kodumuzda neler olduunu anlayabilmek iin aadaki ekil bize daha fazla yardmc olucaktr.
Burada, foreach dngs ierisinde meydana gelen olaylar tasvir edilmeye allmtr.

ekil 7. Bir Mhendisin zerinde alt projelerin elde edilmesi.

www.bsenyurt.com Page 2309


Uygulamay altrp herhangibir Mhendis iin Getir balkl butona tkladmzda, bu mhendisin
alt projelerin elde edildiini grrz.

ekil 8. Uygulamann almasnn sonucu.

imdi gelelim ilkinci ksma. Foreach dngs iinde, seilen Mhendis satrnn, MuhendisPersonel
tablosundaki alanlarn GetChildRows metodu ile elde ettik. Daha sonra elde edilen her satrn,
Projeler tablosunda karlk geldii satrlara ulatk. Bu ilemi gerekletirmemizde, MuhendisProje
tablosunun ve bu tablo ile Muhendis ve Projeler tablolarnn aralarndaki bire-ok ilikilerin byk
bir nemi vardr. imdi ise amacmz elde edilen projelere kimlerin katld. te bunun iin, elde
edilen her proje satrndan geriye doru gidecek ve yine ilikileri kullanarak bu problemi sonuca
kavuturacaz. Bunun iin btnGetir olay prosedrndeki kodlar aadaki ekilde deitirmemiz
yeterlidir.

private void btnGetir_Click(object sender, System.EventArgs e)


{
lbProjeler.Items.Clear();
lbEkip.Items.Clear();

DataRow dr;
dr=dtMuhendisler.Rows.Find(lbMuhendisler.SelectedValue);

foreach(DataRow drProjeNo in dr.GetChildRows("Muhendis_MuhendisProje"))


{
DataRow drProje=drProjeNo.GetParentRow("Projeler_MuhendisProje");
lbProjeler.Items.Add(drProje["ProjeAdi"]);
lbEkip.Items.Add(drProje["ProjeAdi"]);
foreach(DataRow drMuh in drProje.GetChildRows("Projeler_MuhendisProje"))
{
DataRow drMuhBilgi=drMuh.GetParentRow("Muhendis_MuhendisProje");
lbEkip.Items.Add(drMuhBilgi["Ad"]+" "+drMuhBilgi["Soyad"]);
}
}

www.bsenyurt.com Page 2310


}

Yeni dzenlemeler ile uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

ekil 9. Bir Mhendisin alt projeler ve projelerdeki takm arkadalarnn elde edilmesi.

Burada yaptklarmz deerlendirirsek kafa kartrc tek unsurun foreach dngs ierisindeki
yaklamlar olduunu grrz. Bunun yannda, ara tablomuz olan MuhendisProje tablosunun nasl
oluturulduu, verileri nasl tuttuu ve dier tablolar arasndaki ilikilerin .net ortamnda balantsz
katman zerinde nasl simle edildii nemlidir. Bu olgulara dikkat etmenizi ve iyice incelemenizi
neririm. Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde bulumak dileiyle
hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataTable.Compute Metodu ( 29.03.2004 ) -


Ado.Net
Deerli Okurlarm, Merhabalar.

ou zaman, uygulamalarmzda T-Sql' in Aggregate fonksiyonlarn kullanarak, belirli stunlara ait


veriler zerinden, toplam deer, en byk deer, en kk deer, ortalama deer vb. gibi
sonulara ulamaya alrz. Bu amala T-Sql' in Avg, Sum, Count gibi Aggregate fonksiyonlarndan
yararlanrz. te bu makalemizde, bu fonksiyonlar, DataTable snfnn Compute metodu yardmyla
nasl kullanabileceimizi incelemeye alacaz.

ncelikle, T-Sql' de yer alan Aggregate fonksiyonlarndan ksaca bahsetmekta yarar olduunu
dnyorum. Bu fonksiyonlarn en nemlileri ve kullanllar aadaki tabloda yer almaktadr.

www.bsenyurt.com Page 2311


Dn
Fonksiyon Prototipi Aklama rnek
Tipi

Sql sorgusunda int, SELECT AVG(Prim)


AVG AVG ( [ ALL | belirtilen kritere uyan decimal, FROM Primler
(Ortalama) DISTINCT ] ifade ) alanlarn ortalamasn money, WHERE PerID =
alr. float 1002124

Sql sorgusunda int,


SUM SUM ( [ ALL | belirtilen kritere uyan decimal, SELECT SUM(Prim)
(Toplam) DISTINCT ] ifade ) alanlarn toplam money, FROM Primler
deerini alr. float

COUNT COUNT ( { [ ALL |


SELECT COUNT(*)
(Toplam DISTINCT ] ifade ] Satr saysn verir. int
FROM Primler
Say) |*})

ifade
MAX (En Belirtilen alana ait olarak
MAX ( [ ALL | SELECT MAX(Prim)
byk stundaki en byk belirtilen
DISTINCT ] ifade ) FROM Primler
deer) deeri verir. tip ile
ayndr.

ifade
Belirtilen alana ait olarak
MIN (En MIN ( [ ALL | SELECT MIN(Prim) FROM
stunlardaki en belirtilen
kk deer) DISTINCT ] ifade ) Primler
kk deeri verir. tip ile
ayndr.

COUNT Fonksiyonu
COUNT_BIG COUNT_BIG ( { [
gibi satr saysn SELECT COUNT_BIG(*)
(Toplam ALL | DISTINCT bigint
verir. Tek fark dn FROM Primler
Say) ] expression } | * ) deeridir.

Belirtilen kritere
STDEV SELECT STDEV(Alan)
uyan alanlar iin
(Standart STDEV ( expression ) float
Standart Sapma
Sapma) FROM Tablo
deerini hesaplar.

Tablo 1. Aggregate Fonksiyonlar

Bu tip fonksiyonlar .net uygulamalarmzda kullanmak iin, akla gelen ilk yol Command
nesnelerinden yararlanmaktr. rnein, Sql sunucumuzda yer alan, Northwind veritabanndaki,
Products tablosunu ele alalm. Bu tabloda, Aggregate fonksiyonlarn test edebilmemiz iin
kullanabileceimiz alanlar mevcuttur.(UnitPrice, UnitsInStock vb.) imdi ilk dndmz ekilde,
yani bir Command nesnesini kullanarak, belli bir gruba ait UnitPrice ve UnitsInStock alanlarnn

www.bsenyurt.com Page 2312


deerleri zerinde, Aggregate fonksiyonlar ile denemeler yapalm. rnein basit olmas amacyla
bir Console uygulamas gelitirebiliriz.

using System;
using System.Data;
using System.Data.SqlClient;

namespace Compute
{
class Class1
{
static void Main(string[] args)
{
/* Yerel sql sunucumuzdaki Northwind veritabanna bir balant hatt oluturuyoruz.*/
SqlConnection con=new SqlConnection("Data Source=localhost;initial
catalog=Northwind;Integrated Security=SSPI");
/* Bu SqlCommand nesnesinin ierdii sql cmlecii ile, SupplierID deeri 11 olan Products
tablosu alanlarnn UnitPrice deerlerinin toplamn ve ka satr olduklarnn saysn elde ediyoruz.
*/
SqlCommand cmdSum=new SqlCommand("SELECT SUM(UnitPrice),COUNT(SupplierID)
FROM Products WHERE SupplierID=11",con);
/* Bu SqlCommand nesnesinin ierdii sql cmlecii ile, Products tablosundaki UnitPrice
alannn deerlerinin ortalamasn elde ediyoruz. */
SqlCommand cmdAvg=new SqlCommand("SELECT AVG(UnitPrice) FROM Products",con);

/* Balantmz ayoruz. */
con.Open();
SqlDataReader dr; /* SqlDataReader nesnemizi tanmlyoruz.*/
dr=cmdSum.ExecuteReader(); /* Komutumuzu altrp sonular bir akm eklinde
SqlDataReader nesnemize aktarlacan belirtiyoruz. */
/* SqlDataReader akm iinde satr okuyabildii srece devam edicek dngmz
balatyoruz ve sorgu sonucu elde edilen deerleri ekrana yazdryoruz. */
while(dr.Read())
{
Console.WriteLine("Toplam Fiyat {0}, Satr Says {1} ",dr[0],dr[1]);
}
dr.Close(); /* SqlDataReader nesnemizi kapatyoruz. */

dr=cmdAvg.ExecuteReader(); /* Bu kez SqlDataReader nesnemizi ikinci sorgu


cmleciimizi altracak SqlCommand nesnesi ile oluturuyoruz. */
/* SqlDataReader akm iinde satr okuyabildii srece devam edicek dngmz
balatyoruz ve sorgu sonucu elde edilen deerleri ekrana yazdryoruz. */
while(dr.Read())
{
Console.WriteLine("Ortalama Fiyat {0}",dr[0]);
}

dr.Close(); /* SqlDataReader nesnemizi kapatyoruz. */


con.Close(); /* SqlConnection nesnemizi kapatyoruz. */

www.bsenyurt.com Page 2313


}
}
}

Uygulamay altrdmzda aadaki ekran grntsn elde ederiz.

ekil 1. SqlCommand ile Aggregate Fonksiyonlarnn Kullanm.

imdi gelelim, bu gibi ilemlerin DataTable snf ile nasl gerekletirilebileceine. ou zaman
uygulamalarmzda balantsz katman nesneleri ile alkmaktayz. Bunlardan biriside DataTable
nesnesidir. DataTable nesneleri bildiiniz gibi, veritabanndaki bir tabloya ait ieriin bellekte
tutulduu blgeyi iaret ederler. Yada uygulama ierisinde bizim oluturacamz bir tablonun
bellek grntsn temsil ederler. Her iki haldede, DataTable nesnesinin temsil ettii blgede
veriler yer alabilir. Bu veriler zerinde, Aggregate Fonksiyonlarn kullanmak istediimizde, aada
prototipi belirtilen Compute metodunu kullanabiliriz.

public object Compute(string ifade,string filtre);

Compute metodu, belirtilen bir alan iin, belirtilen filtreleme mekanizmasnn artlar dahilinde,
Aggregate Fonksiyonlarnn iletilmesinde kullanlr. lk parametrede SUM, AVG gibi Aggregate
fonksiyonlarnn kullanld ifade yer alr. kinci parametre ise karlatrma koulumuzdur. Bu
koul aslnda Where koulunun devamndaki ifadeyi ierir. Dikkat edicek olursanz, Compute
metodunun geri dn deerinin tipi Object trndendir. Bunun sebebi, altrlan fonksiyonlar
sonucu elde edilecek sonularn veri tipinin tam olarak kestirilememesidir. Aada, Compute
metodunun kullanmna ilikin rnek ifadeler yer almaktadr.

object objToplam;
objToplam= Tablo.Compute("Sum(Primler)", "PerID = 8");

object objToplam;
objToplam= Tablo.Compute("Sum(Primler)", "Baslangic > 1/1/2004 AND Bitis < 31/1/2004");

imdi yukardaki rneimizde, Product isimli veritabanna ait verileri bellekte bir DataTable iinde
sakladmz dnelim. imdi Aggregate fonksiyonlarmz bu rnek zerinde kullanalm.
Dilerseniz bu sefer, DataTable zerindeki Compute metodunun sonularn daha kolay
izleyebileceimiz bir Windows uygulamas gelitirelim. Form tasarmmz aadakine benzer ekilde
olabilir.

www.bsenyurt.com Page 2314


ekil 2. Form tasarmmz.

imdide uygulamamzn kodlarn yazalm.

/* SqlConnection, SqlDataAdapter ve DataTable nesnelerimiz tanmlanyor.*/

SqlConnection con;
SqlDataAdapter da;
DataTable dtProducts;

private void Form1_Load(object sender, System.EventArgs e)


{
con=new SqlConnection("Data Source=localhost;initial catalog=Northwind;Integrated
Security=SSPI"); /* SqlConnection nesnemiz oluturuluyor ve Northwind veritaban iin bir balant
hatt tekil ediliyor. */
da=new SqlDataAdapter("Select * From Products",con); /* SqlDataAdapter nesnemiz Products
tablosundaki tm veriler zerinde alacak ekilde, geerli balant nesnesi zerinden
oluturuluyor. */
dtProducts=new DataTable("Urunler"); /* Products tablosundaki verilerin bellekte tutulaca
blgeyi temsil edicek DataTable nesnemiz oluturuluyor. */
}

private void btnDoldur_Click(object sender, System.EventArgs e)


{
da.Fill(dtProducts); /* DataTable nesnemizin bellekte temsil ettii blge, SqlDataAdapter
nesnemiz ile dolduruluyor. */
dgProducts.DataSource=dtProducts; /* DataGrid nesnemiz veri kaynana balanyor ve
Products tablosundaki verileri gstermesi salanyoru. */
}

private void btnOrtalama_Click(object sender, System.EventArgs e)


{
double ortalama;
ortalama=Convert.ToDouble(dtProducts.Compute("AVG("+cmbAlan.SelectedItem.ToString()+")"
,"SupplierID=11")); /* Burada kullancnn setii alana gre SupplierID deeri 11 olanlarn
ortalamas hesaplanyor. Sonu noktal say kabileceinden Convert snfnn ToDouble metodu ile
Double veri tipine aktarlyor. */
lblOrt.Text=ortalama.ToString();

www.bsenyurt.com Page 2315


}

private void btnToplam_Click(object sender, System.EventArgs e)


{
double toplam;
toplam=Convert.ToDouble(dtProducts.Compute("SUM("+cmbAlan.SelectedItem.ToString()+")","
SupplierID=11")); /* Bu kezde SupplierID alannn deeri 11 olan alanlarn Toplam deeri
hesaplanyor. */
lblToplam.Text=toplam.ToString();
}

Uygulamadaki en nemli nokta Compute metodunun kullanm eklidir. Burada kullancnn


ekrandaki ComboBox kontrolnden setii alana gre ilemler yaplr. Uygulamay altrdmzda
aadaki ekran grntsn elde ederiz. Bu uygulama daha ok gelitirilebilir. rnein koul
ifadesininde kullanc tarafndan belirlenmesi salanabilir. Bu gelitirmeleri siz deerli okurlarmza
brakyorum.

ekil 3. Compute metodu ile Aggregate fonksiyonlarnn altrlmas.

Bu ksa makalemizde DataTable snfna ait Compute metodu yardmyla balantsz katman verileri
zerinde Aggregate Fonksiyonlarn kolayca nasl kullanabileceimizi incelemeye altk. Umarm
siz deerli okurlarm iin yararl bir makale olmutur. Bir sonraki makalemizde grmek dileiyle,
hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

OleDbDataAdapter Snf Olaylar ( 18.03.2004 )


- Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, OleDbDataAdapter snfnn olaylarn incelemeye alacaz. OleDbDataAdapter


snf aadaki tabloda belirtilen nemli olay iermektedir.

www.bsenyurt.com Page 2316


Olay Prototipi Aklama

OleDbDataAdapter'n
fill metodu
kullanldnda
FillError public event FillErrorEventHandler FillError;
oluabilecek bir hata
durumunda bu olay
alr.

Update metodu
altrlarak,
veritabanndaki
tabloya yaplan
public
RowUpdating deiiklikler (satr
event OleDbRowUpdatingEventHandlerRowUpdating;
ekleme, satr silme,
satr gncelleme gibi)
gerekletirilemden
nce bu olay alr.

Veritabannda
yaplacak olan
public deiiklikler, Update
RowUpdated
event OleDbRowUpdatedEventHandlerRowUpdated; metodu ile
gerekletirildikten
sonra bu olay alr.

Tablo 1. OleDbDataAdapter olaylar.

imdi dilerseniz bu olaylar ksaca incelemeye alalm. RowUpdating olayndan balayalm. Bu


olay, OleDbRowUpdatingEventArgs snf trnden bir parametre almaktadr. Bu paramterenin sahip
olduu zellikleri kullanarak, balantsz katmandaki veriler, veritabanna yazlmadan nce deiik
ilevleri yerine getirme imkanna sahip olmu oluruz. OleDbRowUpdatingEventArgs snfnn
zellikleri aadaki tabloda yer almaktadr.

OleDbRowUpdatingEventArgs Snf zellikleri

zellik Grevi Prototipi

Update metodu altrldnda


alacak olan OleDbCommand
public new OleDbCommand Command
Command tipindeki komutu iaret eder. Bu
{get; set;}
nedenle zelliin deerinin tipi
OleDbCommand'dr.

Row Update metodu arldnda, public DataRow Row {get;}


veritabanna gnderilecek olan satr

www.bsenyurt.com Page 2317


iaret eder. Bu satr DataRow tipindedir
ve bu nedenle zelliin veri tipi
DataRow'dur.

Bu zellik ile alacak olan komut


nesnesinin durumu elde edilir veya
deitirilir. zellik UpdateStatus
numaralandrcs trnden bir deeri
Status belirtir. Bu numaralandrc Continue, public UpdateStatus Status {get; set;}
ErrorsOccurred,
SkipAllRemainingRows,
SkipCurrentRow deerlerinden birisini
alr.

Bu zellik Update metodu ile


altrlacak olan sql ifadesini iaret
etmektedir. StatementType
numaralandrcs tipinden bir deeri public StatementType StatementType
StatementType
belirtir. Bu numaralandrc sql {get;}
ifadesinin tipini belirten select, insert,
delete ve update deerlerinden birisini
alr.

Bu zellik, update metodu


altrldnda, balantsz katman
nesnesindeki tablo haritas ile,
public DataTableMapping TableMapping
TableMapping veritabanndaki tablo arasndaki
{get;}
eletirme ilikisini DataTableMapping
snf rnei olan bir nesne ile ifade
eder.

Update metodu altrldnda


iletilen sql komutunun almasnda
Errors bir hata olumas durumunda, oluan public Exception Errors {get; set;}
hatay temsil eden bir zelliktir. Bu
sebepler zelliin tipi Exception'dr.

Tablo 2. OleDbRowUpdatingEventArgs Snf zellikleri

Bu zelliklerin, RowUpdating metodu iinde nasl ilendiini rnekler ile incelemeden nce,
RowUpdating olaynn ileme geme srecini ve yerini incelemekte fayda olduu kansndaym.
RowUpdating olaynn, Update metodu iindeki sql komutlar altrlp, gerekli deiiklikler
veritabanna yanstlmadan nce gerekletiini syleyebiliriz. Aadaki ekil bu konuda bizlere
daha iyi bir fikir verecektir.

www.bsenyurt.com Page 2318


ekil 1. RowUpdating ve RowUpdated olaylarnn devreye girdii noktalar.

imdi RowUpdating olayn incelemeye balayalm. ncelikle basit bir windows uygulamas
oluturalm. Bu uygulamada, Friends isimli veritabanndaki, Kisier isimli tablomuzun verilerini
kullanacaz. imdi uygulamamzn balang kodlarn oluturalm. OleDbDataAdapter nesnemiz
iin, RowUpdating olaynn nasl eklendiine dikkatinizi ekmek isterim.

/* Sql veritabanndaki Friends isimli veritabanndaki Kisiler isimli tabloya balanabilmek iin bize
gerekli olan nesneleri tanmlyoruz. Bir OleDbConnection nesnesi, sql veritabanna balant hatt
ekmek iin; bir OleDbDataAdapter nesnesi, Kisiler tablosundaki verileri, balantsz katman
nesnemiz olan DataTable'n veritabannda gsterdii alana yklemek ve verilerdeki deiiklikleri
veritabanna yazmak iin.*/
OleDbConnection con;
OleDbDataAdapter da;
DataTable dt;

private void Form1_Load(object sender, System.EventArgs e)


{
con=new OleDbConnection("provider=SQLOLEDB;data source=localhost;integrated
security=sspi;database=Friends"); /* Balant hattmz oluturuluyor.*/
da=new OleDbDataAdapter("Select * From Kisiler",con); /* OleDbDataAdapter nesnemiz

www.bsenyurt.com Page 2319


oluturuluyor. */
da.RowUpdating+=new OleDbRowUpdatingEventHandler(RowUpdatingOlayi);
/*OleDbDataAdapter nesnemiz iin, RowUpdating olayn tanmlyor ve oluturuyoruz.*/
dt=new DataTable("Kisiler"); /* DataTable nesnemizin oluturuluyor. */
}

private void btnDoldur_Click(object sender, System.EventArgs e)


{
da.Fill(dt); /* DataTable nesnemizin bellekte iaret ettii blge, Kisiler tablosundaki veriler ile
dolduruluyor.*/
dataGrid1.DataSource=dt; /* DataGrid nesnemize veri kayna olarak DataTable nesnemiz
atanyor.*/
}
private void btnGuncelle_Click(object sender, System.EventArgs e)
{

OleDbCommandBuilder cb=new OleDbCommandBuilder(da); /* OleDbDataAdapter nesnemiz


iin gerekli insert,delete ve update sql komutlarn otomatik olarak OleDbCommandBuilder
yardmyla olutuyuroz.*/
da.Update(dt); /* DataTable'daki deiiklikler veritabanna gnderiliyor.*/
}

/* RowUpdating olaymz tetiklendiinde bu yordammz altrlacak. */


private void RowUpdatingOlayi(object Sender,OleDbRowUpdatingEventArgs arg)
{

imdi RowUpdating olaymz incelemeye balayalm. rnein, Row ve Status zelliklerini bir arada
inceleyelim. Farzedelimki, KisiID numaras 1000 olan satrnn hi bir ekilde gncellenmesini
istemiyoruz. Bu durumu deerlendirebileceimiz en gzel yer, Update ilemi baar ile
gereklemeden nceki yerdir. Yani RowUpdating metodu.

private void RowUpdatingOlayi(object sender,OleDbRowUpdatingEventArgs arg)


{
if(arg.StatementType==StatementType.Update) /* Eer u an yaplan ilem OleDbDataAdapter
nesnesinin UpdateCommand metodunun ierdii OleDbCommand' altracaksa bu kod blou
devreye giriyor.*/
{
if(arg.Row["KisiID"].ToString()=="1000") /* u an ilemde olan satrn KisiID alannn
deerine bakyoruz.*/
{
listBox1.Items.Add("1000 nolu kayd gncelleyemessiniz.");
arg.Status=UpdateStatus.SkipCurrentRow; /* SkipCurrentRow ile bu satrn
gncellenmesini engelliyoruz.*/
}
}
}

www.bsenyurt.com Page 2320


Bu rnek kodlar ile uygulamamz altrdmzda, KisiID alannn deerinin 1000 olduu satrn
DataTable zerinde deitirilsede, veritaban zerinde deitirilmediini grrz. Ancak dier
satrlardaki deiiklikler veritabanna yanstlr.

ekil 2. Uygulamann almas.

Burada Ad alanndaki Burak Selim deerini Burak S. olarak deitirdik. Bu deiiklik DataTable
zerinde gereklemitir. Ancak bunu veritabannada yanstmak istediimizde, RowUpdating
olayndaki karlatrma ifadeleri devreye girecek ve deiiklik veritabanna yanstlmayacaktr.
Visual Studio.NET ortamndan tablo ieriinde baktmzda bu deiikliin gereklemediini
grrz.

ekil 3. Deiiklik veritabanndaki tabloya yanstlmad.

RowUpdating olay ile ilgili verilebilecek bir dier gzel rnek ise, henz gncellenmi olan bir
satrn baka bir kullanc tarafndan gncellenmek istenmesi gibi bir durumu kontrol altna
almaktr. Bu olayda, o anki satra ait Orjinal deerlere bakarak, gncellenmek istenen deerler ile
ayn olup olmad aratrlr. Byle bir sonu karsa kullancya bu satrn zaten gncellendii
tekrar gncellemek isteyip istemeyecei sorulabilir. Bu ilevi yerine getirmek iin RowUpdating
olaymz aadaki gibi ekillendirebiliriz.

private void RowUpdatingOlayi(object sender,OleDbRowUpdatingEventArgs arg)

www.bsenyurt.com Page 2321


{
if(arg.StatementType==StatementType.Update)
{
string sqlKomutu="SELECT * FROM Kisiler WHERE
KisiID='"+arg.Row["KisiID",DataRowVersion.Original]+"' AND
Ad='"+arg.Row["Ad",DataRowVersion.Original]+"' AND
Soyad='"+arg.Row["Soyad",DataRowVersion.Original]+"' AND
DogumTarihi='"+arg.Row["DogumTarihi",DataRowVersion.Original]+"' AND
Meslek='"+arg.Row["Meslek",DataRowVersion.Original]+"'";
OleDbCommand cmd=new OleDbCommand(sqlKomutu,con);
con.Open();
if(cmd.ExecuteNonQuery()==0)
{
listBox1.Items.Add("Bu satr zaten gncellenmi.");
arg.Status=UpdateStatus.SkipCurrentRow;
}
}
}

Burada ncelikle bir select sorgusu oluturuyoruz. Bu sorgu, Update komutu arldnda,
OleDbDataAdapter nesnesinin ilgili komutlarna gnderilen satra ait alanlarn, en son Fill
metodunun arlndan sonraki hallerine bakyor. Eer ayn gncellemeler baka bir kullanc
tarafndan yaplm ise, bu gncel satrn o anki deeri ile veritabanndaki ayn olmayacaktr.
Dolaysyla, orjinal deerler deimi olacandan select sorgusunun almas sonucu geriye 0
deeri dnecektir. Bu baka bir kullancnn bu satr gncellediini gstermektedir. Bu halde iken
kullanc uyarlr. stersek buraya, bir soru kutucuu aarak kullancnn bu satr tekrardan
gncellemek isteyip istemedii sorulabilir. Ben bunun gelitirilmesini siz deerli okurlarma
brakyorum. If dngmz iindede bu satr eer daha nceden gncellenmi ise, SkipCurrentRow
deerini, OleDbRowUpdatingEventArgs snfnn Status zelliine atayarak bu satrn
gncellenmemesini salyoruz. imdi uygulamamz altrp deneyelim. Bunun iin ayn program
kendi bilgisayarnzda iki kez amanz yeterli olucaktr.

www.bsenyurt.com Page 2322


ekil 4. lk hali.

nce, soldaki pencerede grlen uygulamada Nihat Ali Demir'in soyadn D. olarak deitiriyoruz ve
Guncelle balkl butona basarak bu satr veri tabannda da gncelliyoruz. imdi ekrann sandaki
kullancnnda ayn soyadn ayn ekilde deitirmek istediini dnelim. Bu amala sadaki
programda yine Nihat Ali Demir'in soyadn D. yapyoruz ve Guncelle balkl butona tklyoruz. Bu
andan itibaren bizim RowUpdating olayna yazdmz kodlar devreye giriyor. Satrn, Soyad
alannn, Fill metodunun arlmas ile birlikte orjinal deeri halen Demir dir. imdi bunu D. nokta
yapmak istediimizde, ncelikle orjinal alan deeri olan Demir select sorgumuza girer. Bu sorgu
altnda byle bir satr bulunamayacaktr. nk Demir, D. ile deitirilmitir. Ancak ikinci
program fill metodunu bu son gncellemeden sonra armad iin durumdan habersizdir. Bu
nedenle ikinci programn yapmak istedii deiiklik zaten yaplm olduundan geri alnacaktr.

www.bsenyurt.com Page 2323


ekil 5. kinci programn ayn gncellemeyi yapmas engellenir.

Bununla birlikte ikinci kullancnn bu noktadan sonra, D. ismini Demirci olarak deitirmek
istediini yani farkl bir veri girdiini farzedelim. Bu deiiklik gerekleecektir. Bu durumu yle
aklayabiliriz. kinci program, Demir alann D. nokta yapmaya altnda, bu gncelleme dier
program tarafndan yaplm olduundan, satrn gncellenmesi geri alnr. Ancak bu noktada Soyad
alannn orjinal deeride deiir ve D. olur. te bu nedenle bu noktadan sonra ikinci program bu
alann deerini baka bir deer ile deitirebilecektir.

Gelelim RowUpdated olayna. Bu olay ise, ekil 1'de grld gibi, veritabanna olan gncelleme
ilemleri tamamyla gerekletirildikten sonra oluur ve eklenen, silinen, yada gncellenen her satr
iin tetiklenir. Bu olayn OleDbDataRowUpdatedEventArgs snf trnden bir parametresi vardr. Bu
snfn zellikleri OleDbDataRowUpdatingEventArgs snfnn zellikleri ile ayndr. Bununla birlikte
kullanabileceimiz ekstradan bir zellii daha vardr. Bu zellik, RecordsAffected zelliidir. Bu
zellik ile, yaplan gncelletirmeler sonucu etkilenen satr saysn elde edebiliriz. Dilerseniz, bu
olay kodumuza uygulayalm. rnein yaptmz gncelletirmeler sonucu, bu gncelletirmelerden
etkilenen satr saysn elde etmeye alalm. ncelikle OleDbDataAdapter nesnemize, bu olaymz
ekliyoruz.

da.RowUpdated+=new OleDbRowUpdatedEventHandler(RowUpdatedOlayi);

imdide program kodlarmz aadaki gibi gncelleyelim.

private void btnGuncelle_Click(object sender, System.EventArgs e)


{
listBox1.Items.Clear();
OleDbCommandBuilder cb=new OleDbCommandBuilder(da);
da.Update(dt);

www.bsenyurt.com Page 2324


dt.AcceptChanges();

listBox1.Items.Add("Girilen :"+girilen.ToString());
listBox1.Items.Add("Silinen :"+silinen.ToString());
listBox1.Items.Add("Guncellenen :"+guncellenen.ToString());
}

public int girilen=0,silinen=0,guncellenen=0;

private void RowUpdatedOlayi(object sender,OleDbRowUpdatedEventArgs arg)


{
if(arg.StatementType==StatementType.Insert)
{
girilen+=arg.RecordsAffected;
}
else if (arg.StatementType==StatementType.Delete)
{
silinen+=arg.RecordsAffected;
}
else if (arg.StatementType==StatementType.Update)
{
guncellenen+=arg.RecordsAffected;
}
}

Burada yaptmz son derece basit. RowUpdated olay, veritabanna girilecek, gncellenecek veya
veritabanndan silinecek her bir satr iin tetiklendiinden, bu olay yordam iinde, o anki satr iin
altrlacak sql ifadesinin ne olduunu temin ediyoruz. Bunun iinde, OleDbRowUpdatedEventArgs
parametresinin StatementType zelliinin deerine bakyoruz. Uygun deerlere grede, public
integer sayalarmzn deerlerini arttyoruz. Bylece insert,update ve delete ilemlerinin ka satra
uygulandn tespit etmi oluyoruz.

www.bsenyurt.com Page 2325


ekil 6. Gncelleme saylarnn elde edilmesinin sonucu.

Makalemizde son olarak FillError olayn ele almaya alacam. Bu olay bahsettiimiz gibi Fill
metodu uygulandnda oluabilecek hatalarda devreye girmektedir.FillError olay FillErrorEventArgs
snf trnden bir parametre alr. FillErrorEventArgs snfnn, FillError olay iin kullanabileceimiz
zellikleri aadaki tabloda yer almaktadr.

FillErrorEventArgs
Aklama
zellii

Fill metodu ile karlaldnda bir hata oluduu takdirde Continue


Continue zellii kullanlrsa, bu hatalar grmezden gelinerek ileme devam
edilir.

Values Bir hata olutuunda bu hata ile ilgili alanlarn deerlerini belirtir.

DataTable Hatann olutuu DataTable nesnesine iaret eder.

Errors Meydana gelen hatay exception trnden belirtir.

Tablo 3. FillErrorEventArgs Snfnn zellikleri

FillError olaynn devreye girmesine rnek olarak, veri kaynandaki veri tiplerinin, .net
framework'tekiler ile ayn olmamas durumunu gsterebiliriz.

www.bsenyurt.com Page 2326


Bylece geldik bir makalemizin daha sonuna. lerleyen makalelerimizde Ado.net'in temel
kavramlarn incelemeye devam edeceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

OleDbDataAdapter Snf ve Update Metodu. (


14.03.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, OleDbDataAdapter snfnn , veriler zerindeki gncelleme ilemlerinin, veri


kaynana yanstlmas srasnda nasl bir rol oynadn ve kullanldn incelemeye alacaz.
nceki makalelerimizde belirttiimiz gibi, OleDbDataAdapter nesnesi yardmyla veri kaynandan,
uygulamalarmzdaki balantsz katman nesnelerine veri kmelerini aktarmak amacyla Fill
metodunu kullanyorduk. Dier yandan, balantsz katman nesnelerimizin temsil ettii veriler
zerinde yaplan deiiklikleri veritabanna gndermek istersek, Update metodunu kullanrz.

Update metodu alma sistemi asndan olduka ilgi ekici bir metoddur. Bildiiniz gibi,
DataAdapter nesnelerinin, verilerin gncellenmesi iin UpdateCommand, verileri eklemek iin
InsertCommand, veri silmek iin DeleteCommand zellikleri vardr. Uygulamamz alrken,
balantsz katman nesnelerimiz verilerin satrsal bazda durumlarn gsteren bir deer ieririr.
RowState olarak bilinen bu zellik DataRow snfna ait bir zellik olup aadaki tabloda yer alan
DataRowState numaralandrcs trnden deerlerden birisini almaktadr.

DataRowState
Aklama
Deeri

Added Yeni bir satr eklendiini belirtir.

Deleted Bir satrn silindiini belirtir.

Modified Bir satrn dzenlendiini belirtir.

Yeni bir satr oluturulduunu ama henz ilgili


Detached balantsz katman nesnesinin DataRow
koleksiyonuna eklenmediini belirtir.

Satrda herhangibir deiiklik olmadn


Unchanged
belirtir.

Tablo1. RowState zelliinin DataRowState numaralandrcs tipinden alabilecei deerler.

Buradan yola karasak, Update metodu uygulandnda, OleDbDataAdapter nesnesi, parametre


olarak belirtilen DataTable nesnesinin tm satrlarna bakcaktr. Bu satrlarda yukardaki deerleri
aryacaktr. Sonu olarak, Added satrlar iin, InsertCommand zelliindeki sql komutunu, Deleted
satrlar iin DeleteCommand zelliindeki sql komutunu, Modified satrlar iin ise, UpdateCommand

www.bsenyurt.com Page 2327


zelliindeki sql komutunu altracak, bylece uygun gncellemelerin veritabanna en doru sql
ifadeleri ile aktarlmalarn salayacaktr.

Elbette Update komutunun baarya ulamas, Fill metodunun geerli bir SelectCommand sql
komutunu altrmasna baldr. nk, dier komutlarn parametreleri bu select sorgusu ile elde
edilen tablo alanlarndan oluturulacaktr. Ayrca, DeleteCommand ve UpdateCommand
zelliklerinin sahip olduu sql komutlar Where kouluna sahiptirler ve bu koul iin ounlukla
tabloya ait Primary Key(Birincil Anahtar) alann parametre olarak kullanrlar. Bu sebeple, tablonun
birincil anahtara sahip olmas nemlidir.

Bahsetmi olduumuz gncelleme komutlarn elle programlayabileceimiz gibi, bu ilemi bizim iin
basitletiren CommandBuilder snfnda kullanabiliriz. imdi dilerseniz, OleDbCommandBuilder snf
yardmyla bu ilemin nasl gerekletirileceini bir rnek zerinde inceleyelim. rneimizde, basit
bir sql tablosunu kullanacaz. ncelikle programmzn kodlarn yazalm.

/* global seviyede gerekli nesnelerimizi tanmlyoruz. Sql sunucusuna balantmz iin bir
oleDbConnection nesnesi, verileri tablodan ekmek ve DataTable nesnemize aktarmak,
gncellemeleride ayn dataTable nesnesi zerinden veri kaynana gndermek iin bir DataAdapter
nesnesi, balantsz katmanda verilerimizi tutmak iin bir dataTable nesnesi ve OleDbDataAdapter
nesnemiz iin gerekli Update,Delete,Insert komutlarn oluturacak bir OleDbCommandBuilder
nesnesi. */
OleDbConnection con;
OleDbDataAdapter da;
DataTable dt;
OleDbCommandBuilder cb;

private void btnDoldur_Click(object sender, System.EventArgs e)


{
con=new OleDbConnection("Provider=SQLOLEDB;data
source=localhost;database=Friends;integrated security=sspi"); /* Balantmz oluturuluyor. */
da=new OleDbDataAdapter("Select * From Kisiler",con); /* DataAdapter nesnesmiz, select
sorgusu ile birlikte oluturuluyor. */
dt=new DataTable("Kisiler"); /*DataTable nesnemiz oluturuluyor. */
da.Fill(dt); /* DataTable nesnemizin bellekte gsterdii alan Kisiler tablosundaki veriler ile
dolduruluyor. */
dgKisiler.DataSource=dt; /* DataGrid kontrolmz, balantsz katmandaki verileri iaret eden
DataTable nesnemize balanyor. */
}

private void btnGuncelle_Click(object sender, System.EventArgs e)


{
try
{
cb=new OleDbCommandBuilder(da); /* CommandBuilder nesnemiz , OleDbDataAdapter
nesnemiz iin oluturuluyor. CommandBuilder'a ait new yaplandrcs parametre olarak ald
OleDbDataAdapter nesnesinin SelectCommand zelliindeki sql komutuna bakarak gerekli
dier UpdateCommand,DeleteCommand ve InsertCommand komutlarn oluturuyor. */

da.Update(dt); /* DataTable'daki deiiklikler Update metodu ile, veritabanna gnderiliyor.


*/
}

www.bsenyurt.com Page 2328


catch(Exception hata)
{
MessageBox.Show(hata.Message.ToString());
}
}

Uygulamamz altrdmzda ve Doldur isimli butona tkladmzda, tablomuza ait verilerin


dataGrid kontrolne yklendiini grrz.

ekil 1. Fill metodunun altrlmas sonucu.

imdi yeni bir satr ekleyip bir ka satr zerinde deiiklik yapalm ve baka bir satrda silelim.

ekil 2. Update komutunu altrmadan nceki hali.

Gncelle balkl butona tkladmzda, OleDbCommandBuilder nesnemiz, OleDbDataAdapter


nesnemiz iin gerekli olan komutlar oluturur. Daha sonra Update metodu altrlmaktadr.
Update tablomuzda yapm olduumuz dzenleme, silme ve ekleme ilemlerini grmek iin,
DataTable nesnemizin DataRow koleksiyonundaki her bir DataRow nesnesi iin RowState
zelliklerinin deerlerine bakar ve uygun olan sql komutlarna bu satrlardaki deerleri parametreler
vastasyla aktararak veritabannn gncellenmesini salar. Bu noktadan sonra veritabanmzdaki

www.bsenyurt.com Page 2329


tablomuza baktmzda balantsz katman nesnesinin iaret ettii bellek alanndaki tm
deiikliklerin yanstldn grrz.

ekil 3. Tabloya yanstlan deiiklikler.

Dilerseniz CommandBuilder nesnemizin bizim iin oluturmu olduu komutlarn nasl sql ifadeleri
ierdiini inceleyelim. Bu amala, OleDbCommandBuilder snfna ait aada prototipleri belirtilen
metodlar kullanacaz.

Metod Prototipi

GetInsertCommand public OleDbCommand GetInsertCommand();

GetDeleteCommand public OleDbCommand GetDeleteCommand();

GetUpdateCommand public OleDbCommand GetUpdateCommand();

Tablo 2. OleDbCommandBuilder iin Get metodlar.

Dikkat edecek olursanz tm bu metodlar geriye OleDbCommand snf trnden bir nesne deeri
dndrmektedir. Uygulamamzdaki btnGuncelle kodlarn aadaki gibi dzenlediimizde,
OleDbCommandBuilder nesnesinin, OleDbDataAdapter nesnesi iin oluturmu olduu komutlar
grebiliriz.

OleDbCommand cmdInsert=new OleDbCommand();


cmdInsert=cb.GetInsertCommand();
MessageBox.Show("Insert Sql Ifadesi :"+cmdInsert.CommandText.ToString());

OleDbCommand cmdDelete=new OleDbCommand();


cmdDelete=cb.GetDeleteCommand();
MessageBox.Show("Delete Sql Ifadesi :"+cmdDelete.CommandText.ToString());

OleDbCommand cmdUpdate=new OleDbCommand();


cmdUpdate=cb.GetUpdateCommand();
MessageBox.Show("Update Sql Ifadesi :"+cmdUpdate.CommandText.ToString());

imdi uygulamamz altralm.

www.bsenyurt.com Page 2330


ekil 4. CommandBuilder nesnemizin oluturduu Delete sql komutu.

ekil 5. CommandBuilder nesnemizin oluturduu Insert sql komutu.

ekil 6. CommandBuilder nesnemizin oluturduu Update sql komutu.

Grld gibi ilem bu kadar basittir. Ancak dilersek CommandBuilder nesnesini kullanmayp,
DataAdapter nesnemiz iin gerekli sql komutlarn kendimizde yazabiliriz. Bu biraz daha uzun bir
yntem olmakla birlikte, daha ok kontrole sahip olmamz salar. Ayrca her programlama dilinde
olduu gibi, ileri bylesine kolaylatrc nesneler performans kaybna neden olabilmektedir. Bu
nedenlerden tr, OleDbDataAdapter nesnemizin ihtiya duyduu komutlar kendimiz yazmak
isteyebiliriz. Burada nemli olan nokta gerekli parametrelerin doru bir ekilde oluturulmasdr.
imdi yukarda CommandBuilder snf yardmyla gelitirdiimiz uygulamay yineleyelim.

OleDbConnection con;
OleDbDataAdapter da;
DataTable dt;

private void btnDoldur_Click(object sender, System.EventArgs e)


{
con=new OleDbConnection("Provider=SQLOLEDB;data
source=localhost;database=Friends;integrated security=sspi");
da=new OleDbDataAdapter("Select * From Kisiler",con);
dt=new DataTable("Kisiler");
da.Fill(dt);
dgKisiler.DataSource=dt;
}

www.bsenyurt.com Page 2331


private void btnGuncelle_Click(object sender, System.EventArgs e)
{
try
{
da.InsertCommand=new OleDbCommand("INSERT INTO Kisiler
(Ad,Soyad,DogumTarihi,Meslek) VALUES (?,?,?,?)",con);
da.InsertCommand.Parameters.Add("prmAd",OleDbType.VarChar,50,"Ad");
da.InsertCommand.Parameters.Add("prmSoyad",OleDbType.VarChar,50,"Soyad");
da.InsertCommand.Parameters.Add("prmDogum",OleDbType.Date,8,"DogumTarihi");
da.InsertCommand.Parameters.Add("prmMeslek",OleDbType.VarChar,50,"Meslek");

da.UpdateCommand=new OleDbCommand("UPDATE Kisiler SET


Ad=?,Soyad=?,DogumTarihi=?,Meslek=? WHERE KisiID=?",con);
da.UpdateCommand.Parameters.Add("prmKID",OleDbType.Integer,4,"KisiID");
da.UpdateCommand.Parameters.Add("prmSoyad",OleDbType.VarChar,50,"Soyad");
da.UpdateCommand.Parameters.Add("prmDogum",OleDbType.Date,8,"DogumTarihi");
da.UpdateCommand.Parameters.Add("prmMeslek",OleDbType.VarChar,50,"Meslek");
da.UpdateCommand.Parameters.Add("prmKisiID",OleDbType.Integer,4,"KisiID");

da.DeleteCommand=new OleDbCommand("DELETE FROM Kisiler WHERE KisiID=?",con);


da.DeleteCommand.Parameters.Add("prmKisiID",OleDbType.Integer,4,"KisiID");

da.Update(dt);
}
catch(Exception hata)
{
MessageBox.Show(hata.Message.ToString());
}
}

Burada tanmladmz komutlar iin gerekli parametreleri olutururken Parameters koleksiyonunun


Add metodunun aadaki prototipini kullandk.

public OleDbParameter Add(string parameterName,OleDbType oleDbType,int size, string sourceC


olumn);

Buradaki parametreleri ksaca aklayacak olursak; ilk parametremiz, komutumuz iin


kullanacamz parametre ad. kinci parametremizde ise tablodaki alanmzn veri tipini belirliyoruz.
Buradaki veri tipleri OleDbType trndendir. nc parametremizde ise alann bykln
belirtiyoruz. Son parametremiz ise, sql komutu iindeki bu parametrenin hangi alan iin
kullanlacan belirtmektedir ve bu anlam nedeniylede olduka nemlidir. Dikkat ederseniz OleDb
snfnda OleDbParameter trndeki parametreleri sql komutlar iinde ? ile belirttik. Bu nedenle,
parametrelerimizi, ilgili sql komutu nesnesinin OleDbParameter koleksiyonuna eklerken ? srasna
gre tanmlamalyz. imdi uygulamamz altralm ve veriler zerinde aadaki grnen
deiiklikleri yapalm.

www.bsenyurt.com Page 2332


ekil 7. Deiikliklerimiz yaplyor.

imdi Gncelle balkl butonumuza tklayalm. Deiikliklerin tanmladmz sql komutlar


yardmyla veritabannada yanstldn grrz.

ekil 8. Deiikliklerimiz veritabanna yanstld.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde, OleDbDataAdapter snfna
ait olaylar incelemeye alacaz. imdilik grmek dileiyle, hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

OleDbDataAdapter Snf - 2 ( 02.03.2004 ) -


Ado.Net
Deerli Okurlarm, Merhabalar.

nceki makalemizde, OleDbDataAdapter snfnn ne ie yaradndan bahsetmi ve ksa bir giri


yapmtk. Bu makalemizde, OleDbDataAdapter snfnn dier nemli unsurlarn incelemeye devam
edeceiz. ncelemek istediim ilk konu, OleDbDataAdapter nesnesi yardmyla, ilikisel veritaban
modellerinden balantsz katmana aktarlan tablolarn, sahip olduu birincil anahtar (Primary Key)
ve kstlamalarn (Constraints) ne ekilde irdelendii olucak. Konuyu iyice kavrayabilmek amacyla
aadaki basit rnek ile incelememize balayalm. Bu rneimizde, sql sunucumuzda yer alan bir
tabloya ait verileri DataSet zerine alyor ve alnan alanlarn bir takm bilgilerini okuyoruz. rnein,
alanlarn veri tipi, boyutu, null deerler ierip iermedii ve alan adlar bilgilerini ekrana
yazdryoruz.

using System;

www.bsenyurt.com Page 2333


using System.Data;
using System.Data.OleDb;

namespace OleDbDA2
{
class Class1
{
static void Main(string[] args)
{
OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data
source=localhost;initial catalog=Friends;integrated security=sspi"); // Balant nesnemiz
tanmlanyor.
string sqltext="Select * From Deneme"; // Tablodaki tm verileri ekicek sql ifademiz.
OleDbDataAdapter da=new OleDbDataAdapter(sqltext,con); // OleDbDataAdapter
nesnemiz oluturuluyor.
DataSet ds=new DataSet(); // DataSet balantsz katman nesnemiz oluturuluyor.
da.Fill(ds,"Makale"); // DataSet nesnemiz, tablomuza ait veriler ile dolduruluyor.
/* Tablodaki alanlara ait temel bilgileri edinmek iin foreach dngsn kullanyoruz. 0
indisli tablomuz yani deneme tablomuza ait tm alanlar tek tek DataColumn tipindeki c nesnemiz
ile dolayoruz. */
foreach(DataColumn c in ds.Tables[0].Columns)
{
Console.WriteLine("_"+c.ColumnName.ToString()+"_"); // Alann ad.
Console.WriteLine("Alan genisligi _"+c.MaxLength.ToString()); /* Alan text deer
ieriyorsa maksimum uzunluk. */
Console.WriteLine("Veri tr _"+c.DataType.ToString()); // Alann veri tr.
Console.WriteLine("Null durumu _"+c.AllowDBNull.ToString()); // Alann null deer
ierebilip ieremeyecei.
Console.WriteLine("");
}
}
}
}

Bu kodlarda ne yaptmz ksaca anlatalm. ncelikle, Sql sunucumuzda yer alan Friends isimli
veritabanna OleDb veri salaycs zerinden bir balant hatt ayoruz. Daha sonra, bu
veritabanndaki Deneme isimli tabloya ait tm satrlar elde edebileceimiz sql sz dizimi ile bir
OleDbDataAdapter nesnesi oluturuyoruz. Bu nesnenin Fill metodunu kullanarak, DataSet
nesnemizi ilgili tabloya ait veriler ile dolduruyoruz. Ayn zamanda sql sunucusundaki deneme isimli
tabloya ait alan bilgilerinide elde etmi oluyoruz. Her bir alann ismini, bu alan text veri ieriyorsa
maksimum karakter uzunluunu, veri tipini ve null deer ierip iermediini renmek iin, bir
dng kuruyor ve bu dng ierisinden bu alan bilgilerine, DataColumn snfndan bir nesne
rneini kullanarak eriiyoruz. Uygulamamz altrdmzda aadaki sonucu elde ettiimizi
grrz.

www.bsenyurt.com Page 2334


ekil 1. Uygulamann almasnn sonucu.

Oysa sql sunucumuzda yer alan tablomuzu incelediimizde bilgilerin daha farkl olduunu grrz.
lk gze arpan, alanlarn null deer ierebilip ieremeyeceini gsteren AllowDBNull zelliklerinin
doru bir ekilde elde edilememi olmalardr. Tablomuzun sql sunucusundaki asl grnm
aadaki gibidir. Kodumuz sonucu tm alanlarn null deer ierebilecei belirtilmektedir. Ama
durum gerekte byle deildir. Dier yandan string tipteki Deger1 alannn maksimum uzunluk
deeri 50 olmasna ramen uygulamamzn ekran ktsnda -1 olarak grlmektedir.

www.bsenyurt.com Page 2335


ekil 2. Deneme tablomuzun yaps.

Burada alanlara ait asl bilgilerin elde edilebilmesi iin tabloya ait ema bilgilerinide DataSet
nesnemize yklememiz gerekiyor. te bu amala, OleDbDataAdapter snfna ait FillSchema
metodunu kullanrz. FillSchema metodu ilgili tabloya ait alan bilgilerini rnein Primary Key
verisini, balantsz katman nesnesine eklememizi salar. Bunun iin aadaki kodlamay
kullanrz.

using System;
using System.Data;
using System.Data.OleDb;

namespace OleDbDA2
{
class Class1
{
static void Main(string[] args)
{
OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data
source=localhost;initial catalog=Friends;integrated security=sspi");
string sqltext="Select * From Deneme";
OleDbDataAdapter da=new OleDbDataAdapter(sqltext,con);
DataSet ds=new DataSet();
da.FillSchema(ds,SchemaType.Source); // ema bilgileri ekleniyor.
da.Fill(ds,"Makale");
foreach(DataColumn c in ds.Tables[0].Columns)
{

www.bsenyurt.com Page 2336


Console.WriteLine("_"+c.ColumnName.ToString()+"_");
Console.WriteLine("Alan genisligi _"+c.MaxLength.ToString());
Console.WriteLine("Veri tr _"+c.DataType.ToString());
Console.WriteLine("Null durumu _"+c.AllowDBNull.ToString());
Console.WriteLine("");
}
Console.WriteLine("Birincil anahtar
alanmz:"+ds.Tables[0].PrimaryKey[0].ColumnName.ToString());
}
}
}

imdi uygulamamz altrrsak aadaki sonucu elde ederiz.

ekil 3. Uygulamann almasnn sonucu.

Artk alanlarn null deer ierip iermeyeceklerine ait kstaslar doru bir ekilde grnmektedir.
Ayn zamanda, text bazndaki alanlarn maksimum uzunluklarda elde edilebilmektedir. (Bu
noktada, saysal alanlarn genilik deerlerinin -1 kmas normaldir. Nitekim DataColumn snfnn
MaxLength zellii yanlzca text bazl alanlar iin geerlidir.) Dier yandan, tablonun birincil
anahtar stununun varl elde edilebilmitir. Primary Key alannn nemini aadaki rnek ile
incelemeye alalm. Bu rnekte, windows uygulamamzda, bir DataSet nesnesini deneme
tablosunun verileri ile dolduruyor ve sonular DataGrid kontrolnde gsteriyoruz. lk etapta
FillSchema metodunu kullanmayalm.

private void Form1_Load(object sender, System.EventArgs e)

www.bsenyurt.com Page 2337


{
OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data source=localhost;initial
catalog=Friends;integrated security=sspi");
string sqltext="Select * From Deneme";
OleDbDataAdapter da=new OleDbDataAdapter(sqltext,con);
DataSet ds=new DataSet();
da.Fill(ds,"Makale");
dataGrid1.DataSource=ds.Tables["Makale"];
}

Uygulamay altrp yeni bir satr girelim. ID alannn deerini istediimiz bir say ile
deitirebildiimizi grrz.

ekil 4. ID alannn deerini deitirebiliyoruz.

Oysaki ID alanmz veri kaynamzda birincil anahtar olarak tanmlanmtr ve otomatik olarak
artmaktadr. imdi uygulamamzda FillSchema metodunu kullanalm.

private void Form1_Load(object sender, System.EventArgs e)


{
OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data source=localhost;initial
catalog=Friends;integrated security=sspi");
string sqltext="Select * From Deneme";
OleDbDataAdapter da=new OleDbDataAdapter(sqltext,con);
DataSet ds=new DataSet();
da.FillSchema(ds,SchemaType.Source,"Makale");
da.Fill(ds,"Makale");
dataGrid1.DataSource=ds.Tables["Makale"];
}

Uygulamamz tekrar altrp yeni bir satr eklediimizde ID alannn deerini deitiremediimizi
ve bu deerin yeni bir satrn eklenmesi ile otomatik olarak 1 arttn grrz.

www.bsenyurt.com Page 2338


ekil 5. ID alanna ait kstlamann eklenmesi sonucu.

Bu FillSchema metodunun, veri kaynandaki tabloya ait ID alannn birincil anahtar kstlamasn
balantsz katmana aktarmas sonucu gereklemitir. Ayn ilemi FillSchema metodunu
kullanmadanda gerekletirebiliriz. Bunun iin, birncil anahtar olucak alana ait temel zelliklerin,
ilgili DataTable nesnesinin PrimaryKey zelliince belirlenmesi gerekir. Yukardaki rneimizi
aadaki ekildede gelitirebiliriz.

private void Form1_Load(object sender, System.EventArgs e)


{
OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data
source=localhost;initial catalog=Friends;integrated security=sspi");
string sqltext="Select * From Deneme";
OleDbDataAdapter da=new OleDbDataAdapter(sqltext,con);
DataSet ds=new DataSet();
da.Fill(ds,"Makale");
/* Birincil anahtarmz olan ID alannn otomatik artan, null deer iermeyen, 1'den balayp 1'er
artan ve benzersiz deerler alan bir alan olduunu belirtiyoruz. */
ds.Tables["Makale"].Columns["ID"].AutoIncrement=true; // Alann deerleri otomatik artcak.
ds.Tables["Makale"].Columns["ID"].AutoIncrementSeed=1; // Balama deeri 1 olucak.
ds.Tables["Makale"].Columns["ID"].AutoIncrementStep=1; // Art deeri 1 olucak.
ds.Tables["Makale"].Columns["ID"].AllowDBNull=false; // Alan null deer ieremiyecek.
ds.Tables["Makale"].Columns["ID"].Unique=true; // Alan benzersiz deerler almak zorunda
olucak.
/* Bu tanmlamalarn ardndan yapmamz gereken, Makale isimli DataTable nesnemiz iin
PrimaryKey alannn ID alan olduunu belirtmektir. */
ds.Tables["Makale"].PrimaryKey=new DataColumn[]{ds.Tables["Makale"].Columns["ID"]}; /*
ID alannn tanmladmz zellikleri ile birlikte, Makale tablosunun birincil anahtar olacan
belirtiyoruz. */
dataGrid1.DataSource=ds.Tables["Makale"];
}

Bu durumda da ayn sonucu elde ederiz. Dier yandan birbirleri ile ilikili olan tablolarn bu
ilikilerini belirten ForeingKeyConstraint kstlamalarnda DataSet nesnelerine aktarmamz gerekir.
Bu konuyu ilerleyen makalelerimizde DataSet kavramn ilerken incelemeye alacaz. imdi
OleDbDataAdapter ile ilgili dier konularmza devam edelim.

OleDbDataAdapter snflar ile ilgili incelemek istediim ikinci konu bu nesnelerin, Visual Studio.Net
ortamnda nasl oluturulduudur. Visual Studio.Net ortamnda bu ilem olduka kolaydr. Bunun
iin pek ok yntemimiz var. Bunlardan birisi Server Explorer alanndan tabloyu, Form zerine
srklemektir. Bu ilem sonucunda, bu tablo iin gerekli Connection nesnesi ve DataAdapter
nesnesi otomatik olarak oluturulacaktr. Bir dier yol ise, OleDbDataAdapter Componentini

www.bsenyurt.com Page 2339


kullanmaktr. Ben makalemde, bu ikinci yolu incelemeye alacam. Visual Studio.Net ortamnda
yeni bir windows uygulamas an ve Formun zerine, OleDbDataAdapter componentini srkleyin.

ekil 6. OleDbDataAdapter arac dier Ado.Net aralar gibi ToolBox'n Data ksmnda yer alr.

Bu durumda karmza DataAdapter Configuration Wizard penceresi kacaktr. Bu pencereyi next


butonuna basarak geelim.

ekil 7. Balang noktamz.

Bu admdan sonra, OleDbDataAdapter nesnemizin kullanaca balant hatt iin gerekli balant
bilgilerini ayarlarz. Burada halen var olan bir balanty kullanabileceimiz gibi New Connection
seenei ile yeni bir balant bilgisede oluturabiliriz. Bu admda oluturacamz balant bilgisi,
uygulamamz iin gerekli olan OleDbConnection nesnesinin oluturulmasndada kullanlacaktr. Ben
burada New Connection diyerek yeni bir balant bilgisi oluturdum. Artk OleDbDataAdapter
nesnemiz bu balant katarn kullancak.

www.bsenyurt.com Page 2340


ekil 8. Balant bilgimizi tanmlyoruz.

Next ile bu admda getikten sonra, sorgu tipini seeceimiz blme geliriz. Burada seeneimiz
vardr. Use Sql Statements ile, OleDbDataAdapter nesnesi yardmyla bilgilerini alacamz
tablo(lar) iin gerekli sql ifadelerinin sihirbaz yardmyla oluturulmasn salarz. Bu ilem
sonucunda bizim iin gerekli olan SelectCommand, InsertCommand, UpdateCommand ve
DeleteCommand zelliklerine ait sql ifadeleri otomatik olarak oluturulacaktr. Dier yandan ikinci
seenek ile, bu sql ifadeleri iin sakl yordamlarn oluturulmasn salayabiliriz. Son seeneimiz
ise, sistemde var olan sakl yordamlarn kullanlmasn salar. Biz u an iin ilk seenei seiyoruz.

www.bsenyurt.com Page 2341


ekil 9. Sorgu tipinin seilmesi.

Bu admdan sonra Select sorgusunu oluturacamz blm ile karlarz. Burada SelectCommand
iin kullanlacak sql sorgusunu kendimiz elle yazabileceimiz gibi Query Builder yardmylada bu
ilemi daha kolay bir ekilde yapabiliriz. Biz Query Builder seenei ile ilemlerimize devam edelim.

www.bsenyurt.com Page 2342


ekil 10. Sql ifadesinin oluturulmas.

Query Builder ksmnda, ilemlerimizin banda belirttiimiz balant bilgisi kullanlr ve balanlan
veri kaynana ilikin kullanlabiliecek tablolar veya grnmler ekrana otomatik olarak gelir. Tek
yapmamz gereken kullanmak istediimiz tabloyu(tablolar) semek ve eklemektir. Daha sonra
setiimiz tablo veya tablolardaki hangi alanlarn select sorgusu ile elde edileceini ve balantsz
katmana aktarlacan belirleriz.

www.bsenyurt.com Page 2343


ekil 11. Tablolarn eklenmesi.

Ben burada Makale isimli tablomuzu setim ve sorguya ekledim. Daha sonra sadece grnmesini
istediim alanlar belirttim. Burada istersek alanlarn balantsz katman nesnesine hangi isimler ile
aktarlacan Alias stununa yazdmz deerler ile belirleyebiliriz. Dier yandan, Sort Type
stununu kullanarak hangi alanlara gre srlama yaplmasn istediimizi belirtebiliriz. Ayrca
alanlara ait eitli kriterler girebileceimiz Criteria stunuda yer almaktadr. Bu stunu kullanmamz
Where anahtar kelimesi iin bir koul bildirmek anlamna gelmektedir. Bu ilemler boyunca, sorgu
ifademizin otomatik olarak oluturulduunu ve gelitirildiini grrz. Oluturulan sorgunun
sonucunu grmek iin bu alan zerinde sa tula girdiimiz menuden Run komutunu verebiliriz.
Bylece sorgu sonucu elde edilcek tablo verileri iinde bir ngrnm elde etmi oluruz.

www.bsenyurt.com Page 2344


ekil 12. Query Builder sorgularmzn kolayca oluturulmasn salar.

Bu pencereyi kapttmzda OleDbDataAdapter nesnemizin, SelectCommand zellii iin gerekli


Command nesnesi oluturulmu olur. Tekrar Next dmesine bastmzda aadaki ekran elde
ederiz. Burada grld gibi Insert, Update ve Delete sorgularda otomatik olarak
oluturulmutur. Ayrca tablo alanlarmz iin kullandmz eletirme ilemleride gerekletirilmi
ve TableMappings koleksiyonuda baarl bir ekilde oluturulmutur.

www.bsenyurt.com Page 2345


ekil 13. lem Tamam.

Finish'e bastmzda Formumuzda bir OleDbConnection nesnesinin ve birde OleDbDataAdapter


nesnesinin oluturulmu olduunu grrz.

ekil 14. Nesnelerimiz oluturuldu.

imdi bize, bu OleDbDataAdapter nesnemizin almas sonucu elde edilecek verilerin aktarlaca
bir balantsz katman nesnesi lazm. Yani bir DataSet nesnesi. Bunun iin, OleDbDataAdapter
nesnesine ait, Generate DataSet seeneini kullanabiliriz.

ekil 15. Generate DataSet seenei, OleDbDataAdapter nesnesinin zelliklerinin altnda yer alr.

Bu durumda karmza kan pencerede var olan bir DataSet'i seebilir yada otomatik olarak yeni
bir tane oluturulmasn salayabiliriz. Bu ilemin ardndan DataSet nesnemizinde oluturulduunu
grrz.

www.bsenyurt.com Page 2346


ekil 16. Generate DataSet penceresi.

Artk yapmamz gerekenler, formumuza bir DataGrid koymak, OleDbDataAdapter nesnemize Fill
metodunu uygulamak ve DataSet'imizi doldurmak, son olarakta DataGrid kontrolmze bu veri
kmesine balamaktr.

private void Form1_Load(object sender, System.EventArgs e)


{
oleDbDataAdapter1.Fill(dataSet11.Tables["Makale"]);
dataGrid1.DataSource=dataSet11.Tables["Makale"];
}

Uygulamamz altrdmzda aadaki sonucu elde ederiz.

www.bsenyurt.com Page 2347


ekil 17. Uygulamann almasnn sonucu.

Burada yaptmz ilem ile, OleDbDataAdapter nesnesi ile balantsz katmandaki veriler zerindeki
deiiklikleri, veri kaynana gnderirken Update metodunun kullanaca UpdateCommand,
DeleteCommand, InsertCommand gibi zelliklerin sql ifadelerini otomatik olarak oluturulmasn
salam olduk. Dier yandan ayn ilevsellii kazanmak iin CommandBuilder nesnesinide
kullanabiliriz. Bu nesnenin kullanlmasn ve OleDbDataAdapter snfna ait Update metodunu bir
sonraki makalemizde incelemeye alacaz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataAdapter Kavram ve OleDbDataAdapter


Snfna Giri ( 27.02.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Ado.Net'in en ok kullanlan kavramlarndan birisi olan DataAdapter kavramn


incelemeye alacak ve OleDbDataAdapter snfna ksa bir giri yapacaz. Pek ok programc,
veritaban uygulamalar gelitirirken, kontrol ve performansa byk nem verir. Ancak ayn
zamanda bu kazanmlara kolay yollar ile ulamak isterler. Ado.Net modelinde, balantsz katman
ile balantl katman arasndaki iletiim ve veri alveriinin, kontrol edilebilir, performansl ve ayn
zamanda kolay gelitirilir olmasnda DataAdapter kavramnn yeri yadrganamyacak kadar fazladr.
Temel tanm olarak, DataAdapter snflar, sahip olduklar veri salayclarnn izin verdii veri
kaynaklar ile, sistem bellei zerinde yer alan balantsz katman nesneleri arasndaki veri
alveriinin kolay, gl ve verimli bir ekilde salanmasndan sorumludurlar. Bu tanmdan yola
karak, DataAdapter snflarnn, veri kaynandan verilerin alnp, balantsz katman nesneleri
olan DataSet ve DataTable nesnelerine doldurulmasndan sorumlu olduunu; ayrca, balantsz
katman nesnelerinin tad verilerdeki deiikliklerinde veri kaynana yanstlmasndan sorumlu
olduunu syleyebiliriz. te bu, DataAdapter snfnn roln tam olarak aklayan bir
tanmlamadr.

Veritaban uygulamalarnda en nemli unsurlarn, verinin tanmas, izlenebilmesi, zerinde


deiikliklerin yaplmas ve tekrar veri kaynana yanstlmas olduunu syleyebiliriz. DataAdapter
snflarnn bu unsurlarn gerekletirilmesinde ok nemli rol oynadklar bir gerektir. Aadaki
ekil DataAdapter snflarnn ileyiini daha iyi anlamamza yardmc olucaktr.

www.bsenyurt.com Page 2348


ekil 1. DataAdapter Snfnn Rol.

Ado.net modeli, .net Framework'n en son srmnde, OleDb veri kaynaklar iin
OleDbDataAdapter, Sql veri kaynaklar iin SqlDataAdapter, Oracle veri kaynaklar iin
OracleDataAdapter ve Odbc veri kaynaklar iinde OdbcDataAdapter snflarna sahiptir.
DataAdapter snflarnn yaps aadaki gibidir.

www.bsenyurt.com Page 2349


ekil 2. DataAdapter snflarnn genel yaps.

imdi dilerseniz bu yelerin hangi amalar iin kullanldna ksaca deinelim. Her DataAdapter
snf mutlaka bir SelectCommand sorgusu iermek zorundadr. Nitekim, bir DataAdapter nesnesinin
yaratl amac, veri kaynandan ekilen verileri balantsz katmandaki ilgili nesnelere
aktarmaktr. te bunun iin, SelectCommand zellii geerli bir sorguya sahip olmaldr. Veri almak
iin kullanlan sorgu bir Command nesnesine iaret etmektedir. ou zaman bir DataAdapter
olutururken bu snfn kurucusu iinde, select sorgularn string olarak gireriz. Bu string aslnda
sonradan bir Command nesnesi haline gelerek, DataAdapter snfnn SelectCommand zelliine
atanr.

Dier yandan, verileri ykl olan bir DataSet ierisinde yaplan deiikliklerin veri kaynana
tekrardan aktarlmas iin, yaplan deiikliin eidine uygun komutlarn DataAdapter tarafndan
oluturulmas gerekmektedir. rnein, DataSet zerinde yeni satrlar girilmi ise, bunlar
InsertCommand zelliinin sahip olduu sql metni ile veri kaynana aktarlr. Ayn ekilde, satr

www.bsenyurt.com Page 2350


silme ilemleri iin DeleteCommand zelliindeki sql sz dizimi, gncelleme ilemleri iin ise
UpdateCommand zelliindeki sql ifadeleri kullanlr. Bu zelliklerin tmn elle oluturabilieceiniz
gibi, Visual Studio.Net ortamnda yada CommandBuilder snfn vastasyla otomatik olarak
oluturulmasn salayabilirsiniz. Bu zellikleri sonraki makelelerimizde incelemeye alacaz.

TableMappings DataTableMappingCollection trnden bir koleksiyondur. Grevi ise olduka ilgintir.


Bir DataAdapter nesnesi ile veri kaynandaki bir tabloyu, DataSet' aktardmzda, aktarma ve
gncelleme ilemleri srasnda alan isimlerinin her iki katmandada eletirilebilmesi iin kullanlr.
Nitekim, DataAdapter ile bir tabloyu elde ettiimizde bu tablo, Table ismi ile ileme sokulur. nk
OleDbDataAdapter tablonun ismi ile ilgilenmez. Fakat biz dilersek TableMappings koleksiyonuna bir
DataTableMapping nesnesi ekleyerek tablo adnn daha uygun bir isme iaret etmesini
salayabiliriz. Ayn konu, stun adlar iinde geerlidir. Bazen tablodaki stun adlar istediimiz
isimlerde olmayabilir. te bu durumda, DataTableMapping nesnesinin ColumnMappings
koleksiyonu kullanlr. DataSet iindeki her tablo DataColumnMapping trnden nesneler ieren bir
ColumnMappings koleksiyonuna sahiptir. Bu nesnelerin her biri veri kaynandaki tabloda yer alan
stun adlarnn, DataSet iindeki tabloda hangi isimlere karlk geldiinin belirlenmesinde kullanlr.
Bu konu u an iin kark grnm olabilir ancak ilerleyen rneklerimizde bu konuya tekrar
deinecek, daha anlalr olmas iin alacaz.

DataAdapter snflarnn genel zelliklerine deindikten sonra dilerseniz OleDbDataAdapter snfmz


incelemeye balayalm. OleDbDataAdapter snf System.Data.OleDb isim uzay iinde yer
almaktadr. Bir OleDbDataAdapter nesnesi yaratmak iin kullanabileceimiz 4 adet ar yklenmi
yapc metod bulunmaktadr. Bunlar aadaki tabloda belirtilmitir.

Yapc Metod Prototipi Aklamas

Select sorgusunu ve balant iin gerekli


public OleDbDataAdapter(string, string); sz dizimini metin eklinde parametre
olarak alr.

Sorguyu metin baznda alrken, balant


public OleDbDataAdapter(string, iin nceden oluturulmu bir
OleDbConnection); OleDbConnection nesnesini parametre
olarak alr.

Select sorgusunu ve geerli bir


balanty iaret eden bir
public OleDbDataAdapter(OleDbCommand);
OleDbCommand nesnesini parametre
olarak alr.

Byle oluturulan bir


OleDbDataAdapter' kullanabilmek iin,
public OleDbDataAdapter();
ilgili zellikler ( SelectCommand gibi.)
sonradan ayarlanr.

Tablo 1. OleDbDataAdapter snfnn yapc metodlar.

imdi burada nemli olan bir iki noktay vurgulamamz gerekiyor. Hereyden nce bir
OleDbDataAdapter nesnesinin kullanlma amac, balantsz katman nesnesini veri kaynandaki
veriler ile doldurmaktr. Bu her DataAdapter snf iinde ncelikli hedeftir. Bu nedenle her

www.bsenyurt.com Page 2351


DataAdapter nesnesinin mutlaka sahip olmas gereken bir select sorgu ifadesi dolaysyla var olan
bir SelectCommand zelliine ihtiyac vardr. Ayrca dier nemli gereklilik, geerli bir balantnn
yani bir Connection nesnesinin olmasdr. imdi dilerseniz, rnekler ile OleDbDataAdapter
nesnelerinin nasl oluturulduunu ve verilerin, veri kaynandan balantsz katman nesnelerine
nasl ekildiini grelim.

lk rneimizde, bir windows uygulamasndaki DataGrid nesnemizi, balantsz katmanda alacak


DataSet nesnemize balyacaz. DataSet nesnemizi veriler ile doldurmak iin, OleDbDataAdapter
nesnemizi kullanacaz. te uygulamamzn ksa kodlar.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
string sqlIfadesi="Select * From Makale";
OleDbDataAdapter daFriends=new OleDbDataAdapter(sqlIfadesi,conFriends);
DataSet ds=new DataSet();
daFriends.Fill(ds);
dgMakale.DataSource=ds;
}

Kodlarmz inceleyecek olursak; ncelikle OleDbDataAdapter nesnemiz iin gerekli ve olmassa


olmaz yeleri tanmladk. ncelikle geerli bir balant hattmzn olmas gerekiyor. Bu amala bir
OleDbConnection nesnesi kullanyoruz. Dier yandan, OleDbDataAdapter nesnesinin
oluturduumuz DataSet nesnesini doldurabilmesi iin, veri kaynandan veri ekebilecei bir sql
ifadesine ihtiyacmz var. Bu amalada bir sql cmleciini string olarak oluturuyoruz. Sonraki
admda ise OleDbDataAdapter nesnemizi yaratyoruz. Burada kullanlan yapc metod, sql ifadesini
string olarak alyor ve birde balant hattn temsil edicek olan OleDbConnection nesnesini
parametre olarak alyor. Daha sonra, veri kaynandan bu sql ifadesi ile ekilecek verilerin bellekte
tutulduu blgeyi referans edicek DataSet nesnemiz oluturuluyor. Burada Fill metodu, sql
ifadesini, geerli balant hatt zerinde altryor ve elde edilen veri kmesini, metod parametresi
olarak ald DataSet nesnesinin bellekte gsterdii adrese yerletiriyor. Uyglamamz
altrdmzda aadaki sonucu elde ederiz.

ekil 3. Fill Metodu ile DataSet'in doldurulmas.

www.bsenyurt.com Page 2352


OleDbDataAdapter nesnesinin Fill metodunu ardmzda, nesne, parametre olarak ald
balanty otomatik olarak amaktadr. Yani Fill metodunu armadan nce balant nesnemizi
Open metodu ile amamza gerek yoktur. Fill metodu ile DataSet nesnesi doldurulduktan sonra ise,
OleDbDataAdapter, ak olan balanty otomatik olarak kapatacaktr. Bu kolaylk birden fazla
tabloyu bir DataSet ierisine farkl OleDbDataAdapter nesneleri ile alacamz zaman dezavantajdr.
Nitekim her bir OleDbDataAdapter nesnesi eer ayn balanty kullanyorlarsa, her defasnda veri
kaynana olan balanty acak ve kapatcaklardr. Sz gelimi aadaki kodlar gz nne alalm.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");

string sqlIfadesi1="Select * From Makale";


string sqlIfadesi2="Select * From Kitap";

OleDbDataAdapter daMakale=new OleDbDataAdapter(sqlIfadesi1,conFriends);


OleDbDataAdapter daKitap=new OleDbDataAdapter(sqlIfadesi2,conFriends);

DataSet ds=new DataSet();


daMakale.Fill(ds);
daKitap.Fill(ds);
dgMakale.DataSource=ds;
}

Bu uygulamada iki OleDbDataAdapter nesnesi ayn balanty kullanarak farkl veri tablolarn ayn
DataSet ierisine yklemitir. Her bir Fill metodu arldnda balant alr, tablodan veriler, sql
ifadeleri gerei alnr, DataSet nesnesinin referans ettii bellek blgesine yklenir ve ak olan
balant kapatlr. Bu durumda, uygulamamzdaki kodlarda balantnn iki kere alp kapatldn
syleyebiliriz. Bu gzle grlr bir performans kaybna yol amyabilir ancak programlama teknii
asndan balantnn bu kadar ksa sreler iin tekrardan alp kapatlmas sistem kaynaklarn bo
yere kullanmak manasnada gelmektedir. Peki ne yaplabilir? OleDbDataAdapter snfnn bir
zellii, eer kullanlan balant ak ise, OleDbDataAdapter bu balanty biz kapatana kadar
kapatmayacak olmasdr. Yani yukardaki kodu u ekilde dzenlersek istediimiz sonuca
ulaabiliriz.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");

string sqlIfadesi1="Select * From Makale";


string sqlIfadesi2="Select * From Kitap";

OleDbDataAdapter daMakale=new OleDbDataAdapter(sqlIfadesi1,conFriends);


OleDbDataAdapter daKitap=new OleDbDataAdapter(sqlIfadesi2,conFriends);

DataSet ds=new DataSet();

conFriends.Open();

daMakale.Fill(ds);
daKitap.Fill(ds);

dgMakale.DataSource=ds;

www.bsenyurt.com Page 2353


conFriends.Close();
}

Bu durumda, Fill metodlar balant durumunu gzleyecek ve eer balant ak ise herhangibir
mdahalede bulunmadan bu ak balant zerinden ilemleri gerekletirecektir. Fill metodu ii
bittiinde, kulland bu ak balanty kapatmayacaktr. Bu sayede ardndan gelen ve ayn
balanty kullanan OleDbDataAdapter nesnesi, yeni bir balant amaya gerek duymayacak, halen
ak olan balanty kullanacaktr. Burada unutulmamas gereken nokta, balant nesnemiz ile
iimiz bittiinde bu nesneyi Close metodu ile kapatmaktr. imdi gelelim Fill metodundaki baka bir
noktaya. Yukardaki son rneimizi altrcak olursak aadaki grnty elde ederiz.

ekil 4. ki tabloda ayn isim altnda yklenir.

Grld gibi iki tablomuzda DataSet'e tek bir tablo ismi altnda yklenmitir. Bu isme
tkladmzda, ilk nce Makale verilerinin grndn ardndan Kitap tablosuna ait verilerin
grndn anlarz.

ekil 5. Her iki tabloya ait verilerin grnm.

Bu elbette istemediimiz bir durumdur. Bunu dzeltmek iin, Fill metodunun aadaki prototipi
verilen ar yklenmi halini kullanrz.

public int Fill(DataSet dataSet,string srcTable);

www.bsenyurt.com Page 2354


Burada ikinci parametre aktarlan tablo iin bir ismi string olarak almaktadr. Bylece, DataSet
ierisine aktarlan tablolar isimlendirebiliriz. Nitekim OleDbDataAdapter snf, Fill metodu ile
tablolardaki verileri DataSet iine alrken, sadece alan adlarn eletirmek iin alr. Tablo adlar ile
ilgilenmez. Bu nedenle bir tablo ismi belirtmessek, bu DataSet ierisine Table ismi ile alnacaktr.
Biz Fill metoduna bir tablo ismini parametre olarak verdiimizde, DataAdapter snfnn
TableMappings koleksiyonu, DataSet iinde bizim verdiimiz tablo ismini, veri kaynandaki ile
eletirir. Dolaysyla yukardaki kodlar aadaki gibi dzenlersek sonu istediimiz gibi olucaktr.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");

string sqlIfadesi1="Select * From Makale";


string sqlIfadesi2="Select * From Kitap";

OleDbDataAdapter daMakale=new OleDbDataAdapter(sqlIfadesi1,conFriends);


OleDbDataAdapter daKitap=new OleDbDataAdapter(sqlIfadesi2,conFriends);

DataSet ds=new DataSet();

conFriends.Open();

daMakale.Fill(ds,"Makaleler");
daKitap.Fill(ds,"Kitaplar");

dgMakale.DataSource=ds;

conFriends.Close();
}

Uygulamamz altrdmzda aadaki sonucu alrz.

ekil 6. Fill metodunda Tablo isimlerinin verilmesi.

Baz durumlarda, toplu sorgular (batch queries) altrmak isteyebiliriz. rnein aadaki kodlar
ele alalm. Burada, 3 sorgunun yer ald bir toplu sorgu cmlecii yer almaktadr.
OleDbDataAdapter nesnemiz iin, bu sql cmleciini kullandmzda sonu kmelerinin Table,
Table1 ve Table2 isimleri ile DataSet ierisine alndn grrz.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data

www.bsenyurt.com Page 2355


Source=localhost;initial catalog=Friends;integrated security=SSPI");
string sqlIfadesi="Select * From Makale;Select * From Kitap;Select * From Kisiler";
OleDbDataAdapter daMakale=new OleDbDataAdapter(sqlIfadesi,conFriends);
DataSet ds=new DataSet();
daMakale.Fill(ds);
dgMakale.DataSource=ds;
}

ekil 7. Toplu Sorgularn altrlmasnn Sonucu.

Bu elbette uygulamamzn grsellii asndan ok ho bir durum deildir. Yapabileceimiz ilem


ise, OleDbDataAdapter nesnemizin TableMappings koleksiyonuna, tablolarn grmek istediimiz asl
isimlerini eklemek olucaktr. Bu amala yazm olduumuz kodlar aadaki gibi deitirmeliyiz.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
string sqlIfadesi="Select * From Makale;Select * From Kitap;Select * From Kisiler";
OleDbDataAdapter da=new OleDbDataAdapter(sqlIfadesi,conFriends);

da.TableMappings.Add("Table","Makaleler");
da.TableMappings.Add("Table1","Kitaplar");
da.TableMappings.Add("Table2","Arkadaslarim");

DataSet ds=new DataSet();


da.Fill(ds);
dgMakale.DataSource=ds;
}

Burada yaplan ilemi aklayalm. OleDbDataAdapter nesnemizin, TableMappings koleksiyonu, veri


kaynandaki tablo isimlerinin, uygulama ierisindeki balantsz katman nesnesi ierisinden nasl
isimlendirileceini belirtmektedir. Dolaysyla Fill metodunu ardmzda ilk sorgu sonucu elde
edilen Table isimli tablo, Makaleler olarak, ikinci sorgu sonucu elde edilen sonu kmesini temsil
edilen Table1 tablosu, Kitaplar olarak ve sonundada Table2 ismiyle gelen son tablo Arkadaslarim
olarak DataSet ierisine alnacaktr. TableMappings burada, sadece isimlerin eletirilmesinde rol
oynar. Ayn ekilde, OleDbDataAdapter nesnemize ait Update metodunu kullandmzda,
TableMappings koleksiyonunda bu tablo isimlerini birbirleri ile eletirilerek, doru tablolarn doru
kaynaklara ynlendirilmesi salanm olur.

www.bsenyurt.com Page 2356


ekil 8. TableMappings Koleksiyonunun nemi.

u ana kadarki rneklerimizde, balantsz katman nesnesi olarak DataSet'i kullandk. DataSet
birden fazla veri tablosunu DataTable nesneleri olarak bnyesinde barndran kuvvetli bir snftr.
Ancak ou zaman uygulamalarmzda sadece tek tabloyu balantsz katmanda kullanmak
isteyebiliriz. Byle bir durumda bu tek tablo verisi iin, DataSet nesnesi kullanmak sistem
kaynaklarn daha ok harcamak anlamna gelir. Bunu zmek iin, veri kaynandan okunan
verileri bir DataTable nesnesine aktarrz. te OleDbDataAdapter nesnesinin Fill metodu ile
DataTable nesnelerinide doldurabiliriz. Bunun iin aadaki kodlarda belirtilen teknii uygularz.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
string sqlIfadesi="Select * From Makale";
OleDbDataAdapter da=new OleDbDataAdapter(sqlIfadesi,conFriends);
DataTable dt=new DataTable("Makalelerim");
da.Fill(dt);
dgMakale.DataSource=dt;
dgMakale.CaptionText=dt.TableName.ToString();
}

Burada DataTable nesnemizi olutururken parametre olarak String bir deer girdiimize dikkat
edelim. Bu deer, verilerin alnd kmenin, hangi isimde bir tabloya iaret edeceini
belirtmektedir. Fill metodunun kullanm eklinde ise parametre olarak DataTable nesnesini alan
aadaki prototip kullanlmtr.

public int Fill (DataTable dataTable);

Son kodlarmz altrdmzda aadaki sonucu elde ederiz.

www.bsenyurt.com Page 2357


ekil 9. Fill metodu ile verilerin DataTable'a aktarlmas.

Fill metodunda dikkati eken bir dier nokta, dndrd integer tipteki deerdir. Bu dn deeri,
OleDbDataAdapter nesnesinin altrd sorgu sonucu dnen satr saysna iaret etmektedir. Sz
gelimi yukardaki rneimizi ele alalm. OleDbDataAdapter nesnemizin dn deerini kontrol
ettiimizde, tablomuzdan okunan satr saysnn dndrldn grm oluruz.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
string sqlIfadesi="Select * From Makale";
OleDbDataAdapter da=new OleDbDataAdapter(sqlIfadesi,conFriends);
DataTable dt=new DataTable("Makalelerim");
int SatirSayisi=da.Fill(dt);
dgMakale.DataSource=dt;
dgMakale.CaptionText=dt.TableName.ToString();
MessageBox.Show("Makale Says "+SatirSayisi.ToString());
}

www.bsenyurt.com Page 2358


ekil 10. Fill metodundan dnen deer ile kayt saysnn renilmesi.

Fill metodunun aada prototipi verilen ar yklenmi halini kullanarak, belli bir satrdan itibaren
belirli bir sayda kaydn elde edilmesini salayabiliriz.

public int Fill(DataSet, int, int, string);

Burada Fill metodu drt parametre almaktadr. lk parametremiz verilerin eklenecei DataSet
nesnesi ve son parametrede eklenecek verilerin temsil edilecei tablo addr. kinci ve nc
parametreler integer tipte deerler alrlar. kinci parametre sorgu sonucu elde edilen kayt
kmesinin hangi satrndan itibaren okuma yaplacan, nc parametre ise ka satr alnacan
belirtmektedir. rnein Makale isimli tablomuzdaki verileri, tarih srasna gre tersten eken bir sql
sorgumuz olduunu dnelim. lk 3 satr elde edip DataSet iindeki ayr bir tabloya almak
istediimizi varsayalm. Bylece tabloya eklenen son 3 Makaleye ait bilgilere erimi olucaz.
Bunun iin aadaki teknii kullanacaz.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
string sqlIfadesi="Select * From Makale Order By Tarih Desc";
OleDbDataAdapter da=new OleDbDataAdapter(sqlIfadesi,conFriends);
DataSet ds=new DataSet("Makaleler");
int SatirSayisi=da.Fill(ds,0,3,"Son3Makale");
dgMakale.DataSource=ds;
}

Burada Fill metodunda select sorgusu sonucu elde edilen kmede 0 indisli satrdan (yani ilk satr)
itibaren 3 satr verinin okunmasn ve Son3Makale isimli tabloya aktarlmasn salyoruz. te
sonu.

www.bsenyurt.com Page 2359


ekil 11. Fill metodu ile belli bir satrdan itibaren belli sayda satr almak.

Fill metodu ile, veri kaynandaki verileri balantsz katmana ekerken sakl yordamlar kullanmak
isteyebiliriz. Bu amala, OleDbDataAdapter snfnn SelectCommand zelliine, bu sakl yordam
altrmak iin kullanlacak bir OleDbCommand nesnesini atamak kullanabileceimiz tekniklerden
birisidir. OleDbCommand nesnesini yaratrken kullandmz new yaplandrcsna ait ar
yklenmi hallerden birisi aadaki gibiydi.

public OleDbDataAdapter(OleDbCommand);

Burada OleDbCommand nesnesini, sakl yordammz altracak ekilde olutururuz. Aadaki


rnek sakl yordammz gz nne alalm.

CREATE PROCEDURE Makaleler


AS
Select * From Makale
RETURN

imdi bu sakl yordammz altracak OleDbDataAdapter nesnemiz iin gerekli kodlamalar


yapalm.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
OleDbCommand cmd=new OleDbCommand("Makaleler",conFriends);
cmd.CommandType=CommandType.StoredProcedure;
OleDbDataAdapter da=new OleDbDataAdapter(cmd);
DataSet ds=new DataSet();
da.Fill(ds,"TumMakaleler");
dgMakale.DataSource=ds;
}

www.bsenyurt.com Page 2360


Burada OleDbDataAdapter nesnemizi, OleDbCommand nesnemizi kullanacak ekilde oluturduk.
Dolaysyla, OleDbDataAdapter, OleDbCommand nesnesinin belirttii sql ifadesini, yine
OleDbCommand nesnesinin kulland balant zerinden altrmaktadr. OleDbCommand
nesnemiz bir sakl yordama iaret ettii iin, OleDbDataAdapter sonu olarak bu sakl yordam
altrm olur. Bylece DataSet nesnemizin bellekte iaret ettii blge, sakl yordamn almas
sonucu dnen veriler ile doldurulmu olucaktr.

ekil 12. OleDbDataAdapter ile Sakl yordamn altrlmas.

Tabi bu amala illede bir OleDbCommand nesnemiz kullanmak art deildir. Ayn ilem iin
aadaki sz dizimini sql ifadesi olarak SelectCommand zellii iin belirleyebiliriz.

{Call Makaleler}

Bu durumda kodlarmz aadaki gibi deitirmemiz gerekmektedir.

private void btnDoldur_Click(object sender, System.EventArgs e)


{
OleDbConnection conFriends=new OleDbConnection("Provider=SQLOLEDB;Data
Source=localhost;initial catalog=Friends;integrated security=SSPI");
OleDbDataAdapter da=new OleDbDataAdapter("{CALL Makaleler}",conFriends);
DataSet ds=new DataSet();
da.Fill(ds,"TumMakaleler");
dgMakale.DataSource=ds;
}

Burada dikkat edilmesi gereken bir nokta vardr. SqlDataAdapter nesneleri iin bu arm {EXEC
Makaleler} eklindedir. Buraya kadar anlattklarmzla OleDbDataAdapter snf ile ilgili olarak
baya bir yol katettiimizi dnyorum. Bir sonraki makalemizde, OleDbDataAdapter snfn
incelemeye devam edeceiz. ncelikle OleDbDataAdapter nesnelerinin Visual Studio.Net ortamnda
kolayca nasl oluturulduklarn inceleyeceiz. Bylece OleDbDataAdapter snf iin gereken
SelectCommand, InsertCommand, DeleteCommand, UpdateCommand zelliklerinin nasl otomatik
olarak oluturulduunu anlayacaz. Daha sonra ayn i iin CommandBuilder snfnn nasl

www.bsenyurt.com Page 2361


kullanldn inceleyeceiz. Bir sonraki makelemizde grmek dileiyle hepinize mutlu gnler
dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Command Kavram ve OleDbCommand Snf (


23.02.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Ado.Net mimarisi iinde ok nemli bir yere sahip olan Command kavramn ve
OleDbCommand snfna ait en temel yeleri incelemeye alacaz. Veritaban uygulamalar
gelitiren her programc mutlaka, veri kaynana doru bir takm sorgu komutlarna ihtiya
duymaktadr. rnein, veri kaynandaki bir tabloya yeni bir satr eklemek iin, veri kayna
zerinde bir tablo yaratmak iin veya veri kaynandan belli artlara uyan veri kmelerini ekmek
iin vb... Tm bu ilemler iin Ado.Net mimarisi bize, sql sorgularn barndrabileceimiz ve geerli
bir balant hatt zerinden altrabileceimiz Command snfn sunmaktadr. u an itibariyle,
Ado.Net mimarisi 4 temel Command snf ierir. Bunlar, OleDbCommand, SqlCommand,
OracleCommand ve OdbcCommand snflardr.

Bahsetmi olduumuz bu 4 Command snfda temelde ayn grevler iin tasarlanmlardr. Farkllk
sadece iaret ettikleri veri kaynkalarndan ibarettir. Hepsinin grevleri ortaktr. Kullanldklar veri
kaynaklar zerinde sql ifadelerinden oluturulan komutlar altrmak. Bunun iin elbette
ihtiyacmz olan en nemli kaynak geerli bir balant hattnn ve bu hattn eritii veri kayna iin
geerli bir sql ifadesinin olmasdr. Command snflar, altracaklar sql ifadelerini temsil eden
nesneler olduklar iin Command (Komut) terimini bnyelerinde barndrrlar.

Bu makalemizde, Command snflarndan OleDbCommand snfn incelemeye alacaz.


OleDbCommand snf, OleDb veri salaycs tarafndan eriilebilen kaynaklar zerinde sql
ifadelerini altrmamza izin verir. OleDbCommand snfna ait nesne rneini oluturmak iin
kullanabileceimiz farkl yol vardr. Bunlardan ilki OleDbCommand nesnesini new yaplandrcs
ile her hangibir komut szc iermeden oluturmaktr. Bu teknik iin kullanlan yapc metodun
prototipi aadaki gibidir.

public OdbcCommand();

Bu teknik ile oluturulan bir komut nesnesi iin bir takm zellikleri sonradan belirleyebiliriz.
ncelikle geerli bir balant nesnesine yani bir OleDbConnection nesnesine ihtiyacmz vardr.
Dier gereklilik ise, OleDbCommand snf nesne rneinin, altraca sql ifadesidir. Bu amalar
iin OleDbCommand snfnn Connection ve CommandText zelliklerini kullanrz. Yukardaki teknik
ile oluturduumuz bir OleDbCommand nesnesi iin Connection zellii null, CommandText zellii
ise bo bir string'e iaret etmektedir. Bu teknii daha iyi anlamak iin basit bir rnek gelitirelim.
rnein, Sql Sunucumuzda yer alan Friends isimli veri tabanndaki taboya bir satr veri gireceimiz
aadaki sql ifadesini altracak bir komut tasarlamak istediimizi varsayalm.

Insert Into Siteler (Baslik,Adres,Resim,Icerik)


Values('C#','www.csharpnedir.com','images/resim1.jpg','C# zerine her trl makale.')

www.bsenyurt.com Page 2362


Bunun iin yazacamz kodlar aadadr.

using System;

using System.Data.OleDb; /* OleDbCommand snf bu isim uzaynda yer almaktadr. */

namespace OleDbCmd1

class Class1

static void Main(string[] args)

/* nce geerli bir balant hatt oluturmamz gerekiyor. */

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand(); /* Komut nesnemiz oluturuluyor. */

cmd.Connection=con; /* Komut nesnesinin hangi balant hattn kullanaca belirleniyor. */

cmd.CommandText="Insert Into Siteler (Baslik,Adres,Resim,Icerik) Values


('C#','www.csharpnedir.com','images/resim1.jpg','C# zerine her trl makale.')"; /* Komutun
altraca sql ifadesi belirleniyor. */

Grld gibi OleDbCommand snfn oluturduktan sonra Connection ve CommandText zellikleri


belirleniyor. Dier yandan, bir OleDbCommand nesnesini aada prototipi olan dier yapc metodu
ilede oluturabiliriz.

public OleDbCommand(string cmdText, OleDbConnection connection);

Bu yapc metodumuz parametre olarak sql ifadesini string veri tipinde ve balant nesnesinide
OleDbConnection snf tipinde almaktadr. Bu haliyle yukarda yazdmz kodlar dahada
ksaltabiliriz.

www.bsenyurt.com Page 2363


using System;

using System.Data.OleDb; /* OleDbCommand snf bu isim uzaynda yer almaktadr. */

namespace OleDbCmd1

class Class1

static void Main(string[] args)

/* nce geerli bir balant hatt oluturmamz gerekiyor. */

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("Insert Into Siteler (Baslik,Adres,Resim,Icerik)


Values('C#','www.csharpnedir.com','images/resim1.jpg','C# zerine her trl makale.')",con);

OleDbCommand nesnesinin oluturmak iin bahsettiimiz bu iki yol dnda kullanabileceimiz iki
ar yklenmi metod daha vardr. Bunlarn protoipleride aadaki gibidir.

public OleDbCommand(string cmdText);

Bu prototip sadece sql ifadesini almaktadr. Komut nesnesine ait dier zellikler (Connection gibi)
sonradan belirlenir.

public
OleDbCommand(string cmdText, OleDbConnection connection, OleDbTransaction transaction);

Bu prototip ise, komut ifadesi ve balant nesnesi haricinde birde OleDbTransaction nesnesi
tipinden bir parametre alr. Bu prototip ounlukla, bir i parac iine alnmak istenen komut
nesneleri iin idealdir. Bir OleDbCommand nesnesi oluturabilmek iin kullanabileceimiz son yol

www.bsenyurt.com Page 2364


ise OleDbConnection snfna ait CreateCommand metodunun aadaki rnekte olduu gibi
kullanlmasdr.

using System;

using System.Data.OleDb; /* OleDbCommand snf bu isim uzaynda yer almaktadr. */

namespace OleDbCmd1

class Class1

static void Main(string[] args)

/* nce geerli bir balant hatt oluturmamz gerekiyor. */

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=con.CreateCommand();

cmd.CommandText="Insert Into Siteler (Baslik,Adres,Resim,Icerik)


Values('C#','www.csharpnedir.com','images/resim1.jpg','C# zerine her trl makale.')";

Bu teknikte, geerli olan balant nesnesinin tesis ettii hat zerinde alacak OleDbCommand
snf nesne rnei, CreateCommand metodu ile oluturulmutur. Bu admdan sonra tek yaplmas
gereken CommandText zelliine sql cmleciini atamak olucaktr.

Tm bu teknikler bir OleDbCommand snf nesne rneini oluturmak iindir. Ancak komutu
altrmak iin henz bir adm atm deiliz. Bu haliye program kodlarmz derlense dahi hi bir ie
yaramyacaktr. Nitekim, OleDbCommand nesnelerinin temsil ettii sql cmleciklerini altrmamz
gerekmektedir. Bu amala kullanabileceimiz OleDbCommand metodu vardr. Bunlar;
ExecuteNonQuery, ExecuteReader ve ExecuteScalar metodlardr. metodda farkl amalar ve
performanslar iin kullanlr. Bu amalar, altrmak istediimiz sql ifadesine gre deiiklik
gstermektedir. Sz gelimi, yukardaki kod paralarnda yer alan sql ifadesi DDL (Data Defination
Language- Veri Tanmlama Dili) komutlarndan birisidir. Benzer ekilde update, delete sorgularda

www.bsenyurt.com Page 2365


byledir. Dier taraftan DML (Data Manipulation Language- Veri dare Dili) komutlar dediimiz
Create Table, Alter Table gibi komutlarda mevcuttur. Bu iki kategoriye ait komutlar, etki komutlar
olarakta adlandrlrlar. Hepsinin ortak zellii geriye sonu dndrmemeleridir. Tamamiyle veri
kayna zerinde bir takm sonularn domasna yardmc olurlar. te bu tip komut cmlecikleri
iin, ExecuteNonQuery metodu kullanlr. Bu metodun prototipi aadaki gibidir.

public virtual int ExecuteNonQuery();

Bu metod grld gibi int veri tipinden bir tamsayy geri dndrr. Bu say komutun
altrlmas sonucu etkilenen kayt saysn ifade etmektedir. Dolaysyla bu metod, DDL ve DML
komutlar iin gelitirilmitir diyebiliriz. rnein, yukardaki kod paralarn hayat geirelim. Bunun
iin aadaki kodlar yazacaz.

using System;

using System.Data.OleDb; /* OleDbCommand snf bu isim uzaynda yer almaktadr. */

namespace OleDbCmd1

class Class1

static void Main(string[] args)

/* nce geerli bir balant hatt oluturmamz gerekiyor. */

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("Insert Into Siteler (Baslik,Adres,Resim,Icerik)


Values('C#','www.csharpnedir.com','images/resim1.jpg','C# zerine her trl makale.')",con);

try

con.Open(); /* Balantmz ayoruz.*/

int sonuc=cmd.ExecuteNonQuery(); /* Komutumuzu altryoruz.ExecuteNonQuery


metodunun dndrecei deeri tam say tipindeki sonuc deikenine atyoruz.*/

Console.WriteLine(sonuc.ToString()+" Kayt Girildi...");

catch(Exception hata)

www.bsenyurt.com Page 2366


{

Console.WriteLine(hata.Message.ToString());

finally

con.Close();

Uygulamamz altrdmzda aadaki sonucu alrz.

ekil 1. ExecuteNonQuery sonucu geri dnen deer.

imdi birde aadaki rnee bakalm. Bu kez elimizde, tablomuzun tm satrlarndaki Resim
alanlarnn deerlerinin sonuna img ifadesini eklyecek sql ifadesini ieren bir OleDbCommand
nesnemiz olsun.

using System;

using System.Data.OleDb; /* OleDbCommand snf bu isim uzaynda yer almaktadr. */

namespace OleDbCmd1

class Class1

static void Main(string[] args)

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data

www.bsenyurt.com Page 2367


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmdUpdate=new OleDbCommand("Update Siteler Set Resim=Resim+'img'


",con);

try

con.Open();

int Guncellenen=cmdUpdate.ExecuteNonQuery();

Console.WriteLine(Guncellenen.ToString()+" Kayt Gncellendi");

catch(Exception hata)

Console.WriteLine(hata.Message.ToString());

finally

con.Close();

Bu durumda aadaki sonucu alrz.

www.bsenyurt.com Page 2368


ekil 2. Update komutu sonucu ExecuteNonQuery'nin dndrd deer.

Grld gibi tablomuzdaki 5 kaydn hepsi gncellenmi ve ExecuteNonQuery geriye 5 deerini


dndrmtr. Bu altrlan komut sonucu etkilenen kayt saysn renmek iin iyi ve etkili bir
yoldur. ExecuteNonQuery metodu ile ilgili unutulmamas gereken nokta, bu metodun geriye her
hangibir sonu kmesi, her hangibir k parametresi veya k deeri dndrmemesidir. Elbette
uygulamalarmzda, veri kaynaklarndan veri kmeleri ekme ihtiyacn hissederiz. Byle bir
durumda ise, ExecuteReader metodunu kullanabiliriz. ExecuteReader metodu, altrlan komut
sonucu elde edilen sonu kmesinden bir OleDbDataReader nesnesi iin veri akn salar.
OleDbDataReader nesnesinin benzeri olan SqlDataReader nesnesi ve ExecuteReader metodunun
kullanmn, SqlDataReader nesneleri ile ilgili makelelerimizde incelediimiz iin bu metodun nasl
kullanldna tekrar deinmiyorum.

OleDbCommand snfna ait bir dier veri elde etme metodu ExecuteScalar metodudur. Prototipi
aadaki gibi olan bu metod sadece tek alanlk veri dndren sql sorgular iin kullanlr.

public virtual object ExecuteScalar();

rnein tablomuzdaki kayt saysnn renmek istiyoruz veya tablomuzdaki ucretler adl alanda yer
alan ii cretlerinin ortalamasnn ne olduunu bilmek istiyoruz yada primary key alan zerinden
arama yaptmz bir satra ait tek bir stunun deerini elde etmek istiyoruz. Bu tarz durumlarda,
altrlacak olan komut iin bilgileri ExecuteReader metodu ile almak veya bilgileri bir DataSet
kmesi iine almak vb... sistem kaynaklarnn gereksiz yer harcanmasna ve perfrormansn
olumsuz ekilde etkilenerek azalmasna neden olur. are ExecuteScalar metodunu kullanmaktr.
rnein;

using System;

using System.Data.OleDb; /* OleDbCommand snf bu isim uzaynda yer almaktadr. */

namespace OleDbCmd1

class Class1

www.bsenyurt.com Page 2369


static void Main(string[] args)

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("Select Baslik From Siteler Where ID=8",con);

OleDbCommand cmdToplamSite=new OleDbCommand("Select Count(*) From Siteler",con);

try

con.Open();

Console.WriteLine("ID=8 olan satrn Baslik alannn deeri:


"+cmd.ExecuteScalar().ToString());

Console.WriteLine("Site Says: "+cmdToplamSite.ExecuteScalar().ToString());

catch(Exception hata)

Console.WriteLine(hata.Message.ToString());

finally

con.Close();

www.bsenyurt.com Page 2370


ekil 3. ExecuteScalar Sonucu.

Bu rnekte, Siteler isimli tablomuza ID deeri 8 olan satrn sadece Baslik isimli alannn deerini
veren bir komut nesnesi ve Siteler tablsundaki satr saysn veren baka bir komut nesnesi
kullanlmtr. Her iki sql ifadeside tek bir hcreyi sonu olarak dndrmektedir. Eer sql
ifadenizden birden fazla stun alyorsanz ve bu ifadeyi ExecuteScalar ile altryorsanz, ilk satrn
ilk stunu haricindeki tm veriler gz ard edilecektir. Sz gelimi yukardaki rneimizde, cmd
OleDbCommand nesnesinin CommandText ifadesini aadaki gibi deitirelim.

OleDbCommand cmd=new OleDbCommand("Select * From Siteler",con);

Bu durumda aadaki sonucu elde ederiz.

ekil 4. ExecuteScalar sadece ilk hcreyi dndrr.

Grld gibi sonu olarak, ilk satrn ilk alannn deeri elde edilmitir. (ID alannn deeri.)
OleDbCommand snf ile veri kaynanda yer alan bir sakl yordamda (Stored Procedure)
altrabiliriz. Bu durumda CommandText olarak bu sakl yordamn adn girmemiz yeterli olucaktr.
Ancak, altrlacak olan komutun bir sakl yordam altracan belirtmemiz gerekmektedir. te
bu noktada OleDbConnection snf nesne rneinin CommandType zelliinin deerini belirtmemiz
gerekir.

public virtual CommandType CommandType {get; set;}

Prototipi yukardaki gibi olan bu zellik, CommandType numaralandrcs trnden 3 deer alabilir.
Bu deerler ve ne ie yaradklar aadaki tabloda belirtilmitir.

CommandType Deeri Aklamas

Sql ifadelerini altrmak iin kullanlr. Bu ayn zamanda


Text OleDbCommand snfna ait nesne rnekleri iin varsaylan
deerdir.

Veri kaynanda yer alan bir Sakl Yordam altrlmak


StoredProcedure
istendiinde, CommandType deerine StoredProcedure verilir.

CommandType zelliine bu deer atandnda, CommandText


zellii tablo adn alr. Komut altrldnda alan sql ifadesi
TableDirect
"Select * From tabloadi" ifadesidir. Bylece belirtilen tablodaki
tm kaytlar dndrlm olur.

www.bsenyurt.com Page 2371


Tablo 1. CommandType numaralandrcsnn deerleri.

imdi bu zelliklerin nasl kullanlacan tek tek incelemeye alalm. ncelikle TableDirect
deerinden balayalm. Tek yapmamz gereken tm satrlarn elde etmek istediimiz tablo adn
CommandText olarak belirtmek olucaktr. te rneimiz.

using System;

using System.Data.OleDb;

using System.Data;

namespace OleDbCmd1

class Class1

static void Main(string[] args)

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("Makale",con); /* Komut sz dizimi olarak tm


satrlarn almak istediimi veri tablosunun adn giriyoruz. */

cmd.CommandType=CommandType.TableDirect; /* Komut tipimizi TableDirect olarak


ayarlayp, komut nesnemizin sql ifadesinin Select * From Makale olmasn salyoruz. */

try

con.Open();

/* Bir OleDbDataReader nesnesi tanmlayp, komutumuzu ExecuteReader metodu ile


altrarak, sonu kmesine ait satrlardaki Konu alannn deerlerini ekrana yazdryoruz. */

OleDbDataReader dr;

dr=cmd.ExecuteReader();

while(dr.Read())

Console.WriteLine(dr["Konu"].ToString());

www.bsenyurt.com Page 2372


}

dr.Close();

catch(Exception hata)

Console.WriteLine(hata.Message.ToString());

finally

con.Close();

Uygulamamz altrdmzda, Makale tablosundaki tm satrlarn alnd sonu kmesi


iinden, Konu alanlarnn deerlerinin ekrana yazdrldn grrz.

ekil 5. TableDirect sonucu.

Ancak burada istisnai bir durum vardr. Baz tablo isimleri iinde boluklar olabilir. rnein "Site
Adlari" isminde bir tablomuz olduunu dnelim. Byle bir durumda TableDirect deerinin
sonucunda bir istisnann frlatldn grrz. Yukardaki rneimizde tablo ad olarak Site Adlari
verdiimizi dnelim.

www.bsenyurt.com Page 2373


using System;

using System.Data.OleDb;

using System.Data;

namespace OleDbCmd1

class Class1

static void Main(string[] args)

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("Site Adlari",con);

cmd.CommandType=CommandType.TableDirect;

try

con.Open();

OleDbDataReader dr;

dr=cmd.ExecuteReader();

while(dr.Read())

Console.WriteLine(dr["Baslik"].ToString());

dr.Close();

catch(Exception hata)

Console.WriteLine(hata.Message.ToString());

www.bsenyurt.com Page 2374


}

finally

con.Close();

ekil 6. Tablonun olmad syleniyor.

Bunun sebebi OleDbCommand nesnesinin tablo isminde yer alan boluklar anlamam olmasdr.
Bu nedenle ayn ifadeyi aadaki ekilde deitirmemiz gerekmektedir.

OleDbCommand cmd=new OleDbCommand("[Site Adlari]",con);

Bu durumda uygulamann sorunsuz altn grrz. OleDbCommand snfnn CommandType


zelliinin dier deeri ise StoredProcedure' dr. Bu veri kaynandaki sakl yordamlarnn
arlmas iin kullanlmaktadr. Bir sakl yordam kendisi iin parametreler alabilecei gibi geriye
deerlerde dndrebilir. rnein, Primary Key alanlar zerinden arama yaplan sorgularda Sakl
Yordamlarn kullanlmas son derece verimlidir. Nitekim kullanclarn aramak iin girdikleri her ID
deeri iin ayr bir select sorgusu oluturmak yerine, veri kaynanda bir nesne olarak yer alan ve
ID deerini parametre olarak alan hazr, derlenmi bir select ifadesini altrmak daha verimli
olucaktr. rnein Makale isimli tablomuzdan ID alan 41 olan bir satr elde etmek istiyoruz. Bu
durumda, buradaki sakl yordammza bu ID deerini geirmemiz ve dnen sonular almamz
gerekiyor. ncelikle sakl yordammza bir gz atalm.

ALTER PROCEDURE dbo.MakaleBul

@MakaleID int

AS

www.bsenyurt.com Page 2375


SELECT * FROM Makale Where ID=@MakaleID

RETURN

Bu sakl yordam ID deerine @MakaleID isminde bir parametre alr. Bu parametre deeri ile
tablodaki ilgili satr aranr.Bu satr bulunduunda, geriye bu satrdaki tm alanlar aktarlr. imdi
uygulamamzda bunun nasl kullanacamz grelim. ncelikle OleDbCommand snf nesne
rneimizi bu sakl yordam ismini CommandText deeri olacak ekilde olutururuz. Daha sonra,
CommandType zelliine StoredProcedure deerini veririz. Bylece, CommandText zelliindeki sz
diziminin bir sakl yordam temsil ettiini ifade etmi oluruz. Geriye parametre kalr.
OleDbCommand snf, parametrelerini OleDbParameterCollection koleksiyonunda birer
OleDbParameter nesnesi olarak tutmaktadr. Dikkat etmemiz gereken nokta parametre adnn ,
sakl yordamdaki ile ayn olmasdr. Dilerseniz kodlarmz yazalm ve bu ilemin nasl yapldn
grelim.

using System;

using System.Data.OleDb;

using System.Data;

namespace OleDbCmd1

class Class1

static void Main(string[] args)

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("MakaleBul",con); /* altrlacak sql ifadesi


olarak sakl yordammzn ismini giriyoruz. */

cmd.CommandType=CommandType.StoredProcedure; /* CommandText ifadesinin, geerli


balant nesnesinin temsil ettii veri kaynandaki bir sakl yordam ifade ettiini belirtiyor. */

cmd.Parameters.Add("@MakaleID",OleDbType.Integer); /* Parametremiz oluturuluyor. Ad


@MakaleID, sakl yordammzdaki ile ayn. Parametre tipi integer, nitekim Sakl Yordammzdaki
tipide int.*/

cmd.Parameters["@MakaleID"].Value=41; /* Parametremizin deeri veriliyor. */

try

www.bsenyurt.com Page 2376


con.Open();

OleDbDataReader dr;

dr=cmd.ExecuteReader();

while(dr.Read())

Console.WriteLine(dr["ID"].ToString()+"-"+dr["Konu"].ToString()+"-
"+dr["Tarih"].ToString());

dr.Close();

catch(Exception hata)

Console.WriteLine(hata.Message.ToString());

finally

con.Close();

Bu uygulamay altrdmzda, aadaki sonucu elde ederiz.

ekil 7. Sakl Yordamn almasnn sonucu.

www.bsenyurt.com Page 2377


CommandType zelliinin Text deeri varsaylandr. Text deeri, CommandText iin yazlan sql
ifadelerinin altrlmasnda kullanlr. Aslnda bir sakl yordam bu ekildede arabiliriz. Yani bir
sakl yordam, OleDbCommand snfnn CommandType zelliini Text olarak brakarakta
arabiliriz. Bunun iin "{CALL MakaleBul(?)}" sz dizimini aadaki rnekte olduu gibi kullanrz.
Sonu ayn olucaktr. Burada, CALL ifadesinde parametrenin ? iareti ile temsil edildiine dikkat
edin. SqlCommand snfnda bu parametreler @ParametreAd olarak kullanlr.

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data source=localhost;initial


catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("{CALL MakaleBul(?)}",con);

cmd.Parameters.Add("@MakaleID",OleDbType.Integer);

cmd.Parameters["@MakaleID"].Value=41;

try

con.Open();

OleDbDataReader dr;

dr=cmd.ExecuteReader();

while(dr.Read())

Console.WriteLine(dr["ID"].ToString()+"-"+dr["Konu"].ToString()+"-"+dr["Tarih"].ToString());

dr.Close();

catch(Exception hata)

Console.WriteLine(hata.Message.ToString());

finally

con.Close();

www.bsenyurt.com Page 2378


Gelelim, OleDbCommand snfnn dier nemli yelerine. Bu yelerden birisi CommandTimeOut
zelliidir. Bir sql ifadesi , OleDbCommand nesnesi tarafndan altrldnda, ilk sonular
dndrlene kadar belli bir sre geer. te bu srenin uzunluu CommandTimeOut zellii
tarafndan belirlenir. Balang deeri olarak 30 saniyeye ayarlanmtr. Bu sre zarfnda komut
altrlmas ile birlikte herhangibir sonu dndrlemez ise, bir istisna frlatlr. Bu zellik aslnda,
ilk sonularn dnmeye balamas iin ne kadar sre bekleneceini belirtir. Dnnk, bir
OleDbAdapter nesnesinin altrd bir OleDbCommand nesnemiz var. Bu komutun iaret ettii sql
ifadesi altrldktan sonra, CommandTimeout'ta belirtilen srede bir sonu dnmez ise, sre am
nedeni ile bir istisna oluur. Ancak burada zel bir durum vardr. Eer, bu sre iinde belli bir
sayda kayt( en azndan tek satrlk veri ) geri dnm ise, CommandTimeout sresi geersiz hale
gelir. Byle bir durumda OleDbDataAdapter tarafndan dndrlmeye allan kaytlarn hepsi elde
edilene kadar komut almaya devam eder. Bu bazen bir mr boyu srebilir. Buda tam anlamyla
bir ironidir.

Daha nceki makalelerimizde hatrlayacanz gibi, i paracklarnn ok katl mimaride nemli bir
yeri vardr. Bir OleDbCommand snf nesne rneini bir i parac olarak altrmak iin,
Transaction zelliine, i paracn stlenen OleDbTransaction nesnesini atamamz gerekir.
Bununla ilgili basit bir rnek aada verilmitir.

using System;

using System.Data.OleDb;

using System.Data;

namespace OleDbCmd1

class Class1

static void Main(string[] args)

OleDbConnection con=new OleDbConnection("Provider=SQLOLEDB;data


source=localhost;initial catalog=Friends;integrated security=sspi");

OleDbCommand cmd=new OleDbCommand("Insert Into [Site Adlari]


(Baslik,Adres,Resim,Icerik) Values('C#','www.csharpnedir.com','images/resim1.jpg','C# zerine
her trl makale.')",con);

con.Open();

OleDbTransaction trans=con.BeginTransaction(); /* Transaction'mz, geerli balantmz iin


yaratlyor. */

cmd.Transaction=trans; /* Komutumuzun tanmlanan balant iin alm transaction iinde


bir i parac olarak alaca belirleniyor. */

int sonuc=cmd.ExecuteNonQuery();

www.bsenyurt.com Page 2379


if(sonuc==1)

trans.Commit(); /* Komut baarl bir ekilde altrlmsa Commit ile tm ilemler


onaylanyor. */

Console.WriteLine(sonuc.ToString()+" Kayt Girildi...");

else

trans.Rollback(); /* Komut baarsz ise tm ilemler geri alnyor. */

OleDbCommand snfnn kullanld dier nemli bir yerde OleDbDataAdapter snfdr. Nitekim bu
snfn ierdii SelectCommand, UpdateCommand, DeleteCommand, InsertCommand zellikleri,
OleDbCommand snf trnden nesneleri deer olarak alrlar. Bu konuyu ilerliyen makalelerimizde
OleDbDataAdapter snfn ilerken incelemeye alacaz.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Batch Queries (Toplu Sorgular) ve


SqlDataReader ( 17.02.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, toplu sorgularn, SqlDataReader snf ile nasl okunabileceini incelemeye


alacaz. Bildiiniz gibi SqlDataReader nesneleri, bir select sorgusunu altran SqlCommand
snfna ait, ExecuteReader metodu ile oluturulmaktayd. altrlan sorgu sonucu elde edilen kayt
kmesinde sadece okunabilir ve ileri ynl hareket etmemize imkan salayan SqlDataReader snf,
belli bir t annda veri kanandan sadece tek bir satr okumamza izin vermektedir. Bu ynden
bakldnda, SqlDataReader snf, verileri hzl ve verimli bir ekilde okumamza imkan
salamaktadr. rnein aadaki kod satrlar ile, Sql sunucumuzda yer alan makale isimli
tablodaki tm satrlar okunarak ekrana yazdrlmtr.

www.bsenyurt.com Page 2380


using System;
using System.Data.SqlClient;
using System.Data;
namespace BatchQueries
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi"); /* Sql sunucumuza olan balant hattn tesis edicek
SqlConnection nesnemiz tanmlanyor.*/
SqlCommand cmdMakale=new SqlCommand("Select * From Makale",conFriends); /*
Makale tablosundaki tm satrlar alcak sql sorgusunu altracak SqlCommand nesnemiz
oluturuluyor. */
SqlDataReader drMakale; /* SqlDataReader nesnemiz tanmlanyor. */
conFriends.Open(); /*Balantmz alyor. */
drMakale=cmdMakale.ExecuteReader(CommandBehavior.CloseConnection); /*
Komutumuz altrlyor ve sonu kmesinin balangc SqlDataReader nesnemize aktarlyor. */
/* leri ynl olarak, SqlDataReader nesnemiz ile, sonu kmesindeki satrlar okunuyor ve
1 indisli alann deeri ekrana yazdrlyor. */
while(drMakale.Read())
{
Console.WriteLine(drMakale[1]);
}
drMakale.Close(); /* Balantmz kapatlyor. */
}
}
}

Bu kodlar altrdmzda karmzza aadakine benzer bir sonu kacaktr.

ekil 1. Programn almasnn Sonucu.

SqlDataReader nesnesinin kullanmna ksaca deindikten sonra makelemizin asl konusu olan toplu
sorgulara deinelim. Toplu sorgular birbirlerinden noktal virgl ile ayrlm sorgulardr. Birden fazla
sorguyu bu ekilde bir araya getirerek ilemlerin tek bir hamlede balatlmasn ve
gerekletirilmesini salam oluruz. Bu sorgu topluluklarn, eski dostumuz Ms-Dos iletim
sistemindeki bat uzantl Batch dosyalarna benzetebilirsiniz. Sorun u ki, yukardaki tarzda bir
SqlDataReader kullanmn bir toplu sorguya uyguladmzda, sadece ilk sorgunun altrlacak
olmasdr. rnein aadaki biri bir toplu sorgumuz olduunu dnelim;

www.bsenyurt.com Page 2381


Select * From Makale;Select * From Kitap;Select * From
Siteler

Bu toplu sorguda arka arkaya select sorgusu yer almaktadr. Makale, Kitap ve Siteler tablolarnn
tm stunlar talep edilmektedir. Yukardaki kod tekniini byle bir toplu sorguya uyguladmz
dnelim.

using System;
using System.Data.SqlClient;
using System.Data;
namespace BatchQueries
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
string sorgu="Select * From Makale;Select * From Kitap;Select * From Siteler";
SqlCommand cmdMakale=new SqlCommand(sorgu,conFriends);
SqlDataReader drMakale;
conFriends.Open();
drMakale=cmdMakale.ExecuteReader(CommandBehavior.CloseConnection);
while(drMakale.Read())
{
Console.WriteLine(drMakale[1]);
}
drMakale.Close();
}
}
}

Uygulamamz altrdmza sadece Makale isimli tabloya ait verileri okuyabildiimizi ve ekrana
yazdrldklarn grrz.

ekil 2. Sadece ilk kayt kmesi okundu.

Problem udur. Toplu sorgumuz, birbirinden farkl kayt kmesi getirmektedir. Bu nedenle, her
bir kayt kmesinin ayr ayr okunmas gereklidir. Bunu gerekletirmek iin ise, SqlDataReader

www.bsenyurt.com Page 2382


nesnesini, Read metodu false deerini dndrdkten, yani geerli kayt kmesindeki tm satrlarn
okunmas bittikten sonra, baka kayt kmesinin olup olmad kontrol edilmelidir. Bize bu imkan
aada prototipi verilen, NextResult metodu salamaktadr.

public
virtual bool NextResult();

Bu metod geriye bool tipinde bir deer dndrr. Eer gncel kayt kmesinin okunmas bittikten
sonra baka bir kayt kmesi var ise, true deerini dndrecektir. Bu durumda, toplu sorgularda bir
sonraki kayt kmesinin var olup olmadn belirlemek iin baka bir while dngsn kullanrz.
te yukardaki toplu sorgumuz sonucu elde edilen tm kayt kmelerini okuyabileceimiz kodlar;

using System;
using System.Data.SqlClient;
using System.Data;
namespace BatchQueries
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
string sorgu="Select * From Makale;Select * From Kitap;Select * From Siteler";
SqlCommand cmdMakale=new SqlCommand(sorgu,conFriends);
SqlDataReader drMakale;
conFriends.Open();
drMakale=cmdMakale.ExecuteReader(CommandBehavior.CloseConnection);
do
{
Console.WriteLine("---------");
while(drMakale.Read())
{
Console.WriteLine(drMakale[1]);
}
Console.WriteLine("---------");
}
while(drMakale.NextResult());
drMakale.Close();
}
}
}

Burada do while dngmz bizim anahtar noktamzdr. While do dngs iinde, o an geerli olan
kayt kmesindeki tm satrlar okunur. Okunacak satrlar bittikten sonra, sqlDataReader nesnemize
ait Read metodu false deerini dndrr ve bu while-do dngs sonra erer. Bu ilemin ardndan
do-while dngsnde yer alan NextResult metodu altrlr. Eer arkada baka bir kayt kmesi
varsa, whilde-do dngmz bu kayt kmesi iin altrlr. Do-while dngmz, teknii asndan

www.bsenyurt.com Page 2383


en az bir kere altrlr. Zaten ExecuteReader metodu sonucu dnen toplu kayt kmeleri sz
konusu olduunda, SqlDataReader nesnemiz okumak zere hemen ilk kayt kmesine
konumlanr. te sonu;

ekil 3. Toplu sorgunun altrlmas sonucu.

Bylece, SqlDataReader nesnesi ile, toplu sorgularn altrlmas sonucu elde edilen kayt kmeleri
zerinden nasl veri okuyabileceimizi incelemi olduk. Bir sonraki makalemizde grmek dileiyle
hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Connection (Balant) Kavram ve


OleDbConnection Snf ( 13.02.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, ADO.NET mimarisinde temel yap ta olan Connection


(Balant) kavramna ksaca deinecek ve OleDbConnection snfn
incelemeye alacaz. ADO.NET mimarisinde, pek ok snfn veri
kaynaklar ile olan iletiiminde Connection (Balant) nesnelerini

www.bsenyurt.com Page 2384


kullanrz. rnein, bir veri kayandaki tablolara ait verileri, DataSet
snfndan bir nesne rneine tamak istediimizi dnelim. Bu dataSet
nesnesini dolduracak olan DataAdapter snfna, sahip olduu sql
sorgusunun veya komutunun ileyecei bir hatt belirtmemiz gerekir. te
burada devreye Connection (Balant) nesnelerimiz girer. Yada bir
Command snf nesnesi yardmyla veritaban zerindeki bir sakl yordam
(stored procedure) altrmak istediimizi dnelim. Bu durumda
komutun altrlabilecei bir hatt veri kaynamz ile Command nesnesi
arasnda salamamz gerekir. te Connection (Balant) nesnemizi
kullanmamz iin bir sebep daha.

Verdiimiz bu basit rneklerdende anlald gibi, Connection(balant)


snflar, veri kaynana bir hat ekerek, ADO.NET nesnelerinin bu hat
yardmyla ilemlerini gerekletirmelerine imkan salarlar. Ancak sahip
olunan veri kaynann trne gre, ADO.NET ierisine deiik
Connection snflar eklenmitir. DotNet'in ilk srmnde
OleDbConnection ve SqlConnection nesneleri ile bu hatlar temin edilirken,
.NET Framework 1.1 srm ile birlikte, OdbcConnection ve
OracleConnection snflarda ADO.NET ktphanelerine dahil edilerek
Odbc ve Oracle veri kaynaklarna balantlar salanmas imkan
kazandrlmtr.

OleDbConnection snf ile, bir OleDb Data Provider (veri salaycs)


zerinden, ole db destekli veri kaynaklarna eriim salayabiliriz.
SqlConnection snf Sql Sunucularna dorudan balant salar. Ayn
ekilde OracleConnection snfda Oracle veri kaynaklarna dorudan
eriim salar. OdbcConnection snf ise odbc destekli veri kaynaklarna
eriim iin kullanlr. Bu makalemizde bu balant snflarndan
OleDbConnection snfn inceleyeceiz. OleDbConnection snf, ADO.NET
snflarnn , Ole Db destei olan veri kaynaklarna eriebilmesi amacyla
kullanlr. Veri kaynann tipi tam olarak bilinmedii iin, arada bu ilevi
ayrt etmeye yarayan bir COM+ nesnesi yer almaktadr. OleDbConnection
snfna ait bir nesne iletiim kurmak istedii veri kaynana ait ole db veri
salaycsn belirtmek durumundadr. Bunu daha iyi kavramak iin
aadaki ekle bakalm.

www.bsenyurt.com Page 2385


ekil 1. OleDbConnection ile Veri Kaynaklarna Balant.

Grld gibi bir OleDbConnection nesnesi ncelikle bir Ole Db Data Provider ( Ole Db Veri
Salaycs) ile iletiim kurar. Ardndan bu veri salayc istenen veri kaynana erierek, gerekli
hatt tesis etmi olur. Peki bu ilemi nasl gerekletireceiz. te tm Connection nesnelerinin en
nemli zellii olan ConnectionString zellii bu noktada devreye girmektedir. Ksaca
ConnectionString zellii ile, veri kayna ile salanacak olan iletiim hattnn kurulum bilgileri
belirlenir. OleDbConnection snf iin ConnectionString zellii aadaki prototipe sahiptir.

public virtual string ConnectionString {get; set;}

ConnectionString zellii belirlenmi bir OleDbConnection snf nesne rneini atmzda, yani
veri kaynana olan hatt kullanlabilir hale getirdiimizde, bu zellik yanlz-okunabilir (read-only)
hale gelir. Dolaysyla ak bir OleDbConnection nesnesinin ConnectionString zelliini
deitiremezsiniz. Bunun iin bu balanty tekrardan kapatmanz gerekecektir. ConnectionString
zellii, bir takm anahtar-deer iftlerinin noktal virgl ile ayrlmasndan oluturulan string bir bilgi
topluluudur. ConnectionString zellii iinde kullanabileceimiz bu anahtar-deer iftlerinin en
nemlisi Provider anahtardr. Bu anahtara vereceimiz deer, hangi tip ole db veri salaycsn
kullanmak istediimizi belirtmektedir.

rnein Sql sunucusuna, Sql Ole Db Provider ile balanmak istersek, Provider anahtarna,
SQLOLEDB deerini atarz. Provider anahtar mutlaka belirtilir. Daha sonraki anahtar-deer iftleri
ise bu Provider seimine bal olarak deiiklik gsterecektir. Veri kaynana hangi tip Ole Db Veri
Salaycsndan balandmz setikten sonra, balanmak istediimiz veri kaynada belli olmu
olucaktr. Srada bu veri kaynann adn veya adresine belirteceimiz anahtar-deer iftlerinin
belirlenmesi vardr. rnein bir Sql Sunucusuna balanyorsak, sunucu adnda Ole Db Data
Provider( Veri Salyacs) 'na bildirmemiz gerekir. Bunun iin Data Source anahtarn kullanrz.
Bununla birlikte balandmz veri kayna, sql yada oracle gibi bir veritaban ynetim sistemi
deilde, Access gibi bir tablolama sistemi ise, Data Source anahtar, tablonun fiziki adresini alr. Sql
ve Oracle gibi sunuculara yaplacak balantlarda Provider ve Data Source seiminin yannda hangi

www.bsenyurt.com Page 2386


veritabanna balanlacanda Initial Catalog anahtar yada Database anahtar ile belirleriz.
Bunlarn dnda veri kaynana yaplacak olan balantnn gvenlik ayarlarnda belirtiriz.
ounlukla Integrated Security gibi bir anahtara True deerinin atandn grrz. Bu anahtar,
veri kaynana balanmak istenen uygulama iin, makinenin windows authentication ayarlarna
bakldn belirtir. Dolaysyla sql sunucusuna balanma yetkisi olan her windows kullancs bu
balanty salayabilir. Ancak istersek belli bir kullanc ad veya ifresi ilede bir veritabanna
balant almasn salayabiliriz. Bunun iin ise, User ID ve Password anahtarlarn kullanrz.

Buraya kadar bahsettiklerimiz kavramsal aklamalardr. Dilerseniz basit rnekler ile konuyu daha
iyi aklamaya alalm. rneklerimizi Console uygulamalar eklinde gerekletireceiz. lk
rneimizde, Sql Sunucusundaki veritaban iin, bir balant hatt oluturup aacaz.

using System;
using System.Data.OleDb; /* OleDbConnection snf, Data.OleDb isim uzaynda yer almaktadr. */
namespace OleDbCon1
{
class Class1
{
static void Main(string[] args)
{
OleDbConnection conFriends=new OleDbConnection(); /* OleDbConnection nesnemiz
oluturuluyor. */
/* ConnectionString zellii belirleniyor. Provider (Salaycmz) SQLOLEDB. Bu bir sql
sunucusuna balanmak istediimizi belirtir. Data Source anahtarna localhost deerini atayarak,
sunucunun yerel makinede olduunu belirtiyoruz. Ancak buraya baka bir adreste girilebilir.
Sunucunuz nerede ise orann adresi. Database ile, balant hattnn alaca veritabann
belirliyoruz. Burada sql sunucumuzda yer alan Friends veritabanna balant hatt ayoruz. Son
olarak Integrated Security=SSPI anahtar-deer ifti sayesinde Windows Dorulamas ile sunucuya
balanabileceimizi belirtiyoruz. Yani sql sunucusuna balanma yetkisi olan her windows kullancs
bu hatt tesis edebilecek.*/
conFriends.ConnectionString="Provider=SQLOLEDB;Data
Source=localhost;Database=Friends;Integrated Security=SSPI";
try
{
conFriends.Open(); /* Open metodu ile oluturduumuz iletiim hattn kullanma
ayoruz. */
Console.WriteLine("Balant ald...");
conFriends.Close(); /* Close metodu ilede oluturulan iletiim hattn kapatyoruz.
*/
Console.WriteLine("Balant kapatld...");
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
}
}
}

www.bsenyurt.com Page 2387


ekil 2. Uygulamann almasnn Sonucu.

Ayn rnekte bu kez belli bir kullanc ile balanmak istediimizi dnelim. Bu durumda
ConnectionString'imizi aadaki ekilde deitirmemiz gerekir. Bu durumda User ID ve Password
anahtarlarna gerekli kullanc deerlerini atarz.

conFriends.ConnectionString="Provider=SQLOLEDB;Data
Source=localhost;Database=Friends;User Id=sa;Password=CucP??80.";

imdide bir Access tablosuna nasl balanabileceimizi grelim. Bunun iin ConnectionString
zelliimizi aadaki gibi yazarz.

OleDbConnection conYazarlar=new OleDbConnection("Provider=Microsoft.Jet.OLEDB.4.0;data


source=c:\\Authors.mdb");
try
{
conYazarlar.Open();
Console.WriteLine("Yazarlar Access veritabanna balant ald...");
conYazarlar.Close();
Console.WriteLine("Yazarlar Access veritabanna olan balant kapatld...");
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}

ekil 3. Access Veritabanna Balat.

Bu rnekte dikkat ederseniz ConnectionString zelliini, OleDbConnection nesnemizin dier yapc


metodu ierisinde parametre olarak belirledik. Ayraca, Provider olarak bu kez
Microsoft.Jet.OLEDB.4.0 ' seerek, bir Access veritabanna balanmak istediimizi bu Ole Db
Provider'a bildirmi olduk. Daha sonra bu veri salayc componenti, Data Source anahtarndaki
deere bakarak, ilgili adresteki veritabanna bir hat ekti.

Baka bir ConnectionString anahtarda File Name dir. Bu anahtara bir udl uzantl dosya adresi
vererek, balant hattnn bu dosyadaki ayarlar zerinden gerekletirilmesini salayabiliriz. Bir udl

www.bsenyurt.com Page 2388


dosyas Data Link Properties ( veri linki zellikleri) zelliklerini belirler. Byle bir dosya oluturmak
son derece basittir. Bir text editor ile bo bir dosya an ve onu udl uzants ile kaydedin. Bu
durumda dosyamzn grnm u ekilde olucaktr.

ekil 4. Bir udl dosyasnn grnts.

Bu dosyay atmzda hepimizin aina olduu veritaban balant seenekleri ile karlarz.

ekil 5. Connection ayarlar.

Bu penceredeki admlar takip ederek bir ConnectionString'i bir udl dosyasna kaydedebilir ve
OleDbConnection nesnemiz iin sadece File Name anahtarna bu deeri vererek ilgili balantnn, bu
udl dosyasndaki ayarlar zerinden gerekletirilmesini salayabiliriz. lk yapmamz gereken
ConnectionString zelliinde olduu gibi , Provider (Salayc) seimidir.

www.bsenyurt.com Page 2389


ekil 6. Provider Seimi.

Burada rnek olarak Sql Server Provider'mz seelim. Sonraki admda ise srasyla sunucu admz
(Server Name), sunucuya hangi kimlik dorulamas ile balanacamz ve veritabanmzn adn
seeriz. Son olarakta bu dosyamz kaydedelim.

www.bsenyurt.com Page 2390


ekil 7. Connection zelliklerinin belirlenmesi.

imdi uygulamz buna gre deitirelim.

OleDbConnection con=new OleDbConnection();


con.ConnectionString="File Name=C:\\baglanti.udl";
try
{
con.Open();
Console.WriteLine("Balant ald...");
con.Close();
Console.WriteLine("Balant kapatld...");
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}

www.bsenyurt.com Page 2391


ekil 8. Udl dosyas zerinden balant amak ve kapatmak.

Tabiki burada Visual Studio.Net'in balant salamak iin bize sunduu grsel nimetlerden
szetmedende geemeyiz. Visual Studio.NET ortamnda, OleDbConnection oluturmak iin
kullanabileceimiz Server Explorer sekmesi yer almaktadr.

ekil 9. Server Explorer

Burada servers sekmesinde Sql sunucularna eriebiliriz. Buradan tablolara, grnmlere, sakl
yordamlara hatta tabloa alanlarna ulaabiliriz. Server Explorer'n salad pek ok ilevsellik
vardr. rnein bu pencereden, bir sql tablosu yaratabilirsiniz veya bir sakl yordam
oluturabilirsiniz. Hatta bir tabloyu formunuza srklyerek, gerekli olan tm ADO.NET nesnelerinin
otomatik olarak oluturulmasnda salayabilirsiniz. Bu makalemizde OleDbConnection nesnesini
incelediimiz iin bu tip bir balanty Server Explorer yardmyla nasl gerekletireceimizi

inceleyeceiz. Bunun iin (Connect To Database) aracn kullanacaz. Bu butona


bastmzda karmza tandk Data Link Properties penceresi gelecektir. Sratli bir ekilde burada
gerekli balant ayarlarn yaptktan sonra, Server Explorer aadaki grnm alcaktr. Burada
rnek olarak bir Access veritabanna balant salanmtr.

www.bsenyurt.com Page 2392


ekil 10. Balant oluturuldu.

Dikkat ederseniz balantmz zerinden, veri kaynandaki tablolara ve alanlarna ulaabiliyoruz.


imdi bu balanty, bir windows uygulamasnda veya bir asp.net uygulamasnda forma
srklediimizde bir OleDbConnection nesnesinin otomatik olarak oluturulduunu greceksiniz.
te bu kadar basit. Artk bu connection nesnesini kullanabilirsiniz. Dier yandan Server Explorer'da
oluturulan bu balanty baka uygulamalarda da hazr olarak grebilirsiniz. Data Connection
sekmesi uygulamalarda kullanacamz veri balantlarn hazr olarak bulundurmak iin ideal bir
yerdir.

www.bsenyurt.com Page 2393


ekil 11. OleDbConnection1 nesnesinin Server Explorer yardmyla oluturulmas.

Gelelim OleDbConnection nesnesinin dier kullanl yelerine. Buraya kadar bir balant hattn
oluturmak iin ConnectionString zelliinin nasl kullanldn inceledik. Bununla birlikte var olan
bir balant hattn amak iin Open metodunu, bu balant hattn kapatmak iinde Close
metodunun kullanldn grdk. OleDbConnection nesnesinin dier bir zelliide
ConnectionTimeout deeridir. ConnectionTimeout zellii, bir balantnn salanmas iin gerekli
sreyi belirtir. Bu sre boyunca balant salanamamas bir istisnann frlatlmasna neden
olucaktr. Bu zellik yanlz-okunabilir (read-only) bir zellik olduundan, deerini dorudan
deitiremeyiz. Bunun iin, bu zellii ConnectionString ierisinde belirlememiz gerekir. rnein
aadaki kodlarda, Sql sunucusuna balanabilmek iin gerekli sre 10 saniye olarak belirlenmitir.
imdi ben Sql Server servisimizi durduracam ve uygulamay altracam. Bakalm 10 saniye
sonunda ne olucak.

OleDbConnection conFriends=new OleDbConnection();


conFriends.ConnectionString="Provider=SQLOLEDB;Data
Source=localhost;Database=Friends;User Id=sa;Password=CucP??80.;Connect Timeout=10";
try
{
conFriends.Open();
Console.WriteLine("Baglanti aildi...");
conFriends.Close();
Console.WriteLine("Baglanti kapatildi...");
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}

Bu durumda aadaki hata mesajn alrz.

ekil 12. Sql sunucusunun olmadn gsteren istisna.

OleDbConnection snfnn Open ve Close metodlar dndada faydal metodlar vardr. rnein
ChangeDatabase metodu. Bu metod ile ak olan bir balant zerinden, veri kaynandaki seili
veritabann deitirmemiz salanr. Yani hattn ucu baka bir veritabanna ynlendirilebilir. Bu
tabiki Oracle ve Sql gibi veritaban sistemlerinde zellikle ie yarar. rnein, Friends veritabanna
balyken, ak olan balantmz zerinden hattmz, pubs veritabanna ynlendirelim.

OleDbConnection conFr=new OleDbConnection(); /* OleDbConnection nesnemiz oluturuluyor. */


conFr.ConnectionString="Provider=SQLOLEDB;Data
Source=localhost;Database=Friends;Integrate/d Security=SSPI"; /* Balant hattmz iin gerekli
bilgiler giriliyor. Sql sunucumuzda yer alan Friends isimli veritabanna balandk. */
conFr.Open(); /* Balantmz alyor. */
Console.WriteLine("Veritaban "+conFr.Database.ToString()); /* uandaki balantnn hangi
veritabanna yapldn OleDbConnection snfnn Database zellii ile reniyoruz. */
conFr.ChangeDatabase("pubs"); /* ChangeDatabase metodu ile balant hattmz ynlendirmek

www.bsenyurt.com Page 2394


istediimiz veritabannn adn giriyoruz. */
Console.WriteLine("imdiki veritaban "+conFr.Database.ToString()); /* Balant hattnn u an
ynlendirilmi olduu veritabannn adn Database zellii ile elde ediyoruz.*/
conFr.Close(); /* Balantmz kapatyoruz. */

ekil 13. ChangeDatabase metodunun almasnn sonucu.

Dier yararl bir metod ise GetOleDbSchemaTable metodudur ki bunu bir nceki makalemizde
incelemitik. Bunun dnda bir OleDbCommand nesnesini oluturmaya yarayan CreateCommand
metodu, bir Transaction'n balatlmas iin kullanlan BeginTransaction metodu, OleDbConnection'a
ait kaynaklar serbest brakan Dispose metodu'da faydal dier metodlar olarak saylabilir. Bu
metodlardan ilerliyen makalelerde yeri geldike bahsedeceiz. OleDbConnection nesnesinin sadece
3 adet olay vardr. Bunlar, StateChange, Disposed ve InfoMessage olaylardr. Bunlardan en ok,
StateChange olayn kullanrz. Bu olay, OleDbConnection nesnesinin balant durumunda bir
deiiklik olduunda oluur. Bu olayn prototipi aadaki ekildedir.

public event StateChangeEventHandler StateChange;

Bu olay StateChangeEventArgs tipinden bir argman almaktadr. Bu argman iki zellie sahiptir.
Bunlar CurrentState ve OriginalState zellikleridir. CurrentState balantnn o anki drumunu
belirtir. OriginalState ise son deiiklikten nceki halini gsterir. Her iki zellikde ConnectionState
numaralandrcs trnden deerlere iaret ederler. Bu deerler unlardr.

ConnectionState Deeri Aklamas

ConnectionState.Open Balant ak ise bu deer geerlidir.

ConnectionState.Closed Balant kapandnda bu deer geerlidir.

ConnectionState.Connecting Balant hatt iletiime alrken bu deer geerlidir.

Balant hatt akken herhangibir nedenle bir kopma meydana


ConnectionState.Broken
gelmesi ve hattn ilevselliini kaybetmesi durumunda oluur.

ConnectionState.Executing Balant nesnemiz bir komut altrrken oluur.

ConnectionState.Fetching Balant hatt zerinden veriler alnrken bur deer geerlidir.

Tablo 1. ConnectionState numaralandrcsnn deerleri.

www.bsenyurt.com Page 2395


ConnectionState numaralandrcs ayn zamanda, State zellii iinde kullanlabilir. State zellii,
OleDbConnection nesnesinin o anki durumunu, ConnectionState numaralandrcs tipinde saklar.
State zelliini uygulamalarmzda, var olan balantnn durumun kontrol ederek hareket etmek iin
kullanabiliriz. rnein bir balant nesnesini uygulamamzn bir yerinde tekrardan amak
istediimizi varsayalm. Bu balant nesnesinin durumu zaten Open ise yani ak ise, tekrardan
ama ilemi uygulamamz gerekmez. Dilerseniz makalemizin sonunda StateChange olayna ilikin
bir rnek gelitirelim.

OleDbConnection con; /* OleDbConnection nesnemiz tanmlanyor.*/


private void Form1_Load(object sender, System.EventArgs e)
{
lstDurum.Items.Clear();
con=new OleDbConnection("Provider=SQLOLEDB;Data source=localhost;initial catalog=Friends;Integrated
Security=sspi"); /* Balant hattmz oluturuluyor. */
con.StateChange+=new StateChangeEventHandler(con_DurumDegisti); /* OleDbConnection nesnemiz iin
StateChange olaymz ekleniyor. Olay meydana geldiinde con_DurumDegisti isimli metod altrlcak.*/
}
private void btnAc_Click(object sender, System.EventArgs e)
{
if(con.State==ConnectionState.Closed) /* Kullanc ak olan bir balant zerinden tekrar bu
butona basarak bir balant amak isterse bunun nne gemek iin ilgili OleDbConnection
nesnesinin durumuna bakyoruz. Eer con nesnesi kapal ise, alabilmesini salyoruz.*/
{
con.Open(); /* Balantmz alyor. te bu anda StateChange olay altrlr.*/
}
}
private void btnKapat_Click(object sender, System.EventArgs e)
{
if(con.State==ConnectionState.Open) /* Eer ak bir balant varsa kapatma ilemini
uyguluyoruz.*/
{
con.Close(); /* Balant kapanyor. StateChange olay bir kez daha alr. */
}
}
private void con_DurumDegisti(object sender,StateChangeEventArgs e)
{
lstDurum.Items.Add("Balant durumu "+e.OriginalState.ToString()+" idi."); /* Balantmzn
hangi halde olduunu alyoruz.*/
lstDurum.Items.Add("Artk balant durumu "+e.CurrentState.ToString()); /* Ve balantmzn
yeni halini alyoruz.*/
}

www.bsenyurt.com Page 2396


ekil 14. StateChange olay.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

GetOleDbSchemaTable Metodu le
Veritabanmzda Ne Var Ne Yok ( 12.02.2004 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, OleDbConnection snfna ati olan GetOleDbSchemaTable metodu sayesinde, Sql


Veritabanmzdaki varlklara ait ema bilgilerini nasl temin edebileceimizi incelemeye alacaz.
ou zaman programlarmzda, balandmz veritabannda yer alan tablolarn (Tables),
grnmlerin (Views), sakl yordamlarn (Stored Procedures) ve daha pek ok veritaban
nesnesinin bir listesine sahip olmak isteriz. ADO.NET'te yer alan OleDbConnection nesnesine ait
GetOleDbSchemaTable metodunu kullanarak bu istediimiz sonuca varabiliriz.GetOleDbSchema
metodu aadaki prototipe sahiptir.

public DataTable GetOleDbSchemaTable(Guid schema,object[] restrictions);

Dikkat edecek olursanz metodun geri dn deeri DataTable tipindedir. Metodun isminde Table
kullanlmasnn nedenide zaten budur. Yani dnen ema bilgileri bir DataTable nesnesine
aktarlacaktr. Metod iki nemli parametreye sahiptir. lk parametremiz, OleDbSchemaGuid snf
trnden bir numaralandrc deeri almaktadr. Bu parametreye vereceimiz deer ile,
veritabanndan elde etmek istediimiz ema tipini belirleriz. rnein veritabannda yer alan
tablolar elde etmek iin, OleDbSchemaGuid.Tables deerini veririz. Bunun yannda bu parametreye
verebileceimiz baka nemli deerlerde unlardr.

www.bsenyurt.com Page 2397


OleDbSchemaGuid zellii Aklamas

OleDbSchemaGuid .Columns Tablo veya tablolara ait stun yapsn salar.

OleDbSchemaGuid OleDbConnection nesnesinin bal olduu veritabannda yer alan


.Procedures sakl yordamlarn listesini salar.

OleDbConnection nesnesinin bal olduu veritabannda yer alan


OleDbSchemaGuid .Views
grnmlerin listesini salar.

OleDbSchemaGuid .Indexes Belirtilen Catalog'da yer alan indexlerin listesini salar.

OleDbSchemaGuid
Belirtilen tablo veya tablolardaki birincil anahtarlarn listesini verir.
.Primary_Keys

Tablo 1. OleDbSchemaGuid yelerinin Bir Ksm

OleDbSchemaGuid snf yukardaki rnek yelerinin yansra pek ok yeye sahiptir. Bu yeler ile
ilgili daha geni bilgi iin MSDN kaynaklarndan faydalanmanz tavsiye ederim.
GetOleDbSchemaTable metodumuz ikinci bir parametre daha almaktadr. Bu parametre ile ema
bilgisi zerindeki snrlamalar belirleriz. Bu sayede, ilk parametrede istediimiz schema bilgilerinin
sadece belirli bir tablo iinmi, yada veritabannn tamam iinmi oluturulacana dair sonular
elde etmi oluruz. rneklerimizi incelediimizde bu parametrelerin ne ie yaradklarn daha iyi
anlayacanz dnyorum. imdi ilk rneimizi gelitirelim. Basit bir Console uygulamas olarak
gelitireceimiz bu rnekte, Sql sunucumuzda yer alan, Friends isimli veritabanndaki tm
tablolarn bir listesini elde edeceiz. te program kodlarmz.

using System;
/* OleDb isim uzayn ve Data isim uzayn ekliyoruz. */
using System.Data;
using System.Data.OleDb;
namespace GetOleDbSchemaTables1
{
class Class1
{
static void Main(string[] args)
{
/* OleDbConnection nesnemizi oluturuyoruz. SQLOLEDB provider'n kullanarak, Sql
sunucumuzda yer alan Friends isimli veritabanna bir balant nesnesi tanmlyoruz. */
OleDbConnection con=new OleDbConnection("provider=SQLOLEDB;data
source=localhost;initial catalog=Friends;Integrated Security=sspi");
con.Open(); /* Balantmz ayoruz. */
DataTable tblTabloListesi; /* GetOleDbSchemaTable metodunun sonucunu tutacak
DataTable nesnemizi tanmlyoruz.*/
tblTabloListesi=con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,null); /*
OleDbConnection nesnemizin, GetOleDbSchemaTable metodunu altryoruz ve elde edilen ema
bilgisini (ki bu rnekte Friends isimli veritabanndaki tm tablolarn listesini alyor.) alyoruz ve
DataTable nesnemizin bellete referans ettii alana aktaryoruz.*/

www.bsenyurt.com Page 2398


foreach(DataRow dr in tblTabloListesi.Rows) /* DataTable'mz iindeki satrlarda
gezinebileceimiz bir dng oluturuyoruz ve bu dng iinde her bir satrn TABLE_NAME alannn
deerini, dolaysyla Friends veritabanndaki tablo adlarn ekrana yazdryoruz. */
{
Console.WriteLine(dr["TABLE_NAME"]);
}
}
}
}

imdi uygulamamz altrdmzda Friends isimli veritabannda yer alan tm tablolarn ekrana
yazldn grrsnz.

ekil 1. Friends veritabanndaki tablolarn listesi.

imdi kodlarmzdaki blTabloListesi=con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables,null);


satrn daha yakndan incelemeye alalm. lk parametremizOleDbSchemaGuid.Tables, con isimli
OleDbConnection nesnemizin baland Sql sunucusundaki Friends veritabanndan sadece tablo
bilgilerini elde etmek istediimizi gstermektedir. Snrlandrc zellie sahip olan ikinci
parametremize null deerini vererek tm tablolarn emaya dahil edilmesini ve DataTable
nesnesine aktarlmasn salam olduk. Bu noktada bu iki parametrenin birbirleri ile ilikil
olduklarn syleyebiliriz. nk, OleDbSchemaGuid parametresinin verecei tablolarn ema yaps,
ikinci parametreye baldr. yleki;

Snrlama Alan Aklamas

www.bsenyurt.com Page 2399


TABLE_CATALOG Katalog ad. Eer provider'mz kataloglar desteklemiyorsa null deeri verilir.

TABLE_SCHEMA ema ad. Yine provider'mz emalar desteklemiyorsa null deeri verilir.

Belirli bir tabloya ait ema bilgileri kullanlacaksa, rnein bu tabloya ait stun
TABLE_NAME
bilgileri alncaksa kullanlr.

TABLE_TYPE Veritabanndan hangi tipteki tablolar alacamz belirtmek iin kullanlr.

Tablo 2. OleDbSchemaGuid.Tables in Snrlama Parametresi Elemanlar

Ancak farzedelimki sadece kullanc tanml tabolarn listesine ihtiyacmz var. te bu durumda
snrlandrc parametremiz devreye girecek. Bunun iin, snrlandrc parametremizin son
elemannn deerini belirlememiz yeterli olucak. O halde bu ilemi nasl gerekletirebiliriz? Bunun
iin uygulamamzn kodlarn aadaki ekilde deitirmemiz yeterlidir.

object[] objSinirlama;
objSinirlama=new object[]{null,null,null,"TABLE"};
tblTabloListesi=con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, objSinirlama);

ekil 2. Sadece Kullanc Tanml Tablolarn Listesi

Burada snrlandrc nesnemizin nasl tanmlandna dikkat edin. Bu tanmlama biraz kark
gelebilir. Ancak OleDbSchemaGuid zelliinin ald deere gre ema bilgileri zerinde bir
snrlama koymak istiyorsak, bu yenin kullanabilecei deerleri bilmemiz gerekir. Burada object
dizimizin son elemann TABLE deeri atanmtr. TABLE deeri ema bilgisine sadece kullanc
tarafndan tanmlanm tabolarn alnacan belirtir. Dier yandan bu drdnc elemana, ALIAS,
SYSTEM TABLE, VIEW, SYSTEM VIEW, SYNONYM, TEMPORARY, LOCAL TEMPORARY deerlerinide
verebiliriz. Hepsi, OleDbSchemaGuid.Tables parametresi sonucunda oluturulacak tablo ema
bilgilerinin yapsnda deitirecektir. rnein, SYSTEM TABLE deerini vermemiz halinde, Friends
tablosundaki system tablolarnn listesini elde etmi oluruz. Yada VIEW deerini verdiimizde
kullanc tanml grnm nesnelerinin listesini elde etmi olurduk.

Yukardaki rneimizde, veritabanmzda yer alan tablolara ait schema bilgilerini aldk. imdi ise
belirli bir tablonun stun bilgilerini almak istediimizi farzedelim. Burada stun bilgileri
iin, OleDbSchemaGuid.Columns parametresini kullanmamz gerekiyor. Bu durumda
snrlandrcmzda bu parametreye gre deitirmek durumundayz. Eer ilk rneimizdeki gibi null
deerini verirsek veritabanndaki tm tablolarn kolonlarna ait ema bilgilerini elde etmi oluruz.
Oysaki belirli bir tabloya ait alanlar iin ema bilgisi alcaksak,OleDbSchemaGuid.Columns

www.bsenyurt.com Page 2400


parametresinin snrlandrc koullarn deitirmemiz gerekecektir. te bu noktada snrlandrc
deikenimizin nc eleman olan TABLE_NAME elemann kullanrz. Bu amala kodlarmz
aadaki ekilde deitirmemiz yeterli olucaktr.

object[] objSinirlama;
objSinirlama=new object[]{null,null,"Kitap",null};
tblTabloListesi=con.GetOleDbSchemaTable(OleDbSchemaGuid.Columns, objSinirlama); /*
OleDbConnection nesnemizin, GetOleDbSchemaTable metodunu altryoruz. Bu kez, Columns
deeri sayesinde, snrlama nesnemizin nc elemannda belirttiimiz tablo adna ait alanlarn
listesini elde ediyoruz. */
foreach(DataRow dr in tblTabloListesi.Rows)
{
Console.WriteLine(dr["COLUMN_NAME"]);
}

ekil 3. Tablomuza ait alanlarn adlar.

Bylece Kitap isimli tablomuzun alanlarna ait schema bilgilerini elde etmi olduk. Bu rnekte ve bir
nceki rnekte dikkat ederseniz, DataTable nesnesindeki belirli bir alann deerini ekrana yazdrdk.
Bu rnekte, COLUMN_NAME, nceki rnekte ise, TABLE_NAME. Elbette elde ettiimiz ema
bilgilerinde sadece bu alanlar yer almyor. rnein Friends veritabanndaki kullanc tanml
tablolara ait baka ne tr bilgilerin emaya alndna bir bakalm. Bu amala, DataTable nesnemize
aktarlan ema bilgilerine ait satrlardaki tm alanlar bir dng ile gezmemiz yeterli olucaktr. Bunu
aadaki kodlar ile gerekletirebiliriz.

object[] objSinirlama;
objSinirlama=new object[]{null,null,null,"TABLE"};
tblTabloListesi=con.GetOleDbSchemaTable(OleDbSchemaGuid.Tables, objSinirlama);
foreach(DataRow dr in tblTabloListesi.Rows)
{
for(int i=0;i<=tblTabloListesi.Rows.Count;++i)
{
Console.Write(dr[i]);
Console.Write("---");
}
Console.WriteLine("");
}

www.bsenyurt.com Page 2401


ekil 4. emadaki dier bilgiler.

Bylece geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Data Form Wizard Yardmyla likili Tablo


Uygulamalarnn Hazrlanmas ( 09.02.2004 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Bu makalemizde, Visual Studio.NET ortamnda, Data Form Wizard yardmyla, veritaban


uygulamalarnn ne kadar kolay bir ekilde oluturulabileceini inceleyeceiz. Pek ok programc,
uygulamalarn gelitirirken sihirbazlar kullanmaktan aka kanr. Bunun bir nedeni, sihirbazlarn
ilemleri ok fazla kolaylatrmas ve programcy tembellie itmesidir. Gerektende, bir Data Form
Wizard yardmyla uzun srede programlayacanz bir veritaban uygulamsn inanlmaz ksa
srede tamamlayabilirisiniz. Dier yandan, bir programc iin bir uygulamay gelitirmekteki en
nemli unsur belkide u kelimenin arkasnda gizlidir; Kontrol.

Kontrol bir programc iin, uygulamann her yerinde hakim olmak demektir. Yazlabilecek her kodun
programc tarafndan yazlmas, olabilecek tm hatalarn dzeltilmesi, mantksal btnlklerin
salanmas ve kullancnn ihtiyalarna en st dzeyde cevap verilebilmesi, programcnn
kontroln glendiren unsurlar arasnda yer alr. Gerektende ben size, gerek hayatta sihirbazlar
ok fazla kullanmamanz tavsiye ederim. Hereyden nce, sihirbazlar tek dzelik salarlar ve
srekli ayn admlar atarlar. Bu bir sre sonra hem sizi tembelletirecek hemde gerek bir
programc gibi dnmekten rnein oluabilecek programatik hatalarn nceden sezilebilmesi
yeteninden mahrum brakacaktr.

Ancak tm bu olumsuzluklarn yannda, bir Data Form Wizard aracn kullanaraktan, .NET
ortamnda veritaban programlamasn renmeye alan bir programc iin, neler yaplabilecei? ,
bunlarn hangi temel admlarla gerekletirildii? , hatta Visual Studio.NET tarafndan otomatik
olarak oluturulan kodlarn nerelerde devreye girdii? gibi sorunlarn anlalmasda olduka kolay
olucaktr. Dier yandan profesyonel programclarda zaman zaman, sadece kendileri iin bir takm
verileri kolayca izleyebilmek amacyla yada ani mdahalelerde bulunmak amacyla oluturacaklar
uygulamalarda ayn kodlar tekrardan yazmak yerine sihirbazlar kullanmay tercih edebilirler.

www.bsenyurt.com Page 2402


Dolaysyla zaman zaman sihirbazlar kullanmak olduka ie yarayabilir ama bunu alkanlk
halinede getirmemek gerekir. te bu makalemizde, bir Ado.Net uygulamasnn, ilikili iki tablo iin
nasl kolayca oluturulabileceini incelyeceiz. Uygulamamz sona erdiinde, tablolar izleyebilecek,
ilikili kaytlar inceleyebilecek, yeni kaytlar ekleyebilecek, var olanlar dzenleyip silebilecek ve
kaytlar arasnda gezinebileceiz. Ayrca sihirbazmz, programatik olarak oluturulan Ado.Net
uygulamalarnda da hangi admlar takip edeceimiz hakknda bize klavuzluk etmi olucak. imdi
dilerseniz uygulamamz yazmaya balayalm. ncelikle Visual Studio ortamnda bir C# Windows
Uygulamas aalm. Daha sonra veritaban uygulamamz tayacak formu eklemek iin, Solution
sekmesinde, projemize sa tu ile tklayalm ve Add New Item esini seelim.

ekil 1. Add New Item.

Bu durumda karmza aadaki pencere gelecektir. Bu pencerede Data Form Wizard aracn
seelim. Data Form Wizard arac tm admlar bitirildikten sonra, projemize cs uzantl bir snf ve
bu snf kullanan bir Form ekleyecektir. Veritabanna balanlmas, tablolarn doldurulumas, satrlar
arasnda gezinme gibi pek ok ilevi yerine getiren metodlar, zellikler ve nesneler, Data Form
Wizard ile oluturulan bu snf ierisine yazlacaktr. Burada Form dosyanza anlaml bir isim
vermenizi neririm.

www.bsenyurt.com Page 2403


ekil 2. Data Form Wizard

Bundan sonra, artk uygulamay oluturacamz admlara gemi oluruz.

www.bsenyurt.com Page 2404


ekil 3. Admlara balyoruz.

lk admmz DataSet nesnemizin isimlendirilmesi. Bir DataSet, veritabanndan bamsz olarak


uygulamann alt sistemin belleinde oluturulan bir alana referans eden kuvvetli bir nesnedir.
Bir DataSet iersine, tablolar, tablolar aras ilikiler vb. ekleyebiliriz. Bir DataSet
ile, veritabanndanki gerekli veriler DataSet nesnesinin bellekte temsil ettii blgeye yklendikten
sonra bu veritabanna bal olmakszn alabiliriz. Dahada nemlisi, veritabanna bal olmakszn,
veriler ekleyebilir, verileri dzenleyebilir, silebilir, yeni tablolara, grnmler, ilikiler oluturabiliriz.
DataSet, ADO.NET 'in en nemli yeniliklerinden birisi olmakla birlikte, balantsz katman dediimiz
ksmn bir parasdr. DataSet'i ilerleyen makalelerimizde daha detayl olarak da inceleyeceiz. u
an iin bilmeniz gereken, oluturacamz DataSet'in Sql sunucumuzda (veya baka bir
databasede) yer alan ilikili tablolarmz ve aralarndaki ilikiyi ierecek olan balantsz ( ADO' daki
RecordSet gibi, Veritabanna srekli bir balanty gerektirmeyen ) bir nesne oluudur. imdi
burada uygulamaya nceden eklediimiz bir DataSet nesnesini seebileceimiz gibi yeni bir tanede
oluturabiliriz. Biz yeni bir DataSet oluturacamzdan, Creat a new database named alanna,
DataSet'imizin adn giriyoruz.

www.bsenyurt.com Page 2405


ekil 4. lk admmz DataSet nesnemizi belirleyeceimiz ad ile oluturmak.

Sradaki adm, veritabanna olan balantmz gerekletirecek nesnemizi tanmlayacak. Hereyden


nce DataSet nesnemize bir veritabanndan veriler ykleyeceksek, bir veri salaycs zerinden bu
verileri ekmemiz gerekecektir. te bu amala, pek ok ADO.NET nesnesi iin gerekli olan ve
belirtilen veri salaycs zerinden ilgili veri kaynana bir balant amamza yarayan bir balant (
Connection ) nesnesi kullanacaz. Burada uygulamamzda Sql Sunucumuzda yer alan veritabanna
OleDb zerinden erimek istediimiz iin, sihirbazmz bize bir OleDbConnection nesnesi rnei
oluturacaktr. Veri salaycsnn tipine gre, OleDbConnection, SqlConnection, OracleConnection,
OdbcConnection balant nesnelerini oluturabiliriz. New Connection seeneini seerek yeni bir
balant oluturmamz salayacak dier bir sihirbaza gei yapyoruz.

www.bsenyurt.com Page 2406


ekil 5. Connection nesnemizi oluturmaya balyoruz.

imdi karmzda Data Link Properties penceresi yer almakta. Burada, Provider ksmnda Microsoft
OLE DB Provider For Sql Server seenei seili olmaldr.

www.bsenyurt.com Page 2407


ekil 6. Provider.

Connection sekmesinde ise ncelikle balanmak istediimiz sql sunucusunun adn girmeliyiz. Sql
sunucumuz bu uygulamada, istemci bilgisayar zerinde kurulu olduundan buraya localhost
yazabiliriz. 2nci seenekte, sql sunucusuna log in olmamz iin gerekli bilgileri veriyoruz. Eer sql
sunucumuz windows authentication' kullanyorsa, Use Windows Integrated Security seeneini
seebiliriz. Bu durumda sql sunucusuna balanmak iin windows kullanc bilgileri kontrol
edilecektir. Bunun sonucu olarak username ve password kutucuklar geersiz klncakatr. Dier
yandan sql sunucusuna, burada oluturulmu bir sql kullanc hesab ilede eriebiliriz. Ben
uygulamamda sa kullancsn kullandm. Bildiiniz gibi sa sql kullancs admin yetkilerine sahip bir
kullanc olarak sql sunucusunun kurulmas ile birlikte sisteme default olarak yklenir. Ancak ilk
yklemede herhangibir ifresi yoktur. Gvenlik amacyla bu kullancya mutlaka bir ifre
verin.(Bunu sql ortamnda gerekletireceksiniz.) Allow Saving Password seeneini
iaretlemediimiz takdirde, uygulamay kim kullanyor ise, uygulama balatldnda sql sunucusuna
balanabilmek iin kendisinden bu kulllanc adna istinaden ifre sorulacaktr. Eer bu seenei
iaretlersek, program altrldnda buraya girilen ifre sorulmayacaktr. imdi 3nci seenee
geersek ve combo box kontroln aarsak sql sunucusunda yer alan veritabanlarnn tmn
grebiliriz. Buradan kullanacamz veritabann seeceiz.

www.bsenyurt.com Page 2408


ekil 7. Connection bilgileri giriliyor.

Dilersek Test Connection butonuna tklayarak, sql sunucusuna balanp balanamadmz


kontrolde edebiliriz. imdi OK diyelim ve Data Link Properties penceresini kapatalm. Bu durumda
karmza bir Login penceresi kacaktr. Bu az nce Allow Saving Password seeneini
iaretlemediimiz iin karmza gelmitir. ifremizi tekrardan girerek bu adm geiyoruz. Bu
durumda, sql sunucumuz iin gerekli balanty salyacak connection nesnemizde oluturulmu
olur.

ekil 8. Login penceresi.

Sradaki admmzda ise, uygulamamzda kullanacamz tablolar seeceiz. Bu admda,


balandmz veritabannda yer alan tablolar ve grnmler yer almaktadr. Biz hemen
ekleyeceimiz iki tabloyu seip pencerenin sa tarafnda yer alan Seleceted Item(s) ksmna
aktaryoruz. Bu tablolarn her biri birer DataTable nesnesi olucak ekilde DataSet nesnemize

www.bsenyurt.com Page 2409


eklenir. DataTable nesneleri tablolara ait bilgilerinin ve verilerinin bellekte yklendii belli bir alan
referans ederler. Bir DataSet nesnesi birden fazla DataTable ierebilir. Bylece veritaban ortamn
DataSet nesnesi ile uygulamann alt sistem belleinde simule etmi oluruz.

ekil 9. Tablolar seiliyor.

Bu iki tablomuz hakknda yeri gelmiken ksaca bilgi verelim. Sepetler tablosunda alveri
sepetlerine ait bilgiler yer alyor. Siparsler tablosu ise bu belirli sepetin iinde yer alan rnlerin
listesini tutuyor. Yani Sepetler tablosundan Siparisler tablosuna doru bire-ok iliki sz konusu. Bu
admda tamamladktan sonra, veri kaynana log in olmamz iin tekrar bir ifre ekran ile
karlacaz. Burayda getikten sonra sra, iki tablo arasndaki ilikiyi kuracamz adma geldi.
Burada aralarnda iliki oluturmak istediimiz tablolar ve ilgili kolonlar seerek ilikimiz iin bir
isim belirleyeceiz. Bunun sonucu olarak sihirbazmz bir DataRelation nesnesi oluturacak ve bu
nesneyi DataSet'e ekliyecek. Bylece veritabanndan bamsz olarak alrken, DataSet kmemiz
bu DataRelation nesnesini kullanarak tablolar arasndaki btnlde salam olucak. ncelikle bu
iliki iin anlmal bir ad belirleyin. ounlukla ilikinin hangi taboladan hangi tabloya doru
olduuna bal olunarak bir isimlendirme yaplr. Daha sonra Parent(Master) tablo ve Primary Key
seilir. Ardndan Foreign Key alann ieren tabloda, Child(Detail) tablo olarak seilir. Uyulamamzda
Sepetler tablosu ile Siparisler tablosu SepetID alanlar ile birbirlerine ilikilendirilmitir.

www.bsenyurt.com Page 2410


ekil 10. DataRelation nesnesi oluturuluyor.

Bir sonraki admmzda tablolarn hangi alanlarnn Form zerinde grntleneceini belirleriz.
Balang iin btn alanlar seili haldedir. Bizde bunu uygulamamzda bu halde brakacaz.

www.bsenyurt.com Page 2411


ekil 11. Grntlenecek Alanlarn Seilmesi.

Son adm ise, Formun tasarmnn nasl olacadr. stersek master tabloyu DataGrid kontrol iinde
gsterebiliriz. Ya da Master tabloya ait verileri balanm kontollerlede gsterebiliriz. Bunun iin
Single record in individual controls seeneini seelim. Dier seenekleride olduu gibi brakalm.

www.bsenyurt.com Page 2412


ekil 12. Son Adm. Formun grntsnn ayarlanmas.

Bylece Data Form Wizard yardmyla veritaban uygulamamz iin gerekli formu oluturmu olduk.
Karmza aadaki gibi bir Form kacaktr.

www.bsenyurt.com Page 2413


ekil 13. Formun son hali.

Grld gibi tm kontrolleri ile birlikte uygulamamz oluturulmutur. Sql sunucumuza Ole Db
veri salaycs zerinden erimemizi salyan OleDbConnection nesnemiz, tablolardaki verileri
DataSet nesnesine yklemek (Fill) ve bu tablolardaki deiiklikleri, veritabanna yanstmak
(update) iin kullanlan OleDbDataAdapter nesneleri, tablolar ve tablolar aras ilikiyi bellekte
sakayp veritabanndan bamsz olarak almamz salayan DataSet nesnemiz ve dierleri...
Hepsi sihirbazmz sayesinde kolayca oluturulmutur. Gelelim bu form ile neler yapabileceimize.

Her eyden nce uygulamamz altrdmzda hi bir kontrolde verilerin grnmediine ahit
olucaksnz. nce, veritabanndan ilgili tablolara ait verilerin DataSet zerinden DataTable
nesnelerine yklenmesi gerekir. Bu Fill olarak tanmlanan bir ilemdir. Load butonu bu ilemi
gerekletirir. Load balkl butonun koduna bakarasak;

private void btnLoad_Click(object sender, System.EventArgs e)


{
try
{
// Attempt to load the dataset.
this.LoadDataSet();
}
catch (System.Exception eLoad)
{
// Add your error handling code here.

www.bsenyurt.com Page 2414


// Display error message, if any.
System.Windows.Forms.MessageBox.Show(eLoad.Message);
}
this.objdsSatislar_PositionChanged();
}

Grld gibi kod LoadDataSet adl bir procedure'e ynlendirilir.

public void LoadDataSet()


{
// Create a new dataset to hold the records returned from the call to FillDataSet.
// A temporary dataset is used because filling the existing dataset would
// require the databindings to be rebound.
Wizard.dsSatislar objDataSetTemp;
objDataSetTemp = new Wizard.dsSatislar();
try
{
// Attempt to fill the temporary dataset.
this.FillDataSet(objDataSetTemp);
}
catch (System.Exception eFillDataSet)
{
// Add your error handling code here.
throw eFillDataSet;
}
try
{
grdSiparisler.DataSource = null;
// Empty the old records from the dataset.
objdsSatislar.Clear();
// Merge the records into the main dataset.
objdsSatislar.Merge(objDataSetTemp);
grdSiparisler.SetDataBinding(objdsSatislar, "Sepetler.drSepetlerToSiparisler");
}
catch (System.Exception eLoadMerge)
{
// Add your error handling code here.
throw eLoadMerge;
}
}

Bu metodda da ykleme ilemi iin bir DataSet nesnesi oluturulur veFillDataSet procedure' bu
DataSet'i parametre alarak arlr. Bu kodlarda ise OleDbDataAdapter nesnelerinin Fill metodlara
tablolara ait verileri, veritabanndan alarak DataTable nesnelerine yklerler. Bunu yaparken
OleDbDataAdapter nesneleri Select sorgularn kullanr. Bu sorgular, program iinde oluturulmu
SqlCommand nesnelerinde saklanmaktadr. Her bir tablo iin bir OleDbDataAdapter, bu tabodaki
verileri almak iin altraca bir Sql sorgusunu, bir SqlCommand nesnesinden alr.

www.bsenyurt.com Page 2415


public void FillDataSet(Wizard.dsSatislar dataSet)
{
// Turn off constraint checking before the dataset is filled.
// This allows the adapters to fill the dataset without concern
// for dependencies between the tables.
dataSet.EnforceConstraints = false;
try
{
// Open the connection.
this.oleDbConnection1.Open();
// Attempt to fill the dataset through the OleDbDataAdapter1.
this.oleDbDataAdapter1.Fill(dataSet);
this.oleDbDataAdapter2.Fill(dataSet);
}
catch (System.Exception fillException)
{
// Add your error handling code here.
throw fillException;
}
finally
{
// Turn constraint checking back on.
dataSet.EnforceConstraints = true;
// Close the connection whether or not the exception was thrown.
this.oleDbConnection1.Close();
}
}

Uygulamann dier butonlarna ilikin kodlarda incelediinizde hereyin otomatik olarak sihirbaz
tarafndan uygulandn greceksiniz. Uygulamann tm kodlarn ektekiDataForm1.cs dosyas
iinden inceleyebilirsiniz. imdi uygulamamz altralm ve grelim. Uygulamay altrdnzda
Form1'in ekrana geldiini ve DataForm1 in grnmediini greceksiniz. Bu durumu dzeltmek iin,
projenin balang formunu deitirmemiz gerekiyor.Bunun iin, Form1'in Main Procedure'nn
kodunu aadaki gibi deitirmemiz yeterlidir.

static void Main()


{
Application.Run(new DataForm1());
}

imdi uygulamamz altrabiliriz. Load balkl button kontrolne tkladmzda tablo verilerinin
ekrana geldiini ve kontrollere yklendiini greceksiniz. Yn kontrolleri ile Sepetler tablosunda
gezinirken DataGrid kontrolndeki verilerinde deitiine dikkatinizi ekmek isterim.

www.bsenyurt.com Page 2416


ekil 14.Uygulamann almasnn sonucu.

Dilerseniz veriler zerinde deiiklikler yapabilirsiniz. Ancak yaptnz bu deiiklilker bellekteki


DataSet kmesi zerinde gerekleecektir. Bu deiiklikleri eer, veritabannada yazmak isterseniz
Update balkl button kontrolne tklamanz gerekir. Bu durumda temel olarak, OleDbDataAdapter
nesnesi, DataSet zerindeki tm deiiklikleri alcak ve veritabann Update metodu ile
gncelleyecektir. Bu ilem iin OleDbDataAdapter nesnesinin Update metodu, UpdateCommand
zelliine bakar. UpdateCommand zellii, Update sorgusu ieren bir SqlCommand nesnesini
iaret eder. Bylece gncelleme ilemi bu komut vastasyla gerekleir. Bu ilemler yannda yeni
satrlar ekleyebilir, var olanlarn silebilirsiniz. Grld gibi komple bir veritaban uygulamas
oldu. Bunun dnda uygulamamzn gl ynleride vardr. rnein yeni bir Siparis girin. Ancak
Siparis numarasn aadaki gibi var olmayan bir SepetID olarak belirleyin.

www.bsenyurt.com Page 2417


ekil 15. Var olmayan bir ForeignKey girdik.

Bu durumda aadaki uyary alrsnz.

ekil 16. ForeignKeyConstraint durumu.

Bu durumda Yes derseniz buradaki deer otomatik olarak 1000 yaplr. te bu olay DataRelation
nesnemizin becerisidir. Deerli okurlarm uzun ama bir okadarda faydal olduuna inandm bir
makalemizin daha sonuna geldik. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Strongly Typed DataSet - 2 (Kuvvetle


Trlendirilmi Veri Kmeleri) ( 05.02.2004 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde, Kuvvetle Trlendirilmi Veri Kmelerinin ne olduunu ve nasl


oluturulduunu incelemitik. Bu makalemizde ise, bir trlendirilmi veri kmesi yardmyla satr
ekleme, arama, dzenleme ve silme gibi ilemlerin nasl yaplacan inceleyeceiz. Bu amala ie
basit bir windows uygulamas ile balyoruz. Bu uygulamamzda kolaylk olmas asndan Kuvvetle

www.bsenyurt.com Page 2418


Trlendirilmi Veri Kmemizi, Visual Studio.NET ortamnda oluturdum. Uygulamamzda, Makale
isimli sql tablomuzu kullanacaz. Uygulamamzn formu izleyen ekildeki gibi olucak.

ekil 1. Form Tasarmmz.

Kullanc, Ekle balkl butona tkladnda, textBox kontrollerine girmi olduu deerlerden oluan
yeni satrmz, dataTable'mza eklenmi olucak. Bu ilemi gerekletiren kodlar aada verilmitir.

private void btnEkle_Click(object sender, System.EventArgs e)


{
dsMakale.MakaleRow dr; /* Yeni bir satr tanmlanyor. MakaleRow bir DataRow tipidir ve bizim
dsMakale isimli Kuvvetle Trlendirilmi Veri Kmesi snfmzda yer almaktadr.*/
dr=mk.Makale.NewMakaleRow(); /* MakalNewRow ile dr isimli MakaleRow nesnemizin, Makale
isimli DataTable'mzda yeni ve bo bir satra referans etmesi salanyor. */
dr.Konu=txtKonu.Text; /* Veriler yeni satrmzn ilgili alanlarna yerletiriliyor. */
dr.Tarih=Convert.ToDateTime(txtTarih.Text);
dr.Adres=txtAdres.Text;
mk.Makale.AddMakaleRow(dr); /* Son olarak AddMakaleRow metodu ile oluturulan yeni satr
dataTable'mza ekleniyor.*/
}

Bu teknikte dikkat edicek olursanz Kuvvetle Trlendirilmi Veri Kmemize ait metodlar ve nesneler
kullanlmtr. rnein, bir DataTable nesnesi ile referans edilen bellek blgesindeki tabloya, yeni
bir satr eklemek iin ncelikle yeni bir DataRow nesnesi tanmlarz. Sonra bu DataRow nesnesini
bo bir satr olacak ekilde DataTable nesnemiz iin olutururuz. Daha sonra bu DataRow
nesnesinde her bir alan iin yeni verileri ekleriz. Son olarakta bu oluturulan yeni DataRow
nesnesini DataTable'mza ekleriz. Bylece, DataTable nesnemizin iaret ettii tabloya yeni bir satr

www.bsenyurt.com Page 2419


eklemi oluruz. Bu teknik klasik olarak Trlendirilmemi Veri Kmelerini kullandmz rneklerde
aadaki kodlar ile gerekletirimektedir.

DataRow drKlasik;
drKlasik=ds.Tables[0].NewRow();
drKlasik[1]=txtKonu.Text;
drKlasik[2]=Convert.ToDateTime(txtTarih.Text);
drKlasik[3]=txtAdres.Text;
ds.Tables[0].Rows.Add(drKlasik);

Grdnz gibi teknik olarak iki yaklamda ayndr. Ancak, aralarndaki fark anlamak iin
kullanlan ifadelere yakndan bakmamz yeterlidir. Hereyden nce Kuvvetle Trlendirilmi Veri
Kmelerini kullanmak, kod yazarken programcya daha anlalr gelmektedir. Dilerseniz, bu iki
teknii aadaki tablo ile karlatralm.

UnTyped Dataset Teknii Typed DataSet Teknii

Yeni Bir Satr Tanmlamak

dsMakale.MakaleRow dr;

DataRow drKlasik;

Grld gibi intelliSense zellii sayesinde,


dsMakale dataSet'inden sonra yeni bir
DataRow nesnesi oluturmak iin gerekli sz
dizimini bulmak ve anlamak son derece kolay.

Tanmlanan Yeni Satr Oluturmak

drKlasik=ds.Tables[0].NewRow();

dr=mk.Makale.NewMakaleRow();

www.bsenyurt.com Page 2420


Grld gibi, Typed DataSet snfmz
yardmyla tanmlanan yeni satr oluturmak
iin kullanacamz sz dizimi ok daha
okunakl ve anlaml.

Alanlara Verileri Aktarmak

dr.Konu=txtKonu.Text;

dr.Tarih=Convert.ToDateTime(txtTarih.Text
);

dr.Adres=txtAdres.Text;

drKlasik[1]=txtKonu.Text;

drKlasik[2]=Convert.ToDateTime(txtTarih.Text
);

drKlasik[3]=txtAdres.Text;

Bir Type DataSet zerinden oluturduumuz


DataRow nesnesinin alanlarna veri aktarrken
hangi alanlarn olduunu kolayca
gzlemleyebiliriz. stelik bu biim, kodumuza
daha kolay okunurluk ve anlam kazandrr.

Oluturulan Satrn Tabloya Eklenmesi

ds.Tables[0].Rows.Add(drKlasik); mk.Makale.AddMakaleRow(dr);

www.bsenyurt.com Page 2421


NewMakaleRow metoduna ulamak
grdnz gibi daha kolaydr.

Tablo 1. Trlendirilmi (Typed) ve Trlendirilmemi (UnTyped) Veri Kmelerinde Satr Ekleme


lemlerinin Karlatrlmas.

Her iki teknik arasnda kavramsal olarak fark bulunmamasna ramen, uygulanabilirlik ve kolaylk
asndan farklar olduunu gryoruz. Bu durum verileri ararken, dzenlerken veya silerkende
karmza kmaktadr. imdi uygulamamzda belli bir satr nasl bulacamz inceleyelim. Kullanc
Bul balkl butona tkladnda txtMakaleID textBox kontrolne girdii deerdeki satr bulunacak ve
bulunan satra ait alan verileri, formumuzdaki dier textBox kontrollerine yklencek. Arama
ileminin PrimaryKey zerinden yapldnda belirtelim. imdi kodlarmz yazalm.

private void btnBul_Click(object sender, System.EventArgs e)


{
dsMakale.MakaleRow drBulunan; /* Arama sonucu bulunan satr tutacak DataRow nesnemiz
tanmlanyor. */
drBulunan=mk.Makale.FindByID(Convert.ToInt32(txtMakaleID.Text)); /* FindByID metodu,
Trlendirilimi Veri Kmemizdeki tablomuzun Primary Key alan zerinden arama yapyor ve
sonucu drBulunan DataRow(MakaleRow) nesnemize atyor. */
if(drBulunan!=null) /* Eer aranan satr bulunursa drBulunan deeri null olmayacaktr. */
{
txtKonu.Text=drBulunan.Konu; /* Bulunan satra ait alan verileri ilgili kontrollere atanyor.
*/
txtTarih.Text=drBulunan.Tarih.ToString();
txtAdres.Text=drBulunan.Adres;
}
else
{
MessageBox.Show("Aranan Makale Bulunamad");
}
}

Bu arama tekniinin, trlendirilmemi veri kmelerindeki arama tekniine gre ok farkl bir zellii
vardr. Klasik yntemde bir DataTable zerinden arama yaparken Find metodunu kullanrz.

www.bsenyurt.com Page 2422


ekil 3. Klasik Find metodu.

Grld gibi Find metodu, PrimaryKey deerini alr ve bu deeri kullanarak, tablonun PrimaryKey
alan zeriden arama yapar. Oysa rneimizde kullandmz Trlendirilmi Veri Kmesine ait
Makale DataTable nesnesinin Find metodu isim deiikliine urayrak FindByID haline
dnmtr. Nitekim, bu yeni DataTable nesnesi hangi alann PrimaryKey olduunu bilir ve
metodun ismini buna gre deitirerek arama kodunu yazmamz son derece kolaylatrr.

ekil 4. FindByID metodu;

Dier yandan, Klasik Find metodumuz, key parametresini object trnden alrken, FindByID
metodumuz PrimaryKey alannn deeri ne ise, parametreyi o tipten alr. Buda FindByID
metodunun, klasik Find metodundanki object trnden dolay, daha performansl almasna
neden olur.

ekil 5. FindByID metodunda parametre tipi.

Dier yandan ayn ii yapan bu metodlar arasndaki fark birden fazla Primary Key alanna sahip
olan tablolarda daha ok belirginleir. Sz gelimi, Sql sunucusunda yer alan Northwind veri
tabanndaki, Order Details tablosunun hem OrderID alan hemde ProductID alan Primary Key'dir.
Dolaysyla bu iki alan zerinden arama yapmak istediimizde klasik Find metodunu aadaki
haliyle kullanrz.

DataRow drBulunan;
drBulunan = dt.Find(new objcet[]{10756,9);

Oysaki bu tabloyu Trlendirilmi Veri Kmesi zerinden kullanrsak kod satrlar aadakine
dnr.

drBulunan=ds.SiparisDetay.FindByOrderIDProductID(10756,9);

Gelelim verilerin dzenlenmesi ilemine. imdi uygulamamzda bulduumuz satra ait verileri
textBox kontrollerine aktarldktan sonra, zerlerinde deiiklik yaptmzda bu deiikliklerin
DataTable'mza nasl yanstacamza bakalm. Normal artlarda, Trlendirilmemi Veri Kmesi
zerindeki bir DataTable'a ait herhangibir satrda yaplan deiklikler iin, gncel DataRow
nesnesine ait BeginEdit ve EndEdit metodlar kullanlmaktadr. Oysaki Trlendirilmi Veri
Kmelerindenki satrlara ait alanlar birer zellik olarak tutulduklarndan, sadece bu zelliklere yeni
deerlerini atamamz yeterli olmaktadr. Bu veri kmesinin bir snf eklinde tutuluyor olmasnn

www.bsenyurt.com Page 2423


salam olduu gtr. Bu nedenle Trlendirilmi Veri Kmeleri Strongly taksn haketmektedir.
Dilerseniz uygulamamzda arama sonucu elde ettiimiz bir satra ait alan deerlerini
gncelleyeceimiz kod satrlarn yazalm.

private void btnDegistir_Click(object sender, System.EventArgs e)


{
drBulunan.Konu=txtKonu.Text;
drBulunan.Adres=txtAdres.Text;
drBulunan.Tarih=Convert.ToDateTime(txtTarih.Text);
}

imdi uygulamamz altralm. ID deeri 6 olan satr bulalm. Daha sonra bu satrdaki baz veileri
deitirelim ve Degistir balkl butona tklayalm. Deiikliklerin hemen gerekletiini ve DataGrid
kontrolnede yansdn grrz.

ekil 6. ID=6 olan satr bulunuyor.

www.bsenyurt.com Page 2424


ekil 7. Gncel Satr Verileri Deitiriliyor.

Son olarak satr silme ilemini inceleyelim. Bu amala RemoveMakaleRow metodunu kullanacaz.
Elbette bu metod, rneimizde oluturduumuz Kuvvetle Trlendirilmi Veri Kmemizin
snf iinde yeniden yazlm bir metoddur ve snfmz iindeki prototipide u ekildedir.

public void RemoveMakaleRow(MakaleRow row)


{
this.Rows.Remove(row);
}

Akas yapt ilem snfn Rows koleksiyonundan row parameteresi ile gelen satr kartmaktr.
Uygulamamzda ise bu metodu aadaki ekilde kullanrz.

private void btnSil_Click(object sender, System.EventArgs e)


{
mk.Makale.RemoveMakaleRow(drBulunan);
}

Bu metod parametre olarak ald satr tablodan kartr.

Bylece Kuvvetle Trlendirilmi Veri Kmeleri zerinden satr ekleme, arama, dzenleme ve silme
ilemlerinin nasl yaplacan incelemi olduk. Umuyorumki hepiniz iin faydal bir makale
olmutur. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2425


Strongly Typed DataSet - 1 (Kuvvetle
Trlendirilmi Veri Kmeleri) ( 04.02.2004 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde kuvvetle trlendirilmi veri kmelerinin ne olduunu ve nasl


oluturulduklarn incelemeye alacaz. Kuvvetle trlendirilmi veri kmelerini tanmlamadan
nce, aadaki kod satrnn incelemekle ie balayalm.

textBox1.Text=dsMakale1.Tables["Makale"].Rows[3]["Konu"].ToString();

Bu satr ile, dsMakale isimli dataSet nesnemizin bellekte iaret ettii veri blgesinde yer alan
DataTable'lardan Makale tablosuna iaret edenin, 4nc satrndaki Konu alannn deeri alnarak,
TextBox kontrolmzn text zelliine atanmaktadr. imdide aadaki kod satrn ele alalm.

textBox1.Text=rsMakale.Fields("Konu").Value

Bu ifade eski dostumuz ADO daki rsMakale isimli recordSet'i kullanarak, Konu isimli alann deerine
ulamtr. Dikkat edicek olursanz bu iki ifade arasnda uzunluk asndan belirgin bir fark vardr.
kinci yazm daha kolaydr. Zaten bu nedenle, ADO.NET'i renen programclarn ilk bata en ok
karlatklar zorluk, bu kod yazmnn uzunluu olmutur. Bununla birlikte, ADO.NET' in XML
tabanl bir mimariye sahip olmas, karmza Kuvvetle Trlendirilmi Veri Kmelerini karmaktadr.
Microsfot.NET mimarlar, programlarmzda aadakine benzer daha ksa ifadelerin kullanlabilmesi
amacyla, Kuvvetle Glendirilmi Veri Kmeleri kavramn ADO.NET'e yerletirmitir.

textBox1.Text=dsTypedMakale.Makale[3].Konu.ToString();

Bu ifade ilk yazdmz ifadeye gre ok daha ksadr. Peki bu nasl salanmtr. dsTypedMakale
isimli DataSet nesnemiz aslnda Kuvvetle Trlendirilmi Veri Kmemizin ta kendisidir. Bu noktada
Kuvvetle Trlendirilmi Veri Kmesi'nin ne olduunu tanmlayabiliriz.

Bir Strongly Typed DataSet ( Kuvvetle Trlendirilmi Veri Kmesi ), DataSet snfndan tretilmi,
programc tarafndan belirtilen bir xml schema snfn baz alan, veri balantlarnn zelletirilip
yukardaki gibi ksa yazmlar ile eriimlere imkan salayan, zelletirilmi bir DataSet snfdr.

Bu geni kavram anlamak iin elbette en kolay yol rneklendirmek olucak. Ancak bundan nce
Kuvvetle Trlendirilmi Veri Kmemizin nasl oluturacamz grelim. Bunun iin elimizde iki yol
var. Yollardan birisi, komut satrndan XSD.exe XML Schema Defination Tool'unu kullanmak. Bu yol
biraz daha zahmetli olmakla birlikte Visual Studio.NET'e olan gereksinimi kaldrd iin zaman
zaman tercih edilir. Dier yolumuz ise Kuvvetle Trlendirilmi Veri Kmemizi Visual Studio.NET
ortamnda oluturmak. Yollardan hangisini seersek seelim, Kuvvetle Trlendirilmi Veri
Kmemizin oluturulmas iin bize mutlaka bir xml schema dosyas (xsd uzantl) gerekiyor. nk
Kuvvetle Trlendirilmi Veri Kmemiz, bir xml schema dosyas baz alnarak oluturulmaktadr.
imdi dilerseniz komut satr yardmyla bir Kuvvetle Trlendirilmi Veri Kmesinin nasl
oluturulacan inceleyelim. Bunun iin ncelikle biraz kod yazmamz gerekecek. zleyen kodlar ile,
bir DataSet'i gerekli tablo bilgileri ile ykleyecek ve daha sonra bu DataSet'e ait xml schema

www.bsenyurt.com Page 2426


bilgilerini, DataSet snfna ait WriteXmlSchema metodu ile bir xsd dosyasna aktaracaz. rnein
basit olmas amacyla bir console uygulamas oluturalm.

using System;
using System.Data;
using System.Data.SqlClient;
namespace TypeDataSet2
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
SqlDataAdapter da=new SqlDataAdapter("Select * From Makale",conFriends);
DataSet dsMakale=new DataSet("Makaleler");
conFriends.Open();
da.FillSchema(dsMakale,SchemaType.Source,"Makale");
conFriends.Close();
dsMakale.WriteXmlSchema("Makaleler.xsd");
}
}
}

Yukardaki kodlar ksaca aklayalm. Burada Sql sunucumuzda yer alan Friends isimli veritabanna
balanyor ve Makale isimli tabloya ait schema bilgilerini DataSet nesnemize yklyoruz. Daha
sonra ise, DataSet nesnemizin WriteXmlSchema metodu ile, DataSet'in yapsn xml tabanl schema
dosyas olarak ( Makaleler.xsd ) sisteme kaydediyoruz. te Kuvvetle Trlendirimi Veri Kmemizi
bu xsd uzantl schema dosyas yardmyla oluturacaz. Sistemizde uygulamamz oluturduumuz
yerdeki Debug klasrne baktmzda, aadaki grnty elde ederiz.

ekil 1. XML Schema Dosyamz.

imdi .NET Framework'n XSD.exe aracn kullanarak, bu schema dosyasndan Kuvvetle


Trlendirilmi Veri Kmemizi temsil edicek snf oluturalm. Bunun iin, komut satrnda aadaki
satr yazarz.

www.bsenyurt.com Page 2427


ekil 2. Kuvvetle Trlendirilmi Veri Kmesi snfnn oluturulmas.

Burada grld gibi, xsd schema dosyamzdan, Kuvvetle Trlendirilmi Veri Kmesi snfmz
(Makaleler.cs) oluturulmutur. xsd aracndaki /d parametresi, snfmzn DataSet snfndan
tretileceini belirtmektedir. imdi Debug klasrmze tekrar bakcak olursak, Kuvvetle
Trlendirilmi Veri Kmesi snfmzn oluturulmu olduunu grrz.

ekil 3. Kuvvetle Trlendirilmi Veri Kmesi Snfmz.

Peki bu oluturduumuz Kuvvetle Trlendirilmi Veri Kmesi snfn uygulamamzda nasl


kullanacaz. Bu olduka basit. Yeni DataSet nesnemizi, Makaleler.cs snfndan treteceiz.
Aadaki kodu inceleyelim.

using System;
using System.Data;
using System.Data.SqlClient;
namespace TypeDataSet2
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
SqlDataAdapter da=new SqlDataAdapter("Select * From Makale",conFriends);
conFriends.Open();
Makaleler dsTypedMakale=new Makaleler(); /* Kuvvetle Trlendirilmi Veri Kmesi
snfmzdan bir DataSet nesnesi tretiyoruz.*/
da.Fill(dsTypedMakale.Makale); /* SqlDataAdapter nesnemiz yardmyla, yeni
dataSet'imizdeki Makale isimli tablomuzu Sql sunucumuzda yer alan Makale isimli tablonun verileri
ile yklyoruz. */
Console.WriteLine(dsTypedMakale.Makale[3].Konu.ToString()); /* Yeni DataSet

www.bsenyurt.com Page 2428


nesnemizdeki Makale tablosunun 4nc satrndaki Konu alannn deerine eriiyoruz. */
conFriends.Close();
}
}
}

Uygulamamz altrdmzda aadaki sonu elde ederiz.

ekil 4. Uygulamann sonucu.

Grld gibi bir Kuvvetle Trlendirilmi Veri Kmesi oluturmak ve kullanmak son derece basit.
Dilerseniz xsd arac ile oluturduumuz Makaleler.cs isimli Kuvvetle Trlendirilmi Veri Kmesi
snfmz ele alalm. Bu snf oluturduunuzda mutlaka incelemenizi tavsiye ederim. ok uzun bir
dosya olduunundan tm kod satrlarna burada yer vermiyorum. Ancak dikkatimizi ekicek bir ka
yeyi gstereceim. ncelikle snf tanmmza bir gz atalm.

public class Makaleler : DataSet


{
...
}

Daha ncedende sylediimiz gibi Kuvvetle Trlendirilmi Veri Kmesi snflar DataSet snfndan
tretilmektedir. Yeni dataSet snfmz, ierecei tablo, alan, kstlama, iliki gibi bilgileri bir xsd
dosyasndan almaktayd. Biz xsd dosyasn olutururken, DataSet'e Makale isimli tablonun yapsn
yklemitik. Bu durumda, Kuvvetle Trlendirilmi Veri Kmesi snfmz iinde, Makale isimli
tablomuzu belirten yeni bir DataTable yesi kullanlr.

private MakaleDataTable tableMakale;

Burada MakaleDataTable, DataTable snfnn zelletirilmi bir haline sunar.

protected Makaleler(SerializationInfo info, StreamingContext context)


{
string strSchema = ((string)(info.GetValue("XmlSchema", typeof(string))));
if ((strSchema != null))
{
DataSet ds = new DataSet();
ds.ReadXmlSchema(new XmlTextReader(new System.IO.StringReader(strSchema)));
if ((ds.Tables["Makale"] != null))
{
this.Tables.Add(new MakaleDataTable(ds.Tables["Makale"]));

www.bsenyurt.com Page 2429


}
...
}
...
public MakaleDataTable Makale
{
get
{
return this.tableMakale;
}
}
...

Grld gibi MakaleDataTable isminde yeni bir snfmz vardr. Bu snf Makale isimli tabloyu tm
elemanlar ile tanmlar. Bunun iin, bu snf DataTable snfndan tretilir. Makale tablosundaki her
bir alan bu snf ierisinde birer zellik haline gelir. Bununla birlikte bu yeni DataTable snf, alan
ekleme, alan silme gibi metodlar ve pek ok olayda tanmlar. Dier yandan pek ok DataTable
metoduda bu snf iinde override edilir.

public class MakaleDataTable : DataTable, System.Collections.IEnumerable


{
private DataColumn columnID;
private DataColumn columnKonu;
private DataColumn columnTarih;
private DataColumn columnAdres;
...
public int Count
{
get
{
return this.Rows.Count;
}
}
internal DataColumn IDColumn
{
get
{
return this.columnID;
}
}
public MakaleRow this[int index]
{
get
{
return ((MakaleRow)(this.Rows[index]));
}
}
public event MakaleRowChangeEventHandler MakaleRowChanged;

www.bsenyurt.com Page 2430


...
public void AddMakaleRow(MakaleRow row)
{
this.Rows.Add(row);
}
public MakaleRow AddMakaleRow(string Konu, System.DateTime Tarih, string Adres)
{
MakaleRow rowMakaleRow = ((MakaleRow)(this.NewRow()));
rowMakaleRow.ItemArray = new object[] {null,Konu,Tarih,Adres};
this.Rows.Add(rowMakaleRow);
return rowMakaleRow;
}
...
}

Buraya kadar , komut satr yardmyla ve kod yazarak bir Kuvvetle Trlendirilmi Veri Kmesinin
nasl oluturulacan grdk. Bu teknikteki admlar gzden geirmek gerekirse izlememiz gereken
yol yle olucaktr.

ekil 5. Kuvvetle Trlendirilmi Veri Kmesi Oluturulma Aamalar

imdide, Kuvvetle Trlendirilmi Veri Kmesi snfn, Visual Studio.NET ortamnda nasl
gelitireceimizi grelim. Bu daha kolay bir yoldur. ncelikle Visual Studio.Net ortamnda bir
Windows Uygulamas aalm. Daha sonra, Server Explorer penceresinden Makale isimli tablomuzu
Formumuza srkleyelim.

www.bsenyurt.com Page 2431


ekil 6. Server Explorer ile Makale Tablosunun Forma Alnmas

Bu durumda formumuzda otomatik olarak SqlConnection ve SqlDataAdapter nesnelerimiz oluur.

ekil 7. SqlConnection ve SqlDataAdapter otomatik olarak oluturulur.

imdi SqlDataAdapter nesnemizin zelliklerinden Generate DataSet'e tkladmzda karmza


aadaki pencere kacaktr.

www.bsenyurt.com Page 2432


ekil 8. DataSet oluturuluyor.

Burada DataSet nesnemiz otomatik olarak oluturulacaktr. DataSet'imize dsMakale adn verelim
ve OK balkl butona basalm. imdi Solution Explorer'da Show All Files seeneine tklarsak,
Kuvvetle Trlendirilmi Veri Kmesi snfmzn oluturulduunu grrz.

ekil 9. Kuvvetle Trlendirilmi Veri Kmesi

Artk uygulamamzda bu snf kullanabiliriz. te rnek kod satrlarmz.

private void Form1_Load(object sender, System.EventArgs e)

www.bsenyurt.com Page 2433


{

dsMakale mk=new dsMakale();

sqlDataAdapter1.Fill(mk.Makale);

textBox1.Text=mk.Makale[3].Konu.ToString();

Uygulamamz altrdmzda aadaki sonucu elde ederiz.

ekil 10. Uygulamann Sonucu.

Bu makalemizde, Kuvvetle Trlendirilmi Veri Kmelerinin ne olduunu, nasl oluturulacan ve


nasl kullanlacan grdk. zleyen makalemizde bu konuya devam edicek ve Satr Ekleme, Satr
Dzenleme, Satr Silme gibi ilemlerin nasl yaplacan inceleyeceiz. Hepinize mutlu gnler
dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Stored Procedureler ve ParameterDirection


Numaralandrcs ( 31.01.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, Sql sunucularnda yazdmz Stored Procedure'lere ilikin parametreleri


incelemeye alacaz. Stored Procedure'ler ile ilgili daha nceki makalelerimizde,
uygulamamzdan bu procedure'lere nasl parametre aktarlacan incelemitik. Parametre
aktarmnda yaptmz ilem, SqlCommand nesnesimizin parametre koleksiyonuna, Stored
Procedure iinde tanmladmz parametrenin eklenmesiydi. Bunun iin, SqlCommand snfnn
Parameters koleksiyonuna Add metodunu kullanarak SqlParameter snf trnden bir nesne
ekliyorduk. Bu parametrelere program ierisinden ilgili deerleri aktararak, bu deerlerin Stored
Procedure iinede aktarlmasna imkan salyorduk.

Bugnk makalemizde ise, bir Stored Procedure'den programmza nasl deer(ler)


dndrebileceimizi inceleyeceiz. Dikkat ederseniz, bir Stored Procedure'e program iinden

www.bsenyurt.com Page 2434


parametre aktarabileceimiz gibi, Stored Procedure'dende programmza deerler
aktarbildiimizden bahsediyoruz. Dolaysyla parametrelerin bir takm farkl davranlar
sergiliyebilmesi sz konusu. SqlParameters snf, parametrelerin davranlarn yada baka bir
deyile hangi yne doru hareket edeceklerini belirten bir zellik iermektedir. Bu zellik Direction
zelliidir ve C# prototipi aadaki gibidir.

public virtual ParameterDirection Direction {get; set;}

Direction zellii, ParameterDirection numaralandrcs tipinden deerler almaktadr. Bu deerlerin


aklamas aadaki tabloda yer almaktadr.

Direction Deeri Aklama

Bir SqlParametre'sinin varsaylan deeri budur. Program iinden Stored


Procedure'e deerler gnderilecei zaman, SqlParameter nesnesinin
Input Direction zellii Input olarak kullanlr. Yani parametre deerinin yn
Stored Procedure'e dorudur.

Stored Procedure'den programmza doru deer aktarm sz konusu ise


SqlParameter nesnesinin Direction deeri Output yaplr. Bu, parametre
Output ynnn, Stored Procedure'den programmza doru olduunu
gstermektedir.

Bazen bir Stored Procedure'n almas sonucunu deerlendirmek


iseyebiliriz. Bu durumda zellikle Stored Procedure'den Return anahtar
szc ile dndrlen deerler iin kullanlan parametrelerin Direction
ReturnValue deeri ReturnValue olarak belirlenir. Bu tip bir parametreyi, bir
fonksiyonun geri dndrd deeri iaret eden bir parametre olarak
dnebiliriz.

Bu durumda parametremiz hem Input hemde Output yetenklerine sahip


InputOutput olucaktr.

Tablo 1.ParameterDirection Numaralandrcsnn Deerleri.

Bugnk makalemizde arlkl olarak ReturnValue ve Output durumlarn incelemeye alacaz.


Dilerseniz ie ReturnValue ile balayalm. Bu rnekler iin, Makaleler ile ilgili bilgilere sahip olan bir
tablo kullanacaz. imdi sql sunucumuzda, bu tablo iin aadaki Stored Procedure nesnesini
oluturalm.

www.bsenyurt.com Page 2435


ekil 1. MakaleMevcutmu Stored Procedure'mz.

Bu Stored Procedure, programdan @MakaleID isimli bir parametre alyor. Bu parametreyi, SELECT
sorgusuna geiyor ve Makale tablosunda ID alan, @MakaleID parametresinin deerine eit olan
satr seiyor. Burada kullanlan @MakaleID parametresinin deeri program iinden belirlenecektir.
Dolaysyla bu parametremizin yn, programmzdan Stored Procedure'mze dorudur. Bu
nedenle, programmzda bu parametre tanmlandnda Direction deeri Input olmaldr. Ancak
bunu program iinde belirtmeyecek yani SqlParameter nesnesinin Direction zelliine aka
ParameterDirection.Input deerini atamayacaz. nk bir SqlParametresinin Direction zelliinin
varsaylan deeri budur.

Gelelim RETURN ksmna. Burada @@RowCount isimli sql anahtar kelimesi kullanyoruz. Bu anahtar
kelime Stored Procedure altrldktan sonra, Select sorgusu sonucu dnen satr saysn
vermektedir. If koulumuz ile, procedure iinden, bu select sorgusu sonucunun deerine bakyoruz.
Eer PrimaryKey olan ID alanmzda, @MakaleID parametresine atadmz deer mevcutsa,
@@RowCount, 1 deerini dndrecektir. Daha sonra, RETURN anahtar kelimesini kullanarak,
Stored Procedure'den programa deer dndryoruz. te bu deerler, programmzdaki
SqlParameter nesnesi iin, Direction zelliinin ParameterDirection.ReturnValue olmasn gerektirir.
rneimizi tamamladmzda bu durumu daha iyi anlayacanza inanyorum.

imdi aadaki Form tasarmmz yapalm ve kodlarmz yazalm. Program basit bir ekilde, bu
Stored Procedure'e kullancnn girdii Makale numarasn gnderecek ve sonuta bu makalenin var
olup olmadn bize belirtecek. Bu arada unuda belirtmekte fayda var. Bu tip bir ilemi elbette,
SqlCommand nesnesine, bir Select sorgusu girerek de gerekletirebilirdik. Ancak Stored
Procedure'lerin en nemli zelliklerinin, derlenmi sql nesneleri olduklar iin, saladklar
performans ve hz art kazanmlar olduunuda grmezden gelemeyiz. Bununla birlikte gvenlik

www.bsenyurt.com Page 2436


asndanda daha verimlidirler. zelliklede web uygulamalar iin. imdi Formumuzu tasarlayalm.
Bunun iin basit bir windows uygulamas gelitireceiz.

ekil 2. Form Tasarmmz.

private void button1_Click(object sender, System.EventArgs e)


{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi"); /* Sql sunucumuza olan balantmz gerekletiriyoruz. */
SqlCommand cmd=new SqlCommand("MakaleMevcutmu",conFriends); /* SqlCommand
nesnemizi oluturuyoruz. SqlCommand nesnemize, Stored Procedure'mzn adn parametre
olarak veriyoruz. */
cmd.CommandType=CommandType.StoredProcedure; /* SqlCommand nesnemiz bir Stored
Procedure altraca iin CommandType zellii CommandType.StoredProcedure olarak
belirlenir.*/
/* Burada, Stored Procedure'mzden Return ile dnen deeri iaret edicek SqlParameter
nesnemizi ,SqlCommand nesnemizin Parameters koleksiyonuna Add metodu ile ekliyoruz. Return
anahtar szc ile geri dnen deeri iaret edicek paramterenin ad herhangibir isim olabilir.
Ancak her sql parametresinde olduu gibi banda @ iaretini kullanmay unutmamalyz.*/
cmd.Parameters.Add("@DonenDeger",SqlDbType.Int);
cmd.Parameters["@DonenDeger"].Direction=ParameterDirection.ReturnValue; /*
Parametrenin, Stored Procedure'den, programa doru olduunu ve Return anahtar szc ile
geriye dnen bir deeri iaret ettiini belirtmek iin, Direction zelliine,
ParameterDirection.ReturnValue deerini veriyoruz.*/
/* Burada programmzda kullancnn girdii Makale numarasn, Stored Procedure'mze doru
gnderecek SqlParameter nesnemizi tanmlanyoruz. Bu parametre Input tipindedir. Bu nedenle,
adnn, Stored Procedure'mzdeki ile ayn olmasna dikkat etmeliyiz. */
cmd.Parameters.Add("@MakaleID",SqlDbType.Int);
cmd.Parameters["@MakaleID"].Value=txtMakaleNo.Text; /* Parametremizin deeri veriliyor.*/
/* Gvenli bloumuzda, ncelikle sql sunucumuza olan balantmz SqlConnection yardmyla
ayoruz ve ardndan SqlCommand nesnemizin referans ettii Stored Procedure nesnemizi
altryoruz.*/
try
{
conFriends.Open();
cmd.ExecuteNonQuery();
int Sonuc;
/* Stored Procedure'mzden Return anahtar szc ile dnen deeri @DonenDeger
SqlParameter nesnesi ile alyor ve sonuc ismindeki integer tipteki deikenimize atyoruz.
SqlCommand nesnesinin, Parameters koleksiyonunda yer alan SqlParameter nesnelerinin Value
zellii geriye Object tipinden deer dndrd iin, bu deeri integer tipine dntrme ilemide
uyguladmza dikkat edelim. */
Sonuc=Convert.ToInt32(cmd.Parameters["@DonenDeger"].Value);
/* Burada dnen deeri deerlendirerek kullancnn girdii ID'ye sahip bir Makale olup

www.bsenyurt.com Page 2437


olmadn belirliyoruz.*/
if(Sonuc==1)
{
MessageBox.Show("MAKALE BULUNDU...");
}
else if(Sonuc==0)
{
MessageBox.Show("MAKALE BULUNAMADI...");
}
}
catch(Exception hata)
{
MessageBox.Show("Hata:"+hata.Message.ToString());
}
finally
{
conFriends.Close(); /* Balantmz kapatyoruz. */
}
}

imdi progammz altralm ve bir ID deeri girelim. Bu noktada kullancnn girdii ID deeri,
@MakaleID isimli SqlParameter nesnemiz yardmyla, Stored Procedure'mze aktarlacak ve
Stored Procedure'n almas sonucu geri dnen deerde @DonenDeger isimli SqlParameter
nesnesi yardmyla uygulamamzda deerlendirilecek.

ekil 3. Programn almas Sonucu. Makale bulunduunda.

ekil 4. Makale bulunamadnda.

Elbette bu rnek bize pek bir ey ifade etmiyor. Nitekim makalenin var olup olmadnn farkna
vardk o kadar. Ama Makale tablosundaki belli alanlarda grmek istediimizi varsaylm. te bu,
Output tipindeki SqlParameter nesnelerini kullanmak iin gzel bir frsat. imdi bu Stored
Procedure nesnemizin sql kodunu biraz deitireceiz.

www.bsenyurt.com Page 2438


ekil 5. Output Tipi Sql Parametreleri.

Burada Select sorgusundaki @MakaleKonusu=Konu ifadesine dikkatinizi ekmek isterim. Eer


@MakaleID parametresinin deerinde bir Makale satr var ise, bu satrn Konu alannn deerini,
@MakaleKonusu isimli parametreye aktaryoruz. te bu parametre, programmza doru dnen
Output tipinde bir parametredir. Dier yandan Output parametrelerini kullanrken, sql yazm
iindede bu parametre deikeninin OUTPUT anahtar szc ile belirtilmesi gerekmektedir. Yeni
duruma gre program kodlarmz aadaki gibi olmaldr.

private void button1_Click(object sender, System.EventArgs e)


{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi");
SqlCommand cmd=new SqlCommand("MakaleMevcutmu",conFriends);
cmd.CommandType=CommandType.StoredProcedure;
cmd.Parameters.Add("@DonenDeger",SqlDbType.Int);
cmd.Parameters["@DonenDeger"].Direction=ParameterDirection.ReturnValue;
cmd.Parameters.Add("@MakaleKonusu",SqlDbType.NVarChar,255);
cmd.Parameters["@MakaleKonusu"].Direction=ParameterDirection.Output;
cmd.Parameters.Add("@MakaleID",SqlDbType.Int);
cmd.Parameters["@MakaleID"].Value=txtMakaleNo.Text;

www.bsenyurt.com Page 2439


try
{
conFriends.Open();
cmd.ExecuteNonQuery();
int Sonuc;
string MakaleAdi;
Sonuc=Convert.ToInt32(cmd.Parameters["@DonenDeger"].Value);
MakaleAdi=cmd.Parameters["@MakaleKonusu"].Value.ToString();
if(Sonuc==1)
{
MessageBox.Show("MAKALE BULUNDU...");
lblMakaleKonusu.Text=MakaleAdi;
}
else if(Sonuc==0)
{
MessageBox.Show("MAKALE BULUNAMADI...");
}
}
catch(Exception hata)
{
MessageBox.Show("Hata:"+hata.Message.ToString());
}
finally
{
conFriends.Close();
}
}

imdi uygulamamz altralm. Aadaki sonucu elde ederiz.

ekil 6. Makalemizin Konu isimli alannn deeri dndrld.

Deerli okurlarm. Geldik bir makalemizin daha sonuna. Umarm yararl bir makale olmutur.
Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2440


Tablo Deiikliklerini GetChanges ile zlemek (
29.01.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, balantsz olarak veri tablolar ile alrken, bu tablolar zerinde meydana
gelen deiiklikleri nasl izleyebileceimizi ve davranlarmz bu deiikliklere gre nasl
ynledirebileceimizi incelemeye alacaz.

Hepimizin bildii gibi, balantsz veriler ile alrken, bir veri kaynanda, makinemizin belleine
tablo veya tablolar alrz. Bu tablolar zerinde, yeni satrlar oluturur, var olan satrlar zerinde
deiiklikler yapar, her hangibir satr siler ve bunlar gibi bir takm ilemler gerekletiririz. Tm bu
ilemler, bellek blgesine aldmz veriler zerinde bir DataTable nesnesinde yada bir DataSet
kmesinde gerekleir. Bununla birlikte, bahsettiimiz bu deiiklikleri, asl veri kaynanada
yanstarak, gncellenmelerinide salarz.

Ancak, network trafiinin nemli ve youn olduu uygulamalarda, veri kaynandan aldmz bir
veri kmesinin zerindeki deiiklikleri, asl veri kaynana gncellerken karmza iki durum kar.
lk olarak, makinemizin belleinde bulunan tm veriler asl veri kaynana gnderilir ki bu veriler
iinde hi bir deiiklie uramam olanlarda vardr. Dier yandan istersek, sadece yeni eklenen
satrlar veya dzenlenen satrlar vb., veri kaynana gnderek daha aklc bir i yapm oluruz.
te makalemizin ana konusunu tekil eden bu ikinci durumu gerekletirebilmek iin GetChanges
metodunu kullanrz. GetChanges metodu, DataSet ve DataTable snflar iinde
kullanlabilmektedir. DataTable ve DataSet snflar iin, GetChanges metodunun ikier ar
yklenmi ekli vardr.

DataTable in DataSet in

public DataTable GetChanges(); public DataSet GetChanges();

public DataTable GetChanges(DataRowState ro public DataSetGetChanges(DataRowStatero


wStates); wStates);

Grld gibi her iki snf iinde metodlar ayn ekilde ilemektedir. Sadece metodlarn geri dn
tipleri farkldr. DataSet iin, GetChanges metodu baka bir DataSet geri dndrrken, DataTable'n
GetChanges metodu ise geriye DataTable trnden bir nesne referansn dndrr. Peki
GetChanges metodunun grevi nedir? GetChanges metodunun parametresiz kullanlan hali,
DataTable veya DataSet iin, AcceptChanges metodu arlana kadar meydana gelen tm
deiiklikleri alr. rnein bir DataTable nesnesinin referans ettii bellek blgesinde yer alan bir
veri kmesi zerinde, satr ekleme, satr silme ve satr dzenleme ilemlerini yaptmz
farzedelim. Bu durumda, bu DataTable nesnesi iin AcceptChanges metodunu arp tm
deiiklikleri onaylamadan nce, GetChanges metodunu kullanrsak, tablo zerindeki tm
deiiklikleri izleyebiliriz. Bunu daha iyi grmek iin aadaki rnei inceleyelim. Bu rnekte Sql
sunucumuz zerinde yer alan bir tablo verilerini DataTable nesnemizin bellekte referans ettii
blgeye yklyor ve verilerin grntsn DataGrid kontrolmze balyoruz. Programdaki nemli
nokta, GetChanges metodu ile meydana gelen deiiklikleri baka bir DataTable nesnemize
almamzdr. Bu DataTable nesnesinin verileride ikinci DataGrid kontrolmzde grntlenecektir.
Ancak kullanc, DataTable'da meydana gelen bu deiiklikleri DataTable nesnesinin AcceptChanges
metodunu kullanarak onayladnda, GetChanges geriye bo bir DataTable nesne referans
dndrecektir. Yani deiiklikleri, AcceptChanges metodu arlncaya kadar elde edebiliriz.
ncelikle aadaki Formu tasarlayalm.

www.bsenyurt.com Page 2441


ekil 1. Form Tasarmmz.

imdide program kodlarmz oluturalm.

SqlConnection conNorthwind; /*Sql sunucumuza yapcamz balanty salyacak SqlConnection


nesnemizi tanmlyoruz.*/
SqlDataAdapter daPersonel; /* Personel tablosundaki verileri, dtPersonel tablosuna yklemek iin
SqlDataAdapter nesnemizi tanmlyoruz.*/
DataTable dtPersonel; /* Personel tablosundaki verilerin bellek grntsn referans edicek
DataTable nesnemizi tanmlyoruz.*/
DataTable dtDegisiklikler; /* dtPersonel, DataTable nesnesi iin AcceptChanges metodu
uygulanana kadar meydana gelen deiikliklerin kmesini referans edicek DataTable nesnemizi
tanmlyoruz.*/
/* Kullanc bu butona bastnda, Sql sunucumuzdaki Personel tablosunun tm satlar, dtPersonel
DataTable nesnesinin bellekte iaret ettii alana yklenecek ve bu veriler DataGrid kontrolne
balanacak.*/
private void btnYukle_Click(object sender, System.EventArgs e)
{
conNorthwind=new SqlConnection("data source=localhost;initial catalog=Northwind;integrated
security=sspi");
daPersonel=new SqlDataAdapter("Select * From Personel",conNorthwind);
dtPersonel=new DataTable();
daPersonel.Fill(dtPersonel);
dgVeriler.DataSource=dtPersonel;
}
private void btnOnayla_Click(object sender, System.EventArgs e)
{
dtPersonel.AcceptChanges(); /* dtPersonel tablosunda meydana gelen deiiklikleri
onaylyoruz.*/
}

www.bsenyurt.com Page 2442


private void btnDegisiklikler_Click(object sender, System.EventArgs e)
{
dtDegisiklikler=new DataTable();
dtDegisiklikler=dtPersonel.GetChanges(); /* GetChanges metodu ile dtPersonel DataTable
nesnesinin iaret ettii bellek blgesinde yer alan veri kmesinde meydana gelen deiiklileri,
dtDegisiklikler DataTable nesnesinin bellekte referans ettii blgeye alyoruz. */
dgDegisiklikler.DataSource=dtDegisiklikler; /* Bu deiiklikleri DataGrid kontrolnde
gsteriyoruz. */
}

imdi programmz altralm ve tablomuzdaki veriler zerinde deiiklik yapalm. rnein yeni
bir satr girelim ve bir satr zerinde de deiiklik yapalm.

ekil 2. Yeni bir satr ekleyip bir satr zerinde deiiklik yaptk.

imdi Deiiklikleri Al balkl butona tkladmzda, GetChanges metodu devreye girecek ve


yaptmz bu deiikliklerin meydana geldii satrlar aadaki gibi , dtDegisiklikler DataTable
nesnesini baladmz DataGrid kontrolnde grnecek.

www.bsenyurt.com Page 2443


ekil 3. Yaplan Deiikliklerin Grnts.

imdi bu noktadan sonra, dtDegisiklikler isimli DataTable nesnesi zerinden, SqlDataAdapter


nesnesini Update metodunu kullanmak daha akllca bir yaklam olucaktr. Dier yandan,
GetChanges metodunun bu kullanm, DataTable(DataSet) de meydana gelen her tr deiiklii
almaktadr. Ancak dilersek, sadece yeni eklenen kaytlar ya da sadece deiiklik yaplan kaytlarda
elde edebiliriz. Bunu gerekletirmek iin, GetChanges metodunun DataRowState numaralandrcs
trnden parametre ald versiyonunu kullanrz. Bu parametre her bir satrn yani DataRow
nesnesinin durumunu belirtmektedir ve alabilecei deerler aadaki tabloda verilmitir.

DataRowState Aklama
Deeri

Added DataRowCollection koleksiyonuna yeni bir satr yani DataRow


eklenmi ve AcceptChanges metodu henz arlmamtr.

Deleted Delete metodu ile bir satr silinmitir.

Detached Yeni bir satr, DataRowCollection iin oluturulmu ancak henz


Add metodu ile bu koleksiyona dolaysyla DataTable'a
eklenmemitir.

Modified Satrda deiiklikler yaplm ve henz AcceptChanges metodu


arlmamtr.

Unchanged Son AcceptChanges arsndan bu yana, satrda herhangibir


deiiklik olmamtr.

Tablo 1. DataRowState Numaralandrcsnn Deerleri

www.bsenyurt.com Page 2444


imdi GetChanges metodunun, DataRowState numaralandrcs kullanlarak nasl altn
incelemeye alalm. Bunun iin aadaki rnek formu tasarlayalm. Bu kez programmzda,
deiiklik olan satrlar alcak ve bunlarn durumlarnda gsterecek bir uygulama oluturacaz.

ekil 4. Yeni Formumuz.

Formumuza bir ComboBox ekledik. Kullanc bu ComboBox'tan DataRowState deerini seicek ve


GetChanges metodumuz buna gre alacak. ComboBox'mzn eleri ise unlar olucak;

ekil 5. ComboBox elerimiz.

Uygulamamza sadece, Duruma Gre Deiiklikleri Al balkl butonumuzun kodlarn ekleyeceiz.

private void btDurumaGoreDegisiklikler_Click(object sender, System.EventArgs e)


{
dtDegisiklikler=new DataTable();
if(cmbRowState.SelectedIndex==0)
{
dtDegisiklikler=dtPersonel.GetChanges(DataRowState.Detached); /* Yeni alan ancak
henz DataRowCollection'a eklenmeyen satrlar.*/
dgDegisiklikler.DataSource=dtDegisiklikler;
}

www.bsenyurt.com Page 2445


else if(cmbRowState.SelectedIndex==1)
{
dtDegisiklikler=dtPersonel.GetChanges(DataRowState.Added); /* DataRowCollection'a yeni
eklenen satrlar.*/
dgDegisiklikler.DataSource=dtDegisiklikler;
}
else if(cmbRowState.SelectedIndex==2)
{
dtDegisiklikler=dtPersonel.GetChanges(DataRowState.Deleted); /* DataTable'dan silinen
satrlar.*/
dgDegisiklikler.DataSource=dtDegisiklikler;
}
else if(cmbRowState.SelectedIndex==3)
{
dtDegisiklikler=dtPersonel.GetChanges(DataRowState.Modified); /* Deiiklie urayan
satrlar. */
dgDegisiklikler.DataSource=dtDegisiklikler;
}
else if(cmbRowState.SelectedIndex==4)
{
dtDegisiklikler=dtPersonel.GetChanges(DataRowState.Unchanged); /* Son
AcceptChanges'den sonra deiiklie uramam satrlar.*/
dgDegisiklikler.DataSource=dtDegisiklikler;
}

imdi uygulamamz altralm ve deneyelim. Tablomuzda yine birtakm deiiklikler yapalm.


rnein satrlar ekleyelim, satrlar gncelleyelim (Satr eklemek ve satr gncellemek en ok
yaptmz ilemlerdir dikkat ederseniz). Sonrada ComboBox kontrolmzden istediimiz durumu
seip elde ettiimiz sonucu grelim. rnein ben yeni bir satr ekledim ve bir satr zerinde
deiiklik yaptm. Daha sonra sadece yeni eklenen satrlar grmek iin ComboBox kontrolnde
Yeni Ekelenen Satlar(Added) seeneini seip dmeye bastm. Bu durumda if koumuz durumu
deerlendirir ve GetChanges metodunu DataRowState.Added parametresi ile uygular. Sonu
olarak, deiiklik yaptm satr grnmez sadece yeni eklenen satr dtDegisiklikler tablosuna alnr.

www.bsenyurt.com Page 2446


ekil 6. DataRowState.Added Sonras.

Bu noktadan sonra artk bir veri tablosunu gncellerken, GetChanges yaklamn kullanarak,
rnein sadece yeni eklenen satrlarn veri kaynana gnderilmesini salam oluruz. Buda bize
daha hzl ve rahat bir a trafii salayacaktr. Bu durum zellikle web servisleri iin ok idealdir.
Uzak sunuculardan ilgili verileri bilgisayarna balantsz olarak ilemek iin alan bir istemci
uygulama, veri kmesinin tamamn geri gndermek yerine, sadece yeni eklenen veya gncellenen
satrlar temsil eden bir veri kmesini(dataTable veya DataSet) geri gndererek snrl internet
kapasitesi iin en uygun baarm elde edebilir.

Geldik bir makalemizin daha sonuna. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Indeksleyiciler (Indexers) ( 27.01.2004 ) - C#


Deerli Okurlarm, Merhabalar.

Bugnk makalemizde ksaca indeksleyicilerin C# programlama dilindeki kullanmn incelemeye


alacaz. Bir indeksleyici, bir snf dizi eklinde kullanabilmek ve bu snftan tretilen nesneleri
dizinleyebilmek amacyla kullanlr. Baka bir deyile bir indeksleyici, nesnelere dizi gibi
davranlabilmesini salar.

www.bsenyurt.com Page 2447


Indeksleyiciler tanmlanlar itibariyle, zelliklere (properties) ok benzerler . Ancak aralarnda
temel farkllklarda vardr. Hereyden nce bu benzerlik, indeksleyicilerin tanmlanmasnda gze
arpar. Bir indeksleyiciyi teorik olarak aadaki sz dizimi ile tanmlanr.

public int this[int indis]


{
get
{
// Kodlar
}
set
{
// Kodlar
}
}

Grld gibi bir indeksleyici tanmlanmas, zellik tanmlanmas ile neredeyse ayndr. Ancak bir
indeksleyici tanmlarken uymamz gereken bir takm kurallarda vardr. Bu kurallar aadaki
tabloda belirtilmitir.

Indeksleyici Kurallar

Bir indeksleyici mutlaka bir geri dn tipine sahip olmaldr. Yani


bir indeksleyiciyi void olarak tanmlayamayz.

Bir indeksleyiciyi static olarakta tanmlayamayz.

Bir indeksleyici en az bir parametre almaldr. Bununla birlikte, bir


indeksleyici birden fazla ve eitte parametrede alabilmektedir.

Indeksleyicileri ar ykleyebiliriz (Overload). Ancak bir


indeksleyiciyi ar yklediimizde, bu indeksleyicileri birbirlerinden
ayrrken ele aldmz imzalar sadece parametreler ile belirlenir.
Indeksleyicinin geri dn deeri bu imzada ele alnmaz.

Indeksleyici parametrelerine , normal deikenlermi gibi


davranamayz. Bu nedenle bu parametreleri ref ve out anahtar
szckleri ile ynlendiremeyiz.

Bir indeksleyici her zaman this anahtar szc ile


tanmlamalyz. Nitekim this anahtar szc , indeksleyicinin
kullanld snf nesnelerini temsil etmektedir. Bylece snfn

www.bsenyurt.com Page 2448


kendisi bir dizi olarak kullanlabilir.

Tablo 1. Indeksleyici tanmlama kurallar.

Indeksleyicileri siz deerli okurlarma anlatmann en iyi yolunun basit bir rnek gelitirmek
olduunu dnyorum. Dilerseniz vakit kaybetmeden rneimize geelim.

ncelikle bir snf tanmlayacaz. Bu snfmz, Sql veri tabannda oluturduumu Personel isimli
tablonun satrlarn temsil edebilecek bir yapda olucak. Tablomuz rnek olarak Personelimize ilikin
ID,Ad,Soyad bilgilerini tutan basit bir veri tablosu. Her bir alan, bahsetmi olduumuz snf iinde
birer zellik olarak tanmlanacak. Dier yandan baka bir snfmzda daha var olucak. Bu snfmz
ise, bir indeksleyiciye sahip olucak. Bu indeksleyiciyi kullanarak, veri satrlarn temsil eden snf
rneklerini, bu snf ierisinde tanmlayacamz object trnden bir dizide tutacaz. Sonu olarak
tablo satrlarna, snf dizi elemanlarym gibi eriebileceiz. Burada indeksleyiciler sayesinde
snfmza sanki bir diziymi gibi davrancak ve ierdii veri satrlarna indeks deerleri ile
eriebileceiz. rneimizi gelitirdiimizde konuyu daha iyi kavrayacanza inanyorum. imdi
dilerseniz bir console uygulamas aalm ve aadaki kodlar yazalm.

using System;
using System.Collections;
using System.Data.SqlClient;
namespace Indexers1
{
/* Tablomuzda yer alan satrlar temsil eden snfmz ve bu tablodaki her bir alan temsil
edicek zelliklerimizi tanmlyoruz. */
public class Personel
{
private int perid;
private string perad;
private string persoyad;
public int PerID
{
get
{
return perid;
}
set
{
perid=value;
}
}
public string PerAd
{
get
{
return perad;
}

www.bsenyurt.com Page 2449


set
{
perad=value;
}
}
public string PerSoyad
{
get
{
return persoyad;
}
set
{
persoyad=value;
}
}
}
/* PersonelListesi snfmz, Personel tipinden nesneleri tutucak Object trnden bir tanmlar. Bu
dizimizde, Personel snf trnden nesneleri tutacaz. Bu nedenle Object trnden tanmladk.
Ayrca snfmz bir indeksleyiciye sahip. Bu indeksleyici, object trnden dizimizdeki elemanlara
eriirken, bu snftan tretilen nesneyi bir diziymi gibi kullanabilmemize imkan salayacak. Yani
uygulamamzda, bu snftan bir nesne tretip nesneadi[indis] gibi bir satr yazdmzda buradaki
indis deeri, indeksleyicinin tanmland bloa aktarlcak ve get veya set bloklar iin kullanlacak.
Bu bloklar aldklar bu indis parametresinin deerini Object trnden dizimizde kullanarak, karlk
gelen dizi eleman zerinde ilem yaplmasna imkan salamaktadrlar.*/
public class PersonelListesi
{
private Object[] liste=new Object[10];
/* Indeksleyicimizi tanmlyoruz.*/
public Personel this[int indis]
{
get
{
/* liste isimli Object trnden dizimizin indis indeksli deerini dndrr. Bunu
dndrrken Personel snf tipinden dndrr. Bylece iligili elemandan Personel snfndaki
zelliklere, dolaysyla tablo alanlarndaki deere ulam oluruz. */
return (Personel)liste[indis];
}
set
{
/* liste isimli Object trnden dizimizdeki indis indeksli elemana value deerini
aktarr. */
liste[indis]=(Personel)value;
}
}
}
class Class1
{
static void Main(string[] args)

www.bsenyurt.com Page 2450


{
SqlConnection con=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=sspi");
SqlCommand cmd=new SqlCommand("Select * From Personel",con);
SqlDataReader dr;
con.Open();
dr=cmd.ExecuteReader();
PersonelListesi pliste=new PersonelListesi(); /* Indeksleyicimizi kullandmz snftan bir
nesne tretiyoruz. */
int PersonelSayisi=0;
int i=0;
try
{
/* SqlDataReader nesnesi ile, satrlarmz okurken bu satra ait alanlarn deerlerini
tutacak Personel tipinden bir snf nesnesi oluturulur ve ilgili alan deerleri bu nesnenin ilgili
zelliklerine atanr. */
while(dr.Read())
{
Personel p=new Personel();
p.PerID=(int)dr[0];
p.PerAd=dr[1].ToString();
p.PerSoyad=dr[2].ToString();
/* imdi PersonelListesi snf trnden nesnemize gncel satr temsil eden
Personel nesnesini atyoruz. Bunu yaparken bu snf rneine sanki bir diziymi gibi davrandmza
dikkat edelim. te bunu salayan indeksleyicimizdir. Burada PersonelListesi iindeki, object
trnden liste isimli dizideki i indeksli elemana p nesnesi aktarlyor. */
pliste[i]=p;
i+=1;
PersonelSayisi+=1;
}
/* Bu dngde, pliste isimli PersonelListesi trnden nesneye, i indeksini
kullanarak ierdii object trnden liste isimli dizi elemanlarna, tanmladmz indeksleyici
sayesinde bir dizi elemanna eriir gibi eriiyoruz. */
for(int j=0;j<PersonelSayisi;++j)
{
/* pliste'nin tretildii PersonelListesi snf indeksleyicisinin kulland dizi
elemanlarn Personel trne dntrerek elde ettiimiz iin, bu nesnenin zelliklerinede yani veri
satr alanlarnada kolayca eriebiliyoruz. */
Console.WriteLine(pliste[j].PerAd.ToString()+" "+pliste[j].PerSoyad.ToString()+"
"+pliste[j].PerID.ToString());
}
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
finally
{
dr.Close();

www.bsenyurt.com Page 2451


con.Close();
}
}
}
}

Kodlar size karmak gelebilir o nedenle aadaki ekil indeksleyicilerin kullanmn daha iyi
anlayabilmemizi salayacaktr.

ekil 1. Indeksleyicilerin Kullanm

Uygulamamzda pliste[i]=p; satr ile, Personel snf trnden nesnemiz, pliste isimli PersonelListesi
snfnn i indeksli eleman olarak belirleniyor. Bu satr derleyici tarafndan ilendiinde,
PersonelListesi snfndaki indeksleyicimizin set blou devreye girer. Set blou pliste[i] deki i
deerini indis parametresi olarak alr ve Object trnden liste isimli dizide indis indeksine sahip
elemana nesnemizi aktarr.

Dier yandan, pliste[j] ile PersonelListesi snfna eriildiinde, indeksleyicinin get blou devreye
girer. Get blounda, indeksleyicinin parametre olarak ald indis deeri j deeridir. Bu durumda,
liste[indis] ile, j indeksli liste dizisi eleman arlr. Sonra bu eleman Personel tipine dntrlr.
Bu sayedede pliste[j].PerAd.ToString() gibi bir ifade ile, bu nesnenin temsil ettii zellik deerinede
ulalabilir.

Uygulamamz altralm ve deneyelim. Aadaki ekran grntsn elde ederiz.

www.bsenyurt.com Page 2452


ekil 2. Uygulamann almasnn Sonucu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Sql Tablolarndaki Binary Resimlere Bakmak ve


Dosya Olarak Kaydetmek ( 24.01.2004 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Hatrlayacanz gibi bir nceki makalemizde, bir resim dosyasn sql tablosundaki Image veri
tipinden bir alana nasl yazabileceimizi grmtk. Bugnk makalemizde ise, bu tablodaki Image
veri tipindeki Resim alannda yer alan byte'lara nasl okuyabileceimizi ,( rneimizde, PictureBox
kontrolnde nasl grntleyebileceimizi inceledik) ve bu alandaki resmi, jpg uzantl bir resim
dosyas olarak nasl kaydedebileceimizi incelemeye alacaz.

Image tipindeki binary(ikili) bir alandan verileri okumak iin yine stream nesnelerinden ve
BinaryWriter snfndan faydalanacaz. Visual Studio.Net ortamnda, SqlClient isim uzayndaki
snflar kullanarak Wallpapers isimli sql tablomuza eritiimizde, PictureBox kontrolne , Image
tipindeki Resim alanmz balayamadmz grrz. Bu nedenle, bu ikili(binary) alan okuyup,
PictureBox kontrolmzn anlayaca bir hale getirmeliyiz.

Bu amala, bu iki alandaki veriyi okuyucak ve bunu bellekteki bir tampon blgeye alacaz . Daha
sonra bellekte oluturduumuz bu MemoryStream alann, System.Drawing.Image snfnn
FromStream metoduna parametre olarak vereceiz. Bylece, PictureBox kontrolmzn Image
zellii, resmin ieriini bellekteki bu tampon alandan okuyabilecek. Dolaysyla resmimiz
gsterilebilecek.

Ancak burada dikkat etmemiz gereken baka bir husus var. O da bu ikili alan nasl okuyacamz.
Bu alan ikili olarak okuyabilmek iin, SqlDataReader nesnesine SequentialAccess parametresini
vereceiz. Bu parametre SqlDataReader nesnesinin, verileri srasal bir ekilde okuyabilmesine
imkan salamaktadr. Normalde SqlDataReader okuduu veri satrn komple alr ve alanlarn
indeksleri sayesinde ilgili verilere ulalr. Bununla birlikte SqlDataReader nesnemizin sadece ileri
ynl ve yanlz okunabilir bir veri ak saladnda hatrladnz sanyorum. Bu srasal okuma
yetenei sayesinde, makalemize konu olan tablonun, Resim adndaki ikili alannn tm byte'larn
srasal bir ekilde okuyabilme ikmanna sahip olacaz.

www.bsenyurt.com Page 2453


Kullanacamz teknik ise biraz uzun bir kodlama gerektirmekle birlikte, pek ok konuyada aklk
getirmektedir. Yapacamz ilem udur. Sql tablomuzdan kullancnn setii satra ait Resim
alann bir SqlDataReader nesnesi ile elde etmek. Daha sonra, bu alanda srasal bir okuma balatp,
tm byte'lar, BinaryWriter nesnesi yardmyla bloklar halinde, bir MemoryStream nesnesine
aktarmak. Son olarakta PictureBox kontrolmze, bellekteki tampon blgede tutulan bu akm
aktararak resmin grntlenebilmesini salamak. MemoryStream nesneleri bellekte geici olarak
oluturulan byte dizilerine iaret eder. Dorudan bellekte oluturulduklar iin performans
asndanda yksek verimlilik salarlar. ounlukla programlarmzda oluturduumuz geici
dosyalar iin MemorStream olduka etkin bir yntemdir. Dier bir deyile programlarmzda geici
depolamalar yapmak iin idealdir.

Ayn teknik yardmyla, kullanc setii resmi bir dosya olarakta kaydedebilecek. Bu kez,
MemoryStream nesnesi yerine, fiziki bir dosyay temsil edicek FileStream nesnesini kullanacaz.
Bu konular biraz kark gibi grnsede, kodun iindeki detayl aklamalar sayesinde olay iyice
kafanzda canlandrabileceinize inanyorum. imdi dilerseniz uygulamamzn ekrann tasarlayalm
ve ardndan kodlarmz yazalm.

ekil 1. Form Tasarmmz.

SqlConnection conResim; /* SqlConnection nesnemizi tanmlyoruz. */


private void Form1_Load(object sender, System.EventArgs e)
{
conResim=new SqlConnection("data source=localhost;initial catalog=Northwind;integrated
security=sspi"); /* SqlConnection nesnemizi oluturuyor ve Norhtwind veritabanna balanyoruz.
*/
SqlDataAdapter daResim=new SqlDataAdapter("Select WallID,Yorum From
Wallpapers",conResim); /* Wallpapers tablosundan, WallID, ve Yorum alanlarnn deerlerini almak
ve bunlar SqlDataAdapter nesnemizin Fill metodu ile DataTable nesnemizin bellekte iaret ettii
alana aktarmak iin SqlDataAdapter nesnemizi oluturuyoruz. */
DataTable dtResim=new DataTable("Duvarlar"); /* DataTable nesnemizi oluturuyoruz.*/
daResim.Fill(dtResim); /* DataTable'nesnemizi select sorgusu sonucu elde edilen veri satrlar
ile dolduruyoruz. */
dgResim.DataSource=dtResim; /* DataGrid nesnemizi DataTable veri kaynamza balyoruz.
*/
}

www.bsenyurt.com Page 2454


/* Yaz balklk buton kontrolne tklandnda, kullancnn setii resim sistemimize, jpg uzantl
bir resim dosyas olarak kaydedilcektir.*/
private void btnYaz_Click(object sender, System.EventArgs e)
{
/* SqlDataReader nesnemiz, ileri ynl bir okuma salamak iin kullanlacak. */
SqlDataReader drResim;
int secilen;
/* Kullancnn dataGrid kontrolnde setii satrn, ilk stununu yani WallID deerini seiyoruz.
Bu deeri sql sorgumuzda, ilgili satra ait resim alann bulmak iin kullanacaz. */
secilen=System.Convert.ToInt32(dgResim[dgResim.CurrentCell.RowNumber,0].ToString());
/* Sql Sorgumuzu oluturuyoruz. Bu sorgu, seilen satra ait Resim alannn deerini elde
etmemizi salyacak.*/
string sqlStr="Select Resim From Wallpapers Where WallID="+secilen;
SqlCommand cmdResim=new SqlCommand(sqlStr,conResim); /* SqlCommand nesnemizi, sql
sorgumuz ve SqlConnection nesnemiz zerinden altrlmak zere oluturuyoruz. */
/* Eer SqlConnection'mz ak deilse ayoruz. Nitekim SqlCommand nesnesinin ierdii sql
sorgusunun altrlmas ak bir balanty gerektirmektedir. */
if(conResim.State!=ConnectionState.Open)
{
conResim.Open();
}
/* SqlDataReader nesnemizi, SqlCommand nesnemizin, ExecuteReader metodu ile
dolduruyoruz. CommandBehavior.SequentialAccess parametresi sayesinde, Resim alan zerinde
byte seviyesinde srasal bilgi okuma imkanna sahip oluyoruz. */
drResim=cmdResim.ExecuteReader(CommandBehavior.SequentialAccess);
/* Resim alanndaki byte'lar tayacak bir dizi oluturuyoruz. Bu dizinin boyutu 50. BinaryWrite
nesnemiz , FileStream nesnesinin iaret ettii dosyaya doru bu dizideki byte'lar aktcak. Yani
seilen Resim alanndaki byte'lar 50 byte'lk bloklar halinde okuyacaz ve bu dizileri srasyla,
BinaryWriter nesnemiz ile, sistemde yazmak zere oluturduumuz dosyaya aktaracaz. Burada
ben 50 byte'lk bloklar seimsel olarak ele aldm. Sizler bu bloklar, 100 byte'lk veya 25 byte'lk
veya istediiniz bir miktarda da kullanabilirsiniz. */
byte[] bytediziResim=new byte[50];
/* FileStream nesnemiz ile, BinaryWriter nesnesinin okuduu byte'lar yazcak dosyay
oluturuyoruz. Dosyamz sistemde daha nceden var olabilir. Bu durumda terkardan alp stne
yazlr. Yok ise bu dosya oluturulur.Dier yandan FileAccess.Write parametresi ile dosyay, yazmak
amacyla atmz belirtiyoruz. Burada deneme olsun diye Deneme.jpg isimli bir dosya oluturduk.
Ancak dilerseniz siz, bu dosya adna WallID alannn deerinide ekleyerek benzersiz dosyalar
oluturabilirsiniz. Veya kullancdan bir dosya ismi girmesini isteyebilirsiniz. Bunun gelitirilemesini
siz deerli okurlarma brakyorum. */
FileStream fs=new FileStream("c:\\Deneme.jpg",FileMode.OpenOrCreate,FileAccess.Write);
/* BinaryWriter nesnemiz, veri akn okuduu alandan, ald fs parametresinin belirttii
dosyaya doru balatyor. */
BinaryWriter bw=new BinaryWriter(fs);
long donenBytelar;
long baslangicIndeksi=0;
/* SqlDataReader nesnemizin dndrd satr okumaya balyoruz. Sorgumuzun sadece
Resim alannn deerini dndrdn hatrlayalm. */
while(drResim.Read())
{
/* imdi Resim alanndan ilk 50 byte'lk blm okuyoruz. GetBytes metodunun ald ilk
parametre, SqlDataReader'n dndrd veri kmesindeki Resim alannn indeks deeridir. kinci

www.bsenyurt.com Page 2455


parametre bu alann hangi byte'ndan itibaren okunmaya balayacadr. Balang iin 0'nc
byte'tan itibaren okumaya balyoruz. nc parametre okunan byte'larn hangi Byte disizine
yazlacan belirtir. Drdnc parametre bu dizi ierisine dizinin hangi indeksinden itibaren
yazlmaya balyacan ve beinci parametrede okunan byte'larn, bu dizi iinde ka byte'lk bir
alana yazlacan belirtiyor. */
donenBytelar=drResim.GetBytes(0,0,bytediziResim,0,50);
/* GetBytes metodu SqlDataReader nesnesinden okuyup, bytediziResim dizisine aktard
byte saysn geri dndrr. Bu dnen deeri donenBytelar isimli Long tipinde deikenimizde
tutuyoruz. Aadaki dngyle, okunan byte says 50'ye eit olduu srece, Resim alanndan 50
byte'lk bloklar okunmaya devam ediyor. Okundukada, BinaryWriter nesnemiz bu byte'lar
FileStream ile atmz dosyaya yazyor. Farz edelimki 386 byte'lk bir alana sahibiz. 350 byte
okunduktan sonra, kalan 36 byte'ta son olarak okunur ve bundan sonrada dngnde klm
olur.*/
while(donenBytelar==50)
{
bw.Write(bytediziResim);
bw.Flush();
baslangicIndeksi+=50;
donenBytelar=drResim.GetBytes(0,baslangicIndeksi,bytediziResim,0,50);
}
/* Bahsettiimiz 36 bytelk ksmda son olarak buradan yazlr. */
bw.Write(bytediziResim);
bw.Flush(); /* Flush metodu, BinaryWriter nesnesinin o an sahip olduu tampon hafzay
temizler. */
/* BinaryWriter nesnemiz ve FileStream nesnemiz kapatlyor. */
bw.Close();
fs.Close();
}
drResim.Close();
conResim.Close();
}
/* Setiimiz resmi PictureBox kontrolnde gstermek iini aadaki teknii kullanyoruz. Bu
teknikte bellekte geici bir tampon blgeyi MemoryStream nesnesi yardmyla oluturuyoruz. Bunun
dnda yaptmz ilemlerin tm, Yaz balkl butona uyguladmz kodlar ile ayn.*/
private void btnBak_Click(object sender, System.EventArgs e)
{
SqlDataReader drResim;
int secilen;
secilen=System.Convert.ToInt32(dgResim[dgResim.CurrentCell.RowNumber,0].ToString());
string sqlStr="Select Resim From Wallpapers Where WallID="+secilen;
SqlCommand cmdResim=new SqlCommand(sqlStr,conResim);
if(conResim.State!=ConnectionState.Open)
{
conResim.Open();
}
drResim=cmdResim.ExecuteReader(CommandBehavior.SequentialAccess);
byte[] bytediziResim=new byte[50];
MemoryStream ms=new MemoryStream();
BinaryWriter bw=new BinaryWriter(ms);
long donenBytelar;

www.bsenyurt.com Page 2456


long baslangicIndeksi=0;
while(drResim.Read())
{
donenBytelar=drResim.GetBytes(0,0,bytediziResim,0,50);
while(donenBytelar==50)
{
bw.Write(bytediziResim);
bw.Flush();
baslangicIndeksi+=50;
donenBytelar=drResim.GetBytes(0,baslangicIndeksi,bytediziResim,0,50);
}
bw.Write(bytediziResim);
pbResim.Image=System.Drawing.Image.FromStream(ms); /* Bellekteki tampon blgeye
aldmz, byte dizisini, PictureBox kontrolnde gstermek iin, Image snfnn FromStream
metodunu kullanyoruz. Bu metod parametre olarak ald akmdan gerekli byte'lar okuyarak,
resmin PictureBox kontrolnde gsterilebilmesini salyor. */
bw.Flush();
bw.Close();
ms.Close();
}
drResim.Close();
conResim.Close();
}

imdi uygulamamz altralm ve herhangibir resme bakalm. Sonrada bunu kaydedelim.

ekil 2: WallID deeri 1003 olan satrdaki Resim.

imdi Yaz balkl butona basp bu resmi sisteme fiziki bir dosya olarak kaydedelim. ekildende
grld gibi dosyamz sistemde oluturulmutur. Bu dosyaya tkladmzda resmimizi grebiliriz.

www.bsenyurt.com Page 2457


ekil 3. Fiziki dosyamz oluturuldu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Sql Tablolarna Resim Eklemek ( 23.01.2004 ) -


Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, rnek bir sql tablomuzda yer alan image veri tipinden bir alana, setiimiz
resim dosyalarn nasl kaydedebileceimizi incelemeye alacaz. ncelikle, sql tablolarnda
kullanabildiimiz image tipinden biraz bahsedelim. Bu tip, ikili (binary) formatta verileri tutmak iin
gelitirilmitir. Image veri tipi, 0 byte' dan 2,147,483,647 byte'a kadar veri alann
tayabilmektedir. Bu alan, verileri bir byte dizisi eklinde tutmaktadr. Dolaysyla resim dosyalarn
tutmak iin ideal bir yap sergiler. Elbette st snr amamaya almak gerekir. ou zaman
uygulamalarmzda, resim dosyalarn ikili bir dizi eklinde sql tablolarmzda, image tipindeki
alanlarda tutmak isteyeceimiz durumlar oluabilir. (rnein irket alanlar ile ilgili personel
bilgilerini tuttuumuz tablolarda, personelin vesikalk fotoraflarn bu alanlarda tadmz
dnelim.)

te imdi, bu tarz resim dosyalarn, sql tablolarmzdaki ilgili alanlara nasl yazabileceimizi
inceleyeceiz. Yapmamz gereken ilem aslnda son derece kolay. Resim dosyasn ikili formatta
okumak, dosyann okunan byte'larn bir byte dizisine aktarmak ve oluan bu diziyi, image tipindeki
alanmza aktarmak. Bu anafikir nda ilemlerimizi gerekletirebilmek iin, ncelikle dosyamz
bir FileStream nesnesine aacaz. Daha sonra, bir BinaryRead nesnesi kullanarak, FileStream
nesnesinin iaret ettii dosyadan tm byte'lar okuyacak ve bunlar bir byte dizisinee aktaracaz.
Sonrada oluturduumuz bu diziyi, sql tablomuzda yer alan image veri tipindeki alana koyacaz.

Uygulamamz gerekletirmeden nce, FileStream ve BinaryReader snflar hakknda da ksaca


bilgi verelim. FileStream nesnelerini, sistemimizde yer alan dosyalar okumak veya bu dosyalara
yazmak amacyla kullanrz. BinaryReader nesnesi, FileStream nesnesinden byte trnden bir ak
oluturmamz salar. BinaryReader, FileStream nesnesinin temsil ettii dosyadan, okumann
ynlendirilecei kaynaa doru bir akm oluturur. Bu ak sayesinde, FileStream nesnesinin temsil
ettii dosyadan verileri byte byte okuyabilir ve bir byte dizisine aktarabiliriz. Bunun nasl yapldn
rneimizi gelitirdiimizde daha iyi anlayacaz.

imdi dilerseniz, uygulamamz gelitirmeye balayalm. ncelikle, veri tablomuzu yapalm.


rnein, internetten indirip bilgisayarmzda bir klasrde topladmz gzel duvar katlarn

www.bsenyurt.com Page 2458


tablomuzada kaydetmek istediimizi varsayalm. Bununla ilgili olarak aadaki rnek tabloyu
oluturdum.

ekil 1. Wallpapers tablomuz

Sra geldi uygulamamzn ekrann tasarlamaya. Uygulamamzda kullanc, istedii resim dosyasn
seecek, bunu ayn zamanda ekranda yer alan bir PictureBox kontrolnde grebilecek ve bunu
isterse Wallpapers isimli sql tablomuza yazabilecek. te ekran tasarmmz.

ekil 2. Form Tasarmmz.

imdi uygulama kodlarmz yazmaya balayabiliriz.

string resimAdresi; /* OpenFileDialog kontrolnden setigimiz dosyanin tam adresini tutacak genel
bir degisken. */
/* Bu metodumuzda OpenFileDialog kontrolmzn temel ayarlarini yapiyoruz. */
public void DialogHazirla()
{
ofdResim.Title="Duvar Kagidini Se"; /* Dosya ama iletisim kutumuzun basligini belirliyoruz.
*/
ofdResim.Filter="Jpeg Dosyalari(*.jpg)|*.jpg|Gif dosyalari(*.gif)|*.gif"; /* Iletisim kutumuzun,
sadece jpg ve gif dosyalarini gstermesini, Filter zelligi ile ayarliyoruz.*/
}

www.bsenyurt.com Page 2459


private void Form1_Load(object sender, System.EventArgs e)
{
DialogHazirla();
}
private void btnResimSec_Click(object sender, System.EventArgs e)
{
/* Kullanici bu butona tikladiginda, OpenFileDialog kontrolmz, dosya ama iletisim kutusunu
aar. Kullanici bir dosya seip OK tusunda bastiginda, Picture Box kontrolmze seilen resim
dosyasi alinarak gsterilmesi salanr. Daha sonra seilen dosyanin tam adresi label kontrolmze
alnr ve resimAdresi degiskenimize atanr. */
if(ofdResim.ShowDialog()==DialogResult.OK)
{
pbResim.Image=System.Drawing.Image.FromFile(ofdResim.FileName); /* Drawing isim
uzayinda yer alan Image sinifinin FromFile metodunu kullanarak belirtilen adresteki dosya
PictureBox kontrol iine izilir. */
lblDosyaAdi.Text=ofdResim.FileName.ToString();
resimAdresi=ofdResim.FileName.ToString();
}
}
private void btnKaydet_Click(object sender, System.EventArgs e)
{
/* Simdi en nemli kodlarimizi yazmaya basliyoruz. ncelikle dosyamizi amamiz gerekli.
nk resim dosyasinin ierigini byte olarak okumak istiyoruz. Bu amala FileStream nesnemizi
olusturuyor ve gerekli parametrelerini ayarliyoruz. Ilk parametre, dosyanin tam yolunu belirtir.
Ikinci parametre ise dosyamizi amak iin kullanacagimizi belirtir. Son parametre ise dosyanin
okuma amaci ile aildigini belirtir. */
FileStream fsResim=new FileStream(resimAdresi,FileMode.Open,FileAccess.Read);
/* BinaryReader nesnemiz, byte dizimiz ile, parametre olarak aldigi FileStream nesnesi arasinda
, veri akisini saglamak iin olusturuluyor. Akim, FileStream nesnesinin belirttigi dosyadan,
dosyadaki byte'larin aktarilacagi diziye dogru olucaktir.*/
BinaryReader brResim=new BinaryReader(fsResim);
/* Simdi resim adinda bir byte dizisi olusturuyoruz. brResim isimli BinaryReader nesnemizin,
ReadBytes metodunu kullanarak, bu nesnenin veri akisi iin baglanti kurdugu FileStream
nesnesinin belirttigi dosyadaki tm byte'lari, byte dizimize akitiyoruz. Bylece resim dosyamizin
tm byte'lari yani dosyamizin kendisi, byte dizimize aktarilmis oluyor.*/
byte[] resim=brResim.ReadBytes((int)fsResim.Length);
/* Son olarak, BinaryReader ve FileStream nesnelerini kapatiyoruz. */
brResim.Close();
fsResim.Close();
/* Artik Sql baglantimizi olusturabilir ve sql komutumuzu alistirabiliriz. nce SqlConnection
nesnemizi olusturuyoruz. */
SqlConnection conResim=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=sspi");
/* Simdi sql komutumuzu alistiracak olan SqlCommand nesnemizi olusturuyoruz. Burada
alanlarin degerlerini parametreler zerinden aktardigimiza dikkat edelim. */
SqlCommand cmdResimKaydet=new SqlCommand("insert into Wallpapers (Yorum,Resim)
values (@yorum,@res)",conResim);
cmdResimKaydet.Parameters.Add("@Yorum",SqlDbType.Char,250).Value=txtYorum.Text; /*
Bu parametremiz @Yorum isminde ve Char tipinde. 250 karakter uzunlugunda. Hemen ayni satirda
Value zelligini kullanarak parametrenin degerinide belirliyoruz. */
cmdResimKaydet.Parameters.Add("@res",SqlDbType.Image,resim.Length).Value=resim; /*

www.bsenyurt.com Page 2460


Setigimiz resim dosyasinin byte'larini, tablodaki ilgili alana tasiyacak parametremizi belirtiyoruz.
Deger olarak, resim isimli byte dizimizi aktariyoruz. Parametre tipinin, image olduguna dikkat
edelim. */
/* Gnveli blogumuzda, Sql baglantimizi aiyoruz. Ardindan, sql komutumuzu
ExecuteNonQuery metodu ile alistiriyoruz. Son olarakta herhangibir hata olsada, olmasada, finally
blogunda sql baglantimizi kapatiyoruz.*/
try
{
conResim.Open();
cmdResimKaydet.ExecuteNonQuery();
MessageBox.Show(lblDosyaAdi.Text+" Tabloya Basarili Bir Sekilde Kaydedildi.");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message.ToString());
}
finally
{
conResim.Close();
}
}

imdi uygulamamz altralm ve tablomuzdaki Resim alanna yazmak iin bir resim seelim.

ekil 3. Resim Seilir.

imdi Kaydet butonuna tklayalm. Bu durumda aadaki mesaj alrz.

www.bsenyurt.com Page 2461


ekil 4. Resim image tipindeki alana kaydedildi.

Son olarak sql tablomuzda bu alanlarn nasl grndne bir bakalm.

ekil 5. Tablonun grnm.

Grdnz gibi, tablomuzda Resim adl image tipindeki alanmzda <Binary> yazmaktadr. Acaba
gerekten resmimiz bu alana dzgn bir ekilde kaydedildi mi? Bir sonraki makalemizde, bu kez
var olan image alanlarn, tablodan nasl okuyacamz ve bir dosyaya nasl kaydedebileceimizi
incelemeye alacaz. Umuyorumki hepiniz iin yararl bir makale olmutur. Bir sonraki
makalemizde grmek dileiyle mutlu gnler, iyi almalar dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Net Data Providers(Veri Salayclar) (


22.01.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemiz ile, ADO.NET ' te yer alan veri salayclarn inceleyeceiz. Bildiiniz gibi
hepimiz uygulamalarmzda youn bir ekilde veri kaynaklarn kullanmaktayz. Normalde
sistemimizde, bu veri kaynaklarna erimek iin kullanlan sistem srcleri vardr. Bu srcler,
sistemimize dll ktphaneleri olarak yklenirler ve kendilerini sisteme kayt ederler(register). Bu
noktadan itibaren bu veri srclerinin ierdii fonksiyonlar kullanarak veritabanlar zerinde
istediimiz ilemleri gerekletirebiliriz. Ksaca, bu veri srcleri uygulamalarmz ile, veritaban
arasndaki iletiimi salarlar. Sistemizide ykl olan programlara gre pek ok veri srcsne
sahip olabiliriz. rnein ODBC srcleri, SQL srcleri, Ole Db Jet srcleri ve bazlar.

ADO.NET ile veritaban uygulamalar gelitirirken, bu srcler zerinden veritabanlarna eriim


salarz. Bu sebeple .Net Framework 'te her bir veri srcs iin gelitirilmi veri salayclar
(data providers) vardr. Bu veri salayclarnn grevi, uygulamalarmz ile veri srclerini
balamak ve veri srclerindeki ilgili ktphane fonksiyonlarn altrarak veriler zerinde ilem
yapabilmemizi salamaktr. .Net Framework' n 1.1 srm aadaki listede yer alan veri
salayclar ile birlikte gelmektedir. .Net Framework'n ilk srmlerinde sadece Sql ve Ole Db veri
salayclar varsaylan olarak yer almaktadr. Ancak 1.1 srm ile birlikte bu veri salayclarna,
Oracle ve ODBC veri salayclarda eklenmitir.

www.bsenyurt.com Page 2462


.Net Framework Veri
Salayclar

Data Provider For SQL Server

Data Provider For OLE DB

Data Provider For ODBC

Data Provider For Oracle

Tablo 1: .NET Veri Salayclar

imdi dilerseniz, bu veri salayclar ksaca incelemeye alalm.

SQL veri salaycsna ait tm yeler, System.Data.SQLClient isim uzaynda yer almaktadr. SQL
veri salaycsnn en nemli zellii, sql motoruna direkt sql api'si zerinden eriim
salayabilmesidir. Bu zellik ona dier veri salayclarna gre daha yksek performans kazandrr.
Nitekim sql veri salaycs, sql server'a dorudan ulamak iin kendi iletiim protokol olan
TDS(Tabular Data Stream)'yi kullanmaktadr. Elbette bu zellii ile, rnein SqlDataReader
nesnesinin kullanld veri okuma yntemlerinde, ole db veri kaynana gre ok daha hzl ve
verimlidir. Nitekim ayn sql veri kaynaklarna ole db veri salaycs ilede erimemiz mmkndr.
Ama belirttiimiz gibi performans ve verimlilik bu iki veri kayna iin olduka farkldr.

ekil 1. Sql Veri Salaycmz.

Sql veri salaycs, Sql Server'n 7 ve daha st versiyonlarn desteklemektedir. Bu nedenle 6.5
versiyonu ve daha ncesi iin, Ole Db veri salaycsn kullanmak zorundayz. Dier yandan Sql
veri salaycs MDAC(Microsoft Data Access Component)'n 2.6 veya st srmnn sistemimizde
kurulu olmasn gerektirmektedir. Sql veri salaycs, sql server'n 7.0 ve sonraki srmlerinde
zellikle ok katl uygulamalarda yksek verim ve performans salar.

Ole Db veri salaycs, Ole Db destei veren tm veri srcleri ile iliki kurabilmektedir. Bunu
yaparken, Ole Db Com nesnelerini kullanr. Aadaki ekilde grld gibi, uygulamamzda ole db
veri salaycs kullanarak, bir oledb veri kaynana erimek olduka maliyetlidir. Bunun yannda ole
db'yi destekleyen ok eitli veri kayna srclerinin olmas ole db nin rn yelpazesini geniliini
gsterir.

www.bsenyurt.com Page 2463


ekil 2 . Ole Db Veri Salaycs

Ole Db veri salaycs Ole Db destei veren her trl veri srcs ile alabilir. Aada ole db
veri salaycs ile kullanlabilen rnek Ole Db veri srcleri listelenmitir.

Ole Db veri salaycsnn .net framework yeleri, System.Data.OleDb isim uzaynda yer alr.
ounlulkla bu veri salaycsn Access tablolarna erimek iin uygulamalarmzda kullanmaktayz.
Bununla bilrikte Paradox, dBASE, Excel, FoxPro,Oracle 7.3,Oracle8 gibi veri tablolarnada
eriebiliriz. Dier yandan Oracle srclerine ve ODBC srclerinede eriebiliriz. Ancak elbetteki,
ok katl uygulamalarda, sql veri salaycsn veya oracle veri salaycsn tercih etmemiz daha
doru olucaktr. Dier yandan ole db veri salaycs, com servsileri ile veri srclerine eritii iin,
zellikle sql veri salaycsna gre ok daha dk bir performans sergiler. Ole Db veri kaynaklar
ile alan ole db veri salaycsnn , zellikle sql server'n 6.5 ve nceki srmlerinin kullanld
tek katl ve ok katl uygulamalarda kullanlmas tercih edilir. Bununla birlikte, access tablolar ile
alrken, ok katl mimarilerin, bu veri tablolar zerinden ole db salayclar ile oluturulmas
microsoft otoriterlerince tavsiye edilmemektedir.

www.bsenyurt.com Page 2464


ODBC veri salaycs, Ole Db veri salaycs gibi, ODBC destei veren srcler ile, ODBC Servis
Component'lerini kullanarak iletiim kurar.

ekil 3 . ODBC Veri Salaycs

ODBC veri salaycs ile ilgili yeler, .net framework iinde, System.Data.Odbc isim uzaynda yer
almaktadr. Aslnda bu veri salayc, .net framework'n 1.0 versiyounda yer almamaktayd. Ancak
1.1 verisyonu ile birlikte ADO.NET ' teki yerini almtr. ODBC srcs yardmyla,sql server'a,
access tablolarna ve odbc'yi destekleyen veri srclerine eriebiliriz. ODBC veri salaycs, odbc
veri kaynaklar zerinden yaplan tek katl (single-tier) ve orta katl(middle-tier) mimarilerinde
kullanlabilir.

Oracle servis salaycs, .net framework'n System.Data.OracleClient isim uzaynda yer alan
yelerden oluur. Oracle servis salaycs, oracle veri kaynaklarna eriebilmek iin, sql veri
salaycs gibi kendi iletiim protokn ieren Oracle Client Connectivity'yi kullanr. Oracle veri
salaycsnn .net'e yerletirilmesindeki temel ama, oracle veri tabanlarna ole db veri salaycs
ile ole db zerinden deil, dorudan eriilebilmesini salamaktr. Bu sayede oracle veri kayna ile
oluturulan etkileimde en iyi performansn elde edilmesi salanmtr. Zaten bu yn ilede oracle
veri salaycs, sql veri salaycsna benzer bir yapdadr. Doal olarak, oracle veri kaynaklar
zerinde gerekletirilen, ok katl ve tek katl mimarilerde yksek performans sergilemektedir.

Bu makalemizde .net veri salayclarna ksaca deinmeye altk. lerliyen makalelerimiz ile
birlikte ado.net'in tm kavramlarn inclemeye alacam. Bir sonraki makalemde ole db veri
salaycs yelerinden olan, OleDbConnection nesnesini incelemeye alacam. Hepinize mutlu
gnler ve iyi almalar dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Temsilciler (Delegates) Kavramna Giri (


20.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, C# programlama dilinde ileri seviye kavramlardan biri olan


Temsilcileri(delegates) incelemeye balayacaz. Temsilciler ileri seviye bir kavram olmasna
ramen, her seviyden C# programcsnn bilmesi gereken unsurlardandr. Uygulamalarmz
temsilciler olmadan da gelitirebiliriz. Ancak bu durumda, yapamyacaklarmz, yapabileceklerimizin
nne geecektir. Dier yandan temsilcilerin kullanmn grdke bize getirecei avantajlar daha
iyi anlayacamz kansndaym. Bu makalemizde temsilcileri en basit haliyle anlamaya alcaz.

www.bsenyurt.com Page 2465


Temsilci (delegate), program ierisinde bir veya daha fazla metodu gsteren(iaret eden), referans
trnden bir nesnedir. Programlarmzda temsilciler kullanmak istediimizde, ncelikle bu
temsilcinin tanmn yaparz. Temsilci tanmlar, arayzlerdeki metod tanmlamalar ile neredeyse
ayndr. Tek fark delegate anahtar szcnn yer almasdr. Bununla birlikte, bir temsilci
tanmlandnda, aslnda iaret edebilecei metod(larn) imzalarnda belirlemi olur. Dolaysyla, bir
temsilciyi sadece tanmlad metod imzasna uygun metodlar iin kullanabiliceimizi syleyebiliriz.
Temsilci tanmlar tasarm zamannda yaplr. Bir temsilciyi, bir metodu iaret etmesi iin kullanmak
istediimizde ise, alma zamannda onu new yaplandrcs ile oluturur ve iaret etmesini
istediimiz metodu ona parametre olarak veririz. Bir temsilci tanm genel haliyle, aadaki
ekildeki gibidir.

ekil 1. Temsilci tanmlamas.

ekildende grld gibi, temsilciler aslnda bir metod tanmlarlar fakat bunu uygulamazlar. te
bu zellikleri ile arayzlerdeki metod tanlamalarna benzerler. Uygulamalarmzda, temsilci
nesneleri ile gstermek yani iaret etmek istediimiz metodlar bu imzaya sahip olmaldr. Bildiiniz
gibi metod imzalar, metodun geri dn tipi ve ald parametreler ile belirlenmektedir.

Bir temsilcinin tanmlanmas, onu kullanmak iin yeterli deildir elbette. Hereyden nce bir
amacmz olmaldr. Bir temsilciyi alma zamannda oluturabiliriz ve kullanabiliriz. Bir temsilci
sadece bir tek metodu iaret edebilecei gibi, birden fazla metod iin tanmlanm ve oluturulmu
temsilcileride kullanabiliriz. Dier yandan, tek bir temsilcide birden fazla temsilciyi toplayarak bu
temsilcilerin iaret ettii, tm metodlar tek bir seferde altrma lksnede sahibizdir. Ancak
temsilciler gerek anlamda iki amala kullanlrlar. Bunlardan birincisi olaylardr(events). Dier
yandan, bugnk makalemizde ileyeceimiz gibi, bir metodun alma zamannda, hangi
metodlarn altrlacana karar vermesi gerektii durumlarda kullanrz. Elbette bahsetmi
olduumuz bu amac, herhangibir temsilye ihtiya duymadan da gerekletirebiliriz. Ancak
temsilcileri kullanmadmzda, bize salad stn programlama teknii, kullanm kolayl ve
artan verimliliide gz ard etmi oluruz.

imdi dilerseniz bahsetmi olduumuz bu amala ilgili bir rnek verelim ve konuyu daha iyi
kavramaya alalm. rnein, personelimizin yapm olduu sat tutarlarna gre, prim hesab
yapan ve ilgili yerlere bu deiiklikleri yazan bir projemiz olsun. Burada primlerin hesaplanmas iin
deiik katsaylar, yaplan satn tutarna gre belirlenmi olabilir. rnein bu oranlar dk, orta
ve yksek olarak tanmlanm olsun. Personel hangi gruba giriyorsa, metodumuz ona uygun
metodu arsn. te bu durumda karar verici metodumuz, altrabilecei metodlar temsil eden
temsilci nesnelerini parametre olarak alr. Yani, alma zamannda ilgili metodlar iin temsilci
nesneleri oluturulur ve karar verici metoda , hangi metod altrlacak ise onun temsilcisi
gnderilir. Bylece uygulamamz altnda, tek yapmamz gereken hangi metodun altrlmas
isteniyorsa, bu metoda ilikin temsilcinin, karar verici metoda gnderilmesi olucaktr.

Olduka kark grnyor. Ancak rnekleri yazdka daha iyi kavrayacanza inanyorum. imdiki
rneimizde, temsilcilerin tasarm zamannda nasl tanmlandn, alma zamannda nasl

www.bsenyurt.com Page 2466


oluturulduklarn ve karar verici bir metod iin temsilcilerin nasl kullanlacan incelemeye
alacaz.

using System;
namespace Delegates1
{
public class Calistir
{
public static int a;
public delegate void temcilci(int deger); /* Temsilci tanmlamamz yapyoruz. Ayn zamanda
temsilcimiz , deer dndrmeyen ve integer tipte tek bir parametre alan bir metod tanmlyor.
Temsilcimizin ad ise temsilci.*/
/* imdi bu temsilciyi kullacanak bir metod yazyoruz. te karar verici metodumuz budur.
Dikkat ederseniz metodumuz parametre olarak, temsilci nesnemiz tipinden bir temsilci(Delegate)
alyor. Daha sonra metod blou iinde, parametre olarak geirilen bu temsilcinin iaret ettii metod
arlyor ve bu metoda parametre olarak integer tipte bir deer geiriliyor. Ksaca, metod iinden,
temsilcinin iaret ettii metod arlyor. Burada, temsilci tanmna uygun olan metodun arlmas
garanti altna alnmtr. Yani, programn almas srasnda, new yaplandrcs kulllanarak
oluturacamz bir temsilci(delegate), kendi metod tanm ile uyumayan bir metod iin
yaratlmaya alldnda bir derleyici hatas alacazdr. Dolaysyla bu, temsilcilerin yksek
gvenlikli iaretiler olmasn salar. Bu , temsilcileri, C++ dilindeki benzeri olan iaretilerden
ayran en nemli zelliktir. */
public void Metod1(Calistir.temcilci t)
{
t(a);
}
}
class Class1
{
/* IkKat ve UcKat isimli metodlarmz, temsilcimizin programn almas srasnda iaret
etmesini istediimiz metodlar. Bu nedenle imzalar, temsilci tanmmzdaki metod imzas ile ayndr.
*/
public static void IkiKat(int sayi)
{
sayi=sayi*2;
Console.WriteLine("IkiKat isimli metodun temsilcisi tarafindan
agirildi."+sayi.ToString());
}
public static void UcKat(int sayi)
{
sayi=sayi*3;
Console.WriteLine("UcKat isimli metodun temsilcisi tarafindan
agirildi."+sayi.ToString());
}
static void Main(string[] args)
{
/* Temsilci nesnelerimiz ilgili metodlar iin oluturuluyor. Burada, new yaplandrcs ile
oluturulan temsilci nesneleri parametre olarak, iaret edecekleri metodun ismini alyorlar. Bu
noktadan itibaren t1 isimli delegate nesnemiz IkiKat isimli metodu, t2 isimli delegate nesnemizde
UcKat isimli metodu iaret ediceklerdir. */

www.bsenyurt.com Page 2467


Calistir.temcilci t1=new Delegates1.Calistir.temcilci(IkiKat);
Calistir.temcilci t2=new Delegates1.Calistir.temcilci(UcKat);
Console.WriteLine("1 ile 20 aras deer girin");
Calistir.a=System.Convert.ToInt32(Console.ReadLine());
Calistir c=new Calistir();
/* Kullancnn Console penceresinden girdii deer gre, Calistir snfnn a isimli integer
tipteki deerini 10 ile karlatrlyor. 10 dan bykse, karar verici metodumuza t1 temsilcisi
gnderiliyor. Bu durumda Metod1 isimli karar verici metodumuz, kendi kod blou iinde t1 delegate
nesnesinin temsil ettii IkKat metodunu, Calistir.a deikeni ile aryor. Ayn ilem tarz t2
delegate nesnesi iinde geerli.*/
if(Calistir.a>=10)
{
c.Metod1(t1);
}
else
{
c.Metod1(t2);
}
}
}
}

Uygulamamz altralm ve bir deer girelim.

ekil 2. Programn almasnn sonucu.

Bu basit rnek ile umarm temsilciler hakknda biraz olsun bilgi sahibi olmusunuzdur. imdi
temsilciler ile ilgili kavramlarmza devam edelim. Yukardaki rneimiz nda temsilcileri
programlarmzda temel olarak nasl kullandmz aadaki ekil ile daha kolay anlayabileceimizi
sanyorum.

www.bsenyurt.com Page 2468


ekil 3. Temsilcilerin Karar Verici metodlar ile kullanm.

Yukardaki rneimizde, her bir metod iin tek bir temsilci tanmladk ve temsilcileri teker ardk.
Bu Single-Cast olarak adlandrlmaktadr. Ancak programlarmz da bazen, tek bir temsilciye birden
fazla temsilci ekleyerek, birden fazla metodu tek bir temsilci ile altrmak isteyebiliriz. Bu
durumda Multi-Cast temsilciler tanmlarz. imdi multi-cast temsilciler ile ilgili bir rnek yapalm. Bu
rneimizde t1 isimli temsilcimiz, multi-cast temsilcimiz olucak.

using System;
namespace Delegates2
{
public class temsilciler
{
public delegate void dgTemsilci(); /* Temsilcimiz tanmlanyor. Geri dn deeri olmayan
ve parametre almayan metodlar temsil edebilir. */
/* Metod1, Metod2 ve Metod3 temsilcilerimizin iaret etmesini istediimiz metodlar
olucaktr.*/
public static void Metod1()
{
Console.WriteLine("Metod 1 altrld.");
}
public static void Metod2()
{
Console.WriteLine("PI deeri 3.14 alnsn");
}

www.bsenyurt.com Page 2469


public static void Metod3()
{
Console.WriteLine("Mail gnderildi...");
}
/* Temsilcilerimizi altran metodumuz. Parametre olarak gnderilen temsilciyi, dolaysyla
bu temsilcinin iaret ettii metodu alyor. */
public static void TemsilciCalistir(temsilciler.dgTemsilci dt)
{
dt(); /* Temsilcinin iaret ettii metod altrlyor.*/
}
}
class Class1
{
static void Main(string[] args)
{
/* metodumuz iinde temsilci nesnelerimiz oluturuluyor .*/
temsilciler.dgTemsilci t1=new Delegates2.temsilciler.dgTemsilci(temsilciler.Metod1);
temsilciler.dgTemsilci t2=new Delegates2.temsilciler.dgTemsilci(temsilciler.Metod2);
temsilciler.dgTemsilci t3=new Delegates2.temsilciler.dgTemsilci(temsilciler.Metod3);
Console.WriteLine("sadece t1");
temsilciler.TemsilciCalistir(t1);
Console.WriteLine("---");
/* Burada t1 temsilcimize, t2 temsilcisi ekleniyor. Bu durumda, t1 temsilcimiz hem kendi
metodunu hemde, t2 temsilcisinin iaret ettii metodu iaret etmeye balyor. Bu halde iken
TemsilciCalistir metodumuza t1 temsilcisini gndermemiz her iki temsilcinin iaret ettii metodlarn
altrlmasna neden oluyor.*/
t1+=t2;
Console.WriteLine("t1 ve t2");
temsilciler.TemsilciCalistir(t1);
Console.WriteLine("---");
t1+=t3; /* imdi t1 temsilcimiz hem t1, hem t2, hem de t3 temsilcilerinin iaret ettii
metodlar iaret etmi olucak.*/
Console.WriteLine("t1,t2 ve t3");
temsilciler.TemsilciCalistir(t1);
Console.WriteLine("---");
t1-=t2; /* Burada ise t2 metodunu t1 temsilcimizden kartyoruz. Bylece, t1
temsilcimiz sadece t1 ve t3 temsilcilerini ieriyor. */
Console.WriteLine("t1 ve t3");
temsilciler.TemsilciCalistir(t1);
Console.WriteLine("---");
}
}
}

Uygulamamz altrdmzda aadaki sonucu elde ederiz.

www.bsenyurt.com Page 2470


ekil 4. Multi-Cast temsilciler.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde temsilcilerin kullanld
olaylar(events) kavramna gireceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Checked, Unchecked Anahtar Kelimeleri ve


OverFlow Hatas ( 15.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, deikenlerin ierdikleri verilerin birbirleri arasnda atanmas srasnda


oluabilecek durumlar incelemeye alacaz. Bildiiniz gibi, deikenler bellekte tutulurken,
tanmlandklar veri tipine gre belirli bir bit boyutuna sahip olurlar. Ayrca her deikenimizin belli
bir deer aral vardr. Programlarmz yazarken, ou zaman deikenleri birbirlerine atarz.
Kk boyutlu bir deikeni, kendisinden daha byk boyutlu bir deikene atarken bir problem
yoktur. Ancak, boyutu byk olan bir deikeni, daha kk boyuta sahip bir deikene atamak
istediimizde durum deiir. Elbette byle bir durumda, derleyicimiz bizi uyaracaktr. Ancak bilinli
olarak yani tr dntrme anahtar kelimelerini kullandmz durumlarda herhangibir derleyici
hatasn almayz. Bu konuyu daha iyi anlayabilmek, deikenleri tanmladmz trlere ait boyut
bilgilerinin iyi bilinmesini gerektirir. Bu amala aadaki tabloda, C# programlama dilinde
kullanlan deiken trlerini bulabilirsiniz.

Deiken
Boyut (Bit) Alt Aralk st Aralk
Tr

Byte 8 0 255

www.bsenyurt.com Page 2471


SByte 8 -128 127

Short 16 -32768 32767

UShort 16 0 65535

Int 32 -2,147,483,648 2,147,483,647

UInt 32 0 4,294,967,295

-
Long 64 9,223,372,036,854,775,807
9,223,372,036,854,775,808

ULong 64 0 18,446,744,073,709,551,615

Float 32 +/- 1.5 X 10^-45 +/- 3.4 X 10^38

Double 64 +/- 5 X 10^-324 +/- 1.7 X 10^308

Decimal 128 1 X 10^-28 7.9 X 10^1028

Char 16 - -

Bool - - -

Tablo 1. C# Deiken Trlerini Hatrlayalm.

Byk alanl deikenlerin, kk alanl deikenler iine alnmas srasnda neler olabilieceini
gzlemlemek amacyla aadaki rneimizi inceleyelim.

using System;
namespace checkedUnchecked
{
class Class1
{
static void Main(string[] args)
{
short degisken1=32760;
byte degisken2;
degisken2=(byte)degisken1;
Console.WriteLine("Short tipinden deikenimiz : {0}",degisken1);
Console.WriteLine("Short deikenimizi byte tipinden deikene aldk : {0}",degisken2);
}

www.bsenyurt.com Page 2472


}
}

Uygulamamzda, Short tipinde degisken1 isminde bir deikenimiz var. Deeri 32760. Short tipi
deiken trleri -32768 ile 32767 arasndaki deerleri alabilen saysal bir trdr. Degisken2 isimli ,
deikenimiz ise Byte trnden olmakla birlikte deer aral 0 ile 255 arasndadr. Kodumuzda
bilinli bir ekilde, (byte) dntrcs yardmyla, short trnden deikenimizi, byte trnden
deikenimize atyoruz. Bu kod hatasz olarak derlenecektir. Ancak, uygulamamz altrdmzda
karmza kacak olan sonu beklemediimiz bir sonu olucaktr.

ekil 2. Sonu artc m?

Grdnz gibi anlamsz bir sonu elde ettik. imdi gelin bunun nedenini ele alalm. ncelikle
degisken1 isimli short trnden deikenimizi ele alalm. Short tipi 16 bitlik bir veri alann temsil
eder. Degisken1 isimli veri tipimizin bellekte bitsel dzeyde tutulu ekli aadaki gibi olucaktr.

ekil 2. Short tipinden deikenimizin bellekte tutuluu.

imdi byte trnden tanmladmz deikenimizi ele alalm. Byte tr 8 bitlik bir veri trdr ve 0
ile 256 arasnda saysal deerler alr. degisken1 isimli short trnden deikenimizi, byte trnden
deisken2 deikenimiz iine almaya altmzda aadaki sonu ile karlarz.

www.bsenyurt.com Page 2473


ekil 3. Atama sonras.

Grld gibi 16 bitlik short tipi deikenin ilk 8 biti havaya umutur. nk, byte veri tipi 8
bitlik bir veri tipidir. Dolaysyla 16 bitlik bir alan, 8 bitlik alana sdrmaya altmzda veri kayb
meydana gelmi ve istemediimiz bir sonu ortaya kmtr. Elbette hibirimiz, yazdmz
programlarn almas srasnda bylesi mantk hatalarnn olmasn istemeyiz. Bu durumun en
gzel zmlerinden birisi, checked anahtar kelimesini kullanmaktr. Checked anahtar kelimesi,
uyguland bloktaki tm tr dnmlerini kontrol eder ve yukardaki gibi bir durum olutuunda,
OverFlow istisnasnn frlatlmasn salar. Yukardaki rneimizi imdide checked blou ile
altralm.

static void Main(string[] args)


{
short degisken1=32760;
byte degisken2;
checked
{
degisken2=(byte)degisken1;
}
Console.WriteLine("Short tipinden deikenimiz : {0}",degisken1);
Console.WriteLine("Short deikenimizi byte tipinden deikene aldk : {0}",degisken2);
}

Bu durumda uygulamamz altrdmzda aadaki sonucu elde ederiz.

ekil 4. OverFlow istisnasnn frlatlmas.

Derleyicimiz, checked anahtar kelimesinin kullanld bloktaki tm tr dnmlerini izlemeye alr.


Eer byk alanl bir deiken tr, kendisinden daha kk alanl bir deiken trne atanmaya
alrsa derleyici, OverFlow istisnasn frlatr. Bu bize, checked bloklarnn, try...catch...finally
bloklar ile kullanarak, kodumuzu dahada gvenli bir hale getirmemize imkan salar. Ne dediimizi
daha iyi anlayabilmek iin, yukarda yazdmz kodu aadaki gibi deitirelim.

static void Main(string[] args)


{
short degisken1=32760;
byte degisken2=0;
try
{
checked
{
degisken2=(byte)degisken1;

www.bsenyurt.com Page 2474


Console.WriteLine("Short tipinden deikenimiz : {0}",degisken1);
Console.WriteLine("Short deikenimizi byte tipinden deikene aldk : {0}",degisken2);
}
}
catch(System.OverflowException hata)
{
Console.WriteLine(hata.Message.ToString());
Console.WriteLine("Deiken 2 :{0}",degisken2.ToString());
}
}

Burada, checked blounu, try...catch...finally blou iine alarak, programn kesilemesinin de nne
gemi olduk. Bununla birlikte, checked anahtar kelimesinin bir dier zelliide, kontrol altna ald
blok iresinde oluabilecek tama hatalarnn sonucunda, tama hatasna maruz kalan deikenlerin
orjinal deerlerini korumasdr. rnein yukardaki rnekte, byte trndeki deikenimiz 248 deeri
yerine ilk atama yaptmz 0 deerini korumutur.

Dier yandan bazen, meydana gelebilecek bu tarz tama hatalrn grmezden gelerek, baz tr
atamalarnn mutlaka yaplmasn isteyebiliriz. Bu durumda unchecked bloklarn kullanrz. Bunu
daha iyi anlayabilmek iin, aadaki rneimize bir gz atalm.

static void Main(string[] args)


{
short degisken1=32760;
byte degisken2=0;
byte degisken3=0;
try
{
checked
{
unchecked
{
degisken3=(byte)degisken1;
Console.WriteLine("Kontrol edilmeyen degisken3 deeri: {0}",degisken3);
}
degisken2=(byte)degisken1;
Console.WriteLine("Short tipinden deikenimiz : {0}",degisken1);
Console.WriteLine("Short deikenimizi byte tipinden deikene aldk : {0}",degisken2);
}
}
catch(System.OverflowException hata)
{
Console.WriteLine(hata.Message.ToString());
Console.WriteLine("Deiken 2 :{0}",degisken2.ToString());
}
}

www.bsenyurt.com Page 2475


Uygulamamz altrdmzda, degisken3 isimli byte trnden deikenimiz iin, bilinli olarak
gerekletirdiimiz dnmn gerekletiini grebiliriz. Bunu salayan unchecked anahtar
kelimesidir. Dolaysyla oluacak OverFlow hatasnn grmezden gelindiini grrz.

ekil 5. Unchecked anahtar kelimesinin uygulanmasnn sonucu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Bir Arayz, Bir Snf ve Bir Tablo ( 14.01.2004 ) -


C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, bir arayz uygulayan snf nesnelerinden faydalanarak, bir Sql
tablosundan nasl veri okuyacamz ve deiiklikleri veritabanna nasl gndereceimizi
incelemeye alacaz. Gelitireceimiz rnek, arayzlerin nasl oluturulduu ve bir snfa nasl
uygulandn incelemekle yetinmeyecek, Sql veritabanmzdaki bir tablodaki belli bir kayda ait
verilerin bu snf nesnelerine nasl aktarlacan da ileyecek. Ksacas uygulamamz, hem
arayzlerin hem snflarn hemde Sql nesnelerinin ksa bir tekrar olucak.

ncelikle uygulamamzn amacndan bahsedelim. Uygulamamz bir Windows uygulamas eklinde


gelitireceiz. Kullanacamz veri tablosunda arkadalarmzla ilgili bir ka veriyi tutuyor olacaz.
Kullanc, Windows formunda, bu tablodaki alanlar iin Primary Key nitelii tayan bir ID deerini
girerek, buna karlk gelen tablo satrna ait verilerini elde edicek. stedii deiiklikleri yaptktan
sonra ise bu deiiklikleri tekrar veritabanna gnderecek. Burada kullanacamz teknik
makalemizin esas amac olucak. Bu kez veri tablosundan ekip aldmz veri satrnn programdaki
edeeri, oluturacamz snf nesnesi olucak. Bu snfmz ise, yazm olduumuz arayz
uygulayan bir snf olucak. Veriler snf nesnesine, satrdaki her bir alan deeri, ayn isimli zellie
denk gelicek ekilde yklenecek. Yaplan deiiklikler yine bu snf nesnesinin zelliklerinin sahip
olduu deerlerin veri tablosuna gnderilmesi ile gerekletirilecek.

Uygulamamzda, verileri Sql veritabanndan ekmek iin, SqlClient isim uzaynda yer alan
SqlConnection ve SqlDataReader nesnelerini kullanacaz. Hatrlayacanz gibi SqlConnection
nesnesi ile , balanmak istediimiz veritabanna, bu veritabannn bulunduu sunucu zerinden bir
balant tanmlyoruz. SqlDataReader nesnemiz ile de, sadece ileri ynl ve yanlz okunabilir bir
veri akm salayarak, aradmz kayda ait verilerin elde edilmesini salyoruz.

imdi uygulamamz gelitirmeye balayalm. ncelikle vs.net ortamnda bir Windows Application
oluturalm. Burada aadaki gibi bir form tasarlayalm.

www.bsenyurt.com Page 2476


ekil 1. Form tasarmmz.

Kullanc bilgilerini edinmek istedii kiinin ID'nosunu girdikten sonra, Getir balkl butona
tklayarak ilgili satrn tm alanlarna ait verileri getirecek. Ayrca, kullanc veriler zerinde
deiiklik yapabilecek ve bunlarda Gncelle balkl butona tklayarak Sql veritabanndaki
tablomuza aktarabilecek. Sql veritabannda yer alan Kisiler isimli tablomuzun yaps aadaki
gibidir.

www.bsenyurt.com Page 2477


ekil 2. Tablomuzun yaps.

imdi gelelim iin en nemli ve anahtar ksmlarna. Program kodlarmz. ncelikle arayzmz
tasarlayalm. Arayzmz, sonra oluturacamz snf iin bir rehber olucak. Snfmz, veri
tablomuzdaki alanlar birer zellik olarak tayacana gre arayzmzde bu zellik tanmlarnn
yer almas gerektiini syleyebiliriz. Ayrca ilgili kiiye ait verileri getirecek bir metodumuzda
olmaldr. Elbette bu arayze baka amalar iin ye tanmlamalarda ekleyebiliriz. Bu konuda tek
snr bizim hayal gcmz. in gerei bu makalemizde hayal gcm biraz ksdm konunun daha
fazla dalmamas amacyla :) . (Ama siz, rnein kullancnn yeni girdii verileri veritabanna
yazcak bir metod tanmnda bir ye olarak ekleyebilir ve gerekli kodlamalar yapabilirsiniz.) te
arayzmzn kodlar.

public interface IKisi


{
/* ncelikle tablomuzdaki her alana karlk gelen zellikler iin tanmlamalarmz yapyoruz.*/
int KisiID /* KisiID, tablomuzda otomatik artan ve primary key olan bir alandr. Dolaysyla
programcnn var olan bir KisiID'sini deitirmemesi gerekir. Bu nedenle sadece okunabilir bir
zellik olarak tanmlanmasna izin veriyoruz. */
{
get;
}
string Ad /* Tablomuzdaki char tipindeki Ad alanmz iin string tipte bir alan.*/
{
get;set;
}
string Soyad
{
get;set;
}
DateTime DogumTarihi /* Tablomuzda, DogumTarihi alanmz datetime tipinde olduundan,
DateTime tipinde bir zellik tanmlanmasna izin veriyoruz.*/
{
get;set;
}
string Meslek
{
get;set;
}
void Bul(int KID); /* Bul metod, KID parametresine gre, tablodan ilgili satra ait verileri alcak
ve alanlara karlk gelen zelliklere atayacak metodumuzdur.*/
}

imdide bu arayzmz uygulayacamz snfmz oluturalm. Snfmz IKisi arayznde


tanmlanan her yeyi uygulamak zorundadr. Bu bildiiniz gibi arayzlerin bir zelliidir.

public class CKisi:IKisi /* IKisi arayzn uyguluyoruz.*/


{
/* ncelikle snftaki zelliklerimiz iin, verilerin tutulaca alanlar tanmlyoruz.*/
private int kisiID;

www.bsenyurt.com Page 2478


private string ad;
private string soyad;
private DateTime dogumTarihi;
private string meslek;
/* Arayzmzde yer alan yeleri uygulamaya balyoruz.*/
public int KisiID
{
get{ return kisiID;}
}
public string Ad
{
get{return ad;}set{ad=value;}
}
public string Soyad
{
get{return soyad;}set{soyad=value;}
}
public DateTime DogumTarihi
{
get{return dogumTarihi;}set{dogumTarihi=value;}
}
public string Meslek
{
get{return meslek;}set{meslek=value;}
}
public void Bul(int KID)
{
/* ncelikle Sql Veritabanmza bir balant ayoruz.*/
SqlConnection conFriends=new SqlConnection("data source=localhost;integrated
security=sspi;initial catalog=Friends");
/* Tablomuzdan, kullancnn bu metoda parametre olarak gnderdii KID deerini baz
alarak, ilgili KisiID'ye ait verileri elde edicek sql kodunu yazyoruz.*/
string sorgu="Select * From Kisiler Where KisiID="+KID.ToString();
/* SqlCommand nesnemiz yardmyla sql sorgumuzu altrlmak zere hazrlyoruz.*/
SqlCommand cmd=new SqlCommand(sorgu,conFriends);
SqlDataReader rd;/* SqlDataReader nesnemizi yaratyoruz.*/
conFriends.Open(); /* Balantmz ayoruz. */
rd=cmd.ExecuteReader(CommandBehavior.CloseConnection); /* ExecuteReader ile sql
sorgumuzu altryoruz ve sonu kmesi ile SqlDataReader nesnemiz arasnda bir akm(stream)
ayoruz. CommandBehavior.CloseConnection sayesinde, SqlDataReader nesnemizi kapattmzda,
SqlConnection nesnemizinde otomatik olarak kapanmasn salyoruz.*/
while(rd.Read())
{
/* Eer ilgili KisiID'ye ait bir veri satr bulunursa, SqlDataReader nesnemizin Read
metodu sayesinde, bu satra ait verileri snfmzn ilgili alanlarna aktaryoruz. Bylece, bu alanlarn
atand snf zellikleride bu veriler ile dolmu oluyor.*/
kisiID=(int)rd["KisiID"];
ad=rd["Ad"].ToString();
soyad=rd["Soyad"].ToString();

www.bsenyurt.com Page 2479


dogumTarihi=(DateTime)rd["DogumTarihi"];
meslek=rd["Meslek"].ToString();
}
rd.Close();
}
public CKisi()
{
}
}

Artk IKisi arayzn uygulayan, CKisi isimli bir snfmz var.imdi Formumuzun kodlarn yazmaya
balayabiliriz. ncelikle module dzeyinde bir CKisi snf nesnesi tanmlayalm.

CKisi kisi=new CKisi();

Bu nesnemiz veri tablosundan ektiimiz veri satrna ait verileri tayacak. Kullanc Getir balkl
button kontrolne bastnda olucak olaylar gerekletirecek kodlar yazalm.

private void btnGetir_Click(object sender, System.EventArgs e)


{
int id=Convert.ToInt32(txtKisiID.Text.ToString()); /* Kullancnn TextBox kontrolne girdii ID
deeri Convert snfnn ToInt32 metodu ile Integer'a eviriyoruz.*/
kisi.Bul(id); /* Kisi isimli CKisi snfndan nesne rneimizin Bul metodunu aryoruz.*/
Doldur(); /* Doldur Metodu, kisi nesnesinin zellik deerlerini, Formumuzdaki ilgili kontrollere
alarak, bir nevi veri balama ilemini gerekletirmi oluyor.*/
}

imdide Doldur metodumuzun kodlarn yazalm.

public void Doldur()


{
txtAd.Text=kisi.Ad.ToString(); /* txtAd kontrolne, kisi nesnemizin Ad zelliinin u anki deeri
ykleniyor. Yani ilgili veri satrnn ilgili alan bu kontrole balam oluyor.*/
txtSoyad.Text=kisi.Soyad.ToString();
txtMeslek.Text=kisi.Meslek.ToString();
txtDogumTarihi.Text=kisi.DogumTarihi.ToShortDateString();
lblKisiID.Text=kisi.KisiID.ToString();
}

Evet grld gibi artk aradmz kiiye ait verileri formumuzdaki kontrollere ykleyebiliyoruz.
imdi TextBox kontrollerimizin TextChanged olaylarn kodlayacaz. Burada amacmz,
TextBox'larda meydana gelen deiikliklerin annda, CKisi snfndan trettiimiz Kisi nesnesinin
ilgili zelliklerine yanstlabilmesi. Bylece yaplan deiiklikler annda nesnemize yansyacak. Bu
nedenle aadaki kodlar ekliyoruz.

/* Metodumuz bir switch case ifadesi ile, ald ozellikAdi parametresine gre, CKisi isimli snfmza
ait Kisi nesne rneinin ilgili zelliklerini deitiriyor.*/

www.bsenyurt.com Page 2480


public void Degistir(string ozellikAdi,string veri)
{
switch(ozellikAdi)
{
case "Ad":
{
kisi.Ad=veri;
break;
}
case "Soyad":
{
kisi.Soyad=veri;
break;
}
case "Meslek":
{
kisi.Meslek=veri;
break;
}
case "DogumTarihi":
{
kisi.DogumTarihi=Convert.ToDateTime(veri);
break;
}
}
}
private void txtAd_TextChanged(object sender, System.EventArgs e)
{
Degistir("Ad",txtAd.Text);
}
private void txtSoyad_TextChanged(object sender, System.EventArgs e)
{
Degistir("Soyad",txtSoyad.Text);
}
private void txtDogumTarihi_TextChanged(object sender, System.EventArgs e)
{
Degistir("DogumTarihi",txtDogumTarihi.Text.ToString());
}
private void txtMeslek_TextChanged(object sender, System.EventArgs e)
{
Degistir("Meslek",txtMeslek.Text);
}
private void btnGuncelle_Click(object sender, System.EventArgs e)
{
int id;
id=Convert.ToInt32(lblKisiID.Text.ToString());
Guncelle(id);
}

www.bsenyurt.com Page 2481


Grld gibi kodlarmz gayet basit. imdi gncelleme ilemlerimizi gerekletireceimiz kodlar
yazalm. Kullancmz, TextBox kontrollerinde yapt deiikliklerin veritabannada yanstlmasn
istiyorsa Guncelle balkl button kontrolne tklayacaktr. te kodlarmz.

private void btnGuncelle_Click(object sender, System.EventArgs e)


{
/* Gncelleme ilemi, u anda ekranda olan Kii iin yaplacandan, bu kiiye ait KisiID sini
ilgili Label konrolmzden alyoruz ve Guncelle isimli metodumuza parametre olarak gnderiyoruz.
Asl gncelleme ilemi Guncelle isimli metodumuzda yaplyor. */
int id;
id=Convert.ToInt32(lblKisiID.Text.ToString());
Guncelle(id);
}
public void Guncelle(int ID)
{
/* Sql Server'mza balantmz oluturuyoruz.*/
SqlConnection conFriends=new SqlConnection("data source=localhost;integrated
security=sspi;initial catalog=Friends");
/* Update sorgumuzu oluturuyoruz. Dikkat edicek olursanz alanlara atanacak deerler, kisi
isimli nesnemizin zelliklerinin deerleridir. Bu zellik deerleri ise, TextBox kontrollerinin
TextChanged olaylarna ekldeimiz kodlar ile srekli gncel tutulmaktadr. En ufak bir deiiklik
dahi buraya yansyabilecektir.*/
string sorgu="Update Kisiler Set
Ad='"+kisi.Ad+"',Soyad='"+kisi.Soyad+"',Meslek='"+kisi.Meslek+"',DogumTarihi='"+
kisi.DogumTarihi.ToShortDateString()+"' Where KisiID="+ID;
SqlCommand cmd=new SqlCommand(sorgu,conFriends); /* SqlCommand nesnemizi sql
cmleciimiz ve geerli balantmz ile oluturuyoruz. */
conFriends.Open(); /* Balantmz ayoruz.*/
try
{
cmd.ExecuteNonQuery(); /* Komutumuzu altryoruz.*/
}
catch
{
MessageBox.Show("Baarsz");
}
finally /* Update ilemi herhangibir neden ile baarsz olsada, olmasada sonu olarak(finally)
ak olan SqlConnection balantmz kapatyoruz. */
{
conFriends.Close();
}
}

te uygulama kodlarmz bu kadar. imdi gelin uygulamamz altrp deneyelim. ncelikle KisiID
deeri 1000 olan satra ait verileri getirelim.

www.bsenyurt.com Page 2482


ekil 3. KisiID=1000 Kaydna ait veriler Kisi nesnemize yklenir.

imdi verilerde bir ka deiiklik yapalm ve gncelleyelim. Ben Ad alannda yer alan "S." deerini
"Selim" olarak deitirdim. Bu durum sonucunda yaplan deiikliklerin veritabanna yazlp
yazlmadn ister programmzdan tekrar 1000 nolu satr getirerek bakabiliriz istersekde Sql
Server'dan direkt olarak bakabiliriz. te sonular.

ekil 4. Gncelleme ileminin sonucu.

Programmz elbette gelimeye ok, ama ok ak. rnein kodumuzda hata denetimi
yapmadmz bir ok l nokta var. Bunlarn gelitirilmesini siz deerli okurlarmza brakyorum.
Bu makalemizde zetle, bir arayz bir snfa nasl uyguladmz, bu arayz nasl yazdmz
hatrlamaya altk. Ayrca, snfmza ait bir nesne rneine, bir tablodaki belli bir veri satrna ait
verileri nasl alabileceimizi, bu nesne zelliklerinde yaptmz deiiklikleri tekrar nasl veri
tablosuna gnderebileceimizi inceledik. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Arayzler'de is ve as Anahtar Szcklerinin


Kullanm ( 12.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

www.bsenyurt.com Page 2483


Bugnk makalemizde, arayzlerde is ve as anahtar kelimelerinin kullanmn inceleyeceiz. Bir
snfa arayz(ler) uyguladmzda, bu arayzlerde tanmlanm metodlar armak iin ounlukla
tercih edilen bir teknik vardr. O da, bu snfa ait nesne rneini, altrlacak metodun tanmland
arayz tipine dntrmek ve bu ekilde armaktadr. Bu teknik, her eyden nce, program
kodlarnn okunabilirliini ve anlalabilirliini arttrmaktadr. yleki, bir isim uzaynda yer alan ok
sayda arayzn ve snfn yer ald uygulamalarda be teknii uygulayarak, hangi arayze ait
metodun altrld daha kolay bir ekilde gzlemlenebilmektedir. Dier yandan bu teknik, ayn
metod tanmlamalarna sahip arayzler iin de kullanlr ki bunu bir nceki makalemizde ilemitik.

Bu teknik ile ilgili olarak, dikkat edilmesi gereken bir noktada vardr. Bir snfa ait nesne rneini,
bu snfa uygulamadmz bir arayze ait herhangibir metodu altrmak iin, ilgili arayz tipine
dntrdmzde InvalidCastException istisnasn alrz. Bu noktay daha iyi vurgulayabilmek
iin aadaki rneimizi gz nne alalm. Bu rnekte iki arayz yer almakta olup, tanmladmz
snf, bu arayzlerden sadece bir tanesini uygulamtr. Ana snfmzda, bu snfa ait nesne rnei,
uygulanmam arayz tipine dntrlm ve bu arayzdeki bir metod arlmak istenmitir.

using System;
namespace Interface3
{
public interface IKullanilmayan
{
void Yaz();
void Bul();
}
public interface IKullanilan
{
void ArayuzAdi();
}
public class ASinifi:IKullanilan
{
public void ArayuzAdi()
{
Console.WriteLine("Arayz adl:IKullanilan");
}
}
class Class1
{
static void Main(string[] args)
{
ASinifi a=new ASinifi();
IKullanilan Kul=(IKullanilan)a;
Kul.ArayuzAdi();
IKullanilmayan anKul=(IKullanilmayan)a;
anKul.Yaz();
}
}
}

Bu rnei derlediinizde herhangibi derleyici hatas ile karlamassnz. Ancak alma


zamannda "System.InvalidCastException: Specified Cast Is Invalid" alma zaman hatasn

www.bsenyurt.com Page 2484


alrz. te bu sorunu is veya as anahtar szcklerinin kullanld iki farkl teknikten birisi ile
zebiliriz. Is ve as bu sorunun zmnde ayn amaca hizmet etmekle beraber aralarnda nemli
iki fark vardr.

Is anahtar kelimesi aadaki formasyonda kullanlr.

nesne is tip

Is anahtar kelimesi nesne ile tipi karlatrr. Yani belirtilen nesne ile, bir snf veya arayz
kyaslarlar. Bu sz dizimi bir if karlatrmasnda kullanlr ve eer nesnenin retildii snf,
belirtilen tip'teki arayzden uygulanmsa bu koullu ifade true deerini dndrecektir. Aksi
durumda false deerini dndrr. imdi bu teknii yukardaki rneimize uygulayalm. Yapmamz
gereken deiiklik Main metodunda yer almaktadr.

static void Main(string[] args)


{
ASinifi a=new ASinifi();
IKullanilan Kul=(IKullanilan)a;
Kul.ArayuzAdi();
if(a is IKullanilmayan)
{
IKullanilmayan anKul=(IKullanilmayan)a;
anKul.Yaz();
}
else
{
Console.WriteLine("ASinifi, IKullanilmayan arayzn uygulamamtr.");
}
}

ekil 1: is Anahtar Kelimesinin Kullanm.

If koullu ifadesinde, a isimli nesneyi oluturduumuz ASinifi snfna, IKullanilmayan arayzn


uygulayp uyguladmz kontrol etmekteyiz. Sonu false deerini dndrecektir. Nitekim, ASinifi
snfna, IKullanilmayan arayzn uygulamadk.

Is anahtar szc arayzler dnda snflar iinde kullanabiliriz. Bununla birlikte is anahtar
szcn kullanldnda, program kodu Intermediate Language (IL) evrildiinde, yaplan
denetlemenin iki kere tekrar edildiini grrz. Bu verimlilii drc bir etkendir.
te is yerine as anahtar szcn tercih etmemizin nedenlerinden biriside budur. Dier
taraftan is ve as teknikleri, dndrdkleri deerler bakmndan da farkllk gsterir. Is anahtar
kelimesi, bool tipinde ture veya false deerlerini dndrr. As anahtar kelimesi ise, bir nesneyi , bu
nesne snfna uygulanm bir arayz tipine dntrr. Eer nesne snf, belirtilen arayz

www.bsenyurt.com Page 2485


uygulamamsa, dntrme ilemi yinede yaplr, fakat dntrlmenin aktarld deiken null
deerine sahip olur. As anahtar kelmesinin formu aadaki gibidir.

snf nesne1=nesne2 as tip

Burada eer nesneye belirtilen tipi temsil eden arayz uygulanmamsa, nesne null deerini alr.
Aksi durumda nesne belirtilen tipe dntrlr. te is ile as arasndaki ikinci farkta budur.
Konuyu daha iyi anlayabilmek iin as anahtar kelimesini yukardaki rneimize uygulayalm.

static void Main(string[] args)


{
ASinifi a=new ASinifi();
IKullanilan Kul=(IKullanilan)a;
Kul.ArayuzAdi();
IKullanilmayan anKul=a as IKullanilmayan;
if(anKul!=null)
{
anKul.Yaz();
}
else
{
Console.WriteLine("ASinifi IKullanilmayan tipine dntrlemedi");
}
}

Burada a nesnemiz ASinifi snfnn rneidir. As ile bu rnei IKullanilmayan arayz tipinden
anKul deikenine aktarmaya alyoruz. te bu noktada, ASinifi, IKullanilmayan arayzn
uygulamad iin, anKul deikeni null deerini alcaktr. Sonra if koullu ifadesi ile, anKul 'un null
olup olmad kontrol ediyoruz. Uygulamay altrdmzda aadaki sonucu elde ederiz.

ekil 2: as Anahtar Kelimesinin Kullanm

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2486


Arayz(Interface), Snf(Class) ve oklu Kaltm
( 09.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, arayzleri incelemeye devam ediceiz. Bir nceki makalemizde, arayzleri
kullanmann en byk nedenlerinden birisinin snflara oklu kaltm destei vermesi olduunu
sylemitik. nce basit bir uygulama ile bunu gsterelim.

using System;
namespace Interfaces2
{
public interface IMusteri
{
void MusteriDetay();
int ID{get;}
string Isim{get;set;}
string Soyisim{get;set;}
string Meslek{get;set;}
}
public interface ISiparis
{
int SiparisID{get;}
string Urun{get;set;}
double BirimFiyat{get;set;}
int Miktar{get;set;}
void SiparisDetay();
}
public class Sepet:IMusteri,ISiparis /* Sepet isimli snfmz hem IMusteri arayzn hemde
ISiparis arayzn uygulayacaktr. */
{
private int id,sipId,mkt;
private string ad,soy,mes,ur;
private double bf;
public int ID
{
get{return id;}
}
public string Isim
{
get{return ad;}
set{ad=value;}
}
public string Soyisim
{
get{return soy;}

www.bsenyurt.com Page 2487


set{soy=value;}
}
public string Meslek
{
get{return mes;}
set{mes=value;}
}
public void MusteriDetay()
{
Console.WriteLine(ad+" "+soy+" "+mes);
}
public int SiparisID
{
get{return sipId;}
}
public string Urun
{
get{return ur;}
set{ur=value;}
}
public double BirimFiyat
{
get{return bf;}
set{bf=value;}
}
public int Miktar
{
get{return mkt;}
set{mkt=value;}
}
public void SiparisDetay()
{
Console.WriteLine("----Siparisler----");
Console.WriteLine("Urun:"+ur+" Birim Fiyat"+bf.ToString()+" Miktar:"+mkt.ToString());
}
}
class Class1
{
static void Main(string[] args)
{
Sepet spt1=new Sepet();
spt1.Isim="Burak";
spt1.Soyisim="Software";
spt1.Meslek="Mat.Mh";
spt1.Urun="Modem 56K";
spt1.BirimFiyat=50000000;
spt1.Miktar=2;
spt1.MusteriDetay();

www.bsenyurt.com Page 2488


spt1.SiparisDetay();
}
}
}

ekil 1. Programn almasnn Sonucu.

Yukardaki kodlarda aslnda deiik olarak yaptmz bir ey yok. Sadece oluturduumuz
arayzleri bir snfa uyguladk ve ok kaltmll gerekletirmi olduk. Ancak bu noktada dikkat
etmemiz gereken bir unsur vardr. Eer arayzler ayn isimli metodlara sahip olurlarsa ne olur? Bu
durumda arayzlerin uyguland snfta, ilgili metodu bir kez yazmamz yeterli olucaktr. Sz
gelimi, yukardaki rneimizde, Baslat isimli ortak bir metodun arayzlerin ikisi iinde tanmlanm
olduunu varsayalm.

public interface IMusteri


{
void MusteriDetay();
int ID{get;}
string Isim{get;set;}
string Soyisim{get;set;}
string Meslek{get;set;}
void Baslat();
}
public interface ISiparis
{
int SiparisID{get;}
string Urun{get;set;}
double BirimFiyat{get;set;}
int Miktar{get;set;}
void SiparisDetay();
void Baslat();
}

imdi bu iki arayzde ayn metod tanmna sahip. Snfmzda bu metodlar iki kez yazmak anlamsz
olucaktr. O nedenle snfmza aadaki gibi tek bir Baslat metodu ekleriz. Snf nesnemizi
oluturduumuzda, Baslat isimli metodu aadaki gibi altrabiliriz.

spt1.Baslat();

www.bsenyurt.com Page 2489


Fakat baz durumlarda, arayzlerdeki metodlar ayn isimlide olsalar, arayzlerin uyguland snf
ierisinde sz konusu metod, arayzlerin her biri iin ayr ayrda yazlmak istenebilir. Byle bir
durumda ise snf ierisindeki metod yazmlarnda arayz isimlerini de belirtiriz.rnein;

void IMusteri.Baslat()
{
Console.WriteLine("Mteriler hazrland...");
}
void ISiparis.Baslat()
{
Console.WriteLine("Sipariler hazrland...");
}

Metodlarn isimleri banda hangi arayz iin yazldklarna dikkat edelim. Dier nemli bir nokta
public belirtecinin kullanlmaydr. Public belirtecini kullanmamz durumunda, "The modifier
'public' is not valid for this item" derleyici hatasn alrz. nk, metodumuzu public olarak
tanmlamaya gerek yoktur. Nitekim, bu metodlarn kullanld snflara ait nesnelerden, bu
metodlar armak istediimizde dorudan aramadmz grrz. nk derleyici hangi
arayzde tanmlanm metodun arlmas gerektiini bilemez. Bu metodlar kullanabilmek iin,
nesne rneini ilgili arayz tiplerine dntrmemiz gerekmektedir. Bu dntrmenin yaplmas
ilgili snf nesnesinin, arayz tipinden deikenlere ak bir ekilde dntrlmesi ile oluur. te
bu yzdende bu tip metodlar, tanmlandklar snf iinde public yaplamazlar. Bu aka dntrme
ilemide aadaki rnek satrlarda grld gibi olur.

IMusteri m=(IMusteri)spt1;
ISiparis s=(ISiparis)spt1;

te imdi istediimiz metodu, bu deiken isimleri ile birlikte aadaki rnek satrlarda olduu gibi
arabiliriz.

m.Baslat();
s.Baslat();

ekil 2. Programn almasnn Sonucu.

Geldik bir makalemizin daha sonuna ilerleyen makalelerimizde arayzleri incelemeye devam
edeceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2490


Interface (Arayz) Kullanmna Giri (
08.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, nesneye dayal programlamann nemli kavramlarndan birisi olan


arayzleri incelemeye alacaz. ncelikle, arayz'n tanmn yapalm. Bir arayz, baka snflar
iin bir rehberdir. Bu ksa tanmn arkasnda, deryalar gibi bir kavram denizi olduunu sylemekte
yarar buluyorum.. Arayzn ne olduunu tam olarak anlayabilmek iin belkide asl kullanm
amacna bakmamz gerekmektedir.

C++ programlama dilinde, snflar arasnda ok kaltmllk sz konusu idi. Yani bir snf, birden fazla
snftan tretilebiliyordu kaltmsal olarak. Ancak bu teknik bir sre sonra kodlarn dahada
karmaklamasna ve anlalabilirliin azalmasna neden oluyordu. Bu sebeten tr deerli
Microsoft mimarlar, C# dilinde, bir snfn sadece tek bir snf kaltmsal olarak alabilecei
kstlmasn getirdiler. ok kaltmlk grevini ise anlalmas daha kolay arayzlere braktlar. te
arayzleri kullanmamzn en byk nedenlerinden birisi budur.

Dier yandan, uygulamalarmzn gelecei asndan da arayzlerin ok kullanl olabileceini


sylememiz gerekiyor. Dnnk, bir ekip tarafndan yazlan ve gelitirilen bir uygulamada
grevlisiniz. Kullandnz nesnelerin, tretildii snflar zaman ierisinde, gelien yeniliklere adapte
olabilmek amacyla, saysz yeni metoda, zellie vb.. sahip olduklarn farzedin. Bir sre sonra,
nesnelerin tretildii snflar ierisinde yer alan kavram kargasn, "bu neyi yapyordu?, kime
yapyordu? , ne iin yapyordu?" gibi sorularn ne kadar ok sorulduunu dnn. Oysa
uygulamanzdaki snflarn izleyecei yolu gsteren rehber(ler) olsa fena m olurdu? te size
arayzler. Bir arayz oluturun ve bu arayz uygulayan snflarn hangi metodlar, zellikleri vb
kullanmas gerektiine karar verin. Programn gelimesimi gerekiyor?. Yeni niteliklere mi ihtiyacn
var? ster kullanlan arayzleri, birbirlerinden kaltmsal olarak tretin, ister yeni arayzler
tasarlayn. Tek yapacanz snflarn hangi arayzlerini kullanacan belirtmek olucaktr.

Bu aklamalar nda bir arayz nasl tanmlanr ve hangi yelere sahiptir bundan bahsedelim.Bir
arayz tanmlanmas aadaki gibi yaplr. Yazlan kod blounun bir arayz olduunu Interface
anahtar szc belirtmektedir. Arayz isminin banda I harfi kullanldna dikkat edin. Bu
kullanlan snfn bir arayz olduunu anlamamza yarayan bir isim kullanma tekniidir. Bu sayede,
snflarn kaltmsal olarak ald elemanlarn arayz olup olamdn daha kolayca anlayabiliriz.

public interface IArayuz


{
}

Tanmlama grld gibi son derece basit. imdi arayzlerin yelerine bir gz atalm. Arayzler,
sadece aadaki yelere sahip olabilirler.

Arayz yeleri

zellikler (properties)

www.bsenyurt.com Page 2491


metodlar (methods)

olaylar (events)

indeksleyiciler
(indexers)

Tablo 1. Arayzlerin sahip olabilecei yeler

Dier yandan, arayzler ierisinde aadaki yeler kesinlikle kullanlamazlar.

Arayzlerde
Kullanlamayan yeler

yapclar (constructors)

yokediciler (destructors)

alanlar (fields)

Tablo 2. Arayzlerde kullanlamayan yeler.

Arayzler Tablo1 deki yelere sahip olabilirler. Peki bu yeler nasl tanmlanr. Hereyden nce
arayzler ile ilgili en nemli kural onun bir rehber olmasdr. Yani arayzler sadece, kendisini rehber
alan snflarn kullanaca yeleri tanmlarlar. Herhangibir kod satr iermezler. Sadece zelliin,
metodun, olayn veya indeksleyicinin tanm vardr. Onlarn kolay okunabilir olmalarn salayan ve
oklu kaltm iin tercih edilmelerine neden olan sebepte budur. rnein;

public interface IArayuz


{
/* double tipte bir zellik tanm. get ve set anahtar szcklerinin herhangibir blok {}
iermediine dikkat edin. */
double isim
{
get;
set;
}
/* Yanlz okunabilir (ReadOnly) string tipte bir zellik tanm. */
string soyisim
{
get;
}
/* integer deer dndren ve ili integer parametre alan bir metod tanm. Metod tanmlarndada
metodun dn tipi, parametreleri, ismi dnda herhangibir kod satr olmadna dikkat edin. */

www.bsenyurt.com Page 2492


int topla(int a,int b);
/* Dn deeri olmayan ve herhangibir parametre almayan bir metod tanm. */
void yaz();
/* Bir indeksleyici tanm */
string this[int index]
{
get;
set;
}
}

Grld gibi sadece tanmlamalar mevcut. Herhangibir kod satr mevcut deil. Bir arayz
tasarlarken uymamz gereken bir takm nemli kurallar vardr. Bu kurallar aadaki tabloda ksaca
listelenmitir.

Bir arayz'n tm yeleri public kabul edilir. Private, Protected gibi belirtiler kullanamayz.
Bunu yaptmz takdirde rnein bir eleman private tanmladmz takdirde, derleme
1
zamannda aadaki hatay alrz.

"The modifier 'private' is not valid for this item"

Dier yandan bir metodu public olarakta tanmlayamayz. nk zaten varsaylan olarak
btn yeler public tanmlanm kabul edilir. Bir metodu public tanmladmzda yine
2
derleme zamannda aadaki hatay alrz.

"The modifier 'public' is not valid for this item"

Bir arayz, bir yap(struct)'dan veya bir snf(class)'tan kaltmla tretilemez. Ancak, bir
3
arayz baka bir arayzden veya arayzlerden kaltmsal olarak tretebiliriz.

4 Arayz elemanlarn static olarak tanmlayamayz.

5 Arayzlerin uyguland snflar, arayzde tanmlanan btn yeleri kullanmak zorundadr.

Tablo 3. Uyulmas gereken kurallar.

imdi bu kadar laftan sonra konuyu daha iyi anlayabilmek iin basit ama aklayc bir rnek
gelitirelim. nce arayzmz tasarlayalm.

public interface IArayuz


{
void EkranaYaz();
int Yas
{

www.bsenyurt.com Page 2493


get;
set;
}
string isim
{
get;
set;
}
}

imdide bu arayz kullanacak snfmz tasarlayalm.

public class Kisiler:IArayuz


{
}

imdi bu anda uygulamay derlersek, IArayuz'ndeki elemanlar snfmz iinde kullanmadmzdan


dolay aadaki derleme zaman hatalarn alrz.

'Interfaces1.Kisiler' does not implement interface member


'Interfaces1.IArayuz.EkranaYaz()'

'Interfaces1.Kisiler' does not implement interface member 'Interfaces1.IArayuz.isim'

'Interfaces1.Kisiler' does not implement interface member 'Interfaces1.IArayuz.Yas'

Grld gibi kullanmadmz tm arayz yeleri iin bir hata mesaj olutu. Bu noktada unu
tekrar hatrlatmak istiyorum,

Arayzlerin uyguland snflar, arayzde(lerde)


tanmlanan tm yeleri kullanmak yani kodlamak
zorundadr.

imdi snfmz dzgn bir ekilde gelitirelim.

public class Kisiler:IArayuz /* Snfn kullanaca arayz burada belirtiliyor.*/


{
private int y;
private string i;
/* Bir snfa bir arayz uygulamamz, bu snfa baka yeler eklememizi engellemez. Burada
rnein snfn yapc metodlarnda dzenledik. */
public Kisiler()
{
y=18;
i="Yok";
}
/* Dikkat ederseniz zelliin hereyi, arayzdeki ile ayn olmaldr. Veri tipi, ismi vb... Bu tm

www.bsenyurt.com Page 2494


dier arayz yelerinin, snf ierisinde uygulanmasnda da geerlidir. */
public Kisiler(string ad,int yas)
{
y=yas;
i=ad;
}
public int Yas
{
get
{
return y;
}
set
{
y=value;
}
}
public string Isim
{
get
{
return i;
}
set
{
i=value;
}
}
public void EkranaYaz()
{
Console.WriteLine("Adm:"+i);
Console.WriteLine("Yam:"+y);
}
}

imdi oluturduumuz bu snf nasl kullanacamza bakalm.

class Class1
{
static void Main(string[] args)
{
Kisiler kisi=new Kisiler("Burak",27);
Console.WriteLine("Yam "+kisi.Yas.ToString());
Console.WriteLine("Adm "+kisi.Isim);
Console.WriteLine("-----------");
kisi.EkranaYaz();
}

www.bsenyurt.com Page 2495


}

Uygulamamz altrdmzda aadaki sonucu elde ederiz.

ekil 1. Uygulamann almas Sonucu.

Geldik bir makalemizin daha sonuna. Bu makalemizde arayzlere ksa bir giri yaptk. Bir sonraki
makalemizde, bir snfa birden fazla arayzn nasl uygulanacan incelemeye alacaz. Hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

ArrayList Koleksiyonu ve DataGrid ( 07.01.2004


) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, veritabanlarndaki tablo yapsnda olan bir ArrayList'i bir DataGrid
kontrolne nasl veri kayna olarak balayacamz inceleyeceiz. Bildiiniz gibi ArrayList bir
koleksiyon snfdr ve System.Collections isim uzaynda yer almaktadr. Genelde ArrayList
koleksiyonlarn tercih etmemizin nedeni, dizilere olan stnlklerinden kaynaklanmaktadr.

En byk tercih nedeni, normal dizilerin boyutlarnn alma esnasnda deitirilemeyiidir. Byle
bir ilemi gerekletirmek iin, dizi elemanlar yeni boyutlu baka bo bir diziye kopyalanr. Oysaki,
ArrayList koleksiyonunda byle bir durum sz konusu deildir. Koleksiyonu, aadaki yapc
metodu ile oluturduunuzda boyut belirtmezsiniz. Eleman ekledike, ArrayList'in kapasitesi
otomatik olarak byyecektir.

public ArrayList();

Bu ekilde tanmlanan bir ArrayList koleksiyonu varsaylan olarak 16 elemal bir koleksiyon dizisi
olur. Eer kapasite alrsa, koleksiyonun boyutu otomatik olarak artacaktr. Bu elbette karmza
17 elemanl bir koleksiyonumuz varsa fazladan yer harcadmz anlamnada gelmektedir. Ancak
sorunu TrimToSize metodu ile halledebiliriz. Dilerseniz bu konuyu aadaki basit console
uygulamas ile aklayalm.

www.bsenyurt.com Page 2496


using System;
using System.Collections;
namespace TrimToSizeArray
{
class Class1
{
static void Main(string[] args)
{
ArrayList list=new ArrayList();
Console.WriteLine("ArrayList'in balangtaki kapasitesi "+list.Capacity.ToString()); /*Capacity
koleksiyonun st eleman limitini verir. */
Console.WriteLine("--------");
for(int i=1;i<=15;++i)
{
list.Add(i); /* ArrayList koleksiyonunun sonuna eleman ekler. */
}
Console.WriteLine("ArrayList'in gncel eleman says "+list.Count.ToString()); /* Count zellii
koleksiyonun o anki eleman saysn verir. */
Console.WriteLine("ArrayList'in gncel kapasitesi "+list.Capacity.ToString());
Console.WriteLine("--------");
for(int j=1;j<8;++j)
{
list.Add(j);
}
Console.WriteLine("ArrayList'in gncel eleman says "+list.Count.ToString());
Console.WriteLine("ArrayList'in gncel kapasitesi "+list.Capacity.ToString());
Console.WriteLine("--------");
list.TrimToSize(); /* TrimToSize dizideki eleman says ile kapasiteyi eitler. */
Console.WriteLine("TrimToSize sonras:");
Console.WriteLine("ArrayList'in gncel eleman says "+list.Count.ToString());
Console.WriteLine("ArrayList'in gncel kapasitesi "+list.Capacity.ToString());
}
}
}

Bu rnei altrdmzda aadaki sonucu elde ederiz.

www.bsenyurt.com Page 2497


ekil 1. TrimToSize'n etkisi.

Grld gibi koleksiyonumuz ilk oluturulduunda kapasitesi 16'dr. Daha sonra koleksiyona 15
eleman ekledik. Halen koleksiyonun kapasite limitleri iinde olduumuzdan, kapasitesi 16 dr.
Ancak sonra 8 eleman daha ekledik. 17nci eleman koleksiyona girdiinde, koleksiyonun kapasitesi
otomatik olarak iki katna kar. Bu durumda Capacity zelliimiz 32 deerini verecektir.
TrimToSize metodunu uyguladmzda koleksiyonun kapasitesinin otomatik olarak eleman says ile
eletrildiini grrz.

rneimizde koleksiyonumuza eleman eklemek iin Add metodunu kullandk. Add metodu her
zaman yeni eleman koleksiyonun sonuna ekler. Eer koleksiyonda araya eleman eklemek
istiyorsak insert metodunu, koleksiyonumuzdan bir eleman kartmak istediimizde ise Remove
metodunu kullanrz. Insert metodunun prototipi aadaki gibidir.

public virtual void Insert(int index,object value );

lk parametremiz 0 indeks tabanl bir deerdir ve object tipindeki ikinci parametre deerinin hangi
indeksli eleman olarak yerletirileceini belirtmektedir. Dolaysyla bu elemann insert edildii
yerdeki eleman bir ileriye telenmi olucaktr.

Remove metodu ise belirtilen eleman koleksiyondan kartmaktadr. Prototipi aadaki gibidir.

public virtual void Remove(object obj);

Metodumuz direkt olarak, kartlmak istenen elemann deerini alr. ArrayList koleksiyonu, Remove
metoduna alternatif baka metodlarada sahiptir. Bunlar, RemoveAt ve RemoveRange metodlardr.
RemoveAt metodu parametre olarak bir indeks deeri alr ve bu indeks deerindeki eleman
koleksiyondan kartr. Eer girilen indeks deeri 0 dan kk yada koleksiyonun eleman saysna
eit veya byk ise ArgumentOutOfRangeException istisnas frlatlr.

RemoveRange metodu ise, ilk parametrede belirtilen indeks'ten, ikinci parametrede belirtilen
sayda eleman koleksiyondan kartr. Elbette eer indeks deeri 0 dan kk yada koleksiyonun
eleman saysna eit veya byk ise ArgumentOutOfRangeException istisnas alnr. Tabi girdiimiz
ikinci parametre deeri, kartlmak istenen eleman saysn, indeksten itibaren ele alndnda,
koleksiyonun count zelliinin deerinin stne kabilir. Bu durumda ise ArgumentException
istisnas retilecektir.

public virtual void RemoveAt(int index);

public virtual void RemoveRange(int index,int count);

imdi dilerseniz bu metodlar kk bir console uygulamas ile deneyelim.

using System;
using System.Collections;
namespace TrimToSizeArray
{
class Class1

www.bsenyurt.com Page 2498


{
static void Main(string[] args)
{
ArrayList kullanicilar=new ArrayList(); /* ArrayList koleksiyonumuz oluturuluyor. */
/* ArrayList koleksiyonumuza elemanlar ekleniyor. */
kullanicilar.Add("Burki");
kullanicilar.Add("Selo");
kullanicilar.Add("Melo");
kullanicilar.Add("Alo");
kullanicilar.Add("Neo");
kullanicilar.Add("Ceo");
kullanicilar.Add("Seko");
kullanicilar.Add("Dako");
/* Foreach dngs yardmyla, koleksiyonumuz iindeki tm elemanlar ekrana
yazdryoruz. Elemanlarn herbirinin object tipinden ele alndna dikkat edin. */
foreach(object k in kullanicilar)
{
Console.Write(k.ToString()+"|");
}
Console.WriteLine();
Console.WriteLine("-----");
kullanicilar.Insert(3,"Melodan Sonra"); /* 3 noldu indeks'e "Melodan Sonra" elemann
yerletirir. Bu durumda, "Alo" isimli eleman ve sonrakiler bir ileriye kayarlar. */
foreach(object k in kullanicilar)
{
Console.Write(k.ToString()+"|");
}
Console.WriteLine();
Console.WriteLine("-----");
kullanicilar.Remove("Melodan Sonra"); /* "Melodan Sonra" isimli eleman koleksiyondan
kartr. */
foreach(object k in kullanicilar)
{
Console.Write(k.ToString()+"|");
}
Console.WriteLine();
Console.WriteLine("-----");
kullanicilar.RemoveAt(2); /* 2nci indeks'te bulunan eleman koleksiyondan kartlr. Yani
"Melo" kartlr. */
foreach(object k in kullanicilar)
{
Console.Write(k.ToString()+"|");
}
Console.WriteLine();
Console.WriteLine("-----");
kullanicilar.RemoveRange(3,2); /* 3nc indeks'ten itibaren, 2 eleman koleksiyondan
kartlr. Yani "Neo" ve "Ceo" koleksiyondan kartlr. */
foreach(object k in kullanicilar)

www.bsenyurt.com Page 2499


{
Console.Write(k.ToString()+"|");
}
Console.WriteLine();
Console.WriteLine("-----");
}
}
}

Uygulamamz altrdmzda aadaki ekran grntsn elde ederiz.

ekil 2. Insert,Remove,RemoveAt ve RemoveRange metodlar.

ArrayList koleksiyonu ile ilgili bu bilgilerden sonra sra geldi DataGrid ile ilikili olan ksma. Bildiiniz
gibi ArrayList'ler tm koleksiyon snflar gibi elemanlar object olarak tutarlar. Dolaysyla bir snf
nesnesinide bir ArrayList koleksiyonuna eleman olarak ekleyebiliriz. imdi gelitireceimiz rnek
uygulamada, bir veri tablosu gibi davranan bir ArrayList oluturacaz. Bir veritablosu gibi alanlar
olucak. Peki bunu nasl yapacaz?

ncelikle, tablodaki her bir alan birer zellik olarak tutacak bir snf tanmlayacaz. Bu durumda,
bu snftan trettiimiz her bir nesnede sahip olduu zellik deerleri ile, tablodaki bir satrlk veriyi
temsil etmi olucak. Daha sonra bu nesneyi, oluturduumuz ArrayList koleksiyonuna ekleyeceiz.
Son olarakta bu ArrayList koleksiyonunu , DataGrid kontrolmze veri kayna olarak balyacaz.

ncelikle Formumuzu tasarlayalm.

www.bsenyurt.com Page 2500


ekil 3. Form Tasarmmz.

imdi koleksiyonumuzun tayaca nesnelerin snfn tasarlayalm.

using System;

using System.Collections;

namespace ArrayListAndDataGrid

public class MailList

public MailList(string k,string m)


{
mailAdresi=m;
kullanici=k;
}
public MailList()
{
}
protected string mailAdresi;
protected string kullanici;
public string MailAdresi
{
get
{

www.bsenyurt.com Page 2501


return mailAdresi;
}
set
{
mailAdresi=value;
}
}
public string Kullanici
{
get
{
return kullanici;
}
set
{
kullanici=value;
}
}
}
}

MailList snfmz Kullanici ve MailAdresi isimli iki zellie sahip. te bunlar tablo alanlarmz temsil
etmektedir. imdi program kodlarmz yazalm.

ArrayList mList; /* ArrayList koleksiyonumuzu tanmlyoruz. */


private void Form1_Load(object sender, System.EventArgs e)
{
mList=new ArrayList(); /* Form yklenirken, ArrayList koleksiyonumuz oluturuluyor. */
lblElemanSayisi.Text=mList.Count.ToString(); /* Koleksiyonumuzun eleman says alnyor ve
label kontrolne yazdrlyor. */
}
private void btnEkle_Click(object sender, System.EventArgs e)
{
if((txtKullanici.Text.Length==0) && (txtMail.Text.Length==0))
{
MessageBox.Show("Ltfen veri girin");
}
else
{
MailList kisi=new MailList(txtKullanici.Text,txtMail.Text); /* MailList snfndan bir nesne
oluturuluyor. Yapc metodumuz parametre olarak, textBox kontrollerine girilen deerleri alyor ve
bunlar ilgili alanlara atyor. */
mList.Add(kisi); /* MailList snfndan oluturduumuz nesnemizi koleksiyonumuza
ekliyoruz. */
dgListe.DataSource=null; /* DataGrid' veri kayna olarak nce null deer atyor. Nitekim,
koleksiyonumuza her bir snf nesnesi eklendiinde, koleksiyon gncellenirken, dataGrid'in
gncellenmediini grrz. Yaplacak tek ey veri kaynan nce null olarak ayarlamaktr. */
dgListe.Refresh();

www.bsenyurt.com Page 2502


dgListe.DataSource=mList; /* imdi ite, dataGrid kontolmze veri kayna olarak
koleksiyonumuzu balyoruz. */
dgListe.Refresh();
lblElemanSayisi.Text=mList.Count.ToString();
txtKullanici.Clear();
txtMail.Clear();
}
}
private void btnSil_Click(object sender, System.EventArgs e)
{
int index;
index = dgListe.CurrentCell.RowNumber; /* Silinmek istenen eleman DataGrid'te seildiinde,
hangi satrn seildiini renmek iin CurrentCell.RowNumber zelliini kullanyoruz. */
try
{
MailList kisi=new MailList(); /* Bir MailList nesnesi oluturuyoruz. */
kisi = (MailList)mList[index]; /* index deerimiz, DataGrid kontrolnde, bizim setiimiz
satrn, koleksiyonda karlk gelen index deeridir. mList koleksiyonunda ilgili indeks'teki eleman
alp (MailList) sz dizimi ile MailList tipinden bir nesneye dntryoruz. Nitekim koleksiyonlar
elemanlarn object olarak tutarken, bu elemanlar dar alrken aka bir dntrme ilemi
uygulamamz gerekir. */
mList.Remove(kisi); /* Remove metodu ile, kisi nesnemiz, dolaysyla dataGrid kontrolnde
setiimiz eleman koleksiyondan kartlyor. */
dgListe.DataSource = null;
dgListe.Refresh();
dgListe.DataSource = mList;
dgListe.Refresh();
lblElemanSayisi.Text=mList.Count.ToString();
}
catch(Exception hata)
{
MessageBox.Show(hata.Message.ToString());
}
}

imdi uygulamamz altralm.

www.bsenyurt.com Page 2503


ekil 4. Programn almas

Bir sonraki admmz bu ArrayList'in sahip olduu verilerin gerek bir tabloya yazdrlmas olabilir.
Bu admn gelitirilesini siz deerli Okurlarma brakyorum. Bylece geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

e Yarar Bir MultiThreading(ok Kanall)


Uygulama rnei ( 06.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bundan nceki makalemizde i paracklar hakknda bilgiler vermeye altm. Bu makalemde


ise iimize yarayacak tarzda bir uygulama gelitirecek ve bilgilerimizi pekitireceiz. Bir i
paracnn belkide en ok ie yarayaca yerlerden birisi veritaban uygulamalardr. Bazen
programmz ok uzun bir sonu kmesi dndrecek sorgulara veya uzun srecek gncelleme
ifadeleri ieren sql cmlelerine sahip olabilir. Byle bir durumda programn dier eleri ile olan
aktivitemizi devam ettirebilmek isteyebiliriz. Ya da ayn anda bir den fazla i paracnda, birden
fazla veritaban ilemini yaptrarak bu ilemlerin tamamnn daha ksa srelerde bitmesini
salyabiliriz. te bu gibi nedenleri gz nne alarak bu gn birlikte basit ama faydal olacana
inandm bir uygulama gelitireceiz.

Olay iyi anlayabilmek iin ncelikle bir milat koymamz gerekli. paracndan nceki durum ve
sonraki durum eklinde. Bu nedenle uygulamamz nce i parac kullanmadan oluturacaz.
Sonrada i parac ile. imdi programmzdan ksaca bahsedelim. Uygulamamz aadaki sql

www.bsenyurt.com Page 2504


sorgusunu altrp, bellekteki bir DataSet nesnesinin referans ettii blgeyi, sorgu sonucu dnen
veri kmesi ile dolduracak.

SELECT Products.* From [Order Details] Cross Join Products

Bu sorgu altrldnda, Sql sunucusunda yer alan Northwind veritaban


zerinden, 165936 satrlk veri kmesi dndrr. Elbette normalde byle bir ilemi istemci
makinenin belleine ymamz anlamsz. Ancak sunucu zerinde alan ve zellikle raporlama
amac ile kullanlan sorgularn bu tip sonular dndrmeside olasdr. imdi bu sorguyu altrp
sonular bir DataSet'e alan ve bu veri kmesini bir DataGrid kontrol iinde gsteren bir uygulama
gelitirelim. ncelikle aadaki formumuzu tasarlayalm.

ekil 1. Form Tasarmmz.

imdide kodlarmz yazalm.

DataSet ds;
public void Bagla()
{
dataGrid1.DataSource=ds.Tables[0];
}
public void Doldur()
{
SqlConnection conNorthwind=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=sspi");
conNorthwind.Open();
SqlDataAdapter daNorthwind=new SqlDataAdapter("SELECT Products.* From [Order Details]
Cross Join Products",conNorthwind);

www.bsenyurt.com Page 2505


ds=new DataSet();
daNorthwind.Fill(ds);
conNorthwind.Close();
MessageBox.Show("DataTable dolduruldu...");
}
private void btnKapat_Click(object sender, System.EventArgs e)
Close();
}
private void btnCalistir_Click(object sender, System.EventArgs e)
{
Doldur();
}
private void btnGoster_Click(object sender, System.EventArgs e)
{
Bagla();
}

Yazdmz kodlar gayet basit. Sorgumuz bir SqlDataAdapter nesnesi ile, SqlConnection'mz
kullanlarak altrlyor ve daha sonra elde edilen veri kmesi DataSet'e aktarlyor. imdi
uygulamamz bu haliyle altralm ve sorgumuzu altr balkl buton ile altrdktan sonra,
textBox kontrolne mouse ile tklayp bir eyler yazmaya alalm.

ekil 2. parac olmadan programn almas.

Grld gibi sorgu sonucu elde edilen veri kmesi DataSet'e doldurulana kadar TextBox
kontrolne bir ey yazamadk. nk ilemcimiz satr kodlarn iletmek ile meguld ve bizim
TextBox kontrolmze olan tklamamz ele almad. Demekki buradaki sorgumuzu bir i parac
iinde tanmlamalyz. Nitekim programmz donmasn ve baka ilemleride yapabilelim. rnein
TextBox kontrolne bir eyler yazabilelim (bu noktada pek ok ey sylenebilir. rnein baka bir

www.bsenyurt.com Page 2506


tablonun gncellenmesi gibi). Bu durumda yapmamz gereken kodlamay inanyorumki nceki
makalelerden edindiiniz bilgiler ile biliyorsunuzdur. Bu nedenle kodlarmz detayl bir ekilde
aklamadm. imdi gelin yeni kodlarmz yazalm.

DataSet ds;
public void Bagla()
{
if(!t1.IsAlive)
{
dataGrid1.DataSource=ds.Tables[0];
}
}
public void Doldur()
{
SqlConnection conNorthwind=new SqlConnection("data source=localhost;initial
catalog=Northwind;integrated security=sspi");
conNorthwind.Open();
SqlDataAdapter daNorthwind=new SqlDataAdapter("SELECT Products.* From [Order Details]
Cross Join Products",conNorthwind);
ds=new DataSet();
daNorthwind.Fill(ds);
conNorthwind.Close();
MessageBox.Show("DataTable dolduruldu...");
}
ThreadStart ts1;
Thread t1;
private void btnKapat_Click(object sender, System.EventArgs e)
{
if(!t1.IsAlive)
{
Close();
}
else
{
MessageBox.Show("Is paracigi henz sonlandirilmadi...Daha sonra tekrar deneyin.");
}
}
private void btnCalistir_Click(object sender, System.EventArgs e)
{
ts1=new ThreadStart(Doldur);
t1=new Thread(ts1);
t1.Start();
}
private void btnIptalEt_Click(object sender, System.EventArgs e)
{
t1.Abort();
}
private void btnGoster_Click(object sender, System.EventArgs e)

www.bsenyurt.com Page 2507


{
Bagla();
}

imdi programmz altralm.

ekil 3. Paracnn sonucu.

Grld gibi bu youn sorgu alrken TextBox kontrolne bir takm yazlar yazabildik. stelik
programn almas hi kesilmeden. imdi Gster balkl butona tkladmzda veri kmesinin
DataGrid kontrolne alndn grrz.

www.bsenyurt.com Page 2508


ekil 4. Programn almasnn Sonucu.

Geldik bir makalemizin daha sonuna. lerliyen makalelerimizde Thred'leri daha derinlemesine
incelemeye devam edeceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Thread'lerde ncelik(Priority) Durumlar (


05.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

paracklarn ilediimiz yaz dizimizin bu nc makalesinde, i paracklarnn birbirlerine kar ncelik durumlarn
incelemeye alacaz. paracklar olarak tanmladmz metodlarn alma ralarn, sahip olduklar neme gre
deitirmek durumunda kalabiliriz. Normal artlar altnda, oluturduumuz her bir i parac nesnesi ayn ve eit ncelie
sahiptir. Bu ncelik deeri Normal olarak tanmlanmtr. Bir i paracnn nceliini deitirmek istediimizde, Priority
zelliinin deerini deitiririz. Priority zelliinin .NET Framework'teki tanm aadaki gibidir.

public ThreadPriority Priority {get; set;}

zelliimiz ThreadPriority numaralandrcs (enumerator) tipinden deerler almaktadr. Bu deerler aadaki tabloda
verilmitir.

ncelik Deeri

www.bsenyurt.com Page 2509


Highest

AboveNormal

Normal

BelowNormal

Lowest

Tablo 1. ncelik(Priority) Deerleri

Programlarmz yazarken, i paracklarnn alma ekli verilen ncelik deerlerine gre deiecektir. Elbette tahmin
edeceiniz gibi yksek ncelik deerlerine sahip olan i paracklarnn iaret ettikleri metodlar dierlerine gre daha sk
aralklarda arlacak, dolaysyla dk ncelikli i paracklarnn referans ettii metodlar daha ge sonlanacaktr. imdi olay
daha iyi canlandrabilmek iin aadaki rneimizi gelitirelim. Daha nceden sylediimiz gibi, bir i paracnn Priority
zelliine her hangibir deer vermez isek, standart olarak Normal kabul edilir. Buda tm i paracklarnn varsaylan olarak eit
nceliklere sahip olacaklar anlamna gelmektedir. imdi aadaki formumuzu oluturalm. Uygulamamz iki i paracna
sahip. Bu paracklarn iaret ettii metodlardan birisi 1' den 1000' e kadar sayp bu deerleri bir label kontrolne yazyor.
Dieri ise 1000' den 1' e kadar sayp bu deerleri baka bir label kontrolne yazyor. Formumuzun grnts aadakine
benzer olmaldr.

ekil 1. Form Tasarmmz.

imdide program kodlarmz yazalm.

/* Bu metod 1' den 1000' e kadar sayar ve deerleri lblSayac1 isimli label kontrolne yazar.*/
public void Say1()
{
for(int i=1;i<1000;++i)
{
lblSayac1.Text=i.ToString();
lblSayac1.Refresh(); /* Refresh metodu ile label kontrolnn grntsn tazeleriz. Bylece herbir i deerinin label
kontrolnde grlebilmesini salam oluyoruz. */

www.bsenyurt.com Page 2510


for(int j=1;j<90000000;++j)
{
j+=1;
}
}
}
/* Bu metod 1000' den 1' e kadar sayar ve deerleri lblSayac2 isimli label kontrolne yazar.*/
public void Say2()
{
for(int i=1000;i>=1;i--)
{
lblSayac2.Text=i.ToString();
lblSayac2.Refresh();
for(int j=1;j<45000000;++j)
{
j+=1;
}
}
}
/* ThreadStart ve Thread nesnelerimizi tanmlyoruz. */
ThreadStart ts1;
ThreadStart ts2;
Thread t1;
Thread t2;
private void btnBaslat1_Click(object sender, System.EventArgs e)
{
/* Metodlarmz ThreadStart nesneleri ile ilikilendiriyoruz ve ThreadStart nesnelerimizi oluturuyoruz.*/
ts1=new ThreadStart(Say1);
ts2=new ThreadStart(Say2);
/* paracklarmz, ilgili metodlarn temsil eden ThreadStart nesnelerimiz ile oluturuyoruz.*/
t1=new Thread(ts1);
t2=new Thread(ts2);
/* paracklarmz altryoruz.*/
t1.Start();
t2.Start();
btnBaslat1.Enabled=false;
btnIptal.Enabled=true;
}
private void btnIptal_Click(object sender, System.EventArgs e)
{
/* paracklarmz iptal ediyoruz. */
t1.Abort();
t2.Abort();
btnBaslat1.Enabled=true;
btnIptal.Enabled=false;
}
private void btnKapat_Click(object sender, System.EventArgs e)
{
/* Uygulamay kapatmak istediimizde, alan i parac olup olmadn kontrol ediyoruz. Bunun iin i paracklarnn
IsAlive zelliinin deerlerine bakyoruz. Nitekim kullancnn, herhangibir i parac sonlanmadan uygulamay kapatmasn
istemiyoruz. Ya iptal etmeli yada sonlanmalarn beklemeli. ptal ettiimizde yani Abort metodlar altrldnda
hatrlayacanz gibi, i paracklarnn IsAlive deerleri false durumuna dyordu, yani iptal olmu oluyorlard.*/
if((!t1.IsAlive) && (!t2.IsAlive))

www.bsenyurt.com Page 2511


{
Close();
}
else
{
MessageBox.Show("Hala kapatlamam i paracklar var. Ltfen bir sre sonra tekrar deneyin.");
}
}

Uygulamamzda u an iin bir yenilik yok aslnda. Nitekim i paracklarmz iin bir ncelik ayarlamas yapmadk. nk size
gstermek istediim bir husus var. Bir i parac iin herhangibir ncelik ayar yapmadmzda bu deer varsaylan olarak
Normal dir. Dolaysyla her i parac eit ncelie sahiptir. imdi rneimizi altralm ve kafamza gre bir yerde iptal
edelim.

ekil 2. ncelik deeri Normal.

Ben 11 ye 984 deerinde ilemi iptal ettim. Tekrar i paracklarn Balat balkl butona tklayp altrrsak ve yine ayn yerde
ilemi iptal edersek, ya ayn sonucu alrz yada yakn deerleri elde ederiz. Nitekim programmz altrdmzda arka planda
alan iletim sistemine ait pek ok i paracda alma sonucunu etkiler. Ancak aa yukar ayn veya yakn deerle
ularz. Oysa bu i paracklarnn ncelik deelerini deitirdiimizde sonularn ok daha farkl olabilieceini syleyebiliriz.
Bunu daha iyi anlayabilmek iin rneimizi gelitirelim ve i paracklarnn ncelik deerleri ile oynayalm. Formumuzu
aadaki gibi tasarlayalm.

www.bsenyurt.com Page 2512


ekil 3. Formumuzun yeni tasarm.

Artk i paracklarn balatmadan nce nceliklerini belirleyeceiz ve sonularn incelemeye alacaz. Kodlarmz u ekilde
deitirelim. nemli olan kod satrlarmz, i paracklarnn Priority zelliklerinin deitii satrlardr.

/* Bu metod 1' den 1000' e kadar sayar ve deerleri lblSayac1 isimli label kontrolne yazar.*/
public void Say1()
{
for(int i=1;i<1000;++i)
{
lblSayac1.Text=i.ToString();
lblSayac1.Refresh(); /* Refresh metodu ile label kontrolnn grntsn tazeleriz. Bylece herbir i deerinin label
kontrolnde grlebilmesini salam oluyoruz. */
for(int j=1;j<90000000;++j)
{
j+=1;
}
}
}
/* Bu metod 1000' den 1' e kadar sayar ve deerleri lblSayac2 isimli label kontrolne yazar.*/
public void Say2()
{
for(int i=1000;i>=1;i--)
{
lblSayac2.Text=i.ToString();
lblSayac2.Refresh();
for(int j=1;j<45000000;++j)
{
j+=1;
}
}
}
ThreadPriority tp1; /* Priority ncelikleri ThreadPriority tipindedirler. */
ThreadPriority tp2;
/* OncelikBelirle metodu, kullancnn TrackBar'da setii deerleri gz nne alarak, i paracklarnn Priority zelliklerini
belirlemektedir. */

www.bsenyurt.com Page 2513


public void OncelikBelirle()
{
/* Switch ifadelerinde, TrackBar kontrollnn deerine gre , ThreadPriority deerleri belirleniyor. */
switch(tbOncelik1.Value)
{
case 1:
{
tp1=ThreadPriority.Lowest; /* En dk ncelik deeri. */
break;
}
case 2:
{
tp1=ThreadPriority.BelowNormal; /* Normalin biraz alt. */
break;
}
case 3:
{
tp1=ThreadPriority.Normal; /* Normal ncelik deeri. Varsaylan deer budur.*/
break;
}
case 4:
{
tp1=ThreadPriority.AboveNormal; /* Normalin biraz st ncelik deeri. */
break;
}
case 5:
{
tp1=ThreadPriority.Highest; /* En st dzey ncelik deeri. */
break;
}
}
switch(tbOncelik2.Value)
{
case 1:
{
tp2=ThreadPriority.Lowest;
break;
}
case 2:
{
tp2=ThreadPriority.BelowNormal;
break;
}
case 3:
{
tp2=ThreadPriority.Normal;
break;
}
case 4:
{
tp2=ThreadPriority.AboveNormal;
break;

www.bsenyurt.com Page 2514


}
case 5:
{
tp2=ThreadPriority.Highest;
break;
}
}
/* Paracklarmza ncelik deerleri aktarlyor.*/
t1.Priority=tp1;
t2.Priority=tp2;
}
/* ThreadStart ve Thread nesnelerimizi tanmlyoruz. */
ThreadStart ts1;
ThreadStart ts2;
Thread t1;
Thread t2;
private void btnBaslat1_Click(object sender, System.EventArgs e)
{
/* Metodlarmz ThreadStart nesneleri ile ilikilendiriyoruz ve ThreadStart nesnelerimizi oluturuyoruz.*/
ts1=new ThreadStart(Say1);
ts2=new ThreadStart(Say2);
/* paracklarmz, ilgili metodlarn temsil eden ThreadStart nesnelerimiz ile oluturuyoruz.*/
t1=new Thread(ts1);
t2=new Thread(ts2);
OncelikBelirle(); /* ncelik ( Priority ) deerleri, i paracklar Start metodu ile balatlmadan nce belirlenmelidir. */
/* paracklarmz altryoruz.*/
t1.Start();
t2.Start();
btnBaslat1.Enabled=false;
btnIptal.Enabled=true;
tbOncelik1.Enabled=false;
tbOncelik2.Enabled=false;
}
private void btnIptal_Click(object sender, System.EventArgs e)
{
/* paracklarmz iptal ediyoruz. */
t1.Abort();
t2.Abort();
btnBaslat1.Enabled=true;
btnIptal.Enabled=false;
tbOncelik1.Enabled=true;
tbOncelik2.Enabled=true;
}
private void btnKapat_Click(object sender, System.EventArgs e)
{
/* Uygulamay kapatmak istediimizde, alan i parac olup olmadn kontrol ediyoruz. Bunun iin i paracklarnn
IsAlive zelliinin deerlerine bakyoruz. Nitekim kullancnn, herhangibir i parac sonlanmadan uygulamay kapatmasn
istemiyoruz. Ya iptal etmeli yada sonlanmalarn beklemeli. ptal ettiimizde yani Abort metodlar altrldnda
hatrlayacanz gibi, i paracklarnn IsAlive deerleri false durumuna dyordu, yani iptal olmu oluyorlard.*/
if((!t1.IsAlive) && (!t2.IsAlive))
{
Close();
}

www.bsenyurt.com Page 2515


else
{
MessageBox.Show("Hala kapatlamam i paracklar var. Ltfen bir sre sonra tekrar deneyin.");
}
}

imdi rneimizi altralm ve birinci i paracmz iin en yksek ncelik deerini (Highest) ikinci i paracmz iinde en
dk ncelik deerini (Lowest) seelim. Sonular aadakine benzer olucaktr.

ekil 4. nceliklerin etkisi.

Grld gibi ncelikler i paracklarnn almasn olduka etkilemektedir. Geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde i paracklar hakknda ilerlemeye devam edeceiz. Grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Thread'leri Belli Sreler Boyunca Uyutmak ve


Yoketmek ( 02.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde i paracklarnn belli sreler boyunca nasl durgunlatrlabileceini yani


etkisizletirebilieceimizi ilemey alcaz. Ayrca i paracklarnn henz sonlanmadan nce nasl
yokedildiklerini greceiz.

Bir nceki makalemizde hatrlayacak olursanz, i paracklar haline getirdiimiz metodlarmzda


ilemeleri yavalatmak amac ile baz dngler kullanmtk. Gerek hayatta ou zaman, i
paracklarnn belirli sreler boyunca beklemesini ve sre sona erdiinde tekrardan ilemelerine
kald yerden devam etmesini istediimiz durumlar olabilir. nceki makalemizde kullandmz
Suspend metodu ile ilgili i paracn durdurabiliyorduk. Bu ilgili i paracklarn geici sre ile
bekletmenin yollarndan birisidir. Ancak byle bir durumda bekletilen i paracn tekrar

www.bsenyurt.com Page 2516


hareketlendirmek kullancnn Resume metodunu altrmas ile olabilir. Oysaki biz, i
paracmzn belli bir sre boyunca beklemsini isteyebiliriz. te byle bir durumda Sleep
metodunu kullanrz. Bu metodun iki adet overload edilmi versiyonu vardr.

public static void Sleep(int);

public static void Sleep(TimeSpan);

Biz bugnk uygulamamzda ilk versiyonu kullanacaz. Bu versiyonda metodumuz parametre


olarak int tipinde bir deer almaktadr. Bu deer milisaniye cinsinden sreyi bildirir. Metodun Static
bir metod olduu dikkatinizi ekmi olmaldr. Static bir metod olmas nedeni ile, Snf ad ile birlikte
arlmak zorundadr. Yani herhangibir thread nesnesinin ardndan Sellp metodunu yazamassnz.
Peki o halde bekleme sresinin hangi i parac iin geerli olacan nereden bileceiz. Bu
nedenle, bu metod i parac olarak tanmlanan metod bloklar ierisinde kullanlr. Konuyu rnek
zerinden inceleyince daha iyi anlayacaz. Metod altrldnda parametresinde belirtilen sre
boyunca geerli i paracn bekletir. Bu bekleme dier paracklarn almasn engellemez. Sre
sona erince, i paracmz almasna devam edicektir. imdi dilerseniz tnek bir uygulama
gelitirelim ve konuya aklk getirmeye alalm.

Formumuzda bu kez adet ProgressBar kontrolmz var. Baslat balkl dmeye bastmzda i
paracklarmz alyor ve tm ProgressBar'lar ayn anda deiik sreler ile ilerliyor. Burada i
paracklar olarak belirlediimiz metodlarda kullandmz Sleep metodlarna dikkat edelim. Tabi
kodlarmz yazmadan nce System.Threading isim uzayn eklemeyi unutmayalm.

ekil 1. Form Tasarmmz.

public void pb1Ileri()


{
for(int i=1;i<100;++i)
{
pb1.Value+=1;
Thread.Sleep(800);
}
}
public void pb2Ileri()
{
for(int i=1;i<100;++i)
{
pb2.Value+=1;
Thread.Sleep(500); /* Metodumuz i parac olarak baladktan sonra dng iince her

www.bsenyurt.com Page 2517


bir artmdan sonra 500 milisaniye bekler. */
}
}
public void pb3Ileri()
{
for(int i=1;i<100;++i)
{
pb3.Value+=1;
Thread.Sleep(300);
}
}
/* ThreadStart temsilcilerimiz ve Thread nesnelerimizi tanmlyoruz. */
ThreadStart ts1;
ThreadStart ts2;
ThreadStart ts3;
Thread t1;
Thread t2;
Thread t3;
private void btnBaslat_Click(object sender, System.EventArgs e)
{
/* ThreadStart temsilcilerimizi ve Thread nesnelerimizi oluturuyoruz. */
ts1=new ThreadStart(pb1Ileri);
ts2=new ThreadStart(pb2Ileri);
ts3=new ThreadStart(pb3Ileri);
t1=new Thread(ts1);
t2=new Thread(ts2);
t3=new Thread(ts3);
/* Thread nesnelerimizi start metodu ile balatyoruz. */
t1.Start();
t2.Start();
t3.Start();
}

Uygulamamz altralm. Her i parac Sleep metodu ile belirtilen sre kadar beklemeler ile
almasna devam eder. rnein pb3Ileri metodunda i paracmz ProgressBar'n Value deerini
her bir arttrdktan sonra 300 milisaniye bekler ve dng bir sonraki deerden itibaren devam eder.
Sleep metodu ile Suspend metodlar arasnda nemli bir ba daha vardr. Bildiiniz gibi Suspend
metodu ilede bir i paracn durdurabilmekteyiz. Ancak bu i paracn tekrar devam ettirmek
iin Resume metodunu kullanmamz gerekiyor. Bu iki yntem arasndaki fark idi. Dieri nemli olgu
ise udur; bir i parac metodu iinde, Sleep metodunu kullanm olsak bile, programn
herhangibir yerinden bu i parac ile ilgili Thread nesnesinin Suspend metodunu ardmzda,
bu i parac yine duracaktr. Bu andan itibaren Sleep metodu geerliliini, bu i parac iin
tekrardan Resume metodu arlncaya kadar kaybedecektir. Resume arsndan sonra ise Sleep
metodlar yine ilemeye devam eder.

www.bsenyurt.com Page 2518


ekil 2. Sleep Metodunun almas

imdi gelelim dier konumuz olan bir i paracnn nasl yok edileceine. Bir i paracn
yoketmek amac ile Abort metodunu kullanabiliriz. Bu metod altrldnda derleyici aslnda bir
ThreadAbortException istisnas retir ve i paracn yoketmeye zorlar. Abort yntemi
arldnda, ilgili i paracn tekrar resume gibi bir komutla balatamayz. Dier yandan Abort
metodu i parac ile ilgili metod iin ThreadAbortException istisnasn frlattnda (throw) , bu
metod iinde bir try..catch..finally korumal blounda bu istisnay yakalayabiliriz veya Catch
blounda hi bir ey yazmas isek program kodumuz kesilmeden almasna devam edicektir.

Abort metodu ile bir i parac sonlandrldnda, bu i paracn Start metodu ile tekrar
altrmak istersek;

"ThreadStateException' Additional information: Thread is running or terminated; it can not


restart."

hatasn alrz. Yani i paracmz tekrar batan balatmak gibi bir ansmz yoktur.

imdi bu metodu inceleyeceimiz bir kod yazalm. Yukardaki uygulamamz aadaki ekilde
gelitirelim.

ekil 3. Form Tasarmmz.

Kodlarmza geelim.

public void pb1Ileri()


{

www.bsenyurt.com Page 2519


try
{
for(int i=1;i<100;++i)
{
pb1.Value+=1;
Thread.Sleep(800);
}
}
catch(ThreadAbortException hata)
{
}
finally
{
}
}
public void pb2Ileri()
{
for(int i=1;i<100;++i)
{
pb2.Value+=1;
Thread.Sleep(500); /* Metodumuz i parac olarak baladktan sonra dng iince
her bir artmdan sonra 500 milisaniye bekler. */
}
}
public void pb3Ileri()
{
for(int i=1;i<100;++i)
{
pb3.Value+=1;
Thread.Sleep(300);
}
}
/* ThreadStart temsilcilerimiz ve Thread nesnelerimizi tanmlyoruz. */
ThreadStart ts1;
ThreadStart ts2;
ThreadStart ts3;
Thread t1;
Thread t2;
Thread t3;
private void btnBaslat_Click(object sender, System.EventArgs e)
{
/* ThreadStart temsilcilerimizi ve Thread nesnelerimizi oluturuyoruz. */
ts1=new ThreadStart(pb1Ileri);
ts2=new ThreadStart(pb2Ileri);
ts3=new ThreadStart(pb3Ileri);
t1=new Thread(ts1);
t2=new Thread(ts2);
t3=new Thread(ts3);

www.bsenyurt.com Page 2520


/* Thread nesnelerimizi start metodu ile balatyoruz. */
t1.Start();
t2.Start();
t3.Start();
btnBaslat.Enabled=false;
btnDurdur.Enabled=true;
btnDevam.Enabled=false;
}
private void btnDurdur_Click(object sender, System.EventArgs e)
{
t1.Abort(); /* t1 isimli Thread'imizi yokediyoruz. Dolaysyla pb1Ileri isimli metodumuzunda
almasn sonlandrm oluyoruz. */
/* Dier iki i paracn uyutuyoruz. */
t2.Suspend();
t3.Suspend();
btnDurdur.Enabled=false;
btnDevam.Enabled=true;
}
private void btnDevam_Click(object sender, System.EventArgs e)
{
/* paracklarn tekrar kaldklar yerden altryoruz. te burada t1 thread nesnesini
Resume metodu ile tekrar kald yerden altramayz. Bu durumda programmz hataya
decektir. Nitekim Abort metodu ile Thread'imiz sonlandrlmtr. Ayn zamanda Start metodu ile
Thread'imizi batanda balatamayz.*/
t2.Resume();
t3.Resume();
btnDurdur.Enabled=true;
btnDevam.Enabled=false;
}

Uygulamamz deneyelim.

ekil 4. Uygulamann almas sonucu.

Deerli okurlarm geldik bir makalemizin daha sonuna. Bir sonraki makalemizde Threading
konusunu ilemeye devam edeceiz. Hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 2521


Burak Selim ENYURT

selim@bsenyurt.com

StreamReader Snf Yardmyla Dosya Okumak


( 01.01.2004 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, sistemimizde yer alan text tabanl dosyalar nasl okuyabileceimizi
incelemeye alacaz. .NET ortamnda, dosyalarn okunmas iin streamler(akmlar) kullanlr.
Bugn ileyeceimi StreamReader snfda bunlardanbir tanesidir. StreamReader snf dosyalarn
okunmasn, dosyalara yazlmasn vb.. salar. StreamReader snfn bir FileStream nesnesi ile
kullanabileceimiz gibi, tek banada kullanabiliriz. Kullanabileceimiz yapc metodlardan birisi;

public StreamReader( Stream stream );

dir. Bu yapc metod Stream tipinden bir nesne alr. Bu stream nesnesi ounlukla FileStream
snfndan tretilmi bir nesne olur. Bu yapc metodumuz dnda direkt olarak okuma amac ile
StreamReader nesnesini ;

public StreamReader( string path );

yapcs ilede oluturabiliriz. Burada string tipindeki path deikenimiz, okumak amacyla
aacamz dosyann tam adresini temsil etmektedir. StreamReader nesnesi ile dosyamz atktan
sonra dosya iindeki verileri ReadLine metodu ile okuyabiliriz. ReadLine metodu, dosyadan her
defasnda bir satr okur ve bunun string olarak geriye dndrr. Metodun prototipi aadaki
gibidir.

public override string ReadLine();

Genellikle bu metod bir while dngs ile kullanlr. Bu sayade dosyann tm ieriinin okunmas
salanm olur. ReadLine metodu geriye null deerini dndrd zaman dosyann sonuna gelindii
anlalr. Bu nedenle While dngsnde kontrol ifadesi okunan her bir satrn null olup olmadna
bakar.

imdi bu ksa aklamalarn ardrdan dilerseniz uygulamamz yazalm. Bu kk uygulamamzda


kullancnn semi olduu bir dosyay bir listBox kontrolne satr baznda acaz.ncelikle
aadaki rnek formu oluturalm. OpenFileDialog kontrolmzn Filter zelliinede ekranda
grlen deerleri aktaryoruz. Bylece OpenFileDialog kontrolmz aldnda cs,vb uzantl
dosyalar ve tm dosyalar grebileceiz.

www.bsenyurt.com Page 2522


ekil 1. Form Tasarmmz.

imdi dilersenin projemizin kodlarn yazalm.

private void btnDosyaAc_Click(object sender, System.EventArgs e)


{
if(ofdDosya.ShowDialog()==DialogResult.OK)
{
this.Text=ofdDosya.FileName.ToString();
FileStream d=new FileStream(ofdDosya.FileName,FileMode.Open,FileAccess.Read); /*
Burada okuma amac ile OpenFileDialog kontrolnden setiimiz dosyaya bir akm oluturyoruz. */
StreamReader sr=new StreamReader(d); /* imdi ise StreamReader nesnemizi
FileStream nesnesini kullanarak oluturuyoruz. */
String input;
/* Bu dng, sr isimli StreamReader nesnemizin temsil ettii akm vastasyla,
dosyamzdan bir satr alr ve bunu bellekteki tampon blgeye yerletirir. Daha sonra bunu bir string
deikene atyoruz. Ardndan bunun deerinin null olup olmadna bakyoruz. Null olmas halinde
dosya sonuna geldiimiz anlalmaktadr. ReadLine metodu otomatik olarak bir satr tampona
aldktan sonra, akmdan bir sonraki satr okur ve bellee alr. */
while ((input=sr.ReadLine())!=null)
{
lstDosya.Items.Add(input); /* ListBox kontrolmze ounan her bir satr ekliyoruz.*/
}
sr.Close(); /* Son olarak StreamReader nesnemizi ve FileStream nesnemizi kapatyoruz.
*/
d.Close();
}
}

www.bsenyurt.com Page 2523


imdi uygulamamz altralm. Grld gibi OpenFileDilaog kutumuzda Filter zelliinde
belirlediimiz dosyalar grnyor.

ekil 2. OpenFileDialog letiim Kutumuz.

ekil 3. Dosyamzn ierii.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

www.bsenyurt.com Page 2524


Burak Selim ENYURT

selim@bsenyurt.com

ok Kanall(Multithread) Uygulamalar (
01.01.2004 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makelemiz ile birlikte threading kavramn en basit haliyle tanmaya alacaz. Sonraki
makalelerimizde de threading kavramn daha st seviyede ilemeye alacaz.

Bugn hepimiz bilgisayar bandayaken ayn anda pek ok uygulamann sorunsuz bir ekilde
altn grrz. Bir belge yazarken, ayn zamanda mzik dinleyebilir, internet zerinden
program indirebilir ve sistemimizin kaynaklarnn elverdii lde uygulamayla ezamanl olarak
alabiliriz. Bu bize, gnmz ilemcilerinin ve zerlerinde alan iletim sistemlerinin ne kadar
yetenekli oluunu gsterir. Gsterir mi acaba?

Aslnda tek ilemcili makineler gnmzn modern sihirbazlar gibidirler. Gerekte alan
uygulamalarn tm ilemleri ayn anda gereklememektedir. Fakat ilemciler ylesine byk saat
hzlarna sahiptirlerki. lemcinin yapt, altrlan uygulamaya ait ilemleri i
paracacklar(thread) halinde ele almaktr. Her bir i paraca bir ilemin birden fazla paraya
blnmesinden oluur. lemciler her i parac iin bir zaman dilimi belirler. T zaman diliminde
bir ilem parac yrtlr ve bu zaman dilim bittiinde ilem parac geici bir sre iin durur.
Ardndan kuyrukta bekleyen dier i paraca baka bir zaman dilimi iinde altrlr. Bu bylece
devam ederken, ilemcimiz her i paracna geri dner ve tm i paracklar sra sra altrlr.
Dedik ya, ilemciler bu ilemleri ok yksek saat ve frekans hznda gerekletiri. te bu yksek
hz nedeniyle tm bu olaylar saniyenin milyon srelerinde gerekleir ve sanki tm bu uygulamalar
ayn anda alyor hissi verir.

Gerektende uygulamalar birbirleriyle paralel olarak ve e zamanl altrmak aslnda birden fazla
ilemciye sahip sistemler iin gereklenir.

Bugnk uygulamamz ile, bahsetmi olduumuz threadin kavramna basit bir giri yapcaz.
Nitekim threading kavram ve teknikleri, uygulamalarda profesyonel olarak kod yazmay gerektirir.
Daha ak ekilde sylemek gerekirse bir uygulama iinde yazdmz kodlara uygulayacam
thread'ler her zaman avantaj salamaz. Baz durumlarda dezavantaja dnp programlarn daha
yava almasna neden olabilir. Nitekim thread'lerin alma mantn iyi kavramak ve
uygulamalarda titiz davranmak gerekir.

rnein thread'lerin zaman dilimlerine blndklerinde sistemin nasl bir nceki veya daha nceki
thread'i altrabildiini dnelim. lemci zaman dilimini dolduran bir thread iin donanmda bir
kesme iareti brakr, bunun ardnda thread'e ait bir takm bilgiler bellee yazlr ve sonra bu bellek
blgesinde Context ad verilen bir veri yapsna depolanr. Sistem bu thread'e dnecei zaman
Context'te yer alan bilgilere bakar ve hangi donanmn kesme sinyali verdiini bulur. Ardndan bu
sinyal alr ve ilemin bir sonraki ilem paracnn alaca zaman dilimine girilir. Eer thread
ilemini ok fazla kullanrsanz bu durumda bellek kaynaklarnda fazlas ile tketmi olursunuz. Bu
thread'leri neden titiz bir ekilde programlamamz gerektiini anlatan nedenlerden sadece birisidir.
yleki yanl yaplan thread programlamalar sistemlerin kilitlenmesine de yol aacaktr.

www.bsenyurt.com Page 2525


Threading grdnz gibi ok basit olmayan bir kavramdr. Bu nedenle olay daha iyi
aklayabileceimi dndm rneklerime gemek istiyorum. Uygulamamzn formu aadaki
ekildeki gibi olucak.

ekil 1. Form Tasarmmz.

imdi kodlarmz yazalm.

public void z1()


{
for(int i=1;i<60;++i)
{
zaman1.Value+=1;
for(int j=1;j<10000000;++j)
{
j+=1;
}
}
}
public void z2()
{
for(int k=1;k<100;++k)
{
zaman2.Value+=1;
for(int j=1;j<25000000;++j)
{
j+=1;
}
}
}
private void btnBaslat_Click(object sender, System.EventArgs e)
{
z1();
z2();

www.bsenyurt.com Page 2526


}

Program kodlarmz ksaca aklayalm. Z1 ve z2 isimli metodlarmz progressBar kontrolllerimizin


deerlerini belirli zaman aralklaryla arttryorlar. Bu ilemleri geekletirmek iin, Balat balkl
butonumuza tklyoruz. Burada nce z1 daha sonrada z2 isimli metodumuz altrlyor. Bunun
sonucu olarak nce zaman1 isimli progressBar kontrolmz doluyor ve dolmas bittikten sonra
zaman2 isimli progressBar kontrolmzn value deeri arttrlarak dolduruluyor.

imdi bu programn yle almasn istediimizi dnelim. Her iki progressBar'da ayn anda
dolmaya balasnlar. stediimiz zaman z1 ve z2 metodlarnn almasn durduralm ve tekrar
balatabilelim. Tekrar balattmzda ise progressBar'lar kaldklar yerden dolmaya devam etsinler.
Sz ettiimiz aslnda her iki metodunda ayn anda almasdr. te bu ii baarmak iin bu
metodlar sisteme birer i paraca ( thread ) olarak tantmal ve bu thread'leri ynetmeliyiz.

.Net ortamnda thread'ler iin System.Threading isim uzayn kullanrz. ncelikle programmza bu
isim uzayn ekliyoruz. Ardndan z1 ve z2 metodlarn birer i parac olarak tanmlamamz
gerekiyor. te kodlarmz.

public void z1()


{
for(int i=1;i<60;++i)
{
zaman1.Value+=1;
for(int j=1;j<10000000;++j)
{
j+=1;
}
}
}
public void z2()
{
for(int k=1;k<100;++k)
{
zaman2.Value+=1;
for(int j=1;j<25000000;++j)
{
j+=1;
}
}
}
ThreadStart ts1;
ThreadStart ts2;
Thread t1;
Thread t2;
private void btnBaslat_Click(object sender, System.EventArgs e)
{
ts1=new ThreadStart(z1); /* ThreadStart i parac olarak kullanlcak metod iin bir
temsilcidir. Bu metod iin tanmlanacak thread snf nesnesi iin paramtere olucak ve bu nesnenin
hangi metodu i parac olarak greceini belirtecektir. */

www.bsenyurt.com Page 2527


ts2=new ThreadStart(z2);
t1=new Thread(ts1);
t2=new Thread(ts2);
t1.Start(); /* paran Start metodu ile balatyoruz. */
t2.Start();
btnBaslat.Enabled=false;
}
private void btnDurdur_Click(object sender, System.EventArgs e)
{
t1.Suspend(); /* paraca geici bir sre iin uyku moduna geer. Uyku modundaki bir i
paracan tekrar aktif hale getirmek iin Resume metodu kullanlr. */
t2.Suspend();
}
private void btnDevam_Click(object sender, System.EventArgs e)
{
t1.Resume(); /* Uyku modundaki i paracnn kald yerden devam etmesini salar. */
t2.Resume();
}
private void btnKapat_Click(object sender, System.EventArgs e)
{
if(t1.IsAlive) /* Eer i paracklar henz sonlanmamsa bunlar canldr ve IsAlive zellikleri
true deerine sahiptir. Programmzda ilk biten i parac t1 olucandan onun bitip bitmediini
kontrol ediyoruz. Eer bitmi ise programmz close metodu sayesinde kapatlabilir. */
{
MessageBox.Show("alan threadler var program sonlanamaz.");
}
else
{
this.Close();
}
}

Uygulamamzda z1 ve z2 isimli metodlarmz birer i parac (thread) haline getirdik. Bunun iin
System.Threding isim uzaynda yer alan ThreadStart ve Thread snflarn kullandk. ThreadStart
snf , i parac olucak metodu temsil eden bir delegate gibi davranr. paracklarn
balatcak(start), durdurucak(suspend), devam ettirecek(resume) thread nesnelerimizi
tanmladmz yapc metod ThreadStart snfndan bir temsilciyi parametre olarak alr. Sonu
itibariyle kullanc Balat balkl button kontrolne tkladnda, her iki progressBar kontrolnnde
ayn zamanda dolmaya baladn ve ilerlediklerini grrz. Bu aamada Durdur isimli button
kontrolne tklarsak her iki progressBar'n ilerleyiinin durduunu grrz. Nitekim i
paracklarnn Suspend metodu arlm ve metodlarn altrlmas durdurulmutur.

www.bsenyurt.com Page 2528


ekil 2. Suspend metodu sonras.

Bu andan sonra tekrar Devam button kontrolne tklarsak thread nesnelerimiz Resume metodu
sayesinde almalarna kaldklar yerden devam ediceklerdir. Dolaysyla progressBar
kontrolllerimizde kaldklar yerden dolmaya devam ederler. Bu srada program kapatmaya
almamz henz sonlanmam i paracklar nedeni ile hataya neden olur. Bu nedenle Kapat
button kontrolnde IsAlive zellii ile i paracklarnn canl olup olmad yani metodlarn
almaya devam edip etmedii kontrol edilir. Eer sonlanmamsa kullanc aadaki mesaj kutusu
ile uyarlr.

ekil 3. Paracklar henz sonlanmam ise.

Evet geldik Threading ile ilgili makale dizimizin ilk blmnn sonuna . Bir sonraki makalemizde
Threading kavramn dahada derinlemesine incelemeye alacaz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2529


Boxing (Kutulamak) ve Unboxing (Kutuyu
Kaldrmak) ( 30.12.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, Boxing ve Unboxing kavramlarn incelemeye alacaz. Boxing deer


tr bir deikeni, referans tr bir nesneye aktarmaktr. Unboxing ilemi ise bunun tam tersidir.
Yani referans tr deikenin iaret ettii deeri tekrar , deer tr bir deikene aktarmaktr. Bu
tanmlarda karmza kan ve bilmemiz gereken en nemli noktalar, deer tr deikenler ile
referans tr nesnelerin bellekte tutulu ekilleridir.

Net ortamnda iki tr veri tipi vardr. Referans tipleri (reference type) ve deer tipleri (value
type). ki veri trnn bellekte farkl ekillerde tutulmalar nedeni ile boxing ve unboxing ilemleri
gndeme gelmitir. Bu nedenle ncelikle bu iki farkl veri tipinin bellekte tutulu ekillerini iyice
anlamamz gerekmektedir.

Bu anlamda karmza iki nemli bellek blgesi kar. Yn (stack) ve bek (heap). Deer tipi
deikenler, rnein bir integer deiken vb.. bellein stack ad verilen ksmnda tutulurlar.
DotNette yer alan deer trleri aadaki tabloda yer almaktadr. Bu tiplerin stack blegesinde nasl
tutulduuna ilikin aklayc ekli de aada grebilirsiniz.

Value type ( Deer Tipler)

bool long

byte sbyte

char short

decimal Struct ( Yaplar )

double uint

Enum ( Numaralandrclar ) ulong

float ushort

int

Tablo 1. Deer Tipleri

www.bsenyurt.com Page 2530


ekil 1. Deer Tiplerinin Bellekte Tutuluu

ekildende grld gibi, Deer Trleri bellekte, Stack dediimiz blgede tutulurlar. imdi
buraya kadar anlalmayan bir ey yok. lgin olan reference( bavuru) tiplerinin bellekte nasl
tutulduudur. Adndanda anlald gibi reference tipleri asl veriye bir bavuru
ieriler. rnein snflardan trettiimiz nesneler bu tiplerdendir. Dier bavuru tipleri ise
aadaki tabloda yer almakdadr.

Reference Type ( Bavuru Tipleri


)

Class ( snflar )

Interface ( arayzler )

Delegate ( delegeler )

Object

String

Tablo 2. Bavuru Tipleri

imdi gelin bavuru trlerinin bellekte nasl tutulduklarna bakalm.

www.bsenyurt.com Page 2531


ekil 2. Bavuru tiplerinin bellekte tutuluu.

Grld gibi ,bavuru tipleri hakikatende isimlerinin layn vermekteler. Nitekim asl
veriler bekte tutulurken ynda bu verilere bir bavuru yer almaktadr. ki veri tr arasndaki
bu farktan sonra bir farkta bu verilerle iimiz bittiinde geri iade edili ekilleridir. Deer trleri
ile iimiz bittiinde bunlarn ynda kapladklar alanlar otomatik olarak yna geri
verilir. Ancak referans trlerinde sadece yndaki bavuru sisteme geri
veririlir. Verilerin tutulduu bekteki alanlar, Garbage Collectorun denetimindedirler ve ne zaman
sisteme iade edilicekleri tam olarak bilinmez. Bu ayr bir konu olmakla beraber olduka
karmaktr. lerleyen makalelerimizde bu konudan da bahsetmeye alacam.

Deer trleri ile bavuru trleri arasndaki bu temel farktan sonra gelelim asl
konumuza. . NETte her snf aslnda en st snf olan Object snfndan trer. Yani her snf
aslnda System.Object snfndan kaltm yolu ile otomatik olarak tretilmi olur. Sorun object gibi
referans bir tre, deer tipi bir deerin aktarlmasnda yaanr. . NETte herey aslnda birer nesne
olarak dnlebilir. Bir deer trn bir nesneye atamaya altmzda, deer trnn ierdii
verinin bir kopyasnn yndan alnp, bee tanmas ve nesnenin bu veri kopyasna bavurmas
gerekmektedir. te bu olay kutulama ( boxing ) olarak adlandrlr. Bu durumu minik bir rnek ile
inceleyelim.

using System;
namespace boxunbox
{
class Class1
{
static void Main(string[] args)
{
double db=509809232323;
object obj;
obj=db;
Console.WriteLine(db.ToString());
Console.WriteLine(obj.ToString());
db+=1;
Console.WriteLine(db.ToString());

www.bsenyurt.com Page 2532


Console.WriteLine(obj.ToString());
}
}
}

Kodumuzun almasn inceleyelim. Db isimli double deikenimiz bir deer tipidir. rnekte bu
deer tipini object tipinden bir nesneye aktaryoruz. Bu halde bu deerler ierisindeki verileri
ekrana yazdryoruz. Sonra db deerimizi 1 arttryor ve tekrar bu deerlerin ieriini ekrana
yazdryoruz. te sonu;

ekil 3 Boxing lemi

Grld gibi db deikenine yaplan arttrm object trnden obj nesnemize yansmamtr.
nk boxing ilemi sonucu, obj nesnesi , db deerinin bekteki kopyasna bavurmaktadr.
Oysaki artm db deikeninin ynda yer alan orjinal deeri zerinde gereklemektedir. Bu ilemi
aklayan ekil aada yer almaktadr.

ekil 4. Boxing lemi

Boxing ilemi otomatik olarak yaplan bir ilemdir. Ancak UnBoxing ileminde durum biraz daha
deiir. Bu kez , bavuru nesnemizin iaret ettii veriyi bekten alp yndaki bir deer tipi alan
olarak kopyalanmas sz konusudur. te burada tip uyumazl denen bir kavramla
karlarz. bekten , yna kopylanacak olan verinin, ynda kendisi iin ayrlan yerin ayn tipte
olmas veya bekteki tipi ierebilecek tipte olmas gerekmektedir. rnein yukardaki rneimize
unboxing ilemini uygulayalm. Bu kez integer tipte bir deer trne atama gerekletirelim.

using System;
namespace boxunbox
{

www.bsenyurt.com Page 2533


class Class1
{
static void Main(string[] args)
{
double db=509809232323;
object obj;
obj=db;
Console.WriteLine(db.ToString());
Console.WriteLine(obj.ToString());
db+=1;
Console.WriteLine(db.ToString());
Console.WriteLine(obj.ToString());
int intDb;
intDb=(int)obj;
Console.WriteLine(intDb.ToString());
}
}
}

Bu kodu altrdmzda InvalidCastException istisnasnn frlatlacan


grceksiniz. n referenas tipimizin bekte bavurduu veri tipi integer bir deer iin fazla
byktr. Bu noktada ( int) ile aka dnm bildirmi olsak dahi bu hatay alrz.

ekil 5. InvalidCastException stisnas

Ancak kk tipi, byk tipe dntrmek gibi bir serbestliimiz vardr. rnein,

using System;
namespace boxunbox
{
class Class1
{
static void Main(string[] args)
{
double db=509809232323;
object obj;
obj=db;
Console.WriteLine(db.ToString());
Console.WriteLine(obj.ToString());

www.bsenyurt.com Page 2534


db+=1;
Console.WriteLine(db.ToString());
Console.WriteLine(obj.ToString());
/*int intDb;
intDb=(int)obj;
Console.WriteLine(intDb.ToString());*/
double dobDb;
dobDb=(double)obj;
Console.WriteLine(dobDb.ToString());
}
}
}

Bu durumda kodumuz sorunsuz alacaktr. nk ynda yer alan veri tipi daha byk boyutlu
bir deer trnn iine koyulabilir. te buradaki aktarm ilemi unboxing olarak isimlendirilmitir.
Yani boxing ilemi ile kutulanm bir veri kmesi, bekten alnp tekrar yndaki bir Alana
konulmu dolaysyla kutudan kartlmtr. Olayn grafiksel aklamas aadaki gibidir.

ekil 6. Unboxing lemi

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

SqlDataReader Snf 2 ( 29.12.2003 ) - Ado.Net


Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde SqlDataReader snfn incelemeye balamtk Listeleme amal veri
kmelerinin grntlemesinde performans asndan etkin bir rol oynadndan

www.bsenyurt.com Page 2535


bahsetmitik. Bugnk makalemizde , SqlDataReader snfnn faydal dier zelliklerinden
bahsedeceiz. ncelikle, bir SqlDataReader nesnesinin, geerli ve ak bir SqlConnection nesnesi
zerinde alan bir SqlCommand nesnesi yardmyla oluturulduunu hatrlayalm. Burada
SqlCommand snfna ait ExecuteReader metodu kullanlmaktadr. ExecuteReader metoduna deiik
parametreler geirerek uygulamann performansn dahada arttrabiliriz. nceki makalemizde,
CommandBehavior.CloseConnection parametre deerini kullanmtk. CommandBehavior,
altrlacak olan sql sorgusu iin bir davran belirlememizi salar. SqlCommand nesnesinin
ExecuteReader metodunun alabilecei parametre deerleri ekil1 de grlmektedir. Bunlarn ne ie
yarad ksaca tablo 1 de bahsedilmitir.

ekil 1. CommandBehavior Davranlar

CommandBehavior Deeri levi

SqlDataReader nesnesi Close metodu ile


kapatldnda, ,ilikili SqlConnection
nesneside otomatik olarak kapatlr. Nitekim,
CommandBehavior.CloseConnection
iimiz bittiinde SqlConnection nesnesinin ak
unutulmas sistem kaynaklarnn gereksiz yere
harcanmasna neden olur.

En ok kullanlan parametrelerden
birisidir.Eer sql sorgumuz tek bir satr
dndrecek tipte ise bu davran kullanmak
CommandBehavior.SingleRow performans olumlu ynde etkiler. rnein
PrimaryKey zerinden yaplan sorgular. (
Select * From Tablo Where ID=3
tarznda.)

Tek bir deer dndrecek tipteki sorgular iin


kullanlr. rnein belli bir alandaki saysal
deerlerin toplam veya tablodaki kayt
CommandBehavior.SingleResult saysn veren sorgular gibi. Bu teknie
alternatif olan ve daha ok tercih edilen bir
dier yntem, SqlCommand nesnesinin
ExecuteScalar metodudur

altrlan sorgu sonucu elde edilen


CommandBehavior.SchemaOnly
satr(satrlarn) sadece alan bilgisini dndrr.

www.bsenyurt.com Page 2536


Baz durumlarda tablo alanlar ok byk
boyutlu binary tipte veriler ierebilirler. Bu
tarz byk verilerinin okunmas iin en kolay
yol bunlar birer akm (stream) halinde bellee
CommandBehavior.SequentialAccess
okumak ve oradan ilgili nesnelere tamaktr.
SequnetialAccess davran bu tarz akmlarn
ilenmesine imkan tanrken performansda
arttrmaktadr.

Bu durumda sql sorgusu sonucunda


CommandBehavior.KeyInfo SqlDataReader nesnesi, tabloya ait anahtar
alan bilgisini ierir.

Tablo 1. CommandBehavior Davranlar

imdi dilerseniz basit Console uygulamalar ile, yukardaki davranlarn ileyilerini


inceleyelim. CommandBehavior. CloseConnection durumunu nceki makalemizde ilediimiz iin
tekrar ileme gerei duymuyorum. imdi en ok kullanacamz davranlardan birisi olan
SingleRow davranna bakalm. Uygulamamz ID isimli PrimaryKey alan zerinden bir sorgu
altryor. Dnen veri kmesinin tek bir satrdan oluaca kesindir. Bu durum, SingelRow
davrann kullanmak iin en ideal durumdur.

using System;
using System.Data;
using System.Data.SqlClient;
namespace SqlDataReader2
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;integrated
security=sspi;initial catalog=Friends");
SqlCommand cmd=new SqlCommand("Select * From Kitaplar Where
ID=18",conFriends); /* Sql sorgumuz ID isimli primary key zerinden bir sorgu altryor ve 18
nolu ID deerine sahip satr elde ediyor. Burada tek satrlk veri olduu kesin. */
SqlDataReader dr;
conFriends.Open();
dr=cmd.ExecuteReader(CommandBehavior.SingleRow); /* Tek satrlk veri iin
davranmz SingleRow olarak belirliyoruz. */
dr.Read(); /* Elde edilen satr bellee okuyoruz. Grld gibi herhangibir while
dngs kullanma gerei duymadk.*/
for(int i=0;i<dr.FieldCount;++i) /* Satrn alan says kadar devam edicek bir dng
kuruyoruz ve her alann adn GetName, bu alanlara ait deerleride dr[i].ToString ile ekrana
yazdryoruz. */
{
Console.WriteLine(dr.GetName(i).ToString()+"="+dr[i].ToString());
}

www.bsenyurt.com Page 2537


dr.Close(); /* SqlDataReader nesnemizi kapatyoruz. Ardndan SqlConnection
nesnemizide kapatmay unutmuyoruz. Bylece bu nesnelere ait kaynaklar serbest kalm oluyor.*/
conFriends.Close();
}
}
}

ekil 2. SingleRow davran.

imdi SingleResult davrann inceleyelim. Bu kez Northwind veritabannda yer alan Products
tablosundaki UnitPrice alanlarnn ortalamasn hesaplayan bir sql sorgumuz var. Burada tek bir
deer dnmektedir. te SingleResult bu duruma en uygun davran olucaktr.

using System;
using System.Data;
using System.Data.SqlClient;
namespace SqlDataReader3
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conNorthwind=new SqlConnection("data source=localhost;integrated
security=sspi;initial catalog=Northwind");
SqlCommand cmd=new SqlCommand("Select SUM(UnitPrice)/Count(UnitPrice)As
[Ortalama Birim Fiyat] From Products",conNorthwind);
SqlDataReader dr;
conNorthwind.Open();
dr=cmd.ExecuteReader(CommandBehavior.SingleResult);
dr.Read();
Console.WriteLine(dr.GetName(0).ToString()+"="+dr[0].ToString());
dr.Close();
conNorthwind.Close();
}
}
}

www.bsenyurt.com Page 2538


ekil 3. SingleResult davran.

imdie SchemaOnly davrann inceleyelim. nce aadaki kodlar yazp altralm.

using System;
using System.Data;
using System.Data.SqlClient;
namespace SqlDataReader4
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conNorthwind=new SqlConnection("data source=localhost;integrated
security=sspi;initial catalog=Northwind");
SqlCommand cmd=new SqlCommand("Select * From Products",conNorthwind);
SqlDataReader dr;
conNorthwind.Open();
dr=cmd.ExecuteReader(CommandBehavior.SchemaOnly);
dr.Read();
try
{
for(int i=0;i<dr.FieldCount;++i)
{
Console.WriteLine(dr.GetName(i).ToString()+" "+ dr.GetFieldType(i).ToString()+"
"+dr[i].ToString());
}
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
dr.Close();
conNorthwind.Close();
}
}
}

Yukardaki console uygulamasn altrdmzda aadaki hata mesajn alrz.

www.bsenyurt.com Page 2539


ekil 4. Hata.

SchemaOnly davran sorgu ne olursa olsun sadece alan bilgilerini dndrr. Herhangibir veri
dndrmez. Bu yzden dr[i].ToString() ifadesi i nolu indexe sahip alan iin herhangibir veri
bulamaycaktr. Kodun bu blmn aadaki gibi deitirirsek;

Console.WriteLine(dr.GetName(i).ToString()+" "+dr.GetFieldType(i).ToString());

Ve imdi console uygulamamz altrrsak aadaki ekran grntsn elde ederiz. GetFieldType
metodu i indeksli alann veri tipinin .NETteki karln dndrrken GetName ile bu alann adn
elde ederiz.

ekil 5. SchemaOnly davran.

imdi SequentialAccess davrann inceleyelim. Bu sefer pubs isimli veritabannda yer alan
pub_info isimli tablonun Text tipinde uzun veriye sahip pr_info alannn kullanacaz. Sorgumuz
belli bir pub_id deerine sahip satrn pr_info alann alyor. Biz GetChars metodunu kullanarak alan
iindeki veriyi karakter karakter okuyor ve belee doru bir akm (stream) oluturuyoruz. GetChars
metodu grld zere 5 parametre almaktadr. l parametre ile hangi alann okunacan
belirtiriz. kin paramtere bu alann kanc karakterinden itibaren okunmaya balanaca bildirir.
nc parameter ise char tipinden bir diziyi belirtir. Okunan her bir karakter bu diziye
aktarlacaktr. Drdnc parameter ile dizinin kanc elemanndan itibaren aktarmn yaplaca
belirtilir. Son parametremiz ise ne kadar karakter okunacan belirtmektedir. imdi kodlarmz
yazalm.

using System;
using System.Data;
using System.Data.SqlClient;
namespace SqlDataReader5
{
class Class1
{
static void Main(string[] args)
{
SqlConnection conPubs=new SqlConnection("data source=localhost;integrated
security=sspi;initial catalog=pubs");
SqlCommand cmd=new SqlCommand("Select pr_info From pub_info where
pub_id=0736",conPubs);
SqlDataReader dr;
conPubs.Open();

www.bsenyurt.com Page 2540


dr=cmd.ExecuteReader(CommandBehavior.SequentialAccess);
dr.Read();
try
{
char[] dizi=new char[130]; /* 130 char tipi elemandan oluan bir dizi tanmladk. */
dr.GetChars(0,0,dizi,0,130); /* Dizimize pr_info alanndan 130 karakter okuduk.*/
for(int i=0;i<dizi.Length;++i) /* Dizideki elemanlar ekrana yazdryoruz. */
{
Console.Write(dizi[i]);
}
Console.WriteLine();
}
catch(Exception hata)
{
Console.WriteLine(hata.Message.ToString());
}
dr.Close();
conPubs.Close();
}
}
}

Sonu olarak ekran grntmz aadaki gibi olucaktr.

ekil 6. SequentialAccess davran.

Evet deerli Okurlarm. Geldik bir makalemizin daha sonuna. Umarm sizi, SqlDataReader snf ile
ilgili bilgilerle donatabilmiimdir. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler
dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

SqlDataReader Snf 1 ( 28.12.2003 ) - Ado.Net


Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, SqlDataReader snfn incelemeye alacaz. ADO.NETin bilgisayar


programclna getirdii en byk farklklardan birisi balantsz veriler ile allabilmemize imkan
salamasyd. DataSet snfn ve buna bal dier teknikleri kastettiimi anlamsnzdr. Bu

www.bsenyurt.com Page 2541


teknikler ile, bir veritaban iinde yer alan tablolar, tablolar arasndaki ilikileri, ierdikleri verileri
vb istemci makinenin belleinde tutmamz mmkn olabiliyor. Bu sayede, bu veriler istemci makine
bellei zerinde tutulduundan, bir veritabanna srekli balants olan bir sisteme gore daha hzl
alabiliyoruz. Ayrca veritaban sunucusuna srekli olarak bal olmadmz iin network
trafiinide hafifletmi oluyoruz. Tm bu ho ayrntlar dnda hepimiz iin naho olan ayrnt, her
halikarda bellek tketiminin artmas. yleki bazen kullandmz programlarda sadece listeleme
amac ile, sadece grsellik amac ile kk veriler ile almak durumunda kaldmzda, bu elde
edilebilirlik iin fazlasyla kaynak tketmi oluyoruz. te ADO.NET te bu tip veriler dnlerek,
listeleme amac gden, kk boyutlarda olan veri kmeleri iin DataReader snflar tasarlanm.
Biz bugn SqlDataReader snfn inceleyeceiz.

Bir SqlDataReader snf bir veri akmn(data stream) temsil eder. Bu nedenle herhangibir anda
bellekte sadece bir veri satrna eriebilir. te bu performans ve hz arttran bir unsurdur. Bu veri
akmn elde etmek iin srekli ak bir sunucu balants ve verileri getirecek sql sorgularn
altracak bir SqlCommand nesnesi gereklidir. Dikkat edicek olursanz srekli ak olan bir sql
sunucu balantsndan yani bir SqlConnectiondan bahsettik. SqlDataReader nesnesi sql sunucu
balantsnn srekli ak olmasn gerektirdii iin network trafiini megul eder, ayn zamanda
kulland SqlConnection nesnesinin baka ilemler iin kullanlmasnda engeller. te bu eksiler
nedeni ile, onun sadece okuma amal veya listeleme amal ve yanlz okunabilir veri kmeleri iin
kullanlmas nerilir. Bu nedenlede, read-only(yanlz okunabilir) ve forward-only(sadece ileri ynl)
olarak tanmlanr. imdi SqlDataReader nesnesi ile bir veri akmnn elde edilmesi konusunu
aadaki ekil yardmyla incelemeye alalm.

ekil 1. SqlDataReader nesnesinin alma ekli.

Grld gibi sql sunucusuna srekli bal durumdayz. Bunun yannda SqlCommand sorgusunun
altrlmas sonucu elde edilen veri akm SqlDataReader nesnesince temsil edilmektedir. stemci
bilgisayarmz, her hangibir t zamannda kendi belleinde SqlDataReadern tad veri akmnn
sadece tek bir satrn temsil etmektedir. SqlCommand nesnesinin altrd sql cmleciinin
sonucunu(sonu kmesini) SqlDataReader nesnemize aktarmak iin ExecuteReader metodu
kullanlr. Burada bir noktaya daha deinelim. SqlDataReader snf herhangibi yapc metoda sahip

www.bsenyurt.com Page 2542


deildir. Yani bir SqlDataReader nesnesini bir new metodu ile oluturamayz. Sadece bir
SqlDataReader nesnesi tanmlayabiliriz. Maharet aslnda SqlCommand nesnesinin ExecuteReader
metodundadr. Bu metod ile, daha nceden tanmladmz SqlDataReader nesnesini oluturur ve
SqlCommand sorgusunun sonucu olan veri kmesini temsil etmesini salarz. Ancak bir DataTable
veya bir DataSette olduu gibi sorgu sonucu elde edilen veri kmesinin tamam bellekte
saklanmaz. Bunun yerine SqlDataReader nesnesi kendisini, altrlan sorgu sonularn tutan geici
bir dosyann ilk satrnn ncesine konumlandrr.

te bu noktadan sonraki satrlar okuyabilmek iin bu snfa ait Read metodunu kullanrz. Read
metodu, her zaman bir sonraki satra konumlanlmasn salar. Tabi bir sonrasnda kayt olduu
srece bu ilemi yapar. Bylece bir While dngs ile Read metodunu kullanrsak, sorgu sonucu
elde edilen veri kmesindeki tm satrlar gezebiliriz. Konumlanlan her bir satr bellekte temsil
edilir. Dolaysyla bir sonraki t zamannda, bellekte eski satrn yerini yeni satr alr. Bu sorgu
sonucu elde edilen veri kmesinden bellee doru devam eden bir akm(stream) dr. Geriye
hareket etmek gibi bir lksmz olmad gibi, t zamannda bellekte yer alan satrlar deitirmek
gibi bir imkanmzda bulunmamaktadr. te performans bu arttrmaktadr. Ama elbetteki ok
byk boyutlu ve satrl verilerle alrken listeleme amacmz yok ise veriler zerinde deiiklikler
yaplabilmesinide istiyorsak bu durumda balantsz veri elemanlarn kullanmak daha mantkl
olucaktr. imdi dilerseniz konumuz ile ilgili bir rnek yapalm. zellikle ticari sitelerde, ounlukla
kullanc olarak rnleri inceleriz. rnein kitap alacaz. Belli bir kategorideki kitaplara bakmak
istiyoruz. Kitaplarn sadece adlar grnr olsun. Kullanc bir kitab setiinde, bu kitaba ait
detaylarda grebilsin. Tm bu ilemler sadece izlemek ve bakmaktan ibaret. Dolaysyla bu veri
listelerini, rnein bir listBox kontrolne ykleyecek isek ve sonu olarak bir listeleme yapcak isek,
SqlDataReader nesnelerini kullanmamz daha avantajl olucaktr. Dilerseniz uygulamamz yazmaya
balayalm. ncelikle Visual Studio.Net ortamnda bir Web Application oluturalm. Default.aspx
isimli sayfamz ben aadaki gibi tasarladm.

ekil 2. WebForm tasarmmz.

imdi de kodlarmz yazalm.

www.bsenyurt.com Page 2543


SqlConnection conFriends;
public void baglantiAc()
{
/* Sql Sunucumuza balanmak iin SqlConnection nesnemizi oluturuyoruz ve balanty
ayoruz. */
conFriends=new SqlConnection("data source=localhost;integrated security=sspi;initial
catalog=Friends");
conFriends.Open();
}
private void Page_Load(object sender, System.EventArgs e)
{
if(!Page.IsPostBack) /* Eer sayfa daha nce yklenmediyse bu if blou iindeki kodlar
altrlyor. */
{
baglantiAc(); /* Sql sunucumuza olan SqlConnection nesnesini tanmlayan ve balanty
aan metodumuzu aryoruz. */
/* SqlCommand nesnemize altracamz sql sorgusunu bildiriyoruz. Bu sorgu Kitaplar
tablosundan Kategori alanna ait verileri Distinct komutu sayesinde, benzersiz ekilde alr. Nitekim
ayn Kategori isimleri tabloda birden fazla sayda. Biz Distinct sasyesinde birbirinden farkl
kategorileri tek tek elde ediyoruz. Bylece veri kmemizizde mmkn olduunca kltm ve bir
SqlDataReader nesnesinin tam diine gre hazrlam oluyoruz. */
SqlCommand cmdKategori=new SqlCommand("Select distinct Kategori From Kitaplar Order
By Kategori",conFriends);
SqlDataReader drKategori; /* SqlDataReader nesnemizi tanmlyoruz. Ltfen tanmlama
eklimize dikkat edin. Sanki bir deiken tanmlyoruz gibi. Herhangibir new yapc metodu yok. */
drKategori=cmdKategori.ExecuteReader(CommandBehavior.CloseConnection); /*
SqlCommand nesnemizin ExecuteReader yardmyla sorgumuzu altryor ve sonu kmesini
temsil edicek SqlDataReader nesnemizi atyoruz. Bu aamada SqlDataReader nesnemiz sorgu
sonucu oluan veri kmesinin ilk satrnn ncesine konumlanyor. */
/* Bahsetmi olduumuz while dngs ile satrlar teker teker ileri doru olucak ekilde
bellee alyoruz. Her bir t zamannda bir satr bellee geliyor ve oradanda ListBox kontrolne iligli
satrn, 0 indexli alanna ait deer GetString metodu ile alnyor. */
while(drKategori.Read())
{
lstKategori.Items.Add(drKategori.GetString(0));
}
drKategori.Close(); /* SqlDataReader nesnemiz kapatlyor. Biz ExecuteReader metodunu
altrrken parametre olarak, CommandBehavior.CloseConnection deerini verdik. Bu bir
SqlDataReader nesnesi kapatldnda, ak olan balantnn otomatik olarak kapatlmasn, yani
SqlConnection balantsnn otomatik olarak kapatlmasn salar. Buda system kaynaklarnn
serbest braklmasn salar.*/
}
}
private void btnKitaplar_Click(object sender, System.EventArgs e)
{
string kategori=lstKategori.SelectedItem.ToString();
baglantiAc();
SqlCommand cmdKitaplar=new SqlCommand("Select distinct Adi,ID From Kitaplar Where
Kategori='"+kategori+"' order by Adi",conFriends);
SqlDataReader drKitaplar;
drKitaplar=cmdKitaplar.ExecuteReader(CommandBehavior.CloseConnection);

www.bsenyurt.com Page 2544


int KitapSayisi=0;
lstKitaplar.Items.Clear();
while(drKitaplar.Read())
{
lstKitaplar.Items.Add(drKitaplar.GetString(0));
KitapSayisi+=1;
}
drKitaplar.Close();
lblKitapSayisi.Text=KitapSayisi.ToString();
/* Yukardaki dngde elde edilen kayt saysn renmek iin KitapSayisi isimli bir sayac
dng iine koyduumuzu farketmisinizdir. SqlDataReader nesnesi herhangibir t zamannda
bellekte sadece bir satr temsil eder. Asl veri kmesinin tamamn iermez, yani bellee almaz. Bu
nedenle veri kmesindeki satr saysn temsil edicek, Count gibi bir metodu yoktur. te bu nedenle
kayt saysn bu teknik ile renmek durumundayz. */
}
private void lstKitaplar_SelectedIndexChanged(object sender, System.EventArgs e)
{
string adi=lstKitaplar.SelectedItem.ToString();
baglantiAc();
SqlCommand cmdKitapBilgisi=new SqlCommand("Select * From Kitaplar Where
Adi='"+adi+"'",conFriends);
SqlDataReader drKitapBilgisi;
drKitapBilgisi=cmdKitapBilgisi.ExecuteReader(CommandBehavior.CloseConnection);
lstKitapBilgisi.Items.Clear();
while(drKitapBilgisi.Read())
{
/* FieldCount zellii SqlDataReader nesnesinin t zamannda bellekte temsil etmi olduu
satrn kolon saysn vermektedir. Biz burada tm kolonlardaki verileri okuyacak dolaysyla t
zamannda bellekte yer alan satrn verilerini elde edebileceimiz bir For dngs oluturduk.
Herhangibir alann deerine, drKitapBilgisi[i].ToString() ifadesi ile ulayoruz. */
for(int i=0;i<drKitapBilgisi.FieldCount;++i)
{
lstKitapBilgisi.Items.Add(drKitapBilgisi[i].ToString());
}
lstKitapBilgisi.Items.Add("------------------");
}
drKitapBilgisi.Close();
}

imdi programmz bir altralm ve sonularn bir grelim.

www.bsenyurt.com Page 2545


ekil 3. Programn almasnn sonucu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde SqlDataReader snfn incelemeye
devam edeceiz. zellikle SqlCommand snfnn ExecuteReader metodunun ald parameter
deerlerine gore nasl sonular elde edebileceimizi incelemeye alacaz. Bunun yannda
SlqDataReader snfnn dier zelliklerinide inceleyeceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Kaltm (Inheritance) Kavramna Ksa Bir Bak


( 25.12.2003 ) - C#
Deerli Okurlarm, Merhabalar.

Bir nceki makalemizde C# dilinde snf kavramna bir giri yapm ve OOP(Objcet Oriented
Programming-Nesneye Dayal Programlama) tekniinin en nemli kavramlarndan biri olan
kaltmdan bahsedeceimizi sylemitik. Bugnk makalemizde bu kavram incelemeye
alacaz.

Kaltm kavram iin verilebilecek en gzel rnekler doamzda yer almaktadr. rnein Bitkiler,
trlerine gore snflandrlrlar. Ancak hepsinin birer bitki olmas ortak bir takm zelliklere sahip
olduklar anlamnada gelmektedir. Bitki isimli bir snf gz nne alp Aalar,iekler,Deniz
Bitkileri vb gibi alt snflara ayrabiliriz. Tm bu alt snflar Bitki snfndan gelmekte, yani
tremektedirler. Ayn ekilde Bitki tr olan bir snf kendi iinde baka alt snflara ayrlabilir.
rnein, iek snf Gller, Orkideler, Papatyalar vb Tm bu nesneler hiyerarik bir yapda ele
alndklarnda temel bir snftan tredikleri grlebilmektedir.

www.bsenyurt.com Page 2546


Temel bir nesne ve bu nesneden bir takm zellikleri alm ve baka ek zelliklere sahip olan
nesneler bir araya getirildiklerinde aralarndaki ilikinin kaltmsal olduundan sz ederiz.
te nesneye dayal programlama dillerininde en nemli kavramlarndan birisi kaltmdr. Ortak
zelliklere sahip olan tm nesneleriniz iin bir snf yazarsnz. Ancak elinizde bu ortak zelliklerin
yannda baka ek zelliklere sahip olacak veya ortak zelliklerden bir kan farkl ekillerde
deerlendirecek nesnelerinizde olabilir. Bunlar iin yazacanz snf , ilk snf temel snf olarak baz
alcak ve bu temel snftan tretilecek ve kendi zellikleri ile ilevselliklerine sahip olucaktr.
Konuyu daha iyi pekitirmek amac ile aadaki ekili gz nne alarak durumu zihnimizde
canlandrmaya alalm.

ekil 1. Inheritance Kavram

C# ile Temel bir snftan birden fazla snf tretebilirsiniz. Ancak bir snf birden fazla snftan
tretmeniz mmkn deildir. Bunu yapmak iin arayzler (interface) kullanlr. Treyen bir snf
tredii snfn tm zelliklerine ve ilevlerine sahiptir ve tredii snftaki bu elemanlarn yeniden
tanmlanmasna gerek yoktur. Ayrca siz yeni zellikler ve ilevsellikler katabilirsiniz. Bu
makalemizdeki rnek uygulamamzda kaltmda nemli role sahip base ve new anahtar
kelimelerinin kullanmnda greceksiniz. Base ile temel snfa nasl paramtere gnderebileceimizi,
temel snftaki metodlar nasl arabileceimizi ve new anahtar szc sayesinde treyen snf
iinde, temel snftaki ile ayn isme sahip metodlarn nasl ilevsellik kazanacan da inceleme
frsat bulacaksnz. Dilerseniz bu ksa aklamalardan sonra hemen rnek uygulamamzn kodlarna
geelim. Konu ile ilgili detayl aklamalar rnek ierisindeki yorum satrlarnda bulabilirisiniz.

using System;
namespace Inheritance1
{

class TemelSinif /* ncelikle temel snfmz yani Base Class'mz yazalm. */

private string SekilTipi; /* Sadece bu class iinde tanml bir alan tanmladk. Bu alana
Treyen snfmz (derived class) ierisinden de eriemeyiz. Eer temel snfta yer alan bir alana
sadece treyen snftan eriebilmek ve baka snflardan eriilmesini engellemek istiyorsak, bu
durumda bu alan protected olarak tanmlarz.*/

www.bsenyurt.com Page 2547


/* Bir zellik tanmlyoruz. Sadece get blou olduu iin yanlzca okunabilir bir zellik. */

public string sekilTipi

get

return SekilTipi;

public TemelSinif() /* Temel snfmzn varsaylan yapc metodu. */

SekilTipi="Kare";

public TemelSinif(string tip) /* Overload ettiimiz yapc metodumuz. */

SekilTipi=tip;

public string SekilTipiYaz() /* String sonu dndren bir metod.*/

return "Bu Nesnemiz, "+SekilTipi.ToString()+" tipindedir";

/* te treyen snfmz. :TemelSinif yazm ile, bu snfn TemelSinif'tan tretildiini


belirtiyoruz. Bylece, TureyenSinif class'mz TemelSnf class'nn zelliklerinide bnyesinde
barndrm oluyor.*/

class TureyenSinif:TemelSinif

private bool Alan;

www.bsenyurt.com Page 2548


private bool Cevre;

private int Taban;

private int Yukseklik;

private int UcuncuKenar;

private bool Kare;

private bool Dikdortgen;

private bool Ucgen;

public bool alan

get

return Alan;

public bool cevre

get

return Cevre;

public int taban

get

return Taban;

www.bsenyurt.com Page 2549


}

public int yukseklik

get

return Yukseklik;

public int ucuncuKenar

get

return UcuncuKenar;

public bool kare

get

return Kare;

set

Kare=value;

www.bsenyurt.com Page 2550


}

public bool dikdortgen

get

return Dikdortgen;

set

Dikdortgen=value;

public bool ucgen

get

return Ucgen;

set

Ucgen=value;

public TureyenSinif():base() /* Burada base anahtar kelimesine dikkatinizi ekerim. Eer bir
TureyenSinif nesnesini bu yapc metod ile tretirsek, TemelSinif'taki yapc metod altrlacaktr.
*/

www.bsenyurt.com Page 2551


}

public TureyenSinif(string tip,bool alan,bool cevre,int taban,int yukseklik,int ucuncuKenar):b


ase(tip) /* Buradada base anahtar kelimesi kullanlmtr. Ancak sadece tip isimli string
deikenimiz, TemelSinif'taki ilgili yapc metoda gnderilmitir. Yani bu yapc metod kullanlarak
bir TureyenSinif nesnesi oluturduumuzda, TemelSinif'taki bir tek string parametre alan yapc
metod arlr ve daha sonra buraya dnlerek aadaki kodlar altrlr.*/

Alan=alan;

Cevre=cevre;

Taban=taban;

Yukseklik=yukseklik;

UcuncuKenar=ucuncuKenar;

public double AlanBul() /* Tureyen snfmzda bir metod tanmlyoruz. */

if(Kare==true)

return Taban*Taban;

if(Dikdortgen==true)

return Taban*Yukseklik;

if(Ucgen==true)

return (Taban*Yukseklik)/2;

return 0;

www.bsenyurt.com Page 2552


}

public double CevreBul() /* Baka bir metod. */

if(Kare==true)

return 4*Taban;

if(Dikdortgen==true)

return (2*Taban)+(2*Yukseklik);

if(Ucgen==true)

return Taban+Yukseklik+UcuncuKenar;

return 0;

public new string SekilTipiYaz() /* Buradaki new anahtar kelimesine dikkat edelim.
SekilTipiYaz metodunun ayns TemelSinif class'mzda yer almaktadr. Ancak bir new anahtar
kelimesi ile ayn isimde bir metodu TureyenSinif class'mz iinde tanmlam oluyoruz. Bu
durumda, TureyenSinif class'ndan oluturulan bir nesneye ait SekilTipiYaz metodu arlrsa,
buradaki kodlar altrlr. Oysaki new anahtar kelimesini kullanmasaydk, TemelSinif iindeki
SekilTipiYaz metodunun altrlacan grecektik. */

if(Kare==true)

return "kare";

if(Dikdortgen==true)

www.bsenyurt.com Page 2553


{

return "dikdortgen";

if(Ucgen==true)

return "gen";

return "Belirsiz";

class Class1

static void Main(string[] args)

/* nce TemelSinif tipinde bir nesne oluturup SekilTipiYaz metodunu aryoruz.*/

TemelSinif ts1=new TemelSinif();

Console.WriteLine(ts1.SekilTipiYaz());

TemelSinif ts2=new TemelSinif("Dikdrtgen"); /* Bu kes TemelSinif tipinden bir nesneyi


dier yapc metodu ile aryor ve SekilTipiYaz metodunu altryoruz. */

Console.WriteLine(ts2.SekilTipiYaz());

/* imdi ise TureyenSinif'tan bir nesne oluturduk ve sekilTipi isimli zelliin deerini
aldk. Kodlara bakcak olursanz sekilTipi zelliinin TemelSinif iinde tanmlandn grrsnz.
Yani TureyenSinif nesnemizden, TemelSinif class'ndaki izin verilen alanlara,metodlara vb..
ulaabilmekteyiz.*/

TureyenSinif tur1=new TureyenSinif();

Console.WriteLine(tur1.sekilTipi);

/* imdi ise baka bir TureyenSinif nesnesi tanmladk. Yapc metodumuz'un ilk
parametresinin deeri olan "Benim eklim" ifadesi base anahtar kelimesi nedeni ile, TemelSinif
class'ndaki ilgili yapc metoda gnderilir. Dier parametreler ise TureyenSinif class' iinde
ilenirler. Bu durumda tur2 isimli TureyenSinif nesnemizden TemelSinifa ait sekilTipi zelliini
ardmzda, ekrana Benim eklim yazdn grrz. nk bu deer TemelSinif class'mzda

www.bsenyurt.com Page 2554


ilenmi ve bu class'taki zellie atanmtr. Bunu salayan base anahtar kelimesidir.*/

TureyenSinif tur2=new TureyenSinif("Benim eklim",true,true,2,4,0);

Console.WriteLine(tur2.sekilTipi);

tur2.dikdortgen=true;

Console.WriteLine(tur2.SekilTipiYaz()); /* Tureyen sinif iinde tanmladmz


SekilTipiYaz metodu altrlr. Eer, TureyenSinif iinde bu metodu new ile tanmlamasaydk
TemelSinif class'i iinde yer alan ayn isimdeki metod altrlrdr.*/

if(tur2.alan==true)

Console.WriteLine(tur2.sekilTipi+" Alan:"+tur2.AlanBul());

if(tur2.cevre==true)

Console.WriteLine(tur2.sekilTipi+" evresi:"+tur2.CevreBul());

TureyenSinif tur3=new TureyenSinif("Benim genim",true,false,10,10,10);

Console.WriteLine(tur3.sekilTipi);

tur3.ucgen=true;

Console.WriteLine(tur3.SekilTipiYaz());

Console.WriteLine(tur3.sekilTipi+" Alan:"+tur3.AlanBul());

if(tur2.cevre==true)

Console.WriteLine(tur3.sekilTipi+" evresi:"+tur3.CevreBul());

www.bsenyurt.com Page 2555


Uygulamamz altrdmzda ekran grntmz aadaki gibi olucaktr. Umuyorum ki kaltm ile
ilgili olarak yazm olduumuz bu rnek sizlere yeni fikirler verebilecektir. rnein ok ilevsel
olmas u an iin nemli deil. Ancak bir snfn baka bir snftan nasl tretildiine, zellikle base
ve new anahtar kelimelerinin bize salad avantajlara dikkat etmenizi isterim.

ekil 2. Uygulamann almasnn sonucu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Virtual(Sanal) Metodlar ( 25.12.2003 ) - C#


Deerli Okurlarm, Merhabalar.

Bugnk makalemizde sanal metodlarn kaltm ierisindeki rolne bakacaz. Sanal metodlar,
temel snflarda tanmlanan ve treyen snflarda geersiz klnabilen metodlardr. Bu tanm bize pek
bir ey ifade etmez aslnda. O halde gelin sanal metodlarn neden kullanrz, once buna bakalm. Bu
amala minik bir rnek ile ie balyoruz.

using System;
namespace ConsoleApplication1
{
public class Temel
{
public Temel()
{
}
public void Yazdir()
{
Console.WriteLine("Ben TEMEL(BASE) sinifim");
}

www.bsenyurt.com Page 2556


}
public class Tureyen:Temel
{
public Tureyen()
{
}
public void Yazdir()
{
Console.WriteLine("Ben TUREYEN(DERIVED) sinifim");
}
}
class Class1
{
static void Main(string[] args)
{
Temel bs;
Tureyen drv=new Tureyen();
bs=drv;
bs.Yazdir();
}
}
}

Bu rnei altrmadan once satrlarmz bir inceleyelim. Kodumuz Temel isimli bir base class ve
Tureyen isimli bir Derived Class vardr. Her iki snf iinde Yazdir isimli iki metod tanmlanmtr.
Main metodu iinde Temel snftan trettiimiz bir nesneye ( bs nesnesi) Tureyen snf tipinden bir
nesneyi (drv nesnesi) aktaryoruz. Ardndan bs nesnemizin Yazdir isimli metodunu aryoruz.
Sizce derleyici hangi snfn yazdr metodunu aracaktr. Drv nesnemiz Tureyen snf nesnesi
olduundan ve Temel snftan kaltmsal olarak tretildiinden bs isimli nesnemize aktarlabilmitir.
u durumda bs isimli Temel snf nesnemiz drv isimli Tureyen snf nesnemizi tamaktadr. Bu tip
bir atamam byle base-derived ilikide snflar iin geerli bir atamadr. Sorun bs isimli nesne iin
Yazdir metodunun arlmasndadr. Biz burada Tureyen snf nesnesini aktardmz iin bu snfa
ait Yazdir metodunun altrlmasn bekleriz. Oysaki sonu aadaki gibi olucaktr.

ekil 1. Temel Snfn Yazdir metodu arld.

Grld gibi Temel snfa ait Yazdir metodu altrlmtr. Bir zm olarak daha nceki kaltm
kavramn anlattmz makalemizde inceledeimiz new anahtar kelimesini Tureyen isimli derived
class iinde kullanmay dnebilirsiniz. Birde byle deneyelim, bakalm neler olucak.

using System;
namespace ConsoleApplication1
{
public class Temel

www.bsenyurt.com Page 2557


{
public Temel()
{
}
public void Yazdir()
{
Console.WriteLine("Ben TEMEL(BASE) sinifim");
}
}
public class Tureyen:Temel
{
public Tureyen()
{
}
public new void Yazdir()
{
Console.WriteLine("Ben TUREYEN(DERIVED) sinifim");
}
}
class Class1
{
static void Main(string[] args)
{
Temel bs;
Tureyen drv=new Tureyen();
bs=drv;
bs.Yazdir();
}
}
}

Ancak new anahtar kelimesini kullanm olsakta sonu yine ayn olucaktr ve aadaki grnty
alacazdr.

ekil 2. Yine style='mso-spacerun:yes'> Temel Snfn Yazdir metodu arld.

te bu noktada zm Temel snftaki metodumuzu Virtual( sanal) tanmlamak ve ayn metodu,


Tureyen snf iersinde Override (Geersiz Klmak) etmektir. Sanal metodlarn kullanm amac
budur; Base snfta yer alan metod yerine base snfa aktarlan nesnenin retildii derived classtaki
metodu armaktr.

imdi rneimizi buna gore deitirelim.

www.bsenyurt.com Page 2558


using System;
namespace ConsoleApplication1
{
public class Temel
{
public Temel()
{
}
public virtual void Yazdir()
{
Console.WriteLine("Ben TEMEL(BASE) sinifim");
}
}
public class Tureyen:Temel
{
public Tureyen()
{
}
public override void Yazdir()
{
Console.WriteLine("Ben TUREYEN(DERIVED) sinifim");
}
}
class Class1
{
static void Main(string[] args)
{
Temel bs;
Tureyen drv=new Tureyen();
bs=drv;
bs.Yazdir();
}
}
}

ekil 3. Tureyen snftaki Yazdir metodu arlmtr.

Burada nemli olan nokta, Temel snfaki metodun virtual anahtar kelimesi ile tanmlanmas,
Tureyen snftaki metodun ise override anahtar kelimesi ile tanmlanm olmasdr. Sanal metodlar
kullanrken dikkat etmemiz gereken bir takm noktalar vardr. Bu noktalar;

1 ki metodda ayn isime sahip olmaldr.

www.bsenyurt.com Page 2559


2 ki metodda ayn tr ve sayda parametre almaldr.

3 ki metodunda geri dn deerleri ayn olmaldr.

Metodlarn eriim haklarn ayn olmaldr. Biri public tanmlanm ise dieride public
4
olmaldr.

Temel snftaki metodu treyen snfta override (geersiz) hale getimez isek metod
5
geersiz klnamaz.

Sadece virtual olarak tanmlanm metodlar override edebiliriz. Herhangibir base class
6
yntemini tureyen snfta override edemeyiz.

Bu noktalara dikkat etmemiz gerekmektedir. Deerli Okurlarm, geldik bir makalemizin daha
sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Bir Snf Yazalm ( 23.12.2003 ) - C#


Deerli Okurlarm, Merhabalar.

Bugnk makalemizde ADO.NET kavram ierisinde snflar nasl kullanabileceimizi incelemeye


alacak ve snf kavramna ksa bir giri yapcaz. Nitekim C# dili tam anlamyla nesne ynelimli
bir dildir. Bu dil ierisinde snf kavramnn nemli bir yeri vardr. Bu kavram iyi anlamak, her trl
teknikte, snflarn avantajlarndan yararlanmanz ve kendinize zg nesnelere sahip olabilmenizi
salar. Zaten .net teknolojisinde yer alan her nesne, mutlaka snflardan tretilmektedir.

evremize baktmz zaman, ok eitli canllar grrz. rnein iekler. Dnya zerinde ka
tr(cins) iek olduunu bileniniz var m ? Ama biz bir iek grdmzde ona
ounlukla iek diye hitap ederiz zellikle adn bilmiyorsak. Sonra ise bu iein
renginden, yapraklarnn eklinden, ait olduu trden, adndan bahsederiz. iek tm bu iekler
iin temel bir snf olarak kabul edilebilir. Dnya zerindeki tm iekler iin ortak nitelikleri vardr.
Her iein bir renginin(renklerinin) olmas gibi. te nesne ynelimli programlama kavramnda
bahsedilen ve her eyin temelini oluturan snf kavram bu benzetme ile tamamen ayndr. iek
bir snf olarak alglanrken, sokakta grdmz her iek bu snfn ortak zelliklerine sahip birer
nesne olarak nitelendirilebilir. Ancak tabiki iekler arasnda da trler mevcuttur. Bu trler ise,
iek temel snfndan treyen kendi belirli zellikleri dnda iek snfnn zelliklerinide kaltsal
olarak alan baka snflardr. Bu yaklam inheritance (kaltm) kavram olarak ele alnr ve nesne
ynelimli programlamann temel esinden biridir. Kaltm konusuna ve dierlerine ilerliyen
makalelerimizde deinmeye alacaz.

Bugn yapacamz bir snfn temel yap talarna ksaca deinmek ve kendimize ait iimize
yarayabiliecek bir snf tasarlamak. iek snfndan gerek C# ortamna getiimizde, her eyin bir

www.bsenyurt.com Page 2560


nesne olduunu grrz. Ancak her nesne temel olarak Object snfndan tremektedir. Yani
hereyin stnde bir snf kavram vardr. Snflar, bir takm yelere sahiptir. Bu yeler, bu snftan
rneklendirilen nesneler iin farkl deerlere sahip olurlar. Yani bir snf varken, bu snftan
rneklendirilmi n sayda nesne oluturabiliriz. Kaldki bu nesnelerin her biri, tanmland snf
iin ayr ayr zelliklere sahip olabilirler.

ekil 1. Snf (Class) ve Nesne (Object) Kavram

Bir snf kendisinden oluturulacak nesneler iin bir takm yeler iermelidir. Bu yeler, alanlar
(fields), metodlar (methods), yapclar (constructor), zellikler (properties), olaylar(events),
delegeler (delegates) vb dr. Alanlar verileri snf ierisinde tutmak amacyla kullanlrlar. Bir takm
ilevleri veya fonksiyonellikleri gerekletirmek iin metodlar kullanrz. ounlukla snf iinde yer
alan alanlarn veya zelliklerin ilk deerlerin atanmas gibi hazrlk ilemlerinde ise yapclar
kullanrz. zellikler kapslleme dediimiz Encapsulating kavramnn bir parasdr. ounlukla, snf
iersinden tanmladmz alanlara, dardan dorudan eriilmesini istemeyiz. Bunun yerine bu
alanlara erien zellikleri kullanrz. te bu snf iindeki verileri d dnyadan soyutlamaktr yani
kapsllemektir. Bir snfn genel hatlar ile ierecei yeleri aadaki ekilde de grebilirsiniz.

ekil 2 . Bir snfn yeleri.

Snflar ile ilgili bu ksa bilgilerden sonra dilerseniz snf kavramn daha iyi anlamamz salyacak
basit bir rnek gelitirelim. Snflar ve yeleri ile ilgili dier kavramlar kodlar ierisinde yer alan
yorum satrlarnda aklamaya devam edeceiz. Bu rnek almamzda, Sql Suncusuna
balanrken, balant ilemlerini kolaylatracak birtakm yeler salyan bir snf gelitirmeye
alacaz. Kodlar yazdka bunu ok daha iyi anlayacaksnz. te bu uygulama iin
gelitirdiimiz, veri isimli snfmzn kodlar.

www.bsenyurt.com Page 2561


using System;
using System.Data.SqlClient;
namespace Veriler /* Snfmz Veriler isimli isim uzaynda yer alyor. ou zaman ayn isme sahip
snflara sahip olabiliriz. te bu gibi durumlarda isim uzaylar bu snflarn birbirinden farkl
olduunu anlamamza yardmc olurlar.*/
{
public class Veri /* Snfmzn ad Veri */
{
/* zleyen satrlarda alan tanmlamalarnn yapldn grmekteyiz. Bu alanlar private olarak
tanmlanmtr. Yani sadece bu snf ierisinden eriilebilir ve deerleri deitirilebilir. Bu alanlar
tanmladmz zelliklerin deerlerini tutmak amacyla tanmlyoruz. Amacmz bu deerlere snf
dndan dorudan eriilmesini engellemek.*/
private string SunucuAdi;
private string VeritabaniAdi;
private string Kullanici;
private string Parola;
private SqlConnection Kon; /* Burada SqlConnection tipinden bir deiken tanmladk. */
private bool BaglantiDurumu; /* Sql sunucumuza olan balantnn ak olup olmadna
bakcaz.*/
private string HataDurumu; /* Sql sunucusuna balanrken hata olup olmadna
bakacaz.*/
/* Aada sunucu adnda bir zellik tanmladk. Herbir zellik, get veya set bloklarndan en
az birini iermek zorundadr. */
public string sunucu /* public tipteki yelere snf iinden, snf dndan veya tretilmi
snflardan yani ksaca heryerden eriilebilmektedir.*/
{
get
{
return SunucuAdi; /* Get ile, sunucu isimli zellie bu snfn bir rneinden
eriildiinde okunacak deerin alnabilmesi salanr . Bu deer bizim private olarak tanmladmz
SunucuAdi deikeninin deeridir. */
}
set
{
SunucuAdi=value; /* Set blounda ise, bu zellie, bu snfn bir rneinden deer
atamak istediimizde yani zelliin gsterdii private SunucuAdi alannn deerini deitirmek iin
kullanrz. zellie snf rneinden atanan deer, value olarak tanmakta ve SunucuAdi alanna
aktarlmaktadr.*/
}
}
public string veritabani
{
get
{
return VeritabaniAdi;
}
set
{
VeritabaniAdi=value;
}

www.bsenyurt.com Page 2562


}
public string kullanici /* Bu zellik sadece set blouna sahip olduu iin sadece deer
atanabilir ama ierii grntlenemez. Yani kullanici zelliini bir snf rneinde, Kullanici private
alannn deerini renmek iin kullanamayz.*/
{
set
{
Kullanici=value;
}
}
public string parola
{
set
{
Parola=value;
}
}
public SqlConnection con /* Buradaki zellik SqlConnection nesne trndendir ve sadece
okunabilir bir zelliktir. Nitekim sadece get blouna sahiptir. */
{
get
{
return Kon;
}
}
public bool baglantiDurumu
{
get
{
return BaglantiDurumu;
}
set /* Burada set blounda baka kodlar da ekledik. Kullancmz bu snf rnei ile bir
Sql balants yarattktan sonra eer bu balanty amak isterse baglantiDurumu zelliine true
deerini gndermesi yeterli olucaktr. Eer false deeri gnderirse balant kapatlr. Bu ilemleri
gerekletirmek iin ise BaglantiAc ve BaglantiKapat isimli sadece bu snfa zel olan private
metodlarmz kullanyoruz.*/
{
BaglantiDurumu=value;
if(value==true)
{
BaglantiAc();
}
else
{
BaglantiKapat();
}
}
}
public string hataDurumu

www.bsenyurt.com Page 2563


{
get
{
return HataDurumu;
}
}
public Veri() /* Her snf mutlaka hi bir parametresi olmayan ve yandaki satrda grld
gibi, snf ad ile ayn isme sahip bir metod ierir. Bu metod snfn yapc metodudur. Yani
Constructor metodudur. Bir yapc metod iersinde ounlukla, snf iinde kullanlan alanlara
balang deerleri atanr veya ilk atamalar yaplr. Eer siz bir yapc metod tanmlamaz iseniz,
derleyici aynen bu metod gibi bo bir yapc oluturacak ve saysal alanlara 0, mantksal alanlara
false ve string alanlara null balang deerlerini atayacaktr.*/
{
}
/* Burada biz bu snfn yapc metodunu ar yklyoruz. Bu snftan bir nesneyi izleyen
yaplandrc ile oluturabiliriz. Bu durumda yapc metod ierdii drt parametreyi alcaktr.
Metodun amac ise belirtilen deerlere gre bir Sql balants yaratmaktr.*/
public Veri(string sunucuAdi,string veritabaniAdi,string kullaniciAdi,string sifre)
{
SunucuAdi=sunucuAdi;
VeritabaniAdi=veritabaniAdi;
Kullanici=kullaniciAdi;
Parola=sifre;
Baglan();
}
/* Burada bir metod tanmladk. Bu metod ile bir Sql balants oluturuyoruz. Eer bir
metod geriye herhangibir deer gndermiyecek ise yani vb.net teki fonksiyonlar gibi almayacak
ise void olarak tanmlanr. Ayrca metodumuzun sadece bu snf ierisinde kullanlmasn istediimiz
iin private olarak tanmladk. Bu sayede bu snf dndan rnein formumuzdan ulaamamalarn
salam oluyoruz.*/
private void Baglan()
{
SqlConnection con=new SqlConnection("data source="+SunucuAdi+";initial
catalog="+VeritabaniAdi+";user id="+Kullanici+";password="+Parola);
Kon=con;
}
/* Bu metod ile Sql sunucumuza olan balanty ayoruz ve BaglantiDurumu alanna true
deerini aktaryoruz.*/
private void BaglantiAc() /* Bu metod private tanmlanmtr. nk sadece bu snf ierisin
den arlabilsin istiyoruz. */
{
Kon.Open();
try
{
BaglantiDurumu=true;
HataDurumu="Baglanti salandi";
}
catch(Exception h)
{
HataDurumu="Baglanti Salanamd. "+h.Message.ToString();

www.bsenyurt.com Page 2564


}
}
/* Bu metod ilede Sql balantmz kapatyor ve BaglantiDurumu isimli alanmza false
deerini akataryoruz.*/
private void BaglantiKapat()
{
Kon.Close();
BaglantiDurumu=false;
}
}
}

imdi ise snfmz kullandmz rnek uygulama formunu tasarlayalm . Bu uygulamamz aadaki
form ve kontrollerinden oluuyor.

ekil 3. Form Tasarmmz.

Formumuza ait kodlar ise yle.

Veriler.Veri v;
private void btnBaglan_Click(object sender, System.EventArgs e)
{
/* Bir snf rnei yaratmak iin new anahtar kelimesini kullanrz. New anahtar kelimesi bize
kullanabileceimiz tm yapc metodlar gsterecektir. (IntelliSense zellii). */
v=new Veri(txtSunucu.Text,txtVeritabani.Text,txtKullanici.Text,txtParola.Text);

}
private void btnAc_Click(object sender, System.EventArgs e)
{
v.baglantiDurumu=true;
stbDurum.Text="Sunucu Balants Ak? "+v.baglantiDurumu.ToString();

www.bsenyurt.com Page 2565


}
private void btnKapat_Click(object sender, System.EventArgs e)
{
v.baglantiDurumu=false;
stbDurum.Text="Sunucu Balants Ak? "+v.baglantiDurumu.ToString();
}

imdi uygulamamz bir altralm.

ekil 5. Balanty amamz halinde.

ekil 6. Balanty kapatmamz halinde.

Deerli okurlarm, ben bu snfn gelitirilmesini size brakyorum. Umarm snf kavram ile ilgili
bilgilerimizi hatrlam ve yeni ufuklara yelken amaya hazr hale gelmisinizdir. Bir sonraki
makalemizde snflar arasnda kaltm kavramna bakcak ve bylece nesneye dayal programlama
terminolojisinin en nemli kavramlarndan birini incelemeye alsacaz. Hepinize mutlu gnler
dilerim.

Burak Selim ENYURT

www.bsenyurt.com Page 2566


selim@bsenyurt.com

Reflection Snf le Tiplerin Srr Ortaya


kyor ( 22.12.2003 ) - C#
Deerli Okurlarm, Merhabalar.

Hi .NET te yer alan bir tipinin yelerini renebilmek istediniz mi? rnein var olan bir .NET
snfnn veya sizin kendi yazm olduunuz yada bir bakasnn yazd snfa ait tm yelerin neler
olduuna programatik olarak bakmak istediniz mi? te bugnk makalemizin konusu bu. Herhangi
bir tipe (type) ait yelerin neler olduunu anlayabilmek. Bu amala, Reflection isim uzayn ve bu
uzaya ait snflar kullanacaz. Bildiiniz gibi .NET te kullanlan her ey bir tipe aittir. Yani
hereyin bir tipi vardr. yelerini renmek isteimiz bir tipi ncelikle bir Type deikeni olarak
alrz. (Yani tipin tipini alrz. Bu nedenle ben bu teknie Tip-i-Tip adn verdim ). Bu noktadan sonra
Reflection uzayna ait snflar ve metodlarn kullanarak ilgili tipe ait tm bilgileri edinebiliriz. Kk
bir Console uygulamas ile konuyu daha iyi anlamaya alalm. Bu rneimizde, System.Int32
snfna ait yelerin bir listesini alacaz. te kodlarmz;

using System;

namespace ReflectionSample1

class Class1

static void Main(string[] args)

Type tipimiz=Type.GetType("System.Int32");/* ncelikle String snfnn tipini


reniyoruz. */

System.Reflection.MemberInfo[] tipUyeleri=tipimiz.GetMembers(); /* Bu satr ile,


System.String tipi iinde yer alana yelerin listesini Reflection uzaynda yer alan, MemberInfo snf
tipinden bir diziye aktaryoruz. */

Console.WriteLine(tipimiz.Name.ToString()+" snfndaki ye
says:"+tipUyeleri.Length.ToString());/* Length zellii, MemeberInfo tipindeki dizimizde yer alan
yelerin saysn, (dolaysyla System.String snf iinde yer alan yelerin saysn) veriyor.*/

/* zleyen dng ile, MemberInfo dizininde yer alan yelerin birtakm bilgilerini ekrana
yazyoruz.*/

www.bsenyurt.com Page 2567


for(int i=0;i<tipUyeleri.Length;++i)

Console.WriteLine(i.ToString()+". ye
ad:"+tipUyeleri[i].Name.ToString()+"||"+tipUyeleri[i].MemberType.ToString()); /* Name zellii
yenin adn verirken, MemberType zellii ile, yenin tipini alyoruz. Bu ye tipi metod, zellik,
yapc metod vb... dir.*/

Uygulamay altrdmzda aadaki ekran grntsn elde ederiz.

ekil 1. System.Int32 snfnn yeleri.

ye listesini incelediimizde 15 yenin olduunu grrz. Metodlar, alanlar vardr. Ayrca dikkat
ederseniz, Parse , ToString metodlar birden fazla defa gemektedir. Bunun nedeni bu metodlarn
overload ( ar yklenmi ) versiyonlara sahip olmasdr. Kodlar incelediimizde, System.Int32
snfna ait tipleri GetMembers metodu ile, System.Reflection uzaynda yer alan MemberInfo snf
tipinden bir diziye aldmz grrz. te olayn nemli kodlar bunlardan olumaktadr.
MemberInfo dnda kullanabaileceimiz baka Reflection snflarda vardr. Bunlar;

ConstructorInfo Tipe ait yapc metod yelerini ve bu yelere ait


bilgilerini ierir.
EventInfo Tipe ait olaylar ve bu olaylara ait bilgileri ierir.
MethodInfo Tipe ait metodlar ve bu metodlara ait bilgileri ierir.

www.bsenyurt.com Page 2568


FieldInfo Tip iinde kullanlan alanlar ve bu alanlara ilikin
bilgileri ierir.
ParameterInfo Tip iinde kullanlan parametreleri ve bu parametrelere
ait bilgileri ierir.
PropertyInfo Tip iinde kullanlan zellikleri ve bu zelliklere ait
bilgileri ierir.

Tablo 1. Reflection Uzaynn Dier Kullanl Snflar

imdi bu snflara ait rneklerimizi inceleyelim. Bu kez bir DataTable snfnn yelerini
inceleyeceiz. rnek olarak, sadece olaylarn ve bu olaylara ilikin zelliklerini elde etmeye
alalm. Bu rneimizde, yukarda bahsettiimiz tip-i-tip tekniini biraz deitireceiz. Nitekim bu
teknii uygulamamz halinde bir hata mesaj alrz. Bunun nne gemek iin, bir DataTable rnei
(instance) oluturup bu rnein tipinden hareket edeceiz. Dilerseniz hemen kodlarmza geelim.

using System;

namespace ReflectionSample2

class Class1

static void Main(string[] args)

System.Data.DataTable dt=new System.Data.DataTable(); /* Bir DataTable


rnei(instance) yaratyoruz.*/

Type tipimiz=dt.GetType(); /* DataTable rneimizin GetType metodunu kullanarak, bu


rnein dolaysyla DataTable snfnn tipini elde ediyoruz. */

System.Reflection.MethodInfo[] tipMetodlari=tipimiz.GetMethods(); /* Bu kez sadece


metodlar incelemek istediimizden, GetMethods metodunu kullanyor ve sonular, MethodInfo
snf tipinden bir diziye aktaryoruz.*/

Console.WriteLine(tipimiz.Name.ToString()+" snfndaki metod


says:"+tipMetodlari.Length.ToString()); /* Metod saysn Length zellii ile alyoruz.*/

/* Dngmz oluturuyor ve Metodlarmz bir takm zellikleri ile birlikte


yazdryoruz.*/

for(int i=0;i<tipMetodlari.Length;++i)

Console.WriteLine("Metod adi:"+tipMetodlari[i].Name.ToString()+" |Dn


deeri:"+tipMetodlari[i].ReturnType.ToString()); /* Metodun ismini name zellii ile alyoruz.
Metodun dn tipini ReturnType zellii ile aliyoruz. */

www.bsenyurt.com Page 2569


System.Reflection.ParameterInfo[] prmInfo=tipMetodlari[i].GetParameters();

/* Bu satrda ise, i indeksli metoda ait parametre bilgilerini GetParameters metodu ile
alyor ve Reflection uzaynda bulunan ParameterInfo snf tipinden bir diziye aktaryoruz. Bylece
ilgili metodun parametrelerine ve parametre bilgilerine eriebilicez.*/

Console.WriteLine("-----Parametre Bilgileri-----"+prmInfo.Length.ToString()+"
parametre");

/* Dngmz ile i indeksli metoda ait parametrelerin isimlerini ve tiplerini


yazdryoruz. Bunun iin Name ve ParameterType metodlarn kullanyoruz.*/

for(int j=0;j<prmInfo.Length;++j)

Console.WriteLine("P.Adi:"+prmInfo[j].Name.ToString()+"
|P.Tipi:"+prmInfo[j].ParameterType.ToString());

Console.WriteLine("----");

imdi uygulamamz altralm ve sonularna bakalm.

www.bsenyurt.com Page 2570


ekil 2. System.Data.DataTable tipinin metodlar ve metod parametrelerine ait bilgiler.

Reflection teknikleri yardmyla altrdmz programa ait snflarnda bilgilerini elde edebiliriz.
zleyen rneimizde, yazdmz bir snfa ait ye bilgilerine bakacaz. yelerine bakacamz
snfn kodlar;

using System;

namespace ReflectionSample3

public class OrnekSinif

private int deger;

public int Deger

get

return deger;

set

deger=value;

public string metod(string a)

return "Burak Selim SENYURT";

int yas=27;

string dogum="istanbul";

www.bsenyurt.com Page 2571


}

ikinci snfmzn kodlar;

using System;

using System.Reflection;

namespace ReflectionSample3

class Class1

static void Main(string[] args)

Type tipimiz=Type.GetType("ReflectionSample3.OrnekSinif");

MemberInfo[] tipUyeleri=tipimiz.GetMembers();

for(int i=0;i<tipUyeleri.Length;++i)

Console.WriteLine("Uye adi:"+tipUyeleri[i].Name.ToString()+" |Uye


Tipi:"+tipUyeleri[i].MemberType.ToString());

imdi uygulamamz altralm.

www.bsenyurt.com Page 2572


ekil 3. Kendi yazdm snf yelerinede bakabiliriz.

Peki kendi snfmza ait bilgileri edinmenin bize ne gibi bir faydas olabilir. te imdi tam diimize
gore bir rnek yazacaz. rneimizde, bir tablodaki verileri bir snf iersinden tanmladmz
zelliklere alacaz. Bu uygulamamz sayesinde sadece tek satrlk bir kod ile, herhangibir kontrol
veriler ile doldurabileceiz. Bu uygulamada esas olarak, veriler veritabanndaki tablodan alncak ve
oluturduumuz bir koleksiyon snfndan bir diziye aktarlacak. Oluturulan bu koleksiyon dizisi, bir
DataGrid kontrol ile ilikilendirilecek. Teknik olarak kodumuzda, Reflection uzaynn PropertyInfo
snfn kullanarak, oluturduumuz snfa ait zellikler ile tablodaki alanlar karlatracak ve uygun
iseler bu zelliklere tabloda karlk gelen alanlar iindeki deerleri aktaracaz. Dilerseniz kodumuz
yazmaya balayalm.

using System;

using System.Reflection;

using System.Data;

using System.Data.SqlClient;

namespace ReflectDoldur

/* Kitap snf KitapKoleksiyonu isimli koleksiyon iinde saklayacamz deerlerin tipi olucaktr
ve iki adet zellik ierecektir. Bunlardan birisi, tablomuzdaki Adi alannn deerini, ikincisi ise
BasimEvi alannn deerini tutacaktr.*/

public class Kitap

private string kitapAdi;

private string yayimci;

/* zelliklerimizin adlarnn tablomuzdan alacamz alan adlar ile ayn olmasna dikkat
edelim.*/

www.bsenyurt.com Page 2573


public string Adi

get

return kitapAdi;

set

kitapAdi=value;

public string BasimEvi

get

return yayimci;

set

yayimci=value;

/* Yapc metodumuz parametre olarak geirilen bir DataRow deikenine sahip. Bu


deiken ile o anki satr alyoruz.*/

public Kitap(System.Data.DataRow dr)

PropertyInfo[] propInfos=this.GetType().GetProperties(); /* this ile bu snf temsil


ediyoruz. Bu snfn tipini alp bu tipe ait zellikleri elde ediyor ve bunlar PropertyInfo snf tipinden

www.bsenyurt.com Page 2574


diziye aktaryoruz.*/

/* Dngmz ile tm zellikleri geziyoruz. Eer metodumuza parametre olarak geirilen


dataRow deikenimiz, bu zelliin adnda bir alan ieriyorsa, bu zellie ait SetValue metodunu
kullanarak zelliimize, iligili tablo alannn deerini aktaryoruz.*/

for(int i=0;i<propInfos.Length;++i)

if(propInfos[i].CanWrite) /* Burada zelliimizin bir Set blouna sahip olup


olmadna baklyor. Yani zelliimizen yazlabilir olup olmadna. Bunu salayan zelliimiz
CanWrite. Eer zellik yazlabilir ise (yada baka bir deyile readonly deil ise) true deerini
dndrr.*/

try

if(dr[propInfos[i].Name]!=null) /* dataRow deikeninde, zelliimin adndaki


alann deerine baklyor. Null deer deil ise SetValue ile alann deeri zelliimize yazdrlyor. */

propInfos[i].SetValue(this,dr[propInfos[i].Name],null);

else

propInfos[i].SetValue(this,null,null);

catch

propInfos[i].SetValue(this,null,null);

www.bsenyurt.com Page 2575


}

/* KitapKoleksiyonu snfmz bir koleksiyon olucak ve tablomuzdan alacamz iki alana ait
verileri Kitap isimli nesnelerde saklanmasn salyacak. Bu nedenle, bir CollectionBase snfndan
tretildi. Bylece snfmz iinde indeksleyiciler kullanabileceiz.*/

public class KitapKoleksiyonu:System.Collections.CollectionBase

public KitapKoleksiyonu()

SqlConnection conFriends=new SqlConnection("data source=localhost;initial


catalog=Friends;integrated security=sspi");

SqlDataAdapter da=new SqlDataAdapter("Select Adi,BasimEvi From


Kitaplar",conFriends);

DataTable dtKitap=new DataTable();

da.Fill(dtKitap);

foreach(DataRow drow in dtKitap.Rows)

this.InnerList.Add(new Kitap(drow));

public virtual void Add(Kitap _kitap)

this.List.Add(_kitap);

public virtual Kitap this[int Index]

get

www.bsenyurt.com Page 2576


return (Kitap)this.List[Index];

Ve ite formumuzda kullandmz tek satrlk kod;

private void btnDoldur_Click(object sender, System.EventArgs e)

dataGrid1.DataSource = new ReflectDoldur.KitapKoleksiyonu();

imdi uygulamamz altralm ve bakalm.

ekil 4. Programn almasnn Sonucu

Grld gibi tablomuzdaki iki Alana ait veriler yazdmz KitapKoleksiyonu snf yardmyla, her
biri Kitap tipinde bir nesne alan koleksyionumuza eklenmi ve bu sonularda dataGrid
kontrolmze balanmtr. Siz bu rnei dahada iyi bir ekilde gelitirebilirisiniz. Umuyorumki bu
rnekte yapmak istediimizi anlamsnzdr. Yansma tekniini bu kod iinde ksa bir yerde
kullandk. Snfn zelliklerinin isminin, tablodaki alanlarn ismi ile ayn olup olmadn ve ayn iseler
yazlabilir olup olmadklarn renmekte kullandk. Deerli Okurlarm. Geldik bir makalemizin daha
sonuna. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

www.bsenyurt.com Page 2577


selim@bsenyurt.com

Stack ve Queue Koleksiyon Snf ( 19.12.2003 ) -


C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde Stack ve Queue koleksiyon snflarn incelemeye alacaz. Bir nceki
makalemizde bildiiniz gibi, HashTable koleksiyon snfn incelemetik. Stack ve Queue
koleksiyonlarda, System.Collections isim alannda yer alan ve ortak koleksiyon zelliklerine sahip
snflardr. Stack ve Queue koleksiyonlar, her koleksiyn snfnda olduu gibi, elemanlarn nesne
(object) tipinde tutmaktadrlar. Bu koleksiyonlarn zellii giren-kan eleman prensibleri zerine
almalardr. Stack koleksiyon snf, LIFO ad verilen, Last In First Out( Son giren ilk kar)
prensibine gore alrken, Queue koleksiyon snf ise FIFO yani First In First Out(ilk giren ilk kar)
prensibine gore alr.Konuyu daha iyi anlayabilmek iin aadaki ekilleri gz nne alalm.

ekil 1. Stack Koleksiyon Snfnn alma Yaps

Grld gibi, Stack koleksiyonunda yer alan elemanlardan son girene ulamak olduka kolaydr.
Oysaki ilk girdiimiz elemana ulamak iin, bu elemann stnde yer alan dier tm elemanlar
silmemiz gerekmektedir. Queue koleksyion snfna gelince;

www.bsenyurt.com Page 2578


ekil 2. Queue Koleksiyon Snfnn alma Yaps

Grld gibi Queue koleksiyon snfnda elemanlar koleksiyona arkadan katlrlar ve ilk giren
eleman kuyruktan ilk kan eleman olur. Stack ve Queue farkl yaplarda tasarlandklar iin
elemanlarna farkl metodlar ile ulalmaktadr. Stack koleksiyon snfnda, en son giren eleman
elde etmek iin Pop metodu kullanlr. Koleksiyona bir eleman eklerken Push metodu kullanlr.
Elbette eklenen eleman en son elemandr ve Pop metodu arldnda elde edilecek olan ilk
eleman halini alr. Ancak Pop metodu son giren eleman verirken bu eleman koleksiyondan siler.
te bunun nce geen metod Peek metodudur. imdi diyebilirsinizki maden son giren eleman
siliyor Pop metodu o zaman niye kullanyoruz. Hatrlarsanz, Stack koleksiyonunda, ilk giren
eleman elde etmek iin bu elemann stnde yer alan tm elemanlar silmemiz gerektiini
sylemitik. te bir dng yapsnda Pop metodu kullanldnda, ilk giren elemana kadar inebiliriz.
Tabi dier elemanlar kaybettikten sonra bunun ok byk nem tayan bir eleman olmasn
isteyebiliriz.

Gelelim Queue koleksiyon snfnn metodlarna. Dequeue metodu ile koleksiyona ilk giren eleman
elde ederiz. Ve bunu yaptmz anda eleman silinir. Nitekim dequeue metodu pop metodu gibi
alr. Koleksiyona eleman eklemek iin ise, enqueue metodu kullanlr. lk giren eleman elde
etmek ve silinmemesini salamak istiyorsak yine stack koleksiyon snfnda olduu gibi, Peek
metodunu kullanrz. Bu koleksiyonlarn en gzel yanlarndan birisi size leman saysn
belirtmediiniz takdirde koleksiyonun boyutunu otomatik olarak kendilerinin ayarlamalardr. Stack
koleksiyon snf, varsaylan olarak 10 elemanl bir koleksiyon dizisi oluturur .( Eer biz eleman
saysn yapc metodumuzda belirtmez isek). Eer eleman says 10u geerse, koleksiyon dizisinin
boyutu otomatik olarak iki katna kar. Ayn prensib queue koleksiyon snf iinde geerli olmakla
birlikte, queue koleksiyonu iin varsaylan dizi boyutu 32 elemanl bir dizidir. imdi dilerseniz,
basit bir console uygulamas ile bu konuyu anlamaya alalm.

using System;
using System.Collections; /* Uygulamalarmzda koleksiyon snflarn kullanabilmek iin Collections
isim uzayn kullanmamz gerekir.*/
namespace StackSample1
{
class Class1
{
static void Main(string[] args)

www.bsenyurt.com Page 2579


{
Stack stc=new Stack(4); /* 4 elemanl bir Stack koleksiyonu oluturduk.*/
stc.Push("Burak"); /*Eleman eklemek iin Push metodu kullanlyor.*/
stc.Push("Selim");
stc.Push("ENYURT");
stc.Push(27);
stc.Push(true);
Console.WriteLine("kan eleman {0}",stc.Pop().ToString());/* Pop metodu son
giren(kalan) eleman verirken, ayn zamanda bu eleman koleksiyon dizisinden siler.*/
Console.WriteLine("kan eleman {0}",stc.Pop().ToString());
Console.WriteLine("kan eleman {0}",stc.Pop().ToString());
Console.WriteLine("------------------");
IEnumerator dizi=stc.GetEnumerator(); /* Koleksiyonn elemanlarn IEnumerator
arayznden bir nesneye aktaryoruz.*/
while(dizi.MoveNext()) /* dizi nesnesinde okunacak bir sonraki eleman var olduu
srece ileyecek bir dng.*/
{
Console.WriteLine("Gncel eleman {0}",dizi.Current.ToString()); /* Current metodu
ile dizi nesnesinde yer alan gncel eleman elde ediyoruz. Bu dngy altrdmzda sadece iki
elemann dizide olduunu grrz. Pop metodu saolsun.*/
}
Console.WriteLine("------------------");
Console.WriteLine("En stteki eleman {0}",stc.Peek()); /* Peek metodu son giren
eleman veya en ste kalan eleman verirken bu eleman koleksiyondan silmez.*/
dizi=stc.GetEnumerator();
while(dizi.MoveNext())
{
Console.WriteLine("Gncel eleman {0}",dizi.Current.ToString()); /* Bu durumda yine
iki eleman verildiini Peek metodu ile elde edilen elemann koleksiyondan silinmediini grrz.*/
}
}
}
}

ekil 3. Stack ile ilgili programn almasnn sonucu.

Queue rneimiz ise ayn kodlardan oluuyor sadece metod isimleri farkl.

www.bsenyurt.com Page 2580


using System;
using System.Collections;
namespace QueueSample1
{
class Class1
{
static void Main(string[] args)
{
Queue qu=new Queue(4);
qu.Enqueue("Burak"); /*Eleman eklemek iin Enqueue metodu kullanlyor.*/
qu.Enqueue("Selim");
qu.Enqueue("ENYURT");
qu.Enqueue(27);
qu.Enqueue(true);
Console.WriteLine("kan eleman {0}",qu.Dequeue().ToString());/* Dequeue metodu ilk
giren(en alttaki) eleman verirken, ayn zamanda bu eleman koleksiyon dizisinden siler.*/
Console.WriteLine("kan eleman {0}",qu.Dequeue().ToString());
Console.WriteLine("kan eleman {0}",qu.Dequeue().ToString());
Console.WriteLine("------------------");
IEnumerator dizi=qu.GetEnumerator(); /* Koleksiyonn elemanlarn IEnumerator
arayznden bir nesneye aktaryoruz.*/
while(dizi.MoveNext()) /* dizi nesnesinde okunacak bir sonraki eleman var olduu
srece ileyecek bir dng.*/
{
Console.WriteLine("Gncel eleman {0}",dizi.Current.ToString()); /* Current metodu
ile dizi nesnesinde yer alan gncel eleman elde ediyoruz. Bu dngy altrdmzda sadece iki
elemann dizide olduunu grrz. Dequeue metodu saolsun.*/
}
Console.WriteLine("------------------");
Console.WriteLine("En altta kalan eleman {0}",qu.Peek()); /* Peek metodu son giren
eleman veya en ste kalan eleman verirken bu eleman koleksiyondan silmez.*/
dizi=qu.GetEnumerator();
while(dizi.MoveNext())
{
Console.WriteLine("Gncel eleman {0}",dizi.Current.ToString()); /* Bu durumda yine
iki eleman verildiini Peek metodu ile elde edilen elemann koleksiyondan silinmediini grrz.*/
}
}
}
}

www.bsenyurt.com Page 2581


ekil 4. Queue ile ilgili programn almasnn sonucu.

Geldik bir makalemizin daha sonuna. Umuyorumki sizlere faydal olabilecek bilgiler
sunabilmiimdir. Bir sonraki makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

HashTable Koleksiyon Snf ( 18.12.2003 ) - C#


Deerli Okurlarm, Merhabalar.

Bugnk makalemizde HashTable koleksiyon snfn incelemeye alacaz. Bildiiniz gibi


Koleksiyonlar System.Collections namespace'inde yer almakta olup, birbirlerinin ayn veya
birbirlerinden farkl veri tiplerinin bir arada tutulmasn salayan diziler oluturmamza imkan
salamaktadrlar. Pek ok koleksiyon snf vardr. Bugn bu koleksiyon snflarndan birisi olan
HashTable koleksiyon snfn inceleyeceiz. HashTable koleksiyon snfnda veriler key-value
dediimiz anahtar-deer iftleri eklinde tutulmaktadrlar. Tm koleksiyon snflarnn ortak zellii
barndrdklar verileri object tipinde olmalardr. Bu nedenle, HashTable'lardada key ve value
deerleri herhangibir veri tipinde olabilirler. Temel olarak bunlarn her biri birer DictionaryEntry
nesnesidir. Bahsetmi olduumuz key-value iftleri hash tablosu ad verilen bir tabloda saklanrlar.
Bu deer iftlerine erimek iin kullanlan bir takm karmak kodlar vardr.

Key deerleri tektir ve deitirilemezler. Yani bir key-value iftini koleksiyonumuza eklediimizde,
bu deer iftinin value deerini deitirebilirken, key deerini deitiremeyiz. Ayrca key deerleri
benzersiz olduklarnda tam anlamyla birer anahtar alan vazifesi grrler. Dier yandan value
deerline null deerler atayabilirken, anahtar alan niteliindeki Key deerlerine null deerler
atayamayz. ayet uygulamamzda varolan bir Key deerini eklemek istersek ArgumentException
istisnas ile karlarz. HashTable koleksiyonu verilere hz bir biimde ulamamz salayan bir
kodlama yapsna sahiptir. Bu nedenle zellikle arama maliyetlerini drd iin tercih
edilmektedir. imdi konuyu daha iyi pekitirebilmek amacyla, hemen basit bir uygulama
gelitirelim. Uygulamamzda, bir HastTable koleksiyonuna key-value iftleri ekliyecek, belirtilen
key'in sahip olduu deere baklacak, tm HashTable'n ierdii key-value iftleri listelenecek,
eleman iftlerini HashTable'dan kartacak vb... ilemler gerekletireceiz. Form tasarmn ben
aadaki ekildeki gibi yaptm. Temel olarak teknik terimlerin trke karlna dair minik bir
sz bir HashTable olarak tasarlayacaz.

www.bsenyurt.com Page 2582


1. Form Tasarmmz.

imdi kodlarmza bir gz atalm.

System.Collections.Hashtable htTeknikSozluk; /* HashTable koleksiyon nesnemizi tanmlyoruz.*/


private void Form1_Load(object sender, System.EventArgs e)
{
htTeknikSozluk=new System.Collections.Hashtable(); /* HashTable nesnemizi oluturuyoruz.*/
stbDurum.Text=htTeknikSozluk.Count.ToString(); /* HashTable'mzdaki eleman saysn Count
zellii ile reniyoruz.*/
}
private void btnEkle_Click(object sender, System.EventArgs e)
{
try
{
htTeknikSozluk.Add(txtKey.Text,txtValue.Text);/* HashTable'mza key-value ifti
ekleyebilmek iin Add metodu kullanlyor.*/
lstAnahtar.Items.Add(txtKey.Text);
stbDurum.Text=htTeknikSozluk.Count.ToString();
}
catch(System.ArgumentException) /* Eer var olan bir key'i tekrar eklemeye alrsak bu
durumda ArgumentException istisnas frlatlacaktr. Bu durumda, belirtilen key-value ifti
HashTable koleksiyonuna eklenmez. Bu durumu kullancya bildiriyoruz.*/
{
stbDurum.Text=txtKey.Text+" Zaten HashTable Koleksiyonunda Mevcut!";
}
}
private void lstAnahtar_DoubleClick(object sender, System.EventArgs e)
{
string deger;

www.bsenyurt.com Page 2583


deger=htTeknikSozluk[lstAnahtar.SelectedItem.ToString()].ToString(); /* HashTable'daki bir
deere ulamak iin, keli parantezler arasnda aranacak key deerini giriyoruz. Sonucu bir string
deikenine aktaryoruz.*/
MessageBox.Show(deger,lstAnahtar.SelectedItem.ToString());
}
private void btnSil_Click(object sender, System.EventArgs e)
{
if(htTeknikSozluk.Count==0)
{
stbDurum.Text="kartlabilecek hi bir eleman yok";
}
else if(lstAnahtar.SelectedIndex==-1)
{
stbDurum.Text="Listeden bir eleman semelisiniz";
}
else
{
htTeknikSozluk.Remove(lstAnahtar.SelectedItem.ToString()); /* Bir HashTable'dan bir
nesneyi kartmak iin, Remove metodu kullanlr. Bu metod parametre olarak kartlmak istenen
deer iftinin key deerini alr.*/
lstAnahtar.Items.Remove(lstAnahtar.SelectedItem);
stbDurum.Text="kartld";
stbDurum.Text=htTeknikSozluk.Count.ToString();
}
}
private void btnTumu_Click(object sender, System.EventArgs e)
{
lstTumListe.Items.Clear();
/* Aadaki satrlarda, bir HashTable koleksiyonu iinde yer alan tm elemanlara nasl
eriildiini grmekteyiz. Keys metodu ile HashTable koleksiyonumuzda yer alan tm anahtar
deerlerini (key'leri), ICollection arayz(interface) trnden bir nesneye atyoruz. Foreach
dngmz ile bu nesne iindeki her bir anahtar, HashTable koleksiyonunda bulabiliyoruz.*/
ICollection anahtar=htTeknikSozluk.Keys;
foreach(string a in anahtar)
{
lstTumListe.Items.Add(a+"="+htTeknikSozluk[a].ToString());
}
}

imdi uygulamamz altrp deneyelim.

www.bsenyurt.com Page 2584


2. Programn almasnnn sonucu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataGrid Denetimi zerinde Sralama(Sorting)


lemi ( 17.12.2003 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, bir Web Sayfas zerinde yer alan DataGrid kontrol zerinde tklanan
kolon balna gore sralama ileminin manuel olarak nasl yaplacan ileyeceiz. Konu teknik
arla sahip olduu iin hemen kodlara gemek istiyorum.

Uygulamamz , C# ile yazlm bir Web Application. Bir adet herhangibir zellii
belirlenmemi DataGrid kontrol iermekte. Aspx sayfamzn kodlarna gz atcak olursak,
DataBound taglar ierisinde yer alan SortExpression ifadeleri ve DataGrid tagnda yer alan,
OnSortCommand ifadesi bizim anahtar terimlerimizdir. SortExpression ifadesi, kolon
balna tklandnda ilgili veri kmesinin hangi alan adn gz nne alacan belirlemek iin
kullanlr. OnSortCommand deeri ise, SortExpression ifadesinin ilenerek sralamann yaplaca
kodlar ieren procedure adna iaret etmektedir. Bu bilgiler nda izleyeceimiz yol udur;

www.bsenyurt.com Page 2585


1- DataBound taglar iinde SortExpression
deerlerini belirlemek.

2- DataGrid tag iinde, OnSortCommand olay


iin metodu belirlemek.

3- OnSortCommand olay iin ilgili metodu


gelitirmek.

imdi ncelikle default.aspx sayfamzn ieriine bir bakalm.

imdi ise code-behind ksmnda yer alan default.aspx.cs dosyamzn ieriine bir bakalm.

SqlConnection conFriends;
SqlDataAdapter da;
DataTable dtKitaplar;
DataView dvKitaplar;
/* Sql sunucumuzda yer alan Friends isimli veritabanna balanyoruz. Buradan Kitaplar isimli
tablodaki verileri SqlDataAdapter nesnemiz ile alp dataTable nesnemizin bellekte iaret ettii yere
aktaryoruz. Daha sonra ise dataTable nesnemizin defaultView metodunu kullanarak, dataView
nesnemizi varsaylan tablo grnm ile dolduruyoruz. Eer sayfalarmzda sadece grsel amal
dataGrid'ler kullanacaksak yada baka bir deyile bilgilendirme amal veri kmelerini sunacaksak
DataView nesnelerini kullanmak performans asndan fayda salyacaktr.*/
public void Baglan()
{
conFriends =new SqlConnection("Data source=localhost;integrated security=sspi;initial
catalog=Friends");
da=new SqlDataAdapter("Select ID,Adi,Yazar,BasimEvi,Fiyat From Kitaplar",conFriends);
dtKitaplar=new DataTable("Kitap Listesi");
da.Fill(dtKitaplar);
dvKitaplar=dtKitaplar.DefaultView;
DataGrid1.AutoGenerateColumns=false; /* DataGrid nesnemizin ierecei kolonlar kendimiz

www.bsenyurt.com Page 2586


belirlemek istediimizden AutoGenerateColumns zelliine false deerini atadk.*/
DataGrid1.AllowSorting=true; /* AllowSorting zelliine true deerini aktardmzda,
DataGrid'in balk ksmnda yer alan kolon isimlerine tkladmzda bu alanlara gre sralama
yapabilmesini salam oluyoruz. */
}
/* Sirala isimli metodumuz, DataGrid tagnda OnSortCommand iin belirttiimiz metoddur. Bu
metod ile , bir kolon balna tklandnda yaplacak sralama ilemlerini belirtiyoruz. Bu metod,
DataGridSortCommandEventArgs tipinde bir parametre almaktadr. Bu parametremizin
SortExpression deeri, tklanan kolon balnn dataGrid tagnda,bu alan ile ilgili olan DataBound
sekmesinde yer alan SortExpression ifadesine atanan deerdir. Biz bu deeri alarak DataView
nesnemizin Sort metoduna gnderiyoruz. Bylece DataView nesnesinin bellekte iaret ettii veri
kmesini e.SortExpression zelliinin deerine gre yani seilen alana gre sralatm oluyoruz.
Daha sonra ise yaptmz ilem DataGrid kontrolmz tekrar bu veri kmesine balamak
oluyor.*/
public void Sirala(object sender,DataGridSortCommandEventArgs e)
{
lblSiralamaKriteri.Text="Sralama Kriteri : "+e.SortExpression.ToString();
dvKitaplar.Sort=e.SortExpression;
DataGrid1.DataSource=dvKitaplar;
DataGrid1.DataBind();
}
private void Page_Load(object sender, System.EventArgs e)
{
Baglan();
DataGrid1.DataSource=dvKitaplar;
DataGrid1.DataBind();
}

imdi uygulamamz altralm ve kolon balklarna tklayarak sonular izleyelim. te rnek


ekran grntleri.

www.bsenyurt.com Page 2587


ekil 1. Kitap Adna gore sralanm hali.

ekil 2. ID alanna gore sralanm hali.

www.bsenyurt.com Page 2588


ekil 3. Yazar adna gore sralanm hali.

Geldik bir makalemizin daha sonuna, bir sonraki makalemizde grmek dileiyle hepinize mutlu
gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataGrid Denetimi zerinde Sayfalama(Paging)


lemi ( 16.12.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, bir ASP.NET sayfasnda yer alan DataGrid kontrolmzde nasl sayfalama
ilemlerini gerekletireceimizi greceiz. Uygulamamz, sql sunucusundaki veritabanmzdan bir
tablo ile ile ilgili bilgileri ekranda gsterecek. Ancak ok sayda kayt olduu iin biz bunlar,
dataGrid kontrolmzde 10ar 10ar gstereceiz. Konumuzu anlayabilmek iin dorudan kodlama
ile ie balayalm diyorum. ncelikle VS.NET ile bir ASP.NET Web Application oluturalm ve
WebForm1.aspx sayfamzn adn default.aspx olarak deitirelim. imdi ncelikle bir DataGrid
nesnesini sayfamza yerletirelim ve hi bir zelliini ayarlamayalm. Bunlar default.aspx sayfasnn
html grnmnde elle kodlayacaz. u an iin DataGrid kontrolmze ait aspx dataGrid
tag'mzn hali yledir.

<asp:DataGrid id="dgKitap" style="Z-INDEX: 101; LEFT: 56px; POSITION: absolute; TOP: 56px"
runat="server"></asp:DataGrid>

imdi, code-behind ksmnda yer alcak kodlar yazalm. Sql sunucumuza bir balant oluturacaz,
Friends veritabanmzda yer alan Kitaplar tablosundaki satrlar bir DataTable nesnesine ykleyip
daha sonra dataGrid kontrolmze balayacaz. Bunu salayacak olan code-behind kodlarmz ise
u ekilde olucaktr;

SqlConnection conFriends;
SqlDataAdapter da;
DataTable dtKitaplar;

www.bsenyurt.com Page 2589


public void Baglan()
{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi");
da=new SqlDataAdapter("select ID,Kategori,Adi,Yazar,BasimEvi,BasimTarihi,Fiyat from kitaplar
order by Adi",conFriends);
dtKitaplar=new DataTable("Tum Kitaplar");
da.Fill(dtKitaplar);
}
private void Page_Load(object sender, System.EventArgs e)
{
Baglan();
dgKitap.AutoGenerateColumns=false; /* DataGrid kontrolmzde yer alcak kolonlar kendimiz
ayarlayacmz iin bu zellie false deerini aktardk.*/
dgKitap.DataSource=dtKitaplar; /*DataGrid kontrolmze veri kayna olarak dtKitaplar isimli
DataTable nesnemizin bellekte iaret ettii veri kmesini gsteriyoruz.*/
dgKitap.DataBind(); /* DataGrid kontrolndeki kolonlar (bizim yazdmz ve ayarladmz
kolonlar) veri kaynandaki ilgili alanlara balyoruz.*/
}

imdi sayfamzda yer alan DataGrid tag'ndaki dzenlemelerimizi yapalm. Burada Columns isimli
taglar arasnda, dataGrid kontrolmzde grnmesini istediimiz BoundColumn tipindeki stunlar
belirleyeceimiz taglar yazacaz. Bu sayede DataGrid kontrolne ait DataBind metodu
arldnda, bizim bu taglarda belirttiimiz alanlar DataGrid kontrolmzn kolonlar olacak
ekilde ilgili veri alanlarna balanacak. Gelin imdi buradaki dzenlemeleri gerekletirelim.
Unutmadan, kendi DataGrid kolonlarnz ayarlayabilmeniz iin AutoGenerateColumns zelliine
false deerini aktarmanz gerekmektedir. Aksi takdirde ayarladnz kolonlarn hemen arkasndan,
otomatik olarak DataTable'da yer alan tm kolonlar tekrardan gelir. Yaptmz son gncellemeleri
ile DataGrid tag'mzn yeni hali u ekildedir.

Burada grld gibi, DataGird kontrolmzde grnmesini istediim tablo alanlarn birer
BoundColumn olarak, DataGrid taglar arasna ekledik. Ksaca bahsetmek gerekirse hepsi iin,
DataField zellii ile tablodaki hangi alana ait verileri gstereceklerini, HeaderText zellii ile stun
balklarnda ne yazacan, ReadOnly zellii ile sadece okunabilir alanlar olduklarn belirliyoruz.Bu
haliyle uygulamamz altrrsak aadakine benzer bir ekran grnts ile karlarz.

www.bsenyurt.com Page 2590


ekil 1.Programn lk Hali.

Grld gibi kitap listesi uzayp gitmektedir. Bizim amacmz bu listeyi 10arl gruplar halinde
gstermek. Bunun iin yaplacak hareket gayet basit gzksede ince bir teknik kullanmamz
gerektiriyor. ncelikle dataGrid kontrolmzn, bir takm zelliklerini belirlemeliyiz. Bu amala
code-behind ksmnda yer alan Page_Load procedureunde bir takm deiiklikler yaptk.

private void Page_Load(object sender, System.EventArgs e)


{
if(!Page.IsPostBack) /* Sayfa ilk kez ykleniyorsa dataGrid'e ait zellikler belirlensin. Dier
yklemelerde tekrardan bu ilemler yaplmasn istediimiz iin...*/
{
dgKitap.AllowPaging=true; /* DataGrid kontrolmzde sayfalama yaplabilmesini
salyoruz.*/
dgKitap.PagerStyle.Mode=PagerMode.NumericPages; /* Sayfalama sistemi saysal olucak.
Yani 1 den balayp ka kaytlk sayfa olutuysa o kadar sayda bir buton dizesi dataGrid
kontrolnn en altnda yer alcak.*/
dgKitap.AutoGenerateColumns=false; /* DataGrid kontrolmzde yer alcak kolonlar
kendimiz ayarlayacmz iin bu zellie false deerini aktadk.*/
}
Baglan();
dgKitap.DataSource=dtKitaplar; /*DataGrid kontrolmze veri kayna olarak dtKitaplar isimli
DataTable nesnemizin bellekte iaret ettii veri kmesini gsteriyoruz.*/
dgKitap.DataBind(); /* DataGrid kontrolndeki kolonlar (bizim yazdmz ve ayarladmz
kolonlar) veri kaynandaki ilgili alanlara balyoruz.*/
}

imdi kodumuzu yeniden altrrsak bu kez DataGrid kontrolmzm alt ksmnda sayfa linklerinin
olutuunu grrz.

ekil 2. Sayfa Linkleri

www.bsenyurt.com Page 2591


Ancak bu linklerden herhangibirine bastmzda ilgili sayfaya gidemediimizi ayn sayfann gerisin
geriye geldiini grrz. te pek oumuzun zorland ve gzden kard teknik burada kendini
gsterir. Aslnda her ey yolunda gzkmektedir ve sistem almaldr. Ama almamaktadr.
Yapacamz bu sayfalama ilemini gerekletirecek bir metod yazmak ve son olarakta bu metodu
DataGrid tag'na yazacamz OnPageIndexChanges olay procedure' ile ilikilendirmektir.
OnPageIndexChanges olay DataGrid kontolnde yer alan sayfalama linklerinden birine basldnda
alacak kodlar ierir. Bu durumda DataGrid tag'mzn son hali aadaki gibi olur.

imdide code_behind ksmnda Sayfa_Guncelle metodumuzu ekleyelim.

Public void Sayfa_Guncelle(object sender , DataGridPageChangedEventArgs e)


{
dgKitap.CurrentPageIndex=e.NewPageIndex; /* te olay bitiren hamle. CurrentPageIndex
zelliine baslan linkin temsil ettii sayfann index nosu aktarlyor. Bylece belirtilen sayfaya
geilmi oluyor. Ancak i bununla bitmiyor. Veritabanndan verilerin tekrardan yklenmesi ve
dataGrid kontrolmze balanmas gerekli.*/
Baglan();
dgKitap.DataSource=dtKitaplar;
dgKitap.DataBind();
}

imdi uygulamamz altrsak eer, sayfalar arasnda rahata gezebildiimizi grrz. Geldik bir
makalemizin daha sonuna, bir sonraki makalemizde, yine DataGrid kontroln inceleyeiz. Bu defa,
kolonlar zerinden sralama ilemlerinin nasl yapldn incelemeye alacaz. Umuyorumki
hepiniz iin faydal bir makale olmutur. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2592


DataView Snf ve Faydalar ( 15.12.2003
) - Ado.Net

Deerli Okurlarm, Merhabalar.

Bugnk makalemizde getirileri ve performans ile ADO.NET ierisinde nemli bir yere sahip olan
DataView nesnesini incelemeye alacaz. zellikle bu snfa ait, RowFilter zelliinin ne gibi
faydalar salyacana da deineceiz.

DataView snf, veritaban ynetim sistemlerindeki view nesneleri gz nne alnarak oluturulmu
bir snftr. Bilindii gibi veritaban ynetim sistemlerinde (DBMS-DataBase Management System) ,
bir veya birden fazla tablo iin gerekletireceimiz eitli tipteki birletirici veya ayr ayr
sorgulamalar sonucu elde edilen veri kmelerini view nesnelerine aktarabilmekteyiz. View nesneleri
sahip olduklar veri alt kmelerini temsil eden birer veritaban nesnesi olarak, nceden
derlendiklerinden, sratli ve performans yksek yaplardr. Sz gelimi her hangibi tabloya ait bir
filtreleme iini bir view nesnesinde barndrabiliriz. Bunun sonucu olarak, ayn sorguyu yazp
altrmak, view nesnesinin ieriine( yani sahip olduu verilere) bakmaktan ok daha yavatr.
Bununla birlikte bu sorgulamann birden fazla tabloyu ierdiini dnrsek, bu durumda da
altrlan sorgu sonucu elde edilecek veri alt kmelerini bir(birka) view nesnesinde barndrmak
bize performans, hz olarak geri dnecektir.

Gelelim ADO.NET e. ADO.NET iersinde de, view lara benzer bir zellik olarak DataView nesneleri
yer almaktadr. DataView nesneleri, veritaban ynetim sistemlerinde yer alan viewlar ile benzerdir.
Yine performans ve hz asndan avantajldr. Bunlarn yannda bir DataView nesnesi
kullanlabilmek, mutlaka bir DataTable nesnesini gerektirmektedir. Nitekim DataView nesnesinin
sahip olaca veri alt kmeleri bu dataTable nesnesinin bellekte iaret ettii tablo verileri zerinden
alnacaktr. DataView nesnesinin kullanmnn belkide en gzel yeri udur; bir DataTable nesnesinin
bellekte iaret ettii tablodan, bir den fazla grnm elde ederekten, bu farkl grnmleri birden
fazla kontrole balayarak, ekranda ayn anda tek bir tablonun verilerine ait birden fazla veri
kmesini izlememiz mmkn olabilmektedir. te bu, bence DataView nesnesi(lerini) kullanmann
ne kadar faydal olduunu gstermektedir.

Bilindii gibi DataTable nesnesine ait Select zelliine ifadeler atayarakta var olan bir tablodan veri
alt kmeleri elde edebiliyorduk. Fakat bu select zelliine atanan ifade sonucu elde edilen veriler
bir DataRows dizisine aktarlyor ve kontollere balanamyordu. Oysaki DataView sonularn
istediiniz kontrole balamanz mmkndr.DataTable ile DataView arasnda yer alan bir farkta,
DataTablen sahip olduu satrlar DataRow snf ile temsil edilirken DataView nesnesinin sahip
olduu satrlar DataRowView snf ile temsil edilirler. Bir DataTable nesnesine nasl ki yeni satrlar
ekleyebiliyor, silebiliyor ve primary key zerinden arama yapabiliyorsak ayn ilemleri DataView
nesnesi iinde yapabiliriz. Bunlar AddNew, Delete ve Find yntemleri ile yapabiliriz. Bir sonraki
makalemizde bu metodlar ile ilgili geni bir rnek daha yapacaz.

Bugnk makalemizde konuya aklk getirmesi asndan iki adet rnek yapacaz. Her iki
rneimizde arlkl olarak DataView nesnesinin RowFilter zellii zerinde duracak. RowFilter
zellii DataTable snfnn Select zelliine ok benzer. Bir szme ifadesi alr. Oluturulan ifade
iinde, kullanlacak alan(alanlarn) veri tiplerine gre baz semboller kullanmamz gerekmektedir.
Bunu aklayan tablo aada belirtilmitir.

www.bsenyurt.com Page 2593


Kullanlan
Veri Tipi rnek
Karakter

Tm Metin
' (Tek trnak) " Adi='Burak' "
Deerleri

"
Tarihsel Deerler # DogumTarihi=#04.12.1976#
"

Saysal Deerler Hibirey " SatisTutari>150000000"

Tablo 1. Veritipine gre kullanlacak zel karakterler

Dier yandan RowFilter zelliinde IN, Like gibi ileler kullanarak eitli deiik sorgular elde
edebiliriz.Mantksal birletiriciler yardmyla(and,or...) birleik ifadeler oluturabiliriz. Aslnda
RowFilter zellii sqlde kullandmz ifadeler ile ayndr. rnekler verelim;

Kullanlan
rnek Ne Yapar?
le

" PUAN IN(10,20,25)


IN PUAN isimli alan 10, 20 veya 25 olan satrlar.
"

ADI A ile balayanlar (* burada asteriks


LIKE " ADI LIKE 'A*' "
karakterimizdir.)

Tablo 2. leler.

imdi gelin konuyu daha iyi anlayabilmek amacyla rneklerimize geelim. Konuyu anlayabilmek
iin iki farkl rnek yapacaz. lk rneimizde, ayn DataTable iin farkl grnmler elde edip
bunlar kontrollere balayacaz. lk rneimizde, eitli ifadeler kullanp deiik alt veri kmeleri
alacaz. te kodlarmz,

SqlConnection conFriends;
SqlDataAdapter da;
DataTable dtKitaplar;
/* Baglan metodumuz ile SqlConnection nesnemizi oluturarak, sql sunucumuza ve Friends
isimli veritabanmza balanyoruz. Daha sonra ise SqlDataAdapter nesnemiz vastasyla Kitaplar
isimli tablodan tm verileri alp DataTable nesnemize yklyoruz. */
public void Baglan()
{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi");
da=new SqlDataAdapter("Select * From Kitaplar",conFriends);

www.bsenyurt.com Page 2594


dtKitaplar=new DataTable("Kitap Listesi");
da.Fill(dtKitaplar);
}
private void Form1_Load(object sender, System.EventArgs e)
{
Baglan();
DataView dvTum_Kitaplar=dtKitaplar.DefaultView; /* Bir DataTable nesnesi yaratld zaman,
standart olarak en az bir tane grnme sahiptir. Bu varsaylan grnm bir DataView nesnesi
dndren DefaultView metodu ile elde edilebilir. altrdmz sql sorgusu Kitaplar tablosundaki
tm kaytlar aldndan buradaki DefaultView'da ayn veri kmesini sahip olucak bir DataView
nesnesi dndrr. Biz bu dnen veri kmesini dvTum_Kitaplar isimli DataView nesnesine aktardk.
Daha sonra ise DataView nesnemizi dgTum_Kitaplar isimli dataGrid nesnemize baladk.*/
dgTum_Kitaplar.DataSource=dvTum_Kitaplar;
/* Yeni bir DataView nesnesini yaplandrcsnn deiik bir versiyonu ile oluturuyoruz. Bu
yaplandrc 4 adet parametre alyor. lk parametremiz dataTable nesnemiz, ikinci parametremiz
RowFilter ifademiz ki burada Adi alan B ile balayanlar buluyor, nc parametremiz sralamann
nasl yaplaca ki burada Adi alannda gre tersten sralama yapyor. Son parametre ise,
DataViewRowState trnden bir parametre. Bu zellik DataView ierisinde ye alan her bir
DataRowView'un (yani satrn) durumunun deerini belirtir. Alaca deerler
* 1. Added ( Sadece DataView'a eklenen satrlar ifade eder)
* 2. Deleted ( Sadece DataView'dan silinmi satrlar ifade eder)
* 3. CurrentRows ( O an iin geerli tm satrlar ifade eder)
* 4. ModifiedCurrent ( Deitirilen satrlarn o anki deerlerini ifade eder)
* 5. ModifiedOriginal ( Deitirilen satrlarn orjinal deerlerini ifade eder)
* 6. Unchanged ( Herhangibir deiiklie uramam satrlar ifade eder)
* 7. OriginalRows ( Tm satrlarn asl deerlerini ifade eder)
* 8. None (Herhangibir satr dndrmez)
Buna gre bizim DataView nesnemiz gncel satrlar dndrecektir. */
DataView dvBIleBaslayan=new DataView(dtKitaplar,"Adi Like 'B*'","Adi
Desc",DataViewRowState.CurrentRows);
dgA.DataSource=dvBIleBaslayan;
/* imdi ise 2002 yl ve sonras Basm tarihine sahip verilerden oluan bir DataView nesnesi
oluturuyoruz. Bu kez yapc metodumuz sadece DataTable nesnemizi parametre olarak ald. Dier
ayarlamalar RowFilter,Sort zellikleri ile yaptk. Sort zelliimiz sralama kriterimizi belirliyor.*/
DataView dv2002Sonrasi=new DataView(dtKitaplar);
dv2002Sonrasi.RowFilter="BasimTarihi>=#1.1.2002#";
dv2002Sonrasi.Sort="BasimTarihi Asc";
/* Bu kez DataView nesnemizi bir ListBox kontrolne baladk ve sadece Adi alan deerlerini
gstermesi iin ayarladk.*/
lstPahali.DataSource=dv2002Sonrasi;
lstPahali.DisplayMember="Adi";
}

alma sonucu ekran grntmz ekil 1deki gibi olur.

www.bsenyurt.com Page 2595


ekil 1. lk Programn Sonucu

imdi gelelim ikinci uygulamamza. Bu uygulamamzda yine Kitaplar tablosunu ele alacaz. Bu kez
RowFilter zelliine vereceimiz ifadeyi alma zamannda biz oluturacaz. Alanmz seecek,
sralama kriterimizi belirleyecek,aranacak deeri gireceiz. Girdiimiz deerlere gre program
kodumuz bir RowFilter Expression oluturacak. Programn ekran tasarmn ben aadaki gibi
yaptm. Sizde buna benzer bir tasarm ile ie balayn.

www.bsenyurt.com Page 2596


ekil2. Form Tasarm

imdide kodlarmz yazalm.

SqlConnection conFriends;
SqlDataAdapter da;
DataTable dtKitaplar;
DataView dvKitaplar;
/* Bu metod cmbAlanAdi isimli comboBox kontroln, dataTable nesnemizin bellekte temsil ettigi
tablonun Alanlari ile doldurur. Nitekim bu alanlari, RowFilter zelliginde kullanacagiz. */
public void AlanDoldur()
{
for(int i=0;i<dtKitaplar.Columns.Count;++i)
{
this.cmbAlanAdi.Items.Add(dtKitaplar.Columns[i].ColumnName.ToString());
this.cmbAlanSira.Items.Add(dtKitaplar.Columns[i].ColumnName.ToString());
}
}
private void Form1_Load(object sender, System.EventArgs e)
{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi");
da=new SqlDataAdapter("Select Kategori,Adi,Yazar,BasimEvi,BasimTarihi,Fiyat From
Kitaplar",conFriends);
dtKitaplar=new DataTable("Kitap Listesi");
/* DataTable nesnemizin bellekte temsil ettigi alani,Kitaplar tablosundaki veriler ile,
SqlDataAdapter nesnemizin Fill metodu sayesinde dolduruyoruz.*/
da.Fill(dtKitaplar);
dvKitaplar=new DataView(dtKitaplar); /* Dataview nesnemizi yaratiyoruz. Dikkat ederseniz
yapici metod, paremetre olarak DataTable nesnemizi aliyor. Dolayisiyla DataView nesnemiz,
dataTable iindeki veriler ile dolmus sekilde olusturuluyor.*/
dataGrid1.DataSource=dvKitaplar; /* DataGrid kontrolmze veri kaynagi olarak, DataView
nesnemizi isaret ederek, DataView iindeki verileri gstermesini sagliyoruz.*/
AlanDoldur();
}
/* Bu butona bastigimizda, kullancnn setigi alan, filtreleme kriteri ve filtreleme iin
kullanilacak deger verileri belirlenerek, DataView nesnesinin RowFilter metodu iin bir syntax
belirleniyor.*/
private void btnCreateFilter_Click(object sender, System.EventArgs e)
{
string secilenAlan=cmbAlanAdi.Text;
string secilenKriter=cmbKriter.Text;
string deger="";
/* If kosullu ifadelerinde, seilen alanin veri tipine bakiyoruz. Nitekim RowFilter metodunda,
alan'in veri tipine gre ifademiz degisiklik gsteriyor. Tarih tipindeki verilerde # karakteri aranan
metnin basina ve sonuna gelirken, string tipinde degerlerde ' karakteri geliyor. Sayisal tipteki
degerler iin ise herhangibir karakter ifadenin aranan degerin basina veya sonuna eklenmiyor. */
if(dtKitaplar.Columns[secilenAlan].DataType.ToString()=="System.String")
deger="'"+txtDeger.Text+"'";
if(dtKitaplar.Columns[secilenAlan].DataType.ToString()=="System.DateTime")

www.bsenyurt.com Page 2597


deger="#"+txtDeger.Text+"#";
if(dtKitaplar.Columns[secilenAlan].DataType.ToString()=="System.Decimal")
deger=txtDeger.Text;
txtFilter.Text=secilenAlan+secilenKriter+deger; /* Olusturulan ifade grmemiz iin textBox
kontrolmze yaziliyor. */
}
private void btnFilter_Click(object sender, System.EventArgs e)
{
dvKitaplar.RowFilter=txtFilter.Text; /* DataView nesnemizin RowFilter metoduna, ilgili ifademiz
atanarak, szme islemini gereklestirmis oluyoruz. */
dvKitaplar.Sort=cmbAlanSira.Text+" "+cmbSiralamaKriteri.Text; /* Burada ise Sort zelligine
siralama yapmak iin gerekli veriler ataniyor. */
}

imdi uygulamamz altralm ve deneyelim.

ekil 3. Programn almas

rnein ben, Fiyat 10 milyon TL snn stnde olan kitaplarn listesini Adlarna gre z den a ya
sralanm bir ekilde elde ettim.Deerli okurlarm geldik bir makalemizin daha sonuna. DataView
nesnesinin zellikle RowFilter tekniine ilikin olarak yazdmz bu makale ile inanyorum ki yeni
fikirler ile donanmsnzdr. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2598


SQL_DMO lemleri ( 12.12.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, Sql Distributed Management Objects (SQL Datk Ynetim Nesneleri)
ktphanesini incelemeye alacaz. SQL_DMO ktphanesi bir COM uygulamas olup, SQL
sunucusu ile birlikte sisteme kurulmaktadr. Bu ktphanedeki snflar yardmyla, var olan bir sql
sunucusu zerinde ynetimsel ilemler gerekletirebiliriz. rnein, kullanc tanmlayabilir, yeni bir
veritaban yaratabilir bu veritabanna ait tablolar oluturabilir, var olan bir veritaban iin
yedekleme ilemleri gerekletirebilir, yedeklenmi veritabanlarn geri ykleyebilir ve bunlar gibi
pek ok ynetsel ilemi gerekletirebiliriz. Uygulamalarmzda bu tip ilemleri kodlayabilmek iin,
Microsoft SQL Distributin Controlun projemize referans edilmesi gerekmektedir. Bir uygulamaya
bunu referans etmek iin VS.NET ortamnda, Add Reference ksmnda, COM nesneleri altnda
Microsoft SQL Distribution Control 8.0 seilmelidir. Aadaki ekilde bunun nasl yapldn
grebilirsiniz.

ekil 1. Microsoft SQL Distribution Control 8.0 in eklenii.

Bu noktadan sonra uygulamamzda SQLDMO isimli temel snf kullanarak bahsetmi olduumuz
ilemleri gerekletirebiliriz. Konuyu daha iyi kavrayabilmek amacyla dilerseniz, hemen basit bir
uygulama gerekletirelim. Bu uygulamamzda, Sql sunucumuz zerinde, bir veritaban yaratacak
bu veritaban iinde ok basit bir tablo oluturacak, Sql sunucusunda yer alan veritabanlarn
grcek ve bu veritabanlarna ait tablolara bakabileceiz. Kodlarn ileyiini incelediinizde , iin
pf noktasnn SQLDMO snfnda yer alan SQLServerClass, DatabaseClass, TableClass,
ColumnClass snflarnda olduunu grebilirisiniz. Buradaki matnk aslnda ADO.NET mant ile
tamamen ayndr. SQL Sunucunuza balanmak iin kullanacanz bir SQLServerClass snf, bir

www.bsenyurt.com Page 2599


veritabann temsil eden DatabaseClass snf, bir tablo iin TableClass snf ve tabloya ait alanlar
temsil edicek olan ColumnClass snf vardr.

Matnk ayn demitik. Bir veritaban yaratmak iin, DatabaseClass snfndan rnek bir nesne
oluturursunuz. Bunu var olan Sql sunucusuna eklemek demek aslnda bu nesneyi SQLServerClass
nesnenizin Databases koleksiyonuna eklemek demektir. Ayn ekilde bir tablo oluturmak iin
TableClass snf rneini kullanr,ve bunu bu kez DatabaseClass nesnesinin Tables koleksiyonuna
eklersini. Tahmin edeceiniz gibi bir tabloya bir alan eklemek iin ColumnClass snfndan rnek bir
nesne kullanr ve bunun zelliklerini ayarladktan sonra tablonun Columns koleksiyonuna eklersiniz.
Kodlarmz incelediiniz zaman konuyu ok daha net bir ekilde anlayacaksnz. Uygulamamz
aadakine benzer bir formdan olumakta. Sizde buna benzer bir form oluturarak ie
balayabilirsiniz.

ekil 2. Form tasarmmz.

imdi kodlarmz yazalm.

SQLDMO.SQLServerClass srv;
SQLDMO.DatabaseClass db;
SQLDMO.TableClass tbl;
private void btnConnect_Click(object sender, System.EventArgs e)
{
srv=new SQLDMO.SQLServerClass(); /* SQL Sunucusu zerinde, veritabani yaratma gibi
islemler iin, Sql Sunucusunu temsil edicek ve ona baglanmamizi sagliyacak bir nesneye ihtiyacimiz
vardir. Bu nesne SQLDMO sinifinda yer alan SQLServerClass sinifinin bir rnegi olucaktir. */
srv.LoginSecure=false; /* Bu zellik true olarak belirlendiginde, Sql Sunucusuna Windows
Authentication seklinde baglanilir. Eger false degerini verirsek bu durumda Sql Server
Authentication geerli olur. Iste bu durumda SQLServerClass nesnesini Connect metodu ile Sql
Sunucusuna baglanirken geerli bir kullanici adi ve sifre girmemiz gerekmektedir. */

www.bsenyurt.com Page 2600


try
{
srv.Connect("BURKI","sa","CucP??80."); /* Baglanti kurmak iin kullandigimiz Connect
metodu parametre almaktadir. Ilk parametre sql sunucusunun adidir. Ikinci parametre kullanici
adi ve nc parametrede sifresidir. Eger LoginSecure=true olarak ayarlasaydik, kullanici adini ve
sifreyi bos birakicaktik, nitekim Windows Authentication (windows dogrulamasi) sz konusu
olucakti.*/
durumCubugu.Text="Sunucuya baglanildi..."+srv.Status.ToString();
}
catch(Exception hata)
{
MessageBox.Show(hata.Message);
}
}
private void btnVeritabaniOlustur_Click(object sender, System.EventArgs e)
{
try
{
db=new SQLDMO.DatabaseClass(); /* SQL-DMO ktphanesinde, veritabanlarini temsil
eden sinif DatabaseClass sinifidir. */
db.Name=this.txtVeritabaniAdi.Text; /* Veritabani nesnemizin name zelligi ile
veritabaninin adi belirlenir.*/
srv.Databases.Add(db); /* olusturulan DatabaseClass nesnesi SQLServerClass sinifinin
Databases koleksiyonuna eklenerek Sql Sunucusu zerinde olusturulmasi saglaniyor. */
durumCubugu.Text=db.Name.ToString()+" veritabani "+srv.Name.ToString()+" SQL
Sunucusunda olusturuldu";
}
catch(Exception hata)
{
MessageBox.Show(hata.Message);
}
}
private void btnTabloOlustur_Click(object sender, System.EventArgs e)
{
try
{
tbl=new SQLDMO.TableClass(); /* Yeni bir tablo olusturabilmek iin SQL-DMO
ktphanesinde yer alan, TableClass sinifi kullanilir.*/
tbl.Name=txtTabloAdi.Text; /* Tablomuzun ismini name zelligi ile belirliyoruz.*/
SQLDMO.ColumnClass dc; /* Tabloya eklenecek alanlarin her birisi birer ColumnClass sinifi
nesnesidir. */
dc=new SQLDMO.ColumnClass();/* Bir ColumnClass nesnesi yaratiliyor ve bu nesnenin
gerekli zellikleri belirleniyor. Name zelligi ile ismi, Datatype zelligi ile veri tr belirleniyor.
Biz burada ID isimli alanimizin otomatik olarak artan ve 1000 den baslayarak 1'er artan bir alan
olmasini istedik. */
dc.Name="ID";
dc.Datatype="Int";
dc.Identity=true;
dc.IdentitySeed=1000;
dc.IdentityIncrement=1;

www.bsenyurt.com Page 2601


tbl.Columns.Add(dc); /* Olusturulan bu alan TableClass nesnemizin Columns koleksiyonuna
eklenerek tabloda olusturulmasi saglanmis oluyor. */
dc=new SQLDMO.ColumnClass();
dc.Name="ISIM";
dc.Datatype="char"; /* String tipte bir alan */
dc.Length=50;
tbl.Columns.Add(dc);
dc=new SQLDMO.ColumnClass();
dc.Name="SOYISIM";
dc.Datatype="char";
dc.Length=50;
tbl.Columns.Add(dc);
/* Son olarak olusturulan TableClass nesnesi veritabanimizin tables koleksiyonuna
ekleniyor. Bylece Sql sunucusunda yer alan veritabani iinde olusturulmasi saglanmis oluyor.
*/
db.Tables.Add(tbl);
durumCubugu.Text=tbl.Name.ToString()+" olusturuldu...";
}
catch(Exception hata)
{
MessageBox.Show(hata.Message);
}
}
private void btnSunucuVeritabanlari_Click(object sender, System.EventArgs e)
{
this.lstDatabases.Items.Clear();
/* ncelikle listBox nesnemize Sql Sunucusunda yer alan veritabanlarinin sayisini
aktariyoruz.*/
this.lstDatabases.Items.Add("Sunucudaki veritabani sayisi="+srv.Databases.Count);
/* Simdi bir for dngs ile, srv isimli SQLServerClass nesnemizin Databases koleksiyonunda
geziniyoru ve her bir databaseClass nesnesinin adini alip listBox nesnemize aktariyoruz. Burada
index degerinin 1 den basladigina sifirdan baslamadigina dikkat edelim. */
for(int i=1;i<srv.Databases.Count;++i)
{
this.lstDatabases.Items.Add(srv.Databases.Item(i,srv).Name.ToString());
}
}
private void btnTablolar_Click(object sender, System.EventArgs e)
{
/* Burada seilen veritabanna ait tablolar listBox kontrolne getiriliyor */
this.lstTabels.Items.Clear();
this.lstTabels.Items.Add("Tablo
Sayisi="+srv.Databases.Item(this.lstDatabases.SelectedIndex,srv).Tables.Count.ToString());
/* Dngmz Sql Suncusundan yer alan veritaban says kadar sren bir dng. */
for(int i=1;i<srv.Databases.Item(this.lstDatabases.SelectedIndex,srv).Tables.Count;++i)
{
this.lstTabels.Items.Add(srv.Databases.Item(this.lstDatabases.SelectedIndex,srv).Tables.Ite
m(i,srv). Name.ToString());
}

www.bsenyurt.com Page 2602


}

imdi uygulamamz altralm ve ncelikle Sql Sunucumuza balanalm.

ekil 3. Sunucumuza Balandk.

imdi bir veritaban oluturalm. Ben veritaban ad olarak DENEME1 yazdm.

ekil 4. Veritabanmz Oluturuldu.

imdi ise tablo ismimizi yazalm. Ben deneme olarak Personel yazdm. imdi dilerseniz Sql
Sunucumuzu bir aalm ve bakalm veritabanmz ve ilgili tablomu yaratlmm.

ekil 5. Veritabanmz ve Tablomuz oluturuldu.

Ve tablomuza baktmzda oluturduumuz alanlarda grebiliriz.

www.bsenyurt.com Page 2603


ekil 6. Tablomuzdaki alanlar.

Son olarak suncumuzda yer alan veritabanlarnn ve Deneme veritabanu altndaki tablolarnda
programmzda nasl grndne bakalm. Dikkat ederseniz tablolar ekrana geldiinde sistem
tablolarda gelir. Bununla birlikte veritabanlar grnrken sadece TempDBd veritaban grnmez.

www.bsenyurt.com Page 2604


ekil 7. Program ekrann son grnts

Evet geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle, hepinize
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

likili Tablolar DataSet le Kullanmak - 2 (


10.12.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde ilikili tablolar arasnda kstlamalarn ( constraints ) nasl kullanldn


ilemey alacaz. Hatrlayacanz gibi bu yaz dizisinin ilk blmnde DataRelation snfn
kullanarak ilikil tablolarn bellekte nasl ifade edilebileceini grmtk.Bir dier nemli konu, bu
ilikili tablolar arasndaki parent-child ilikisinin kayt gncelleme, kayt silme gibi durumlarda nasl
hareket edeceini belirlemektir.

Buna verilecek en gzel rnek mterilere ait sipari detaylarnn ve buna benzer ilikilerin yer
ald veritaban tasarmlardr. Sz gelimi parent tablodan bir kaydn silinmesi ile bu kayda bal
child tablodaki kaytlarn da silinmesi gerekebilir yada silinmemesi istenebilir. te bu noktada
DataSet ile belleer yklenen tablolar arasndaki bu zorlamalar bir ekilde tanmlamamz
gerekmektedir. Bu zorlamalar Constraints olarak tanmlanr. Bizim iin en neli iki kstlama Foreign

www.bsenyurt.com Page 2605


Key Constraints ve Unique Constraints dir. Foreign Key Constraints ( Yabanc anahtar kstlamas ),
parent-child ilikisine sahip tablolarda kaytlarn gncelleme ve silme olaylarnda nasl hareket
edeceini belirleriz. Unique Constraints tanmlas ilede bir alann deerlerinin asla tekrar
edilemiyecei artn bildirmi oluruz.Bir yababc anahtar kstlamas iin ForeignKeyConstraint snf
kullanlr. Ayn ekilde bir tekillik kstlamas iin de UniqueConstraints snf kullanlmaktadr. Her iki
snfa ait rnek nesnelerin kullanlabilmesi iin, ilgili tablonun Constraints koleksiyonuna eklenmesi
gerekmektedir.

yleki, diyelimki siparilerin tutulduu tablodaki veriler ile sipari iinde yer alan rnlerin
tutulduu tablolar arasnda bire-ok bir iliki var. Bu durumda, siparilerin tutulduu tablodan bir
kayt silindiinde buradaki siparii belirleyici alan (ounlukla ID olarak kullanrz) ile child tabloda
yer alan ve yabanc anahtar ile parent tabloya bal olan alanlar silmek isteyebiliriz. Burada
zorlama unsurumuz parent tabloyu ilgilendirmektedir. Dolaysyla, oluturulacak
ForeignKeyConstraints nesnesini parent tablonun Constraints koleksiyonuna ekleriz. Elbette,
kstlamann silme ve gncelleme gibi ilemlerde nasl davran gstermesi gerektiini belirlemek
iin, ForeignKeyConstraintse ati bir takm zelliklerinde ayarlanmas gerekir. Bunlar,

DeleteRule

UpdateRule

AcceptRejectRule

zellikleridir. Bu zelliklere atayabileceimiz deerler ise,

Rule.Cascade

Rule.None

Rule.SetDefault

Rule.SetNull

Cascade deeri verildiinde gncelleme ve silme ilemlerinden, child tablodaki kaytlarnda


etkilenmesi salanm olunur. Szgelimi parent tabloda bir satrn silinmesi ile ilikili tablodaki
ilikili satrlarnda tm silinir. None deeri verildiinde tahmin edeceiniz gibi bu deiiklikler
sonunda child tabloda hi bir deiiklik olmaz. SetDefault deeri, silme veya gncelleme ilemleri
sonucunda child tablodaki ilikili satrlarn alanlarnn deerlerini varsaylan deerlerine ( ounlukla
veritabannda belirlenen ) ayarlar. SetNull verildiinde ise bu kez, child tablodaki ilikili satrlardaki
alanlarn deerleri, DbNull olarak ayarlanr.

Burada AcceptRejectRule isimli bir zellikde dikkatinizi ekmi olmal. Bu zellik bir DataSet,
DataTable veya DataRow nesnesine ait AcceptChanges ( deiiklikleri onayla ) veya RejectChanges
( deiiklikleri iptal et) durumunda nasl bir kstlama olacan belirlemek iin kullanlr. Bu zelik
Cascade veya Null deerlerinden birini alr.Bir dataSetin kstlamalar uygulamas iin
EnforceConstraints zelliine true deeri atanmas gerektiinide syleyelim.

imdi nceki makalemizde yazdmz rnek uygulama zerinden hareket ederek,


ForeignKeyConstraint tekniini inceleyelim. Konuyu uzatmamak amacyla ayn rnek kodlar

www.bsenyurt.com Page 2606


zerinden devam edeceim. Uygulamamzda kullanc silemk istedii Siparisin SiparisID bilgisini
elle girecek ve silme ilemini balatcak. te bu noktada, DataSete eklemi olduumuz kstlama
devreye girerek, Sepet tablosunda yer alan ilikili satrlarnda silinmesi gerekletirilecek. Haydi
gelin kodlarmz yazalm.

SqlConnection conFriends;
SqlDataAdapter daSiparis;
SqlDataAdapter daSepet;
DataTable dtSiparis;
DataTable dtSepet;
ForeignKeyConstraint fkSiparisToSepet;
DataSet ds;
private void Form1_Load(object sender, System.EventArgs e)
{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi");
daSiparis=new SqlDataAdapter("Select * From Siparis",conFriends);
daSepet=new SqlDataAdapter("Select * From Sepet",conFriends);
dtSiparis=new DataTable("Siparisler");
dtSepet=new DataTable("SiparisDetaylari");
daSiparis.Fill(dtSiparis);
daSepet.Fill(dtSepet);
dtSiparis.PrimaryKey=new DataColumn[] {dtSiparis.Columns["SiparisID"]};
/* Sra geldi foreignKeyConstraint tanmlamamza. */
fkSiparisToSepet=new ForeignKeyConstraint("fkS_S",dtSiparis.Columns["SiparisID"],dtSepet.C
olumns["SiparisID"]); /* ncelikle yeni bir ForeignKeyConstraint nesnesi tanmlyoruz.*/
fkSiparisToSepet.DeleteRule=Rule.Cascade; /* Delete ileminde uygulanacak kural
belirliyoruz.*/
fkSiparisToSepet.UpdateRule=Rule.Cascade;/* Gncelleme ileminde uygulanacak kural
belirliyoruz.*/
fkSiparisToSepet.AcceptRejectRule=AcceptRejectRule.Cascade;/* AcceptChanges ve
RejectChanges metodlar arldnda uygulanacak olan kurallar belirliyoruz.*/
ds=new DataSet();
ds.Tables.Add(dtSiparis);
ds.Tables.Add(dtSepet);
ds.Tables["SiparisDetaylari"].Constraints.Add(fkSiparisToSepet);/* Oluturduumuz kstlamay
ilgili tablonun Constraints koleksiyonuna ekliyoruz. */
ds.EnforceConstraints=true; /* Dataset'in barndrd kstlamalar uygulatmasn bildiriyoruz.
False deeri atarsak dataset nesnesinin ierdii tablo(lara) ait kstlamalar grmezden gelinir.*/
dataGrid1.DataSource=ds;
}
private void btnSil_Click(object sender, System.EventArgs e)
{
try
{
DataRow CurrentRow=dtSiparis.Rows.Find(txtSiparisID.Text);
CurrentRow.Delete();
}
catch(Exception hata)

www.bsenyurt.com Page 2607


{
MessageBox.Show(hata.Source+":"+hata.Message);
}
}

imdi uygulamamz altralm. Siparis tablosuna baktmzda aadaki grnm yer


almaktadr.

ekil 1. Sipari Verileri

Siparis Detaylarnn tutulduu Sepet tablosunda ise grnm yledir.

ekil 2. Sipari Detaylar

www.bsenyurt.com Page 2608


imdi 10002 nolu sipari satrn silelim. Grld gibi Sepet tablosundan 10002 ile ilgili tm ilikil
kaytlarda silinecektir. Ayn zamanda Siparis tablosundan da bu siparis numarasna ait satr
silinecektir. Elbette dataSet nesnemize ait Update metodunu kullanmadmz iin bu deiiklikler
sql sunucumuzdaki orjinal tablolara yansmayacaktr.

ekil 3. 10002 nolu siparise ait tm kaytlar, Sepet tablosundan Silindi.

ekil 4. 10002 Siparis tablosundan silindi.

imdi oluturmu olduumuz bu kstlamada Delete kuraln None yapalm ve bakalm bu kez neler
olucak. Bu durumda aadaki hata mesajn alacaz.

ekil 5. DeleteRule=Rule.None

www.bsenyurt.com Page 2609


Doal olaraktanda, ne Siparis tablosundan ne de Sepet tablosundan satr silinmeyecektir. Bu ksa
bilgilerden sonra umuyorumki kstlamalar ile ilgili kavramlarkafanzda daha net bir ekilde
canlanmaya balamtr. Geldik bir makalemizin daha sonuna bir sonraki makalemizde grmek
dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

likili Tablolar DataSet le Kullanmak - 1 (


09.12.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, aralarnda relationship (iliki) bulunan tablolarn, bir DataSet nesnesinin
bellekte temsil ettii alanda nasl saklandn incelemeye alcacaz. Bunu yaparken de,
gelitireceimiz uygulama ile parant-child (ebeveyn-ocuk) yada master-detail (efendi-detay) ad
verilen ilikileri tayan tablolarmz bir windows applicationda bir dataGrid nesnesi ile nasl kolayca
gstereceimizi greceiz.

in srr Olinde diye bir reklam vard eskiden. imdi aklma o reklam geldi. Burada da iin srr
DataRelation ad verilen snftadr. DataRelation snfna ait nesneler, aralarnda ilikisel ba olan
tablolarnn, aralarndaki ilikiyi temsil ederler. Bir DataRelation nesnesi kullandmzda, bu nesneyi
mutlaka bir DataSet snf nesnesine eklememiz gerekmektedir. Dolaysyla DataSet snfmz,
aralarnda iliki olan tablolar temsil eden DataTable nesnelerini ve bu tablolar arasndaki ilikiyi
temsil eden DataRelation nesnesini(lerini) tamak durumundadr.

Aadaki ekil ile , bu konuyu zihnimizde daha kolay canlandrabiliriz. Sz konusu tablolar,
yazacamz uygulamayada da kullanacamz tablolardr. Dikkat edilecek olursa buradaki iki tablo
arasnda Siparis isimli tablodan, Sepet isimli tabloya bire-ok ( one to many ) bir iliki sz
konusudur. DataRelation nesnemiz bu ilikiyi DataSet iinde temsil etmektedir.

www.bsenyurt.com Page 2610


ekil 1 . DataRelation

Bir DataRelation nesnesi oluturmak iin kullanabileceimiz Constructor metodlar unlardr.

1 - public DataRelation(string, DataColumn,


DataColumn);

2 - public DataRelation(string, DataColumn[],


DataColumn[]);

3 - public DataRelation(string, DataColumn,


DataColumn, bool);

4 -public DataRelation(string, DataColumn[],


DataColumn[], bool);

Tm yapc metodlar ilk parametre olarak DataRelation iin string trde bir isim alrlar. l yapc
metodumuz, iki adet DataColumn tipinde parametre almaktadr. lk parametre master tabloya ati
primary key alann, ikinci DataColumn parametresi ise detail tabloya ait secondary key alann
temsil etmektedir. kinci yapc metodu ise aralarndaki ilikiler birden fazla tablo alanna bal olan
tablo ilikilerini tanmlamak iindir. Dikkat edilicek olursa, DataColumn[] dizileri sz
konusudur.nc ve drdnc yapclarnda kullanm tarzalar bir ve ikinci yapclar ile benzer
olmasna karn aldklar bool tipinde drdnc bir parametre daha vardr. Drdnc parametre ,
tablolar aras kullanlacak veri btnl kurallar uygulanacak ise True deerini alr eer bu
kurallar uygulanmayacak ise false deeri verilir.

imdi gelin ksa bir uygulama ile bu konuyu ileyelim. Uygulamamzda kullanlan tablolara ait
alanlar ve zellikleri yledir. lk tablomuz Siparis isimli tablomuz. Bu tabloda kullancnn vermi

www.bsenyurt.com Page 2611


olduu sipariin numaras ve tarihi ile ilgili bilgiler tutuluyor. Bu tablo bizim parent( master)
tablomuzdur.

ekil 2. Siparis Tablosu

Dier tablomuzda ise, verilen sipariin hangi rnlerden olutuuna dair bilgiler yer almakta.Bu
tablomuz ise bizim child tablomuzdur.

ekil 3. Sepet Tablosu

Uygulamamz bir windows application olarak gelitireceim. Bu nedenle vs.net ortamnda, yeni bir
windows application oluturuyoruz. Sayfann tasarm son derece basit. Bir adet dataGrid nesnemiz
var ve bu nesnemiz ilikil tablolarn kaytlarn gsterecek. Dilerseniz kodlarmz yazmaya
balayalm.

private void Form1_Load(object sender, System.EventArgs e)


{
/* nce sql sunucumuzda yer alan Friends isimli veritabanmz iin bir balant nesnesi
oluturuyoruz. */
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
/* SqlDataAdapter nesneleri yardmyla, Friends veritabannda yer alan Siparis ve Sepet
tablolarndaki verileri alyoruz ve sonrada bunlar DataTable nesnelerimize aktaryoruz.*/
SqlDataAdapter daSiparis=new SqlDataAdapter("Select * From Siparis",conFriends);
SqlDataAdapter daSepet=new SqlDataAdapter("Select * From Sepet",conFriends);
DataTable dtSiparis=new DataTable("Siparisler");
DataTable dtSepet=new DataTable("SiparisDetaylari");

www.bsenyurt.com Page 2612


daSiparis.Fill(dtSiparis);
daSepet.Fill(dtSepet);
/* imdi ise bu iki tablo arasndaki bire ok ilikiyi temsil edecek DataRelation nesmemizi
oluturuyoruz. */
DataRelation
drSiparisToSepet=new DataRelation("Siparis_To_Sepet",dtSiparis.Columns["SiparisID"],dtSepet.Co
lumns["SiparisID"]);
/* Artk oluturduumuz bu DataTable nesnelerini ve DataRelation nesnemizi DataSet
nesnemize ekleyebiliriz. Dikkat edicek olursanz, DataRelation nesnemizi dataSet nesnemizin
Relations koleksiyonuna ekledik. DataRelation nesneleri DataTable nesneleri gibi DataSet'e ait ilgili
koleksiyonlarda tutulmaktadrlar. Dolaysyla bir DataSet'e birden fazla tabloyu nasl
ekleyebiliyorsak birden fazla ilikiyide ekleyebiliriz. */
DataSet ds=new DataSet();
ds.Tables.Add(dtSiparis);
ds.Tables.Add(dtSepet);
ds.Relations.Add(drSiparisToSepet);
/* imdi ise dataGrid nesnemizi dataSet nesnemiz ile ilikilendirelim */
dataGrid1.DataSource=ds.Tables["Siparisler"];
}

Uygulamamz altrdmzda aadaki ekran grntsn elde ederiz. Grld gibi Siparis
tablosundaki veriler grnmektedir. Ltfen satrlarn yanlarndaki + iaretine dikkat edelim.( ekil
4) Bu art iaretine tkladmzda oluturmu olduumuz DataRelationn adn grrz.(ekil 5 )

ekil 4.

ekil 5.

Bu isimler birer link iermektedir. Bu linklerden birine tkladmzda bu satra ait detayl bilgiler
child tablodan(Sepet) gsterilirler. (ekil 6)

www.bsenyurt.com Page 2613


ekil 6.

Bir sonraki makalemizde tablolar arasndaki veri btnln salayan Constraint kurallarnn nasl
DataSete aktarldn inceleyeceiz.

Geldik bir makalemizin daha sonuna. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataColumn.Expression zellii le
Hesaplanm Alanlarn Oluturulmas (
06.12.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde bir tabloda sonradan hesaplanan alanlarn nasl oluturulacan incelemeye
alacaz. Her zaman olduu gibi konuyu iyi anlayabilmek iin bir rnek zerinden gideceiz. Bir
hesaplanan alan aslnda bir hesaplama ifadesidir. rnein var olan bir tablodaki bir alana ait her
deere ortak bir ilem yaptrmak istediimizi ve bu her veri iin oluan sonularnda tabloda ayr bir
alan ad altnda gzkmesini istediimizi varsayalm. Buna en gzel rneklerden birisi;

Diyelimki personelinizin maa bilgilerinin tutulduu tablomuz var. Bu tablomuzda yer alan maa
verilerinde deiik oranlarda artlar uygulamak istediinizi varsayalm. Yzde 10, yzde 15 vb...Bu
artlarda sadece ekranda izlemek istediinizi tablo zerinde kalc olarak yer almasn
istemediinizi dnn. Bu minik problemin zm DataColumn snfna ait Expression zelliidir.
Bu zellii yapmak istediimiz ilemin sonucunu oluturacak ifadelerden olutururuz. Konuyu daha
net anlayabilmek iin hi vakit kaybetmeden rneimizde geelim. Bu rnekte Maas isimli bir
tablodaki Maas alanlarna ait deerlere kullancnn setii oranlarda art uygulayacaz. Form
tasarmmz aadakine benzer olucak. Burada comboBox kontrolmzde %5 ten %55 e kadar
deerler girili. Hesapla balkl butona basldnda, hesaplanan alana ilikin ilemlerimizi
gerekletirilecek.

www.bsenyurt.com Page 2614


ekil 1. Form Tasarm

Hi vakit kaybetmeden kodlarmza geelim.

SqlConnection conFriends;
SqlDataAdapter da;
DataTable dtMaas;
/* Aadaki procedure ile, Sql sunucumuzda yer alan Friends isimli veritabanna balanyor,
buradan Maas isimli tablodaki verileri DataTable nesnemize yklyoruz. Daha sonrada dataGrid
kontrolmze veri kayna olarak bur DataTable nesnesimizi gsterek tablonun ieriinin
grnmesini salyoruz.*/
public void doldur()
{
conFriends=new SqlConnection("data source=localhost;initial catalog=Friends;integrated
security=sspi");
da=new SqlDataAdapter("Select * From Maas",conFriends);
dtMaas=new DataTable("Maaslar");
da.Fill(dtMaas);
dgMaas.DataSource=dtMaas;
}
private void Form1_Load(object sender, System.EventArgs e)
{
doldur(); /* Tablodan verilerimizi alan procedure'u aryoruz*/
}
private void btnHesapla_Click(object sender, System.EventArgs e)
{
/* Hesaplanan Alanmz iin bir DataColumn nesnesi tanmlyoruz. */
DataColumn dcArtisAlani=new DataColumn();
/* Expression zelliine yapmak istediimiz hesaplamay giriyoruz. Buradaki hesaplamada,
kullancnn cmbAris isimli comboBox kontrolnden setii oran kadar maalara art uygulanyor.*/

www.bsenyurt.com Page 2615


dcArtisAlani.Expression="Maas + (Maas *"+cmbArtis.Text+"/100)";
/* Yeni alanmz iin anlaml bir isim veriyoruz. Bu isimde art oranda yazmakta.*/
dcArtisAlani.ColumnName="Yuzde"+cmbArtis.Text+"Artis";
/* Daha sonra oluturduumuz bu hesaplanm alan DataTable nesnemize ekliyoruz. Bylece
bellekteki Maas tablomuzda, maaslara belirli bir art oran uygulanm verileri ieren DataColumn
nesnemiz hazrlanm oluyor.*/
dtMaas.Columns.Add(dcArtisAlani);
/* Son olarak dataGrid nesnemizi Refresh() metodu ile tazeleyerek hesaplanm alanmznda
grnmesini salyoruz.*/
dgMaas.Refresh();
}

Uygulamamz altrdmzda aadaki ekran grnts ile karlarz. Ben rnek olarak %10 luk
art uyguladm.

ekil 2. Program lk altnda.

te ilemimizin sonular.

www.bsenyurt.com Page 2616


ekil 3. Hesaplanm Alan

Grld gibi %10 luk artn uyguland yeni alanmz dataGridimiz iinde grlmektedir.
Unutmayalmki bu oluturduumuz DataColumn nesnesi sadece bellekteki tablomuza eklenmi bir
grntdr. Veritabanmzdaki tablomuza dorudan bir etisi yoktur. Tabiki performans asndan
ok yksek kapasiteli tablolarda alrken byle bir ilemin yaplmas zellikle a ortamlarnda
performans kaybnada yol aabilir. Bunun nne gemek iin kullanabileceimiz yntemlerden
birisi, sql sunucusunda bu hesaplamalarn yaptrlmas ve sonularn view nesneleri olarak
alnmasdr. Ancak kk boyutlu veya szlm veriler zerinde, Expression zelliinin kullanm
sizinde grdnz gibi son derece kolay ve faydaldr. Geldik bir makalemizin sonuna daha, tekrar
grnceye kadar hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataTable Snfn Kullanarak Programatik


Olarak Tablolar Oluturmak-2 ( 05.12.2003 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Hatrlayacanz gibi yaz dizimizin ilk blmnde, DataTable snfn kullanarak bellekte bir tablonun
ve bu tabloya ait alanlarn nasl yaratldn ilemitik. Bugnk makalemizde oluturmu
olduumuz bu tabloya kaytlar ekleyeceiz ve sonra bu DataTable nesnesini bir DataSete aktarp
ierisindeki verileri bir DataGrid kontrolnde gstereceiz. Bir dataTable nesnesinin bellekte temsil
ettii tabloya yeni satrlar baka bir deyile kaytlar eklemek iin, DataRow snfndan nesneleri
kullanacaz. Dilerseniz hi vakit kaybetmeden uygulamamza balayalm. lk rneimizin devam

www.bsenyurt.com Page 2617


niteliinde olucak bu almamzda kullancnn oluturduu tablodaki alan says kadar textBox
nesnesinide label nesneleri ile birlikte programatik olarak oluturacaz. te programmzn
kodlar,

DataTable dt; /* DataTable nesnemizi uygulama boyunca kullanabilmek iin tm metodlarin


disinda tanimladik. */
private void btnTabloOlustur_Click(object sender, System.EventArgs e)
{
dt=new DataTable(txtTabloAdi.Text);
MessageBox.Show(dt.TableName.ToString()+" TABLOSU BELLEKTE OLUSTURULDU");
lblTabloAdi.Text=dt.TableName.ToString(); /* TableName zelligi DataTable nesnesinin bellekte
temsil ettigi tablonun adini vermektedir.*/
/*Tablo olusturuldugunda otomatik olarak bir ID alani ekleyelim. Bu alan benzersiz bir alan
olucak yani ierdigi veriler tekrar etmiyecek. 1 den baslayarak birer birer otomatik olarak articak.
Ayni zamanda primary key olucak. Primary key oldugu zaman arama gibi islemleri yaparken bu
alani kullanacagiz.*/
DataColumn dcID=new DataColumn(); /* DataColumn nesnesi olusturulur.*/
dcID.ColumnName="ID"; /* Alanin adi veriliyor*/
dcID.DataType=Type.GetType("System.Int32"); /* Alanin veritipi belirleniyor*/
dcID.Unique=true;/* Alanin ierdigi verilerin tekrar etmeyecegi syleniyor.*/
dcID.AutoIncrement=true;/* Alanin degerlerinin otomatik olarak artacagi syleniyor.*/
dcID.AutoIncrementSeed=1;/* Ilk degeri 1 olucak.*/
dcID.AutoIncrementStep=1;/* Alanin degerleri 1'er articak.*/
dt.Columns.Add(dcID);/* Yukarida zellikleri belirtilen ID alani tablomuza ekleniyor. */
/* Asagidaki kod satirlari ile ID isimli alani Primary Key olarak belirliyoruz. */
DataColumn[] anahtarlar=new DataColumn[1];
anahtarlar[0]=dt.Columns["ID"];
dt.PrimaryKey=anahtarlar;
lstAlanlar.Items.Add(dt.Columns["ID"].ColumnName.ToString()+" Primary Key");
}
private void btnAlanEkle_Click(object sender, System.EventArgs e)
{
/*nce yeni alanimiz iin bir DataColumn nesnesi olusturulur*/
DataColumn dc=new DataColumn();
/*Simdi ise DataTable nesnemizin Columns koleksiyonuna olusturulan alanimizi ekliyoruz. Ilk
parametre, alanin adini temsil ederken, ikinci parametre ise alanin veri trn belirtmektedir. Add
metodu bu zellikleri ile olusturulan DataColumn nesnesini dataTable'a ekler. Bu sayede tabloda
alanimiz olusturulmus olur.*/
dt.Columns.Add(txtAlanAdi.Text,Type.GetType("System."+cmbAlanTuru.Text));
lstAlanlar.Items.Add("Alan Adi: "+dt.Columns[txtAlanAdi.Text].ColumnName.ToString()+" Veri
Tipi: "+dt.Columns[txtAlanAdi.Text].DataType.ToString());
/* ColumnName zelligi ile eklenen alanin adini, DataType zelligi ilede bu alanin veri trn
greniyoruz.*/
}
public void KontrolOlustur(string alanAdi,int index)
{
/* Aadaki kodlar asl konumuzdan uzaklamadan,aklamak istiyorum. DataTable'daki her
bir alan iin bir TextBox nesnesi ve Label nesnesi oluturulup formumuza ekleniyor. Top zelliinin
ayarlanna dikkatinizi ekmek isterin. Top zelliini bu metoda gnderdiimiz index paramteresi
ile arpyoruz. Bylece, o srada hangi indexli datacolumn nesnesinde isek ilgili kontroln formun

www.bsenyurt.com Page 2618


st noktasndan olan uzakl o kadar KAT artyor. Elbette en nemli zellik kontrollerin adlarnn
verilemsi. Tabi her bir kontro this.Controls.Add syntax' formumuza eklemeyi unutmuyoruz. */
System.Windows.Forms.TextBox txtAlan=new System.Windows.Forms.TextBox();
txtAlan.Text="";
txtAlan.Left=275;
txtAlan.Top=30*index;
txtAlan.Name="txt"+alanAdi.ToString();
txtAlan.Width=100;
txtAlan.Height=30;
this.Controls.Add(txtAlan);
System.Windows.Forms.Label lblAlan=new System.Windows.Forms.Label();
lblAlan.Text=alanAdi.ToUpper();
lblAlan.Left=200;
lblAlan.Top=30*index;
lblAlan.AutoSize=true;
this.Controls.Add(lblAlan);
}
private void btnKontrol_Click(object sender, System.EventArgs e)
{
/* Aadaki dng ile dataTable nesnemizdeki DataColumn says kadar dnecek bir dng
oluturuyoruz. Yanlk ID alanmz (0 indexli alan) deeri otomatik olarak atand iin bu kontrol
oluturmamza gerek yok. Bu nedenle dngmz 1 den balyor. Dng her bir DataColumn
nesnesi iin, bu alann adn parametre olarak alan ve ilgili textBox ve label nesnesini oluturacak
olan KontrolOlustur isimli metodu aryor.*/
for(int i=1;i<dt.Columns.Count;++i)
{
KontrolOlustur(dt.Columns[i].ColumnName.ToString(),i);
}
dgKayitlar.DataSource=dt; /* Burada dataGrid nesnemizin DataSource zelliini DataTable
nesnemiz ile ilikilendirerek dataGrid'i oluturduumuz tabloya balam oluyoruz. */
}
private void btnKaytEkle_Click(object sender, System.EventArgs e)
{
/* Bu butona tklandnda kullancnn oluturmu olduu kontrollere girdii deerler, tablonun
ilgili alanlarna ekleniyor ve sonular DataGrid nesnemizde gsteriliyor. */
string kontrol;
/* ncelikle yeni bir dataRow nesnesi tanmlyoruz ve DataTable snfna ait NewRow metodunu
kullanarak dataTable'mzn bellekte iaret ettii tabloda, veriler ile doldurulmak zere bo bir satr
ayoruz. */
DataRow dr;
dr=dt.NewRow();
/* Aadaki dng gznze korkutucu gelmesin. Yaptmz ilem DataTable'daki alan says
kadar srecek bir dng. Her bir alana, kullancnn ilgili textBox'ta girdii deeri eklemek iin, dr[i]
satrn kullanyoruz. dr[i] dataRow nesnesinin temsil ettii i indexli alana iaret ediyor. Peki ya i
indexli bu DataRow alannn dataTable'daki hangi alana iaret ettii nereden belli. te dt.NewRow()
dediimizde, dataTable'daki alanlardan oluan bir DataRow yani satr oluturmu oluyoruz. Daha
sonra yapmamz gereken ise textBox kontrolndeki veriyi almak ve bunu DataRow nesnesindeki
ilgili alana aktarmak. Bunun iin formdaki tm kontroller taranyor ve her bir kontrol acaba alanlar
iin oluturulmu TextBox nesnesi mi? ona baklyor. Eer yleyse dataRow nesnesinin i indexli
alanna bu kontroln ierdii text aktarlyor.*/

www.bsenyurt.com Page 2619


for(int i=1;i<dt.Columns.Count;++i)
{
kontrol="txt"+dt.Columns[i].ColumnName.ToString();
for(int j=0;j<this.Controls.Count;++j)
{
if(this.Controls[j].Name==kontrol)
{
dr[i]=this.Controls[j].Text;
}
}
}
/* Artk elimizde iindeki alanlar bizim girdiimiz veriler ile dolu bir DataRow nesne rnei var.
Tek yapmamz gereken bunu dataTable nesnemizin Rows koleksiyonuna eklemek. Daha sonra ise
dataGrid nesnemizi tazeleyerek grntnn yenilenmesini ve girdiimiz satrn burada grnmesini
salyoruz. */
dt.Rows.Add(dr);
.Refresh();
}

imdi programmz deneyelim. Ben rnek olarak Ad ,Soyad ve Birim alanlarndan oluan bir
tablo oluturdum ve iki kayt girdi. te sonu,

ekil 1. Programn almasnn sonucu.

Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde, DataRelation nesnesi yardm ile
birbirleri ilikili tablolarn nasl oluturulacan greceiz. Hepinize mutlu gnler dilerim.

www.bsenyurt.com Page 2620


Burak Selim ENYURT

selim@bsenyurt.com

Struct (Yap) Kavram ve Class (Snf) ile Struct


(Yap) Arasndaki Farklar ( 04.12.2003 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde struct kavramn incelemeye alacaz. Hatrlayacanz gibi, kendi


tanmladmz veri trlerinden birisi olan Numaralandrclar (Enumerators) grmtk. Benzer
ekilde dier bir veri tipide struct (yap) lardr.Yaplar, snflar ile byk benzerleklik gsterirler.
Snf gibi tanmlanrlar. Hatta snflar gibi, zellikler,metodlar,veriler, yapclar vb... ierebilirler.
Buna karn snflar ile yaplar arasnda ok nemli farkllklar vardr. l

Hereyden nce en nemli fark, yaplarn deer tr olmas ve snflarn referans tr olmasdr.
Snflar referans trnden olduklar iin, bellekte tutulu biimleri deer trlerine gre daha
farkldr. Referans tiplerinin sahip olduu veriler bellein bek(heap) ad verilen tarafnda
tutulurken, referansn ad stack(yn) da tutulur ve bekteki verilerin bulunduu adresi iaret eder.
Ancak deer trleri bellein stack denilen ksmnda tutulurlar. Aadaki ekil ile konuyu daha net
canlandrabiliriz. l

ekil 1. Referans Tipleri

www.bsenyurt.com Page 2621


Aadaki ekilde ise deer tiplerinin bellekte nasl tutulduunu gryorsunuz. l

ekil 2. Deer Tipleri

te snflar ile yaplar arasndaki en byk fark budur. Peki bu farkn bize salad getiriler
nelerdir? Ne zaman yap ne zaman snf kullanmalyz? zellikle metodlara veriler aktarrken bu
verileri snf ierisinde tanmladmzda, tm veriler metoda aktarlacan sadece bu verilerin
bekteki balang adresi aktarlr ve ilgili parametrenin de bu adresteki verilere iaret etmesi
salanm olur. Bylece byk boyutlu verileri stackta kopyalayarak gereksiz miktarda bellek
harcanmasnn nne geilmi olunur. Ancak kk boyutlarda veriler ile alrken bu verileri
snflar ierisinde kullandmzda bu kezde gereksiz yere bellek kullanld bek ier ve
performans der. Bu konudaki uzman gr 16 bytetan kk veriler iin yaplarn kullanlmas,
16 bytetan byk veriler iin ise snflarn kullanlmasdr. l

Dier taraftan yaplar ile snflar arasnda baka farkllklarda vardr. rnein bir yap iin varsaylan
yapc metod (default constructor) yazamayz. Derleyici hatas alrz. Ancak bu deiik sayda
parametreler alan yapclar yazmamz engellemez. Oysaki snflarda istersek snfn varsaylan
yapc metodunu kendimiz yazabilmekteyiz. l

Bir yap iersinde yer alan constructor metod(lar) iinde tanmlam olduumuz alanlara balang
deerlerini atamak zorundayz. Oysaki bir snftaki constructor(lar) iinde kullanlan alanlara
balang deerlerini atamaz isek, derleyici bizim yerimize saysal deerlere 0, boolean deerlere
false vb... gibi balang deerlerini kendisi otomatik olarak yapar. Ancak derleyici ayn ii yaplarda
yapmaz. Bu nedenle bir yap iinde kullandmz constructor(lar)daki tanmlam olduumuz
alanlara mutlaka ilk deerlerini vermemiz gerekir. Ancak yinede dikkat edilmesi gereken bir nokta
vardr. Eer yap rneini varsaylan yaplandrc ile oluturursak bu durumda derleyici yap iinde
kullanlan alanlara ilk deerleri atanmam ise kendisi ilk deerleri atar. Unutmayn, parametreli
constructorlarda her bir alan iin balang deerlerini bizim vermemiz gerekmektedir. rnein,
aadaki Console uygulamasn inceleyelim. l

using System;
namespace StructSample1
{
struct Zaman
{
private int saat,dakika,saniye;
private string kosucuAdi;

www.bsenyurt.com Page 2622


public string Kosucu
{
get
{
return kosucuAdi;
}
set
{
kosucuAdi=value;
}
}
public int Saat
{
get
{
return saat;
}
set
{
saat=value;
}
}
public int Dakika
{
get
{
return dakika;
}
set
{
dakika=value;
}
}
public int Saniye
{
get
{
return saniye;
}
set
{
saniye=value;
}
}
}
class Class1
{
[STAThread]

www.bsenyurt.com Page 2623


static void Main(string[] args)
{
Zaman z;
Console.WriteLine("Koucu:"+z.Kosucu);
Console.WriteLine("Saat:"+z.Saat.ToString());
Console.WriteLine("Dakika:"+z.Dakika.ToString());
Console.WriteLine("Saniye:"+z.Saniye.ToString());
}
}
}

Yukardaki kod derlenmeyecektir. Nitekim derleyici Use of unassigned local variable


'z' hatas ile z yaps iin ilk deerlerin atanmadn bize syleyecektir. Ancak z isimli Zaman
yap trn new anahtar ile tanmlarsak durum deiir. l

Zaman z;
Satr yerine
Zaman z=new Zaman();

yazalm .Bu durumda kod derlenir. Uygulama altnda aadaki ekran grnts ile
karlarz. Grld gibi z isimli yap rneini new yaplandrcs ile tanmladmzda, derleyici
bu yap iindeki zelliklere ilk deerleri kendi atamtr. Kosucu isimli zellik iin null, dier integer
zellikler iin ise 0.

ekil 3.New yaplandrcs ile ilk deer atamas.

Yine nemli bir farkta yaplarda tretme yapamyacamzdr. Bilindii gibi bir snf
oluturduumuzda bunu baka bir temel snftan kaltm yolu ile tretebilmekteyiz ki inheritance
olarak geen bu kavram ilerliyen makalelerimizde ileyeceiz. Ancak bir yapy baka bir yapy
temel alarak tretemeyiz. imdi yukarda verdiimiz rnekteki yapdan baka bir yap tretmeye
alalm.

struct yeni:Zaman
{
}

satrlarn kodumuza ekleyelim.Bu durumda uygulamay derlemeye altmzda aadaki hata


mesajn alrz.

'Zaman' : type in interface list is not an interface

www.bsenyurt.com Page 2624


Bu belirgin farkllklarda inceledikten sonra dilerseniz rneklerimiz ile konuyu pekitirmeye
alalm.

using System;
namespace StructSample1
{
struct Zaman
{
private int saat,dakika,saniye;
private string kosucuAdi;
/* Yap iin parametreli bir constructor metod tanmladk. Yap iinde yer alan
kosucuAdi,saat,dakika,saniye alanlarna ilk deerlerin atandna dikkat edelim. Bunlar atamassak
derleyici hatas alrz. */
public Zaman(string k,int s,int d,int sn)
{
kosucuAdi=k;
saat=s;
dakika=d;
saniye=sn;
}
/* Bir dizi zellik tanmlayarak private olarak tanmladmz asl alanlarn kullanmn
kolaylatryoruz. */
public string Kosucu
{
get
{
return kosucuAdi;
}
set
{
kosucuAdi=value;
}
}
public int Saat
{
get
{
return saat;
}
set
{
saat=value;
}
}
public int Dakika
{
get
{

www.bsenyurt.com Page 2625


return dakika;
}
set
{
dakika=value;
}
}
public int Saniye
{
get
{
return saniye;
}
set
{
saniye=value;
}
}
}
class Class1
{
static void Main(string[] args)
{
/* Zaman yaps iinde kendi yazdmz parametreli constuructorlar ile Zaman yaps
rnekleri oluturuyoruz. Yaptmz bu tanmlamarn ardndan bellein stack blgesinde derhal 4
adet deiken oluturulur ve deerleri atanr. Yani kosucuAdi,saat,dakika,saniye isimli private
olarak tanmladmz alanlar bellekte stack blgesinde oluturulur ve atadmz deerleri alrlar.
Bu oluan veri dizisinin adda Zaman yaps tipinde olan Baslangic ve Bitis deikenleridir. */

Zaman Baslangic=new Zaman("Burak",1,15,23);


Zaman Bitis=new Zaman("Burak",2,20,25);
/* Zaman yaps iinde tanmladmz zelliklere eriip ilem yapyoruz. Burada elbette
zamanlar birbirinden bu ekilde karmak matematiksel olarak bir cinayet. Ancak amacmz
yaplarn kullanmn anlamak. Bu satrlarda yap iindeki zelliklerimizin deerlerine eriiyor ve

www.bsenyurt.com Page 2626


bunlarn deerleri ile sembolik ilemler yapyoruz */
int saatFark=Bitis.Saat-Baslangic.Saat;
int dakikaFark=Bitis.Dakika-Baslangic.Dakika;
int saniyeFark=Bitis.Saniye-Baslangic.Saniye;
Console.WriteLine("Fark {0} saat, {1} dakika, {2}
saniye",saatFark,dakikaFark,saniyeFark);
}
}
}

Bir sonraki makalemizde grmek dileiyle. Hepinize mutlu gnler dilerim

Burak Selim ENYURT

selim@bsenyurt.com

DataTable Snfn Kullanarak Programatik


Olarak Tablolar Oluturmak-1 ( 04.12.2003 ) -
Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde balantsz katmann nemli bir snf olan DataTable nesnesini bir adan
incelemeye alacaz. Bilindii gibi DataTable snfndan tretilen bir nesne, bir tabloyu ve
elemanlarn bellekte temsil etmek iin kullanlmaktadr. DataTable snf bellekte temsil ettii
tablolara ait olan satrlar Rows koleksiyonuna ait DataRow nesneleri ile temsil ederken, tabloun
alanlarn ise, Columns koleksiyonuna ait DataColumn nesneleri ile temsil etmektedir. rnek
uygulamamzda bu snf nesnelerini detayl olarak kullanacaz. Dier yandan DataTable snf bir
tabloya ilikin kstaslarn yer ald Constraints koleksiyonuna ait Constraint nesnelerinedee
sahiptir. DataTable snfnn ve ye elemanlarn aadaki ekilde daha kolayca canlandrabiliriz.

www.bsenyurt.com Page 2627


ekil 1 DataTable mimarisi

Gelitireceimiz uygulamada, bizim belirlediimiz alanlardan oluan bir tabloyu bellekte


oluturmaya alacaz. ncelikle DataTable nesnesi ile bir tablo oluturmak iin aadaki admlar
takip etmeliyiz.

1 Bir DataTable nesnesi oluturup DataTablen bellekte temsil edecei tablo iin bir isim
belirlenir.

2 Tablomuzun ierecei alanlarn isimleri, veri trleri belirlenerek birer DataRow nesnesi
eklinde, DataTable nesnesinin Columns koleksiyonuna eklenir.

3 Tablomuz iin bir primary key alan belirlenir.

Bu admlarn ardndan tablomuz bellekte oluturulmu olucaktr. Bu noktadan sonra bu tablo


zerinde dilediimiz ilemleri yapabiliriz. Kayt ekleyebilir, silebilir, sorgulayabiliriz. Ama tabiki
program kapattmzda bellekteki tablonun yerinde yeller esiyor olucaktr. Ama zlmeyin ilerliyen
makalelerimizde SQL-DMO komutlar yardmyla programmz iinden bir sql sunucusu zerinde
veritaban oluturacak ve tablomuzu buraya ekleyeceiz.imdi dilerseniz birinci admdan itibaren
bu ilerin nasl yapldn minik rnekler ile inceleyelim ve daha sonrada asl uygulamamaz
yazalm. ncelikle ie tablomuzu bellekte temsil edicek datatable nesnesi oluturarak balayalm.
Aadaki kk uygulamay oluturalm.

www.bsenyurt.com Page 2628


ekil 2. Formun ilk hali

Ve kodlar,

private void btnTabloOlustur_Click(object sender, System.EventArgs e)

/* Bir tabloyu bellekte temsil edicek bir datatable nesnesi oluturarak ie balyoruz.
Tablomuza txtTabloAdi isimli TextBox'a giriline deeri isim olarak veriyoruz */

DataTable dt=new DataTable(txtTabloAdi.Text);

MessageBox.Show(dt.TableName.ToString()+" TABLOSU BELLEKTE OLUTURULDU");

imdi programmz altralm ve tablo ismi olarak DENEME diyelim. te sonu,

ekil 3. DataTable nesnesi oluturuldu.

imdi ise tablomuza nasl field(alan) ekleyeceimize bakalm. nceden bahsettiimiz gibi tablonun
alanlar aslnda DataTable snfnn Columns koleksiyonuna ait birer DataColumn nesnesidir.
Dolaysyla ncelikle bir DataRow nesnesi oluturup bu nesneyi ilgili DataTablen Columns
koleksiyonuna eklememiz gerekmektedir. Alann ismi dnda tabiki veri trnde belirtmeliyiz. Bu
veri trlerini belirtirken Type.GetType syntax kullanlr. Formumuzu biraz deitirelim. Kullanc
belirledii isimde ve trdeki alan, tabloya ekleyebilecek olsun. Sylemek isterimki bu uygulamada
hi bir kontrol mekanizmas uygulanmam ve hatalarn nnce geilmeye allmamtr. Nitekim
amacmz DataTable ile bir tablonun nasl oluturulacana dair basit bir rnek vermektir.

www.bsenyurt.com Page 2629


Formumuzu aadaki gibi deitirelim. Kullanc bir tablo ad girip oluturduktan sonra istedii
alanlar ekleyecek ve bu bilgiler listbox nesnemizde kullancya ayrca gsterilecek.

ekil 4. Formumuzun yeni hali.

imdide kodlarmz grelim.

DataTable dt; /* DataTable nesnemizi uygulama boyunca kullanabilmek iin tm metodlarn


dnda tanmladk. */

private void btnTabloOlustur_Click(object sender, System.EventArgs e)

dt=new DataTable(txtTabloAdi.Text);

MessageBox.Show(dt.TableName.ToString()+" TABLOSU BELLEKTE OLUTURULDU");

lblTabloAdi.Text=dt.TableName.ToString(); /* TableName zellii DataTable nesnesinin


bellekte temsil ettii tablonun adn vermektedir.*/

private void btnAlanEkle_Click(object sender, System.EventArgs e)

/*nce yeni alanmz iin bir DataColumn nesnesi oluturulur*/

DataColumn dc=new DataColumn();

/*imdi ise DataTable nesnemizin Columns koleksiyonuna oluturulan alanmz ekliyoruz.


lk parametre, alann adn temsil ederken, ikinci parametre ise alann veri trn belirtmektedir.

www.bsenyurt.com Page 2630


Add metodu bu zellikleri ile oluturulan DataColumn nesnesini dataTable'a ekler. Bu sayede
tabloda alanmz oluturulmu olur.*/

dt.Columns.Add(txtAlanAdi.Text,Type.GetType("System."+cmbAlanTuru.Text));

lstAlanlar.Items.Add("Alan Ad: "+dt.Columns[txtAlanAdi.Text].ColumnName.ToString()+"


Veri Tipi: "+dt.Columns[txtAlanAdi.Text].DataType.ToString());

/* ColumnName zellii ile eklenen alann adn, DataType zellii ilede bu alann veri
trn reniyoruz.*/

Uygulamamz deneyelim.

ekil 5. Alanlarmzda tabloya ekleyelim.

Alanlara veri trlerini aktarrken kullanabileceimiz dier rnek deerler aadaki gibidir; bunlar
listbox kontrolne desing time(tasarm zamannda) eklenmitir.

System.Int32

System.Int16

System.Int64

System.Byte

System.Char

System.Single

System.Decimal

www.bsenyurt.com Page 2631


System.Double

Gibi...

imdi de setiimiz bir alan primary key olarak belirleyelim. Unique (benzersiz) integer deerler
alcak bir alan olsun bu ve 1000 den balayarak 1er 1er otomatik olarak artsn. Bildiini ID
alanlarndan bahsediyorum. Bunu kullancya sormadan otomatik olarak biz yaratalm ve konudan
fazlaca uzaklamayalm. Sadece btnTabloOlusturun kodlarna ekleme yapyoruz.

private void btnTabloOlustur_Click(object sender, System.EventArgs e)

dt=new DataTable(txtTabloAdi.Text);

MessageBox.Show(dt.TableName.ToString()+" TABLOSU BELLEKTE OLUTURULDU");

lblTabloAdi.Text=dt.TableName.ToString(); /* TableName zellii DataTable nesnesinin


bellekte temsil ettii tablonun adn vermektedir.*/

/* Tablo oluturulduunda otomatik olarak bir ID alan ekleyelim. Bu alan benzersiz bir
alan olucak yani ierdii veriler tekrar etmiyecek. 1 den balayarak birer birer otomatik olarak
artcak. Ayn zamanda primary key olucak. Primary key olduu zaman arama gibi ilemleri
yaparken bu alan kullanacaz.*/

DataColumn dcID=new

DataColumn(); /* DataColumn nesnesi oluturulur.*/

dcID.ColumnName="ID"; /* Alann ad veriliyor*./

cID.DataType=Type.GetType("System.Int32"); /* Alann veritipi belirleniyor*/

dcID.Unique=true;/* Alann ierdii verilerin tekrar etmeyecei syleniyor.*/

dcID.AutoIncrement=true;/* Alann deerlerinin otomatik olarak artaca syleniyor.*/

dcID.AutoIncrementSeed=1;/* lk deeri 1 olucak.*/

dcID.AutoIncrementStep=1;/* Alann deerleri 1'er artcak.*/

dt.Columns.Add(dcID);/* Yukarda zellikleri belirtilen ID alan tablomuza ekleniyor. */

/* Aadaki kod satrlar ile ID isimli alan Primary Key olarak belirliyoruz. */

DataColumn[] anahtarlar=new DataColumn[1];

anahtarlar[0]=dt.Columns["ID"];

dt.PrimaryKey=anahtarlar;

lstAlanlar.Items.Add(dt.Columns["ID"].ColumnName.ToString()+" Primary Key");

www.bsenyurt.com Page 2632


Geldik bir makalemizin daha sonuna. Bir sonraki makalemizde oluturduumuz bu tabloya nasl
veri ekleneceini greceimiz ok ksa bir uygulama yazacaz. Hepinizi mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Basit Bir Web Service Uygulamas ( 01.12.2003 )


- Web Servis
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde web servislerinin nasl kullanldn greceiz. Her zaman olduu gibi
konuyu aklayc basit bir rnek zerinde alacaz. ncelikle web servisi nedir, ne ie yarar bunu
aklamaya alalm. Web servisi, internet zerinden eriilebilen, her trl platform ile balant
kurabileceimiz, geriye sonu dndren(dndrmeye) fonksiyonelliklere ve hizmetlere sahip olan
bir uygulama parasdr. Aadaki ekil ile konuyu zihnimizde daha kolay canlandrabiliriz.

ekil 1 . Web Servislerinin yaps

lekildende grld gibi SOAP isminde bir yapdan bahsediyoruz. SOAP Simple Object Access
Protocol anlamna gelen XML tabanl bir haberleme teknolojisidir. Web servisi ile bu web servisinin
kullanan uygulamalar arasndaki iletiimi salar. Dolaysyla, web servisleri ve bu servisleri kullanan
uygulamalarn birbirlerini anlayabilmesini salar. Web servislerinden uygulamalara giden veri
paketleri ve uygulamalardan web servislerine giden veri paketleri bu standart protokol
kullanmaktadr. Web servislerinin yazld dil ile bunlaru kullanan uygulamalarn (bir windows

www.bsenyurt.com Page 2633


application, bir web application vb...) yazld diller farkl olabilir. SOAP aradaki iletiim
standartlatrdndan farkl diller sorun yaratmaz. Tabi bunu salayan en byk etken SOAPn XML
tabanl teknolojisidir.

Bir web servis uygulamas yaratldnda, bu web servisi kullanacak olan uygulamalarn web
servisinin nerede olduunu ncelikle bilmesi gerekir. Bunu salayan ise web proxylerdir. Bir web
proxy yazmak ounlukla kafa kartrc kodlardan olumaktadr. Ancak VS.Net gibi bir ortamda
bunu hazrlamakta olduka kolaydr. Uygulamaya, web servisin yeri Web Proxy dosyas ile
bildirildikten sonra, uygulamamzdan bu web servis zerindeki metodlara kolayca eriebiliriz.

imdi, basit bir web servis uygulamas gelitireceiz. ncelikle web servisimizi yazacaz. Daha
sonra ise, bu web servisini kullanacamz bir windows application gelitireceiz. Normalde birde
web proxy uygulamas gelitirmemiz gerekiyor. Ancak bu ii VS.NETe brakacaz.

Basit olmas asndan web servisimiz, bulunduu sunucu zerindeki bir sql sunucusunda yer alan
bir veritabanndan, bir tabloya ait veri kmesini DataSet nesnesi olarak, servisi aran
uygulamaya geirecek. Gelitirdiim uygulamam ayn makine zerindeki bir web servisini
kullanyor. ncelikle web servisimizi oluturalm. Bunun iin New Projectten ASP.NET Web Service
seiyoruz. Grld gibi uygulama otomatik olarak internet information servern kurulu olduu
sanal web sunucusunda oluturuluyor. Dolaysyla oluturulan bu web servise bir browser
yardmylada eriebiliriz.

ekil 2. Web Service

Bu ilemi yaptmz takdirde Service1.asmx isimli bir dosya ieren bir web servis uygulamasnn
olutuunu grrz. Web servislerinin dosya uzants asmx dir. Bu uzant alma zamannda veya
bir tarayc penceresinde bu dosyann bir web servis olduunu belirtir.

www.bsenyurt.com Page 2634


ekil 3. Web servisleri asmx uzantsna sahiptir.

lTo Switch Code Window ile kod penceresine getiimizde aadaki kodlar grrz. ( Burada,
Service1 ismi SrvKitap ile deitirilmi ayn zamanda Constructorun ad ve Solution Explorerda yer
alan dosya adda SrvKitap yaplmtr.)

using System;

using System.Collections;

using System.ComponentModel;

using System.Data;

using System.Diagnostics;

using System.Web;

using System.Web.Services;

namespace KitapServis

/// <summary>

/// Summary description for Service1.

/// </summary>

public class SrvKitap : System.Web.Services.WebService

public SrvKitap()

//CODEGEN: This call is required by the ASP.NET Web Services Designer

www.bsenyurt.com Page 2635


InitializeComponent();

#region Component Designer generated code

//Required by the Web Services Designer

private IContainer components = null;

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

/// <summary>

/// Clean up any resources being used.

/// </summary>

protected override void Dispose( bool disposing )

if(disposing && components != null)

components.Dispose();

base.Dispose(disposing);

#endregion

www.bsenyurt.com Page 2636


// WEB SERVICE EXAMPLE

// The HelloWorld() example service returns the string Hello World

// To build, uncomment the following lines then save and build the project

// To test this web service, press F5

// [WebMethod]

// public string HelloWorld()

// {

// return "Hello World";

// }

Kodlar ksaca inceleyecek olursak, web servislere ait zellikleri kullanabilmek iin
System.Web.Services namespaceinin eklendiini, SrvKitap isimli snfn bir web servisin niteliklerine
sahip olmas iin, System.Web.Services snfndan tretildiini grrz. Ayrca yorum satr olarak
belirtilen yerde VS.NET bize hazr olarak HelloWorld isimli bir web metodu sunmaktadr. Bu
metodun bandada dikkat edicek olursanz [WebMothod] satr yer alyor. Bu anahtar szck,
izleyen metodun bir web servis metodu olduunu belirtmektedir. imdi biz kendi web servis
metodumuzu buraya ekleyelim.

[WebMethod]

public DataSet KitapListesi()

SqlConnection conFriends=new SqlConnection("data source=localhost;initial


catalog=Friends;integrated security=sspi");

SqlDataAdapter da=new SqlDataAdapter("Select Adi,Fiyat From Kitaplar",conFriends);

DataSet ds=new DataSet();

da.Fill(ds);

return ds;

Eklediimiz bu web metod sadece Sql sunucusu zerinde yer alan Friends isimli veritabanna
balanmakta ve burada Kitaplar isimli tablodan Adi ve Fiyat bilgilerini alarak, sonu kmesini bir

www.bsenyurt.com Page 2637


DataSet iine aktarmaktadr. Sonra metod bu DataSetI geri dndrmektedir.imdi uygulamamz
derleyelim ve Internet Explorer aarak adres satrna unu girelim

http://localhost/kitapservis/SrvKitap.asmx

bu durumda, aadaki ekran grntsn alrz.

ekil 4. Internet Explorer penceresinde SrvKitap.asmxin grnts.

SrvKitap isimli web servisimiz burada grlmektedir. imdi KitapListesi adl linke tklarsak (ki bu
link oluturduumuz KitapListesi adl web servis metoduna iaret etmektedir)

ekil 5. Invoke

www.bsenyurt.com Page 2638


Invoke butonuna basarak web servisimizi test edebiliriz. Bunun sonucunda metod altrlr ve
sonular xml olarak gsterilir.

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

- <DataSet xmlns="http://tempuri.org/">
- <xs:schema
id="NewDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="u
rn:schemas-microsoft-com:xml-msdata">
- <xs:element name="NewDataSet" msdata:IsDataSet="true" msdata:Locale="tr-TR">
- <xs:complexType>
- <xs:choice maxOccurs="unbounded">
- <xs:element name="Table">
- <xs:complexType>
- <xs:sequence>
<xs:element name="Adi" type="xs:string" minOccurs="0" />
<xs:element name="Fiyat" type="xs:decimal" minOccurs="0" />

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:choice>

</xs:complexType>

</xs:element>

</xs:schema>

- <diffgr:diffgram xmlns:msdata="urn:schemas-microsoft-com:xml-
msdata" xmlns:diffgr="urn:schemas-microsoft-com:xml-diffgram-v1">
- <NewDataSet xmlns="">
- <Table diffgr:id="Table1" msdata:rowOrder="0">
<Adi>Delphi 5'e Bak</Adi>
<Fiyat>100.0000</Fiyat>

</Table>

- <Table diffgr:id="Table2" msdata:rowOrder="1">


<Adi>Delphi 5 Uygulama Gelitirme Klavuzu</Adi>
<Fiyat>250.0000</Fiyat>

</Table>

- <Table diffgr:id="Table3" msdata:rowOrder="2">


<Adi>Delphi 5 Kullanm Klavuzu</Adi>
<Fiyat>50.0000</Fiyat>

www.bsenyurt.com Page 2639


</Table>

- <Table diffgr:id="Table4" msdata:rowOrder="3">


<Adi>Microsoft Visual Basic 6.0 Gelitirmek Ustalama Dizisi</Adi>
<Fiyat>75.0000</Fiyat>

</Table>

- <Table diffgr:id="Table5" msdata:rowOrder="4">


<Adi>Visual Basic 6 Temel Balang Klavuzu</Adi>
<Fiyat>80.0000</Fiyat>

</Table>

- <Table diffgr:id="Table6" msdata:rowOrder="5">


<Adi>Microsoft Visual Basic 6 Temel Kullanm Klavuzu Herkes in!</Adi>
<Fiyat>15.0000</Fiyat>

</Table>

- <Table diffgr:id="Table7" msdata:rowOrder="6">


<Adi>ASP ile E-Ticaret Programcl</Adi>
<Fiyat>25.0000</Fiyat>

</Table>

- <Table diffgr:id="Table8" msdata:rowOrder="7">


<Adi>ASP 3.0 Active Server Pages Web Programcl Temel Balang Klavuzu</Adi>
<Fiyat>150.0000</Fiyat>

</Table>

</NewDataSet>

</diffgr:diffgram>

</DataSet>

Sra geldi bu web servisini kullanacak olan uygulamamz yazmaya. rnein bir Windows
Uyulamasndan bu servise erielim. Yeni bir Windows Application oluturalm ve Formumuzu
aadakine benzer bir ekilde tasarlayalm.

www.bsenyurt.com Page 2640


ekil 6 Form Tasarm.

Formumuz bir adet datagrid nesnesi ve bir adet button nesnesi ieriyor. Button nesnemize
tkladmzda, web servisimizdeki KitapListesi adl metodumuzu aracak ve dataGridimizi bu
metoddan dnen dataSete balyacaz.Ancak ncelikle uygulamamza, web servisin yerini
belirtmeliyiz ki onu kullanabilelim.Bunun iin Solution Explorer penceresinde Add Web Reference
seimi yapyoruz.

ekil 7. Uygulamaya bir Web Reference eklemek.

Karmza gelen pencerede adres satrna http:\\localhost\KitapServis\SrvKitap.asmx (yani web


servisimizin adresi) yazyor ve Go tuuna basyoruz. Web service bulunduunda bu bize1 Service
Found ifadesi ile belirtiliyor.

www.bsenyurt.com Page 2641


ekil 8. Servisin eklenmesi.

Add Reference diyerek servisimizi uygulamamza ekliyoruz. Bu durumda Solution Explorerdan


uygulamamzn ierdii dosyalara baktmzda yeni dosyalarn eklendiini gryoruz.

www.bsenyurt.com Page 2642


ekil 9. Reference.cs adl dosyasna dikkat.

Burada Reference.cs isimli dosya ite bizim yazmaktan ekindiimi Web Proxy dosyasnn ta kendisi
oluyor. Bu dosyann kodlar ise aadaki gibidir.

//------------------------------------------------------------------------------

// <autogenerated>

// This code was generated by a tool.

// Runtime Version: 1.1.4322.573

//

// Changes to this file may cause incorrect behavior and will be lost if

// the code is regenerated.

// </autogenerated>

//------------------------------------------------------------------------------

//

// This source code was auto-generated by Microsoft.VSDesigner, Version 1.1.4322.573.

//

namespace KitapFiyatlari.localhost

using System.Diagnostics;

using System.Xml.Serialization

using System;

using System.Web.Services.Protocols;

using System.ComponentModel;

using System.Web.Services;

/// <remarks/>

[System.Diagnostics.DebuggerStepThroughAttribute()]

www.bsenyurt.com Page 2643


[System.ComponentModel.DesignerCategoryAttribute("code")]

[System.Web.Services.WebServiceBindingAttribute(Name="SrvKitapSoap",
Namespace="http://tempuri.org/")]

public class SrvKitap : System.Web.Services.Protocols.SoapHttpClientProtocol

/// <remarks/>

public SrvKitap()

this.Url = "http://localhost/KitapServis/SrvKitap.asmx";

/// <remarks/>

[System.Web.Services.Protocols.SoapDocumentMethodAttribute("http://tempuri.org/Kitap
Listesi", RequestNamespace="http://tempuri.org/", ResponseNamespace="http://tempuri.org/",
Use=System.Web.Services.Description.SoapBindingUse.Literal,
ParameterStyle=System.Web.Services.Protocols.SoapParameterStyle.Wrapped)]

public System.Data.DataSet KitapListesi()

object[] results = this.Invoke("KitapListesi", new object[0]);

return ((System.Data.DataSet)(results[0]));

/// <remarks/>

public System.IAsyncResult BeginKitapListesi(System.AsyncCallback


callback, object asyncState)

return this.BeginInvoke("KitapListesi", new object[0], callback, asyncState);

/// <remarks/>

public System.Data.DataSet EndKitapListesi(System.IAsyncResult asyncResult)

www.bsenyurt.com Page 2644


object[] results = this.EndInvoke(asyncResult);

return ((System.Data.DataSet)(results[0]));

Karmak olduu gzlenen bu kodlarn aklamasn ilerleyen makalerimde iyeceim. Artk web
servisimizi uygulamamza eklediimize gore, bunu kullanmaya ne dersiniz. te button nesnemize
tklandnda altrlacak kodlar.

private void button1_Click(object sender, System.EventArgs e)

localhost.SrvKitap srv=new localhost.SrvKitap(); /* Servisimizi kullanabilmek iin bu servisten


bir rnek nesne yaratyoruz*/

DataSet ds=new DataSet();

ds=srv.KitapListesi(); /* Servisteki KitapListesi isimli metodumuzu aryoruz.*/

dataGrid1.DataSource=ds;

ekil 10. Sonu.

www.bsenyurt.com Page 2645


Evet geldik bir makalemizin daha sonuna . Bir sonraki makalemizde grmek dileiyle hepinizze
mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Enumerators ( 01.12.2003 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, kendi deer trlerimizi oluturmann yollarndan birisi olan Enumeratorlar
inceleyeceiz. C# dilinde veri depolamak iin kullanabileceim temel veri trleri yannda kendi
tanmlayabileceimiz trlerde vardr. Bunlar Structs(Yaplar), Arrays(Diziler) ve
Enumerators(Numaralandrclar) dr. Numaralandrclar, snrl sayda deer ieren deikenler
yaratmamza olanak salarlar. Burada bahsi geen deiken deerleri bir grup olutururlar ve
sembolik bir adla temsil edilirler. Numaralandrclar kullanma nedenlerimizden birisi verilere
anlamlar yklekleyerek, program ierisinde kolay okunabilmelerini ve anlalabilmelerini
salamaktr. rneklerimizde bu konuyu ok daha iyi anlyacaksnz. Bir Numaralandrc tanmlamak
iin aadaki syntax kullanlr.

Kapsam belirteleri enum numaralandrcAdi


{
birinciUye,
ikinciUye,
ucuncuUye,
}

Kapsam belirteleri protected,public,private,internal yada new deerini alr ve numaralandrcnn


yaayaca kapsam belirtir. Dikkat edilecek olursa, elemanlara herhangibi deer atamas
yaplmamtr. Nitekim Numaralandrclarn zelliidir bu. lk eleman 0 deerine sahip olmak zere
dier elemanlar 1 ve 2 deerlerini sahip olucak ekilde belirlenirler. Dolaysyla programn
herhangibir yerinde bu numaralandrcya ait elemana ulatmzda, bu elemann index deerine
erimi oluruz. Grdnz gibi numaralandrc kullanmak okunurluu arttrmaktadr.Dilersek
numaralandrc elemanlarnn 0 indexinden deil de her hangibir deerden balamasn salayabilir
ve hatta dier elemanlarada farkl index deerleri atayabiliriz. Basit bir Numaralandrc rnei ile
konuyu daha iyi anlamaya alalm.

using System;
namespace enumSample1
{
class Class1
{
/* Haftann gnlerini temsil edicek bir numaralandrc tipi oluturuyoruz. Pazartesi 0 index
deerine sahip iken Pazar 6 index deerine sahip olucaktr.*/
enum Gunler
{
Pazartesi,

www.bsenyurt.com Page 2646


Sali,
Carsamba,
Persembe,
Cuma,
Cumartesi,
Pazar
}
static void Main(string[] args)
{
Console.WriteLine("Pazartesi gnnn deeri={0}",(int)Gunler.Pazartesi);
Console.WriteLine("aramba gnn deeri={0}",(int)Gunler.Carsamba);
}
}
}

Burada Gunler. Yazdktan sonar VS.NET in intellisense zellii sayesinde, numaralandrcnn


sahip olduu deerler kolayca ulaabiliriz.

ekil 1. Intellisense saolsun.

Program altracak olursak aadaki ekran grntsn elde ederiz.

ekil 2. Ilk Ornek

imdi baka bir rnek gelitirelim. Bu kez numaralandrcnn deerleri farkl olsun.

enum Artis
{
Memur=15,
Isci=10,
Muhendis=8,
Doktor=17,

www.bsenyurt.com Page 2647


Asker=12
}
static void Main(string[] args)
{
Console.WriteLine("Memur maa zam art oran={0}",(int)Artis.Memur);
Console.WriteLine("Muhendis maa zam art oran= {0}",(int)Artis.Muhendis);
}

ekil 3. kinci rnein Sonucu

Dikkat edicek olursak, numaralandrclar program iinde kullanrken, ak olarak (explicit) bir
dnm yapmaktayz. u ana kadar numaralandrc elemanlarna integer deerler atadk. Ama
dilersek Long tipinden deerde atayabiliriz. Fakat bu durumda enum n deer trnde
belirtmemiz gerekmektedir.rnein,

enum Sinirlar:long
{
EnBuyuk=458796452135L,
EnKucuk=255L
}
static void Main(string[] args)
{
Console.WriteLine("En st snr={0}",(long)Sinirlar.EnBuyuk);
Console.WriteLine("Muhendis maa zam art oran={0}",(long)Sinirlar.EnKucuk);
}

Grld gibi Sinirlar isimli numaralandrc long tipinde belirtilmitir. Bu sayede numaralandrc
elemanlarna long veri tipinde deerler atanabilmitir. Dikkat edilecek bir dier noktada, bu
elemanlara ait deerleri kullanrken, long tipine dntrme yaplmasdr. Bir numaralandrc
varsaylan olarak integer tiptedir. Bu nedenle integer deerleri olan bir numaralandrc
tanmlanrken int olarak belirtilmesine gerek yoktur. imdi daha ok ie yarar bir rnek
gelitirmeye alalm. Uygulamamz son derece basit bir forma sahp ve bir ka satr koddan
oluuyor. Amacmz numaralandrc kullanmann programc asndan ileri daha da kolaylatryor
olmas. Uygulamamz bir Windows Application. Form tasarmmz aadaki gibi olucak.

www.bsenyurt.com Page 2648


ekil 4. Form Tasarmmz.

Form yklenirken ehir Kodlarnn yer ald comboBox kontrolmz otomatik olarak
numaralandrcnn yardmyla doldurulucak. te program kodlar.

public enum AlanKodu


{
Anadolu=216,
Avrupa=212,
Ankara=312,
Izmir=412
}
private void Form1_Load(object sender, System.EventArgs e)
{
comboBox1.Items.Add(AlanKodu.Anadolu);
comboBox1.Items.Add(AlanKodu.Ankara);
comboBox1.Items.Add(AlanKodu.Avrupa);
comboBox1.Items.Add(AlanKodu.Izmir);
}

te sonu,

ekil 5 . Sonu .

Aslnda bu comboBox kontroln baka ekillerde de alan kodlar ile ykleyebiliriz . Bunu
yapmann saysz yolu var. Burada asl dikkat etmemiz gereken nokta numaralandrc sayesinde bu
saysal kodlarla kafamz kartrmak yerine daha bilinen isimler ile ayn sonuca ulamamzdr.

www.bsenyurt.com Page 2649


Geldik bir makalemizin daha sonuna. lerliyen makalelerimizde bu kez yine kendi deer tiplerimizi
nasl yaratabileceimize struct kavram ile devam edeceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

DataSet ve WriteXml Metodunun Kullanm (


30.11.2003 ) - Ado.Net
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, bir dataset nesnesinin ierdii tablolarn ve bu tablolardaki alanlara ait
bilgilerin xml formatnda nasl yazdrldn greceiz. rneimiz son derece basit. rnek
uygulamamzda, Sql sunucusu zerinde yer alan, Friends isimli databaseden Kitaplar isimli tabloya
ait verileri tayan bir dataset nesnesini kullanacaz. DataSet snfna ait WriteXml metodu dataset
ierisinde yer alan bilgilerin bir xml dokumanna Schema bilgisi ile birlikte aktarlmasna imkan
salmakatadr. Bu metoda ait 8 adet yapc(Constructor) metod bulunmakta olup biz
rneimizde,

Public void WriteXml(string dosyaadi, XmlWriteMode mod);

Yapcsn kullanacaz. Burada yer alan ilk parametre xml ieriini kaydedeciimiz dosyann tam
yol adn tamaktadr. kinci parametre ise ;

XmlWriteMode.IgnoreSchema

XmlWriteMode.WriteSchema

XmlWriteMode.DiffGram

Deerlerinden birini alr. IgnoreSchema olarak belirtildiinde, DataSet nesnesinin ierdii veriler,
Schema bilgileri olmadan ( rnein alan adlar, veri tipleri, uzunluklar vb...) xml dokuman haline
getirilir. WriteSchema olmas halinde ise, Schema bilgileri ayn xml dosyasnn st ksmna
<xs:schema> ile </xs:schema> taglar arasnda yazlr. DiffGram durumunda ise, veriler zerinde
yaplan deiikliklerin takip edilebilmesi amalanmtr. Dilerseniz vakit kaybetmeden rnek
uygulamamza geelim. Basit bir Console uygulamas oluturacaz.

using System;
using System.Data;
using System.Data.SqlClient;
namespace WriteXml
{
class Class1
{
[STAThread]
static void Main(string[] args)

www.bsenyurt.com Page 2650


{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
SqlDataAdapter da=new SqlDataAdapter("Select Kategori,Adi,Yazar,BasimEvi From
Kitaplar",conFriends);
DataSet ds=new DataSet();
conFriends.Open();
da.Fill(ds);
/*yukardaki admlarda, Sql sunucumuz zerinde yer alan Friends isimli database'e bir
balant ayor, SqlDataAdapter nesnemiz yardmyla bu database iindeki Kitaplar isimli tablodan
verileri alyor ve bunlar bir dataset nesnesine yklyoruz.*/
ds.WriteXml("D:\\Kitaplar.xml",XmlWriteMode.WriteSchema); /* Bu admda ise, dataset
nesnesini ierdii verileri Schema bilgisi ile birlikte Kitaplar.xml isimli xml dokumanna yazyoruz.
*/
conFriends.Close(); // Balantmzla iimiz bittiinden kapatyoruz.
}
}
}

Bu uygulamay altrdmzda, D:\Kitaplar.xml isimli bir dosyann olutuunu grrz. Bu dosyay


atmzda ise aada yer alan xml kodlarn elde ederiz. Grdnz gibi verilerin yannda
alanlara ait bilgilerde ayn xml dosyas iine yklenmitir.

www.bsenyurt.com Page 2651


Kodu imdide aadaki gibi deitirelim. IgnoreSchema seimini kullanalm bu kezde.

using System;
using System.Data;
using System.Data.SqlClient;
namespace WriteXml
{
class Class1
{
[STAThread]
static void Main(string[] args)
{
SqlConnection conFriends=new SqlConnection("data source=localhost;initial
catalog=Friends;integrated security=sspi");
SqlDataAdapter da=new SqlDataAdapter("Select Kategori,Adi,Yazar,BasimEvi From
Kitaplar",conFriends);

www.bsenyurt.com Page 2652


DataSet ds=new DataSet();
conFriends.Open();
da.Fill(ds);
ds.WriteXml("D:\\Kitaplar.xml",XmlWriteMode.IgnoreSchema);
conFriends.Close();
}
}
}

Bu durumda, Kitaplar.xml dosyamzn ieriine bakcak olursak schema bilgilerinin eklenmediini


sadece tablonun ierdii verilerin yer aldn grrz.

Bir sonraki makalemizde grmek dileiyle hepinizi mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Params Anahtar Szcnn Kullanm (


30.11.2003 ) - C#
Deerli Okurlarm, Merhabalar.

www.bsenyurt.com Page 2653


Bugnk makalemizde, C# metodlarnda nemli bir yere sahip olduunu dndm params
anahtar kelimesinin nasl kullanldn incelemeye alacaz. Bildiiniz gibi metodlara verileri
parametre olarak aktarabiliyor ve bunlar metod iersinde ileyebiliyoruz. Ancak parametre olarak
geirilen veriler belli sayda oluyor. Diyelimki saysn bilmediimiz bir eleman kmesini parametre
olarak geirmek istiyoruz. Bunu nasl baarabiliriz? te params anahtar szc bu noktada
devreye girmektedir. Hemen ok basit bir rnek ile konuya hzl bir giri yapalm.

using System;
namespace ParamsSample1
{
class Class1
{
/* burada Carpim isimli metodumuza, integer tipinde deerler geirilmesini salyoruz.
params anahtar bu metoda istediimiz sayda integer deer geirebileceimizi ifade ediyor*/
public int Carpim(params int[] deger)
{
int sonuc=1;
for(int i=0;i<deger.Length;++i) /*Metoda gnderilen elemanlar doal olarak bir dizi
olutururlar. Bu dizideki elemanlara bir for dngs ile kolayca eriebiliriz. Dizinin eleman saysn
ise Length zellii ile reniyoruz.*/
{
sonuc*=deger[i]; /* Burada metoda geirilen integer deerlerin birbirleri ile
arplmasn salyoruz*/
}
return sonuc;
}
static void Main(string[] args)
{
Class1 cl=new Class1();
Console.WriteLine("1*2*3*4={0}",cl.Carpim(1,2,3,4)); /* Burada Carpim isimli metoda
4 integer deer gnderdik. Aadaki kodda ise 2 adet integer deer gnderiyoruz.*/
Console.WriteLine("8*5={0}",cl.Carpim(8,5));
Console.ReadLine();
}
}
}

Bu rnei altracak olursak, aadaki sonucu elde ederiz.

ekil 1. Ilk Params rneinin Sonucu

Peki derleyici bu ilemi nasl yapyor birazda ondan bahsedelim. Carpim isimli metoda deiik
saylarda parametre gnderdiimizde, derleyici gnderilen paramtetre says kadar boyuta sahip bir
integer dizi oluturur ve du dizinin elemanlarna sras ile (0 indexinden balayacak ekilde)

www.bsenyurt.com Page 2654


gnderilen elemanlar atar. Daha sonra ayn metodu bu eleman says belli olan diziyi aktararak
arr. cl.Carpim ( 8,5) satrn dnelim; derleyici,

lk admda,

int[] dizi=new int[2] ile 2 elemanl 1 dizi yaratr.

kinci admda,

dizi[0]=8

dizi[1]=5 eklinde bu dizinin elemanlarn belirler.

Son admda ise metodu tekrar arr.

cl.Carpim(dizi);

Baz durumlarda parametre olarak geireceimiz deerler farkl veri tiplerine sahip olabilirler. Bu
durumda params anahtar szcn, object tipinde bir dizi ile kullanrz. Hemen bir rnek ile
grelim. Ayn rneimize Goster isimli deer dndrmeyen bir metod ekliyoruz. Bu metod
kendisine aktarlan deerleri console penceresine yazdryor.

public void Goster(params object[] deger)


{
for(int i=0;i<deger.Length;++i)
{
Console.WriteLine("{0}. deerimiz={1}",i,deger[i].ToString());
}
Console.ReadLine();
}
static void Main(string[] args)
{
cl.Goster(1,"Ahmet",12.3F,0.007D,true,599696969,"C");
}

Grld gibi Goster isimli metodumuza deiik tiplerde ( int,Float,Decimal,bool, String)


parametreler gnderiyoruz. te sonu;

ekil 2. params object[] kullanm.

www.bsenyurt.com Page 2655


imdi dilerseniz daha ie yarar bir rnek zerinde konuyu pekitirmeye alalm. rnein deiik
sayda tabloyu bir dataset nesnesine yklemek istiyoruz. Bunu yapcak bir metod yazalm ve
kullanalm. Programmz, bir sql sunucusu zerinde yer alan her hangibir databasee balanp
istenilen saydaki tabloyu ekranda programatik olarak oluturulan dataGrid nesnelerine ykleyecek.
Kodlar inceledike rneimizi daha iyi anlyacaksnz.

ekil 3. Form Tasarmmz

Uygulamamz bir Windows Application. Bir adet tabControl ve bir adet Button nesnesi ieriyor.
Ayrca params anahtar szcn kullanan CreateDataSet isimli metodumuzu ieren CdataSet
isimli bir classmzda var. Bu classa ait kodlar yazarak iimize balayalm.

using System;
using System.Data;
using System.Data.SqlClient;
namespace CreateDataSet
{
public class CDataSet
{
/* CreateDataSet isimli metod gnderilen baglantiAdi stringinin deerine gre bir
SqlConnection nesnesi oluturur. tabloAdi ile dataset nesnesine eklemek istediimi tablo adlarini bu
metoda gndermekteyiz. params anahtar kullanld iin istediimiz sayda tablo ad
gnderebiliriz. Elbette, geerli bir Database ve geerli tablo adlar gndermeliyiz.*/
public DataSet CreateDataSet(string baglantiAdi,params string[] tabloAdi)
{
string sqlSelect,conString;
conString="data source=localhost;initial catalog="+baglantiAdi+";integrated
security=sspi"; /* Burada SqlConnection nesnesinin kullanaca connectionString'i belirliyoruz.*/
DataSet ds=new DataSet();/* Tablolarimizi tayacak dataset nesnesini oluturuyoruz*/
SqlConnection con=new SqlConnection(conString); /*SqlConnection nesnemizi
oluturuyoruz*/
SqlDataAdapter da;/* Bir SqlDataAdapter nesnesi belirtiyoruz ama henz
oluturmuyoruz*/
/*Bu dng gnderdiimiz tabloadlarn alarak bir Select sorgusu oluturur ve

www.bsenyurt.com Page 2656


SqlDataAdapter yardmyla select sorgusu sonucu dnen tablo verilerini oluturulan bir DataTable
nesnesine ykler. Daha sonra ise bu DataTable nesnesi DataSet nesnemizin Tables kolleksiyonuna
eklenir. Bu ilem metoda gnderilen her tablo iin yaplacaktr. Bylece dng sona erdiinde,
DataSet nesnemiz gndermi olduumuz tablo adlarna sahip DataTable nesnelerini iermi
olucaktr. */
for(int i=0;i<tabloAdi.Length;++i)
{
sqlSelect="SELECT * FROM "+tabloAdi[i];
da=new SqlDataAdapter(sqlSelect,con);
DataTable dt=new DataTable(tabloAdi[i]);
da.Fill(dt);
ds.Tables.Add(dt);
}
return ds; /* Son olarak metod arld yere DataSet nesnesini gndermektedir.*/
}
public CDataSet()
{
}
}
}

imdi ise btnYukle isimli butonumuzun kodlarn yazalm.

private void btnYukle_Click(object sender, System.EventArgs e)


{
CDataSet c=new CDataSet();
DataSet ds=new DataSet();
ds=c.CreateDataSet("northwind","Products","Orders");
for(int i=0;i<ds.Tables.Count;++i)
{
/* tabControl'umuza yeni bir tab page ekliyoruz.*/
tabControl1.TabPages.Add(new System.Windows.Forms.TabPage(ds.Tables[i].TableName.T
oString()));
/* Oluturulan bu tab page'e eklenmek zere yeni bir datagrid oluturuyoruz.*/
DataGrid dg=new DataGrid();
dg.Dock=DockStyle.Fill;/*datagrid tabpage'in tamamn kaplyacak*/
dg.DataSource=ds.Tables[i]; /* DataSource zellii ile DataSet te i indexli tabloyu
balyoruz.*/
tabControl1.TabPages[i].Controls.Add(dg);/* Oluturduumuz dataGrid nesnesini TabPage
stnde gstermek iin Controls koleksiyonunun Add metodunu kullanyoruz.*/
}
}

imdi programmz altralm. te sonu;

www.bsenyurt.com Page 2657


ekil 4. Tablolarn yklenmesi.

Grld gibi iki tablomuzda yklenmitir. Burada tablo saysn arttrabilir veya azaltabiliriz.
Bunu params anahtar kelimesi mmkn klmaktadr. rnein metodomuzu bu kez 3 tablo ile
aralm;

ds=c.CreateDataSet("northwind","Products","Orders","Suppliers");

Bu durumda ekran grntmz ekil 5 teki gibi olur.

ekil 5. Bu kez 3 tablo gnderdik.

www.bsenyurt.com Page 2658


Umuyorumki params anahtar szc ile ilgili yeterince bilgi sahibi olmusunuzdur. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Bir Form ve Kontrollerinin Elle


Programlanmas ( 21.11.2003 ) - C#
Deerli Okurlarm, Merhabalar.

Bugnk makalemizde, bir Formu kodla nasl oluturacamz, bu form stne nasl kontroller
ekleyeciimizi, bu kontoller iin nasl olaylar yazacamz vb. konular ilemeye alacaz.
Bildiiniz gibi Visual Studio.NET gibi grafiksel ortamlar ile Form ve Form nesnelerini grsel olarak,
kolay ve hzl bir ekilde oluturabilmekteyiz. Bu bizim programlama iin ayracamz srede ,
ekran tasarmlarnn daha hzl yaplabilmesine olanak salamaktadr.

Ancak bazen elimizde sadece csc gibi bir C# derleyicisi ve .Net Framework vardr. te byle bir
durumda, Windows Formlarn tasarlamak iin manuel olarak kodlama yapmamz gerekmektedir.
Ayrca, iyi ve uzman bir programc olabilmek iin zellikle Visual ortamlarda Windows Form, Button,
TextBox gibi kontrollerin nasl oluturulduunu, nasl kodlandn olaylara nasl ve ne ekilde
balandn bilmek, olduka faydaldr. Bu ayn zamanda kontroln bizde olmasn da salayan bir
unsur olarak karza kmar ve kendimize olan gvenimizi dahada arttrr.

Dilerseniz konuyu anlamak iin basit ama etkili bir rnekle balayalm. Bu rneimizde basit olarak
bo bir Form oluturacaz ve bunu csc.exe (C# Compiler) ile derleyeceiz. Bir Windows Formu
aslnda System.Windows.Forms snfndan treyen bir nesnedir. Bu nedenle oluturacamz C#
snf iersinde bu bildirimi gerekletirmeliyiz. Ayrca snfmzn Form nesnesine ait elemanlarda
kullanabilmesi iin, Form snfndan tretmeliyiz(Inherting). Bunlara ek olarak Formumuzu ekranda
gsterebilmek iin Application nesnesini ve buna bal Run metodunu kullanacaz. Hemen bir text
editor aalm ve burada aadaki kodlar girelim.

using System.Windows.Forms;
public class BirForm:Form // Form snfnn elemanlarn kaltsal olarak devralyoruz.
{
public static void Main() // Programn balad nokta.
{
BirForm yeni1=new BirForm(); // BirForm snfndan bir nesne tanmlyoruz.
Application.Run(yeni1);
/* yeni1 isimli Form nesnemiz Application nesnesi tarafndan grntlenir. Bu noktadan
itibaren programn ileyii bir dngye girer. Bu dngde Application nesnesi srekli olarak
programn ileyiini sonlandracak bir olayn tetiklenip tetiklenmediini de kontrol eder. Bu arada
tabi yazlan dier olaylar ve metodlar alr. Ancak program sonlandrma ile ilgili ( rnein Close
metodu ) bir kod ile karlaldnda veya kullanc Formun varsa kapatma simgesine tkladnda
(veya ALT+F4 yaptnda) Application nesnesi artk programn ileyiini durdurur. */
}
}

www.bsenyurt.com Page 2659


Yazdmz bu dosyay cs uzants ile kaydetmeyi unutmayalm. imdi bu dosyay csc.exe ile
derleyelim. Program derlerken dikkat etmemiz gereken bir nokta var. System.Windows.Forms
un programa referans edilmesi gerekir. Bunu salamak iin derleme komutumuzun nasl yazldna
dikkat edelim. /reference: burada devreye girmektedir.

ekil 1. lk Derleme

Grld gibi, csc dosyamz derlemi ve CreateForm.exe dosyasn olturmutur. Burada


/t:winexe program Windows iletim sistemine, " Ben bir WinFormum " olarak tantmaktadr. imdi
bu dosyay komut satrndan altracak olursak aadaki ekilde grlen sonucu elde ederiz.

ekil 2. Oluturulan Form Nesnemiz.

ekil 2.'de oluturulumu olduumuz Form nesnesini grebilirsiniz. Yazm olduumuz kodlarda bu
Form nesnesine ait zellikleri deitirerek farkl Form grnmleride elde edebiliriz. Bu noktada

www.bsenyurt.com Page 2660


size Form oluturma olaylarnn kodlama tekniinin aslen nasl yaplmas gerektiini gstermek
isterim. Bu bir tarzdr yada uygulanan bir formattr ancak en uygun ekildir. Nitekim Visual
Studio.NET ortamnda bir Windows Application gelitirdiinizde, uygulama kodlarna bakcak
olursanz bahsetmi olduumuz formasyonun uygulanm olduunu greceksiniz.

using System.Windows.Forms;

public class BirForm:Form


{
public BirForm() // Constructor(Yapc) metodumuz.
{
InitializeComponent(); /* BirForm snfndan bir Form nesnesi retildiinde new
yaplandrcs bu constructora bakar ve InitializeComponent metodunu arr. */
}
private void InitializeComponent()
{
/* Burada Form'a ait zellikler ve Form zerinde yer alacak nesneler tanlanr. Tanlanan
nesneler ayn zamanda Form'a burada eklenir ve zellikleri belirlenir. */
}
public static void Main()
{
Application.Run(new BirForm());
}
}

Bu yazm teknii daha anlaml deil mi ? Kodumuzu bu ekilde deitirip altrdmzda yine ayn
sonucu elde ederiz. Ancak dilersek bu kodu u ekilde de yazabiliriz.

using System.Windows.Forms;
public class BirForm:Form
{
public BirForm()
{
NesneleriAyarla();
}
private void NesneleriAyarla()
{
}
public static void Main()
{
Application.Run(new BirForm());
}
}

Yine ayn sonucu alrz.imdi Formumuza biraz renk katalm ve stnede bir ka nesne ekleyelim.

using System;
using System.Windows.Forms;

www.bsenyurt.com Page 2661


using System.Drawing;
public class BirForm:Form
{
/* Kullanacamz nesneler tanmlanyor. Iki adet Label nesnesi, iki adet TextBox nesnesi ve
birde Button kontrol. */
private Label lbl1;
private Label lbl2;
private TextBox txtUsername;
private TextBox txtPassword;
private Button btnOK;
public BirForm()
{
NesneleriAyarla();
}
private void NesneleriAyarla()
{
this.Text="Yeni Bir Form Sayfas"; /* this anahtar kelimesi oluturulan Form nesnesini
temsil eder.*/
this.BackColor=Color.Silver; /* Formun arka plan rengini belirliyoruz. Color
Enumaration'nn kullanabilmek iin Drawing snfnn eklenmi olmas gereklidir. */
this.StartPosition=FormStartPosition.CenterScreen; /* Form oluturulduunda ekrann
ortasnda grnmesi salanyor. */
this.FormBorderStyle=FormBorderStyle.Fixed3D; /* Formun border izgileri 3 boyutlu ve
sabit olarak belirleniyor. */
/* Label nesnelerini oluturuyor ve zelliklerini ayarlyoruz. */
lbl1=new Label();
lbl2=new Label();
lbl1.Text="Username";
lbl1.Location=new Point(50,50); /* lbl1 nesnesini 50 birim saa 50 birim aaya
konumlandryoruz */
lbl1.AutoSize=true; /* Label'n boyutunun text uzunluuna gre otomatik olarak
ayarlanmasn salyoruz. */
lbl2.Text="Password";
lbl2.Location=new Point(50,100); /* Bu kez 50 birim saa, 100 birim aaya
yerletiriyoruz. */
lbl2.AutoSize=true;
/* TextBox nesnelerini oluturuyor ve zelliklerini ayarlyoruz. */
txtUsername=new TextBox();
txtPassword=new TextBox();
txtUsername.Text="";
txtUsername.Location=new Point(lbl1.PreferredWidth+50,50); /* Textbox nesnemizi lbl1 in
uzunluundan 50 birim fazla olucak ekilde saa ve 50 birim aaya konumlandryoruz. */
txtPassword.Text="";
txtPassword.Location=new Point(lbl2.PreferredWidth+50,100);
/* Button nesnemizi oluturuyor ve zelliklerini belirliyoruz */
btnOK=new Button();
btnOK.Text="TAMAM";
btnOK.Location=new Point(0,0);
/* Buraya btnOK nesnesi iin olay procedure tanm eklenecek. */

www.bsenyurt.com Page 2662


/* imdi kontrollerimizi Formumuza ekleyelim . Bunun iin Form snfna ait Controls
koleksiyonunu ve Add metodunu kullanyoruz. */
this.Controls.Add(lbl1);
this.Controls.Add(lbl2);
this.Controls.Add(txtUsername);
this.Controls.Add(txtPassword);
this.Controls.Add(btnOK);
this.Width=lbl1.PreferredWidth+txtUsername.Width+200; /* Son olarak formun geniliini
ve yksekliini ayarlyoruz. */
this.Height=lbl1.PreferredWidth+lbl2.PreferredWidth+200;
}
/* Buraya btnOK iin Click olay procedure kodlar eklenecek. */
public static void Main()
{
Application.Run(new BirForm());
}
}

Evet bu kodu derleyip altrdmzda aadaki Form grntsn elde etmi oluruz.

ekil 3. Form tasarn gelitiriyoruz.

imdi iin en nemli kslarndan birine geldi sra. Oda olay gdml kodlar yazmak. Yani kullanc
etkilerine tepki vericek kodlar yazmak. Ksaca Event-Handler. Kullanc bir eylem
gerekletirdiinde programn hangi tepkileri vereceini belirtmek durumundayz. Bunun iin u
syntax kullanrz.

protected void metodunAdi(object sender,System.EventArgs e)

Burada metodumuzun hangi nesne iin altrlacan sender anahtar kelimesi belirtir. Metod
protected tanmlanr. Yani bulunduu snf ve bulunduu snftan tretilen snflarda kullanlabilir.

www.bsenyurt.com Page 2663


Geri dn deeri yoktur. Bu genel formasyonla tanmlanan bir olay proceduren nesne ile
ilikilendirmek iin System.EventHandler delegesi kullanlr.

nesneAdi.OlayinTanlayiciBilgisi+= new System.EventHandler(this.metodunAdi)

Yukardaki rneimizde klasik rnek olarak, Button nesnemize tklandnda altrlmas iin bir
Click olay procedure ekleyelim.

imdi /* Buraya btnOK nesnesi iin olay procedure tanm eklenecek */ yazan yere , aadaki kod
satrn ekliyoruz.

btnOK.Click+=new System.EventHandler(this.btnOK_Tiklandi);

Bu satr ile btnOK nesnesine tklandnda btnOK_Tiklandi isimli proceduren altrlacan


belirtiyoruz. /* Buraya btnOK iin Click olay procedure kodlar eklenecek */ yazan yere ise olay
proceduremzn ve kodlarn ekliyoruz.

protected void btnOK_Tiklandi(object sender,System.EventArgs e)


{
MessageBox.Show(txtUsername.Text+" "+txtPassword.Text);
}

imdi program tekrar derleyip altrdmzda aadaki sonucu elde ederiz.

ekil 4. Event-Handler sonucu.

Evet geldik bir makalemizin daha sonuna. Bir sonraki makalemizde grmek dileiyle hepinize
mutlu ve huzurlu gnler dilerim.

Burak Selim ENYURT

www.bsenyurt.com Page 2664


selim@bsenyurt.com

Distributed Transactions ( 19.11.2003 ) -


Ado.Net
Deerli Okurlarm, Merhabalar.

Bildiiniz gibi bir nceki makalemizde Transaction kavramndan bahsetmi, ancak birden fazla
veritaban iin geerli olucak Transaction ilemlerinin Datk Transactionlar olarak
adlandrldndan szetmitik. Bu makalemizde Datk Transactionlar inceleyecek ve her zaman
olduu gibi konuyu aklayc basit bir rnek gelitireceiz.

uygulamalarnda, Online Transaction Processing(OLTP) dediimiz olay ok sk


kullanlmaktadr. Buna verilecek en gzel rnek bankalarn ATM uygulamalardr. Veriler e zamanl
olarak ayn anda bir btn halinde ilenmekte ve gncellenmektedir. Bu tarz projelerin
uygulanmasnda OLTP teknii yaygn bir biimde kullanlmaktadr. Bu tekniin uygulanabilmesi
Datk Transactionlarn kullanlmasn gerektirir. .NET ile Datk Transactionlar yazmak
iin Component Services kullanmamz gerekmektedir. zellikle,ok katl mimari dediimiz i
uygulamalarnda Datk Transactionlar ok sk kullanrz. Burada Datk Transactionlar baka
componentler tarafndan stlenilir ve Sunu Katman ile Veritabanlar arasndaki ilemlerin
gerekletirilmesinde rol oynarlar. Bu componentlerin bulunduu katman Katman olarakda
adlandrlmaktadr. Nitekim Componentler aslnda Transaction balatp gerekli metodlar altrarak
veriler zerindeki btnsel ilevleri yerine getirir ve transaction sonlandrrlar. Yani Sunum
Katman nda yer alan uygulamalar sadece gerekli verileri parametre olarak i katmannda yer alan
componentlere gnderirler. Dolaysyla zerlerinde ilgili veritaban verileri iin herhangibir fonksiyon
veya metodun altrlmasna gerek yoktur. Btn sorumluluk Component Services da yer alan
COM+ componentindedir. Burada veirtabanlarna balanlr , gerekli dzenlemeler bir Transaction
iersinde gerekletirilir ve sorunsuz bir transaction tm i paracklar ile teyid edilerek gerekli
dzenlemeler veritabanlarna yanstlr.

En basit haliyle 3 katl mimaride, Sunum Katman ile Veritabanlar arasndaki transaction ilemlerini
COM+ Componentleri ile gerekletirebiliriz. Bu componentler Windows 2000 den itibaren
Component Service olarak adlandrlan bir servis altnda yer almaktadrlar. Elbetteki bu componenti
biz gelitireceiz. Componentin grevi , transaction ilemlerinin otomatik yada manuel olarak
gerekletirilmesini salamaktr. Bir dll dosyas haline getirilen bu componentleri istenilen Sunum
Katman uygulamasna ekleyerek kullanabiliriz. Yazacamz component iinde Transaction
ilemlerini kullanabilmek amacyla .NET ierisinde yer alan System.EnterpriseServices snfnn
metodlarn kullanrz. Oluturulan componenti rneklerimizde de greceiniz gibi bir Strong
Name haline getirmemizde gerekmektedir. rneimizi yazarken bunlar daha iyi anlyacaksnz.
katl mimaride, Datk Transaction uygulamalarnn aadaki ekil ile zihnimizde daha berrak
canlanaca kansndaym.

www.bsenyurt.com Page 2665


ekil 1. 3 Katl Mimari iin COM+ Kullanm

zetlemek gerekirse, Datk Transaction larn kullanld uygulamalarda Component Services


kullanlmas gerekmektedir. Bir Datk Transaction Componenti yazdmzda, transaction
ilemlerini otomotik olarak Component Servicea yaptrabiliriz. Bunun yannda ContexrUtil ad
verilen nesneyi ve bu nesneye ait SetComplete(), SetAbort()gibi metodlar kullanarak
Transaction ilmelerini elle de yaplandrabiliriz. Bu makalemizde otomatik olan setim. Bir sonraki
makalede ilemleri manuel olarak yapcaz.Dilerseniz rneimize geelim . Bu uygulamzda 2
veritaban zerindeki 2 farkl tablo iin, bir Transaction ierisinde basit veri giri ilemleri
gerekletireceiz. ncelikle tablolarmn yapsn ve databaselerimizi belirtelim. Firends isimli bir
Veritaban nda kullanacamz basit bir tablo var. Satislar isimli bu tabloda Ad,Soyad ve SatisTutari
alanlar yer almakta.

www.bsenyurt.com Page 2666


ekil 2. Satislar tablosunun yaps.

kinci Veritabanmz ise IstanbulMerkez. Tablolamuzun ad Primler. Bu tabloda ise yine Ad,Soyad ve
Prim bilgisi yer alyor.

www.bsenyurt.com Page 2667


ekil 3. Primler tablosunun yaps.

Uygulamamzda Satislar isimli tabloya bilgi girildikten sonra SatisTutarinin %10 u zerinden prim
hesaplancak ve ayn anda Primler tablosuna bu bilgiler eklenecek. Tabiki bu iki basit veritaban
ilemi bir Transaction iinde gerekletirilecek. Uygulamamz tasarlamaya balayalm. nce yeni
bir C# ile yeni bir Windows Application oluturalm. Bu uygulamann ierdii Form Sunum
Katman nda yer alan veri giri ekranmz olucaktr. Formu aadakine benzer veya ayn ekilde
tasarlayalm.

ekil 4. Formun yaps.

www.bsenyurt.com Page 2668


Kullanc bu ekrandan Ad,Soyad ve Sat Tutar bilgilerini girecek. Girilen bu bilgiler, yazacamz
COM+ Componentindeki metoda parametre olarak gidicek ve bu metod iinde ilenerek
veritabanlarndaki tablolarda gerekli dzenlemeler yaplcak. Eer tm ilmeler baarl olursa ve
metod tam olarak alrsa geriyede ilemlerin dolaysyla Transactionn baarl olduuna dair bir
string bilgi gnderecek. Evet imdi uygulamann en nemli ksmna sra geldi . Componentin
tasarlanmasna. lk nce, Project mensndenAdd Component komutunu vererek component
imizi uygulamamza ekliyoruz.

ekil 5. Component Eklemek.

Ben componentimize SatisPrimEkle adini verdim. Bu durumda Solutionmza SatisPrimEkle.cs isimli


dosya eklenir ve Visual Studio.NET IDEde aadaki gibi grnr.

ekil 6. Componentin ilk eklendiinde IDE de durum.

www.bsenyurt.com Page 2669


imdi ise bu component iersinde yer alcak datk transaction ilemleri iin gerekli olan
referansmzn projemize eklememize gerekiyor. Daha ncede System.EnterpriseServices olarak
bahsettiimiz bu snf eklemek iin yine, Project mensnden, Add Reference komutunu
veriyoruz. Burada ise .NET sekmesinden System.EnterpriseServices snfn ekliyoruz.

ekil 7. System.EnterpriseServices Snfnn eklenmesi.

imdi Componentimizin kodlarn yazmaya balayabiliriz. To Switch To Code Window linkine


tklayarak component imizin kodlarna gei yapyoruz. lk haliye kodlar aadaki gibidir.

using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
namespace distrans
{
/// <summary>
/// Summary description for SatisPrimEkle.
/// </summary>
public class SatisPrimEkle : System.ComponentModel.Component
{
/// <summary>
/// Required designer variable.
/// </summary>

www.bsenyurt.com Page 2670


private System.ComponentModel.Container components = null;
public SatisPrimEkle(System.ComponentModel.IContainer container)
{
///
/// Required for Windows.Forms Class Composition Designer support
///
container.Add(this);
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
public SatisPrimEkle()
{
///
/// Required for Windows.Forms Class Composition Designer support
///
InitializeComponent();
//
// TODO: Add any constructor code after InitializeComponent call
//
}
/// <summary>
/// Clean up any resources being used.
/// </summary>
protected override void Dispose( bool disposing )
{
if( disposing )
{
if(components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
components = new System.ComponentModel.Container();
}
#endregion
}
}

www.bsenyurt.com Page 2671


Biz buradaki kodlar aadaki ekliyle dzenleyecek ve yukarda yazl ou kodu kartacaz.
Haydi balayalm. ncelikle using ksmna,

using System.Data.SqlClient;
using System.EnterpriseServices;

snflarn eklememiz gerekiyor. nk Transaction ilemleri iin EnterpriseServices snfn ve


veritaban ilemlerimiz iinde SqlClient snfnda yer alan nesnelerimizi kullanacaz. kinci kkl
deiimiz ise SatisPrimEkle isimli snfmzn ServicedComponent snfndan tretilmi olmas. Bu
deiiklii ve dier fazlalklar karttmz takdirde, kodlarmzn son hali aadaki gibi
olucaktr.

using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Data.SqlClient;
using System.EnterpriseServices;
namespace distrans
{
public class SatisPrimEkle : ServicedComponent
{
}
}

imdi metodumuzu ekliyelim ve gerekli kodlamalar yazalm.

using System;
using System.ComponentModel;
using System.Collections;
using System.Diagnostics;
using System.Data.SqlClient;
using System.EnterpriseServices;
namespace distrans
{
/* [Transaction(TransactionOption.Required)] satr ile belirtilen udur. Component imiz var
olan Transaction ierisinde altrlacaktr. Ancak eer oluturulmu yani balatlm bir transaction
yoksa, bu component imiz iin yeni bir tane oluturulmas salanacaktr. Burada,
TransactionOption'n sahip olabilecei dier deerler Disabled, NotSupported, RequiresNew ve
Supported dr.
Disabled durumunda, transaction zellii grmezden gelinir. Default olarak bu deer kabul
edilir. Bu durumda Transaction balatlmas gibi ilemler manuel olarak yaplr.
Not Supported durumunda ise Component imiz bir transaction var olsa bile bu transaction'n
dnda alcaktr.
RequiresNew durumunda, Component imiz iin bir transaction var olsada olmasada mutlaka
yeni bir transaction balatlacaktr.
Supported durumu ise , var olan bir transaction olmas durumunda, Component imizin bu
transaction'a katlmasn salar.

www.bsenyurt.com Page 2672


Biz uygulamamzda otomatik transaction tekniini kullandmz iin Required seeneini
kullanyoruz.
*/
[Transaction(TransactionOption.Required)]public class SatisPrimEkle : ServicedComponent
{
/* AutoComplete() satr izleyen metodun bir transaction ierisinde yer alacan ve transaction
ilemlerinin balatlmas ve bitirilmesini Component Services 'n stleneceini belirtir. Dolaysyla
Component imizin bu metodunu altrdmzda bir transaction balatlr ve ContexUtil nesnesi ile
manuel olarak yapacamz SetComplete (Commit) ve SetAbort(Rollback) hareketlerini COM+
Servisi kendisi yapar. */
[AutoComplete()]public string VeriGonder(string ad,string soyad,double satisTutari)
{
SqlConnection conFriends = new SqlConnection("initial catalog=Friends;data
source=127.0.0.1;integrated security=sspi;packet size=4096");
SqlConnection conIstanbulMerkez = new SqlConnection("initial
catalog=IstanbulMerkez;data source=127.0.0.1;integrated security=sspi;packet size=4096");
/* Yukardaki SqlConnection nesneleri tanmlanrken data source zelliklerine sql
sunucusunun bulunduu ip adresi girildi. Bu farkl ip'lere sahip sunucular sz konusu olduunda
farkl veritabanlarnda kullanabiliriz anlamna gelmektedir. Uygulamamz ayn sunucu zerinde
gerekletirmek zorunda olduum iin ayn ip adreslerini verdim.*/
/* Adaki satrlarda veri girii iin gerekli sql cmlelerini hazrladk ve bunlar
SqlCommand nesneleri ile ilikilendirip altrdk. */
string sql1="INSERT INTO Satislar (Ad,Soyad,SatisTutari) VALUES
('"+ad+"','"+soyad+"',"+satisTutari+")";
double prim=satisTutari*0.10;
string sql2="INSERT INTO Primler (Ad,Soyad,Prim) VALUES
('"+ad+"','"+soyad+"',"+prim+")";
SqlCommand cmdSatisGir=new SqlCommand(sql1,conFriends);
SqlCommand cmdPrimGir=new SqlCommand(sql2,conIstanbulMerkez);
conFriends.Open();
conIstanbulMerkez.Open();
cmdSatisGir.ExecuteNonQuery();
cmdPrimGir.ExecuteNonQuery();
return "ISLEM TAMAM"; /* Metod baarl bir ekilde altnda, COM+ sevisi
transaction' otomatik olarak sonlandrr ve metodumuz geriye ISLEM TAMAM stringini dndrr.
*/
}
}
}

Component imizi oluturduktan sonar bunu Sunum Katmanndaki uygulamalarda kullanabilmek ve


COM+ Servisinede eklenmesini salamak iin bir Strong Name Key dosyas oluturmamz
gerekiyor. Bu IDE dndan ve sn.exe isimli dosya ile yaplan bir ilemdir. Bunun iin D:\Program
Files\Microsoft.NET\FrameworkSDK\Bin\sn.exe dosyasn kullanacaz. te komutun altrl;

www.bsenyurt.com Page 2673


ekil 8. sn.exe ile snk(strong name key) dosyasnn oluturulmas.

Grld gibi snk uzantl dosyamz oluturuldu. imdi Formumuzda bu Component imize ait
metodu kullanabilmek iin oluturulan bu snk uzantl dosyay Solutionmza Add Exciting
Item seenei ile eklememiz gerekiyor. Aadaki 3 ekilde bu admlar grebilirsiniz.

www.bsenyurt.com Page 2674


ekil 9 . SatisPrimEkle.snk dosyasnn projemize eklenmesi.

Formumuzda Component imize ait metodu kullanabilmek iin yapmamz gereken bir adm daha
var. Oda uygulamann AssemblyInfo.cs dosyasna aadaki kod satrn eklemek.

[assembly: AssemblyKeyFile("..\\..\\SatisPrimEkle.snk")]

imdi formumuzdaki kodlar inceleyelim. ncelikle SatisPrimEkle tipinde bir nesne tanmlyoruz.
imdi bu nesnesin VeriGonder isimli metoduna eritiimizde aadaki ekilde grdnz gibi
IntelliSense zellii bize kullanabileceimiz parametreleride gsteriyor.

www.bsenyurt.com Page 2675


ekil 10. Metodun kullanm.

imdi tm kodumuzu tamamlayalm ve rneimizi altralm.

private void btnGonder_Click(object sender, System.EventArgs e)


{
SatisPrimEkle comp=new SatisPrimEkle();
double st=System.Convert.ToDouble(txtSatisTutari.Text);
try
{
MessageBox.Show(comp.VeriGonder(txtAd.Text,txtSoyad.Text,st));
}
catch(Exception hata)
{
MessageBox.Show(hata.Source + ":" + hata.Message);
}
}

imdi rneimizi altralm.

www.bsenyurt.com Page 2676


ekil 11. ISLEM TAMAM

Grld gibi , metodumuz baarl bir ekilde altrld. Hemen tablolarmz kontrol edelim.

ekil 12. IstanbulMerkez veritabanndaki Primler Tablosu.

ekil 13. Friends veritabanndaki Satislar tablosu.

imdi Component Servicesa bakcak olursak oluturmu olduumuz distrans isimli Component
Application ve ierdii SatisPrimEkle isimli Componenti, burada da grebiliriz.

ekil 14. Componet Services.

www.bsenyurt.com Page 2677


Bir sonraki makalemizde ayn rnei Manuel yntemelerle ve dolaysyla ContextUtil snfnn
metodlar ile gerekletireceiz. Hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Transaction Kavram ( 17.11.2003 ) - Ado.Net


Deerli Okurlarm, Merhabalar.

Bu makalemizde sizlere veritaban programclnda ve zellikle de ok katl mimaride ok nemli


bir yere sahip olan Transactionlar hakknda bilgi vermeye alacam. Her zaman olduu gibi
konuyu iyi anlayabilmek iin bir de rnek uygulamamz olucak. ncelikle Transaction nedir , ne ie
yarar bunlardan bahsedelim. ou zaman programlarmzda ard arkasna veritaban ilemleri
uygulatrz. rnein, bir veritabanndaki bir tablodan kayt silerken, ayn olayn sonucunda baka
bir ilikli tabloya silinen bu verileri ekleyebilir veya gncelleyebiliriz. Hatta bu ilemin arkasndan
da silinen kaytlarn bulunduu tablo ile ilikili baka tablolaradan da ayn verileri sildiimiz ilemleri
balatabiliriz. Dikkat edicek olursanz burada birbirleriyle ilintili ve ardk ilemlerden sz
ediyoruz.

Farzedelim ki , zerinde altmz bu tablolara farkl veritaban sunucularnda bulunsun. rnein,


birisi Adanada dieri Arnavutlukta orta olduumuz irketin sunucularnda. Hatta bir dieride
Kazakistandaki ortamzn bir ka sunucusunda bulunuyor olsun. E hadi bir tanede bizim
sunucumuzda farkl bir veya bir ka tablo olsun. imdi dnn ki, biz Kazakistan a sattmz
mallarn bilgisini , Arnavutluk taki ortamzn sunucularnada bildiriyoruz. Stoumuzda bulunan
mallarda 1000 adet televizyonu Kazakistana gndermek amacyla ihra birimimize rapor ediyoruz.
hra birimi ilgili ilemleri yaptktan sonra, Kazakistandaki sunuculardan gelen deme bilgisini
alyor. Sonra ise stok tan 1000 televizyonu dyor , muhasebe kaytlarn gncelliyor, Kazakistan
daki sunucularda stok artn ve hesap eksililerini bildiriyor. Daha sonra ise , Arnavutluk taki
sunuculara stok art ve stok azallarn ve muhasebe hareketlerini belirtiyor. Senaryo bu ya. ok
hzl bir teknolojik alt yapya sahip olduumuzu ve bankalardan irkete olan para aklarnn annda
grlp , tablolara yanstlabildiini ve bu sayede de stoklardaki hareketlerin ve irket muhasebe
kaytlarndaki hareketlerin hemen gerekleebileceini yani mmkn olduunu dnelim. (Deerli
okuyucalarm biliyorum ki uzun bir cmle oldu ama umarm gelmek istediim noktay anlamaya
balamsnzdr)

Bahsettiimiz tm bu ilemler birer i paracdr ve aslnda hepsi toplu olarak tek bir amaca
hizmet etmektedir. Tm sunucular stok hareketlerinden ve gerekli muhasebe deiikliklerinden e
zamanl olarak (aa yukar yani ) haberdar etmek ve veritaban sunucularn gncellemek.
Dolaysyla tm bu i paracklarn, tek bir btn ii gerekletirmeye alan unsurlar olduunu
syleyebiliriz. te burada tm bu i paracklar iin sylenebilecek baz hususlar vardr.
ncelikle,

paracklarnn birinde meydana gelen aksaklk , dier ilerin ve zellikle takib eden i
paracklarnn doru ekilde ilemesine neden olabilir. Dolaysyla tm bu i paracklar baarl

www.bsenyurt.com Page 2678


olduu takdirde btn i baarl olmu saylabilir.

Dier yandan i paracklarnn ileyii srasnda veriler zerindeki deiikliklerin de tutarl olmas
birbirlerini tamamlayc nitelik tamas gerekir. Sz gelimi stoklarmzda 2000 televiyon varken
1000 televizyon ihra ettiimizde stoumuza mal eklenmediini dnecek olursak 1000 televizyon
kalmas gerekir. 1001 televizyon veya 999 televizyon deil. te bu verilerin tutarlln gerektirir.

te bu nedenlerde tr Transaction kavram ortaya karmtr. Bu kavrama gre aslnda


bahsedilen tm i paraklar kusursuz olarak baarl olduklarnda ilem tamam denebilir.
te bizde veritaban uygulamalarmz gelitirirken, bu tip i paracklarn bir Transaction blouna
alrz. imdi ise karmza iki yeni kavram kacaktr. Commit ve Rollback.Eer Transaction blouna
dahil edilen i paracklarnn tm baarl olmu ise Transaction Commit edilir ve i
paracklarndaki tm veri deiimleri gerekten veritabanlarna yanstlr. Ama i paracklarndan
her hangibirinde tek bir hata oluup i paracnn ileyii bozulur ise bu durumda tm Transaction
Rollback edilir ve bu durumda, o ana kadar ileyen tm i paracklarndaki ilemler geri alnarak ,
veritabanlar Transaction balamadan nceki haline dndrlr. Bu bir anlamda gvenlik ve verileri
koruma adna oluturulmu bir koruma mekanizmasdr.

Peki ya i paracklarnn dzgn ilemiyiine sebep olarak neler gsterebiliriz. Tabiki evresel
faktrler en byk etkendir. Sunucular birbirine balayan hatlar zerinde olabilecek fiziki bir hasar
ilemleri yarda brakabilir ve Kazakistan daki sunuculardaki 1000 televizyonluk art buraya hi
yansmayabilir. Kazakistandaki yetkili Trkiyedeki merkezi arayp stoumda hala 1000
televizyon grnmyor. diyebilir. Merkezdeki yetkili ise. Bizim stoklardan 1000 tv dn
km. Bilgisayar kaytlar yalan m syliyecek kardeim. diyebilir. Neyseki Transactionlar
sayesinde olay yle geliir.

Kazakistan Bro : Stokta bir hareket yok bir sorunmu var acaba?

Merkez: Evet . Karadenizden geen boru hattnda frtna nedeni ile kopma olmu. Mallar bizim
stokta halen daha kmadlar. Gemide bekletiyoruz.

ok abart bir senaryo oldu aslnda. Nitekim o televizyonlar bir ekilde yerine ular Transactionlara
gerek kalmadan. Ama olay umarm size betimleyebilmiimdir. imdi gelin olayn teknik ksmn bir
de grafik zerinde grelim.

www.bsenyurt.com Page 2679


ekil 1. Transaction Kavram

ekilde grld gibi rnek olarak 3 adet ilem parac ieren bir Transaction bloumuz var. Bu
ilemler birbirine bal olarak tasvir edilmitir. Eer herhangibiri baarsz olursa veriler zerinde o
ana kadar olan deiiklikler geri alnr ve sistem Transaction balamadan nceki haline
konumlandrlr. ekilimize bunlar R-point yani Rollback Noktasna git olarak tasvir edilmitir. Ancak
tm ilemler baarl olursa Transaction iinde gerekleen tm veri deiiklikleri onaylanm
demektir.

Transactionlar ile ilgili olarak nemli bir konu ise yukardaki rneklerde anlattmz gibi birden fazla
veritaban olmas durumunda bu Transaction ilemlerinin nasl koordine edilceedir. Burada Datk
Transaction dediimiz Distributed Transaction kavram ortaya kar. Bu konuyu ilerliyen
makalelerimizde ilemey alacam. imdilik sadece tek bir veritaban zerinde yazabileceimiz
Transaction lardan bahsetmek istiyorum..NET ierisinde SqlClient snfnda yer alan nesneleri
Transaction nesneleri kullanlarak bu ilemi gerekletirebiliriz. Ben SqlTransaction nesnesini ele
alacam. Bu nesneyi oluturmak iin herhangibir yapc metod yoktur. SqlDataReader snfnda
olduu gibi bu snfa ait nesneler birer deikenmi gibi tanmlanr. Nesne atamalar SqlConnection
nesnesi ile gerekletirilir ve bu ayn zamanda Transactionn hangi SqlConnection balants iin
balatlacan belirlemeye yarar.

SqlTransaction tran;

www.bsenyurt.com Page 2680


tran = conNorthwind.BeginTransaction();

Yukardaki ifadeye dikkat edersek, bir SqlTransaction nesnesi tanmlanm ve daha sonra
conNorthwind isimli SqlConnection nesnesi iin balatlmtr. te Transaction blounun balad
nokta burasdr. imdi ise , hangi Sql komutlarn dolaysyla hangi i paracklarn bu transaction
nesnesine(yani blouna) dahil ediceimizi belirlemeliyiz. Bu ilem genelde altrlcak olan
SqlCommand nesnelerinin Transaction zelliklerine Transaction nesnesinin atanmas ile
gerekletirilir. Dilerseniz gereki bir rnek zerinde alalm ve Transaction kavramn daha iyi
anlayalm.

Merkezi stanbulda olan uluslararas devre mlk satan bir irket, lke ofislerinde satn yapt
devre mlkler iin, sat yapan personele ait banka hesaplarna EFT ilemi ieren bir uygulamaya
sahip olsun. Bahsi geen uygulamann almasna bir rnek verelim; Brezilyadaki ofisimizde bir
sat personelimizin, devre mlk sattn ve sat tutar zerinden %1 prim aldn farz edelim.
Yaplan sat sonucunda stanbuldaki suncuda yer alan veritabanna ait tablolarda peisra ilemler
yapldn varsayalm.

Personelin bilgilerinin olduu tabloda alaca toplam prim tutar sat tutarnn %1i orannda artsn ,
dencek prime ait bilgiler ayr bir tabloya ilensin ve ayn zamanda, irkete ait finans kurumundaki
toplam para hesabndan bu prim tutar kadar TL eksilsin. te bu ilemi gz nnde
bulundurduumuzda, tek bir ileme ait i paracklar olduunu anlayabiliriz. Dolaysyla burada bir
Transactiondan rahatlkla sz edebiliriz.Dilerseniz uygulamamza geelim. ncelikle tablolarmza
bir gz atalm. IstanbulMerkez isimli veritabanmzda u tablolar yer alyor.

ekil 2. IstanbulMerkez veritabanndaki tablolar.

Buradaki tablolardan ve grevlerinden ksaca bahsedelim. Personel tablosunda personele ait bilgiler
yer alyor. Bu tablo Prim isimli tablo ile bire-ok ilikiye sahip. AFinans ise, bize ait finas
kurumunun kasasndaki gncel TLs miktarn tutan bir tablo. Personel sat yaptnda, sat tutar
zerinde prim Personel tablosundaki PrimToplami alannn deerini %1 arttryor sonra Prim
tablosuna bunu iliyor ve son olarakta AFinans tablosundaki Tutar alanndan bahsi geen %1 lik
prim miktarn azaltyor.

www.bsenyurt.com Page 2681


Peki buradaki ilem iin neden Transaction kullanyoruz? Farz edelim ki, Personel tablosunda
PrimToplami alannn deeri arttktan sonra, bir sorun nedeni ile veritabanna olan balant kesilmi
olsun ve dier ilemler gereklememi olsun. Bu durumda personelin artan prim tutarn
karlayacak kadar TLs finans kurumunun ilgili hesabndan dlmemi olaca iin , finansal
dengeler bozulmu olucaktr. in iine para girdii zaman Transactionlar daha bir nem
kazanmaktadr. Uygulamamz basit olmas asndan Console uygulamas olarak gelitireceim.
Haydi balayalm. lemlerin kolay olmas asndan balang iin Personel tablosuna bir kayt
girdim. u an iin grld gibi PrimToplami alannn deeri 0 TLsdr. Ayraca AFinans tablosunda
bir balang tutarmzn olmas gerelkiyor.

ekil 3. Personel Tablosu

ekil 4. Afinans tablosu

Uygulamamzda , Personel tablosunda yer alan PrimToplami alannn deerini prim tutar kadar
arttrmak iin aadaki Stored Procedure kullanacaz.

CREATE PROCEDURE [Prim Toplami Arttir]


@prim float,
@pid int
AS
UPDATE Personel SET PrimToplami = PrimToplami+@prim
WHERE PersonelID=@pid
GO

Prim tablosuna eklenecek veriler iin ise INSERT sql cmlecii ieren bir Stored Proceduremz
var.

CREATE PROCEDURE [Prim Bilgisi Gir]


@pid int,
@st float,
@p float,
@str datetime
AS
INSERT INTO Prim (PersonelID,SatisTutari,Prim,SatisTarihi)
VALUES (@pid,@st,@p,@str)
GO

Son olarak AFinans isimli tablomuzdan prim miktar kadar TLsn decek olan Stored
Proceduremz yazalm.

www.bsenyurt.com Page 2682


CREATE PROCEDURE [Prim Dus]
@prim float
AS
UPDATE AFinans SET Tutar=Tutar-@prim
GO

Artk program kodlarmza geebiliriz. Kodlar C# ile yazmay tercih ettim.

using System;
using System.Data;
using System.Data.SqlClient;
namespace TransactionSample1
{
class Trans
{
[STAThread]
static void Main(string[] args)
{
/* IstanbulMerkez veritabanna bir balant nesnesi referans ediyoruz. */
SqlConnection conIstanbulMerkez=new SqlConnection("initial
catalog=IstanbulMerkez;data source=localhost;integrated security=sspi");
/* Transaction nesnemizi tanmlyor ve bu Transaction'n conIstanbulMerkez isimli
SqlConnection nesnesinin belirttii balantya ait komutlar iin altrlacan belirtiyoruz. */
SqlTransaction tr;
conIstanbulMerkez.Open();
tr=conIstanbulMerkez.BeginTransaction();
double satisTutari=150000000000;
double primTutari=satisTutari*0.01;
/* imdi, Personel tablosundaki PrimToplami alann deerini primTutari deikeninin
deerin kadar arttracak Stored Procedure' altracak SqlCommand nesnesini tanmlyor ve
gerekli parametreleri ekleyerek bu parametrelere deerlerini veriyoruz. Son olaraktan da
SqlCommand'in Transaction zelliine oluturduumuz tr isimli SqlTransaction nesnesini atyoruz.
Bu u anlama geliyor. "Artk bu SqlCommand tr isimli Transaction iinde alcak olan bir i
paracadr." */
SqlCommand cmdPrimToplamiArttir=new SqlCommand("Prim Toplami
Arttir",conIstanbulMerkez);
cmdPrimToplamiArttir.CommandType=CommandType.StoredProcedure;
cmdPrimToplamiArttir.Parameters.Add("@prim",SqlDbType.Float);
cmdPrimToplamiArttir.Parameters.Add("@pid",SqlDbType.Int);
cmdPrimToplamiArttir.Parameters["@prim"].Value=primTutari;
cmdPrimToplamiArttir.Parameters["@pid"].Value=1;
cmdPrimToplamiArttir.Transaction=tr;
/* Aadaki satrlarda ise "Prim Bilgisi Gir" isimli Stored Procedure' altracak olan
SqlCommand nesnesi oluturulup gerekli paramtere ayarlamalar yaplyor ve yine Transaction
nesnesi belirlenerek bu komut nesneside Transaction blou ierisine bir i parac olarak
bildiriliyor.*/
SqlCommand cmdPrimBilgisiGir=new SqlCommand("Prim Bilgisi
Gir",conIstanbulMerkez);
cmdPrimBilgisiGir.CommandType=CommandType.StoredProcedure;

www.bsenyurt.com Page 2683


cmdPrimBilgisiGir.Parameters.Add("@pid",SqlDbType.Int);
cmdPrimBilgisiGir.Parameters.Add("@st",SqlDbType.Float);
cmdPrimBilgisiGir.Parameters.Add("@p",SqlDbType.Float);
cmdPrimBilgisiGir.Parameters.Add("@str",SqlDbType.DateTime);
cmdPrimBilgisiGir.Parameters["@pid"].Value=1;
cmdPrimBilgisiGir.Parameters["@st"].Value=satisTutari;
cmdPrimBilgisiGir.Parameters["@p"].Value=primTutari;
cmdPrimBilgisiGir.Parameters["@str"].Value=System.DateTime.Now;
cmdPrimBilgisiGir.Transaction=tr;
/* Son olarak AFinans isimli tablodaki Tutar alanndan prim tutar kadar TL'sn dcek
olan Stored Procedure iin bir SqlCommand nesnesi tanmlanyor, prim tutarn tayacak olan
parametre eklenip deeri veriliyor. Tabiki en nemlisi, bu komut nesnesi iinde SqlTransaction
nesnemiz belirleniyor.*/
SqlCommand cmdTutarDus=new SqlCommand("Prim Dus",conIstanbulMerkez);
cmdTutarDus.CommandType=CommandType.StoredProcedure;
cmdTutarDus.Parameters.Add("@prim",SqlDbType.Float);
cmdTutarDus.Parameters["@prim"].Value=primTutari;
cmdTutarDus.Transaction=tr;
/* Evet sra geldi programn can alc kodlarna. Aada bir Try-Catch-Finally blou var.
Bu bloklarda dikkat edicek olursanz tm SqlCommand nesnelerinin altrlmas try blounda
yaplamktadr. Eer tm bu komutlar sorunsuz bir ekilde alrsa bu durumda, tr.Commit() ile
transaction onaylanr vee deiikliklerin veritaban zerindeki tablolara yazlmas onaylanm olur*/
try
{
int etkilenen=cmdPrimToplamiArttir.ExecuteNonQuery();
Console.WriteLine("Personel tablosunda {0} kayt gncellendi",etkilenen);
int eklenen=cmdPrimBilgisiGir.ExecuteNonQuery();
Console.WriteLine("Prim tablosunda {0} kayt eklendi",eklenen);
int hesaptaKalan= cmdTutarDus.ExecuteNonQuery();
Console.WriteLine("AFinans tablosunda {0} kayt gncellendi",hesaptaKalan);
tr.Commit();
}
catch(Exception hata) /* Ancak bir hata olmas durumdan ise, kullanc hatann bilgisi ile
uyarlr ve tr.Rollback() ile hatann olutuu ana kadar olan tm ilemler iptal edilir.*/
{
Console.WriteLine(hata.Message+" Nedeni ile ilmeler iptal edildi");
tr.Rollback();
}
finally /* hata olusada olumasada ak bir balant var ise bunun kapatlmasn garanti
altna almak iin finally blounda balant nesnemizi Close metodu ile kapatrz.*/
{
conIstanbulMerkez.Close();
}
}
}
}

www.bsenyurt.com Page 2684


ekil 5. Programn almas sonucu.

Bu durumda veritabanndaki tabloalara bakcak olursak; Personel tablosuna PrimToplami alannn


deeri artm,

ekil 6. Personel tablosunda PrimToplami alannn deeri arttrld.

Prim tablosuna ilgili personele ait bilgiler eklenmi,

ekil 7. Prim tablosuna denecek prime ait bilgiler girildi.

Son olarakta, AFinans isimli tablondaki Tutar alannn deeri gncellenmitir.

ekil 8. AFinans tablosundaki Tutar alannn deeri prim tutar kadar azald.

imdi dilerseniz bir hata tetikleyelim ve ne olacana bakalm. Bir hata retmek aslnda isteyince o
kadar kolay deil malesef. Ben Stored Procedure lerden birinin ismini yanl yazcam. Bakalm ne
olucak. u anda tablodaki veriler yukardaki ekil 6,7 ve ekil 8da olduu gibi.

SqlCommand cmdPrimBilgisiGir=new SqlCommand("Prim Bisi Gir",conIstanbulMerkez);

Burada Stored Proceduren ismi Prim Bilgisi Gir iken ben Prim Bisi Gir yaptm. imdi
altracak olursak; aadaki ekran ile karlarz. lemler iptal edilir.

www.bsenyurt.com Page 2685


10. lemler iptal edildi.

Eer transaction kullanmasaydk ilk SqlCommand alr ve Personel tablosunda PrimToplami


alann deeri artartd. Oysa imdi bu tabloyu kontrol edicek olursak,

ekil 11. Bir etki olmadi.

Tekrar nemli bir noktay vurgulamak isterim. Bu Transaction tek br veritaban zerinde
almaktadr. Eer birden fazla veritaban sz konusu olursa , Distibuted Transaction tekniklerini
kullanmamz gerekiyor. Bunu ilerliyen makalelerimizde incelemeye alacam. Umarm buraya
kadar anlattklarmla Transactionlar hakknda bilgi sahibi olmusunuzdur. Bir sonraki makalemizde
grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Overload Metodlarn Gc ( 13.11.2003 ) - C#


Deerli Okurlarm, Merhabalar.

Bu makalemde sizlere overload kavramndan bahsetmek istiyorum. Konunun daha iyi


anlalabilmesi asndan, ilerliyen ksmlarda basit bir rnek zerinde de alacaz.

ncelikle Overload ne demek bundan bahsedelim. Overload kelime anlam olarak Ar Ykleme
anlamna gelmektedir. C# programlama dilinde overload dendiinde, ayn isme sahip birden fazla
metod akla gelir. Bu metodlar ayn isimde olmalarna ramen, farkl imzalara sahiptirler. Bu
metodlarn imzalarn belirleyen unsurlar, parametre saylar ve parametre tipleridir. Overload
edilmi metodlar kullandmz snflarda, bu snflara ait nesne rnekleri iin ayn isme sahip fakat
farkl grevleri yerine getirebilen ( veya ayn grevi farkl say veya tipte parametre ile yerine
getirebilen ) fonksiyonellikler kazanm oluruz.

rnein;

www.bsenyurt.com Page 2686


ekil 1 : Overload metodlar.

ekil 1 de MetodA isminde 3 adet metod tanm gryoruz. Bu metodlar ayn isime sahip olmasna
ramen imzalar nedeni ile birbirlerinden tamamyla farkl metodlar olarak alglanrlar. Bize
salad avantaj ise, bu metodlar barndran bir snf nesnesi yarattmzda ayn isme sahip
metodlar farkl parametreler ile arabilmemizdir. Bu bir anlamda her metoda farkl isim vermek
gibi bir karklnda bir nebze nne geer. Peki imza dediimiz olay nedir? Bir metodun imzas u
unsurlardan oluur.

Metod mzas Kabul Edilen Unsurlar Metod mzas Kabul Edilmeyen Unsurlar

Parametre Says
Metodun Geri Dn Tipi
Parametrenin Tipleri

Tablo 1. Kullanm Kurallar

Yukardaki unsurlara dikkat ettiimiz srece dilediimiz sayda ar yklenmi ( overload edilmi)
metod yazabiliriz. imdi dilerseniz kk bir Console uygulamas ile , overload metod oluumuna
engel tekil eden duruma bir gz atalm.ncelikle metodun geri dn tipinin metodun imzas
olarak kabul edilemiyeceininden bahsediyoruz. Adaki rneimizi inceleyelim.

using System;
namespace Overloading1
{
class Class1
{
public int Islem(int a)
{
return a*a;
}
public string Islem(int a)
{
string b=System.Convert.ToString(a);
return "Yam:"+b;
}
[STAThread]
static void Main(string[] args)
{
}

www.bsenyurt.com Page 2687


}
}

rnein yukardaki uygulamada, Islem isimli iki metod tanmlanmtr. Ayn parametre tipi ve
saysna sahip olan bu metodlarn geri dn deerlerinin farkl olmas nedeni ile derleyici
tarafndan farkl metodlar olarak alglanm olmas gerektii dnlebilir. Ancak byle
olmamaktadr. Uygulamay derlemeye altmzda aadaki hata mesaj ile karlarz.

Overloading1.Class1' already defines a member called 'Islem' with


the same parameter types

Yapc metodlarda overload edebiliriz. Bu da olduka nemli bir noktadr. Bunu zaten .NET ile
program gelitirirken ska kullanrz. rnein SqlConnection snfndan bir nesne rnei yaratmak
istediimizde, bunu yapabileceimiz 2 overload edilmi yapc metod olduunu grrz. Bunlardan
birisi ada grnmektedir.

ekil 2. rnek bir Overload Constructor(Ar Yklenmi Yapc) metod.

Dolaysyla bizde yazdmz snflara ait constructorlar overload edebiliriz. imdi dilerseniz
overload ile ilgili olaraktan ksa bir uygulama gelitirelim. Bu uygulamada yazdmz bir snfa ait
constructor metodlar overload ederek deiik tipte fonksiyonellikler edinmeye alacaz.

Bu uygulamada KolayVeri isminde bir snfmz olucak. Bu snfn adet yapcs olucak. Yani iki
adet overload constructor yazcaz. ki tane diyorum nk C# zaten default constructoru biz
yazmasak bile uygulamaya ekliyor. Bu default constructorlar parametre almayan constructorlardr.
Overload ettiimiz constructor metodlardan birisi ile, setiimiz bir veritabanna balanyoruz. Dier
overload metod ise, parametre olarak veritaban adndan baka, veritabanna balanmak iin
kullanc ad ve parola parametrelerinide alyor. Nitekim ou zaman veritabanlarmzda yer alan
baz tablolara eriim yetkisi snrlamalar ile karlaabiliriz. Bu durumda bu tablolara balant
aabilmek iin yetkili kullanc ad ve parolay kullanmamz gerekir. Byle bir olay canlandrmaya
altm. Elbetteki asl amacmz overload constructor metodlarn nasl yazldn, nasl kullanldn
gstermek. rnek gelimeye ok, hemde ok ak. imdi uygulamamzn bu ilk ksmna bir
gzatalm. Adakine benzer bir form tasarm yapalm.

www.bsenyurt.com Page 2688


imdi sra geldi kodlarmz yazmaya. ncelikle uygulamamza KolayVeri adnda bir class ekliyoruz.
Bu classn kodlar aadaki gibidir. Aslnda uygulamaya bu aamada baktmzda SqlConnection
nesnemizin bir balant oluturmasn zelletirmi gibi oluyoruz. Gerektende ayn ilemleri zaten
SqlConnection nesnesini overload constructorlari ile yapabiliyoruz. Ancak temel amacmz ar
yklemeyi anlamak olduu iin programn alma amacnn ok nemli olmad dncesindeyim.
Umuyorum ki sizlere ar ykleme hakknda bilgi verebiliyor ve vizyonunuzu gelitirebiliyorumdur.

using System;
using System.Data.SqlClient;
namespace Overloading
{
public class KolayVeri
{
private string baglantiDurumu; /* Connection'n durumunu tutacak ve sadece bu class
iinde geerli olan bir string deiken tanmladk. private anahtar kelimesi deikenin sadece bu
class ierisinde yaayabilceini belirtir. Yazmayabilirizde, nitekim C# default olarak deikenleri
private kabul eder.*/
public string BaglantiDurumu /* Yukarda belirttiimiz baglantiDurumu isimli deikenin
sahip olduu deeri, bu class'a ait nesne rneklerini kullandmz yerde grebilmek iin sadece
okunabilir olan (readonly), bu sebeplede sadece Get blouna sahip olan bir zellik tanmlyoruz.*/
{
get
{
return baglantiDurumu; /* Bu zellie eritiimizde baglantiDurumu deikeninin o
anki deeri geri dndrlecek. Yani zelliin arld yere dndrlcek.*/
}
}
public KolayVeri() /* te C# derleyicisinin otomatik olarak ekledii parametresiz yapc
metod. Biz bu yapcya tek satrlk bir kod ekliyoruz. Eer nesne rnei parametresiz bir
Constructor ile yaplrsa bu durumda baglantinin kapal olduunu belirtmek iin baglantiDurumu
deikenine bir deer atyoruz. Bu durumda uygulamamzda bu nesne rneinin BaglantiDurumu
zelliine eritiimizde BAGLANAMADIK deerini elde edeceiz.*/

www.bsenyurt.com Page 2689


{
baglantiDurumu="BAGLANAMADIK";
}
public KolayVeri(string veritabaniAdi) /* Bizim yazdm ar yklenmi ilk yapc metoda
gelince. Burada yapcmz, parametre olarak bir string alyor. Bu string veritabannn adn
barndrcak ve SqlConnection nesnemiz iin gerekli balant stringine bu veritabannn adn
geiricek.*/
{
string connectionString="initial catalog="+veritabaniAdi+";data
source=localhost;integrated security=sspi";
SqlConnection con=new SqlConnection(connectionString); /* SqlConnection balantmz
yaratlyor.*/
try /* Balant ilemini bir try blounda yapyoruz ki, herhangibir nedenle Sql
sunucusuna balant salanamassa (rnein hatal veritaban ad nedeni ile) catch blounda
baglantiDurumu deikenine BAGLANAMADIK deerini atyoruz. Bu durumda program iinde
KolayVeri snfndan rnek nesnenin BaglantiDurumu zelliinin deerine baktmzda
BAGLANAMADIK deerini alyoruz bylece balantnn salanamadna kanaat getiriyoruz. Kanaat
dedikte aklma skdarda ki Kanaat lokantas geldi :) Yemekleri ok gzeldir. Sanrm karnmz
ackt deerli okuyucularm.Neyse kaldmz yerden devam edelim.*/
{
con.Open(); // Balantmz alyor.
baglantiDurumu="BAGLANDIK"; /* BaglantiDurumu zelliimiz (Property),
baglantiDurumu deikeni sayesinde BAGLANDIK deerini alyor.*/
}
catch(Exception hata) /* Eer bir hata olursa baglantiDurumu deikenine
BAGLANAMADIK deerini atyoruz.*/
{
baglantiDurumu="BAGLANAMADIK";
}
}
public KolayVeri(string veritabaniAdi,string kullaniciAdi,string parola) /* Sra geldi ikinci
overload constructor metoda. Bu metod ekstradan iki parametre daha alyor. Bir tanesi user id ye
tekabl edicek olan kullaniciAdi, dieri ise bu kullanc iin password'e tekabl edicek olan parola.
Bunlari SqlConnection'n connection stringine alarak , veritabanna belirtilen kullanc ile giri
yapm oluyoruz. Kodlarn ileyii bir nceki metodumuz ile ayn.*/
{
string connectionString="initial catalog="+veritabaniAdi+";data source=localhost;user
id="+kullaniciAdi+";password="+parola;
SqlConnection con=new SqlConnection(connectionString);
try
{
con.Open();
baglantiDurumu="BAGLANDIK";
}
catch(Exception hata)
{
baglantiDurumu="BAGLANAMADIK";
}
}
}

www.bsenyurt.com Page 2690


}

imdi sra geldi, formumuz zerindeki kodlar yazmaya.

string veritabaniAdi;
private void lstDatabase_SelectedIndexChanged(object sender, System.EventArgs e)
{
veritabaniAdi=lstDatabase.SelectedItem.ToString();
/* Burada kv adnda bir KolayVeri snfndan nesne rnei (object instance) yaratlyor. Dikkat
edicek olursanz burada yazdm ikinci overload constructor'u kullandk.*/
KolayVeri kv=new KolayVeri(veritabaniAdi); /* Burada KolayVeri( dediimizde .NET bize
kullanabileceimiz ar yklenmi constructorlar aadaki ekilde olduu gibi hatrlatacaktr.
IntelliSencein gzn seveyim.*/

stbDurumBilgisi.Text=lstDatabase.SelectedItem.ToString()+" "+kv.BaglantiDurumu;
private void btnOzelBaglan_Click(object sender, System.EventArgs e)
{
string kullanici,sifre;
kullanici=txtKullaniciAdi.Text;
sifre=txtParola.Text;
veritabaniAdi=lstDatabase.SelectedItem.ToString();
KolayVeri kvOzel=new KolayVeri(veritabaniAdi,kullanici,sifre); /* Burada ise dier ar
yklenmi yapcmz kullanarak bir KolayVeri nesne rnei oluturuyoruz.*/

stbDurumBilgisi.Text=lstDatabase.SelectedItem.ToString()+" "+kvOzel.BaglantiDurumu+"
User:"+kullanici;
}
}

Evet imdide programn nasl altna bir bakalm. Listbox nesnesi zerinde bir veritaban adna
bastmzda bu veritabanna bir balant alr.

www.bsenyurt.com Page 2691


ekil 6. Listboxta tklanan veritabanna balandktan sonra.

Ve birde kullanc ad ile parola verilerek nasl balanacamz grelim.

ekil 7. Kullanc ad ve parola ile baplant

Peki ya yanl kullanc ad veya parola girersek.

www.bsenyurt.com Page 2692


ekil 8. Yanlk kullanc ad veya parolas sonras.

Evet deerli MsAkademik okuyucular bu seferlikte bu kadar. Bir sonraki makalemizde grmek
dileiyle hepinize mutlu gnler, yarnlar dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

Stored Procedure Yardmyla Tablodan Kayt


Silmek ( 12.11.2003 ) - Ado.Net
Bugn ki makalemde Stored Procedure yardmyla bir veritaban tablosundan, bizim setiimiz
herhangi bir satr nasl sileceimizi sizlere anlatmaya alacam.Her zaman olduu gibi rneimizi
gelitirmek iin, SQL Server zerinde yer alan Northwind veritabann kullanmak istiyorum. SQL
Server zerinde alan rnekler gelitirmek istememin en byk nedeni, bir veritaban ynetim
sistemi (Database Management System;DBMS) zerinde .NET ile projeler gelitirmenin
gerekiliidir. Gncel yaantmzda a zerinde alan uygulamalar ounlukla , iyi bir veritaban
ynetim sistemi zerinde yazlm programlar ile gerekletirilmektedir. ok katl mimari olarak
hepimizin kulana bir ekilde gelmi olan bu sistemde, aslnda yazm olduumuz programlar,
birer arayz nitelii tamakta olup kullanc ile veritaban arasndaki iletiimi grsel anlamda
kolaylatran birer ara haline gelmitir. te bu sunum katman (presantation layer) denen yerdir.
Burada veri tablolarn ve veritabanlarn zerinde barndran yer olarak veritaban katman
(Database Layer) byk nem kazanmaktadr.

te bir nceki makalemde belirttiim gibi Stored Procedure' leri kulanmamn en byk amac
performans, hz ve gvenlik kriterlerinin nemidir. Dolaysyla, rneklerimizi bu ekilde gerek

www.bsenyurt.com Page 2693


uygulamalara yakn tutarak, alrsak daha baarl olucamz inancndaym.Evet bu kadar laf
kalabalndan sonra dilerseniz uygulamamza geelim.Uygulamamzn kolay ve anlalr olmas
amacyla az satrl bir tablo zerinde ilemlerimizi yapmak istiyorum. Bu amala Categories
tablosunu kullanacam.

ekil 1. Categories tablosunda yer alan veriler.

Tablomuzun yapsn da ksaca incelersek ;

ekil 2. Categories tablosunun alan yaps.

www.bsenyurt.com Page 2694


Burada CategoryID alan bizim iin nemlidir. Nitekim silme ilemi iin kullanacamz Stored
Procedure ierisinde , belirleyici alan olarak bir parametreye dnecektir. imdi dilerseniz, Stored
Proceduremz yazalm.

ekil 3. Stored Procedure Kodlari

CREATE PROCEDURE [Delete Category]


@kid int
AS
DELETE FROM Categories WHERE CategoryID=@kid
GO

Grld gibi burada son derece kolay bir T-SQL( Transact SQL ) cmlecii var. Burada yaplan
ilem aslnda @kid parametresine geilen deeri CategoryID alan ile eletirmek. Eer bu
parametre deerine karlk gelen bir CategoryID deeri varsa; bu deeri tayan satr Categories
isimli tablodan silinecektir.

Evet imdi de .NET ortamnda formumuzu tasarlayalm. New Project ile yeni bir C# projesi aarak
ie balyoruz. Formumuzun tasarmn ben aadaki ekilde yaptm. Sizde buna uygun bir form
tasarlayabilir yada ayn tasarm kullanabilirsiniz. Visual Studio.NET ile program gelitirmenin
belkide en zevkli ve gzel yan form tasarmlar. Burada gerekten de iimizdeki sanat ruhunu
ortaya kartma imkanna sahibiz. Ve doruyu sylemek gerekirse Microsoft firmasda artk
iimizdeki sanat ocuu zellikle bu tarz uygulamalarda, daha kolay aa kartabilmemiz iin
elinden geleni yapyor. Doal olarakta ok da gzel sonular ortaya kyor. Birde o eski
bankalardaki ( halen daha varya ) siyah ekranlarda, incecik, kargack, burgack tasarmlar ve
arayzleri dnn. F12 ye bas geri dn. Tab yap. imdi F4 kodu gir.

www.bsenyurt.com Page 2695


ekil 4. Formun Ilk Yapisi

Formumuzda bir adet dataGrid nesnesi ve bir adetde button nesnesi yer alyor. DataGrid nesnesini
Categories tablosu iersinde yer alan bilgileri gstermek iin kullanacaz. Datagrid verileri
gsterirken kullancnn kayt eklmek, dzenlemek, ve setii satr buradan silmesini egellemek
istediimden ReadOnly zelliine True deerini aktardm. rneimizin amac gerei silme ilemini
Sil textine sahip btnSil button nesnesinin Click olay procedurenden yapcaz. Elbette burada
databasedeki bilgileri dataGrid iersinde gstermek amacyla bir SqlDataAdapter nesnesi
kullanacam. Bu sadece Categories isimli tablo ierisindeki tm satrlar seicek bir Select
sorgusuna sahip olucak ve bunlar dataGrid ile ilikili olan bir DataTable nesnesine aktarcak.

Dilerseniz kodlarmz yazmaya balayalm. nceliklie SqlConnection nesnemiz yardmyla,


Northwind veritabanna bir balant ayoruz. Daha sonra SqlDataAdapter nesnemizi
oluturuyoruz. SqlDataAdapter nesnesini yaratmak iin new anahtar szc ile
kullanabileceimiz 4 adet overload constructor var. Overload constructor, ayn isme sahip yapc
metodlar anlamna geliyor. Yani bir SqlDataAdapter nesnesini yaratabileceimiz 4 kurucu(
constructor) metod var ve bunlarn hepside ayn isme sahip(Overload;ar yklenmi) metodlar.
Yeri gelmiken bunlardan da bahsederek bilgilerimizi hem tazeleyelim hem de arttrm olalm. te
bu yapc metodlarn prototipleri.

public SqlDataAdapter();
public SqlDataAdapter(string selectCommandText,string connectionString);
public SqlDataAdapter(string selectCommandText,SqlConnection selectConnection);
public SqlDataAdapter(SqlCommadn selectCommand);

Ben uygulamamda ilk yapc metodu baz almak istiyorum. Evet artk kodlarmz yazalm.

NOT: Her zaman olduu gibi projemizin bana System.Data.SqlClient


namespace ini eklemeyi unutmayalm.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;
using System.Data;

www.bsenyurt.com Page 2696


using System.Data.SqlClient;
/* nce SqlConnection nesnesi yardimiyla SQL Server zerinde yer alan, Northwind isimli
veritabanina bir baglanti nesnesi tanimliyoruz. Ilk parametre yani initial catalog, veritabaninin
ismini temsil ediyor. u anda SQL Server in zerinde yer alan makinede alisitigimizdan Data
Source parametresine localhost degerini aktardik. */
SqlConnection conNorthwind=new SqlConnection("initial catalog=Northwind;Data
Source=localhost;integrated security=sspi;packet size=4096");
/* imdi Categories tablosunu bellekte temsil edicek olan DataTable nesnemizi yaratiyoruz. Dikkat
edersek bellekte dedik. DataTable nesnesi Categories tablosundaki verileri programin alistigi
bilgisayar zerindeki bellekte sakliyacaktir. Bu durumda SqlConnection nesnemizin aik kalmasina
gerek yoktur. Bu da elbetteki sunucu zerindeki yk azaltan bir etkendir.*/
DataTable dtbCategories=new DataTable("Kategoriler");
private void Form1_Load(object sender, System.EventArgs e)
{
conNorthwind.Open();//Balantmz ayoruz.
SqlDataAdapter da=new SqlDataAdapter();//Bir SqlDataAdapter nesnesi tanimladik.
/* Asagidaki satir ile yarattigimiz SqlDataAdapter nesnesine bir Select sorgusu eklemis
oluyoruz. Bu sorgu sonucu dnen deger kmesi, SqlDataAdapter nesnesinin Fill metodunu
kullandigimizda DataTable' in ierisini hangi veriler ile dolduracagimizi belirtecek nemli bir
zelliktir. Bir SqlDataAdapter nesnesi yaratildiginda, SelectCommand zelligine SqlCommand
trnden bir nesne atanarak bu islem gereklestirilir. Burada aslinda, SelectCommand zelliginin
prototipinden dolayi new anahtar szcg kullanilarak bir SqlCommand nesnesi parametre olarak
verilen select cmlecigi ile olusturulmus ve SelectCommand zelligine atanmistir.
*
* public new SqlCommand SelectCommand
*{
* get;
* set;
*}
* Prototipten de grldg gibi SelectCommand zelliginin tipi SqlCommand nesnesi
trndendir. Bu yzden new SqlCommand("....") ifadesi kullanilmistir.
* */
da.SelectCommand=new SqlCommand("SELECT * FROM Categories");
da.SelectCommand.Connection=conNorthwind; /* Select sorgusunun alistirilacagi baglanti
belirlenir.*/
da.FillSchema(dtbCategories,SchemaType.Mapped);/* Burada dataTable nesnemize,
veritabannda yer alan Categories isimli tablonun Schema bilgilerinide yklyoruz. Yani primaryKey
bilgileri, alanlarn bilgileri ykleniyor. Bunu yapmamzn sebebi, Stored Procedure ile
veritabanndaki Categories tablosundan silme ilemini yapmadan nce , bellekteli tablodan da ayn
satr silip dataGrid iindeki grntnn ve DataTable nesnesinin gncel olarak kalmasn salamak.
Nitekim silme ileminde DataTable nesnesinden seili satr silmek iim kullanacamz Remove
metodu PrimaryKey alannn deerini istemektedir. Bunu verebilmek iin tablonun PrimaryKey
bilgisininde bellee yani bellekteki DataTable nesnesine yklenmi olmas gerekir. te bu amala
Schema bilgilerinide alyoruz*/
da.Fill(dtbCategories);/* Burada SqlDataAdapter nesnesinin Fill metodu agirilir. Fill metodu
ncelikle SelectCommand.CommandText in degeri olan Select sorgusunu alistirir ve dnen veri
kmesini dtbCategories isimli DataTable nesnesinin bellekte referans ettigi alana ykler. Artik
baglantiyida kapatabiliriz.*/
conNorthwind.Close();
/* Simdi dataGrid nesnemize veri kaynagi olarak DataTable nesnemizi gsterecegiz. Bylece
DataGrid, Categories tablosundaki veriler ile dolucak. */
dgCategories.DataSource=dtbCategories;

www.bsenyurt.com Page 2697


}
private void btnDelete_Click(object sender, System.EventArgs e)
{
/* mdi silme ilemini gerekletireceimiz Stored Procedure'e DataGrid nesnesi zerinde
kullancnn semi olduu satrn CategoryID stununun deerini gndereceiz. Bunun iin
kullancnn setii satrn numarasn CurrentCell.RowNumber zellii ile alyoruz. Daha sonra,
CategoryID stunu dataGrid'in 0 indexli stunu olduundan CategoryID deerini elde ederken
dgCategories[currentRow,0] metodunu kullanyoruz.*/
int currentRow;
int selectedCategoryID;
currentRow=dgCategories.CurrentCell.RowNumber;
selectedCategoryID=(int)dgCategories[currentRow,0]; /* Burada dgCategories[currentRow,0]
aslnda object tipinden bir deer dndrr. Bu yzden ak olarak dntrme dediimiz (Explicit)
bir Parse(dntrme) ilemi yapyoruz. */
/* imdi de Stored Procedure'mz altracak olan SqlCommand nesnesini tanmlayalm*/
SqlCommand cmdDelete=new SqlCommand();
cmdDelete.CommandText="Delete Category";/* Stored Procedure'n ad CommandText
zelliine atanyor. Ve bu stringin bir Stored Procedure'e iaret ettiini belirtmek iin
CommandType deerini CommandType.StoredProcedure olarak belirliyoruz.*/
cmdDelete.CommandType=CommandType.StoredProcedure;
cmdDelete.Connection=conNorthwind;//Komutun altrlaca balant belirleniyor.
/* imdi ise @id isimli parametremizi oluturacaz ve kullancnn semi olduu satrn
CategoryID deerini bu parametre ile Stored Proecedure'mze gndereceiz.*/
cmdDelete.Parameters.Add("@kid",SqlDbType.Int);
cmdDelete.Parameters["@kid"].Value=selectedCategoryID;
/* Ve nemli bir nokta. Kullancy uyarmalyz. Gerekten setii satr silmek istiyor mu?*
Bunun iin MessageBox nesnesni ve Show metodunu kullanacaz. Bu metodun dn deerini
DialogResult tipinde bir deikenle kontrol ettiimize dikkat edin.*/
DialogResult result;
result=MessageBox.Show("CategoryID : "+selectedCategoryID.ToString()+". Bu satr silmek
istediinizden emin misiniz?","Sil",MessageBoxButtons.YesNo, MessageBoxIcon.Question,
MessageBoxDefaultButton.Button1);
if (result==DialogResult.Yes ) /*Eer kullancnn cevab evet ise aadaki kod bloundaki
kodlar altrlr ve satr once DataTable nesnesinden sonrada kalc olarak databaseden silinir.*/
{
conNorthwind.Open();// Balantmz ayoruz.
/* Elbette veritabanndan dorudan sildiimiz satr bellekteki DataTable nesnesinin referans
ettii yerdende siliyoruz ki datagrid nesnemiz gncelliini korusun. Bunun iin seili olan dataTable
satrnu bir DataRow nesnesine aktaryoruz. Bunu yaparkende seili kayd Find metodu ile
CategoryID isimli Primary Key alan zerinden arama yapyoruz. Kayt bulunduunda tm
satrbilgisi bir DataRow tr olarak geri dnyor ve bunu DataRow nesnemize atyoruz. Remove
metodu silinmek istenen satr bilgisini parameter olarak alr. Ve bu parameter DataRow tipinden bir
parametredir.*/
DataRow drSelectedRow;
drSelectedRow=dtbCategories.Rows.Find(selectedCategoryID);
dtbCategories.Rows.Remove(drSelectedRow);
cmdDelete.ExecuteNonQuery();/ * Artk Stored Procedure de altrlyor ve slime ilemi
dorudan veritabanndaki tablo zerinden gerekletiriliyor. ExecuteNonQuery bu Stored
Procedure' altracak olan metoddur. Delete,Update,Insert gibi kayt dndrmesi beklenmeyen
(Select sorgular gibi) sql cmlecikleri iin ExecuteNonQuery metodu kullanlr.*/
conNorthwind.Close();

www.bsenyurt.com Page 2698


}
}

imdi dilerseniz programmz altrp sonularna bir bakalm. ncelikle Categories isimli tabloya
dorudan SQL Server zerinden rnek olmas asndan bir ka kayt ekleyelim.

ekil 5. Categories tablosuna 3 yeni kayt ekledik.

imdi uygulamamz altralm. Bu durumda ekran grnts aadaki gibi olucaktr. u anda
dataGrid iindeki bilgiler veritabanndan alnp , bellekteki dataTable nesnesinin referans ettii
blgedeki verilerden olumaktadr. Dolaysyla Sql Servera olan balantmz ak olmad halde
verileri izleyebilmekteyiz. Hatta bunlarn zerinde deiiklilkler yapp normal tablo ilemlerinide
(silme,kayt ekleme,gncelleme vb... gibi) gerekletirebiliriz. Bu balantsz katman olarak
adlandrdmz olaydr. Bu konuya ilerliyen makalelerimizide daha detayl olarak inceleyeceiz.

ekil 6. Load Procedurenn altrlmasndan sonraki grnm.

imdi setiimiz 17 CategoryID satrn silelim. Ekrana bir soru kacaktr.

www.bsenyurt.com Page 2699


ekil 7. MessageBox.Show(.....) metodunun sonucu.

imdi Yes butonuna basalm. Bu durumda 17 CategoryID li satr dataTabledan dolaysyla


dataGridden silinir. Ayn zamanda altrdmz Stored Procedure ile veritabanndan da dorudan
silinmitir.

ekil 8. Silme ilemi sonras.

imdi SQL Servera geri dnp tablonun ieriini kontrol edicek olursak aadaki sonucu elde
ederiz.

ekil 9. Sonu.

Grld gibi CategoryID=17 olan satr veritabanndaki tablodanda silinmitir. Bir sonraki
makalemizde grmek dileiyle.

www.bsenyurt.com Page 2700


Burak Selim ENYURT

selim@bsenyurt.com

Web Sayfalarnda Stored Procedure Kullanm (


12.11.2003 ) - Asp.Net
Bugnk makalemde sizlere bir Web Sayfas zerinde, bir tablonun belli bir satrna ait detayl
bilgilerin, bir Stored Procedure yardmyla nasl gsterileceini anlatmaya alacam.
Uygulamamzda rnek olmas asndan, Kitap bilgileri barndran bir Sql tablosu kullanacam.
Tablomuzun yapsn aadaki ekil 1 de grebilirsiniz. Temel olarak, kitap isimlerini, kitaplarn
kategorilerini, yazar isimlerini , basm evi bilgilerini vb barndran bir tablomuz var. Bu tablonun
rnek verilerini de ekil2 de grebilirsiniz.

ekil 1. Kitaplar tablosunun alan yaps.

ekil 2. Kitaplar tablosunun rnek verileri.

www.bsenyurt.com Page 2701


imdi projemizin en nemli unsuru olan Stored Procedure nesnemizi Sql Server zerinde
oluturalm. Bu Stored Procedure ile kullancnn, web sayfasnda listbox nesnesi iinden setii
kitaba ait tm verileri dndrecek olan bir Sql cmlecii yazcaz. Burada aranan satr
belirleyecek olan deerimiz ID isimli ayn zamanda Primary Key olan alann deeri olucaktr.
Kullanc listBox nesnesinde yer alan bir kitab setiinde (yani listBox nesnesine ait
lstKitaplar_SelectedIndexChanged olay procedure altrldnda) seili olan eye ait id
numaras Stored Proceduremze parametre olarak gnderilicek. Elde edilen sonu kmesine ait
alanlar dataGrid nesnemizde gsterilerek kitabmza ait detayl bilgilerin grntlenmesi salanm
olucak. Dilerseniz Kitap Bul isimli Stored Proceduremz oluturarak devam edelim. ekil
3 yazdmz Stored Procedure nesnesini gstermekte.

ekil 3. Stored Procedure nesnemiz ve Sql ifadesi.

Sra geldi uygulamamzda yer alan WebFormumuzu oluturmaya. Uygulamamz C# dili ile
oluturmay tercih ettiimden New Project ksmnda Visual C# Proejct blmn setim. Dikkat
edicek olursanz, uygulmamz bir Web Application dr. Oluturulduu yer http://localhost/kitap adl
adrestir.

www.bsenyurt.com Page 2702


ekil 4. Web Application

Evet gelelim WebFormun tasrmna. Ben aadaki gibi bir tasarm oluturdum. Sizlerde buna yakn
bir tasarm oluturabilirsiniz veya aynsn kullanamay tercih edebilirsiniz.

ekil 5. Web Form tasarm.

Sra geldi kodlarmz yazmaya. nce sayfa yklenirken neler olucan belirleyeceimiz kodlarmz
yazmaya balayalm. zet olarak Page_Load olay procedurende Sql Server a balanp, Kitaplar
tablosundan yanlzca ID ve Adi alanna ait deerleri alyoruz ve bunlar bir SqlDataReader nesnesi

www.bsenyurt.com Page 2703


vastasyla, lstKitaplar isimli listBox nesnemize yklyoruz. Gelin kodumuzu yazalm, hem de
inceleyelim.

/* nce gerekli SqlConnection nesnemizi oluturuyor ve gerekli ayarlarmz yapyoruz.*/


SqlConnection conFriends=new SqlConnection("initial catalog=Friends;Data
Source=localhost;integrated security=sspi");
private void Page_Load(object sender, System.EventArgs e)
{
if (Page.IsPostBack==false)
{
/* SqlCommand nesnemizi yaratyoruz. Bu nesne Select sorgusu ile Kitaplar tablosundan ID
ve Adi alanlarnn deerlerini alcak. Alnan bu veri kmesi Adi alanna gre A'dan Z'ye sralanm
olucak. Bunu salayan sql cmleciindeki, "Order By Adi" ifadesidir. Tersten sralamak istersek
"Order By Adi Asc" yazmamz gerekir. */
SqlCommand cmdKitaplar=new SqlCommand("Select ID,Adi From Kitaplar Order By
Adi",conFriends);
cmdKitaplar.CommandType=CommandType.Text; // SqlCommand'in command String'inin
bir Sql cmleciine iaret ettiini belirtiyoruz.
SqlDataReader dr; // Bir SqlDataReader nesnesi oluturuyoruz.
/* SqlDataReader nesnesi ileri ynl ve sadece okunabilir bir veri ak salar. (Forward and
Readonly) Bu da nesneden veri aktarmlarnn (rnein bir listboxa veya datagride) hzl
almasna bir nedendir. Uygulamalarmzda, listeleme gibi sadece verilere bakmak amacyla
altracamz sorgulamalar iin, SqlDataReader nesnesini kullanmak, performans asndan
olumlu etkiler yapar. Ancak SqlDataReader nesnesi alt sre boyunca sunucuya olan
balantnnda srekli olarak ak olmasn gerektirir.
Yukardaki kod satrnda dikkat ekici dier bir unsur ise, bir new yaplandrcs
kullanlmaydr. SqlDataReader snfnn bir yapc metodu ( Constructor ) bulunmamaktadr. O
nedenle bir deiken tanmlanyormu gibi bildirilir. Bu nesneyi asl ykleyen, SqlCommand
nesnesinin ExecuteReader metodudur. */
conFriends.Open(); // Balantmz ayoruz.
dr=cmdKitaplar.ExecuteReader(CommandBehavior.CloseConnection); /* Burada
ExecuteReader metodu , SqlCommand nesnesine yle bir seslenite bulunuyor. "
SqlCommand'cm, sana verilen Sql Cmleciini (Select sorgusu) altr ve sonularn bir zahmet
eitliin sol tarafnda yer alan SqlDataReader nesnesinin bellekte referans ettii alana ykle.
Sonrada sana belirttiim, samdaki CommandBehavior.CloseConnection parametresi nedeni ile,
SqlDataReader nesnesi Close metodu ile kapatldnda, yine bir zahmet SqlConnection
nesnesininde otomatik olarak kapanmasn salayver". */
lstKitaplar.DataSource=dr; // Elde edilen veri kmesi SqlDataReader nesnesi yardmyla
ListBox nesnesine veri kayna olarak gsteriliyor.
lstKitaplar.DataTextField="Adi"; // ListBox nesnesinde Text olarak Adi alannn deerleri
grncek.
lstKitaplar.DataValueField="ID"; // Grnen Adi deerlerinin sahip olduu ID deerleri de
ValueField olarak belirleniyor. Bylece "Kitap Bul" isimli Stored Procedure'mze ID parametresinin
deeri olarak bu alann deeri gitmi olucak. Ksacas grnen yaz kitabn ad olurken, bu yaznn
deeri ID alannn deeri olmu oluyor.
lstKitaplar.DataBind(); // Web Sayfalarnda , verileri nesnelere balarken DataBind metodu
kullanlr.
dr.Close(); // SqlDataReader nesnemiz kapatlyor. Tabiki SqlConnection nesnemizde
otomatik olarak kapatlyor.
}
}

www.bsenyurt.com Page 2704


imdi oluturduumuz projeyi altrrsak aadaki gibi bir sonu elde ederiz. Grld gibi
Kitaplar tablosundaki tm kitaplara ait Adi alanlarnn deerleri listBox nesnemize yklenmitir.

ekil 6. Page_Load sonras.

imdi ise listBoxta bir eyi setiimizde neler olucana bakalm. Temel olarak, seilen eye ait
ID deeri Kitap Bul isimli Stored Proceduree gidicek ve dnen sonular dataGrid nesnesinde
gsterceiz.

ListBox nesnesine tkland zaman, alcak olan lstKitaplar_ SelectedIndexChanged olay


procedurende gerekli kodlar yazmadan once ListBox
nesnesinin AutoPostBackzelliine True deerini atamamz gerekiyor. Bylece kullanc sayfa
zerinde listbox iindeki bir nesneye tkladnda lstKitaplar_SelectedIndexChanged olay
procedurenn almasn salam oluyoruz. Nevarki byle bir durumda sayfann Page_Load olay
procedrnn de tekrar almasn engellemek yada baka bir deyile bir kere almasn
garantilemek iin if (Page.IsPostBack==false) kontroln Page_Load olay procedurene
ekliyoruz.

www.bsenyurt.com Page 2705


ekil 7. AutoPostBack zellii

private void lstKitaplar_SelectedIndexChanged(object sender, System.EventArgs e)


{
SqlCommand cmdKitapBul=new SqlCommand("Kitap Bul",conFriends); /* SqlCommand
nesnemizi oluturuyoruz ve commandString parametresine Stored Procedure'n ismini
yazyoruz.*/
cmdKitapBul.CommandType=CommandType.StoredProcedure; /* Bu kez SqlCommand'in bir
Stored Procedure altracana iaret ediyoruz.*/
cmdKitapBul.Parameters.Add("@id",SqlDbType.Int); /* "Kitap Bul" isimli Stored Procedure'de
yer alan @id isimli parametreyi komut nesnemize bildirmek iin SqlCommand nesnemizin,
Parameters koleksiyonuna ekliyoruz.*/
cmdKitapBul.Parameters[0].Value=lstKitaplar.SelectedValue; /* listBox nesnesinde seilen
enin deerini (ki bu deer ID deeridir) SelectedValue zellii ile alyor ve SqlCommand
nesnesinin 0 indexli parametresi olan @id SqlParameter nesnesine atyoruz. Artk SqlCommand
nesnemizi altrdmzda , @id paramteresinin deeri olarak seili listBox esinin deeri
gnderilicek ve bu deere gre alan Select sorgusunun dndrd sonular SqlDataReader
nesnemize yklenecek.*/
SqlDataReader dr;
conFriends.Open(); // Balantmz alyor.
dr=cmdKitapBul.ExecuteReader(CommandBehavior.CloseConnection); // Komut altrlyor.
dgDetaylar.DataSource=dr; // dataGrid nesnesine veri kayna olarak SqlDataReader nesnemiz
gsteriliyor.
dgDetaylar.DataBind(); // dataGrid verilere balanyor.

www.bsenyurt.com Page 2706


dr.Close(); // SqlDataReader nesnemiz ve sonrada SqlConnection nesnemiz ( otomatik olarak )
kapatlyor.
}

ekil 8. Sonu.

Geldik bir makalemizin daha sonuna. Yeni makalelerimizde grmek dileiyle, hepinizi mutlu
gnler.

Burak Selim ENYURT

selim@bsenyurt.com

Stored Procedure Yardmyla Yeni Bir Kayt


Eklemek ( 08.11.2003 ) - Ado.Net
Bu yazmzda Sql Server zerinde, kendi yazdmz bir Sakl Yordam (Sakl Yordam) ile ,
veritabanndaki ilgili tabloya nasl kayt ekleyeceimizi incelemeye alacaz.

ncelikle, Sakl Yordamlar hakknda ksa bir bilgi vererek hzl bir giri yapalm. Sakl yordamlar
derlenmi sql cmlecikleridir. Bunlar birer veritaban nesnesi olduklar iin, dorudan veritaban
yneticisi olan programda (rnein Sql Server) yer alrlar. Bu nedenle veritabannz bir yere
tadnzda otomatik olarak, sakl yordamlarnzda tam olursunuz. Bu Sakl Yordam'lerin tercih
edilme nedenlerinden sadece birisidir. Dier yandan, derlenmi olmalar aslnda bu sql
cmleciklerinin dorudan makine diline dntrld anlamna gelmez. Aslnda , altrmak
istediimiz sql cmleciklerini bir Sakl Yordam iine yerletirerek, bunun bir veritaban nesnesi
haline gelmesini ve altrldnda dorudan, veritaban yneticisini zerinde barndran sunucu
makinede ilemesini salarz. Bu doal olarak, istemci makinelerdeki i ykn azaltr ve
performans arttrr. Nitekim bir program iinde altrlan sql cmleleri, Sakl Yordam lardan ok
daha yava sonu dndrr. Dolaysyla Sakl Yordamlar zellikle ok katl mimariyi uygulamak
isteimiz projelerde faydaldr. Sakl Yordamlarn faydalarn genel hatlar ile zetlemek gerekirse ;

www.bsenyurt.com Page 2707


ekil 1. Sakl Yordam Kullanmann Avantajlar.

te bizim bugnk uygulamamzda yapacamz ilemde budur. Bu uygulamamzda basit bir Sakl
Yordam yaratacak, SqlCommand nesnesinin CommandType zelliini, SqlParameters
koleksiyonunu vb. kullanarak geni bir bilgi sahibi olucaz. ncelikle zerinde alacamz
tablodan bahsetmek istiyorum. Basit ve konuyu hzl renebilmemiz asndan ok detayl bir
kodlama teknii uygulamyacam. Amacmz Sakl Yordammza parametreler gndererek
dorudan veritabanna kaydetmek olucak. Dilerseniz tablomuzu inceleyelim ve oluturalm.

ekil 2. Tablonun Yaps.

www.bsenyurt.com Page 2708


ekil 2' de tablomuzda yer alan alanlar grlmekte. Bu tabloda arkadalarmzn doum gnlerini,
ilerini , isim ve soyisim bilgilerini tutmay planlyoruz. Tablomuzda FriendsID isminde Primary Key
olan ve otomatik olarak artan bir alanda yer alyor. imdi ise insert sql deyimini kullandmz Sakl
Yordammza bir gze atalm.

ekil 3. Insert Friend Sakl Yordamnn Kodlar.

ekil 3 kullanacamz Sakl Yordamn T-SQL(Transact SQL) deyimlerini gsteriyor. Burada


grld gibi Sql ifademizin 4 parametresi var. Bu parametrelerimiz;

Parametre Ad Veri Tipi Veri Uzunluu Aklama

@fn Nvarchar 50 First Name alan iin kullanlacak.

@ln Nvarchar 50 Last Name alan iin kullanlacak.

@bd Datetime - BirthDay alan iin kullanlacak.

@j Nvarchar 50 Job alan iin kullanlacak.

Tablo 1. Sakl Yordammzda Kullanlan Giri Parametreleri.

www.bsenyurt.com Page 2709


Insert Into Base (FirstName,LastName,BirthDay,Job) values (@fn,@ln,@bd,@j)

cmlecii ile standart bir kayt ekleme ilemi yapyoruz. Tek nemli nokta values(deerler) olarak,
parametre deerlerini gnderiyor olmamz. Bylece, Sakl Yordammz, .net uygulamamzdan
alaca parametre deerlerini bu sql cmleciine alarak, tablomuz zerinde yeni bir satr
oluturulmasn salyor. Peki bu parametre deerlerini .net uygumlamamzdan nasl vereceiz?
Bunun iin uygulamamzda bu Sakl Yordam kullanan bir SqlCommand nesnesi oluturacaz. Daha
sonra, Sakl Yordammzda yer alan parametreleri, bu SqlCommand nesnesi iin oluturacak ve
Parameters koleksiyonuna ekleyeceiz. Bu ilemin tamamlanamasnn ardndan tek yapacamz
Sakl Yordama geicek parametre deerlerinin, SqlCommand nesnesindeki uygun SqlParameter
nesnelerine aktarlmas ve Sakl Yordamn altrlmas olucak.

ncelikle C# iin yeni bir Windows Application oluturalm ve formumuzu aadaki ekilde
dzenleyelim. Burada 3 adet textBox nesnemiz ve tarih bilgisini girmek iinde bir adet
DateTimePicker nesnemiz yer alyor. Elbette insert ilemi iinde bir Button kontrol koymay ihmal
etmedik. Ksaca formun ileyiinden bahsetmek istiyorum. Kullanc olarak biz gerekli bilgileri
girdikten sonra insert balkl Button kontrolne bastmzda, girdiimiz bilgiler Sakl Yordam daki
parametre deerleri olucak. Ardndan Sakl Yordammz altrlacak ve girdiimiz bu parametre
deerleri ile, sql sunucumuzda yer alan veritabanmzdaki Base isimli tablomuzda yeni bir satr
oluturulacak.

ekil 4. Formun Tasarm Zamanndaki Grnts.

imdide kodumuzu inceleyelim. Her zaman olduu gibi SQLClient snfna ait nesneleri
kullanacamz iin bu snf using ile projemizin en bana ekliyoruz.

using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Windows.Forms;

www.bsenyurt.com Page 2710


using System.Data;
using System.Data.SqlClient;

Srada veritabanna olan balantmz referans edicek olan SQLConnection nesnemiz var.

SqlConnection conFriends = new SqlConnection("initial catalog=Friends;data


source=localhost;integrated security=sspi;packet size=4096");

Ksaca anlatmak gerekirse, SQL Sunucumuz' daki Friends isimli Database e balant salyacak
bir SqlConnection nesnesi tanmladk. Burada SqlConnection snfnn prototipi aada
verilen Constructor(yapc metodunu) metodunu kullandk. Bildiiniz gibi SqlConnection nesnesi,
Sql Sunucusu ile ado.net nesneleri arasnda iletiimin salanabilmesi iin bir balant hatt tesis
etmektedir.

public SqlConnection(string connectionString);

imdi btnInsert isimli butonumuzun click olay procedure' ndeki kodumuzu yazalm.

private void btnInsert_Click(object sender, System.EventArgs e)


{
conFriends.Open();/* Baglanti ailiyor. SqlCommand nesnesi ile ilgili ayarlamalara geiliyor.
Komut SQL Server da Friends databaseinde yazili olan "Insert Friend" isimli Sakl Yordam
alistiracak. Bu Procedure n ismini, CommandText parametresine geirdikten sonar ikinci
parameter olarak SqlConnection nesnemizi belirtiyoruz.*/
SqlCommand cmdInsert = new SqlCommand("Insert Friend",conFriends);
/* SqlCommand nesnesinin CommandType degerinide CommandType.StoredProcedure
yapiyoruz. Bu sayede CommandTexte girilen deerin bir Sakl Yordame iaret ettiini belirtmi
oluyoruz.*/
cmdInsert.CommandType=CommandType.StoredProcedure;
/* imdi bu Sakl Yordam iin gerekli parametreleri olusturacagiz. Bunun iin SqlCommand
nesnesininin parameters koleksiyonunun Add metodunu kullaniyoruz. Parametreleri eklerken,
parametre isimlerinin SQL Serverda yer alan Sakl Yordamlardaki parametre isimleri ile ayni
olmasina ve baslarina @ isareti gelmesine dikkat ediyoruz. Bu Add metodunun ilk parametresinde
belirtiliyor. Add metodu ikinci parametre olarak bu parametrenin veri tipini alyor. nc
parametresi ise bu parametrik degiskenin boyutu oluyor.*/
SqlParameter paramFirstName=cmdInsert.Parameters.Add("@fn",SqlDbType.NVarChar,50);
/* Burada SqlCommand nesnesine @fn isimli nvarchar tipinde ve uzunluu 50 karaketerden
olusan bir parametre ekleniyor. Ayn ekilde dier parametrelerimizi de belirtiyoruz.*/
SqlParameter paramLastName=cmdInsert.Parameters.Add("@ln",SqlDbType.NVarChar,50);
SqlParameter paramBirthDay=cmdInsert.Parameters.Add("@bd",SqlDbType.DateTime);
SqlParameter paramJob=cmdInsert.Parameters.Add("@j",SqlDbType.NVarChar,50);
// imdide paremetrelerimize degerlerini verelim.
paramFirstName.Value=txtFirstName.Text;
paramLastName.Value=txtLastName.Text;
paramBirthDay.Value=dtBirthDay.Text;
paramJob.Value=txtJob.Text;
// Bylece ilgili paremetrelere degerleri geirilmis oldu. simdi komutu alistiralim.
cmdInsert.ExecuteNonQuery();

www.bsenyurt.com Page 2711


/* Bylece Sakl Yordamimiz, paremetrelerine atanan yeni degerler ile alisitirlir. Bunun sonucu
olarak SQL Server daki Sakl Yordama burada belirttiimiz parametre deerleri gider ve insert
cmlecii altrlarak yeni bir kayit eklenmis olur.*/
conFriends.Close(); // Son olarak SqlConnection mz kapatyoruz.
}

imdi bir deneme yapalm.

ekil 5. Programn almas.

ekil 6. Sakl Yordam'n ilemesinin Sonucu.

Grld gibi Sakl Yordamlar yardmyla tablolarmza veri eklemek son derece kolay, hzl ve
etkili. Bununla birlikte Sakl Yordamlar saladklar gvenlik kazanmlar nedeni ilede tercih edilirler.
Sakl Yordamlar gelitirmek son derece kolaydr. stediini sql ilemini gerekletirebilirisiniz. Satr
silmek, satr aramak gibi. Sakl Yordamlar ile ilgili bir sonraki makalemizde, tablolardan nasl satr
silebileceimizi incelemeye alacaz. Bylece geldik bir makalemizin daha sonuna. Bir sonraki
makalemizde grmek dileiyle hepinize mutlu gnler dilerim.

Burak Selim ENYURT

selim@bsenyurt.com

www.bsenyurt.com Page 2712

You might also like