Как работает Viewer

Жизненный цикл запросов документа

Doconut рендерит документы в виде постраничных изображений, обслуживаемых через middleware ASP.NET Core. Понимание жизненного цикла — открытие, токен, запросы страниц, закрытие — объясняет почти все наблюдаемые поведения, включая сообщения об ошибках.

Три движущиеся части

  • Viewer — публичный сервис, который вы внедряете. Он открывает документы и возвращает токены сеанса.
  • Сеанс документа — объект на стороне сервера, хранящий загруженный документ, индексируемый токеном в IMemoryCache.
  • Промежуточное ПО Doconut — добавляется через UseDoconut(); отвечает на каждый запрос, который делает виджет браузера (pages, thumbnails, search, annotations, …), всегда аутентифицированный токеном.

Viewer без состояния — по замыслу

Viewer запечатан, не хранит состояние документа per‑request и сознательно не реализует IDisposable. Сеансы живут независимо в менеджере сеансов и очищаются истечением кэша или явным вызовом CloseDocument(token).

Внедрите его там, где нужно:

csharp
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync($"files/{fileName}");
    return Results.Content(token, "text/plain");
});

Что происходит внутри OpenDocumentAsync

  1. Проверка лицензии. Отклонённая или просроченная версия лицензии (в чёрном списке, подделана, или сборка вне окна обновления лицензии) сразу бросает LicenseException с причиной отклонения в сообщении — открытие никогда не деградирует тихо при недействительной (в отличие от отсутствующей) лицензии. Исключением является календарно‑просроченная временная или подписочная лицензия: она не бросает исключение, а переходит в режим водяного знака.
  2. Создание сеанса. Фабрика viewer выбирает подходящий просмотрщик формата по расширению файла и загружает документ (см. Rendering Pipeline). Сеанс сохраняется в IMemoryCache под новым GUID‑токеном с скользящим истечениемDocOptions.TimeOut минут, по умолчанию 60. Каждый запрос страницы сбрасывает таймер.
  3. Регистрация безопасности. При UnsafeMode = false (по умолчанию) токен привязывается к ASP.NET‑сеансу вызывающего: в сеанс записывается маркер secure-{token}, поэтому только браузерный сеанс, открывший документ, может запрашивать его страницы.
  4. Токен возвращается. Это единственное удостоверение для всех последующих действий.

Три перегрузки отличаются лишь входными параметрами: путь к файлу, путь к файлу плюс конфигурация формата (PdfConfig, WordConfig, …) или Stream плюс FileInfo, расширение которого определяет формат.

Как виджет получает страницы

Виджет клиента вызывает middleware Doconut с токеном в строке запроса. Действия middleware зависят от запроса:

ЗапросНазначение
?token=…&page=NИзображение отрендеренной страницы (PNG)
?token=…&page=N&thumb=1Миниатюра
?token=…&zoom=…Рендеринг увеличенной страницы
?token=…&search=termПолнотекстовый поиск (по лицензии)
?token=…&bookmarksОглавление/закладки документа
?token=…&copy / &showlinks / &fileFormatКопирование текста, гиперссылки и информация о формате
?token=…&metaТехнические метаданные DICOM; возвращает 501 для DICOM‑сеанса в .NET 6
?token=…&action=rotate/flip/closeДействия со страницей и явное закрытие
?token=…&AnnSave=… / &AnnLoadСохранение/загрузка аннотаций

Каждый из этих путей сначала проходит проверку:

  • Отсутствует токен → middleware возвращает 404 (или баннер версии, когда ShowDoconutInfo = true).
  • Неизвестный или просроченный токен → изображение ошибки с текстом «Сеанс документа не найден. Пожалуйста, откройте документ заново».
  • Отсутствует middleware сеанса (при UnsafeMode = false) → HTTP 500 с сообщением «Middleware сеанса не сконфигурирован. Вызовите UseSession() перед UseDoconut()».
  • Токен открыт другим браузерным сеансом → изображение ошибки с текстом «У вас нет прав для просмотра этой страницы».

Закрытие документа

csharp
viewer.CloseDocument(token);

CloseDocument удаляет сеанс из кэша (что освобождает движок документа и сразу освобождает память), удаляет маркер secure-{token} и отзывает право доступа. Вызывать его необязательно — скользящее истечение делает то же самое автоматически — но для больших документов это вежливый способ освободить память сразу после завершения работы пользователя.

Основные выводы

  • Один открытый документ = один сеанс = один токен. Токены привязаны к браузерному сеансу, а не к глобальным URL.
  • Токен истекает по скользящему окну; если viewer простаивает дольше DocOptions.TimeOut, требуется повторное открытие.
  • Viewer можно внедрять и свободно делить; всё состояние хранится в сеансах.

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