Günümüzde artık tarayıcı içi iş uygulamalarında uygulama geliştirme platformu
olarak Silverlight dışında pek birşey düşünülemiyor. Fakat bu manzara içerisinde
de tabi ki daha üçüncü sürümünde bir ürün olarak Silverlight'ın eksikleri var.
Bu eksiklerin bazıları maalesef Silverlight yapısı gereği içerisine oturduğu
mimari rolle de alakalı olabiliyor. Çok basit bir örnek olarak veri erişim
modelini ele alabiliriz. Bugün Silverlight ile bir uygulama geliştirmek isteyen
herhangi bir iş uygulaması geliştirme ekibinin alışması gereken ilk şey servis
yönelimli mimari. Buraya kadar herşey aslında çok güzel fakat en basit CRUD
(Create, Read, Update; Delete) operasyonları için bile birer servis hazırlayıp,
bu servislerin referanslarını alıp SL tarafında tek tek kullanıyor olmak bazı
durumlarda rahatsız edici şekilde uygulama geliştirme sürecini uzatabiliyor da.
.NET RIA Services!
İş uygulamalarınızın çapına/büyüklüğüne göre .NET RIA Services dertlerinize
çare olabilir. Peki nasıl? Aslında yapmak istediğimiz şey bir şekilde http:80
üzerinden CRUD operasyonlarını yapabilmek. Hemen belki de aklınıza ADO.NET Data
Services gelecektir. Kesinlikle doğru yoldasınız. Aslında ADO.NET Data Services
ile sunucu tarafında ciddi bir gelişme olmuştu ve artık URL üzerinden
sorgularımızı atabiliyor, sonrasında da XML olarak cevabı alabiliyorduk. Fakat
hala bazı sorunlar vardı, çünkü ADO.NET Data Services'ın kullanımı Silverlight
tarafında pek de kolay değildi. Bu gelişmeleri takiben .NET RIA Services aslında
ADO.NET Data Services üzerine oturarak bu altyapının Silverlight ile rahatlıkla
konuşabilmesini sağladı. Validasyon kodlarının hem sunucu hem istemci tarafında iki defa
yazılması gibi sorunları belirli senaryolarda gidererek .NET RIA Services şu anda
July Preview sürümü ile indirilebilir durumda. Daha Release olmamış
(yayınlanmamış) bir ürün olduğunun altını çizerek devam edelim.
RIA Services'ın development sürecinde bir çok avantajı var. Bunlardan ilki
artık sunucu tarafındaki uygulamanız ile istemci tarafındaki uygulamanızın tek
bir uygulama gibi gözükmesi. İlk bakışta çok garip geleceğinin farkındayım fakat
artık istemci tarafındaki Silverlight uygulamanızdan sunucuya anında
ulaşabiliyorsunuz, herhangi bir şekilde service reference eklemeniz vs
gerekmiyor. Tabi tüm bu işlemleri biz yapmıyorsak bizim yerimize birileri
yapıyor demektir ki bu durumda Visual Studio yardımımıza koşuyor ve otomatik
olarak sunucu ile istemci taraflarını birbiri ile konuşturacak ek kodları
yaratıyor. Ayrıca RIA Services tarafında da bulunan bazı sınıflar tabi ki
kullanılıyor. Validasyonla ilgili tüm sunucu
taraflı tanımlamalar otomatik olarak istemci tarafına da derleme zamanında
ekleniyor. Tüm bu kolaylıkları görmek için gelin yeni bir Silverlight projesi
yaratalım.

RIA Services kullanacağız.
Yeni bir Silverlight projesi yaratırken karşınıza çıkan ilk ekranda projeye
bir ASP.NET Web Sitesi eklediğimiz gibi bir de "Enable .NET RIA Services"
checkbox'ını işaretlememiz gerekiyor. Böylece gerekli referanslar alınacak ve
ayarlar yapılacaktır. Yapılan ayarlardan ve altyapının çalışma şeklinden detaylı
olarak bahsedeceğiz. Yeni projeyi yarattıktan sonra hızlı bir şekilde projenize
bir "LINQ2SQL" dosyası ekleyip veritabanından da istediğiniz
bir tabloyu kullanabilirsiniz. Tabi tüm bunları ASP.NET tarafında yapıyoruz.
Sunucu tarafında DAL (Data Access Layer) olarak LINQ2SQL'imiz hazır olduğuna
göre bir sonraki adımda servis katmanını hazırlamamız gerekecek. Yani bir
şekilde bu veritabanındaki tabloları Silverlight tarafına aktaracak olan katmanı
yaratmalıyız. Bunun için ASP.NET tarafında projenize "Domain Service
Class" türünde yeni bir dosya ekleyebilirsiniz.

