Reputation: 181
I'm struggling to understand what I'm doing wrong here. I've been using Automapper + Automapper.Attributes (https://github.com/schneidenbach/AutoMapper.Attributes) in a solution and recently I've had to split my API project out into a "core" library and the original API. Automapper is not able to create a map when the class files are move outside of the API project. I have setup a demo project with the following structure to confirm this issue: (Available here: https://github.com/greghesom/AutoMapper_Example)
API.Core - Dog Class
namespace API.Core
{
public class Dog
{
public string Name { get; set; }
}
}
API.Core - Pet Class
namespace API.Core
{
[MapsTo(typeof(Dog))]
public class Pet
{
[MapsToProperty(typeof(Dog), "Name")] //Edit: Fixed this typo
public string PetName { get; set; }
}
}
API - Person Class
namespace API.Models
{
[MapsTo(typeof(Customer))]
public class Person
{
[MapsToProperty(typeof(Customer), "FirstName")]
public string Name { get; set; }
}
}
API - Customer Class
namespace API.Models
{
public class Customer
{
public string FirstName { get; set; }
}
}
API - Startup
AutoMapper.Mapper.Initialize(cfg => {
typeof(API.WebApiConfig).Assembly.MapTypes(cfg);
});
API - Controller
var person = new Person { Name = "John" };
var customer = AutoMapper.Mapper.Map<Customer>(person);//This Works
var dog = new Dog { Name = "Lucky" };
var pet = AutoMapper.Mapper.Map<Pet>(dog);//This throws exception
EXCEPTION:
An error has occurred. Unmapped members were found. Review the types and members below. Add a custom mapping expression, ignore, add a custom resolver, or modify the source/destination type For no matching constructor, add a no-arg ctor, add optional arguments, or map all of the constructor parameters ============================= AutoMapper created this type map for you, but your types cannot be mapped using the current configuration. Dog -> Pet (Destination member list) API.Core.Dog -> API.Core.Pet (Destination member list)
Unmapped properties: PetName AutoMapper.AutoMapperConfigurationException at lambda_method(Closure , Dog , Pet , ResolutionContext ) at lambda_method(Closure , Object , Object , ResolutionContext ) at API.Controllers.ValuesController.Get() in c:\users\greg\Source\Repos\AutoMapperTest\API\Controllers\ValuesController.cs:line 26 at lambda_method(Closure , Object , Object[] ) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.Execute(Object instance, Object[] arguments) at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken) --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext() --- End of stack trace from previous location where exception was thrown --- at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()
Upvotes: 3
Views: 5581
Reputation: 111
I ran into the same issue (AutoMapper 7.0.0). The key to the problem is in the error message: "AutoMapper created this type map for you, but your types cannot be mapped using the current configuration". From 6.2.0 onwards AutoMapper tries to create mappings itself for types that aren't explicitly mapped, ie: in a lot of cases it's no longer needed to create a mapping.
However, it seems that it's using the mappings it creates itself instead of your defined mappings, even for the types you explicitly defined them for. At least, that's what I ran into.
A quick way to check this: downgrade to version 6.1.1, and see if the problem still occurs. In my case, the downgrade solved the issue.
I do have a feeling there must be a better way to fix this (or maybe it's even a bug...), but I don't know how yet. In case I find it, I'll post back here. Just figured I'd thrown this out here already in case you need a quick fix :)
Upvotes: 4
Reputation: 10849
MapsToProperty on PetName of Pet class is declared incorrectly. It should be typeof(Dog) instead of typeof(Pet).
[MapsTo(typeof(Dog))]
public class Pet
{
[MapsToProperty(typeof(Dog), "Name")]
public string PetName { get; set; }
}
Edit
Since you have defined the Mapping for Person
to Customer
mapping that's in your question it worked. But in case of Dog
, you have defined the mapping for Pet
to Dog
but you are trying to map dog
object to pet
object (but the mapping does not exist).
If you are required two way mapping, then would suggest you to define the mapping using MapsToAndFromProperty
.
Check this link for further details.
Upvotes: 0