【发布时间】:2017-06-14 03:13:38
【问题描述】:
我正在使用 Autofac 4.3、Autofac.Owin 4、Autofac.Mvc5 4、AutoFac.Mvc5.Owin 4 和 AutoMapper 5.2 在 Asp.Net MVC5 应用程序中配置 AutoMapper 以将域对象从/映射到视图模型对象。
我确实决定为每个域实体创建一个 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:此代码在引用程序集 A 的程序集 B 中。
注意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 应用程序运行并尝试解析配置文件时,会发生以下异常:
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 替换类 Profile,它会起作用,但这样做会使程序集扫描配置文件无效。
- 最后我通过创建一个继承自 AutoMapper.Profile 的基本抽象类并在 Startup 类的 ConfigureAutoMapper 方法中引用它来管理它,这样我可以对该类的后代执行程序集扫描...
注意:此代码在汇编 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();
}
...但我仍然不明白为什么原始代码不适合我。
【问题讨论】:
标签: c# asp.net-mvc-5 owin automapper autofac