DomainServiceClass ile sunucudan istemciye bağlantı sağlıyoruz.
Domain Service Class eklediğiniz anda karşınıza yukarıdaki ekran gelecektir.
Burada "Enable Client Access" zaten seçili olacaktır. Eğer bu seçenecek seçili
olmaz ise tabi ki Silverlight'ın bu servise ulaşması mümkün olmaz. Sonrasında
hemen alt basamakta kullanacağınız DAL'ı seçiyorsunuz. Bizim projemizde bir
LINQ2SQL dosyası bulunduğuna göre onu seçebiliriz. Seçtiğiniz veri kaynağına
göre Entity'lerin listesi alt tarafa gelecektir. Buradan da hangi Entity'leri
istemciye açmak istiyorsanız onu seçebilirsiniz. Eğer bu Entity'ler aracılığı
ile veri üzerinde değişiklik yapılacaksa "Enable Editin" checkbox'ını
işaretlemeyi de unutmamanızda fayda var. Son olarak en altta yer alan "Generate
associated classes for metadata" kısmı ise her sınıfın propertylerine metadata
tanımlanabilmesini sağlayacak ek sınıfları yaratacak kodun otomatik olarak
yaratılıp yaratılmaması ile ilgili. Bu konuya ileride detaylıca değineceğiz
fakat şimdilik bilmemiz gereken şey şu; eğer sunucu taraflı validasyon kodları
yaazacaksan ve bu kodların otomatik olarak istemciye de taşınmasını istiyorsak
kesinlikle bu seçenek işaretli kalmalı.
[VB]
<EnableClientAccess()> _
Public Class DomainService1
Inherits LinqToSqlDomainService(Of DataClasses1DataContext)
Public Function GetInsans() As IQueryable(Of Insan)
Return Me.Context.Insans
End Function
Public Sub InsertInsan(ByVal insan As Insan)
Me.Context.Insans.InsertOnSubmit(insan)
End Sub
Public Sub UpdateInsan(ByVal currentInsan As Insan)
Me.Context.Insans.Attach(currentInsan, Me.ChangeSet.GetOriginal(currentInsan))
End Sub
Public Sub DeleteInsan(ByVal insan As Insan)
Me.Context.Insans.Attach(insan)
Me.Context.Insans.DeleteOnSubmit(insan)
End Sub
End Class
Domain Service Class'ı eklediğiniz gibi projenizde
DomainService1.vb/cs adında bir dosya göreceksiniz. Bu dosya içerisinde
kodlar yukarıdaki gibi olacaktır. Görüldüğü üzere yaratılan DomainService
doğrudan LinqToSqlDomainService'den türetilmiş hatta türetilirken de DAL olarak
LINQ2SQL sınıfımızın gösterilmiş. DomainService içerisinde Insert, Update,
Delete işlemlerini yapan metodlar ve bu metodlar içerisinde de aslında LINQ2SQL
Context'i kullanan kodlar var. GetInsans adındaki metod ise doğrudan SQL'deki
tüm insanları döndürüyor.
Bu noktaya kadar yaptığımız şey iki tıklama ile DAL kısmını çözmek sonrasında
da servis katmanı için de bir DomainService eklemek oldu. Daha bir satır kod
bile yazmadık. Şimdi ilginç bir sürpriz ile karşılaşmak için Silverlight
tarafına geçip Page.XAML arkasındaki VB/CS dosyasını açıyoruz.

