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
나는 당신의 대답을 좋아합니다. 나는 포장 생각 MappingProfiles과 new 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.