Search code examples
c#asp.net-coreautomapperasp.net-core-2.1

AutoMapperMappingException when using ConstructUsingServiceLocator() in ASP.NET Core 2.1


I'm using AutoMapper 7.0.1 and AutoMapper.Extensions.Microsoft.DependencyInjection 5.0.1 in my ASP.NET Core 2.1 web application. When I map to a type that isn't configured with ConstructUsingServiceLocator(), the mapping works. When I map to a type that is configured with ConstructUsingServiceLocator(), it throws the following:

AutoMapperMappingException: Cannot create an instance of type 
AutoMapperTest.Destination
AutoMapper.MappingOperationOptions<TSource, TDestination>.CreateInstance<T>() in MappingOperationOptions.cs, line 47

I'm following the latest guidance for using AutoMapper with ASP.NET Core given here: How to pass a service from .net core di container to a new object created with automapper

I've reproduced this with a minimal example in a brand new project. Here's the relevant parts:

New project > APS.NET Core Web Application > Web Application

Install AutoMapper 7.0.1 and AutoMapper.Extensions.Microsoft.DependencyInjection 5.0.1 Nuget packages.

Source:

public class Source
{
    public string Name { get; set; }
}

Destination:

public class Destination
{
    private readonly IDestinationRepository _repo;

    public Destination(IDestinationRepository repo)
    {
        _repo = repo ?? throw new ArgumentNullException(nameof(repo));
    }

    public string Name { get; set; }
}

IDestinationRepository:

public interface IDestinationRepository
{
}

DestinationRepository:

public class DestinationRepository : IDestinationRepository
{
}

MappingProfile:

public class MappingProfile : Profile
{
    public MappingProfile()
    {           
        CreateMap<Source, Destination>().ConstructUsingServiceLocator();
    }
}

Startup.ConfigureServices(IServiceCollection services):

public void ConfigureServices(IServiceCollection services)
{
    services.AddScoped<IDestinationRepository, DestinationRepository>();

    services.Configure<CookiePolicyOptions>(options =>
    {
        // This lambda determines whether user consent for non-essential cookies is needed for a given request.
        options.CheckConsentNeeded = context => true;
        options.MinimumSameSitePolicy = SameSiteMode.None;
    });

    services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);

    services.AddAutoMapper();
}

IndexModel:

public class IndexModel : PageModel
{
    private readonly IMapper _mapper;

    public IndexModel(IMapper mapper)
    {
        _mapper = mapper;
    }

    public void OnGet()
    {
        _mapper.ConfigurationProvider.AssertConfigurationIsValid();            // <- Succeeds
        var repo = _mapper.ServiceCtor.Invoke(typeof(IDestinationRepository)); // <- repo is non-null

        var source = new Source {Name = "Test"};
        var destination = _mapper.Map<Source, Destination>(source);            // <- Fails!!
    }
}

The above fails on the _mapper.Map<Source, Destination>(source) call with the exception listed above. I've verified MappingProfile is getting loaded.

If I change the Destination ctor to be parameterless, it still fails.

However, if I remove ConstructUsingServiceLocator() from MappingProfile (with the empty Destination ctor), my mapping starts to work.

What am I doing wrong here? Thanks for any help!


Solution

  • Your Destination class is not registered in di container and so it's not possible to let di container create a new instance of class Destination.