使用带有DI容器的AutoMapper实例化类型

时间:2017-07-07 14:25:22

标签: c# dependency-injection automapper castle-windsor

请参阅以下代码:

public class Test : ITest
    {
        public ITest2 _iTest2;
        public int _id;
        public string _name;

        public Test(ITest2 test2)
        {
            _iTest2 = test2;
        }
    }

    public interface ITest
    {
    }

    public class Test2 : ITest2
    {
    }

    public interface ITest2
    {

    }

    public class Test3 : ITest3
    {
        public int _id;
        public string _name;
    }

    public interface ITest3
    {

    }

我在Global.asax中有以下内容:

Mapper.Initialize(m =>
            {  
 m.CreateMap<DataLayer.Test3, BusinessLayer.Test>().ConstructUsing(opt => new BusinessLayer.Test(new BusinessLayer.Test2()));
});

我可以在我的客户端应用中映射这些类型:

cfg.CreateMap<DataLayer.Test3, BusinessLayer.Test>().ConstructUsing(opt => new BusinessLayer.Test(new BusinessLayer.Test2()));

如何使用Castle Windsor映射类型,而不必为Test和Test2使用new关键字?

我读了另一个答案,有人建议这样做:

 public void Install(IWindsorContainer container, IConfigurationStore store)
    {

        container.Register(Types.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn(typeof(IValueResolver<,,>)));
        // container.Register(Types.FromAssembly(Assembly.GetExecutingAssembly()).BasedOn<IValueResolver>());
        container.Register(Types.FromThisAssembly().BasedOn<Profile>().WithServiceBase());
        var profiles = container.ResolveAll<Profile>();

        // Add your list of profiles to the mapper configuration here
        Mapper.Initialize(m => {
            m.ConstructServicesUsing(container.Resolve);
            profiles.ToList().ForEach(p => m.AddProfile(p));
        });

        // I'm not sure about this as I haven't used AutoMapper for a while,
        // but I assume you want to resolve the static mapper instance
        container.Register(Component.For<IMapper>().Instance(Mapper.Instance));
    }

我必须这样做:

cfg.CreateMap<DataLayer.Test3, BusinessLayer.Test>().ConstructUsing(opt => new BusinessLayer.Test(new BusinessLayer.Test2()));

或者AutoMapper是否能够使用以下方式映射类型:

cfg.CreateMap<DataLayer.Test3, BusinessLayer.Test>()

2 个答案:

答案 0 :(得分:1)

为了让AutoMapper使用Windsor创建目标类型,您需要配置两件事:

  1. 告诉AutoMapper使用Windsor构建服务
  2. 告诉AutoMapper(按映射)实际使用上述配置

     var container = new WindsorContainer();
    
        Mapper.Initialize(m =>
        {
            m.ConstructServicesUsing(container.Resolve);
    
            m.CreateMap<Test3, ITest>().ConstructUsingServiceLocator(); // This is important!
    
        });
    
        container.Register(Component.For<ITest>().ImplementedBy<Test>());
        container.Register(Component.For<ITest2>().ImplementedBy<Test2>());
        container.Register(Component.For<ITest3>().ImplementedBy<Test3>());
    
        var test3 = new Test3();
        var test1 = Mapper.Instance.Map<Test3, ITest>(test3);
    

答案 1 :(得分:0)

对于需要使用 3.6, 7.1和 8.1的用户来说,这是对我有用的。

在App.xml.cs文件中

protected override void RegisterTypes(IContainerRegistry containerRegistry)
        {
/// other registrations ...

            containerRegistry.RegisterSingleton<IMapperProvider, MapperProvider>();
            containerRegistry.RegisterInstance(typeof(IMapper), GetMapper(containerRegistry));
 }

        /// <summary>
        /// This function required in order for injection into custom automapper resolvers
        /// </summary>
        private IMapper GetMapper(IContainerRegistry container)
        {
            var mp = container.GetContainer().Resolve<IMapperProvider>(new[] { container });
            return mp.GetMapper();
        }

映射器提供程序如下:

public class MapperProvider : IMapperProvider
    {
        private readonly IContainerRegistry _container;

        public MapperProvider(IContainerRegistry container)
        {
            _container = container;
        }

        public IMapper GetMapper()
        {
            var config = new MapperConfiguration(cfg =>
            {
                cfg.ConstructServicesUsing(t => _container.GetContainer().Resolve(t));
                // any custom profile statement such as
                cfg.AddProfile<MappingSourcesProfile>();
                // ....
            });

            return config.CreateMapper();
        }
    }

现在我的自定义解析器可以工作了,例如:

    public class BarcodesResolver : IValueResolver<repo.Book, Book, List<Barcode>>
    {
        private readonly IMapper _mapper;

        public BarcodesResolver(IMapper mapper)
        {
            _mapper = mapper;
        }

        public List<Barcode> Resolve(repo.Book source, Book destination, List<Barcode> destMember, ResolutionContext context)
        {
            repo.BookAttributes groupedAttribs = JsonConvert.DeserializeObject<repo.BookAttributes>(source.BookAttributes);

            return _mapper.Map<List<repo.Barcode>, List<Barcode>>(groupedAttribs.Barcodes);
        }
    }

这里要解决的难题是如何指定将containerRegistry传递给MapperProvider的构造函数。也许有更好的方法可以做到这一点,但至少可以奏效。

到达cfg.ConstructServicesUsing(t => _container.GetContainer().Resolve(t));行也很晦涩,因为那里似乎没有什么例子。