【问题标题】:Automapper together with Dependency InjectionAutomapper 和依赖注入
【发布时间】:2011-05-11 10:03:14
【问题描述】:

我目前有以下映射:

Mapper.CreateMap<Journal, JournalDto>();

现在,Journal 包含一个名为RefTypeID 的成员,其对应的值存在于数据库的另一个表中;为了查找这个值,我有一个服务可以处理一个简单的int -&gt; string 请求。自动映射器配置当前发生在程序开始时的静态类中。可以将映射代码移动到注入到我的 DI 容器中的类中还是有更好的方法?

【问题讨论】:

  • 我认为不这样做的唯一原因是纯粹的组织性。您可能会在整个项目中使用映射代码。如果您的域对象更改或 dto 可能不太理想。但我很想从其他人那里了解他们的意见。
  • 好吧,我仍然会将映射代码保存在一个地方 - 即。那个类,它将从 DI 容器中获取所有需要的服务。我只需要自己初始化映射,而不是依赖静态构造函数自动执行它。
  • 最新版本请看this所以回答

标签: dependency-injection automapper


【解决方案1】:

更好的方法是使用客户解析器。映射配置是静态的,因此自定义解析器旨在为单个成员提供映射:

Mapper.Initialize(cfg => {
    cfg.ConstructServicesUsing(type => WhateverMefUsesToGetInstances.GetInstance(type));

    cfg.CreateMap<Journal, DisplayJournal>()
        .ForMember(dest => dest.RefTypeName, 
            opt => opt.ResolveUsing<RefTypeNameResolver>());
});

那么你的解析器就变成了:

[Export(typeof(IRefTypeNameResolver))]
public class RefTypeNameResolver : ValueResolver<Journal, string>, IRefTypeNameResolver
{
    private readonly IRefTypesLookup iRefTypesLookup;

    [ImportingConstructor]
    public RefTypeNameResolver (IRefTypesLookup rtl)
    {
        iRefTypesLookup = rtl;
    }

    protected override string ResolveCore(Journal source)
    {
        return iRefTypesLookup.Lookup(source.RefTypeID);
    }
}

配置需要执行一次,这就是配置 API 提供挂钩到执行 API(类型转换器、值解析器等)的原因

【讨论】:

  • 我知道 ValueResolver,但我认为它们没用,因为我缺少 ConstructServicesUsing 配置。不错!
【解决方案2】:

您可以依赖 IMappingEngine 而不是使用静态类 Mapper

这里有一篇不错的博客文章:Mocking out AutoMapper with Dependency Injection

【讨论】:

    【解决方案3】:

    我是这样解决的:

    我定义了一个IMappingCreator 接口:

    public interface IMappingCreator
    {
      void CreateMappings();
    }
    

    我继续使用该接口实现了一个类(我使用 MEF 作为 DI 容器,这就是属性的来源),它作为 IMappingCreator 放入 DI 容器中:

    [Export(typeof(IMappingCreator))]
        public class Mapping : IMappingCreator
        {
            private readonly IRefTypesLookup iRefTypesLookup;
    
    
            [ImportingConstructor]
            public Mapping(IRefTypesLookup rtl)
            {
                iRefTypesLookup = rtl;
            }
    
            public void CreateMappings()
            {
                Mapper.CreateMap<Journal, DisplayJournal>().AfterMap((j, dj) => dj.RefTypeName = iRefTypesLookup.Lookup(j.RefTypeID));
            }
        }
    

    最后,在我的应用程序启动中,我在容器中获取该接口的所有实例并在它们上调用CreateMappings 方法:

        var mappings = container.GetExportedValues<IMappingCreator>();
    
        foreach (IMappingCreator mc in mappings)
        {
            mc.CreateMappings();
        }
    

    这使得初始设置变得非常容易,因为所有创建都在一个地方进行,并且您可以拥有任意数量的地图创建者(但是,您应该将这些创建者保持在最低限度,可能每个项目左右一次,抓住映射该项目中的特定类型所需的所有服务)。

    【讨论】:

    • 这很好...我可能不得不借用这个! :D MEF 是对框架的一个很好的补充。
    • 随意,我不认为我是唯一遇到这个问题的人。
    【解决方案4】:

    这是最新的做法......

    https://pintoservice.wordpress.com/2016/01/31/dependency-injection-for-automapper-4-2-in-asp-net-vnext-mvc-project/

    虽然我个人在控制器中添加了自动映射,而不是在存储库中。这样,您可以为不同的控制器使用相同的存储库并具有不同的映射。相同的概念,只需将IMapper 注入控制器而不是存储库。

    【讨论】: