Fluent Validation ile Server-Side Validation İşlemleri

@ 21 Ağustos 2009 tarihinde yazdı. Yazıya yorum yazın.

Merhaba sevgili arkadaşlar,

Bu yazımda sizlere projelerinizde Validation işlemlerinizi yapabilmek adına kullanabileceğiniz OpenSource bir uygulama olan FluentValidation‘dan bahsedeceğim. Dilerseniz öncelikle validasyon kavramı nedir ve neden önemlidir kısaca bir bakalım…

Validation Nedir, Neden Gereklidir ?

Validation işlemleri genellikle web uygulamalarında karşımıza çıksada aslında her türlü proje tipinde kullanılması gereken önemli tekniklerden biridir. Validation dediğimiz şey aslında sadece bir kontrol sistemidir. Kontrol ettiğimiz şey ise, kullanıcının giriş yapabileceği hemen hemen her türlü input kontrolüne girilen bilgilerin tutarlılığıdır. Örnek vermek gerekirse, bir web sitesine üye olacağımızı düşünelim. Böyle bir durumda karşımıza, bizden kullanıcı adı, şifre ve mail gibi çeşitli bilgiler isteyen bir sayfa gelir. Veri tutarlılığı açısından bu girilen bilgiler öncelikli olarak mutlaka ama mutlaka girilmek zorundadır. (örneği daraltıp, kullanıcı adı, şifre ve mail üzerinden gidiyorum) Bunun dışında girilen mail adresinin formatı da standart mail adresi formatı ile uyuşmalıdır. Yani girilen bilginin içinde birden fazla @ işareti olamaz gibi…

Yukarda da bahsettiğim gibi bu tarz kontroller her türlü proje tipinde yapılması gereken işlemlerdir. Fakat projeniz bir web uygulaması ise bu validasyon işlemlerinin yapılması gerekliliği bir adım daha öne çıkan bir önceliğe sahip oluyor. Bunun başlıca sebeplerinden biride tabiki güvenliktir. Sayfanızda yer alan özellikle text inputları injectionlara yol açabilecek kontrollerdir. JavaScriptInjection ve SQLInjection gibi saldırıların önüne geçmek için kullanabileceğiniz en etkili yöntemlerden biri etkili bir validasyon kontrolü yapmaktır. Bir diğeride girilen verilerden injectionlara neden olabilecek kodları ayrıştırmak için bu verileri bir RegEx filtresinden geçirmektir. Validasyon kontrolü güvenlik dışında ayrıca, veritabanına girilecek olan verilerin tutarlılığı açısından da önemli bir adımdır. Bu bağlamda yazımızın geri kalan kısmı web uygulamaları üzerine olacaktır. Fakat FluentValidation’ ı , desktop veya console gibi farklı uygulama tiplerinde de kullanabilirsiniz.


Validation Nerede ve Nasıl Yapılır ?

Validation işlemlerini, projelerimizde iki ana layer’a yayabiliriz. İlk olarak Client tarafında GUI katmanında JavaScript ile bir validation kontrolü yapıp ardından, Server tarafında daha etkili bir şekilde Validation veya Business katmanında bir kontrol yapabiliriz. Her iki katmandada yaptığımız işlemler özünde aynıdır, öyleyse neden iki kere yapma ihtiyacı duyuyoruz buna şimdi değineceğim…

Öncelikle neden JavaScript ile GUI katmanında bir validasyon yaptığımızı açıklayalım. Şimdi, web uygulamalarında, kullanıcı bilgileri girdikten sonra sayfayı sunucuya gönderir. Biz sayfa sunucuya gitmeden önce bir kontrol yaparsak eğer, girilen bilgilerin tutarlılığını sayfayı sunucuya göndermeden önce yapabilmiş oluruz, böyle bir durumda tutarlılığı bozan birşeyler varsa sayfayı sunucuya göndermeden önce kullanıcıya bunu belirtme şansımız olur. Buda gereksiz yere kullanıcının zaman kaybetmesini önler ve gereksiz yere zaten tutmayan veriler ile server-side validasyon yapmamıza gerek kalmaz. Buna örnek olarak, mutlaka girilmesi gereken verilerin kontrolü ve mail adresi formatının tutarlılığı gibi şeyler verilebilir. Bunun yanında server-side validasyonda şu gibi durumlarda geçerlidir. Mesela kullanıcı adının daha önceden kullanılan bir isme eşit olup olmadıgı kontrolünü yapabilmek için mutlaka bunu server tarafında yapmak gerekir. Veya saat ve tarih değerleri üzerinde bir validasyon yapılıyorsa gibi… Hatta bunları Ajax ile desteklediğiniz zaman çok daha pratik ve kullanılabilir login formları oluşturabilirsiniz.

Server-Side validasyon için bir diğer önemli konuda, JavaScriptlerin browser’a olan bağımlılığıdır. Yani JavaScriptlerin çalışması bir şekilde browserdan iptal edilebilir. Bu durumda en son adım olarak, Client-Side validation yapmasak bile mutlaka Server-Side Validation yapmak zorundayız. Yazımızın geri kalan bölümü, FluentValidation kullanarak Server Side Validation ‘lar yazmak üzerine olacaktır. Client-Side Validationlar için internette bir çok hazır JavaScript framework’ ü bulabilirsiniz.

Validator Sınıfı Oluşturmak

Fluent Validation projesinin bir open source uygulama olduğunu söylemiştik. Uygulamaya CodePlex üzerinden erişip buradan download edebilirsiniz.

Şimdi Visual Studio’da FluentValidationTest adında bir web projesi yaratalım. Ardından projemize en basit haliyle bir entity ‘i temsil etmesi amacıyla Customer adında bir class ekleyelim. Customer sınıfımız aşağıdaki gibi olabilir.


public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}

Validation işlemlerini yaparken FluentValidation’dan yararlanabilmek içinde gerekli olan .ddl’ i referans olarak eklememiz gerekiyor tabiki. Bunun için download ettiğiniz dosya içindeki FluentValidation klasörü içindeki, FluentValidation.dll dosyasını referanslara eklemeniz yeterlidir.

Evet bu hazırlık işlemlerinden sonra asıl konumuz olan Validation işlemlerinin yapılacağı sınıfı yazabiliriz. Bunun için projemize CustomerValidator adında bir class ekleyelim. Ardından namespace’imizi gösterelim;

using FluentValidation;

Burada önemli olan nokta bu sınıfımızın FluentValidation ‘içinde bulunan AbstractValidator<> isimli generic sınıftan türetilmesidir.

public class CustomerValidator : AbstractValidator<Customer> {}

Şimdi en basit hali ile bu Customer’ bilgilerinden hepsinin girilmek zorunda olduğunu ve Age ‘inde 18 den büyük veya 18′e eşit olması gerektiğinin zorunlu olduğunu düşünelim. Bunun için yazılacak kod gerçekten çok basit, aşağıdaki kodu Default Constructor ‘ımıza yazabiliriz;


public CustomerValidator()
{
RuleFor(customer => customer.FirstName).NotNull();
RuleFor(customer => customer.LastName).NotNull();
RuleFor(customer => customer.Age).NotNull().And.GreaterThanOrEqualTo(18);
}

Kodu kısaca özetlemek gerekirse, RuleFor methodları yardımıyla kurallar belirliyoruz. NotNull() methodu ile girilecek bilginin boş bırakılmaması kontrol ediliyor ve GreaterThanOrEqualTo(18) ilede 18 yaşından büyük veya 18′e eşit olması kontrol ediliyor. Bu kodlardaki bir diğer önemli noktada 3.satırda NotNull() ile GreaterThanOrEqualTo methodları arasındaki And bağlacıdır. And’ in aslında sadece bir property olduğunu düşünürsek işlevsellik bakımından nekadar büyük bir iş yaptığını rahatlıkla görebiliriz.Çünkü bu şekilde zincirleme kod yazmamızı sağlayan bir yapı sunabiliyor bize.Aslında bu şekilde kod yazabilmenin altında FluentInterface mimarisi yatıyor. Bu konuda sevgili Cihat Altuntaş ‘ın yazmış olduğu bir makale var. Buradan okumanızı tavsiye ederim. Bunun dışında FluentValidation içinde yer alan diğer bir çok methoda da birazdan kısaca bakacağız. Ama dilerseniz önce bu Validator sınıfımızı nasıl kullanacağımıza bir bakalım…

