ASP.NET Core에서 Automapper를 설정하는 방법


255

저는 .NET을 처음 접했고 "오래된 방식"을 배우는 대신 .NET Core를 다루기로 결정했습니다. .NET Core 용 AutoMapper 설정 에 대한 자세한 기사를 여기 에서 찾았 지만 초보자에게는 더 간단한 연습이 있습니까?



최신 버전의 코어 (> v1)는 @Saineshwar의 답변 stackoverflow.com/a/53455699/833878
Robbie

1
예를 가진 완전한 대답은 이 링크를 클릭
이만 Bahrampour

답변:


554

나는 그것을 알아! 세부 사항은 다음과 같습니다.

  1. NuGet 을 통해 기본 AutoMapper 패키지를 솔루션에 추가하십시오 .
  2. NuGet 을 통해 AutoMapper Dependency Injection Package를 솔루션에 추가하십시오 .

  3. 맵핑 프로파일의 새 클래스를 작성하십시오. (주요 솔루션 디렉토리에 클래스를 MappingProfile.cs만들고 다음 코드를 추가합니다.) 예제로 Userand UserDto객체를 사용합니다 .

    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. 그런 다음 Startup.cs아래와 같이 AutoMapperConfiguration을 추가하십시오 .

    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. 코드에서 맵핑 된 오브젝트를 호출하려면 다음과 같이 수행하십시오.

    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!
        }
    }

이것이 ASP.NET Core로 새로 시작하는 데 도움이되기를 바랍니다. .NET 세계를 처음 접하면서 의견이나 비판을 환영합니다!


3
상세한 기사 링크, lostechies.com/jimmybogard/2016/07/20/…Profile 은 수업의 위치를 설명합니다
Kieren Johnstone

22
@theutz 두 개의 CreateMap 줄을 끝에 .ReverseMap ()과 병합 할 수도 있습니다. 아마도 의견을 말하지만 더 직관적이라고 생각합니다.
Astravagrant 2016 년

6
3 단계에서 "AutoMapper 사용"을 추가하는 것이 도움이 될 수 있습니다. 확장 방법을 가져올 수 있도록 맨 위에
Rocklan

8
.net 코어 2.0으로 업그레이드하면 더 이상 .net 코어 1.1에서 제대로 작동했습니다. 논리 프로필 클래스 어셈블리를 명시 적으로 지정해야한다고 생각합니다. 아직도 그것을 달성하는 방법을 연구하고 있습니다. 업데이트 : 아 대답은 귀하의 의견에 있으며, 내 프로필 인 classof 클래스를 전달해야합니다. // services.AddAutoMapper (typeof (Startup)); // <-최신 오토 매퍼 버전은이 서명을 사용합니다
Esen

3
AutoMapper v8 및 Dependency Injection v5 애드온에서 필요한 것은 services.AddAutoMapper (); Startup 클래스의 ConfigureServices 메소드에있는 행 저에게는 종속 클래스 라이브러리 프로젝트에서 프로파일 클래스를 찾을 수도있었습니다.
stricq

68

ASP.NET Core에서 AutoMapper를 사용하는 단계

1 단계. NuGet 패키지에서 AutoMapper.Extensions.Microsoft.DependencyInjection 설치

여기에 이미지 설명을 입력하십시오

2 단계. 솔루션에서 폴더를 생성하여 이름이 "Mappings"인 매핑을 유지합니다.

여기에 이미지 설명을 입력하십시오

3 단계. Mapping 폴더를 추가 한 후 이름이 " MappingProfile "인 클래스를 추가했습니다. 이 이름은 독특하고 이해하기 쉬운 것입니다.

이 클래스에서는 모든 매핑을 유지 관리합니다.

여기에 이미지 설명을 입력하십시오

4 단계 시작 "ConfigureServices"에서 맵퍼 초기화

Startup Class에서는 생성 한 프로파일을 초기화하고 AutoMapper 서비스를 등록해야합니다.

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

  services.AddAutoMapper();

AutoMapper를 초기화하고 등록해야하는 ConfigureServices 메소드를 표시하는 코드 스 니펫

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);

    }}

5 단계. 출력을 얻습니다.

매핑 된 결과를 얻으려면 AutoMapper.Mapper.Map을 호출하고 적절한 대상 및 소스를 전달해야합니다.

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

코드 스 니펫

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

13
다음과 같은 오류가 발생 'Mapper' does not contain a definition for 'initialize'합니다.. AutoMapper.Extensions.Microsoft.DependencyInjection버전 7.0.0을 사용하고 있습니다.
kimbaudi

매우 자세한 답변. 감사합니다.
Rod Hartzell

1
ASP.NET CORE 3.0을 사용하는 경우이 자습서를 확인하십시오. ASP.NET Core 3.0에서 AutoMapper를 설정하는 방법 tutexchange.com/how-to-set-up-automapper-in-asp-net-core-3-0
Saineshwar

44

@theutz의 답변을 확장하고 싶습니다.

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

