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

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

Плагін Converter перетворює Doconut у сервіс конвертації документів. Він надає движок, що стоїть за публічним фасадом DocumentConverter і — за бажанням — готовий віджет, що обслуговується DocImage.axd, тому ви можете конвертувати документи з C#, з віджета або з фронтенду, який створите самостійно.

Встановити пакет

powershell
Install-Package Doconut.NETFramework.Converter

Тримайте пакет Converter тієї ж версії, що і Doconut.NETFramework.

Зареєструвати плагін

Кожен плагін реєструється однаково: AddPlugin<TPlugin>() у DoconutHost.Initialize.

csharp
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 там, де потрібен, і вільно повторно використовуйте.

csharp
// Отримайте DocumentConverter з DoconutHost.Services; його конструктор є 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) надходить у вигляді потоку, як і будь‑який інший результат.

У контролері MVC 5

Зробіть дію асинхронною і await конвертацію:

csharp
[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" і запустіть конвертацію як асинхронне завдання сторінки:

aspx
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>
csharp
// Web Forms: директива @Page потребує Async="true", а конвертація виконується як асинхронне завдання сторінки.
// Блокування його таким чином (.Result, .Wait(), .GetAwaiter().GetResult()) призводить до deadlock‑у запиту:
// він ніколи не повертається, і нічого не записується.
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 там.

Формати призначення

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, PSD, веб‑документ) має власний набір дозволених цілей. Не жорстко кодуйте цей перелік у вашому UI: ?convert=open повертає allowedTargets для завантаженого файлу, і саме це має керувати вибором.

Вбудований віджет

Кінцеві точки ?convert=open|run|download віджету обслуговуються DocImage.axd і вимкнені за замовчуванням. Увімкніть їх поруч із реєстрацією плагіна:

csharp
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 віджета.
html
<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 («Файл занадто великий.»). Завантаження, що перевищує обмеження хоста, спочатку відхиляється IIS з помилковою сторінкою, яку віджет не може прочитати. Тримайте обидва обмеження хоста у Web.config вище межі віджету:

xml
<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):

ОпціяТипЗа замовчуваннямПримітки
basePathstring/doconutURL кінцевої точки. Встановіть '/DocImage.axd' у цьому пакеті
resPathstring/doconut-resПрийнято для узгодженості з іншими віджетами Doconut; віджет конвертера не створює жодного URL з цього
maxUploadMbnumber25Лише попередня перевірка на боці клієнта; сервер застосовує власне обмеження
licenseUrlstring | nullnullПеретворює повідомлення про водяний знак на екрані результату у посилання
labelsobject{}Перезаписує будь-яку підмножину англійських рядків віджету

Зворотні виклики:

Зворотний викликКоли спрацьовуєДані
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, field file)Завантажити та відкрити вихідний документ200 — { token, pages, sourceExt, allowedTargets }
POST /DocImage.axd?token=<token>&convert=run&target=<ext>Перетворити завантажений вихідний файл у target200 — { 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.

МаршрутСтатусКолиТіло
any404Віджет не ввімкнено (AddConverterWidget() ніколи не викликався)лише статус
any405Неправильний метод (open/run вимагає POST, download вимагає GET)лише статус
open413Завантаження перевищує MaxUploadMb (але не межі IIS){ "error": "File is too large." }
open400Відсутнє multipart‑тіло, файл або тип, який не можна конвертувати{ "error": "..." }
open403Тип файлу потребує можливості, яку ліцензія не надає{ "error": "..." }
run400Некоректний токен, невідомий target або ціль, що не входить у allowedTargets{ "error": "..." }
run404Термін дії завантаження закінчився або його ніколи не відкривали{ "error": "Upload expired — please re-open the file." }
open, run500Обробка не вдалася{ "error": "<sanitized message>" }
download400 / 404Некоректний, невідомий або прострочений токен завантаженнялише статус

Власність ресурсів

Викликаюча сторона володіє MemoryStream, який повертає конверсія, і повинна його звільнити після копіювання або повернення (MVC‑овий File(stream, …) звільняє його за вас). Не створюйте і не звільняйте DocumentConverter самостійно — його конструктор є внутрішнім.

Водяний знак

Стан ліцензіїЗапускВихід конверсії
Платна ліцензія переглядача, що надає ConverterЗапускаєтьсяЧистий — watermarked: false
Активна тимчасова/демо‑ліцензіяЗапускаєтьсяКонвертує, з водяним знаком оцінки — watermarked: true
Відсутня ліцензія, застарілий файл TRIAL або ліцензія без ConverterApplication_Start викидає виключення; кожен запит відповідає порожнім 500—
Прострочена тимчасова/демо‑ліцензіяЗапускаєтьсяКонвертує, з водяним знаком оцінки — watermarked: true

Інтеграцію можна створити та протестувати від початку до кінця на оцінній ліцензії перед покупкою — змінюються лише байти вихідних даних.

Усунення неполадок

СимптомПеревірка
Кожен запит відповідає порожнім 500 після додавання плагінаЛіцензія надає Converter — журнал подій Windows, джерело ASP.NET
Вирішення DocumentConverter викликає виключенняAddPlugin<ConverterPlugin>() знаходиться у DoconutHost.Initialize
Конверсія Web Forms ніколи не повертає результатСторінка блокується на ConvertAsync — використайте Async="true" та RegisterAsyncTask
Трансляція конверсії повідомляє, що формат не підтримуєтьсяsourceExtension містить початкову крапку
Віджет завантажується, але його запити повертають 404AddConverterWidget() не був викликаний, або basePath не є '/DocImage.axd'
Велике завантаження показує сторінку помилки IIS замість повідомлення віджетаmaxRequestLength / maxAllowedContentLength нижче за MaxUploadMb
Ціль відсутняВикористайте allowedTargets з convert=open
Термін дії завантаження закінчивсяПовторіть convert=open / convert=run; токени навмисно тимчасові

Чи була ця сторінка корисною?