从经典 .NET 6 集成迁移

将现有 Doconut.NET6 应用迁移到当前的 DI 和异步 API

Doconut 有两种不同的 .NET 6 集成方式。它们可以使用相同的 Doconut.NET6 包名,因此在更改包、启动方式、许可证或浏览器资源之前,需要先通过应用中的 API 确认使用的是哪一代。

您正在使用哪种 .NET 6 集成?

如果项目包含…代别
app.MapWhen(... "DocImage.axd" ...)传统 / 经典
new Viewer(_cache, _accessor, ...)传统 / 经典
Viewer.DoconutLicense(...) 或 Viewer.SetLicensePlugin(...)传统 / 经典
手动复制的 docViewer.js、documentLinks.js 或 docViewer.UI.js传统 / 经典
builder.Services.AddDoconut(...)当前集成
app.UseDoconutResources() 加 app.UseDoconut()当前集成
通过依赖注入提供的 Viewer当前集成
await viewer.OpenDocumentAsync(...)当前集成

如果同一应用中出现了两列的内容,则视为迁移未完成。不要在资源或中间件中使用一个代别的文档令牌来处理另一个代别的请求。

为什么 NuGet 包名可能无法告诉你

两代都使用 Doconut.NET6 包标识。因此,仅凭包引用、锁文件或缓存的 .nupkg 并不能单独确定所使用的 API。请记录确切的包版本,并一起检查 Program.cs、Viewer 构造、文档打开方式以及浏览器脚本。

本指南审计的当前发布版本是 Doconut.NET6 26.7.0。其可选的公共包为 Doconut.NET6.Converter 和 Doconut.NET6.Dicom,与核心包保持相同的发布版本。

迁移前的准备

  1. 为现有应用创建一个分支并生成可部署的备份。
  2. 记录核心包和插件包的确切版本。
  3. 清点每一个 DocImage.axd 映射、new Viewer(...) 调用、许可证加载调用、复制的 Doconut 脚本、自定义工具栏操作以及文档打开端点。
  4. 将当前的 .lic 文件和部署机密保存在源码控制之外。
  5. 收集一套具有代表性的 PDF、Office、图像、CAD、电子邮件、DICOM、可搜索、受密码保护以及带批注的文档。
  6. 记录现有的会话超时、安全行为、字体以及平台设置。

在更改生产环境之前,先在一个环境中完成迁移。当前的集成会改变服务生命周期、请求路由、会话所有权以及客户端资源交付方式。

包和许可证兼容性

请有意识地替换或更新核心包;不要依赖相同的包 ID 来自动选择新 API。默认命令会安装最新的稳定版:

bash
dotnet add package Doconut.NET6

若要进行可重现的迁移以匹配本指南审计的发布版本,请将版本号作为单独的选项传入:

bash
dotnet add package Doconut.NET6 --version 26.7.0

保持每个 Doconut 插件的版本与核心包保持一致。当前的集成在 AddDoconut() 时一次性加载许可证,使用以下优先级:

text
LicenseStream > LicenseContent > LicensePath > automatic discovery

自动发现会查找 Doconut.Viewer.lic 以及伴随的 Doconut.Viewer.<Capability>.lic 文件。传统的 Viewer.DoconutLicense(...) 或 Viewer.SetLicensePlugin(...) 调用已不再是当前的启动机制。请将许可证移动到 DoconutOptions,在使用自动发现时保持伴随文件一起放置,修改许可证后重新启动,并通过 IDoconutLicenseService 验证功能。

不要假设旧插件许可证的存在就等同于当前插件构建的授权。请分别使用已批准的发布制品测试 Viewer、Search、Annotation、Converter 和 DICOM。

启动与依赖注入

经典应用使用 ASP.NET 缓存和请求访问器依赖来构造 Viewer:

csharp
// 经典集成 — 仅作对比;不要在当前 SDK 上编译此代码。
var viewer = new Viewer(_cache, _accessor, licenseFilePath);

当前的集成只注册一次 Doconut,并通过依赖注入获取 Viewer:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.UnsafeMode = false;
});
builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession();

app.UseSession();
app.UseDoconutResources();
app.UseDoconut();

Viewer 是瞬态服务。文档会话管理器及其缓存拥有更长生命周期的文档状态,而不是特定注入的 Viewer 实例。

中间件与资源路由

移除检测 DocImage.axd 的经典 MapWhen 分支:

csharp
// 经典集成 — 在切换期间移除。
app.MapWhen(
    context => context.Request.Path.ToString().EndsWith("DocImage.axd"),
    branch => branch.UseDoconut(new DoconutOptions()));

在当前管道中:

  1. 在启用会话安全时,在 Doconut 之前调用 UseSession();
  2. 在 UseDoconut() 之前调用 UseDoconutResources();
  3. 保持 ResourcesPath、生成的资源 URL 与客户端 ResPath 对齐;
  4. 将 UseDoconut() 映射到分支时,保持该分支和客户端 BasePath 对齐。

MiddlewarePath 是已验证的配置;它本身不会创建 ASP.NET Core 分支。可以使用上面编译示例中的简易管道,或使用一致的 app.Map("/doconut", branch => branch.UseDoconut()) 布局。

Viewer 构造与生命周期

移除应用拥有的 Viewer 缓存。将 Viewer 注入到端点、Razor 页面、控制器或作用域的应用服务中:

csharp
app.MapPost("/api/open", async (Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
    return Results.Ok(new { token });
});

