ASP.NET Core'da Automapper nasıl kurulur


256

.NET'te nispeten yeniyim ve "eski yolları" öğrenmek yerine .NET Core ile uğraşmaya karar verdim. Burada .NET Core için AutoMapper kurulumu hakkında ayrıntılı bir makale buldum , ancak bir acemi için daha basit bir yol var mı?



Çekirdeğin daha yeni sürümleri için (> v1) @ Saineshwar'ın cevabına göz atın stackoverflow.com/a/53455699/833878
Robbie

1
Bir örnekle eksiksiz bir cevap bu bağlantıyı tıklayın
Iman Bahrampour

Yanıtlar:


554

Bunu anladım! Ayrıntılar:

  1. Aracılığıyla çözüme ana AutoMapper Paketi ekle Nuget .
  2. Aracılığıyla çözüme AutoMapper Bağımlılık Enjeksiyon Paketi ekle Nuget .

  3. Bir eşleme profili için yeni bir sınıf oluşturun. (Ana çözüm dizininde bir sınıf yaptım MappingProfile.csve aşağıdaki kodu ekledim.) Örnek olarak bir Userve UserDtonesnesi kullanacağım .

    public class MappingProfile : Profile {
        public MappingProfile() {
            // Add as many of these lines as you need to map your objects
            CreateMap<User, UserDto>();
            CreateMap<UserDto, User>();
        }
    }
  4. Ardından AutoMapperConfiguration'ı Startup.csaşağıda gösterildiği gibi ekleyin :

    public void ConfigureServices(IServiceCollection services) {
        // .... Ignore code before this
    
       // Auto Mapper Configurations
        var mappingConfig = new MapperConfiguration(mc =>
        {
            mc.AddProfile(new MappingProfile());
        });
    
        IMapper mapper = mappingConfig.CreateMapper();
        services.AddSingleton(mapper);
    
        services.AddMvc();
    
    }
  5. Eşlenen nesneyi kodda çağırmak için aşağıdakine benzer bir şey yapın:

    public class UserController : Controller {
    
        // Create a field to store the mapper object
        private readonly IMapper _mapper;
    
        // Assign the object in the constructor for dependency injection
        public UserController(IMapper mapper) {
            _mapper = mapper;
        }
    
        public async Task<IActionResult> Edit(string id) {
    
            // Instantiate source object
            // (Get it from the database or whatever your code calls for)
            var user = await _context.Users
                .SingleOrDefaultAsync(u => u.Id == id);
    
            // Instantiate the mapped data transfer object
            // using the mapper you stored in the private field.
            // The type of the source object is the first type argument
            // and the type of the destination is the second.
            // Pass the source object you just instantiated above
            // as the argument to the _mapper.Map<>() method.
            var model = _mapper.Map<UserDto>(user);
    
            // .... Do whatever you want after that!
        }
    }

Umarım bu ASP.NET Core ile yeni başlayan birine yardımcı olur! .NET dünyasında hala yeni olduğum için herhangi bir geri bildirimi veya eleştiriyi memnuniyetle karşılıyoruz!


3
Bağlantılı ayrıntılı makale lostechies.com/jimmybogard/2016/07/20/… , Profilesınıfların nasıl bulunduğunu açıklıyor
Kieren Johnstone

22
@theutz Bu iki CreateMap satırını sonunda bir .ReverseMap () ile de birleştirebilirsiniz. Belki yorum yap, ama daha sezgisel buluyorum.
Astravagrant

6
3. Adımda bir "AutoMapper kullanarak;" üstte uzantı yöntemi içe aktarılır.
Rocklan

8
.Net core 2.0 sürümüne geçtikten sonra artık .net core 1.1 ile sorunsuz çalıştı. Bence, açıkça mantık profili sınıf derleme belirtmek gerekiyor. Hala bunu nasıl başaracağımızı araştırıyorum. Güncelleme: Ah cevap sizin yorumunuzda bulunuyor, benim profilim olan typeof sınıfını geçmek zorundayım. // services.AddAutoMapper (typeof (Başlangıç)); // <- daha yeni otomatik harita sürümü bu imzayı kullanıyor
Esen

