AutoMapper 15.0 升级指南:许可认证引入、目标框架调整与破坏性 API 变更全解析
2026/9/24 14:23:16 网站建设 项目流程
  • 后端

【免费下载链接】AutoMapper

A convention-based object-object mapper in .NET.

项目地址:https://gitcode.com/gh_mirrors/au/AutoMapper
点击查看免费下载

本文是面向 AutoMapper 15.0 的升级实战指南,完整解读本次版本在目标框架、商业许可与 DI 集成 API 上的三项重大变化,并针对AddAutoMapperMapperConfiguration的破坏性变更给出可复制的迁移代码。读完本文,你将能够把现有 14.x 及以下版本的项目平稳升级到 15.0,并正确配置许可证、适配新的构造签名,避免编译错误与运行时日志异常。

本指南以 docs/source/15.0-Upgrade-Guide.md 为骨架,结合仓库中 src/AutoMapper 的源码实现与 docs/source/License-configuration.md 官方文档展开,全部结论均可在此仓库内验证。

一、目标框架调整:.NET 8、.NET 9 与 .NET Standard 2.0

15.0 版本将目标框架(Target Framework)收敛为.NET 8、.NET 9 与 .NET Standard 2.0。这意味着:

  • 面向 .NET 8 / .NET 9 的新应用可以直接引用;基于 .NET Standard 2.0 的兼容面(如 .NET Framework、.NET Core 3.1 等运行时)依然可以获得 AutoMapper 的能力;
  • 低于这些版本的目标框架(例如旧的 .NET Core 版本)将无法再直接引用 15.0 的程序集,需要先升级运行时或继续停留在旧版本。

从当前仓库的工程文件 src/AutoMapper/AutoMapper.csproj 可以看到更完整的实际构建矩阵:

<TargetFrameworks>netstandard2.0;net8.0;net9.0;net10.0</TargetFrameworks>

即除升级指南列出的三个框架外,仓库还额外编译了net10.0;且在 Windows 环境下还会追加net471(见该 csproj 中IsWindows条件属性)。在 Windows 上为netstandard2.0net471目标额外引用了Microsoft.Bcl.HashCodeSystem.Reflection.EmitPolySharp等兼容包(见 src/AutoMapper/AutoMapper.csproj 的ItemGroup条件引用),保证旧平台上的 API 面一致。

升级动作:升级前先确认项目的TargetFramework落在上述范围内;若项目同时面向多个框架,升级后请重新跑一遍dotnet build与单元测试,确认没有因框架切换引入的平台差异。

二、15.0 起 AutoMapper 需要许可证(License)

15.0 之后,AutoMapper 转向商业许可模式(仓库采用双许可证,见 LICENSE.md)。与 13.0 及更早版本不同,15.0 在使用时需要配置许可证密钥。

2.1 通过 DI 集成配置许可证

最常见的配置方式是在AddAutoMapper的配置回调中设置LicenseKey

services.AddAutoMapper(cfg => { cfg.LicenseKey = "<License Key Here>"; });

LicenseKeyIMapperConfigurationExpression上新增的读写属性(见 src/AutoMapper/Configuration/MapperConfigurationExpression.cs 的接口声明与MapperConfigurationExpression类中的public string LicenseKey { get; set; }实现)。

2.2 非 DI 场景:直接构造 MapperConfiguration 时配置

在不使用Microsoft.Extensions.DependencyInjection的场景下,直接在MapperConfiguration构造函数回调中设置即可:

var mapperConfiguration = new MapperConfiguration(cfg => { cfg.LicenseKey = "License Key Here"; }, loggerFactory);

注意:如后文第三节所述,15.0 中MapperConfiguration的构造函数必须传入ILoggerFactory,因此上面的loggerFactory参数不可省略。

2.3 环境变量自动发现(无需改代码)

