Asp.NET Core Identity – UserManager Sınıfı İle Kullanıcı Yönetimi – V

Merhaba,

Asp.NET Core Identity yazı dizimizin 5. adımı olan bu içeriğimizde UserManager sınıfı ile kullanıcı yönetimi üzerine inceleme gerçekleştireceğiz. Önceki yazılarımızda kullanıcılarımızı modellediğimiz IdentityUser ve o kullanıcılara biçilen rolleri tanımladığımız IdentityRole sınıflarının ne olduğunu ele almış ve nasıl kullanıldıklarını detaylıca incelemiştik. Şimdi sıra bu yapılanmaları kullanarak kullanıcı oluşturmamızı ve var olan kullanıcıları yönetmemizi sağlayan UserManager sınıfını ele almaya gelmiştir.

UserManager Sınıfı

Uygulama üzerinde a’dan z’ye kullanıcı yönetimini gerçekleştirmemizi sağlayan sınıftır.
UserManager sınıfı hangi kullanıcı türünü yöneteceğini generic özelliğinden bilmek ister. Dolayısıyla ilgili sınıfın yapısını şöyle bir incelersek eğer;
Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V
görüldüğü üzere generic parametreye verilen IdentityUser türevi sınıf hangisiyle sistemde ona dair bir kullanıcı yönetimi söz konusu olacaktır.

Bu sınıfa erişebilmek için Asp.NET Core Identity mimarisinin kullanıldığı uygulamalarda Dependency Injection(DI Kaynak, DI Başka Bir Kaynak) ile talepte bulunmamız yeterli olacaktır.

    public class UserController : Controller
    {
        readonly UserManager<AppUser> _userManager;
        public UserController(UserManager<AppUser> userManager)
        {
            _userManager = userManager;
        }
    }

Bu işlem neticesinde artık “AppUser” modeline özel UserManager sınıfını kullanabilmekte ve aşağıdaki metotlar ve propertyler eşliğinde tüm yönetimi sağlayabilmekteyiz.
Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V
Ben burada UserManager sınıfı içerisindeki bazı metot ve propertylerin görselini çekmiş bulunmaktayım. Şöyle rastgele göz atarsanız eğer göreceksiniz ki renkli kareler içerisine alınan tüm memberlar genel anlamda tüm kullanıcılara erişebilmeyi(select) ve bunların yanında kullanıcı oluşturmayı(insert), silmeyi(delete) ve güncellemeyi(update) sağlayan işlevselliğe sahiptirler. Bunların dışında şartlı sorgular oluşturan ve hususi bir kullanıcı odaklı çalışmamızı sağlayan metotlarda mevcuttur. Buradan anlayacağınız UserManager sınıfı kullanıcı yönetimiyle ilgili ana karargah görevi gören bir sorumluluğa sahiptir.

UserManager sınıfı kullanıcı yönetiminin ana karargahıdır.

İçeriğimizin bu noktasına kadar baş aktör olarak UserManager sınıfını yeterince teorik olarak ele almış bulunmaktayız. Artık olayı biraz daha somutlaştırmalı ve son noktaya doğru yaklaşırken örnek mahiyetinde ilgili yapıya imza atmalıyız. Bunun için ise ben kullanıcı oluşturma ve listeleme üzerine bir örneklendirme yapmayı tercih ediyorum.

Kullanıcı Oluşturma ve Listeleme

Şimdi kullanıcı bilgilerini alabileceğimiz örnek bir sayfa tasarlayacağız. Tabi bu örneği Asp.NET Core MVC uygulamasında geliştireceğimizden dolayı ilgili sayfanın modeli kullanıcı modeline karşılık gelen “AppUser” sınıfı olmalıdır. Olmalıdır diyorum çünkü UserManager sınıfı “AppUser” modeli üzerinden tüm kullanıcı yönetimi sağlayacaktır. Lakin “AppUser” sınıfının “IdentityUser” sınıfından türemesinden dolayı bu miras neticesinde gelen tüm propertylere karşılık kullanıcı kaydı esnasında bir değer verilmesi gerekecektir. Tabi bizler bu örneğimizde sadece kullanıcıdan kullanıcı adı(UserName), e-posta(Email) ve şifre(PasswordHash) bilgilerini isteyeceğimizden dolayı süreçte bu verisel trafiğe eşlik edecek ViewModel tasarlamamız gayet yerinde ve yeterli olacaktır. ViewModel yapılanmasının ne olduğuna dair detaylı bilgi edinmek istiyorsanız AutoMapper üzerine kaleme almış olduğum şu adresteki makaleyi inceleyebilirsiniz. İlgili makale içerisinde ViewModel yapılanmasına dair tüm senaryolar eşliğinde detaylı açıklamalar barındırmakla beraber ekstra olarak dolaylı yoldan bu içeriğimizede katkıda bulunacaktır.

Şimdi “Models” klasörü içerisinde “ViewModels” isminde bir klasör oluşturarak içerisine “AppUserViewModel” isminde class oluşturalım ve aşağıdaki gibi inşa edelim.

    public class AppUserViewModel
    {
        [Required(ErrorMessage = "Lütfen kullanıcı adını boş geçmeyiniz...")]
        [StringLength(15, ErrorMessage = "Lütfen kullanıcı adını 4 ile 15 karakter arasında giriniz...", MinimumLength = 4)]
        [Display(Name = "Kullanıcı Adı")]
        public string UserName { get; set; }
        [Required(ErrorMessage = "Lütfen emaili boş geçmeyiniz...")]
        [EmailAddress(ErrorMessage = "Lütfen email formatında bir değer belirtiniz...")]
        [Display(Name = "Email")]
        public string Email { get; set; }
        [Required(ErrorMessage = "Lütfen şifreyi boş geçmeyiniz...")]
        [DataType(DataType.Password, ErrorMessage = "Lütfen şifreyi tüm kuralları göz önüne alarak giriniz...")]
        [Display(Name = "Şifre")]
        public string Sifre { get; set; }
    }

Bu viewmodele dikkat ederseniz eğer salt bilgileri karşılayacak olan propertyler, süreçte verisel transferi sağlayacağımız “AppUser” nesnesinde tutarsızlığa mahal vermemek için eşleşecek olan propertyler ile aynı isimde olacak şekilde tasarlanmıştır. Ya da benzer mantıkla süreçte AutoMapper kütüphanesi ile otomatik eşleştirme gerçekleştirilebilir. Eee doğal olarak bu otomatik eşleştirmeyi property isimlerindeki benzerliklerden gerçekleştireceğinden yine doğru bir tasarım gerçekleştirmiş oluyoruz. Sadece “Şifre” propertysi hariç. Sebebini ileriki satırlarda anlayacaksınız. Ayrıca bilgilerini girecek olan kullanıcıyla direkt muhattap olan viewmodel nesnemiz olacağından dolayı data annotations yapılanmasıyla gerekli veri güvenliği sağlanmıştır.

Bu işlemden sonra “User(Controller).cs” isimli controller sınıfında “SignIn” isminde bir action oluşturalım ve View katmanındaki karşılığını aşağıdai gibi kodlayalım.

@model AspNetCoreIdentityExample.Models.ViewModels.AppUserViewModel
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

<h3>Üye Ol</h3>

<hr />
<form asp-action="SignIn">
    <table>
        <tr>
            <td colspan="3"><div asp-validation-summary="ModelOnly"></div></td>
        </tr>
        <tr>
            <td><label asp-for="UserName"></label></td>
            <td><input asp-for="UserName" /></td>
            <td><span asp-validation-for="UserName"></span></td>
        </tr>
        <tr>
            <td><label asp-for="Email"></label></td>
            <td><input asp-for="Email" /></td>
            <td><span asp-validation-for="Email"></span></td>
        </tr>
        <tr>
            <td><label asp-for="Sifre"></label></td>
            <td><input asp-for="Sifre" /></td>
            <td><span asp-validation-for="Sifre"></span></td>
        </tr>
        <tr>
            <td colspan="3"><input type="submit" value="Üye Ol" /></td>
        </tr>
    </table>
</form>


Bu işlemden sonra bind edilmiş “AppUserViewModel” nesnesini post neticesinde backend’de aşağıdaki gibi karşılayalım.

    public class UserController : Controller
    {
        readonly UserManager<AppUser> _userManager;
        public UserController(UserManager<AppUser> userManager)
        {
            _userManager = userManager;
        }
        public IActionResult Index()
        {
            return View(_userManager.Users);
        }
        [HttpGet]
        public IActionResult SignIn()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> SignIn(AppUserViewModel appUserViewModel)
        {
            if (ModelState.IsValid)
            {
                AppUser appUser = new AppUser
                {
                    UserName = appUserViewModel.UserName,
                    Email = appUserViewModel.Email
                };
                IdentityResult result = await _userManager.CreateAsync(appUser, appUserViewModel.Sifre);
                if (result.Succeeded)
                    return RedirectToAction("Index");
            }
            return View();
        }
    }

Yukarıdaki kod bloğunu incelerseniz eğer; “HttpPost” tipinden olan “SignIn” metodunun içerisinde gerekli validasyon kontrolü yapıldıktan sonra post edilen “AppUserViewModel” nesnesinden gelen verileri oluşturulan “AppUser” nesnesine transfer etmekte ve ilgili “AppUser” nesnesini UserManager nesnesi üzerinden “CreateAsync” metodu aracılığıyla veritabanına kaydetmekteyiz. Burada iki hususa dikkatinizi çekmek istiyorum; birincisi, post neticesinde gelen viewmodel içerisindeki “Sifre” propertysi “CreateAsync” içerisinde ikinci parametreye verilerek ilgili parolanın Hash algoritması ile şifrelenerek kaydedilmesi sağlanmaktadır. İşte buradaki işlem yüzünden viewmodel içerisinde şifreyi “AppUser/IdentityUser” içerisindeki “PasswordHash” propertysinden isim olarak benzersiz tanımlamış bulunmaktayız. İkinci olarak ise burada manuel olarak yapılan eşleştirmeyi Automapper kütüphanesini kullanarakta otomatik bir şekilde gerçekleştirebiliriz. Tabi bu çalışmayıda sizlere bırakmaktayım…

“Index” actionu içerisinde ise UserManager nesnesi üzerinden “Users” propertysi çağrılmıştır ve böylece tüm kullanıcılar ilgili action içerisinde listelenecektir. Eğer ki üyelik işlemi başarıyla sonuçlanırsa Index actionına yönlendirme yapılacaktır.
Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V

Hoca örneklendirmede bootstrap kullanmadın, bari şu validation error mesajlarını dinamik eyle…” diyenleriniz olabilir 🙂 Eee hadi istiyorsunuz madem sizleri kırmayalım ve son olarak hata mesajlarını daha da dinamik hale getirip yazımızı sonlandıralım.

Bu işlem için “jquery”, “jquery.validate” ve “jquery.validate.unobtrusive” kütüphanelerinin projeye include edilmesi yeterli olacaktır. Bunun için; “Projeye Sağ Tıklayarak” -> “Add” -> “Client-Side Library…” kombinasyonunu takip ediniz.
Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V
Bu kombinasyon neticesinde açılan pencereye yukarıda ismi verilen kütüphaneleri yazınız ve “Install” butonuna tıklayınız.

Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V

