.Net 6.0 Üzerinde Validation Factory Yaratmak Part 1

Selamlar,

Bu makalede, bir projede ortak kullanılabilecek validation ve operationları, modellerin propertyleri üzerindeki işaretlemelere göre üretip, topluca işleteceğiz. Ve çıkan sonuçları hep beraber inceleyeceğiz.

Öncelikle gelin, olayı en başından ele alalım:

Validators/IValidator: Esas amaç, girilen input bir alanın kontrol edilmesidir. O zaman gelin bir interface yaratalım ve istenen value bir değere göre, Validate() methodunu çalıştıralım. Geriye bool(true veya false), Exception(hata) döndüren bir Tuple bekleyelim.  Unutulmamalıdır ki, bu değerler hata yakalamak haricinde, referance boyutunda değerleri değiştirmek, (Encrypt, Decrypt ya da Hash) gibi methodlar ile içeriği gizlemek ya da göstermek için de kullanılabilirler. Aşağıda, bu IValidator interface’inin beklediği parametreler, detaylıca anlatılmıştır.

  • T value“=> Sınıfa ait, kontrol edilmek amaçlı işaretlenmiş property’nin değeri.
  • int? param” => Null olabilen, ilgili property’nin işaretlendiği attribute’e ait integer parametredir. Bir Attribute, parametre ala da bilir almaya da.
  • “string source” => İlgili property’nin, string adıdır.
  • PropertyInfo? pi” => İlgili property’nin referance’ına ulaşmak amacı ile gönderilen nullable değerdir. Amaç “Encrypt, Decrypt ve Hashişlemlerinde, ilgili propertynin referance değerine ulaşmaktır. Böylece, orjinal değeri değiştirlebilecek yani encrypt ya da decrypt yapılabilecektir.
  • “object? model” => İlgili propertynin referance değerini değiştirmek, yani “Encrypt, Decrypt veya Hashlemek için gönderilen, object valuedur.

Validators/DefaultValidator: Belirtilen işaretlemeye uygun Validator bulunamaz ise, hata alınmaması amacı ile default bir validator yaratılıp, bunun geriye dönülmesi sağlanmıştır.

Validators/DateValidator: Tarih alanlarının yaş ya da zaman kontrolü amacı ile, belirtilen minimum yıldan büyük olmasına bakılır. Aksi durumda, “errorList” hata listesine ilgili error eklenerek geriye dönülür. Bu Validator’da tek hata dönülse de, bazı validatorlarda birden fazla hata dönüldüğü için, global tuple errorList (“List<bool,Execption>()“) şeklinde tanımlanmıştır.

