Reputation: 12978
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
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
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
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