3
AutoMapper v8 ve Bağımlılık Enjeksiyonu v5 eklentilerinde, gereken tek şey services.AddAutoMapper (); Başlangıç ​​sınıfının ConfigureServices yönteminde. Benim için, bağımlı sınıf kütüphanesi projelerinde Profil sınıflarını bile bulabildim.
stricq

69

ASP.NET Core ile AutoMapper Kullanımı Adım.

Adım 1. NuGet Paketinden AutoMapper.Extensions.Microsoft.DependencyInjection uygulamasını kurma.

resim açıklamasını buraya girin

Adım 2. "Eşlemeler" Adlı Eşlemeleri tutmak için Çözümde bir Klasör oluşturun.

resim açıklamasını buraya girin

Adım 3. Eşleme klasörü ekledikten sonra " MappingProfile " adında bir sınıf ekledik, bu ad benzersiz ve anlaşılması iyi bir şey olabilir.

Bu sınıfta, tüm eşlemeleri koruyacağız.

resim açıklamasını buraya girin

Adım 4. "ConfigureServices" Başlangıçta Eşleştiriciyi Başlatma

Başlangıç ​​Sınıfında, oluşturduğumuz Profili Başlatmamız ve AutoMapper Hizmetini Kaydetmemiz Gerekir.

  Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());

  services.AddAutoMapper();

AutoMapper'ı başlatmamız ve kaydetmemiz gereken ConfigureServices Yöntemini göstermek için Kod Parçacığı.

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }


    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });


        // Start Registering and Initializing AutoMapper

        Mapper.Initialize(cfg => cfg.AddProfile<MappingProfile>());
        services.AddAutoMapper();

        // End Registering and Initializing AutoMapper

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    }}

Adım 5. Çıktı Al.

Eşlenmiş sonucu almak için AutoMapper.Mapper.Map'i çağırmalı ve Doğru Hedef ve Kaynağı geçmeliyiz.

AutoMapper.Mapper.Map<Destination>(source);

CodeSnippet

    [HttpPost]
    public void Post([FromBody] SchemeMasterViewModel schemeMaster)
    {
        if (ModelState.IsValid)
        {
            var mappedresult = AutoMapper.Mapper.Map<SchemeMaster>(schemeMaster);
        }
    }

13
Aşağıdaki hatayı alıyorum: 'Mapper' does not contain a definition for 'initialize'. AutoMapper.Extensions.Microsoft.DependencyInjection7.0.0 sürümünü kullanıyorum
kimbaudi

Süper detaylı cevap. Teşekkürler bayım.
Rod Hartzell

1
ASP.NET CORE 3.0 kullanıyorsanız bu öğreticiyi denetleyin
Saineshwar

44

@ Theutz'un cevaplarını uzatmak istiyorum - yani bu satır:

// services.AddAutoMapper(typeof(Startup));  // <-- newer automapper version uses this signature.

AutoMapper.Extensions.Microsoft.DependencyInjection sürüm 3.2.0'da bir hata ( muhtemelen ) var. (.NET Core 2.0 kullanıyorum)

Bu baş ettiğini bu GitHub konuda. AutoMapper'in Profile sınıfını devralan sınıflarınız, Startup sınıfını oluşturduğunuz montajın dışındaysa, AutoMapper enjeksiyonunuz şöyle görünüyorsa muhtemelen kaydedilmeyecektir:

services.AddAutoMapper();

hangi derlemeleri AutoMapper profillerinde arayacağınızı açıkça belirtmediğiniz sürece.

Startup.ConfigureServices öğenizde şu şekilde yapılabilir:

services.AddAutoMapper(<assembies> or <type_in_assemblies>);

burada "montajlar" ve "type_in_assemblies" , uygulamanızdaki Profil sınıflarının belirtildiği montajı gösterir. Örneğin:

services.AddAutoMapper(typeof(ProfileInOtherAssembly), typeof(ProfileInYetAnotherAssembly));

