簡體   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