2016-02-13 8 views
20

Próbuję znaleźć właściwy sposób konfiguracji AutoMappera w pliku Startup.cs mojej aplikacji, a następnie użyć go w całej mojej aplikacji.Konfigurowanie AutoMapper 4.2 z wbudowanym IoC w ASP.NET Core 1.0 MVC6

Próbuję użyć this documentation, który nieco wyjaśnia, jak wciąż dać AutoMapperowi wrażenie statyczne bez starego statycznego API. W przykładzie zastosowano StructureMap.

Chciałbym wiedzieć, jak mogę zrobić coś podobnego, ale w aplikacji Core 1.0 za pomocą wbudowanego kontenera usług.

Zakładam, że w funkcji Konfiguracji skonfigurowałbym AutoMapper, a następnie w funkcji ConfigureServices dodałbym go jako przejściowy.

Zakładam, że najczystszym i najodpowiedniejszym sposobem na to jest zastrzyk zależności. Oto moja obecna próba, ale to nie działa:

Startup.cs

public IMapper Mapper { get; set; } 
private MapperConfiguration MapperConfiguration { get; set; } 
public void ConfigureServices(IServiceCollection services) 
{ 
    services.AddTransient<IMapper, Mapper>(); 
} 
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{ 
    MapperConfiguration MapperConfiguration = new MapperConfiguration(cfg => 
    { 
     cfg.CreateMap<Product, ProductViewModel>().ReverseMap(); 
    }); 

    Mapper = MapperConfiguration.CreateMapper(); 
} 

W moim kontrolera:

private IMapper _mapper { get; set; } 
// Constructor 
public ProductsController(IMapper mapper) 
{ 
    _mapper = mapper; 
} 

public IActionResult Create(ProductViewModel vm) 
{ 
    Product product = _mapper.Map<ProductViewModel, Product>(vm); 
} 

To po prostu nie działa w ogóle .. Muszę pominąć jakiś krok lub zrobić coś złego.

+0

nie mam pełną odpowiedź na to (zmaga się z nią sam!), Ale w swojej AddTransient, drugi generic param jest typu * * od Mapper zamiast instancji Mappera utworzonej za pomocą CreateMapper. Zgaduję, że będzie to coś podobnego do usług. Zamiast tego dodam. – DavidGouge

Odpowiedz

36

ta odpowiedź pasuje do podejścia MVC 6 trochę więcej wokół warstwy Kontroler:

I migrowały z AutoMapper 4.1.1 do 4.2.0, miał kilka spraw dotyczących zawiłości, ale dotarłem na końcu.

Najpierw rozdzieliłem kompilację profilu AutoMappera na nową klasę (patrz poniżej), aby zapisać zapychanie klasy Początek.

using AutoMapper; 
using YourModels; 
using YourViewModels; 

namespace YourNamespace 
{ 
    public class AutoMapperProfileConfiguration : Profile 
    { 
     protected override void Configure() 
     { 
      CreateMap<Application, ApplicationViewModel>(); 
      CreateMap<ApplicationViewModel, Application>(); 
      ... 
     } 
    } 
} 

Wprowadziłem następujące poprawki do klasy Startup.

Dodałem prywatną zmienną składową typu MapperConfiguration.

private MapperConfiguration _mapperConfiguration { get; set; } 

W konstruktorze startowym dodałem następujący kod, aby utworzyć instancję mojego nowego profilu AutoMappera.

_mapperConfiguration = new MapperConfiguration(cfg => 
{ 
    cfg.AddProfile(new AutoMapperProfileConfiguration()); 
}); 

W ConfigureServices() Rzuciłem moją nową AutoMapper profilu w Singleton.

services.AddSingleton<IMapper>(sp => _mapperConfiguration.CreateMapper()); 

To była prosta operacja, aby wstrzyknąć odpowiednie kontrolery.

using AutoMapper; 
using ... 

namespace YourNamespace 
{ 
    public class ApplicationsController : BaseController 
    { 
     [FromServices] 
     private IMapper _mapper { get; set; } 

     [FromServices] 
     private IApplicationRepository _applicationRepository { get; set; } 

     public ApplicationsController(
      IMapper mapper, 
      IApplicationRepository applicationRepository) 
     { 
      _mapper = mapper; 
      _applicationRepository = applicationRepository; 
     } 

