2016-02-13 25 views
20

Sto cercando di capire il modo corretto di configurare AutoMapper nel file Startup.cs della mia applicazione e quindi utilizzarlo nell'intera applicazione.Configurazione di AutoMapper 4.2 con IoC integrato in ASP.NET Core 1.0 MVC6

Sto tentando di utilizzare this documentation che in qualche modo spiega come dare ancora a AutoMapper una sensazione statica senza la vecchia API statica. L'esempio utilizza StructureMap.

Mi piacerebbe sapere come posso fare qualcosa di simile, ma in un'app Core 1.0 che utilizza il contenitore dei servizi integrato.

Suppongo che nella funzione Configura configurerei AutoMapper e quindi nella funzione ConfiguraServizi lo aggiungerei come transitorio.

Suppongo che alla fine il modo più pulito e corretto per farlo sia l'iniezione di dipendenza. Qui è il mio tentativo in corso, ma non funziona:

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

Nel mio controller:

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

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

Semplicemente non funziona a tutti .. Devo perdere qualche passo o fare qualcosa di sbagliato.

+0

Non ho la risposta completa per questo (alle prese con me stesso!), Ma nel tuo AddTransient, la seconda param generica è il * tipo * di Mapper piuttosto che l'istanza di Mapper creata con CreateMapper. Sto indovinando che sarà qualcosa sulla falsariga dei servizi. Aggiunta invece. – DavidGouge

risposta

36

Questa risposta adatta l'approccio MVC 6 un po 'di più in tutto il livello del Controllore:

ho migrato da automapper da 4.1.1 a 4.2.0, ha avuto un pochi problemi a capire le complessità, ma alla fine sono arrivati.

Per prima cosa ho separato la build del profilo AutoMapper in una nuova classe (vedi sotto) per salvare l'intasamento della classe di avvio.

using AutoMapper; 
using YourModels; 
using YourViewModels; 

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

Ho apportato le seguenti modifiche alla classe di avvio.

Ho aggiunto una variabile membro privata di tipo MapperConfiguration.

private MapperConfiguration _mapperConfiguration { get; set; } 

Nel costruttore Startup ho aggiunto il seguente codice per istanziare il mio nuovo profilo AutoMapper.

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

In ConfigureServices() ho abbandonato la mia nuova automapper profilo in un Singleton.

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

E 'stata solo una semplice operazione per iniettare i relativi controller.

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

     ... 
} 

Grazie a Rexebin sopra a https://pintoservice.wordpress.com/2016/01/31/dependency-injection-for-automapper-4-2-in-asp-net-vnext-mvc-project/ per il suo posto che aiutano enourmously.

4

Nei servizi di configurazione è possibile creare nuovamente un'istanza di MapperConfiguration e quindi creare le mappe e aggiungerle.

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

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

Poi basta iniettare l'IMapper nel costruttore e mappa

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

sto solo sperimentando con lo spostamento di un API Web su da .net 4.5 al core .net e bisogno di questo. Eri molto vicino, dato che @DavidGouge suggeriva di dover registrare l'istanza del mapper che hai creato nel COI. Quindi la configurazione di AutoMapper deve essere fatta in ConfigureServices. (Sono stati inclusi in linea qui, ma nel mio progetto chiama un metodo in una classe AutoMapperConfiguration, quindi Startup rimane il più pulito possibile, lo stesso con le registrazioni IOC). L'IMapper verrà quindi inserito correttamente nel controller.

Startup.cs diventa

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

La risposta inviata è un'ottima soluzione, ma ho pensato di farvi sapere come lo sto facendo attualmente con Core 1.0 e AutoMapper v5.1.1. Mi sembra un approccio molto carino e facile da capire.

Nel Startup.cs nella parte superiore del metodo di configurazione è sufficiente scrivere il seguente codice per inizializzare le mappature:

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

Poi nel controller o qualsiasi altra parte del codice in cui è necessario mappare:

Mapper.Map<Product>(productViewModel); 
7

È inoltre possibile utilizzare il pacchetto di estensione dall'autore di automapper.

È possibile passare una configurazione, specificare gli assiemi per eseguire la scansione o non passare nulla e consentire la scansione di assiemi da 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>(); 
     ... 
    }); 
    ... 
Problemi correlati