Подтвердить что ты не робот

Как вставить AutoMapper IMappingEngine с помощью StructureMap

Большинство примеров, которые я нашел для Automapper, используют статический объект Mapper для управления сопоставлениями типов. Для моего проекта мне нужно ввести IMapperEngine как часть построения объекта с помощью StructureMap, чтобы мы могли издеваться над компоновщиком в модульных тестах, чтобы мы не могли использовать статический mapper. Мне также необходимо поддерживать настройку профилей AutoMapper.

Мой вопрос в том, как настроить реестр StructureMap, чтобы он мог предоставить экземпляр IMappingEngine, когда будет создан экземпляр MyService.

Вот подпись конструктора службы:

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>();
    }
}
4b9b3361

Ответ 1

Класс Mapper имеет статическое свойство Mapper.Engine. Используйте это, чтобы зарегистрировать двигатель с контейнером:

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

Если вам нужно загрузить свои профили, прежде чем вводить двигатель, я бы вставлял этот код конфигурации вместе с вышеприведенным фрагментом.


Обновление

Ваш пользовательский реестр будет выглядеть следующим образом

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 для создания экземпляра mapper.

в новой версии (4.2.0 > =) мы должны провести и передать IMapper через DI.

простая служба настройки должна быть такой (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


update:
Выпущено AutoMapper 4.2.1 - Static возвращается

После немного обратной связи и поиска души и честно устали с вопросами, некоторые статические API восстанавливаются в этом выпуск. Теперь вы можете (и в будущем) использовать Mapper.Initialize и Mapper.Map

Ответ 3

Вот что я закончил, так как не мог понять, как настроить конфигурацию на Mapper.Engine и передать ее в For().

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