I'm getting an error that AutoMapper v11.0.1
cannot create an instance of a custom IMemberValueResolver
type.
This is my custom resolver:
public class FooCollectionResolver<TModel, TViewModel> : IMemberValueResolver<object, object, BlockListModel?, IEnumerable<TViewModel>?>
where TModel : class, IPublishedElement
where TViewModel : class
{
public IEnumerable<TViewModel>? Resolve(object source, object destination, BlockListModel? sourceMember, IEnumerable<TViewModel>? destMember, ResolutionContext context)
{ }
}
It takes a source BlockListModel
member and returns a collection of TViewModel
.
Example usage:
this.CreateMap<FooModel, FooViewModel>().ForMember(
dest => dest.BlockListModelMember,
src => src.MapFrom<FooCollectionResolver<FooCollectionModel, FooCollectionViewModel>, BlockListModel>(s => s.BlockListModelMember));
FooModel.cs:
public class FooModel
{
public string Title { get; set; }
public BlockListModel BlockListModelMember { get; set; }
}
FooViewModel.cs
public class FooViewModel
{
public string Title { get; set; }
public IEnumerable<FooCollectionViewModel> BlockListModelMember { get; set; }
}
FooCollectionModel.cs
public class FooCollectionModel
{
public string FooMember { get; set; }
}
FooCollectionViewModel.cs
public class FooCollectionViewModel
{
public string FooMember { get; set; }
}
This is how the DI is registered:
services.AddAutoMapper(cfg =>
{
cfg.AddMaps(new[]
{
"FooNamespace.Web",
"FooNamespace.Web.Framework",
});
});
This particular mapping profile is contained within FooNamespace.Web
. There are no issues with any other maps in this profile.
AutoMapper
throws an error that it cannot create an instance of FooCollectionResolver
at runtime. I believe it attempts to create an instance via reflection when using the generic .MapFrom<T>
method.
Exception:
AutoMapperMappingException: Cannot create an instance of type GPE.Web.Framework.Mapping.ValueResolvers.FooCollectionResolver`2[FooCollectionModel,FooCollectionViewModel]
AutoMapper.ResolutionContext.CreateInstance(Type type)
AutoMapperMappingException: Error mapping types.
Mapping types: FooModel -> FooViewModel
Type Map configuration: FooModel -> FooViewModel
Destination Member: BlockListModelMember
Does anyone know why this is?
I can get this working with an inline resolution function e.g:
this.CreateMap<FooModel, FooViewModel>()
.ForMember(
dest => dest.BlockListModelMember,
src => src.MapFrom((src, dest, destMember, context) =>
{
// mapping logic
}));
But I want to reuse this logic as its the same general pattern applied to various different models, hence the generic IMemberValueResolver
CodePudding user response:
When you use that specific overload of services.AddAutoMapper
it is not adding your value resolver to the container. You can use this instead which will scan the assemblies looking for all relevant types:
services.AddAutoMapper(
typeof(FooCollectionResolver<,>).Assembly,
typeof(SomeOtherType).Assembly /*, more if required */);
If you look at the implementation of AddAutoMapperClasses, which is what the AddAutoMapper
extension method ultimately calls, you will see that it only registers IMemberValueResolver
types (amoung others) if it's passed a collection of assembliesToScan
.
The overload that you're using passes null
for this parameter so they won't be registered.