2010-11-17 18 views
17

Mam obecnie następujące odwzorowanie:Automapper wraz z Dependency Injection

Mapper.CreateMap<Journal, JournalDto>(); 

Teraz Journal zawiera element o nazwie RefTypeID, który istnieje odpowiednia wartość w innej tabeli w bazie danych; aby sprawdzić tę wartość, mam usługę, która obsługuje proste żądanie int -> string. Konfiguracja automappera odbywa się obecnie w klasie statycznej na początku programu. Czy można przenieść kod mapowania do klasy, która zostanie wstrzyknięta do mojego kontenera DI lub czy istnieje lepszy sposób?

+0

Jedyny powód, dla którego nie mogę, byłby czysto organizacyjny. Będziesz mieć kod mapowania w całym projekcie (ach). Jeśli twój obiekt domeny się zmienia lub dtos może być mniejszy niż idealny. Ale jestem ciekawy, aby dowiedzieć się od innych ludzi ich opinii. – Daniel

+0

Cóż, nadal zachowałbym kod mapowania w jednym miejscu - tj.tej klasy, która pobierałaby wszystkie potrzebne usługi z kontenera DI. Muszę tylko zainicjować mapowanie, zamiast polegać na automatycznym wykonaniu konstruktora statycznego. – Femaref

+0

Aby uzyskać najnowszą wersję, spójrz na [this] (http://stackoverflow.com/a/35431096/1977871), więc odpowiedz – VivekDev

Odpowiedz

8

Oto jak rozwiązać go:

ja zdefiniował IMappingCreator interfejs:

public interface IMappingCreator 
{ 
    void CreateMappings(); 
} 

poszedł do przodu i wdrożone klasę z tego interfejsu (używam MEF jako DI kontenera, to gdzie atrybuty są comming z), która jest umieszczona w kontenerze DI jako 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)); 
     } 
    } 

Wreszcie w moim uruchamiania aplikacji, ja pobrać wszystkie instanc es tego interfejsu w pojemniku i wywołać metodę CreateMappings na nich:

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

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

To sprawia, że ​​początkowa konfiguracja dość łatwe, jak wszystko stworzenie dzieje się w jednym miejscu, i można mieć tyle twórców odwzorowań, ile chcesz (jednak powinieneś ograniczyć je do minimum, może raz na projekt lub tak, chwytając wszystkie potrzebne usługi do mapowania konkretnych typów w tym projekcie).

+0

To jest całkiem miłe ... Może będę musiał pożyczyć od tego! : D MEF jest tak wspaniałym dodatkiem do ram. – Daniel

+0

Czuję się wolny, nie sądzę, że jestem jedynym, który wymyśliłby ten problem. – Femaref

14

Lepszym sposobem jest użycie rozpoznawania nazw klientów. konfiguracja mapowania ma być statyczna, więc niestandardowych przeliczniki są przeznaczone do zapewnienia mapowanie dla pojedynczego użytkownika:

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

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

Wtedy twój rezolwer staje:

[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); 
    } 
} 

Konfiguracja musi wykonać raz, dlatego też konfiguracja API udostępnia API haki do egzekucji (konwertery typu, resolwera wartości etc.)

+1

Wiedziałem o ValueResolver, ale myślałem, że są bezużyteczne, ponieważ brakowało mi konfiguracji ConstructServicesUsing. Niezłe! – Kugel

Powiązane problemy