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

Asp.NET Core’da AutoMapper Kullanımı

Merhaba,

Bu içeriğimizde Asp.NET Core uygulamalarında, ViewModel nesnelerinin modellediği gerçekci model entityleri ile eşleştirilmesini dinamik bir şekilde sağlayan AutoMapper kütüphanesinin entegrasyonunu ve kullanımını inceleyeceğiz.

Makalemize ilk olarak hiç bilmeyenler için Viewmodel nesnesinin ne olduğunu açıklayarak başlayalım;

Viewmodel Nedir?

Viewmodel nesneleri, temelde iki farklı senaryoya karşı sorumluluk üstlenen ve biz geliştiricilerin işini kolaylaştıran operasyonel nesnelerdir.

  • 1. Senaryo
    OOP yapılanmasında bir modelin kullanıcıyla etkileşimi neticesinde kullanılan/doldurulan memberlarını temsil eden ve süreçte ilgili model yerine kullanılan/taşınan/transfer edilen/post edilen vs. bir nesnedir.

    Örnek olarak hesap girişi için kullanıcı adı ve şifre ile yapılan bir post işleminde aşağıdaki gibi rol üstlenmektedir.
    Gerçek model(entity);

        public class Personel
        {
            public int Id { get; set; }
            public string Adi { get; set; }
            public string Soyadi { get; set; }
            public string KullaniciAdi { get; set; }
            public string Sifre { get; set; }
            virtual public ICollection<Musteri> Musteriler { get; set; }
            virtual public ICollection<Satis> Satislar { get; set; }
        }
    

    Asp.NET Core'da AutoMapper Kullanımı

    Viewmodel;

        public class VMPersonel
        {
            public string KullaniciAdi { get; set; }
            public string Sifre { get; set; }
        }
    

    Asp.NET Core'da AutoMapper Kullanımı

    Bu şekilde bir senaryoda post edilen nesneyi direkt olarak gerçek model/entity ile karşılarsak ilgili propertyler dışında konuyla alakasız memberlar varsayılan değerleriyle gelecektirler. Dolayısıyla bu çokta kullanışlı bir yapılanma olmayacaktır. İşte burada, post neticesinde gelen veriyi direkt değersel muhattabı olan ViewModel nesnesi ile karşılayarak lüzumsuz propertylerden arındırmış ve kullanım açısından da kolaylık sağlamış olmaktayız.

  • 2. Senaryo
    Birden fazla modele ihtiyaç duyulan durumlarda tek bir nesne üzerinden bu modelleri birleştirme görevi gören nesnedir.

    Örnek olarak aşağıdaki yapılanmayı inceleyiniz.
    Gerçek model;

        public class Satis
        {
            public int Id { get; set; }
            public int PersonelId { get; set; }
            public string SatisNo { get; set; }
            virtual public Personel Personel { get; set; }
        }
    

    Gerçek model;

        public class Musteri
        {
            public int Id { get; set; }
            public int PersonelId { get; set; }
            public string Adi { get; set; }
            public string Sirketi { get; set; }
            virtual public Personel Personel { get; set; }
        }
    

    Viewmodel;

        public class VMSatis_Musteri
        {
            public Satis Satis { get; set; }
            public Musteri Musteri { get; set; }
        }
    

    View;

    @using AutoMapperProjectExample.Models.ViewModels
    @model VMSatis_Musteri
    
    @using (Html.BeginForm("Create", "Home", FormMethod.Post))
    {
        @Html.TextBoxFor(p => p.Satis.SatisNo)<br />
        @Html.TextBoxFor(p => p.Musteri.Sirketi)<br />
        <button>Gönder</button>
    }
    

    Asp.NET Core'da AutoMapper Kullanımı

    Yukarıdaki örnekten de görüldüğü üzere “Satis” ve “Musteri” nesnelerini “VMSatis_Musteri” isimli ViewModel ile tek bir nesnede birleştirmiş ve bu şekilde organize etmiş bulunmaktayız.

Görüldüğü üzere ViewModel nesneleri, bu şekilde iki farklı senaryoya göre sorumluluk üstlenen model destekçisi nesnelerimizdir.

