Automapper无法与Net Core 2.2的三元和计算值一起使用.MapFrom

时间:2019-04-11 13:29:46

标签: c# automapper

我正在使用;

AutoMapper.Extensions.Microsoft.DependencyInjection 6.0.0

在运行net core 2.2的网络api项目中

映射我的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);

所有标准成员都映射到上面列出的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);

有人知道为什么会这样吗?

2 个答案:

答案 0 :(得分: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)));
            });
        }
    }
}

答案 1 :(得分: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:   找到未映射的成员。在下面查看类型和成员。   添加自定义映射表达式,忽略,添加自定义解析器或修改> source / destination类型

     

对于没有匹配的构造函数,请添加一个无参数ctor,添加可选参数,或映射所有?构造函数参数

     

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

     

未映射的属性:   平均分   接收更新   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);

如果这不是您的问题,那么无论是因为我花了很多时间在解决这个问题上,还是治愈了我的失眠症。