Blazor’da FluentValidation

Selamlar,

Bu makalede, .Net Core üzerinde populer olarak kullanılan FluentValidation‘ın Blazor ile beraber nasıl kullanılabileceğini hep beraber inceleyeceğiz. Blazor hakkında herhangi bir fikriniz yok ise, öncelikle bu link‘i sonra şu link‘i inceleyebilirsiniz. Bildiğiniz üzere, .Net Core üzerinde hali hazırda gelen ve hata ayıklama amaçlı kullanılan [DataAnnotation]’lar bulunmaktadır. FluentValidationlar da, bu hata kontrollerinin daha esnek hale getirilebilmesini, kolayca değiştirilebilmesini ve genişletilebilmesine olanak sağlamaktadır. Kullanım şekilleri Angular’ın, Reactive Form Validationlarına benzemektedir.

Bu örnekte amaç, bir motorsiklet servisinde müşteri kaydı girilmektir. Müşteri kaydı girilirken, müşteriye ait motor(bike) kaydı ve yine müşteriye ait servis(service) kayıtları da beraberinde girilmektedir. Bu giriş işlemi sırasında, belli alanlar FluentValidation kullanılarak kontrol edilmektedir.

Öncelikle gelin, .Net Core’da bir Blazor projesi oluşturalım.  Bu makalenin yazıldığı an itibari ile kullanılan en son .Net Core 3.0 sürümü aşağıdaki gibidir.

Not: En son versiyon .Net Core 3.0 kütüphanesi ile çalışmaya dikkat edin.

Eğer yukarıdaki komut yazıldığında, aşağıdaki blazor templateler gelmiyor ise, öncelike .Net Core CLI’a aşağıdaki komut ile, ilgili Blazor Templateler’i yüklenir.

Şimdi sıra geldi Blazor projesini oluşturmaya. Aşağıdaki komut ile Blazor “bikeservice” projesi oluşturulur. 2 proje template’inden bu makalede,  “blazorserver” seçilmiştir. Nedir blazor server, yine javascript yazılmaya ihtiyaç duyulmadan .Net Codelarının yazıldığı ama bu sefer browser’da değil de, server side’da çalışan client side ile server side arasında iletişimin signalR ile yapıldığı yapılardır.

Açılan Projeden Pages klasörü altına BikeService.razor aşağıdaki gibi eklenir.

BikeService.razor: Şu an sayfada, sadece boş bir başlık gözükmektedir.

Shared/NavMenu.razor içerisine yönlendirme amaçlı ilgili bikeservice sayfası aşağıdaki gibi eklenir.

