Application

Represent a Wisej application session. Provides methods and events to manage the application in the context of the current session

The Application class exposes to the application everything it needs to interact with the session, the user's browser, and all system events. It is a static class but all the properties, methods, and events are isolated by session.

You can use it to:

  • Save custom data in the Application.Session object.

  • Read the server variables in the Application.ServerVariables collection.

  • Read the Default.json configuration in the Application.Configuration property.

  • Handle application's exceptions using the Application.ThreadException event.

  • Handle the session disposal using the Application.ApplicationExit event.

  • Manage session expiration with the Application.SessionTimeout event.

  • Detect changes in the client device profile using the Application.ResponsiveProfileChanged, see Responsive Properties.

  • Access the logged-in user through the Application.User and Application.UserIdentity properties.

  • Read the current Application.Url and the Application.StartupUrl to extract the arguments, or use Application.QueryString for the collection of the argument name and values in the URL.

  • Download files to the browser with Application.Download() or open them in the browser using Application.DownloadAndOpen().

  • Change the culture programmatically by setting the Application.CurrentCulture property.

  • Read the current theme using the Application.Theme property.

  • Manage the browser's cookies using Application.Cookies or Application.Browser.CookieStorage. See Cookies for more details.

Session Object

Application.Session is a dynamic object that can store any kind of object. You can use it as if it was a regular object like this:

// save something in the session
Application.Session.MyName = "Wisej";
Application.Session.MyComplexDataObject  = new TestApp.Data.EmployeesList();

// retrieve session variables.
string name = Application.Session.MyName;
TestApp.Data.EmployeesList data = Application.Session.MyComplexDataObject

Notice that since Application.Session is a dynamic object you can just add any field. You are just limited by the name since it must be compilable. If you want to use a variable name with dots, dashes, or any non-compilable character, use it through the indexer:

Application.Session.value = "Hello";
Application.Session["my-complex-@var-name"] = 12
string value = Application.Session["value"]; 

Option Strict Off

In VB.NET in order to use dynamic fields, you must have Option Strict Off. Otherwise, always use the Session with the (name) indexer.

Server Variables

All the server variables that are supported by the Web server are available in Application.ServerVariables. Some well known and common server variables are also available as properties of the Application class:

  • UserAgent is "HTTP_USER_AGENT"

  • UserHostAddress is "REMOTE_ADDR"

  • UserHostName is "REMOTE_HOST"

  • UserLanguages is "HTTP_ACCEPT_LANGUAGE" split by a comma

  • ServerName is "SERVER_NAME"

  • ServerPort is "SERVER_PORT" parsed into an integer

Different web servers add different server variables. Don't expect all the server variables to be always present.

Application Events

There are many global events exposed by the Application class. They let your code receive all sorts of notifications from the Wisej infrastructure.

Exception Handling

In addition to the regular exception handling that you have in your code, Wisej lets you handle any unhandled exception through the Application.ThreadException event.

Exceptions are suppressed simply by handling the Application.ThreadException event. Once you attach a handler, it is up to your code to log, show, do nothing, or rethrow the exception.

Session Events

There are three events that are relevant to the session management system in Wisej:

NameDescription

ApplicationStart

Fired after the application is started, after the Program.Main() method is executed. It is fired only once for each new session.

ApplicationExit

Fired when the session is expired and is being disposed. At this point, the session is not recoverable. This is similar to a desktop application being closed.

SessionTimeout

Fired when the session is about to time out due to user inactivity. You can suppress the default behavior setting e.Handled = true. Otherwise, Wisej will show the built-in SessionTimeoutForm.

Threading

Use Application.ThreadBegin and Application.ThreadEnd to receive a notification every time Wisej starts a new thread processing code in your application, including Application.StartTask(). This event can be used to clear or initialize thread static variables using the advanced coding pattern below:

// Reset the thread static.
Application.ThreadBegin += (s, e) =>
{
	_test = null;
};
Application.ThreadEnd += (s, e) =>
{
	_test = null;
};

// Session-static variable.
public static String Test
{
	get
	{
		if (_test == null)
			_test = Application.Session.test;

		return _test;
	}
	set
	{
		value = value ?? string.Empty;
		_test = value;
		Application.Session.test = value;
	}
}

[ThreadStatic]
private static string _test;

The code above shows a static property that is backed by a [ThreadStatic] field. When the field is null, it is initialized from the value stored in the application's session object. When it's not null, it is returned immediately. This pattern allows the creation of very fast session statics that only access the session lookup object once.

