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

教程:在 .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使用 ReferenceCssReferenceScripts 输出嵌入资源
通用的 JavaScript init() API初始化 $('#div_ctlDoc').docViewer(...)
持久化查看器令牌持久化文档 ID;将令牌视为临时的

在将示例适配到生产代码之前,请使用官方的 Doconut 文档 并根据已安装的包版本进行验证。

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