Program.cs : İstenen bir porttan sayfanın yayımlanabilmesi için, “webBuilder.UseUrls(“http://localhost:1923″)” satırı aşağıdaki gibi eklenir.

Sayfanın son hali aşağıdaki gibidir:

Öncelikle gelin classlarımızı aşağıdaki gibi tanımlayalım:

Customer.cs, Bike.cs, Service.cs: Customer sınıfının Name ve Surname kolonları haricinde diğer 2 kolonu, Bike ve Service sınıflarınca temsil edilmektedirler. İlgili kolonlar, Customer’a ait tek bir Bike kolunu ve birden fazla Service sınıfına ait bir listeden oluşmaktadır.

Bike sınıfı, Model, yıl ve SeriNo kolonlarından oluşmaktadır.

Service sınıfı, Type enum tipinde ServiceType, SeriNo ve Price kolonlarından oluşmaktadır.

Projeye FluentValidation kütüphanesi aşağıdaki komut ile eklenir.
Customer için validation işlemlerinin yapılabilmesi için, CustomerValidator sınıfı aşağıdaki gibi oluşturulur.
CustomerValidator.cs:  FluentValidation sınıfının methodlarının kullanılabilmesi için AbstractValidator<Customer> ‘den türetilmiştir.
  • RuleFor() : İlgili kolon için kontrol amaçlı bir kural atanır.
  • NotEmpty(): Seçili kolon boş olamaz.
  • MaximumLength(): Seçili kolonun Maximum değeri belirlenir.
  • WithMessage() : Kurala uymayan bir durum ile karşılaşıldığında, yazılacak mesajın tanımlandığı methoddur.
  • SetValidator() : Kontrol amaçlı, başka bir sınıf belirlenir.
  • Matches() : İstenen bir RegEx tanımı, ilgili method içinde yapılır.
  • RuleForEach(customer => customer.Services).SetValidator(new ServiceValidator()) : Customer sınıfına ait Services listesinin kontrolu, “ServiceValidator” adında başka bir sınıfa verilmiştir. Her bir servis kayıdı, ServiceValidator sınıfı tarafından tek tek “RuleForEach()” methodu ile kontrol edilmektedir.

FluentValidation ile kullanılabilecek tüm methodların listesi, bu linkdedir. https://fluentvalidation.net/built-in-validators

BikeValidator.cs:

  • RuleFor(bike => bike.Model).NotEmpty() : Bike sınıfına ait Model kolonu boş geçilemez.
  • RuleFor(bike => bike.Year).NotEmpty().Matches(“^[0-9]*$”).WithMessage(“Year must be number!”): Bike sınıfına ait Year kolonu boş geçilemez ve RegEx ile tanımlanan mutlaka sayısal bir alan olmalıdır.
  • RuleFor(bike => bike.Serino).NotEmpty().MaximumLength(10): Yine Bike sınıfına ait Serino boş olamaz ve maximum uzunluğu 10’dur.

ServiceValidator.cs:

  • RuleFor(service => service.SeriNo) .NotEmpty().Matches(“^[0-9]*$”).WithMessage(“Seri No must be number!”) .When(service => service.ServiceType == Service.Type.OnikiBinBakım) : Service sınıfına ait SeriNo kolonu, Services Tiplerinden OnikiBinBakım olduğu zaman boş geçilemez ve sayısal bir alan olması gerekmektedir.

Not : Kısaca bir sınıfa ait validation işlemi, bir koşula bağlanabilmektedir.

FluentValidation Methodları :

Pages/BikeService.razor: Sıra geldi blazor ile kayıt işleminin yapıldığı sayfaya.

  • “@using bikeservice.Data” : Validation sınıfları sayfaya import edilir.
  • “<EditForm Model=”customer” OnValidSubmit=”SaveCustomer”>” : Submit edilecek formun açıldığı tag’dir. Form-Submit işleminde SaveCustomer() methodu çağrılır.
  • “<FluentValidator TValidator=”CustomerValidator” />” : Form üzerinde bind olan elementleri validationları, <FluentValidator> component’u ile yapılmaktadır. Bu Blazor template’i ile gelen bir kod parçası değildir.  Aşağıda bulunan FluentValidator.cs‘in ayrıca projeye dahil edilmesi gerekmektedir.
  • “<InputText placeholder=”First name” @bind-Value=”customer.Name” />”: Text alan “Customer” tablosunda “Name” alanına bağlanmaktadır.
  • “<ValidationMessage For=”@(() => customer.Name)” />” : Customer tablosunda Name alanında validation sırasında, bulunan hatanın mesajı bu tanımlı taglar arasında yazılır.
  • “[<a href=”javascript: void(0)” @onclick=”AddService”>Add Service Record</a>]” : Burada link yerine button konulması durumunda, tüm validationlar çalışır idi. Bunun yerine “a href” koyuldu ve tıklandığında yönlenme olmaması için “javascript: void(0)” komutu yazıldı. @onclick=”AddService” tıklandığında “AddService()” methodu çağrıldı. İlgili method’da yaratılan boş service kaydı, customer.Services listesine eklendi.
  • “@foreach (var service in customer.Services)” : Customer için açılmış her bir servis kaydı, ekrana basılır.
  • “<InputSelect @bind-Value=”service.ServiceType”>” : Servis tipi, service sınıfının ServiceType property’sine combo araclı ile bağlanır.
  • @if (service.ServiceType == Service.Type.OnikiBinBakım)” : Servis tipi “OnikiBinBakım” olduğu zaman, “SeriNo” alanı ekrana gelmektedir. Yukarıda ServiceValidator‘da tanımladığı gibi, ancak OnikiBinBakım seçeneği seçilmesi durumunda, SeriNo zorunlu ve sayısal bir alandır.
  • “<button type=”button” @onclick=”@(() => customer.Services.Remove(service))”>Remove</button>” : İlgili button tıklandığında, seçilen service customer.Services listesinden çıkarılır.
  • “<ValidationMessage For=”@(() => service.SeriNo)” />” : SeriNo ile oluşabilecek, tüm hata mesajlarının yazıldığı yerdir.
  • @code {” : ServerSide şeklinde tanımlayabileceğimiz, kodun yazıldığı kısımdır.
  • “SaveCustomer()” : Tüm validasyon işlemleri sağlanıp, form post olduğunda çağrılan methoddur.

FluentValidator.cs: Bu sınıf, Blazor template’i ile gelen bir kod parçası değildir.  Olduğu gibi alınıp projeye dahil edilebilir.

Bu makalede Blazor üzerinde, bir form kaydedilirken ilgili input alanların kontrolünü, Fluent Validation kütüphanesi kullanarak yaptık. Fluent Validation kütüphanesi, henüz Blazer proje template’i ile birlikte gelmemektedir. Bu projede custom olarak FluentValidator.cs eklenmiştir. Kod tarafında, ilgili propertylere bir veya birden fazla kontrolün, istenir ise belli koşulara bağlanarak atanabilmesi, hem kodun okunaklığını arttırır, hem de genişletilebilir, esnek olmasını sağlar. Bu da ilerde kodun kolaylıkla değiştirilebilmesine ve istenen yeni özellikler hızlıca kodlanarak eklenebilmesine yol açar. Makalenin kodlarına, aşağıdaki github adresinden erişebilirsiniz.

Geldik bir makalenin daha sonuna. Yeni bir makalede görüşmek üzere hepinizi hoşçakalın.

Github: https://github.com/borakasmer/BlazorFluentValidation

Source :

Herkes Görsün:

Bunlar da hoşunuza gidebilir...

Bir cevap yazın

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