Background Tasks
Background Tasks are one of the most important features of Wisej. There is no other Web development system that allows developers to launch background tasks (threads) on the server and update the client asynchronously with the same level of simplicity and robustness.
Wisej.BackgroundTasks.zip
354KB
Binary
Download Wisej.BackgroundTasks.zip

What is a Background Task?

In short, it's exactly what the name says. It's a task running on the server in the background, which means that the client request has been completed and the user is doing other things while the task is still running.
Background tasks are completely separated from the session and the user that started them. They are simply threads running on their own without any knowledge of the session that started them. In fact, you can start separate threads when an application is loaded the first time without any session or user request.
To run code when an application is loaded the first time, create a static constructor on any class. The most appropriate would Program.cs or the first page or window that they are created for new sessions.
What can I do in a Background Task?
Anything. You can connect to other servers, query the database, use the file system, remote services, etc...
How do I terminate a Background Task?
It's simple, just return from the call. A background task (like any thread) starts by calling your start method. The method will run until you exit it. Typically it's a loop that checks certain conditions and goes to sleep periodically (using Thread.Sleep(ms)) and exits when it's done.

Update the UI

Wisej provides a very simple and straightforward way to launch a Background Task bound to a specific session, allowing the code to interact with the user's UI in real-time.
C#
VB.NET
1
void button1_Click(EventArgs e)
2
{
3
Application.StartTask(() =>
4
{
5
// Change the text of button 1 from 1 to 10 in the background.
6
for (int i = 0; i < 10; i++)
7
{
8
this.button1.Text = i.ToString();
9
10
// We are running out-of-bound and we need to push the updates
11
// to the client using Application.Update(). It can be called at any time
12
// and interval. It simply flushes the changed back to the client.
13
Application.Update(this);
14
15
Thread.Sleep(1000);
16
}
17
});
18
}
Copied!
1
Private Sub button1_Click(e As EventArgs)
2
3
Application.StartTask(Sub()
4
5
' Change the text of button 1 from 1 to 10 in the background.'
6
For i = 0 To 10
7
Me.button1.Text = i.ToString()
8
9
' We are running out-of-bound and we need to push the updates'
10
' to the client using Application.Update(). It can be called at any time'
11
' and interval. It simply flushes the changed back to the client.'
12
Application.Update(this)
13
14
Thread.Sleep(1000)
15
Next
16
End Sub)
17
18
End Sub
Copied!
The example above is able to update the specific button1 in the specific session that started the task by clicking button1 because the thread is started using Application.StartTask().
Application.StartTask() starts a new thread and then updates the context to match the calling session. If you started the thread using Thread.Start() instead, the code in the thread method wouldn't be able to access the objects in the session unless you wrapped the call in Application.RunInContext().
When your code is running in context (either in-bound, or out-of bound for background tasks) you can call Application.Update() at any time to push the UI updates to the client.
If the client or the server doesn't support WebSocket, calling Application.Update() doesn't have any effect since the connection is simply not there. Wisej provides an alternative method to update the client through automatic polling. See Real Time Web Applications and pollingInterval in Configuration.

Systems Without WebSocket

Older clients or servers may not support WebSocket connections, therefore out-of-bound UI updates from a background task cannot be pushed to the client browser.
Wisej provides an alternative method to update the clients, you can use the Application.StartPolling(milliseconds) and Application.EndPolling() methods to make the client periodically poll the server for updates. These methods are ignored when the client is connected using WebSocket.
C#
VB.NET
1
// this has no effect when the client and server are connected using WebSocket.
2
Application.StartPolling(1000);
3
4
Application.StartTask(() => {
5
6
for (int i = 0; i < 100; i++) {
7
this.label1.Text = "Counting..." + i;
8
Thread.Sleep(1000);
9
}
10
11
// this has no effect when the client and server are NOT connected using WebSocket.
12
Application.Update(this);
13
14
// this has no effect when the client and server are connected using WebSocket.
15
Application.EndPolling();
16
});
Copied!
1
' this has no effect when the client and server are connected using WebSocket.'
2
Application.StartPolling(1000)
3
4
Application.StartTask(Sub()
5
6
For i = 0 To 100
7
Me.label1.Text = "Counting..." + i
8
Thread.Sleep(1000)
9
Next
10
11
' this has no effect when the client and server are NOT connected using WebSocket.'
12
Application.Update(this)
13
14
' this has no effect when the client and server are connected using WebSocket.'
15
Application.EndPolling()
16
17
End Sub)
Copied!
Check with Microsoft and other technology providers to determine which platforms support WebSocket connections

Background Task with Multiple Users

