news 2026/10/13 22:43:54

EPPlus 8 许可证配置指南:ExcelPackage.License 的四种设置方式与源码级解析

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
EPPlus 8 许可证配置指南:ExcelPackage.License 的四种设置方式与源码级解析
  • 后端

【免费下载链接】EPPlus

EPPlus-Excel spreadsheets for .NET

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

本文围绕 EPPlus 8 的许可证机制展开:EPPlus 8 采用"非商业/商业"双许可模式,在创建任何 ExcelPackage 之前必须先声明你使用的是哪种许可证。读完本文,你将掌握通过代码、appsettings.json、app/web.config和环境变量四种方式配置许可证的完整方法,并理解 EPPlus 在源码层面如何读取、校验许可证以及在保存工作簿时写入许可标记的完整机制。

一、EPPlus 8 的双许可模式

EPPlus 8 采用双许可(dual license)模型:

  • 非商业使用:遵循Polyform Noncommercial 1.0.0社区许可,个人或非商业组织可以免费使用 EPPlus;
  • 商业使用:在商业企业中使用时必须购买商业许可证(含技术支持),可前往 EPPlus Software 官网购买。

这一点在仓库根目录的 license.md 中同样有声明,src/EPPlus/EPPlus.csproj 的PackageReleaseNotes也明确记录了"From version 5 EPPlus changes the license model using a dual license, Polyform Non Commercial / Commercial license"。

当前仓库中的主库版本为8.7.1(见 src/EPPlus/EPPlus.csproj 中<Version>8.7.1</Version>),目标框架覆盖net35、net462、netstandard2.0、netstandard2.1、net8.0、net9.0、net10.0,因此下文描述的许可证行为适用于 EPPlus 8 全系版本。

二、许可证参数必须设置:LicenseNotSetException 从何而来

在 EPPlus 8 中,许可证通过ExcelPackage类的静态License属性来声明。从源码看,这是一个进程级单例:

// src/EPPlus/ExcelPackage.cs(L771) public static EPPlusLicense License { get; } = new EPPlusLicense();

检查是惰性的:构造ExcelPackage本身不会立即报错,只有当首次访问package.Workbook触发工作簿初始化时,才会调用License.IsLicenseSet(_initErrors)检查许可证是否已设置;若未设置且无法从配置中自动读取,则抛出LicenseNotSetException(见 src/EPPlus/ExcelPackage.cs):

if (License.IsLicenseSet(_initErrors) == false) { throw (new LicenseNotSetException("Please set the license using one of the methods on the static property ExcelPackage.License. ...")); }

EPPlusLicense.IsLicenseSet的逻辑是:如果已通过代码设置(静态标志_licenseSet为 true)则直接返回 true;否则回退到SetLicenseFromConfig尝试从环境变量或配置文件读取(见 src/EPPlus/EPPlusLicense.cs)。

相关的异常类型都定义在 src/EPPlus/LicenseException.cs 中,包括:

异常触发场景
LicenseNotSetException访问 Workbook 时许可证尚未设置
InvalidLicenseKeyException商业许可证密钥无法通过校验(签名/格式错误)
LicenseNotValidException许可证已过期或不适用于当前版本
LicenseInformationException非商业使用名称校验失败,或配置串缺少名称部分
LicenseContextPropertyObsoleteException使用了 EPPlus 7 及更早版本废弃的LicenseContext属性

三、四种方式配置许可证

1. 通过代码设置

这是最直接的方式,在创建任何ExcelPackage之前调用:

// 商业用户(已购买商业许可证): ExcelPackage.License.SetCommercial("<Your License Key here>"); // 非商业使用(遵循 Polyform Noncommercial 许可): ExcelPackage.License.SetNonCommercialPersonal("<Your Name>"); // 或者,代表一个非商业组织使用: ExcelPackage.License.SetNonCommercialOrganization("<Your Noncommercial Organization>"); using(var package = new ExcelPackage(new FileInfo("MyWorkbook.xlsx"))) { // ... 业务逻辑 }

三个方法对应 src/EPPlus/EPPlusLicense.cs 中的同名成员:

  • SetCommercial(string licenseKey):传入购买的许可证密钥,密钥可在 EPPlus Software 网站的 "My Licenses" 页面以及 2025 年 2 月之后创建的 EPPlus 许可证文档中查看;
  • SetNonCommercialPersonal(string fullName):传入个人姓名,会写入 Office 文档属性;
  • SetNonCommercialOrganization(string organizationName):传入非商业组织名称。