Ben varsayalım (ve bu kelimeye vurgu) olduğu nedeniyle parametresiz aşırı (kaynak kodu uygulanmasını takip etmek GitHub'dan ):

public static IServiceCollection AddAutoMapper(this IServiceCollection services)
{
     return services.AddAutoMapper(null, AppDomain.CurrentDomain.GetAssemblies());
}

AutoMapper profillerini içeren JITed derlemesine sahip olan ve yalnızca gerektiğinde kesilebileceği için doğru olabilecek veya olmayabilecek CLR'ye güveniyoruz ( bu StackOverflow sorusunda daha fazla ayrıntı ).


5
Bu AutoMapper ve
AspNetCore'un

1
AutoMapper 8.1 (en son sürüm) için aradığım cevap
buydu

30

theutz'un cevabı çok iyi, sadece bunu eklemek istiyorum:

Eşleme profilinizin MapperConfigurationExpressionbunun yerine miras almasına izin Profileverirseniz, eşleme kurulumunuzu doğrulamak için her zaman kullanışlı olan bir test ekleyebilirsiniz:

[Fact]
public void MappingProfile_VerifyMappings()
{
    var mappingProfile = new MappingProfile();

    var config = new MapperConfiguration(mappingProfile);
    var mapper = new Mapper(config);

    (mapper as IMapper).ConfigurationProvider.AssertConfigurationIsValid();
}

Bir hata alıyorum: "AutoMapper Extension Dependency enjeksiyon asp.net core 1.1 ile uyumsuz". Lütfen yardım et!
Rohit Arora

Görünüşe göre "doğrulama" tanımı tartışmaya açık. Eşleştirmeyi önlemek için belirli özellikler tasarımla sağlandığında bu patlar.
Jeremy Holovacs

2
Bir mülkün eşlenmesini istemiyorsanız, .Ignore () ile ayarlayın. Bu şekilde, her bir vakayı ele almayı aktif olarak düşünmeye zorlar - değişiklikler yapılırken şeyleri kaçırmamanızı sağlar. Aslında çok pratik. Evet, doğrulama testi birçok kişinin fark ettiğinden daha büyük bir güvenlik ağıdır. Kusursuz değildir, ancak ilk% 90'ına bakar.
Arve Systad

18

.NET Core 2.2 / Automapper 8.1.1 / Extensions için bu şekilde çözdüm (yukarıdakine benzer ama daha temiz bir çözüm gibi hissediyorum).

MappingProfile.cs sınıfı oluşturun ve yapıcıyı Haritalar ile doldurun (Tüm eşlemelerimi tutmak için tek bir sınıf kullanmayı planlıyorum)

    public class MappingProfile : Profile
    {
        public MappingProfile()
        {
            CreateMap<Source, Dest>().ReverseMap();
        }
    }

Startup.cs içinde, DI'ye eklemek için aşağı ekleyin (montaj argümanı, eşleme yapılandırmalarınızı tutan sınıf içindir, benim durumumda MappingProfile sınıfıdır).

//add automapper DI
services.AddAutoMapper(typeof(MappingProfile));

Denetleyici'de bunu diğer DI nesnelerinde yaptığınız gibi kullanın

    [Route("api/[controller]")]
    [ApiController]
    public class AnyController : ControllerBase
    {
        private readonly IMapper _mapper;

        public AnyController(IMapper mapper)
        {
            _mapper = mapper;
        }

        public IActionResult Get(int id)
        {
            var entity = repository.Get(id);
            var dto = _mapper.Map<Dest>(entity);

            return Ok(dto);
        }
    }


2
Cevabını beğendim. Ben sarma düşünüyorum MappingProfilesile new Type[]{}gösterildiği gibi bu cevap gereksizdir.
Çok Şişman Adam Boyun Yok

10

Startup.cs dosyamda (Core 2.2, Automapper 8.1.1)

services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });            

Veri erişim projemde

namespace DAL
{
    public class MapperProfile : Profile
    {
        // place holder for AddAutoMapper (to bring in the DAL assembly)
    }
}

Model tanımımda

namespace DAL.Models
{
    public class PositionProfile : Profile
    {
        public PositionProfile()
        {
            CreateMap<Position, PositionDto_v1>();
        }
    }

    public class Position
    {
        ...
    }

Neden sadece kullanmayın services.AddAutoMapper( typeof(DAL.MapperProfile) ); yerine services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });?
Çok Şişman Adam Boyun Yok

8

Birçok cevabı severim, özellikle @saineshwar'ın cevabı. AutoMapper 9.0 ile .net Core 3.0 kullanıyorum, bu yüzden cevabını güncelleme zamanı geldiğini hissediyorum.

