Avoid InvalidCastException when using ConvertTo() method

Whenever converting a more complex POCO to a DTO, I first use the ConvertTo() extension helper to copy the simple properties over. Unfortunately, it also tries to copy the more complex objects over (e.g. List of objects) resulting in a whole bunch of System.InvalidCastException exceptions with similar messages:

Message	"Unable to cast object of type 'System.Collections.Generic.HashSet`1[MyProduct.MyEntity]' to type 'System.Collections.Generic.List`1[MyProduct.Dtos.MyEntityDto]'."

Is there any way to avoid these exceptions without going through each property and assigning them manually?

There is a new AutoMapping.RegisterConverter() API in v5.4.1 on MyGet you can use to override what AutoMapping Utils uses to convert different types.

Otherwise you can use any Attribute you like to ignore the property and use the PopulateFromPropertiesWithoutAttribute() extension method to populate all other properties.

FYI I’ve improved support for Auto Mapping where you can register a single converter for mapping different POCO types and it will handle converting elements in different collections.

Here’s an example from AutoMappingCustomConverterTests.cs:

You can register mappings to use when mapping between different types, e.g. here’s an example from mapping between a User model to a UserDto model which only contains string Car property that we also register a mapping for.

Converters should be configured once on Startup:

AutoMapping.RegisterConverter((User from) => 
    from.ConvertTo<UserDto>(skipConverters:true)); // avoid infinite recursion
AutoMapping.RegisterConverter((Car from) => $$"{from.Name} ({from.Age})");

Which will then be used when mapping to different types including nested types, e.g:

// Data Models
public class UsersData
{
    public int Id { get; set; }
    public List<User> Users { get; set; }
}

public class User
{
    public string FirstName { get; set; }
    [DataMember]
    public string LastName { get; set; }
    public Car Car { get; set; }
}

public class Car
{
    public string Name { get; set; }
    public int Age { get; set; }
}

// DTOs
public class UsersDto
{
    public int Id { get; set; }
    public List<UserDto> Users { get; set; }
}

public class UserDto
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Car { get; set; }
}

Which you can convert as normal:

var users = new UsersData {
    Id = 1,
    Users = new List<User> {
        new User {
            FirstName = "John",
            LastName = "Doe",
            Car = new Car { Name = "BMW X6", Age = 3 }
        }
    }
};

var dtoUsers = users.ConvertTo<UsersDto>();

dtoUsers.PrintDump();

Which will output:

{
	Id: 1,
	Users: 
	[
		{
			FirstName: John,
			LastName: Doe,
			Car: BMW X6 (3)
		}
	]
}

I’ve also added support for ignoring mappings with the new AutoMapping.IgnoreMapping API, e.g: you can ignore mapping the Users Collection with:

AutoMapping.IgnoreMapping<List<User>, List<UserDto>>();

At which point that explicit mapping will be ignored:

var dtoUsers = users.ConvertTo<UsersDto>();

dtoUsers.PrintDump();

Now prints out:

{
	Id: 1
}

This latest change is available from v5.4.1 that’s now available on MyGet. If you previously had v5.4.1 installed you’ll need to clear your NuGet packages cache to download the latest version.

Hey, thanks for the suggestions and enhancement. However, since I’m doing the conversion inside a reusable library I’m inclined to declare attributes for complex properties and use the PopulateFromPropertiesWithoutAttribute() method.