Konverteringsplugin

Konvertera dokument till 24 målformat

Konverteringspluginet gör Doconut till en dokumentkonverteringstjänst. Det bidrar med motorn bakom den offentliga DocumentConverter‑fasaden och – vid behov – en färdig widget med eget HTTP‑kontrakt, så att du kan konvertera dokument från C#, från widgeten eller från ett eget frontend‑gränssnitt som du bygger själv.

Install the package

Install the latest stable Converter plugin:

bash
dotnet add package Doconut.NET8.Converter

To pin the plugin to the current 26.7.0 release, pass the version separately:

bash
dotnet add package Doconut.NET8.Converter --version 26.7.0

Keep the Converter package at the same version as Doconut.NET8. The package ID is Doconut.NET8.Converter; .26.7.0 appears only in the downloaded .nupkg filename.

Register the plugin

There is no AddConverter() method — Doconut's plugin model is uniform. Every plugin, Converter included, registers the same way: call AddPlugin<TPlugin>() inside AddDoconut(). ConverterPlugin ships in its own NuGet package, Doconut.NET8.Converter, installed alongside the base viewer package.

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
});

This call throws at startup for a missing license, a legacy TRIAL file, or a non-temporary license that does not grant the Converter capability — an InvalidOperationException raised from inside AddDoconut(), before the app serves requests. Temporary Demo/NFR registrations are accepted; after their calendar expiry, conversion remains available with watermarked output. There is no silent free tier. See Licensinställning for how licenses are loaded.

Convert from C#

Every conversion returns a seekable MemoryStream positioned at 0, ready to read or copy immediately. Resolve DocumentConverter from DI wherever you need it — it is stateless by design, so a single instance is safe to reuse across requests.

csharp
// Inject DocumentConverter; 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);

Two details that are easy to get wrong: sourceExtension on the stream overload must include the leading dot (".xlsx", not "xlsx") — the converter matches it against the format catalog and a bare extension won't resolve. And despite its name, WordToHtmlAsync returns Task<Stream>, not Task<string> — you get the HTML document (images embedded as Base64) as a stream, the same as every other conversion result.

Target formats

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

Not every source converts to every target — the plugin maps each source's format family (Word, Excel, PowerPoint, PDF, CAD, Image, Email, Diagram, Project/Task, PSD, web document) to its own fixed set of allowed targets. Don't hardcode this enum as your UI's target list: ?convert=open returns the actual allowedTargets for whatever file was just uploaded, and that's what should drive a picker.

Drop-in widget

The widget's ?convert=open|run|download endpoints are opt-in and disabled out of the box — secure by default. Enable them server-side, alongside the plugin registration:

csharp
builder.Services.AddDoconut(options =>
{
    options.LicensePath = "Doconut.Viewer.lic";
    options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
    options.AddConverterWidget(widget =>
    {
        widget.MaxUploadMb = 25;
    });
});
html
<div id="doconut-convert"></div>
<script src="/doconut-res/js/doconutConverter.js"></script>
<script>
  Doconut.convert('#doconut-convert', { basePath: '/doconut', resPath: '/doconut-res', maxUploadMb: 25 });
</script>

Without AddConverterWidget(), the three ?convert= endpoints answer 404 — but the JS file itself is still served regardless (it's a plain embedded static resource; only the endpoints it talks to are gated). AddConverterWidget() still requires the Converter plugin to be registered and a license that grants Converter — it doesn't grant conversion rights on its own.

Customize the widget

Init options passed to Doconut.convert(selector, options):

AlternativTypStandardAnteckningar
basePathstring/doconutBas‑sökväg för ?convert=‑endpunkterna; den måste matcha den ASP.NET‑gren där UseDoconut() faktiskt är monterad (vanligtvis koordinerad via MiddlewarePath)
resPathstring/doconut-resAccepterad för konfigurationskonsekvens med andra Doconut‑widgets; konverteringswidgeten bygger för närvarande ingen URL från detta
maxUploadMbnumber25Endast en klient‑sidig förkontroll — avvisar en för stor fil innan uppladdning. Servern har sin egen gräns och svarar med 413 om den överskrids
licenseUrlstring | nullnullNär satt, gör vattenstämpel‑meddelandet på resultatskärmen till en länk till denna URL
labelsobject{}Åsidosätter valfri delmängd av widgetens engelska standardsträngar (drop‑text, knappar, aria‑live‑meddelanden, felmeddelanden)

Callbacks:

ÅteruppringningNär den triggasPayload
onReady()Widgeten har renderat sin idle/drop‑skärm
onSourceLoaded({ token, pages, sourceExt, allowedTargets })?convert=open lyckassessions‑token, sidantal, källfilens extension (utan inledande punkt), lista över tillåtna mål
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target })?convert=run lyckassamma fält som i run‑svaret, plus det begärda target‑värdet
onDownload({ downloadName, downloadToken })Användaren klickar på Nedladdnings‑länkenavfyras tillsammans med webbläsarens inbyggda nedladdning — den avbryter eller ersätter den inte
onError({ phase, message })En open‑ eller run‑begäran misslyckasphase är 'open' eller 'run'; message är det sanerade server‑felet (eller ett klient‑sidigt meddelande för för‑kontrollen av uppladdnings‑storlek)

