Plugin de conversion

Convertir des documents en 24 formats cibles

Le plugin Converter transforme Doconut en un service de conversion de documents. Il fournit le moteur derrière la façade publique DocumentConverter et — en option — un widget intégré servi par DocImage.axd, vous permettant de convertir des documents depuis C#, depuis le widget, ou depuis une interface que vous créez vous‑même.

Installer le paquet

powershell
Install-Package Doconut.NETFramework.Converter

Conservez le paquet Converter à la même version que Doconut.NETFramework.

Enregistrer le plugin

Chaque plugin s’enregistre de la même manière : AddPlugin<TPlugin>() dans DoconutHost.Initialize.

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

Si aucune licence active n’accorde la capacité Converter — aucune licence, un fichier TRIAL hérité, ou une licence qui ne la possède pas — DoconutHost.Initialize lève une exception depuis Application_Start. Dans System.Web, cela signifie que chaque requête renvoie un 500 vide, et la raison n’apparaît que dans le journal d’événements Windows (source ASP.NET). Les licences temporaires Demo/NFR sont acceptées. Voir Configuration de licence.

Convertir depuis C#

Chaque conversion renvoie un MemoryStream recherchable positionné à 0. DocumentConverter est sans état : résolvez‑le depuis DoconutHost.Services où que vous en ayez besoin et réutilisez‑le librement.

csharp
// Resolve DocumentConverter from DoconutHost.Services; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);
csharp
// sourceExtension includes the leading dot. password is null unless the document is protected.
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);

Deux détails faciles à se tromper : sourceExtension dans la surcharge de flux doit inclure le point initial (".xlsx", pas "xlsx"), sinon la résolution échoue. Et malgré son nom, WordToHtmlAsync renvoie un Task<Stream>, pas un Task<string> — le document HTML (images intégrées en Base64) arrive sous forme de flux, comme tout autre résultat.

Dans un contrôleur MVC 5

Rendez l’action asynchrone et await la conversion :

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

Dans Web Forms : ne jamais bloquer une conversion

Une page Web Forms s’exécute dans un contexte de requête mono‑thread. ConvertAsync reprend sur ce même contexte lorsqu’il se termine, de sorte qu’une page qui attend de façon synchrone — .Result, .Wait(), .GetAwaiter().GetResult() — monopolise le thread dont la conversion a besoin pour se terminer. La requête ne revient jamais. Le navigateur reste en attente, IIS n’enregistre rien, et le reste du site continue de fonctionner, ce qui donne l’impression d’une conversion lente plutôt que d’un blocage.

Marquez la page Async="true" et exécutez la conversion comme une tâche asynchrone de page :

aspx
<%@ Page Language="C#" Async="true" CodeBehind="Convert.aspx.cs" Inherits="MyApp.Convert" %>
csharp
// Web Forms: the @Page directive needs Async="true", and the conversion runs as a page async task.
// Blocking on it instead (.Result, .Wait(), .GetAwaiter().GetResult()) deadlocks the request:
// it never returns, and nothing is logged.
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, not HttpContext.Current: after an await the latter can be null.
            Context.ApplicationInstance.CompleteRequest();
        }
    }));
}

Sans Async="true" dans la directive @Page, RegisterAsyncTask est silencieusement ignoré. Après un await, utilisez le Context de la page ; HttpContext.Current peut être null à cet endroit.

Formats cibles

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

Tous les formats source ne se convertissent pas en tous les formats cible : chaque famille de format source (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project, PSD, document web) possède son propre ensemble de cibles autorisées. Ne codez pas en dur cette énumération comme la liste des cibles de votre interface : ?convert=open renvoie les allowedTargets du fichier téléchargé, et c’est ce qui doit alimenter le sélecteur.

Widget intégrable

Les points de terminaison ?convert=open|run|download du widget sont fournis par DocImage.axd et sont désactivés par défaut. Activez‑les à côté de l’enregistrement du 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 lit l'intégralité du téléchargement avant que Doconut ne le voie : conservez maxRequestLength (KB) et
// maxAllowedContentLength (bytes) dans Web.config au-dessus du MaxUploadMb du 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>

Deux points à vérifier lorsque le widget se comporte mal :

  • basePath: '/DocImage.axd'. Le défaut du widget, /doconut, est le point de terminaison ASP.NET Core. Dans ce package, les points de terminaison sont le gestionnaire DocImage.axd provenant de Web.config.
  • Le script et les points de terminaison sont indépendants. Le module de ressources sert doconutConverter.js que le widget soit activé ou non. Sans AddConverterWidget(), le widget se charge, dessine sa zone de dépôt et apparaît parfaitement correct — et sa première action renvoie 404.

Limites de téléchargement

ASP.NET lit l’intégralité du corps de la requête avant que DocImage.axd ne s’exécute. Un téléchargement supérieur à MaxUploadMb mais inférieur aux limites de l’hôte renvoie le JSON 413 du widget (« File is too large. »). Un téléchargement dépassant les limites de l’hôte est d’abord rejeté par IIS, avec une page d’erreur que le widget ne peut pas lire. Conservez les deux limites d’hôte dans Web.config au-dessus du plafond du widget :

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

Personnaliser le widget

Options passées à Doconut.convert(selector, options) :

