C# İle Fluentvalidation Kullanarak Veri Doğrulama Katmanı Nasıl Yapılır?

C# İle Fluentvalidation Kullanarak Veri Doğrulama Katmanı Nasıl Yapılır?
C# İle Fluentvalidation Kullanarak Veri Doğrulama Katmanı Nasıl Yapılır?

Gereksinimler ve Ön Hazırlık

FluentValidation kütüphanesini projenize dahil etmek için .NET 8.0 veya üzeri bir sürüm kullanmanız önerilir. Projenizin kök dizininde terminali açarak veya NuGet Paket Yöneticisi üzerinden gerekli paketi yüklemelisiniz. Bu kütüphane, iş mantığınızı (business logic) veri doğrulama kurallarından ayırmanıza yardımcı olur.

Kurulum için aşağıdaki komutu kullanabilirsiniz:

dotnet add package FluentValidation.DependencyInjectionExtensions

Bu paket, FluentValidation'ın .NET'in yerleşik bağımlılık enjeksiyonu (Dependency Injection) mekanizmasıyla sorunsuz çalışmasını sağlar. Kurulum tamamlandıktan sonra, projenizde doğrulama katmanını oluşturmaya başlayabilirsiniz.

Adım Adım FluentValidation Sınıfı Oluşturma

Doğrulama kurallarını tanımlarken, her model sınıfı için ayrı bir "Validator" sınıfı oluşturmak en iyi pratiktir. Örneğin, bir kullanıcı kayıt işlemi için UserRegisterRequest sınıfımız olduğunu varsayalım. Bu sınıfın kurallarını AbstractValidator sınıfından türeterek tanımlarız.

Aşağıdaki örnekte, bir kullanıcı kaydı için temel doğrulama kurallarının nasıl yazılacağını görebilirsiniz:

using FluentValidation;

public class UserRegisterRequest
{
    public string Username { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
}

public class UserRegisterValidator : AbstractValidator
{
    public UserRegisterValidator()
    {
        RuleFor(x => x.Username).NotEmpty().WithMessage("Kullanıcı adı boş bırakılamaz.");
        RuleFor(x => x.Email).EmailAddress().WithMessage("Geçerli bir e-posta adresi giriniz.");
        RuleFor(x => x.Age).InclusiveBetween(18, 99).WithMessage("Yaşınız 18 ile 99 arasında olmalıdır.");
    }
}

Burada RuleFor metodu, doğrulanacak özelliği belirtir. NotEmpty, EmailAddress ve InclusiveBetween ise hazır doğrulama metotlarıdır. WithMessage ise doğrulama başarısız olduğunda kullanıcıya dönecek özel mesajı belirler.

Bağımlılık Enjeksiyonu ile Entegrasyon

FluentValidation kurallarının uygulama genelinde otomatik olarak algılanması için, Program.cs dosyanızda servis kaydını yapmanız gerekir. Bu sayede, uygulamanızın herhangi bir yerinde doğrulama işlemini manuel olarak tetiklemek yerine, otomatik enjeksiyon avantajından yararlanabilirsiniz.

using FluentValidation;
using System.Reflection;

var builder = WebApplication.CreateBuilder(args);

// Validator sınıflarının bulunduğu assembly'i tarar ve kaydeder
builder.Services.AddValidatorsFromAssembly(Assembly.GetExecutingAssembly());

var app = builder.Build();

Bu işlem, projenizdeki tüm AbstractValidator türevlerini bulur ve IoC (Inversion of Control) konteynerine ekler. Böylece controller veya servis katmanlarınızda bu doğrulayıcıları kolayca kullanabilirsiniz.

Controller İçerisinde Doğrulama Kullanımı

Doğrulama katmanını oluşturduktan sonra, bunu API uç noktalarınızda kullanmanız gerekir. En temiz yöntem, IValidator arayüzünü kullanarak bağımlılığı enjekte etmek ve Validate metodunu çağırmaktır.

[ApiController]
[Route("api/[controller]")]
public class UsersController : ControllerBase
{
    private readonly IValidator _validator;

