Skip to content

Troubleshooting

Arnel Robles edited this page Sep 28, 2026 · 1 revision

Troubleshooting

Common Issues

Issue: Properties Not Mapping

Symptom: Destination properties remain default/null after mapping

Causes & Solutions:

  1. Property name mismatch

    // Problem: Source has "UserName", destination has "Name"
    
    // Solution 1: Use [MapFrom] attribute
    public class UserDto
    {
        [MapFrom("UserName")]
        public string Name { get; set; }
    }
    
    // Solution 2: Use Fluent configuration
    cfg.CreateMap<User, UserDto>()
        .ForMember(d => d.Name, opt => opt.MapFrom(s => s.UserName));
  2. Property not readable/writable

    // ❌ Won't map (no setter)
    public string Name { get; }
    
    // ✅ Will map
    public string Name { get; set; }
    
    // ✅ Also works (init setter)
    public string Name { get; init; }
  3. Type incompatibility

    // Check which properties can't map
    var unmapped = Mapper.GetUnmappedProperties<User, UserDto>();
    Console.WriteLine($"Unmapped: {string.Join(", ", unmapped)}");

Issue: StackOverflowException

Cause: Circular references exceeding MaxDepth (default 32)

Solutions:

// Solution 1: Increase depth limit
Mapper.MaxDepth = 64;

// Solution 2: Enable logging to see depth warnings
Mapper.Logger = msg => Console.WriteLine($"[Mapsicle] {msg}");

// Solution 3: Use [IgnoreMap] to break cycle
public class User
{
    public int Id { get; set; }

    [IgnoreMap]  // Don't map back to parent
    public List<Order> Orders { get; set; }
}

Issue: Poor Collection Mapping Performance

Symptom: Mapping 10,000+ items is slow

Solutions:

// ❌ Don't: Map items individually
foreach (var user in users)
{
    dtos.Add(user.MapTo<UserDto>());
}

// ✅ Do: Map entire collection
var dtos = users.MapTo<UserDto>();  // 20% faster with cached mapper

// ✅ Do: Pre-warm cache at startup for frequently used types
new User().MapTo<UserDto>();
new Order().MapTo<OrderDto>();

Issue: Memory Growth in Long-Running Apps

Symptom: Memory usage grows over time

Cause: Unbounded cache with many dynamic type combinations

Solution:

// Enable memory-bounded LRU cache
Mapper.UseLruCache = true;
Mapper.MaxCacheSize = 1000;  // Adjust based on # of unique type pairs

// Monitor cache performance
var stats = Mapper.CacheInfo();
if (stats.HitRatio < 0.8)
{
    // Consider increasing cache size
    Mapper.MaxCacheSize = 2000;
}

Issue: EF Core ProjectTo Not Working

Symptom: Exception thrown or results incorrect

Common Causes:

  1. Missing configuration

    // ❌ Don't use convention mapping with complex expressions
    var dtos = context.Orders.ProjectTo<Order, OrderDto>().ToList();
    
    // ✅ Pass configuration for ForMember expressions
    var config = new MapperConfiguration(cfg =>
    {
        cfg.CreateMap<Order, OrderDto>()
            .ForMember(d => d.CustomerName, opt => opt.MapFrom(s => s.Customer.Name));
    });
    var dtos = context.Orders.ProjectTo<Order, OrderDto>(config).ToList();
  2. Non-translatable expressions

    // ❌ Method calls that don't translate to SQL
    cfg.CreateMap<User, UserDto>()
        .ForMember(d => d.Name, opt => opt.ResolveUsing(u => FormatName(u)));
    
    // ✅ Use expressions that translate to SQL
    cfg.CreateMap<User, UserDto>()
        .ForMember(d => d.Name, opt => opt.MapFrom(u => u.FirstName + " " + u.LastName));

Debugging Tips

// 1. Enable verbose logging
Mapper.Logger = msg => _logger.LogDebug($"[Mapsicle] {msg}");

// 2. Validate mapping at startup
#if DEBUG
Mapper.AssertMappingValid<User, UserDto>();
#endif

// 3. Check configuration in fluent mapper
config.AssertConfigurationIsValid();

// 4. Monitor cache statistics
var stats = Mapper.CacheInfo();
_logger.LogInformation($"Cache: {stats.Total} entries, Hit ratio: {stats.HitRatio:P1}");

// 5. Use MapperFactory for isolated testing
using var mapper = MapperFactory.Create(new MapperOptions
{
    MaxDepth = 16,
    Logger = Console.WriteLine
});
var dto = mapper.MapTo<UserDto>(user);

Clone this wiki locally