Fluent Validation
Yazılım geliştirirken sistemin daha düzgün ve kararlı çalışması için birçok yerde validasyon(doğrulama) işlemleri yapıyoruz. Küçük çaplı projelerde validasyon işlemleri için kendi yazdığımız basit yapıları kullanabiliyorken proje büyüdükçe oluşturduğumuz yapı yetmeyebilir. Gerek okunması, kuralların esnekliği gerekse yönetilebilirliği yüzünden daha büyük yapılara ihtiyaç duyuyoruz. Bu amaçla hazırlanmış birçok açık kaynaklı veya üçüncü parti validation(doğrulama) kütüphaneleri mevcuttur.
Bu yazıda .NET uygulamaları için Fluent Validation kütüphanesininin kurulumuna ve kullanımına basit bir örnek üzerinden bakacağız.
Fluent Validation Kurulumu
Fluent Validation kütüphanesi açık kaynaklıdır ve kaynak kodlarına GitHub üzerinden erişebilirsiniz. Projenizde kullanmak için nuget paketini kurmanız gerekmektedir. Aşağıdaki nuget komutuyla paketi projenize dahil edebilirsiniz:
Install-Package FluentValidation
İlk Validator’un Oluşturulması
Fluent Validation’da validatorlar(doğrulayıcı) genelde bir sınıf özelinde yazılır. Örnek vermek gerekirse Customer isimli bir sınıfımız varsa bunun için bir CustomerValidator yazarız. Bu isimlendirme veya işleyiş zorunlu değildir, sadece genel yaklaşım bu şekildedir. Yazacağımız validator sınıfını AbstractValidator<T>
üzerinden miras almamız gerekiyor. Buradaki generic tipi simgeleyen T
tahmin edeceğiniz üzere Customer olacaktır. (AbstractValidator<T>
, içerisine verdiğimiz sınıfa kurallar yazmak, nesnenin geçerli olup olmadığını kontrol etmek gibi işlemleri gerçekleştirir.)
Kod örneğini Customer isimli sınıf üzerinden ele alalım:
public class Customer { public int Id { get; set; } public string Name { get; set; } public string Password { get; set; } public string Email { get; set; } }
Customer sınıfına ait kuralları tanımlamak için bir sınıf oluşturuyoruz ve gerekli miras alma işlemlerini yapıyoruz.
using FluentValidation; public class CustomerValidator : AbstractValidator<Customer> { }
Validasyon kurallarının tanımlanması, oluşturduğumuz Validator sınıfına ait constructor
içerisinde yapılır. RuleFor()
metotu çağrılarak lambda expression
ile hangi property üzerinden kural yazılacağı sağlanır. Örneğin, Name property’sinin boş olmamasını ve minimum 10 karakter olmasını sağlayan kural aşağıdaki gibi tanımlanmaktadır.
public class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { RuleFor(customer => customer.Name).NotEmpty().MinimumLength(10); } }
Bu basit tanımlamaların yanı sıra bazı genel tanımlamaları da aşağıdaki örnek üzerinden inceleyebiliriz.
public class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { RuleFor(customer => customer.Id) .GreaterThan(0).WithMessage("Id alanı 0'dan büyük olmalıdır!"); RuleFor(customer => customer.Email) .EmailAddress() .WithMessage("Geçerli bir e-posta değeri giriniz!").When(i => !string.IsNullOrEmpty(i.Email)); RuleFor(customer => customer.Name) .NotEmpty().WithMessage("İsim alanı boş geçilemez!") .Length(5, 20).WithMessage("İsim alanı 5 ile 20 karakter arasında olmalıdır!"); RuleFor(customer => customer.Password) .NotEmpty().WithMessage("Parola alanı boş geçilemez!") .Must(IsPasswordValid).WithMessage("Parolanız en az sekiz karakter, en az bir harf ve bir sayı içermelidir!"); } private bool IsPasswordValid(string arg) { Regex regex = new Regex(@"^(?=.*[A-Za-z])(?=.*\d)[A-Za-z\d]{8,}$"); return regex.IsMatch(arg); } }
Yukarıdaki tanımlanan kuralların açıklanmış haline bakacak olursak:
- Id değeri 0’dan büyük olmalıdır değil ise de tanımlanan hata mesajı verilecektir.
- Email boş geçilebilir fakat boş değil ise de kontrolü yapılır. Hatalı olması durumunda tanımlanan hata mesajı verilecektir.
- Name değeri boş geçilemez, boş geçilir ise o kurala ait hata mesajı gönderilir. Uzunluğu 5-20 karakter arasında olması gerekiyor, olmaz ise de o kurala ait hata mesajı verilecektir.
- Password alanı boş geçilemez, boş geçilir ise o kurala ait hata mesajı gönderilir.
- Password alanına ait kuralda
Must
diye bir ifade mevcut.Must
delegedir, bizim kullandığımız ise 1. overload.Fun<string, bool>
, string değer alan ve bool değer döndüren bir yapı. Bu metotu aynı sınıf içerisine oluşturduk ve Password alanına ait değeri direkt parametre olarak gönderdik. Kurallarımızda ise değerin “en az sekiz karakter, en az bir harf ve bir sayı” içermesi gerektiğini söyledik. Şayet bu kural sağlanır ise true değeri dönecek ve kural sağlanmış olacak. Kural sağlanmaz ise de o kurala ait hata mesajı gönderilecektir.
Kompleks Yapılar Üzerinde Validation İşlemi
Validation işlemlerini yaparken kompleks tipler üzerinde de çalışıyoruz. Fluent Validation bu konuda bize esneklik tanıyarak kompleks tipler içerisinde tekrardan kural tanımlamamıza olanak sağlıyor.
Örneğin, Customer ve Address adında sınıflarımız olsun.
public class Customer { public string Name { get; set; } public Address Address { get; set; } }
public class Address { public string Line1 { get; set; } public string Line2 { get; set; } public string Town { get; set; } public string County { get; set; } public string Postcode { get; set; } }
Bu sınıflara birer Validator tanımlansın
public class AddressValidator : AbstractValidator<Address> { public AddressValidator() { RuleFor(address => address.Postcode).NotNull(); //etc } }
public class CustomerValidator : AbstractValidator<Customer> { public CustomerValidator() { RuleFor(customer => customer.Name).NotNull(); RuleFor(customer => customer.Address).SetValidator(new AddressValidator()); } }
Kompleks tip içerisinde başka bir sınıf örneğine kural atamak için SetValidator
metotunu kullanarak, Validator’ün bir örneğini parametre olarak veriyoruz. Böylece Customer sınıfına ait bir nesneyi validasyon işlemine tabi tuttuğumuzda bunun yanında AddressValidator sınıfı da çalışacaktır.
Validator Testi ve Validasyonların Yapılması
Fluent Validation kütüphanesinde doğrulama işlemlerini validator nesnesinin Validate() metoduyla yaparız. Aşağıdaki örnek üzerinden bakalım.
Customer customer = new Customer(); CustomerValidator validator = new CustomerValidator(); ValidationResult result = validator.Validate(customer);
Validasyon işleminin yapılması için kullanmak istediğimiz Validator sınıfının bir örneğini oluşturup, işlemi gerçekleştirmek için Validate
metotuna kontrol etmek istediğimiz nesneyi parametre olarak veriyoruz.
Bu Validate
metotu geriye ValidationResult
nesnesi döndürür. ValidationResult
nesnesi şu property’leri içerir:
IsValid
: Validasyon işleminin başarılı olup olmadığına dair boolean değer döndürür.Errors
: Validasyon işlemi başarısız ise hataların bulunduğu property’leri ve ona ait hata mesajını döndürür.
Customer customer = new Customer(); CustomerValidator validator = new CustomerValidator(); ValidationResult results = validator.Validate(customer); if (!results.IsValid) { foreach (var error in results.Errors) { string errorMessage = $"{error.PropertyName} -> {error.ErrorMessage}"; } }
Yukarıdaki kod validasyon işleminin başarısız olması durumunda gelen hatalar içerisinde dönüp, hata mesajlarını ele almamızı sağlayacaktır.
Fluent Validation kütüphanesinin en temel şekilde nasıl kullanılabileceğine yönelik 1-2 örnekle kısa bir inceleme yaptık.