
教程:在 .NET 8 中使用注入的 Doconut 查看器打开文档
介绍
较旧的 Doconut 示例可能直接使用缓存、HTTP 上下文和 license-path 参数构造 Viewer。这不是当前的 .NET 8 集成模型。AddDoconut() 使用依赖注入注册 Viewer,应用程序端点接收该服务,而不是调用构造函数。

本教程遵循当前的请求流程:注册服务和中间件,输出嵌入的查看器资源,使用 OpenDocumentAsync 打开文档,返回不透明的会话令牌,并将该令牌传递给浏览器小部件。
1. 安装并注册 Doconut
添加 .NET 8 包:
dotnet add package Doconut.NET8
注册 Doconut 和 ASP.NET 会话服务:
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false;
});
builder.Services.AddSession();
按要求的顺序连接中间件。资源中间件必须在终端文档中间件之前运行:
app.UseRouting();
app.UseSession();
app.UseDoconutResources();
app.Map("/doconut", branch => branch.UseDoconut());
MiddlewarePath 协调配置,但本身不会创建 ASP.NET 分支。映射的 /doconut 路径必须与小部件的 BasePath 相匹配。
2. 添加查看器表面和资源
Doconut 浏览器查看器是一个 jQuery 插件。在 Razor 页面中,注入 Viewer 并让它按依赖顺序输出资源标签:
@inject Doconut.Viewer Viewer
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeViewerCss = true
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeViewerScripts = true
}))
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>
使用与服务器注册匹配的路径初始化小部件:
const objViewer = $('#div_ctlDoc').docViewer({
showThumbs: true,
autoLoad: false,
pageZoom: 100,
FitType: 'width',
BasePath: '/doconut',
ResPath: '/doconut-res/images',
onError: function (message) {
console.error('Doconut viewer error:', message);
}
});
选项的大小写很重要。请使用已安装版本显示的名称,而不是将它们统一为单一风格。
3. 注入 Viewer 并打开文档
Viewer 被注册为瞬态服务。通过端点注入、构造函数注入或 ASP.NET Core 应用程序中的等效机制来解析它。
app.MapPost("/api/open", async (
Viewer viewer,
CancellationToken ct) =>
{
string token = await viewer.OpenDocumentAsync(
"wwwroot/files/Sample.pdf",
ct: ct);
return Results.Ok(new { token });
});
对于上传,提供一个流和一个 FileInfo,其扩展名标识源格式:
app.MapPost("/api/open-upload", async (
IFormFile file,
Viewer viewer,
CancellationToken ct) =>
{
await using var stream = file.OpenReadStream();
string token = await viewer.OpenDocumentAsync(
stream,
new FileInfo(file.FileName),
ct: ct);
return Results.Ok(new { token });
});
在打开用户提供的内容之前,验证上传的大小、扩展名和授权。不要将提交的文件名转换为服务器路径。
4. 将令牌传递给小部件
获取打开端点并将返回的令牌交给 objViewer.View:
fetch('/api/open', { method: 'POST' })
.then(response => {
if (!response.ok) throw new Error('The document could not be opened.');
return response.json();
})
.then(data => objViewer.View(data.token))
.catch(error => console.error(error));
将令牌视为实时文档会话的持有者凭证:
- 不要记录或持久化它。
- 仅向授权客户端返回它。
- 不要暴露源文件路径。
- 会话过期时重新打开文档。
- 文档不再需要时关闭会话。
5. 有意关闭服务器端会话
当用户离开查看器时,客户端代码可以调用 objViewer.Close()。服务器工作流也可以显式撤销已知令牌:
app.MapPost("/api/close", (string token, Viewer viewer) =>
{
viewer.CloseDocument(token);
return Results.NoContent();
});
显式关闭对大型文档尤为有用。会话过期仍然是备选方案,而不是可预测的应用程序生命周期管理的替代方案。
6. 在核心工作完成后再添加可选模块
搜索和注释附加到同一个已初始化的查看器。仅在基础流程成功后才添加它们的 CSS、脚本、挂载、许可证检查和生命周期回调:
AddDoconut + session services
-> UseSession
-> UseDoconutResources
-> mapped UseDoconut branch
-> viewer resources and mount
-> initialize docViewer
-> OpenDocumentAsync
-> objViewer.View(token)
此顺序将核心渲染错误与可选模块配置分离。
常见迁移错误
| 旧的或不正确的模式 | 当前 .NET 8 方向 |
|---|---|
new Viewer(cache, accessor, licensePath) | 在 AddDoconut() 之后注入 Viewer |
| 请求代码中的静态许可证加载调用 | 在 AddDoconut() 中配置许可证输入 |
同步 OpenDocument(...) 示例 | 使用 OpenDocumentAsync(...) |
| 外部或自创的查看器 CDN | 使用 ReferenceCss 和 ReferenceScripts 输出嵌入资源 |
通用的 JavaScript init() API | 初始化 $('#div_ctlDoc').docViewer(...) |
| 持久化查看器令牌 | 持久化文档 ID;将令牌视为临时的 |
在将示例适配到生产代码之前,请使用官方的 Doconut 文档 并根据已安装的包版本进行验证。