Burak Selim Senyurt(MVP)
Matematik Mühendisi bir .NET Severin Yazıları...

.Net RIA Servisleri - Doğrulama(Validation)

Cumartesi, 30 Mayıs 2009 12:01 by bsenyurt

Merhaba Arkadaşlar,

Bildiğiniz gibi bir süredir PLINQ(Parallel Language INtegrated Query) ile ilişkili araştırmalarıma devam etmekteyim. Nevarki dün gece uzun süredir ara verdiğim bir konuyu farkettim. .Net RIA Servisleri. Bunun üzerine yaz sıcaklarının kendini iyiden iyiye hissettirmeye başladığı şu günlerde serinlemek için deniz kenarında bir yerlere gitmeden önce,(Örneğin güzelim Ortaköy sahilinde denize karşı çay içmek gibi) esinti ferahlığı verecek, hafif ve basit bir konuyu araştırmaya niyetlendim. Bunun üzerine, verinin eklenmesi veya güncellenmesi sırasında doğrulama işlemlerinin nasıl yapılabileceğini incelemeye karar verdim. Özellikle Asp.Net veya Windows Forms, WPF gibi, kullanıcı ile etkileşimde olan arayüzlerin kullanıldığı projelerde, verinin çeşitli nedenler ile doğrulanması gerekebilir. Doğruluğu kanıtlanan veri, kaynağa eklenebilir, güncelleştirilebilir. Tabiki verinin doğruluğunu kontrol etmek adına pek çok stratejiden faydalanılabilir. Örneğin, Asp.Net web tabanlı uygulamalarda kullanılan doğrulama işlemleri, istemci tarafında Javascript savunması ile başlayıp sunucu tarafında devam eder. En büyük amaç, maliyeti yüksek olan veri işlemlerinden önce çeşitli kriterlerin sağlandığını kontrol etmek olarak düşünülebilir. Tabiki bu maliyet hesabına, güvenlik kontrolünüde eklediğimizde, doğrulamanın aslında son derece önemli bir cephe olduğu ortaya çıkmaktadır. Doğrulama kontrolleri, bir ürün fiyatının belirli aralıkta olması şeklinde düşünülebileceği gibi, bir kredi kartı numarasının Lhun algoritmasına uygun olup olmadığı gibi karmaşık bir denetim mekanizması olarak ta düşünülebilir. Peki Silverlight, .Net RIA Services ve üretilen Entity tipleri göz önüne alındığında söz konusu doğrulama işlemleri acaba nasıl yapılabilir?

Dilerseniz konuyu basit bir örnek üzerinden ele almaya çalışalım. İşe biraz daha renk katmak adınada Silverlight tarafında DataForm veri kontrolünü kullanabiliriz. Nitekim bu kontrol özellikle doğrulama işlemleri sırasında olan hataları gayet hoş bir biçimde gösterebilmektedir. Tabi işe ilk olarak Silverlight projesini oluşturarak başlamak gerektiğini hepimiz biliyoruz. Söz konusu projede .Net RIA Servislerini ele alacağımızdan, veri erişim katmanında(Data Access Layer) Ado.Net Entity Framework veya LINQ to SQL modellerinden birisini kullanmayı tercih edebiliriz. Ben Ado.Net Entity Framework kullanmayı tercih ettim ve kobay tablo olarak Northwind veritabanında yer alan Products nesnesini seçtim. Buna göre oluşan EDM diagramı aşağıdaki gibidir.

Tabiki bu işlemin ardından Web projesine, Domain Service Class öğesininde eklenmesi gerekmektedir. Bu şekilde .Net RIA Servisin, sunucu tarafındaki kısmı ve build işlemi sonrasındada istemci tarafındaki Domain Context parçası oluşturulmuş olacaktır. Ancak dikkat edilmesi gereken önemli bir nokta vardır.

Şekildende görüldüğü gibi Domain Service Class öğesinin eklenmesi sırasında Generate associated classes for metadata özelliği etkinleştirilmiştir. Bu sayede Web projesine, NorthwindService.metadata.cs isimli bir dosyanın daha eklendiği görülür.

Bu metadata dosyası içerisinde ise, Products isimli Entity sınıfı için üretilmiş partial bir tip daha olduğu görülür. Asıl önemli olan bu partial tip içerisinde, ProductsMetadata ({EnitiyName}Metadata) isimli internal erişim belirleyicisine sahip(yani sadece bulunduğu assembly içerisinde kullanılabilen) bir sınıf daha tanımlanmış olmasıdır. Bu sınıf aynı zamanda sealed bir tiptir. Bir başka deyişle kendisinden türetilme yapılamamaktadır.