OptionTypeValeur par défautRemarques
basePathstring/doconutL'URL du point de terminaison. Définissez '/DocImage.axd' pour ce package
resPathstring/doconut-resAccepté pour la cohérence avec les autres widgets Doconut ; le widget de conversion ne construit aucune URL à partir de celui‑ci
maxUploadMbnumber25Vérification préliminaire côté client uniquement ; le serveur impose son propre plafond
licenseUrlstring | nullnullTransforme l’avertissement de filigrane sur l’écran de résultat en lien
labelsobject{}Remplace tout sous‑ensemble des chaînes anglaises du widget

Rappels :

RappelSe déclenche quandCharge utile
onReady()Le widget a affiché son écran de dépôt—
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open réussitJeton source, nombre de pages, extension source (sans point initial), cibles autorisées
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run réussitLa réponse d’exécution plus le target demandé
onDownload({ downloadName, downloadToken })L'utilisateur clique sur TéléchargerSe déclenche en même temps que le téléchargement natif du navigateur
onError({ phase, message })Une requête open ou run échouephase vaut 'open' ou 'run' ; message est l’erreur serveur sanitizée

Doconut.convert() renvoie l’instance du widget : reset() revient à l’écran de dépôt, loadFile(file) lance le flux avec un File, et destroy() le supprime.

Créez votre propre interface frontale

Le widget est un client pour ce contrat HTTP sur DocImage.axd :

ItinéraireObjectifRéponse réussie
POST /DocImage.axd?convert=open (multipart, champ file)Téléverser et ouvrir un document source200 — { token, pages, sourceExt, allowedTargets }
POST /DocImage.axd?token=<token>&convert=run&target=<ext>Convertir la source téléversée vers target200 — { downloadToken, resultToken, resultPages, downloadName, watermarked }
GET /DocImage.axd?convert=download&token=<downloadToken>Diffuser le fichier converti200 — le fichier, Content-Disposition: attachment

Les sources téléversées sont conservées pendant 30 minutes ; passé ce délai, run renvoie 404 et le fichier doit être rouvert. downloadToken bénéficie de sa propre fenêtre de 30 minutes lorsque la conversion se termine. resultToken est un jeton de visualisation ordinaire qui suit la durée de vie de la session du visualiseur.

sourceExt dans la réponse open ne comporte pas de point initial ("docx") — le contraire du paramètre sourceExtension de ConvertAsync.

ItinéraireStatutQuandCorps
n'importe lequel404Le widget n'est pas activé (AddConverterWidget() n'a jamais été appelé)statut uniquement
n'importe lequel405Verbe incorrect (open/run nécessitent POST, download nécessite GET)statut uniquement
open413Le téléversement dépasse MaxUploadMb (mais pas les limites IIS){ "error": "File is too large." }
open400Aucun corps multipart, aucun fichier, ou un type qui ne peut pas être converti{ "error": "..." }
open403Le type de fichier nécessite une capacité que la licence n'accorde pas{ "error": "..." }
run400Un jeton mal formé, un target inconnu, ou un target qui ne figure pas dans allowedTargets{ "error": "..." }
run404Le téléversement a expiré ou n'a jamais été ouvert{ "error": "Upload expired — please re-open the file." }
open, run500Le traitement a échoué{ "error": "<sanitized message>" }
download400 / 404Un jeton de téléchargement mal formé, inconnu ou expiréstatut uniquement

Propriété des ressources

L'appelant possède le MemoryStream renvoyé par une conversion et doit le libérer après l'avoir copié ou renvoyé (la méthode File(stream, …) de MVC le libère pour vous). Ne construisez ni ne libérez vous‑même DocumentConverter — son constructeur est interne.

Filigrane

État de la licenceDémarrageSortie de conversion
Licence de visualisation payée accordant ConverterDémarrePropre — watermarked: false
Licence temporaire/démo activeDémarreConvertit, avec le filigrane d'évaluation — watermarked: true
Aucune licence, un fichier TRIAL hérité, ou une licence sans ConverterApplication_Start lève une exception ; chaque requête renvoie un 500 vide—
Licence temporaire/démo expiréeDémarreConvertit, avec le filigrane d'évaluation — watermarked: true

Une intégration peut être construite et testée de bout en bout avec une licence d'évaluation avant l'achat — seuls les octets de sortie changent.

Dépannage

SymptômeVérification
Chaque requête renvoie un 500 vide après l'ajout du pluginLa licence accorde Converter — journal des événements Windows, source ASP.NET
La résolution de DocumentConverter lève une exceptionAddPlugin<ConverterPlugin>() se trouve dans DoconutHost.Initialize
Une conversion Web Forms ne renvoie jamaisLa page bloque sur ConvertAsync — utilisez Async="true" et RegisterAsyncTask
La conversion de flux indique que le format n'est pas pris en chargesourceExtension inclut le point initial
Le widget se charge mais ses requêtes renvoient 404AddConverterWidget() n'a pas été appelé, ou basePath n'est pas '/DocImage.axd'
Un gros téléversement affiche une page d'erreur IIS au lieu du message du widgetmaxRequestLength / maxAllowedContentLength sont inférieurs à MaxUploadMb
Un target est manquantUtilisez allowedTargets provenant de convert=open
Le téléchargement a expiréRefaites convert=open / convert=run ; les jetons sont temporaires de façon intentionnelle

Cette page était-elle utile ?