Ответ 1
Это будет эквивалент:
container.RegisterSingleton<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
Обновлен до AutoMapper 4.2.0 и следуйте приведенному ниже руководству по миграции: https://github.com/AutoMapper/AutoMapper/wiki/Migrating-from-static-API/f4784dac61b91a0df130e252c91a0efd76ff51de#preserving-static-feel. Попытка перевести код на этой странице для StructureMap в Simple Injector. Может ли кто-нибудь показать мне, как выглядит этот код в Simple Injector?
StructureMap
public class AutoMapperRegistry : Registry
{
public AutoMapperRegistry()
{
var profiles =
from t in typeof (AutoMapperRegistry).Assembly.GetTypes()
where typeof (Profile).IsAssignableFrom(t)
select (Profile)Activator.CreateInstance(t);
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(profile);
}
});
For<MapperConfiguration>().Use(config);
For<IMapper>().Use(ctx => ctx.GetInstance<MapperConfiguration>().CreateMapper(ctx.GetInstance));
}
}
Простой инжектор
?
Это будет эквивалент:
container.RegisterSingleton<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
Интерфейс Simple Injector IPackage выглядит как ближайший эквивалент типа StructureMap Registry. Здесь используется пакет, построенный из @Steven answer:
using System;
using System.Linq;
using System.Reflection;
//
using AutoMapper;
//
using SimpleInjector;
using SimpleInjector.Packaging;
public class AutoMapperPackage : IPackage
{
public void RegisterServices(Container container)
{
var profiles = Assembly.GetExecutingAssembly()
.GetTypes()
.Where(x => typeof(AutoMapper.Profile).IsAssignableFrom(x));
var config = new MapperConfiguration(cfg =>
{
foreach (var profile in profiles)
{
cfg.AddProfile(Activator.CreateInstance(profile) as AutoMapper.Profile);
}
});
container.RegisterSingleton<MapperConfiguration>(config);
container.Register<IMapper>(() => config.CreateMapper(container.GetInstance));
}
}
Вам нужно будет добавить пакет SimpleInjector.Packaging, а затем добавить вызов container.RegisterPackages();
в ваш код начальной загрузки/конфигурации.
По сути, единственное, что действительно меняется из StructureMap, это две последние строки.
Для сопоставления нескольких IMapper с различными объектами MapperConfiguration, которые кажутся несколько повторяющейся проблемой, я рекомендую следующий подход, который даже не требует рефакторинга вызовов метода mapper:
1) Создайте общую оболочку вокруг интерфейса IMapper. Эта оболочка может быть либо интерфейсом, либо классом, но, очевидно, в конечном итоге вам нужно реализовать свою оболочку, поэтому я покажу конкретный класс ниже. Попросите этот обертку реализовать (или наследовать, если вы выбрали интерфейс) интерфейс IMapper, например:
public class ProfileMapper<TProfile> : IMapper where TProfile : Profile
{
private IMapper mapper;
private Profile profile;
public ProfileMapper(TProfile profile)
{
this.profile = profile;
this.mapper = new MapperConfiguration( cfg => cfg.AddProfile( this.profile ) )
.CreateMapper();
}
}
Общий аргумент должен быть подклассом "Профиль", потому что из этого профиля вы получите конфигурацию вашего картографа.
2) В этом классе реализуйте интерфейс IMapper просто перенаправлением вызовов на частный экземпляр IMapper, который вы создаете в конструкторе, например:
public TDestination Map<TDestination>(object source)
{
return mapper.Map<TDestination>( source );
}
3) Теперь вам нужно зарегистрировать в Simple Injector частично закрытый экземпляр этого класса ProfileMapper для каждого вашего профиля. Вы делаете это сначала, получая все классы, которые наследуют от профиля, затем создавая этот частично закрытый экземпляр, а затем регистрируя его. Существует несколько способов получить все классы профиля, но я пошел с этим:
IEnumerable<Type> profileRegistrations =
from type in profileAssembly.GetExportedTypes()
where type.Namespace == "Namespace.Of.My.Profiles"
where type.BaseType.Equals( typeof( Profile ) )
select type;
foreach (Type profileType in profileRegistrations)
{
Container.RegisterSingleton( profileType, profileType );
Type mapperClosedType = typeof( ProfileMapper<> ).MakeGenericType( profileType );
Container.RegisterSingleton( typeof( ProfileMapper<> ), mapperClosedType );
}
Этот код сначала получает все типы, которые наследуются от профиля, расположенного в указанном пространстве имен. Затем для каждого профиля я регистрирую его с помощью SimpleInjector (не обязательно, поскольку они являются конкретными типами и как таковые могут быть созданы контейнером "на лету" ), тогда я делаю частично закрытый экземпляр класса ProfileWrapper с текущим Профиль как общий аргумент, а затем, наконец, я зарегистрирую свой закрытый экземпляр как Singleton. Таким образом, вы можете создавать новые профили без необходимости вручную регистрировать новые Wrappers.
И что это. Теперь вместо того, чтобы вписываться в IMapper и вводить его, вы вводите свой профиль ProfileWrapper профилем, который хотите использовать, например:
ProfileMapper<ApplicationProfile> appProfileMapper;
ProfileMapper<MvcProfile> mvcProfileMapper;
ProfileMapper<GuestProfile> guestProfile;
и т.д. Каждый Wrapper был создан с использованием отдельной MapperConfiguration с использованием разных профилей. Поскольку обертка реализует IMapper, весь ваш код сопоставления остается прежним. Нет необходимости рефакторировать вызовы метода, просто типы зависимостей.
Если вы создаете BaseProfile, просто измените общий параметр в ProfileMapper, чтобы принимать только экземпляры для этого базового файла.