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:
dotnet add package Doconut.NET8.ConverterTo pin the plugin to the current 26.7.0 release, pass the version separately:
dotnet add package Doconut.NET8.Converter --version 26.7.0Keep 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.
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
TRIALfile, or a non-temporary license that does not grant theConvertercapability — anInvalidOperationExceptionraised from insideAddDoconut(), 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.
// Inject DocumentConverter; its constructor is internal, so never `new` it.
Stream pdf = await converter.ConvertAsync("contract.docx", ConversionTarget.Pdf, ct: ct);// 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);Stream html = await converter.WordToHtmlAsync("report.docx", ct);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
Pdf, Docx, Doc, Html, Xlsx, Pptx, Png, Jpeg, Csv, Tiff, Bmp, Gif, Svg, Xml,
Txt, Xls, Jp2, Rtf, Odt, Ods, Odp, Epub, Xps, WebpNot 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:
builder.Services.AddDoconut(options =>
{
options.LicensePath = "Doconut.Viewer.lic";
options.AddPlugin<Doconut.Plugins.Converter.ConverterPlugin>();
options.AddConverterWidget(widget =>
{
widget.MaxUploadMb = 25;
});
});<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):
| Alternativ | Typ | Standard | Anteckningar |
|---|---|---|---|
basePath | string | /doconut | Bas‑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) |
resPath | string | /doconut-res | Accepterad för konfigurationskonsekvens med andra Doconut‑widgets; konverteringswidgeten bygger för närvarande ingen URL från detta |
maxUploadMb | number | 25 | Endast 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 |
licenseUrl | string | null | null | När satt, gör vattenstämpel‑meddelandet på resultatskärmen till en länk till denna URL |
labels | object | {} | Åsidosätter valfri delmängd av widgetens engelska standardsträngar (drop‑text, knappar, aria‑live‑meddelanden, felmeddelanden) |
Callbacks:
| Återuppringning | När den triggas | Payload |
|---|---|---|
onReady() | Widgeten har renderat sin idle/drop‑skärm | — |
onSourceLoaded({ token, pages, sourceExt, allowedTargets }) | ?convert=open lyckas | sessions‑token, sidantal, källfilens extension (utan inledande punkt), lista över tillåtna mål |
onConverted({ downloadToken, resultToken, resultPages, downloadName, watermarked, target }) | ?convert=run lyckas | samma fält som i run‑svaret, plus det begärda target‑värdet |
onDownload({ downloadName, downloadToken }) | Användaren klickar på Nedladdnings‑länken | avfyras tillsammans med webbläsarens inbyggda nedladdning — den avbryter eller ersätter den inte |
onError({ phase, message }) | En open‑ eller run‑begäran misslyckas | phase ä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:
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 thisBuild 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):
| Rutt | Syfte | Framgångssvar |
|---|---|---|
POST ?convert=open (multipart, field file) | Ladda upp och öppna ett källdokument för förhandsgranskning | 200 — { token, pages, sourceExt, allowedTargets } |
POST ?token=<token>&convert=run&target=<ext> | Konvertera den lagrade källan till target | 200 — { downloadToken, resultToken, resultPages, downloadName, watermarked } |
GET ?convert=download&token=<downloadToken> | Strömma den konverterade filen | 200 — 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:
| Rutt | Status | När | Body |
|---|---|---|---|
| any | 404 | Widgeten är inte aktiverad (AddConverterWidget() har aldrig anropats) — kontrolleras innan någon av de tre rutterna dispatchas | endast status |
| any | 405 | Fel HTTP‑verb (open/run kräver POST; download kräver GET) | endast status |
open | 413 | Uppladdad fil överskrider MaxUploadMb | { "error": "File is too large." } |
open | 400 | Ingen multipart‑kropp, ingen fil, eller en käll‑extension som inte kan konverteras | { "error": "..." } |
run | 400 | Felaktig token (inte ett GUID), eller ett target som inte kan parsas till en ConversionTarget | { "error": "Invalid token." } / { "error": "Unknown target format." } |
run | 400 | target finns inte i källans allowedTargets | { "error": "That target format is not available for this file." } |
run | 404 | Den lagrade uppladdningen har gått ut (30‑minuters TTL) eller token har aldrig öppnats | { "error": "Upload expired — please re-open the file." } |
open, run | 500 | Intern bearbetning misslyckades | { "error": "<sanitized message>" } — sanerat på samma sätt som alla andra Doconut‑felvägar; läcker aldrig interna motor‑namn |
download | 400 | Felaktig token (inte ett GUID) | endast status |
download | 404 | Okänd eller utgången nedladdningstoken | endast 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
| Symptom | Check |
|---|---|
Resolving DocumentConverter fails | ConverterPlugin registration happened inside AddDoconut() |
| Application fails during startup | The loaded license grants Converter |
| Stream conversion says the format is unsupported | sourceExtension includes the leading dot |
| Widget JavaScript loads but requests return 404 | AddConverterWidget() was not called |
| Widget requests use the wrong URL | basePath matches the branch where UseDoconut() is mapped |
| Target is missing | Use allowedTargets returned by convert=open; not every source supports every enum target |
| Download expired | Repeat convert=open/convert=run; stash tokens are intentionally temporary |
Watermarking
With ConverterPlugin registered, the host's license is in one of three states:
| License state | Startup gate | Conversion output |
|---|---|---|
Paid viewer license granting Converter, within its validity period | Passes | Clean — watermarked: false |
| Active evaluation (demo/NFR) license | Passes | Converts successfully, stamped with the evaluation watermark — watermarked: true |
Unlicensed, a legacy TRIAL file, or a non-temporary license that doesn't grant Converter | App never starts — the startup gate described above throws | — |
| Expired Temporary/Demo license | Registration survives expiry | Converts 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?