Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Asp.NET Core Identity – Varsayılan Validasyon Mesajlarının IdentityErrorDescriber Sınıfı İle Özelleştirilmesi – VIII

Merhaba,

Asp.NET Core Identity yazı dizimizin son iki makalesinde(1. makale, 2. makale) hem password hem de username değerlerine dair varsayılan validasyon konfigürasyonun ve özelleştirilmiş validasyon yapılanmalarının nasıl geliştirildiğini incelemiştik. Bu içeriğimizde ise Identity mekanizmasında varsayılan validasyonlara verilen hata mesajlarının IdentityErrorDescriber sınıfı ile nasıl özelleştirilebildiğini inceleyeceğiz.

Yazı dizimizde kullandığımız örnek uygulamanın şuana kadar üzerinde yapılan etkinlikler neticesindeki en son halinde email adresi tekilleştirilmiştir. Ee bunun yanında username değeride değişmez bir varsayımla tekildir. Dolayısıyla gelin bu iki doğrulamaya takılacak bir üye ekleme girişiminde bulunalım.
Asp.NET Core Identity - Varsayılan Validasyonların Mesajlarının Özelleştirilmesi - VIII
Görüldüğü üzere belirtilen kullanıcı adı ve email bilgilerini kullanan kayıtlar olduğunu bildirmektedir. Lakin bunu İngilizce bir mesaj ile söylemektedir 🙂 Şimdi bizim amacımız bu mesajların içeriğini kendimize göre değiştirmektir. Yani bir başka deyişle özelleştirmektir.

Bu işlem için IdentityErrorDescriber sınıfından türeyen bir sınıf tasarlamamız gerekmektedir. Bu sınıf içerisinde varsayılan hata mesajını değiştirmek istediğimiz validasyonun, base classta virtual olarak tanımlanmış metodunu override ederek tekrar düzenleyeceğiz. Düzenleme işleminin ardından ilgili sınıfı Identity mekanizmasına entegre edecek ve böylece varsayılan validasyonlarda kendi hata mesajlarımızı devreye sokmuş olacağız.

Öncelikle IdentityErrorDescriber sınıfının içeriğini inceleyelim;
Asp.NET Core Identity - Varsayılan Validasyonların Mesajlarının Özelleştirilmesi - VIII
Görüldüğü üzere; email, password, username vs. gibi belli başlı ana değerlerin tekrar etmesi, uygunsuz veri olması vesair durumlarına karşılık metotlar barındırmaktadır. İşte yukarıda bahsettiğim ve override edileceğini söylediğim metotlar bunlar. Şimdi gelin çalışmamızı icra edelim.

Uygulamanın ana dizininde önceki makalelerimizde oluşturduğumuz “CustomValidations” klasörünün içerisine “CustomIdentityErrorDescriber” isminde bir sınıf ekleyelim ve ardından ilgili sınıfı IdentityErrorDescriber sınıfından türetelim.

    public class CustomIdentityErrorDescriber : IdentityErrorDescriber
    {
        public override IdentityError DuplicateUserName(string userName) => new IdentityError { Code = "DuplicateUserName", Description = $"\"{ userName }\" kullanıcı adı kullanılmaktadır." };
        public override IdentityError InvalidUserName(string userName) => new IdentityError { Code = "InvalidUserName", Description = "Geçersiz kullanıcı adı." };
        public override IdentityError DuplicateEmail(string email) => new IdentityError { Code = "DuplicateEmail", Description = $"\"{ email }\" başka bir kullanıcı tarafından kullanılmaktadır." };
        public override IdentityError InvalidEmail(string email) => new IdentityError { Code = "InvalidEmail", Description = "Geçersiz email." };
    }