    public UsersController(IValidator validator)
    {
        _validator = validator;
    }

    [HttpPost]
    public IActionResult Register(UserRegisterRequest request)
    {
        var result = _validator.Validate(request);
        if (!result.IsValid)
        {
            return BadRequest(result.Errors);
        }
        return Ok("Kayıt başarılı.");
    }
}

Bu yapı, gelen isteğin doğruluğunu kontrol eder. Eğer kurallara uyulmadıysa, result.Errors koleksiyonu üzerinden hataları JSON formatında istemciye döndürürüz.

Özel Doğrulama Kuralları Yazma

Hazır kurallar bazen karmaşık iş mantıklarını karşılamayabilir. Örneğin, veritabanında bir kullanıcı adının daha önce alınıp alınmadığını kontrol etmeniz gerekebilir. Bu durumda Must metodunu kullanarak özel bir mantık ekleyebilirsiniz.

RuleFor(x => x.Username).Must(BeUniqueUsername).WithMessage("Bu kullanıcı adı zaten alınmış.");

private bool BeUniqueUsername(string username)
{
    // Veritabanı kontrolü burada yapılır
    return _userRepository.GetByUsername(username) == null;
}

Bu yöntem, iş mantığınızı (business logic) doğrulama katmanına taşımanıza olanak tanır, ancak veritabanı işlemlerini asenkron yapmanız gerektiğini unutmayın.

Veri Doğrulama Yöntemlerinin Karşılaştırılması

Yöntem Avantajları Dezavantajları
Data Annotations Hızlı, basit, model üzerinde tanımlanır. Karmaşık kurallar için yetersiz, kod kirliliği yaratır.
FluentValidation Okunabilir, test edilebilir, ayrık mimari sunar. Ek kütüphane bağımlılığı, başlangıçta kurulum gerektirir.

Güvenlik Uyarısı: İstemci tarafındaki doğrulamalar asla tek başına yeterli değildir. FluentValidation ile yapılan sunucu tarafı doğrulamaları, SQL Injection ve XSS saldırılarına karşı bir savunma hattı olsa da, veritabanına kaydedilecek verilerin her zaman parametreli sorgularla işlendiğinden ve uygun şekilde temizlendiğinden emin olun.

Sıkça Sorulan Sorular

FluentValidation neden Data Annotations'dan daha iyidir?

FluentValidation, doğrulama mantığını model sınıfından ayırır (Separation of Concerns). Bu sayede model sınıflarınız temiz kalır ve karmaşık, çok adımlı doğrulama kurallarını yönetmek çok daha kolay hale gelir.

Doğrulama hatalarını nasıl özelleştirebilirim?

WithMessage metodu ile her kural için özel hata mesajları tanımlayabilir veya WithErrorCode ile hata kodları atayarak istemci tarafında yerelleştirme (localization) yapabilirsiniz.

Asenkron doğrulama yapabilir miyim?

Evet, MustAsync metodunu kullanarak veritabanı veya dış servis çağrıları gerektiren asenkron doğrulama kuralları tanımlayabilirsiniz.

Tüm validatörleri tek tek kaydetmek zorunda mıyım?

Hayır, AddValidatorsFromAssembly metodu ile tüm validatörleri tek bir satırla IoC konteynerine kaydedebilirsiniz.

Doğrulama hatalarını global olarak nasıl yönetirim?

ASP.NET Core'da ActionFilter veya Middleware kullanarak, her controller'da manuel kontrol yapmak yerine, tüm istekleri global bir doğrulama filtresinden geçirebilirsiniz.

FluentValidation ile İleri Seviye Senaryolar: CascadeMode ve RuleSet Kullanımı

FluentValidation, karmaşık iş kurallarını yönetmek için sadece basit doğrulama yöntemlerinden fazlasını sunar. Özellikle büyük ölçekli projelerde, doğrulama akışını kontrol etmek ve belirli senaryolara göre kuralları gruplandırmak, kodun okunabilirliğini ve performansını doğrudan etkiler.

CascadeMode ile Doğrulama Akışını Kontrol Etme

Varsayılan olarak FluentValidation, bir özellik için tanımlanan tüm kuralları çalıştırır. Ancak bazen, bir kural başarısız olduğunda sonraki kuralları çalıştırmayı durdurmak isteyebilirsiniz. CascadeMode özelliği ile bu davranışı yönetebilirsiniz.

public class UserValidator : AbstractValidator
{
    public UserValidator()
    {
        // Stop: İlk hata alındığında durur
        RuleFor(x => x.Email)
            .Cascade(CascadeMode.Stop)
            .NotEmpty()
            .EmailAddress();
    }
}

RuleSet ile Koşullu Doğrulama Grupları

Aynı modelin farklı durumlarda farklı kurallara tabi tutulması gerekebilir. Örneğin, bir kullanıcı kaydı sırasında şifre zorunluyken, güncelleme sırasında şifre alanı opsiyonel olabilir. Bu durumda RuleSet yapısını kullanmak en temiz çözümdür.

public class UserValidator : AbstractValidator
{
    public UserValidator()
    {
        RuleSet("Register", () => {
            RuleFor(x => x.Password).NotEmpty().MinimumLength(8);
        });

        RuleSet("Update", () => {
            RuleFor(x => x.FullName).NotEmpty();
        });
    }
}

FluentValidation ile Birim Testi (Unit Testing) Yazma

Doğrulama kurallarınızın doğru çalıştığından emin olmak için bunları birim testleri ile doğrulamak, özellikle karmaşık iş mantığı içeren projelerde kritik öneme sahiptir. FluentValidation.TestHelper kütüphanesi, bu süreci oldukça kolaylaştırır.

Öncelikle test projenize FluentValidation.TestHelper paketini ekleyin. Ardından, aşağıdaki gibi bir test senaryosu oluşturabilirsiniz:

using FluentValidation.TestHelper;
using Xunit;

public class UserValidatorTests
{
    private readonly UserValidator _validator = new UserValidator();