Sunucu ve istemci arası iletişim.
Yukarıda gördüğünüz manzaradan da anlaşılabileceği üzere bir anda sunucu
tarafındaki ASP.NET projemizin namespace'ine istemcide ulaşır hale geldik. Bunun
çalışabilmesi için herhangi bir şekilde web servisi eklememiz vs gerekmedi. Aynı
şekilde bu namespace altından sunucu tarafındaki DomainService'e
de rahatlıkla ulaşabileceğiz hatta sunucu tarafında yapılan değişiklikler de
istemci tarafında development zamanında Visual Studio tarafından yansıtılacak.
Peki basit bir şekilde sunucudan tüm insanların bilgilerini çekmek istersek ne
yapabiliriz? Deneme amaçlı olarak XAML tarafında sayfanıza adı myGrid olan
bir Grid yerleştirdikten sonra aşağıdaki kod örneğinden
faydalanabiliriz.
[C#]
void MainPage_Loaded(object sender, RoutedEventArgs e)
{
DomainService1 Servis = new DomainService1();
System.Windows.Ria.Data.LoadOperation Yukleme = Servis.Load(Servis.GetInsansQuery());
Yukleme.Completed += new EventHandler(Yukleme_Completed);
}
void Yukleme_Completed(object sender, EventArgs e)
{
myGrid.ItemsSource = ((System.Windows.Ria.Data.LoadOperation<Insan>)sender).Entities;
}
Örneğimizde hemen UserControl load olduğu gibi DomainService1 adında, aslında
sunucu tarafındaki yarattığımız DomainService nesnemizden bir kopya alıyoruz. Ne
de olsa bu nesne otomatik olarak istemci tarafına taşındı. Not olarak bu nesneyi
SilverlightApplication1.Web altında bulabileceğinizi o nedenle
using ile söz konusu sınıfı eklemeyi unutmamakta fayda var. Söz
konusu DomainService'den bir kopya aldıktan sonra yükleme işlemini başlatmak
üzere bir LoadOperation nesnesi tanımlıyoruz. Bu LoadOperation
nesnesine de Servis üzerinden bir Load operasyonu yaratım aktarmamız gerekiyor.
Bizim zaten tüm insanların bilgisini getirecek olan sunucu tarafında bir
sorgumuz vardı. Onu kullanabilmek için doğrudan Servis
üzerinden GetInsansQuery dememiz yeterli oluyor. Aslına
bakarsanız GetInsansQuery bize sorgulanabilir bir insan listesi
tanımı getirmekle mükellef. Bir sonraki adımda biraz daha detaylara gireceğiz.
Yükleme işlemimiz hazır olduğuna göre hemen yüklememizin Completed event'ını da
yakalamakta fayda var. Completed event'ının sender'ı malum
bizim LoadOperation'ın ta kendisi. Geriye Insan
nesnesi döneceğini bildiğimiz için uygun casting işlemini de yapıp hemen
operasyon tarafından döndürülen Entities dizisini alıp
gridimize bağlayabiliyoruz.
[C#]
void MainPage_Loaded(object sender,
RoutedEventArgs e)
{
DomainService1 Servis =
new DomainService1();
System.Windows.Ria.Data.LoadOperation Yukleme = Servis.Load(from inc in Servis.GetInsansQuery()
where inc.Adi.Contains("A") select inc);
Yukleme.Completed +=
new EventHandler(Yukleme_Completed);
}
void Yukleme_Completed(object sender,
EventArgs e)
{
myGrid.ItemsSource = ((System.Windows.Ria.Data.LoadOperation<Insan>)sender).Entities;
}
RIA Services'ın esas esnek taraflarından biri de doğrudan istemciden
istediğimiz sorguyu sunucuya gönderebiliyor olmamız. Tabi bu noktada itiraf
etmem gerek ki kullanılabilecek keyword'lerde ADO.NET Data Services mimarisi
gereği bazı sınırlar var fakat genel kullanımda pek sorun yaşanacağını
sanmıyorum. Eğer çok kompleks sorgular düşünüyorsanız bunları sunucu tarafında
ayrı metodlar olarak tanımlamak gerekecektir. Fakat basit bir where
sorgusu gibi sorgularınızın çoğunu yukarıdaki şekilde doğrudan istemciden
sunucuya gönderebilirsiniz.
Yukarıdaki kod içerisinde değişen tek şey bizim LoadOperation'ın yaratılırken
aldığı parametre. Artık sadece bir GetInsansQuery değil de söz konusu Query ile
dönen nesne tanımını tekrar sorgulayan bir yapı tanımlıyoruz. Burada aklınıza
takılabilecek nokta; "Acaba tüm veriyi istemciye alıp orada mı sorguluyor?"
olabilir. Tabi ki hayır! :)

Sorgumuz nereye nasıl gidiyor?
Ekran görüntüsünde inceleyebileceğiniz rapor hazırladığımız Silverlight
uygulaması çalıştırıldığında sunucumuza giden istekleri listeliyor. İsteklerin
en sonunda ClientBin altında DataService.axd
adında bir yere talep gönderildiğini görebiliyoruz. Bu talebin tam yolunu
incelersek aslında bizim sorgunun da orada bulunduğunu görebilirsiniz. Bu da şu
anlama geliyor; sorgu doğrudan sunucuya URL üzerinden gönderilmiş durumda.

SQL Profile'a baktık, sorgu orada!
Aynı şekilde SQL Profile ile SQL'e giden isteklere baktığımızda da bizim taaa
:) Silverlight'tan gönderdiğimiz LINQ sorgusunun ASP.NET tarafından da algılanıp
bir SQL sorgusuna çevrilerek parametremiz ile SQL'e gönderildiğini
görebiliyoruz. Sanırım yeterince başarılı :)
Insert, Delete, Update nasıl yapılır?
.NET RIA Services tarafındaki operasyonların çoğu LINQ2SQL operasyonlarına
benziyor. Yeni bir kayıt eklemek için ilk olarak söz konusu kayda ait Entity'den
bir kopya alarak veriyi doldurmanız sonrasında da DomainService üzerinden uygun
listeye eklemeniz yeterli.
[C#]
DomainService1 Servis = new DomainService1();
Servis.Insans.Add(new Insan() { Adi = "Denek", Soyadi = "denek2", Dogum=DateTime.Now, Tip=1 });
Servis.SubmitChanges();
Son satırda ayrıca SubmitChages metodunu çağırmamız gerekli. Aksi halde
yaptığımız değişiklikler sunucu tarafına gönderilmeyecektir. Delete işleminde
ise Servis'in bizden istediği silinecek nesnenin bir referansı oluyor. Bu
durumda örneğimizdeki Grid'de seçili nesneyi rahatlıkla silinmek üzere
aktarabiliriz.
[C#]
DomainService1 Servis = new DomainService1();
void btnTikla_Click(object sender, RoutedEventArgs e)
{
Servis.Insans.Remove((Insan)myGrid.SelectedItem);
Servis.SubmitChanges();
}
Kod örneğindeki gibi servis üzerinden Insans listesinden Grid'deki seçili
Insan nesnesini kaldırdıktan sonra tekrar SubmitChanges ile
gerekli değişikliklerin sunucu tarafına yansıtılmasını sağlıyoruz. Aynı şekilde
Entity'ler üzerinde yaptığımız değişiklikler de sunucu tarafına birer Update
komutu ile yansıtılacaktır.
[C#]
DomainService1 Servis = new DomainService1();
void btnTikla_Click(object sender, RoutedEventArgs e)
{
Insan Degisecek = (Insan)myGrid.SelectedItem;
Degisecek.Adi = "Deneme83";
Servis.SubmitChanges();
}
Yukarıdaki kod Grid'de seçili nesneyi alıp adını değiştirip değişikliklerin
sunucu tarafına gönderilmesi için de SubmitChanges metodunu
çağırarak işlemi tamamlıyor. Zaten Grid içerisinde bir nesne aldığımız için bu
değişiklik görsel olarak kullanıcıya da anında yansıyacaktır. Bir diğer güzellik
ise aslında Grid'imize aktardığımız verinin zaten servisimiz ile sürekli
bağlantı içerisinde olması. Yani biz ilk aşamada verimizi Grid'e bağladıktan
sonra kullanıcının yaptığı tüm değişiklikleri otomatik olarak sunucuya göndermek
istersek aslında sadece servisin SubmitChanges metodunu çağırmamız yeterli
olacaktır. Böylece zaten tüm değişikliker sunucuya gönderilecektir.
Önemli Uyarı!
Silverlight ile uygulama geliştirmeyi çok kolaylaştıran bir yapı olarak RIA
Services eminim ki sizleri heyecanlandıracaktır fakat unutmamak gerek ki ürün
daha yayınlanmış değil ve Preview aşamasında. Çıkacak yeni Preview'larda çok şey
değişebilir. O nedenle bu sistem üzerine yapacağınız yatırımlarda dikkatli olup
bu risklerin bilincinde olmak önemli.
Hepinize kolay gelsin.