Automapper 6.0. Missing map type configuration or unsupported mapping
I've already seen this question , this one and this one .
And I have this exception when I go from Automapper 3.3.1.0
to Automapper 6.0.1.0
. This code does not throw an exception in Automapper 3.3.1.0
.
I have class 2:
Class 1: (Domain)
public class Movie:IEntityBase
{
public Movie()
{
Stocks = new List<Stock>();
}
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public int GenreId { get; set; }
public virtual Genre Genre { get; set; }
public string Director { get; set; }
public string Writer { get; set; }
public string Producer { get; set; }
public DateTime ReleaseDate { get; set; }
public byte Rating { get; set; }
public string TrailerURI { get; set; }
public virtual ICollection<Stock> Stocks { get; set; }
}
Class 2:
public class MovieViewModel : IValidatableObject
{
public int ID { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public string Image { get; set; }
public string Genre { get; set; }
public int GenreId { get; set; }
public string Director { get; set; }
public string Writer { get; set; }
public string Producer { get; set; }
public DateTime ReleaseDate { get; set; }
public byte Rating { get; set; }
public string TrailerURI { get; set; }
public bool IsAvailable { get; set; }
public int NumberOfStocks { get; set; }
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
var validator = new MovieViewModelValidator();
var result = validator.Validate(this);
return result.Errors.Select(item => new ValidationResult(item.ErrorMessage, new[] { item.PropertyName }));
}
}
I tried to display in the constructor the reasons for the class Automapper 6.0.1.0
does not have a method Configure()
to override:
public class DomainToViewModelMappingProfile : Profile
{
public override string ProfileName
{
get { return "DomainToViewModelMappings"; }
}
public DomainToViewModelMappingProfile()
{
Mapper.Initialize(cfg => {
cfg.CreateMap<Genre, GenreViewModel>()
.ForMember(vm => vm.NumberOfMovies, map => map.MapFrom(g => g.Movies.Count()));
cfg.CreateMap<Movie, MovieViewModel>()
.ForMember(vm => vm.Genre, map => map.MapFrom(m => m.Genre.Name))
.ForMember(vm => vm.GenreId, map => map.MapFrom(m => m.Genre.ID))
.ForMember(vm => vm.IsAvailable, map => map.MapFrom(m => m.Stocks.Any(s => s.IsAvailable)))
.ForMember(vm => vm.NumberOfStocks, map => map.MapFrom(m => m.Stocks.Count))
.ForMember(vm => vm.Image, map => map.MapFrom(m => string.IsNullOrEmpty(m.Image) == true ? "unknown.jpg" : m.Image));
});
Mapper.AssertConfigurationIsValid();
}
}
And I have the following exception:
Missing map type configuration or unsupported mapping.
Display types: Movie β MovieViewModel HomeCinema.Entities.Movie β HomeCinema.Web.Models.MovieViewModel
I tried to find out which property is causing this exception using the method Ignore()
, however I am still getting the above exception.
cfg.CreateMap<Genre, GenreViewModel>()
.ForMember(vm => vm.NumberOfMovies, map => map.MapFrom(g => g.Movies.Count()));
cfg.CreateMap<Movie, MovieViewModel>()
.ForMember(vm => vm.Genre, map => map.Ignore())
.ForMember(vm => vm.GenreId, map => map.Ignore())
.ForMember(vm => vm.IsAvailable, map => map.Ignore())
.ForMember(vm => vm.NumberOfStocks, map => map.Ignore())
.ForMember(vm => vm.Image, map => map.Ignore());
Forgot to say that I am calling the following method in Global.asax.cs
:
AutoMapperConfiguration.Configure();
Could you tell me what I am doing wrong? Any help would be greatly appreciated.
The most interesting thing is that this code is valid in Automapper 3.3.1.0
.
Update:
It works! :) Thanks to all of you guys and special thanks to @AndriiLitvinov. Working code:
public class DomainToViewModelMappingProfile : Profile
{
public override string ProfileName
{
get { return "DomainToViewModelMappings"; }
}
public DomainToViewModelMappingProfile()
{
CreateMap<Genre, GenreViewModel>()
.ForMember(vm => vm.NumberOfMovies, map => map.MapFrom(g => g.Movies.Count()));
CreateMap<Movie, MovieViewModel>()
.ForMember(vm => vm.Genre, map => map.MapFrom(m => m.Genre.Name))
.ForMember(vm => vm.GenreId, map => map.MapFrom(m => m.Genre.ID))
.ForMember(vm => vm.IsAvailable, map => map.MapFrom(m => m.Stocks.Any(s => s.IsAvailable)))
.ForMember(vm => vm.NumberOfStocks, map => map.MapFrom(m => m.Stocks.Count))
.ForMember(vm => vm.Image, map => map.MapFrom(m => string.IsNullOrEmpty(m.Image) == true ? "unknown.jpg" : m.Image));
}
}
and call Initialize()
only once:
//Global.asax.cs
protected void Application_Start()
{
var config = GlobalConfiguration.Configuration;
AreaRegistration.RegisterAllAreas();
WebApiConfig.Register(config);
Bootstrapper.Run();
RouteConfig.RegisterRoutes(RouteTable.Routes);
GlobalConfiguration.Configuration.EnsureInitialized();
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
public class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<DomainToViewModelMappingProfile>();
});
}
}
public class Bootstrapper
{
public static void `Run()
{
//Configure Autofac
AutofacWebapiConfig.Initialize(GlobalConfiguration.Configuration);
//Configure Automapper
AutoMapperConfiguration.Configure();
}
}
source to share
I tried to implement such a mapping locally and it all worked. I assume you have a lot of profiles that everyone calls Mapper.Initialize
, as far as I remember, it is meant to be called only once at application startup, and all profiles should call the CreateMap Method :
public class MappingProfile : Profile
{
public MappingProfile()
{
CreateMap<Foo, Bar>();
}
}
source to share
When you call a method Mapper.AssertConfigurationIsValid();
, you must ensure that each property has a valid source and target for the mapping. If you don't have a valid source and target for each property, you will receive an error message. If you look at the error message it will tell you in detail. I just looked at your code, but for example public virtual ICollection<Stock> Stocks { get; set; }
has no mapping.
source to share