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.
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.
voidbutton1_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); } });}
Private Sub button1_Click(e As EventArgs)
Application.StartTask(Sub()
' Change the text of button 1 from 1 to 10 in the background.'
For i = 0 To 10
Me.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)
Next
End Sub)
End Sub
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.
// 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();});
' this has no effect when the client and server are connected using WebSocket.'
Application.StartPolling(1000)
Application.StartTask(Sub()
For i = 0 To 100
Me.label1.Text = "Counting..." + i
Thread.Sleep(1000)
Next
' 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()
End Sub)
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.
Module Program
Sub New()
' Start the service.'
BackgroundService.Start()
End Sub
...
End Mdule
Module BackgroundService
Private _thread As Thread
Private _stop As Boolean
Public Event Message As BackgroundServiceEventHandler
public Sub Start()
If _thread = null Then
_thread = new Thread(ThreadStart)
End If
_stop = false
_thread.Start()
End Sub
Private Sub ThreadStart()
Dim i as Int32
While Not _stop
Thread.Sleep(1000)
i++
If Not Message Is Nothing Then
Message(Nothing, New BackgroundServiceEventArgs("Hello #" + i))
End If
End While
End Sub
Public Sub Stop()
_stop = true
End Sub
End Module
Handling Events from the Background Service
privatevoidbutton1_Click(object sender,EventArgs e){ // Any number of clients can attach to the event from the Background service.if (_subscribed)BackgroundService.Message-= BackgroundService_Message;elseBackgroundService.Message+= BackgroundService_Message; _subscribed =!_subscribed;this.button1.Text= _subscribed ?"Unsubscribe":"Subscribe";}privatebool _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 to restore the context while executing the code below.privatevoidBackgroundService_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; });}
Private Sub button1_Click(sender As Object, e As EventArgs)
' Any number of clients can attach to the event from the Background service.'
If _subscribed Then
RemoveHander BackgroundService.Message, AddressOf BackgroundService_Message
Else
AddHandler BackgroundService.Message, AddressOf BackgroundService_Message
End If
_subscribed = Not _subscribed
Me.button1.Text = If (_subscribed, "Unsubscribe", "Subscribe")
End Sub
Private _subscribed as Boolean
' The event handler is called by the Background service thread, so the thread'
' does not have any knowledge of the session, but "this" refers to this specific'
' object, which allows Wisej to restore the context while executing the code below.'
Private Sub BackgroundService_Message(sender As Object, e As BackgroundServiceEventArgs)
' Application.Update() can optionally call a code block in context before updating the UI.'
Application.Update(Me, Sub()
Me.label1.Text = e.Message
End Sub)
End Sub
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...