Плагин Конвертера
Конвертировать документы в 24 целевых формата
Плагин Converter превращает Doconut в сервис конвертации документов. Он предоставляет движок, стоящий за публичным фасадом DocumentConverter, и — при желании — готовый к использованию виджет, обслуживаемый DocImage.axd, так что вы можете конвертировать документы из C#, из виджета или из собственного фронтенда.
Установить пакет
Install-Package Doconut.NETFramework.ConverterДержите пакет Converter той же версии, что и Doconut.NETFramework.
Зарегистрировать плагин
Каждый плагин регистрируется одинаково: AddPlugin<TPlugin>() в DoconutHost.Initialize.
Doconut.DoconutHost.Initialize(options =>
{
options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});Если активная лицензия не предоставляет возможность
Converter— отсутствие лицензии, устаревший файлTRIALили лицензия без этой возможности —DoconutHost.Initializeгенерирует исключение изApplication_Start. В System.Web это означает, что каждый запрос возвращает пустой500, а причина отображается только в журнале событий Windows (источник ASP.NET). Принимаются временные лицензии Demo/NFR. См. Настройка лицензии.
Конвертировать из C#
Каждая конверсия возвращает перемещаемый MemoryStream, позиционированный на 0. DocumentConverter без состояния: получайте его из DoconutHost.Services где бы вам это ни потребовалось и свободно переиспользуйте.
// Получите DocumentConverter из DoconutHost.Services; его конструктор 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) приходит в виде потока, как и любой другой результат.
В контроллере MVC 5
Сделайте действие асинхронным и await конверсию:
[HttpPost]
public async Task<ActionResult> ToPdf(HttpPostedFileBase file)
{
var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
Stream pdf = await converter.ConvertAsync(
file.InputStream, Path.GetExtension(file.FileName), ConversionTarget.Pdf,
password: null, ct: Response.ClientDisconnectedToken);
return File(pdf, "application/pdf", Path.GetFileNameWithoutExtension(file.FileName) + ".pdf");
}В Web Forms: никогда не блокировать конвертацию
Страница Web Forms работает в однопоточном контексте запроса. ConvertAsync возобновляется в этом контексте после завершения, поэтому страница, ожидающая его синхронно — .Result, .Wait(), .GetAwaiter().GetResult() — удерживает тот же поток, необходимый для завершения конверсии. Запрос никогда не возвращается. Браузер крутится, IIS ничего не записывает, а остальная часть сайта продолжает работать, поэтому выглядит как медленная конверсия, а не взаимная блокировка.
Отметьте страницу Async="true" и запустите конверсию как асинхронную задачу страницы:
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>// Web Forms: директива @Page должна иметь Async="true", а конверсия выполняется как асинхронная задача страницы.
// Блокировка на нём вместо этого (.Result, .Wait(), .GetAwaiter().GetResult()) приводит к взаимной блокировке запроса:
// он никогда не возвращается, и ничего не логируется.
protected void Page_Load(object sender, EventArgs e)
{
if (!IsPostBack) return;
RegisterAsyncTask(new PageAsyncTask(async ct =>
{
var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
using (var pdf = await converter.ConvertAsync(
Server.MapPath("~/App_Data/contract.docx"), ConversionTarget.Pdf, ct: ct))
using (var ms = new MemoryStream())
{
if (pdf.CanSeek) pdf.Position = 0;
await pdf.CopyToAsync(ms);
Response.ContentType = "application/pdf";
Response.AddHeader("Content-Disposition", "attachment; filename=contract.pdf");
Response.BinaryWrite(ms.ToArray());
// Context, а не HttpContext.Current: после await последнее может быть null.
Context.ApplicationInstance.CompleteRequest();
}
}));
}Без Async="true" в директиве @Page, RegisterAsyncTask будет тихо проигнорирован. После await используйте Context страницы; HttpContext.Current может быть null там.
Целевые форматы
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, PSD, web document) есть собственный набор разрешённых целей. Не захардкодьте этот enum как список целей в вашем UI: ?convert=open возвращает allowedTargets для загруженного файла, и именно это должно управлять выбором.
Встроенный виджет
?convert=open|run|download конечные точки виджета обслуживаются DocImage.axd и по умолчанию отключены. Включите их рядом с регистрацией плагина:
Doconut.DoconutHost.Initialize(options =>
{
options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
options.AddConverterWidget(widget =>
{
widget.MaxUploadMb = 25;
});
});
// System.Web читает всю загрузку до того, как Doconut её увидит: сохраняйте maxRequestLength (KB) и
// maxAllowedContentLength (bytes) в Web.config выше MaxUploadMb виджета.<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
Doconut.convert('#doconut-convert', { basePath: '/DocImage.axd', maxUploadMb: 25 });
</script>Две вещи, которые нужно проверить, когда виджет работает некорректно:
basePath: '/DocImage.axd'. По умолчанию у виджета,/doconut, является конечная точка ASP.NET Core. В этом пакете конечные точки — обработчикDocImage.axdизWeb.config.- Скрипт и конечные точки независимы. Модуль ресурсов обслуживает
doconutConverter.jsнезависимо от того, включён ли виджет. БезAddConverterWidget()виджет загружается, рисует свою зону перетаскивания и выглядит полностью корректно — и его первое действие отвечает404.
Ограничения загрузки
ASP.NET читает всё тело запроса до того, как запустится DocImage.axd. Загрузка, превышающая MaxUploadMb, но ниже ограничений хоста, получает собственный JSON 413 виджета ("File is too large."). Загрузка, превышающая ограничения хоста, сначала отклоняется IIS с ошибочной страницей, которую виджет не может прочитать. Держите оба ограничения хоста в Web.config выше предела виджета:
<system.web>
<httpRuntime maxRequestLength="30720" /> <!-- КИЛОБАЙТЫ: 30 MB -->
</system.web>
<system.webServer>
<security>
<requestFiltering>
<requestLimits maxAllowedContentLength="31457280" /> <!-- БАЙТЫ: 30 MB -->
</requestFiltering>
</security>
</system.webServer>Настройка виджета
Параметры, передаваемые в Doconut.convert(selector, options):
| Параметр | Тип | По умолчанию | Примечания |
|---|---|---|---|
basePath | string | /doconut | URL конечной точки. Установите '/DocImage.axd' в этом пакете |
resPath | string | /doconut-res | Принимается для согласованности с другими виджетами Doconut; виджет конвертера не формирует URL из него |
maxUploadMb | number | 25 | Только клиентская предварительная проверка; сервер применяет собственный предел |
licenseUrl | string | null | null | Превращает уведомление о водяном знаке на экране результата в ссылку |
labels | object | {} | Переопределяет любой набор английских строк виджета |
Обратные вызовы:
| Обратный вызов | Срабатывает при | Полезные данные |
|---|---|---|
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() возвращает экземпляр виджета: reset() возвращает к экрану перетаскивания, loadFile(file) запускает процесс с File, а destroy() удаляет его.
Создайте собственный фронтенд
Виджет является клиентом этого HTTP‑контракта на DocImage.axd:
| Маршрут | Назначение | Ответ при успехе |
|---|---|---|
POST /DocImage.axd?convert=open (multipart, поле file) | Загрузить и открыть исходный документ | 200 — { token, pages, sourceExt, allowedTargets } |
POST /DocImage.axd?token=<token>&convert=run&target=<ext> | Преобразовать загруженный источник в target | 200 — { downloadToken, resultToken, resultPages, downloadName, watermarked } |
GET /DocImage.axd?convert=download&token=<downloadToken> | Передать потоком преобразованный файл | 200 — файл, Content-Disposition: attachment |
Загруженные источники хранятся в течение 30 минут; после этого run отвечает 404, и файл необходимо открыть заново. downloadToken получает собственное 30‑минутное окно после завершения преобразования. resultToken — обычный токен просмотрщика, который действует в течение срока жизни сессии просмотрщика.
sourceExt в ответе open не имеет ведущей точки ("docx") — противоположно параметру sourceExtension функции ConvertAsync.
| Маршрут | Статус | Когда | Тело |
|---|---|---|---|
| любой | 404 | Виджет не включён (AddConverterWidget() никогда не вызывался) | только статус |
| любой | 405 | Неправильный глагол (open/run требуют POST, download требует GET) | только статус |
open | 413 | Загрузка превышает MaxUploadMb (но не ограничения IIS) | { "error": "File is too large." } |
open | 400 | Отсутствует multipart‑тело, файл или тип, который нельзя преобразовать | { "error": "..." } |
open | 403 | Тип файла требует возможности, которую лицензия не предоставляет | { "error": "..." } |
run | 400 | Некорректный токен, неизвестный target или цель, не входящая в allowedTargets | { "error": "..." } |
run | 404 | Срок действия загрузки истёк или она никогда не открывалась | { "error": "Upload expired — please re-open the file." } |
open, run | 500 | Обработка не удалась | { "error": "<sanitized message>" } |
download | 400 / 404 | Некорректный, неизвестный или просроченный токен загрузки | только статус |
Владение ресурсом
Вызывающая сторона владеет MemoryStream, который возвращает преобразование, и должна освободить его после копирования или возврата (MVC‑овский File(stream, …) освобождает его за вас). Не создавайте и не освобождайте DocumentConverter самостоятельно — его конструктор является внутренним.
Добавление водяного знака
| Состояние лицензии | Запуск | Вывод преобразования |
|---|---|---|
Платная лицензия просмотрщика, предоставляющая Converter | Запускается | Чистый — watermarked: false |
| Активная временная/демо‑лицензия | Запускается | Преобразует, с водяным знаком оценки — watermarked: true |
Отсутствует лицензия, устаревший файл TRIAL или лицензия без Converter | Application_Start бросает исключение; каждый запрос отвечает пустым 500 | — |
| Просроченная временная/демо‑лицензия | Запускается | Преобразует, с водяным знаком оценки — watermarked: true |
Интеграцию можно собрать и протестировать от начала до конца на оценочной лицензии перед покупкой — меняются только байты вывода.
Устранение неполадок
| Симптом | Проверка |
|---|---|
Каждый запрос отвечает пустым 500 после добавления плагина | Лицензия предоставляет Converter — журнал событий Windows, источник ASP.NET |
Разрешение DocumentConverter вызывает исключение | AddPlugin<ConverterPlugin>() находится в DoconutHost.Initialize |
| Преобразование Web Forms никогда не возвращает результат | Страница блокируется на ConvertAsync — используйте Async="true" и RegisterAsyncTask |
| Потоковое преобразование сообщает, что формат не поддерживается | sourceExtension содержит ведущую точку |
Виджет загружается, но его запросы возвращают 404 | AddConverterWidget() не был вызван, или basePath не является '/DocImage.axd' |
| Большая загрузка показывает страницу ошибки IIS вместо сообщения виджета | maxRequestLength / maxAllowedContentLength ниже MaxUploadMb |
| Отсутствует цель | Используйте allowedTargets из convert=open |
| Срок загрузки истёк | Повторите convert=open / convert=run; токены намеренно временные |
Была ли эта страница полезной?