Validators/StringValidator: Bu validator’da, string bir text’in 3 farklı kontrolü yapılmaktadır.

  • 1. Kontrol “if (stringValue.Length > max)” girilen text, belli bir karakterden fazla olamaz.
  • 2. Kontrol “(!(!stringValue.Equals(stringValue.ToLower())))” girilen text’in içinde, en az bir karakterin büyük harf olması gerekmektedir.
  • 3. Kontrol { “!”, “@”, “#”, “$”, “%”, “^”, “&”, “*”, “(“, “)”, “-” } girilen text’in içinde, ilgili karakterlerden hiçbiri geçmemelidir.

Bu 3 hata, bir tuple errorList (“List<bool,Execption>()“)’e doldurulmakta ve geri dönülmektedir. Böylece tüm kontrollerin, tek bir sonuç altında geriye dönülmesi sağlanmaktadır.

if (errorList.Count == 0): Eğer hiç hata yok ise “”All tests succesful” şeklinde bir mesaj konsola’a basılmaktadır.

Validators/EmailValidator: Bu validatorda, işler biraz farklılaşmaktadır. Burada girilen bir email’in validasyonu, girilen parametreye göre farklı bussineslarda kontrol edilmektedir. Bu farklı bussines seçimi aslında, hemen bir sonraki adımda tanımlanan “enum EmailValidateType” bir “int? validateType” ile yapılmaktadır. Bu enum içerisindeki (Syntax, Goverment, Education ve Gmail)  senaryolarının kontrolü yapılmıştır.

  1. case EmailValidateType.Syntax“: Standart geçerli bir email kontrolünün yapıldığı bir senaryodur.
  2. case EmailValidateType.Gmail:” Girilen mailin, gmail olup olmadığı kontrol edilir. Değil ise, en başta yaratılan “errorList“‘e eklenir.
  3. case EmailValidateType.Government: Girilen mailin, bir devlet kurumuna ait olup olmadığı kontrol edilir.
  4. “case EmailValidateType.Education:” Girilen mailin, bir üniversite email’i olup olmadığı kontrol edilmektedir.

Not: Burada aslında “single responsibility” biraz bozulmuş gibi görünse de, ortak amaç email kontrolü altında farklı bussinesların koşturulmasıdır. Kod okunaklığı açısından bu yol tercih edilmiştir. Aksi takdirde herbir senaryo için, farklı bir attribute’un yaratılması gerekecek, bu da test, devops ve debug gibi süreçleri daha da zorlaştıracaktır. Kısacası, benzer işleri ortak bir grup altında toplamak, bazen iş hayatında normal karşılanabilmektedir.

Email Bussines Validate Enum: Mail kontrolü için ilgili bussines seçimi, aşağıda tanımlanmış Enum paramtrelerine göre yapılmaktadır.

Validators/EncryptValidator: Bu validator’da amaç, text alanın kontrolü değil içeriğin “2 way encryption” dediğimiz, geri çevirilebilir şifrelenmesidir. Bu yüzden ilgili property’nin PropertyInfo’su => “System.Reflection.PropertyInfo pi” alınmıştır. Bu PropertyInfo ile, ilgili alanın değeri değiştirilebilecektir. Ayrıca “object model“, propertyleri kontrol edilen sınıfın ta kendisidir.

  • if (!typeof(T).IsValueType && typeof(T) != typeof(String))” : T value değerin, “ValueType” ve “string” olup olmadığı kontrol edilir.
  • “using (Encryption en = new()) { pi.SetValue(model, en.EncryptText(stringValue)); }”: İlgili property değerinin şifrelenip setlendiği kısımdır.
    • string stringValue = value.ToString(): Kontrol edilen sınıfın, işaretli property değeridir.
    • en.EncryptText(stringValue): EncryptText(), bir sonraki adımda anlatılacak olan çift yönlü yani geri dönülebilir şifreleme methodudur.
    • pi.SetValue(): İlgili property değerinin setlenmesi için PropertyInfo class’ının SetValue() methodu kullanılarak, var olan data güvenlik amaçlı şifreli hali ile değiştirilir.

Kısaca bu validator, kontrol amaçlı değil, var olan property’nin referance değerinin değiştirilmesi amacı ile kullanılmıştır.

Validators/HashValidator: Bu validator’da amaç, text alanın kontrolü değil içeriğin “One way encryption” dediğimiz, yani geri çevrilemiyecek şekilde şifrelenmesidir. Burada EncryptionValidator’dan farklı olarak, bir “SaltKey”‘e ihtiyaç duyulmaktadır. Normalde tek bir SaltKey kullanılsa da, bu örnekde her HashKey için farklı bir SaltKey kullanılmış ve HashKey’in içine, ilgili SaltKey gömülmüştür.

Security/IEncryption: İşaretlenen propertyleri tek ve çift yönlü şifrelemek için kullan sınıfın genel işlevlerinin gösterildiği Interface, aşağıdaki gibidir.

  • EncryptText: Çift yönlü verilen text’in, şifrelenmesini sağlar.
  • DecryptText: Verilen encrypt text’in, deşifre edilmesini sağlar.
  • HashCreate: Tek yönlü verilen textin, şifrelenmesini sağlar. Kısaca decrypt edilemez.
  • ValidateHash: Girilen okunur bir text’i, aynı SaltKey ile Hashleyip, eşitliği kontrol edilecek diğer Hashli key ile matchlenip sonuç geriye dönülür.
  • GenerateSalt: Hashleme amaçlı ihtiyaç duyulan SaltKey’in, üretilmesi için kullanılır.

Security/Encryption: Aşağıda görüldüğü gibi, EncryptValidator ve HashValidator’ın kullanacağı methodlar bu sınıf altında tanımlanmıştır. “EncryptText ve HashCreate” methodları ile istenen içerik gizlenir.

Model/User: Aşağıda, User modelin belli propertyleri, ilerde tanımlanacak Attributelar ile işaretlenmiştir. Bu tanımlamalara göre gönderilen UserData, işlenmeden önce çalıştırılacak validatorler bu attributelara göre çağrılacak ve ilgili alanlar duruma göre, ya kontrol edilecek ya da içerikleri şifrelenecektir.

  • [StringData(max = 10)] => UserName’in en fazla 10 karakter olması, Custom bir şekilde sağlanmıştır.
  • [HashData] => Password’ün güvenlik amaçlı ,geri dönülmeyecek şekilde şifrelenmesi sağlanmıştır.
  • [DateData(minYear =1900)] => BirthDate alanının 1900 yılından daha eski bir tarih olması engellenmiştir.
  • [EmailData(type = EmailValidateType.Syntax)] => Email alanının, “Syntax” parametresi ile geçerli olup olmadığına bakılmıştır.
    • [EncryptData] => Gene Email alanının, 2. bir kontrol ile şifrelenmesi sağlanmıştır.
  • [EmailData(type = EmailValidateType.Gmail)] => Email2 alanının, “Gmail” paramteresi ile Gmail’e uygun bir mail adresi olup olmadığı kontrol edilmiştir.
  • [EncryptData] => Gsm alanının güvenlik amaçlı 2 yönlü, yani geriye dönülebilir şekilde şifrelenmesi sağlanmıştır.

Sıra geldi, bir sınıfın propertylerini işaretleme amaçlı kullanılan attributelere. Doğru işaretleme ve istenen bussines’a göre doğru parametre atama, ilgili validator’un koşturulması sırasında,  tanımlı olduğu property için çağrılmasını ve gerekli kontrollerin yapılmasını sağlar. Aslında tanımlayacağımız attributelar, birer kabuktur. Yani içleri boş, parametre alan sadece işaretleme amaçlı kullanılan basit sınıflardır. Bu tanımlamaları, bir sonraki makalede kaldığımız yerden devam ederek detaylıca inceleyeceğiz. Daha sonrasında, bu attributelara göre doğru validator’ı nasıl seçeceğimize ve birden fazla attribute olması durumunda ne yapacağımıza hep beraber bakacağız. Ayrıca attributelere ait birden fazla parametre durumlarını da ayrıca araştıracağız.

Bir sonraki makalede görüşmek üzere hepinize hoşçakalın.

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

E-posta hesabınız yayımlanmayacak.