Peki bu metadata sınıfını neden ürettirdik? Ne işe yaramaktadır?

Senaryomuzda dikkat edileceği üzere Ado.Net Entity Framework modeli kullanılmaktadır. Bu model, veritabanından seçilen nesnelerin karşılığı olan sınıfların otomatik üretilmesinide içermektedir. Dolayısıyla Products tablosunun karşılığı olan Entity tipi otomatik olarak üretilen bir sınıftır aslında. Aynı durumu LINQ to SQL tarafı içinde geçerlidir. Çok doğal olarak üretilen Entity tipi, modele has nitelikler ile süslenmiştir. Örneğin, özelliğin identity olup olmadığı, hangi entity ile ilişkili olduğu vb... Oysaki doğrulama gibi, ek nitelikler yardımıyla gerçekleştirmek isteyebileceğimiz işlemler, Entity' ye değil, .Net RIA Servis tarafına özeldir. Bu nedenle var olan Entity yapısının bozulması istenmediğinden ve hatta otomatik üretimler sonucu eski haline dönmesi ihtimalide bulunduğundan, ek metadata girişlerinin güvenli bir şekilde yapılması için .Net RIA Servis tarafında ayrı bir sınıf daha üretilmektedir. Yani Entity ile ilişkili yapmak istediğimiz ek işlemleri bu metadata sınıfı içerisinde toplayabiliriz. Dolayısıyla doğrulama işlemleri ile ilgili nitelik tanımlamalarının yapılacağı en uygun yerin, üretilen metadata sınıfları olduğunu söyleyebiliriz. Bizde üretilen bu metadata sınıfı üzerinde aşağıdaki değişiklikleri yapabiliriz.


namespace ValidationSystem.Web
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using System.Web.Ria;
    using System.Web.Ria.Data;
    using System.Web.DomainServices;
    using System.Data;

    [MetadataTypeAttribute(typeof(Products.ProductsMetadata))]
    public partial class Products
    {

#pragma warning disable 649

        internal sealed class ProductsMetadata
        {
            private ProductsMetadata()
            {
            }

            public int ProductID;

            [Required(ErrorMessage="Lütfen ürün adını giriniz")] // Mutlaka girilmeli(boş geçilemez)
            public string ProductName;

            [Required] // Mutlaka gerekli
            [RegularExpression("^\\d{2}")]  // İki hanel sayısal değer
            public Nullable<int> SupplierID;

            [Required]
            public Nullable<int> CategoryID;

            [StringLength(20,MinimumLength=3)] // minimum 3 karakter maksimum 20 karakter
            [Required]
            public string QuantityPerUnit;

            [Range(0,300)]
            [Required]
            public Nullable<Decimal> UnitPrice;

            [Range(0,1000)]
            [Required]
            public Nullable<short> UnitsInStock;

            public Nullable<short> UnitsOnOrder;

            public Nullable<short> ReorderLevel;

            public bool Discontinued;

            public EntityState EntityState;
        }

#pragma warning restore 649
    }
}

  • Required niteliği tahmin edileceği üzere, söz konusu alanın mutlaka girilmesi gerektiğini, bir başka deyişle boş geçilemeyeceğini belirtmektedir.
  • Range niteliği ile sayısal değer aralığı belirtilir.
  • StringLength niteliği ise, minimum ve maksimum karaketer aralığını belirtir.
  • RegularExpression niteliğinde ise, basit bir RegEx ifadesi kullanılarak, verinin hangi formatta olması gerektiği belirtilir.

Dikkat edileceği üzere bu niteliklerin benzer özellikleri vardır. Örneğin ErrorMessage özelliklerine atanan değerler ile, hata sonrası gösterilecek mesajın içeriği belirlenebilir. Yapılan bu ilaveler sırasında kullanılan niteliklerin(attributes), istemci tarafında üretilen otomatik cs dosyası içerisinde yer alan Products sınıfınada aktarıldığı gözlemlenecektir.

Artık testleri yapmak üzere XAML tarafındaki geliştirmelere başlayabiliriz. Baştada belirttiğimiz gibi DataForm isimli veri bağlı kontrolden yararlanıyor olacağız. Bu kontrol kendi içerisindeki Field' larda verinin nasıl gösterileceğini tanımlayabilmemizede olanak sağlamaktadır. Ayrıca, doğrulama işlemeleri sırasındaki hata mesajlarınıda güzel bir şekilde göstermektedir. İşte MainPage.xaml içeriğimiz;