Yukarıdaki kod bloğunu incelerseniz eğer belli başlı validasyon mesajlarını override ederek özelleştirmiş bulunmaktayım. Bu işlemden sonra artık yapmamız gereken, oluşturduğumuz “CustomIdentityErrorDescriber” sınıfını uygulamaya dahil etmektir. Bunun için “Startup.cs” sınıfını açıyoruz ve “ConfigureServices” metodu içerisine aşağıdaki eklemelerde bulunuyoruz.

    public class Startup
    {
        public IConfiguration Configuration { get; set; }
        public Startup(IConfiguration configuration) => Configuration = configuration;
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddDbContext<AppDbContext>(_ => _.UseSqlServer(Configuration["ConnectionStrings:SqlServerConnectionString"]));
            services.AddIdentity<AppUser, AppRole>(_ =>
            {
                _.Password.RequiredLength = 5; //En az kaç karakterli olması gerektiğini belirtiyoruz.
                _.Password.RequireNonAlphanumeric = false; //Alfanumerik zorunluluğunu kaldırıyoruz.
                _.Password.RequireLowercase = false; //Küçük harf zorunluluğunu kaldırıyoruz.
                _.Password.RequireUppercase = false; //Büyük harf zorunluluğunu kaldırıyoruz.
                _.Password.RequireDigit = false; //0-9 arası sayısal karakter zorunluluğunu kaldırıyoruz.

                _.User.RequireUniqueEmail = true; //Email adreslerini tekilleştiriyoruz.
                _.User.AllowedUserNameCharacters = "abcçdefghiıjklmnoöpqrsştuüvwxyzABCÇDEFGHIİJKLMNOÖPQRSŞTUÜVWXYZ0123456789-._@+"; //Kullanıcı adında geçerli olan karakterleri belirtiyoruz.
            }).AddPasswordValidator<CustomPasswordValidation>()
              .AddUserValidator<CustomUserValidation>()
              .AddErrorDescriber<CustomIdentityErrorDescriber>().AddEntityFrameworkStores<AppDbContext>();
            services.AddMvc();
        }

        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
        {
            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            app.UseStatusCodePages();
            app.UseStaticFiles();
            app.UseAuthentication();
            app.UseMvc(_ => _.MapRoute("Default", "{controller=Home}/{action=Index}/{id?}"));
        }
    }

Yukarıdaki kod bloğunda 20. satıra göz atarsanız eğer “AddErrorDescriber” metodu ile oluşturduğumuz sınıfımızı uygulamaya dahil ediyoruz ve böylece uygulamadaki varsayılan validasyonların hata mesajlarının hangi kaynakta tanımlandığını belirtmiş oluyoruz. Dizisel içerik oluşturduğumuz için içeriksel sıralamayı göz önüne alarak önceki makalelerle bütünlüğü zedelememek adına örnek uygulamanın Startup.cs dosyasını sadeleştirmeden alma sebebimi mazur görürsünüz umarım.

Ve bu işlemden sonra artık uygulamayı derleyip çalıştırdığımızda tekrar aynı doğrulamalara yakalanacak verilerle bir üyelik işlemi gerçekleştirmeyi denediğimizde aşağıdaki görselde olduğu gibi hata mesajları tarafımızca özelleştirildiği gibi verilecektir…
Asp.NET Core Identity - Varsayılan Validasyonların Mesajlarının Özelleştirilmesi - VIII

Netice olarak bu noktaya kadar Identity mekanizmasının modifiye edilebilir bir esnekliğe sahip olduğunu gördüğünüzü düşünüyorum…
Bir sonraki içeriğimizde Cookie bazlı kimlik doğrulama mekanizması üzerine konuşacağız. Biliyorum… Konular derinleştikçe, yeni şeyler öğrendikçe ve mekanizmayı ifşa ettikçe daha ilgi çekici ve eğlenceli olmaktadır 🙂 Sabrınıza yetişebilmek için şimdilik görüşmek üzere diyorum 🙂

İlgilenenlerin faydalanması dileğiyle…
İyi çalışmalar…

