AutoMapper: сопоставление с типом получателя с помощью конструктора (Prism, Unity, EntityFramework) - PullRequest
0 голосов
/ 03 ноября 2019

Я столкнулся с небольшой проблемой в приложении WPF Prism.Unity (7.2.0.1367) с EntityFramework (6.3.0), AutoMapper (9.0.0) и AutoMapper.EF6 (2.0.0), который мне не кажетсячтобы выяснить самостоятельно:

У меня есть FooListViewModel, который загружает список FooEntity с из EntityFramework и отображает их на FooViewModel с помощью AutoMapper. FooEntity имеет отношение 1-ко-многим к BarEntity, которое превращается в наблюдаемую коллекцию BarViewModel с в FooViewModel. Все идет нормально. Теперь я хотел предоставить FooViewModel доступ к DbContext и добавил зависимость к Ctor FooViewModel, когда AutoMapper начал жаловаться, что «FooViewModel должен иметь конструктор с 0 аргументами или только необязательными аргументами».

Это FooViewModel (все свойства на самом деле являются полными свойствами с использованием INotifyPropertyChanged, но я сократил его для достижения лучшей читаемости):

public class FooViewModel : BindableBase
{
    public int FooId { get; set; }

    public string Name { get; set; }

    public string Desc { get; set; }

    public ObservableCollection<BarViewModel> Bars { get; set; }

    public FooViewModel(FooBarContext context) // <-- this is the problem
    {

    }
}

После прочтения этого поста: AutoMapper CustomResolver запрашивает необязательные параметры в конструкторе

Я начал с добавления ConstructServicesUsing(x => IUnityContainer.Resolve(x)):

    protected override void RegisterTypes(IContainerRegistry containerRegistry)
    {
        IUnityContainer _container = containerRegistry.GetContainer();

        MapperConfiguration mapperConfig = new MapperConfiguration(cfg =>
        {
            cfg.AddProfile<FooProfile>();
            cfg.ConstructServicesUsing(x => _container.Resolve(x));
        });

        IMapper mapper = mapperConfig.CreateMapper();

        containerRegistry.RegisterInstance(mapper);
    }

... но проблема осталась. Затем я нашел этот пост: Внедрение зависимостей AutoMapper с параметрами

Итак, я создал TypeConverter:

public class FooConverter : ITypeConverter<Foo, FooViewModel>
{
    private readonly IUnityContainer _container;
    private readonly IMapper _mapper;

    public FooConverter(IUnityContainer container, IMapper mapper)
    {
        _container = container;
        _mapper = mapper;
    }

    public FooViewModel Convert(Foo source, FooViewModel destination, ResolutionContext context)
    {
        FooViewModel result = new FooViewModel(_container.Resolve<FooBarContext>());

        result.FooId = source.FooId;
        result.Name = source.Name;
        result.Desc = source.Desc;

        result.Bars = _mapper.Map<ObservableCollection<BarViewModel>>(source.Bars);

        return result;
    }
}

И мое приложение снова работает! НО: мне кажется, что я что-то здесь упускаю. Назначение всех свойств «вручную» в моем TypeConverter только для того, чтобы получить зависимость от Ctor, похоже на то, что вы упускаете точку использования AutoMapper. Такое ощущение, что One-Liner, например, ConstructServicesUsing(x => IUnityContainer.Resolve(x)) должен сказать Mapper, чтобы он получал все зависимости Constructor от DI-контейнера без использования TypeConverter. Кроме того, если я добавлю еще одну зависимость в свой FooViewModel Ctor, мне придется изменить TypeConverter. Если я начну добавлять зависимости к BarViewModel, мне нужно будет изменить Foo TypeConverter И создать Bar TypeConverter. Это должно быть проще, чем это! (?)

...