     // GET: Applications 
     public async Task<IActionResult> Index() 
     { 
      IEnumerable<Application> applications = await _applicationRepository.GetForIdAsync(...); 

      if (applications == null) 
       return HttpNotFound(); 

      List<ApplicationViewModel> viewModel = _mapper.Map<List<ApplicationViewModel>>(applications); 

      return View(viewModel); 
     } 

     ... 
} 

Dzięki Rexebin na co https://pintoservice.wordpress.com/2016/01/31/dependency-injection-for-automapper-4-2-in-asp-net-vnext-mvc-project/ na swoim stanowisku, które pomagają enourmously.

4

W usłudze ConfigurationServices można utworzyć instancję MapperConfiguration, a następnie utworzyć mapy i dodać je.

public void ConfigureServices(IServiceCollection services) 
{  
    MapperConfiguration configuration = new MapperConfiguration(cfg => 
    { 
     cfg.AddProfile<MappingProfile.Profile1>(); 
     cfg.AddProfile<MappingProfile.Profile2>(); 
    }); 

    services.AddInstance(typeof (IMapper), configuration.CreateMapper()); 
} 

Następnie wystarczy wstrzyknąć IMapper w konstruktorze i map

public class Handler 
{ 
     private readonly ProfileContext _db; 
     private readonly IMapper _mapper; 

     public Handler(ProfileContext db, IMapper mapper) 
     { 
      _db = db; 
      _mapper = mapper; 
     } 

     public void Handle(Profile1 request) 
     { 

      ProfileModel profile = _mapper.Map<Profile1, ProfileModel>(request); 

      _db.Profiles.Add(profile); 

      try 
      { 
       db.SaveChanges(); 
      } 
      catch (Exception ex) 
      { 

       throw; 
      } 

      return profile; 
     } 
} 
0

Ja tylko eksperymentowanie z ruchomymi API Web ciągu od 4,5 do .net .net rdzenia i potrzebne to. Byłeś bardzo blisko, ponieważ @DavidGouge zasugerował, że musisz zarejestrować instancję mappera, którą utworzyłeś w IOC. Tak więc konfiguracja AutoMapper musi zostać wykonana w ConfigureServices. (Zawarłem tutaj wiersz, ale w moim projekcie wywołuje on metodę w klasie AutoMapperConfiguration, więc Startup pozostaje tak czysty, jak to możliwe, tak samo jak przy rejestracji IOC). IMapper zostanie poprawnie wypełniony w twoim kontrolerze.

Startup.cs staje

public IMapper Mapper { get; set; } 
    private MapperConfiguration MapperConfiguration { get; set; } 
    public void ConfigureServices(IServiceCollection services) 
    { 
     MapperConfiguration MapperConfiguration = new MapperConfiguration(cfg => 
     { 
      cfg.CreateMap<Product, ProductViewModel>().ReverseMap(); 
     }); 

     Mapper = MapperConfiguration.CreateMapper(); 

     services.AddInstance(Mapper); 
    } 
    public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
    { 
     // AutoMapper Configuration moved out of here. 
    } 
3

Zamieszczona odpowiedź jest świetnym rozwiązaniem, ale pomyślałem, że dałbym wam znać, jak obecnie robię to z Core 1.0 i AutoMapper v5.1.1. Czuję, że jest to bardzo ładne podejście i łatwe do zrozumienia.

W Startup.cs na górze metody Konfiguracja prostu napisać następujący kod do zainicjowania mapowania:

Mapper.Initialize(config => 
{ 
    config.CreateMap<ProductViewModel, Product>().ReverseMap(); 
    config.CreateMap<CustomerViewModel, Customer>().ReverseMap(); 
}); 

Następnie w kontrolerze lub jakiejkolwiek innej części kodu, gdzie trzeba mapować:

Mapper.Map<Product>(productViewModel); 
7

Możesz również skorzystać z pakietu rozszerzeń od twórcy automapper.

Można przekazać konfigurację, określić złożenia, aby skanować lub przekazać nic, i pozwolić skanować złożenia z DependencyContext.

https://github.com/AutoMapper/AutoMapper.Extensions.Microsoft.DependencyInjection

https://www.nuget.org/packages/AutoMapper.Extensions.Microsoft.DependencyInjection/

public void ConfigureServices(IServiceCollection services) 
{ 
    //configure DI 
    services.AddTransient<IFoo, Foo>(); 

    //Add automapper - scans for Profiles 
    services.AddAutoMapper(); 
    //or specify 
    services.AddAutoMapper(cfg => 
    { 
     cfg.AddProfile<ViewModelProfile>(); 
     ... 
    }); 
    ...