Not : Örnek projeyi indirmek için buraya tıklayınız.

Bunlar da hoşunuza gidebilir...

20 Cevaplar

  1. Senol dedi ki:

    Merhaba,

    Burada özelleştirdiğimiz validasyon mesajlarını client side da çalışacak şekilde yapılandırabilir miyiz?

    • Gençay dedi ki:

      Merhaba,

      Zaten yazı dizisini takip ederseniz örnek projeden de görüleceği üzere tüm alt yapı client side’da da çalışacak şekilde konfigüre edilmiştir.

      • Senol dedi ki:

        CustomIdentityErrorDescriber sınıfı oluşturup içerisinde; PasswordRequiresDigit, PasswordRequiresUpper, PasswordRequiresLower ve PasswordRequiresNonAlphanumeric özelliklerini override ederek özelleştirdim. Sonrasında da sınıfı Startup’a dahil ettim. Ancak uygulamayı çalıştırdığımda oluşturduğum hata mesajları sayfa refresh edildikten sonra görüntüleniyor.

  2. Senol dedi ki:

    Kusura bakmayın biraz uzattım herhalde konuyu. Aslında hata da yok ortada. Öğrenmek istediğim bir şey var. CustomIdentityErrorDescriber sınıfı içerisinde override ederek özelleştirdiğim PasswordRequiresDigit, PasswordRequiresUpper, PasswordRequiresLower ve PasswordRequiresNonAlphanumeric hata mesajları ancak “Üye Ol” butonuna tıklanıp web sayfası refresh edildikten sonra görüntüleniyor. Yukarıda bahsettiğim bu mesajları da, “Lütfen kullanıcı adını boş geçmeyiniz” veya “Lütfen kullanıcını adını 6 ile 15 karakter arasında giriniz” mesajları gibi anlık olarak ve sayfa refresh edilmeden göstermek mümkün müdür?
    Sabrınız için teşekkürler… 🙂

    • Gençay dedi ki:

      Çözüme gitmek mümkündür. Bunun için dediğim gibi bir önceki yorumda vermiş olduğum adresteki makalede içeriğin sonlarına doğru bahsettiğiniz konuyu ele almış bulunmaktayım.

      Estafurullah 🙂 Benim için sabır gösterilecek bir durum yok Şenol Bey.
      Faydalanabiliyor ve birşeyler öğrenebiliyorsanız ne mutlu bana…

  3. Serbest dedi ki:

    Merhaba,

    Konunun üzerinden zaman geçmiş ama ben bu aralar, bir projemde Identity 5.0 kullanıyorum. Ancak validasyon mesajlarını bir türlü override edemedim. En son yazınıda bahsettiğiniz yolu da denedim ama override ettiğim mesajlar yerine varsayılan inglizce mesajlar veriyor sürekli. Özellikle “InvalidMail” metodunu override etmeye çalışıyorum. Ama bir trlü olmuyor. Yardımcı olursanız sevinirim.

    • Gençay dedi ki:

      Merhaba,
      Konunun üzerine zaman geçsede hala teknik güncelliğini korumaktadır.
      Yaptığınız çalışmaya dair örnek kod paylaşırsanız yardımcı olabilirim.

      Sevgiler.

  4. Serbest dedi ki:

    Merhaba,
    Öncelikle ilginiz için teşekkür ederim.

    Oluşturduğum IdentityErrorDescriber sınıfı aşağıdadır.

        public class TrIdentityErrorDescriber:IdentityErrorDescriber
        {
            public override IdentityError DuplicateEmail(string email)
            {
                return new IdentityError { Code = "DuplicateEmail", Description = $"'{email}'mail adresi kullanılmaktadır. Başka bir adres girin." };
            }
                    
            public override IdentityError LoginAlreadyAssociated()
            {
                return new IdentityError { Code = "LoginAlreadyAssociated", Description = "Bu kullanıcı oturumu zaten açık." };
            }
    
            public override IdentityError InvalidEmail(string email)
            {
                return new IdentityError { Code = "InvalidEmail", Description = "Geçersiz mail adresi." }; ;
            }
        }
    

    Sınıfı, IdentityHostingStartup sınıfında, aşağıdaki gibi deklare ettim.

        services.AddDefaultIdentity(options =>
                    {
                        options.SignIn.RequireConfirmedAccount = true;                   
                        options.User.RequireUniqueEmail = true;
                    })
                    .AddErrorDescriber<TrIdentityErrorDescriber>()
                    .AddRoles()
                    .AddEntityFrameworkStores();
    

    Ancak bütün denemelerimde hep inglizce mesajlar vermeye devam etti.

    Bunun yanında Password Validator’da hiç hata mesajı gelmiyor. Yani, default olarak, bir passwordda bir rakam, bir büyük, bir küçük harf bir de alfanümerik olmayan harf olması gerekirken ben sadece rakamlardan oluşan password oluşturduğum halde hiç hata mesajı vermeden kaydediyor.

    Yardımlarınız için şimdiden teşekkürler.

  5. Ali dedi ki:

    Merhabalar. Aynı soruyu sormak için gelmiştim ki zaten sorulduğunu gördüm.

    Gençay hocam, arkadaşın demek istediği şey IdentityOptions üzerinde ki yapıların sayfa yenilenmeden client-side olarak gözükmesi. Sizin yaptığınız yapıda AppUser da ki DataAnnotation ile ayarlanan validasyonlar gözüküyor. Yapılandırma ayarları server’a gidip gelişte gözükebiliyor.

    Aklıma 2 tane çözüm geldi. 1 tanesi ViewModel’e DataAnnotation eklemek fakat hazır yapılar yeterli değil. Özel DataAnnotation yazmak lazım sanırım.

    2. yöntem de formu gönderirken ajax isteği atarsak, server yeni bir view render eder ve gelen view’i sayfa olarak basarız. Böylelikle sanki client-side’mış gibi gözükebilir hatalar.

    Umarım anlatabilmişimdir. Hala bu konuya bakıyorsanız yorumunuzu merak ediyorum.

  6. özgür dedi ki:

    Merhaba ben bu şekilde Türkçeleştirdim. işinize yarar mı bilmiyorum.

                    foreach (var error in result.Errors)
                    {
                            if (error.Description == "Passwords must have at least one non alphanumeric character.")
                            {
                                error.Description = "Şifrede en az bir adet özel karakter gerekli( _, -, +, * gibi)";
                            }
                            if (error.Description == "Passwords must have at least one lowercase ('a'-'z').")
                            {
                                error.Description = "Şifrede en az bir adet küçük harf gerekli";
                            }
                            if (error.Description == "Passwords must have at least one uppercase ('A'-'Z').")
                            {
                                error.Description = "Şifrede en az bir adet BÜYÜK harf gerekli";
                            }
    
                           
                            ModelState.AddModelError(string.Empty, error.Description);
                    }
    
  7. bilisimtech dedi ki:

    Teşekkürler öncelikle emekleriniz için.
    Bu sayfadaki anlatımı uyguladığımda şu hatayı alıyorum:

    An unhandled exception occurred while processing the request.
    InvalidOperationException: Sequence contains more than one element

    • bilisimtech dedi ki:
      public override IdentityError DuplicateUserName(string userName) => new IdentityError { Code = "DuplicateUserName", Description = $"\"{ userName }\" kullanıcı adı kullanılmaktadır." };
      

      kullanılan bir ad için uyarı verilmek istendiğinde CustomIdentityErrorDescriber altındaki bu satırda hataya düşüyor.

  1. 16 Ağustos 2019

    […] Asp.NET Core Identity – Varsayılan Validasyon Mesajlarının IdentityErrorDescriber Sınıfı… […]

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir