2016-05-19 10 views
3

Ich habe eine ASP.NET 5 (läuft auf 4.6.2, nicht Core) -Anwendung. Ich wollte die ProjectTo <>() -Methode von AutoMapper verwenden, um die Ergebnisse von der Datenbank zu meinen Viewmodels zu projizieren.AutoMapper ProjectTo <>() finde keine Karte

Ich habe viele Tests ausprobiert, aber es scheint, dass die Karte bei der Verwendung von ProjectTo <>() nicht gefunden werden kann. Die Verwendung von mapper.Map <>() an verschiedenen Orten mit dem gleichen Modell und Viewmodel funktioniert perfekt.

Ich denke, es ist etwas falsch mit AutoMapper funktioniert mit meinem DI (Autofac), aber ich kann nicht herausfinden, was.

Wie auch immer, der Code:

Startup.Cs

public IServiceProvider ConfigureServices(IServiceCollection services) 
     { 
      (...) 

      // Autofac DI 
      AutofacContainer = AutofacLoader.Configure(services).Build(); 

      return AutofacContainer.Resolve<IServiceProvider>(); 
     } 

AutofacLoader.cs

public static ContainerBuilder Configure(IServiceCollection services) 
     { 
      var builder = new ContainerBuilder(); 

(...) 


      // AutoMapper 
      builder.RegisterModule<AutoMapperModule>(); 

      if (services != null) 
      { 
       builder.Populate(services); 

      } 
      return builder; 
     } 

AutoMapperModule.cs

public class AutoMapperModule : Module 
{ 
    protected override void Load(ContainerBuilder builder) 
    { 
     var mapping = new MapperConfiguration(cfg => 
     { 
      cfg.AddProfile(new Core.Mappings.AutoMapperProfileConfiguration()); 
      cfg.AddProfile(new Dieet.Core.Mappings.AutoMapperProfileConfiguration()); 
     }); 
     builder.RegisterInstance(mapping.CreateMapper()).As<IMapper>().AutoActivate(); 
    } 
} 

Der Test, der mit nicht ‚vermisste Karte von Patient zu PatientViewModel. Erstellen Sie mit Mapper.CreateMap '.

[Fact] 
    public async void InfohosServiceReturnsPatientViewModels() 
    { 
     var db = _container.Resolve<IInfohosDb>(); 

     var search = new PaginatedSearchBase(); 
     search.OrderBy = "Naam"; 

     var mapper = _container.Resolve<IMapper>(); 

     var result = await search.PagedResultAsAsync<Patient,PatientViewModel >(null,db.Patienten,mapper); 
    } 

PaginatedSearchBase

public class PaginatedSearchBase 
{ 
    public string OrderBy { get; set; } 
    public bool OrderDescending { get; set; } 
    public int Page { get; set; } = 1; 
    public int PageSize { get; set; } = 10; 
} 

und schließlich die Erweiterung, die die ProjectTo

public static class PagedResultExtensions 
{ 
    public static async Task<PagedResult<T>> PagedResultAsync<T>(this PaginatedSearchBase vm, ICollection<Expression<Func<T, bool>>> whereCollection, IEnumerable<T> context) where T : class 
    { 
     int totalCount; 
     var query = PrepareQuery(vm, whereCollection, context, out totalCount); 

     return new PagedResult<T> 
     { 
      Results = await query.ToListAsync(), 
      Page = vm.Page, 
      PageSize = vm.PageSize, 
      Total = totalCount 
     }; 
    } 
    public static async Task<PagedResult<TAs>> PagedResultAsAsync<T, TAs>(this PaginatedSearchBase vm, ICollection<Expression<Func<T, bool>>> whereCollection, IEnumerable<T> context, IMapper mapper) where T : class 
    { 
     int totalCount; 
     var query = PrepareQuery(vm, whereCollection, context, out totalCount); 

     return new PagedResult<TAs> 
     { 
----------> Results = await query.ProjectTo<TAs>(mapper).ToListAsync(), 
      Page = vm.Page, 
      PageSize = vm.PageSize, 
      Total = totalCount 
     }; 
    } 

