Automapper unmapped properties error with simple objects mappings

.net-core automapper c# entity-framework-core mapping

Question

I need to map a model object coming from API to my actual entity object on DbContext. It is used when creating a new machine object using a POST action.

As always, I created a simple map for the source/destination objects. In this case we consider the source object as the API model and the destination object as the entity. Also the model has just a subset of properties of the entity.

Source/destination types

// Destination (entity on DbContext)
public class Machine
{
    public long Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public string MnmConfiguration { get; set; }
    public MachineBootStatus Status { get; set; }
    public long MachineDriverId { get; set; }
    public MachineDriver MachineDriver { get; set; }
    public string DriverConfiguration { get; set; }
    public string DriverStatus { get; set; }
}

// Source (from API controller)
public class MachineCreateModel
{
    public string Name { get; set; }
    public string Description { get; set; }
    public string MnmConfiguration { get; set; }
    public long MachineDriverId { get; set; }
}

Mapping configuration

public class DomainProfile : Profile
{
    public DomainProfile()
    {
        //CreateMap<MachineCreateModel, Machine>();
        // Update 2019/01/30 with proposed solution
        CreateMap<MachineCreateModel, Machine>(MemberList.Source);
    }
}

I'm using Unity DI container and the configuration of AutoMapper is this:

container = new UnityContainer();
// ... some other configurations...
container.RegisterType<IMapper, Mapper>(new InjectionConstructor(new MapperConfiguration(cfg => cfg.AddProfile<DomainProfile>())));

Version

Using AutoMapper v8.0.0.

Expected behavior

I expect to obtain a simple automatic mapping without errors, since my source model is just a subset of properties of the destination model, with same names.

Actual behavior

I get this error about unmapped properties when I hit this line of code:

Machine entity = Mapper.Map<Machine>(request.Machine);
[14:08:34.363 8 2e62361a INF] Creating new machine: TEST M1
[14:08:36.205 8 bd577466 ERR] An unhandled exception has occurred while executing the request.
AutoMapper.AutoMapperConfigurationException:
Unmapped members were found. Review the types and members below.
Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type
For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters
=================================================================================================
AutoMapper created this type map for you, but your types cannot be mapped using the current configuration.
MachineCreateModel -> Machine (Destination member list)
MyApplication.Dcs.Application.Models.MachineCreateModel -> MyApplication.Dcs.Domain.Entities.Machine (Destination member list)

Unmapped properties:
Id
Status
MachineDriver
DriverConfiguration
DriverStatus

   at AutoMapper.ConfigurationValidator.AssertConfigurationIsValid(IEnumerable`1 typeMaps)
   at lambda_method(Closure , MachineCreateModel , Machine , ResolutionContext )
   at lambda_method(Closure , Object , Object , ResolutionContext )
   at AutoMapper.Mapper.AutoMapper.IMapper.Map[TDestination](Object source)
   at MyApplication.Dcs.Application.Commands.MachineCreateCommandHandler.Handle(MachineCreateCommand request, CancellationToken cancellationToken) ..Commands\MachineCreateCommand.cs:line 28

Note

In my solution I've many projects and 3 of them are making use of AutoMapper (same version for all). There're 3 different DomainProfile.cs files (1 for each project) with the needed mappings. In the other 2 DomainProfile classes I've some manual mappings (see example below) because I need to "translate" an object with italian property names to another one with english property names. So there're many lines for each object mapping, such as:

CreateMap<ArticleCreateUpdateModel, Articoli>()
    .ForMember(d => d.Categoria, opt => opt.MapFrom(src => src.Category))
    .ForMember(d => d.CodiceArticolo, opt => opt.MapFrom(src => src.Code))
    .ForMember(d => d.Descrizione, opt => opt.MapFrom(src => src.Description))
    .ForMember(d => d.Famiglia, opt => opt.MapFrom(src => src.Family))
    .ForMember(d => d.Note, opt => opt.MapFrom(src => src.Note))
    ...

I don't know if the usage of those manual members mapping on one or more DomainProfile class, obliges me in some way to always explain all the subsequent mappings, even if they should be simple like those of this example.

1
1
1/30/2019 12:43:52 PM

Accepted Answer

By default, AutoMapper validates the destination properties. As there are neither matching properties nor ForMember constructs for a bunch of properties in your destination type you get the exception above.

Try to validate on the source properties instead:

CreateMap<ArticleCreateUpdateModel, Articoli>(MemberList.Source)
    .ForMember(d => d.Categoria, opt => opt.MapFrom(src => src.Category))
    // ...

Remark: On the other hand, I have to mention that this is the typical case when AutoMapper is an overkill. Apart from trivial cases I would never use it anymore.

I had to use it in a project for more than a year but actually it is only good for making simple things more complicated than necessary. Some FromDto and ToDto [extension] methods are just simpler, faster, easier to debug and more reactive to code changes. Mapping between different class layouts or property names often results practically as much code (or even more with tons of lambdas) as simply writing the mapping manually. See also this link.

1
1/30/2019 8:35:11 AM


Related Questions





Related

Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow
Licensed under: CC-BY-SA with attribution
Not affiliated with Stack Overflow