https://buraksenyurt.com/Burak Selim Şenyurt - .Net RIA Services2010-02-26T00:06:36+00:00Matematik Mühendisi Bir Bilgisayar Programcısının NotlarıBurak Selim SenyurtBlogEngine.Net Syndication Generatorhttps://buraksenyurt.com/opml.axdBurak Selim SenyurtMatematik Mühendisi Bir Bilgisayar Programcısının Notlarıtr-TRBurak Selim Şenyurt0.0000000.000000https://buraksenyurt.com/post/Net-RIA-Servisleri-Ozel-Dogrulama(Custom-Validation).Net RIA Servisleri - Özel Doğrulama(Custom Validation)2009-05-31T04:03:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bir önceki blog yazımızda, .Net RIA Servislerin kullanıldığı Silverlight uygulamalarında doğrulama(Validation) işlemlerinin nasıl yapılabileceğini incelemeye çalışmıştık. Bu yazımızda ise, <strong>Range, Required, StringLength, RegularExpression</strong> gibi built-in niteliklerle(attribute) gerçekleştirilen doğrulamalar haricinde kalan özel durumlar için nasıl ilerleyebileceğimizi araştıracağız. Konuyu adım adım irdelersek, aşağıdaki işlemleri yapmamız gerekmektedir.</p>
<ul>
<li>Sunucu uygulama tarafında(Web App) shared niteliği ile işaretlenmiş bir sınıf tasarlanır ve içerisine özel doğrulama operasyonları ilave edilir.</li>
<li>Özel doğrulamaların uygulanacağı sınıf veya üyelerine, CustomValidation niteliği yardımıyla geliştirilen Validator tipi bildirilir.</li>
</ul>
<p>Gördüğünüz gibi gayet basit. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> Önceki blog yazımızda geliştirdiğimiz örnek proje için bu adımları uygulamaya başlayabiliriz. Örnek olarak <strong>ProductName</strong> alanı için özel bir doğrulama fonksiyonelliği geliştireceğiz. Bu doğrulamaya göre, ProductName ile ilişkili veri giriş alanı içerisinde <strong>Select, Where, Delete</strong> gibi <strong>SQL </strong>kelimelerinin olmamasını sağlamaya çalışacağız. Bu tabiki konunun anlaşılması için öne sürdüğümüz bir senaryo. Şu an için önemli olan, tekniğin nasıl uygulandığıdır. Bu amaçla web projesi tarafında <strong>ProductNameValidator.shared.cs </strong>isimli bir kod dosyası oluşturarak işe başlayabiliriz. Bu kod dosyasının adında <strong>shared</strong> kelimesinin eklenmesinin geliştirme ortamı(IDE) içinde özel bir anlamı vardır. <strong>SınıfAdı.shared.cs/vb </strong>formatında yazılan dosya adı sayesinde, istemci tarafı içinde otomatik kod üretiminin gerçekleştirilmesi sağlanmış olmaktadır.</p>
<p>Söz konusu sınıfın kod içeriği ise aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.ComponentModel.DataAnnotations;
using System.Web.Ria.Data;
// Dosya adında shared kullanılmasının bir nedeni vardır. Bu isimlendirme standardı sayesinde, derleme zamanı alt yapısının istemci tarafı için otomatik dosya üretimi gerçekleştirmesi sağlanmış olunur.
namespace ValidationSystem.Web
{
[Shared]
public static class ProductNameValidator
{
public static bool QueryCheck(string productName, ValidationContext context, out ValidationResult result)
{
// sembolik olarak eklenmiş kontrol değerleri
string[] keywords = { "Select", "Where", "Delete", "Create" };
// ürün adının, yasaklı kelimelerden herhangibirini içerip içermediğine bakılır.
foreach (string keyword in keywords)
{
// Bir tane bile içeriyorsa, ValidationResult nesne örneği oluşturulurken hata mesajı bildirimi yapılır ve geriye false değer döndürülür
if (productName.Contains(keyword))
{
result = new ValidationResult("Tehlikeli kelimeler yer almakta");
return false;
}
}
// Eğer doğrulama işlemi başarılıysa ValidationResult nesne örneğine null değer atanır ve geriye true değer döndürülür
result = null;
return true;
}
}
}</pre>
<p><strong>Static</strong> olarak tanımlanan sınıfın <strong>shared </strong>niteliği ile imzalandığına dikkat edilmelidir. Diğer taraftan doğrulama işlemi için kullanılacak olan metod(metodlar), ilk parametre olarak doğrulanacak veri içeriğini taşıyabilecek tipte bir değişken kullanırlar. ProductName alanı tablo üzerinde <strong>nvarchar </strong>tipinden tanımlanmış ve bu nedenle <strong>Entity</strong> içerisinde <strong>string </strong>olarak ele alınmıştır. Dolayısıyla ilk parametrenin string tipinden tasarlanmış olması doğru bir tercihtir. Diğer taraftan ikinci parametre olarak <strong>ValidationContext </strong>ve üçüncü parametre olarakta <strong>ValidationResult </strong>tiplerinden değişkenler tanımlanmıştır. Her ne kadar örneğimizde <strong>ValidationContext</strong> parametresini kullanmamış olsakta, çalışma zamanında doğrulamaya tabi olan içeriğin sahibi tipe ait bilgileri içerdiğini söyleyebiliriz. Dolayısıyla bu değişken ile, doğrulamaya tabi olan ProductName değerine sahip Products nesne örneğine ulaşabilir ve doğrulamayı farklı açılardan ele alabiliriz. Aşağıdaki ekran görüntüsünde bu durum daha net bir şekilde görülebilmektedir.</p>
<p><img src="/pics/2009%2f5%2fblg25_1.gif" alt="" /></p>
<p>Gelelim <strong>ValidationResult</strong> tipine. Sonuç olarak doğrulamanın <span style="text-decoration: underline;">başarılı</span> veya <span style="text-decoration: underline;">başarısız </span>olma durumu söz konusudur. Başarısız olunması halinde, istemci tarafında hata mesajı gibi bilgileri içeren bir nesne örneğinin var olması gerekmektedir. İşte <strong>ValidationResult </strong>nesne örneğinin üretilmesi ile, doğrulamanın başarısız olması durumunda geriye nasıl bir bilgi döndürüleceği belirtilmektedir. Tabi metodun böyle bir durumda geriye <strong>false</strong> değer döndürmeside gerekmektedir. Elbetteki doğrulama işleminin başarılı olması halinde geriye <strong>true</strong> değer döndürülmesi ve ayrıca <strong>ValidationResult</strong> nesne örneğinin <strong>null</strong> olarak aktarılması sağlanmalıdır.</p>
<p>Sırada ikinci adım var. Geliştirilen bu doğrulama tipinin, çalışma zamanı tarafından ele alınması gerekmektedir. Tabiki hal böyle olunca devreye <strong>niteliklerin(attribute)</strong> girmeside kaçınılmazdır. Neyseki kendi niteliklerimizi yazmak yerine, herhangibir <strong>validator</strong> tipini, istediğimiz özellik veya sınıfa uygulamamızı sağlayan tek bir <strong>built-in</strong> nitelik mevcuttur. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /> <strong>CustomValidation</strong>. Dolayısıyla metadata dosyası içerisinde, <strong>ProductName</strong> özelliğinin aşağıdaki hale getirilmesi yeterli olacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">[Required(ErrorMessage="Lütfen ürün adını giriniz")]
[CustomValidation(typeof(ProductNameValidator),"QueryCheck")]
public string ProductName;</pre>
<p><strong>CustomValidation</strong> niteliği ilk parametre olarak doğrulama tipini almaktadır. İkinci parametrede ise, takip öden özelliğin(veya sınıfın) kontrolünü gerçekleştirecek olan metod adı belirtilmektedir. Uygulama bu son haliyle derlendiğinde, istemci projesindede aşağıdaki şekilde görülen ek dosyanında üretildiği gözlemlenebilir.</p>
<p><img src="/pics/2009%2f5%2fblg25_2.gif" alt="" /></p>
<p>Artık uygulamayı test etmeye başlayabiliriz. Bu amaçla herhangibir ürünün güncellenmeye çalışıldığını düşünelim ve ürün adında <strong>Delete</strong> kelimesini kullandığımızı varsayalım. İşte sonuç...</p>
<p><img src="/pics/2009%2f5%2fblg25_3.gif" alt="" /></p>
<p>Tataaaa!!! <img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /> Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fValidationSystem2.rar">ValidationSystem2.rar (1,86 mb)</a></p>2009-05-31T04:03:00+00:00.net ria servicessilverlightbsenyurtir önceki blog yazımızda, .Net RIA Servislerin kullanıldığı Silverlight uygulamalarında doğrulama(Validation) işlemlerinin nasıl yapılabileceğini incelemeye çalışmıştık. Bu yazımızda ise, Range, Required, StringLength, RegularExpression gibi built-in niteliklerle(attribute) gerçekleştirilen doğrulamalar haricinde kalan özel durumlar için nasıl ilerleyebileceğimizi araştıracağız. Konuyu adım adım irdelersek, aşağıdaki işlemleri yapmamız gerekmektedir.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=f65b28e3-5cf6-43ea-9732-794e9fc2b6383https://buraksenyurt.com/trackback.axd?id=f65b28e3-5cf6-43ea-9732-794e9fc2b638https://buraksenyurt.com/post/Net-RIA-Servisleri-Ozel-Dogrulama(Custom-Validation)#commenthttps://buraksenyurt.com/syndication.axd?post=f65b28e3-5cf6-43ea-9732-794e9fc2b638https://buraksenyurt.com/post/Net-RIA-Servisleri-DomainDataSource-Kulanc4b1mc4b1.Net RIA Servisleri - DomainDataSource Kulanımı2009-05-14T12:30:00+00:00bsenyurt<p><img style="float: right;" src="/pics/2009%2f5%2fblg17_4.jpg" alt="" />Merhaba Arkadaşlar,</p>
<p>Her ne kadar şu günlerde güzel ülkemizin <strong>Ege </strong>kıyılarında kısa bir dinlenme molası vermiş olsamda, internetin sahil kıyılarındaki cafe' lere kadar girmiş olması, herşeyi değiştiriyor. <img title="Cool" src="/editors/tiny_mce3/plugins/emotions/img/smiley-cool.gif" alt="Cool" border="0" /> Artık bir yaşam tarzı haline gelen Yazılımdan, onun gizemli dünyasından uzak durmak bu nedenle, şu sıralar aşağıdaki şekilde görülen yerde tatilde bile olsam çok zor.</p>
<p>Bu kısa yazımda sizlere yine <strong>.Net RIA Servisleri </strong>ile ilişkili bilgilerimi aktarmaya gayret edeceğim. Bu seferki konumuz <strong>DomainDataSource </strong>isimli <strong>Silverlight </strong>kontrolü. Kontrolün adında yer alan <strong>DataSource </strong>son eki aslında olayı biraz olsun açıklamakta. .Net RIA Servislerinin kullanıldığı senaryolarda, sunucu tarafında mutlaka bir veri kaynağı yer almaktadır. Ağırlık olarak <strong>Ado.Net Entity Framework </strong>veya <strong>LINQ to SQL </strong>tabanlı sağlayıcılar ile eriştiğimiz bu veri kaynaklarını, istemci tarafında değiştirmek gibi işlemlerle uğraştığımızda bir gerçektir. Kısacası, istemci tarafına çekilen verinin sadece gösterilmesi dışında, düzenlenmesi, yenilerinin eklenmesi veya var olanların silinmesi gibi operasyonlar söz konusudur. Bunlara ek olarak, <strong>Silverlight </strong>tabanlı istemci tarafını düşündüğümüzde, verinin kullanıcı ile etkileşimde olan kontrollerde gösterilmeside bu işin önemli kısımlarından birisidir.</p>
<p>Tam bu noktada aklıma Asp.Net 2.0 ile birlikte gelen <strong>veri-bağlı kontrolleri(Data-Bound Controls)</strong> geliyor. <strong>SqlDataSource</strong>, <strong>ObjectDataSource</strong>, <strong>SiteMapDataSource </strong>vb...Bu kontrollerin en büyük amacı, sayfa üzerindeki sunucu kontrollerini, veri kaynağını bağlamaktır. <strong>SqlDataSource</strong> gibi kontroller sayesinde bu bağlama işlemleri ile birlikte,<strong> Insert, Update </strong>ve <strong>Delete </strong>operasyonlarına hizmet edecek kod parçalarının kolay bir şekilde geliştirilmesi ve ele alınmasıda mümkün olmaktadır. Şu anda bulunduğumuz noktayı düşündüğümüzde, .Net RIA Servislerini kullanan Silverlight istemcileri içinde benzer bir kolaylığın sağlanması önemlidir. Öyleyse bu kontrol nasıl kullanılır, tam olarak ne işe yarar hemen bir bakalım.</p>
<p>Örnek Silverlight Projemizde bu kez Northwind veri kaynağına <strong>Ado.Net Entity Framework </strong>öğesi yardımıyla bağlanıyor olacağız. Yine bir önceki blog yazımızda olduğu gibi <strong>Categories </strong>tablosunu ve ek olarak <strong>Products</strong> tablosunu kullanabiliriz. İstemci tarafında, Insert, Update ve Delete gibi işlemleride ele alma ihtimalimiz olduğundan(en azından sonraki blog yazılarımda), <strong>DomainService</strong> tipinin eklenmesi sırasında, her iki <strong>Entity</strong> tipi içinde <strong>Enable Editing</strong> özelliğinin işaretli olduğuna dikkat etmemiz gerekmektedir. Gelelim kullanacağımız <strong>DomainDataSource</strong> bileşenine. Bu bileşen varsayılan olarak <strong>Silverlight</strong> kontrol sekmesinde görünmemektedir. Dolayısıyla söz konusu kontrolün, .Net RIA Service sisteme yüklendikten sonra <strong>Visual Studio 2008</strong> ortamında kullanılabilmesi için <strong>Toolbox' </strong>a <strong>Silverlight Components </strong>kısmından eklenmesi gerekir.</p>
<p><img src="/pics/2009%2f5%2fblg17_1.gif" alt="" /></p>
<p><strong>DataSource</strong> bileşenleri genellikle veri-bağlı kontroller ile kullanılırlar. <strong>DomainDataSource</strong> kontrolünü bu anlamda, <strong>DataGrid</strong> bileşeni ile etkileştirebiliriz. <strong>XAML</strong> içeriğimizin ilk halini aslında aşağıdaki gibi tasarladım.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><UserControl xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="DomainDS.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ds="clr-namespace:DomainDS.Web"
Width="500" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<riaControls:DomainDataSource x:Name="dsProducts" AutoLoad="True" LoadSize="10" LoadMethodName="LoadProducts">
<riaControls:DomainDataSource.DomainContext>
<ds:NorthwindContext/>
</riaControls:DomainDataSource.DomainContext>
</riaControls:DomainDataSource>
<data:DataGrid x:Name="dgProducts" Height="Auto" Background="BlanchedAlmond" ItemsSource="{Binding Data, ElementName=dsProducts}"/>
</Grid>
</UserControl></pre>
<p>Şimdi bu XAML içeriğinde, üzerinde durulması gereken önemli noktalar olduğu aşikardır. Öncelikli olarak <strong>DataGrid</strong> veya <strong>DomainDataSouce</strong> kontrollerini kullanabilmemiz için gerekli <strong>assembly</strong> veya isim alanları(Namespaces), ilgili bileşenleri <strong>XAML</strong> içerisine <span style="text-decoration: underline;">sürüklediğimizde</span>, eğer gerekiyorsa projeye otomatik olarak dahil edileceklerdir. <strong>riaControls</strong> ön eki ile eklenen <strong>DomainDataSource</strong> elementi içerisinde kullanılan bazı nitelik verileri dikkate değerdir.</p>
<p><strong>LoadSize</strong> niteliğine atanan değer, Silverlight uygulaması ilk yüklendiğinde çekilecek olan satır sayısını belirtmektedir. Gerçektende, uygulama bu haliyle çalıştırıldığında, <strong>SQL Server Profiler </strong>aracından yakalanan sorgu cümlesi aşağıdaki gibidir.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">SELECT
[Limit1].[C1] AS [C1],
[Limit1].[ProductID] AS [ProductID],
[Limit1].[ProductName] AS [ProductName],
[Limit1].[SupplierID] AS [SupplierID],
[Limit1].[QuantityPerUnit] AS [QuantityPerUnit],
[Limit1].[UnitPrice] AS [UnitPrice],
[Limit1].[UnitsInStock] AS [UnitsInStock],
[Limit1].[UnitsOnOrder] AS [UnitsOnOrder],
[Limit1].[ReorderLevel] AS [ReorderLevel],
[Limit1].[Discontinued] AS [Discontinued],
[Limit1].[CategoryID] AS [CategoryID]
FROM ( SELECT TOP (10)
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[SupplierID] AS [SupplierID],
[Extent1].[CategoryID] AS [CategoryID],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
1 AS [C1]
FROM [dbo].[Products] AS [Extent1]
) AS [Limit1]</pre>
<p>Sanıyorumki <strong>SELECT TOP (10)</strong> ifadesi sizlerin dikkatinizden kaçmamıştır. Ancak <strong>LoadSize</strong> niteliği kaldırılırsa bu durumda SQL tarafında aşağıdaki sorgunun çalıştırıldığı görülecektir.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">SELECT
1 AS [C1],
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[SupplierID] AS [SupplierID],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
[Extent1].[CategoryID] AS [CategoryID]
FROM [dbo].[Products] AS [Extent1]</pre>
<p>Bu kez tüm Products tablosunun içeriği seçilmektedir. <strong>LoadSize</strong> özelliğini kullanarak, Silverlight uygulamasının ilk açılışı sırasındaki veri kümesinin yoğunluğunu kontrol altına alabilir ve performansı doğudan etkileyebiliriz. Burada dikkat çeken bir diğer önemli nitelik ise <strong>LoadMethodName </strong>niteliğine atanan değerdir. Bu değer, istemci tarafında kullanılan <strong>DomainContext</strong> tipinin içerisinde yer alan yükleme metodunun kendisidir. Örneğimizde bu metod <strong>LoadCategories</strong> isimli fonksiyondur. Ancak fonksiyon adı text tabanlı olarak yazılmaktadır. Peki, <strong>DomainDataSource</strong> bileşeni, hangi <strong>DataContext</strong> nesne örneği içerisindeki <strong>LoadCategories</strong> metodunu kullanacağını nasıl bilecektir? <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Bu sorunun cevabı, <strong>DomainDataSource.DomainContext </strong>elementi içerisinde verilmektedir. Bu kısımda, <strong>ds </strong>ön ekli <strong>namespace </strong>üzerinden <strong>NorthwindContext </strong>isimli <strong>DomainContext </strong>nesne referansının tanımlaması yapılmaktadır. Böylece, DomainDataSource bileşeninin kullanacağı DomainContext nesne örneği belirlenmiş olur.</p>
<p>DataGrid bileşeninin söz konusu <strong>DomainDataSource</strong> kontrolüne bağlanması içinse, <strong>ItemsSource </strong>niteliğine ilgili değerin atanması yeterlidir. (İtiraf etmeliyim ki, ItemsSource niteliğine atanan değerin yazım stilini, ne kadar dekleratif olsada halen ezbere yazamamaktayım <img title="Embarassed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-embarassed.gif" alt="Embarassed" border="0" /> ) Uygulamayı bu haliyle çalıştırdığımızda aşağıdaki ekran görüntüsü ile karşılaşmamız son derece muhtemeldir.</p>
<p><img src="/pics/2009%2f5%2fblg17_2.gif" alt="" /></p>
<p>Burada önemli olan noktalardan birisi, tanımlamalarım tamamen dekleratif olarak yapılmış olması ve geliştiricinin herhangibir kodlama yapmamış olmasıdır. Daha önceki blog yazılarımda yer alan örnekler göz önüne aldığımızda, CRUD operasyonları için istemci tarafında bazı kodlamalar yaptığımız ortadadır. Şimdi XAML içeriğimizi biraz daha zengineştirmeye çalışalım. Örneğin, sıralama kriteri ekleyebiliriz. Bunun için <strong>SortDescriptor</strong> elementinin kullanılması gerekmektedir. Bu element, <strong>System.Windows.Ria.Controls.dll assembly'</strong> ı içerisinde yer aldığında, isim alanının XAML içeriğinde bildirilmesi gerekir. Bu şekilde başlayan düzenlemelerin son hali aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false"><UserControl xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="DomainDS.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ds="clr-namespace:DomainDS.Web"
xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Ria.Controls"
Width="500" Height="300">
<Grid x:Name="LayoutRoot" Background="White">
<riaControls:DomainDataSource x:Name="dsProducts" AutoLoad="True" LoadSize="40" LoadMethodName="LoadProducts">
<riaControls:DomainDataSource.DomainContext>
<ds:NorthwindContext/>
</riaControls:DomainDataSource.DomainContext>
<riaControls:DomainDataSource.SortDescriptors>
<riaData:SortDescriptor Direction="Descending" PropertyPath="UnitPrice"/>
</riaControls:DomainDataSource.SortDescriptors>
</riaControls:DomainDataSource>
<data:DataGrid x:Name="dgProducts" Height="Auto" Background="BlanchedAlmond" ItemsSource="{Binding Data, ElementName=dsProducts}"/>
</Grid>
</UserControl></pre>
<p><strong>SortDescription</strong> elementi içerisinde yer alan <strong>Direction</strong> niteliğine atanan değer ile sıralamanın yönü belirtilmektedir. Diğer taraftan <strong>PropertyPath</strong> niteliğine atanan değer ilede hangi alana göre sıralama yapılacağına karar verilir. Bu ayarlamalara göre Products tablosundan ilk yüklemede <strong>40</strong> adet ürün bilgisi, <strong>UnitPrice</strong> değerlerine göre <span style="text-decoration: underline;">ters sırada</span> çekilecektir. Nitekim SQL tarafında çalıştırılan sorguya bakıldığında aşağıdaki cümlenin çalıştırıldığı kolayca tespit edilebilir.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">SELECT TOP (40)
[Project1].[C1] AS [C1],
[Project1].[ProductID] AS [ProductID],
[Project1].[ProductName] AS [ProductName],
[Project1].[SupplierID] AS [SupplierID],
[Project1].[QuantityPerUnit] AS [QuantityPerUnit],
[Project1].[UnitPrice] AS [UnitPrice],
[Project1].[UnitsInStock] AS [UnitsInStock],
[Project1].[UnitsOnOrder] AS [UnitsOnOrder],
[Project1].[ReorderLevel] AS [ReorderLevel],
[Project1].[Discontinued] AS [Discontinued],
[Project1].[CategoryID] AS [CategoryID]
FROM ( SELECT [Project1].[ProductID] AS [ProductID], [Project1].[ProductName] AS [ProductName], [Project1].[SupplierID] AS [SupplierID], [Project1].[CategoryID] AS [CategoryID], [Project1].[QuantityPerUnit] AS [QuantityPerUnit], [Project1].[UnitPrice] AS [UnitPrice], [Project1].[UnitsInStock] AS [UnitsInStock], [Project1].[UnitsOnOrder] AS [UnitsOnOrder], [Project1].[ReorderLevel] AS [ReorderLevel], [Project1].[Discontinued] AS [Discontinued], [Project1].[C1] AS [C1], row_number() OVER (ORDER BY [Project1].[UnitPrice] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[SupplierID] AS [SupplierID],
[Extent1].[CategoryID] AS [CategoryID],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
1 AS [C1]
FROM [dbo].[Products] AS [Extent1]
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 40
ORDER BY [Project1].[UnitPrice] DESC</pre>
<p>Oldukça kolay gördüğünüz gibi. <strong>.Net RIA Servislerini</strong> sisteme yüklediğimizde gelen dökümantasyon içerisinde bu tip bir örnek yapılmaktadır. İlerleyen kısımlarında, verinin çekilmesi işlemi sırasında kullanılabilecek <strong>sayfalama(Paging) ve filtreleme(Filtering) </strong>seçenekleride örneğe dahil edilmektedir. Size tavsiyem söz konusu dökümantasyonda yer alan örneği incelemeniz olacaktır.</p>
<p>Ben yazımı sonlandırmadan önce sayfalama kriterinide <strong>XAML</strong> içeriğine dahil etmeye çalışacağım. Bu amaçla, <strong>DataPager</strong> isimli Silverlight bileşenini XAML içerisine sürüklememiz yeterli olacaktır. MainPage.xaml içeriğinin son hali aşağıdaki gibidir.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><UserControl xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm" xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Ria.Controls" xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
x:Class="DomainDS.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ds="clr-namespace:DomainDS.Web"
xmlns:riaData="clr-namespace:System.Windows.Data;assembly=System.Windows.Ria.Controls"
Width="500" Height="350">
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical">
<riaControls:DomainDataSource x:Name="dsProducts" AutoLoad="True" LoadSize="40" LoadMethodName="LoadProducts">
<riaControls:DomainDataSource.DomainContext>
<ds:NorthwindContext/>
</riaControls:DomainDataSource.DomainContext>
<riaControls:DomainDataSource.SortDescriptors>
<riaData:SortDescriptor Direction="Descending" PropertyPath="UnitPrice"/>
</riaControls:DomainDataSource.SortDescriptors>
</riaControls:DomainDataSource>
<data:DataGrid x:Name="dgProducts" Height="330" Background="BlanchedAlmond" ItemsSource="{Binding Data, ElementName=dsProducts}"/>
<dataControls:DataPager PageSize="20" Height="20" Source="{Binding Data,ElementName=dsProducts}"></dataControls:DataPager>
</StackPanel>
</UserControl></pre>
<p><strong>DataPager</strong> kontrolü doğal olarak kimi(yani hangi veri kaynağını) sayfalayacağını bilmek zorundadır. Bu nedenle <strong>Source</strong> niteliğine <strong>dsProducts</strong> isimli <strong>DomainDataSource</strong> bileşeni atanmıştır. Diğer taraftan <strong>PageSize</strong> niteliğine atanan değer ile her sayfada <strong>20</strong> adet satırın gösterileceği belirtilmektedir. Uygulamayı bu haliyle çalıştırdığımızda aşağıdakine benzer bir ekran görüntüsü ile karşılaşmamız muhtemeldir.</p>
<p><img src="/pics/2009%2f5%2fblg17_3.gif" alt="" /></p>
<p>Burada dikkat çeken noktalardan biriside <strong>LoadSize</strong> ile ilk etapta <strong>40</strong> satırın yüklenmesine rağmen, sayfalama içerisinde <strong>en çok 80 (4X20)</strong> kaydın gösterilebilecek olmasıdır. Bu aslında kayda değer ve incelenmesi gereken bir durumdur. Nitekim SQL tarafında çalıştırılan sorgu cümelelerine dikkatlice bakmak gerekmektedir. İşte eğlence başlıyor. <img title="Tongue out" src="/editors/tiny_mce3/plugins/emotions/img/smiley-tongue-out.gif" alt="Tongue out" border="0" /></p>
<p>Sayfa ilk yüklendiğinde <strong>TOP 40</strong> ile <strong>40</strong> satırlık bir veri bloğunun yüklenmesi sağlanır. <strong>PageSize</strong> değeri <strong>20</strong> olarak berlilendiğinden 1nci sayfadan 2nci sayfaya geçtiğimizde, SQL tarafında herhangibir sorgu çalıştırılmadığı gözlemlenir.(İyi bir gelişme <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" />) Ancak 3ncü sayfaya geçmek istediğimizde, 40 satırlık yükleme boyutunu geçtiğimiz için sunucu tarafında yeni bir SQL sorgusu çalıştırılacak ve<strong> row_number</strong> değeri <strong>40'</strong> ın üzerinde olanlar talep edilecektir. Aşağıdaki SQL cümlesinde görüldüğü gibi...</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">SELECT TOP (40)
[Project1].[C1] AS [C1],
[Project1].[ProductID] AS [ProductID],
[Project1].[ProductName] AS [ProductName],
[Project1].[SupplierID] AS [SupplierID],
[Project1].[QuantityPerUnit] AS [QuantityPerUnit],
[Project1].[UnitPrice] AS [UnitPrice],
[Project1].[UnitsInStock] AS [UnitsInStock],
[Project1].[UnitsOnOrder] AS [UnitsOnOrder],
[Project1].[ReorderLevel] AS [ReorderLevel],
[Project1].[Discontinued] AS [Discontinued],
[Project1].[CategoryID] AS [CategoryID]
FROM ( SELECT [Project1].[ProductID] AS [ProductID], [Project1].[ProductName] AS [ProductName], [Project1].[SupplierID] AS [SupplierID], [Project1].[CategoryID] AS [CategoryID], [Project1].[QuantityPerUnit] AS [QuantityPerUnit], [Project1].[UnitPrice] AS [UnitPrice], [Project1].[UnitsInStock] AS [UnitsInStock], [Project1].[UnitsOnOrder] AS [UnitsOnOrder], [Project1].[ReorderLevel] AS [ReorderLevel], [Project1].[Discontinued] AS [Discontinued], [Project1].[C1] AS [C1], row_number() OVER (ORDER BY [Project1].[UnitPrice] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[SupplierID] AS [SupplierID],
[Extent1].[CategoryID] AS [CategoryID],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
1 AS [C1]
FROM [dbo].[Products] AS [Extent1]
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 40
ORDER BY [Project1].[UnitPrice] DESC</pre>
<p>Ne yazıkki 20 satır veri çekilmesi gerekmesine rağmen <strong>LoadSize</strong> özelliği nedeniyle <strong>Top 40</strong> kullanımı söz konusudur. ( <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> Bu açıkçası benim pek beklediğim bir durum değildi.) Peki 4ncü sayfaya geçmek istersek ne olacaktır? Bu durumda <strong>row_number</strong> değeri <strong>60'</strong> ın (3X20 veya 3ncü sayfa X PageSize) üzerinde olan veriler çekilmeye çalışılacaktır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">SELECT TOP (40)
[Project1].[C1] AS [C1],
[Project1].[ProductID] AS [ProductID],
[Project1].[ProductName] AS [ProductName],
[Project1].[SupplierID] AS [SupplierID],
[Project1].[QuantityPerUnit] AS [QuantityPerUnit],
[Project1].[UnitPrice] AS [UnitPrice],
[Project1].[UnitsInStock] AS [UnitsInStock],
[Project1].[UnitsOnOrder] AS [UnitsOnOrder],
[Project1].[ReorderLevel] AS [ReorderLevel],
[Project1].[Discontinued] AS [Discontinued],
[Project1].[CategoryID] AS [CategoryID]
FROM ( SELECT [Project1].[ProductID] AS [ProductID], [Project1].[ProductName] AS [ProductName], [Project1].[SupplierID] AS [SupplierID], [Project1].[CategoryID] AS [CategoryID], [Project1].[QuantityPerUnit] AS [QuantityPerUnit], [Project1].[UnitPrice] AS [UnitPrice], [Project1].[UnitsInStock] AS [UnitsInStock], [Project1].[UnitsOnOrder] AS [UnitsOnOrder], [Project1].[ReorderLevel] AS [ReorderLevel], [Project1].[Discontinued] AS [Discontinued], [Project1].[C1] AS [C1], row_number() OVER (ORDER BY [Project1].[UnitPrice] DESC) AS [row_number]
FROM ( SELECT
[Extent1].[ProductID] AS [ProductID],
[Extent1].[ProductName] AS [ProductName],
[Extent1].[SupplierID] AS [SupplierID],
[Extent1].[CategoryID] AS [CategoryID],
[Extent1].[QuantityPerUnit] AS [QuantityPerUnit],
[Extent1].[UnitPrice] AS [UnitPrice],
[Extent1].[UnitsInStock] AS [UnitsInStock],
[Extent1].[UnitsOnOrder] AS [UnitsOnOrder],
[Extent1].[ReorderLevel] AS [ReorderLevel],
[Extent1].[Discontinued] AS [Discontinued],
1 AS [C1]
FROM [dbo].[Products] AS [Extent1]
) AS [Project1]
) AS [Project1]
WHERE [Project1].[row_number] > 60
ORDER BY [Project1].[UnitPrice] DESC</pre>
<p>Yinede TOP 40 oluşumu söz konusudur. Ancak istediğimiz sonuç alınmıştır. Sayfalama işlemide başarılı bir şekilde gerçekleştirilmiştir. Böylece geldik bir blog yazımızın daha sonuna. Şimdi müsadenizle biraz dinlenmeye çekileceğim. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2009-05-14T12:30:00+00:00.net ria servicessilverlightbsenyurtHer ne kadar şu günlerde güzel ülkemizin Ege kıyılarında kısa bir dinlenme molası vermiş olsamda, internetin sahil kıyılarındaki cafe' lere kadar girmiş olması, herşeyi değiştiriyor. Cool Artık bir yaşam tarzı haline gelen Yazılımdan, onun gizemli dünyasından uzak durmak bu nedenle, şu sıralar aşağıdaki şekilde görülen yerde tatilde bile olsam çok zor.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=42d0cc0a-08f1-4f2d-8008-7d5883e2b63b0https://buraksenyurt.com/trackback.axd?id=42d0cc0a-08f1-4f2d-8008-7d5883e2b63bhttps://buraksenyurt.com/post/Net-RIA-Servisleri-DomainDataSource-Kulanc4b1mc4b1#commenthttps://buraksenyurt.com/syndication.axd?post=42d0cc0a-08f1-4f2d-8008-7d5883e2b63bhttps://buraksenyurt.com/post/Net-RIA-Servisleri-CRUD-Islemleri.Net RIA Servisleri - CRUD İşlemleri2009-05-13T22:50:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Bildiğiniz gibi bir süredir .Net RIA Servisleri ile ilişkili araştırmalarıma devam etmekteyim. Bu yazımızda, .Net RIA Servislerinde <strong>Insert, Update </strong>ve <strong>Delete </strong>işlemlerini nasıl yapabileceğimizi basit bir örnek üzerinden adım adım aktarmaya çalışacağım. Daha önceki Hello World örneğimizden farklı olarak, DAL(Data Access Layer) içerisinde <strong>LINQ to SQL </strong>modelini kullanıyor olacağız. İlk adımımız elbetteki bir<strong> Silverlight Application</strong> projesi oluşturmak olmalıdır. .Net RIA Servisini kullanacağımız için, projenin oluşturulması sırasında <strong>Link to ASP.NET Server Project</strong> seçeneğinin işaretli olmasına dikkat edelim.</p>
<p>Sonrasında Web projesine bir adet<strong> LINQ to SQL</strong> öğesi eklemeli ve bağlanmak istediğimiz veri kaynağı üzerinden, kullanmak istediğimiz tablo veya stored procedure' leri diagram üzerine sürüklemeliyiz. Ben Insert, Update ve Delete işlemlerini çok basit bir şekilde ele almak istediğimdeN kullanabileceğim en kolay kobay tabloyu seçtim :) Northwind veritabanında yer alan Categories tablosu. Nitekim sadece CategoryName ve Description alanlarına veri eklemek bizim için yeterli olacaktır.</p>
<blockquote>
<p>Ancak örneği biraz daha ileri seviyede geliştirmeye çalışmanızıda şiddetle tavsiye ederim. Söz gelimi, Categories tablosunda Image tipinden Picture isimli bir alan bulunmaktadır. Bu resim alanı binary tiptedir. Bir başka deyişle Silverlight istemcisinin, kategori resmini seçip sunucu tarafına binary formatta aktarmaya çalışmasıda iyi bir mücadele antrenmanı olarak göz önüne alınabilir. Hatta resmin istemci tarafında bir kontrol içerisinde gösterilmeside söz konusu olabilir.</p>
</blockquote>
<p>LINQ to SQL diagramımızın içeriği aşağıdaki şekilde görüldüğü gibi olacaktır.</p>
<p><img src="/pics/2009%2f5%2fblg16_0.gif" alt="" /></p>
<p>Bundan sonra yapmamız gereken, DomainService tipinin eklenmesidir. Bu seferki örneğimizde, tüm CRUD operasyonuna ihtiyacımız olacağından, Categories Entity' si için, <strong>Enable Editing </strong>özelliğinin etkinleştirilmiş olması şarttır.</p>
<p><img src="/pics/2009%2f5%2fblg16_1.gif" alt="" /></p>
<p>Bu işlemlerin arkasından CategoryService isimli DomainService sınıfı içerisinde aşağıdaki fonksiyonelliklerin oluşturulduğu görülür.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace Editing.Web
{
using System.Linq;
using System.Web.DomainServices.LinqToSql;
using System.Web.Ria;
[EnableClientAccess()]
public class CategoryService : LinqToSqlDomainService<NorthwindDataContext>
{
public IQueryable<Category> GetCategories()
{
return this.Context.Categories;
}
public void InsertCategory(Category category)
{
this.Context.Categories.InsertOnSubmit(category);
}
public void UpdateCategory(Category currentCategory, Category originalCategory)
{
this.Context.Categories.Attach(currentCategory, originalCategory);
}
public void DeleteCategory(Category category)
{
this.Context.Categories.Attach(category, category);
this.Context.Categories.DeleteOnSubmit(category);
}
}
}</pre>
<p>GetCategories metodu ile LINQ to SQL sağlayıcısı üzerinden kategorilerin çekilmesi sağlanmaktadır. Bir kategorinin eklenmesi sırasında <strong>InsertOnSubmit</strong>, silinmesi işleminde <strong>DeleteOnSubmit</strong> ve son olarak güncellenmesinde ise <strong>Attach</strong> isimli LINQ to SQL tarafından hazır olarak gelen fonksiyonların kullanıldığı görülmektedir. Tabiki projenin Build edilmesi sonrasında, istemci tarafındada uygun metodları içeren <strong>CategoryContext</strong> isimli <strong>DomainContext</strong> tipi ile sunucu tarafındaki Category entity sınıfının karşılığı hazırlanmış olacaktır. Artık tek yapmamız gereken istemci tarafını tasarlamak ve kodlamaktır. Ben tasarım konusunda özürlü olduğumdan, ancak aşağıdaki <strong>Silverlight</strong> <strong>UserControl</strong> bileşenini oluşturabilmiş bulunuyorum. <img title="Embarassed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-embarassed.gif" alt="Embarassed" border="0" /></p>
<p>MainPage.xaml</p>
<p><img src="/pics/2009%2f5%2fblg16_2.gif" alt="" /></p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><UserControl x:Class="Editing.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Width="400" Height="300">
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical">
<TextBlock Text="Categories" FontSize="12" FontStyle="Italic"/>
<ComboBox x:Name="cmbCategories" Height="24" SelectionChanged="cmbCategories_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="id" Text="{Binding CategoryID}" Foreground="RoyalBlue"/>
<TextBlock x:Name="name" Text="{Binding CategoryName}" Foreground="SeaGreen"/>
<TextBlock x:Name="description" Text="{Binding Description}" Foreground="Salmon" FontSize="9" FontStyle="Italic"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<TextBlock Text="ID" Foreground="BlueViolet"/>
<TextBlock x:Name="txtCategoryID"/>
<TextBlock Text="Name" Foreground="BlueViolet"/>
<TextBox x:Name="txtCategoryName"/>
<TextBlock Text="Description" Foreground="BlueViolet"/>
<TextBox x:Name="txtCategoryDescription"/>
<StackPanel Orientation="Horizontal" Margin="5">
<Button x:Name="btnUpdate" Click="btnUpdate_Click" Content="Update" Width="100" Margin="2"/>
<Button x:Name="btnDelete" Click="btnDelete_Click" Content="Delete" Width="100" Margin="2"/>
<Button x:Name="btnInsert" Click="btnInsert_Click" Content="Insert" Width="100" Margin="2"/>
</StackPanel>
</StackPanel>
</UserControl></pre>
<p>Hemen bu sayfadanın tasarlanma amacını açıklıyayım. ComboBox kontrolümüz içerisinde, sayfanın oluşturulması sırasında yüklenen Category nesne örnekleri yer alacaktır. Bu nesne örneklerine ait CategoryID,CategoryName ve Description alanları <strong>DataTemplate</strong> şablonun içerisindeki TextBlock kontrollerinin <strong>Text</strong> özelliklerine <strong>bağlanmıştır(Binding)</strong>. Kullanıcı isterse, sayfanın alt kısmında yer alan TextBox kontrollerini kullanarak yeni bir Category ekleyebilir. Tek yapması gereken, Insert başlıklı Button kontrolüne basmaktır. Diğer taraftan ComboBox kontrolünde bir Category seçildiğinde, buna ait CategoryName ve Description bilgileri ile CategoryID değeri, alt tarafta yer alan kontrollere, istemci tarafındaki <strong>DomainContext</strong> tipinin ilgili <strong>Categories</strong> özelliği üzerinden getirilmektedir. Kullanıcı bu işleyişi güncelleme sırasında değerlendirebilir. Bilgiler üzerinde gerekli değişiklikleri yaptıktan sonra <strong>Update</strong> düğmesini kullanması yeterlidir. Benzer şekilde silme işlemi içinde sadece ve sadece Delete düğmesini ele alabilir.</p>
<blockquote>
<p>Tabi bu örnekte, silinmek istenen Category bilgisinin, sunucu tarafında başka birisi tarafından silinmiş olma durumu söz konusu olabilir. Yada var olan bir kaydı güncellemek isteyen kullanıcıdan önce başka birisi güncelleştirmiş olabilir ve o anki kullanıcı eski veriye bakıyor olabilir. Sanıyorumki nereye varmak istediğimi biraz anladınız. Eş zamanlı olarak birbirlerinden habersiz bir şekilde veriyi ektiliyen istemcilerin olduğu vaka. Bu tip bir vaka .Net RIA Servislerinin kullanıldığı bir ortamda son derece olasıdır. Önemli olan noktalardan birisi, SQL tarafında çalıştırılan sorgulardaki Where kriteridir. Where kriterinde varsayılan olarak nasıl bir yaklaşım sergilenmektedir? Bunu ilerleyen kısımlarda görmeye çalışacağız.</p>
</blockquote>
<p>Gelelim kod tarafına...</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using Editing.Web;
namespace Editing
{
public partial class MainPage : UserControl
{
CategoryContext context = new CategoryContext();
public MainPage()
{
InitializeComponent();
cmbCategories.ItemsSource = context.Categories;
context.LoadCategories();
}
private void cmbCategories_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (e.AddedItems.Count>0
&& e.AddedItems[0]!=null)
{
Category selectedCategory = (Category)e.AddedItems[0];
txtCategoryID.Text = selectedCategory.CategoryID.ToString();
txtCategoryName.Text = selectedCategory.CategoryName;
txtCategoryDescription.Text = selectedCategory.Description;
}
}
private void btnUpdate_Click(object sender, RoutedEventArgs e)
{
// Güncellenmek istenen category nesne örneği, DataContext referansının Categories koleksiyonu üzerinden çekilir.
if (!String.IsNullOrEmpty(txtCategoryID.Text))
{
Category category = context.Categories.Single<Category>(c => c.CategoryID == Convert.ToInt32(txtCategoryID.Text));
// Güncellenmek istenen Category nesne örneğinin CategoryName ve Description alanlarına ilgili değerler aktarılır
category.CategoryName = txtCategoryName.Text;
category.Description = txtCategoryDescription.Text;
}
// Değişiklikler sunucu tarafına gönderilir.
context.SubmitChanges();
}
private void btnDelete_Click(object sender, RoutedEventArgs e)
{
// Silinmek istenen Category tipi ComboBox içerisinden seçildikten sonra
// ilk olarak DataContext tipi içerisindeki koleksiyondan çıkartılır.
context.Categories.Remove((Category)cmbCategories.SelectedItem);
// Değişiklikler sunucu tarafına gönderilir
context.SubmitChanges();
// Silme işleminden sonra sunucu tarafından Categories tablosunun son içeriği alınır
context.LoadCategories();
// Kontrollerin içeriği temizlenir
txtCategoryDescription.Text = "";
txtCategoryName.Text = "";
txtCategoryID.Text = "";
}
private void btnInsert_Click(object sender, RoutedEventArgs e)
{
// Yeni Category tipi örneklenir
Category newCategory = new Category {
CategoryName = txtCategoryName.Text
, Description = txtCategoryDescription.Text };
// Örneklenen Category tipi, DataContext üzerindeki Categories koleksiyonuna eklenir.
context.Categories.Add(newCategory);
// Değişiklikler onaylanır ve sunucu tarafına aktarılır
context.SubmitChanges();
}
}
}</pre>
<p>Artık testlerimize başlayabiliriz. Burada <strong>Insert, Update </strong>ve <strong>Delete </strong>gibi işlemler söz konusu olduğundan ve sunucu tarafında SQL kullanıldığından, arka planda çalıştırılan sorgu cümlelerini eminimki sizde en az benim ettiğim kadar merak ediyorsunuzdur. Bu nedenle <strong>SQL Server Profiler </strong>aracımızda bir yandan açık duruyor olacak. <img title="Wink" src="/editors/tiny_mce3/plugins/emotions/img/smiley-wink.gif" alt="Wink" border="0" /></p>
<p>İlk karşılaşacağımız ekran görüntüsü aşağıdakine benzer olacaktır.</p>
<p><img src="/pics/2009%2f5%2fblg16_3.gif" alt="" /></p>
<p>Görüldüğü gibi ComboBox içerisinde, kategorilerin tamamı yer almaktadır. Eğer kullanıcı herhangibir öğeyi seçerse aşağıdaki ekran görüntüsünde olduğu gibi, o kategoriye ait bilgiler gelecektir.</p>
<p><img src="/pics/2009%2f5%2fblg16_4.gif" alt="" /></p>
<p>Bu sırada ekrana gelen veri içeriğini değiştirdiğimizi ve sonrasında Update tuşuna bastığımızı düşünelim. Örnek olarak kategori adı ve açıklamalarının sonuna üç nokta koyduğumuzu varsayalım. Bu durumda SQL tarafında aşağıdaki sorgunun çalıştırıldığını görebiliriz.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">exec sp_executesql N'UPDATE [dbo].[Categories]
SET [CategoryName] = @p2, [Description] = @p3
WHERE ([CategoryID] = @p0) AND ([CategoryName] = @p1)',N'@p0 int,@p1 nvarchar(10),@p2 nvarchar(13),@p3 ntext',@p0=2,@p1=N'Condiments',@p2=N'Condiments...',@p3=N'Sweet and savory sauces, relishes, spreads, and seasonings...'</pre>
<p>Hemen dikkatimi çeken bir noktayı vurgulamak istiyorum. Sadece CategoryName ve Description alanlarını güncelleştirdik. Bu nedenle SQL tarafında yürütülen Update sorgusunda yanlızca bu alanlar yer almaktadır. Picture alanı için herhangibir ifade bulunmamaktadır. Bu neden önemlidir? n tane alandan oluşan bir tablonun kullanıldığı düşünüldüğünde, sadece bir alan için güncelleştirme yapılıyorsa, tüm alanların sorguya dahil edilmesi yerine sadece ilgili olanın eklenmesi söz konusudur...Mu acaba? Bunu test etmek son derece kolaydır aslında. Sadece CategoryName alanın değerini güncelleştirdiğinizi düşünelim. Bu durumda SQL profiler ile yaklanan sorguya bakarsak eğer, Description özelliğine, txtCategoryDescription kontrolünün değişmeyen içeriğini aktarmış olsak bile, sadece CategoryName alanının sorguya dahil edildiğini görebiliriz. Bu bizim için oldukça iyi bir haber aslında.</p>
<p>Yeni bir kategori eklenmek istendiğindeyse,</p>
<p><img src="/pics/2009%2f5%2fblg16_5.gif" alt="" /></p>
<p>sunucu tarafında aşağıdaki SQL sorgusu çalıştırılacaktr.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">exec sp_executesql N'INSERT INTO [dbo].[Categories]([CategoryName], [Description], [Picture])
VALUES (@p0, @p1, @p2)
SELECT CONVERT(Int,SCOPE_IDENTITY()) AS [value]',N'@p0 nvarchar(5),@p1 ntext,@p2 image',@p0=N'Kitap',@p1=N'Bisiklet nasıl sürülür, nasıl monte edilir :)',@p2=NULL</pre>
<p>Sorgu cümlesinde standart bir Insert ifadesi olmasının dışında, eklenen kayıt için üretilen Identity değerinin, <strong>SCOPE_IDENTITY()</strong> fonksiyonundan yararlanılarak geriye döndürüldüğü gözden kaçırılmamalıdır. Öyleki, yeni eklenen satıra ait bilgiler ComboBox kontrolüne otomatik olarak bağlanırken, CategoryID değerininde sunucudan alındığı rahatlıkla gözlemlenebilir.</p>
<p><img src="/pics/2009%2f5%2fblg16_6.gif" alt="" /></p>
<p>Silme işlemi için bir kategorinin seçilmesi gerekmektedir. Seçilen kategoriye ait Category nesne örneği bulunduktan sonra ise <strong>Remove</strong> metodu ile <strong>DomainContext</strong> içerisindeki koleksiyondan çıkartılır. Sonrasında ise değişikleri sunucu göndermek için yine <strong>SubmitChanges</strong> metodundan yararlanılır. Sonuç itibariyle SQL sunucusuna giden sorgu cümlesi aşağıdaki gibidir.</p>
<pre class="brush:sql;auto-links:false;toolbar:false" contenteditable="false">exec sp_executesql N'DELETE FROM [dbo].[Categories] WHERE ([CategoryID] = @p0) AND ([CategoryName] = @p1)',N'@p0 int,@p1 nvarchar(5)',@p0=12,@p1=N'Kitap'</pre>
<p>Sorguda dikkat çeken en önemli nokta Where kriterine, <strong>Image</strong> tipinden olan <strong>Picture</strong> ile <strong>ntext</strong> tipinden olan <strong>Description</strong> dışındaki tüm alanların dahil edilmesidir. Bu bir anlamda eş zamanlı çakışmaların önüne geçilmesini sağlamaktadır ki aynı durum Update için çalıştırılan SQL sorgusunda da geçerlidir. Bilmem farketmiş miydiniz? <img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /></p>
<p>Böylece geldik bir yazımızın daha sonuna. Bu kısa yazıda, .<strong>Net RIA Servislerinde Insert,Update</strong> ve <strong>Delete </strong>işlemlerini basit bir biçimde ele almaya ve arka planda hareket eden SQL cümleciklerine bakıldığında gözümüze çarpan önemli noktaları vurgulamaya çalıştım. .Net RIA Servisleri ile ilişkiki araştırmalarıma devam ettikçe sizlerle paylaşıyor olacağım. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fEditing.rar">Editing.rar (1,14 mb)</a></p>2009-05-13T22:50:00+00:00.net ria servicessilverlightbsenyurtBildiğiniz gibi bir süredir .Net RIA Servisleri ile ilişkili araştırmalarıma devam etmekteyim. Bu yazımızda, .Net RIA Servislerinde Insert, Update ve Delete işlemlerini nasıl yapabileceğimizi basit bir örnek üzerinden adım adım aktarmaya çalışacağım.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=29156ed7-e072-466f-8893-dfb6e3b8f0910https://buraksenyurt.com/trackback.axd?id=29156ed7-e072-466f-8893-dfb6e3b8f091https://buraksenyurt.com/post/Net-RIA-Servisleri-CRUD-Islemleri#commenthttps://buraksenyurt.com/syndication.axd?post=29156ed7-e072-466f-8893-dfb6e3b8f091https://buraksenyurt.com/post/Net-RIA-Servisleri-Hello-World.Net RIA Servisleri - Hello World2009-05-13T13:29:00+00:00bsenyurt<p>Merhaba Arkadaşlar,</p>
<p>Hatırlayacağınız gibi bir önceki <a title=".Net RIA Servisleri Nedir?" href="https://buraksenyurt.com/post/Net-RIA-Servisleri-Nedir" target="_blank">blog </a>yazımda, <strong>.Net RIA Servisleri</strong> hakkında edindiğim kısa ve özet teorik bilgileri sizinle paylaşmaya çalışmıştım. Bu yazımda ise, teoriği pratiğe dökmeye gayret edeceğim. Geliştireceğimiz örnek, .Net RIA Servisini kullanan bir <strong>Silverlight</strong> uygulaması olacak. Geliştirmeyi <strong>Visual Studio 2008</strong> üzerinde, <strong>Silverlight 3.0</strong> ortamını kullanarak gerçekleştireceğim. Bu nedenle aşağıdaki şekilde görüldüğü gibi, klasik bir silverlight projesi oluşturarak işe başlayabiliriz.</p>
<p><img src="/pics/2009%2f5%2fblg15_1.gif" alt="" /></p>
<p>Bu işlemin ardından ekrana gelen aşağıdaki pencerede,</p>
<p><img src="/pics/2009%2f5%2fblg15_2.gif" alt="" /></p>
<p><strong>LINQ to ASP.Net Server Project</strong> seçeneğinin işaretli olması önemlidir. Böylece, <strong>.NET RIA Servisi</strong> için gerekli ön hazırlığın yapılması sağlanmış olur. Elbetteki bunu seçmediğimiz takdirde elimiz kolumuz bağlı değildir. Daha sonradan istenirse, Silverlight uygulamasının özelliklerinden, .Net RIA Servisi destekleyecek şekilde değişiklikler yapılabilir. Yapmış olduğumuz bu işlemlerin sonrasında, <strong>HelloRIAServices</strong> isimli <strong>Silverlight</strong> uygulaması <strong>sunum mantığını(Presentation Logic)</strong> içeren <strong>istemci tarafını(client-tier)</strong> oluştururken, <strong>HelloRIAServices.Web</strong> isimli web uygulaması ise, <strong>iş mantığını(Business Logic)</strong> içeren <strong>orta katmanı(mid-tier) </strong>oluşturmaktadır. Bu sebepten, veriye erişimi sağlayacak olan <strong>LINQ to SQL(veya Ado.Net Entity Framework) </strong>öğeleri, <strong>Asp.Net Web </strong>uygulaması üzerinde yer alacaktır. Aynı şekilde <strong>DomainService</strong> sınıfıda, Asp.Net Web uygulaması üzerinde konuşlandırılacaktır. Tahmin edileceği üzere, servis için istemci tarafından gönderilecek çağrıları ele alacak olan <strong>içerik sınıfı ise(DataContext), Silverlight</strong> uygulaması tarafında yer almalıdır.</p>
<p>Bu işlemlerin ardından, <strong>DomainService'</strong> in erişip istemci tarafına sunacağı veri kümesini oluşturmamız gerekmektedir. Burada, veriye erişmek amacıyla(<strong>Data Access Layer </strong>tarafı olarak düşünebiliriz), <strong>Ado.Net Entity Framework</strong> öğesini veya <strong>LINQ to SQL </strong>sınıflarını kullanabileceğimizi belirtmiştik. Ben örneğimizde, Ado.Net Entity Framework' ü kullanarak, <strong>Northwind </strong>veritabanı üzerinden aşağıdaki şemaya sahip olan tabloları kullanmayı planlıyorum. Bu noktada şunu hatırlatmakta yarar var. <strong>Ado.Net Entity Framework </strong>veya <strong>LINQ to SQL </strong>kullanımı, <strong>.Net RIA Servisleri </strong>açısından bakıldığında bir zorunluluk yada şart değildir. Dolayısıyla farklı veri kaynaklarını kullanabilir(Örneğin <strong>XML </strong>tabanlı...) ve istemci tarafına bir DomainService üzerinden sunabiliriz.</p>
<p><img src="/pics/2009%2f5%2fblg15_3.gif" alt="" /></p>
<p>Şunu hemen belirteyim; <strong>EDM </strong>içeriğini <strong>Asp.Net Web Project </strong>üzerinde oluşturmalıyız. EDM diagramından görüldüğü üzere <strong>Categories, Products </strong>ve <strong>Suppliers </strong>tabloları için gerekli <strong>Entity </strong>tipleri otomatik olarak üretilmiştir. Böylece, veriye erişimi sağlayacak olan katmanı bir nevi hazırlamış bulunuyoruz. Bu işlemin ardından proje bir kere derlendikten sonra, istemciye veriyi sunacak olan <strong>DomainService</strong> içeriğinin hazırlanmasına başlanabilir; ki buda son derece kolaydır <img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /> Tek yapmamız gereken, yine web uygulaması projesi içerisine, aşağıdaki şekildende görüldüğü gibi bir <strong>DomainService</strong> öğesi eklemektir.</p>
<p><img src="/pics/2009%2f5%2fblg15_4.gif" alt="" /></p>
<p><em>(Kullandığım sistemdeki kurulumdan kaynaklanan bir sorun olsa gerek, ikon ne yazıkki görünmüyor <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" /> )</em></p>
<p>Bu seçimin ardından karşımıza aşağıdaki iletişim kutusu gelecektir.</p>
<p><img src="/pics/2009%2f5%2fblg15_5.gif" alt="" /></p>
<p>Burada <strong>Categories</strong> ve <strong>Products </strong>tipleri işaretlenmiştir. Bu tiplerin hiç birisi için <strong>Insert, Update </strong>veya <strong>Delete </strong>operasyonu hazırlanmayacaktır. Ancak bu operasyonlarında hazırlanmasını istersek, <strong>Enable Editing </strong>özelliklerini işaretlememiz yeterlidir. Dikkat edileceği üzere, <strong>Available DataContexts/ObjectContexts </strong>kısmında az önce oluşturulan <strong>NorthwindEntities </strong>isimli <strong>Ado.Net Entity Framework </strong>tipi seçilidir. Taşlar yavaş yavaş yerine oturmaktadır. Artık, <strong>DomainService</strong> sınıfı hazırdır ve veriyi sunmak için, <strong>DAL</strong> içerisinde oluşturulan Entity içeriğine bağlanmıştır. Bu noktada biraz durup, oluşturulan tipleri incelemekte yarar olacağını düşünüyorum. Web uygulaması içerisindeki <strong>sınıf diagramını(Class Diagram)</strong> açtığımızda aşağıdaki şekilde yer alan tiplerin oluşturulduğunu görürüz.</p>
<p><img src="/pics/2009%2f5%2fblg15_6.gif" alt="" /></p>
<p><strong>Products, Suppliers, Categories </strong>isimli sınıflar, <strong>Northwind </strong>veritabanında seçtiğimiz aynı isimli tabloların karşılıkları olan <strong>Entity</strong> tipleridir. <strong>NorthwindEntities</strong> sınıf ise, söz konusu tiplere ait koleksiyonları içerisinde özellik bazında tutmakta ve ekleme gibi temel fonksiyonellikleri içermektedir. Buraya kadarki tipler, veri erişim mantığını içeren parçalar olarak düşünülebilir. <strong>NorthwinDomainService</strong> sınıfı ise asıl üzerinde odaklanmamız gereken tiptir. Şimdi bu tip ile ilişkili analizlerimizi değerlendirelim.</p>
<p>Herşeyden önce, <strong>LinqToEntitesDomainService<T></strong> isimli <strong>generic</strong> ve <strong>abstract </strong>bir sınıftan türetildiğini görüyoruz. <strong>T </strong>tipi olarak örneğimizde, <strong>Ado.Net Entity Framework </strong>tarafında ürettiğimiz, <strong>NorthwindEntities </strong>tipi yer almakta. Buna göre, söz konusu <strong>DomainService </strong>sınıfının, hangi <strong>veri içeriğini(DataContenxt) </strong>ve üyelerini kullanacağı belirlenmiş oluyor. Burada dikkat çekici noktalardan biriside, <strong>DomainService</strong> sınıfının türediği tipe ait generic kısıtlamadır.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace System.Web.DomainServices.LinqToEntities
{
public abstract class LinqToEntitiesDomainService<T>
: LinqToEntitiesDomainService where T : System.Data.Objects.ObjectContext
{
protected LinqToEntitiesDomainService();
protected T Context { get; }
}
}</pre>
<p>Koddanda görüleceği üzere <strong>T</strong> tipinin <strong>ObjectContext'</strong> ten türeme zorunluluğu bulunmaktadır. Buda geliştiricilere bir bağımsızlık getirmektedir. Yani, <strong>ObjectContext</strong> sınıfından türeteceğimiz özel tipler sayesinde farklı veri içeriklerinide <strong>DomainService</strong> içerisinde ele alabiliriz.</p>
<p>Bir diğer nokta, <strong>DomainService</strong> sınıfı içerisinde sadece <strong>GetProducts</strong> ve <strong>GetCategories</strong> isimli metodların yer almasıdır. Her iki metodda <strong>IQueryable<T></strong> tipinden referans döndürmektedir. Kod içeriğine baktığımızda durum biraz daha netleşmektedir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace HelloRIAServices.Web
{
using System.Linq;
using System.Web.DomainServices.LinqToEntities;
using System.Web.Ria;
[EnableClientAccess()]
public class NorthwindDomainService : LinqToEntitiesDomainService<NorthwindEntities>
{
public IQueryable<Categories> GetCategories()
{
return this.Context.Categories;
}
public IQueryable<Products> GetProducts()
{
return this.Context.Products;
}
}
}</pre>
<p>Her iki metodda basit olarak <strong>Context</strong> referansına gitmekte ve <strong>Categories </strong>ile <strong>Products </strong>koleksiyonlarının içeriklerini istemci tarafına döndürmektedir. Dönüş tipleri <strong>IQueryable</strong> olduğundan, istemci tarafında <strong>LINQ</strong> ifadeleri ile sorgulanmaya devam edilmeleri pekala mümkündür. Bunlara ek olarak çok daha önemli bir nokta vardır. Metodlara istenirse parametre verilebilir ve geriye döndürülecek içerik ile ilişkili bazı kısıtlamalar yaptırılabilir.</p>
<p>Bir başka deyişle geliştirici, metodların parametrik yapısı ile oynayabileceği gibi, dönüş içeriğini <strong>IQueryable<T></strong> olmasına(<strong>IEnumerable<T></strong> da olabilir) dikkat edecek şekilde değiştirebilir. Söz gelimi, belkide istemcinin bulunduğu lokasyondaki tedarikçiye göre bir Products veya Categories içeriğinin döndürülmesi sağlanabilir. Yada çok basit anlamda, içeriklerin örneğin ürün adına veya kategori adına göre sıralanarak döndürülmesi sağlanabilir. Bu nedenle kod içeriğini aşağıdaki gibi değiştirmeye karar verdim.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">namespace HelloRIAServices.Web
{
using System.Linq;
using System.Web.DomainServices.LinqToEntities;
using System.Web.Ria;
[EnableClientAccess()]
public class NorthwindDomainService
: LinqToEntitiesDomainService<NorthwindEntities>
{
public IQueryable<Categories> GetCategories()
{
// Lamda operatörü ve extension method yardımıyla
return this.Context.Categories.OrderBy(c => c.CategoryName);
}
public IQueryable<Products> GetProducts()
{
// basit bir LINQ ifadesi yardımıyla
return (from p in this.Context.Products
orderby p.ProductName descending
select p);
}
}
}</pre>
<p>Tabiki bu değişiklikler ile sınırlı değiliz. İstersek, <strong>DomainService</strong> sınıfı içerisine farklı fonksiyonelliklerde ekleyebiliriz. Örneğin;</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">public IQueryable<Products> GetProductsByCategory(int categoryId)
{
return (from p in this.Context.Products
where p.Categories.CategoryID == categoryId
orderby p.ProductName
select p);
}</pre>
<p>gibi.</p>
<p>Son olarak <strong>DomainService</strong> sınıfı içerisinde dikkat çeken bir noktayı daha vurgulayalım. Sınıfın kendisine <strong>EnableClientAccess</strong> isimli bir <strong>nitelik(attribute)</strong> uygulanmıştır. Bu nitelik, söz konusu sınıfın istemci katmanından görünebileceği anlamına gelmektedir.</p>
<p>Bu adımların ardından <strong>Solution</strong> tamamıyla derlenirse ve <strong>Silverlight</strong> uygulamasının öğelerine <strong>Show All Files</strong> seçeneği ile bakılırsa, aşağıdaki şekilde görülen bir dosyanın üretildiği farkedilebilir.</p>
<p><img src="/pics/2009%2f5%2fblg15_7.gif" alt="" /></p>
<p>Buradaki kod dosyası, <strong>DomainService</strong> sınıfı her <span style="text-decoration: underline;">değiştiğinde</span> ve bu nedenle Web projesi her <span style="text-decoration: underline;">derlendiğinde</span> otomatik olarak yeniden üretilmektedir. Söz konusu kod dosyası içerisinde, servisten sunulan her bir <strong>Entity </strong>tipi için karşılık olan bir sınıf bulunmaktadır.</p>
<p><img src="/pics/2009%2f5%2fblg15_8.gif" alt="" /></p>
<p><br />Şekildende görüleceği gibi, <strong>Ado.Net Entity Framework </strong>kullanarak servis üzerinden sunulan <strong>Categories </strong>ve <strong>Products </strong>tipleri için, istemci tarafında birer sınıf üretilmiştir. Ayrıca, daha önceki yazımızda da bahsettiğimiz gibi, <strong>.NET RIA Servislerinin </strong>önemli iki parçasından birisi olan <strong>DomainContext </strong>türevli bir sınıfda(<strong>NorthwindDomainContext</strong>) oluşturulmuştur. Servis tarafında(<strong>DomainService </strong>içerisinde) yer alan <strong>GetProducts </strong>ve <strong>GetCategories </strong>metodlarına karşılık olarak, istemci tarafındaki <strong>DomainContext </strong>tipi içerisine <strong>LoadProducts </strong>ve <strong>LoadCategories </strong>fonksiyonları hazırlanmıştır.</p>
<p>Yine özel olarak eklediğimiz <strong>GetProductsByCategory</strong> metoduna karşılık olarak, <strong>DataContext</strong> tarafında <strong>LoadProductsByCategory</strong> isimli fonksiyon üretilmiştir. Dolayısıyla, <strong>Silverlight</strong> uygulamasında, servis ile konuşulmasını sağlayacak olan <strong>proxy</strong> içeriği otomatik olarak üretilmiştir. Aslında <strong>orta katmanda(mid-tier)</strong> yer alan her bir <strong>DomainService</strong> tipi için, sunum katmanında bir <strong>DomainContext</strong> tipi var olacaktır. Yani, birden fazla veri kaynağına, farklı <strong>DAL</strong> öğeleri ile çıkan servisleri barındıran bir sunucu ile bunları ayrı ayrı kullanabilen bir istemci tasarlanması mümkündür. Artık tek yapmamız gereken, <strong>DomainContext</strong> tipinin ilgili fonksiyonlarını kullanarak istemci tarafını geliştirmektir. Bu amaçla <strong>Silverlight</strong> uygulamasının <strong>MainPage.xaml </strong>içeriğini aşağıdaki gibi geliştirdiğimizi düşünelim.</p>
<pre class="brush:xml;auto-links:false;toolbar:false" contenteditable="false"><UserControl x:Class="HelloRIAServices.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:data="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data"
Width="500" Height="320">
<StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical">
<ComboBox x:Name="cmbCategories" Height="50" VerticalAlignment="Top" SelectionChanged="cmbCategories_SelectionChanged">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock x:Name="categoryId" Text="{Binding CategoryID}" FontSize="12" FontFamily="Calibri" Foreground="Blue"/>
<TextBlock x:Name="categoryName" Text="{Binding CategoryName}" FontSize="12" FontFamily="Calibri" Foreground="Black"/>
<TextBlock x:Name="categoryDescription" Text="{Binding Description}" FontStyle="Italic" FontSize="9" FontFamily="Calibri" Foreground="LimeGreen"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
<data:DataGrid x:Name="grdProducts" Height="250" Background="Lavender" BorderBrush="CadetBlue"/>
</StackPanel>
</UserControl></pre>
<p><strong>UserControl</strong> içerisinde bir adet <strong>ComboBox</strong> ve <strong>DataGrid</strong> bileşeni bulunmaktadır. <strong>DataGrid</strong> bileşeninin kullanılabilmesi için <strong>Silverlight</strong> uygulamasına <strong>System.Windows.Controls.Data.dll</strong> <strong>assembly'</strong> ının <strong>referans</strong> edilmesi gerekmektedir. Ayrıca <strong>DataGrid</strong> kulanımı için, <strong>XAML</strong> içerisinde gerekli <strong>namespace</strong> tanımlamasıda yapılmalıdır. Sayfanın kullanımı son derece basit olacaktır. <strong>ComboBox</strong> içeriği, <strong>MainPage</strong> yapıcı metodu içerisinde, kategoriler ile doldurulacaktır. Kullanıcı, <strong>ComboBox</strong> içerisinden herhangibir kategoriyi seçtiğinde ise, buna bağlı ürün listeside <strong>DataGrid</strong> kontrolünde gösterilecektir. <strong>ComboBox</strong> kontrolüne ait veri içeriğinde, bir <strong>DataTemplate</strong> kullanılmaktadır ve dikkat edileceği üzere <strong>Categories</strong> isimli <strong>Entity</strong> tipinin <strong>CategoryID</strong>, <strong>CategoryName </strong>ve <strong>Description </strong>özellikleri kullanılarak bir şablon oluşturulmuştur. <strong>MainPage</strong> <strong>UserControl'</strong> üne ait kod içeriği ise aşağıdaki gibidir.</p>
<pre class="brush:csharp;auto-links:false;toolbar:false" contenteditable="false">using System.Windows.Controls;
using HelloRIAServices.Web;
namespace HelloRIAServices
{
public partial class MainPage : UserControl
{
// DomainContext nesnesi
NorthwindDomainContext context = null;
public MainPage()
{
InitializeComponent();
// DomainContext nesnesi örneklenir
context = new NorthwindDomainContext();
// ComboBox kontrolüne veri kaynağı olarak, EntityList tipinden olan Categories özeliği bağlanır.
cmbCategories.ItemsSource = context.Categories;
// DataGrid kontrolü için veri kaynağı DomainContext nesne örneğindeki Products özelliği ile belirlenir
grdProducts.ItemsSource = context.Products;
// Categories listesi LoadCategories metodu ile yüklenir.
context.LoadCategories();
}
private void cmbCategories_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
// Seçilen öğe Categories tipinden olduğu için CategoryID özelliğine aşağıdaki kod parçasında olduğu gibi ulaşılabilir.
int selectedCategoryId=((Categories)e.AddedItems[0]).CategoryID;
// Eğer aşağıdaki temizleme işlemini uygulamassak, Grid kontrolü içerisinde veriler arka arkaya eklenerek çoğalır.
context.Entities.GetEntityList<Products>().Clear();
// LoadProductsByCategory metoduna, seçili kategorinin CategoryID değeri gönderilerek, bağlı olan ürün listesinin yüklenmesi sağlanır.
context.LoadProductsByCategory(selectedCategoryId);
}
}
}</pre>
<p>Aslında kod içeriği son derece basittir. <strong>.Net RIA Servisleri</strong> açısından olaya baktığımızda iki önemli nokta göze çarpmaktadır. İlk olarak veri bağlı kontrolleri, <strong>Entity</strong> içeriklerine bağlamak için <strong>DomainContext</strong> nesne örneğine ait özelliklerden yararlanılmaktadır<strong>(Categories, Products</strong> gibi). Diğer taraftan veriyi doldurmak için, bu isteğin sunucu tarafındaki <strong>DomainService</strong> tipine ulaştırılması gerektiği de ortadadır. Bu sebepten <strong>LoadCategories</strong> ve <strong>LoadProductByCategory</strong> metodlarından yararlanılmaktadır. Sonuç olarak uygulama çalışma zamanında test edildiğinde aşağıdaki örnek çıktılar ile karşılaşılacaktır.</p>
<p>Uygulama ilk çalıştırıldığında kategoriler, ComboBox bileşeni içerisine yüklenecektir.</p>
<p><img src="/pics/2009%2f5%2fblg15_9.gif" alt="" /></p>
<p>Herhangibir kategori seçildiğinde ise...</p>
<p><img src="/pics/2009%2f5%2fblg15_10.gif" alt="" /></p>
<p>DataGrid kontrolü, bu kategoriye bağlı ürünler ile doldurulacaktır. İşte bu kadar. Görüldüğü gibi, <strong>Silverlight</strong> uygulamalarında <strong>.Net RIA Servislerini</strong> kullanılarak, <strong>çok katmanlı modelin(n-tier),</strong> basitçe <strong>iki katmana(2-tier)</strong> indergenmesi sağlanabilmektedir. Geliştirdiğimiz örnek göz önüne alındığında, aşağıdaki şekil durumu biraz daha açıklığa kavuşturmaktadır.</p>
<p><img src="/pics/2009%2f5%2fblg15_11.gif" alt="" /></p>
<p>Böylece geldik bir yazımızın daha sonuna. <strong>.Net RIA Servisleri</strong> ile ilişkili araştırmalarıma devam ettikçe, öğrendiklerimi sizlerle paylaşmaya devam ediyor olacağım. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>
<p><a href="https://buraksenyurt.com/pics/2009%2f5%2fHelloRIAServices.rar">HelloRIAServices.rar (1,60 mb)</a></p>2009-05-13T13:29:00+00:00.net ria servicessilverlightbsenyurtHatırlayacağınız gibi bir önceki blog yazımda, .Net RIA Servisleri hakkında edindiğim kısa ve özet teorik bilgileri sizinle paylaşmaya çalışmıştım. Bu yazımda ise, teoriği pratiğe dökmeye gayret edeceğim. Geliştireceğimiz örnek, .Net RIA Servisini kullanan bir Silverlight uygulaması olacak. Geliştirmeyi Visual Studio 2008 üzerinde, Silverlight 3.0 ortamını kullanarak gerçekleştireceğim. Bu nedenle aşağıdaki şekilde görüldüğü gibi, klasik bir silverlight projesi oluşturarak işe başlayabiliriz.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=52dca1b0-bca8-49b6-be06-02000cdfb2170https://buraksenyurt.com/trackback.axd?id=52dca1b0-bca8-49b6-be06-02000cdfb217https://buraksenyurt.com/post/Net-RIA-Servisleri-Hello-World#commenthttps://buraksenyurt.com/syndication.axd?post=52dca1b0-bca8-49b6-be06-02000cdfb217https://buraksenyurt.com/post/Net-RIA-Servisleri-Nedir.Net RIA Servisleri Nedir?2009-05-08T13:41:00+00:00bsenyurt<p>Merhaba Arkadaşlar</p>
<p>Son yıllarda bildiğiniz üzere <strong>Servis Tabanlı Uygulamalar(Service Oriented Applications)</strong> hayatımızda oldukça fazla yer kaplamaya başladı. <strong>Microsoft </strong>cephesinden olaya baktığımızda, en büyük sıçramanın <strong>Windows Communication Foundation </strong>ile <strong>.Net Framework 3.0' </strong>da yaşandığını söyleyebiliriz. <strong>WCF</strong>' in getirdiği servis bazlı uygulama geliştirme yaklaşımı, <strong>.Net Framework 3.5 </strong>ile dahada zenginleşti. Eklenen <strong>Web programlama modeli(Web Programming Model)</strong> özellikleri sayesinde, <strong>REST(Representational State Transfer)</strong> bazlı servislerin geliştirilebilmesinin yolu açıldı. Sonrasında <strong>Workflow Foundation</strong> ile iç içe geçen <strong>WCF</strong> özellikleri sayesinde, iş akışlarının farklı domainler ile haberleşebilmesi veya servis gibi sunulabilmesi olanaklı hale geldi. Derken <strong>.Net Framework 3.5 Service Pack 1 </strong>ile hayatımıza başka bir kavram daha girdi. <strong>Ado.Net Data Services</strong>.</p>
<p>Bu model ile, <strong>Ado.Net Entity Framework</strong> veya <strong>LINQ(Language INtegrated Query)</strong> bazlı sağlayıcılar üzerinden verinin REST tabanlı olarak sunulabilmesi mümkün hale geldi.Tabi bu geçişler sırasında <strong>Client Application Services</strong> ve <strong>Azure</strong> gibi kavramlar ile geliştiricinin hayatını kolaylaştıran <strong>REST Starter Kit</strong> gibi pek çok yeni fikir ve vizyon ile karşılaştık. Ama <strong>Microsoft</strong> cephesindeki yenilikler tüm hızıyla sürmeye devam etti, ediyor, edecek...<img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /> Bir süredir <strong>.Net Framework 4.0 </strong>ve bu etapta <strong>WF 4.0&WCF 4.0</strong> yeniliklerini incelemekteyim. Ancak arada kaçırdığım önemli bir konu var. <strong>.Net RIA(Rich Internet Application) Services</strong> ve <strong>Silverlight</strong> <img title="Embarassed" src="/editors/tiny_mce3/plugins/emotions/img/smiley-embarassed.gif" alt="Embarassed" border="0" /> Dolayısıyla bu yazımda sizlere, .Net RIA Servisleri ile ilişkili öğrendiklerimi ve bilgilerimi aktarmaya çalışıyor olacağım.</p>
<p>En nihayetinde, <strong>Silverlight</strong> sayesinde istemci tarafında çok zengin içeriklere sahip olabilecek ve tarayıcı tabanlı(ve hatta Silverlight 3.0 sonrası masaüstü...) uygulamaların geliştirilmesi mümkün. Ancak Silverlight gibi bir uygulama geliştirme modelinde, istemcinin sunucu üzerinde yer alan bazı veri kaynaklarına erişmesi için, servislerin kullanılmasıda <span style="text-decoration: underline;">kaçınılmaz</span> bir gerçek. <em>(Nedenini biraz sonra daha iyi anlatabileceğim.) </em></p>
<p>Özellikle<strong> Silverlight 3.0</strong> ve <strong>.Net RIA Service</strong> çıkana kadar, geliştiricilerin sunucu verilerine erişmesi için biraz daha fazla kodlama yapması gerekmektedir. Aslında olaya sadece Silverlight değil, <strong>Asp.Net Ajax</strong> gibi istemciler açısından bakıldığında da, benzer kodlama süreçleri söz konusudur. Bu tip <strong>RIA</strong> uygulamalarını, <strong>n-tier</strong> tarzı mimariler ile geliştirmek istediğimizden, aslında <strong>sunum(Presentation)</strong> katmanının standart <strong>Asp.Net</strong> modelinden farklı olarak, tamamen istemci tarafına yıkıldığı oldukça önemli bir noktadır. Sanıyorum burada biraz kafaları karıştırdım. <img title="Undecided" src="/editors/tiny_mce3/plugins/emotions/img/smiley-undecided.gif" alt="Undecided" border="0" />Gelin olayı standart <strong>n-tier</strong> modelin Asp.Net uygulamalarındaki genel kullanımı ile analiz etmeye başlayalım. Aşağıdaki şekilde bu model vurgulanmaya çalışılmaktadır.</p>
<p><img src="/pics/2009%2f5%2fblg14_1.gif" alt="" /></p>
<p>Klasik olarak bir <strong>Asp.Net Web</strong> uygulamasında<em>(çoğunlukla Asp.Net Ajax içinde benzer durum söz konusudur),</em> katmanların tamamı sunucu üzerinde yer alır. <strong>Uygulama mantığı(Application Logic-Business Layer), veriye erişim katmanı(Data Access Layer)</strong> ve istemcinin göreceği HTML çıktının üretileceği <strong>sunum katmanı(Presentation Layer)</strong>. Bunlara ek olarak web uygulaması içerisinde, veri erişim katmanından dış servisler yardımıyla farklı kaynaklara gidilebilir veya uygulamanın kendisinin farklı alanlardaki programlara sunacağı bir takım hizmetler/servisler olabilir. Oldukça basit ve kullanışlı.</p>
<p>Ancak, günümüz uygulamalarında ve özellikle son yıllarda <strong>kullanıcı deneyimini(User Experience)</strong> zenginleştirecek şekilde yapılan bir çok atılım vardır. <em>(Bu etkileşim özellikle web tabanlı mimarilerde kendini daha da ön plana çıkarmaktayken, geliştirme süreçlerinin standart masaüstü uygulamalara nazaran daha karmaşık ve zor olduğuda söylenebilir.)</em> Bu nedenle tarayıcı uygulamalar üzerindeki kullanıcı deneyimini zenginleştirecek <strong>Silverlight</strong> gibi geliştirme ortamları söz konusudur. Hal böyle olunca yukarıdaki şekilde çizdiğimiz katmanlı model biraz daha değişim göstermektedir. Aşağıdaki şekilde olduğu gibi.</p>
<p><img src="/pics/2009%2f5%2fblg14_2.gif" alt="" /></p>
<p>Zengin internet uygulamalarında, sunum katmanı/mantığı istemci tarafına yıkılmaktadır<em>(Hatırlayalım, Silverlight uygulamalarının çalıştırılması için istemci tarafında minik bir framework, add-in tarzında yüklenmiş olmalıdır).</em> Bu da kullanıcı etkileşimini dahada üst seviyeye çıkartmak anlamına gelmektedir. Ama doğal olarak<strong> n-tier</strong> modelde sunum katmanı ile uygulama mantığı arasına internet ağının girmesi gerekmektedir. Buna göre <strong>RIA</strong>' ları basit bir istemci uygulamadan ziyade, sunucu bileşenlerinide içeren birer <strong>Internet uygulaması</strong> olarak düşünmek gerekmektedir. Hal böyle olunca, sunucu tarafındaki veri kaynaklarının sunum tarafında kullanılabilmesinde servisler önemli bir rol üstlenmektedir.</p>
<p><strong>.Net RIA Servislerine</strong> kadarki zaman diliminde, geliştiricilerin bu anlamda düşünmesi gereken pek çok kıstas vardır. Herşeyden önce veriyi istemci tarafına taşıyacak servisin ve metodlarının yazılması gerekir. Ayrıca istemci tarafında, bu servisin kullanılabilmesi için gerekli <strong>proxy</strong> üretiminin yapılması şarttır. <strong>Silverlight</strong> tarafında kolay olan proxy üretimi, <strong>Asp.Net Ajax</strong> tarafı düşünüldüğünde ek <strong>javascript</strong> kütüphaneleri anlamına gelmektedir. Yinede, sunucu tarafında <strong>Ado.Net Entity Framework</strong> veya <strong>LINQ to SQL</strong> gibi modelleri kullanabileceğimizden bu zahmete girmeye değmektedir. Microsoft'un söz konusu servislerin, <strong>n-tier</strong> içerisindeki uyarlanışını daha da kolaylaştırmak adına <strong>.Net RIA Servislerini</strong> geliştirdiğini söyleyebiliriz. .Net RIA Servisleri kavramsal olarak iki ana parçadan oluşur.</p>
<p><img src="/pics/2009%2f5%2fblg14_3.gif" alt="" /></p>
<p><strong>DataService</strong> sınıfı aslında, temel <strong>CRUD(CreateRetrieveUpdateDelete)</strong> işlemlerini ve özel bir takım operasyonları içerebilir. Bunlara ek olarak <strong>doğrulama(Validation), yetkilendirme(Authorization)</strong> gibi kısıtlarıda ele alabilir. Bu nedenle <strong>DataService</strong> sınıfının, veri için ele alınacak iş mantığını içerdiğini söyleyebiliriz. DataService sınıfı genel olarak arka planda, <strong>hazır olan(built-in)</strong> veri modellerini kullanır. Yani <strong>Ado.Net Entity Framework</strong> veya <strong>LINQ to SQL</strong> burada göz önüne alınabilir. Elbetteki diğer veri kaynaklarıda gerek servisler, gerek özel kodlamalar yardımıyla kullanılabilir.</p>
<p>İkinci bölümde yer alan <strong>DataContext</strong> sınıfı ise, servislerin istemciye sunduğu verilerin, tip bazındaki karşılıklarını içermektedir. Bu nedenle istemci tarafında, verilerin yüklenmesi, üzerinde yapılan değişikliklerin tekrardan sunucu tarafına gönderilmesi için gerekli kodlamaları ve metodlarıda hazır olarak içermektedir. Tahmin edeceğiniz üzere, <strong>.Net RIA Servislerinin Visual Studio 2008</strong> ortamında geliştirilmesi son derece kolay ve basittir. <img title="Laughing" src="/editors/tiny_mce3/plugins/emotions/img/smiley-laughing.gif" alt="Laughing" border="0" /></p>
<p>Son olarak .Net RIA Servisleri ile ilişkili olaraktan merak edilen sorulara cevap bulabileceğiniz ve gerekli yüklemeleri edinebileceğini bir <a title=".NET RIA Services FAQ" href="http://silverlight.net/forums/t/80529.aspx" target="_blank">internet adresini</a> paylaşmak isterim.</p>
<p>Böylece geldik bir yazımızın daha sonuna. Bu yazımda sizlere .Net RIA Servislerini, anladığım kadarıyla anlatmaya çalıştım. Bir sonraki yazımızda basit bir örnek geliştirerek Merhaba <strong>.Net RIA Servisi</strong> diyeceğiz. Tekrardan görüşünceye dek hepinize mutlu günler dilerim.</p>2009-05-08T13:41:00+00:00.net ria servicessilverlightbsenyurtSon yıllarda bildiğiniz üzere Servis Tabanlı Uygulamalar(Service Oriented Applications) hayatımızda oldukça fazla yer kaplamaya başladı. Microsoft cephesinden olaya baktığımızda, en büyük sıçramanın Windows Communication Foundation ile .Net Framework 3.0' da yaşandığını söyleyebiliriz. WCF' in getirdiği servis bazlı uygulama geliştirme yaklaşımı, .Net Framework 3.5 ile dahada zenginleşti. Eklenen Web programlama modeli(Web Programming Model) özellikleri sayesinde, REST(Representational State Transfer) bazlı servislerin geliştirilebilmesinin yolu açıldı. Sonrasında Workflow Foundation ile iç içe geçen WCF özellikleri sayesinde, iş akışlarının farklı domainler ile haberleşebilmesi veya servis gibi sunulabilmesi olanaklı hale geldi. Derken .Net Framework 3.5 Service Pack 1 ile hayatımıza başka bir kavram daha girdi. Ado.Net Data Services.https://buraksenyurt.com/pingback.axdhttps://buraksenyurt.com/post.aspx?id=6b9c1668-bb09-4506-872e-5760380549111https://buraksenyurt.com/trackback.axd?id=6b9c1668-bb09-4506-872e-576038054911https://buraksenyurt.com/post/Net-RIA-Servisleri-Nedir#commenthttps://buraksenyurt.com/syndication.axd?post=6b9c1668-bb09-4506-872e-576038054911