我正在配置AutoMapper,以使用Autofac 4.3,Autofac.Owin 4,Autofac.Mvc5 4,AutoFac.Mvc5.Owin 4和AutoMapper 5.2在Asp.Net MVC5应用程序中将域对象映射到视图模型。
我确实决定为每个域实体创建一个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
}
要注册AutoMapper,我关注的个人资料this和this指南会很好地解释用户mpetito there,并且用户已经检查here。我在Startup分部类中的代码是这样的:
注1:此代码在程序集B中引用程序集A.
注意2:我对已注册的装配体进行装配扫描,然后将扫描装配数组作为参数传递给ContainerBuilder的方法 RegisterAssemblyTypes
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<Assembly>().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<Profile>(); //.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<IEnumerable<Profile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
#endregion Methods
}
当de application运行并尝试解析配置文件时,会发生以下异常:
Autofac.Core.DependencyResolutionException 使用可用的服务和参数可以调用在'AutoMapper.Configuration.MapperConfigurationExpression + NamedProfile'类型上找到'Autofac.Core.Activators.Reflection.DefaultConstructorFinder'的构造函数:无法解析构造函数的参数'System.String profileName' Void .ctor(System.String,System.Action`1 [AutoMapper.IProfileExpression])'。
当上下文尝试解析配置文件时,错误行是 foreach循环:
foreach (var profile in ctx.Resolve<IEnumerable<Profile>>())
我相信它是由于Autofac默认构造函数的位置约定,它正在寻找具有大多数参数的构造函数,这是在AutoMapper.Profile类的情况下:
protected Profile(string profileName, Action<IProfileExpression> configurationAction)
{
}
为了解决这个问题,我替换了查找配置文件的行,这是 ConfigureAutoMapper 中的第一行代码,强制它使用没有参数的构造函数:
builder.RegisterAssemblyTypes(registeredAssemblies).AssignableTo(typeof(Profile)).As<Profile>().UsingConstructor();
但仍然不起作用。
解决方案/解决方法我找到了:
如果我在方法 ConfigureAutoMapper 中用我的 DoctorsMappingProfile 替换了个人资料这个类,那么它可以正常工作,但这样做会使程序集扫描无效轮廓。
注意:此代码在Assembly C
中public abstract class G2AutoMapperProfile : Profile
{
#region Constructors
protected G2AutoMapperProfile()
{
}
protected G2AutoMapperProfile(string profileName) : base(profileName)
{
}
#endregion Constructors
}
注意:此代码在程序集A
中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
}
最后,这是程序集B中 ConfigureAutoMapper 的代码,有效:
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<G2AutoMapperProfile>();
//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<IEnumerable<G2AutoMapperProfile>>())
{
cfg.AddProfile(profile);
}
})).AsSelf().SingleInstance();
//register your mapper
builder.Register(ctx => ctx.Resolve<MapperConfiguration>()
.CreateMapper(ctx.Resolve))
.As<IMapper>()
.InstancePerLifetimeScope();
}
...但我仍然不明白为什么原始代码对我不起作用。
答案 0 :(得分:0)
首先,您无需在Profile
中明确调用DoctorsMappingProfile
的受保护构造函数。原因是您传递的profileName
是AutoMapper默认使用的builder
.RegisterAssemblyTypes(registeredAssemblies)
.AssignableTo(typeof(Profile))
.As<Profile>()
.UsingConstructor(typeof(string));
,因为我们可以看到here。
此外,关于尝试在Autofac容器中注册配置文件的第一种方式:
Profile
这意味着您明确要求Autofac使用具有一个string
类型参数的构造函数来创建string
类的实例。问题是Autofac不知道它必须在构造函数中使用UsingConstructor
。
这也是错误的,因为你创建了一个无参数构造函数,而后者又调用参数化构造函数。
我不确定在没有参数的情况下调用Profile
是什么,但在我看来,你最好离开Autofac为你选择最好的构造函数,特别是当defaut参数少的是一个你想要它使用。
通过查看您提供的解决方案/解决方法,我的感觉得到了加强。你实际做的是:
string
所具有的基类,即默认的无参数构造函数和带UsingConstructor
的构造函数Profile
所以我很确定通过:
UsingConstructor
继承List<Evaluator>
你应该没事。