2

I am trying to use AutoMapper to map between two types where the destination type needs to be created from a constructor rather than a property mapping.

The complication is that whilst one of the construction parameters is a value I want to map from the source, the second is a service that I want Automapper to resolve using the configured DI container.

I have tried using the recommended .ForCtorParam method but if I only specify the first parameter I get a runtime error of:

"Destination needs to have a constructor with 0 args or only optional args

I thought I might need to specify both parameters but I can't see how I could instruct the mapper to resolve the service.

Below details an example of the type of class structures I am using and how the mapper has been configured.

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

public class Destination
{
    private IService _someService;

    public Destination(string value, IService someService)
    {
        Value = value;
        _someService = someService;
    }
    
    public string Value {get;}
}

public static class MapperFactory
{
   public static IMapper CreateMapper(IUnitContainer container)
   {
      var config = new MapperConfiguration(cfg => 
      {
          cfg.ConstructServicesUsing(type => container.Resolve(type));
     
          cfg.CreateMap<Source,Destination>().ForCtorParam("value", opt => opt.MapFrom(s => s.Value));
      });

      return config.CreateMapper();
    }
}
gouldos
  • 1,015
  • 1
  • 16
  • 30

1 Answers1

0

Do you have to use a constructor? Every case where I've used automapper, it's been to a class without a constructor, and if particular properties need particular values, then I've gone with this approach (using your example):

cfg.CreateMap<Source,Destination>()
    .ForMember(dest => dest.Value, opt => opt.MapFrom(src => src.Value);

and if you have specific hard coded values that need to be passed in through constructors then you just use opt => opt.UseValue("hard-coded")

have you got a specific example of a class that you deem needs to be made via a constructor?

Dan Scott
  • 554
  • 3
  • 10
  • I'm afraid it does, Automapper does look like it has support specifically for using constructors, and for resolving container supplied services, but I can't figure out if it can do both. – gouldos Nov 16 '20 at 13:46
  • @gouldos what about specifying the parameter using the container? `.ForCtorParam("someService", opt => opt.MapFrom(s => container.Resolve(typeof(ISomeService))));` – Dan Scott Nov 17 '20 at 14:05
  • Yea, thats the approach I was taking, was trying to keep the code a bit more separated without having to inject the container and thought that it looked like structure map had support already for resolving the parameters themselves. – gouldos Dec 07 '20 at 21:16