Меня смущает степень использования Autofac с Automapper для отображения объектов. Я прочитал довольно много материала в Интернете об интеграции двух пакетов, но почти все, кажется, сосредоточены на том, как создавать экземпляры IMapper из профилей Automapper, используя код, похожий на этот, который определяет модуль Autofac (CSContainer. статический экземпляр IContainer от Autofac):
public class AutoMapperModule : Module
{
private static object ServiceConstructor( Type type )
{
return CSContainer.Instance.Resolve( type );
}
protected override void Load( ContainerBuilder builder )
{
base.Load( builder );
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyTypes( assemblies )
.Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
.As<Profile>();
builder.Register( c => new MapperConfiguration( cfg =>
{
cfg.ConstructServicesUsing( ServiceConstructor );
foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
{
cfg.AddProfile( profile );
}
} ) )
.AsSelf()
.AutoActivate()
.SingleInstance();
builder.Register( c => c.Resolve<MapperConfiguration>().CreateMapper( c.Resolve ) )
.As<IMapper>()
.SingleInstance();
}
}
(см. http://www.protomatter.co.uk/blog/development/2017/02/modular-automapper-registrations-with-autofac/ для объяснения этого подхода)
Я бы хотел, чтобы Automapper вызывал Autofac для создания объектов. Прямо сейчас единственный способ, которым я могу это сделать - это сделать что-то вроде этого:
CreateMap ()
.ConstructUsing (src => CSContainer.Instance.Resolve ());
Это работает, но кажется глупым. Было бы лучше, если бы Automapper попытался выяснить, как автоматически разрешать экземпляры, используя Autofac, за кулисами.
Я подумал, что что-то вроде этого может помочь (это модифицированная версия того первого модуля Autofac, который я цитировал выше):
public class AutoMapperModule : Module
{
protected override void Load( ContainerBuilder builder )
{
base.Load( builder );
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyTypes( assemblies )
.Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
.As<Profile>();
builder.Register( c => new MapperConfiguration( cfg =>
{
cfg.ForAllMaps( ( map, opts ) =>
opts.ConstructUsing( ( x, y ) => CSContainer.Instance.Resolve(map.DestinationType) ) );
foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
{
cfg.AddProfile( profile );
}
} ) )
.AsSelf()
.AutoActivate()
.SingleInstance();
builder.Register( c => c.Resolve<MapperConfiguration>().CreateMapper( c.Resolve ) )
.As<IMapper>()
.SingleInstance();
}
но это привело к тому, что Autofac выдал исключение, пожаловавшись на то, что я пытался повторно использовать уже созданный конструктор (извините, точная формулировка у меня не под рукой).
Можно ли интегрировать Automapper и Autofac, чтобы Automapper разрешал новые экземпляры через Autofac? Если да, то как лучше это сделать?
Дополнительная информация
Итак, я реализовал предложенный ответ следующим образом:
protected override void Load( ContainerBuilder builder )
{
base.Load( builder );
var assemblies = AppDomain.CurrentDomain.GetAssemblies();
builder.RegisterAssemblyTypes( assemblies )
.Where( t => typeof(Profile).IsAssignableFrom( t ) && !t.IsAbstract && t.IsPublic )
.As<Profile>();
builder.Register( c => new MapperConfiguration( cfg =>
{
cfg.ConstructServicesUsing( ServiceConstructor );
foreach( var profile in c.Resolve<IEnumerable<Profile>>() )
{
cfg.AddProfile( profile );
}
} ) )
.AsSelf()
.AutoActivate()
.SingleInstance();
builder.Register( c =>
{
// these are the changed lines
var scope = c.Resolve<ILifetimeScope>();
return new Mapper(c.Resolve<MapperConfiguration>(), scope.Resolve );
} )
.As<IMapper>()
.SingleInstance();
}
Но это приводит к исключению Automapper, поскольку жалоба на объект, который я пытаюсь создать с помощью вызова Map (), должна иметь нулевые аргументы или только необязательные аргументы. Все же все аргументы конструктора объекта также зарегистрированы в Autofac, и у него нет проблем с созданием экземпляров объектов в другом месте моего кода. Просто когда Automapper пытается создать экземпляр, все идет наперекосяк.