Γρήγορη Εκκίνηση

Αποδώστε το πρώτο σας έγγραφο σε λίγα λεπτά

Αυτός ο οδηγός μετατρέπει μια εφαρμογή ASP.NET Core από ένα κενό Program.cs σε ένα έγγραφο που αποδίδεται στον περιηγητή: καταχώρηση στον διακομιστή, το πλήρες πακέτο Viewer (εργαλειοθήκη Viewer, τοποθέτηση Viewer και προαιρετικές ταινίες Αναζήτησης/Σχόλιου), αναφορές πόρων, αρχικοποίηση πελάτη, άνοιγμα εγγράφου και εκτέλεση.

Ρύθμιση διακομιστή

AddDoconut() καταχωρεί τις υπηρεσίες· UseDoconutResources() και UseDoconut() συνδέουν το middleware. Η κλήση των πόρων πρέπει να γίνει πρώτη. Οι κλήσεις συνεδρίας είναι επίσης απαραίτητες — η προεπιλεγμένη ασφάλεια εγγράφων του Doconut επαληθεύει κάθε αίτημα σελίδας έναντι της κατάστασης συνεδρίας του ASP.NET. Έχετε ήδη καταχωρήσει το Doconut κατά την Εγκατάσταση; προχωρήστε στην επόμενη ενότητα.

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

Για μια διάταξη διαδρομών τύπου παραγωγής, αντιστοιχίστε το middleware εγγράφου σε έναν ρητό κλάδο και διατηρήστε τις τέσσερις ρυθμίσεις διαδρομής ευθυγραμμισμένες:

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 είναι μια τιμή συντονισμού· δεν αντιστοιχίζει αυτόνομα έναν κλάδο ASP.NET Core. Σε αυτό το παράδειγμα ο κεντρικός υπολογιστής αντιστοιχίζει το /doconut, έτσι ο πελάτης πρέπει να χρησιμοποιήσει BasePath: '/doconut'. Το ResourcesPath εξυπηρετεί το ενσωματωμένο πακέτο στο /doconut-res, και η διαδρομή πόρων εικόνας του widget είναι επομένως ResPath: '/doconut-res/images'.

Προσθήκη του προβολέα σε σελίδα

Ο Viewer είναι ο απαιτούμενος πυρήνας της σελίδας. Η επιφάνεια απόδοσής του χρησιμοποιεί δύο ένθετα divs:

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

Αντιμετωπίστε την εργαλειοθήκη, τις τοποθετήσεις των μονάδων και την επιφάνεια του Viewer ως μία σύνθεση σελίδας. Η Αναζήτηση και το Σχόλιο ενσωματώνουν τις ταινίες τους σε προαιρετικές τοποθετήσεις, αλλά αυτές οι μονάδες δεν είναι ποτέ αυτόνομες: συνδέονται πάντα με τον Viewer στην ίδια σελίδα. Χρησιμοποιήστε την ίδια σειρά όπως στα Doconut.TestApp και 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>

Αναφορά των πόρων του Viewer

Σε μια Razor προβολή, η ενσωματωμένη υπηρεσία Viewer εκδίδει τις ετικέτες <link> και <script> του viewer με σειρά εξαρτήσεων — το widget είναι ένα πρόσθετο jQuery, επομένως το jQuery πρέπει να φορτωθεί πριν από τα script του viewer:

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

Για το πλήρες πακέτο Viewer, ζητήστε μαζί τους πόρους του Viewer και των μονάδων:

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 και IncludeViewerScripts είναι οι υποχρεωτικές βασικές σημαίες. Μην δημοσιεύετε ποτέ ένα παράδειγμα ταινίας Αναζήτησης ή Σχολίου χωρίς αυτά, την τοποθέτηση Viewer και μια παρουσία docViewer. Τα ReferenceCss και ReferenceScripts παραλείπουν τους πόρους μιας προαιρετικής μονάδας όταν η τρέχουσα άδεια δεν παρέχει αυτή τη δυνατότητα· ο βασικός Viewer εξακολουθεί να ξεκινά.

Αρχικοποίηση του Viewer

