M Kenyon II M Kenyon II - 8 days ago 6
C# Question

Automapper says Mapper.Map is obsolete, global mappings?

I had defined in my project a global Automapper configuration that would allow me to use

Mapper.Map<targetType>(sourceObject);
in my code. (See my configuration below.)

I updated the NuGet package, and I see the message that Mapper.Map is obsolete/depreciated. I went back to Automapper on GitHub and see examples like this:

[Test]
public void Example()
{
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Source1, SubDest1>().FixRootDest();
cfg.CreateMap<Source2, SubDest2>().FixRootDest();
});

config.AssertConfigurationIsValid();

var mapper = config.CreateMapper();

var subDest1 = mapper.Map<Source1, SubDest1>(new Source1 {SomeValue = "Value1"});
var subDest2 = mapper.Map<Source2, SubDest2>(new Source2 {SomeOtherValue = "Value2"});

subDest1.SomeValue.ShouldEqual("Value1");
subDest2.SomeOtherValue.ShouldEqual("Value2");
}


Am I going to have to create a configuration in EVERY method that uses a mapping?

My current global configuration:

namespace PublicationSystem.App_Start
{
public class AutoMapperConfig
{
public static void CreateMaps()
{
CreateProjectMaps();
}

private static void CreateProjectMaps()
{
Mapper.CreateMap<Project, ProjectCreate>();
Mapper.CreateMap<Project, ProjectSelectable>();
//...
}
}
}


UPDATE: Thanks to some coaching from Scott Chamberlain I have created a class like this:

public class MkpMapperProfile : AutoMapper.Profile
{
protected override void Configure()
{
this.CreateMap<Project, ProjectCreate>();

this.CreateMap<Project, ProjectSelectable>();

this.CreateMap<Project, ProjectDetails>();

// Many Many other maps
}
}


I'm thinking I should have the 'MapperConfiguration' in my BaseController class. I started to do something like this:

public partial class BaseController : Controller
{

private MapperConfiguration mapConfig;

public BaseController()
{
db = new MkpContext();
SetMapperConfig();
}

private void SetMapperConfig()
{
mapConfig = new MapperConfiguration(cfg =>
{
cfg.AddProfile<MkpMapperProfile>();
});
}

public BaseController(MapperConfiguration config)
{
db = new MkpContext();
this.mapConfig = config;
}
}


Am I on the right track?

Answer

This is how I've handled it.

Create maps in a Profile, taking care to use the Profile's CreateMap method rather than Mapper's static method of the same name:

internal class MappingProfile : Profile
{
    protected override void Configure()
    {
        CreateMap<Project, ProjectCreate>();
    }
}

Then, wherever dependencies are wired-up (ex: Global.asax or Startup), create a MapperConfiguration and then use it to create an IMapper.

var mapperConfiguration = new MapperConfiguration(cfg =>
    {
        cfg.AddProfile(new MappingProfile());
    });

Then, use the configuration to generate an IMapper:

var mapper = mapperConfiguration.CreateMapper();

Then, register that mapper with the dependency builder (I'm using Autofac here)

builder.RegisterInstance(mapper).As<IMapper>();

Now, wherever you need to map stuff, declare a dependency on IMapper:

internal class ProjectService : IProjectService {
    private readonly IMapper _mapper;
    public ProjectService(IMapper mapper) {
         _mapper = mapper;
    }
    public ProjectCreate Get(string key) {
        var project = GetProjectSomehow(key);
        return _mapper.Map<Project, ProjectCreate>(project);
    }
}