【问题标题】:How to inject AutoMapper IMappingEngine with StructureMap如何使用 StructureMap 注入 AutoMapper IMappingEngine
【发布时间】:2012-09-26 15:11:52
【问题描述】:

我为Automapper 找到的大多数示例都使用静态 Mapper 对象来管理类型映射。对于我的项目,我需要注入一个 IMapperEngine 作为使用 StructureMap 的对象构造的一部分,以便我们可以在单元测试中模拟映射器,因此我们不能使用静态映射器。我还需要支持配置 AutoMapper Profiles。

我的问题是如何配置 StructureMap 注册表,以便在构造 MyService 实例时它可以提供 IMappingEngine 实例。

这是服务构造函数签名:

public MyService(IMappingEngine mapper, IMyRepository myRepository, ILogger logger)

这里是 StructureMap 注册表

public class MyRegistry : StructureMap.Configuration.DSL.Registry
{
    public MyRegistry()
    {
        For<IMyRepository>().Use<MyRepository>();
        For<ILogger>().Use<Logger>();
        //what to do for IMappingEngine?
    }
}

还有我要加载的配置文件

public class MyAutoMapperProfile : AutoMapper.Profile
{
    protected override void Configure()
    {
        this.CreateMap<MyModel, MyDTO>();
    }
}

【问题讨论】:

  • @Sebastian,感谢您编辑美化代码。不知道该怎么做。

标签: dependency-injection automapper structuremap


【解决方案1】:

Mapper 类有一个静态属性 Mapper.Engine。使用它向容器注册引擎:

For<IMappingEngine>().Use(() => Mapper.Engine);

如果您需要在注入引擎之前加载配置文件,我会将该配置代码与上述 sn-p 一起插入。


更新

您的自定义注册表如下所示

class MyRegistry : Registry
{
  public MyRegistry()
  {
    For<IMyRepository>().Use<MyRepository>();
    For<ILogger>().Use<Logger>();

    Mapper.AddProfile(new AutoMapperProfile());
    For<IMappingEngine>().Use(() => Mapper.Engine);
  }
}

此代码在您的引导程序中运行一次,然后任何类型为 IMappingEngine 的依赖项都将使用静态属性 Mapper.Engine 的值提供服务,该属性使用您的自定义 AutoMapperProfile 配置。

【讨论】:

  • 为我工作。不敢相信我浪费了这么多时间来解决这个问题。
【解决方案2】:

静态 API 将在 5.0 版中移除。 使用 MapperConfiguration 实例并根据需要静态存储。采用 CreateMapper 创建一个映射器实例。

在新版本 (4.2.0 >=) 中,我们应该持有并通过 DI 传递 IMapper

一个简单的配置服务应该是这样的(ASP.NET Core)

services.AddSingleton<IMapper>(_ => new MapperConfiguration(cfg =>
            {
                cfg.CreateMap<Foo,Bar>();
            })
            .CreateMapper());

和我们的服务层(在构造函数注入的帮助下):

public class CrudService<TDocument> : ICrudService<TDocument>
    {
        private readonly IMapper _internalMapper;
        private readonly IRepository<TDocument> _repository;

        public CrudService(IRepository<TDocument> repository, IMapper mapper)                
        {
            _internalMapper = mapper;
            _repository = repository;
        }

        public virtual ServiceResult<string> Create<TModel>(TModel foo)
        {
            var bar = _internalMapper.Map<TDocument>(foo);

            try
            {
                _repository.Create(bar);
            }
            catch (Exception ex)
            {
                return ServiceResult<string>.Exception(ex);
            }

            return ServiceResult<string>.Okay(entity.Id);
        }
}

consider TDocument as Bar, and TModel as Foo


更新
AutoMapper 4.2.1 发布 - 静态回归

经过一些反馈和自我反省,真的厌倦了 处理问题,部分静态API在此还原 释放。您现在(以及将来)可以使用 Mapper.Initialize 和 映射器.Map

【讨论】:

    【解决方案3】:

    我写了一篇博文,展示了我的 AutoMapper 和 StructureMap 设置。我为 AutoMapper 3.1.0(也适用于 3.1.1)和 3.0.0 和 2.2.1 创建了特定的注册表。

    http://www.martijnburgers.net/post/2013/12/20/My-AutoMapper-setup-for-StructureMap.aspx

    【讨论】:

    【解决方案4】:

    这就是我最终得到的结果,因为我不知道如何在 Mapper.Engine 上设置配置并将其传递给 For().Use。

    public MyRegistry()
    {
        For<IMyRepository>().Use<MyRepository>();
        For<ILogger>().Use<Logger>();
    
        //type mapping
        For<ConfigurationStore>()
            .Singleton()
            .Use(ctx =>
            {
                ITypeMapFactory factory = ctx.GetInstance<ITypeMapFactory>();
                ConfigurationStore store 
                    = new ConfigurationStore(factory, MapperRegistry.AllMappers());
                IConfiguration cfg = store;
                cfg.AddProfile<MyAutoMapperProfile>();
                store.AssertConfigurationIsValid();
                return store;
            });
        For<IConfigurationProvider>().Use(ctx => ctx.GetInstance<ConfigurationStore>());
        For<IConfiguration>().Use(ctx => ctx.GetInstance<ConfigurationStore>());
        For<IMappingEngine>().Singleton().Use<MappingEngine>();
        For<ITypeMapFactory>().Use<TypeMapFactory>();
    }
    

    【讨论】:

    • Mapper.AddProfile() 呢?
    • Sebastian,我试图避免使用静态 Mapper 对象,但如果我按照您的思路,这会是配置吗? For&lt;IMappingEngine&gt;() .Use(ctx =&gt; { IConfiguration c = Mapper.Configuration; c.AddProfile&lt;MyAutoMapperProfile&gt;(); IMappingEngine e = Mapper.Engine; return e; });
    • 不完全。这意味着只要组件需要IMappingEngine 类型的依赖项,您就可以添加您的配置文件。请参阅我之前的答案的更新,了解我想到的代码。
    • @JayWalker MappingEngine 实现了IDisposable 所以一定要处理掉它们!
    • @JayWalker 有很多选择。将其声明为单例,因此处理它的需要变得更小,因为您只创建了 1 个实例,因此需要清理的东西更少。在我的例子中,一个 ASP.NET MVC 应用程序,当整个应用程序池死掉时,该实例就死了,这对我来说已经足够好了,特别是因为 dispose 没有对非托管资源的钩子。如果你使用 ASP.NET,你可以使用ReleaseAndDisposeAllHttpScopedObjects 或者你可以使用nested container
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多