Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Automapper mapping to an interface: "TypeLoadException" exception

I'm working on an MVC application that uses Inversion of Control and consequently makes extensive uses of interface types, concrete implementations being injected by a dependency resolver as required. The entity interfaces inherit from a base interface that describes some basic management features for the entities. ViewModels are also widely used.

The app uses Automapper and I have created mappings from view models to various entity interfaces. The mapping configuration validates correctly. However, when I call Automapper to perform a mapping, the code fails with a TypeLoadException.

I believe Automapper is capable of mapping to interfaces (see this from Jimmy Bogard).

It seems possible that the Automapper proxy generator has omitted to add MyMethod() to the proxy and this is causing an exception when Reflection tries to create the type.

If that's not the case, how do I get this map to work? Have I missed something obvious?

Here's a simplified console app that demonstrates the scenario, and which reproduces the error when run:

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

The exception thrown is:

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)
like image 507
Paul Taylor Avatar asked Aug 30 '13 14:08

Paul Taylor


1 Answers

When using an interface as a destination, AutoMapper will create a proxy type for you, but this only supports properties.

To get around the issue you can tell AutoMapper how the destination object should be constructed using ConstructUsing on your mapping, so in your example above your create map would look like this...

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

For reference I found this out from this SO article : https://stackoverflow.com/a/17244307/718672

like image 127
Sean Avatar answered Sep 21 '22 14:09

Sean