许可证设置
Doconut 查找许可证文件的位置
没有许可证时,Doconut 仍然可以渲染文档——每页只会带有评估水印。本页介绍提供许可证的四种方式,以及当设置多个时的确切优先级。
提供许可证的四种方式
共有四种:DoconutOptions 上的三种显式来源——流、原始内容或文件路径——以及当它们均未设置时的自动发现。当设置多个时,优先级如下:
LicenseStream 优先于 LicenseContent,LicenseContent 优先于 LicensePath,LicensePath 优先于自动搜索。
通过路径
LicensePath 会原样传递给 File.Exists。相对路径会相对于进程的 当前工作目录 解析——而不是你的项目文件夹,也不是 Program.cs 所在的文件夹。如果路径无法解析,Doconut 不会抛异常,也 不会 回退到自动搜索——它仅仅不加载许可证,查看器会显示水印。只有当 LicensePath、LicenseContent 和 LicenseStream 均未设置时,自动搜索才会运行。位于同一文件夹下的每个插件许可证文件(Doconut.Viewer.<Capability>.lic)会随之读取,因此当插件许可证与基础许可证并列时,LicensePath 与 AddPlugin<...>() 可以协同工作。
建议使用绝对路径(例如由 IWebHostEnvironment.WebRootPath 或 AppContext.BaseDirectory 构建),或者完全省略 LicensePath,依赖下面的自动发现。
builder.Services.AddDoconut(options =>
{
options.LicensePath = Path.Combine(AppContext.BaseDirectory, "wwwroot", "Doconut.Viewer.lic");
});通过流
LicenseStream 在启动时读取一次——当许可证来自密钥存储而不是磁盘文件时非常有用。
// 优先级:LicenseStream > LicenseContent > LicensePath > 自动搜索.
builder.Services.AddDoconut(options =>
{
options.LicenseStream = licenseStream;
});通过内容
LicenseContent 接受许可证文本本身——可以来自环境变量、数据库或密钥管理器:
// 来自数据库、环境变量或密钥管理器的许可证 XML —
// 没有磁盘文件。仅在 LicenseStream 更高时才会被覆盖.
builder.Services.AddDoconut(options =>
{
options.LicenseContent = Environment.GetEnvironmentVariable("DOCONUT_LICENSE") ?? "";
});自动发现
不配置上述三种显式来源,Doconut 会自行搜索许可证:
// 不做任何配置,Doconut 将自行搜索许可证,仅在以下两个文件夹中:
// 1. {CurrentDirectory}/wwwroot
// 2. {AppContext.BaseDirectory}/wwwroot (构建输出文件夹内的 wwwroot)
// 它首先查找 Doconut.lic,然后是 Doconut.Viewer.lic,以及任何与之并列的
// Doconut.Viewer.<Capability>.lic 插件许可证文件.
builder.Services.AddDoconut();1. {CurrentDirectory}/wwwroot
2. {AppContext.BaseDirectory}/wwwroot
Filenames (checked in each folder above, in order):
Doconut.lic — base viewer license (checked first)
Doconut.Viewer.lic — base viewer license
Doconut.Viewer.<Capability>.lic — per-plugin license, alongside the base license除 wwwroot 文件夹之外的任何位置都不会被读取:位于输出文件夹根目录或 wwwroot/lib 中的 .lic 文件会被忽略。
将许可证复制到输出文件夹
当进程不从项目文件夹运行——例如已发布的应用、IIS、容器或测试运行器——第一次探测会失效,第二次探测 {AppContext.BaseDirectory}/wwwroot 必须找到该文件。SDK 自带的测试应用会在每次构建时通过以下 MSBuild 目标将许可证复制过去:
<Target Name="CopyLicensesToOutput" AfterTargets="Build">
<ItemGroup>
<DoconutLicenseFiles Include="$(MSBuildProjectDirectory)\wwwroot\*.lic" />
<StaleOutputLicenses Include="$(OutDir)wwwroot\*.lic" />
</ItemGroup>
<!-- Delete first, so renaming or removing a .lic in wwwroot also takes it out of the output. -->
<Delete Files="@(StaleOutputLicenses)" />
<Copy SourceFiles="@(DoconutLicenseFiles)" DestinationFolder="$(OutDir)wwwroot" />
</Target>目标必须是 $(OutDir)wwwroot:复制到输出根目录的 .lic 永远不会被自动搜索到。本页中的 LicensePath 示例指向的也是同一位置。
将
.lic文件排除在源代码控制之外——将它们与应用一起部署,或通过LicenseContent或LicenseStream从密钥存储注入许可证。
没有许可证会怎样
缺少许可证不会抛出异常。AddDoconut() 成功,应用启动,查看器运行——但每页都会带有评估水印,且没有授予任何可选功能。
找到但被拒绝的许可证文件情况不同。签名无效、被篡改、列入黑名单,或构建版本超出许可证的版本窗口,都会导致 OpenDocumentAsync 抛出带有 License.RejectionMessage 的 LicenseException。没有拒绝信息的日历过期许可证会继续以水印模式运行。
插件需要功能
为没有相应授权的插件进行注册的情况也不同:对于缺少许可证、旧版 TRIAL 文件,或不包含该功能的付费许可证,AddDoconut() 会抛出 InvalidOperationException,导致应用无法启动。例如,注册 Converter 插件但没有授予 Converter 的许可证:
InvalidOperationException: The Converter plugin is registered via AddPlugin but no active
license grants Converter. Remove the AddPlugin<...>() call or install a license (or
trial/demo) that includes Converter.该信息直接告诉你如何修复:要么移除该插件的 options.AddPlugin<...>() 调用,要么安装包含该功能的付费许可证或有效的临时/演示(NFR)许可证。临时注册可以在过期后仍然保留,以便已配置的应用在运行时降级而不是在重启时崩溃;过期后,它们的功能仍会被撤销。
验证已加载的许可证
使用 IDoconutLicenseService(SDK 使用的同一真实数据源),可以公开经过身份验证的诊断端点或驱动功能标记。不要返回许可证内容或密钥。
app.MapGet("/api/doconut/license", (IDoconutLicenseService license) => Results.Ok(new
{
viewer = license.IsViewerLicensed || license.IsTemporary,
temporary = license.IsTemporary,
search = license.IsCapabilityGranted(LicenseCapability.Search),
annotation = license.IsCapabilityGranted(LicenseCapability.Annotation),
converter = license.HasConverter,
dicom = license.HasDicom
}));许可证在 AddDoconut() 注册期间读取。ResetLicense 目前是一个兼容性属性,没有可用的主动重新加载路径,因此更换许可证文件需要重新启动应用程序。
故障排查矩阵
| 症状 | 可能原因 | 检查 |
|---|---|---|
| 查看器可用,但每页都有水印 | 未加载许可证,或许可证已过期 | 解析 IDoconutLicenseService;检查输出目录和进程工作目录 |
AddDoconut() 对插件抛出异常 | 许可证未授予该插件的功能 | 检查 IsCapabilityGranted(...) 并移除未购买的注册 |
| 配置的相对路径在本地可用,但在 IIS/容器中不可用 | 进程工作目录已更改 | 使用 AppContext.BaseDirectory 或绝对路径 |
替换的 .lic 文件无效 | 单例许可证服务已创建 | 重新启动应用程序 |
OpenDocumentAsync 抛出 LicenseException | 签名、域、版本窗口、黑名单或插件运行时门禁拒绝了许可证 | 读取异常/拒绝信息,但不要向不受信任的客户端暴露 |
后续步骤
此页面对您有帮助吗?