    private static IQueryable<T> PrepareQuery<T>(PaginatedSearchBase vm, ICollection<Expression<Func<T, bool>>> whereCollection, IEnumerable<T> context, 
     out int totalCount) where T : class 
    { 
     var query = context.AsQueryable(); 
     if (whereCollection != null) 
     { 
      foreach (var w in whereCollection) 
      { 
       if (w != null) 
       { 
        query = query.Where(w); 
       } 
      } 
     } 
     // Order by 
     query = query.OrderBy($"{vm.OrderBy} {(vm.OrderDescending ? "DESC" : "ASC")}"); 

     // Total rows 
     totalCount = query.Count(); 

     // Paging 
     query = query.Skip((vm.Page - 1)*vm.PageSize).Take(vm.PageSize); 
     return query; 
    } 
} 

Informationen nennt, ich bin mit Versionen:

  • "Autofac": " 4.0.0-rc1-177 "
  • "Autofac.Extensions.DependencyInjection": "4.0.0-rc1-177"
  • "AutoMapper": "4.2.1"

Edit:

Ein neuer Test, dass ich hat zu überprüfen, ob die Zuordnungen wirklich funktionieren:

var mapper = _container.Resolve<IMapper>(); 
     var p = new Patient(); 
     p.Naam = "Test"; 
     var vm = mapper.Map<PatientViewModel>(p); 

     vm.Naam.ShouldBeEquivalentTo("Test"); 

Dieser Test

geht

Edit 2:

Wenn ich die Karte <> in einer Select() statt, es funktioniert auch, es ist also wirklich die ProjectTo <>(), die fehlschlägt:

var results = await query.ToListAsync(); 
     return new PagedResult<TAs> 
     { 
      Results = results.Select(mapper.Map<TAs>).ToList(), 
      Page = vm.Page, 
      PageSize = vm.PageSize, 
      Total = totalCount 
     }; 

Dies funktioniert, aber es erfordert, dass der Mapper einbezogen wird und nicht injiziert wird, und er verwendet nicht den ProjectTo, den Automapper für den Datenbankzugriff hat ...

+0

Sie können versuchen, "mit AutoMapper.QueryableExtensions;" –

+0

Ich verwende Visual Studio zum code, der Compiler gibt einen Fehler, wenn es nicht in den 'usings' ist. Die Methode wird aufgerufen, sie kann jedoch nicht die Instanz von IMapper oder etwas erhalten. Sie findet die Map nicht. – AppSum

Antwort

8

Ich stieß auf das gleiche Problem, schaffte es aber, dass es funktionierte. Dies geschieht aufgrund der kürzlichen Verschiebung durch Automapper, da die gesamte API keine statischen Methoden verwendet.Da nun alles instanzbasiert ist, kennen die statischen Erweiterungsmethoden die Mapping-Konfiguration nicht mehr und müssen nun an die Methode übergeben werden. Ich beenden eine Instanz der MapperConfiguration als IConfigurationProvider up Registrierung (Ich bin mit Unity)

container.RegisterInstance(typeof (IConfigurationProvider), config); 

Dieser in meinen Abfrage-Handler injiziert wird:

[Dependency] 
public IConfigurationProvider MapperConfigurationProvider { get; set; } 

Schließlich ist der MapperConfigurationProvider an den Aufruf übergeben wird ProjectTo:

.ProjectTo<Payment>(MapperConfigurationProvider); 

Hoffe, das hilft.

+3

Danke, Hinzufügen des MapperConfigurationProvider in der Tat löste das Problem! Da mein PagedResultAsAsync statisch ist, injiziere ich den IMapper in meine Methode. Ich bevorzuge es, IMapper zu injizieren, da ich bei Bedarf die mapper.Map() verwenden kann. Ich habe meine Anweisung wie folgt geändert: query.ProjectTo (mapper.ConfigurationProvider) .ToListAsync() – AppSum