Bu işlemler neticesinde uygulamadaki “wwwroot” klasörü altına ilgili kütüphaneler indirilmiş olacaktır. Şimdi tek yapmamız gereken bu kütüphaneleri “_Layout.cshtml” sayfasında uygun bir yere ekleyerek html’e include etmektir.

<!DOCTYPE html>

<html>
<head>
    <script src="~/jquery/jquery.js"></script>
    <script src="~/lib/jquery-validate/jquery.validate.js"></script>
    <script src="~/lib/jquery-validation-unobtrusive/jquery.validate.unobtrusive.js"></script>
</head>
<body>
    <div>
        @RenderBody()
    </div>
</body>
</html>

Bu işlemden de sonra uygulamayı derleyip çalıştırdığımızda aşağıdaki ekran görüntüsünde olduğu gibi bir işlevle karşılaşmaktayız…
Asp.NET Core Identity - UserManager Sınıfı İle Kullanıcı Yönetimi - V

Evet… Bu makalemizde de kullanıcıları tüm yönleriyle yönetmemizi sağlayan UserManager sınıfının nasıl kullanıldığına dair detaylı bir inceleme yaptığımızı düşünüyorum. Bir sonraki yazı dizimizin devamı niteliğindeki makalemizde bu içeriğimizdeki şifre doğrulama validasyonu üzerine odaklanacağımızı bilmenizi isterim. O halde şimdilik görüşmek üzere…

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

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

Bunlar da hoşunuza gidebilir...

