1

I am looking some utility using which I can avoid writing extra line of code.

For Example

config.CreateMap<ModelClass, DTOClass>();

Though I dont have any difference between ModelClass and DTOClass still I need to create map or automapper can do it by itself?

StuartLC
  • 104,537
  • 17
  • 209
  • 285
Serry
  • 17
  • 3

1 Answers1

3

As per the comments, seemingly the Automapper team elected to remove the CreateMissingTypeMaps option in the 9.0 upgrade. Speculatively, this was because automatic map creation could lead to unexpected mappings and awkward runtime bugs, and also, it is preferable to define all maps at bootstrap time and compile them, rather than have them compiled lazily on the fly during first mapping.

However, if you use a consistent naming scheme between your Poco class layers, you can quite easily replicate the automapping capability, at bootstrap time, for all classes with the same names in the two poco layers. For example, if you're convention is:

namespace Models
{
    public class MyModel
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Amount { get; set; }
        public DateTime Date { get; set; }
    }
}

namespace Dtos
{
    public class MyDto
    {
        public int Id { get; set; }
        public string Name { get; set; }
        public decimal Amount { get; set; }
        public DateTime Date { get; set; }
    }
}

You can then reflect out all the classes meeting your naming convention in each of the layers, and explicitly create a mapping between the matching classes:

const string modelSuffix = "Model";
const string dtoSuffix = "Dto";
var mapperConfiguration = new MapperConfiguration(cfg =>
{
    // You may need to repeat this if you have Pocos spread across multiple assemblies
    var modelTypes = typeof(MyModel).Assembly
        .GetTypes()
        .Where(type => type.Namespace == "Models" && type.Name.EndsWith(modelSuffix))
        .ToDictionary(t => StripSuffix(t.Name, modelSuffix));

    var dtoTypes = typeof(MyDto).Assembly
        .GetTypes()
        .Where(type => type.Namespace == "Dtos"
                       && type.Name.EndsWith(dtoSuffix));

    foreach (var dtoType in dtoTypes)
    {
        if (modelTypes.TryGetValue(StripSuffix(dtoType.Name, dtoSuffix), out var modelType))
        {
            // I've created forward and reverse mappings ... remove as necessary
            cfg.CreateMap(dtoType, modelType);
            cfg.CreateMap(modelType, dtoType);
        }
    }
});
var mapper = mapperConfiguration.CreateMapper();

StripSuffix is simply:

public static string StripSuffix(string someString, string someSuffix)
{
    if (someString.EndsWith(someSuffix))
        return someString.Substring(0, someString.Length - someSuffix.Length);
    else
        return someString;
}

Which you can now test as applicable:

var model = new MyModel
{
    Id = 1,
    Name = "Foo",
    Amount = 1.23m,
    Date = DateTime.UtcNow
};

var dto = mapper.Map<MyDto>(model);
var backTomodel = mapper.Map<MyModel>(dto);
StuartLC
  • 104,537
  • 17
  • 209
  • 285
  • 1
    Yes, or simply use attribute mapping. Automatic maps work in the very simple cases. And then things are not so simple anymore :) There is no easy way to isolate them to the simple cases. You can do that with multiple `MappingConfiguration`s, but nobody did that. – Lucian Bargaoanu Jun 16 '21 at 09:02
  • Yes, good point. To be honest, I stopped using `CreateMissingTypeMaps` ages ago and hadn't realised it had been dropped altogether - as you say, it's better to make things explicit and have finer control over how mapping occurs. Like many, I'm fairly adverse to polluting multi-tier classes with attributes such as mapping or IoC concerns, as this creates additional coupling in these assemblies. – StuartLC Jun 16 '21 at 09:07