2010-11-17 2 views
17

Я в настоящее время имеют следующее отображение:Automapper вместе с Dependency Injection

Mapper.CreateMap<Journal, JournalDto>(); 

Теперь Journal содержит член с именем RefTypeID, который существует соответствующее значение в другой таблице в базе данных; чтобы посмотреть это значение, у меня есть служба, которая обрабатывает простой запрос int -> string. Конфигурация automapper в настоящее время происходит в статическом классе в начале программы. Можно ли переместить код преобразования в класс, который вводится в мой контейнер DI или есть лучший способ?

+0

Единственная причина, по которой я могу думать, что это было бы чисто организационно. У вас потенциально будет код сопоставления по всему вашему проекту. Если ваш объект домена изменяется или dtos может быть менее идеальным. Но мне любопытно узнать от других людей их мнение. – Daniel

+0

Ну, я бы все равно сохранил код отображения в одном месте - то есть.этот класс, который будет захватывать все необходимые сервисы из контейнера DI. Мне просто нужно инициализировать отображение, а не полагаться на статический конструктор, выполняющий его автоматически. – Femaref

+0

Для последней версии взгляните на [это] (http://stackoverflow.com/a/35431096/1977871), так что ответьте – VivekDev

ответ

8

Вот как я ее решил:

Я определил IMappingCreator интерфейс:

public interface IMappingCreator 
{ 
    void CreateMappings(); 
} 

Я пошел вперед и реализовал класс с этим интерфейсом (я использую MEF, как DI контейнер, там атрибуты пришедшего из), который помещается в контейнер DI, как IMappingCreator:

[Export(typeof(IMappingCreator))] 
    public class Mapping : IMappingCreator 
    { 
     private readonly IRefTypesLookup iRefTypesLookup; 


     [ImportingConstructor] 
     public Mapping(IRefTypesLookup rtl) 
     { 
      iRefTypesLookup = rtl; 
     } 

     public void CreateMappings() 
     { 
      Mapper.CreateMap<Journal, DisplayJournal>().AfterMap((j, dj) => dj.RefTypeName = iRefTypesLookup.Lookup(j.RefTypeID)); 
     } 
    } 

Наконец, в моем запуске приложения, принести все instanc эс этого интерфейса в контейнере и вызвать метод CreateMappings на них:

var mappings = container.GetExportedValues<IMappingCreator>(); 

    foreach (IMappingCreator mc in mappings) 
    { 
     mc.CreateMappings(); 
    } 

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

+0

Это довольно приятно ... Мне, возможно, придется брать взаймы из этого! : D MEF - это отличное дополнение к структуре. – Daniel

+0

не стесняйтесь, я не думаю, что я единственный, кто подходит к этой проблеме. – Femaref

14

Лучший способ заключается в использовании распознаватель клиента. Конфигурация Mapping предназначено быть статическим, так заказные резольверы предназначены для отображения для одного члена:

Mapper.Initialize(cfg => { 
    cfg.ConstructServicesUsing(type => WhateverMefUsesToGetInstances.GetInstance(type)); 

    cfg.CreateMap<Journal, DisplayJournal>() 
     .ForMember(dest => dest.RefTypeName, 
      opt => opt.ResolveUsing<RefTypeNameResolver>()); 
}); 

Тогда ваш распознаватель становится:

[Export(typeof(IRefTypeNameResolver))] 
public class RefTypeNameResolver : ValueResolver<Journal, string>, IRefTypeNameResolver 
{ 
    private readonly IRefTypesLookup iRefTypesLookup; 

    [ImportingConstructor] 
    public RefTypeNameResolver (IRefTypesLookup rtl) 
    { 
     iRefTypesLookup = rtl; 
    } 

    protected override string ResolveCore(Journal source) 
    { 
     return iRefTypesLookup.Lookup(source.RefTypeID); 
    } 
} 

конфигурации необходимо выполнить один раз, из-за чего конфигурация API обеспечивает захваты в исполнение API (преобразователи типа, значение арбитры и т.д.)

+1

Я знал о ValueResolver, но я думал, что они бесполезны, потому что мне не хватает конфигурации ConstructServicesUsing. Хороший! – Kugel

1

Вот это новейший способ сделать это ...

https://pintoservice.wordpress.com/2016/01/31/dependency-injection-for-automapper-4-2-in-asp-net-vnext-mvc-project/

Хотя я лично добавляю автоматическое сопоставление в контроллер, а не в репозиторий. Таким образом, вы можете использовать один и тот же репозиторий для разных контроллеров и иметь разные сопоставления. Тем не менее, одна и та же концепция, просто введите IMapper в контроллер вместо репозитория.