AutoMapper throwing "No default constructor" during validation
Asked Answered
S

2

17

I have classes to map, but they don't have default constructors, and I don't want them to have. This is because I only map to/from already existing objects.

public class Order
{
    public string OrderName { get; set; }
    public Order(string name) 
    { 
        this.OrderName = name; 
    }
}

public class OrderProcessor
{
    private IService service;
    public string OrderName { get; set; }

    public OrderProcessor(IService service)
    { 
        this.service = service; 
        Mapper.Initialize(config => config.CreateMap<Order, OrderProcessor>());
    }

    public void Init()
    { 
        var order = this.service.GetOrder();

        // this works
        Mapper.Map(order, this);

        // this fails
        Mapper.Configuration.AssertConfigurationIsValid();
    }
}

AutoMapper.AutoMapperConfigurationException : 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

Order -> OrderProcessor (Destination member list)

No available constructor.

at Test() in Tests.cs:line

How to make configuration assert pass and why it fails when I don't want to create new objects?

Shortterm answered 25/4, 2017 at 9:37 Comment(0)
C
33

I also stumbled onto this problem after recently upgrading from Automapper 4.x to 6.x.

You need to tell AutoMapper that you don't intend to have it construct the destination type by calling CreateMap<TSource, TDest>().DisableCtorValidation().

As per the method documentation:

    // Summary:
    //     Disable constructor validation. During mapping this map is used 
    //     against an existing destination object and never constructed itself.
    //
Cicatrize answered 4/7, 2017 at 13:2 Comment(4)
Bingo, this is exactly what I've searched for. Tested and works. Thank you.Shortterm
How do I add this for Map<TDestination>(object source, Action<IMappingOperationOptions> opts) implementation? I am really new to thisMatzo
@VaibhawKumar, it should affect all uses of the map. CreateMap defines the mapping between two types. The Map method you show above will still be doing a conversion between the actual runtime type of the source object to the TDestination type. It has been a while since I've worked on this, but I think you can also say mappingConfig.ForAll(map => map.DisableCtorValidation()) - but this is just pseudo-ish code. You'll have to elaborate or me to be more specific.Cicatrize
This is specially helpful and a must-have in DDD when you're trying to map from database entities back to domain models, where usually you would have private setters and no default constructor!!!Jasso
J
3

You need to use .ConstructUsing(), as your type does not have a parameter-less constructor...

So something like;

 Mapper.Initialize(config => 
    config.CreateMap<Order, OrderProcessor>()
    .ConstructUsing(x => new OrderProcessor(new WhateverService()));
);

You may obviously need to resolve WhateverService using whatever DI Framework you are using....

Jowett answered 25/4, 2017 at 9:43 Comment(5)
My OrderProcessor in reality has couple more dependencies. Resolving them manually during mapping is not a way to go. Also, in reality OrderProcessor is a ViewModel, which cannot be recreated (for sample I used simplistic version).Shortterm
What do you mean it 'cannot be recreated'? Sadly you will have to either do this, or not use Automapper...Jowett
Only alternative is writing your own Mapping Extension, which uses the DI Framework... but this will actually be more work and overkill in your situation. If you want to try that here is documentation from automapper which explains it: github.com/AutoMapper/AutoMapper/wiki/Dependency-injectionJowett
So I have an OrderViewModel that has binding properties. I wanted to map them from OrderModel when some ICommand is executed in OrderViewModel. So I assume I shouldn't recreate OrderViewModel, when it is already binded to View and being displayed.Shortterm
I have no idea what you mean... That does not make senseJowett

© 2022 - 2024 — McMap. All rights reserved.