自动映射器不使用NetMap 2.2上的三元和计算值的.MapFrom

问题描述 投票:2回答:2

我用的;

AutoMapper.Extensions.Microsoft.DependencyInjection 6.0.0

在一个web api项目中运行net core 2.2

在映射我的DTO对象时,我使用Automapper来映射几个字段;

public class AutoMapperProfile : AutoMapper.Profile
{
    public AutoMapperProfile()
    {     
        CreateMap<ReviewPostInputModel, Review>()
            .ForMember(x => x.ReceiveThirdPartyUpdates, opt => opt.MapFrom(src => src.ReceiveThirdPartyUpdates ? (DateTime?)DateTime.UtcNow : null))
            .ForMember(x => x.ReceiveUpdates, opt => opt.MapFrom(src => src.ReceiveUpdates ? (DateTime?)DateTime.UtcNow : null))
            .ForMember(x => x.AverageScore, opt => opt.MapFrom(src => (decimal)Math.Round((src.Courtsey + src.Reliability + src.Tidiness + src.Workmanship) / 4, 2)));
        // ...
    }
}

哪里;

using System;
using System.Collections.Generic;
using System.Text;

public class Review 
{
    // ...

    public decimal Reliability { get; set; }
    public decimal Tidiness { get; set; }
    public decimal Courtsey { get; set; }
    public decimal Workmanship { get; set; }

    public decimal AverageScore { get; set; }
    public DateTime? ReceiveUpdates { get; set; }
    public DateTime? ReceiveThirdPartyUpdates { get; set; }
} 

但是,当我尝试使用地图时;

var review = _mapper.Map<Review>(model);

所有标准成员都映射到上面列出的my ForMember,其中DateTimes设置为DateTime的新实例,Averagescore设置为0。

为了完整性,我将映射器放入我的控制器中,如下所示;

private readonly IMapper _mapper;

public ReviewController( IMapper mapper)
{
    _mapper = mapper;
}

我在StartUp.cs中配置Automapper如下;

services.AddAutoMapper();

我还尝试向控制器添加一个测试,以确认输入的值不是问题(在映射之后完成并且可以确认该值已正确更新);

review.AverageScore = (decimal)Math.Round((model.Courtsey + model.Reliability + model.Tidiness + model.Workmanship) / 4, 2);

有没有人有任何想法为什么会这样?

c# automapper
2个回答
0
投票

你需要使用“ResolveUsing”而不是“MapFrom”

public class AutoMapperProfile : AutoMapper.Profile
{
    public AutoMapperProfile()
    {     
        CreateMap<ReviewPostInputModel, Review>()
            .ForMember(x => x.ReceiveThirdPartyUpdates, opt => opt.ResolveUsing(src => src.ReceiveThirdPartyUpdates ? (DateTime?)DateTime.UtcNow : null))
            .ForMember(x => x.ReceiveUpdates, opt => opt.ResolveUsing(src => src.ReceiveUpdates ? (DateTime?)DateTime.UtcNow : null))
            .ForMember(x => x.AverageScore, opt => opt.ResolveUsing(src => (decimal)Math.Round((src.Courtsey + src.Reliability + src.Tidiness + src.Workmanship) / 4, 2)));
        // ...
    }
}

你可以看看这个答案:AutoMapper: What is the difference between MapFrom and ResolveUsing?

我们在过去从“ConfigureServices”添加自动映射器时遇到了问题,可能对您来说也是一样的。你可以尝试这个:

AutoMapperConfiguration.Init();

在启动功能中添加此类:

    using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using AutoMapper;

namespace yournamespace.ViewModels.Mappings
{
    public static class AutoMapperConfiguration
    {
        public static void Init()
        {
            Mapper.Initialize(cfg =>
            {
                cfg.CreateMap<ReviewPostInputModel, Review>()
                .ForMember(x => x.ReceiveThirdPartyUpdates, opt => opt.MapFrom(src => src.ReceiveThirdPartyUpdates ? (DateTime?)DateTime.UtcNow : null))
                .ForMember(x => x.ReceiveUpdates, opt => opt.MapFrom(src => src.ReceiveUpdates ? (DateTime?)DateTime.UtcNow : null))
                .ForMember(x => x.AverageScore, opt => opt.MapFrom(src => (decimal)Math.Round((src.Courtsey + src.Reliability + src.Tidiness + src.Workmanship) / 4, 2)));
            });
        }
    }
}

0
投票

经过一番调查,我想我已经复制了你的问题。我创建了一个基本的ASP.NET Core 2.2网站,安装了AutoMapper.Extensions.Microsoft.DependencyInjection 6.0.0,创建了一个与你匹配的Review类,并根据你的映射定义最好地猜测了ReviewPostInputModel类的外观。然后我将您的映射配置文件类AutoMapperProfile添加到项目中,并配置启动如下:

public void ConfigureServices(IServiceCollection services)
{
    ...
    services.AddAutoMapper();
    services.AddMvc...
}

然后我“破解”默认生成的HomeController,如此测试映射:


 public class HomeController : Controller
    {
        private IMapper _mapper;

        public HomeController(IMapper mapper)
        {
            _mapper = mapper;
        }

        public IActionResult Index()
        {
            var input = new ReviewPostInputModel();
            input.ReceiveThirdPartyUpdates = true;
            input.Tidiness = 3;
            input.Reliability = 2;
            input.NotDefinedOnProfile = "sss";

            var output = _mapper.Map<Review>(input);

            // Lazy test to avoid changing model.
            throw new Exception($"{output.ReceiveThirdPartyUpdates} - {output.AverageScore} - {output.NotDefinedOnProfile}");

            return View();
        }
...

现在这对我有用,就像我收到的例外消息是11/04/2019 2:56:31 PM - 1.25 - sss

然后我创建了另一个程序集并将AutoMapperProfile类移入其中。然后我重新运行测试,但得到以下错误:

AutoMapper.AutoMapperConfigurationException:找到未映射的成员。查看下面的类型和成员。添加自定义映射表达式,忽略,添加自定义解析程序或修改>源/目标类型

For no matching constructor, add a no-arg ctor, add optional arguments, or map all of ?the constructor parameters

AutoMapper为您创建了此类型映射,但无法使用>当前配置映射您的类型。 ReviewPostInputModel - > Review(目标成员列表)ReviewPostInputModel - > Review(目标成员列表)

未映射的属性:AverageScore ReceiveUpdates NotDefinedOnProfile

这是有道理的,因为services.AddAutoMapper();方法只搜索当前程序集中的profiles

所以我然后改为配置为:services.AddAutoMapper(cfg => cfg.ValidateInlineMaps = false);关闭错误,并重新运行测试。

新产出:1/01/0001 12:00:00 AM - 0 - sss

所以这让我相信AutoMapper找不到你的Profile类,在这种情况下,你可以使用以下方法手动配置它:

 services.AddAutoMapper(cfg =>
 {
    cfg.AddProfile<AutoMapperProfile>();
 });

或者手动定义要使用其他重载之一进行搜索的程序集,例如:

services.AddAutoMapper(param System.Reflection.Assembly[] assemblies);

如果这不是你的问题,不管是因为我花在复制这个问题上的时间已经治好了我的失眠。

© www.soinside.com 2019 - 2024. All rights reserved.