Load Balancing: Using Different TCP Service Locations using a Custom WebSocketHandler
The Text Control online document editor requires a backend TCP service to synchronize the document rendering. This article explains how to route the synchronization traffic to different servers dynamically using a custom WebSocketHandler.

When deploying the TX Text Control document editor in an ASP.NET Core (.NET 5) Web Application, the synchronization service can be deployed separately to one or more Windows VMs. This can be useful when separating the web application from the Text Control stack for deployment reasons (for example when deploying your web application to Azure App Services running on Linux) or when load balancing the TCP synchronization service separately.
In order to do this, a custom WebSocketMiddleware can be implemented.
What is a WebSocketMiddleware?
TX Text Control uses a WebSocket connection from the browser to an application layer that handles the traffic between the client and the TCP synchronization service. The WebSocketHandler (part of TX Text Control), routes the synchronization calls from and to the TCP service. The WebSocketMiddleware is creating an instance of the WebSocketHandler.
The ASP.NET (Core) MVC NuGet package that is required to implement the document editor comes with a standard, out-of-the-box WebSocketMiddleware that connects to a TCP service that runs on the same machine.
The following class CustomWebSocketMiddleware implements a custom WebSocketMiddleware:
using Microsoft.AspNetCore.Http;
using System.Collections.Generic;
using System.Net;
using System.Threading.Tasks;
using TXTextControl.Web;
public class CustomWebSocketMiddleware {
private RequestDelegate m_next;
private IPAddress m_serviceAddress;
private int m_servicePort;
// list of available backend TCP services
internal readonly List<byte[]> DefaultServiceAddress =
new List<byte[]>() {
new byte[] { 127, 0, 0, 2 },
new byte[] { 127, 0, 0, 1 }
};
internal const int DefaultServicePort = 4278;
public CustomWebSocketMiddleware(RequestDelegate next) {
m_next = next;
m_serviceAddress = new IPAddress(DefaultServiceAddress[0]);
m_servicePort = DefaultServicePort;
}
public async Task Invoke(HttpContext context) {
if (context.WebSockets.IsWebSocketRequest &&
context.WebSockets.WebSocketRequestedProtocols.Contains("TXTextControl.Web")) {
// server id from query string (provided in view code)
int serverId = int.Parse(context.Request.Query["server"]);
// create a new WebSocketHandler with random server
var ws = new WebSocketHandler(
new IPAddress(DefaultServiceAddress[serverId]),
m_servicePort);
await ws.Invoke(context);
}
else if (m_next != null) {
await m_next.Invoke(context);
}
}
}
As described in a previous blog article, the custom WebSocketMiddleware must be added to the Startup.cs:
app.UseMiddleware<CustomWebSocketMiddleware>();
In the view code, an additional query string is provided to the WebSocketURL property:
@using TXTextControl.Web.MVC
@{
Random rand = new Random();
string serverId = rand.Next(0, 2).ToString();
// build WebSocketURL including a server id in query string
var sProtocol = (Context.Request.IsHttps) ? "wss://" : "ws://";
var sWebSocketURL = sProtocol + Context.Request.Host
+ "/TXWebSocket?server=" + serverId;
}
@Html.TXTextControl().TextControl(settings => {
settings.WebSocketURL = sWebSocketURL;
}).Render()
This workflow is just a simplified idea of what can be done using a custom WebSocketMiddleware. A random value (1 or 0) is passed as a query string to the WebSocketMiddleware. In the WebSocketMiddleware itself, a specific IP is used from a list of IP addresses based on the given random index value from the query string.
// server id from query string (provided in view code)
int serverId = int.Parse(context.Request.Query["server"]);
// create a new WebSocketHandler with random server
var ws = new WebSocketHandler(
new IPAddress(DefaultServiceAddress[serverId]),
m_servicePort);
Following this simple workflow, a random load balancer has been implemented that routes the TCP traffic to 2 different servers.
Pro tip
A custom WebSocketMiddleware can be also used to create an instance of the WebSocketHandler without passing a value from the view code. Typically, when changing the IP address of the TCP backend or when providing this IP dynamically.
Angular
Integrate document processing, editing, sharing, collaboration, creation, electronic signatures, and PDF generation into your Angular Web applications.
Related Posts
Building an ASP.NET Core Backend Application to Host the Document Editor and…
This article explains how to create an ASP.NET Core backend application to host the Document Editor and Document Viewer. This backend application is required to provide the required functionality…
Deploying the TX Text Control Document Editor Backend Web Server in Docker
This article describes how to deploy the TX Text Control Document Editor backend web server in Docker. The backend web server is a .NET Core application that provides the required synchronization…
Configuring the TX Text Control Document Editor Backend Web Server,…
This article describes how to configure the TX Text Control Document Editor Backend Web Server, including port and logging settings.
Designing a Maintainable PDF Generation Web API in ASP.NET Core (Linux) C#…
This article shows how to create a PDF generation Web API in ASP.NET Core on Linux using TX Text Control .NET Server. The clean architecture is used to create a maintainable and testable solution.
Building an ASP.NET Core Backend (Linux and Windows) for the Document Editor…
This article shows how to create a backend for the Document Editor and Viewer using ASP.NET Core. The backend can be hosted on Windows and Linux and can be used in Blazor, Angular, JavaScript, and…