Server-Side Document Conversion in .NET with Doconut
← Back to Blog4 min read

Server-Side Document Conversion in .NET with Doconut

Introduction

Server-side document conversion lets an application generate a normalized output without automating Microsoft Office or sending the source to a separate online conversion service. That can simplify document portals, background jobs, and controlled export workflows—but the host application still owns access control, storage, retention, monitoring, and delivery of the result.

Abstract document formats flowing through a conversion pipeline into one normalized output
Abstract document formats flowing through a conversion pipeline into one normalized output

Doconut's .NET 8 Converter Plugin exposes conversion through the dependency-injected DocumentConverter service. This guide focuses on the current registration and API model and avoids coupling conversion to a viewer session.


Install matching packages

Install the base viewer and converter packages:

dotnet add package Doconut.NET8
dotnet add package Doconut.NET8.Converter

Keep both packages on the same release version. When reproducible builds matter, pin the version in the project file or pass the same --version value to both commands.

Register the Converter Plugin

Plugins register inside the AddDoconut options callback. There is no separate AddConverter() registration method:

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

The application must use a license that grants the Converter capability. Resolve startup and licensing errors before accepting conversion work; do not defer them to a background queue where they become harder to diagnose.

Convert a file from C#

Inject DocumentConverter into the endpoint or service that owns the conversion request. The converter's constructor is internal, so application code should not instantiate it directly.

app.MapPost("/api/convert", async (
    DocumentConverter converter,
    CancellationToken ct) =>
{
    await using Stream pdf = await converter.ConvertAsync(
        "documents/contract.docx",
        ConversionTarget.Pdf,
        ct: ct);

    using var copy = new MemoryStream();
    await pdf.CopyToAsync(copy, ct);
    return Results.File(copy.ToArray(), "application/pdf", "contract.pdf");
});

The returned stream is seekable and positioned at the beginning. The caller owns it and should dispose it after copying or returning the content.

Convert an uploaded stream

The stream overload needs the source extension—including its leading dot—because the converter uses it to resolve the source format:

app.MapPost("/api/convert-upload", async (
    IFormFile file,
    DocumentConverter converter,
    CancellationToken ct) =>
{
    var extension = Path.GetExtension(file.FileName);
    await using var source = file.OpenReadStream();
    await using Stream output = await converter.ConvertAsync(
        source,
        extension,
        ConversionTarget.Pdf,
        password: null,
        ct: ct);

    using var copy = new MemoryStream();
    await output.CopyToAsync(copy, ct);
    return Results.File(copy.ToArray(), "application/pdf", "converted.pdf");
});

Treat the filename and extension as untrusted input. Enforce upload limits, validate the source type, authorize the requesting user, and avoid using the submitted filename as a storage path.

Choose targets from actual capabilities

The plugin exposes a ConversionTarget enum, but not every source format can produce every target. A custom UI should show only the targets permitted for the uploaded source rather than displaying every enum value.

When using Doconut's optional converter widget, its open response includes allowedTargets. Use that response as the source of truth for the current file.

Design background conversion as an application workflow

The converter can be called from an application service or queued worker. A robust job normally includes:

  1. An authenticated request that records the source and desired target.
  2. A queue message containing an application job ID, not raw credentials.
  3. A worker that retrieves the source through an authorized storage abstraction.
  4. A bounded conversion operation with cancellation.
  5. Durable output storage with explicit retention rules.
  6. A status update that does not expose internal paths or sensitive exception details.

Measure concurrency with representative documents before selecting worker counts. Conversion cost varies by source format, document complexity, fonts, images, and output target.

Keep security claims precise

Running the converter inside your .NET application means the conversion operation does not require Microsoft Office automation or a separate online conversion API. It does not automatically guarantee privacy, compliance, deletion, or encryption for the complete system.

Those properties depend on how the application authenticates users, retrieves source files, configures storage, protects logs, distributes output, and removes temporary or retained data.

Operational checklist

  • Keep Doconut.NET8 and Doconut.NET8.Converter versions aligned.
  • Register ConverterPlugin during service configuration.
  • Resolve DocumentConverter through dependency injection.
  • Include the leading dot in stream source extensions.
  • Dispose source and result streams.
  • Use cancellation and application-level file-size limits.
  • Validate source-to-target support instead of assuming every pair works.
  • Test fidelity and resource use with representative files.
  • Keep storage, authorization, audit, and retention decisions in application code.

See the official Doconut Converter Plugin overview and Doconut documentation for current product and integration information.

#.NET 8#Document Conversion#Enterprise Architecture#Doconut#Server-Side Processing