.NET RIA Services'a giriş.

0 dakikada yazıldı

7379 defa okundu

Düzenle

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.
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.
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.
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?
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!
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.