繁体   English   中英

automapper 中没有为此 object 定义无参数构造函数

[英]No parameterless constructor defined for this object in automapper

问题

我有以下值解析器:

public class StudentResolver : IValueResolver<Lesson, LessonResponse, UserResponse>
{
    private readonly ApplicationDbContext _dbContext;

    public StudentResolver(ApplicationDbContext dbContext)
    {
        _dbContext = dbContext;
    }
    
    public UserResponse Resolve(
        Lesson lesson, 
        LessonResponse response, 
        UserResponse member, 
        ResolutionContext context)
    {
        var user = _dbContext.Users
            .Where(x => x.Id == lesson.StudentId)
            .FirstOrDefault();
        if (user == null)
            return null;
        var result = Mapper.Map<UserResponse>(user); // this line triggers a "no parameterless constructor", why?
        return result;
    }
}

此解析器尝试获取此 model 的Student属性:

public class LessonResponse
{
    public string Id { get; set; }

    public UserResponse Student { get; set; }
}

但是在线:

var result = Mapper.Map<UserResponse>(user);

我得到:

{System.MissingMethodException: No parameterless constructor defined for this object. at System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor) at System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache, StackCrawlMark& stackMark ) 在 System.Activator.CreateInstance(Type type, Boolean nonPublic) 在 System.Activator.CreateInstance(Type type) 在 AutoMapper.MappingOperationOptions`2.CreateInstanceT}

该表达式中唯一应该创建的类型是UserResponse ,其定义如下:

public class UserResponse
{
    public string Id { get; set; }
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string FullName { get; set; }
    public string UserName { get; set; }
    public string Email { get; set; }
    public string PhoneNumber { get; set; }
    public string Picture { get; set; }
    public string X { get; set; }

    public bool IsAdmin { get; set; }
    public bool IsClient { get; set; }
    public bool IsInstructor { get; set; }
}

但它是可构造的,那么我做错了什么?


额外的

映射配置文件如下:

public class MappingProfile : Profile 
{
    public MappingProfile() {
        CreateMap<Lesson, LessonResponse>()                
            .ForMember(
                dest => dest.Student,
                opts => opts.ResolveUsing<StudentResolver>());

    }
}

用户的映射是:

public class MappingProfile : Profile 
{
    public MappingProfile() {
        CreateMap<ApplicationUser, UserResponse>()
            .ForMember(
                dest => dest.FullName, 
                opts => opts.MapFrom(
                    origin => origin.FirstName + " " + origin.LastName))
            .ForMember(
                dest => dest.IsAdmin,
                opts => opts.ResolveUsing<IsAdminResolver>())
            .ForMember(
                dest => dest.IsInstructor,
                opts => opts.ResolveUsing<IsInstructorResolver>())
            .ForMember(
                dest => dest.IsClient,
                opts => opts.ResolveUsing<IsClientResolver>());
    }
}

boolean 解析器都类似于:

public class IsAdminResolver : IValueResolver<ApplicationUser, UserResponse, bool>
{
    private readonly UserManager<ApplicationUser> _userManager;

    public IsAdminResolver(UserManager<ApplicationUser> userManager)
    {
        _userManager = userManager;
    }
    
    public bool Resolve(ApplicationUser user, UserResponse response, bool member, ResolutionContext context)
    {
        return _userManager.IsInRoleAsync(user, "Admin").Result;
    }
}

由于我的疏忽,我遇到了同样的问题......我通过 Visual Studio 快速提示默认构造函数为从Profile继承的类生成,该类是protected而不是public 可能这会对某人有所帮助,因为我花了几个小时才弄清楚

抱歉昨天下班后回复时间过长。

我能够复制你的问题。 您有 2 个选择:

第一个选项来解决您的StudentResolver与你DbContext

CreateMap<Lesson, LessonResponse>()
            .ForMember(
                dest => dest.Student,
                opts => opts.ResolveUsing(new StudentResolver(ApplicationDbContext.Create())));

第二个选项,配置您的映射器配置ConstructServicesUsing 就我而言,我使用 Simple Injector 来测试。

Mapper.Initialize(cfg =>
        {
            cfg.ConstructServicesUsing(type => container.GetInstance(typeof(StudentResolver)));
            cfg.AddProfile<MappingProfile>();
        });

对于我的测试,我收到了一个错误抛出var lessonResponse = Mapper.Map<LessonResponse>(lesson);

所以如果你被抛出Mapper.Map<UserResponse>(user); 您可能必须为IsAdminResolverIsInstructorResolverIsClientResolver

如果其他人做了和我一样的事情,这就是我的问题:

public sealed class MyProfile : Profile
{
    MyProfile()
    {
        // Configuration
    }
}

如您所见,我忘记将构造函数标记为public 一旦我将其标记为公开,一切正常。

我们遇到了同样的问题,结果这行代码应该是我们启动中的最后一行代码

services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

此外,在加载 autofac 模块时,我们将本地注册移到最后几行,以便它们覆盖来自 nuget 包的那些。

请注意,删除构造函数不是解决方案,因此请尝试解决上述依赖项注入问题。

就我而言,我有以下映射器:

public class Mapper : Profile
{
   public Mapper(IConfiguration configuration)
   {

   }
}

修复是从构造函数中删除配置参数(从而使其成为无参数构造函数)。

启动 - 配置服务

services.AddAutoMapper(x=> x.AddProfile(new
MappingProfile(dependencyAlredyDefinedBefore) ));

映射配置文件 class

DependencyClass readonly dependency;

//Constructor as usual
public MappingProfile(DependencyClass dependency)
{
    this.dependency = dependency;
    //Configure maps using dependency...
}

我在AutoMapper 11.0.1AutoMapper.Extensions.Microsoft.DependencyInjection 11.0.0 中也遇到了这个问题。

似乎如果为包含没有 No-Args 构造函数的Profile派生 class 的程序集启用程序集扫描,则 AutoMapper 会尝试实例化它,即使是显式注册也是如此。 对我有用的是通过提供一个空数组来匹配正确的重载来禁用该存储库的类型扫描。 TypeAssembly的空数组都可以使用。

假设您的依赖ApplicationDbContext可通过 .NET 核心依赖注入获得,那么您可以在AutoMapper.Extensions.Microsoft.DependencyInjection中使用IServiceCollection扩展方法的重载,该方法接受Action<IServiceProvider,AutoMapper.IMapperConfigurationExpression>params Type[]params Assembly[] arguments 在构建 DI 容器时实例化您的配置文件 class。

这样做的缺点是因为需要禁用扫描,该程序集中的所有配置文件类现在都需要显式注册,包括无参数的。 这对我来说似乎是一个错误,因为我希望显式实例化对一个类型比通用扫描更受青睐,但是在实现中可能存在一个时序组件,这会使实现变得困难。

        return services.AddAutoMapper((serviceProvider, mapperConfiguration) =>
            {
                mapperConfiguration.AddProfile(new MappingProfile(serviceProvider.GetRequiredService<ApplicationDbContext>()));
            },
            Array.Empty<Type>()
        );

在我的项目中,我有多个 class 库,其中一个库中有 AutoMapperProfile 文件。 我将它移到我的启动项目中并且它起作用了。 另一种解决方案是在启动时启用自动映射器,如下所示:

            builder.Services.AddAutoMapper(AppDomain.CurrentDomain.GetAssemblies());

那么您的配置文件可以位于项目中的任何位置。

我的建议是使用 Mapster 而不是 AutoMapper,因为 Mapster 有很多好处:)

但你的问题的答案:

向 class 添加一个无参数的构造函数

像这样:

public class MappingProfile : Profile
{
    public MappingProfile()
    {

    }
    public MappingProfile(AnyParameter)
    {
        //do config with input parameter
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM