1
votes

I did search in SO + google for mentioned problem, I went through all SO questions but did not get the solution of my issue.

Here is my problem: I am getting AutoMapper.AutoMapperConfigurationException while tried to map IEnumerable prop with List prop.

Here is snippet:

//Logical
public class TestClassPLogical
{
    public List<TestClassLogical> TestProp
    {
        get;
        set;
    }
}

public class TestClassLogical
{
    //defined prop
}

//Model

public class TestClassPDto
{
    public virtual IEnumerable<TestClassDto> TestProp
    {
        get;
        set;
    }
}

public class TestClassDto
{
    //defined prop
}

//Mapping

public class TestClassMapper
{
    public static void Configure()
    {
        //ToDto
        Mapper.CreateMap<TestClassPDto, TestClassPLogical>()
             .ForMember(d => d.TestProp,
             o => o.MapFrom(s => AutoMapperExtensions.MapIEnumerableToList(s.TestProp)));

        //ToLogical
        Mapper.CreateMap<TestClassPLogical, TestClassPDto>()
            .ForMember(d => d.TestProp, o => o.MapFrom(s => AutoMapperExtensions.MapListToIEnumerable(s.TestProp)));

    }
}

//Custom class

public class CustomMapperExtensions
{
    public static List<T> MapIEnumerableToList<T>(IEnumerable<T> source) where T : class
    {
        return source == null
            ? new List<T>()
            : source.ToList();
    }

    public static IEnumerable<T> MapListToIEnumerable<T>(List<T> source) where T : class
    {
        return source.Count > 0
            ? source.ToList()
            : new List<T>();
    }
}

//Unit Test

public class TestClassMapperTest
{
    [TestFixtureSetUp]
    public void Setup()
    {
        TestClassMapper.Configure();
    }

    [Test]
    public void EnsureFieldsAreAllMappedOrIgnored()
    {
        Mapper.AssertConfigurationIsValid();
    }
}

P.S.: We are using Fluent Nhibernate as ORM.

Following is the exception:

AutoMapper.AutoMapperConfigurationException : The following property on TestClassPLogical cannot be mapped: TestProp Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type TestClassLogical.

Any help to resolve above issue will be heartily appreciated.

Update I already tried with ReverseMap(), which is throwing same exception, here is snippet:

//Mapping

public class TestClassMapper
{
    public static void Configure()
    {
        //ToDto
        Mapper.CreateMap<TestClassPDto, TestClassPLogical>()
             .ForMember(d => d.TestProp,
             o => o.MapFrom(s => AutoMapperExtensions.MapIEnumerableToList(s.TestProp)));

        Mapper.CreateMap<TestClassDto, TestClassLogical>().ReverseMap();

        //ToLogical
        Mapper.CreateMap<TestClassPLogical, TestClassPDto>()
            .ForMember(d => d.TestProp, o => o.MapFrom(s => AutoMapperExtensions.MapListToIEnumerable(s.TestProp)));

        Mapper.CreateMap<TestClassLogical, TestClassDto>().Reverse();

    }
}

Exception is:

AutoMapper.AutoMapperConfigurationException : The following property on TestClassPLogical cannot be mapped:

TestProp

Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type TestClassLogical. Context: Mapping to property TestProp from TestClassDto to TestClassLogical Mapping to property TestProp from System.Collections.Generic.List1[[TestClassDto, TestMapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] to System.Collections.Generic.List1[[TestClassLogical, TestMapper, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]] Mapping from type TestClassPDto to ClassPLogical Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown. at AutoMapper.ConfigurationStore.DryRunTypeMap(ICollection1 typeMapsChecked, ResolutionContext context) at AutoMapper.ConfigurationStore.DryRunTypeMap(ICollection1 typeMapsChecked, ResolutionContext context) at AutoMapper.ConfigurationStore.DryRunTypeMap(ICollection1 typeMapsChecked, ResolutionContext context) at AutoMapper.ConfigurationStore.AssertConfigurationIsValid(IEnumerable1 typeMaps) at AutoMapper.ConfigurationStore.AssertConfigurationIsValid() at AutoMapper.Mapper.AssertConfigurationIsValid()

2

2 Answers

1
votes

You're making this much harder than necessary. Just map all class pairs you need and AutoMapper will be able to map nested source collections to nested target collections.

See this little example in Linqpad (I used some less confusing names):

void Main()
{
    Mapper.CreateMap<Parent,ParentDto>().ReverseMap();
    Mapper.CreateMap<Child,ChildDto>().ReverseMap();
    Mapper.AssertConfigurationIsValid();

    var par = new Parent { TestProp = new List<Child> 
                           { new Child(),
                             new Child() 
                           }
                         };
    Mapper.Map<ParentDto>(par).Dump();
    Mapper.Map<Parent>(Mapper.Map<ParentDto>(par)).Dump();
}

class Parent
{
    public List<Child> TestProp{ get; set; }
}
class Child {}

class ParentDto
{
    public IEnumerable<ChildDto> TestProp{ get; set; }
}
class ChildDto {}

Output of the Dump statements:

ParentDto
 - ChildDto 
 - ChildDto 

Parent
 - Child 
 - Child 
1
votes

I drill-down my code, also after knowing what does 'ReverseMap()' do exactly.

I have Mapped TestClass as:

public class TestClassMapper
        {
            public static void Configure()
            {
                //ToDto
                Mapper.CreateMap<TestClassDto, TestClassPLogical>();

                //ToLogical
                Mapper.CreateMap<TestClassLogical, TestClassDto>();
            }
        }

Now, whenever I was trying 'ReverseMap()' as suggested by @Gert Arnold, it called mapping twice, one is with ReverseMap and another is with Configure() method and this broke everything.

P.S.: I have many child classes like

TestClassPLogical 
  TestClassLogical 
  TestClass1Logical 
  TestClass2Logical
  TestClass3Logical

Here is my changed snippet:

public class TestClassPMapper
        {
            public static void Configure()
            {
                //ToDto
                Mapper.CreateMap<TestClassPDto, TestClassPLogical>();

                //ToLogical
                Mapper.CreateMap<TestClassPLogical, TestClassPDto>();

                //What I changed
                TestClassMapper.Configure();

            }
        }

Following code is working, when I removed Configure() method and make a call as follow:

Mapper.CreateMap<TestClassPDto, TestClassPLogical>().ReverseMap()
Mapper.CreateMap<TestClassDto, TestClassLogical>().ReverseMap()

P.S.

  • With above changes now, there is no need to Map prop even it is of Generic IEnumerable <=> List.
  • I need have to use .MapFrom() only for those members/props, which required some kind of customization, like I need to map Full_Name, which should be First_Name + ' ' + Last_Name.

Finally, my unit test passed :)

public class TestClassMapperTest
        {
            [TestFixtureSetUp]
            public void Setup()
            {
                TestClassMapper.Configure();
            }

            [Test]
            public void EnsureFieldsAreAllMappedOrIgnored()
            {
                Mapper.AssertConfigurationIsValid();
            }
        }