Speed Up Document Generation by Factor 2 Using Selection Objects in .NET C#
This article compares two ServerTextControl document generation patterns: Assigning prebuilt Selection objects and formatting text after inserting and selecting it. The benchmark shows an approximately 2x performance improvement when using Selection objects.

When documents are generated from scratch on the server, without using templates or Mail
This benchmark compares two ways to create the same generated document with Server
Selection Object Performance
In this benchmark, prebuilding TXTextControl.Selection objects is consistently about factor 2 faster than inserting text, selecting it, and formatting the live selection afterwards.
The Faster Pattern: Build the Selection First
The recommended pattern prepares the complete selection object before it is assigned to the current document position. Text and formatting are applied to the temporary object, and the assignment to Selection inserts the prepared content in one step.
AppendPrebuilt(control, new Selection
{
Text = paragraph + "\r\n",
FontName = "Calibri",
FontSize = Twips(10)
});
static void AppendPrebuilt(ServerTextControl control, Selection selection)
{
control.Selection = selection;
}
The same approach is used for headings, normal paragraphs, and bullet text. Formatting such as font name, font size, bold, and italic is applied directly to the new Selection instance before it is inserted.
The Slower Pattern: Insert, Select, and Format
The comparison path performs more document-selection work. It inserts the text, selects the inserted range in the live document, applies formatting to the active selection, and then moves the selection back to the end of the inserted text.
int start = control.Selection.Start + control.Selection.Length;
control.Selection.Text = text;
control.Select(start, text.Length);
control.Selection.FontName = "Calibri";
control.Selection.FontSize = Twips(10);
control.Select(start + text.Length, 0);
This pattern is easy to write because it resembles interactive editing. But in generated documents it repeats selection and formatting operations for every fragment. The more paragraphs, sections, and list items the document contains, the more visible this overhead becomes.
Benchmark Setup
The benchmark is a .NET console application using TXTextControl.TextControl.Core.SDK and ServerTextControl. Both test paths create the same logical document content. The generated document contains a title, subtitle, sections, section headings, paragraphs, and bullet lists.
Each profile is warmed up before timing. The measured result is reported as average milliseconds per generated document. PDF files are written after the benchmark run so that disk I/O and PDF export do not affect the timing numbers.
Two dimensions were tested separately:
- A static number of sections with an increasing number of paragraphs per section.
- A linear increase in the number of sections with a static number of paragraphs and bullets per section.
Results: Static Sections, Variable Paragraphs
The first test keeps the document structure stable with 10 sections and 4 bullets per section. Only the number of paragraphs per section changes from 10 to 100.
| Sections | Paragraphs/Section | Bullets/Section | Elements | Prebuilt ms/doc | Select ms/doc | Speedup |
|---|---|---|---|---|---|---|
| 10 | 10 | 4 | 152 | 5.7 | 10.6 | 1.86x |
| 10 | 20 | 4 | 252 | 9.2 | 16.5 | 1.80x |
| 10 | 30 | 4 | 352 | 10.6 | 21.6 | 2.04x |
| 10 | 40 | 4 | 452 | 14.2 | 29.3 | 2.06x |
| 10 | 50 | 4 | 552 | 18.2 | 37.2 | 2.04x |
| 10 | 60 | 4 | 652 | 22.2 | 46.7 | 2.10x |
| 10 | 70 | 4 | 752 | 27.2 | 56.7 | 2.09x |
| 10 | 80 | 4 | 852 | 34.7 | 68.9 | 1.99x |
| 10 | 90 | 4 | 952 | 37.3 | 85.3 | 2.29x |
| 10 | 100 | 4 | 1052 | 42.9 | 88.9 | 2.08x |
The paragraph test shows a clear scaling trend. As the number of generated text fragments grows, both approaches take longer, but the live-selection approach grows faster. Across the test range, the prebuilt selection pattern stays close to twice as fast.
Results: Variable Sections
The second test keeps the content inside each section stable with 10 paragraphs and 4 bullets per section. The section count increases linearly from 2 to 20.
| Sections | Paragraphs/Section | Bullets/Section | Elements | Prebuilt ms/doc | Select ms/doc | Speedup |
|---|---|---|---|---|---|---|
| 2 | 10 | 4 | 32 | 1.4 | 3.0 | 2.18x |
| 4 | 10 | 4 | 62 | 2.3 | 4.6 | 2.02x |
| 6 | 10 | 4 | 92 | 3.2 | 6.4 | 2.03x |
| 8 | 10 | 4 | 122 | 4.4 | 8.1 | 1.85x |
| 10 | 10 | 4 | 152 | 5.2 | 9.1 | 1.75x |
| 12 | 10 | 4 | 182 | 5.3 | 10.4 | 1.98x |
| 14 | 10 | 4 | 212 | 6.1 | 12.3 | 2.02x |
| 16 | 10 | 4 | 242 | 7.2 | 14.1 | 1.95x |
| 18 | 10 | 4 | 272 | 8.0 | 16.2 | 2.02x |
| 20 | 10 | 4 | 302 | 9.0 | 18.3 | 2.04x |
This section-based test isolates document structure growth. The number of sections increases in equal steps, while the amount of content per section remains unchanged. Again, the result is consistent: prebuilt Selection objects avoid repeated live-selection operations and remain approximately twice as fast.
What the Results Show
The important point is not a single timing value. Timings vary by machine, runtime, and document complexity. The important result is the shape of the data. Both benchmarks show that prebuilding the Selection object scales more efficiently as the number of generated content elements increases.
For applications that generate contracts, reports, invoices, statements, or other business documents, this pattern is especially useful when many formatted text fragments are inserted programmatically. Instead of thinking like an editor that inserts text and then selects it, think like a document generator: prepare the content fragment first and insert it once.
Conclusion
When generating documents with TX Text Control .NET Server, creating and formatting a Selection object before assigning it to control.Selection is the more efficient pattern. In this benchmark, it reduced document generation time by approximately factor 2 compared to inserting text first, selecting the inserted range, and formatting the live selection.
The code change is small, but the effect is visible as documents grow. For high-volume document generation or templates with many formatted fragments, using prebuilt Selection objects is a practical optimization that keeps the code simple and improves throughput.