Since a Background Task is not bound to a specific session, it can perform global tasks that can serve many users at the same time. The example above shows a task serving a single session (update the text in the button for a specific user), but we can easily create a task that is not bound to any session.
Examples could be a chat server, a stock market watcher, or any other task that periodically checks a resource of any kind. The best way to create such a service would be to fire events from the service (the background task) and let user sessions subscribe to the events.
The example below shows a simplified service that fires an event every second and a client that subscribers to the event.
Wisej.BackgroundService.zip
13KB
Binary
Download Wisej.BackgroundService.zip
C#
VB.NET
1
static class Program
2
{
3
static Program()
4
{
5
// Start the service.
6
BackgroundService.Start();
7
}
8
...
9
}
10
11
public static class BackgroundService
12
{
13
private static Thread _thread;
14
private static bool _stop = false;
15
16
public static event BackgroundServiceEventHandler Message;
17
18
public static void Start()
19
{
20
if (_thread == null)
21
_thread = new Thread(ThreadStart);
22
23
_stop = false;
24
_thread.Start();
25
}
26
27
private static void ThreadStart()
28
{
29
var i = 0;
30
while (!_stop)
31
{
32
Thread.Sleep(1000);
33
34
i++;
35
if (Message != null)
36
Message(null, new BackgroundServiceEventArgs("Hello #" + i));
37
}
38
}
39
40
public static void Stop()
41
{
42
_stop = true;
43
}
44
}
Copied!
1
Module Program
2
3
Sub New()
4
' Start the service.'
5
BackgroundService.Start()
6
End Sub
7
...
8
End Mdule
9
10
Module BackgroundService
11
12
Private _thread As Thread
13
Private _stop As Boolean
14
15
Public Event Message As BackgroundServiceEventHandler
16
17
public Sub Start()
18
19
If _thread = null Then
20
_thread = new Thread(ThreadStart)
21
End If
22
23
_stop = false
24
_thread.Start()
25
End Sub
26
27
Private Sub ThreadStart()
28
29
Dim i as Int32
30
While Not _stop
31
32
Thread.Sleep(1000)
33
34
i++
35
If Not Message Is Nothing Then
36
Message(Nothing, New BackgroundServiceEventArgs("Hello #" + i))
37
End If
38
39
End While
40
End Sub
41
42
Public Sub Stop()
43
_stop = true
44
End Sub
45
46
End Module
Copied!
Handling Events from the Background Service
C#
VB.NET
1
private void button1_Click(object sender, EventArgs e)
2
{
3
// Any number of clients can attach to the event from the Background service.
4
if (_subscribed)
5
BackgroundService.Message -= BackgroundService_Message;
6
else
7
BackgroundService.Message += BackgroundService_Message;
8
9
_subscribed = !_subscribed;
10
this.button1.Text = _subscribed ? "Unsubscribe" : "Subscribe";
11
}
12
private bool _subscribed;
13
14
// The event handler is called by the Background service thread, so the thread
15
// doesn't have any knowledge of the session, but "this" refers to this specific
16
// object, which allows Wisej to restore the context while executing the code below.
17
18
private void BackgroundService_Message(object sender, BackgroundServiceEventArgs e)
19
{
20
// Application.Update() can optionally call a code block in context before updating the UI.
21
Application.Update(this, () =>
22
{
23
this.label1.Text = e.Message;
24
});
25
}
Copied!
1
Private Sub button1_Click(sender As Object, e As EventArgs)
2
3
' Any number of clients can attach to the event from the Background service.'
4
If _subscribed Then
5
RemoveHander BackgroundService.Message, AddressOf BackgroundService_Message
6
Else
7
AddHandler BackgroundService.Message, AddressOf BackgroundService_Message
8
End If
9
10
_subscribed = Not _subscribed
11
Me.button1.Text = If (_subscribed, "Unsubscribe", "Subscribe")
12
End Sub
13
14
Private _subscribed as Boolean
15
16
' The event handler is called by the Background service thread, so the thread'
17
' does not have any knowledge of the session, but "this" refers to this specific'
18
' object, which allows Wisej to restore the context while executing the code below.'
19
20
Private Sub BackgroundService_Message(sender As Object, e As BackgroundServiceEventArgs)
21
22
' Application.Update() can optionally call a code block in context before updating the UI.'
23
Application.Update(Me, Sub()
24
Me.label1.Text = e.Message
25
End Sub)
26
27
End Sub
Copied!
It's hard to overestimate the power and simplicity of background tasks in Web applications and the simplicity provided by the Wisej framework. You can handle the browser from the server as if it was a "screen" directly connected to the server...