转换插件
将文档转换为 24 种目标格式
Converter 插件将 Doconut 转变为文档转换服务。它提供了公共 DocumentConverter 门面的引擎,并且(可选)提供了一个带有自身 HTTP 合约的即插即用小部件,这样您可以从 C#、从小部件或从您自行编写的前端进行文档转换。
安装包
安装最新的稳定版 Converter 插件:
dotnet add package Doconut.NET8.Converter要将插件固定到当前的 26.7.0 版本,请单独传递版本号:
dotnet add package Doconut.NET8.Converter --version 26.7.0保持 Converter 包与 Doconut.NET8 使用相同的版本。包 ID 为 Doconut.NET8.Converter;.26.7.0 仅出现在下载的 .nupkg 文件名中。
注册插件
没有 AddConverter() 方法——Doconut 的插件模型是统一的。每个插件,包括 Converter,都是以相同方式注册的:在 AddDoconut() 中调用 AddPlugin<TPlugin>()。ConverterPlugin 以其自己的 NuGet 包 Doconut.NET8.Converter 形式提供,安装在基础查看器包旁边。
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});此调用在启动时会因缺少许可证、旧版
TRIAL文件或不授予Converter功能的非临时许可证而抛出异常——在AddDoconut()内部抛出的InvalidOperationException,在应用处理请求之前。接受临时的演示/NFR 注册;在其日历到期后,转换仍可使用,但输出会带有水印。没有静默的免费层。请参阅 许可证设置 了解许可证的加载方式。
从 C# 转换
每次转换都会返回一个定位在 0 的可寻址 MemoryStream,可立即读取或复制。从 DI 中解析 DocumentConverter,在任何需要的地方使用——它本质上是无状态的,因此单个实例可以安全地在请求之间复用。
// 注入 DocumentConverter;其构造函数是 internal 的,所以永远不要 `new` 它。
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);// sourceExtension 包含前导点。除非文档受保护,否则 password 为 null。
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);Stream html = await converter.WordToHtmlAsync("report.docx", ct);Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);两个容易出错的细节:流重载上的 sourceExtension 必须包含前导点(".xlsx",而不是 "xlsx")——转换器会将其与格式目录匹配,单独的扩展名无法解析。并且尽管名字如此,WordToHtmlAsync 返回的是 Task<Stream>,而不是 Task<string>——您会得到 HTML 文档(图像以 Base64 嵌入)作为流,这与其他所有转换结果相同。
目标格式
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, Webp并非所有源文件都能转换为所有目标——插件将每种源的格式族(Word、Excel、PowerPoint、PDF、CAD、Image、Email、Diagram、Project/Task、PSD、web 文档)映射到其固定的允许目标集合。不要将此枚举硬编码为 UI 的目标列表:?convert=open 返回刚上传的文件对应的实际 allowedTargets,这才应该用于驱动选择器。
嵌入式小部件
该小部件的 ?convert=open|run|download 端点默认是可选择的且已禁用——默认安全。请在服务器端启用它们,并配合插件注册:
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
options.AddConverterWidget(widget =>
{
widget.MaxUploadMb = 25;
});
});<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
Doconut.convert('#doconut-convert', { basePath: '/doconut', resPath: '/doconut-res', maxUploadMb: 25 });
</script>如果没有 AddConverterWidget(),这三个 ?convert= 端点会返回 404 ——但 JavaScript 文件本身仍会被提供(它是普通的嵌入式静态资源;只有它所调用的端点受到限制)。AddConverterWidget() 仍然需要注册 Converter 插件并拥有授予 Converter 的许可证——它本身并不授予转换权限。
自定义小部件
传递给 Doconut.convert(selector, options) 的初始化选项:
| 选项 | 类型 | 默认值 | 备注 |
|---|---|---|---|
basePath | string | /doconut | ?convert= 端点的基础路径;必须与实际挂载 UseDoconut() 的 ASP.NET 分支匹配(通常通过 MiddlewarePath 协调) |
resPath | string | /doconut-res | 为与其他 Doconut 小部件的配置保持一致而接受;转换器小部件目前不会从中构建任何 URL |
maxUploadMb | number | 25 | 仅客户端预检查——在上传前拒绝超大文件。服务器会独立强制其自身的上限,如果超出则返回 413 |
licenseUrl | string | null | null | 设置后,会将结果屏幕上的水印提示转换为指向此 URL 的链接 |
labels | object | {} | 覆盖小部件的英文默认字符串的任意子集(拖拽文字、按钮、aria‑live 通知、错误信息) |
回调:
| 回调 | 触发时机 | 负载 |
|---|---|---|
onReady() | 小部件已渲染其空闲/拖拽屏幕 | — |
onSourceLoaded({ token, pages, sourceExt, allowedTargets }) | ?convert=open 成功 | 源会话令牌、页数、源扩展名(无前导点)、允许的目标列表 |
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target }) | ?convert=run 成功 | 与运行响应相同的字段,加上请求的 target |
onDownload({ downloadName, downloadToken }) | 用户点击下载链接 | 与浏览器的原生下载同时触发——它不会拦截或替代下载 |
onError({ phase, message }) | 打开或运行请求失败 | phase 为 'open' 或 'run';message 为已清理的服务器错误(或上传大小预检查的客户端消息) |
Doconut.convert() 返回小部件实例本身——保存它以编程方式控制小部件:
const conv = Doconut.convert('#doconut-convert', { basePath: '/doconut' });
conv.reset(); // 返回空闲/掉落屏幕;不会重新触发 onReady
conv.loadFile(file); // 使用 File 对象启动流程;除非当前空闲,否则不执行任何操作
conv.destroy(); // 移除监听器,清空挂载点;此实例在之后不可使用构建自己的前端
该小部件只是此 HTTP 合约的客户端——直接基于它构建自己的前端以获得不同的用户体验。所有三个路由都位于挂载 UseDoconut() 的 ASP.NET 分支下(通常为 /doconut):
| 路由 | 目的 | 成功响应 |
|---|---|---|
POST ?convert=open (multipart, field file) | 上传并打开源文档以供预览 | 200 — { token, pages, sourceExt, allowedTargets } |
POST ?token=<token>&convert=run&target=<ext> | 将已存储的源转换为 target | 200 — { downloadToken, resultToken, resultPages, downloadName, watermarked } |
GET ?convert=download&token=<downloadToken> | 流式传输已转换的文件 | 200 — 文件字节, Content-Disposition: attachment, Cache-Control: no-store |
上传的源字节在服务器端存储,TTL 为 30 分钟;一旦该窗口到期,run 返回 404,文件必须重新打开。转换后的结果也存放在同一存储中——转换完成后,downloadToken 获得其自己的 30 分钟新窗口——而 resultToken 是普通的查看器会话令牌,其生命周期遵循查看器的会话缓存,独立于存储。
sourceExt 在 open 响应中没有前导点(例如 "docx")——这与 DocumentConverter.ConvertAsync 上的 sourceExtension 参数的约定相反,后者需要前导点。
失败模式,按路由分组:
| 路由 | 状态 | 何时 | 正文 |
|---|---|---|---|
| 任意 | 404 | 小部件未启用(AddConverterWidget() 从未被调用)——在任何三个路由分发之前检查 | 仅状态 |
| 任意 | 405 | HTTP 动词错误(open/run 需要 POST;download 需要 GET) | 仅状态 |
open | 413 | 上传的文件超过 MaxUploadMb | { "error": "File is too large." } |
open | 400 | 没有 multipart 正文、没有文件,或源扩展名无法转换 | { "error": "..." } |
run | 400 | 令牌格式错误(非 GUID),或 target 无法解析为 ConversionTarget | { "error": "Invalid token." } / { "error": "Unknown target format." } |
run | 400 | target 不在源的 allowedTargets 中 | { "error": "That target format is not available for this file." } |
run | 404 | 已存储的上传已过期(30 分钟 TTL)或令牌从未被打开 | { "error": "Upload expired — please re-open the file." } |
open, run | 500 | 内部处理失败 | { "error": "<sanitized message>" } — 已清理,方式与其他所有 Doconut 错误路径相同;永不泄露内部引擎名称 |
download | 400 | 令牌格式错误(非 GUID) | 仅状态 |
download | 404 | 未知或已过期的下载令牌 | 仅状态 |
资源所有权
转换器返回一个定位在零的可寻址 MemoryStream。调用方拥有该流,并应在复制或返回其内容后进行释放。DocumentConverter 服务本身是无状态的,并通过依赖注入解析;不要手动构造或释放该服务。
对于网页小部件,上传和下载缓存各自拥有独立的 30 分钟 TTL。相反,查看器 resultToken 遵循查看器会话的生命周期。关闭查看器结果不会删除仍然有效的下载缓存,重置浏览器小部件也不会延长任一 TTL。
故障排查
| 症状 | 检查 |
|---|---|
解析 DocumentConverter 失败 | ConverterPlugin 注册发生在 AddDoconut() 内部 |
| 应用程序在启动期间失败 | 加载的许可证授予 Converter |
| 流转换提示格式不受支持 | sourceExtension 包含前导点 |
| 小部件 JavaScript 加载但请求返回 404 | AddConverterWidget() 未被调用 |
| 小部件请求使用了错误的 URL | basePath 与映射了 UseDoconut() 的分支匹配 |
| 目标缺失 | 使用 convert=open 返回的 allowedTargets;并非所有来源都支持每个枚举目标 |
| 下载已过期 | 重复 convert=open/convert=run;缓存令牌本意是临时的 |
水印
注册了 ConverterPlugin 后,主机的许可证处于以下三种状态之一:
| 许可证状态 | 启动门槛 | 转换输出 |
|---|---|---|
付费查看器许可证授予 Converter,且在其有效期内 | 通过 | 干净 — watermarked: false |
| 活跃的评估(演示/NFR)许可证 | 通过 | 成功转换,并加上评估水印 — watermarked: true |
未授权的、遗留的 TRIAL 文件,或不授予 Converter 的非临时许可证 | 应用程序永不启动 — 上述启动门槛会抛出异常 | — |
| 已过期的临时/演示许可证 | 注册在过期后仍然有效 | 转换时带有评估水印 — watermarked: true |
两个调用路径都依据相同的规则计算该标志:DocumentConverter C# 门面内部从许可证的 IsViewerLicensed 和 IsTemporary 状态派生出它,且小部件的 ?convert=run 处理程序进行等价检查(IsViewerLicensed && !IsTrial && !IsTemporary)以填充它返回的 watermarked 字段。在购买前,可以在评估许可证上构建并端到端测试集成——仅输出字节会变化。
此页面对您有帮助吗?