AutoMapper 从静态迁移 API
AutoMapper Migrating from static API
https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API
此更改破坏了我的系统。
更新前,我使用:
===> 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>();
...
}
}
错误:
'Mapper.CreateMap()' 已过时:'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.'
我可以使用Mapper.Map。现在我该如何使用它
而不是:
Mapper.CreateMap<AbcEditViewModel, Abc>();
新语法是:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<AbcEditViewModel, Abc>();
});
然后:
IMapper mapper = config.CreateMapper();
var source = new AbcEditViewModel();
var dest = mapper.Map<AbcEditViewModel, Abct>(source);
使用 IMapperConfigurationExpression 扩展代替 Automapper 配置文件:
映射配置:
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;
}
}
积分(Startup.cs等):
var mappingConfig = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.AddAdminMapping();
});
services.AddSingleton(x => mappingConfig.CreateMapper());
依赖注入给我的遗留项目增加了一个整体的复杂性,我只是不想处理。由于使用许多不同的技术、Webforms、MVC、Azure 服务等调用同一个库...
依赖注入也会迫使我重写几个方法或传递一个 IMapper。
所以我只是对它在 8.0 中所做的事情进行了逆向工程,并为它编写了一个包装器。
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();
}
像在以前的版本中一样初始化它
public static class AutoMapperConfig
{
public static void Configure()
{
MapperWrapper.Initialize(cfg =>
{
cfg.CreateMap<Foo1, Foo2>();
});
MapperWrapper.AssertConfigurationIsValid();
}
}
只需在您的启动程序中调用它,(Global.asax 等...)
AutoMapperConfig.Configure();
然后您所要做的就是在所有静态调用之前添加 MapperWrapper 。一切都像以前一样工作。
MapperWrapper.Mapper.Map<Foo2>(Foo1);
Ben Walters: Dependency injection added a whole level of complexity to
my legacy project that I just didn't want to deal with...
嗨
此外,您可以使用语句应用 class 别名
无需更改代码,只需更改 using 语句即可。
为 class 定义一个 using 指令和一个 using 别名:
https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/keywords/using-directive#example-2
--
。您的 class 兼容性实现。
namespace AutoMappers
{
public class Mapper
{
public static void Initialize(Action<AutoMapper.IMapperConfigurationExpression> config)
{
...
}
}
}
。将 "using AutoMapper" 更改为 "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
--
https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API
此更改破坏了我的系统。
更新前,我使用:
===> 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>();
...
}
}
错误:
'Mapper.CreateMap()' 已过时:'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.'
我可以使用Mapper.Map。现在我该如何使用它
而不是:
Mapper.CreateMap<AbcEditViewModel, Abc>();
新语法是:
var config = new MapperConfiguration(cfg => {
cfg.CreateMap<AbcEditViewModel, Abc>();
});
然后:
IMapper mapper = config.CreateMapper();
var source = new AbcEditViewModel();
var dest = mapper.Map<AbcEditViewModel, Abct>(source);
使用 IMapperConfigurationExpression 扩展代替 Automapper 配置文件:
映射配置:
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;
}
}
积分(Startup.cs等):
var mappingConfig = new AutoMapper.MapperConfiguration(cfg =>
{
cfg.AddAdminMapping();
});
services.AddSingleton(x => mappingConfig.CreateMapper());
依赖注入给我的遗留项目增加了一个整体的复杂性,我只是不想处理。由于使用许多不同的技术、Webforms、MVC、Azure 服务等调用同一个库...
依赖注入也会迫使我重写几个方法或传递一个 IMapper。
所以我只是对它在 8.0 中所做的事情进行了逆向工程,并为它编写了一个包装器。
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();
}
像在以前的版本中一样初始化它
public static class AutoMapperConfig
{
public static void Configure()
{
MapperWrapper.Initialize(cfg =>
{
cfg.CreateMap<Foo1, Foo2>();
});
MapperWrapper.AssertConfigurationIsValid();
}
}
只需在您的启动程序中调用它,(Global.asax 等...)
AutoMapperConfig.Configure();
然后您所要做的就是在所有静态调用之前添加 MapperWrapper 。一切都像以前一样工作。
MapperWrapper.Mapper.Map<Foo2>(Foo1);
Ben Walters: Dependency injection added a whole level of complexity to my legacy project that I just didn't want to deal with...
嗨
此外,您可以使用语句应用 class 别名 无需更改代码,只需更改 using 语句即可。
为 class 定义一个 using 指令和一个 using 别名: https://docs.microsoft.com/zh-tw/dotnet/csharp/language-reference/keywords/using-directive#example-2
--
。您的 class 兼容性实现。
namespace AutoMappers
{
public class Mapper
{
public static void Initialize(Action<AutoMapper.IMapperConfigurationExpression> config)
{
...
}
}
}
。将 "using AutoMapper" 更改为 "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
--