2017-11-12 1 views
0

속성 기반 자동 매퍼 기능을 만들고 싶습니다. 도메인 모델 클래스를 DTO 및 역방향으로 매핑해야하지만 DTO의 일부 속성을 절대로 도메인 클래스에 매핑하면 안됩니다. 읽기 전용 속성으로. 서버에서 클라이언트로의 방향 만 허용됩니다.속성에 의한 자동 매퍼 설정

좋아, 그래서 속성을 사용하여 방향을 설정하고자하기 때문에 나는이

public class Person 
{ 
    public int Id { get; set; } 
    public string Name { get; set; } 
} 

public class PersonDTO 
{ 
    [MapperDirection(Direction.ClientToServer)] 
    public string Name { get; set; } 
    public string Metadata { get; set; } 
} 

이,이 일

[Flags] 
public enum Direction 
{ 
    None = 0, 
    ServerToClient = 1, 
    ClientToServer = 2, 
    Both = 4 
} 

[AttributeUsage(AttributeTargets.Property)] 
public class MapperDirectionAttribute : Attribute 
{ 
    public Direction Direction { get; } 

    public MapperDirectionAttribute(Direction direction = Direction.Both) 
    { 
     Direction = direction; 
    } 
} 

내가 클라이언트에 전용 서버를 허용하는 DTO 클래스에 이름 속성을 장식해야 이름에 대한 방향.

나는 소스에서 모든 값을 복사하려면이 확장자를 가진 매퍼 도우미로

가 그래서

public static class MapperExpressions 
{ 
    public static IMappingExpression<TSource, TDestination> OnlyIfClientToServer<TSource, TDestination>(this IMappingExpression<TSource, TDestination> expression) 
    { 
     var sourceType = typeof(TSource); 
     var props = sourceType.GetMembers().Where(prop => prop.IsDefined(typeof(MapperDirectionAttribute), false)); 
     foreach (var property in props) 
     { 
      var attribute = property.GetCustomAttribute<MapperDirectionAttribute>(); 
      var allow = attribute.Direction == Direction.ClientToServer || attribute.Direction == Direction.Both; 
      if (!allow) 
      { 
       // THIS DOESN'T WORK FOR SOURCE MEMBER 
       // AND CAN'T BE USED FOR DESTINATION MEMBER (BECAUSE OF MISSING PROPERTIES) 
       expression.ForSourceMember(property.Name, opt => opt.Ignore()); 
      } 
     } 

     return expression; 
    } 
} 

매퍼 초기화를 설정하는 속성에 따라 대상으로하는

 // Init mapper 
     Mapper.Initialize(cfg => 
     { 
      cfg.CreateMap<Person, PersonDTO>(); 

      cfg.CreateMap<PersonDTO, Person>() 
       .OnlyIfClientToServer(); 
      //.ForSourceMember(src => src.Name, src => src.Ignore()) // DOESN'T WORK 
      //.ForMember(dst => dst.Name, dst => dst.Ignore()); // WORKS, BUT DON'T WANT EXPLICIT DEFINITION 
     }); 

그리고 콘솔 응용 프로그램의 일부입니다

 // Map Domain -> ViewModel 
     var person = new Person { Id = 1, Name = "Default Name From Domain" }; 
     var personDto = Mapper.Map<PersonDTO>(person); 

     Console.WriteLine($"Person: Id = '{person.Id}', Name = '{person.Name}'"); 
     Console.WriteLine($"PersonDTO: Name = '{personDto.Name}', Metadata = '{personDto.Metadata}'"); 
     Console.WriteLine(); 

     // Map ViewModel -> Domain 
     personDto.Name = "Changed from DTO"; 
     personDto.Metadata = "Custom metadata from DTO"; 
     Mapper.Map(personDto, person); 

     Console.WriteLine($"PersonDTO: Name = '{personDto.Name}', Metadata = '{personDto.Metadata}'"); 
     Console.WriteLine($"Person: Id = '{person.Id}', Name = '{person.Name}'"); 

     Console.ReadLine(); 

이제 문제가 발생합니다.

알고 싶습니다. 왜 ForSourceMember이 예상대로 작동하지 않습니까? 어떻게 소스 회원을 사용하여 매핑을 방지하기 위해?

ForMember 매핑을 사용 할 수 없기 때문에 원본이 대상으로되어 있기 때문에 대상은 도메인 모델 일뿐입니다. 다른 문제는 DTO 클래스의 모든 속성이 도메인 클래스에있는 것은 아니므로 내 확장은 물론 예외입니다.

복제 된 속성을 유지 관리하는 방법은 입니다. CreateMap <>이지만 구성 코드에 모든 속성을 추가하고 싶지는 않습니다. 속성을 설정하는 것이 좋습니다.

내 논리를 AutoMapper 확장으로 유지하기 위해 내 솔루션을 수정하는 방법을 아는 사람이 있습니까?

답변

0

ForSourceMember는 유효성 검사를위한 것으로 ForMember-> Ignore와 같은 매핑 목적을 위해 실제로 무시하지 않습니다. 따라서 원하는 것을 얻기 위해 ForMember를 사용하여 역방향 맵을 구성해야합니다. ForAllPropertyMaps를 사용하여 일반적인 방법으로이 작업을 시도 할 수 있습니다.