Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

AutoMapper using the wrong constructor

Today I upgraded a fully functioning application using AutoMapper v1.1 to now use AutoMapper v2.1 and I am coming across some issues that I never encountered using the previous version.

Here is an example of my code mapping back from Dto to Domain object

public class TypeOne {    public TypeOne()    {    }     public TypeOne(TypeTwo two)    {       //throw ex if two is null    }     public TypeOne(TypeTwo two, TypeThree three)    {       //throw ex if two or three are null    }     public TypeTwo Two {get; private set;}     public TypeThree Three {get; private set;} }  public class TypeOneDto {    public TypeOneDto()    {    }     public TypeTwoDto Two {get; set;}     public TypeThreeDto Three {get; set;} } 

...

Mapper.CreateMap<TypeThreeDto, TypeThree>(); Mapper.CreateMap<TypeTwoDto, TypeTwo>(); Mapper.CreateMap<TypeOneDto, TypeOne>();  var typeOne = Mapper.Map<TypeOne>(typeOneDto); 

However the first problem I encountered with v2.1 was that AutoMapper was trying to use the constructor with 2 args when one of the args was null and should be using the 1 arg constructor.

I then tried to use

Mapper.CreateMap<TypeOneDto, TypeOne>().ConstructUsing(x => new TypeOne()); 

But I kept getting an 'Ambiguous Invocation' error that I couldn't resolve.

I then tried

Mapper.CreateMap<TypeOneDto, TypeOne>().ConvertUsing(x => new TypeOne()); 

and that did successfully create the TypeOne object using the parameterless constructor but then it failed to set the private setter properties.

I have looked for help on the AutoMapper website and downloaded the source code to have a good look but didn't get far with the little documentation about and there were not many unit tests for ConstructUsing.

Is there anything obvious I am missing that I should change with v2.1? I am surprised that it has changed so much from v1.1.

like image 584
Mark Vickery Avatar asked Jun 21 '12 21:06

Mark Vickery


People also ask

Does AutoMapper call constructor?

At the time of writing this answer, AutoMapper will do this automatically (with a simple CreateMap<>() call) for you if the properties match the constructor parameters.

Does AutoMapper map both ways?

The Automapper Reverse Mapping is nothing but the two-way mapping which is also called as bidirectional mapping.

How do I ignore source property AutoMapper?

So, the AutoMapper Ignore() method is used when you want to completely ignore the property in the mapping. The ignored property could be in either the source or the destination object.


2 Answers

You just need to add explicit cast to

Func<ResolutionContext, TypeOne> 

Here is the code:

Mapper.CreateMap<TypeOneDto, TypeOne>().ConstructUsing(             (Func<ResolutionContext, TypeOne>) (r => new TypeOne())); 

Current version of AutoMapper works as described below:

  1. Sorts destination type constructors by parameter count

    destTypeInfo.GetConstructors().OrderByDescending(ci => ci.GetParameters().Length); 
  2. Takes first constructor which parameters match source properties (without any check for null value). In your case it is constructor with two parameters.

like image 138
k0stya Avatar answered Sep 20 '22 16:09

k0stya


Here's an extension method...

    public static void CreateMapWithDefaultConstructor<T, TU>(this Profile profile)         where TU : class, new()     {         profile.CreateMap<T, TU>().ConstructUsing(source => new TU());     } 
like image 29
LawMan Avatar answered Sep 21 '22 16:09

LawMan