TX Text Control .NET Server

Performance Best Practices

Topic

Several decisions make document processing with TX Text Control .NET Server measurably faster, and Text Control has published benchmarks for most of them. Each recommendation comes with its numbers and the conditions they were measured under, so that you can judge which ones matter for your documents, and with a link to the page that shows the code. The last one matters most: measure with your own templates and data.

At a Glance

PracticeEffectRead
Use the Core enginePDF from plain text up to 11 times faster than with the Classic engineUse the Core Engine
Build text with Selection objectsAbout twice as fast as inserting, selecting and formattingBuild Text With Selection Objects
Keep documents in the TX Text Control format while they changeNo conversion when loading and savingKeep the Internal Format Until the End
Return short jobs, queue long onesA typical invoice in about 300 msKeep Requests Short
Keep processing apart from editingEditing sessions stay responsive under loadSeparate Processing From Editing
Use processes for large batches100 merges about three times faster in parallel processesMultiple Processes
Compress images in PDF documents14.68 MB down to 1.48 MB in a test documentKeep Documents Small
Measure your own workloadEvery benchmark depends on its documents and hardwareMeasure Your Own Workload

Use the Core Engine

The Core engine, TXTextControl.TextControl.Core.SDK, was faster than the Classic engine in both of Text Control's published comparisons. In the first, a text with one GUID per line was loaded into ServerTextControl and saved as DOCX and PDF:

LinesCore, DOCXCore, PDFClassic, DOCXClassic, PDF
10011 ms23 ms51 ms214 ms
5,000113 ms684 ms289 ms7,842 ms
100,000 (1,588 pages)3,047 ms14,518 ms5,885 ms159,313 ms

A second benchmark compared individual operations, averaged over five runs:

OperationClassic on WindowsCore on WindowsCore on Linux
A table with 500 rows and 10 columns, filled with text11,297 ms7,476 ms7,321 ms
Inserting 500 images952 ms40 ms34 ms
500 formatting operations1,783 ms86 ms96 ms

Neither article names the hardware. The blog articles TX Text Control Core vs. Classic Performance Comparison Plain Text to DOCX and PDF and Benchmarking TX Text Control: Classic vs. Core on Windows and Linux contain the code.

Processing time turns into server time. Text Control projects from these timings that 10,000 PDF documents of the 5,000-line size, created one after another, take 21.8 hours with Classic and 1.9 hours with Core. The blog article From Milliseconds to Cloud Costs: The Real Impact of Faster Document Processing in C# .NET calls these projections, not production measurements, and lists what changes real results. The Classic engine remains the choice for applications that must load or save DOC files or stay with an existing Classic integration, as The Document Engine explains.

Build Text With Selection Objects

A document built in code from many paragraphs is faster when each piece of text arrives with its formatting: a new Selection object with Text, FontName and FontSize assigned to ServerTextControl.Selection inserts formatted text in one step. Inserting the text, selecting it with Select and formatting it afterward takes three.

In Text Control's measurements with the Core engine, documents with 10 sections and 10 to 100 paragraphs per section took 5.7 to 42.9 ms each with Selection objects and 10.6 to 88.9 ms with insert, select and format: about twice as long. The article doesn't name the hardware either. Insert Formatted Text shows the code, and the blog article Speed Up Document Generation by Factor 2 Using Selection Objects in .NET C# the measurements.

Keep the Internal Format Until the End

The TX Text Control format, StreamType.InternalUnicodeFormat, is the format of the engine itself. Text Control recommends it for every step of a document's life in which the document still changes: templates are designed in it, merged without leaving it and edited and reviewed in it. Loading and saving it needs no conversion, and it supports every feature of TX Text Control. The Document Editor saves it with TXTextControl.StreamType.InternalUnicodeFormat, and the DataRowMerged event of MailMerge delivers merged documents in it. Text Control publishes no measurements for this recommendation; the blog article Document Lifecycle Optimization: Leveraging TX Text Control's Internal Format describes the workflow.

Convert a document to PDF once, when it's final: a PDF that is created before the data and approvals are complete has to be created again. Create PDF Documents Efficiently in PDF Creation summarizes this.

Keep Requests Short

A typical invoice is created in about 300 ms, and an HTTP request can return it directly. Documents that take several seconds, such as merges with many nested merge blocks and thousands of pages, are better accepted by the endpoint, created by a background service and announced when they're ready. For long-running work in ASP.NET Core, Microsoft recommends the BackgroundService base class. Keep the Service Responsive in REST Services describes the pattern, and Merge Documents With Thousands of Pages the design of long merge templates.

Separate Processing From Editing

Editing sessions of the Document Editor need a predictable amount of memory, while document processing needs an unpredictable amount of CPU. In one application, heavy processing can block the WebSocket connections of the editors. With many concurrent users, Text Control recommends a separate application for PDF generation, batch mail merges and conversions, which scales on its own. Container Scaling describes how each part scales.

Measure Your Own Workload

Text Control publishes no fixed maximum number of ServerTextControl instances or documents per second for a server, and the benchmarks above name little of their hardware. Your templates, data, images and fonts decide the numbers. The following program measures the three steps of a merge separately, so that you know which one to improve. It expects a template template.docx and a data file data.json in the folder of the application, as in Simple Mail Merge:

using System.Diagnostics;
using TXTextControl;
using TXTextControl.DocumentServer;

string jsonData = File.ReadAllText("data.json");
Stopwatch stopwatch = Stopwatch.StartNew();

using (ServerTextControl tx = new ServerTextControl())
{
    tx.Create();

    LoadSettings loadSettings = new LoadSettings
    {
        ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
        LoadSubTextParts = true
    };

    tx.Load("template.docx", StreamType.WordprocessingML, loadSettings);
    Console.WriteLine($"Load:  {stopwatch.ElapsedMilliseconds} ms");

    stopwatch.Restart();
    using (MailMerge mailMerge = new MailMerge { TextComponent = tx })
    {
        mailMerge.MergeJsonData(jsonData);
    }
    Console.WriteLine($"Merge: {stopwatch.ElapsedMilliseconds} ms");

    stopwatch.Restart();
    tx.Save("result.pdf", StreamType.AdobePDF);
    Console.WriteLine($"Save:  {stopwatch.ElapsedMilliseconds} ms");
}

The code works as follows:

  • Stopwatch from System.Diagnostics measures the elapsed time, and Restart starts each step at zero.
  • Load with the load settings imports the fields and merge blocks of the DOCX template, MergeJsonData merges the data and Save creates the PDF.
  • Run the program several times and compare the later runs. Text Control's benchmark of Selection objects warms up every test before it measures it, and the Windows and Linux benchmark averages five runs.

Measure on hardware like your production servers, with the documents your users create. Multiple Processes describes how to find the number of parallel workers that gives the highest throughput.

Next Steps