我目前正在将几个映射配置文件从Automapper 4.2.1迁移到最新版本9.0.0。旧的映射配置文件是按层次结构构建的,其中抽象基类需要类型为IDatetime
的参数。此注入仅用于测试。
public abstract MappingProfileBase : Profile
{
protected MappingProfileBase(IDatetime datetime)
{
this.CreateMap<Foo, FooDto>()
.ForMember(dest => dest.SomeTimeStamp, opt => opt.MapFrom(src => datetime));
// Further mappings
}
}
public MappingProfileA : MappingProfileBase
{
public MappingProfileA(IDatetime datetime) : base(datetime)
{
this.CreateMap<FooDerived, FooDerivedDto>()
// Further and more specific mappings
}
}
现在,我想移至新的Include
和IncludeBase<>
方法并撤消MappingProfileA
和MappingProfileBase
的继承,但是根本不知道如何处理注入的接口。新方法都没有采用任何参数。
这就是我的想法应该看起来像:
public class MappingProfileBase : Profile
{
public MappingProfileBase(IDatetime datetime)
{
this.CreateMap<Foo, FooDto>()
.ForMember(dest => dest.SomeTimeStamp, opt => opt.MapFrom(src => datetime));
// Further mappings
}
}
public class MappingProfileA : Profile
{
public MappingProfileA()
{
this.CreateMap<FooDerived, FooDerivedDto>();
.IncludeBase<Foo, FooDto>();
}
}
那么如何将参数传递给base类的构造函数?还有其他可能性吗?
再次感谢Lucian。我通过为AddProfile
提供配置文件instance来解决了该问题(而不是Type
)使用Autofac。为此,我必须事先将具体类型注册到容器中。
private static MapperConfiguration GetMappingConfiguration()
{
var containerBuilder = new ContainerBuilder();
containerBuilder.RegisterType<DateTime>().As<IDateTime>();
var assembly = Assembly.GetExecutingAssembly();
var loadedProfiles = assembly.ExportedTypes
.Where(type => type.IsSubclassOf(typeof(Profile)))
.ToArray();
containerBuilder.RegisterTypes(loadedProfiles);
var container = containerBuilder.Build();
var config = new MapperConfiguration(cfg =>
{
cfg.ConstructServicesUsing(container.Resolve);
foreach (var profile in loadedProfiles)
{
var resolvedProfile = container.Resolve(profile) as Profile;
cfg.AddProfile(resolvedProfile);
}
});
return config;
}
以下是两个示例配置文件:
public class BaseMappingProfile : Profile
{
public BaseMappingProfile(IDateTime datetime)
{
this.CreateMap<Foo, FooDto>()
.ForMember(d => d.Timestamp, o => o.MapFrom(s => datetime))
.ForMember(d => d.PropertyA, o => o.MapFrom(s => s.Property1));
}
}
public class FooMappingProfile : Profile
{
public FooMappingProfile()
{
this.CreateMap<FooDerived, FooDerivedDto>()
.IncludeBase<Foo, FooDto>()
.ForMember(d => d.PropertyB, o => o.MapFrom(s => s.Property2));
}
}
然后在单元测试中:
[Fact]
public void Should_Map_From_Foo_To_FooDto()
{
var config = GetMappingConfiguration();
var mapper = config.CreateMapper();
var foo = new Foo {Property1 = "I am property 1"};
var fooDto = mapper.Map<FooDto>(foo);
// Asserts...
}
当然,静态方法GetMappingConfiguration
需要进一步修改。但原则上它是可行的。
使用IncludeBase
具有无代码重复的好处。但是另一方面,更复杂的配置文件和测试设置尤其是在这种情况下。