PanoramicData.Mapper: A MIT-Licensed AutoMapper Alternative for .NET 10

Why We Built PanoramicData.Mapper

If you use AutoMapper in your .NET projects, two recent changes may affect you:

1. High-Severity Security Vulnerability

GHSA-rvv3-g6hj-g44x is a High severity vulnerability (CVSS 7.5) affecting all AutoMapper versions prior to 16.1.1. It allows denial of service via uncontrolled recursion (CWE-674). While a patch exists in 16.1.1+, upgrading to that version means accepting the new license terms below.

2. License Change from MIT to RPL-1.5

AutoMapper is no longer MIT-licensed. The project, now under “Lucky Penny Software”, uses the Reciprocal Public License 1.5 (RPL-1.5). Under RPL-1.5, if you deploy software using AutoMapper, you must release your entire source code under the same license — or purchase a commercial license. For commercial and closed-source projects, this is a significant change.

Our Response

Rather than accept the licensing implications or suppress the vulnerability warning indefinitely, we built PanoramicData.Mapper — a comprehensive, drop-in replacement for AutoMapper, released under the MIT license.


What Is PanoramicData.Mapper?

PanoramicData.Mapper is a .NET 10 object-to-object mapping library that provides full API compatibility with AutoMapper. It covers 40 distinct API features, each implemented and tested:

  • Profile-based configuration — inherit from Profile, call CreateMap<TSource, TDestination>()
  • ForMember / Ignore / MapFrom — member-level configuration with lambda expressions
  • ForMember (string overload) — member configuration by name
  • ForAllMembers — apply configuration to all destination members at once
  • BeforeMap / AfterMap — inline lambda and generic IMappingAction<TSrc, TDst> pre/post-mapping callbacks
  • ReverseMap.ReverseMap() creates the inverse mapping automatically
  • ConvertUsing — lambda, ITypeConverter<TSrc, TDst> type, or instance for full-type conversion
  • ConstructUsing — custom destination construction via lambda
  • ForPath.ForPath(d => d.Inner.Prop, opt => ...) for deep nested member configuration
  • ForCtorParam.ForCtorParam("name", opt => ...) for constructor parameter mapping
  • Condition / PreCondition — conditional member mapping (evaluated after/before value resolution)
  • NullSubstitute — substitute a default value when the source resolves to null
  • Value ResolversIValueResolver<TSrc, TDst, TMember> for custom resolution logic
  • Mapping InheritanceInclude, IncludeBase, IncludeAllDerived for polymorphic hierarchies
  • Value Transformers.AddTransform<T>(expr) for per-type value transforms
  • Open GenericsCreateMap(typeof(Source<>), typeof(Dest<>)) for generic type mappings
  • UseDestinationValue — preserve existing destination property values
  • MaxDepth.MaxDepth(n) to limit recursive mapping depth
  • Map to newmapper.Map<TDest>(source) creates a new destination
  • Map to existingmapper.Map(source, destination) updates an existing object
  • Non-generic Map overloadsmapper.Map(obj, sourceType, destType) and mapper.Map(obj, obj, sourceType, destType)
  • ProjectToIQueryable<T>.ProjectTo<TDest>(configurationProvider) for EF Core SQL projection
  • [Ignore] attributePanoramicData.Mapper.Configuration.Annotations.IgnoreAttribute
  • IgnoreAllPropertiesWithAnInaccessibleSetter — extension method to ignore all destination properties with non-public or absent setters
  • Nested mappings — recursive mapping of complex child types and collection properties
  • Collection/List/Array mappingmapper.Map<List<Dest>>(sourceList) maps collections automatically
  • Flattening — PascalCase destination property names are split and traversed on the source graph (e.g. CustomerNameCustomer.Name); also matches GetX() methods
  • AssertConfigurationIsValid — detects unmapped destination properties at startup
  • DI integrationAddAutoMapper() extension methods for IServiceCollection (assembly scanning, explicit configuration, or both)

Key Design Decisions

Decision Rationale
MIT license No licensing surprises for commercial projects
.NET 10 only Modern target, no legacy baggage
Reflection-based engine Simpler implementation, matches AutoMapper runtime behavior
Compiled mapper caching Property assignments compiled once, reused for performance
Expression tree projection ProjectTo builds real expressions that EF Core translates to SQL
Codacy-compliant complexity All methods kept at cyclomatic complexity <= 8 for maintainability

Test Coverage

The library ships with 90 tests covering all 40 API features, built with xUnit v3 and AwesomeAssertions. Every row in the MASTER PLAN API surface table shows both “Implemented” and “Tested” checkmarks.

CI runs on every push and pull request via GitHub Actions, with code coverage reported to Codacy.


Migration Guide

Migrating from AutoMapper takes three steps:

Step 1 — Swap the NuGet package:

dotnet remove package AutoMapper
dotnet add package PanoramicData.Mapper

Step 2 — Update using directives (ideally in a GlobalUsings.cs):

// Before
global using AutoMapper;
global using AutoMapper.QueryableExtensions;
global using AutoMapper.Configuration.Annotations;

// After
global using PanoramicData.Mapper;
global using PanoramicData.Mapper.QueryableExtensions;
global using PanoramicData.Mapper.Configuration.Annotations;

Step 3 — Build and test. All type names (Profile, IMapper, MapperConfiguration, AddAutoMapper()) remain identical.

That is it. We migrated our own 90+ project solution (10 projects using AutoMapper directly, 84 mapping profiles, ~110 Map call sites) with zero code changes beyond the steps above.


Installation

dotnet add package PanoramicData.Mapper

The package is available on NuGet — current version 10.0.8.


Contributions Welcome

PanoramicData.Mapper is open source under the MIT license. We welcome contributions:

If you are affected by the AutoMapper license change or vulnerability and want a clean, MIT-licensed alternative, give PanoramicData.Mapper a try.