Как вставить 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>();
}
}
Ответы
Ответ 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>();
}
Ответ 4
Я написал сообщение в блоге, в котором показан мой 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