Validator Sınıfını Kullanmak

Şimdi Default.aspx sayfamızı aşağıdaki gibi oluşturalım.

imgFluentValidation_1

Ardından buton’ umuza tıkladığımız zaman yapılması gereken işlemleri yazabiliriz artık. Buton’ un Click olayına kodları yazmadan önce namespace’lerimizi belirtmeyi unutmayalım;

using FluentValidation;
using FluentValidation.Results;
// Validasyon sonuçlarına erişebilmek için.


protected void btnSend_Click(object sender, EventArgs e)
{
Customer customer = new Customer();
customer.FirstName = txtFirstName.Text;
customer.LastName = txtLastName.Text;
customer.Age = Convert.ToInt32(txtAge.Text);

CustomerValidator customerVal = new CustomerValidator();

ValidationResult result = customerVal.Validate(customer);

if (!result.IsValid)
{
foreach (var failure in result.Errors)
{
lblResult.Text += “Property ” + failure.PropertyName + ” failed validation. Error was : ” + failure.ErrorMessage;
}
}
else
{
lblResult.Text = “Bilgiler başarıyla gönderildi…”;
}
}

Kodlarda önemli üç nokta var. Önce yeni bir CustomerValidator nesnesi yarattığımız anda zaten otomatikman constructor’ ında kontroller yapılıyor. Ardından ValidationResult ile bunlar bir sonuç kümesi olarak ele alınıyor ve biz bu sonucun geçerli olup olmadığını result‘ ın IsValid değeri ile kontrol ediyoruz. Eğer işlem onaylanmazsa neyin eksik veya yanlış yapıldığı kullanıcıya gösteriliyor böylece. FluentValidation’ ın kullanılması en basit hali ile işte bu şekilde.Sanırım gayette basit olsa gerek. Şimdi bu güzel framework’ ün bize sunduğu diğer karşılaştırma ve kontrol methodlarını inceleyelim isterseniz…

Validatörler

NotNull Bilginin Null olmaması gerektiğini kontrol ediyor.

RuleFor(customer => customer.Surname).NotNull();

NotEmpty Bilginin boş bırakılmaması gerektiğini kontrol ediyor.

RuleFor(customer => customer.Surname).NotEmpty();

NotEqual Bilginin herhangi bir bilgiye eşit olmaması gerekliliğini kontrol ediyor. Örneğin var olan bir username ‘in yeni bir üye tarafından kullanılamaması sırasında yapılan kontrol gibi.

RuleFor(customer => customer.Surname).NotEqual("Foo");

RuleFor(customer => customer.Surname).NotEqual(customer => customer.Forename)

Equal Bilginin herhangi diğer bir bilgiye eşit olması gerektiğini kontrol ediyor. Örneğin password girilmesi iki kere istendiğinde bunların eşit olması gerektiğinin kontrolü gibi.

RuleFor(customer => customer.Surname).Equal("Foo");

RuleFor(customer => customer.Password).Equal(customer => customer.PasswordConfirmation);

Length Bilginin belli bir aralıkta olması gerektiğini kontrol ediyor.

RuleFor(customer => customer.Surname).Length(1, 250);

LessThan Bilginin, herhangi bir değerden küçük olması gerektiğini kontrol ediyor.

RuleFor(customer => customer.CreditLimit).LessThan(100);

RuleFor(customer => customer.CreditLimit).LessThan(customer => customer.MaxCreditLimit);

LessThanOrEqual Bilginin, herhangi bir değerden küçük veya ona eşit olması gerektiğini kontrol ediyor.

RuleFor(customer => customer.CreditLimit).LessThanOrEqual(100);

RuleFor(customer => customer.CreditLimit).LessThanOrEqual(customer => customer.MaxCreditLimit);

GreaterThan Bilginin, herhangi bir değerden büyük olması gerektiğini kontrol ediyor.

RuleFor(customer => customer.CreditLimit).GreaterThan(0);

