Ayyıldız2 | 2008 TR Yapısı • 1-99 Orta Emek Destan • Oto Avsız • 10 Temmuz 21:00 HEMEN TIKLA!
ASP.NET Core Custom Validation Attribute Yazma Örneği
Built-in validation attribute'ları çoğu senaryo için yeterli olsa da bazen işler karmaşıklaşıyor ve kendi özel validation kurallarınızı yazmanız gerekiyor. Geçen bir projede TC kimlik numarası doğrulaması yapmam gerekti. Tabii ki bunun için hazır bir attribute yok. İşte tam bu noktada custom validation attribute devreye giriyor. Ben ilk custom attribute yazımımda bayağı zorlanmıştım çünkü ValidationAttribute sınıfının nasıl çalıştığını tam anlamıyordum. Ama bir kere mantığını kavradıktan sonra çok güçlü bir araç olduğunu fark ettim. Hatta şimdi projelerimde bir validation helpers kütüphanesi oluşturdum ve tekrar tekrar kullanıyorum.
Custom Validation Attribute Neden Gerekli
Düşünün ki bir yaş kontrolü yapmanız gerekiyor ama bu kontrol sadece "18'den büyük mü" değil, aynı zamanda "120'den küçük mü" ve "doğum tarihi gelecekte mi" gibi birden fazla koşulu içeriyor. Range attribute'u ile yapabilirsiniz belki ama ya tarih bazlı hesaplama gerekiyorsa? Ya da bir IBAN numarasının geçerli olup olmadığını kontrol etmeniz gerekiyorsa? Bu tür senaryolarda custom attribute yazmak hem kodu temiz tutar hem de DRY prensibine uygun olur. Aynı validation kuralını farklı modellerde tekrar tekrar yazmazsınız, bir kere attribute olarak yazarsınız ve istediğiniz yerde kullanırsınız.
Custom validation attribute yazmanın bir diğer avantajı da testedilebilirlik. Attribute'unuz bağımsız bir sınıf olduğu için unit test yazmak çok kolay. Ben her custom attribute için mutlaka unit test yazıyorum çünkü validation logic'te bug olursa sonuçları ağır oluyor. Yanlış veri veritabanına girerse temizlemesi çok zor. Bir de şunu belirteyim, custom attribute'lar client-side validation ile de entegre edilebilir. IClientModelValidator interface'ini implement ederek jQuery validation ile çalışan client-side kurallar da tanımlayabilirsiniz. Bu biraz daha advanced bir konu ama bilmenizde fayda var.
Basit Custom Attribute Örneği - Yaş Kontrolü
C#:
using System.ComponentModel.DataAnnotations;
public class MinimumYasAttribute : ValidationAttribute
{
private readonly int _minimumYas;
public MinimumYasAttribute(int minimumYas)
{
_minimumYas = minimumYas;
ErrorMessage = $"En az {minimumYas} yaşında olmalısınız.";
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null)
return ValidationResult.Success; // Required ayrıca kontrol eder
if (value is DateTime dogumTarihi)
{
var bugun = DateTime.Today;
var yas = bugun.Year - dogumTarihi.Year;
if (dogumTarihi.Date > bugun.AddYears(-yas))
yas--;
if (yas < _minimumYas)
{
return new ValidationResult(
string.Format(ErrorMessage, validationContext.DisplayName));
}
if (dogumTarihi > DateTime.Today)
{
return new ValidationResult("Doğum tarihi gelecekte olamaz.");
}
return ValidationResult.Success;
}
return new ValidationResult("Geçersiz tarih formatı.");
}
}
Bu attribute DateTime tipindeki bir property üzerinde yaş kontrolü yapıyor. Dikkat edin, value null geldiğinde Success dönüyoruz. Neden? Çünkü null kontrolü Required attribute'unun işi. Validation attribute'larında tek sorumluluk prensibini uygulamak önemli. Her attribute kendi işini yapsın, başkasının işine karışmasın. Yaş hesaplamasında da dikkatli olmak lazım, basit yıl farkı almak yetmez çünkü doğum günü henüz gelmemiş olabilir.
Daha Gelişmiş Örnek - TC Kimlik Numarası Doğrulama
C#:
public class TCKimlikNoAttribute : ValidationAttribute
{
public TCKimlikNoAttribute()
{
ErrorMessage = "Geçerli bir TC Kimlik Numarası giriniz.";
}
protected override ValidationResult IsValid(object value, ValidationContext validationContext)
{
if (value == null || string.IsNullOrWhiteSpace(value.ToString()))
return ValidationResult.Success;
string tcNo = value.ToString().Trim();
// 11 haneli olmalı
if (tcNo.Length != 11)
return new ValidationResult(ErrorMessage);
// Tamamı rakam olmalı
if (!tcNo.All(char.IsDigit))
return new ValidationResult(ErrorMessage);
// İlk hane 0 olamaz
if (tcNo[0] == '0')
return new ValidationResult(ErrorMessage);
// Algoritma kontrolü
int[] digits = tcNo.Select(c => int.Parse(c.ToString())).ToArray();
int tekToplam = digits[0] + digits[2] + digits[4] + digits[6] + digits[8];
int ciftToplam = digits[1] + digits[3] + digits[5] + digits[7];
int onuncuHane = ((tekToplam * 7) - ciftToplam) % 10;
if (digits[9] != onuncuHane)
return new ValidationResult(ErrorMessage);
int toplam = digits.Take(10).Sum();
if (digits[10] != toplam % 10)
return new ValidationResult(ErrorMessage);
return ValidationResult.Success;
}
}
TC Kimlik Numarası doğrulaması Türkiye'deki projelerde çok sık lazım olan bir şey. Bu algoritma resmi algoritmadır ve hem uzunluk hem de matematiksel doğruluk kontrolü yapıyor. Ben bunu bir kütüphane olarak tutuyorum ve her projede kullanıyorum. Dikkat edin, bu sadece format kontrolüdür, numaranın gerçekten birine ait olup olmadığını kontrol etmez. Gerçek doğrulama için NVI servislerini kullanmanız gerekir.
Kullanım Örneği
C#:
public class KullaniciModel
{
[Required(ErrorMessage = "Ad zorunludur.")]
public string Ad { get; set; }
[Required(ErrorMessage = "TC Kimlik No zorunludur.")]
[TCKimlikNo]
public string TCKimlikNo { get; set; }
[Required(ErrorMessage = "Doğum tarihi zorunludur.")]
[MinimumYas(18)]
[DataType(DataType.Date)]
public DateTime? DogumTarihi { get; set; }
}
Kullanım bu kadar basit. Attribute'u property'nin üzerine koyuyorsunuz ve gerisini framework hallediyor. DogumTarihi'ni nullable DateTime yaptığıma dikkat edin. Eğer nullable yapmazsanız default değer olan 01.01.0001 gelir ve Required attribute'u bunu geçerli kabul eder. Bu çok yaygın bir hata.
İpuçları ve Best Practice'ler
Custom attribute yazarken birkaç şeye dikkat edin. Birincisi, attribute constructor'ında ağır işlemler yapmayın. Attribute'lar reflection ile yaratılır ve cache'lenir, constructor'da veritabanı çağrısı falan yapmayın. İkincisi, ValidationContext parametresini kullanarak dependency injection'dan servis alabilirsiniz. Mesela veritabanı kontrolü gerekiyorsa GetService metodu ile DbContext'e erişebilirsiniz ama ben bunu tavsiye etmiyorum, bu tür kontroller için Remote Validation veya IValidatableObject daha uygun.
Bir de hata mesajlarını her zaman parametrik yapın. Hardcoded Türkçe mesajlar yerine resource dosyalarından çekmek, çoklu dil desteği eklemeniz gerektiğinde hayat kurtarır. Şahsen ben küçük projelerde bile resource kullanmaya çalışıyorum çünkü alışkanlık olması lazım. Son olarak, attribute'larınızı mutlaka test edin. Geçerli ve geçersiz senaryolar için unit test yazın. Validation'da bug çıkması kullanıcı deneyimini doğrudan etkiler.
Emeğiniz ve katkınız için teşekkür ederiz!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!
Konunuz gerekli incelemelerden geçerek onaylandı. Topluluğumuza katkılarınızın devamını bekliyoruz.
İyi forumlar!

Şu an konuyu görüntüleyenler (Toplam : 0, Üye: 0, Misafir: 0)
Benzer konular
- Cevaplar
- 2
- Görüntüleme
- 375
- Kilitli
- Cevaplar
- 7
- Görüntüleme
- 2K
- Kilitli
- Cevaplar
- 1
- Görüntüleme
- 427
Metin2 Hile İstek
c# oto tuş hakkında destek
- Cevaplar
- 8
- Görüntüleme
- 678