You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

AutoMapper接口列表映射配置断言失败问题排查与解决

问题背景

需要将SummaryDto映射到Summary,相关类和接口定义如下:

DTO层代码

public class SummaryDto
{
    public List<IOrderDto> Orders { get; init; }
}

public interface IOrderDto
{
    Guid Id { get; init; }
}

public class OnlineOrderDto : IOrderDto
{
    public Guid Id { get; init; }
    public string WebsiteReference { get; init; }
}

public class ShopOrderDto : IOrderDto
{
    public Guid Id { get; init; }
    public string ShopReference { get; init; }
}

实体层代码

public class Summary
{
    public List<IOrder> Orders { get; set; }
}

public interface IOrder
{
    Guid Id { get; set; }
}

public class OnlineOrder : IOrder
{
    public Guid Id { get; set; }
    public string WebsiteReference { get; set; }
}

public class ShopOrder : IOrder
{
    public Guid Id { get; set; }
    public string ShopReference { get; set; }
}

当前AutoMapper Profile配置

public class OrdersProfile : Profile
{
    public OrdersProfile()
    {
        CreateMap<SummaryDto, Summary>();

        CreateMap<ShopOrderDto, ShopOrder>();

        CreateMap<ShopOrderDto, IOrder>()
            .As<ShopOrder>();

        CreateMap<OnlineOrderDto, OnlineOrder>();

        CreateMap<OnlineOrderDto, IOrder>()
            .As<OnlineOrder>();
    }
}

运行时正常工作的代码

var config = new MapperConfiguration(configure => configure.AddProfile<OrdersProfile>());
var mapper = config.CreateMapper();

var dto = new SummaryDto
{
    Orders = new()
    {
        new ShopOrderDto { Id = Guid.NewGuid(), ShopReference = "Random shop" },
        new OnlineOrderDto { Id = Guid.NewGuid(), WebsiteReference = "Random website" }
    }
};

var summary = mapper.Map<Summary>(dto); // 运行正常,summary被正确填充

单元测试中的报错

单元测试代码:

public class MappingTests
{
    [Fact]
    public void Configuration_IsValid()
    {
        // ARRANGE
        var config = new MapperConfiguration(configure => configure.AddProfile<OrdersProfile>());

        // ASSERT
        config.AssertConfigurationIsValid(); // 抛出异常
        // 异常信息:
        // AutoMapper.AutoMapperConfigurationException : The following member on ConsoleAppAutoMapper.Objects.Summary cannot be mapped: 
        //     Orders
        // Add a custom mapping expression, ignore, add a custom resolver, or modify the destination type ConsoleAppAutoMapper.Objects.Summary.
        // Context:
        //    Mapping to member Orders from ConsoleAppAutoMapper.Dtos.SummaryDto to ConsoleAppAutoMapper.Objects.Summary
        // Exception of type 'AutoMapper.AutoMapperConfigurationException' was thrown.
    }
}

问题核心:运行时能识别具体DTO类型并完成映射,但配置验证仅检查IOrderDto到IOrder的接口级映射,当前缺少该配置;直接添加CreateMap<IOrderDto, IOrder>()会破坏原有运行时映射逻辑。


解决方案

可以通过两种方式修改Profile,既满足配置验证要求,又不影响运行时映射:

方式一:使用ConstructUsing处理类型转换

为接口间映射添加自定义构造逻辑,根据具体DTO类型返回对应实体实例:

public class OrdersProfile : Profile
{
    public OrdersProfile()
    {
        CreateMap<SummaryDto, Summary>();

        // 具体DTO到具体实体的映射
        CreateMap<ShopOrderDto, ShopOrder>();
        CreateMap<OnlineOrderDto, OnlineOrder>();

        // 接口到接口的映射,通过类型判断处理转换
        CreateMap<IOrderDto, IOrder>()
            .ConstructUsing((dto, context) => dto switch
            {
                ShopOrderDto shopDto => context.Mapper.Map<ShopOrder>(shopDto),
                OnlineOrderDto onlineDto => context.Mapper.Map<OnlineOrder>(onlineDto),
                _ => throw new NotSupportedException($"不支持的IOrderDto类型:{dto.GetType()}")
            });

        // 保留具体DTO到接口的映射(适配直接映射具体DTO到IOrder的场景)
        CreateMap<ShopOrderDto, IOrder>().As<ShopOrder>();
        CreateMap<OnlineOrderDto, IOrder>().As<OnlineOrder>();
    }
}

方式二:使用Include关联具体类型映射

通过Include方法将具体类型的映射关联到接口映射中,让AutoMapper自动识别实现类:

public class OrdersProfile : Profile
{
    public OrdersProfile()
    {
        CreateMap<SummaryDto, Summary>();

        // 定义接口到接口的映射,并关联具体类型的映射规则
        CreateMap<IOrderDto, IOrder>()
            .Include<ShopOrderDto, ShopOrder>()
            .Include<OnlineOrderDto, OnlineOrder>();

        // 具体DTO到具体实体的映射
        CreateMap<ShopOrderDto, ShopOrder>();
        CreateMap<OnlineOrderDto, OnlineOrder>();

        // 具体DTO到接口的映射
        CreateMap<ShopOrderDto, IOrder>().As<ShopOrder>();
        CreateMap<OnlineOrderDto, IOrder>().As<OnlineOrder>();
    }
}

两种方案均可让config.AssertConfigurationIsValid()通过验证,同时保持运行时的正确映射逻辑。


内容的提问来源于stack exchange,提问作者Arthur Rey

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 09:45:25