Conversion events

Starting with GroupDocs.Conversion for .NET v26.6, conversion event handlers are aggregated into a single typed object — ConversionEvents. This replaces three previously separate registration paths:

  • The IConverterListener interface assigned to ConverterSettings.Listener — for pipeline lifecycle callbacks.
  • Per-result handler properties on ConverterSettings (OnConversionFailed, OnConversionByPageFailed, OnCompressionCompleted).
  • The fluent chain methods placed after WithOptions(...) or Compress(...) (.OnConversionCompleted(...), .OnConversionFailed(...), .OnCompressionCompleted(...)).

The aggregator is registered with the Converter constructor via a new events: factory parameter, or with the fluent API via the entry-stage FluentConverter.WithEvents(...) method.

Event groups

ConversionEvents exposes two distinct groups of handlers.

Pipeline lifecycle

Fire once per conversion run, regardless of how many documents or pages the run produces. These replace the Started / Progress / Completed callbacks of IConverterListener.

HandlerSignatureWhen it fires
OnConversionStartedActionOnce, when the conversion pipeline starts
OnConversionProgressAction<byte>While the pipeline is running, with the current progress percentage (0–100)
OnConversionCompletedActionOnce at the end of the pipeline, regardless of success or failure
Name reuse — read before upgrading
The OnConversionCompleted name is reused with new semantics in v26.6. The pre-v26.6 fluent chain method .OnConversionCompleted(Action<ConvertedContext>) (per-document) is now OnDocumentConverted on the aggregator. The new ConversionEvents.OnConversionCompleted is a lifecycle handler — its signature is Action (no parameters) and it fires once at pipeline end. If you copy a v26.5-and-earlier example expecting per-document context, switch to OnDocumentConverted.

Per-result

Fire once per produced item — each converted document, each converted page, each compressed archive — including failures.

HandlerSignatureWhen it fires
OnDocumentConvertedAction<ConvertedContext>After each document conversion completes successfully
OnDocumentFailedAction<ConvertContext, Exception>When a document conversion throws
OnPageConvertedAction<ConvertedPageContext>After each page is converted in page-by-page conversions
OnPageFailedAction<ConvertContext, Exception>When a single page fails during page-by-page conversion
OnCompressionCompletedAction<Stream>After contents have been converted and packaged into a compressed archive (see Extract and Convert Archive Contents)

See Context Objects — Complete Guide for the properties exposed by ConvertedContext, ConvertContext, and ConvertedPageContext.

Registering events with the classic API

Pass a ConversionEvents factory as the third argument to the Converter constructor:

using GroupDocs.Conversion;
using GroupDocs.Conversion.Contracts;
using GroupDocs.Conversion.Options.Convert;

var events = new ConversionEvents
{
    // Pipeline lifecycle
    OnConversionStarted   = ()      => Console.WriteLine("Conversion started"),
    OnConversionProgress  = percent => Console.WriteLine($"... {percent}% ..."),
    OnConversionCompleted = ()      => Console.WriteLine("Conversion finished"),

    // Per-result
    OnDocumentConverted = ctx       => Console.WriteLine($"Done: {ctx.SourceFileName} -> {ctx.ConvertedFormat}"),
    OnDocumentFailed    = (ctx, ex) => Console.WriteLine($"Failed: {ctx.SourceFileName} ({ex.Message})"),
    OnPageFailed        = (ctx, ex) => Console.WriteLine($"Page failed: {ex.Message}"),
};

using (var converter = new Converter(
    "sample.docx",
    () => new ConverterSettings(),
    () => events))
{
    converter.Convert("converted.pdf", new PdfConvertOptions());
}

Registering events with the fluent API

The fluent API exposes a single entry-stage method — WithEvents — that accepts a builder action and replaces the per-method chain previously placed after ConvertTo(...).WithOptions(...):

using GroupDocs.Conversion;
using GroupDocs.Conversion.Options.Convert;

FluentConverter
    .WithEvents(e =>
    {
        e.OnConversionStarted   = ()         => Console.WriteLine("Conversion started");
        e.OnConversionProgress  = percent    => Console.WriteLine($"... {percent}% ...");
        e.OnConversionCompleted = ()         => Console.WriteLine("Conversion finished");

        e.OnDocumentConverted   = ctx        => Console.WriteLine($"Done: {ctx.SourceFileName}");
        e.OnDocumentFailed      = (ctx, ex)  => Console.WriteLine($"Failed: {ex.Message}");
        e.OnPageFailed          = (ctx, ex)  => Console.WriteLine($"Page failed: {ex.Message}");
    })
    .Load("sample.docx")
    .ConvertTo("converted.pdf").WithOptions(new PdfConvertOptions())
    .Convert();

WithEvents is an early-stage call — it must appear before Load(...). It can be combined with WithSettings(...) in either order.

Global vs per-call handlers

Handlers registered on ConversionEvents are global — they live for the lifetime of the Converter instance and fire on every Convert(...) call:

using (var converter = new Converter("source.docx", () => new ConverterSettings(), () => events))
{
    converter.Convert("page1.pdf",  new PdfConvertOptions());   // events.OnDocumentConverted fires
    converter.Convert("page2.tiff", new TiffConvertOptions());  // same global handler fires again
}

Convert(...) overloads that accept an Action<ConvertedContext> register a per-call result handler that wins over the global OnDocumentConverted for that single call:

using (var converter = new Converter("source.docx", () => new ConverterSettings(), () => events))
{
    // Per-call handler — overrides events.OnDocumentConverted for THIS call only
    converter.Convert(
        new PdfConvertOptions(),
        (ConvertedContext ctx) =>
        {
            using (var fileStream = File.Create("custom.pdf"))
            {
                ctx.ConvertedStream.CopyTo(fileStream);
            }
        });

    // No per-call handler — events.OnDocumentConverted fires
    converter.Convert("page2.pdf", new PdfConvertOptions());
}

The precedence rule is (perCall ?? global)?.Invoke(...): if a per-call handler is supplied, the global OnDocumentConverted does not fire for that call. The other per-result handlers (OnDocumentFailed, OnPageConverted, OnPageFailed, OnCompressionCompleted) and all lifecycle handlers are always global — there is no per-call override.

Between consecutive Convert(...) calls on the same Converter, only the per-call slot is reset. The global ConversionEvents bag is preserved across runs.

Handling compressed archive output

When converting and re-compressing archive contents (see Extract and Convert Archive Contents), OnCompressionCompleted is invoked once the new archive stream is ready:

using GroupDocs.Conversion;
using GroupDocs.Conversion.FileTypes;
using GroupDocs.Conversion.Options.Convert;

FluentConverter
    .WithEvents(e => e.OnCompressionCompleted = stream =>
    {
        using (var fileStream = File.Create("converted-documents.zip"))
        {
            stream.CopyTo(fileStream);
        }
    })
    .Load("documents.rar")
    .ConvertTo((SaveContext _) => new MemoryStream()).WithOptions(new PdfConvertOptions())
    .Compress(new CompressionConvertOptions { Format = CompressionFileType.Zip })
    .Convert();

The previous late-stage .OnCompressionCompleted(stream => ...) placed after .Compress(...) continues to work but is obsolete — the IConversionCompressResultCompleted interface that declares it is planned for removal in v26.9.

Compatibility with the previous API

The previous registration mechanisms continue to work, but are obsolete and planned for removal in v26.9:

Obsolete (still works in v26.6)Replacement
ConverterSettings.Listener (IConverterListener.Started / Progress / Completed)ConversionEvents.OnConversionStarted / OnConversionProgress / OnConversionCompleted
ConverterSettings.OnConversionFailedConversionEvents.OnDocumentFailed
ConverterSettings.OnConversionByPageFailedConversionEvents.OnPageFailed
ConverterSettings.OnCompressionCompletedConversionEvents.OnCompressionCompleted
Fluent chain .OnConversionCompleted(...) after WithOptions(...)FluentConverter.WithEvents(e => e.OnDocumentConverted = ...)
Fluent chain .OnConversionFailed(...) after WithOptions(...)FluentConverter.WithEvents(e => e.OnDocumentFailed = ...)
Fluent chain .OnCompressionCompleted(...) after .Compress(...) (IConversionCompressResultCompleted)FluentConverter.WithEvents(e => e.OnCompressionCompleted = ...)

When values are set on both the obsolete locations and on ConversionEvents, the aggregator wins. Handlers set on ConverterSettings (including a Listener instance) are forwarded into the internal events bag at converter construction.

See the migration notes for a step-by-step upgrade guide.

Close
Loading

Analyzing your prompt, please hold on...

An error occurred while retrieving the results. Please refresh the page and try again.