Швидкий старт

Відобразіть ваш перший документ у MVC 5 або Web Forms

Цей посібник переводить застосунок ASP.NET на .NET Framework 4.7.2 з встановленого пакету до документа, що відображається у браузері: Global.asax, відкритий кінцевий пункт, ресурси переглядача, віджет і токен, який їх з’єднує. Припускається, що реєстрації у Web.config з розділу Встановлення виконані — без обробника DocImage.axd та модуля ресурсів нічого нижче не зможе дістатися до сервера.

Створення Doconut у Global.asax

Повний Application_Start для застосунку MVC 5:

csharp
// Global.asax.cs — ініціалізується один раз на процес‑робітник, звільняється при завершенні.
protected void Application_Start()
{
    Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);

    Doconut.DoconutHost.Initialize(options =>
    {
        options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
        options.UnsafeMode  = false; // сторінка обслуговується лише для сесії, яка відкрила документ
    });

    // лише MVC: тримати два кінцеві точки Doconut поза маршрутизацією.
    RouteTable.Routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
    RouteTable.Routes.IgnoreRoute("doconut-res/{*pathInfo}");
}

protected void Application_End()
{
    Doconut.DoconutHost.Shutdown();
}
  • Encoding.RegisterProvider робить доступними для процесу застарілі кодові сторінки, які використовуються деякими форматами документів. Викликайте його один раз, перед відкриттям першого документа.
  • UnsafeMode = false — це значення за замовчуванням, явно зазначене, щоб ніхто випадково не змінив його: DocImage.axd обслуговує сторінку лише для ASP.NET‑сесії, яка відкрила документ.
  • Два виклики IgnoreRoute тримають маршрутизацію MVC подалі від DocImage.axd та /doconut-res/*, які обслуговуються обробником і модулем. У застосунку Web Forms немає маршрутів MVC, тому цей рядок не потрібен.
  • DoconutHost.Shutdown зупиняє фонову роботу Doconut і звільняє його служби, коли пул застосунків перезапускається. Викликати його безпечно, навіть якщо Initialize ніколи не був виконаний.

Відкрити документ

Відкриття документа повертає непрозорий токен. Віджет надсилає цей токен з кожним запитом сторінки.

У MVC 5 дія контролера отримує сервіс Viewer з DoconutHost.Services — у MVC 5 немає ін’єкції конструктора для нього:

csharp
// POST /Document/Open
[HttpPost]
public async Task<ActionResult> Open()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();

    // Токен є непрозорим — передайте його переглядачу, ніколи не журналюйте і не зберігайте.
    string token = await viewer.OpenDocumentAsync(Server.MapPath("~/files/Sample.pdf"));
    return Json(new { token });
}

Документ має бути відкритий в межах запиту, який має стан сесії, оскільки саме відкриття надає поточній ASP.NET‑сесії доступ до його сторінок. Контролери MVC та сторінки Web Forms мають стан сесії за замовчуванням. Користувацький IHttpHandler його не має, якщо не реалізує System.Web.SessionState.IRequiresSessionState. Відкрийте документ з обробника без цього, і переглядач покаже «Ви не маєте дозволу переглядати цю сторінку.» на кожній сторінці.

У Web Forms сама сторінка може відкрити документ у код‑бекенді. OpenDocument — синхронна форма OpenDocumentAsync, призначена для код‑бекенду, який не використовує асинхронні сторінки:

csharp
// Default.aspx.cs
protected string Token;

protected void Page_Load(object sender, EventArgs e)
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    Token = viewer.OpenDocument(Server.MapPath("~/files/Sample.pdf"));
}

Ставтеся до токену як до облікового даних: ніколи не журналюйте його і не зберігайте; передавайте його лише віджету. Він перестає працювати, коли сесія документа закінчується — відкрийте документ знову, щоб отримати новий.

Посилання на ресурси переглядача

Viewer.ReferenceCss та Viewer.ReferenceScripts генерують теги <link> та <script> для вбудованих ресурсів у порядку залежностей, вказуючи на /doconut-res/. Віджет є плагіном jQuery, тому jQuery підключається першим.

MVC 5. Представлення не мають @inject, тому теги створюються у контролері та передаються через ViewBag:

csharp
public ActionResult Index()
{
    var viewer = Doconut.DoconutHost.Services.GetRequiredService<Viewer>();
    ViewBag.ViewerCss = viewer.ReferenceCss(new CssConfig
    {
        IncludeBootstrapCss = true,
        IncludeViewerCss    = true
    });
    ViewBag.ViewerScripts = viewer.ReferenceScripts(new ScriptConfig
    {
        IncludeJQuery        = true,
        IncludeBootstrap     = true,
        IncludeViewerScripts = true
    });
    return View();
}
html
@Html.Raw(ViewBag.ViewerCss)
...
@Html.Raw(ViewBag.ViewerScripts)

Залиште цю роботу в контролері. MVC 5 компілює представлення під час першого запиту, і без додаткового пакету компілятора цей компілятор розуміє лише C# 5 — без ?., без $"...", без nameof. Представлення, яке їх використовує, успішно компілюється у Visual Studio, а в браузері повертає порожню помилку 500.

Web Forms. Показуйте ті ж рядки з коду‑бекенду та виводьте їх за допомогою <%= %>:

html
<head>
    <%= ViewerCss %>
</head>
<body>
    ...
    <%= ViewerScripts %>
</body>

IncludeViewerCss та IncludeViewerScripts є обов'язковими ядрами. Щоб додати стрічки пошуку та анотації, також встановіть IncludeSearchCss, IncludeAnnotationCss, IncludeSearchScripts, IncludeSearchBar, IncludeAnnotationScripts та IncludeAnnotationBar. Обидва методи пропускають файли відповідної стрічки, якщо ліцензія не передбачає таку можливість; сам переглядач все одно запускається.

Додайте переглядач на сторінку

Поверхня відображення складається з двох вкладених div:

html
<div id="divDocViewer">
    <div id="div_ctlDoc"></div>
</div>

Задайте зовнішньому div реальну висоту — переглядач заповнює свій контейнер і вимірює його під час запуску. Переглядач не малює власну панель інструментів: GotoPage, Next, Zoom, FitType та інші — це методи, які ваша сторінка підключає до своїх кнопок, розташованих поруч із переглядачем:

html
<nav id="toolbar" aria-label="Document viewer controls">
    <button type="button" onclick="objViewer.GotoPage(1)">First</button>
    <button type="button" onclick="objViewer.Next(false)">Previous</button>
    <button type="button" onclick="objViewer.Next(true)">Next</button>
    <button type="button" onclick="objViewer.Zoom(false)">Zoom out</button>
    <button type="button" onclick="objViewer.Zoom(true)">Zoom in</button>
    <button type="button" onclick="objViewer.FitType('width')">Fit width</button>
</nav>

Ініціалізуйте переглядач і покажіть документ

Після скриптів переглядача створіть віджет, а потім передайте йому токен:

javascript
var objViewer = $('#div_ctlDoc').docViewer({
    showThumbs: true,
    autoLoad:   false,
    pageZoom:   100,
    FitType:    'width',
    BasePath:   '/',                   // '/' означає DocImage.axd у корені сайту
    ResPath:    'doconut-res/images',  // без початкового '/'
    onViewerReady: function () {
        // сторінки видимі; сховайте індикатор завантаження тут
    },
    onError: function (message) {
        console.error('Doconut viewer error:', message);
    }
});

fetch('/Document/Open', { method: 'POST' })
    .then(function (resp) { return resp.json(); })
    .then(function (data) { objViewer.View(data.token); });

У Web Forms, де сторінка сама відкриває документ, останні три рядки стають objViewer.View('<%= Token %>');.

Чотири деталі тут не працюють без повідомлення про помилку:

  • BasePath: '/' вказує на DocImage.axd у корені сайту. Для застосунку у віртуальному каталозі використовуйте його назву без слешів ('myapp' запитує /myapp/DocImage.axd). Початковий слеш ('/myapp') створює //myapp/DocImage.axd, який браузер сприймає як запит до іншого хоста.
  • ResPath: 'doconut-res/images' — іконки розташовані на один каталог нижче кореня ресурсів. При 'doconut-res' кожна іконка повертає 404: немає гліфів панелі інструментів і індикатора завантаження, хоча сам документ все ще відображається. Початковий слеш руйнує шлях так само, як і BasePath.
  • Зворотні виклики — це параметри. onViewerReady, onError та інші передаються в об’єкт, який передається до docViewer(...). Глобальна функція з назвою, що відповідає переглядачу, наприклад ctlDoc_ViewerReady, ніколи не викликається.
  • Залишайте переглядач, а потім викликайте View окремо. docViewer(...) повертає об’єкт з методами Zoom, Next та FitType; View(...) повертає інше. var objViewer = $('#div_ctlDoc').docViewer({...}).View(token) відображає документ, а при першому кліку на панелі інструментів виникає помилка objViewer.Zoom is not a function.

Назви параметрів змішують camelCase (showThumbs, autoLoad, pageZoom) та PascalCase (FitType, BasePath, ResPath). Помилково написаний параметр ігнорується, і віджет використовує значення за замовчуванням.

Однорядкова альтернатива

Для сторінки, якій потрібно лише показати документ, без власної панелі інструментів, Viewer.RenderViewer записує весь скрипт ініціалізації — docViewer(...) з BasePath: '/' і ResPath: 'doconut-res/images', потім .View(token). Це існує лише в цьому пакеті:

csharp
// Код-behind Web Forms, після відкриття документа
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

Передайте ViewerConfig як третій аргумент, щоб змінити масштаб, підгонку або панель мініатюр. Оскільки згенерований скрипт не зберігає посилання на переглядач, використовуйте наведений вище ручний код ініціалізації, коли вашій сторінці потрібна власна панель інструментів.

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

Викличте objViewer.Close(true), коли користувач залишає переглядач або відкриває заміну: це очищає віджет і надсилає запит на закриття до DocImage.axd. objViewer.Close() без аргументу очищає лише віджет. На сервері viewer.CloseDocument(token) одразу видаляє сесію документа, звільняє ресурси рендерингу та відкликає доступ сесії до її сторінок. Кінцева (скользяща) дія терміну дії зрештою робить те ж саме, але явне закриття великих документів швидше звільняє пам'ять.

Запустіть

Помістіть PDF у ~/files/Sample.pdf, запустіть сайт в IIS Express (F5 у Visual Studio) і відкрийте сторінку, що містить віджет. Перша сторінка відображається, з мініатюрами ліворуч. Якщо цього не відбувається, дивіться Усунення проблем.

Що ви отримуєте без ліцензії

Відсутність ліцензії не викликає помилку. Переглядач працює звичайно, але кожна сторінка містить водяний знак оцінки. Дивіться Налаштування ліцензії, щоб дізнатися, де Doconut шукає вашу ліцензію.

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