How can I use Automapper to map this complex type

1.5k views Asked by At

I am having to map each property since the Property Names do not match.

How I have done it manually:

        var api = new MovieApi();
        var movie = await api.GetMovieAsync(id);

        var images = await api.GetMovieImages(movie.id);
        var configuration = await api.GetConfiguration();

            //Start the main mapping
            var model = new MovieViewModel()
            {
                Title = movie.title,
                Overview = movie.overview,
                ReleaseDate = movie.release_date,
                Status = movie.status,
                Tagline = movie.tagline,
                VoteAverage = movie.vote_average,
                VoteCount = movie.vote_count,
                Revenue = movie.revenue,
                Video = movie.video,
                TmdbId = movie.id,
                Images = new List<Images>(),
                Genre = new List<Genre>()
                {
                    //Map the Genre
                    new Genre()
                    {
                        Id = movie.genres[0].id,
                        Name = movie.genres[0].name
                    }
                }
            };

            //Add images to the model if they exist.
            if (images.backdrops != null)
            {
                foreach (var image in images.backdrops)
                {
                    model.Images.Add(new Images()
                    {
                        VoteAverage = image.vote_average,
                        VoteCount = image.vote_count,
                        AspectRatio = image.aspect_ratio,
                        FilePath = image.file_path,
                        Height = image.height,
                        Iso6391 = image.iso_639_1,
                        Width = image.width,
                        FullImageUri =
                            new Uri(configuration.images.base_url + configuration.images.backdrop_sizes[3] +
                                    image.file_path)
                    });
                }
            }

Here is my attempt with AutoMapper

       public MovieViewModel MapForDetails(MovieContent movie, Backdrop images, Configuration config)
    {
        var model = new MovieViewModel();

        Mapper.CreateMap<MovieContent, MovieViewModel>()
            .ForMember(d => d.Title, o => o.MapFrom(s => s.title))
            .ForMember(d => d.Overview, o => o.MapFrom(s => s.overview))
            .ForMember(d => d.TmdbId, o => o.MapFrom(s => s.id))
            .ForMember(d => d.ReleaseDate, o => o.MapFrom(s => s.release_date))
            .ForMember(d => d.Popularity, o => o.MapFrom(s => s.popularity))
            .ForMember(d => d.VoteAverage, o => o.MapFrom(s => s.vote_average))
            .ForMember(d => d.VoteCount, o => o.MapFrom(s => s.vote_count))
            .ForMember(d => d.Status, o => o.MapFrom(s => s.status))
            .ForMember(d => d.Tagline, o => o.MapFrom(s => s.tagline))
            .ForMember(d => d.Revenue, o => o.MapFrom(s => s.revenue))
            .ForMember(d => d.Video, o => o.MapFrom(s => s.video))
            .ForMember(d => d.TmdbId, o => o.MapFrom(s => s.id))
            //.ForMember(d => d.Genre, o => o.MapFrom(s => s.genres))
            .ForMember(d => d.Images, o => o.MapFrom(s => new List<MovieImages>()));

        model = Mapper.Map<MovieContent, MovieViewModel>(movie);

        Mapper.CreateMap<Backdrop, MovieViewModel>()
            .ForMember(d => d.Images.Select(x => x.Width), o => o.MapFrom(s => s.width))
            .ForMember(d => d.Images.Select(x => x.Iso6391), o => o.MapFrom(s => s.iso_639_1))
            .ForMember(d => d.Images.Select(x => x.VoteAverage), o => o.MapFrom(s => s.vote_average))
            ;

        model.Images = (Mapper.Map<Backdrop, MovieViewModel>(images).Images);

        return model;
    }

I am getting the exception:

AutoMapper.AutoMapperConfigurationException : Custom configuration for members is only supported for top-level individual members on a type.

I am not sure how I can Map this to the MovieContent object?

1

There are 1 answers

3
Ivan Doroshenko On BEST ANSWER

Configurations:

Mapper.CreateMap<MovieContent, MovieViewModel>()
            .ForMember(d => d.Title, o => o.MapFrom(s => s.title))
            .ForMember(d => d.Overview, o => o.MapFrom(s => s.overview))
            .ForMember(d => d.TmdbId, o => o.MapFrom(s => s.id))
            .ForMember(d => d.ReleaseDate, o => o.MapFrom(s => s.release_date))
            .ForMember(d => d.Popularity, o => o.MapFrom(s => s.popularity))
            .ForMember(d => d.VoteAverage, o => o.MapFrom(s => s.vote_average))
            .ForMember(d => d.VoteCount, o => o.MapFrom(s => s.vote_count))
            .ForMember(d => d.Status, o => o.MapFrom(s => s.status))
            .ForMember(d => d.Tagline, o => o.MapFrom(s => s.tagline))
            .ForMember(d => d.Revenue, o => o.MapFrom(s => s.revenue))
            .ForMember(d => d.Video, o => o.MapFrom(s => s.video))
            .ForMember(d => d.TmdbId, o => o.MapFrom(s => s.id))
            .ForMember(d => d.Genre, o => o.Ignore())
            .ForMember(d => d.Images, o => o.Ignore());

Mapper.CreateMap<Backdrop, Images>()
            .ForMember(d => d.Width, o => o.MapFrom(s => s.width))
            .ForMember(d => d.Iso6391, o => o.MapFrom(s => s.iso_639_1))
            .ForMember(d => d.VoteAverage, o => o.MapFrom(s => s.vote_average));

Mapping code:

var model = new MovieViewModel();
model = Mapper.Map<MovieContent, MovieViewModel>(movie);

//Check if Null
if (images.backdrops != null)
{
    model.Images = Mapper.Map<IEnumerable<Backdrop>, IEnumerable<Images>>(images.backdrops);
}