-
Notifications
You must be signed in to change notification settings - Fork 1
Troubleshooting
Arnel Robles edited this page Sep 28, 2026
·
1 revision
Symptom: Destination properties remain default/null after mapping
Causes & Solutions:
-
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));
-
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; }
-
Type incompatibility
// Check which properties can't map var unmapped = Mapper.GetUnmappedProperties<User, UserDto>(); Console.WriteLine($"Unmapped: {string.Join(", ", unmapped)}");
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; }
}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>();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;
}Symptom: Exception thrown or results incorrect
Common Causes:
-
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();
-
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));
// 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);Mapsicle
Packages
- Core
- Fluent
- EntityFramework
- Validation
- NamingConventions
- Serilog
- Dapper
- AspNetCore
- Json
- Caching
- Audit
- DataAnnotations
Reference