Automapper не работает с .MapFrom на троичном и вычисленном значении с Net Core 2.2 - PullRequest
2 голосов
/ 11 апреля 2019

Я использую;

AutoMapper.Extensions.Microsoft.DependencyInjection 6.0.0

в проекте web api trunning 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);

Все стандартные члены отображаются в строке ForMember, указанной выше, где DateTimes установлен на новый экземпляр DateTime, а Averagescore установлен на 0.

Для полноты я добавлю преобразователь в мой контроллер следующим образом:

private readonly IMapper _mapper;

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

Я настраиваю Automapper в моем StartUp.cs следующим образом;

services.AddAutoMapper();

Я также попытался добавить тест в контроллер, чтобы подтвердить, что значения со входа не являются проблемой (выполнено после карты и может подтвердить, что это значение правильно обновлено);

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

У кого-нибудь есть идеи, почему это происходит?

Ответы [ 2 ]

0 голосов
/ 11 апреля 2019

После некоторого расследования, я думаю, я воспроизвел вашу проблему.Я создал базовый веб-сайт 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: были найдены несопоставленные элементы.Просмотрите типы и членов ниже.Добавьте пользовательское выражение сопоставления, игнорируйте, добавьте пользовательский распознаватель или измените> тип источника / назначения

Если нет подходящего конструктора, добавьте ctor без аргументов, добавьте необязательные аргументы или сопоставьте весь конструктор?параметры

AutoMapper создал эту карту типов для вас, но ваши типы не могут быть сопоставлены с помощью> текущей конфигурации.ReviewPostInputModel -> Review (список участников-получателей)ищет в текущей сборке профилей .

Поэтому я изменил конфигурацию на: services.AddAutoMapper(cfg => cfg.ValidateInlineMaps = false);, чтобы отключить ошибку и повторно запустить тест.

НовыйВывод: 1/01/0001 12:00:00 AM - 0 - sss

Таким образом, я полагаю, что AutoMapper не может найти ваш класс профиля, и в этом случае вы можете вручную настроить его, используя:

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

или вручную определитьпоиск сборок с использованием одной из других перегрузок, например:

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

Если это не ваша проблема, не важно, потому что мое время, потраченное на воспроизведение этого вопроса, вылечило мою бессонницу.

0 голосов
/ 11 апреля 2019

Вам нужно использовать «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: в чем разница между MapFrom и 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)));
            });
        }
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...