Ayriyetten ViewModel nesneleri;

  • View sayfalarında verileri tutmak için,
  • Data Annotations ile Validations kurallarını belirlemek için,
  • Static verileri/değerleri tutan ihtiyaca dönük nesneleri kullanabilmek için

vs. amaçlıda kullanılır.

AutoMapper Kütüphanesi Ne İşe Yarar?

ViewModel nesnesinin 1. senaryodaki sorumluluğuna karşı gerçek model ile viewmodel arasındaki eşleşmeleri otomatik bir şekilde sağlayabilmek için kullanılan bir kütüphanedir.

Şöyle ki, bir personelin sadece ad ve soyad bilgilerinden bir kayıt oluşturacaksak eğer ilgili verilerle eşleşecek bir viewmodel tasarlayarak post neticesinde gelen datayı bu viewmodel ile karşılayabiliriz. Lakin context üzerinden gerçek entity ile temas kurulabileceğinden dolayı viewmodelde ki verileri gerçek modele yani entitye aktarmamız gerekmektedir. İşte bu işlemi AutoMapper bizler yerine otomatik bir şekilde gerçekleştirmektedir.

Asp.NET Core'da AutoMapper Kullanımı

Yukarıdaki ekran görüntüsünde viewmodel’de ki verileri manuel bir şekilde entitye aktarmış bulunmaktayız. Günün sonunda bu işlemi otomatik bir şekilde yapacak olan AutoMapper nesnesine bırakacağız.

AutoMapper Entegrasyonu

AutoMapper kütüphanesini aşağıdaki kod aracılığıyla projeye entegre edebilirsiniz;

Install-Package AutoMapper.Extensions.Microsoft.DependencyInjection

Kurulumu

Kütüphane entegrasyonundan sonra uygulamaya “Startup.cs” dosyasındaki “ConfigureServices” metodu içerisinden AutoMapper kütüphanesini servis olarak ekliyoruz.

        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAutoMapper();
        }

Kullanımı

AutoMapper kütüphanesini kullanabilmek için gerçek modeller(entity) ile oluşturulan viewmodeller arasındaki ilişki belirtilmelidir. Yani, hangi model hani viewmodelle eşleşecektir…

Asp.NET Core'da AutoMapper Kullanımı

Eşleşme için AutoMapper kütüphanesinin “Profile” sınıfı kullanılmaktadır. Tüm eşleşme profillerini bu sınıf aracılığıyla gerçekleştirmekte ve uygulamaya bildirmekteyiz.
Örnek için aşağıdaki model ve viewmodelleri oluşturalım.
Gerçek modeller;

    public class Musteri
    {
        public int Id { get; set; }
        public int PersonelId { get; set; }
        public string Adi { get; set; }
        public string Sirketi { get; set; }
        virtual public Personel Personel { get; set; }
    }
    public class Personel
    {
        public int Id { get; set; }
        public string Adi { get; set; }
        public string Soyadi { get; set; }
        public string KullaniciAdi { get; set; }
        public string Sifre { get; set; }
        virtual public ICollection<Musteri> Musteriler { get; set; }
        virtual public ICollection<Satis> Satislar { get; set; }
    }
    public class Satis
    {
        public int Id { get; set; }
        public int PersonelId { get; set; }
        public string SatisNo { get; set; }
        virtual public Personel Personel { get; set; }
    }

ViewModeller;

    public class VMMusteri
    {
        public string Adi { get; set; }
        public string Sirketi { get; set; }
    }
    public class VMPersonel
    {
        public string Adi { get; set; }
        public string Soyadi { get; set; }
    }
    public class VMSatis
    {
        public string SatisNo { get; set; }
    }

“Profile” sınıfımız;

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Personel, VMPersonel>();
            CreateMap<VMPersonel, Personel>();
            CreateMap<Musteri, VMMusteri>();
            CreateMap<VMMusteri, Musteri>();
            CreateMap<Satis, VMSatis>();
            CreateMap<VMSatis, Satis>();
        }
    }

