教程:在 .NET 8 中使用注入的 Doconut 查看器打开文档
← Back to Blog••2 min read

教程:在 .NET 8 中使用注入的 Doconut 查看器打开文档

介绍

较早的 Doconut 示例可能直接使用缓存、HTTP 上下文和许可证路径参数构造 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 文档 并在将示例适配到生产代码之前,验证它们与已安装的包版本匹配。

#Doconut#.NET 8#文档查看器#ASP.NET Core#JavaScript