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

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

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

Составные части

  • Viewer — публичный сервис, который вы получаете из DoconutHost.Services. Он открывает документы и возвращает токены сессий.
  • Сессия документа — объект на стороне сервера, хранящий загруженный документ, удерживаемый в памяти под своим токеном.
  • DocImage.axd — Doconut.DocImageHandler, объявленный в Web.config. Он отвечает на каждый запрос, который делает виджет браузера (страницы, миниатюры, поиск, аннотации и т.д.), всегда идентифицируемый токеном.
  • /doconut-res/* — Doconut.DoconutResourceModule, который обслуживает собственные скрипты, стили и иконки виджета.

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

Viewer не хранит состояние документа для каждого запроса и не реализует IDisposable. Сессии существуют независимо от него и очищаются по истечении срока или явным вызовом CloseDocument(token). В System.Web нет внедрения через конструктор, поэтому получайте его там, где нужен — обычно в действии контроллера:

csharp
// POST /ViewerApi/Open?fileName=Sample.pdf
[HttpPost]
public async Task<ActionResult> Open(string fileName)
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    var path   = Server.MapPath("~/files/" + Path.GetFileName(fileName));

    var token = await viewer.OpenDocumentAsync(path);
    return Content(token, "text/plain");
}

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

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

Асинхронные перегрузки принимают путь к файлу, путь к файлу плюс конфигурацию формата (PdfConfig, WordConfig и т.д.), или Stream плюс FileInfo, расширение которого определяет формат. Для кода‑behind Web Forms, не использующего асинхронные страницы, OpenDocument предлагает те же три входа синхронно (путь, поток с именем файла или массив байт с именем файла).

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

Виджет вызывает DocImage.axd с токеном в строке запроса. Действия обработчика зависят от запроса:

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

Каждый запрос проверяется вначале:

  • Отсутствует токен → 404, или баннер версии, когда ShowDoconutInfo = true.
  • Токен не предоставлен этой ASP.NET‑сессии → изображение ошибки с надписью You Are Not Authorized To View This Page.
  • Неизвестный или просроченный токен → изображение ошибки с надписью Document session not found. Please re-open document.

Изображения ошибок — обычные PNG, отправляемые со статусом 200, чтобы виджет мог показывать их вместо страницы. Мониторинг, проверяющий только код статуса, будет считать их обслуженными страницами; реальная страница весит от десятков до сотен килобайт, изображение ошибки — около 2 КБ.

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

csharp
viewer.CloseDocument(token);

CloseDocument удаляет сессию (немедленно освобождая движок документа и его память), удаляет запись secure-{token} из текущей ASP.NET‑сессии запроса и аннулирует токен. Это необязательно — скользящее истечение делает то же самое — но для больших документов память освобождается сразу после завершения работы пользователя. Из браузера objViewer.Close(true) отправляет эквивалентный запрос закрытия к DocImage.axd.

Ключевые выводы

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

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