Yukarıdaki kod bloğuna dikkat ederseniz eğer “Profile” abstract sınıfından türettiğimiz “MappingProfile” isimli sınıfımız bizim için eşleştirme profillerini barındıracak sorumluluğu üstlenmektedir. İşlemleri kolaylık olması açısından ilgili sınıfın constructerında gerçekleştirmeyiz. “Profile” sınıfından gelen “CreateMap” metodu aracılığıyla eşleştirmeler yapılmaktadır. Burada özellikle dikkatinizi çekmek istediğim husus, her eşleştirmenin birde simetriğini sağlayarak tersine bir çevriminde söz konusu olacağı durumlarıda hesaba katmaktayız.

Kullanım;
Asp.NET Core'da AutoMapper Kullanımı
Yukarıdaki ekran görüntüsünü incelerseniz eğer AutoMapper, Assembly’de ki “Profile” nesnesini bulmakta ve eşleştirmeler neticesinde arka planda reflection ile memberları check ederek aralarında verilsel transferi sağlamaktadır. Dolayısıyla bizleri ekstradan bir maliyetten kurtarmakta ve hızımıza hız katmaktadır. “VMPersonel” olarak gelen nesneyi AutoMapper kütüphanesinin nimetlerinden olan “IMapper” sınıfını kullanarak “Personel” sınıfına Map(eşleştirme) etmekteyiz. Bu durum diğer modeller ve viewmodeller içinde geçerliliğini koruyacaktır. Artık gerisini sizlerin deneyine bırakıyorum…

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Bunlar da hoşunuza gidebilir...

