Плагин Конвертера

Конвертировать документы в 24 целевых формата

Плагин Converter превращает Doconut в сервис конвертации документов. Он предоставляет движок, стоящий за публичным фасадом DocumentConverter, и — при желании — готовый к использованию виджет со своим HTTP‑контрактом, так что вы можете конвертировать документы из C#, из виджета или из собственного фронтенда.

Установить пакет

Установите последнюю стабильную версию плагина Converter:

bash
dotnet add package Doconut.NET8.Converter

Чтобы зафиксировать плагин на текущем выпуске 26.7.0, передайте версию отдельно:

bash
dotnet add package Doconut.NET8.Converter --version 26.7.0

Держите пакет Converter той же версии, что и Doconut.NET8. Идентификатор пакета — Doconut.NET8.Converter; .26.7.0 появляется только в имени скачанного файла .nupkg.

Зарегистрировать плагин

Метода AddConverter() не существует — модель плагинов Doconut единообразна. Каждый плагин, включая Converter, регистрируется одинаково: вызовите AddPlugin<TPlugin>() внутри AddDoconut(). ConverterPlugin поставляется в собственном пакете NuGet, Doconut.NET8.Converter, установленном рядом с базовым пакетом просмотрщика.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

Этот вызов бросает исключение при запуске из‑за отсутствующей лицензии, устаревшего файла TRIAL или непостоянной лицензии, не предоставляющей возможности Converter — InvalidOperationException, возникшее внутри AddDoconut(), до того как приложение начнёт обслуживать запросы. Принимаются временные регистрации Demo/NFR; после их календарного истечения конвертация остаётся доступной с водяным знаком на выводе. Тихого бесплатного уровня нет. См. Настройка лицензии для информации о загрузке лицензий.

Конвертировать из C#

Каждая конверсия возвращает перемещаемый MemoryStream, позиционированный на 0, готовый к чтению или копированию сразу. Получите DocumentConverter из DI там, где он нужен — он без состояния по дизайну, поэтому один экземпляр безопасно переиспользовать между запросами.

csharp
// Внедрите DocumentConverter; его конструктор internal, поэтому никогда не `new` его.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension включает ведущую точку. password равен null, если только документ не защищён.
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);
csharp
Stream html = await converter.WordToHtmlAsync("report.docx", ct);
csharp
Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);

Две детали, которые легко перепутать: sourceExtension в перегрузке потока должен включать ведущую точку (".xlsx", а не "xlsx") — конвертер сопоставляет её с каталогом форматов, и простое расширение не будет найдено. И несмотря на название, WordToHtmlAsync возвращает Task<Stream>, а не Task<string> — вы получаете HTML‑документ (изображения встроены как Base64) в виде потока, как и любой другой результат конверсии.

Целевые форматы

text
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) со своим фиксированным набором разрешённых целей. Не жёстко кодируйте этот enum в списке целей вашего UI: ?convert=open возвращает фактический allowedTargets для любого только что загруженного файла, и именно это должно управлять выбором.

Встраиваемый виджет

The widget's ?convert=open|run|download endpoints are opt-in and disabled out of the box — secure by default. Enable them server-side, alongside the plugin registration:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
html
<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>

