2013-08-30 9 views
8

Sto lavorando a un'applicazione MVC che utilizza Inversion of Control e di conseguenza utilizza estensivamente i tipi di interfaccia, le implementazioni concrete vengono iniettate da un resolver di dipendenza come richiesto. Le interfacce di entità ereditano da un'interfaccia di base che descrive alcune funzionalità di gestione di base per le entità. I ViewModels sono anche ampiamente usati.Mappatura automapper a un'interfaccia: eccezione "Metodo non implementato"

L'app utilizza Automapper e ho creato mappature da modelli di visualizzazione a varie interfacce di entità. La configurazione di mappatura si convalida correttamente. Tuttavia, quando chiamo Automapper per eseguire una mappatura, il codice non riesce con un TypeLoadException.

Credo che Automapper sia in grado di eseguire il mapping alle interfacce (vedere this di Jimmy Bogard).

Sembra possibile che il generatore di proxy Automapper abbia omesso di aggiungere MyMethod() al proxy e ciò sta causando un'eccezione quando Reflection tenta di creare il tipo.

Se non è questo il caso, come faccio a far funzionare questa mappa? Ho perso qualcosa di ovvio?

Ecco una console app semplificato che dimostra lo scenario, e che riproduce l'errore quando esegue:

public interface IEntity 
{ 
    string Foo { get; set; } 
    string Bar { get; set; } 
    string MyMethod(); 
} 

public class MyEntity : IEntity 
{ 
    public string Foo { get; set; } 
    public string Bar { get; set; } 
    public string MyMethod() 
    { 
     throw new NotImplementedException(); 
    } 
} 

public class MyViewModel 
{ 
    public string Foo { get; set; } 
    public string Bar { get; set; } 
} 

class Program 
{ 
    static void Main(string[] args) 
    { 
     AutomapperConfig(); 
     MyViewModel vm = new MyViewModel { Foo = "Hello", Bar = "World" }; 
     IEntity e = Mapper.Map<MyViewModel, IEntity>(vm); 
     Console.WriteLine(string.Format("{0} {1}", e.Foo, e.Bar)); 
    } 

    private static void AutomapperConfig() 
    { 
     Mapper.Initialize(cfg => { 
      cfg.CreateMap<MyViewModel, IEntity>(); 
     }); 
     Mapper.AssertConfigurationIsValid(); 
    } 
} 

L'eccezione generata è:

InnerException: System.TypeLoadException 
    HResult=-2146233054 
    Message=Method 'MyMethod' in type 'Proxy<AutomapperException.IEntity_AutomapperException_Version=1.0.0.0_Culture=neutral_PublicKeyToken=null>' from assembly 'AutoMapper.Proxies, Version=0.0.0.0, Culture=neutral, PublicKeyToken=be96cd2c38ef1005' does not have an implementation. 
    Source=mscorlib 
    TypeName=Proxy<AutomapperException.IEntity_AutomapperException_Version=1.0.0.0_Culture=neutral_PublicKeyToken=null> 
    StackTrace: 
     at System.Reflection.Emit.TypeBuilder.TermCreateClass(RuntimeModule module, Int32 tk, ObjectHandleOnStack type) 
     at System.Reflection.Emit.TypeBuilder.CreateTypeNoLock() 
     at System.Reflection.Emit.TypeBuilder.CreateType() 
     at AutoMapper.Impl.ProxyGenerator.CreateProxyType(Type interfaceType) 
     at AutoMapper.Impl.ProxyGenerator.GetProxyType(Type interfaceType) 
     at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.CreateObject(ResolutionContext context) 
     at AutoMapper.Mappers.TypeMapObjectMapperRegistry.NewObjectPropertyMapMappingStrategy.GetMappedObject(ResolutionContext context, IMappingEngineRunner mapper) 
     at AutoMapper.Mappers.TypeMapObjectMapperRegistry.PropertyMapMappingStrategy.Map(ResolutionContext context, IMappingEngineRunner mapper) 
     at AutoMapper.Mappers.TypeMapMapper.Map(ResolutionContext context, IMappingEngineRunner mapper) 
     at AutoMapper.MappingEngine.AutoMapper.IMappingEngineRunner.Map(ResolutionContext context) 

risposta

7

Quando si utilizza un'interfaccia come una destinazione, automapper creerà un tipo di proxy per te, ma questo supporta solo le proprietà.

per aggirare il problema si può dire automapper come l'oggetto di destinazione dovrebbe essere costruito utilizzando ConstructUsing sulla mappatura, così nel tuo esempio sopra la mappa creare sarebbe simile a questa ...

cfg.CreateMap<MyViewModel, IEntity>().ConstructUsing((ResolutionContext rc) => new MyEntity()); 

Per riferimento Ho trovato questo da questo articolo SO: https://stackoverflow.com/a/17244307/718672