Πώς Λειτουργεί ο Viewer

Ο κύκλος ζωής των αιτήσεων εγγράφου

Το Doconut αποδίδει έγγραφα ως σελιδοποιημένες εικόνες που εξυπηρετούνται μέσω του middleware του ASP.NET Core. Η κατανόηση του κύκλου ζωής — άνοιγμα, διακριτικό, αιτήματα σελίδων, κλείσιμο — εξηγεί σχεδόν κάθε συμπεριφορά που θα παρατηρήσετε, συμπεριλαμβανομένων των μηνυμάτων σφάλματος.

Τα τρία κινούμενα μέρη

  • Viewer — η δημόσια υπηρεσία που ενσωματώνετε. Ανοίγει έγγραφα και επιστρέφει διακριτικά συνεδρίας.
  • Η συνεδρία εγγράφου — ένα αντικείμενο στο διακομιστή που κρατά το φορτωμένο έγγραφο, κλειδωμένο με ένα διακριτικό στο IMemoryCache.
  • Το Doconut middleware — προστίθεται με UseDoconut()· απαντά σε κάθε αίτημα που κάνει το widget του προγράμματος περιήγησης (pages, thumbnails, search, annotations, …), πάντα πιστοποιημένο με το διακριτικό.

Το Viewer είναι χωρίς κατάσταση — κατά σχεδιασμό

Το Viewer είναι κλειστό (sealed), δεν διατηρεί κατάσταση εγγράφου ανά αίτημα και σκόπιμα δεν υλοποιεί το IDisposable. Οι συνεδρίες ζουν ανεξάρτητα στον διαχειριστή συνεδριών και καθαρίζονται με τη λήξη της προσωρινής μνήμης ή με ένα ρητό CloseDocument(token).

Δεν το δημιουργείτε πλέον. Το AddDoconut() το καταχωρεί ως υπηρεσία μεταβλητής διάρκειας· ενσωματώστε το όπου το χρειάζεστε:

csharp
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
    var token = await viewer.OpenDocumentAsync($"files/{fileName}");
    return Results.Content(token, "text/plain");
});

Σε μια εφαρμογή MVC, πάρτε το ως παράμετρο κατασκευής· σε μια Razor προβολή, χρησιμοποιήστε @inject Doconut.Viewer Viewer. Οι προσωρινές μνήμες που διαχειρίζονται οι εφαρμογές για στιγμιότυπα του Viewer δεν χρειάζονται πλέον — και δεν είναι πλέον σωστές, επειδή δεν κρατούν τίποτα που αξίζει να αποθηκευτεί.

Τι συμβαίνει μέσα στο OpenDocumentAsync

  1. Πύλη άδειας. Μια άδεια που απορρίπτεται ή έχει λήξει η έκδοση (μαύρη λίστα, παραποιημένη ή μια έκδοση εκτός του παραθύρου ενημέρωσης της άδειας) ρίχνει αμέσως ένα LicenseException, με τον λόγο απόρριψης ως μήνυμα — το άνοιγμα δεν υποβαθμίζεται σιωπηρά για μια μη έγκυρη (αντί για απουσία) άδεια. Μία ημερολογιακά ληγμένη Προσωρινή ή συνδρομητική άδεια αποτελεί εξαίρεση: δεν ρίχνει — υποβαθμίζεται σε υδατογράφημα.
  2. Δημιουργία συνεδρίας. Η εργοστασιακή μονάδα του viewer επιλέγει τον κατάλληλο viewer μορφής για την επέκταση του αρχείου και φορτώνει το έγγραφο (δείτε το Rendering Pipeline). Η συνεδρία αποθηκεύεται στο IMemoryCache κάτω από ένα νέο GUID διακριτικό με ολική λήξη — DocOptions.TimeOut λεπτά, προεπιλογή 60. Κάθε αίτημα σελίδας επαναφέρει το χρονόμετρο.
  3. Καταγραφή ασφαλείας. Με UnsafeMode = false (η προεπιλογή), το διακριτικό συνδέεται με τη συνεδρία ASP.NET του καλούντος: ένα δείκτη secure-{token} γράφεται στη συνεδρία, ώστε μόνο η συνεδρία του προγράμματος περιήγησης που άνοιξε το έγγραφο να μπορεί να ζητήσει τις σελίδες του.
  4. Το διακριτικό επιστρέφεται. Είναι το μοναδικό διαπιστευτήριο για όλα όσα ακολουθούν.

Δεν υπάρχει ξεχωριστό βήμα προθέρμανσης. Η προηγούμενη βιβλιοθήκη εκτέλεσε InitCache() για αυτόν τον σκοπό· δεν υπάρχει πλέον, και τίποτα δεν το αντικαθιστά.