名称校验规则:两个非商业方法内部都会调用私有方法ValidateName(见 src/EPPlus/EPPlusLicense.cs),传入的名称必须同时满足:

  1. 长度至少 3 个字符(否则报 "The license holder name must be at least 3 characters.");
  2. 不能包含/、\、*、控制字符或制表符(报 "The license holder name contains invalid characters");
  3. 至少包含 2 个字母字符(报 "The license holder name contains to few letters.")。

校验不通过会抛出LicenseInformationException。

商业密钥的校验流程(SetCommercial→LicenseHandler.ValidateLicenseKey,见 src/EPPlus/LicenseHandler.cs):

  1. 密钥是 Base64 编码的,先解码出 512 位签名和版本、许可证编号、生效/失效日期、许可证类型、授权开发人数等字段(GetLicenseDataFromKey);
  2. 用内嵌的 RSA 公钥对重建的数据块做SHA256 + PKCS#1签名验证,签名不符则返回InvalidLicenseKey;
  3. 签名通过后进行日期校验(ValidateLicenseDates):
    • 生效日晚于今天 →NotValidForThisVersion;
    • 订阅(Subscription)许可:过期后有 30 天宽限期用于续订;再配合ExtendUnderRenewal = true可额外延长 15 天(续订期临时键);
    • 永久(Perpetual)许可:失效日晚于当前 EPPlus 版本发布日期(源码中为EPPlusLicense._versionDate = "2026-08-20")时,无法用于更新的版本。

另外,SetCommercial中有一个专门约束:如果设置了ExtendUnderRenewal = true,但许可证实际到期日早于"今天 - 20 天",会直接抛出LicenseNotValidException,提示该标志只应在续订窗口内使用。

2. 通过 appSettings.json / appsettings.json 配置

