0

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.

2
  • I've added an example, but maybe you should spend some time reading the docs. A type converter doesn't work that way. It only matches by types. Maybe you want a resolver. Commented May 9, 2018 at 11:23
  • 1
    You get more flexibility then a map with a simple object mapper or you can go even further with ForAllPropertyMaps and a resolver. Commented May 9, 2018 at 11:43

2 Answers 2

1

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;
});
Sign up to request clarification or add additional context in comments.

3 Comments

Where do I get configuration from? I only found Mapper.Configuration.GetMappers() which I cannot change.
Upgrade. Or find a similar thing in your particular version.
Went with adding a custom object mapper to the mappers collection, thanks!
1

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());
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.