1

I use the latest version of Automapper in my application, together with Autofac. I set the configurations and profiles and unit tested all my profiles with AssertIsConfigurationValid() and everything is working fine. However, when I use the mapper within my application I get a "Automapper missing type map configuration or unsupported mapping" exception only when running from code, I suspect it is something to do with how I set the mapper to work with Autofac:

   // This is how I register my mapper with Autofac
    public class ModelsMapperModule : Module
    {
        protected override void Load(ContainerBuilder builder)
        {
            builder.RegisterAssemblyTypes().AssignableTo(typeof(Profile)).As<Profile>();

            builder.Register(c => new MapperConfiguration(cfg =>
            {
                foreach (var profile in c.Resolve<IEnumerable<Profile>>())
                {
                    cfg.AddProfile(profile);
                }
            })).AsSelf().SingleInstance();

            builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper(c.Resolve)).As<IMapper>().InstancePerLifetimeScope();
        }   
    }


// Here is a simple version of my objects and mappings:

public class LetterDomain
{
    public List<StationDomain> Stations {get; set;}

    public string Title {get; set;}

    public int Id {get; set;}

    public int TimeCreated {get; set;}

    public string File {get; set;}

    public bool IsSecret {get; set;}
}

public class StationDomain
{
    public int Id {get; set;}

    public string Owner {get; set;} 

    public string Name {get; set;}
}

public class LetterDto
{
    public DestinationDto Dest {get; set;}

    public int Id {get; set;}
}

public class DestinationDto
{   
    public List<StationDto> Stations {get; set;}
}

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

public class MyProfile : Profile
{   
    protected override void Configure 
    {
        CreateMap<StationDomain, StationDto>()

        CreateMap<LetterDomain, DestinationDto>();

        CreateMap<LetterDomain, LetterDto>()
            .ForMember(x => x.Dest, opt => opt.MapFrom(src => Mapper.Map<DestinationDto>(src)));
    }   
}


public void MyMethodInsideApplication(LetterDomain letter)
{
   // Exception is thrown here
   var dto = _mapper.Map<LetterDto>(letter);
}

I'm trying to map LetterDomain to LetterDto in my application and it tells me that the configuration of LetterDomain to DestinationDto is missing, although I definitely created the mapping..

Would really like for some help here..

Thanks in advance!

Edit: I just wanna add that all other mappings that doesn't use the static Mapper.Map<> inside their configuration profile work good in the application

  • In which class does the `MyMethodInsideApplication` method live? Was such class created via the container? Can you show how? – Yacoub Massad Mar 09 '16 at 20:10
  • It's a singleton, it is resolved in startapp –  Mar 09 '16 at 20:36
  • Where are you using the static `Mapper.Map<>` method? can you show that code? – Yacoub Massad Mar 09 '16 at 21:17
  • In my mapping from LetterDomain to LetterDto inside MyProfile class –  Mar 09 '16 at 21:18
  • Is it that line that throws the exception? – Yacoub Massad Mar 09 '16 at 21:20
  • I think the problem is that you configure a mapper instance (not the static Mapper), and then you use the static Mapper, which is not configured. – Yacoub Massad Mar 09 '16 at 21:24
  • If this is the case, then one way to fix the problem is to configure the static mapper instance and then configure autofac to use that instance. There might be a way without the static mapper but I am not sure how. Is there a way to access the mapper instance from the profile? I am not sure. – Yacoub Massad Mar 09 '16 at 21:26
  • Not I can't use the mapper instance there.. Do you know of a way to avoid it? I don't want to use the static mapper in my application code –  Mar 09 '16 at 21:36
  • 2
    By the way, do you really need `Mapper.Map`? Can you use `.ForMember(x => x.Dest, opt => opt.MapFrom(src => src))` in your case instead of `.ForMember(x => x.Dest, opt => opt.MapFrom(src => Mapper.Map(src)));`? – Yacoub Massad Mar 09 '16 at 21:50
  • I think the MapFrom is to provide a value with the same type and just use it. It won't prefrom a complex mapping as I expected Mapper.Map<> to do –  Mar 09 '16 at 22:03
  • Did you test it? I think that `MapFrom` would actually do mapping. – Yacoub Massad Mar 09 '16 at 22:08
  • It worked! Thank you! –  Mar 10 '16 at 06:52

3 Answers3

0

One problem is that you didn't specify how DestinationDto.Name should be populated when mapping from LetterDomain to DestinationDto.

In other words, LetterDomain has no Name property, so no automatic mapping is possible for that property.

devuxer
  • 41,681
  • 47
  • 180
  • 292
  • My bad, posted wrong..fixed now. I'm sure all the mapings are fine.. I tried it in unit tests and it's good.. It gotta be something to do with my application code - specifically the usage of the static mapper after register insance mapper –  Mar 09 '16 at 21:55
  • I thought it might have just been your posting since you did say the validation succeeded. Maybe this answer would help: http://stackoverflow.com/questions/35565524/cannot-resolve-automapper-imapper-using-automapper-4-2-with-autofac/35566443#35566443 – devuxer Mar 09 '16 at 21:57
  • Although the registration with Autofac seems okay, because I do use the mapper successfully in other parts of the application where the Configuration map doesn't use the static Mapper.Map<> method. Regardless, is there a reason to register both IMapper and IMappingEngine? –  Mar 09 '16 at 22:01
  • I would definitely try leaving out `IMappingEngine`. Unless you have a class that depends on it, I don't think it's needed. (I think I just included it because the OP of that question had it in his code.) – devuxer Mar 09 '16 at 22:32
0

I guess you can't use both static and not static version of the mapper at the same time (unless you create both static and not static map, but is useless); by the way, you don't need to use

CreateMap<LetterDomain, LetterDto>()
        .ForMember(x => x.Dest, opt => opt.MapFrom(src => Mapper.Map<DestinationDto>(src)));

to apply the map, just

CreateMap<LetterDomain, LetterDto>()
        .ForMember(x => x.Dest, opt => opt.MapFrom(src));

The map will be applied automatically, if exists.

You can also simplify the mapping process a bit, if you want:

    protected override void Load(ContainerBuilder builder)
    {
        var profiles =
            from t in typeof (MapperModuleRegistration).Assembly.GetTypes()
            where typeof (Profile).IsAssignableFrom(t)
            select (Profile) Activator.CreateInstance(t);

        var config = new MapperConfiguration(cfg =>
        {
            foreach (var profile in profiles)
            {
                cfg.AddProfile(profile);
            }
        });

        builder.RegisterInstance(config).As<MapperConfiguration>();
        builder.Register(c => c.Resolve<MapperConfiguration>().CreateMapper()).As<IMapper>();
    }

Hope it helps :)

Luca Ghersi
  • 3,261
  • 18
  • 32
0

In my case I had my mapping profiles in a separate dll that was not referenced by any of my other projects. By adding a reference to my mapping profiles .dll it fixed my problem.

Stephen Garside
  • 1,185
  • 10
  • 15