Я столкнулся с небольшой проблемой в приложении 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. Это должно быть проще, чем это! (?)