Plugin di Conversione

Converti documenti in 24 formati di destinazione

Il plugin Converter trasforma Doconut in un servizio di conversione documenti. Fornisce il motore dietro la facciata pubblica DocumentConverter e — su opt-in — un widget pronto all'uso servito da DocImage.axd, così puoi convertire documenti da C#, dal widget o da un frontend che scrivi tu stesso.

Installa il pacchetto

powershell
Install-Package Doconut.NETFramework.Converter

Mantieni il pacchetto Converter alla stessa versione di Doconut.NETFramework.

Registra il plugin

Ogni plugin si registra allo stesso modo: AddPlugin<TPlugin>() in DoconutHost.Initialize.

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

Se nessuna licenza attiva concede la capacità Converter — nessuna licenza, un file legacy TRIAL o una licenza senza di essa — DoconutHost.Initialize genera un'eccezione da Application_Start. In System.Web ciò significa che ogni richiesta risponde con un 500 vuoto, e il motivo è presente solo nel registro eventi di Windows (origine ASP.NET). Le licenze temporanee Demo/NFR sono accettate. Vedi Impostazione Licenza.

Converti da C#

Ogni conversione restituisce un MemoryStream ricercabile posizionato a 0. DocumentConverter è senza stato: ottienilo da DoconutHost.Services ovunque ne abbia bisogno e riutilizzalo liberamente.

csharp
// Risolvi DocumentConverter da DoconutHost.Services; il suo costruttore è interno, quindi non crearlo mai con `new`.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension include il punto iniziale. password è null a meno che il documento non sia protetto.
Stream png = await converter.ConvertAsync(upload, ".xlsx", ConversionTarget.Png, password: null, ct: ct);
csharp
Stream html = await converter.WordToHtmlAsync("report.docx", ct);
csharp
Stream docx = await converter.HtmlToWordAsync(html, ConversionTarget.Docx, ct);

Due dettagli facili da sbagliare: sourceExtension nella sovraccarico di stream deve includere il punto iniziale (".xlsx", non "xlsx"), altrimenti non viene risolto. E nonostante il nome, WordToHtmlAsync restituisce Task<Stream>, non Task<string> — il documento HTML (immagini incorporate come Base64) arriva come stream, come tutti gli altri risultati.

In un controller MVC 5

Rendi l'azione asincrona e await la conversione:

csharp
[HttpPost]
public async Task<ActionResult> ToPdf(HttpPostedFileBase file)
{
    var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();
    Stream pdf = await converter.ConvertAsync(
        file.InputStream, Path.GetExtension(file.FileName), ConversionTarget.Pdf,
        password: null, ct: Response.ClientDisconnectedToken);
    return File(pdf, "application/pdf", Path.GetFileNameWithoutExtension(file.FileName) + ".pdf");
}

In Web Forms: non bloccare mai una conversione

Una pagina Web Forms viene eseguita in un contesto di richiesta a thread singolo. ConvertAsync riprende su quel contesto al completamento, quindi una pagina che lo attende in modo sincrono — .Result, .Wait(), .GetAwaiter().GetResult() — trattiene il thread stesso di cui la conversione ha bisogno per terminare. La richiesta non ritorna mai. Il browser continua a girare, IIS non registra nulla, e il resto del sito continua a funzionare, quindi sembra una conversione lenta piuttosto che un deadlock.

Imposta la pagina Async="true" ed esegui la conversione come un'attività asincrona della pagina:

aspx
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>
csharp
// Web Forms: la direttiva @Page richiede Async="true", e la conversione viene eseguita come attività asincrona della pagina.
// Bloccare su di essa invece (.Result, .Wait(), .GetAwaiter().GetResult()) blocca la richiesta:
// non ritorna mai, e nulla viene registrato.
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack) return;

    RegisterAsyncTask(new PageAsyncTask(async ct =>
    {
        var converter = Doconut.DoconutHost.Services.GetRequiredService<DocumentConverter>();

        using (var pdf = await converter.ConvertAsync(
                   Server.MapPath("~/App_Data/contract.docx"), ConversionTarget.Pdf, ct: ct))
        using (var ms = new MemoryStream())
        {
            if (pdf.CanSeek) pdf.Position = 0;
            await pdf.CopyToAsync(ms);

            Response.ContentType = "application/pdf";
            Response.AddHeader("Content-Disposition", "attachment; filename=contract.pdf");
            Response.BinaryWrite(ms.ToArray());
            // Context, non HttpContext.Current: dopo un await quest'ultimo può essere null.
            Context.ApplicationInstance.CompleteRequest();
        }
    }));
}