Doconut.convert() returns the widget instance itself — hang onto it to drive the widget programmatically:

javascript
const conv = Doconut.convert('#doconut-convert', { basePath: '/doconut' });
conv.reset();         // back to the idle/drop screen; does not re-fire onReady
conv.loadFile(file);  // starts the flow with a File object; no-op unless currently idle
conv.destroy();       // removes listeners, empties the mount; the instance is unusable after this

Build your own frontend

The widget is just a client for this HTTP contract — build your own frontend against it directly for a different UX. All three routes sit under the ASP.NET branch where UseDoconut() is mounted (normally /doconut):

RuttSyfteFramgångssvar
POST ?convert=open (multipart, field file)Ladda upp och öppna ett källdokument för förhandsgranskning200{ token, pages, sourceExt, allowedTargets }
POST ?token=<token>&convert=run&target=<ext>Konvertera den lagrade källan till target200{ downloadToken, resultToken, resultPages, downloadName, watermarked }
GET ?convert=download&token=<downloadToken>Strömma den konverterade filen200 — fil‑bytes, Content-Disposition: attachment, Cache-Control: no-store

Uploaded source bytes are stashed server-side with a 30‑minute TTL; once that window lapses, run answers 404 and the file must be re‑opened. The converted result lives in the same stash — downloadToken gets its own fresh 30‑minute window when the conversion completes — while resultToken is an ordinary viewer session token whose lifetime follows the viewer's session cache, independent of the stash.

sourceExt in the open response has no leading dot (e.g. "docx") — the opposite convention from the sourceExtension parameter on DocumentConverter.ConvertAsync, which requires one.

Failure modes, grouped by route:

RuttStatusNärBody
any404Widgeten är inte aktiverad (AddConverterWidget() har aldrig anropats) — kontrolleras innan någon av de tre rutterna dispatchasendast status
any405Fel HTTP‑verb (open/run kräver POST; download kräver GET)endast status
open413Uppladdad fil överskrider MaxUploadMb{ "error": "File is too large." }
open400Ingen multipart‑kropp, ingen fil, eller en käll‑extension som inte kan konverteras{ "error": "..." }
run400Felaktig token (inte ett GUID), eller ett target som inte kan parsas till en ConversionTarget{ "error": "Invalid token." } / { "error": "Unknown target format." }
run400target finns inte i källans allowedTargets{ "error": "That target format is not available for this file." }
run404Den lagrade uppladdningen har gått ut (30‑minuters TTL) eller token har aldrig öppnats{ "error": "Upload expired — please re-open the file." }
open, run500Intern bearbetning misslyckades{ "error": "<sanitized message>" } — sanerat på samma sätt som alla andra Doconut‑felvägar; läcker aldrig interna motor‑namn
download400Felaktig token (inte ett GUID)endast status
download404Okänd eller utgången nedladdningstokenendast status

Resource ownership

The converter returns a seekable MemoryStream positioned at zero. The caller owns that stream and should dispose it after copying or returning its contents. The DocumentConverter service itself is stateless and is resolved from dependency injection; do not construct or dispose the service manually.

For the web widget, the upload and download stashes have independent 30‑minute TTLs. A viewer resultToken follows the viewer session lifetime instead. Closing a viewer result does not delete a still‑valid download stash, and resetting the browser widget does not extend either TTL.

Troubleshooting

SymptomCheck
Resolving DocumentConverter failsConverterPlugin registration happened inside AddDoconut()
Application fails during startupThe loaded license grants Converter
Stream conversion says the format is unsupportedsourceExtension includes the leading dot
Widget JavaScript loads but requests return 404AddConverterWidget() was not called
Widget requests use the wrong URLbasePath matches the branch where UseDoconut() is mapped
Target is missingUse allowedTargets returned by convert=open; not every source supports every enum target
Download expiredRepeat convert=open/convert=run; stash tokens are intentionally temporary

Watermarking

With ConverterPlugin registered, the host's license is in one of three states:

License stateStartup gateConversion output
Paid viewer license granting Converter, within its validity periodPassesClean — watermarked: false
Active evaluation (demo/NFR) licensePassesConverts successfully, stamped with the evaluation watermark — watermarked: true
Unlicensed, a legacy TRIAL file, or a non-temporary license that doesn't grant ConverterApp never starts — the startup gate described above throws
Expired Temporary/Demo licenseRegistration survives expiryConverts with the evaluation watermark — watermarked: true

Both call paths compute the flag from the same rule: the DocumentConverter C# facade derives it internally from the license's IsViewerLicensed and IsTemporary state, and the widget's ?convert=run handler makes the equivalent check (IsViewerLicensed && !IsTrial && !IsTemporary) to fill the watermarked field it returns. An integration can be built and tested end-to-end on an evaluation license before purchase — only the output bytes change.

Var den här sidan till hjälp?