Memulai Cepat

Render dokumen pertama Anda dalam hitungan menit

Panduan ini membawa aplikasi ASP.NET Core dari Program.cs yang kosong hingga dokumen yang dirender di peramban: pendaftaran server, paket Penampil lengkap (toolbar Penampil, mount Penampil, dan pita Pencarian/Anotasi opsional), referensi aset, inisialisasi klien, pembukaan dokumen, dan eksekusi.

Pengaturan Server

AddDoconut() mendaftarkan layanan; UseDoconutResources() dan UseDoconut() menyambungkan middleware. Panggilan sumber daya harus ditempatkan pertama. Panggilan sesi juga diperlukan — keamanan dokumen Doconut memvalidasi setiap permintaan halaman terhadap status sesi ASP.NET. Sudah mendaftarkan Doconut selama Instalasi? Lewati ke bagian berikutnya.

csharp
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();

Untuk tata letak jalur gaya produksi, petakan middleware dokumen ke cabang eksplisit dan pertahankan empat pengaturan jalur tetap selaras:

csharp
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 adalah nilai koordinasi; ia tidak memetakan cabang ASP.NET Core secara otomatis. Dalam contoh ini host memetakan /doconut, sehingga klien harus menggunakan BasePath: '/doconut'. ResourcesPath menyajikan bundel tersemat di /doconut-res, dan jalur sumber daya gambar widget menjadi ResPath: '/doconut-res/images'.

Tambahkan penampil ke halaman

Penampil adalah inti yang diperlukan pada halaman. Permukaan render‑nya menggunakan dua div bersarang:

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

Anggap toolbar, mount modul, dan permukaan Penampil sebagai satu komposisi halaman. Pencarian dan Anotasi menyuntikkan pita tersemat mereka ke mount opsional, tetapi modul‑modul tersebut tidak pernah berdiri sendiri: mereka selalu menempel pada Penampil di halaman yang sama. Gunakan urutan yang sama seperti Doconut.TestApp dan Doconut.TestApp.Distributed:

html
<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>

Referensikan aset penampil

Di tampilan Razor, layanan Viewer yang disuntikkan menghasilkan tag <link> dan <script> penampil dalam urutan ketergantungan — widget adalah plugin jQuery, sehingga jQuery harus dimuat sebelum skrip penampil:

html
@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
}))

Untuk paket Penampil lengkap, minta sumber daya Penampil dan modul secara bersamaan:

html
@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 dan IncludeViewerScripts adalah flag inti yang wajib. Jangan pernah memublikasikan contoh Pita Pencarian atau Anotasi tanpa mereka, mount Penampil, dan sebuah instance docViewer. ReferenceCss dan ReferenceScripts menghilangkan sumber daya modul opsional ketika lisensi saat ini tidak memberikan kemampuan tersebut; Penampil inti tetap dapat dijalankan.

Inisialisasi penampil

Widget sisi‑klien adalah plugin jQuery. Berikut adalah sekumpulan opsi inisialisasi nyata (bukan pseudocode):

javascript
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);
    }
});

Penulisan huruf pada opsi memang campur‑aduk — showThumbs, autoLoad, dan pageZoom memakai camelCase, sementara FitType, BasePath, dan ResPath memakai PascalCase. Tidak ada aturan konsisten; jika penulisan huruf salah, opsi akan diabaikan secara diam‑diam (widget akan kembali ke nilai baku alih‑alih melempar error).

Rakit paket Penampil lengkap

Kedua aplikasi referensi .NET 8 menginstal bagian‑bagian berikut secara bersamaan pada satu halaman:

Bagian dari paketKebutuhanCara terhubung
Viewer resources, mount, and objViewerDiperlukanCore document renderer
Viewer toolbarDiperlukan dalam komposisi referensiMarkup host; tombol memanggil objViewer yang sama
Search ribbonOpsional, modul berlisensidoconutSearchBar(...).attach(objViewer)
Annotation ribbonOpsional, modul berlisensidoconutAnnotationBar(...).attach(objViewer)

Meskipun toolbar Penampil utama adalah markup host, ia dipasang bersama Penampil dan tidak pernah didokumentasikan sebagai kontrol terpisah. Ini menjaga tata letak, label, ikon, dan aturan otorisasi di bawah kendali aplikasi Anda sementara setiap tombol mengendalikan instance Penampil yang sama:

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.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>

