Skip to content

Commit 4b15dfc

Browse files
committed
Updated ConversionEvents
1 parent 77b7672 commit 4b15dfc

5 files changed

Lines changed: 288 additions & 16 deletions

File tree

net/developer-guide/_index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ hideChildren: true
1414
* [Get document info]({{< ref "conversion/net/developer-guide/basic-usage/get-document-info.md" >}})
1515
* [Convert files]({{< ref "conversion/net/developer-guide/basic-usage/convert/" >}})
1616
* [Listening to conversion process events]({{< ref "conversion/net/developer-guide/advanced-usage/listening.md" >}})
17+
* [Subscribe to conversion events]({{< ref "conversion/net/developer-guide/advanced-usage/conversion-events.md" >}})
1718
* [Cache results]({{< ref "conversion/net/developer-guide/advanced-usage/caching/" >}})
1819
* [Logging]({{< ref "conversion/net/developer-guide/advanced-usage/logging.md" >}})
1920
* [Troubleshooting]({{< ref "conversion/net/developer-guide/troubleshooting/" >}})
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
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.

net/developer-guide/advanced-usage/converting/conversion-options-by-document-family/convert-contents-of-rar-or-zip-document-to-different-formats-and-compress.md

Lines changed: 20 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,43 +72,47 @@ using GroupDocs.Conversion.Contracts;
7272
using GroupDocs.Conversion.FileTypes;
7373
using System.IO;
7474

