Under rare conditions, the creation of a new ServerTextControl TX Text Control .NET Server for ASP.NET
TXTextControl Namespace
ServerTextControl Class
The ServerTextControl class implements a component that provide high-level text processing features for server-based applications.
instance can fail and the Dispose method returns false. In these cases, the instance itself exists, but cannot be used. For example, a typical error when loading a document with an instance that could not be created is:

The TXTextControl object must have been completely loaded to use this method.

In these cases, the Create TX Text Control .NET Server for ASP.NET
TXTextControl Namespace
ServerTextControl Class
Create Method
Initializes the resources of a newly instantiated object.
method returned false and the instance should not be used.

Restart IIS?

Some users report that only an IIS restart helps to resolve this situation. Technically, a restart helps as the process is re-created and existing USER handles are being released. But in fact, only USER handles must be released and there is no need to restart IIS or the worker process.

Possible Reasons

The most typical reason that a ServerTextControl cannot be created is that it is not possible to create a new Window handle. In Windows, there is a limit of 10,000 USER handles and 10,000 GDI objects handles. If this number is exceeded, it is not possible to create a new ServerTextControl instance. In typical applications, it is very most unlikely that this number of handles is created.

Sometimes, we see reports from users that this issue is caused after several days and very inconsistent or sporadic. Most likely, in these cases, the ServerTextControl instances are not properly disposed. It is very important to dispose ServerTextControl objects explicitly. We recommend to use them in a using statement:

using (ServerTextControl serverTextControl = new ServerTextControl()) {
serverTextControl.Create();
}
view raw test.cs hosted with ❤ by GitHub

A better way would be to check whether the Create method has been called successfully:

using (ServerTextControl serverTextControl = new ServerTextControl()) {
if (serverTextControl.Create() == true) {
// ...
}
}
view raw test.cs hosted with ❤ by GitHub

ServerTextControl Factory Class

To monitor the created instances, we implemented a factory class that returns valid instances of ServerTextControl. This diagnostics class can be also used to check the number of active instances, USER handles and GDI handles. Additionally, it can be used to dispose all active instances.

using System.Diagnostics;
using System.Runtime.InteropServices;
namespace TXTextControl.Diagnostics {
/// <summary>
/// Singleton factory class to return and manage ServerTextControl instances.
/// </summary>
public sealed class ServerTextControlFactory {
// private fields
private static readonly ServerTextControlFactory _instance =
new ServerTextControlFactory();
private List<ServerTextControl> _activeControls;
[DllImport("User32")]
extern public static int GetGuiResources(IntPtr hProcess, int uiFlags);
private enum ResourceType {
Gdi = 0,
User = 1
}
static ServerTextControlFactory() {
}
private ServerTextControlFactory() {
_activeControls = new List<ServerTextControl>();
}
/// <summary>
/// Returns the singleton instance.
/// </summary>
public static ServerTextControlFactory Instance {
get {
return _instance;
}
}
/// <summary>
/// Returns the number of active ServerTextControls that are not disposed.
/// </summary>
public int Count {
get {
return _activeControls.Count;
}
}
/// <summary>
/// Returns the total number of USER handles in current process.
/// </summary>
public int UserHandles {
get {
var processHandle = Process.GetCurrentProcess().Handle;
return GetGuiResources(processHandle, (int)ResourceType.User);
}
}
/// <summary>
/// Returns the total number of GDI handles in current process.
/// </summary>
public int GdiHandles {
get {
var processHandle = Process.GetCurrentProcess().Handle;
return GetGuiResources(processHandle, (int)ResourceType.Gdi);
}
}
/// <summary>
/// Disposes all active ServerTextControl instances.
/// </summary>
public int DisposeAll() {
int numControls = _activeControls.Count;
int i;
for (i = 0; i < numControls; i++) {
_activeControls[0].Dispose();
}
return i;
}
/// <summary>
/// Returns a new ServerTextControl instance and adds it to the list of
/// active instances.
/// Returns null in case a new ServerTextControl instance could not be created.
/// </summary>
public ServerTextControl? CreateServerTextControl() {
// create a new ServerTextControl instance and listen for the disposal
ServerTextControl serverTextControl = new ServerTextControl();
// trying to create - if creation fails, dispose the object and return null
if (serverTextControl.Create() == false) {
serverTextControl.Dispose();
return null;
}
// attached the Disposed event to clean up list of instances
serverTextControl.Disposed += ServerTextControl_Disposed;
// add to list of instances
_activeControls.Add(serverTextControl);
return serverTextControl;
}
private void ServerTextControl_Disposed(object sender, EventArgs e) {
// remove from list of instances
_activeControls.Remove((ServerTextControl)sender);
}
}
}
view raw factory.cs hosted with ❤ by GitHub