Without AddConverterWidget(), the three ?convert= endpoints answer 404 — but the JS file itself is still served regardless (it's a plain embedded static resource; only the endpoints it talks to are gated). AddConverterWidget() still requires the Converter plugin to be registered and a license that grants Converter — it doesn't grant conversion rights on its own.

Настройка виджета

Init options passed to Doconut.convert(selector, options):

ОпцияТипПо умолчаниюПримечания
basePathstring/doconutБазовый путь для конечных точек ?convert=; он должен соответствовать ветке ASP.NET, где фактически монтируется UseDoconut() (обычно координируется через MiddlewarePath)
resPathstring/doconut-resПринято для согласованности конфигурации с другими виджетами Doconut; виджет конвертера в настоящее время не формирует из него URL
maxUploadMbnumber25Только клиентская предварительная проверка — отклоняет файл, превышающий размер, до загрузки. Сервер независимо применяет собственный лимит и отвечает 413, если он превышен
licenseUrlstring | nullnullЕсли установлен, превращает уведомление о водяном знаке на экране результата в ссылку на этот URL
labelsobject{}Переопределяет любой набор английских строк по умолчанию виджета (текст подсказки, кнопки, объявления aria-live, сообщения об ошибках)

Обратные вызовы:

Обратный вызовСрабатывает когдаДанные
onReady()Виджет отобразил свой экран простоя/загрузки—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open завершилось успешнотокен сеанса источника, количество страниц, расширение источника (без точки), список разрешённых целей
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run завершилось успешноте же поля, что и в ответе run, плюс запрошенный target
onDownload({ downloadName, downloadToken })Пользователь нажимает ссылку Downloadсрабатывает вместе с нативным скачиванием браузера — не перехватывает и не заменяет его
onError({ phase, message })Запрос open или run завершается ошибкойphase равно 'open' или 'run'; message — это очищенная ошибка сервера (или сообщение клиентской проверки размера загрузки)

Doconut.convert() возвращает сам экземпляр виджета — держите его, чтобы управлять виджетом программно:

javascript
const conv = Doconut.convert('#doconut-convert', { basePath: '/doconut' });
conv.reset();         // возврат к экрану простоя/отбрасывания; не вызывает повторно onReady
conv.loadFile(file);  // запускает поток с объектом File; без действия, если сейчас не в простое
conv.destroy();       // удаляет слушатели, очищает mount; после этого экземпляр непригоден к использованию

Создайте собственный фронтенд

The widget is just a client for this HTTP contract — build your own frontend against it directly for a different UX. All three routes sit under the ASP.NET branch where UseDoconut() is mounted (normally /doconut):

МаршрутНазначениеОтвет при успехе
POST ?convert=open (multipart, field file)Загрузка и открытие исходного документа для предварительного просмотра200 — { token, pages, sourceExt, allowedTargets }
POST ?token=<token>&convert=run&target=<ext>Конвертировать сохранённый источник в target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET ?convert=download&token=<downloadToken>Потоковая передача конвертированного файла200 — байты файла, Content-Disposition: attachment, Cache-Control: no-store

Uploaded source bytes are stashed server-side with a 30-minute TTL; once that window lapses, run answers 404 and the file must be re-opened. The converted result lives in the same stash — downloadToken gets its own fresh 30-minute window when the conversion completes — while resultToken is an ordinary viewer session token whose lifetime follows the viewer's session cache, independent of the stash.

sourceExt в ответе open не имеет ведущей точки (например, "docx") — противоположная конвенция параметру sourceExtension в DocumentConverter.ConvertAsync, который требует её.

Сценарии отказов, сгруппированные по маршруту:

МаршрутСтатусКогдаТело
any404Виджет не включён (AddConverterWidget() никогда не вызывался) — проверяется до обработки любого из трёх маршрутовтолько статус
any405Неправильный HTTP‑метод (open/run требуют POST; download требует GET)только статус
open413Загруженный файл превышает MaxUploadMb{ "error": "File is too large." }
open400Отсутствует multipart‑тело, файл или расширение источника, которое нельзя конвертировать{ "error": "..." }
run400Некорректный токен (не GUID) или target, который не преобразуется в ConversionTarget{ "error": "Invalid token." } / { "error": "Unknown target format." }
run400target отсутствует в allowedTargets источника{ "error": "That target format is not available for this file." }
run404Сохранённая загрузка истекла (TTL 30 минут) или токен никогда не открывался{ "error": "Upload expired — please re-open the file." }
open, run500Внутренняя ошибка обработки{ "error": "<sanitized message>" } — очищена так же, как и любой другой путь ошибки Doconut; внутренние названия движка не раскрываются
download400Некорректный токен (не GUID)только статус
download404Неизвестный или истёкший токен загрузкитолько статус

Владение ресурсом

Конвертер возвращает позиционируемый в ноль MemoryStream. Вызывающая сторона владеет этим потоком и должна освободить его после копирования или возврата его содержимого. Сервис DocumentConverter сам по себе без состояния и получается через внедрение зависимостей; не создавайте и не освобождайте сервис вручную.

Для веб‑виджета загрузочные и скачиваемые хранилища имеют независимые TTL в 30 минут. resultToken просмотрщика следует времени жизни сессии просмотрщика. Закрытие результата просмотрщика не удаляет ещё действительное хранилище загрузки, и сброс виджета браузера не продлевает ни один из TTL.

Устранение неполадок

СимптомПроверка
Не удалось разрешить DocumentConverterРегистрация ConverterPlugin произошла внутри AddDoconut()
Приложение падает при запускеЗагруженная лицензия предоставляет Converter
Конвертация потока сообщает, что формат не поддерживаетсяsourceExtension содержит ведущую точку
JavaScript виджета загружается, но запросы возвращают 404AddConverterWidget() не был вызван
Запросы виджета используют неверный URLbasePath соответствует ветке, где сопоставлен UseDoconut()
Целевой объект отсутствуетИспользуйте allowedTargets, возвращённый convert=open; не каждый источник поддерживает каждый целевой enum
Скачивание истеклоПовторите 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, которое он возвращает. Интеграцию можно построить и протестировать сквозным образом на оценочной лицензии до покупки — меняются только байты вывода.

Была ли эта страница полезной?