Toolbar referensi lengkap juga menyalin wwwroot/js/viewerToolbar.js ke dalam aplikasi host untuk rotasi, thumbnail, cetak, layar penuh, tata letak, dan pembantu status tombol. Muat berkas host itu setelah Viewer.ReferenceScripts(...). Simpan pembantu dan markup <nav id="toolbar">‑nya bersama saat menyalin implementasi demo penuh.

Pertahankan urutan inisialisasi paket yang digunakan oleh kedua aplikasi referensi:

  1. Emit sumber daya Penampil, Pencarian, dan Anotasi secara bersamaan.
  2. Render toolbar Penampil, mount Pita, dan mount Penampil secara bersamaan.
  3. Inisialisasi docViewer terlebih dahulu.
  4. Buat setiap Pita berlisensi dan lampirkan ke objViewer yang sama.
  5. Buka dokumen dan simpan tokennya untuk permintaan modul.

Doconut.TestApp.Distributed mempertahankan komposisi UI persis ini serta pembantu toolbar Penampil yang sama. Nilai permintaan access tambahan dan pengaturan ulang‑coba render asinkron milik transportasi terdistribusi; keduanya tidak mengubah cara Penampil, toolbar, atau Pita dirakit.

Pengaman sisi server penting: ketika kemampuan opsional tidak tersedia, skripnya tidak di‑emit, sehingga fungsi plugin jQuery tidak ada.

html
<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>

Kedua komponen tersemat menghasilkan DOM Pita masing‑masing. Pencarian berisi grup Find, Options, dan Results. Anotasi berisi alat authoring, kontrol gaya, aksi simpan, serta aksi ekspor/gambar opsional. Bar‑bar tersebut mengekspos open(), close(), reset(), dan isOpen(); selalu panggil attach(objViewer) sekali setelah membuatnya.

Contoh di atas menghilangkan callback host opsional dan endpoint ekspor/gambar Anotasi untuk menjaga startup tetap minimal. Lihat Pencarian dan Anotasi untuk penyiapan fitur lengkap, atau Tema Kustom untuk menata atau mengganti toolbar Penampil milik host.

Buka dokumen

Sisi server hanya satu endpoint: layanan Viewer yang disuntikkan membuka dokumen dan mengembalikan token sesi.

csharp
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 });
});

Klien mengambil token itu dan memberikannya ke widget dengan objViewer.View(token):

javascript
fetch('/api/open', { method: 'POST' })
    .then(resp => resp.json())
    .then(data => {
        currentToken = data.token;
        objViewer.View(currentToken);
    });

Tutup dokumen

Panggil objViewer.Close() ketika pengguna meninggalkan penampil atau membuka dokumen pengganti. Pada alur kerja yang digerakkan server, viewer.CloseDocument(token) segera menghapus sesi cache, membuang mesin render, menghapus penanda keamanan, dan mencabut token. Kedaluwarsa bergulir pada akhirnya melakukan pembersihan yang sama, tetapi penutupan eksplisit disarankan untuk dokumen berukuran besar.

Alur permintaan yang selesai adalah:

text
AddDoconut + middleware
    -> render CSS/scripts and mount div
    -> initialize docViewer
    -> OpenDocumentAsync
    -> return opaque token
    -> objViewer.View(token)
    -> page/search/annotation requests
    -> Close / CloseDocument

Perlakukan token seperti kredensial bearer: jangan pernah mencatatnya, jangan pernah menyimpannya, serahkan hanya ke widget. Token mengidentifikasi sesi dokumen aktif di server dan tidak akan berfungsi lagi ketika sesi tersebut kedaluwarsa — buka kembali dokumen untuk mendapatkan token baru.

Jalankan

Letakkan file PDF di wwwroot/files/Sample.pdf, jalankan dotnet run, dan buka halaman yang menampung widget. Halaman pertama akan dirender di penampil, dengan panel thumbnail di sebelah kiri. Jika tidak muncul, lihat Pemecahan Masalah.

Apa yang Anda dapatkan tanpa lisensi

Lisensi yang hilang tidak menyebabkan error. Penampil tetap merender normal, tetapi setiap halaman menampilkan watermark evaluasi. Lihat Pengaturan Lisensi untuk cara Doconut menemukan lisensi dan apa yang berubah setelah ditemukan.

Apakah halaman ini membantu?