RuleFor(customer => customer.CreditLimit).GreaterThan(customer => customer.MinimumCreditLimit);

GreaterThanOrEqual Bilginin, herhangi bir değerden büyük veya ona eşit olması gerektiğini kontrol ediyor.

RuleFor(customer => customer.CreditLimit).GreaterThanOrEqual(1);

RuleFor(customer => customer.CreditLimit).GreaterThanOrEqual(customer => customer.MinimumCreditLimit);

Matches Bilginin verilen Regular Expression’a uyup uymadığını kontrol eder. Bu sayede son derece esnek bir şekilde kendi kıstaslarımızı yazabiliriz.

RuleFor(customer => customer.Surname).Matches("some regex here");

Email Bilginin, email formatına uyup uymadığını kontrol eder.

RuleFor(customer => customer.Email).EmailAddress();

Validatörleri Konfigure Etmek

Default Error ‘u Override Etmek

Bu işlemin amacı mesela bir alan boş bırakıldığında çıkacak olan uyarı mesajını istediğimiz gibi kişiselleştirebilmektir.

RuleFor(customer => customer.Surname).NotNull().WithMessage("Soyisim boş bırakılırmı hiç");

RuleFor(customer => customer.Surname).NotNull().WithMessage(“Soyisim boş bırakılırmı hiç {0}”);
// 0 yerine customer.Surname geliyor, sadece formatlı gösterim için.

Default Property Name ‘i Override Etmek

Siz class’larınızda FirstName, LastName, UserName gibi property isimleri kullanabilirsiniz. Fakat kullanıcıya eksik veya hatalı bilgi girmesi sonucunda bir uyarı bilgisi vereceğimiz zaman FirstName yerine Adı, LastName yerine Soyadı, UserName yerinede Kullanıcı Adı boş bırakılamaz diyebilmek için bu propertyleri override edebiliyoruz.

RuleFor(customer => customer.Surname).NotNull().WithName("Last name");

WHEN / UNLESS (-dığı zaman / -olmadıkça) Bir kontrol, diğer bir kontol olduğu zaman yapılsın(when) veya olmadığı zaman yapılsın(unless) gibi durumlarda kullanılabilir.

RuleFor(customer => customer.CustomerDiscount).GreaterThan(0).When(customer => customer.IsPreferredCustomer);

Örnek kodda müşterinin(customer)’ in sahip olduğu indirim değerinin sıfırdan büyük olması gerekliliği kontrol ediliyor. Fakat bundan önce When ile müşterinin bir indirim hakkına sahip olup olmadığı kontrol ediliyor. Eğer bir indirim hakkına sahipse, ardından sahip olduğu bu hakkın değerinin sıfırdan büyük olması gerektiği kontrol ediliyor. Unless’te bu işlemin mantıksal olarak tam tersi durumda geçerli oluyor. Mesela indirim hakkı yoksa indirim yapılsın gibi =)

ASP.NET MVC Entegrasyonu

FluentValidation ‘ı herhangi bir Asp.net MVC projesinde kullanmak istiyorsak eğer; FluentValidation.Mvc.dll ‘dosyasının projeye referans olarak eklenmesi gerekiyor.

public class CustomerController : Controller
{
public ActionResult Save(Customer customer)
{
var validator = new CustomerValidator();
var results = validator.Validate(customer);
results.AddToModelState(ModelState, "customer");
}
}

Buraya kadar anlattığım herşey ve daha fazlası zaten Fluent Validation’ ın CodePlex’teki sayfasında mevcuttur. Benim anlattıklarım dışında ayrıca kendi validatörlerinizi nasıl yazarsınız ve TDD süreçlerinde nasıl kullanırsınız gibi konularada değinilmektedir…

Bu yazımda sizlere FluentValidation yardımıyla Validasyon işlemlerini ve önemini ve nasıl kullanılacağını anlatmaya çalıştım. Bir sonraki yazımda görüşmek üzere, iyi çalışmalar dilerim…

Kaynak : http://www.codeplex.com/FluentValidation

Mehmet Aydın Ünlü
aydinunlu85@gmail.com
http://www.aydinunlu.blogspot.com