Using the Class

This class uses the singleton pattern and can be created only once in an application:

ServerTextControlFactory serverTextControlFactory = ServerTextControlFactory.Instance;
view raw test.cs hosted with ❤ by GitHub

Once created, the CreateServerTextControl method creates and returns a new instance:

using (ServerTextControl? tx = serverTextControlFactory.CreateServerTextControl()) {
if (tx != null) {
tx.Text = "Test";
}
}
view raw test.cs hosted with ❤ by GitHub

When using this factory class, it is not required to create the ServerTextControl before using it. This is handled in the factory itself.

The ServerTextControlFactory creates and returns a new instance of ServerTextControl and stores it in a list. In case the instance cannot be created, the class returns null. When the instance is disposed, it is removed from that list again automatically. The method ServerTextControlFactory.Count returns the number of active ServerTextControl instances.

When executing the following code, the created ServerTextControl instance is disposed explicitly in the using statement. Therefore, the counter should be 0 after a successful execution.

using (ServerTextControl tx = serverTextControlFactory.CreateServerTextControl()) {
Console.WriteLine(serverTextControlFactory.Count);
if (tx != null) {
tx.Text = "Test";
}
}
Console.WriteLine(serverTextControlFactory.Count);
view raw test.cs hosted with ❤ by GitHub
Number of instances: 1
Number of instances: 0

In case the ServerTextControl is not disposed, the active instance stays in the list until disposed:

Console.WriteLine("Number of instances: {0}", serverTextControlFactory.Count);
ServerTextControl tx = serverTextControlFactory.CreateServerTextControl();
Console.WriteLine("Number of instances: {0}", serverTextControlFactory.Count);
view raw test.cs hosted with ❤ by GitHub
Number of instances: 0
Number of instances: 1

Debugging

When using this factory class in your application, you can always monitor the number of instances to find leaks. In case you would like to dispose all instances - for debugging purposes - the factory class provides the DisposeAll method that loops through all stored instances in order to dispose them:

Console.WriteLine("Number of instances: {0}", serverTextControlFactory.Count);
for (int i = 0; i < 5; i++) {
ServerTextControl tx = serverTextControlFactory.CreateServerTextControl();
Console.WriteLine("Number of instances: {0}", serverTextControlFactory.Count);
}
Console.WriteLine("Disposed instances: {0}", serverTextControlFactory.DisposeAll());
view raw test.cs hosted with ❤ by GitHub
Number of instances: 0
Number of instances: 1
Number of instances: 2
Number of instances: 3
Number of instances: 4
Number of instances: 5
Disposed instances: 5

Handle Counter

Additionally, the factory class provides properties to return the number of USER and GDI handles in the current process:

Console.WriteLine("USER handles: {0}", serverTextControlFactory.UserHandles);
Console.WriteLine("GDI handles: {0}", serverTextControlFactory.GdiHandles);
view raw test.cs hosted with ❤ by GitHub
USER handles: 30
GDI handles: 26

Further Help

If you need assistance of further help debugging these kind of problems, talk to our engineers - we are here to help!