Mapsicle.Caching
1.2.2
dotnet add package Mapsicle.Caching --version 1.2.2
NuGet\Install-Package Mapsicle.Caching -Version 1.2.2
<PackageReference Include="Mapsicle.Caching" Version="1.2.2" />
<PackageVersion Include="Mapsicle.Caching" Version="1.2.2" />
<PackageReference Include="Mapsicle.Caching" />
paket add Mapsicle.Caching --version 1.2.2
#r "nuget: Mapsicle.Caching, 1.2.2"
#:package Mapsicle.Caching@1.2.2
#addin nuget:?package=Mapsicle.Caching&version=1.2.2
#tool nuget:?package=Mapsicle.Caching&version=1.2.2
Mapsicle π¦
Mapsicle is a high-performance, modular object mapping ecosystem for .NET. Choose only what you need:
| Package | Purpose | Dependencies |
|---|---|---|
| Mapsicle | Zero-config mapping | None |
| Mapsicle.Fluent | Fluent configuration + Profiles | Mapsicle |
| Mapsicle.EntityFramework | EF Core ProjectTo<T>() |
Mapsicle.Fluent |
| Mapsicle.Validation | FluentValidation integration | Mapsicle.Fluent |
| Mapsicle.NamingConventions | Naming convention support | Mapsicle.Fluent |
| Mapsicle.Json | JSON serialization integration | Mapsicle.Fluent |
| Mapsicle.AspNetCore | ASP.NET Core Minimal API helpers | Mapsicle.Validation |
| Mapsicle.Caching | Memory/Distributed cache support | Mapsicle.Fluent |
| Mapsicle.Audit | Change tracking/diff detection | Mapsicle.Fluent |
| Mapsicle.DataAnnotations | DataAnnotations validation | Mapsicle.Fluent |
The core
Mapsiclepackage has zero dependencies. Extension packages introduce their respective third-party dependencies (listed in the table above).
"The fastest mapping is the one you don't have to configure."
π Why Choose Mapsicle?
β οΈ AutoMapper is now commercial software. As of July 2025, AutoMapper requires a paid license for commercial use. Mapsicle is 100% free and MPL 2.0 licensed forever.
Quick Comparison
| Feature | Mapsicle | AutoMapper | Mapperly |
|---|---|---|---|
| License | MPL 2.0 (Free) | Commercial | MIT (Free) |
| Architecture | Runtime + Caching | Runtime + Expressions | Source Generator |
| Setup Required | None | Profiles, DI | Partial class |
| Dependencies | 0 (core) | 5+ | 0 (compile-time) |
| Compile-time Safety | Partial | No | Full |
| AOT Compatible | Partial | No | Yes |
| Circular Refs | Handled | Crash | N/A |
| Memory Bounded | LRU Option | No | N/A |
| Cache Statistics | Yes | No | N/A |
| Integrated Validation | Yes | No | No |
| ASP.NET Core Helpers | Yes | No | No |
π Detailed Comparison: Mapsicle vs AutoMapper vs Mapperly
Core Mapping Features
| Feature | Mapsicle | AutoMapper | Mapperly |
|---|---|---|---|
| Convention-based mapping | β | β | β |
Flattening (Address.City β AddressCity) |
β | β | β |
| Custom member mapping | β
ForMember() |
β
ForMember() |
β
[MapProperty] |
| Ignore members | β
[IgnoreMap] |
β
Ignore() |
β
[MapperIgnore] |
| Reverse mapping | β
ReverseMap() |
β
ReverseMap() |
β (define both) |
| Before/After map hooks | β | β | β |
| Type converters | β
CreateConverter<>() |
β
ConvertUsing() |
β User methods |
| Inheritance/Polymorphism | β
Include<>() |
β
Include<>() |
β |
| Nested object mapping | β | β | β |
| Collection mapping | β | β | β |
| Constructor mapping | β
ConstructUsing() |
β
ConstructUsing() |
β (automatic) |
Configuration & Organization
| Feature | Mapsicle | AutoMapper | Mapperly |
|---|---|---|---|
| Profile support | β
MapsicleProfile |
β
Profile |
β (partial classes) |
| Fluent configuration | β | β | β (attributes) |
| Attribute-based config | β
[MapFrom] |
β | β |
| Static zero-config API | β
obj.MapTo<T>() |
β | β |
| DI-friendly | β
IMapper |
β
IMapper |
β |
| Assembly scanning | β | β | N/A |
Extension Packages
| Package/Feature | Mapsicle | AutoMapper | Mapperly |
|---|---|---|---|
| EF Core ProjectTo | β
Mapsicle.EntityFramework |
β Built-in | β (expressions) |
| FluentValidation | β
Mapsicle.Validation |
β | β |
| DataAnnotations | β
Mapsicle.DataAnnotations |
β | β |
| JSON serialization | β
Mapsicle.Json |
β | β |
| ASP.NET Core | β
Mapsicle.AspNetCore |
β | β |
| Caching | β
Mapsicle.Caching |
β | N/A |
| Audit/Change tracking | β
Mapsicle.Audit |
β | β |
| Naming conventions | β 5 conventions | β Built-in | β
NamingStrategy |
Naming Convention Support
| Convention | Mapsicle | AutoMapper | Mapperly |
|---|---|---|---|
| PascalCase | β | β | β |
| camelCase | β | β | β |
| snake_case | β | β | β |
| kebab-case | β | β | β |
| SCREAMING_SNAKE_CASE | β | β | β |
Performance Characteristics
| Aspect | Mapsicle | AutoMapper | Mapperly |
|---|---|---|---|
| First map overhead | Medium | Medium-High | None |
| Subsequent maps | Fast | Fast | Fastest |
| Memory footprint | Low-Medium | Medium | Lowest |
| Startup time impact | Low | Medium | None |
| AOT compatible | Partial | No | Yes |
When to Use Each
| Scenario | Recommendation |
|---|---|
| Maximum performance, AOT required | Mapperly |
| Compile-time safety is critical | Mapperly |
| Quick prototyping, zero setup | Mapsicle (static API) |
| Need integrated validation | Mapsicle |
| Existing AutoMapper codebase | AutoMapper (if licensed) or migrate |
| Budget-conscious / OSS project | Mapsicle or Mapperly |
| Complex mapping configurations | AutoMapper or Mapsicle (fluent) |
| ASP.NET Core Minimal APIs | Mapsicle (AspNetCore package) |
| Need audit trail of changes | Mapsicle (Audit package) |
Code Comparison
Mapsicle (Static - Zero Config)
var dto = user.MapTo<UserDto>();
Mapsicle (Fluent)
var config = new MapperConfiguration(cfg => cfg.CreateMap<User, UserDto>());
var mapper = config.CreateMapper();
var dto = mapper.Map<UserDto>(user);
AutoMapper
var config = new MapperConfiguration(cfg => cfg.CreateMap<User, UserDto>());
var mapper = config.CreateMapper();
var dto = mapper.Map<UserDto>(user);
Mapperly
[Mapper]
public partial class UserMapper
{
public partial UserDto ToDto(User user);
}
// Usage
var dto = new UserMapper().ToDto(user);
Unique Mapsicle Features
Features not found in AutoMapper or Mapperly:
- Static zero-config API:
user.MapTo<UserDto>()- no setup required - Built-in validation integration: Map + validate in one call with FluentValidation or DataAnnotations
- Audit/diff tracking: Track what changed during mapping with
MapWithAudit<T>() - Caching integration: Cache mapped results with
IMemoryCache/IDistributedCache - ASP.NET Core IResult helpers:
MapValidateAndReturn<T, TValidator>() - JSON map-and-serialize:
MapToJson<T>(),MapFromJson<T>() - LRU cache option: Memory-bounded cache for long-running applications
π¦ Quick Start
Complete Example (Copy & Paste)
using Mapsicle;
// 1. Define your types
public class User
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string Email { get; set; }
}
public class UserDto
{
public int Id { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
}
// 2. Map - that's it! No configuration needed
var user = new User { Id = 1, FirstName = "John", LastName = "Doe", Email = "john@example.com" };
var dto = user.MapTo<UserDto>(); // FirstName and LastName copied automatically
// 3. Map collections
List<User> users = GetUsers();
List<UserDto> dtos = users.MapTo<UserDto>(); // Entire list mapped
Requirements: .NET Standard 2.0+ or .NET 6.0+
Installation: dotnet add package Mapsicle
Which Package Do I Need?
Do you need EF Core query translation (ProjectTo)?
ββ YES β Install: Mapsicle + Mapsicle.Fluent + Mapsicle.EntityFramework
ββ NO
ββ Do you need post-mapping validation?
β ββ YES β Install: Mapsicle + Mapsicle.Fluent + Mapsicle.Validation
ββ Do you need naming convention support (snake_case β PascalCase)?
β ββ YES β Install: Mapsicle + Mapsicle.Fluent + Mapsicle.NamingConventions
ββ Do you need custom mapping logic (ForMember, hooks)?
β ββ YES β Install: Mapsicle + Mapsicle.Fluent
ββ NO β Install: Mapsicle (core only - zero config)
| Scenario | Packages Needed |
|---|---|
| Simple POCO mapping | Mapsicle |
| API DTOs with transformations | Mapsicle.Fluent |
| EF Core with SQL projection | Mapsicle.EntityFramework |
| Map + validate DTOs | Mapsicle.Validation |
| snake_case β PascalCase mapping | Mapsicle.NamingConventions |
π Benchmark Results
Real benchmarks on Apple M1, .NET 8.0, BenchmarkDotNet v0.13.12:
Core Mapping Performance
| Scenario | Manual | Mapsicle | AutoMapper | Mapperly | Winner |
|---|---|---|---|---|---|
| Single Object | 13 ns | 26 ns | 54 ns | 13 ns | β Mapsicle (2.1x faster than AutoMapper) |
| Flattening | 13 ns | 29 ns | 56 ns | 15 ns | β Mapsicle (1.9x faster than AutoMapper) |
| Collection (100) | 1.5 ΞΌs | 2.0 ΞΌs | 1.9 ΞΌs | 1.5 ΞΌs | β Mapperly (Mapsicle uses 18% less memory) |
Note: Mapperly generates code at compile-time, resulting in near-manual performance. Mapsicle is now the fastest runtime-based mapper, outperforming AutoMapper by 2.1x for single objects and 1.9x for flattening, while using less memory for collections.
Edge Case Performance
| Scenario | Mapsicle | AutoMapper | Mapperly | Notes |
|---|---|---|---|---|
| Deep Nesting (15 levels) | β Safe | β Safe | β Safe | All handle with limits |
| Circular References | β Handled | β Crashes | β Compile error | Mapsicle wins |
| Large Collection (10K) | 4 ms | 4 ms | ~3.5 ms | Mapperly fastest |
| Parallel (1000 threads) | β Thread-safe | β Thread-safe | β Thread-safe | All thread-safe |
| Cold Start | Medium | Slow | None | Mapperly pre-compiled |
Performance Optimizations (v1.1+)
| Optimization | Improvement | Status |
|---|---|---|
| TypedMapperCache<T,D> | Zero-allocation generic cache | β NEW |
| MapTo<TSource,TDest>() | Strongly-typed mapping, no boxing | β NEW |
| Skip depth tracking for simple | No overhead for flat types | β NEW |
| Lock-free cache reads | Eliminates contention | β |
| Collection mapper caching | +20% for collections (v1.1) | β |
| PropertyInfo caching | +15% faster cold starts | β |
| Primitive fast path | Skips depth tracking | β |
| Cached compiled actions | No runtime reflection | β |
| LRU cache option | Memory-bounded in long-run apps | β |
| Collection pre-allocation | Capacity hints for known sizes | β |
Memory & Cache Statistics (v1.1+)
// Enable memory-bounded caching
Mapper.UseLruCache = true;
Mapper.MaxCacheSize = 1000; // Default
// Monitor cache performance
var stats = Mapper.CacheInfo();
Console.WriteLine($"Cache entries: {stats.Total}");
Console.WriteLine($"Hit ratio: {stats.HitRatio:P1}"); // Only when LRU enabled
Console.WriteLine($"Hits: {stats.Hits}, Misses: {stats.Misses}");
| Feature | Mapsicle (Unbounded) | Mapsicle (LRU) | AutoMapper |
|---|---|---|---|
| Memory Bounded | β | β | β |
| Cache Statistics | Entry count only | Full stats | β |
| Configurable Limit | β | β | β |
| Lock-Free Reads | β | β | Partial |
Smoke Test Results (10,000 mappings)
β Core: 10,000 mappings in 19ms
β Fluent: 10,000 mappings in 10ms
β Deep nesting (10 levels): 1,000 mappings in 3ms
β Large collection (10,000 items): 4ms
π‘ Key Insight: Mapsicle is now 2.1x faster than AutoMapper for single object mapping while maintaining zero-configuration simplicity. Both vastly outperform reflection-based approaches.
Run Benchmarks Yourself
cd tests/Mapsicle.Benchmarks
dotnet run -c Release # Full suite
dotnet run -c Release -- --quick # Smoke test
dotnet run -c Release -- --edge # Edge cases only
π¦ Installation
# Core package - zero config
dotnet add package Mapsicle
# Fluent configuration + Profiles (optional)
dotnet add package Mapsicle.Fluent
# EF Core ProjectTo (optional)
dotnet add package Mapsicle.EntityFramework
# FluentValidation integration (optional)
dotnet add package Mapsicle.Validation
# Naming conventions support (optional)
dotnet add package Mapsicle.NamingConventions
# Serilog structured logging (optional)
dotnet add package Mapsicle.Serilog
# Dapper integration (optional)
dotnet add package Mapsicle.Dapper
# JSON serialization (optional)
dotnet add package Mapsicle.Json
# ASP.NET Core Minimal API helpers (optional)
dotnet add package Mapsicle.AspNetCore
# Memory/Distributed caching (optional)
dotnet add package Mapsicle.Caching
# Change tracking/audit (optional)
dotnet add package Mapsicle.Audit
# DataAnnotations validation (optional)
dotnet add package Mapsicle.DataAnnotations
β‘ Package 1: Mapsicle (Core)
Basic Mapping
using Mapsicle;
var dto = user.MapTo<UserDto>(); // Single object
List<UserDto> dtos = users.MapTo<UserDto>(); // Collection
var flat = order.MapTo<OrderFlatDto>(); // Auto-flattening
Attributes
public class UserDto
{
[MapFrom("UserName")] // Map from different property
public string Name { get; set; }
[IgnoreMap] // Never mapped
public string Secret { get; set; }
}
Stability Features (NEW!)
// Cycle Detection - no more StackOverflow
Mapper.MaxDepth = 32; // Default, configurable
// Validation at startup
Mapper.AssertMappingValid<User, UserDto>();
// Logging
Mapper.Logger = Console.WriteLine;
// Memory-bounded caching (prevents memory leaks in long-running apps)
Mapper.UseLruCache = true; // Enable LRU cache
Mapper.MaxCacheSize = 1000; // Limit cache entries
// Cache statistics
var stats = Mapper.CacheInfo();
Console.WriteLine($"Hit ratio: {stats.HitRatio:P1}");
// Scoped instances with isolated caches
using var mapper = MapperFactory.Create();
var dto = mapper.MapTo<UserDto>(user); // Uses isolated cache
β‘ Package 2: Mapsicle.Fluent
Basic Configuration
using Mapsicle.Fluent;
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => $"{s.First} {s.Last}"))
.ForMember(d => d.Password, opt => opt.Ignore())
.ForMember(d => d.Status, opt => opt.Condition(s => s.IsActive));
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
DI Integration (NEW!)
// In Program.cs
services.AddMapsicle(cfg =>
{
cfg.CreateMap<User, UserDto>();
}, validateConfiguration: true);
// In your service
public class UserService(IMapper mapper)
{
public UserDto GetUser(User user) => mapper.Map<UserDto>(user);
}
Lifecycle Hooks (NEW!)
cfg.CreateMap<Order, OrderDto>()
.BeforeMap((src, dest) => dest.CreatedAt = DateTime.UtcNow)
.AfterMap((src, dest) => dest.WasProcessed = true);
Polymorphic Mapping (NEW!)
cfg.CreateMap<Vehicle, VehicleDto>()
.Include<Car, CarDto>()
.Include<Truck, TruckDto>();
Custom Construction (NEW!)
cfg.CreateMap<Order, OrderDto>()
.ConstructUsing(src => OrderFactory.Create(src.Type));
Global Type Converters (NEW!)
cfg.CreateConverter<Money, decimal>(m => m.Amount);
cfg.CreateConverter<Money, string>(m => $"{m.Currency} {m.Amount}");
β‘ Package 3: Mapsicle.EntityFramework
ProjectTo<T>() that translates to SQLβno in-memory loading!
using Mapsicle.EntityFramework;
var dtos = await _context.Users
.Where(u => u.IsActive)
.ProjectTo<UserEntity, UserDto>()
.ToListAsync();
// Flattening in SQL: Customer.Name β CustomerName
var orders = _context.Orders
.ProjectTo<OrderEntity, OrderFlatDto>()
.ToList();
ProjectTo with Fluent Configuration (NEW!)
// ForMember expressions are translated to SQL!
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<Order, OrderDto>()
.ForMember(d => d.CustomerName, opt => opt.MapFrom(s => s.Customer.FirstName + " " + s.Customer.LastName))
.ForMember(d => d.Total, opt => opt.MapFrom(s => s.Lines.Sum(l => l.Quantity * l.UnitPrice)));
});
// These expressions translate to SQL queries
var orders = _context.Orders.ProjectTo<Order, OrderDto>(config).ToList();
β‘ Package 4: Mapsicle.Validation
Post-mapping validation using FluentValidationβvalidate DTOs immediately after mapping!
Basic Usage
using FluentValidation;
using Mapsicle.Fluent;
using Mapsicle.Validation;
// 1. Define your validator
public class UserDtoValidator : AbstractValidator<UserDto>
{
public UserDtoValidator()
{
RuleFor(x => x.Name).NotEmpty().WithMessage("Name is required");
RuleFor(x => x.Email).NotEmpty().EmailAddress();
RuleFor(x => x.Age).GreaterThan(0).WithMessage("Age must be positive");
}
}
// 2. Map and validate in one call
var result = mapper.MapAndValidate<User, UserDto, UserDtoValidator>(user);
if (result.IsValid)
{
return Ok(result.Value); // The mapped DTO
}
else
{
return BadRequest(result.ErrorsByProperty); // { "Email": ["Valid email is required"] }
}
API Overview
// Map and validate with validator type
var result = mapper.MapAndValidate<TSource, TDest, TValidator>(source);
// Map and validate with validator instance
var validator = new UserDtoValidator();
var result = mapper.MapAndValidate<UserDto>(source, validator);
// Validate an existing object
var result = dto.Validate<UserDto, UserDtoValidator>();
// Get value or throw exception
var dto = result.GetValueOrThrow(); // Throws ValidationException if invalid
Result Properties
result.IsValid // bool - true if validation passed
result.Value // TDest - the mapped object
result.Errors // IList<ValidationFailure> - all validation errors
result.ErrorsByProperty // IDictionary<string, string[]> - errors grouped by property
result.ValidationResult // FluentValidation.Results.ValidationResult - full result
Real-World Example: API Controller
[ApiController]
[Route("api/users")]
public class UsersController : ControllerBase
{
private readonly IMapper _mapper;
private readonly IUserRepository _repo;
public UsersController(IMapper mapper, IUserRepository repo)
{
_mapper = mapper;
_repo = repo;
}
[HttpPost]
public async Task<IActionResult> Create([FromBody] CreateUserRequest request)
{
var result = _mapper.MapAndValidate<CreateUserRequest, UserDto, UserDtoValidator>(request);
if (!result.IsValid)
{
return BadRequest(new { errors = result.ErrorsByProperty });
}
var user = await _repo.CreateAsync(result.Value);
return CreatedAtAction(nameof(GetById), new { id = user.Id }, user);
}
}
β‘ Package 5: Mapsicle.NamingConventions
Automatic naming convention conversionβmap between snake_case, PascalCase, camelCase, and kebab-case!
Basic Usage
using Mapsicle.NamingConventions;
// Source uses snake_case (e.g., from Python API or database)
public class ApiResponse
{
public int user_id { get; set; }
public string first_name { get; set; }
public string email_address { get; set; }
}
// Destination uses PascalCase (C# convention)
public class UserDto
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string EmailAddress { get; set; }
}
// Map with naming convention conversion
var dto = apiResponse.MapWithConvention<ApiResponse, UserDto>(
NamingConvention.SnakeCase,
NamingConvention.PascalCase);
// dto.UserId == apiResponse.user_id
// dto.FirstName == apiResponse.first_name
Built-in Conventions
| Convention | Example | C# Property |
|---|---|---|
NamingConvention.PascalCase |
UserName |
Standard C# |
NamingConvention.CamelCase |
userName |
JavaScript/JSON |
NamingConvention.SnakeCase |
user_name |
Python/Ruby/SQL |
NamingConvention.KebabCase |
user-name |
URLs/CSS |
Convert Property Names
// Convert a single name
var snake = "UserName".ConvertName(NamingConvention.PascalCase, NamingConvention.SnakeCase);
// Result: "user_name"
var pascal = "first_name".ConvertName(NamingConvention.SnakeCase, NamingConvention.PascalCase);
// Result: "FirstName"
var camel = "OrderCount".ConvertName(NamingConvention.PascalCase, NamingConvention.CamelCase);
// Result: "orderCount"
Use with Fluent Mapper
// Combine with IMapper for convention-based mapping
var dto = mapper.MapWithConvention<ApiResponse, UserDto>(
apiResponse,
NamingConvention.SnakeCase,
NamingConvention.PascalCase);
Check Name Matching
// Check if names match across conventions
bool match = NamingConvention.NamesMatch(
"user_name", NamingConvention.SnakeCase,
"UserName", NamingConvention.PascalCase);
// Result: true
Real-World Example: External API Integration
public class ExternalApiClient
{
private readonly HttpClient _http;
public async Task<UserDto> GetUserAsync(int id)
{
// External API returns snake_case JSON
var response = await _http.GetFromJsonAsync<ExternalUserResponse>($"/users/{id}");
// Convert to C# conventions
return response.MapWithConvention<ExternalUserResponse, UserDto>(
NamingConvention.SnakeCase,
NamingConvention.PascalCase);
}
}
// External API response (snake_case)
public class ExternalUserResponse
{
public int user_id { get; set; }
public string first_name { get; set; }
public string last_name { get; set; }
public string email_address { get; set; }
public DateTime created_at { get; set; }
}
// Internal DTO (PascalCase)
public class UserDto
{
public int UserId { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string EmailAddress { get; set; }
public DateTime CreatedAt { get; set; }
}
β‘ Package 6: Mapsicle.Serilog
Structured logging integration for enterprise diagnostics and observability.
Basic Setup
using Mapsicle.Serilog;
using Serilog;
// Configure Serilog logger
var logger = new LoggerConfiguration()
.WriteTo.Console()
.MinimumLevel.Debug()
.CreateLogger();
// Enable Mapsicle logging
MapsicleLogging.UseSerilog(logger);
Map with Logging
// Log individual mappings
var dto = user.MapWithLogging<User, UserDto>(logger);
// Output: [INF] Mapsicle: Mapped User -> UserDto in 0.5ms
// Log collection mappings
var dtos = users.MapCollectionWithLogging<User, UserDto>(logger);
// Output: [INF] Mapsicle: Mapped 100 User -> UserDto items in 5.2ms
Slow Mapping Warnings
// Configure slow mapping threshold (default: 100ms)
MapsicleLogging.SlowMappingThreshold = TimeSpan.FromMilliseconds(50);
// Slow mappings automatically log warnings
var dto = largeObject.MapWithLogging<Large, LargeDto>(logger);
// Output: [WRN] Mapsicle: Slow mapping detected Large -> LargeDto took 75ms
Scoped Logging for Batch Operations
using (var scope = new MappingLoggingScope(logger, "OrderProcessing"))
{
// All mappings in this scope are logged with the operation context
var orderDto = order.MapWithLogging<Order, OrderDto>(logger);
var itemDtos = items.MapCollectionWithLogging<Item, ItemDto>(logger);
}
// Output includes: OperationName = "OrderProcessing"
β‘ Package 7: Mapsicle.Dapper
Seamless integration with Dapper for mapping database query results directly to DTOs.
Basic Usage
using Mapsicle.Dapper;
using Dapper;
// Query and map in one call
var users = connection.QueryAndMap<User, UserDto>("SELECT * FROM Users").ToList();
// With parameters
var user = connection.QuerySingleAndMap<User, UserDto>(
"SELECT * FROM Users WHERE Id = @Id",
param: new { Id = 1 });
Async Support
// Async query and map
var users = await connection.QueryAndMapAsync<User, UserDto>("SELECT * FROM Users");
// Async single result
var user = await connection.QuerySingleAndMapAsync<User, UserDto>(
"SELECT * FROM Users WHERE Id = @Id",
param: new { Id = 1 });
With Custom Configuration
// Use a custom mapper configuration
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserSummaryDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => $"{s.FirstName} {s.LastName}"));
});
var users = connection.QueryAndMap<User, UserSummaryDto>(
"SELECT * FROM Users", config).ToList();
// Or use IMapper instance
var mapper = config.CreateMapper();
var users = connection.QueryAndMap<User, UserSummaryDto>(
"SELECT * FROM Users", mapper).ToList();
Transaction Support
using var transaction = connection.BeginTransaction();
// Mappings work within transactions
var users = connection.QueryAndMap<User, UserDto>(
"SELECT * FROM Users WHERE Active = 1",
transaction: transaction).ToList();
transaction.Commit();
Map Existing Dapper Results
// Map existing IEnumerable from Dapper
var users = connection.Query<User>("SELECT * FROM Users");
var dtos = users.MapTo<User, UserDto>(mapper);
π§ Migration from AutoMapper
API Compatibility
| AutoMapper | Mapsicle |
|---|---|
CreateMap<S,D>() |
Same! |
ForMember().MapFrom() |
Same! |
.Ignore() |
Same! |
BeforeMap/AfterMap |
Same! |
Include<Derived>() |
Same! |
ConstructUsing() |
Same! |
services.AddAutoMapper() |
services.AddMapsicle() |
_mapper.Map<T>() |
mapper.Map<T>() or obj.MapTo<T>() |
Step-by-Step Migration Guide
1. Identify Your AutoMapper Usage
Simple mappings (no profiles) β Use core Mapsicle package
Profiles with configuration β Use Mapsicle.Fluent
EF Core ProjectTo β Use Mapsicle.EntityFramework
2. Install Packages
dotnet remove package AutoMapper
dotnet remove package AutoMapper.Extensions.Microsoft.DependencyInjection
dotnet add package Mapsicle.Fluent # Includes core
3. Convert Profiles to Configuration
Before (AutoMapper):
public class UserProfile : Profile
{
public UserProfile()
{
CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName));
}
}
After (Mapsicle):
// In Program.cs/Startup.cs
services.AddMapsicle(cfg =>
{
cfg.CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName));
}, validateConfiguration: true);
4. Update DI Registration
Before:
services.AddAutoMapper(typeof(UserProfile).Assembly);
After:
services.AddMapsicle(cfg =>
{
cfg.CreateMap<User, UserDto>();
cfg.CreateMap<Order, OrderDto>();
// ... all your mappings
}, validateConfiguration: true);
5. Update Mapping Calls
Before:
public class UserService
{
private readonly IMapper _mapper;
public UserService(IMapper mapper) => _mapper = mapper;
public UserDto GetUser(User user) => _mapper.Map<UserDto>(user);
}
After (same interface!):
public class UserService
{
private readonly IMapper _mapper;
public UserService(IMapper mapper) => _mapper = mapper;
// Option 1: Same as AutoMapper
public UserDto GetUser(User user) => _mapper.Map<UserDto>(user);
// Option 2: Extension method (no DI needed for simple cases)
public UserDto GetUser(User user) => user.MapTo<UserDto>();
}
Known Incompatibilities
β Not Supported:
IMemberValueResolverinterface - useResolveUsing(func)insteadITypeConverterinterface - useCreateConverter<T, U>()instead- Conditional mapping with complex predicates
- MaxDepth per individual mapping (only global
Mapper.MaxDepth)
β Now Supported (via extension packages):
- Custom naming conventions β
Mapsicle.NamingConventions - Post-mapping validation β
Mapsicle.Validation
β οΈ Behavioral Differences:
- Circular references: AutoMapper throws exception, Mapsicle returns default value
- Unmapped properties: Both ignore, but Mapsicle has
GetUnmappedProperties<T, U>()for validation - Null handling: Both return null for null source, but Mapsicle is more aggressive with null-safe navigation
π οΈ Troubleshooting
Common Issues
Issue: Properties Not Mapping
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)}");
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:
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));
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);
β οΈ Known Limitations
Feature Limitations
β Not Supported:
- Async mapping operations
- Source/destination value injection (context passing)
- Open generic types
- Explicit type conversion configuration beyond built-ins
β Supported via Extension Packages:
- Custom naming conventions (PascalCase β snake_case) β
Mapsicle.NamingConventions - Post-mapping validation β
Mapsicle.Validation
β οΈ Partial Support:
- Nested flattening limited to 1 level (
Address.Cityβ ,Address.Street.Line1β) - Collection mapping ~27% slower than AutoMapper for 100-1000 items (competitive on 10K+)
- EF Core ProjectTo works with
ForMemberexpressions, but notResolveUsingdelegates
Behavioral Differences from AutoMapper
- Circular references: Returns default value instead of throwing exception
- Null safety: More aggressive null-safe navigation (fewer NullReferenceException)
- Unmapped properties: Silent (use
GetUnmappedPropertiesfor validation) - Cache behavior: Default is unbounded (must opt-in to LRU)
Platform Support
| .NET Version | Mapsicle Support |
|---|---|
| .NET 8.0 | β Fully supported |
| .NET 6.0-7.0 | β Via .NET Standard 2.0 |
| .NET 5.0 | β Via .NET Standard 2.0 |
| .NET Core 2.0+ | β Via .NET Standard 2.0 |
| .NET Framework 4.6.1+ | β Via .NET Standard 2.0 |
π API Reference
Core Extensions (using Mapsicle)
MapTo<T>(this object source)
Maps a source object to a new instance of type T.
Parameters:
source- The source object to map from
Returns:
T?- New instance of T with mapped properties, ordefault(T)if source is null or max depth exceeded
Example:
var dto = user.MapTo<UserDto>();
MapTo<T>(this IEnumerable source)
Maps a collection to a List<T>.
Parameters:
source- The source collection
Returns:
List<T>- New list with mapped items (empty if source is null)
Optimization: Pre-allocates capacity if source implements ICollection
Example:
List<UserDto> dtos = users.MapTo<UserDto>();
Map<TDest>(this object source, TDest destination)
Updates an existing destination object from source.
Parameters:
source- The source objectdestination- The destination object to update
Returns:
TDest- The updated destination (same instance)
Example:
source.Map(existingDto); // Updates existingDto in-place
ToDictionary(this object source)
Converts an object to a dictionary of property name/value pairs.
Returns:
Dictionary<string, object?>- Case-insensitive dictionary
Example:
var dict = user.ToDictionary();
MapTo<T>(this IDictionary<string, object?> source) where T : new()
Maps a dictionary to an object.
Constraints:
- T must have a parameterless constructor
Example:
var user = dict.MapTo<User>();
Static Mapper Configuration
Mapper.MaxDepth
- Type:
int - Default:
32 - Description: Maximum recursion depth before returning default value (circular reference protection)
Mapper.MaxDepth = 64;
Mapper.UseLruCache
- Type:
bool - Default:
false - Description: Enables memory-bounded LRU cache. Clears all caches when changed.
Mapper.UseLruCache = true;
Mapper.MaxCacheSize
- Type:
int - Default:
1000 - Description: Maximum cache entries when UseLruCache is enabled
Mapper.MaxCacheSize = 2000;
Mapper.Logger
- Type:
Action<string>? - Default:
null - Description: Logger for diagnostic messages (depth warnings, etc)
Mapper.Logger = msg => _logger.LogDebug(msg);
Mapper.ClearCache()
Clears all cached mapping delegates.
Mapper.ClearCache();
Mapper.CacheInfo()
- Returns:
MapperCacheInfo- Current cache statistics
var stats = Mapper.CacheInfo();
Console.WriteLine($"Total: {stats.Total}, Hit Ratio: {stats.HitRatio:P1}");
Mapper.AssertMappingValid<TSource, TDest>()
Validates mapping configuration. Throws InvalidOperationException if unmapped properties exist.
Mapper.AssertMappingValid<User, UserDto>();
Mapper.GetUnmappedProperties<TSource, TDest>()
- Returns:
List<string>- Names of destination properties that cannot be mapped
var unmapped = Mapper.GetUnmappedProperties<User, UserDto>();
MapperFactory
MapperFactory.Create(MapperOptions? options = null)
Creates an isolated mapper instance with independent cache and depth tracking.
Parameters:
options- Optional configuration (MaxDepth, Logger, UseLruCache, MaxCacheSize)
Returns:
IDisposablemapper instance
Example:
using var mapper = MapperFactory.Create(new MapperOptions
{
MaxDepth = 16,
UseLruCache = true,
MaxCacheSize = 100,
Logger = Console.WriteLine
});
var dto = mapper.MapTo<UserDto>(user);
Fluent API (using Mapsicle.Fluent)
MapperConfiguration
var config = new MapperConfiguration(cfg =>
{
cfg.CreateMap<User, UserDto>()
.ForMember(d => d.FullName, opt => opt.MapFrom(s => s.FirstName + " " + s.LastName))
.ForMember(d => d.Password, opt => opt.Ignore())
.ForMember(d => d.IsActive, opt => opt.Condition(s => s.Status == "Active"))
.BeforeMap((src, dest) => Console.WriteLine("Mapping started"))
.AfterMap((src, dest) => dest.MappedAt = DateTime.UtcNow)
.Include<PowerUser, PowerUserDto>()
.ConstructUsing(src => new UserDto(src.Id))
.ReverseMap();
cfg.CreateConverter<Money, decimal>(m => m.Amount);
});
config.AssertConfigurationIsValid();
var mapper = config.CreateMapper();
Configuration Methods
ForMember<TMember>()- Configure individual member mappingopt.MapFrom(expr)- Map from custom expressionopt.Ignore()- Don't map this memberopt.Condition(pred)- Conditional mappingopt.ResolveUsing(func)- Custom resolver function
BeforeMap(action)- Execute action before mappingAfterMap(action)- Execute action after mappingInclude<TDerived, TDest>()- Polymorphic mapping supportConstructUsing(factory)- Custom object constructionReverseMap()- Create reverse mappingCreateConverter<TSource, TDest>(converter)- Global type converter
EntityFramework Extensions (using Mapsicle.EntityFramework)
ProjectTo<TSource, TDest>(this IQueryable<TSource> query, MapperConfiguration? config = null)
Translates mapping to SQL expression (executed in database).
Parameters:
query- Source EF Core queryableconfig- Optional mapper configuration for custom mappings
Returns:
IQueryable<TDest>- Queryable projection
Example:
var dtos = await context.Users
.Where(u => u.IsActive)
.ProjectTo<User, UserDto>(config)
.ToListAsync();
Validation Extensions (using Mapsicle.Validation)
MapAndValidate<TDest, TValidator>(this IMapper mapper, object? source)
Maps source to destination and validates using the specified validator type.
Type Parameters:
TDest- Destination typeTValidator- FluentValidation validator type (must have parameterless constructor)
Returns:
MapperValidationResult<TDest>- ContainsIsValid,Value,Errors,ErrorsByProperty
Example:
var result = mapper.MapAndValidate<User, UserDto, UserDtoValidator>(user);
if (result.IsValid) return result.Value;
MapAndValidate<TDest>(this IMapper mapper, object? source, IValidator<TDest> validator)
Maps source to destination and validates using a provided validator instance.
Example:
var validator = new UserDtoValidator();
var result = mapper.MapAndValidate<UserDto>(user, validator);
Validate<T, TValidator>(this T value)
Validates an existing object using the specified validator type.
Example:
var result = dto.Validate<UserDto, UserDtoValidator>();
NamingConventions Extensions (using Mapsicle.NamingConventions)
MapWithConvention<TSource, TDest>(this TSource source, NamingConvention sourceConvention, NamingConvention destConvention)
Maps source to destination with naming convention transformation.
Parameters:
sourceConvention- The naming convention of source propertiesdestConvention- The naming convention of destination properties
Returns:
TDest?- New instance with convention-matched properties
Example:
var dto = apiResponse.MapWithConvention<ApiResponse, UserDto>(
NamingConvention.SnakeCase,
NamingConvention.PascalCase);
ConvertName(this string name, NamingConvention from, NamingConvention to)
Converts a property name from one convention to another.
Example:
var snakeName = "UserName".ConvertName(NamingConvention.PascalCase, NamingConvention.SnakeCase);
// Result: "user_name"
NamingConvention.NamesMatch(string sourceName, NamingConvention sourceConvention, string destName, NamingConvention destConvention)
Checks if two names match when their conventions are applied.
Example:
bool match = NamingConvention.NamesMatch("user_id", NamingConvention.SnakeCase, "UserId", NamingConvention.PascalCase);
// Result: true
Serilog Extensions (using Mapsicle.Serilog)
MapsicleLogging.UseSerilog(ILogger logger)
Enables global Serilog integration for Mapsicle mapping operations.
Parameters:
logger- Serilog ILogger instance
Example:
MapsicleLogging.UseSerilog(Log.Logger);
MapWithLogging<TSource, TDest>(this TSource source, ILogger logger)
Maps source to destination with timing and structured logging.
Returns:
TDest?- Mapped destination object
Example:
var dto = user.MapWithLogging<User, UserDto>(logger);
// Logs: Mapsicle: Mapped User -> UserDto in 0.5ms
MapCollectionWithLogging<TSource, TDest>(this IEnumerable<TSource> source, ILogger logger)
Maps a collection with aggregated timing and logging.
Returns:
List<TDest>- List of mapped destination objects
Example:
var dtos = users.MapCollectionWithLogging<User, UserDto>(logger);
// Logs: Mapsicle: Mapped 100 User -> UserDto items in 5.2ms
MapsicleLogging.SlowMappingThreshold
Configures the threshold for slow mapping warnings.
Default: 100ms
Example:
MapsicleLogging.SlowMappingThreshold = TimeSpan.FromMilliseconds(50);
Dapper Extensions (using Mapsicle.Dapper)
QueryAndMap<TSource, TDest>(this IDbConnection connection, string sql, ...)
Executes a SQL query and maps results to destination type.
Overloads:
QueryAndMap<TSource, TDest>(sql, param?, transaction?, commandTimeout?)- Auto-mappingQueryAndMap<TSource, TDest>(sql, MapperConfiguration, param?, ...)- With configurationQueryAndMap<TSource, TDest>(sql, IMapper, param?, ...)- With mapper instance
Returns:
IEnumerable<TDest>- Mapped results
Example:
var users = connection.QueryAndMap<User, UserDto>("SELECT * FROM Users").ToList();
QueryAndMapAsync<TSource, TDest>(this IDbConnection connection, string sql, ...)
Async version of QueryAndMap.
Example:
var users = await connection.QueryAndMapAsync<User, UserDto>("SELECT * FROM Users");
QuerySingleAndMap<TSource, TDest>(this IDbConnection connection, string sql, ...)
Executes a query expecting a single result and maps it.
Returns:
TDest?- Mapped result or null
Example:
var user = connection.QuerySingleAndMap<User, UserDto>(
"SELECT * FROM Users WHERE Id = @Id", param: new { Id = 1 });
QueryFirstAndMap<TSource, TDest>(this IDbConnection connection, string sql, ...)
Executes a query and maps the first result.
Returns:
TDest?- First mapped result or null
Example:
var user = connection.QueryFirstAndMap<User, UserDto>("SELECT * FROM Users ORDER BY CreatedAt DESC");
MapTo<TSource, TDest>(this IEnumerable<TSource>? source, IMapper mapper)
Maps an existing collection using a provided mapper.
Returns:
List<TDest>- Mapped results
Example:
var users = connection.Query<User>("SELECT * FROM Users");
var dtos = users.MapTo<User, UserDto>(mapper);
π Complete Feature List
Core Features
- β Zero-config convention mapping
- β Collection mapping (List, Array, IEnumerable)
- β Dictionary mapping (object β Dictionary)
- β
Flattening (
AddressCityβAddress.City) - β
Nullable type coercion (
TβT?) - β Enum to numeric conversion
- β Nested object mapping
- β Case-insensitive property matching
- β Record type support (positional parameters)
- β Anonymous type support
- β Circular reference protection
- β Thread-safe caching
Advanced Features
- β
[MapFrom]attribute - β
[IgnoreMap]attribute - β Fluent configuration API
- β ForMember custom expressions
- β BeforeMap/AfterMap hooks
- β
Polymorphic mapping (
.Include<>) - β
Custom construction (
.ConstructUsing) - β Global type converters
- β Conditional mapping
- β ReverseMap
- β DI integration
- β Configuration validation
Enterprise Features
- β LRU cache option (memory-bounded)
- β Cache statistics (hits, misses, ratio)
- β PropertyInfo caching
- β Lock-free reads
- β Isolated mapper instances
- β Configurable depth limits
- β Diagnostic logging
- β Unmapped property detection
EF Core Features
- β ProjectTo with SQL translation
- β ForMember in ProjectTo
- β Flattening in SQL
- β Nested projection
- β Type coercion in queries
Validation Features (Mapsicle.Validation)
- β MapAndValidate with FluentValidation
- β Validator type parameter
- β Validator instance injection
- β Validation result with IsValid, Errors
- β ErrorsByProperty dictionary
- β GetValueOrThrow pattern
- β Validator caching
Naming Convention Features (Mapsicle.NamingConventions)
- β PascalCase convention
- β camelCase convention
- β snake_case convention
- β kebab-case convention
- β MapWithConvention extension
- β ConvertName string extension
- β NamesMatch cross-convention comparison
- β Property mapping cache
Serilog Features (Mapsicle.Serilog)
- β UseSerilog global integration
- β MapWithLogging extension
- β MapCollectionWithLogging extension
- β Slow mapping warnings
- β MappingLoggingScope for batch operations
- β Structured logging with properties
- β Configurable thresholds
Dapper Features (Mapsicle.Dapper)
- β QueryAndMap / QueryAndMapAsync
- β QuerySingleAndMap / QuerySingleAndMapAsync
- β QueryFirstAndMap / QueryFirstAndMapAsync
- β Transaction support
- β Custom MapperConfiguration support
- β IMapper instance support
- β MapTo collection extension
π§ͺ Test Coverage
| Package | Tests | Coverage |
|---|---|---|
| Mapsicle | 210 | Core + Stability |
| Mapsicle.Fluent | 35 | Fluent + Enterprise |
| Mapsicle.EntityFramework | 19 | EF Core |
| Mapsicle.Validation | 13 | FluentValidation |
| Mapsicle.NamingConventions | 55 | Naming Conventions |
| Mapsicle.Serilog | 22 | Serilog Logging |
| Mapsicle.Dapper | 25 | Dapper Integration |
| Mapsicle.Json | 26 | JSON Serialization |
| Mapsicle.AspNetCore | 23 | ASP.NET Core |
| Mapsicle.Caching | 21 | Caching Integration |
| Mapsicle.Audit | 26 | Change Tracking |
| Mapsicle.DataAnnotations | 24 | DataAnnotations |
| Total | 499 |
π Project Structure
Mapsicle/
βββ src/
β βββ Mapsicle/ # Core - zero config
β βββ Mapsicle.Fluent/ # Fluent + DI + Profiles
β βββ Mapsicle.EntityFramework/ # EF Core ProjectTo
β βββ Mapsicle.Validation/ # FluentValidation integration
β βββ Mapsicle.NamingConventions/ # Naming convention support
β βββ Mapsicle.Serilog/ # Serilog structured logging
β βββ Mapsicle.Dapper/ # Dapper integration
β βββ Mapsicle.Json/ # JSON serialization
β βββ Mapsicle.AspNetCore/ # ASP.NET Core Minimal API
β βββ Mapsicle.Caching/ # Memory/Distributed caching
β βββ Mapsicle.Audit/ # Change tracking/diff
β βββ Mapsicle.DataAnnotations/ # DataAnnotations validation
βββ tests/
β βββ Mapsicle.Tests/
β βββ Mapsicle.Fluent.Tests/
β βββ Mapsicle.EntityFramework.Tests/
β βββ Mapsicle.Validation.Tests/
β βββ Mapsicle.NamingConventions.Tests/
β βββ Mapsicle.Serilog.Tests/
β βββ Mapsicle.Dapper.Tests/
β βββ Mapsicle.Json.Tests/
β βββ Mapsicle.AspNetCore.Tests/
β βββ Mapsicle.Caching.Tests/
β βββ Mapsicle.Audit.Tests/
β βββ Mapsicle.DataAnnotations.Tests/
β βββ Mapsicle.Benchmarks/
βββ examples/
βββ Mapsicle.Examples/ # Working examples for all packages
Run Examples
dotnet run --project examples/Mapsicle.Examples
π€ Contributing
PRs welcome! Areas for contribution:
- Performance optimizations
- Additional type coercion scenarios
- Documentation improvements
π License
MPL 2.0 License Β© Arnel Isiderio Robles
<p align="center"> <strong>Stop configuring. Start mapping.</strong><br> <em>Free forever. Zero dependencies. Pure performance.</em> </p>
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 was computed. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
| .NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
| .NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
| .NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
| MonoAndroid | monoandroid was computed. |
| MonoMac | monomac was computed. |
| MonoTouch | monotouch was computed. |
| Tizen | tizen40 was computed. tizen60 was computed. |
| Xamarin.iOS | xamarinios was computed. |
| Xamarin.Mac | xamarinmac was computed. |
| Xamarin.TVOS | xamarintvos was computed. |
| Xamarin.WatchOS | xamarinwatchos was computed. |
-
.NETStandard 2.0
- Mapsicle.Fluent (>= 1.2.2)
- Microsoft.Extensions.Caching.Abstractions (>= 8.0.1)
- System.Text.Json (>= 8.0.5)
-
net8.0
- Mapsicle.Fluent (>= 1.2.2)
- Microsoft.Extensions.Caching.Abstractions (>= 8.0.1)
- System.Text.Json (>= 8.0.5)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.2.2 | 41 | 3/3/2026 |