Я решил создать один профиль AutoMapper для каждой сущности домена, как показано ниже, оставив только конструктор без параметров, поскольку я хочу установить имя профиля.
Примечание: этот код находится в сборке A.
Код: Выделить всё
public partial class DoctorsMappingProfile : Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
// Code of mapping removed because it is not part of the problem
}
#endregion Constructors
}
Примечание 1: этот код находится в сборке B, которая ссылается на сборку A.
Примечание 2: я выполняю сканирование зарегистрированных сборок, затем передаю в качестве параметра массив отсканированных сборок в метод RegisterAssemblyTypes ContainerBuilder
Код: Выделить всё
public partial class Startup
{
#region Methods
public void ConfigureAutoFacContainer(IAppBuilder app)
{
var builder = new ContainerBuilder();
builder.RegisterControllers(typeof(MvcApplication).Assembly);
builder.RegisterFilterProvider();
builder.RegisterSource(new ViewRegistrationSource());
// TODO: Logger!
var assemblies = BuildManager.GetReferencedAssemblies().Cast().ToArray();
this.ConfigureAutoMapper(builder, assemblies);
// TODO: Modules!
var container = builder.Build();
DependencyResolver.SetResolver(new AutofacDependencyResolver(container));
app.UseAutofacMiddleware(container);
app.UseAutofacMvc();
}
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As
(); //.UsingConstructor(typeof(string));
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve()
.CreateMapper(ctx.Resolve))
.As()
.InstancePerLifetimeScope();
}
#endregion Methods
}
Autofac.Core.DependencyResolutionException
Ни один из конструкторов не найден с помощью «Autofac.Core.Activators.Reflection.DefaultConstructorFinder» для типа «AutoMapper.Configuration.MapperConfigurationExpression+NamedProfile» может быть вызван с доступными службами и параметрами: невозможно разрешить параметр «System.String ProfileName» конструктора «Void .ctor(System.String, System.Action`1[AutoMapper.IProfileExpression])».
строка ошибки — это цикл foreach, когда контекст пытается разрешить профиль:
Код: Выделить всё
foreach (var profile in ctx.Resolve())
Код: Выделить всё
protected Profile(string profileName, Action configurationAction)
{
}
Код: Выделить всё
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As
().UsingConstructor();
Решения/обходные пути, которые я нашел:
- Если я заменю класс Profile на свой DoctorsMappingProfile в методе ConfigureAutoMapper, это работает, но это приведет к аннулированию сканирования сборки для профилей.
Наконец, мне удалось создать базовый абстрактный класс, унаследованный от AutoMapper.Profile, и ссылаясь на него в моем методе ConfigureAutoMapper класса Startup. Таким образом, я могу выполнять сканирование сборки для потомков этого класса...
Примечание: этот код написан на ассемблере C
Код: Выделить всё
public abstract class G2AutoMapperProfile : Profile
{
#region Constructors
protected G2AutoMapperProfile()
{
}
protected G2AutoMapperProfile(string profileName) : base(profileName)
{
}
#endregion Constructors
}
Код: Выделить всё
public partial class DoctorsMappingProfile : G2AutoMapperProfile //Profile
{
#region Constructors
public DoctorsMappingProfile() : base(typeof(DoctorsMappingProfile).FullName)
{
//removed because it is not part of the problem
}
#endregion Constructors
}
Код: Выделить всё
private void ConfigureAutoMapper(ContainerBuilder builder, Assembly[] registeredAssemblies)
{
//register your profiles, or skip this if you don't want them in your container
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(G2AutoMapperProfile)).As();
//register your configuration as a single instance
builder.Register(ctx => new MapperConfiguration(cfg =>
{
//add your profiles (either resolve from container or however else you acquire them)
foreach (var profile in ctx.Resolve())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve()
.CreateMapper(ctx.Resolve))
.As()
.InstancePerLifetimeScope();
}