    [Fact]
    public void Should_have_error_when_Email_is_empty()
    {
        var model = new User { Email = "" };
        var result = _validator.TestValidate(model);
        result.ShouldHaveValidationErrorFor(x => x.Email);
    }

    [Fact]
    public void Should_not_have_error_when_Email_is_valid()
    {
        var model = new User { Email = "test@example.com" };
        var result = _validator.TestValidate(model);
        result.ShouldNotHaveValidationErrorFor(x => x.Email);
    }
}

Bu yaklaşım, kurallarınızı değiştirdiğinizde uygulamanızın geri kalanının bozulmadığından emin olmanızı sağlar. Testleriniz, validasyon mantığınız için bir dokümantasyon görevi de görür.

Sonuç

C# ile FluentValidation kullanarak veri doğrulama katmanı oluşturmak, uygulamanızın sürdürülebilirliğini ve kod kalitesini artırır. Doğrulama kurallarını merkezi bir yapıda toplamak, gelecekteki değişikliklerde size büyük zaman kazandıracaktır. Bir sonraki adım olarak, FluentValidation'ın sunduğu CascadeMode özelliğini inceleyerek, bir kural başarısız olduğunda diğerlerinin çalışıp çalışmayacağını kontrol etmeyi öğrenebilirsiniz.

Unutmayın, iyi bir yazılım mimarisi, hataları en erken aşamada yakalayan yapıdır. FluentValidation, bu hedefe ulaşmanızda en güçlü yardımcılarınızdan biri olacaktır.

Bu yazıya tepkinizi paylaşın:
Kerem Tekin

Teknik rehberler ve dijital araçların verimli kullanımı konusunda uzmanlaşmış bir editörüm. Karmaşık teknolojik süreçleri, herkesin kolayca uygulayabileceği rehberlere dönüştürerek zaman tasarrufu sağlamayı hedefliyorum.

Yorumlar (0)

Yorum Yaz