Benim için işe yarayan Startup.ConfigureServices (...) hizmetini şu şekilde kaydettirdi:

    services.AddAutoMapper(cfg => cfg.AddProfile<MappingProfile>(), 
                               AppDomain.CurrentDomain.GetAssemblies());

@Saineshwar cevabının geri kalanının mükemmel olduğunu düşünüyorum. Ama kimse ilgileniyorsa benim denetleyici kodu:

[HttpGet("{id}")]
public async Task<ActionResult> GetIic(int id)
{
    // _context is a DB provider
    var Iic = await _context.Find(id).ConfigureAwait(false);

    if (Iic == null)
    {
        return NotFound();
    }

    var map = _mapper.Map<IicVM>(Iic);

    return Ok(map);
}

Ve benim harita sınıfım:

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Iic, IicVM>()
            .ForMember(dest => dest.DepartmentName, o => o.MapFrom(src => src.Department.Name))
            .ForMember(dest => dest.PortfolioTypeName, o => o.MapFrom(src => src.PortfolioType.Name));
            //.ReverseMap();
    }
}

----- DÜZENLE -----

Lucian Bargaoanu'nun yorumlarında yer alan dokümanları okuduktan sonra, bu cevabı biraz değiştirmek daha iyi olduğunu düşünüyorum.

Parametresiz services.AddAutoMapper() (@saineshwar cevabı vardı) artık çalışmıyor (en azından benim için). Ancak NuGet derlemesi AutoMapper.Extensions.Microsoft.DependencyInjection kullanırsanız, çerçeve AutoMapper.Profile dosyasını (benimki gibi MappingProfile gibi) genişleten tüm sınıfları denetleyebilir.

Yani, benim durumumda, sınıfın aynı yürütme derlemesine ait olduğu durumda, hizmet kaydı kısaltılabilir services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
(Daha zarif bir yaklaşım, bu kodlama ile parametresiz bir uzantı olabilir).

Teşekkürler Lucian!



6

AutoMapper 6.1.1 ve asp.net Core 1.1.2 kullanıyorum.

Her şeyden önce, Automapper'ın Profile Class tarafından miras alınan Profile sınıflarını tanımlayın. Boş olan IProfile arabirimini oluşturdum, amacı sadece bu tür sınıfları bulmak.

 public class UserProfile : Profile, IProfile
    {
        public UserProfile()
        {
            CreateMap<User, UserModel>();
            CreateMap<UserModel, User>();
        }
    }

Şimdi ayrı bir sınıf oluşturun, örneğin Mappings

 public class Mappings
    {
     public static void RegisterMappings()
     {            
       var all =
       Assembly
          .GetEntryAssembly()
          .GetReferencedAssemblies()
          .Select(Assembly.Load)
          .SelectMany(x => x.DefinedTypes)
          .Where(type => typeof(IProfile).GetTypeInfo().IsAssignableFrom(type.AsType()));

            foreach (var ti in all)
            {
                var t = ti.AsType();
                if (t.Equals(typeof(IProfile)))
                {
                    Mapper.Initialize(cfg =>
                    {
                        cfg.AddProfiles(t); // Initialise each Profile classe
                    });
                }
            }         
        }

    }

Şimdi Startup.cs dosyasındaki MVC Core web Project'te, yapıcıda, uygulama yükleme sırasında tüm eşlemeleri başlatan Mapping sınıfını çağırın.

Mappings.RegisterMappings();

Sadece profil sınıfından ve program hizmetleri çalıştırırken bir alt sınıf oluşturabilirsiniz. kod satırı Automapper bunları otomatik olarak tanır.
isaeid

Nuget içinde bulunan AutoMapper.Extensions.Microsoft.DependancyInjection kullanıyorsanız bunun gerekli olduğunu düşünmüyorum.
Greg Gum

5

ASP.NET Core için (2.0+ ve 3.0 kullanılarak test edilmiştir), kaynak belgeleri okumayı tercih ederseniz: https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md

Aksi takdirde bu 4 adımı takip etmek işe yarar:

  1. Nuget'ten AutoMapper.Extensions.Microsoft.DependancyInjection uygulamasını yükleyin.

  2. Sadece bazı profil sınıfları ekleyin.

  3. Ardından startup.cs sınıfınıza ekleyin. services.AddAutoMapper(OneOfYourProfileClassNamesHere)

  4. Ardından, kontrol cihazlarınıza veya ihtiyacınız olan yere IMapper'ı enjekte edin:

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