Το widget στην πλευρά του πελάτη είναι ένα πρόσθετο jQuery. Αυτό είναι ένα ελάχιστο σύνολο πραγματικών επιλογών αρχικοποίησης (όχι ψευδοκώδικας):

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

Η κεφαλοποίηση των επιλογών είναι πραγματικά μικτή — showThumbs, autoLoad και pageZoom είναι camelCase, ενώ FitType, BasePath και ResPath είναι PascalCase. Δεν υπάρχει συνεπής κανόνας· αν κάνετε λάθος στην κεφαλοποίηση, η επιλογή αγνοείται σιωπηρά (το widget επανέρχεται στην προεπιλογή του αντί να πετάξει σφάλμα).

Συναρμολόγηση του πλήρους πακέτου Viewer

Και οι δύο εφαρμογές αναφοράς .NET 6 εγκαθιστούν τα παρακάτω μέρη μαζί σε μία σελίδα:

Μέρος του πακέτουΑπαίτησηΠώς συνδέεται
Πόροι Viewer, τοποθέτηση και objViewerΑπαιτείταιΚύριος αποδότης εγγράφου
Εργαλειοθήκη ViewerΑπαιτείται στη σύνθεση αναφοράςΣήμανση κεντρικού υπολογιστή· τα κουμπιά καλούν το ίδιο objViewer
Ταινία ΑναζήτησηςΠροαιρετική, μονάδα με άδειαdoconutSearchBar(...).attach(objViewer)
Ταινία ΣχολίουΠροαιρετική, μονάδα με άδειαdoconutAnnotationBar(...).attach(objViewer)

Παρόλο που η κύρια εργαλειοθήκη Viewer είναι σήμανση κεντρικού υπολογιστή, εγκαθίσταται μαζί με τον Viewer και δεν πρέπει ποτέ να τεκμηριώνεται ως ανεξάρτητος έλεγχος. Αυτό διατηρεί τη διάταξη, τις ετικέτες, τα εικονίδια και τους κανόνες εξουσιοδότησης υπό τον έλεγχο της εφαρμογής σας, ενώ κάθε κουμπί ελέγχει την ίδια παρουσία Viewer:

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>

Η πλήρης εργαλειοθήκη αναφοράς αντιγράφει επίσης το wwwroot/js/viewerToolbar.js στην εφαρμογή κεντρικού υπολογιστή για βοηθητικά εργαλεία περιστροφής, μικρογραφίας, εκτύπωσης, πλήρους οθόνης, διάταξης και κατάστασης κουμπιών. Φορτώστε αυτό το αρχείο κεντρικού υπολογιστή μετά το Viewer.ReferenceScripts(...). Διατηρήστε το βοηθητικό πρόγραμμα και τη σήμανση <nav id="toolbar"> μαζί όταν αντιγράφετε την πλήρη υλοποίηση επίδειξης.

Διατηρήστε τη σειρά αρχικοποίησης του πακέτου που χρησιμοποιείται και στις δύο εφαρμογές αναφοράς:

  1. Εκδώστε CSS για τον Viewer και τις μονάδες με άδεια.
  2. Αποδώστε την εργαλειοθήκη Viewer, τις τοποθετήσεις Αναζήτησης/Σχολίου και την τοποθέτηση Viewer μαζί.
  3. Εκδώστε scripts για τον Viewer και τις μονάδες με άδεια.
  4. Φορτώστε το viewerToolbar.js της εφαρμογής κεντρικού υπολογιστή.
  5. Αρχικοποιήστε το docViewer και διατηρήστε το προκύπτον objViewer.
  6. Αρχικοποιήστε κάθε ταινία Αναζήτησης ή Σχολίου με άδεια.
  7. Κλήστε attach(objViewer) σε κάθε ταινία.
  8. Ανοίξτε το έγγραφο και διατηρήστε το token του για αιτήματα Viewer και μονάδων.

Doconut.TestApp.Distributed διατηρεί αυτήν την ακριβή σύνθεση UI και το ίδιο βοηθητικό πρόγραμμα εργαλειοθήκης Viewer. Η πρόσθετη τιμή αιτήματος access και οι ρυθμίσεις επανάληψης ασύγχρονης απόδοσης ανήκουν στη διανεμημένη μεταφορά· δεν αλλάζουν τον τρόπο συναρμολόγησης του Viewer, της εργαλειοθήκης ή των ταινιών.

