SuperJMN
SuperJMN

Reputation: 13992

AutoMapper ConstructServicesUsing is ignored

I have a Person and a PersonViewModel. I created a map from Person => PersonViewModel. The problem is that PersonViewModel's only constructor needs an argument (it has a dependency that I want to be injected) and AutoMapper is complaining because it says it needs a parameterless constructor.

To fix it, I used the ConstructServicesUsing method, but I haven't been successful with it :(

To illustrate the case, I created a test for you to see what I'm doing. It's pretty simple:

    [TestMethod]
    public void TestConstructServicesUsing()
    {
        Mapper.Initialize(configuration =>
        {
            configuration.ConstructServicesUsing(FactoryMethod);
            configuration.CreateMap<Person, PersonViewModel>();
        });

        Mapper.AssertConfigurationIsValid();

        var person = new Person();
        var personViewModel = Mapper.Map<Person, PersonViewModel>(person);
    }

    private object FactoryMethod(Type type)
    {
        throw new NotImplementedException();
    }
}

The rest of the code is the classes and interface definitions. They are almost empty.

public class SomeyDependency : ISomeDependency
{
}

public class PersonViewModel
{
    private readonly ISomeDependency service;

    public PersonViewModel(ISomeDependency service)
    {
        this.service = service;
    }

    public string Name { get; set; }
}

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

public interface ISomeDependency
{
}

As you see, I provide AutoMapper with a FactoryMethod, but it never get called.

When it reaches the last line of the test (Mapper.Map<...>()) it throws an excepton saying:

AutoMapper.AutoMapperMappingException: 

Mapping types:
Person -> PersonViewModel
MappingWithContainerTests.Person -> MappingWithContainerTests.PersonViewModel

Destination path:
PersonViewModel

Source value:
MappingWithContainerTests.Person ---> System.ArgumentException: Type needs to have a constructor with 0 args or only optional args
Parameter name: type

What's the problem? Why isn't the FactoryMethod being called?

Upvotes: 7

Views: 2440

Answers (2)

Lee Song
Lee Song

Reputation: 621

I'm using .NET Core 3.1 and Automapper.Extensions.Microsoft.DependencyInjection.

This does not work for me (Same error as yours):

public class AutoMapping : Profile
{
    public AutoMapping()
    {
         CreateMap<Context, MainViewModel>()
             .ReverseMap()
             .ConstructUsingServiceLocator();
    }
}

But this does work:

public class AutoMapping : Profile
{
    public AutoMapping()
    {
         CreateMap<Context, MainViewModel>()
             .ConstructUsingServiceLocator()
             .ReverseMap();
    }
}

I still do not fully understand the cause.

Upvotes: 0

VladOhotnikov
VladOhotnikov

Reputation: 1188

As @khorvat mention where is missing .ConstructUsingServiceLocator(), for concrete mapping.

Also you can set constructor directly by

.ConstructUsing(source => Method(source.anySourceOptions))

Or as exception said:

PersonViewModel, must have a constructor with 0 args or only optional args. You have only one constructor with 1 not optional argument

you may create one more constructor without args:

public PersonViewModel()
{
    this.service = new SomeDependency();
}

Upvotes: 1

Related Questions