依赖注入(Dependency Injection)
AutoMapper
支持使用静态服务定位构建自定义值解析器和自定义类型转换器的功能:
Mapper.Initialize(cfg =>
{
cfg.ConstructServicesUsing(ObjectFactory.GetInstance);
cfg.CreateMap<Source, Destination>();
});
或者在基于实例的容器(包括子/嵌套容器)中使用动态服务定位:
var mapper = new Mapper(Mapper.Configuration, childContainer.GetInstance);
var dest = mapper.Map<Source, Destination>(new Source { Value = 15 });
陷阱
使用IQueryable.ProjectTo
扩展方法与使用依赖注入是互斥的。请使用
IEnumerable.Select(_mapper.Map<DestinationType>).ToList()
来代替IQueryable.ProjectTo
。
ASP.NET Core
有一个NuGet包与这里描述的默认注入机制搭配使用。
Ninject
对于那些使用Ninject
的人来说,这有一个AutoMapper
使用的Ninject
模块的例子
public class AutoMapperModule : NinjectModule
{
public override void Load()
{
Bind<IValueResolver<SourceEntity, DestModel, bool>>().To<MyResolver>();
var mapperConfiguration = CreateConfiguration();
Bind<MapperConfiguration>().ToConstant(mapperConfiguration).InSingletonScope();
// This teaches Ninject how to create automapper instances say if for instance
// MyResolver has a constructor with a parameter that needs to be injected
Bind<IMapper>().ToMethod(ctx =>
new Mapper(mapperConfiguration, type => ctx.Kernel.Get(type)));
}
private MapperConfiguration CreateConfiguration()
{
var config = new MapperConfiguration(cfg =>
{
// Add all profiles in current assembly
cfg.AddProfiles(GetType().Assembly);
});
return config;
}
}
简单注入器实现
工作流程如下:
- 通过
MyRegistrar.Register
注册你的类型 -
MapperProvider
允许你直接将IMapper
的实例注入到其他类中 -
SomeProfile
使用PropertyThatDependsOnIocValueResolver
解析值 -
PropertyThatDependsOnIocValueResolver
将IService
注入其中
ValueResolver
能访问IService
,是因为我们通过MapperConfigurationExpression.ConstructServicesUsing
注册容器。
public class MyRegistrar
{
public void Register(Container container)
{
// Injectable service
container.RegisterSingleton<IService, SomeService>();
// Automapper
container.RegisterSingleton(() => GetMapper(container));
}
private AutoMapper.IMapper GetMapper(Container container)
{
var mp = container.GetInstance<MapperProvider>();
return mp.GetMapper();
}
}
public class MapperProvider
{
private readonly Container _container;
public MapperProvider(Container container)
{
_container = container;
}
public IMapper GetMapper()
{
var mce = new MapperConfigurationExpression();
mce.ConstructServicesUsing(_container.GetInstance);
var profiles = typeof(SomeProfile).Assembly.GetTypes()
.Where(t => typeof(Profile).IsAssignableFrom(t))
.ToList();
mce.AddProfiles(profiles);
var mc = new MapperConfiguration(mce);
mc.AssertConfigurationIsValid();
IMapper m = new Mapper(mc, t => _container.GetInstance(t));
return m;
}
}
public class SomeProfile : Profile
{
public SomeProfile()
{
var map = CreateMap<MySourceType, MyDestinationType>();
map.ForMember(d => d.PropertyThatDependsOnIoc, opt => opt.ResolveUsing<PropertyThatDependsOnIocValueResolver>());
}
}
public class PropertyThatDependsOnIocValueResolver : IValueResolver<MySourceType, object, int>
{
private readonly IService _service;
public PropertyThatDependsOnIocValueResolver(IService service)
{
_service = service;
}
int IValueResolver<MySourceType, object, int>.Resolve(MySourceType source, object destination, int destMember, ResolutionContext context)
{
return _service.MyMethod(source);
}
}
网友评论