- 后端
【免费下载链接】EPPlus
EPPlus-Excel spreadsheets for .NET
本文围绕 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),传入的名称必须同时满足:
- 长度至少 3 个字符(否则报 "The license holder name must be at least 3 characters.");
- 不能包含
/、\、*、控制字符或制表符(报 "The license holder name contains invalid characters"); - 至少包含 2 个字母字符(报 "The license holder name contains to few letters.")。
校验不通过会抛出LicenseInformationException。
商业密钥的校验流程(SetCommercial→LicenseHandler.ValidateLicenseKey,见 src/EPPlus/LicenseHandler.cs):
- 密钥是 Base64 编码的,先解码出 512 位签名和版本、许可证编号、生效/失效日期、许可证类型、授权开发人数等字段(
GetLicenseDataFromKey); - 用内嵌的 RSA 公钥对重建的数据块做SHA256 + PKCS#1签名验证,签名不符则返回
InvalidLicenseKey; - 签名通过后进行日期校验(
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 解析,规则如下:
- 值按
:或,分割(大小写不敏感匹配前缀); - 前缀为
noncommercialorganization或noncommercialpersonal时,分隔符之后的部分作为组织名/姓名传入对应的SetNonCommercial...方法;若缺少名称部分,抛出LicenseInformationException并提示完整格式; - 前缀为
commercial时,去掉前缀后用剩余部分作为密钥调用SetCommercial; - 没有前缀、或前缀无法识别的值,会整体当作商业许可证密钥处理(直接调用
SetCommercial(v.Trim())); - 解析成功后,
ExcelPackage.License.Source会被标记为EPPlusLicenseSource.EnvironmentVariable或EPPlusLicenseSource.ConfigFile,用于区分许可证来源。
EPPlusLicense对象上可读取的状态属性(定义见 src/EPPlus/EPPlusLicense.cs):
| 属性 | 说明 |
|---|---|
LicenseType | EPPlusLicenseType枚举:Commercial/NonCommercialPersonal/NonCommercialOrganization |
Source | EPPlusLicenseSource枚举: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 的具体行为:
- 将工作簿属性的
Keywords设为"EPPlus noncommercial use",Comments写入"本工作簿由 XX 在 Polyform Noncommercial 许可下使用 EPPlus 创建"的说明文本; Application设为EPPlus,AppVersion设为当前程序集大版本号;- 组织许可写入
Company属性,个人许可写入Author属性; - 在包内创建
/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.json | EPPlus:ExcelPackage:License = Commercial:<Key> |
| .NET Framework 商业服务 | web.config appSettings | EPPlus:ExcelPackage.License = Commercial:<Key> |
| CI/CD 或容器环境 | 环境变量EPPlusLicense | Commercial:<Key> |
需要牢记的三个要点:一是所有方式最终都汇入同一个静态ExcelPackage.License对象,环境变量优先于配置文件、代码设置优先于两者;二是非商业模式会在每个保存的工作簿中写入许可标记(文档属性 +/EPPlusLicense.txt),这是 Polyform Noncommercial 许可的强制合规动作;三是商业密钥包含本地可验证的 RSA 签名与有效期信息,EPPlus 8 会在线下完成完整校验,过期、签名不符或版本不适配都会以明确的异常类型反馈。
- 后端
【免费下载链接】EPPlus
EPPlus-Excel spreadsheets for .NET
相关推荐
EPPlus 8 授权配置完全指南:双许可模型与四种 License 设置方式
EPPlus 8 授权配置完全指南:双许可模型与四种 License 设置方式 EPPlus 8 是 .NET 生态中流行的 Excel 读写库(项目位于 gh
后端Traefik 启动环境配置详解:Install Configuration 的四种配置方式与源码实现
Traefik 启动环境配置详解:Install Configuration 的四种配置方式与源码实现 本文聚焦 Traefik Proxy 的“启动环境(Bo
后端API网关负载均衡微服务网络云原生Xinference 部署 GLM-5:744B MoE 模型的四种格式启动与源码级配置解析
Xinference 部署 GLM 5:744B MoE 模型的四种格式启动与源码级配置解析 GLM 5 是面向复杂系统工程与长程 Agent 任务的新一代 M
模型推理服务人工智能大模型本地部署多模态语音
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考