美文网首页.NETdotNET
14.AutoMapper 之依赖注入(Dependency I

14.AutoMapper 之依赖注入(Dependency I

作者: 做人生的CEO | 来源:发表于2019-01-09 08:38 被阅读1次

    依赖注入(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;
        }
    }
    

    简单注入器实现

    工作流程如下:

    1. 通过 MyRegistrar.Register注册你的类型
    2. MapperProvider允许你直接将IMapper的实例注入到其他类中
    3. SomeProfile使用PropertyThatDependsOnIocValueResolver解析值
    4. PropertyThatDependsOnIocValueResolverIService注入其中

    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);
        }
    }
    

    相关文章

      网友评论

        本文标题:14.AutoMapper 之依赖注入(Dependency I

        本文链接:https://www.haomeiwen.com/subject/bsiirqtx.html