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

Αποδώστε το πρώτο σας έγγραφο σε MVC 5 ή Web Forms

Αυτός ο οδηγός παίρνει μια εφαρμογή ASP.NET σε .NET Framework 4.7.2 από ένα εγκατεστημένο πακέτο σε ένα έγγραφο που αποδίδεται στον περιηγητή: Global.asax, ένα ανοιχτό endpoint, τα περιουσιακά στοιχεία του προβολέα, το widget και το token που τα συνδέει. Υποθέτει ότι οι εγγραφές Web.config από την Εγκατάσταση είναι σε θέση — χωρίς τον χειριστή DocImage.axd και το module πόρων, τίποτα παρακάτω δεν μπορεί να φτάσει στον διακομιστή.

Συνθέστε το 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 endpoints εκτός δρομολόγησης.
    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 routing μακριά από DocImage.axd και /doconut-res/*, που εξυπηρετούνται από τον χειριστή και το module. Μια εφαρμογή Web Forms δεν έχει δρομολογήσεις MVC και δεν χρειάζεται αυτή τη γραμμή.
  • DoconutHost.Shutdown σταματά την παρασκηνιακή εργασία του Doconut και απελευθερώνει τις υπηρεσίες του όταν η δεξαμενή εφαρμογών επανακυκλώνεται. Είναι ασφαλές να κληθεί ακόμη και αν το Initialize δεν εκτελέστηκε ποτέ.

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

Το άνοιγμα ενός εγγράφου επιστρέφει ένα αδιαφανές token. Το widget στέλνει αυτό το token με κάθε αίτημα σελίδας.

Στο MVC 5, μια ενέργεια ελεγκτή επιλύει την υπηρεσία Viewer από το DoconutHost.Services — το MVC 5 δεν έχει ενσωμάτωση μέσω κατασκευής για αυτήν:

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

    // Το token είναι αδιαφανές - δώστε το στον 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"));
}

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

Αναφορά των πόρων του προβολέα

Viewer.ReferenceCss και Viewer.ReferenceScripts εκδίδουν τις ετικέτες <link> και <script> για τα ενσωματωμένα στοιχεία, με σειρά εξάρτησης, που δείχνουν στο /doconut-res/. Το widget είναι ένα πρόσθετο 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. Και οι δύο μέθοδοι παραλείπουν τα αρχεία μιας κορδέλας όταν η άδεια δεν παρέχει αυτή τη δυνατότητα· ο προβολέας εξακολουθεί να ξεκινά.

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

Η επιφάνεια απόδοσης είναι δύο ενσωματωμένα divs:

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>

Αρχικοποίηση του προβολέα και εμφάνιση του εγγράφου

Μετά τα σενάρια του προβολέα, δημιουργήστε το widget, μετά δώστε του το token:

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). Μια εσφαλμένη επιλογή αγνοείται, και το widget χρησιμοποιεί την προεπιλογή του.

Η εναλλακτική μιας γραμμής

Για μια σελίδα που χρειάζεται μόνο να εμφανίσει ένα έγγραφο, χωρίς δική σας γραμμή εργαλείων, Viewer.RenderViewer δημιουργεί ολόκληρο το σενάριο αρχικοποίησης — docViewer(...) με BasePath: '/' και ResPath: 'doconut-res/images', στη συνέχεια .View(token). Υπάρχει μόνο σε αυτό το πακέτο:

csharp
// Κώδικας-πίσω Web Forms, μετά το άνοιγμα του εγγράφου
ViewerInit = viewer.RenderViewer("div_ctlDoc", Token);
html
<div id="div_ctlDoc" style="height: 100vh"></div>
<%= ViewerScripts %>
<%= ViewerInit %>

Περάστε ένα ViewerConfig ως τρίτο όρισμα για να αλλάξετε το ζουμ, την προσαρμογή ή το πάνελ μικρογραφιών. Επειδή το παραγόμενο σενάριο δεν διατηρεί αναφορά στον προβολέα, χρησιμοποιήστε την χειροκίνητη αρχικοποίηση παραπάνω όταν η σελίδα σας χρειάζεται τη δική της γραμμή εργαλείων.

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

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

Εκτέλεση

Τοποθετήστε ένα PDF στο ~/files/Sample.pdf, ξεκινήστε τον ιστότοπο σε IIS Express (F5 στο Visual Studio) και ανοίξτε τη σελίδα που φιλοξενεί το widget. Η πρώτη σελίδα αποδίδεται, με μικρογραφίες στα αριστερά. Αν δεν συμβαίνει, δείτε Αντιμετώπιση προβλημάτων.

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

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

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