<UserControl xmlns:dataControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Data.DataForm"  x:Class="ValidationSystem.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Width="550" Height="455">
    <StackPanel x:Name="LayoutRoot" Background="White" Orientation="Vertical">
        <dataControls:DataForm x:Name="dfProducts" Width="550" Height="425"></dataControls:DataForm>
        <Button x:Name="btnSaveChanges" Content="Save Changes" Width="100" HorizontalAlignment="Left" Height="25" Click="btnSaveChanges_Click"/>
    </StackPanel>
</UserControl>

Kod tarafını ise aşağıdaki gibi geliştirmemiz yeterlidir.

using System.Windows;
using System.Windows.Controls;
using ValidationSystem.Web;

namespace ValidationSystem
{
    public partial class MainPage : UserControl
    {
        // DomainContext nesnesi tanımlanır
        NorthwindContext context = null;

        public MainPage()
        {
            InitializeComponent();
            // DomainContext nesnesi örneklenir
            context = new NorthwindContext();
            // Veri kaynağı olarak Products özelliğinin işaret ettiği referans belirtilir
            dfProducts.ItemsSource = context.Products;
            // Ürünler yüklenir
            context.LoadProducts();
        }

        private void btnSaveChanges_Click(object sender, RoutedEventArgs e)
        {           
            if(dfProducts.Mode== DataFormMode.Display)  //Edit veya Inserted moddayken SubmitChanges metodunun verebileceği olası exception' lara karşı alınan geçici tedbirdir
                context.SubmitChanges();        // Değişiklikler sunucu tarafına gönderilir
        }
    }
}

Uygulamayı Start without debugging modda çalıştırarak testlerimize başlayalım. DataForm kontrolü verileri eğer aksi belirtilmediyse, tipe göre TextBox veya CheckBox gibi kontrollerde göstermektedir. Domain Service öğesi oluşturulurken Enable Editing seçeneği işaretlendiğinden, kontrolün sağ üst köşesinde ekleme, düzenleme ve silme işlemleri için gerekli düğmelerinde otomatik olarak üretildiği görülebilir. Bizim ağırlıklı olarak üzerinde duracağımız kısım doğrulam işlemleridir. Örneğin bir ürünü düzenleme moduna aldığımız varsayalım. Bu durumda, doğrulam işlemlerine tabi tutulan alanlara ait TextBlock kontrollerinin Bold olarak işaretlendiği fark edilecektir. Buda kullanıcıya hangi kontrollerin doğrulama denetimi altında olduğunu işaret eden bir ipucu olarak düşünülebilir. Örnek olarak seçilen ürünün adını boş geçmeye çalıştığımızı var sayalım. ProductName alanı ile ilişkili kontrolü terk ettiğimiz anda(başka bir kontrole geçerek), aşağıdaki şekilde görüldüğü gibi ekranın kırmızı fontlu yazılar ile dolduğunu görebiliriz.

Harika. Wink Burada dikkat edilmesi gereken noktalardan birisi hata mesajıdır. Dikkat edileceği üzere, ilgili niteliğin ErrorMessage özelliğine atanan değer gösterilmektedir. Peki ErrorMessage belirtmediklerimizde durum nasıldır? Örneğin UnitPrice değerini 1000 olarak girdiğimizi varsayalım. Range niteliğinde 0 ile 300 arasında bir değer olabileceğini belirtmiştik. Aşağıdaki durum ile karşılaşırız.

Görüldüğü gibi, built-in tasarlanmış standart bir hata mesajı üretilmektedir. Dolayısıyla doğrulama işlemlerini uyguladığımız senaryolarda ErrorMessage özelliğine bir değer atamamız, kullanıcıyı daha anlaşılır bir şekilde bilgilendirmek adına tercih edilmelidir. İyi güzel her şey hoş ama Asp.Net tarafından biliyoruzki, istersek standart doğrulama işlemleri dışındaki ihityaçlarda CustomValidator bileşeninden yararlanabilmekteyiz. Tabi bu durumda, istemci tarafı için gerekli Javascript içeriğini ve sunucu tarafındaki olay metodu kodlarınıda geliştirmemiz gerekmektedir.

Peki .Net RIA Servislerinin kullanıldığı senaryoda, özel doğrulama işlemleri nasıl ele alınabilir? Bu özel doğrulama işlemleri sınıf seviyesinde veya özellik seviyesinde nasıl uygulanabilir? Bir sonraki blog yazımda bu konulara değinmeye çalışıyor olacağım. Tekrardan görüşünceye dek hepinize mutlu bir yaz günü dilerim.

ValidationSystem.rar (1,85 mb)

Yorum ekle


(Gravatar simgesini gösterecek)

  Country flag

biuquote
  • Yorum
  • Canlı önizleme
Loading