根据 docs/source/License-configuration.md,如果代码中没有显式设置LicenseKey,AutoMapper 会从环境变量中自动查找。这在容器化、云环境和需要跨多个服务共享同一密钥的企业场景下非常方便:

  • AUTOMAPPER_LICENSE_KEY—— AutoMapper 专属许可证密钥;
  • LUCKYPENNY_LICENSE_KEY—— 可在 Lucky Penny 系列产品间共享的密钥(例如 MediatR 也会读取同一变量)。因为是共享密钥,它必须对应一个包含 AutoMapper 的许可(Bundle或 AutoMapper 版本),仅含 MediatR 的许可无法通过校验。

许可证的解析优先级如下(取第一个命中的值):

  1. 代码中显式设置的值(cfg.LicenseKey = "...");
  2. AUTOMAPPER_LICENSE_KEY环境变量;
  3. LUCKYPENNY_LICENSE_KEY环境变量。

该优先级在源码 src/AutoMapper/Licensing/LicenseAccessor.cs 中有明确实现:

internal static string ResolveLicenseKey(string explicitKey) => explicitKey ?? Environment.GetEnvironmentVariable(AutoMapperLicenseKeyEnvVariable) ?? Environment.GetEnvironmentVariable(SharedLicenseKeyEnvVariable);

使用环境变量时无需改代码——不设置LicenseKey,正常注册 AutoMapper 即可。

2.4 许可证的校验机制与日志行为

许可证密钥本身是一个由 Lucky Penny 软件签发的 JWT(JSON Web Token)。源码 src/AutoMapper/Licensing/LicenseAccessor.cs 使用Microsoft.IdentityModel.JsonWebTokensJsonWebTokenHandler结合内置 RSA 公钥完成签名验证,并从中解析出account_idcustomer_idsub_idiatexpeditiontypeperpetual等声明(见 src/AutoMapper/Licensing/License.cs)。

校验结果只通过标准日志输出,不会阻塞或降级任何映射功能(详见 docs/source/License-configuration.md 的 "License Enforcement" 一节):

  • INFO:许可证有效;
  • WARNING:缺少许可证(未配置密钥),提示 "You do not have a valid license key..."(见 src/AutoMapper/Licensing/LicenseValidator.cs);
  • ERROR:许可证无效或已过期。

没有中心许可服务器、没有出站 HTTP 调用、不会禁用或降级任何功能。日志记录在标准Microsoft.Extensions.Logging下,日志类别名为LuckyPennySoftware.AutoMapper.License