15 Cevaplar

  1. Gençay dedi ki:

    Merhaba,

    Automapper ile farklı propertyleri eşleştirmek istiyorsanız eğer aşağıdaki örneği inceleyebilirsiniz.

        public class Product
        {
            public int Id { get; set; }
            public string Name { get; set; }
            public int Quantity { get; set; }
        }
        public class Urun
        {
            public int No { get; set; }
            public string Adi { get; set; }
            public int Adet { get; set; }
        }
    
        public class ProductProfile : Profile
        {
            public ProductProfile()
            {
                CreateMap<Product, Urun>()
                .ForMember(member1 => member1.Adet, member2 => member2.MapFrom(x => x.Quantity))
                .ForMember(member1 => member1.Adi, member2 => member2.MapFrom(x => x.Name))
                .ForMember(member1 => member1.No, member2 => member2.MapFrom(x => x.Id));
    
                CreateMap<Urun, Product>()
                .ForMember(member1 => member1.Quantity, member2 => member2.MapFrom(x => x.Adet))
                .ForMember(member1 => member1.Name, member2 => member2.MapFrom(x => x.Adi))
                .ForMember(member1 => member1.Id, member2 => member2.MapFrom(x => x.No));
            }
        }
    

    Bu şekilde kodu geliştirerek farklı isimdeki propertylerin hangileriyle eşleşeceğini belirtebilirsiniz…

    Sevgiler…

  2. Gençay dedi ki:

    Merhaba,

    Authomapper ile bir metot dönüş değeri ile property’i eşleştirmek istiyorsanız eğer aşağıdaki örneği inceleyebilirsiniz.

        public class Urun
        {
            public int No { get; set; }
            public string Adi { get; set; }
            public int Adet { get; set; }
            public string Ozet() => $"No : {No} | Adı : {Adi} | Adet : {Adet}";
        }
        public class UrunDto
        {
            public string Ozet { get; set; }
        }
    

    Ana modeldeki metot ismiyle Dto’da ki property ismi aynı olduğu taktirde otomatik ilgili metodun değerini property’e verecektir. Burada modeldeki fonksiyonun adı aşağıdaki gibi ‘Get’ ön ekiyle de başlayabilir.

        public class Urun
        {
            public int No { get; set; }
            public string Adi { get; set; }
            public int Adet { get; set; }
            public string GetOzet() => $"No : {No} | Adı : {Adi} | Adet : {Adet}";
        }
        public class UrunDto
        {
            public string Ozet { get; set; }
        }
    

    Bu şekilde de ilgili metotla property sorunsuz eşleştirilmiş olacaktır.

    Eğer ki metot ismiyle eşleştirileceği property ismi farklıysa bunun aşağıdaki örneği inceleyiniz.

        public class Urun
        {
            public int No { get; set; }
            public string Adi { get; set; }
            public int Adet { get; set; }
            public string Ozet() => $"No : {No} | Adı : {Adi} | Adet : {Adet}";
        }
        public class UrunDto
        {
            public string UrunOzeti { get; set; }
        }
    
        public class UrunProfile : Profile
        {
            public UrunProfile()
            {
                CreateMap<Urun, UrunDto>().ForMember(member1 => member1.UrunOzeti, member2 => member2.MapFrom(x => x.Ozet()));
                CreateMap<UrunDto, Urun>();
            }
        }
    

    Böylece ‘Urun’ modelindeki Ozet metodu ‘UrunDto’ modelindeki ‘UrunOzeti’ propertysiyle eşleştirilmiştir.

    Kolay gelsin…
    Sevgiler…

  3. Gençay dedi ki:

    Merhaba,

    Flattening
    Düzleştirmek, yassılaştırmak anlamına gelen bu terim complex bir property’i sadece basit propertyler barındıran bir türe dönüştürmeyi ifade eder.

    Örneğin;

        public class Banka
        {
            public string BankaAdi { get; set; }
            public string BankaSubesi { get; set; }
            public int Bakiye { get; set; }
        }
        public class Musteri
        {
            public string Ad { get; set; }
            public string Soyad { get; set; }
            public string Memleket { get; set; }
            public bool Cinsiyet { get; set; }
            public Banka Banka { get; set; }
        }
        public class MusteriDto
        {
            public string Ad { get; set; }
            public string Soyad { get; set; }
            public int BankaBakiye { get; set; }
        }
    

    Yukarıda görüldüğü üzere ‘Musteri’ sınıfı içerisindeki ‘Banka’ propertysi ‘Banka’ türünden bir nesneyi temsil etmektedir. Yani complex bir propertydir.

        public class MusteriProfile : Profile
        {
            public MusteriProfile()
            {
                CreateMap<Musteri, MusteriDto>();
            }
        }
    

    Bu eşleştirme neticesinde ‘Musteri’ sınıfı içerisindeki ‘Banka’ propertysinin ‘Bakiye’ bilgisi ‘MusteriDto’nun ‘BankaBakiye’ propertysine otomatik eşleştirilecektir. Buradaki formatın ‘[ComplexClassName][PropertyName]‘ olduğuna dikkatinizi çekerim. Eğer ki ‘MusteriDto’nun ‘BankaBakiye’ propertysinin ismi bu formatta olmasaydı aşağıdaki gibi çalışılması gerekecekti.

        public class Banka
        {
            public string BankaAdi { get; set; }
            public string BankaSubesi { get; set; }
            public int Bakiye { get; set; }
        }
        public class Musteri
        {
            public string Ad { get; set; }
            public string Soyad { get; set; }
            public string Memleket { get; set; }
            public bool Cinsiyet { get; set; }
            public Banka Banka { get; set; }
        }
        public class MusteriDto
        {
            public string Ad { get; set; }
            public string Soyad { get; set; }
            public int Bakiye { get; set; }
        }
    

    Yukarıda görüldüğü üzere ‘MusteriDto’da ki ‘Bakiye’ propertysini direkt olarak ‘Musteri’ içerisindeki ‘Banka’ propertysinin ‘Bakiye’ bilgisiyle eşleştirebilmek için;

        public class MusteriProfile : Profile
        {
            public MusteriProfile()
            {
                CreateMap<Musteri, MusteriDto>()
                    .ForMember(member1 => member1.Bakiye, member2 => member2.MapFrom(x => x.Banka.Bakiye));
            }
        }
    

    şeklinde çalışılması yeterlidir.
    Merhaba,

    IncludeMembers
    Yukarıdaki gibi complex bir property’i sadece basit propertyler barındıran bir türe dönüştürürken birebir aynı property isimlerinin kullanıldığı durumlarda otomatik eşleştirme sağlanabilmesi için ‘IncludeMembers’ kullanılabilir.

        public class MusteriProfile : Profile
        {
            public MusteriProfile()
            {
                CreateMap<Banka, MusteriDto>();
                CreateMap<Musteri, MusteriDto>()
                    .IncludeMembers(x => x.Banka);
            }
        }
    

    Bu kullanım ‘MusteriDto’ sınıfındaki ‘Bakiye’ propertysi ile ‘Musteri’ sınıfındaki ‘Banka’ türünden propertynin ‘Bakiye’ verisini otomatik eşleştirmektedir. Haliyle ekstradan ForMember ile bir eşleştirmeye yapmaya gerek kalmamaktadır.

    Sevgiler…

  4. Gençay dedi ki:

    Merhaba,

    Projection
    Bir modeldeki property bilgisinin parçalanarak birden fazla property ile eşleştirilmesine Projection denmektedir.

    Örneğin;

        class EventDate
        {
            public DateTime Date { get; set; }
        }
        class EventDateDto
        {
            public int Year { get; set; }
            public int Month { get; set; }
            public int Day { get; set; }
        }
    

    modelleri uygun olacak şekilde eşleştirilmek istenirse eğer

        public class EventDateProfile : Profile
        {
            public EventDateProfile()
            {
                CreateMap<EventDate, EventDateDto>()
                    .ForMember(member1 => member1.Year, member2 => member2.MapFrom(x => x.Date.Year))
                    .ForMember(member1 => member1.Month, member2 => member2.MapFrom(x => x.Date.Month))
                    .ForMember(member1 => member1.Day, member2 => member2.MapFrom(x => x.Date.Day));
    
                CreateMap<EventDateDto, EventDate>()
                    .ForMember(member1 => member1.Date, member2 => member2.MapFrom(x => new DateTime(x.Year, x.Month, x.Day)));
            }
        }
    

    şeklinde çalışılması yeterli olacaktır.

    Kolay gelsin.

  5. Sena dedi ki:

    Teşekkür ederim gencay bey, .net core’a başlayalı bir hafta oldu. Yazılarınızdan baya yararlandım. Elinize sağlık.

  6. abaki dedi ki:

    Emeklerinize sağlık. Henüz hazmetmeye çalışsam da çok faydalı bir paylaşım olduğunu anlıyorum. Teşekkürler.

  7. MERVE BİLGİÇ dedi ki:

    Elinize emeğinize sağlık çok faydalı oldu.

  8. Burakhan dedi ki:

    hocam claim listesini automapper kullanarak aşağıdaki gibi bir clasa cast ediyorum

    fakat sadece ilk alan mapleniyor ,USERNAME digeri boş geliyor. Neden olabilir.

    –Class

     public  class ClaimModel
      {
        public  string USERNAME { get; set; }
        public  string SMTPADR { get; set; }
    
      }
    
     var claims = new List
            {
              new Claim(type: "USERNAME", value: data.USERNAME),
              new Claim("SMTPADR", data.SMTPADR),
    
            };
    
    List userModel = mapper.Map<List>(claims);
    

    –Profile

    .ForMember(dest => dest.USERNAME, act => act.MapFrom(src =>
    (src.Type == "USERNAME") ? src.Value : ""))
    .ForMember(dest => dest.SMTPADR, act => act.MapFrom(src =>
    (src.Type == "SMTPADR") ? src.Value : "")) ;
    
  9. Teşekkürler hocam gayet açıklayıcı olmuş.

  10. Ayriyetten değil hocam ayrıyeten.

  11. Emre dedi ki:

    Hocam, bende entitye ait alanlar dolu gelmiyor dto’ya makalenizdeki gibi yaptım.

  12. Recep Şentürk dedi ki:

    Hocam merhaba,
    Bir modelde string iken diğer modelde Keyvalue(Key,Value şeklinde bir tip) olduığu senaryoda istiyorum ki heddef alandaki stringe Keyvalue alanının Valuesini atasın. tüm propertylerinde geçerli olacak şekilde nasıl yapılabilir bu.

  13. Selam,
    ViewModel 2. senaryo viewmodel kurallarına aykırı geldi bana bilmiyorum belki yanlış düşünüyorum.
    Oluşturdugunuz viewmodel içerisine “satis” ve “musteri” nesnelerini eklediniz yani viewmodel içerisinde gerçek model nesnelerini dahil ettiniz dolayısıyla dışardan temiz görünen ama içerde kirli, gereksiz bilgi barındırılmış oldu ve buda veri açığına da yol açmış oldu.Sanki viewmodel içerisinde gerçek model tanımlamalarını yapmasan daha iyi olacaktır, hiç bir viewmodel gerçek model(entity) içerisinde barındırmamalı.

Bir cevap yazın

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