Open Closed

Migrating from 6.0 to 8.6 mapping issue #9053


0
amrsaafan created

Hello,

I am doing a migration from version 6.0 to version 8.6, I know that

AutoMapper.Mapper.Map<entityX, entityXDto>(result);

is no longer working and you have to use this instead:

ObjectMapper.Map<entityXDto>(result);

but in the run time when I call this line

ObjectMapper.Map<entityXDto>(result);

I get this error: Error mapping types. AutoMapper.AutoMapperMappingException: Error mapping types. AutoMapper.AutoMapperMappingException: Missing type map configuration or unsupported mapping.

The fix is to create a map in CustomDtoMapper

configuration.CreateMap<entityX, entityXDto>();

Now I have like hundreds of mapping in my application and I want a dynamic way to do the mapping instead of create a custom map for each type which will take forever to do.

Thank you, Amr Saafan https://www.nilebits.com/


5 Answer(s)
  • 0
    maliming created
    Support Team

    hi

    Mainly because automapper has changed.

    https://github.com/aspnetboilerplate/aspnetboilerplate/issues/4724#issuecomment-515679300

    Now I have like hundreds of mapping in my application and I want a dynamic way to do the mapping

    You can reflect the assembly to create a map based on your naming rules.

    entityX => entityXDto
    
    entityY => entityYDto
    
    
  • 0
    amrsaafan created

    Yes how can I do that? is there an example of how to do this? how to reflect the assembly and what about the naming rules? is it related to the assembly name or the types names?

    Thanks, Amr Saafan https://www.nilebits.com/

  • 0
    ismcagdas created
    Support Team
  • 0
    amrsaafan created

    Thank you @ismcagdas for your reply but this only answer one of my questions which is where but what about my other questions?

    Yes how can I do that? is there an example of how to do this? how to reflect the assembly and what about the naming rules? is it related to the assembly name or the types names?

    I already did research and I think this is the code you are talking about: var assemblies = AppDomain.CurrentDomain.GetAssemblies(); configuration.AddMaps(assemblies);

    This works only for AutoMapper.Profile definitions and classes decorated with AutoMapper.AutoMapAttribute. But the legacy code that exisits in version 6.0, is not having profiles or AutoMapAttribute.

    How can we do the assembly scan in this case?

    Thanks, Amr Saafan https://www.nilebits.com/

  • 0
    maliming created
    Support Team

    hi @amrsaafan

    The following code configures the automapper through reflection. For reference only, you can change it according to the actual situation.

    public interface IEntity<TKey>
    {
    	public TKey Id { get; set; }
    }
    
    public class User : IEntity<int>
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; }
    }
    
    
    public class UserOutput
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; }
    }
    
    public class CreateUserInput
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; } = "Create User name";
    }
    
    public class UpdateUserInput
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; } = "Update User name";
    }
    
    
    public class Role : IEntity<int>
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; }
    }
    
    public class RoleOutput
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; }
    }
    
    public class CreateRoleInput
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; } = "Create Role name";
    }
    
    public class UpdateRoleInput
    {
    	public int Id { get; set; }
    
    	public string Name { get; set; } = "Update Role name";
    }
    
    
    class Program
    {
    	static void Main(string[] args)
    	{
    
    		var configuration = new MapperConfiguration(cfg =>
    		{
    			var entities = typeof(Program).Assembly.GetTypes().Where(x =>
    				x.IsClass && x.GetInterfaces().Where(i => i.IsGenericType)
    					.Any(i => i.GetGenericTypeDefinition() == typeof(IEntity<>)));
    
    			foreach (var entity in entities)
    			{
    				var createOrUpdateEntityInputs = typeof(Program).Assembly.GetTypes()
    					.Where(x => x.IsClass && (x.Name == "Create" + entity.Name + "Input" || x.Name == "Update" + entity.Name + "Input"));
    				foreach (var dto in createOrUpdateEntityInputs)
    				{
    					cfg.CreateMap(dto, entity);
    				}
    
    				var outputDto = typeof(Program).Assembly.GetTypes()
    					.Where(x => x.IsClass && x.Name == entity.Name + "Output");
    
    				foreach (var dto in outputDto)
    				{
    					cfg.CreateMap(entity, dto);
    				}
    			}
    		});
    
    		var mapper = configuration.CreateMapper();
    
    		var createUserInput = new CreateUserInput();
    		var user = mapper.Map<User>(createUserInput);
    		var userOutput = mapper.Map<UserOutput>(user);
    
    		var createRoleInput = new CreateRoleInput();;
    		var role = mapper.Map<Role>(createRoleInput);
    		var roleOutput = mapper.Map<RoleOutput>(role);
    
    		Console.WriteLine(userOutput.Name);
    		Console.WriteLine(roleOutput.Name);
    
    		Console.WriteLine("Hello World!");
    	}
    }