gog
gog

Reputation: 12978

Using Automapper with ASP.NET Core

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?

Upvotes: 2

Views: 4080

Answers (3)

John-Luke Laue
John-Luke Laue

Reputation: 3856

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.

Upvotes: 2

Shahzad Hassan
Shahzad Hassan

Reputation: 1003

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

Upvotes: 0

poke
poke

Reputation: 387527

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

Upvotes: 2

Related Questions