Windows Service
A Windows service starts with Windows, runs without a signed-in user and needs no IIS. For applications built with TX Text Control .NET Server, this suits background work such as converting documents from a folder or a queue, and it can also host the Document Editor backend for web applications on other machines.
The sections below build a .NET worker service that converts DOCX files to PDF with ServerTextControl, install it as a Windows service and explain what a service changes for TX Text Control. They follow Microsoft's articles Create Windows Service using BackgroundService and Host ASP.NET Core in a Windows Service.
Choose What the Service Runs
| Service | Use it to |
|---|---|
A worker service with ServerTextControl or MailMerge | Process documents in the background: files in a folder, jobs from a queue, scheduled batches |
| An ASP.NET Core application as a service | Host an application with the Document Editor and the Document Viewer without IIS |
A worker service with DocumentEditorWorkerManager | Run the Document Editor backend on its own machine for web applications on other servers |
Up to version 32.0, the Document Editor needed the TX TextControl Service, a Windows service installed with txregwebsvr.exe. Since version 34.0, the backend package starts the backend from your ASP.NET Core application instead. ASP.NET applications on the .NET Framework still deploy the service: for version 34.0, the redistribution documentation copies TXTextControl.Web.Server.exe out of the installation folder to a folder on the server and registers it there with txregwebsvr.exe /i /e /w, as .NET Framework Applications describes. Migrating from Previous Versions describes how to remove the old service.
Create a Document Processing Service
Create a worker project and add the package for Windows services and the Core engine of TX Text Control:
dotnet new worker -n DocService
cd DocService
dotnet add package Microsoft.Extensions.Hosting.WindowsServices
dotnet add package TXTextControl.TextControl.Core.SDK
The TX Text Control package comes from the Text Control Private NuGet Feed, as described in Text Control Private NuGet Feed. Replace the content of Program.cs:
using DocService;
var builder = Host.CreateApplicationBuilder(args);
// Run as a Windows service when the Service Control Manager starts the application
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "DocService";
});
builder.Services.AddHostedService<Worker>();
var host = builder.Build();
host.Run();
Replace the content of Worker.cs with a background service that converts every DOCX file in an input folder to PDF:
using TXTextControl;
namespace DocService;
public class Worker(ILogger<Worker> logger, IConfiguration configuration) : BackgroundService
{
protected override async Task ExecuteAsync(CancellationToken stoppingToken)
{
// Absolute folder paths from appsettings.json
string inputFolder = configuration["Folders:Input"]!;
string outputFolder = configuration["Folders:Output"]!;
while (!stoppingToken.IsCancellationRequested)
{
foreach (string file in Directory.GetFiles(inputFolder, "*.docx"))
{
string pdfFile = Path.Combine(outputFolder,
Path.GetFileNameWithoutExtension(file) + ".pdf");
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load(file, StreamType.WordprocessingML);
tx.Save(pdfFile, StreamType.AdobePDF);
}
File.Delete(file);
logger.LogInformation("Converted {File} to {PdfFile}", file, pdfFile);
}
await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken);
}
}
}
Add the folders to appsettings.json:
{
"Folders": {
"Input": "C:\\DocService\\Input",
"Output": "C:\\DocService\\Output"
}
}
The code works as follows:
AddWindowsServiceconfigures the application to run as a Windows service when the Service Control Manager starts it: the host reacts to start and stop requests, the content root is the application folder and logging goes to the Windows event log. Started from a console, the application runs as usual.- The worker checks the input folder every 10 seconds. For each file, it creates a ServerTextControl, calls Create first, loads the DOCX file with Load and saves it as PDF with Save. The
usingstatement disposes of the instance after each file. - The folders are absolute paths. The working directory of a Windows service is C:\Windows\System32, so relative paths point there.
Publish and Install the Service
Publish the application for 64-bit Windows on your development machine and copy the output to the server, for example to C:\Services\DocService:
dotnet publish -c Release -r win-x64 --self-contained false -o publishThe output contains DocService.exe, the TX Text Control assemblies with their native libraries and the Fonts folder. Install the .NET Runtime on the server; a service that hosts ASP.NET Core or the Document Editor backend needs the ASP.NET Core Runtime.
Create a user account for the service and give it the right to log on as a service: run secpol.msc, open Local Policies > User Rights Assignment > Log on as a service and add the account. Give the account read access to C:\Services\DocService and read and write access to the input and output folders.
Register the service in an administrative PowerShell:
New-Service -Name DocService -BinaryPathName "C:\Services\DocService\DocService.exe --contentRoot C:\Services\DocService" -Credential "SERVER\DocServiceUser" -DisplayName "Document Conversion" -StartupType AutomaticRestart the service after failures:
sc.exe failure DocService reset= 0 actions= restart/60000/restart/60000/run/1000Start the service with
Start-Service -Name DocServiceand check it withGet-Service -Name DocService.
Copy a DOCX file into the input folder: after a few seconds, the PDF appears in the output folder. Stop-Service stops the service, and Remove-Service removes it.
What Changes in a Service
- Paths. Build every path from configuration or from
AppContext.BaseDirectory, never from the working directory. The Core engine finds its Fonts folder in the application folder in any case. A second font folder registered withServerTextControl.InstallFontsneeds an absolute path, because the method resolves a relative path against the working directory. - Logging. In the event log, a service logs messages of level Warning and higher by default. Set
Logging:EventLog:LogLevel:Defaultin appsettings.json toInformationto see messages such as the conversions above or the output of the Document Editor backend. - Errors. An unhandled exception in a
BackgroundServicestops the host cleanly, and Windows doesn't restart a service that stopped cleanly. To let the recovery options restart the service, catch the exception, log it and end the process withEnvironment.Exit(1). - Account and access. The service runs under its account, including every process it starts. Grant this account access to the folders, certificates and databases the service uses.
Host the Document Editor in a Service
An ASP.NET Core Application Without IIS
Add the package Microsoft.Extensions.Hosting.WindowsServices to an ASP.NET Core application and call builder.Services.AddWindowsService(); in Program.cs. The application listens on http://localhost:5000 by default; set the environment variable ASPNETCORE_URLS for another address. The HTTPS development certificate isn't supported in a service, so configure a certificate for HTTPS endpoints.
DocumentEditorWorkerManager locates the 64-bit dotnet runtime on the machine and starts the Document Editor backend with it, as a process of the service account, so the 64-bit .NET runtime must be installed on the server.
A Backend for Other Machines
A worker service can host the Document Editor backend alone, for web applications on other servers. Add the packages TXTextControl.TextControl.Core.SDK and TXTextControl.Web.DocumentEditor.Backend to a worker project with Microsoft.Extensions.Hosting.WindowsServices, and register the backend in Program.cs:
using TXTextControl.Web.DocumentEditor.Backend;
var builder = Host.CreateApplicationBuilder(args);
builder.Services.AddWindowsService(options =>
{
options.ServiceName = "TXTextControlBackend";
});
// Listen address and port of the backend from appsettings.json
builder.Services.Configure<DocumentEditorWorkerOptions>(
builder.Configuration.GetSection("DocumentEditorWorker"));
builder.Services.AddHostedService<DocumentEditorWorkerManager>();
var host = builder.Build();
host.Run();
In appsettings.json, let the backend listen on all network interfaces:
{
"DocumentEditorWorker": {
"ListenAddress": "0.0.0.0",
"Port": 4283
}
}
The web applications connect with app.UseTXWebSocketMiddleware("<address of the server>", 4283) and don't register DocumentEditorWorkerManager themselves. Allow TCP port 4283 in the Windows firewall for the web servers only: the backend accepts connections from any client that reaches the port. Run the Backend Separately describes this setup.
Next Steps
- IIS: host a web application in IIS instead.
- Creating Documents: what
ServerTextControldoes in a service. - Mail Merge and Reporting: merge templates with data in the background.
- Document Editor Architecture: the backend process and its configuration.