转换插件
将文档转换为 24 种目标格式
Converter 插件将 Doconut 转变为文档转换服务。它提供公共 DocumentConverter 外观背后的引擎,并且(可选)提供带有自身 HTTP 合约的即插即用小部件,这样您可以从 C#、从小部件,或从自己编写的前端进行文档转换。
安装包
安装最新的稳定版 Converter 插件:
dotnet add package Doconut.NET6.Converter要将插件固定在当前 26.7.0 版本,请单独传递版本号:
dotnet add package Doconut.NET6.Converter --version 26.7.0保持 Converter 包的版本与 Doconut.NET6 相同。包 ID 为
Doconut.NET6.Converter;.26.7.0 仅出现在下载的 .nupkg 文件名中。
注册插件
没有 AddConverter() 方法 —— Doconut 的插件模型是统一的。每个插件(包括 Converter)都以相同方式注册:在 AddDoconut() 中调用 AddPlugin<TPlugin>()。ConverterPlugin 随其自己的 NuGet 包 Doconut.NET6.Converter 提供,随基础查看器包一起安装。
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});此调用在启动时会因缺少许可证、遗留的
TRIAL文件,或未授予Converter能力的非临时许可证而抛出InvalidOperationException,该异常在AddDoconut()内部触发,发生在应用提供请求之前。接受临时演示/非正式评估(Demo/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 document)映射到其固定的允许目标集合。不要在 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 —— 但 JS 文件本身仍会被提供(它是一个普通的嵌入式静态资源;只有它所调用的端点被限制)。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 |
上传的源字节会在服务器端缓存 30 分钟 TTL;该窗口过期后,run 会返回 404,必须重新打开文件。转换结果也存放在同一缓存中 —— 当转换完成时,downloadToken 会获得自己的 30 分钟新窗口,而 resultToken 是普通的查看器会话令牌,其生命周期遵循查看器的会话缓存,独立于缓存。
open 响应中的 sourceExt 没有前导点(例如 "docx")——这与 DocumentConverter.ConvertAsync 参数 sourceExtension 的约定相反,后者需要前导点。
失败模式(按路由分组)
| 路由 | 状态 | 何时 | 响应体 |
|---|---|---|---|
| any | 404 | 小部件未启用(从未调用 AddConverterWidget())——在任何路由分发前即检查 | 仅状态码 |
| any | 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 服务本身是无状态的,通过依赖注入解析;不要手动构造或释放该服务。
对于 Web 小部件,上传和下载缓存各自拥有独立的 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 字段。可以在评估许可证下完整构建并端到端测试集成——唯一变化的是输出字节。
此页面有帮助吗?