Sayfalar

7 Haziran 2013 Cuma

ASP.NET MVC DERSLERİ ( 6.9 ) DATAANNOTATIONS CUSTOM VALIDATION

MVC framework un genişletilebilir olması demek, kendi doğrulama mantığımızı yazmak için sınırsız sayıda yöntemin olması demektir. Biz 2 temel senaryo üzerinde duracağız.

  1. Doğrulama mantığını bir validation attribute içerisinde paketleme (Custom Validation Attribute)
  2. Doğrulama mantığını bir modelin kendi içerisinde paketleme (IValidatableObject)
Birinci yöntemle oluşturduğumuz bir annotation nesnesini başka modellerde de kullanabiliriz. Diğer yöntemde ise doğrulama işlemlerini, modelin içerisinde yaparız. Ayrıca bu yöntem daha kolaydır. Çünkü modelin özelliklerini yine modelin içerisinde doğrulamadan geçiririz. Ama bu doğrulanabilir nesne başka modeller için kullanılamayabilir. Bu iki yöntemi daha iyi anlamak için ayrı ayrı başlıklarda inceleyelim.

Custom Annotations

Örneğin kullanıcı adı 10 sözcükten fazla olmasın istiyoruz. On kelime ve daha fazlasından oluşan string bir değer içermeyen özellik istedigimiz her yerde, bu annotation nesnesini kullanabiliriz.

Tüm validation attribute nesneleri (Range, Required gibi...) ValidationAttribute sınıfından türemiştir. Bu sınıf System.ComponentModel.DataAnnotations kütüphanesi içerisindedir. Custom validation sınıfımız aşağıdaki gibi olacaktır:
using System.ComponentModel.DataAnnotations;
namespace HaberPortal
{
    public class MaxWordsAttribute : ValidationAttribute
    {
    }
}

Validation işlemini uygulamak için herhangibir, IsValid metodunu override etmemiz lazım. Bu metoddan bir tanesinin kullanımı aşağıdadır:
public class MaxWordsAttribute : ValidationAttribute
{
    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        return ValidationResult.Success;
    }
}

IsValid metoduna geçirdiğimiz ilk parametre olan value, doğrulamada kullanacağımız değerdir. Peki bu value değerini ne ile karşılaştıracağız. Yani girilen string değer, kaç tane kelimeden büyükse, hata mesajı vereceğiz. Bu karşılaştırma değerini kullanıcıdan alsak daha iyi. Şimdi sınıfımıza parametre alan bir yapıcı metod ekliyoruz.
public class MaxWordsAttribute : ValidationAttribute
{
    public MaxWordsAttribute(int maxWords)
    {
        _maxWords = maxWords;
    }
    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        return ValidationResult.Success;
    }
    private readonly int _maxWords;
}

Böylece, girilen stringin en fazla kaç kelimeden oluşması gerektiğini kullanıcıya vermiş oluyoruz. Şimdi hata yakalabiliriz.
public class MaxWordsAttribute : ValidationAttribute
{
    public MaxWordsAttribute(int maxWords)
    {
        _maxWords = maxWords;
    }
    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            var deger = value.ToString();
            if (deger.Split(' ').Length > _maxWords)
            {
                return new ValidationResult("Çok fazla kelime!");
            }
        }
        return ValidationResult.Success;
    }
    private readonly int _maxWords;
}

Böylece kullanıcının belirleyeceği bir maksimum kelime sayısı ile girilen değerin içerisindeki kelime sayısı karşılaştırılarak, doğrulama yapılır. Doğrulama sonucunda Validation.Success diye bir değer döneriz. Burada ayrıca hard-coded bir mesaj yazdırdık.

Tek problemimiz hard-coded mesajdır. Geliştirici bu mesajı değiştirmek isteyebilir. Bu bağlamda, kodlarımızı son olarak değiştiriyor. Custom Validation Attribute sınıfımızın son hali:
public class MaxWordsAttribute : ValidationAttribute
{
    public MaxWordsAttribute(int maxWords)
        :base("{0} alanı çok fazla kelime içeriyor.")
    {
        _maxWords = maxWords;
    }
 
    protected override ValidationResult IsValid(
        object value, ValidationContext validationContext)
    {
        if (value != null)
        {
            var deger = value.ToString();
            if (deger.Split(' ').Length > _maxWords)
            {
                var errorMessage = FormatErrorMessage(
                    validationContext.DisplayName);
                return new ValidationResult(errorMessage);
            }
        }
        return ValidationResult.Success;
    }
    private readonly int _maxWords;
}


Artık annotation nesnemiz için kendimiz bir hata mesajı girebiliriz. Eğer girmezsen varsayılan olarak yukarıda belirlediğimiz mesaj görünecektir. Ayıca FormatErrorMessage metodu da , eğer hata mesajını bir resource file içerisinden alıyorsak, bu değeri, modelin özelliğinin adı ile beraber formatlamasını sağlar. Örneğin;
[MaxWords(10)]
public string Ad { get; set; }

hata mesajı: Ad alanı çok fazla kelime içeriyor.
[MaxWords(10, ErrorMessage="{0} alanına daha az kelime girin.")]
public string Ad { get; set; }

hata mesajı: Ad alanına daha az kelime girin.

Artık bu oluşturduğumuz Validation Attribute (MaxWordAttributes) nesnesini, istediğimiz alanlar için kullanabiliriz.

IValidatableObject

Modelimizi, IValidatableObject sınıfından türetirsek, modelimiz kendi kendini doğrulama yeteneğine sahip olur. Örneğin;
public class Kullanici : IValidatableObject
{
    public IEnumerable<ValidationResult> Validate(
        ValidationContext validationContext)
    {
        if (Ad != null &&
            Ad.Split(' ').Length > 10)
        {
            yield return new ValidationResult("Ad alanı çok fazla kelime içeriyor!",
                new []{"Ad"});
        }
    }
    // diğer özellikler
    // ...
}

İki versiyon arasındaki fark;

  • IsValid yerine Validate metodu çağrılır. Buradaki önemli fark, parametre ve geri dönüş tipinin farklı olması.
  • Tek bir ValidationResult nesnesi yerine, IEnumerable<ValidationResult> gibi bir liste döner. Sebebi, tüm modeli doğruluyoruz ve birden çok alanı model içerisinde doğrulama yapmak ve birden çok hata mesajı dödürmek isteyebiliriz.
  • Validate metoduna value değerini göndermedik, çünkü zaten modelin özelliklerini doğruluyoruz ve modelin özellikleri zaten modelin içerisinde olduğundan bu parametreye ihtiyacımız yok. 

Hiç yorum yok:

Yorum Gönder