23

I have a services that is calling another services. Both of the services are using "the same classes". The classes are named same and have the same properties but has different namespace so I need to use AutoMapper to map from one of the type to the other type.

No it's pretty simple since all I have to do is the CreateMap<>, but the problem is that we have around hundreds of classes that I manually needs to write the CreateMap<> from, and it's works wired to me. Isn't there any Auto CreateMap function. So if I say CreateMap() then AutoMapper workes thru Organisation and finds all classes and automatically does the CreateMap for these Classes and it's subclasses etc etc…

Hope for a simple solution, or I guess some reflection can fix it...

Vadim Ovchinnikov
  • 13,327
  • 5
  • 62
  • 90
Magnus Gladh
  • 1,817
  • 4
  • 20
  • 31
  • 2
    CreateMissingTypeMaps is obsolete: 'Support for automatically created maps will be removed in version 9.0. You will need to explicitly configure maps, manually or using reflection. Also consider attribute mapping (http://docs.automapper.org/en/latest/Attribute-mapping.html). – Dejan Jun 18 '19 at 07:10

6 Answers6

32

Just set CreateMissingTypeMaps to true in the options:

var dto = Mapper.Map<FooDTO>
     (foo, opts => opts.CreateMissingTypeMaps = true);

If you need to use it often, store the lambda in a delegate field:

static readonly Action<IMappingOperationOptions> _mapperOptions =
    opts => opts.CreateMissingTypeMaps = true;

...

var dto = Mapper.Map<FooDTO>(foo, _mapperOptions);

UPDATE:

The approach described above no longer works in recent versions of AutoMapper.

Instead, you should create a mapper configuration with CreateMissingTypeMaps set to true and create a mapper instance from this configuration:

var config = new MapperConfiguration(cfg =>
{
    cfg.CreateMissingTypeMaps = true;
    // other configurations
});
var mapper = config.CreateMapper();

If you want to keep using the old static API (no longer recommended), you can also do this:

Mapper.Initialize(cfg =>
{
    cfg.CreateMissingTypeMaps = true;
    // other configurations
});

UPDATE 2 - Automapper 9 and later:

Starting from Automapper version 9.0, the CreateMissingTypeMaps API was removed. Automapper documentation now suggests to explicitly configure maps, manually or using reflection.

https://docs.automapper.org/en/stable/9.0-Upgrade-Guide.html#automapper-no-longer-creates-maps-automatically-createmissingtypemaps-and-conventions

peterszabo
  • 137
  • 1
  • 7
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • 1
    Is there a global setting for this? – Chad Kapatch Dec 22 '15 at 17:40
  • @ChadKapatch, not that I know of – Thomas Levesque Dec 23 '15 at 07:50
  • @ThomasLevesque : not works for me, gives error like these, does not contain a definition for 'CreateMissingTypeMaps' and no extension method accepting a first argument of type could be found. any idea? – Bharat Oct 10 '16 at 10:16
  • Thanks, @ThomasLevesque, but seems CreateMapper() is not used instead of DynamicMap<>(), What exactly i have UserProfileVM model = AutoMapper.Mapper.DynamicMap(objUser); and i want to remove above error from these...is CreateMapper() helpful for these situation? – Bharat Oct 11 '16 at 06:08
  • @Bharat, sorry, I don't understand what your problem is. You should probably post a full question with more details. – Thomas Levesque Oct 11 '16 at 07:58
  • @ThomasLevesque ; http://stackoverflow.com/questions/39976989/automapper-createmissingtypemaps-property-warning here i added my question. – Bharat Oct 11 '16 at 12:13
  • Is CreateMissingTypeMaps safe to use in terms of performance? – Ali Karaca Apr 14 '19 at 14:04
  • Will the both models have to have the same name for automapper to create missing types – Mohammed Sohail Ebrahim Nov 20 '19 at 13:13
  • Note: this API was removed in version 9, the suggested approach is to write manual mappers or use reflection: https://docs.automapper.org/en/stable/9.0-Upgrade-Guide.html#the-static-api-was-removed – peterszabo Mar 04 '21 at 02:31
7

CreateMissingTypeMaps can be set within your profile. It's however recommended to explicitly use CreateMap for each mapping and call AssertConfigurationIsValid in your unit tests for each profile to prevent silent errors.

public class MyProfile : Profile {
    CreateMissingTypeMaps = true;

    // Mappings...
}
Greg R Taylor
  • 3,470
  • 1
  • 25
  • 19
5

AutoMapper has a DynamicMap method which you might be able to use: here's an example unit test illustrating it.

[TestClass]
public class AutoMapper_Example
{
    [TestMethod]
    public void AutoMapper_DynamicMap()
    {
        Source source = new Source {Id = 1, Name = "Mr FooBar"};

        Target target = Mapper.DynamicMap<Target>(source);

        Assert.AreEqual(1, target.Id);
        Assert.AreEqual("Mr FooBar", target.Name);
    }

    private class Target
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

    private class Source
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }
}
stuartd
  • 70,509
  • 14
  • 132
  • 163
  • 4
    DynamicMap is now obsolete, and `Mapper.Map (foo, opts => opts.CreateMissingTypeMaps = true)` is the recommended alternative. – PeteGO Mar 21 '16 at 14:36
2

Set CreateMissingTypeMaps option to true. This is package AutoMapper.Extensions.Microsoft.DependencyInjection's example for ASP.NET Core:

public class Startup {
    //...
    public void ConfigureServices(IServiceCollection services) {
        //...
        services.AddAutoMapper(cfg => { cfg.CreateMissingTypeMaps = true; });
        //...
    }
    //...
}
guogangj
  • 2,275
  • 3
  • 27
  • 44
2

In case someone is still interested in this topic, I've created a NuGet package that gives the automatic mapping functionality since AutoMapper removed it in a certain version.

It's available under wakiter.AutoMapper.Extensions name.

To use it, invoke the CreateAutoMap extension method and it'll do the work for you.

Rafal Kozlowski
  • 224
  • 2
  • 2
1

Today I needed this in some generic code as well. I tried something like this:

    private static IMapper CreateMapper<T1, T2>()
    {
        return new MapperConfiguration(cfg => FillMapperConfig(cfg, typeof(T1), typeof(T2)))
            .CreateMapper();
    }

    private static void FillMapperConfig(IMapperConfigurationExpression cfg, Type T1, Type T2)
    {
        if (T1 == T2)
        {
            return;
        }

        cfg.CreateMap(T1, T2);

        foreach (PropertyInfo propertyInfo in T1.GetProperties())
        {
            PropertyInfo correspondingProperty =
                T2.GetProperties()
                    .FirstOrDefault(p =>
                        p.Name == propertyInfo.Name);

            if (correspondingProperty != null)
            {
                if (propertyInfo.PropertyType.IsGenericType && 
                    correspondingProperty.PropertyType.IsGenericType)
                {
                    FillMapperConfig(
                        cfg,
                        propertyInfo.PropertyType.GetGenericArguments()[0],
                        correspondingProperty.PropertyType.GetGenericArguments()[0]);
                }
                else if (propertyInfo.PropertyType.IsClass &&
                    correspondingProperty.PropertyType.IsClass)
                {
                    FillMapperConfig(
                        cfg,
                        propertyInfo.PropertyType,
                        correspondingProperty.PropertyType);
                }
            }
        }
    }

Then I can do something like this:

   IMapper mapper = CreateMapper<ClassA, ClassB>();

Which creates a map from ClassA to ClassB with all sub properties of ClassA and ClassB if they have the same name and recursively for sub sub properties.

Example:

public class ClassA {
    public int IntProperty { get; set; }

    public ClassASubProperty SubProperty { get; set; }

    public List<ClassAListItem> ListItems { get; set; }
}

public class ClassB {
    public int IntProperty { get; set; }

    public ClassBSubProperty SubProperty { get; set; }

    public List<ClassBListItem> ListItems { get; set; }
}

This should result in the IMapper equivalent:

    new MapperConfiguration(cfg => {
        cfg.CreateMap<ClassA, ClassB>();
        cfg.CreateMap<ClassASubProperty, ClassBSubProperty>();
        cfg.CreateMap<ClassAListItem, ClassBListItem>()
    }).CreateMapper();
GHN
  • 65
  • 1
  • 3