我正在使用AutoMapper在DTO对象和业务对象之间进行映射。我有两个AutoMapperConfiguration.cs文件 - 一个在我的服务层,另一个在我的web api层。
如以下链接中的答案所示 Where to place AutoMapper.CreateMaps?
我在Global.asax类
中调用这两个文件的Configure()AutoMapperWebConfiguration.Configure();
AutoMapperServiceConfiguration.Configure();
但似乎我的Service Configure调用(第二次调用)正在覆盖web api层的映射(第一次调用),并且我得到一个异常,说明Mapping缺失了。
如果我将配置调用反向看起来像这样
AutoMapperServiceConfiguration.Configure();
AutoMapperWebConfiguration.Configure();
我没有得到web api映射的异常,但我得到了Service层的相同映射异常。
我做错了什么,因为这在上面的堆栈溢出链接中明确标记为答案?
这是我的代码:
public static class AutoMapperServiceConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<CmciFlowTestToGenericFlowTestSimpleMappingProfile>();
x.AddProfile<FsrsFlowTestToGenericFlowTestSimpleMappingProfile>();
});
}
}
public class FsrsFlowTestToGenericFlowTestSimpleMappingProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<FsrsFlowTest, GenericFlowTest>()
.ConvertUsing<FsrsFlowTestToGenericFlowTestSimpleConverter>();
}
}
public class FsrsFlowTestToGenericFlowTestSimpleConverter : TypeConverter<FsrsFlowTest, GenericFlowTest>
{
protected override GenericFlowTest ConvertCore(FsrsFlowTest source)
{
if (source == null)
{
return null;
}
return new GenericFlowTest
{
FlowTestDate = source.FlowTestDates,
StaticPsi = source.HydrantStaticPsi.ToString(),
ResidualPsi = source.HydrantResidualPsi.ToString(),
TotalFlow = source.NffGallonsPerMinute.ToString(),
FlowTestLocation = source.FsrsFlowTestLocations.Any()
? source.FsrsFlowTestLocations.First().LocationDescription
: null
};
}
public class CmciFlowTestToGenericFlowTestSimpleMappingProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<CmciFlowTest, GenericFlowTest>()
.ConvertUsing<CmciFlowTestToGenericFlowTestSimpleConverter>();
}
}
public class CmciFlowTestToGenericFlowTestSimpleConverter : TypeConverter<CmciFlowTest, GenericFlowTest>
{
protected override GenericFlowTest ConvertCore(CmciFlowTest source)
{
if (source == null)
{
return null;
}
return new GenericFlowTest
{
FlowTestDate = source.FlowTestDates,
StaticPsi = source.HydrantStaticPsi.ToString(),
ResidualPsi = source.HydrantResidualPsi.ToString(),
TotalFlow = source.CalculatedHydrantGallonsPerMinute.ToString(),
FlowTestLocation = source.StaticLocationHydrantFlowPSI
};
}
}
public static class AutoMapperWebConfiguration
{
public static void Configure()
{
Mapper.Initialize(x =>
{
x.AddProfile<ServiceToWebApiMappingProfile>();
x.AddProfile<WebApiToServiceMappingProfile>();
});
}
}
public class ServiceToWebApiMappingProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<ServiceFlowTest, FlowTest>();
}
}
public class WebApiToServiceMappingProfile : Profile
{
protected override void Configure()
{
Mapper.CreateMap<PropertyAddress, ServicePropertyAddress>();
}
}
要解决此问题,我将在AutoMapperWebConfiguration类中添加服务配置文件,并仅在global.asax中调用AutoMapperWebConfiguration.Configure()。
答案 0 :(得分:29)
对 Mapper.Initialize 的调用会重置映射器,以便擦除以前所有内容。
将对AddProfile的调用移到一个Mapper.Initialize调用中,所有调用都应该很好:
Mapper.Initialize(x =>
{
x.AddProfile<CmciFlowTestToGenericFlowTestSimpleMappingProfile>();
x.AddProfile<FsrsFlowTestToGenericFlowTestSimpleMappingProfile>();
x.AddProfile<ServiceToWebApiMappingProfile>();
x.AddProfile<WebApiToServiceMappingProfile>();
});
答案 1 :(得分:11)
@GruffBunny的回答是正确的,但我试图让它更适合可伸缩性(例如,如果你有很多复杂的tmp = (Tuple<bool,T,object>) (object) I(o.ToString());
方法,并且将来可能会增加更多)。
我是通过在Mapper.Initialize()
个文件的所有中实现以下结构来实现此目的的:
AutoMapperConfiguration.cs
方法中的Action<IConfiguration>
解压缩为公共属性我在每个人中都称它为Mapper.Initialize()
。
ConfigAction
这使您可以从需要调用public static Action<IConfiguration> ConfigAction = new Action<IConfiguration>(x =>
{
x.AddProfile<SomeProfile>();
x.AddProfile<SomeOtherProfileProfile>();
//... more profiles
});
的任何地方调用操作。
Mapper.Initialize
内的Mapper.Initialize()
仅引用此属性Configure()
然后,您可以在对public static void Configure()
{
Mapper.Initialize(ConfigAction);
}
的单一集中电话中调用所有不同的ConfigAction
Mapper.Initialize()
中的AutoMapperConfiguration.Configure()
变为Application_Start()
这样就无需将方法正文从每个单独的Mapper.Initialize(x =>
{
Project1.AutoMapperConfiguration.ConfigAction.Invoke(x);
Project2.AutoMapperConfiguration.ConfigAction.Invoke(x);
Project3.AutoMapperConfiguration.ConfigAction.Invoke(x);
//... keep adding as your project grows
});
调用复制并粘贴到您的中央呼叫中。 DRY 等等。
答案 2 :(得分:6)
更新@theetiman对AutoMapper 5.2&amp; amp; .NET Core。
public static class AutoMapperConfiguration
{
public static void Configure()
{
Mapper.Initialize(ConfigAction);
}
public static Action<IMapperConfigurationExpression> ConfigAction = cfg =>
{
cfg.AddProfile<SomeProfile>();
cfg.AddProfile<SomeOtherProfileProfile>();
};
}
API或网络启动。
public Startup(IHostingEnvironment env)
{
Mapper.Initialize(x =>
{
Project1.AutoMapperConfiguration.ConfigAction.Invoke(x);
Project2.AutoMapperConfiguration.ConfigAction.Invoke(x);
Project3.AutoMapperConfiguration.ConfigAction.Invoke(x);
});
}