버그 (이 아마 AutoMapper.Extensions.Microsoft.DependencyInjection 버전 3.2.0에서이). (저는 .NET Core 2.0을 사용하고 있습니다)

이것은 GitHub 문제에서 해결됩니다. AutoMapper의 Profile 클래스를 상속하는 클래스가 Startup 클래스가있는 어셈블리 외부에 존재하면 AutoMapper 주입이 다음과 같은 경우 등록되지 않을 것입니다.

services.AddAutoMapper();

AutoMapper 프로파일을 검색 할 어셈블리를 명시 적으로 지정하지 않는 한.

Startup.ConfigureServices에서 다음과 같이 수행 할 수 있습니다.

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

여기서 "assemblies""type_in_assemblies" 는 응용 프로그램의 프로파일 클래스가 지정된 어셈블리를 가리 킵니다. 예 :

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

나는 매개 변수가없는 과부하 ( GitHub의 소스 코드) 구현으로 인해 다음과 같이 가정합니다 (이 단어에 중점을 둡니다 ).

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

우리는 수 있습니다 또는 (더 자세한 내용은 필요한 때 만 jitted대로 진실하지 않을 수 있습니다 이미 JITed 조립 포함 AutoMapper 프로필을 가진 CLR에 의존 StackOverflow의 질문).


5
최신 버전의 AutoMapper 및 AspNetCore에 대한 정답
Joshit

1
이것은 내가 찾은 AutoMapper 8.1 (최신 버전)
Tinaira

30

theutz의 대답은 여기에 매우 좋습니다. 단지 추가하고 싶습니다.

매핑 프로필 MapperConfigurationExpression대신 에서 프로필을 상속받는 경우 Profile매핑 설정을 확인하는 테스트를 매우 간단하게 추가 할 수 있습니다.

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

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

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

"AutoMapper Extension Dependency injection은 asp.net core 1.1과 호환되지 않습니다"라는 오류가 발생합니다. 도와주세요!
Rohit Arora

"확인"의 정의는 논쟁의 여지가있는 것 같습니다. 매핑을 방지하기 위해 디자인에 의해 특정 속성이 생략 된 경우 문제가 발생합니다.
Jeremy Holovacs 2014 년

2
속성을 매핑하지 않으려면 .Ignore ()로 설정하십시오. 이렇게하면 각 사례 처리에 대해 적극적으로 생각하게되므로 변경시 내용을 놓치지 않도록해야합니다. 실제로는 실용적입니다. 따라서 검증 테스트는 많은 사람들이 알고있는 것보다 더 큰 안전망입니다. 완벽하지는 않지만 처음 90 %를 처리합니다.
Arve Systad

18

.NET Core 2.2 / Automapper 8.1.1 w / Extensions.DI 6.1.1에 대해이 방법으로 해결했습니다 (위와 유사하지만 더 깨끗한 솔루션 인 것 같습니다).

MappingProfile.cs 클래스를 만들고지도로 생성자를 채 웁니다 (모든 클래스를 유지하기 위해 단일 클래스를 사용할 계획입니다)

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

Startup.cs에서 아래를 추가하여 DI에 추가하십시오 (조립 인수는 매핑 구성을 보유하는 클래스에 대한 것입니다. 필자의 경우 MappingProfile 클래스입니다).

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

Controller에서 다른 DI 객체처럼 사용하십시오.

    [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
나는 당신의 대답을 좋아합니다. 나는 포장 생각 MappingProfilesnew Type[]{}같이 이 대답은 필요하지 않습니다.
Money Oriented Programmer

10

내 Startup.cs (Core 2.2, Automapper 8.1.1)에서

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

내 데이터 액세스 프로젝트에서

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

내 모델 정의에서

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

    public class Position
    {
        ...
    }

services.AddAutoMapper( typeof(DAL.MapperProfile) ); 대신에 사용 하지 services.AddAutoMapper(new Type[] { typeof(DAL.MapperProfile) });않습니까?
돈은 프로그래머 지향

8

나는 많은 답변, 특히 @saineshwar의 답변을 좋아합니다. AutoMapper 9.0과 함께 .net Core 3.0을 사용하고 있으므로 답변을 업데이트 할 때가되었다고 생각합니다.

나를 위해 일한 것은 Startup.ConfigureServices (...)에서 다음과 같이 서비스를 등록합니다.

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

@saineshwar의 나머지 답변은 완벽하게 유지된다고 생각합니다. 그러나 누군가 관심이 있다면 내 컨트롤러 코드는 다음과 같습니다.

[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);
}

그리고 내 매핑 클래스 :

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();
    }
}

----- 편집하다 -----

Lucian Bargaoanu의 의견에 연결된 문서를 읽은 후에이 답변을 조금 변경하는 것이 좋습니다.

매개 변수가없는 services.AddAutoMapper()(@saineshwar 답변이 있음) 더 이상 작동하지 않습니다 (적어도 나를 위해). 그러나 NuGet 어셈블리 AutoMapper.Extensions.Microsoft.DependencyInjection을 사용하면 프레임 워크는 AutoMapper.Profile을 확장하는 모든 클래스 (예 : 광산, MappingProfile)를 검사 할 수 있습니다.

