Швидкий старт
Відобразіть ваш перший документ за кілька хвилин
Цей покроковий посібник переводить додаток ASP.NET Core від порожнього Program.cs до документа, що відображається в браузері: реєстрація сервера, повний пакет Viewer (панель інструментів Viewer, монтування Viewer та необов’язкові стрічки Пошуку/Анотацій), посилання на ресурси, ініціалізація клієнта, відкриття документа та виконання.
Налаштування сервера
AddDoconut() реєструє служби; UseDoconutResources() і UseDoconut() підключають проміжне ПЗ. Виклик ресурсів має бути першим. Виклики сесії також потрібні — стандартна безпека документів Doconut перевіряє кожен запит сторінки проти стану сесії ASP.NET. Вже реєстрували Doconut під час Встановлення? Перейдіть до наступного розділу.
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
});
builder.Services.AddSession(); // Doconut document security rides on ASP.NET session state
app.UseSession(); // call UseSession() before UseDoconut()
app.UseDoconutResources(); // must be registered before UseDoconut()
app.UseDoconut();Для розташування шляхів у продакшн‑стилі, прив’яжіть проміжне ПЗ документа до явної гілки та збережіть узгодженість чотирьох налаштувань шляху:
builder.Services.AddDoconut(options =>
{
options.LicensePath = Path.Combine(AppContext.BaseDirectory, "Doconut.Viewer.lic");
options.MiddlewarePath = "/doconut";
options.ResourcesPath = "/doconut-res";
options.UnsafeMode = false;
});
builder.Services.AddSession();
app.UseRouting();
app.UseSession();
app.UseDoconutResources();
app.Map("/doconut", branch => branch.UseDoconut());MiddlewarePath — це координуюче значення; воно не створює гілку ASP.NET Core самостійно. У цьому прикладі хост прив’язує /doconut, тому клієнт має використовувати BasePath: '/doconut'. ResourcesPath подає вбудований пакет за адресою /doconut-res, а шлях до ресурсів зображень віджета становить ResPath: '/doconut-res/images'.
Додайте переглядач на сторінку
Viewer — це обов’язковий ядро сторінки. Його поверхня рендерингу використовує два вкладені div‑и:
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Розглядайте панель інструментів, монтування модулів та поверхню Viewer як одну композицію сторінки. Пошук і
Анотація вбудовують свої стрічки у необов’язкові монтування, але ці модулі ніколи не працюють
самостійно: вони завжди приєднуються до Viewer на тій самій сторінці. Використовуйте той самий порядок, що й
Doconut.TestApp та Doconut.TestApp.Distributed:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- Viewer navigation, zoom, Search, and Annotation buttons -->
</nav>
<div id="searchBarMount"></div>
<div id="annBarMount"></div>
<div id="divDocViewer">
<div id="div_ctlDoc"></div>
</div>Посилання на ресурси переглядача
У Razor‑виді інжектований сервіс Viewer генерує теги <link> і <script> переглядача у правильному порядку — віджет є jQuery‑плагіном, тому jQuery має бути завантажений до скриптів переглядача:
@inject Doconut.Viewer Viewer
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeBootstrapCss = true,
IncludeViewerCss = true
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeBootstrap = true,
IncludeViewerScripts = true
}))Для повного пакету Viewer запитайте ресурси Viewer та модулів одночасно:
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeBootstrapCss = true,
IncludeViewerCss = true,
IncludeSearchCss = true,
IncludeAnnotationCss = true
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeBootstrap = true,
IncludeViewerScripts = true,
IncludeSearchScripts = true,
IncludeSearchBar = true,
IncludeAnnotationScripts = true,
IncludeAnnotationBar = true
}))IncludeViewerCss і IncludeViewerScripts — обов’язкові ядрові прапорці. Ніколи не публікуйте приклад стрічки Пошуку або Анотації без них, без монтування Viewer та без екземпляра docViewer. ReferenceCss і ReferenceScripts пропускають ресурси необов’язкового модуля, якщо поточна ліцензія не надає таку можливість; ядро Viewer все одно запускається.
Ініціалізація переглядача
Віджет на боці клієнта — це jQuery‑плагін. Ось мінімальний набір реальних параметрів ініціалізації (не псевдокод):
let searchBar = null;
let annBar = null;
const objViewer = $('#div_ctlDoc').docViewer({
showThumbs: true,
autoLoad: false,
pageZoom: 100,
FitType: 'width',
BasePath: '/doconut',
ResPath: '/doconut-res/images',
onViewerReady: function () {
// pages are visible; safe to hide a loading spinner here
},
// Forward annotation lifecycle events to the embedded ribbon when it is present.
onAnnLoaded: () => annBar?.handleAnnLoaded(),
onAnnSaved: () => annBar?.handleAnnSaved(),
onAnnSaveError: () => annBar?.handleAnnSaveError(),
onAnnClosed: () => annBar?.handleAnnClosed(),
onError: function (message) {
console.error('Doconut viewer error:', message);
}
});Кейс параметрів справді змішаний — showThumbs, autoLoad і pageZoom написані у camelCase, а FitType, BasePath і ResPath — у PascalCase. Єдина послідовність відсутня; якщо вказати неправильний регістр, параметр буде тихо проігноровано (віджет повернеться до значення за замовчуванням замість помилки).
Збірка повного пакету Viewer
Обидва приклади .NET 8 встановлюють наступні частини разом на одній сторінці:
| Частина пакету | Вимога | Як підключається |
|---|---|---|
Ресурси Viewer, монтування та objViewer | Обов’язково | Ядровий рендерер документу |
| Панель інструментів Viewer | Обов’язково у референсній композиції | Маркап хоста; кнопки викликають той самий objViewer |
| Стрічка Пошуку | Необов’язково, ліцензований модуль | doconutSearchBar(...).attach(objViewer) |
| Стрічка Анотації | Необов’язково, ліцензований модуль | doconutAnnotationBar(...).attach(objViewer) |
Хоча головна панель інструментів Viewer є розміткою хоста, вона встановлюється разом із Viewer і ніколи не повинна документуватись як окремий контроль. Це зберігає її розташування, мітки, іконки та правила авторизації під контролем вашого застосунку, а кожна кнопка керує одним і тим же екземпляром Viewer:
<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.GotoPage(objViewer.TotalPages())">Last</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>
<button type="button" onclick="objViewer.FitType('height')">Fit height</button>
<button type="button" id="openSearch">Search</button>
<button type="button" id="openAnnotations">Annotations</button>
</nav>Повна референсна панель інструментів також копіює wwwroot/js/viewerToolbar.js у хост‑застосунок для
обертання, мініатюр, друку, повноекранного режиму, зміни розкладки та допоміжних функцій стану кнопок.
Завантажте цей файл хоста після Viewer.ReferenceScripts(...). Тримайте допоміжний скрипт і його
розмітку <nav id="toolbar"> разом під час копіювання повної демонстрації.
Дотримуйтесь порядку ініціалізації пакету, що використовується в обох референсних застосунках:
- Випустіть ресурси Viewer, Пошуку та Анотації одночасно.
- Відобразіть панель інструментів Viewer, монтування стрічок та монтування Viewer разом.
- Спочатку ініціалізуйте
docViewer. - Створіть кожну ліцензовану стрічку і приєднайте її до того ж
objViewer. - Відкрийте документ і збережіть його токен для запитів модулів.
Doconut.TestApp.Distributed зберігає саме таку композицію UI та той самий допоміжний скрипт панелі інструментів Viewer. Його додаткове значення запиту access і налаштування повторних асинхронних рендерів належать до розподіленого транспорту; вони не змінюють спосіб складання Viewer, панелі інструментів або стрічок.
Захисти на боці сервера важливі: коли необов’язкова можливість недоступна, її скрипт не випускається, тому функція jQuery‑плагіна не існує.
<script>
let currentToken = '';
const refitViewer = () =>
requestAnimationFrame(() => objViewer.Refit());
@if (Viewer.IsSearchEnabled)
{
<text>
searchBar = $('#searchBarMount').doconutSearchBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onLayout: refitViewer
});
searchBar.attach(objViewer);
</text>
}
@if (Viewer.IsAnnotationEnabled)
{
<text>
annBar = $('#annBarMount').doconutAnnotationBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onLayout: refitViewer
});
annBar.attach(objViewer);
</text>
}
document.getElementById('openSearch').addEventListener('click', () => {
if (!searchBar) return;
searchBar.isOpen() ? searchBar.close() : searchBar.open();
});
document.getElementById('openAnnotations').addEventListener('click', () => {
if (!annBar) return;
annBar.isOpen() ? annBar.close() : annBar.open();
});
</script>Обидва вбудовані компоненти генерують власний DOM‑стрічки. Пошук містить групи Find, Options та Results. Анотація містить інструменти авторства, елементи керування стилем, дії збереження та необов’язкові експорт/зображення. Бар‑стрічки надають методи open(), close(), reset() і isOpen(); завжди викликайте attach(objViewer) один раз після їх створення.
У наведеному вище прикладі пропущені необов’язкові колбеки хоста та кінцеві точки експорту/зображення Анотації, щоб мінімізувати старт. Дивіться Пошук та Анотації для повної налаштування функціоналу, або Користувацькі теми для стилізації чи заміни панелі інструментів Viewer, що належить хосту.
Відкриття документа
На сервері лише один кінцевий пункт: інжектований сервіс Viewer відкриває документ і повертає токен сесії.
app.MapPost("/api/open", async (Viewer viewer) =>
{
// The token is opaque — hand it to the widget, never log or persist it.
string token = await viewer.OpenDocumentAsync("wwwroot/files/Sample.pdf");
return Results.Ok(new { token });
});Клієнт отримує цей токен і передає його віджету за допомогою objViewer.View(token):
fetch('/api/open', { method: 'POST' })
.then(resp => resp.json())
.then(data => {
currentToken = data.token;
objViewer.View(currentToken);
});Закриття документа
Викликайте objViewer.Close(), коли користувач залишає переглядач або відкриває інший документ. У серверних робочих процесах viewer.CloseDocument(token) негайно видаляє кешовану сесію, звільняє рушій рендерингу, стирає маркер безпеки та анулює токен. Поступове закінчення терміну дії також виконує таке очищення, проте явне закриття рекомендується для великих документів.
Повний потік запитів виглядає так:
AddDoconut + middleware
-> render CSS/scripts and mount div
-> initialize docViewer
-> OpenDocumentAsync
-> return opaque token
-> objViewer.View(token)
-> page/search/annotation requests
-> Close / CloseDocumentТримайте токен як облікові дані типу bearer: ніколи не журналюйте його, не зберігайте, передавайте лише віджету. Він ідентифікує активну сесію документа на сервері і перестає працювати, коли сесія закінчується — відкрийте документ знову, щоб отримати новий токен.
Запуск
Помістіть PDF у wwwroot/files/Sample.pdf, запустіть dotnet run і відкрийте сторінку, що містить віджет. Перша сторінка відобразиться у переглядачі, з панеллю мініатюр ліворуч. Якщо цього не сталося, дивіться Усунення проблем.
Що ви отримуєте без ліцензії
Відсутність ліцензії не викликає помилку. Переглядач працює звичайно, але кожна сторінка містить водяний знак оцінки. Дивіться Налаштування ліцензії для того, як Doconut знаходить ліцензію і які зміни відбуваються після її виявлення.
Чи була ця сторінка корисною?