查看器工作原理
文档请求生命周期
Doconut 将文档渲染为通过 ASP.NET Core 中间件提供的分页图像。了解整个生命周期——打开、令牌、页面请求、关闭——可以解释您几乎会观察到的所有行为,包括错误信息。
三个关键组成部分
Viewer— 您注入的公共服务。它打开文档并返回会话令牌。- 文档会话 — 在服务器端保存已加载文档的对象,以
IMemoryCache中的令牌为键。 - Doconut 中间件 — 通过
UseDoconut()添加;响应浏览器小部件发出的每个请求(pages、thumbnails、search、annotations等),始终通过令牌进行身份验证。
Viewer 是无状态的 —— 设计如此
Viewer 为 sealed 类型,不持有每个请求的文档状态,并且刻意 不 实现 IDisposable。会话独立存在于会话管理器中,并通过缓存过期或显式调用 CloseDocument(token) 来清理。
在需要的地方注入它:
csharp
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
var token = await viewer.OpenDocumentAsync($"files/{fileName}");
return Results.Content(token, "text/plain");
});OpenDocumentAsync 内部发生了什么
- 许可证检查。 被拒绝或已过期的许可证(列入黑名单、被篡改,或在许可证更新窗口之外的构建)会立即抛出
LicenseException,并将拒绝原因作为消息——对于无效(而非缺失)许可证,打开操作永不静默降级。日历过期的临时或订阅许可证是例外:它不会抛出异常,而是降级为水印。 - 会话创建。 查看器工厂根据文件扩展名选择合适的格式查看器并加载文档(参见渲染管道)。会话以全新 GUID 令牌存储在
IMemoryCache中,具有 滑动过期——DocOptions.TimeOut分钟,默认 60。每次页面请求都会重置计时。 - 安全注册。 当
UnsafeMode = false(默认)时,令牌绑定到调用者的 ASP.NET 会话:在会话中写入secure-{token}标记,只有打开文档的浏览器会话才能请求其页面。 - 返回令牌。 令牌是后续所有操作的唯一凭证。
这三个重载唯一的区别在于输入:文件路径、带有每种格式配置的文件路径(PdfConfig、WordConfig 等),或带有 FileInfo(其扩展名决定格式检测)的 Stream。
小部件如何获取页面
客户端小部件在查询字符串中携带令牌调用 Doconut 中间件。中间件的行为取决于请求的内容:
| Query | 目的 |
|---|---|
?token=…&page=N | 渲染的页面图像(PNG) |
?token=…&page=N&thumb=1 | 缩略图 |
?token=…&zoom=… | 放大页面渲染 |
?token=…&search=term | 全文搜索(受许可证限制) |
?token=…&bookmarks | 文档大纲/书签 |
?token=…© / &showlinks / &fileFormat | 文本复制、超链接和格式信息 |
?token=…&meta | DICOM 技术元数据;在 .NET 6 的 DICOM 会话中返回 501 |
?token=…&action=rotate/flip/close | 页面操作和显式关闭 |
?token=…&AnnSave=… / &AnnLoad | 保存/加载批注 |
每条路径在处理前都会先进行验证:
- 没有令牌 → 中间件返回 404(如果
ShowDoconutInfo = true则返回版本横幅)。 - 未知或已过期的令牌 → 返回错误图像,显示
Document session not found. Please re-open document. - 缺少会话中间件(当
UnsafeMode = false时) → 返回 HTTP 500,消息为Session middleware not configured. Call UseSession() before UseDoconut(). - 令牌由不同的浏览器会话打开 → 返回错误图像,显示
You Are Not Authorized To View This Page.
关闭文档
csharp
viewer.CloseDocument(token);CloseDocument 将会话从缓存中移除(这会立即释放底层文档引擎并释放其内存),删除 secure-{token} 标记,并撤销访问授权。调用它是可选的——滑动过期会自动进行相同的清理——但对于大型文档来说,这是在用户完成后立即释放内存的礼貌做法。
要点
- 一个打开的文档 = 一个会话 = 一个令牌。令牌是基于浏览器会话的,而非全局 URL。
- 令牌在滑动窗口内过期;如果查看器在
DocOptions.TimeOut之后闲置,则需要重新打开文档。 Viewer可以随意注入和共享;所有状态都由会话承担。
此页面有帮助吗?