Skip to main content

Background Tasks

WATCH & LEARN0:50 · Animated tutorial
7 scenesPlay, pause, or scrub at your own pace

Background tasks let you run work on server threads and update the client asynchronously. Wisej.NET provides methods to start these tasks, associate them with a user session, and send UI updates to the browser.

Download Wisej.BackgroundTasks.zip

What is a Background Task?​

A Background Task runs on the server in the background after the client request has completed, allowing users to continue working while the task executes.

A background thread does not automatically inherit the session of the user who started it. You can also start threads when an application first loads, before any session or user request exists. To work with a user's UI, associate the task with that session using the methods described below.

info

To run code when an application first loads, create a static constructor on any class. The most appropriate would be Program.cs or the first page or window created for new sessions.

What can I do in a Background Task?

A background task can connect to other servers, query databases, use the file system, access remote services, and perform other server-side work.

How do I terminate a Background Task?

A background task ends when its start method returns. A repeating task can use a loop that checks a stop condition and pauses between iterations with Thread.Sleep(ms). To end the task, exit the loop and return from the method.

Update the UI​

Wisej.NET provides a straightforward way to launch a Background Task bound to a specific session, allowing code to interact with the user's UI in real-time.

void button1_Click(EventArgs e)
{
Application.StartTask(() =>
{
// Change the text of button 1 from 1 to 10 in the background.
for (int i = 0; i < 10; i++)
{
this.button1.Text = i.ToString();

// We are running out-of-bound and we need to push the updates
// to the client using Application.Update(). It can be called at any time
// and interval. It simply flushes the changed back to the client.
Application.Update(this);

Thread.Sleep(1000);
}
});
}

The example above updates the specific button1 in the session that started the task because the thread is started using Application.StartTask().

Application.StartTask() starts a new thread and sets its context to the calling session. A thread started with Thread.Start() has no such context; wrap code that needs session access in Application.RunInContext().

When code runs in a session context, either during a client request or in a background task, you can call Application.Update() to push pending UI changes to the client. This is especially useful in a background task, where there is no client request waiting for a response.

danger

If the client or server doesn't support WebSocket, Application.Update() has no effect since the connection doesn't exist. Wisej.NET provides alternative client updates through automatic polling. See Real Time Web Applications and pollingInterval in Configuration.

Systems Without WebSocket​

Older clients or servers may not support WebSocket connections, preventing out-of-bound UI updates from background tasks reaching the client browser.

Wisej.NET provides alternative client updates using Application.StartPolling(milliseconds) and Application.EndPolling() to enable periodic server polling. These methods are ignored when using WebSocket connections.

// this has no effect when the client and server are connected using WebSocket.
Application.StartPolling(1000);

Application.StartTask(() => {

for (int i = 0; i < 100; i++) {
this.label1.Text = "Counting..." + i;
Thread.Sleep(1000);
}

// this has no effect when the client and server are NOT connected using WebSocket.
Application.Update(this);

// this has no effect when the client and server are connected using WebSocket.
Application.EndPolling();
});
info

Check with Microsoft and other technology providers to determine which platforms support WebSocket connections

Background Task with Multiple Users​

Background tasks can also run independently of any session and serve multiple users. Unlike the previous example, which uses Application.StartTask() to associate a task with one session, a shared background service does its work outside a specific user's context.

Examples include chat servers, stock market watchers, and services that check resources periodically. A useful approach is to raise events from the background service and let individual sessions subscribe. Each subscriber then updates its own UI in its session context.

Below is a simplified service firing events every second with a subscribing client.

Download Wisej.BackgroundService.zip

static class Program
{
static Program()
{
// Start the service.
BackgroundService.Start();
}
...
}

public static class BackgroundService
{
private static Thread _thread;
private static bool _stop = false;

public static event BackgroundServiceEventHandler Message;

public static void Start()
{
if (_thread == null)
_thread = new Thread(ThreadStart);

_stop = false;
_thread.Start();
}

private static void ThreadStart()
{
var i = 0;
while (!_stop)
{
Thread.Sleep(1000);

i++;
if (Message != null)
Message(null, new BackgroundServiceEventArgs("Hello #" + i));
}
}

public static void Stop()
{
_stop = true;
}
}

Handling Events from the Background Service

private void button1_Click(object sender, EventArgs e)
{
// Any number of clients can attach to the event from the Background service.
if (_subscribed)
BackgroundService.Message -= BackgroundService_Message;
else
BackgroundService.Message += BackgroundService_Message;

_subscribed = !_subscribed;
this.button1.Text = _subscribed ? "Unsubscribe" : "Subscribe";
}
private bool _subscribed;

// The event handler is called by the Background service thread, so the thread
// doesn't have any knowledge of the session, but "this" refers to this specific
// object, which allows Wisej.NET to restore the context while executing the code below.

private void BackgroundService_Message(object sender, BackgroundServiceEventArgs e)
{
// Application.Update() can optionally call a code block in context before updating the UI.
Application.Update(this, () =>
{
this.label1.Text = e.Message;
});
}

This pattern lets a shared server-side service update each subscribed browser through the corresponding session's controls.