29

https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API

this change breaks my system.

Before update, I use:

===> Startup.cs

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
    ...
        MyAutoMapperConfiguration.Configure();
    }
}

===> MyAutoMapperConfiguration.cs

public class MyAutoMapperConfiguration
{
    public static void Configure()
    {
        Mapper.Initialize(a =>
        {
            a.AddProfile<AbcMappingProfile>();
            a.AddProfile<XyzMappingProfile>();
            a.AddProfile<QweMappingProfile>();
        });
    }
}

===> AbcMappingProfile.cs

public class AbcMappingProfile : Profile
{
    protected override void Configure()
    {
        Mapper.CreateMap<AbcEditViewModel, Abc>();
        Mapper.CreateMap<Abc, AbcEditViewModel>();
        ...
    }
}

ERROR:

'Mapper.CreateMap()' is obsolete: 'The static API will be removed in version 5.0. Use a MapperConfiguration instance and store statically as needed. Use CreateMapper to create a mapper instanace.'

I can use Mapper.Map. Now How can I use it

Asp.net
  • 329
  • 1
  • 3
  • 6

4 Answers4

48

Instead of:

Mapper.CreateMap<AbcEditViewModel, Abc>();

The new syntax is:

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

Then:

IMapper mapper = config.CreateMapper();
var source = new AbcEditViewModel();
var dest = mapper.Map<AbcEditViewModel, Abct>(source);

(Source with more examples)

NikolaiDante
  • 18,469
  • 14
  • 77
  • 117
  • instead of Mapper.Initialize( ? I can not find in the link – Asp.net Feb 07 '16 at 16:51
  • 5
    Yes, there is a lot of confusion on what to do in Startup.cs to configure AutoMapper and how to then use it in a Controller. Does it have to be injected now? – Blake Rivell Feb 13 '16 at 12:13
  • 2
    It doesn't _have_ to be, but in the spirit of DI (that .NET core is trying to promote) perhaps it _should_ be. – NikolaiDante Feb 13 '16 at 12:19
  • 2
    Glad I sometimes abstract classes from third parties. This means that I only need to update few references. – Jose A Feb 17 '16 at 05:16
10

Instead of Automapper Profile use IMapperConfigurationExpression extension:

Mapping configuration:

public static class AutoMapperConfig
{
    public static IMapperConfigurationExpression AddAdminMapping(
        this IMapperConfigurationExpression configurationExpression)
    {
        configurationExpression.CreateMap<Job, JobRow>()
            .ForMember(x => x.StartedOnDateTime, o => o.PreCondition(p => p.StartedOnDateTimeUtc.HasValue))
            .ForMember(x => x.StartedOnDateTime, o => o.MapFrom(p => p.StartedOnDateTimeUtc.Value.DateTime.ToLocalTime()))
            .ForMember(x => x.FinishedOnDateTime, o => o.PreCondition(p => p.FinishedOnDateTimeUtc.HasValue))
            .ForMember(x => x.FinishedOnDateTime, o => o.MapFrom(p => p.FinishedOnDateTimeUtc.Value.DateTime.ToLocalTime()));

        return configurationExpression;
    }
}

Integration (Startup.cs etc.):

        var mappingConfig = new AutoMapper.MapperConfiguration(cfg =>
        {
            cfg.AddAdminMapping();
        });

        services.AddSingleton(x => mappingConfig.CreateMapper());
Skorunka František
  • 5,102
  • 7
  • 44
  • 69
8

Dependency injection added a whole level of complexity to my legacy project that I just didn't want to deal with. As the same library is called with many different technologies, Webforms, MVC, Azure Service, etc...

Also dependency injection would of forced me to rewrite several methods or pass an IMapper around.

So I just reverse engineered what it was doing in 8.0 and wrote a wrapper for it.

public static class MapperWrapper 
{
    private const string InvalidOperationMessage = "Mapper not initialized. Call Initialize with appropriate configuration. If you are trying to use mapper instances through a container or otherwise, make sure you do not have any calls to the static Mapper.Map methods, and if you're using ProjectTo or UseAsDataSource extension methods, make sure you pass in the appropriate IConfigurationProvider instance.";
    private const string AlreadyInitialized = "Mapper already initialized. You must call Initialize once per application domain/process.";

    private static IConfigurationProvider _configuration;
    private static IMapper _instance;

    private static IConfigurationProvider Configuration
    {
        get => _configuration ?? throw new InvalidOperationException(InvalidOperationMessage);
        set => _configuration = (_configuration == null) ? value : throw new InvalidOperationException(AlreadyInitialized);
    }

    public static IMapper Mapper
    {
        get => _instance ?? throw new InvalidOperationException(InvalidOperationMessage);
        private set => _instance = value;
    }

    public static void Initialize(Action<IMapperConfigurationExpression> config)
    {
        Initialize(new MapperConfiguration(config));
    }

    public static void Initialize(MapperConfiguration config)
    {
        Configuration = config;
        Mapper = Configuration.CreateMapper();
    }

    public static void AssertConfigurationIsValid() => Configuration.AssertConfigurationIsValid();
}

Initialize it just like you did in previous versions

public static class AutoMapperConfig
{
    public static void Configure()
    {
        MapperWrapper.Initialize(cfg =>
        {
            cfg.CreateMap<Foo1, Foo2>();              
        });

        MapperWrapper.AssertConfigurationIsValid();
    }
}

And just call it in your startup, (Global.asax etc..)

AutoMapperConfig.Configure();

Then all you have to do is add MapperWrapper before all your static calls. And everything works as it did before.

 MapperWrapper.Mapper.Map<Foo2>(Foo1);
Ben Walters
  • 265
  • 3
  • 4
0

Ben Walters: Dependency injection added a whole level of complexity to my legacy project that I just didn't want to deal with...

HI

Furthermore, you can apply the class alias using statement and no need to change the code, just change the using statement.

Define a using directive and a using alias for a class: https://learn.microsoft.com/zh-tw/dotnet/csharp/language-reference/keywords/using-directive#example-2

--

.Your class implementation for compatibility.

namespace AutoMappers
{
  public class Mapper
  {
    public static void Initialize(Action<AutoMapper.IMapperConfigurationExpression> config)
    {
      ...
    }
  }
}

.Change "using AutoMapper" to "using Mapper = AutoMappers.Mapper".

using Mapper = AutoMappers.Mapper; <-- using statement changed

namespace ...
{
  public class ...
  {
    public ...(...)
    {
      Mapper.Initialize(cfg => cfg.CreateMap<TSource1, TDestination1>()); <-- other code line kept originally

--

Chris Chi
  • 1
  • 1