ASP.NET MVC 3 özellikle doğrulama işlemleriyle ilgili gerek
istemci gerekse sunucu tarafında birçok yenilikleri getirmekte. ASP.NET 3.5 SP1
ile duyurulan Dynamic Data Web Site’larda kullanılan DataAnnotions
nesnelerini, bir önceki MVC 2.0 sürümde Model katmanında entity objelerinde
attribute bazlı olarak kullanabiliyorduk. .NET Framework 4.0’da daha da
geliştirilen bu nesnelere, MVC 3.0 ile de bazı ek nesne ve özellikler eklendi.
Bu özelliklerden bir tanesi de CompareAttribute nesnesidir.
System.Web.Mvc isim alanı(namespace) içinde yer alan bu sınıfın
kullanımı çok kolay gibi görünse de, entity objemizde ek property eklemek
gerekeceği için bu yazı ile CompareAttribute sınıfını kullanımını çok sık
karşılaşılan bir örnekle inceleyeceğiz.
İlk olarak alet çantamızı hazırlayalım. İçerisinde Users
adında bir tablo bulunduran veritabanımızı, MVC 3.0 projemizin Models klasörüne
ADO.NET Entity Data Model(.edmx) dosyası olarak ekleyelim. Ben entity sınıfını
kolay takip etmek ve kod karmaşasını azaltmak için .edmx dosyamın açık olduğu
designer pencesine sağ tıklayıp Add Code Generation Item seçeneğine
tıklıyorum. Açılan pencereden ADO.NET Self-Tracking Entity Generator
dosya tipini seçiyorum(.tt uzantılı template dosyanıza uygun
bir isim verebilirsiniz). POCO için gerekli eklentiler kurulu ise bu adımda POCO
objeleri de oluşturabilirsiniz. Model katmanında şimdilik işimiz bitti.
Controllers kısmına UserController adında bir dosya ekliyorum. Index ve Create
talepleri için ouşturduğum Action metotları aşağıdaki gibi.
using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Web.Mvc; using CompareAttribute.Models; namespace CompareAttribute.Controllers { public class UserController : Controller { NorthwindEntities northwind = new NorthwindEntities(); public ActionResult Index() { return View(northwind.Users); } public ActionResult Create() { return View(new Users()); } [HttpPost] public ActionResult Create(Users user) { try { if (ModelState.IsValid) { northwind.Users.AddObject(user); northwind.SaveChanges(); return RedirectToAction("Index"); } else { ViewBag.ExceptionMessage = "Kullanıcı ekleme işleminde hata!!!"; return View(user); } } catch(Exception ex) { ViewBag.ExceptionMessage = "Kullanıcı ekleme işleminde hata!!!"; return View(user); } } } }
Action metotları içerisindeyken fareye sağ tıklayıp Add View seçeneğinden Index
ve Create işlemleri için View nesnelerimizi ekliyoruz. View ekleme penceresinde
Create a strongly-typed view seçeneğini aktif yapalım ve altta
çıkan listeden Users entity objesini seçili bırakalım. Index sayfası için
Scaffold template‘i List, Create sayfası içinde Create olarak
belirleyebiliriz. Create sayfasını çalıştırıp test ettiğimizde herhangi bir
validation işleminin yapılmadığını göreceğiz. Gelelim asıl konumuza;
CompareAttribute nesnesini Users sınıfına nasıl uygulayacağımıza.
Models klasörü altında NorthwindModel.tt(bu dosya adı sizde farklı olabilir)
dosyasının altındaki Users.cs dosyasını aşağıdaki gibi değiştiriyorum. Kodlara
göz atmadan önce Users entity nesnesinin orjinal halini de aşağıdaki nesne
çiziminden görebilirsiniz.
... using System.ComponentModel.DataAnnotations; using System.Web.Mvc; namespace CompareAttribute.Models { [DataContract(IsReference = true)] public partial class Users: IObjectWithChangeTracker, INotifyPropertyChanged { #region Primitive Properties [DataMember] public int Id { get { ...; } set { ... } } private int _id; [DataMember] [Required] //Username boş bırakılamaz public string Username { get { return _username; } set { if (_username != value) { _username = value; OnPropertyChanged("Username"); } } } private string _username; [DataMember] [Required] //Şifre boş bırakılamaz public string Password { get { return _password; } set { if (_password != value) { _password = value; OnPropertyChanged("Password"); } } } private string _password; [DataMember] [Required] //Şifre tekrar alanı boş bırakılamaz [Compare("Password", ErrorMessage = "Şifrelerin aynı olması gerekiyor")] //Password alanı ile karşılaştırma public string PasswordRepeat { get { return _passwordRepeat; } set { if (_passwordRepeat != value) { _passwordRepeat = value; } } } private string _passwordRepeat; [DataMember] public string Email { get { ... } set { ... } } private string _email; [DataMember] public Nullable<bool> IsActive { get { ... } set { ... } } private Nullable<bool> _isActive; #endregion //ChangeTracking ile ilgili metotlar... } }
Users sınıfında yaptığım değişiklikleri gözden geçirecek olursak; öncelikli
olarak Username ve Password property’lerini System.ComponentModel.DataAnnotations
isim alanı altındaki Required(RequiredAttribute) nesnesiyle işaretliyoruz.
Required attribute nesnesi istemci ve sunucu tarafında ilgili
property’lerin boş bırakılması durumunu değerlendirecektir. Konumuzda asıl
ilişkili olan kısım ise Compare(CompareAttribute) nesnesidir. Yukarıdaki entity
çiziminden de göreceğiniz üzere tablomuzda bir tane şifre alanımız var. Yani
View nesnemiz otomatik üretilirken eğer şifre tekrarı için de ayrı bir özelliğin
algılanmasını istiyorsak sınıf içerisine bir şifre özelliği daha eklememiz
gerekecek. PasswordRepeat adını verdiğim bu özellik, Compare attribute’unu asıl
uygulayacağımız özellik olacak. Compare attribute’unun alacağı en önemli
parametre çalışma zamanı esnasında üzerinde bulunduğu özelliğin hangi özellik
ile karşılaştırılacağını belirtleyen othetProperty parametresidir. En yalın
haliyle [Compare(“Password”)] şekliyle kullanabileceğimiz bu niteliğe istersek
doğrulama ekranında verilecek hata mesajını da ekleyebiliriz. Kod örneğimizde
hata mesajı da eklenmiştir.
Entity nesnemizde gerekli eklemeyi tamamladık. Sıra geldi arayüz tarafında
yapılması gerekenlere. Aslında view nesnenizi entity modelinizi değiştirdikten
sonra otomatik üretecek olursanız, zaten PasswordRepeat özelliğiyle ilgili
kontrol ve doğrulama kısımları da oluşacaktır. Ama biz varolan model üzerinde bu
değişikliği nasıl yapacağımızı inceliyoruz. Bu durumda User/Create.cshtml isimli
view sayfamıza aşağıdaki kodları ekliyoruz.
User/Create.cshtml <div class="editor-label"> @Html.LabelFor(model => model.PasswordRepeat) </div> <div class="editor-field"> @Html.EditorFor(model => model.PasswordRepeat) @Html.ValidationMessageFor(model => model.PasswordRepeat) </div>
Ekran çıktısında sonucu gözlemleyebiliriz.