|
| 1 | +--- |
| 2 | +id: conversion-events |
| 3 | +url: conversion/net/conversion-events |
| 4 | +title: Conversion events |
| 5 | +linkTitle: Conversion events |
| 6 | +weight: 4 |
| 7 | +description: "Subscribe to conversion lifecycle events (completed, failed, by-page-failed) through the typed ConversionEvents aggregator in GroupDocs.Conversion for .NET." |
| 8 | +keywords: ConversionEvents, OnConversionCompleted, OnConversionFailed, OnConversionByPageFailed, WithEvents, conversion lifecycle, event handlers |
| 9 | +productName: GroupDocs.Conversion for .NET |
| 10 | +hideChildren: False |
| 11 | +toc: True |
| 12 | +--- |
| 13 | + |
| 14 | +Starting with **GroupDocs.Conversion for .NET v26.6**, conversion lifecycle event handlers are aggregated into a single typed object — [ConversionEvents](https://reference.groupdocs.com/conversion/net/groupdocs.conversion/conversionevents/). This replaces the previous practice of setting individual handlers on [ConverterSettings](https://reference.groupdocs.com/conversion/net/groupdocs.conversion/convertersettings/) or chaining `.OnConversionCompleted(...).OnConversionFailed(...)` after `WithOptions(...)` in the fluent API. |
| 15 | + |
| 16 | +The aggregator exposes the following handlers: |
| 17 | + |
| 18 | +| Handler | Signature | When it fires | |
| 19 | +|---------|-----------|---------------| |
| 20 | +| `OnConversionCompleted` | `Action<ConvertedContext>` | After the entire conversion completes successfully | |
| 21 | +| `OnConversionFailed` | `Action<ConvertContext, Exception>` | When a conversion run throws | |
| 22 | +| `OnConversionByPageFailed` | `Action<ConvertContext, Exception>` | When a single page fails during page-by-page conversion | |
| 23 | +| `OnCompressionCompleted` | `Action<Stream>` | After contents have been converted and packaged into a compressed archive (see [Extract and Convert Archive Contents]({{< ref "conversion/net/developer-guide/advanced-usage/converting/conversion-options-by-document-family/convert-contents-of-rar-or-zip-document-to-different-formats-and-compress.md" >}})) | |
| 24 | + |
| 25 | +## Registering events with the classic API |
| 26 | + |
| 27 | +Pass a `ConversionEvents` factory as the third argument to the [Converter](https://reference.groupdocs.com/conversion/net/groupdocs.conversion/converter/) constructor: |
| 28 | + |
| 29 | +```csharp |
| 30 | +using GroupDocs.Conversion; |
| 31 | +using GroupDocs.Conversion.Contracts; |
| 32 | +using GroupDocs.Conversion.Options.Convert; |
| 33 | + |
| 34 | +var events = new ConversionEvents |
| 35 | +{ |
| 36 | + OnConversionCompleted = ctx => Console.WriteLine($"Done: {ctx.SourceFileName} -> {ctx.ConvertedFormat}"), |
| 37 | + OnConversionFailed = (ctx, ex) => Console.WriteLine($"Failed: {ctx.SourceFileName} ({ex.Message})"), |
| 38 | + OnConversionByPageFailed = (ctx, ex) => Console.WriteLine($"Page failed: {ex.Message}"), |
| 39 | +}; |
| 40 | + |
| 41 | +using (var converter = new Converter( |
| 42 | + "sample.docx", |
| 43 | + () => new ConverterSettings(), |
| 44 | + () => events)) |
| 45 | +{ |
| 46 | + converter.Convert("converted.pdf", new PdfConvertOptions()); |
| 47 | +} |
| 48 | +``` |
| 49 | + |
| 50 | +## Registering events with the fluent API |
| 51 | + |
| 52 | +The fluent API exposes a single entry-stage method — [WithEvents](https://reference.groupdocs.com/conversion/net/groupdocs.conversion/fluentconverter/withevents/) — that accepts a builder action and replaces the per-method chain previously placed after `ConvertTo(...).WithOptions(...)`: |
| 53 | + |
| 54 | +```csharp |
| 55 | +using GroupDocs.Conversion; |
| 56 | +using GroupDocs.Conversion.Options.Convert; |
| 57 | + |
| 58 | +FluentConverter |
| 59 | + .WithEvents(e => |
| 60 | + { |
| 61 | + e.OnConversionCompleted = ctx => Console.WriteLine($"Done: {ctx.SourceFileName}"); |
| 62 | + e.OnConversionFailed = (ctx, ex) => Console.WriteLine($"Failed: {ex.Message}"); |
| 63 | + e.OnConversionByPageFailed = (ctx, ex) => Console.WriteLine($"Page failed: {ex.Message}"); |
| 64 | + }) |
| 65 | + .Load("sample.docx") |
| 66 | + .ConvertTo("converted.pdf").WithOptions(new PdfConvertOptions()) |
| 67 | + .Convert(); |
| 68 | +``` |
| 69 | + |
| 70 | +`WithEvents` is an early-stage call — it must appear before `Load(...)`. It can be combined with `WithSettings(...)` in either order. |
| 71 | + |
| 72 | +## Global vs per-call handlers |
| 73 | + |
| 74 | +Handlers registered on `ConversionEvents` are **global** — they live for the lifetime of the `Converter` instance and fire on every `Convert(...)` call: |
| 75 | + |
| 76 | +```csharp |
| 77 | +using (var converter = new Converter("source.docx", () => new ConverterSettings(), () => events)) |
| 78 | +{ |
| 79 | + converter.Convert("page1.pdf", new PdfConvertOptions()); // events.OnConversionCompleted fires |
| 80 | + converter.Convert("page2.tiff", new TiffConvertOptions()); // same global handler fires again |
| 81 | +} |
| 82 | +``` |
| 83 | + |
| 84 | +`Convert(...)` overloads that accept an `Action<ConvertedContext>` register a **per-call** result handler that wins over the global `OnConversionCompleted` for that single call: |
| 85 | + |
| 86 | +```csharp |
| 87 | +using (var converter = new Converter("source.docx", () => new ConverterSettings(), () => events)) |
| 88 | +{ |
| 89 | + // Per-call handler — overrides events.OnConversionCompleted for THIS call only |
| 90 | + converter.Convert( |
| 91 | + new PdfConvertOptions(), |
| 92 | + (ConvertedContext ctx) => |
| 93 | + { |
| 94 | + using (var fileStream = File.Create("custom.pdf")) |
| 95 | + { |
| 96 | + ctx.ConvertedStream.CopyTo(fileStream); |
| 97 | + } |
| 98 | + }); |
| 99 | + |
| 100 | + // No per-call handler — events.OnConversionCompleted fires |
| 101 | + converter.Convert("page2.pdf", new PdfConvertOptions()); |
| 102 | +} |
| 103 | +``` |
| 104 | + |
| 105 | +The precedence rule is `(perCall ?? global)?.Invoke(...)`: if a per-call handler is supplied, the global `OnConversionCompleted` does not fire for that call. `OnConversionFailed` and `OnConversionByPageFailed` are always global — there is no per-call override. |
| 106 | + |
| 107 | +Between consecutive `Convert(...)` calls on the same `Converter`, only the per-call slot is reset. The global `ConversionEvents` bag is preserved across runs. |
| 108 | + |
| 109 | +## Handling compressed archive output |
| 110 | + |
| 111 | +When converting and re-compressing archive contents (see [Extract and Convert Archive Contents]({{< ref "conversion/net/developer-guide/advanced-usage/converting/conversion-options-by-document-family/convert-contents-of-rar-or-zip-document-to-different-formats-and-compress.md" >}})), `OnCompressionCompleted` is invoked once the new archive stream is ready: |
| 112 | + |
| 113 | +```csharp |
| 114 | +using GroupDocs.Conversion; |
| 115 | +using GroupDocs.Conversion.FileTypes; |
| 116 | +using GroupDocs.Conversion.Options.Convert; |
| 117 | + |
| 118 | +FluentConverter |
| 119 | + .WithEvents(e => e.OnCompressionCompleted = stream => |
| 120 | + { |
| 121 | + using (var fileStream = File.Create("converted-documents.zip")) |
| 122 | + { |
| 123 | + stream.CopyTo(fileStream); |
| 124 | + } |
| 125 | + }) |
| 126 | + .Load("documents.rar") |
| 127 | + .ConvertTo((SaveContext _) => new MemoryStream()).WithOptions(new PdfConvertOptions()) |
| 128 | + .Compress(new CompressionConvertOptions { Format = CompressionFileType.Zip }) |
| 129 | + .Convert(); |
| 130 | +``` |
| 131 | + |
| 132 | +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. |
| 133 | + |
| 134 | +## Compatibility with the previous API |
| 135 | + |
| 136 | +The previous registration mechanisms continue to work, but are obsolete and planned for removal in **v26.9**: |
| 137 | + |
| 138 | +| Obsolete (still works in v26.6) | Replacement | |
| 139 | +|---------------------------------|-------------| |
| 140 | +| `ConverterSettings.OnConversionFailed` | `ConversionEvents.OnConversionFailed` | |
| 141 | +| `ConverterSettings.OnConversionByPageFailed` | `ConversionEvents.OnConversionByPageFailed` | |
| 142 | +| `ConverterSettings.OnCompressionCompleted` | `ConversionEvents.OnCompressionCompleted` | |
| 143 | +| Fluent chain `.OnConversionCompleted(...)` after `WithOptions(...)` | `FluentConverter.WithEvents(e => e.OnConversionCompleted = ...)` | |
| 144 | +| Fluent chain `.OnConversionFailed(...)` after `WithOptions(...)` | `FluentConverter.WithEvents(e => e.OnConversionFailed = ...)` | |
| 145 | +| Fluent chain `.OnCompressionCompleted(...)` after `.Compress(...)` (`IConversionCompressResultCompleted`) | `FluentConverter.WithEvents(e => e.OnCompressionCompleted = ...)` | |
| 146 | + |
| 147 | +When values are set on both the obsolete locations and on `ConversionEvents`, the aggregator wins. Handlers set on `ConverterSettings` are merged into the internal events bag at converter construction. |
| 148 | + |
| 149 | +See the [migration notes]({{< ref "conversion/net/developer-guide/migration-notes.md" >}}) for a step-by-step upgrade guide. |
0 commit comments