Reputation: 7463
Using AutoMapper (v6.2.2, plus AutoMapper.Extensions.Microsoft.DependencyInjection) I want to use my existing system TypeConverter
classes to convert from certain data models to strings.
Although the internal MapperRegistry
contains a TypeConverterMapper
that should be able to do this automatically (without the need for any manual configuration it says here), it never gets called as the StringMapper
takes precedence when the destination type is a string
.
Other (older) answers suggest changing the mapping objects in the MapperRegistry
, but it appears that this class has since been made internal
.
Can I change the precedence of (or remove) the different in-built mapper classes in AutoMapper?
As a workaround, I also tried creating a map in my Profile
that would attempt to convert any object to a string using type converters:
private class ApiTypeConverter : ITypeConverter<object, string>
{
public string Convert(object source, string destination, ResolutionContext context)
{
TypeConverter sourceTypeConverter = TypeDescriptor.GetConverter(source.GetType());
if (sourceTypeConverter.CanConvertTo(typeof(string)))
{
return (string)sourceTypeConverter.ConvertTo(source, typeof(string));
}
return default(string);
}
}
which I configured to be used with:
CreateMap<object, string>().ConvertUsing<ApiTypeConverter>();
But this has not worked as expected yet either. Ideally I'd only do this for members which could be converted using a condition, something like:
ForAllMaps((m, e) => e.ForAllMembers(opt => opt.Condition(HasConverter))
.ConvertUsing<ApiTypeConverter>());
However, this is not possible (the ForAllMembers
method returns void
).
As I am using AutoMapper.Extensions.Microsoft.DependencyInjection I was able to use the additionalInitAction
parameter to change the mappers:
services.AddAutoMapper(InitAction, GetType().Assembly);
private void InitAction(IMapperConfigurationExpression configuration)
{
var mapper = configuration.Mappers.OfType<StringMapper>().First();
configuration.Mappers.Remove(mapper);
}
This led everything to work as expected, but seems a bit of a hack, as other maps may be relying on the StringMapper
.
Upvotes: 0
Views: 1082
Reputation: 7463
If using dependency injection, the configuration can be changed when adding the AutoMapper to the services:
services.AddAutoMapper(InitializeMapper, typeof(Startup).Assembly);
Then add an appropriate initialization:
private static void InitializeMapper(IMapperConfigurationExpression cfg)
{
StringMapper stringMapper = cfg.Mappers.OfType<StringMapper>().First();
int index = cfg.Mappers.IndexOf(stringMapper);
cfg.Mappers.Insert(index, new CustomObjectMapper());
}
Upvotes: 1
Reputation: 3516
You can use configuration.Mappers
to change the built-in mappers' list, but a map from object to string should also work.
Mapper.Initialize(cfg =>
{
var mappers = cfg.Mappers;
});
Upvotes: 1