19 Cevaplar

  1. Borahan dedi ki:

    Merhaba gencay hocam,
    Dependency Injection kullanmadan bunu manager kullanamazmıyız.
    UserManager _userManager = new UserManager();

    Bu şekilde kullanmamıza izin vermiyor bunu bu şekilde nasıl kullanabiliriz.

    • Gençay dedi ki:

      Dependency Injection ile kullanmak istememenizin nedenini sorabilir miyim?

      • borahan dedi ki:

        Merhaba hocam,
        Şuan bir projede bu yapıyı Business Layer katmanında kullanmam gerekiyor. Onun için gerekli. Api yada normal web sayfasında değil.

        public UserManager _userManager = new UserManager(new UserStore(new DatabaseContext()),null,null, null, null, null, null, null, null);

        bu şekilde oluşturuyorum ancak usermanager fonksiyonlarını çalıştıramıyorum ancak

        public RoleManager _roleManager = new RoleManager(new RoleStore(new DatabaseContext()), null, null, null, null);

        rol manager da kullandığımda hata almıyorum. Sadece user managerda hata alıyorum çözemedim bir türlü.

  2. borahan dedi ki:

    O işime yaramıyor hocam. Bir yolu vardır ama nasıl. Neyse cevap için teşekkürler

    • Gençay dedi ki:

      @Borahan,

      Nihayetinde ilgili Business Layerı web uygulamasıyla bileşik bir şekilde kullanmıyor musun? Lazım olan noktada webde Dependency Injection ile elde edilen nesneyi BL’ye gönderebilirsin.
      Neyse, kolay gelsin.

      • borahan dedi ki:

        Yok hocam Business Layer ayrı bir katmanda, gerektiğinde api için gerektiğinde web için belki ilerde desktop için referans verip kullanılıyor. Buna bir cevap bulabilirsem buraya da yazarım belki başka ihtiyacı olan çıkar.

        • Gençay dedi ki:

          Evet öylede olması gerekiyor zaten. Burada bileşiklikten kastım dll olarak web uygulamasına referans ediyorsun. Nihayetinde bu referans ilişkisi neticesinde web uygulamasından ilgili Business’da ki classa nesne gönderebilmek için dependency injection ile çekip, constructer’dan yahut farklı bir property üzerinden ilgili katmana veri gönderilebilir.

          • Gençay dedi ki:

            Yani anlatmak istediğim şu ki;
            Business’ın istediği nesneyi Presentation Layer’da elde et ve oradan BL’ye gönder. Muhtemelen PL olarak Asp.NET Core uygulaması kullandığından dolayı Dependency Injection ile ilgili nesneyi rahatça orada elde edebilir ve hangi katmanda kullanacaksan oraya gönderebilirsin.

  3. borahan dedi ki:

    Hocam sorunun çözümünü buldum. Herhangibir katmanda User Managerı yeniden üretmek için aşağıdaki kod yeterli. Sorun UserStore ve PasswordHasher birlikte üretmek

    static IUserStore<ApplicationUser> _store = new UserStore<ApplicationUser>(new DatabaseContext());
    static UserManager<ApplicationUser> _userManager = new UserManager<ApplicationUser>(_store, null, new PasswordHasher<ApplicationUser>(), null, null, null, null, null, null);
    

    Burada da sormuştum.
    Referans link: https://github.com/aspnet/AspNetCore/issues/16926

  4. ishak dedi ki:

    Hocam merhaba;

    IdentityResult result = await _userManager.CreateAsync(user, users.Password).Result;

    user hata veriyor ..

    “The name ‘user’ does not exist in the current context”

    Core 2.2

    Çözümünü nasıl yapabilirim hocam

    • Gençay dedi ki:

      Merhaba;

      IdentityResult result = await _userManager.CreateAsync(user, users.Password).Result;
      

      kodunu

      IdentityResult result = await _userManager.CreateAsync(user, users.Password);
      

      şeklinde değiştiriniz.

      Ayriyetten bu kodun kullanıldığı metodu async keywordü ile işaretlemeyi ve geriye Task< T > türevinde bir değer döndürmeyi unutmayınız.

      Kolay gelsin.

      • ishak dedi ki:

        Yaptım ama gene aynı hata alıyorum.

         [HttpPost]
                [ValidateAntiForgeryToken]
                public async Task SignUp(UserViewModel users)
                {
                    if (ModelState.IsValid)
                    {
                        CustomIdentityUser user = new CustomIdentityUser
                        {
                            UserName = users.User_Name,
                            Email = users.Email
                            
                        };
                    }
        
                    IdentityResult result = await _userManager.CreateAsync(user, users.Password);
        
        • Gençay dedi ki:

          Doğru ya… Biz yanlış yere odaklanmışız. _userManager.CreateAsync metodunda kullandığınız “user” referanslı CustomIdentityUser nesnesini siz manuel oluşturmayacaksınız aksi taktirde contextte böyle bir userın olmadığına dair hata alırsınız. İlgili kullanıcıyı UserManager sınıfı aracılığıyla _userManager.FindByIdAsync(…) vs. şeklinde metotlar ile context üzerinden elde etmeniz gerekmektedir.

          • ishak dedi ki:

            Hocam merhaba;
            UserManager userManager1;

            olarak tanımladım.

            IdentityResult result = await _userManager1.CreateAsync(user, users.Password);

            aynı hatayı aldım

          • ishak dedi ki:

            Hocam çok pardon 🙂 geçe geçe yanlışlık yapmışım.

            [HttpPost]
                   [ValidateAntiForgeryToken]
                   public async Task SignUp(UserViewModel users)
                   {
                       if (ModelState.IsValid)
                       {
                           CustomIdentityUser user = new CustomIdentityUser
                           {
                               UserName = users.User_Name,
                               Email = users.Email
                                
                           };
            IdentityResult result = await _userManager.CreateAsync(user, users.Password);
                       }
            

            Bu şekilde olacaktı.

  1. 12 Ağustos 2019

    […] Asp.NET Core Identity – UserManager Sınıfı İle Kullanıcı Yönetimi – V […]

  2. 14 Ağustos 2019

    […] önce bir önceki UserManager Sınıfı İle Kullanıcı Yönetimi başlıklı makalemizde kullanıcının UserManager sınıfını kullanarak nasıl üye olduğunu […]

Bir cevap yazın

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

*