75-
FluentConverter.Load("documents.rar")
76-
.ConvertTo((SaveContext saveContext) => new MemoryStream())
77-
.WithOptions(new PdfConvertOptions())
78-
.Compress(new CompressionConvertOptions
79-
{
80-
Format = CompressionFileType.Zip
81-
})
82-
.OnCompressionCompleted(compressedStream =>
75+
FluentConverter
76+
.WithEvents(e => e.OnCompressionCompleted = compressedStream =>
8377
{
8478
using (var fileStream = File.Create("converted-documents.zip"))
8579
{
8680
compressedStream.CopyTo(fileStream);
8781
}
8882
})
83+
.Load("documents.rar")
84+
.ConvertTo((SaveContext saveContext) => new MemoryStream())
85+
.WithOptions(new PdfConvertOptions())
86+
.Compress(new CompressionConvertOptions
87+
{
88+
Format = CompressionFileType.Zip
89+
})
8990
.Convert();
9091

9192
// Output: converted-documents.zip containing PDFs
9293
```
9394

95+
Starting with v26.6, the compressed archive stream is delivered through the [ConversionEvents]({{< ref "conversion/net/developer-guide/advanced-usage/conversion-events.md" >}}) aggregator via the `WithEvents(...)` entry-stage call. The previous `.OnCompressionCompleted(...)` chain method placed after `.Compress(...)` continues to work but is obsolete and planned for removal in v26.9.
96+
9497
**With password protection:**
9598

9699
```csharp
97-
FluentConverter.Load("sensitive-files.zip")
100+
FluentConverter
101+
.WithEvents(e => e.OnCompressionCompleted = compressedStream =>
102+
{
103+
using (var fileStream = File.Create("protected-archive.zip"))
104+
{
105+
compressedStream.CopyTo(fileStream);
106+
}
107+
})
108+
.Load("sensitive-files.zip")
98109
.ConvertTo((SaveContext saveContext) => new MemoryStream())
99110
.WithOptions(new PdfConvertOptions())
100111
.Compress(new CompressionConvertOptions
101112
{
102113
Format = CompressionFileType.Zip,
103114
Password = "SecurePassword123"
104115
})
105-
.OnCompressionCompleted(compressedStream =>
106-
{
107-
using (var fileStream = File.Create("protected-archive.zip"))
108-
{
109-
compressedStream.CopyTo(fileStream);
110-
}
111-
})
112116
.Convert();
113117
```
114118

net/developer-guide/basic-usage/fluent-syntax.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,3 +42,22 @@ FluentConverter.Load("sample.pdf").GetDocumentInfo();
4242
FluentConverter.Load("sample.pdf").WithOptions(new PdfLoadOptions()).GetPossibleConversions();
4343
FluentConverter.Load("sample.pdf").WithOptions(new PdfLoadOptions()).GetDocumentInfo();
4444
```
45+
46+
## Subscribing to conversion events
47+
48+
Since version 26.6, conversion lifecycle handlers are registered through the [ConversionEvents]({{< ref "conversion/net/developer-guide/advanced-usage/conversion-events.md" >}}) aggregator via the `WithEvents(...)` entry-stage method:
49+
50+
```csharp
51+
FluentConverter
52+
.WithEvents(e =>
53+
{
54+
e.OnConversionCompleted = ctx => Console.WriteLine($"Done: {ctx.SourceFileName}");
55+
e.OnConversionFailed = (ctx, ex) => Console.WriteLine($"Failed: {ex.Message}");
56+
e.OnConversionByPageFailed = (ctx, ex) => Console.WriteLine($"Page failed: {ex.Message}");
57+
})
58+
.Load("sample.docx")
59+
.ConvertTo("converted.pdf").WithOptions(new PdfConvertOptions())
60+
.Convert();
61+
```
62+
63+
`WithEvents(...)` must be called before `Load(...)`. It can be combined with `WithSettings(...)` in either order. The previous chain methods (`.OnConversionCompleted(...).OnConversionFailed(...)` placed after `WithOptions(...)`) continue to work but are obsolete and planned for removal in v26.9 — see the [ConversionEvents]({{< ref "conversion/net/developer-guide/advanced-usage/conversion-events.md" >}}) guide for the full migration story.

net/developer-guide/migration-notes.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,102 @@ using (Converter converter = new Converter(documentPath))
5252
```
5353

5454
For more code examples and specific use cases please refer to our [Developer Guide]({{< ref "conversion/net/developer-guide/_index.md" >}}) or [GitHub](https://github.com/groupdocs-conversion/GroupDocs.Conversion-for-.NET) samples and showcases.
55+
56+
## Migrating to ConversionEvents (v26.6)
57+
58+
Version 26.6 introduces the [ConversionEvents]({{< ref "conversion/net/developer-guide/advanced-usage/conversion-events.md" >}}) aggregator — a single typed object that replaces the per-handler properties on `ConverterSettings` and the fluent chain methods placed after `WithOptions(...)`. The old surface continues to work but is obsolete and planned for removal in **v26.9**.
59+
60+
### Classic API
61+
62+
**Before** — handlers were set as individual properties on `ConverterSettings`:
63+
64+
```csharp
65+
var settings = new ConverterSettings();
66+
settings.OnConversionFailed = (ctx, ex) => Log(ex);
67+
settings.OnConversionByPageFailed = (ctx, ex) => Log(ex);
68+
69+
using (var converter = new Converter("sample.docx", () => settings))
70+
{
71+
converter.Convert("converted.pdf", new PdfConvertOptions());
72+
}
73+
```
74+
75+
**After** — handlers are aggregated in `ConversionEvents` and passed as the third factory:
76+
77+
```csharp
78+
var events = new ConversionEvents
79+
{
80+
OnConversionCompleted = ctx => Console.WriteLine($"Done: {ctx.SourceFileName}"),
81+
OnConversionFailed = (ctx, ex) => Log(ex),
82+
OnConversionByPageFailed = (ctx, ex) => Log(ex),
83+
};
84+
85+
using (var converter = new Converter(
86+
"sample.docx",
87+
() => new ConverterSettings(),
88+
() => events))
89+
{
90+
converter.Convert("converted.pdf", new PdfConvertOptions());
91+
}
92+
```
93+
94+
Existing `Converter` constructor signatures are preserved — the `events:` factory is exposed as an additional overload, not added to the existing ones.
95+
96+
### Fluent API
97+
98+
**Before** — handlers were registered via late-stage chain methods placed after `ConvertTo(...).WithOptions(...)`:
99+
100+
```csharp
101+
FluentConverter
102+
.Load("sample.docx")
103+
.ConvertTo("converted.pdf").WithOptions(new PdfConvertOptions())
104+
.OnConversionCompleted(ctx => Console.WriteLine($"Done: {ctx.SourceFileName}"))
105+
.OnConversionFailed((ctx, ex) => Log(ex))
106+
.Convert();
107+
```
108+
109+
**After** — handlers are aggregated in a single `WithEvents(...)` entry-stage call placed before `Load(...)`:
110+
111+
```csharp
112+
FluentConverter
113+
.WithEvents(e =>
114+
{
115+
e.OnConversionCompleted = ctx => Console.WriteLine($"Done: {ctx.SourceFileName}");
116+
e.OnConversionFailed = (ctx, ex) => Log(ex);
117+
})
118+
.Load("sample.docx")
119+
.ConvertTo("converted.pdf").WithOptions(new PdfConvertOptions())
120+
.Convert();
121+
```
122+
123+
### Fluent API — compression result-delivery
124+
125+
**Before** — the compressed archive stream was handled via `.OnCompressionCompleted(...)` placed after `.Compress(...)`:
126+
127+
```csharp
128+
FluentConverter
129+
.Load("documents.rar")
130+
.ConvertTo((SaveContext _) => new MemoryStream()).WithOptions(new PdfConvertOptions())
131+
.Compress(new CompressionConvertOptions { Format = CompressionFileType.Zip })
132+
.OnCompressionCompleted(stream => HandleArchive(stream))
133+
.Convert();
134+
```
135+
136+
**After** — the handler is registered at the entry stage via `WithEvents(...)`:
137+
138+
```csharp
139+
FluentConverter
140+
.WithEvents(e => e.OnCompressionCompleted = stream => HandleArchive(stream))
141+
.Load("documents.rar")
142+
.ConvertTo((SaveContext _) => new MemoryStream()).WithOptions(new PdfConvertOptions())
143+
.Compress(new CompressionConvertOptions { Format = CompressionFileType.Zip })
144+
.Convert();
145+
```
146+
147+
The chain method continues to work in v26.6 — the `IConversionCompressResultCompleted` interface that declares it is marked obsolete and is planned for removal in v26.9.
148+
149+
### Per-call vs global precedence
150+
151+
Handlers registered through `ConversionEvents` are **global** and fire on every `Convert(...)` call. The `Convert(...)` overloads that accept an `Action<ConvertedContext>` register a **per-call** handler that wins over the global `OnConversionCompleted` for that single call only — the precedence rule is `(perCall ?? global)?.Invoke(...)`. Between consecutive runs on the same converter, only the per-call slot is reset; the global events bag is preserved.
152+
153+
See [Conversion events]({{< ref "conversion/net/developer-guide/advanced-usage/conversion-events.md" >}}) for the full reference.

0 commit comments

Comments
 (0)