值得注意的实现细节:许可证校验发生在MapperConfiguration构造路径中,但它被调度到专用后台线程异步执行(见 src/AutoMapper/Configuration/MapperConfiguration.cs 的注释与Task.Factory.StartNew(ValidateLicense, ...)),以避免在懒构建 DI 单例时因线程池饥饿导致整个应用死锁(源码注释中标注了 issue #4640)。

2.5 许可证相关的常见问题处理

重复的许可证日志:如果启动时看到多条许可证日志,通常是 AutoMapper 被注册或配置了多次。

  • 多次调用AddAutoMapper是安全的:第一次调用注册IMapper后,后续调用会被忽略(见 src/AutoMapper/ServiceCollectionExtensions.cs 中if (services.Any(sd => sd.ServiceType == typeof(IMapper))) return services;的去重逻辑),不会产生额外的许可证校验;
  • 手动创建多个MapperConfiguration实例时,每个实例都会独立执行一次许可证校验并各输出一条日志。避免方式是创建并复用单个MapperConfiguration(通常注册为单例):
var config = new MapperConfiguration(cfg => { cfg.LicenseKey = "key"; }, loggerFactory); var mapper = new Mapper(config);

若确实需要多个配置(如集成测试或模块化场景),可通过过滤日志类别来静默重复消息:

builder.Logging.AddFilter("LuckyPennySoftware.AutoMapper.License", LogLevel.None);

客户端分发场景(Blazor WASM / WPF / MAUI / 桌面应用):不应把许可证密钥写入客户端,否则会把机密传输给终端用户。正确做法是省略许可证密钥配置,并静默该日志类别(同上AddFilter)。缺失或无效的许可证不会以任何方式影响运行时行为

三、破坏性变更(Breaking Changes)与迁移

15.0 有两个必须关注的破坏性变更,升级时会导致编译错误,需要逐一适配。

3.1AddAutoMapper:所有重载都必须提供配置回调

由于 15.0 必须提供许可证,AddAutoMapper所有重载现在都要求第一个参数是Action<IMapperConfigurationExpression>。以最简单的程序集标记类型用法为例:

// 之前(14.x 及以下) services.AddAutoMapper(typeof(Program)); // 现在(15.0) services.AddAutoMapper(cfg => cfg.LicenseKey = "<License Key Here>", typeof(Program));

升级指南强调:"This method parameter is first for allAddAutoMapperoverloads."——即该配置回调参数在所有重载中均位于第一个参数位置

从源码 src/AutoMapper/ServiceCollectionExtensions.cs 可以确认,当前仓库中所有AddAutoMapper重载的签名形态为:

AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction) AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, params Assembly[] assemblies) AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, params Assembly[] assemblies) AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, IEnumerable<Assembly> assemblies, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, IEnumerable<Assembly> assemblies, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, params Type[] profileAssemblyMarkerTypes) AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, params Type[] profileAssemblyMarkerTypes) AddAutoMapper(this IServiceCollection services, Action<IMapperConfigurationExpression> configAction, IEnumerable<Type> profileAssemblyMarkerTypes, ServiceLifetime serviceLifetime = ServiceLifetime.Transient) AddAutoMapper(this IServiceCollection services, Action<IServiceProvider, IMapperConfigurationExpression> configAction, IEnumerable<Type> profileAssemblyMarkerTypes, ServiceLifetime serviceLifetime = ServiceLifetime.Transient)

可以看到不再存在任何"只有程序集/标记类型、没有配置回调"的重载。需要程序集扫描时,配置回调与程序集参数并存:

// 扫描指定程序集中的 Profile 与 [AutoMap] 映射,同时配置许可证 services.AddAutoMapper( cfg => cfg.LicenseKey = "<License Key Here>", typeof(Program).Assembly);

AddAutoMapper的实际注册逻辑位于 src/AutoMapper/ServiceCollectionExtensions.cs 的AddAutoMapperClasses私有方法中:它会将配置回调以IOptions<MapperConfigurationExpression>的形式注册,扫描程序集并尝试以Transient生命周期注册各类解析器/转换器实现,最后注册IConfigurationProvider(单例)与IMapper(默认Transient,可通过serviceLifetime参数调整)。关于 DI 集成的完整说明可参考 docs/source/Dependency-injection.md。

迁移清单

  • 逐个检查项目中所有AddAutoMapper调用点,为其补充cfg => cfg.LicenseKey = ...作为首个参数(即使你已经通过环境变量提供密钥,也需要传入一个非空回调,例如cfg => { }或仍显式赋值,以保证编译通过);
  • 若之前依赖AddAutoMapper的无参形式,请补齐回调参数。

3.2MapperConfiguration:构造函数现在必须传入ILoggerFactory

15.0 中MapperConfiguration的构造函数签名变为:

public MapperConfiguration( MapperConfigurationExpression configurationExpression, ILoggerFactory loggerFactory)

loggerFactory参数用于诊断(diagnostics)。源码 src/AutoMapper/Configuration/MapperConfiguration.cs 显示,_loggerFactory字段会被保存,并在构造路径中传递给LicenseAccessorLicenseValidator(见 src/AutoMapper/Configuration/MapperConfiguration.cs 与 src/AutoMapper/Licensing/LicenseValidator.cs),许可证校验的 INFO/WARNING/ERROR 日志正是通过这个工厂创建的LuckyPennySoftware.AutoMapper.License记录器输出的。

除此之外,当前仓库还提供了基于配置回调的构造重载:

