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

Преобразование документов в 45 целевых форматов

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

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

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

bash
dotnet add package Doconut.NETStandard.Converter

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

bash
dotnet add package Doconut.NETStandard.Converter --version 26.8.0

Поддерживайте пакет Converter той же версии, что и Doconut.NETStandard. Идентификатор пакета — Doconut.NETStandard.Converter; .26.8.0 встречается только в имени загруженного файла .nupkg.

Регистрация плагина

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

viewer.Converter.GetConverter() здесь не существует. Конвертация больше не достигается через экземпляр просмотрщика: вместо этого внедрите Doconut.DocumentConverter.

csharp
// Внедрите DocumentConverter; его конструктор internal, поэтому никогда не `new` его.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension включает ведущую точку. password равен null, если только документ не защищён.
Stream png = await converter.ConvertAsync(stream, ".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) в виде потока, как и любой другой результат конвертации.

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

ConversionTarget (пространство имён Doconut.Configs.Conversion) содержит 45 членов:

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, Msg, Eml, Emlx, Mhtml,
Xlsm, Xlsb, Ppt, Docm, Dot, Dotx, Dotm, Vsdx, Vssx, Vstx, Vsdm, Vssm, Vstm,
Vdx, Vsx, Vtx, Ico

Этот один enum охватывает все семейства источников. В предыдущей библиотеке был тип *ConfigConverter для каждого семейства — WordConfigConverter, ExcelConfigConverter и т.д. — каждый со своим вложенным enum EnTargetFormat, плюс enum SourceFormatConverter для входных данных. Всё это исчезло; см. руководство по миграции.

Не каждый источник конвертируется во каждый целевой формат — плагин сопоставляет каждое семейство форматов источника (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project/Task, PSD, веб‑документ) со своим фиксированным набором разрешённых целей. Не жёстко кодируйте этот enum в списке целей вашего UI: ?convert=open возвращает фактический allowedTargets для любого только что загруженного файла, и именно это должно управлять выбором.

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

Конечные точки ?convert=open|run|download виджета являются опциональными и по умолчанию отключены — безопасно по умолчанию. Включите их на стороне сервера вместе с регистрацией плагина:

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>

Без AddConverterWidget() три конечные точки ?convert= отвечают 404 — но сам файл JS всё равно отдается (это простой встроенный статический ресурс; только конечные точки, к которым он обращается, защищены). AddConverterWidget() всё ещё требует регистрации плагина Converter и лицензии, предоставляющей Converter — она не предоставляет права на конвертацию сама по себе.

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

Параметры инициализации, передаваемые в 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те же поля, что и в ответе выполнения, плюс запрошенный target
onDownload({ downloadName, downloadToken })Пользователь нажимает ссылку Скачатьсрабатывает вместе с нативной загрузкой браузера — не перехватывает и не заменяет её
onError({ phase, message })Запрос open или run завершился ошибкойphase является 'open' или 'run'; message — это очищенная ошибка сервера (или сообщение клиентской стороны для предварительной проверки размера загрузки)

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

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

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

Виджет — это лишь клиент для этого HTTP‑контракта — создайте собственный интерфейс напрямую для другого пользовательского опыта. Все три маршрута находятся под веткой ASP.NET, где монтируется UseDoconut() (обычно /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 — file bytes, Content-Disposition: attachment, Cache-Control: no-store

Загруженные байты источника сохраняются на сервере со сроком жизни 30 минут; после истечения этого окна run отвечает 404, и файл необходимо открыть заново. Сконвертированный результат хранится в том же хранилище — downloadToken получает собственное новое 30‑минутное окно после завершения конвертации — тогда как resultToken является обычным токеном сессии просмотрщика, срок действия которого следует кэшу сессии просмотрщика, независимо от хранилища.

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

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

МаршрутСтатусКогдаТело
любой404Виджет не включён (AddConverterWidget() никогда не вызывался) — проверяется до обработки любого из трёх маршрутовтолько статус
любой405Неправильный 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

Оба пути вызова вычисляют флаг по одному и тому же правилу: фасад C# DocumentConverter получает его внутренне из состояний IsViewerLicensed и IsTemporary лицензии, а обработчик ?convert=run виджета выполняет эквивалентную проверку (IsViewerLicensed && !IsTrial && !IsTemporary), чтобы заполнить поле watermarked, которое он возвращает. Интеграцию можно построить и протестировать от начала до конца на оценочной лицензии до покупки — меняются только байты вывода.

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