Come funziona il Viewer
Il ciclo di vita della richiesta del documento
Doconut rende i documenti come immagini paginate servite tramite middleware ASP.NET Core. Comprendere il ciclo di vita — apertura, token, richieste di pagina, chiusura — spiega quasi tutti i comportamenti che osserverai, inclusi i messaggi di errore.
I tre componenti in movimento
Viewer— il servizio pubblico che inietti. Apre i documenti e restituisce i token di sessione.- La sessione del documento — un oggetto lato server che contiene il documento caricato, indicizzato da un token in
IMemoryCache. - Il middleware Doconut — aggiunto da
UseDoconut(); risponde a ogni richiesta che il widget del browser effettua (pages,thumbnails,search,annotations, …), sempre autenticata dal token.
Viewer è senza stato — per progettazione
Viewer è sigillato, non mantiene alcuno stato del documento per richiesta, e deliberatamente non implementa IDisposable. Le sessioni vivono indipendentemente nel gestore delle sessioni e vengono pulite tramite la scadenza della cache o un CloseDocument(token) esplicito.
Non lo costruisci più. AddDoconut() lo registra come servizio transitorio; iniettalo ovunque ne abbia bisogno:
app.MapPost("/api/open", async (string fileName, Viewer viewer) =>
{
var token = await viewer.OpenDocumentAsync($"files/{fileName}");
return Results.Content(token, "text/plain");
});In un'applicazione MVC, prendilo come parametro del costruttore; in una vista Razor, usa
@inject Doconut.Viewer Viewer. Le cache di istanze Viewer possedute dall'applicazione non sono più necessarie — e non sono più corrette, perché non contengono nulla di valore da memorizzare.
Cosa succede all'interno di OpenDocumentAsync
- Filtro licenza. Una licenza rifiutata o scaduta per versione (in blacklist, manomessa, o una build al di fuori della finestra di aggiornamento della licenza) genera immediatamente un
LicenseException, con il motivo del rifiuto come messaggio — l'apertura non degrada mai silenziosamente per una licenza non valida (invece che assente). Una licenza Temporanea o di abbonamento scaduta per calendario è l'eccezione: non genera eccezione — degrada a un watermark. - Creazione della sessione. La factory del viewer seleziona il visualizzatore di formato corretto per l'estensione del file e carica il documento (vedi Rendering Pipeline). La sessione è memorizzata in
IMemoryCachesotto un nuovo token GUID con una scadenza scorrevole —DocOptions.TimeOutminuti, predefinito 60. Ogni richiesta di pagina resetta il timer. - Registrazione della sicurezza. Con
UnsafeMode = false(il valore predefinito), il token è legato alla sessione ASP.NET del chiamante: un marcatoresecure-{token}è scritto nella sessione, così solo la sessione del browser che ha aperto il documento può richiedere le sue pagine. - Il token viene restituito. È l'unica credenziale per tutto ciò che segue.
Non esiste un passaggio di riscaldamento separato. La libreria precedente esponeva InitCache() a questo scopo; non esiste più, e nulla lo sostituisce.
Le tre sovraccarichi differiscono solo nell'input: un percorso file, un percorso file più una configurazione per formato (PdfConfig, WordConfig, …), oppure un Stream più un FileInfo la cui estensione determina il rilevamento del formato.
Come il widget ottiene le pagine
Il widget client chiama il middleware Doconut con il token nella stringa di query. Ciò che fa il middleware dipende dalla richiesta:
| Query | Scopo |
|---|---|
?token=…&page=N | Immagine della pagina renderizzata (PNG) |
?token=…&page=N&thumb=1 | Miniatura |
?token=…&zoom=… | Rendering della pagina ingrandita |
?token=…&search=term | Ricerca full-text (con licenza) |
?token=…&bookmarks | Struttura del documento / segnalibri |
?token=…© / &showlinks / &fileFormat | Copia del testo, collegamenti ipertestuali e informazioni sul formato |
?token=…&meta | Metadati tecnici DICOM; restituisce 501 per una sessione DICOM su questo pacchetto |
?token=…&action=rotate/flip/close | Azioni di pagina e chiusura esplicita |
?token=…&AnnSave=… / &AnnLoad | Salva/carica annotazioni |
Ognuno di questi percorsi viene prima validato:
- No token → il middleware restituisce 404 (o un banner di versione quando
ShowDoconutInfo = true). - Unknown or expired token → un'immagine di errore con
Document session not found. Please re-open document. - Session middleware missing (con
UnsafeMode = false) → HTTP 500 conSession middleware not configured. Call UseSession() before UseDoconut(). - Token opened by a different browser session → un'immagine di errore con
You Are Not Authorized To View This Page.
Dove è montato il middleware
UseDoconut() risponde alle richieste che trasportano un token, ovunque lo monti. L'applicazione di riferimento mantiene la forma storica della richiesta DocImage.axd su un ramo MapWhen, così un client esistente continua a chiamare l'URL che ha sempre usato. Qualunque cosa tu scelga, il BasePath del client deve concordare con esso — vedi ViewerConfig.
Servire le pagine da storage condiviso invece che dal nodo di apertura è un'organizzazione completamente diversa; vedi Distributed Deployments.
Chiusura di un documento
viewer.CloseDocument(token);CloseDocument rimuove la sessione dalla cache (che elimina il motore del documento sottostante e libera immediatamente la sua memoria), elimina il marcatore secure-{token} e revoca il permesso di accesso. Chiamarlo è opzionale — la scadenza scorrevole esegue la stessa pulizia automaticamente — ma per documenti di grandi dimensioni è il modo corretto di rilasciare la memoria non appena l'utente ha finito.
Viene chiamato sull'Viewer iniettato. Il pattern precedente — costruire un Viewer a vita breve in un blocco using solo per chiudere un token — non ha un equivalente e non è necessario.
Conclusioni
- Un documento aperto = una sessione = un token. I token sono per sessione del browser, non URL globali.
- Il token scade su una finestra scorrevole; un viewer lasciato inattivo oltre
DocOptions.TimeOutnecessita di una riapertura. Viewerpuò essere iniettato e condiviso liberamente; le sessioni contengono tutto lo stato.
Questa pagina è stata utile?