This ASP.NET Core application is a runnable integration sample for
TXTextControl.Web.Collaboration. It demonstrates how an application can maintain a
source-document library, create or reopen collaboration rooms, connect the TX Text
Control Document Editor through the collaboration Tag Helper, and publish the current
room document back to its source.
The sample deliberately keeps application storage separate from collaboration room
storage. Files in Data are source documents. A room owns an authoritative TX document
that is synchronized automatically while users edit it. The source file changes only
when Save to source is selected on the document-library page.
- Lists
.txand.docxfiles from the application'sDatadirectory. - Creates at most one active room for each source document.
- Converts DOCX files to TX Text Control Internal Unicode Format before creating a room.
- Reopens an existing room instead of creating a second room for the same document.
- Uses protected room-access tokens for owners and invited collaborators.
- Renders the collaboration presence and sharing interface with the
<tx-collaboration>Tag Helper. - Uses server-side editor access and TX fragment synchronization for ordinary edits.
- Persists active collaboration rooms and restores them after an application restart.
- Exports the authoritative TX master and converts it back to DOCX when required.
- Detects when a source file was changed outside the room before overwriting it.
- .NET 10 SDK
- A valid TX Text Control license
- Access to the TX Text Control NuGet packages used by the project
The project references:
TXTextControl.TextControl.Core.SDK34.0.4TXTextControl.Web34.4.0TXTextControl.Web.DocumentEditor.Backend34.4.0TXTextControl.Web.Collaboration34.0.0-alpha, through a project reference by default
From the solution directory:
dotnet run --project tests/TXTextControl.Web.Collaboration.TestAppThe launch profile uses:
https://localhost:61484http://localhost:61485
If HTTPS is not trusted locally, use the HTTP address or trust the ASP.NET Core development certificate.
The application starts the TX Text Control Document Editor backend in-process by
default. Set TextControl:StartEditorBackend to false when the editor is connected to
an externally managed backend.
- Enter the name that should appear in collaboration presence.
- Select Add to collaboration for an available source document.
- Use Share in the collaboration bar to create an invitation for another user.
- Open the invitation in another browser or private window and edit from both sessions.
- Return to Document library. The active room continues to contain the current authoritative document.
- Select Save to source to export the room master to the original TX or DOCX file.
- Select Close room when collaboration is complete.
Closing a room does not implicitly publish it to the source file. Save first when the room's final state should replace the source document.
The collaboration package operates exclusively on TX Text Control Internal Unicode Format. Format conversion is therefore an application responsibility:
- TX sources are passed to
CreateRoomFromFileAsyncdirectly. - DOCX sources are loaded by
ServerTextControl, converted to TX, and passed toCreateRoomAsyncas a byte array. ExportDocumentAsyncreturns the current authoritative TX room document.- When saving a DOCX source, the sample converts the exported TX document back to WordprocessingML before replacing the source file.
SampleDocumentService hashes the original source. If the file changes outside the
room, Save to source reports a conflict instead of overwriting the newer file.
Add additional .tx or .docx files to the Data directory to make them available on
the document-library page. Files are copied to build and publish output.
The sample uses three related persistence areas:
App_Data/CollaborationRoomscontains the collaboration package's authoritative TX room documents and metadata.App_Data/SampleCollaborationRooms.jsonmaps source files to their active room IDs so the portal can restore its active-room list.App_Data/DataProtectionKeyscontains the ASP.NET Core Data Protection key ring used for room-access tokens.
The configured room retention is 168 hours. Persistence protects the current room
state, but it does not automatically update files in Data.
The collaboration package reads TextControl:Collaboration. The test application also
uses TextControl:StartEditorBackend to decide whether it should host the TX Text
Control Document Editor backend itself.
| Setting | Sample value | Purpose |
|---|---|---|
TextControl:StartEditorBackend |
true (implicit) |
Registers DocumentEditorWorkerManager and starts the TX Document Editor backend in this process. The key is omitted from the sample file because Program.cs defaults it to true. Set it to false only when the editor is configured to use an externally managed backend. |
AllowedHosts |
* |
Standard ASP.NET Core host filtering. The wildcard accepts every host header and is convenient for a test app. Restrict it to the deployed host names in production. |
Logging:LogLevel:Default |
Information |
Sets the default console logging threshold. Use Debug while diagnosing collaboration worker timings or synchronization fallbacks. |
Logging:LogLevel:Microsoft.AspNetCore |
Warning |
Reduces routine ASP.NET Core request and infrastructure messages while retaining warnings and errors. |
The application clears the framework's default logging providers and adds the console
provider in Program.cs, so these logging levels control console output.
| Setting | Sample value | Purpose |
|---|---|---|
TextControl:Collaboration:HubPath |
/tx-collaboration/hub |
Application-relative route mapped to the collaboration SignalR hub. The Tag Helper uses the same route when it connects the browser component. |
TextControl:Collaboration:PublicPathBase |
Empty (implicit) | Externally visible path prefix when a reverse proxy removes that prefix before forwarding requests, for example /collaboration. It must begin with / and cannot contain ? or #. Leave it empty when the application is hosted at the site root or ASP.NET Core already sets HttpRequest.PathBase. |
For example, if the public URL is https://example.com/collaboration but the proxy
forwards requests to the application without /collaboration, add:
{
"TextControl": {
"Collaboration": {
"PublicPathBase": "/collaboration"
}
}
}This prefixes the generated static-asset and SignalR URLs. It does not change the
internal HubPath route.
| Setting | Sample value | Valid values and behavior |
|---|---|---|
Sharing:Users |
Ada Lovelace, Grace Hopper, Alan Turing | Display names offered by the collaboration bar's invitation picker. This list is presentation and invitation configuration; the consuming application remains responsible for deciding who may access a room. |
Sharing:AllowFreeTextUsers |
true |
When true, the inviter can enter a display name not present in Users. When false, invitations are limited to predefined names. |
Sharing:InvitationLifetimeHours |
168 |
Number of hours before a generated access token expires. Valid range: 1-8760. Existing editor connections are not a reason to reuse expired invitation URLs; generate a new invitation instead. |
The protected invitation stores the assigned user name, room ID, expiration, and a unique nonce. The collaboration hub takes the presence name from this protected token, not from an editable query-string value.
| Setting | Sample value | Valid values and behavior |
|---|---|---|
Workers:WorkerCount |
2 |
Number of isolated TX worker processes. Valid range: 1-32. A room is consistently assigned to one worker by hashing its document ID. Workers are reused across rooms; this is not one worker per document. More workers increase parallel document throughput but also increase process, memory, and CPU overhead. |
Workers:QueueCapacityPerWorker |
32 |
Maximum queued operations for each worker. Valid range: 1-4096. The bounded queue prevents unlimited memory growth when requests arrive faster than TX operations complete. |
Workers:StartupTimeoutSeconds |
30 |
Maximum time allowed for a worker process to start and connect. Valid range: 5-300 seconds. Increase it only when process startup is consistently slower in the hosting environment. |
Workers:RequestTimeoutSeconds |
90 |
Maximum time for one TX worker request. Valid range: 5-600 seconds. Long documents or unusually expensive structural comparisons may need more time, but increasing this also delays failure recovery. |
Workers:RestartAttempts |
1 |
Number of worker restart and retry attempts after a failed request. Valid range: 0-5. A value of 0 disables retry. |
Workers:MaxMessageSizeMegabytes |
128 |
Maximum named-pipe request or response size. Valid range: 16-1024 MB. The package also raises the SignalR receive limit sufficiently for the corresponding Base64 payload used by defensive client-side fallbacks. This is a limit, not preallocated memory. |
Workers:DotNetHostPath |
Empty (implicit) | Optional path to the dotnet executable used to launch isolated workers. Leave empty to use the current/default .NET host. Configure it when the hosting environment requires a specific runtime path. |
Each worker serializes its own TX operations because ServerTextControl contains
process-level critical sections. Different rooms assigned to different workers can be
processed concurrently. If the queues are regularly saturated, first inspect full-update
frequency and TX operation duration before increasing WorkerCount or queue capacity.
| Setting | Sample value | Valid values and behavior |
|---|---|---|
Synchronization:DocumentAccessMode |
ServerSide |
ServerSide reads and applies editor ranges through the TX WebSocket handler in the application process. ClientSide uses asynchronous TX JavaScript calls and transports TX selections or complete documents through SignalR. |
Synchronization:DirectEditorAccessEnabled |
true |
Operational kill switch for direct WebSocket-handler access. It affects only ServerSide mode. If disabled or if an editor connection cannot be registered, synchronization uses the client transport recovery path. |
Synchronization:FragmentUploadsEnabled |
true |
Allows changed TX ranges to be captured or uploaded as fragments. Disabling it makes normal synchronization rely more heavily on complete-document commits and is intended mainly for diagnosis or compatibility recovery. |
Synchronization:CommitIdleMilliseconds |
400 |
Quiet period after the latest edit before a pending change is committed. Valid range: 250-10000 ms. Lower values feel more immediate but create more commits during short typing pauses; higher values reduce request frequency but increase collaboration latency. Starting to type again restarts the idle timer. |
Synchronization:ReconciliationIntervalSeconds |
25 |
Base idle interval between complete authoritative verification passes. Valid range: 10-300 seconds. Reconciliation detects edits missed by the normal event/fragment path. A lower value finds mismatches sooner but performs more complete-document work. |
Synchronization:MaximumReconciliationIntervalSeconds |
300 |
Maximum adaptive interval after consecutive successful reconciliations. Valid range: the configured base interval through 1800 seconds. New edits, reconnects, and mismatches reset the interval toward the base value. |
Synchronization:MaximumFragmentKilobytes |
4096 |
Maximum TX fragment size before synchronization chooses the complete-document fallback. Valid range: 64-65536 KB. Increase it for intentionally large paste or table operations; decrease it to cap individual fragment payloads. |
Synchronization:MaximumVersionSnapshots |
12 |
Maximum retained master versions per document for rebasing concurrent edits. Valid range: 2-128. Older versions are discarded first. A client based on a discarded version receives normal full-refresh recovery. |
Synchronization:MaximumVersionSnapshotMegabytes |
32 |
Total memory budget for retained version snapshots per document. Valid range: 8-2048 MB. Snapshot count and byte budget are both enforced; whichever limit is reached first removes the oldest history. |
The test app's ServerSide mode avoids transferring complete document content through
the browser for normal edits. Ordinary paragraph, formatting, and complete-table
changes are processed as TX fragments. Structural or ambiguous changes retain the
defensive full-document path. Server-side access requires the collaboration hub and TX
Document Editor WebSocket handler to run in the same application process. A scaled-out
deployment therefore needs sticky routing for both connections.
Reconciliation is intentionally still enabled in the optimized mode. It compares the complete editor document with the authoritative master after an idle period and repairs a mismatch, ensuring that an edit missed by an editor event is not silently lost.
| Setting | Sample value | Valid values and behavior |
|---|---|---|
Persistence:Enabled |
true |
Selects the package's file-system room store. When false, collaboration rooms are kept only in process and disappear when the application stops. |
Persistence:DirectoryPath |
App_Data/CollaborationRooms |
Directory containing authoritative TX masters and room metadata. A relative path is resolved from the application content root; an absolute path is used as given. The application identity needs read/write access. |
Persistence:RoomRetentionHours |
168 |
Inactivity period before a persisted room expires. Valid range: 1-8760 hours. Connected rooms are not removed by cleanup. |
Persistence:CleanupIntervalMinutes |
30 |
Frequency of expired-room cleanup. Valid range: 1-1440 minutes. This controls how soon an already-expired room is discovered, not its retention deadline. |
Persistence:FlushDelayMilliseconds |
1000 |
Quiet period before the newest accepted room version is written to storage. Valid range: 0-10000 ms. Updates are broadcast immediately; repeated writes during this window are coalesced. Pending writes are flushed during graceful application shutdown. |
Room persistence is not source-file persistence. It protects and restores the live TX
master under App_Data/CollaborationRooms, but only Save to source updates the .tx
or .docx file in Data.
ASP.NET Core configuration can override any setting without editing appsettings.json.
Use double underscores in environment-variable names. For example, in PowerShell:
$env:TextControl__StartEditorBackend = "false"
$env:TextControl__Collaboration__Workers__WorkerCount = "4"
$env:TextControl__Collaboration__Synchronization__CommitIdleMilliseconds = "500"
dotnet run --project tests/TXTextControl.Web.Collaboration.TestAppInvalid collaboration values fail validation during application startup with a message containing the full configuration key and accepted range.
The application shows the minimum package integration in Program.cs:
builder.Services.AddTXTextControlCollaboration(
builder.Configuration.GetSection(TxTextControlCollaborationOptions.DefaultSectionName));
builder.Services.AddHostedService<DocumentEditorWorkerManager>();
app.UseWebSockets();
app.UseTXWebSocketMiddleware();
app.MapTxTextControlCollaboration();Views/_ViewImports.cshtml registers the collaboration Tag Helper. The room view then
connects the package and editor without a manual collaboration script reference:
<tx-collaboration room-token="@Model.AccessToken" />
<div data-tx-collaboration-editor>
@Html.TXTextControl()
.TextControl(settings => settings.Dock = TXTextControl.Web.DockStyle.Fill)
.Render()
</div>The Tag Helper renders the internal web component and adds the versioned collaboration JavaScript and stylesheet automatically.
The project consumes the collaboration source project by default. To test a packed package instead, configure a package source containing the package and run:
dotnet run --project tests/TXTextControl.Web.Collaboration.TestApp `
-p:UsePackedCollaborationPackage=true `
-p:CollaborationPackageVersion=34.0.0-alphaThe test app includes small endpoints used by integration checks:
/_test/serviceslists registered hosted services./_test/resolveconfirms thatITxTextControlCollaborationresolves./_test/collaboration/{roomId}reports whether an authoritative room document can be exported and returns its byte length.
These endpoints are test conveniences and are not part of the package's public API.