따라서 클래스가 동일한 실행 어셈블리에 속하는 경우 서비스 등록을 단축 할 수 있습니다 services.AddAutoMapper(System.Reflection.Assembly.GetExecutingAssembly());
(보다 우아한 접근 방식은이 코딩으로 매개 변수가없는 확장 일 수 있음).

고마워, 루시안!



6

AutoMapper 6.1.1 및 asp.net Core 1.1.2를 사용하고 있습니다.

우선, Automapper의 프로파일 클래스에 의해 상속 된 프로파일 클래스를 정의하십시오. 비어있는 IProfile 인터페이스를 만들었습니다. 목적은이 유형의 클래스 만 찾는 것입니다.

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

이제 별도의 클래스를 만듭니다. 예 : 매핑

 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
                    });
                }
            }         
        }

    }

이제 Startup.cs 파일의 MVC Core 웹 프로젝트에서 생성자에서 응용 프로그램을로드 할 때 모든 매핑을 초기화하는 Mapping 클래스를 호출합니다.

Mappings.RegisterMappings();

프로파일 클래스에서 그리고 프로그램이 서비스를 실행하고있을 때 서브 클래스를 작성할 수 있습니다. 코드 라인 오토 매퍼가 자동으로 알고 있습니다.
isaeid

너겟에서 사용할 수있는 AutoMapper.Extensions.Microsoft.DependancyInjection을 사용하는 경우 이것이 필요하다고 생각하지 않습니다.
Greg Gum

5

ASP.NET Core (2.0+ 및 3.0을 사용하여 테스트)의 경우 소스 문서를 읽으려면 https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection/blob/master/README.md

그렇지 않으면 다음 4 단계를 따라 작동합니다.

  1. 너겟에서 AutoMapper.Extensions.Microsoft.DependancyInjection을 설치하십시오.

  2. 간단히 프로파일 클래스를 추가하십시오.

  3. 그런 다음 startup.cs 클래스에 아래를 추가하십시오. services.AddAutoMapper(OneOfYourProfileClassNamesHere)

  4. 그런 다음 컨트롤러 또는 필요할 때마다 IMapper를 주입하십시오.

public class EmployeesController {

    private readonly IMapper _mapper;

    public EmployeesController(IMapper mapper){

        _mapper = mapper;
    }

그리고 ProjectTo를 지금 사용하려면 다음을 수행하십시오.

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

4

AutoMapper 9.0.0의 경우 :

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;
            }
        }
    }

매퍼 프로필 :

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

스타트 업에서 :

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

컨트롤러 또는 서비스에서 : 매퍼 주입 :

private readonly IMapper _mapper;

용법:

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

4

최신 버전의 asp.net core에서 다음 초기화를 사용해야합니다.

services.AddAutoMapper(typeof(YourMappingProfileClass));

2

AutoMapper.Extensions.Microsoft.DependencyInjection이 포함 된 Asp.Net Core 2.2

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

Startup.cs에서

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

1

Arve Systad가 테스트를 위해 언급 한 내용을 추가합니다. 어떤 이유로 든 나와 같은지, theutz 솔루션에서 제공되는 상속 구조를 유지하려면 MapperConfiguration을 다음과 같이 설정할 수 있습니다.

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

NUnit 에서이 작업을 수행했습니다.


1

services.AddAutoMapper (); 나를 위해 작동하지 않았다. (Asp.Net Core 2.0을 사용하고 있습니다)

아래와 같이 구성한 후

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

매퍼 초기화 IMapper 매퍼 = config.CreateMapper ();

맵퍼 객체를 서비스에 싱글 톤 서비스로 추가합니다 .AddSingleton (mapper);

이 방법으로 컨트롤러에 DI를 추가 할 수 있습니다

  private IMapper autoMapper = null;

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

내 행동 방법에서 아래와 같이 사용했습니다.

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

안녕하세요 @venkat 당신은 아마 AutoMapper.Extensions.Microsoft.DependancyInjection 패키지를 프로젝트에 추가해야 할 것입니다
dalcam

-1

theutz answer 에 대해서는 컨트롤러 생성자에서 IMapper 매퍼 매개 변수 를 지정할 필요가 없습니다 .

코드의 어느 곳에서나 매퍼를 정적 멤버로 사용할 수 있습니다.

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

11
그러나 스태틱은 약간 테스트 할 수 없습니다.
Scott Fraley

3
네. 이것은 많은 경우에 효과가 있지만 테스트에서이 메소드를 호출 할 때 맵핑을 구성하지 않은 경우 예외가 발생하여 잘못된 이유로 테스트에 실패합니다. 주입 IMapper하면 그것을 조롱 할 수 있으며, 예를 들어 주어진 테스트와 관련이 없다면 null을 반환하도록하십시오.
Arve Systad
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.