在automapper中没有为此对象定义无参数构造函数

时间:2017-11-08 20:56:33

标签: c# asp.net asp.net-core 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;
    }
}

此解析程序尝试获取此模型的Student属性:

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

    public UserResponse Student { get; set; }
}

但是就行了:

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

我明白了:

  

{System.MissingMethodException:没有为此对象定义无参数构造函数。 System.Activator.CreateInstance的System.RuntimeTypeHandle.CreateInstance(RuntimeType类型,Boolean publicOnly,Boolean&amp; canBeCached,RuntimeMethodHandleInternal&amp; ctor)处于System.RuntimeType.CreateInstanceSlow(Boolean publicOnly,Boolean skipCheckThis,Boolean fillCache,StackCrawlMark&amp; stackMark)中的类型类型,Auto NonPublic)在AutoMapper.MappingOperationOptions`2.CreateInstanceT}的System.Activator.CreateInstance(Type type)中。

该表达式中唯一应该创建的类型是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>());
    }
}

布尔解析器类似于:

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;
    }
}

5 个答案:

答案 0 :(得分:7)

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

答案 1 :(得分:4)

很抱歉,自从昨天工作结束后用尽了很长的响应时间。

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

第一个选项使用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

的ConstructService

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

我们遇到了同样的问题,原来这行代码应该是我们启动时的最后一行代码

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

此外,在加载autofac模块时,我们将本地注册移至最后一行,以便它们覆盖nuget软件包中的注册。

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

答案 4 :(得分:0)

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

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

   }
}

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