#c# #automapper #simple-injector
#c# #автоматический преобразователь #простой инжектор
Вопрос:
Я уверен, что эти вопросы задавались несколько раз, но я застрял в колее на этом. Я пытаюсь автоматически сопоставить свойства объектов EF с определенными интерфейсами. Я использую simple injector в качестве своего выбора IOC-фреймворка. (формы выигрыша)
Я зарегистрировал свои интерфейсы в program.cs..
container = new Container();
container.Register<IBob, Bob>();
...
и передайте экземпляр контейнера в класс, в котором я выполняю автоматическое отображение…
public ModelService(IDataRepository repo, Container container)
{
// create a reference to the repository
this.Repository = repo;
var config = new MapperConfiguration(cfg =>
{
// pass the reference into the constructor service.
qcfg.ConstructServicesUsing(type => container.GetInstance(type));
cfg.AddProfile<ModelConfig>();
});
mapper = new Mapper(config);
}
Класс profile выглядит примерно так …
public class ModelConfig : Profile
{
public ModelsConfig()
{
// mapping definition for product buy
this.CreateMap<Entity.BobEF, IBob>()
.ForMember(destination => destination.UniqueIdentifier, option => option.MapFrom(source => source.BobID))
.ReverseMap();
}
Итак, я ожидал, что automapper будет использовать контейнер для создания конкретного класса для IBob, учитывая, что это уже было объявлено в начальной загрузке BI, и он должен использовать «контейнер.Метод getInstance()» для разрешения интерфейса, однако то, что я на самом деле получаю в прокси-представлении класса IBob с типом Proxy_MyProject .IBob_232342
Я действительно не понимаю документацию automapper для этого, поскольку я новичок в использовании automapper.
Любая ПОМОЩЬ очень ценится.
С уважением,
Тим
Редактировать: (Пример используемых классов моделей)
// shows the basic interface for a product
public interface IProduct : IModel
{
string Name { get; set; }
ISupplier Supplier { get; set; }
}
// shows the concrete implementation including the
// exposed property being of type ISupplier
public class Product : Model, IProduct
{
public string Name
{
get;
set;
}
public ISupplier Supplier
{
get;
set;
}
}
Комментарии:
1. docs.automapper.org/en/latest/Mapping-inheritance.html#as
Ответ №1:
ConstructServicesUsing
само по себе применяется только к преобразователям значений, преобразователям значений элементов, преобразователям типов и т. Д. Не имеет отношения к тому, что вам нужно. Вы хотите:
CreateMap<Entity.BobEF, IBob>().ConstructUsingServiceLocator();
Это также приведет к тому, что объекты назначения будут построены таким же образом.
Но я должен согласиться с @JoepVerhoeven, это звучит как чрезмерная разработка.
Комментарии:
1. Возможно, вы оба правы. Я давно не программировал, а фреймворки, стандарты и практики существенно изменились со времен моей code monkey. Однако мое понимание DI приводит меня к мысли, что модели, используемые формами / представлениями, должны быть реализациями интерфейсов, и впоследствии сложные типы, предоставляемые через свойства, должны быть доступны через связанные с ними интерфейсы. Таким образом, в процессе тестирования можно заменить все, что угодно, если оно также реализует тот же интерфейс. Это неправильно? Я изменю исходное сообщение, чтобы включить пример
2. Класс examples для IProduct (выше) имеет свойство типа ISupplier, поэтому я должен создать сопоставление для [ this . Создать карту Поставщик, ISupplier>() ] потому что это тип, который automapper увидит и попытается сопоставить.
Ответ №2:
Причина, по которой automapper возвращает прокси-объект, заключается в том, что вы сопоставляете класс с интерфейсом, а automapper не знает, какую реализацию IBob
использовать.
Комментарии:
1. Спасибо за отзыв, однако ссылка на пример прямо противоположна тому, чего я пытаюсь достичь, поскольку я хочу, чтобы мои конкретные классы были возвращены. Automapper не обязательно знать, какова реализация для IBob, поскольку мы дали ему ссылку на службу, которая знает и может создавать экземпляры объектов concrete по мере необходимости. Это было сделано с помощью этой строки … ConstructServicesUsing(тип => контейнер. getInstance(тип));
2. Привет @ Tim действительно ли необходимо использовать такой интерфейс, как
IBob
. Потому что большинство вариантов использования automapper заключается в сопоставлении объектов Dto с объектами домена и / или объектами домена с viewmodels или ответами api. Каков ваш вариант использования или причина сопоставления модели entity framework с интерфейсом и почему бы вместо этого не сопоставить с фактической реализацией этого интерфейса?
Ответ №3:
Ответ, предоставленный @Lucian Bargaoanu, правильный, но для этого потребовалась комбинация обоих ConstructServicesUsing
и ConstructUsingServiceLocator
. Я прочитал документацию здесь .. введите описание ссылки здесь, но не понял, что это означает, что мы должны использовать дополнительные ConstructUsingServiceLocator
объявления о отображении.
Пример:
// Or marker types for assemblies:
var config = new MapperConfiguration(cfg =>
{
// pass the reference into the constructor service.
cfg.ConstructServicesUsing(type => container.GetInstance(type));
//cfg.ConstructServicesUsing()
cfg.AddProfile(new BusinessModelsConfig(this.Repository.Context));
});
Эта конфигурация содержится в BusinessModelsConfig ..
// mapping definition for product buy
this.CreateMap<Entity.ProductBuy, IProductBuy>()
.ForMember(destination => destination.UniqueIdentifier, option => option.MapFrom(source => source.ProductBuyID))
.ForMember(destination => destination.Status, option => option.MapFrom(source => source.BuyStatus))
.ForMember(destination => destination.TimeStamp, option => option.MapFrom(source => source.ts))
.ConstructUsingServiceLocator();
Для тех, кому необходимо также сопоставить объекты, чтобы изменения могли быть отражены на уровне сохранения, эта статья оказалась бесценной для понимания того, как этого можно достичь, хотя automapper может быть не лучшим инструментом для этого. Эта статья довольно старая, и я был бы рад любой информации, которая предлагает другую перспективу.
Комментарии:
1.Очевидно 🙂 Я имею в виду, как еще это могло бы работать? Я хотел сказать, что само
ConstructServicesUsing
по себе это относится только к службам, а не к объектам назначения.2. Я обновил ответ. Это кажется излишним, но, возможно, это поможет следующему парню.