2
votes

I´m trying to use Automapper with Dependency Injection configuration on a n-layer application.

 public class ApplicationMapping : Profile
{
    public ApplicationMapping()
    {
        RegisterMappings();
        Mapper.AssertConfigurationIsValid();
    }  

    private void RegisterMappings()
    {
      CreateMap<IEnumerable<App>, ListAppsDto>()
            .ForMember(dest => dest.Apps,
                       opt => opt.MapFrom(src =>
                            Mapper.Map<IEnumerable<App>, List<App>>(src.ToList())
                           )
                      );
    }
}

This class is inside my Application dll, where I put my services and DTOs. Also in this dll, I have an extension method to register the mapping:

 public static class MappingServiceExtension
{
    public static void AddApplicationMappings(this IServiceCollection services)
    {
        var mapperConfig = new MapperConfiguration(config =>
        {
            config.AddProfile<ApplicationMapping>();
        });

        IMapper mapper = mapperConfig.CreateMapper();
        services.AddSingleton(mapper);
    }
}

Then in my WebAPI project, on the Startup.cs class I put:

  services.AddApplicationMappings();

And I use it normally with DI in my services:

  public class AppService : IAppService
 {
    private readonly IAppRepository _appRepository;
    private readonly IMapper _mapper;

    public TruckService(IAppRepository appRepository, IMapper mapper)
    {
        _appRepository = appRepository;
        _mapper = mapper;
    }
 }

I would like to use like this. But I'm getting an exception when the Mapper.AssertConfigurationIsValid(); line runs, saying that:

'Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.'

What am I missing here? The problem seems to be in the Mapper.Map<IEnumerable<App>, List<App>>(src.ToList()) line of code.

But how can I get an instance of the Mapper there without using the static Mapper?

3
You need Custom type converter for IEnumerable<App>, List<App> and take mapper from ResolutionContext. - Yurii N.
It not resolved the problem because I still need to use the context.Mapper.Map<...> on the CustomTypeConverter class. Still getting the same error. - gog

3 Answers

2
votes
Mapper.AssertConfigurationIsValid();

This calls the static IMapper instance which is used in situations where you don’t use dependency injection. Since you never set up the static mapper, using it there will fail.

What you want to do instead is call AssertConfigurationIsValid on the actual mapper instance, the one that you are registering as a singleton. So you should remove the assert from the mapper profile and instead call it within your AddApplicationMappings method:

IMapper mapper = mapperConfig.CreateMapper();
mapper.AssertConfigurationIsValid();
services.AddSingleton(mapper);
2
votes

Try using AddAutoMapper from AutoMapper.Extensions.Microsoft.DependencyInjection which you can add as a NuGet package.

So, you'd completely remove the MappingServiceExtension class, and then in Startup.cs add these two lines:

AutoMapper.Mapper.Reset();
services.AddAutoMapper(typeof(ApplicationMapping).Assembly);

I forgot the exact reason, but when using AutoMapper in across multiple projects/assemblies, you need to register it for DI this way. Read more here.

0
votes

Similar to what @johnluke.laue suggested. In AddApplicationMappings simply replace the code with the following:

services.AddAutoMapper(config =>
{
    config.AddProfile<ApplicationMapping>();
});

The above will automatically add the IMapper to the DI. In addition, modify the RegisterMappings function as below. You don't need to explicitly map the IEnumerable<T>. It will be mapped implicitly if the source/destination mappings exist.

private void RegisterMappings()
{
   CreateMap<IEnumerable<App>, ListAppsDto>()
       .ForMember(dest => dest.Apps, opt => opt.MapFrom(src => src.ToList());
}

It would be helpful to see the actual App and ListAppDto classes, as you don't explicitly need the above mappings. I hope this helps