Οι προστασίες στην πλευρά του διακομιστή είναι σημαντικές: όταν μια προαιρετική δυνατότητα δεν είναι διαθέσιμη, το script της δεν εκδίδεται, έτσι η λειτουργία του πρόσθετου jQuery δεν υπάρχει.

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>

Και τα δύο ενσωματωμένα συστατικά δημιουργούν το δικό τους DOM ταινίας. Η Αναζήτηση περιλαμβάνει ομάδες Find, Options και Results. Το Σχόλιο περιλαμβάνει τα εργαλεία συγγραφής, ελέγχους στυλ, ενέργειες αποθήκευσης και προαιρετικές ενέργειες εξαγωγής/εικόνας. Οι μπαρ εκθέτουν open(), close(), reset() και isOpen()· πάντα καλέστε attach(objViewer) μία φορά μετά τη δημιουργία τους.

Το παράδειγμα παραπάνω παραλείπει προαιρετικές κλήσεις κεντρικού υπολογιστή και τελικά σημεία εξαγωγής/εικόνας Σχολίου για να κρατήσει την εκκίνηση ελάχιστη. Δείτε την Αναζήτηση και τις Σχόλια για τη πλήρη ρύθμιση ανά λειτουργία, ή τα Προσαρμοσμένα Θέματα για να μορφοποιήσετε ή να αντικαταστήσετε την εργαλειοθήκη Viewer που ανήκει στον κεντρικό υπολογιστή.

Άνοιγμα εγγράφου

Η πλευρά του διακομιστή είναι ένα σημείο λήψης: η ενσωματωμένη υπηρεσία Viewer ανοίγει το έγγραφο και επιστρέφει ένα token συνεδρίας.

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

Ο πελάτης λαμβάνει αυτό το token και το παραδίδει στο widget με objViewer.View(token):

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

Κλείσιμο του εγγράφου

Καλέστε objViewer.Close() όταν ο χρήστης αφήνει τον viewer ή ανοίγει ένα αντικαταστάσιμο έγγραφο. Σε ροές εργασίας που ελέγχονται από τον διακομιστή, το viewer.CloseDocument(token) αφαιρεί αμέσως τη cached συνεδρία, διακόπτει τη μηχανή απόδοσης, διαγράφει το σήμα ασφαλείας της και ανακαλεί το token. Η κυλιόμενη λήξη τελικά εκτελεί την ίδια εκκαθάριση, αλλά η ρητή κλείσιμο συνιστάται για μεγάλα έγγραφα.

Η ολοκληρωμένη ροή αιτήματος είναι:

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

Αντιμετωπίστε το token ως διακριτικό πρόσβασης: μην το καταγράφετε ποτέ, μην το αποθηκεύετε ποτέ, παραδώστε το μόνο στο widget. Αναγνωρίζει μια ενεργή συνεδρία εγγράφου στον διακομιστή και σταματά να λειτουργεί όταν η συνεδρία λήξει — ανοίξτε ξανά το έγγραφο για να λάβετε ένα νέο.

Εκτέλεση

Τοποθετήστε ένα PDF στο wwwroot/files/Sample.pdf, εκτελέστε dotnet run και ανοίξτε τη σελίδα που φιλοξενεί το widget. Η πρώτη σελίδα αποδίδεται στον viewer, με ένα πάνελ μικρογραφιών στα αριστερά. Αν δεν συμβαίνει, δείτε την Αντιμετώπιση προβλημάτων.

Τι λαμβάνετε χωρίς άδεια

Η έλλειψη άδειας δεν προκαλεί σφάλμα. Ο viewer αποδίδει κανονικά, αλλά κάθε σελίδα φέρει ένα υδατογράφημα αξιολόγησης. Δείτε τη Ρύθμιση Άδειας για το πώς το Doconut βρίσκει μια άδεια και τι αλλάζει όταν το κάνει.

Ήταν αυτή η σελίδα χρήσιμη;