人本善良

导航

14.AutoMapper 之依赖注入(Dependency Injection)

https://www.jianshu.com/p/f66447282780

 

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

码字不易,动动手指给个赞吧

posted on 2019-06-20 17:13  简简单单2018  阅读(1125)  评论(0编辑  收藏  举报