Idle

Use the Application.Idle event to execute code after the current request is executed, and all the events have been dispatched but before the response is sent to the client.

You can achieve the same using the Application.Post() method (similar to Control.Invoke) to register a code block that will be executed at the end of the current request.

Event Filter

Wisej is indeed magic

With Application.AddEventFilter(filter) you can inject an object into the Wisej event pipeline and pre-process all the events that coming from the browser for all the controls in the application.

With Application.AddEventFilter(filter) you can inject add an object into the Wisej event pipeline and pre-process all the events that are coming from the browser for all the controls in the application.

All you need to do is implement the Wisej.Core.IEventFilter single method PreFilterEvent(e). You may also implement that IEventFilter interface in a control class and register a specific control as an event filter.

// register an event filter
Application.AddEventFilter(new MyEventFilter());

// event filter class
class MyEventFilter : IEventFilter
{
	public bool PreFilterEvent(WisejEventArgs e)
	{
		var name = e.Type;
		var control = e.Target as Control;

		// block all KeyDown events to all TextBox controls.
		if (name == "keydown" && control is TextBox)
			return true;

    // let the default dispatching work
		return false;
	}
}

Return true to indicate that your code has handled the event and to stop Wisej from dispatching it any further, or return false to let Wisej continue dispatching the event.

Event filters are invoked in the same order they are added.

Cookies

There are two cookies objects in Wisej:

  1. Application.Cookies is a collection of Cookie objects.

  2. Application.Browser.CookieStorage connects the application to the browser's cookies.

You can read the cookies from the browser either using the Application.Cookies collection or directly through the CookieStorage. The Application.Cookies collection is populated when the application starts up. It receives all the cookies that are available on the browser.

Adding, changing, deleting, reading cookies is all done using the Application.Cookies collection:

// save a cookie
Application.Cookies.Add("another.cookie", "Wisej");

// read a cookie
var value = Application.Cookies["my-cookie"];

Remember that when using the Cookies collection cookies are loaded from the browser only once when the application is loaded (or refreshed) and updated back in the browser only after the request is completed. Adding a cookie to the collection doesn't save it to the browser until the current execution is completed.

As an alternative, you can use the Application.Browser.CookieStorage object. It's not a collection and it doesn't contain any cookie information. It's a connection to the browser's storage and lets you read and write cookies directly from/to the browser:

// request the value of a cookie and receive it in a callback
Application.Browser.CookieStorage.GetValue<string>("my-cookie", (value) => { 

   // do something with the string value

});

// read the value of a cookie and await for it
var value = await Application.Browser.CookieStorage<string>("my-cookie");

Browser Object

Consider the Application.Browser object as a representation of the individual user's browser window through the Wisej.Core.ClientBrowser class. Wisej initializes and updates the object with all sorts of information regarding the user's browser:

  • Device is a string that identifies the device type: "Mobile", "Tablet" or "Desktop".

  • CultureInfo is the primary culture defined in the browser matched to a CultureInfo instance

  • Type is a string that identifies the browser type.

  • ScreenSize is the size of the user's device screen.

  • Size instead is the size of the browser window.

Refer to the API documentation for the full list of properties.

Features

The Browser.Feature object is a dynamic object that defines the features that are supported by the browser. It's an ever changing list that depends on the browser and the features that Wisej detects at startup. Currently, it is implemented like this:

features: {
    worker: ("Worker" in window),
    webSocket: ("WebSocket" in window),
    arrayBuffer: ("ArrayBuffer" in window),
    notification: ("Notification" in window),
    geolocation: ("geolocation" in navigator),
    serviceWorker: ("serviceWorker" in navigator),
    speechSynthesis: (window.speechSynthesis) != null,
    fullScreen: this.platform.isFullScreenSupported(),
    browserStorage: this.platform.isBrowserStorageSupported(),
    speechRecognition: (window.speechRecognition || window.webkitSpeechRecognition || window.mozSpeechRecognition) != null
}

To test if a browser supports a specific feature, simply check the field name: i.e. Application.Browser.Features.speechRecognition == true.

UserData

Browser.UserData is also a dynamic object that is populated by Wisej at startup. It allows a web application to save and send custom data to the Wisej application before it is loaded. It is mostly useful to process a POST request, and OAuth2 and other Single Sign On (SSO) systems.

For example, if another system redirects the user to your Wisej web application using a POST request because it is also sending some data, you cannot receive the POSTed data in Program.Main() because the Wisej application is started in an Ajax request.

