转换器插件
将文档转换为 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 相同。包标识为
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能力的非临时许可证而抛出InvalidOperationException,该异常在AddDoconut()内部触发,发生在应用开始提供请求之前。接受临时演示/非正式评估(Demo/NFR)注册;其日历到期后,转换仍可使用,只是输出会带有水印。没有静默的免费层。请参阅许可证设置了解许可证的加载方式。
从 C# 转换
每次转换都会返回一个定位在 0 的可搜索 MemoryStream,可立即读取或复制。随时从 DI 中解析 DocumentConverter——它本身是无状态的,因此单实例可安全复用于多个请求。
// Inject DocumentConverter; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);// sourceExtension includes the leading dot. password is null unless the document is protected.
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——但 JS 文件本身仍会被提供(它是普通的嵌入式静态资源,只有它所调用的端点受限)。AddConverterWidget() 仍然要求先注册 Converter 插件并拥有授予 Converter 的许可证——它本身并不授予转换权限。
自定义小部件
传递给 Doconut.convert(selector, options) 的初始化选项:
| Option | Type | Default | Notes |
|---|---|---|---|
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 提示、错误信息) |
回调:
| Callback | Fires when | Payload |
|---|---|---|
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):
| Route | Purpose | Success response |
|---|---|---|
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 参数相反,后者需要前导点。
失败模式(按路由分组)
| Route | Status | When | Body |
|---|---|---|---|
| any | 404 | 小部件未启用(未调用 AddConverterWidget())——在任何路由分发前先检查 | 仅状态码 |
| any | 405 | 使用了错误的 HTTP 方法(open/run 需 POST,download 需 GET) | 仅状态码 |
open | 413 | 上传文件超过 MaxUploadMb | { "error": "File is too large." } |
open | 400 | 没有 multipart body、没有文件,或源扩展名无法转换 | { "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。
故障排查
| Symptom | Check |
|---|---|
Resolving DocumentConverter fails | ConverterPlugin registration happened inside AddDoconut() |
| Application fails during startup | The loaded license grants Converter |
| Stream conversion says the format is unsupported | sourceExtension includes the leading dot |
| Widget JavaScript loads but requests return 404 | AddConverterWidget() was not called |
| Widget requests use the wrong URL | basePath matches the branch where UseDoconut() is mapped |
| Target is missing | Use allowedTargets returned by convert=open; not every source supports every enum target |
| Download expired | Repeat convert=open/convert=run; stash tokens are intentionally temporary |
水印
在注册 ConverterPlugin 后,宿主的许可证会处于以下三种状态之一:
| License state | Startup gate | Conversion output |
|---|---|---|
Paid viewer license granting Converter, within its validity period | Passes | Clean — watermarked: false |
| Active evaluation (demo/NFR) license | Passes | Converts successfully, stamped with the evaluation watermark — watermarked: true |
Unlicensed, a legacy TRIAL file, or a non-temporary license that doesn't grant Converter | App never starts — the startup gate described above throws | — |
| Expired Temporary/Demo license | Registration survives expiry | Converts with the evaluation watermark — watermarked: true |
两条调用路径都使用相同的规则计算该标记:DocumentConverter 的 C# 外观内部依据许可证的 IsViewerLicensed 与 IsTemporary 状态得出,而小部件的 ?convert=run 处理程序则进行等价检查(IsViewerLicensed && !IsTrial && !IsTemporary)以填充返回的 watermarked 字段。可以在评估许可证下完整构建并测试集成——唯一变化的只是输出字节。
此页面有帮助吗?