Asp.net
Asp.net

Reputation: 329

AutoMapper Migrating from static API

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

Upvotes: 29

Views: 31641

Answers (4)

Chris Chi
Chris Chi

Reputation: 1

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

--

Upvotes: 0

Ben Walters
Ben Walters

Reputation: 275

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);

Upvotes: 9

Skorunka František
Skorunka František

Reputation: 5430

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());

Upvotes: 10

NikolaiDante
NikolaiDante

Reputation: 18639

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)

Upvotes: 48

Related Questions