2012-09-26 13 views
14

Większość przykładów znalezionych dla Automapper używa statycznego obiektu Mapper do zarządzania odwzorowaniami typów. Do mojego projektu muszę wstrzyknąć IMapperEngine jako część konstrukcji obiektu za pomocą StructureMap, abyśmy mogli sfałszować program odwzorowujący w testach jednostkowych, abyśmy nie mogli używać statycznego narzędzia odwzorowującego. Muszę również obsługiwać konfigurowanie profili AutoMapper.Sposób wstrzykiwania AutoMapper IMappingEngine przy użyciu StructureMap

Moje pytanie brzmi: jak skonfigurować rejestr StructureMap, aby mógł dostarczać instancję IMappingEngine podczas konstruowania instancji MyService.

Oto podpis konstruktora usługi:

public MyService(IMappingEngine mapper, IMyRepository myRepository, ILogger logger) 

A oto StructureMap rejestru

public class MyRegistry : StructureMap.Configuration.DSL.Registry 
{ 
    public MyRegistry() 
    { 
     For<IMyRepository>().Use<MyRepository>(); 
     For<ILogger>().Use<Logger>(); 
     //what to do for IMappingEngine? 
    } 
} 

i profil Chcę załadować

public class MyAutoMapperProfile : AutoMapper.Profile 
{ 
    protected override void Configure() 
    { 
     this.CreateMap<MyModel, MyDTO>(); 
    } 
} 
+1

@Sebastian, dzięki za edycję, aby upiększyć kod. Nie wiedziałem, jak to zrobić. –

Odpowiedz

14

Klasa Mapper ma nieruchomość statyczna Mapper.Engine. Użyj tego, aby zarejestrować silnik z kontenerem:

For<IMappingEngine>().Use(() => Mapper.Engine); 

Jeśli trzeba załadować swoje profile przed wstrzyknięciem silnik chciałbym wstawić ten kod konfiguracji obok powyższym fragmencie.


Aktualizacja

Niestandardowy rejestr będzie wyglądać następująco

class MyRegistry : Registry 
{ 
    public MyRegistry() 
    { 
    For<IMyRepository>().Use<MyRepository>(); 
    For<ILogger>().Use<Logger>(); 

    Mapper.AddProfile(new AutoMapperProfile()); 
    For<IMappingEngine>().Use(() => Mapper.Engine); 
    } 
} 

Ten kod działa raz w inicjującego i jakaś zależność typu IMappingEngine będzie potem być podawane z wartości z Właściwość statyczna Mapper.Engine skonfigurowana przy użyciu niestandardowego AutoMapperProfile.

+0

Pracowałem dla mnie. Nie mogę uwierzyć, że straciłem tyle czasu, ile próbowałem to rozgryźć. –

1

Oto, do czego doszedłem, ponieważ nie mogłem wymyślić, jak ustawić konfigurację na Mapper.Engine i przekazać ją do For().

public MyRegistry() 
{ 
    For<IMyRepository>().Use<MyRepository>(); 
    For<ILogger>().Use<Logger>(); 

    //type mapping 
    For<ConfigurationStore>() 
     .Singleton() 
     .Use(ctx => 
     { 
      ITypeMapFactory factory = ctx.GetInstance<ITypeMapFactory>(); 
      ConfigurationStore store 
       = new ConfigurationStore(factory, MapperRegistry.AllMappers()); 
      IConfiguration cfg = store; 
      cfg.AddProfile<MyAutoMapperProfile>(); 
      store.AssertConfigurationIsValid(); 
      return store; 
     }); 
    For<IConfigurationProvider>().Use(ctx => ctx.GetInstance<ConfigurationStore>()); 
    For<IConfiguration>().Use(ctx => ctx.GetInstance<ConfigurationStore>()); 
    For<IMappingEngine>().Singleton().Use<MappingEngine>(); 
    For<ITypeMapFactory>().Use<TypeMapFactory>(); 
} 
+0

Co z 'Mapper.AddProfile()'? –

+0

Sebastian, staram się unikać używania statycznego obiektu Mapper, ale jeśli podążę za twoim tokiem myślenia, czy to będzie konfiguracja? 'Dla () .Use (CTX => { IConfiguration C = Mapper.Configuration; c.AddProfile (); IMappingEngine e = Mapper.Engine; powrotu E; }); ' –

+0

Niezupełnie. Oznaczałoby to dodanie twojego profilu, ilekroć dany komponent wymaga zależności typu 'IMappingEngine'. Proszę zobaczyć aktualizację mojej poprzedniej odpowiedzi dla kodu, który miałem na myśli. –

1

Napisałem wpis na blogu, który pokazuje moją AutoMapper z konfiguracją StructureMap. Stworzyłem specjalne rejestry dla AutoMapper 3.1.0 (działa również dla wersji 3.1.1) oraz 3.0.0 i 2.2.1.

http://www.martijnburgers.net/post/2013/12/20/My-AutoMapper-setup-for-StructureMap.aspx

+0

Przeczytałem twój wpis, ale nadal mam problemy. Czy wiesz, co robię źle tutaj http://stackoverflow.com/questions/30081545/inject-isession-into-custom-valueresolver/30084362?noredirect=1#comment48282702_30084362 –

+0

@JoshC. odpowiedział –

6

statyczna API zostaną usunięte w wersji 5.0. Użyj instancji MapperConfiguration i przechowuj statycznie w razie potrzeby. Użyj CreateMapper, aby utworzyć instancję odwzorowującą.

w nowej wersji (4.2.0> =) powinniśmy trzymać i przekazać IMapper przez DI.

Prosta usługa konfiguracji powinna wyglądać następująco (ASP.NET rdzenia)

services.AddSingleton<IMapper>(_ => new MapperConfiguration(cfg => 
      { 
       cfg.CreateMap<Foo,Bar>(); 
      }) 
      .CreateMapper()); 

a nasz serwis warstwa (z pomocą iniekcji konstruktora):

public class CrudService<TDocument> : ICrudService<TDocument> 
    { 
     private readonly IMapper _internalMapper; 
     private readonly IRepository<TDocument> _repository; 

     public CrudService(IRepository<TDocument> repository, IMapper mapper)     
     { 
      _internalMapper = mapper; 
      _repository = repository; 
     } 

     public virtual ServiceResult<string> Create<TModel>(TModel foo) 
     { 
      var bar = _internalMapper.Map<TDocument>(foo); 

      try 
      { 
       _repository.Create(bar); 
      } 
      catch (Exception ex) 
      { 
       return ServiceResult<string>.Exception(ex); 
      } 

      return ServiceResult<string>.Okay(entity.Id); 
     } 
} 

consider TDocument as Bar, and TModel as Foo


aktualizacja:
AutoMapper 4.2.1 wydany - Powrót statyczny

Po nieco informacji zwrotnych i poszukiwania duszy i szczerze zmęczony czynienia z pytaniami, niektóre statycznej API zostanie przywrócone w tym wydaniu. Możesz teraz (i w przyszłości) używać Mapper.Initialize i Mapper.Map

Powiązane problemy