Ve ProjectTo şimdi kullanmak istiyorsanız:

var customers = await dbContext.Customers.ProjectTo<CustomerDto>(_mapper.ConfigurationProvider).ToListAsync()

4

AutoMapper 9.0.0 için:

public static IEnumerable<Type> GetAutoMapperProfilesFromAllAssemblies()
    {
        foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies())
        {
            foreach (var aType in assembly.GetTypes())
            {
                if (aType.IsClass && !aType.IsAbstract && aType.IsSubclassOf(typeof(Profile)))
                    yield return aType;
            }
        }
    }

MapperProfile:

public class OrganizationProfile : Profile
{
  public OrganizationProfile()
  {
    CreateMap<Foo, FooDto>();
    // Use CreateMap... Etc.. here (Profile methods are the same as configuration methods)
  }
}

Startup'ınızda:

services.AddAutoMapper(GetAutoMapperProfilesFromAllAssemblies()
            .ToArray());

Denetleyici veya hizmette: Eşleştiriciyi enjekte et:

private readonly IMapper _mapper;

Kullanımı:

var obj = _mapper.Map<TDest>(sourceObject);

4

Asp.net core'un en son sürümlerinde aşağıdaki başlatmayı kullanmalısınız:

services.AddAutoMapper(typeof(YourMappingProfileClass));

2

Asp.Net Core 2.2 ve AutoMapper.Extensions.Microsoft.DependencyInjection.

public class MappingProfile : Profile
{
  public MappingProfile()
  {
      CreateMap<Domain, DomainDto>();
  }
}

Startup.cs içinde

services.AddAutoMapper(typeof(List.Handler));

1

Test için Arve Systad'ın bahsettiklerini eklemek için. Herhangi bir nedenden dolayı benim gibi olursanız ve theutz çözümünde sağlanan kalıtım yapısını korumak istiyorsanız, MapperConfiguration'ı şu şekilde ayarlayabilirsiniz:

var mappingProfile = new MappingProfile();
var config = new MapperConfiguration(cfg =>
{
    cfg.AddProfile(mappingProfile);
});
var mapper = new Mapper(config);

Bunu NUnit'te yaptım.


1

services.AddAutoMapper (); benim için çalışmadı. (Asp.Net Core 2.0 kullanıyorum)

Aşağıdaki gibi yapılandırdıktan sonra

   var config = new AutoMapper.MapperConfiguration(cfg =>
   {                 
       cfg.CreateMap<ClientCustomer, Models.Customer>();
   });

mapper'ı başlat IMapper mapper = config.CreateMapper ();

ve eşleştirici nesnesini tek bir hizmet olarak hizmetlere ekleyin.

bu şekilde denetleyiciye bir DI ekleyebiliyorum

  private IMapper autoMapper = null;

  public VerifyController(IMapper mapper)
  {              
   autoMapper = mapper;  
  }

ve eylem yöntemlerimde aşağıdaki gibi kullandım

  ClientCustomer customerObj = autoMapper.Map<ClientCustomer>(customer);

Merhaba @venkat muhtemelen projenize AutoMapper.Extensions.Microsoft.DependancyInjection paketini eklemeniz gerekiyordu
dalcam

-1

theutz cevabı hakkında , kontrolör yapıcısında IMapper eşleyici parrametresini belirtmeye gerek yoktur .

Mapper'ı, kodun herhangi bir yerinde statik bir üye olduğu için kullanabilirsiniz.

public class UserController : Controller {
   public someMethod()
   {
      Mapper.Map<User, UserDto>(user);
   }
}

11
Fakat statikler biraz test edilebilir, değil mi?
Scott Fraley

3
Evet. Bu, birçok durumda işe yarar, ancak bu yöntemi bir testte çağırırken yapılandırılmış eşlemeniz yoksa, bir istisna atar (ve dolayısıyla testi yanlış nedenden dolayı başarısız olur). Enjekte edildiğinde IMapperbunu alay edebilir ve örneğin, verilen test için ilgisizse null değerini döndürmesini sağlayabilirsiniz.
Arve Systad
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.