27

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?

M Kenyon II
  • 4,136
  • 4
  • 46
  • 94
  • 1
    Automapper is moving away from globally scoped static functions. This allows libraries written by different authors to use AutoMapper without interfering with each other. – Scott Chamberlain Feb 12 '16 at 19:45
  • 1
    I'm not sure what that means for me. I'm getting bits of information here and there, but it's not making a complete picture for me. I've read this: https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API but it's not making sense. Do I need to define a config in EVERY ActionResult that uses AutoMapper? I could move it to a datalayer... And My app doesn't seem to have `MvcApplication.MapperConfiguration`. Where is that defined? – M Kenyon II Feb 12 '16 at 19:49
  • You make one, basicly create a class that derives from `Profile`, override the `Configure()` function, then paste in your `CreateProjectMaps` but replace `Mapper.` with `this.` – Scott Chamberlain Feb 12 '16 at 19:50
  • My app has a class called `Profile`. I'm assuming you mean a `Profile` from the AutoMapper namespace? Details like that help make things less ambiguous. – M Kenyon II Feb 12 '16 at 19:53
  • `MvcApplication.MapperConfiguration` in your example would be `AutoMapperConfig.MapperConfiguration`, you would need to add a `public static MapperConfiguration MapperConfiguration {get; set;}` to the class and assign a value to it like they do in the example you linked to. the `MvcApplication` is not somthing built in, they where using it as a placeholder name for ***your*** MvcApplication. – Scott Chamberlain Feb 12 '16 at 19:53
  • @MKenyonII I'm putting *some* of the static API back in. You'll have Mapper.Map and Mapper.Initialize. But no Mapper.CreateMap, that was too buggy. Continue on. – Jimmy Bogard Feb 12 '16 at 22:58

5 Answers5

41

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);
    }
}
Romi Petrelis
  • 536
  • 6
  • 6
14

I'm using version 5.2.0, support to create maps in constructors instead of override configure.

public class MappingProfile : Profile
{
    public MappingProfile()
    {
        CreateMap<Project, ProjectDto>();
    }
}

In Global.asax.cs call like:

Mapper.Initialize(c=>c.AddProfile<MappingProfile>());

Hope this help.

zquanghoangz
  • 663
  • 5
  • 11
  • 1
    If you need to add profiles dynamically `Mapper.Initialize(c => c.AddProfiles(new string[] { "DLL_NAME" }));` – RasikaSam Jan 18 '17 at 23:30
7

This is new in AutoMapper 4.2. There is a blog post by Jimmy Bogard on this: Removing the static API from AutoMapper. It claims that

The IMapper interface is a lot lighter, and the underlying type is now just concerned with executing maps, removing a lot of the threading problems...

The new syntax: (pasted from the blog post)

var config = new MapperConfiguration(cfg => {
  cfg.CreateMap<User, UserDto>();
});

If you just want the "old way" of doing this. The latest version 4.2.1 has brought back some tradition. Just use

CreateMap<Project, ProjectCreate>();

instead of

Mapper.CreateMap<Project, ProjectCreate>();

The old code will work just fine.

Blaise
  • 21,314
  • 28
  • 108
  • 169
1
Mapper.Initialize(cfg => {
    cfg.CreateMap<Source, Dest>();
});
Roberth Solís
  • 1,520
  • 18
  • 16