5

I am new of ASP.NET BoilerPlate (ABP) and I am trying to understand how to create custom mappings using AutoMapper and, maybe, the ABP automapper attributes: AutoMap, AutoMapFrom, AutoMapTo.

With ABP I can map two classes in this way:

[AutoMapTo(typeof(DestClass)]
public class SourceClass {
    public string A { get; set; }
    public string B { get; set; }
}

public class DestClass {
    public string A { get; set; }
    public string B { get; set; }
}

But if I have two classes like the following where I want the property AB to be automapped as a join of A and B:

[AutoMapTo(typeof(DestClass)]
public class SourceClass {
    public string A { get; set; }
    public string B { get; set; }
}

public class DestClass {
    public string AB { get; set; }
}

Are there some attributes with ABP? Or do I need to use the "classical" AutoMapper code:

Mapper.CreateMap<SourceClass, DestClass>()
    .ForMember(dest => dest.AB,
        opts => opts.MapFrom(src => (src.A + ", " + src.B)));

And where do I have to place such init code?

Gianpiero
  • 3,349
  • 1
  • 29
  • 42

2 Answers2

3

I found a solution I share here.

  1. In "MyProject.Application" project I defined my automapper customs (I used profiles):
   public class MyProjectAutoMapperProfile : AutoMapper.Profile {

        protected override void Configure() {
            CreateMap<SourceClass, DestClass>()
                .ForMember(dest => dest.AB,
                           opts => opts.MapFrom(src => (src.A + ", " + src.B)));
            // other customs here...
        }
  1. Then I registered it for injection in the Initialize method of the class MyProjectApplicationModule:
    [DependsOn(typeof(MyProjectCoreModule), typeof(AbpAutoMapperModule))]
    public class MyProjectApplicationModule : AbpModule
    {
        public override void Initialize()
        {
            IocManager.RegisterAssemblyByConvention(Assembly.GetExecutingAssembly());

            // --- MY CODE for registering custom automapping
            var mapperConfiguration = new MapperConfiguration(cfg => {
                cfg.AddProfile(new MyProjectMapperProfile());  // <= here my custom mapping
            });

            var mapper = mapperConfiguration.CreateMapper();
            IocManager.IocContainer.Register(
                    Castle.MicroKernel.Registration.Component.For<IMapper>().Instance(mapper)
                );
            // --- MY CODE
        }
    }

Note that I directly used the Castle IOC register methods because I did not find any useful registering method for objects in ABP. Do you know one?

  1. Finally I used my custom mapping as injection in my Application Service and used it directly:
    public class MyAppService : MyNewHouseAppServiceBase, IMyAppService {
        // ...

        public MyAppService(IRepository<SourceClass, long> myRepository, AutoMapper.IMapper mapper) {
            _myRepo = myRepository;
            _mapper = mypper;
        }

        public async Task<DestClass> GetSource(long id) {
            var source = await _myRepo.Find(id);

            // USE THE INJECTED MAPPER
            return _mapper.Map<DestClass>(source);
        }

        public async Task<ListResultOutput<DestClass>> GetSources() {
            var sources = await _myRepo.GetAllListAsync();

            return new ListResultOutput<DestClass>(
                           // USE THE INJECTED MAPPER
                          _mapper.Map<List<DestClass>>(sources)
                       );
        }
   }
Gianpiero
  • 3,349
  • 1
  • 29
  • 42
2

No need to list all the customer mapping on the Module. Just tell the module to find all the classes which extend AutoMapper.Profile:

Assembly thisAssembly = typeof(AbpProjectNameApplicationModule).GetAssembly();
IocManager.RegisterAssemblyByConvention(thisAssembly);
cfg.AddProfiles(thisAssembly);
Exiled78
  • 21
  • 1