在 .NET 6+ 项目中,EPPlus 会从 JSON 配置文件读取EPPlus:ExcelPackage:License键(源码头文件为#if(Core),见 src/EPPlus/ExcelConfigurationReader.cs)。注意 docs/articles/readme.md 中的示例 JSON 括号有多余的嵌套,下面是可运行的正确结构:

商业使用:

{ "EPPlus": { "ExcelPackage": { "License": "Commercial:<Your License Key here>" } } }

非商业使用:

{ "EPPlus": { "ExcelPackage": { "License": "NonCommercialPersonal:<Your Name>" } } }

非商业组织则使用"NonCommercialOrganization:<Your organizations name>"。

JSON 配置的读取细节(同样来自 ExcelConfigurationReader.cs):

  • 若通过ExcelPackage.Configuration或ExcelPackage.Configure(...)注入了IConfiguration实例,则优先从注入实例读取;
  • 否则按文件路径构建,其中配置文件名默认为appsettings.json,基础目录默认为当前工作目录,这两项均可通过 ExcelPackageConfiguration 的JsonConfigFileName和JsonConfigBasePath属性覆盖;
  • 若ExcelPackageConfiguration.SuppressInitializationExceptions为 true,读取失败会记录到ExcelPackage.InitializationErrors而不是抛出异常。

3. 通过 app/web.config 配置

在 .NET Framework 项目中,EPPlus 从ConfigurationManager.AppSettings读取键值(见 src/EPPlus/ExcelConfigurationReader.cs),源码同时兼容冒号与点号两种写法(EPPlus:ExcelPackage:License与EPPlus:ExcelPackage.License)。商业使用:

<appSettings> <!--The license context used--> <add key="EPPlus:ExcelPackage.License" value="Commercial:<Your License Key here>" /> </appSettings>

非商业使用:

<appSettings> <!--The license context used--> <add key="EPPlus:ExcelPackage.License" value="NonCommercialPersonal:<Your Name>" /> </appSettings>

非商业组织同样使用NonCommercialOrganization:<Your organizations name>。

4. 设置环境变量 EPPlusLicense

这是最省事的方式。将环境变量EPPlusLicense设置为以下三种格式之一:

  • Commercial:<Your License Key>
  • NonCommercialPersonal:<Your Name>
  • NonCommercialOrganization:<Your organizations name>

在 Windows 控制台使用SETX以用户级设置变量的示例:

> SETX EPPlusLicense "Commercial:<Your License Key>"

从源码看,环境变量的查找顺序是进程(Process)→ 用户(User)→ 机器(Machine)三个作用域依次查找(见 src/EPPlus/EPPlusLicense.cs),并且环境变量优先级高于配置文件。

四、配置字符串的解析规则

无论来自环境变量还是配置文件,EPPlus:ExcelPackage:License的值都交给 EPPlusLicense.SetLicenseFromConfig 解析,规则如下:

  1. 值按:或,分割(大小写不敏感匹配前缀);
  2. 前缀为noncommercialorganization或noncommercialpersonal时,分隔符之后的部分作为组织名/姓名传入对应的SetNonCommercial...方法;若缺少名称部分,抛出LicenseInformationException并提示完整格式;
  3. 前缀为commercial时,去掉前缀后用剩余部分作为密钥调用SetCommercial;
  4. 没有前缀、或前缀无法识别的值,会整体当作商业许可证密钥处理(直接调用SetCommercial(v.Trim()));
  5. 解析成功后,ExcelPackage.License.Source会被标记为EPPlusLicenseSource.EnvironmentVariable或EPPlusLicenseSource.ConfigFile,用于区分许可证来源。

EPPlusLicense对象上可读取的状态属性(定义见 src/EPPlus/EPPlusLicense.cs):

属性说明
LicenseTypeEPPlusLicenseType枚举:Commercial/NonCommercialPersonal/NonCommercialOrganization
SourceEPPlusLicenseSource枚举:Code/EnvironmentVariable/ConfigFile
LegalName非商业使用时的姓名/组织名
LicenseKey商业许可证密钥
LicenseInfo密钥解析出的许可信息:LicenseNumber、LicenseType、LicenseValidFrom、LicenseValidTo、NumberOfLicensedDevelopers、Status
ExtendUnderRenewal续订宽限标志(true 时最多额外延长 15 天)

商业许可的类型是一个 Flags 枚举 EPPlusCommercialLicenseType,包含Subscription、Perpetual、Package、Custom、PayAsYouGo、Trial、TemporaryKey。

五、保存工作簿时许可证如何影响文件内容

这是文档中"非商业使用会占用包内 Comment 与 Tag 字段并添加许可文件"的源码依据。工作簿保存时,ExcelWorkbook.HandleLicense 按许可证类型分派:

  • Commercial:先用ValidateLicenseKey复核密钥,若为 Trial 类型则调用TrialTagDocument写入试用标记(注释中含到期日),否则调用ApplyCommercialLicense;
  • NonCommercialPersonal / NonCommercialOrganization:调用LicenseHandler.TagDocument。

LicenseHandler.TagDocument 的具体行为:

  1. 将工作簿属性的Keywords设为"EPPlus noncommercial use",Comments写入"本工作簿由 XX 在 Polyform Noncommercial 许可下使用 EPPlus 创建"的说明文本;
  2. Application设为EPPlus,AppVersion设为当前程序集大版本号;
  3. 组织许可写入Company属性,个人许可写入Author属性;
  4. 在包内创建/EPPlusLicense.txt部件(text/plain),写入许可声明文本。

而商业许可的ApplyCommercialLicense做的是相反操作:如果包内存在/EPPlusLicense.txt则将其删除——这解释了为什么用商业密钥保存可以"洗掉"非商业标记。

六、测试用例中的验证方式

仓库中的 src/EPPlusTest/LicenseTest.cs 提供了四类可参照的验证示例:

  • NonCommercialPersonalFunctionTest/NonCommercialOrganizationFunctionTest:设置名称后新建工作簿并保存,验证非商业标记链路;
  • CommercialConfigEnvironmentTest:Environment.SetEnvironmentVariable("EPPlusLicense", "NonCommercialPersonal:Jan Källman", EnvironmentVariableTarget.Process),随后断言Source == EnvironmentVariable、LegalName == "Jan Källman",验证了环境变量解析路径;
  • CommercialFunctionTest:对一个已过期的测试密钥断言LicenseInfo.Status == Expired、生效/失效日期与授权人数,展示SetCommercial抛出LicenseNotValidException后仍可通过LicenseInfo读取解析结果;
  • CommercialConfigFileTest:调用RemoveActiveLicense()清除代码设置后,断言许可证从配置文件恢复且Source == ConfigFile。

RemoveActiveLicense(src/EPPlus/EPPlusLicense.cs)会清空LicenseType、LicenseKey、Source、LegalName、LicenseInfo并重置内部标志,适合在测试或切换许可模式时使用。

七、EPPlus 8 的新特性与破坏性变更(速览)

docs/articles/readme.md 将"新特性"与"破坏性变更"指向官方 Wiki。结合 src/EPPlus/EPPlus.csproj 中 EPPlus 8 各小版本的PackageReleaseNotes,EPPlus 8 相对 7.x 的主要增量包括:

  • 8.0.1:OLE 对象(链接或嵌入文件)支持、工作簿数字签名与签名线、单元格内图片 /IMAGE函数支持、Sensitivity Label API(对接 MIP);
  • 8.1.0:图表中嵌入形状与图片、页眉页脚样式接口;
  • 8.2.0:8 个 LAMBDA 族函数(LAMBDA、SCAN、MAP、REDUCE、BYROW、BYCOL 等)支持;
  • 8.3.0:外部连接与查询表的增删改、外部连接作为数据透视表数据源;
  • 8.6.0 / 8.6.1:新增 GROUPBY、PIVOTBY、REGEX 系列等函数及 trim 引用运算符支持;
  • 8.7.0:ExcelPackage.Save新增保存为模板(xlst/xltm)的重载。

破坏性变更中最常见的一条(同样记录于 csproj 发布说明):在 .NET Framework 下,Worksheets 集合的起始索引从 1 变为 0,与 .NET Core 行为对齐;为保持旧行为,可将IsWorksheets1Based设为 true(也可在 app.config 中设置)。

八、配置速查表

场景推荐方式值示例
本地个人开发(非商业)代码或环境变量NonCommercialPersonal:John Smith
高校/研究所等组织(非商业)代码或环境变量NonCommercialOrganization:ACME University
.NET 6+ 商业服务appsettings.jsonEPPlus:ExcelPackage:License = Commercial:<Key>
.NET Framework 商业服务web.config appSettingsEPPlus:ExcelPackage.License = Commercial:<Key>
CI/CD 或容器环境环境变量EPPlusLicenseCommercial:<Key>

需要牢记的三个要点:一是所有方式最终都汇入同一个静态ExcelPackage.License对象,环境变量优先于配置文件、代码设置优先于两者;二是非商业模式会在每个保存的工作簿中写入许可标记(文档属性 +/EPPlusLicense.txt),这是 Polyform Noncommercial 许可的强制合规动作;三是商业密钥包含本地可验证的 RSA 签名与有效期信息,EPPlus 8 会在线下完成完整校验,过期、签名不符或版本不适配都会以明确的异常类型反馈。

  • 后端

【免费下载链接】EPPlus

EPPlus-Excel spreadsheets for .NET

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

相关推荐

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/13 22:43:05

MATLAB 2016b永磁风机混合储能并网仿真建模全解析

前阵子把一套5MW永磁同步风机-1200V直流混合储能并网系统的MATLAB仿真完整跑通了&#xff0c;用的还是MATLAB 2016b。老实说&#xff0c;这个项目只看标题好像没什么特别——风电、储能、并网仿真&#xff0c;都是电气工程里很常规的方向。但真正动手做下来&#xff0c;光是“把…

作者头像 李华
网站建设 2026/10/13 22:42:26

VISSIM动态交通分配DTA实战:从固定路径到路网仿真的调校指南

如果你用过VISSIM做信号优化&#xff0c;八成遇到过这种情况&#xff1a;方案参数调得很到位&#xff0c;仿真动画里车辆还是一股脑扎进同一条路&#xff0c;旁边平行的城市支路空荡荡。问题往往不在信号配时&#xff0c;也不在路网建模&#xff0c;而在你用的是固定路径——车…

作者头像 李华
网站建设 2026/10/13 22:42:07

HIPAA合规实战:ePHI数据加密、访问控制与审计追踪全指南

有朋友问我做医疗健康类项目最头疼的是什么&#xff0c;我的回答几乎都是同一个&#xff1a;HIPAA合规中的数据保护措施。不是HIPAA这套规则本身复杂到没法理解&#xff0c;而是它分散在存储、传输、访问、审计、第三方协作等每一个环节里&#xff0c;随便哪一处漏风&#xff0…

作者头像 李华
网站建设 2026/10/13 22:41:31

贪心最佳优先搜索(GBFS)原理与Python实现,从理论到工程避坑

我在给某导航系统的预研项目做路径规划方案时&#xff0c;第一次认真把贪心最佳优先搜索&#xff08;Greedy Best-First Search&#xff0c;GBFS&#xff09;从理论翻到了工程实现。当时的需求很直白&#xff1a;在几万个节点的路网里&#xff0c;要快&#xff0c;快地给出一个…

作者头像 李华
网站建设 2026/10/13 22:36:06

盲水印与隐写实战:DCT中频嵌入与抗压缩参数调优

简介&#xff1a;这是一份面向CTF Misc方向选手与图像隐写初学者的数字盲水印实战工具包&#xff0c;基于傅里叶变换实现水印的嵌入与提取&#xff0c;可用于赛题复现、隐写原理验证及日常图像取证练习。包内共12个文件&#xff0c;以7个png示例图片、2个Python脚本为主&#x…

作者头像 李华
网站建设 2026/10/13 22:36:00

WordNet可视化:用Python绘制语义图谱的实用指南

1. 项目概述&#xff1a;为什么WordNet可视化不是炫技&#xff0c;而是NLP理解的“显微镜”你有没有试过在教别人什么是“同义词集合”&#xff08;synset&#xff09;时&#xff0c;光靠文字解释半天&#xff0c;对方还是皱着眉头问&#xff1a;“那它到底长什么样&#xff1f…

作者头像 李华