# Architecture

> Follow a Document Editor session through the frontend, WebSocket middleware and TXTextControl.Web.Server.Core backend: reconnection, ports, logging, scaling.

- **Product:** TX Text Control .NET Server
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET Server > Document Editor > Architecture
- **2877 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/architecture/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/architecture/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/architecture/llms-full.txt

---

Several parts share the work while the Document Editor runs in your application. Knowing which part does what pays off when you run the backend on another machine, put the application into a container or investigate a connection problem: you follow an editing session as it starts, survives a lost connection and ends, and you find where to configure the backend process.

The [Document Editor](https://docs.textcontrol.com/tx-text-control-dotnet-server/overview/components/document-editor/llms-full.txt) page in the Overview introduces the editor and its frontends. If you haven't added the editor to an application yet, start with [ASP.NET Core](https://docs.textcontrol.com/tx-text-control-dotnet-server/getting-started/document-editor/aspnet-core/llms-full.txt) in Getting Started.

### The Three Parts

The Document Editor is not a component that runs in the browser alone. Three parts work together, and all of them are required:

```text
Browser: Document Editor frontend
    |
    |  WebSocket connection, one per editor
    v
Your ASP.NET Core application: TX Text Control WebSocket middleware
    |
    |  TCP connection
    v
Backend process: TXTextControl.Web.Server.Core
```

- **The frontend** runs in the browser. It shows the ribbon and the pages and sends every user action, such as typing, selecting or formatting, over its WebSocket connection. What it displays comes back from the server.
- **The WebSocket middleware** runs in your ASP.NET Core application. `app.UseTXWebSocketMiddleware()` adds it, and for each editor that connects it creates a handler that passes the messages between the browser and the backend process. Because it handles the live traffic of all editors, Text Control recommends that applications with many concurrent users run heavy document processing in a separate application instance.
- **The backend process** `TXTextControl.Web.Server.Core` keeps the documents that are open in the editors, synchronizes them and performs the layout and rendering work: cursor movement, layout recalculation and spell checking. It uses the Core engine and renders pages as SVG. The hosted service `DocumentEditorWorkerManager` from the `TXTextControl.Web.DocumentEditor.Backend` package starts it together with your application.

All frontends use this chain: the ASP.NET Core HTML helper, the Angular and React components, the plain JavaScript page and the Blazor component. With Angular, React and JavaScript, only the frontend is a separate application; it still connects to an ASP.NET Core backend, or to a Node.js application in which the `WebSocketServer` of the `@txtextcontrol/tx-websocket-server` package takes the place of the middleware. [Product Architecture](https://docs.textcontrol.com/tx-text-control-dotnet-server/overview/architecture/#document-editor) shows how the editor fits into the rest of the product.

### The Life of an Editing Session

#### Opening the Editor

When a page with the editor opens, the frontend connects to the WebSocket address of your application. The JavaScript frontend passes this address as `webSocketURL` to [TXTextControl.init](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/txtextcontrol/init-method/llms-full.txt). The ASP.NET Core HTML helper builds it from [TextControlSettings.APIRoute](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/txtextcontrol-web-mvc/textcontrolsettings/apiroute-property/llms-full.txt), whose default `api/` leads to the path `/api/TXWebSocket`.

The server opens a session for the connection, and [TXTextControl.connectionID](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/txtextcontrol/connectionid-property/llms-full.txt) returns its unique ID. When the editor is ready to be used from code, it raises the `textControlLoaded` event. Code that calls the JavaScript API therefore starts in a handler of this event; [Events](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/events/llms-full.txt) lists the events that follow during initialization.

#### Editing

Each editor has its own session and its own document on the backend.

> Warning
>
> **Unsaved Documents.** While a user edits, the document exists only in the memory of the backend process. It isn't stored anywhere until your code saves it, for example with `saveDocument` in the browser, and sends it to a database or file storage. [Loading and Saving Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/load-save/llms-full.txt) shows how.

Two users who open the same file in two editors edit two independent copies. Live collaboration on one document is a separate package, `TXTextControl.Web.Collaboration`, which is available as a preview.

#### Losing and Restoring the Connection

The editor needs a constant connection to show the document. If the WebSocket connection drops, for example because of a short network interruption, the editor doesn't close the session right away:

1. The frontend shows a message and tries to reconnect to the same session with its connection ID.
2. If the connection comes back in time, the session continues. Changes that weren't saved yet are still there.
3. If the reconnection attempts stop, the editor raises the `reconnectionFailed` event, and the session is lost.

[DocumentEditorSettings.reconnectTimeout](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/documenteditorsettings/reconnecttimeout-property/llms-full.txt) sets the time in seconds after which the editor stops trying. A user who reloads the page while the editor is reconnecting starts a new session, and unsaved changes are lost.

The following JavaScript page sets the timeout to 20 seconds and reports when the connection closes and when reconnecting fails:

```javascript
TXTextControl.init({
  containerID: "txDocumentEditor",
  webSocketURL: "wss://localhost:7118/api/TXWebSocket",
  editorSettings: {
    reconnectTimeout: 20 // seconds
  }
});

TXTextControl.addEventListener("textControlLoaded", function () {

  TXTextControl.addEventListener("webSocketClosed", function (e) {
    console.log("Connection closed: " + e.code + " " + e.reason + " (clean: " + e.wasClean + ")");
  });

  TXTextControl.addEventListener("reconnectionFailed", function (e) {
    console.log("Reconnection failed: " + e.reason);
  });
});
```

What the code does:

- `editorSettings` passes a [DocumentEditorSettings](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/documenteditorsettings/llms-full.txt) object to `init`, here with `reconnectTimeout`.
- [addEventListener](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/txtextcontrol/addeventlistener-method/llms-full.txt) attaches the handlers once the editor has been loaded.
- The `webSocketClosed` handler receives [WebSocketClosedEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/websocketclosedeventargs/llms-full.txt) with the close [code](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/websocketclosedeventargs/code-property/llms-full.txt), the [reason](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/websocketclosedeventargs/reason-property/llms-full.txt) and whether the connection was closed cleanly ([wasClean](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/websocketclosedeventargs/wasclean-property/llms-full.txt)).
- The `reconnectionFailed` handler receives [ReconnectionFailedEventArgs](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/reconnectionfailedeventargs/llms-full.txt) with the [reason](https://docs.textcontrol.com/tx-text-control-dotnet-server/reference/javascript/reconnectionfailedeventargs/reason-property/llms-full.txt). Use it to tell the user that the document has to be opened again.

To protect unsaved work against a lost connection, save regularly. The blog article [Best Practices: Reliable Auto-Save in TX Text Control Using the WebSocketHandler and Background Services](https://www.textcontrol.com/blog/2025/06/20/best-practices-reliable-auto-save-in-tx-text-control-using-the-websockethandler-and-background-services/) saves the document on the server side.

#### Closing the Editor

The session ends when the connection closes. In single-page applications, call `removeFromDom` before a view with the editor is removed, as [Remove the Editor](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/javascript-api/#remove-the-editor) in JavaScript API describes.

### Configure the Backend Process

By default, `DocumentEditorWorkerManager` starts the backend process on the same machine, and `app.UseTXWebSocketMiddleware()` without parameters connects to it. You need a configuration when the default port is taken, when the backend has to listen on a specific network interface, when it runs on another machine, in a container or in several instances, or when it sits behind a load balancer.

#### Address and Port in Your Application

The options class `DocumentEditorWorkerOptions` sets the `ListenAddress` and `Port` of the backend process from a section of *appsettings.json*. Pass the same address and port to `UseTXWebSocketMiddleware`, for example `app.UseTXWebSocketMiddleware("192.168.3.19", 4567)`; if the values don't match, the editor can't connect. Step 4 of "From the Old Document Editor Backend to the Backend Package" in [Migrating from Previous Versions](https://docs.textcontrol.com/tx-text-control-dotnet-server/installation/upgrading/previous-versions/#from-the-old-document-editor-backend-to-the-backend-package) shows the complete configuration.

#### The Backend's Configuration File

The backend process also reads *TXTextControl.Web.Server.Core.config.json*, which the package deploys next to the worker files. It sets the TCP port, the IP versions and logging:

```json
{
  "Logging": {
    "LogLevel": "Info",
    "LogTarget": "File",
    "FolderPath": "./logs",
    "FileName": "TXTextControl.Web.Server.Core.{date}.log"
  },
  "TcpPort": 5664,
  "SupportedIpVersions": "IPv4"
}
```

| Setting | Description |
|---|---|
| `TcpPort` | The port on which the backend accepts the connections of the middleware |
| `SupportedIpVersions` | `IPv4`, `IPv6` or `Both` |
| `Logging.LogLevel` | How much the backend logs: `None`, `Error`, `Warn`, `Info` or `Debug` |
| `Logging.LogTarget` | Where the backend logs: `Console` or `File`. The file that the package deploys sets `Console`, and `DocumentEditorWorkerManager` forwards the console output to the logging of your application. |
| `Logging.FolderPath` | The folder of the log files when `LogTarget` is `File`, by default *./logs* |
| `Logging.FileName` | The name of the log files when `LogTarget` is `File`; `{date}` is replaced with the current date in the format yyyyMMdd |

If you change the port here, pass it to the middleware as well: `app.UseTXWebSocketMiddleware("localhost", 5664)`. When `DocumentEditorWorkerOptions` in *appsettings.json* also sets a value, that value takes precedence over the file.

### Run the Backend Separately

The backend process doesn't have to run inside your web application. It can run on its own, for example on a dedicated machine, as a Windows service, as a Linux daemon or in a container, as long as the .NET runtime is installed. In that case:

- The TCP port must be reachable from the web application. Open it in the firewall, and in a container, expose and map it.
- Pass the address of the machine or container and the port to `UseTXWebSocketMiddleware`.
- Start the process with the address and port it listens on, as command-line arguments; [The Connection to the Backend Process](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/websockets/#the-connection-to-the-backend-process) shows them.

The [Deployment Guide](https://docs.textcontrol.com/tx-text-control-dotnet-server/deployment/llms-full.txt) describes the setups for Docker, Azure and Linux.

### Scaling and Load Balancing

A session belongs to one backend process, because only that process holds the live document. Behind a load balancer, configure sticky sessions so that each WebSocket connection stays on the same node. Each open session needs memory on the backend; in Text Control's sizing guidance, 50 to 150 MB per session, depending on the loaded spell checking dictionaries. "Scaling Beyond One Instance" in [Product Architecture](https://docs.textcontrol.com/tx-text-control-dotnet-server/overview/architecture/#scaling-beyond-one-instance) describes how to split the workloads, and [Performance and Scalability](https://docs.textcontrol.com/tx-text-control-dotnet-server/performance/llms-full.txt) goes into detail.

The blog article [Scaling TX Text Control Document Editor Applications](https://www.textcontrol.com/blog/2025/12/01/scaling-tx-text-control-document-editor-applications/) explains the recommended setup for many concurrent users.

### Next Steps

- [Loading and Saving Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/load-save/llms-full.txt): get documents into the session and back to your server.
- [Events](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/events/llms-full.txt): the events of initialization, editing and the connection.
- [WebSocket Architecture](https://docs.textcontrol.com/tx-text-control-dotnet-server/integration/websockets/llms-full.txt): the WebSocket connection in detail.
- [WebSocket Security](https://docs.textcontrol.com/tx-text-control-dotnet-server/security/websockets/llms-full.txt): protect the WebSocket endpoint of your application.

---

## Nearby

- **Previous:** [Document Editor](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/llms-full.txt)
- **Next:** [Loading and Saving Documents](https://docs.textcontrol.com/tx-text-control-dotnet-server/document-editor/load-save/llms-full.txt)