public MapperConfiguration(Action<IMapperConfigurationExpression> configure, ILoggerFactory loggerFactory) : this(Build(configure), loggerFactory) { }

(见 src/AutoMapper/Configuration/MapperConfiguration.cs)。因此非 DI 场景下最直接的迁移写法为:

using Microsoft.Extensions.Logging.Abstractions; // 无外部容器时可用 NullLoggerFactory 充当诊断记录器 var config = new MapperConfiguration(cfg => { cfg.LicenseKey = "<License Key Here>"; }, new NullLoggerFactory()); var mapper = new Mapper(config);

在 DI 容器中,AddAutoMapper会自动从容器解析ILoggerFactory并完成构造(见 src/AutoMapper/ServiceCollectionExtensions.cs 的sp.GetRequiredService<ILoggerFactory>()),无需手动处理。

迁移清单

  • 所有new MapperConfiguration(...)的调用点都需要补充ILoggerFactory参数;
  • 在 DI 应用中优先使用AddAutoMapper由容器注入;在控制台、测试等无容器场景可使用NullLoggerFactory(来自Microsoft.Extensions.Logging.Abstractions)作为诊断用记录器;
  • 升级后观察启动日志中LuckyPennySoftware.AutoMapper.License类别的输出,确认许可证状态符合预期。

四、完整的升级迁移示例

综合上述所有变更,一个典型的 15.0 迁移示例如下。

ASP.NET Core(DI 场景)

// Program.cs / Startup builder.Services.AddAutoMapper(cfg => { cfg.LicenseKey = "License Key Here"; // 或依赖 AUTOMAPPER_LICENSE_KEY 环境变量 // 其他全局配置,如 cfg.AddProfile<MyProfile>(); }, typeof(Program).Assembly);

无 DI 容器场景

using Microsoft.Extensions.Logging.Abstractions; var config = new MapperConfiguration(cfg => { cfg.LicenseKey = "License Key Here"; }, new NullLoggerFactory()); var mapper = new Mapper(config);

补充建议

  • 升级后运行AssertConfigurationIsValid()(详见 docs/source/Configuration-validation.md)验证所有映射配置;
  • 若项目此前使用了 13.0 升级时引入的Context.State、移除了AllowAdditiveTypeMapCreation等特性,可一并回顾 docs/source/13.0-Upgrade-Guide.md 确认基线;15.0 的完整发布说明可查阅仓库 Release 标签页。

五、总结

AutoMapper 15.0 是一次引入商业模式与 API 收敛的重要升级,核心变化可归纳为三点:

  1. 目标框架:.NET 8、.NET 9 与 .NET Standard 2.0(仓库构建矩阵中还包含 net10.0 与 Windows 下的 net471);
  2. 许可认证:通过cfg.LicenseKeyAUTOMAPPER_LICENSE_KEY/LUCKYPENNY_LICENSE_KEY环境变量提供密钥,校验结果仅以LuckyPennySoftware.AutoMapper.License类别的日志呈现,不限制任何功能;
  3. 两个破坏性变更AddAutoMapper所有重载的首参数必须为配置回调;MapperConfiguration构造函数必须传入ILoggerFactory(用于许可证等诊断日志)。

按照本文的迁移清单逐项核对AddAutoMapper调用点与MapperConfiguration构造点,即可将项目平稳升级到 15.0。若需深入了解许可证的完整配置方式(含客户端分发、重复日志抑制等场景),请阅读 docs/source/License-configuration.md;DI 集成的完整能力说明见 docs/source/Dependency-injection.md。

  • 后端

【免费下载链接】AutoMapper

A convention-based object-object mapper in .NET.

项目地址:https://gitcode.com/gh_mirrors/au/AutoMapper
点击查看免费下载
上一篇:Qwen CLI 上手指南:从装环境到接入自己的脚本,4 步跑通本地大模型对话
下一篇:Omarchy壁纸系统:动态切换与多显示器适配

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询