Οι τρεις υπερφορτώσεις διαφέρουν μόνο στην είσοδο: μια διαδρομή αρχείου, μια διαδρομή αρχείου συν μια διαμόρφωση ανά μορφή (PdfConfig, WordConfig, …), ή ένα Stream συν ένα FileInfo του οποίου η επέκταση καθορίζει την ανίχνευση μορφής.

Πώς το widget λαμβάνει σελίδες

Το widget του πελάτη καλεί το Doconut middleware με το διακριτικό στη συμβολοσειρά ερωτήματος. Η ενέργεια του middleware εξαρτάται από το αίτημα:

ΕρώτημαΣκοπός
?token=…&page=NΑπόδοση εικόνας σελίδας (PNG)
?token=…&page=N&thumb=1Μικρογραφία
?token=…&zoom=…Απόδοση σελίδας με ζουμ
?token=…&search=termΑναζήτηση πλήρους κειμένου (με πύλη άδειας)
?token=…&bookmarksΔομή εγγράφου/σημειώσεις
?token=…&copy / &showlinks / &fileFormatΑντιγραφή κειμένου, υπερσυνδέσμους και πληροφορίες μορφής
?token=…&metaΤεχνικά μεταδεδομένα DICOM· επιστρέφει 501 για μια συνεδρία DICOM σε αυτό το πακέτο
?token=…&action=rotate/flip/closeΕνέργειες σελίδας και ρητό κλείσιμο
?token=…&AnnSave=… / &AnnLoadΑποθήκευση/φόρτωση σχολίων

Κάθε μία από αυτές τις διαδρομές επικυρώνεται πρώτα:

  • Χωρίς διακριτικό → το middleware επιστρέφει 404 (ή μια μπάνερ έκδοσης όταν ShowDoconutInfo = true).
  • Άγνωστο ή ληγμένο διακριτικό → εικόνα σφάλματος με Document session not found. Please re-open document.
  • Απουσία middleware συνεδρίας (με UnsafeMode = false) → HTTP 500 με Session middleware not configured. Call UseSession() before UseDoconut().
  • Διακριτικό ανοιγμένο από διαφορετική συνεδρία προγράμματος περιήγησης → εικόνα σφάλματος με You Are Not Authorized To View This Page.

Πού τοποθετείται το middleware

UseDoconut() απαντά σε αιτήματα που περιέχουν διακριτικό, όπου και αν το τοποθετήσετε. Η εφαρμογή αναφοράς διατηρεί το ιστορικό σχήμα αιτήματος DocImage.axd σε κλάδο MapWhen, ώστε ένας υπάρχων πελάτης να συνεχίζει να καλεί το URL που πάντα έκανε. Ό,τι και αν επιλέξετε, το BasePath του πελάτη πρέπει να συμφωνεί με αυτό — δείτε ViewerConfig.

Η εξυπηρέτηση σελίδων από κοινόχρηστη αποθήκευση αντί για τον κόμβο ανοίγματος είναι μια εντελώς διαφορετική διάταξη· δείτε Distributed Deployments.

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

csharp
viewer.CloseDocument(token);

CloseDocument αφαιρεί τη συνεδρία από την προσωρινή μνήμη (που απελευθερώνει τη βασική μηχανή εγγράφου και ελευθερώνει τη μνήμη της άμεσα), διαγράφει το δείκτη secure-{token} και ανακαλεί την άδεια πρόσβασης. Η κλήση του είναι προαιρετική — η ολική λήξη κάνει την ίδια εκκαθάριση αυτόματα — αλλά για μεγάλα έγγραφα είναι ο ευγενικός τρόπος να απελευθερώσετε μνήμη τη στιγμή που ο χρήστης ολοκληρώνει.

Καλείται στο ενσωματωμένο Viewer. Το προηγούμενο πρότυπο — δημιουργία ενός βραχύβιας Viewer σε μπλοκ using μόνο για να κλείσει ένα διακριτικό — δεν έχει ισοδύναμο και δεν είναι απαραίτητο.

Συμπεράσματα

  • Ένα ανοιχτό έγγραφο = μία συνεδρία = ένα διακριτικό. Τα διακριτικά είναι ανά συνεδρία προγράμματος περιήγησης, όχι παγκόσμια URLs.
  • Το διακριτικό λήγει σε ολική χρονική περίοδο· ένας viewer που παραμένει αδρανής πέρα από το DocOptions.TimeOut χρειάζεται νέο άνοιγμα.
  • Το Viewer μπορεί να ενσωματωθεί και να μοιραστεί ελεύθερα· οι συνεδρίες μεταφέρουν όλη την κατάσταση.

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