In cases like this, change your Default.html page into a Default.aspx page (don't forget to change it also in Default.json), read the POSTed data in the code behind and save it to a JavaScript variable named Wisej.userData.

<% @Page Language="C#" %>

<!DOCTYPE html>

<html>
<head>
    <title>Wisej.ReceivePostData</title>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=Edge;IE=11" />
    <script src="wisej.wx"></script>
</head>
<body>

    <script>
        <%
            var name = Request.Form["Name"];
            var lastname = Request.Form["LastName"];
        %>
        Wisej.userData = {
            name: "<%=name%>",
            lastName: "<%=lastname%>"
        };
</script>

</body>
</html>

The sample startup page above receives "Name" and "LastName" from a POST request, saves them into a JavaScript object and saves the object in Wisej.userData. It will be available to the Wisej application as a dynamic object in Application.Browser.UserData.

Browser Storage

Access the browser's storage system using the Application.Brower object. All the storages have the same methods and work exactly the same. You can read, write, and enumerate the values either using a callback or the async/await pattern. All methods are asynchronous because they all interact with the browser directly.

There are three storages supported:

StorageDescription

The stored data is saved across browser sessions.

The stored data is cleared when the page session ends. A page session lasts as long as the browser is open, and survives over page reloads and restores.

Cookies are saved with the browser and are cleared depending on their expiration, scope, etc.

Favicon & Title

Wisej projects already include a default favicon.ico file at the root. That is the icon that the browser shows on the tab page and in the page's overview. However, being a file, once you create it it's difficult to change dynamically.

The Application class allows your application to change both, the favicon and the title of the page, dynamically at any time through these properties:

  • Application.FavIcon. Changes the favicon using an Image object.

  • Application.FavIconSource. Changes the favicon using a source string: a URL, embedded resource, or theme icon.

  • Application.Title. Changes the title of the application in the browser.

Printing

You can print (print preview in the browser and then print), any page, window, dialog, or specific control. it's quite easy, simply use Application.Print() or Application.Print(control).

The first will print the entire surface of the browser.

The second allows you to specify a control to isolate and print. You can indicate a window or just a data grid, an image, a panel, etc...

Download

The Application class also allows your application to download a file to the users browser, or to download & open a file in the browser in any tab. There are two overloaded methods:

  • Application.Download(). Takes a file, a stream, or an image and an optional filename to send to the browser.

  • Application.DownloadAndOpen(). Takes the same arguments as Download() plus a string indicating the name of the target tab where the browser should open the file after downloading it.

Sounds

Play sounds on the user's browser using the Application.Play() method and overloads:

  • Application.Play(MessageBoxIcon). Plays a predefined sound that matches the MessageBoxIcon value.

  • Application.Play(url). Plays the sound in the specified .wav file. It can also be a data URL.

The Beep() VB.NET extension uses Application.Play() with a predefined base64 URL.

JavaScript

Use Application.Eval() and Application.Call(), or Application.EvalAsync() and Application.CallAsync() to invoke JavaScript code or functions in the global context.

See also:

pageJavaScriptpageJavaScript Object Model

JavaScript Loading

Application.LoadPackages() and Application.LoadPackagesAsync() loads a list of .js or .css files in the order they are passed to the method and in sequence. Each file is loaded only after the previous is loaded, allowing the loading of dependencies.

Each entry has the following properties:

  • Name. Unique name of the .js or .css file to load. It's used to cache the file on the client and loads it only once even if Application.LoadPackages() is called multiple times, or if a Widget class loads the same file.

  • Source. Is the URL from where to load the file.

  • Integrity. Is the optional hash code used to verify that the file hasn't been tampered with. See https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script.

LoadPackages() takes a callback method as the last optional argument with a boolean result parameter. Wisej calls this method passing true when all the packages have been loaded successfully, or false if any package fails to load.

LoadPackagesAsync() is the same as LoadPackages() but instead of using a callback to notify the application, it's an awaitable method.

Application.LoadPackages(new[] {

	new Widget.Package(){
			Name="jquery",
			Source = "https://code.jquery.com/jquery-3.5.1.min.js",
			Integrity="sha256-9/aliU8dGd2tb6OSsuzixeV4y/faTqgFtohetphbbj0="
		}
	}, (result) => { 
	
	// result is true if all the packages have been
	// loaded successfully,
	
});

If you make changes to a file that you loaded using LoadPackages() or LoadPackagesAsync(), make sure to clear the browser cache so that the correct version of the file is used at runtime.

Last updated