返回的 token 标识服务器端的文档会话。将其视为持有者凭证:不要记录、持久化或放入分析中。

打开与关闭文档

将同步的 OpenDocument(...) 替换为 OpenDocumentAsync(...):

csharp
// 当前 .NET 6 集成:Viewer 来自 DI,文档打开为异步操作。
var token = await viewer.OpenDocumentAsync(path, new PdfConfig { AllowSearch = true });

当前的重载接受文件路径或流、可选的格式配置、可选的 DocOptions,以及取消令牌。当浏览器不再需要时,请显式关闭服务器会话:

csharp
viewer.CloseDocument(token);

切换后不要复用经典 token。请通过当前 API 重新打开每个文档。

配置类

当前 API 将关注点分离:

关注点当前类型
中间件路径、授权、插件注册DoconutOptions
密码、超时、安全性、水印DocOptions
格式渲染和 DPIPdfConfig、WordConfig、ExcelConfig 以及其他 BaseConfig 类型
浏览器部件默认值ViewerConfig 或等效的 JavaScript 选项
生成的 CSS 与脚本CssConfig 与 ScriptConfig

不要继续使用 DocOptions.ImageResolution 作为渲染控制。它已废弃;请在特定格式的配置上设置 BaseConfig.ImageResolution。请检查所有默认值,而不要假设经典配置具有相同的行为。

Viewer 工具栏、搜索与批注

不要逐个迁移旧脚本。当前参考应用会组合成完整的页面包:

  1. 使用 ReferenceCss 输出 Viewer CSS 与授权的 Search/Annotation CSS;
  2. 渲染应用拥有的 Viewer 工具栏;
  3. 渲染 searchBarMount、annBarMount 以及必需的 Viewer 挂载点;
  4. 使用 ReferenceScripts 输出 Viewer 与授权模块脚本;
  5. 加载应用自己的 viewerToolbar.js;
  6. 初始化一个 objViewer;
  7. 初始化授权的 Search 与 Annotation 功能区;
  8. 对每个功能区调用 attach(objViewer);
  9. 打开文档并调用 objViewer.View(token)。

搜索和批注是附加到同一 Viewer 的模块,而非独立的工具栏。主工具栏属于宿主应用;搜索和批注功能区是嵌入式、受功能开关控制的资源。

仅在当前页面能够使用 ReferenceCss 与 ReferenceScripts 输出的资源后,才移除手动复制的经典文件,如 documentLinks.js 和 docViewer.UI.js。

插件注册

传统的静态插件许可证方法不会注册当前插件。请显式安装并注册每个已发布的包:

csharp
builder.Services.AddDoconut(options =>
{
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddPlugin<Doconut.Plugins.Dicom.DicomPlugin>();
});

AddDoconut() 在启动时验证已注册插件的功能。Converter 和 DICOM 是已发布的 .NET 6 插件。Normal Search 和 Annotation 是内置的授权功能,不是 AddPlugin<TPlugin>() 包。

会话和文档安全

当前的集成将文档绑定到不透明令牌和缓存的会话。 在默认 UnsafeMode = false 下,UseDoconut() 会添加文档访问安全性,主机必须配置 ASP.NET 会话:

csharp
builder.Services.AddDistributedMemoryCache(); // 会话状态需要缓存(MVC/Razor Pages 已经添加了一个)
builder.Services.AddSession();
app.UseSession();

除非经过审查的设计另有要求,否则保持 DocOptions.IsSecured = true。 切勿将 UnsafeMode = true 用作迁移的捷径。 测试没有令牌、令牌格式错误、令牌已过期以及来自不同浏览器会话的令牌的请求。

Distributed 示例应用程序会添加访问票据和传输细节。 这些 API 对于普通的单节点迁移并非必需。

测试迁移

至少,需要验证以下内容:

  • 应用程序启动时使用生产许可证并加载所有已注册插件;
  • Viewer 的 CSS/脚本以及所选路径下的所有页面图像请求;
  • 文档打开、导航、缩放、缩略图、打印以及显式关闭;
  • 在包含文本的文档上进行搜索,以及对仅图像文件的不可搜索状态进行验证;
  • 注释的加载、保存、导出以及功能限制;
  • Converter 目标发现、输出、下载以及水印状态;
  • DICOM 页面、帧和动画;.NET 6 技术元数据不可用;
  • 受密码保护的文档、自定义字体、非拉丁文字以及配置的超时;
  • 跨会话令牌拒绝以及会话过期行为;
  • 移动端、暗色模式以及生产环境的反向代理路径。

回滚计划

保留经典部署产物、相匹配的包、许可证文件以及复制的浏览器资源。 安全的回滚会切换整个应用程序的代际,不会将经典服务器与当前脚本混用,也不会将当前服务器与经典的 DocImage.axd 调用混用。

在切换之前,记录以下内容:

  • 用于回滚的部署槽或产物;
  • 数据库/缓存的影响(如果有);
  • 活动文档会话将如何失效;
  • 用于决定回滚的健康检查和冒烟文档;
  • 谁可以恢复之前的包集合和配置。

旧版文档

已翻译的经典手册仍可在 旧版 .NET 6 设置 中获取。 新的 经典集成网关 解释相同的识别信号,并链接回本迁移指南。

在经典安装仍然存在期间,请在书签和支持工单中保留该历史 URL。 它记录了不同的代际,并未重定向到当前的 API。

此页面对您有帮助吗?