Senza Async="true" nella direttiva @Page, RegisterAsyncTask viene silenziosamente ignorato. Dopo un await, usa il Context della pagina; HttpContext.Current può essere null in quel contesto.

Formati di destinazione

text
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, Webp

Non tutte le sorgenti si convertono in tutti i formati di destinazione: ogni famiglia di formati della sorgente (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, web document) ha il proprio insieme di destinazioni consentite. Non codificare in modo fisso questo enum come elenco di destinazioni della tua UI: ?convert=open restituisce gli allowedTargets per il file caricato, ed è questo che dovrebbe guidare un selettore.

Widget integrabile

Gli endpoint ?convert=open|run|download del widget sono forniti da DocImage.axd e sono disattivati per impostazione predefinita. Abilitarli accanto alla registrazione del plugin:

csharp
Doconut.DoconutHost.Initialize(options =>
{
    options.LicensePath = HostingEnvironment.MapPath("~/wwwroot/Doconut.Viewer.lic");
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
// System.Web legge l'intero upload prima che Doconut lo veda: mantieni maxRequestLength (KB) e
// maxAllowedContentLength (byte) in Web.config sopra il MaxUploadMb del widget.
html
<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
  Doconut.convert('#doconut-convert', { basePath: '/DocImage.axd', maxUploadMb: 25 });
</script>

Due cose da verificare quando il widget si comporta in modo anomalo:

  • basePath: '/DocImage.axd'. Il valore predefinito del widget, /doconut, è l'endpoint ASP.NET Core. In questo pacchetto, gli endpoint sono il gestore DocImage.axd proveniente da Web.config.
  • Lo script e gli endpoint sono indipendenti. Il modulo di risorse serve doconutConverter.js indipendentemente dal fatto che il widget sia abilitato o meno. Senza AddConverterWidget(), il widget si carica, disegna la sua zona di rilascio e appare completamente corretto — e la sua prima azione restituisce 404.

Limiti di upload

ASP.NET legge l'intero corpo della richiesta prima che venga eseguito DocImage.axd. Un upload superiore a MaxUploadMb ma inferiore ai limiti dell'host genera il JSON 413 del widget ("File is too large."). Un upload superiore ai limiti dell'host viene prima rifiutato da IIS, con una pagina di errore che il widget non può leggere. Mantieni entrambi i limiti dell'host in Web.config sopra il limite del widget:

xml
<system.web>
  <httpRuntime maxRequestLength="30720" />           <!-- KILOBYTE: 30 MB -->
</system.web>
<system.webServer>
  <security>
    <requestFiltering>
      <requestLimits maxAllowedContentLength="31457280" />  <!-- BYTE: 30 MB -->
    </requestFiltering>
  </security>
</system.webServer>

Personalizza il widget

Opzioni passate a Doconut.convert(selector, options):

OpzioneTipoPredefinitoNote
basePathstring/doconutL'URL dell'endpoint. Imposta '/DocImage.axd' in questo pacchetto
resPathstring/doconut-resAccettato per coerenza con gli altri widget Doconut; il widget di conversione non costruisce alcun URL da esso
maxUploadMbnumber25Solo controllo preliminare lato client; il server applica il proprio limite
licenseUrlstring | nullnullTrasforma l'avviso di filigrana nella schermata del risultato in un collegamento
labelsobject{}Sovrascrive qualsiasi sottoinsieme delle stringhe inglesi del widget

Callback:

CallbackQuando scattaDati
onReady()Il widget ha renderizzato la sua schermata di rilascio—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open ha avuto successoToken della sorgente, numero di pagine, estensione della sorgente (senza punto iniziale), destinazioni consentite
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run ha avuto successoLa risposta del run più il target richiesto
onDownload({ downloadName, downloadToken })L'utente fa clic su DownloadViene attivato insieme al download del browser
onError({ phase, message })Una richiesta di apertura o esecuzione falliscephase è 'open' o 'run'; message è l'errore del server sanificato

Doconut.convert() restituisce l'istanza del widget: reset() ritorna alla schermata di rilascio, loadFile(file) avvia il flusso con un File, e destroy() lo rimuove.

Crea il tuo frontend

Il widget è un client per questo contratto HTTP su DocImage.axd:

PercorsoScopoRisposta di successo
POST /DocImage.axd?convert=open (multipart, field file)Carica e apri un documento sorgente200 — { token, pages, sourceExt, allowedTargets }
POST /DocImage.axd?token=<token>&convert=run&target=<ext>Converti il sorgente caricato in target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET /DocImage.axd?convert=download&token=<downloadToken>Trasmetti il file convertito200 — il file, Content-Disposition: attachment

I sorgenti caricati vengono conservati per 30 minuti; dopo di ciò, run restituisce 404 e il file deve essere riaperto. downloadToken ha una propria finestra di 30 minuti al completamento della conversione. resultToken è un normale token del visualizzatore che segue la durata della sessione del visualizzatore.

sourceExt nella risposta open non ha il punto iniziale ("docx") — l'opposto del parametro sourceExtension di ConvertAsync.

PercorsoStatoQuandoCorpo
qualsiasi404Il widget non è abilitato (AddConverterWidget() non è mai stato chiamato)solo lo stato
qualsiasi405Verbo errato (open/run richiedono POST, download richiede GET)solo lo stato
open413Il caricamento supera MaxUploadMb (ma non i limiti di IIS){ "error": "File is too large." }
open400Nessun corpo multipart, nessun file, o un tipo che non può essere convertito{ "error": "..." }
open403Il tipo di file richiede una capacità che la licenza non concede{ "error": "..." }
run400Un token malformato, un target sconosciuto, o un target non presente in allowedTargets{ "error": "..." }
run404Il caricamento è scaduto o non è mai stato aperto{ "error": "Upload expired — please re-open the file." }
open, run500Elaborazione fallita{ "error": "<sanitized message>" }
download400 / 404Un token di download malformato, sconosciuto o scadutosolo lo stato

Proprietà delle risorse

Il chiamante possiede lo MemoryStream restituito da una conversione e dovrebbe rilasciarlo dopo averlo copiato o restituito (MVC's File(stream, …) lo rilascia per te). Non costruire né rilasciare DocumentConverter manualmente — il suo costruttore è interno.

Filigrana

Stato della licenzaAvvioOutput della conversione
Licenza viewer a pagamento che concede ConverterAvviaPulito — watermarked: false
Licenza Temporanea/Demo attivaAvviaConverte, con la filigrana di valutazione — watermarked: true
Nessuna licenza, un file legacy TRIAL, o una licenza senza ConverterApplication_Start genera un'eccezione; ogni richiesta restituisce un 500 vuoto—
Licenza Temporanea/Demo scadutaAvviaConverte, con la filigrana di valutazione — watermarked: true

Un'integrazione può essere costruita e testata end to end con una licenza di valutazione prima dell'acquisto — cambiano solo i byte di output.

Risoluzione dei problemi

SintomoVerifica
Ogni richiesta restituisce un 500 vuoto dopo aver aggiunto il pluginLa licenza concede Converter — registro eventi di Windows, sorgente ASP.NET
La risoluzione di DocumentConverter genera un'eccezioneAddPlugin<ConverterPlugin>() si trova in DoconutHost.Initialize
Una conversione Web Forms non restituisce maiLa pagina si blocca su ConvertAsync — usa Async="true" e RegisterAsyncTask
La conversione in streaming segnala che il formato non è supportatosourceExtension include il punto iniziale
Il widget si carica ma le sue richieste restituiscono 404AddConverterWidget() non è stato chiamato, o basePath non è '/DocImage.axd'
Un grande caricamento mostra una pagina di errore IIS invece del messaggio del widgetmaxRequestLength / maxAllowedContentLength sono inferiori a MaxUploadMb
Manca un targetUsa allowedTargets da convert=open
Il download è scadutoRipeti convert=open / convert=run; i token sono temporanei di proposito

Questa pagina è stata utile?