Pages - Routing and Page Mechanics

The Runtime Core and the Runtime Support Scripts

It is important to understand that the runtime consists of two key components:

  • The runtime Core
  • The Runtime support Scripts

The runtime core is made up of a number of binary components such as casemaster.web.exe. This is the true core of CaseMaster and implements all the essential features such as:

  • The .cms script parser and interpreter
  • The expression language parser and interpreter
  • A number of expression function handlers and the framework to handle dynamic expression handlers (see here)
  • Connecting to data sources
  • The concept of business objects
  • Integration with the .Net HTTP model

A set of runtime support scripts are shipped with the runtime that provide an out-of-the-box application platform. This is implemented using a set of .cms scripts that you will find in the CaseMaster runtime folder.

The standard set of scripts implements a web environment that heavily revolves around server sire rendering, Bootstrap, JQuery and a specific look & feel.

It is perfectly possible to replace / amend the runtime support scripts so that, for example, the web environment is optimized for a client side rendering platform such as Vue or React.

This documentation describes the standard web environment that comes with CaseMaster.

The HTTP Request Life Cycle

CaseMaster makes use of the Kestrel HTTP server optionally front-ended with IIS (or even NGINX). This is implemented by the casemaster.web.exe module. It is this module that accepts and processes all the HTTP requests.

Casemaster.web.exe is started (optionally on request on arrival of a request), will read the relevant configuration files and initialize the CaseMaster core.

Casemaster.web.exe will read, parse and invoke the script web/router.cms in the script namespace.

This router script will first try to establish the mode and does so based on the URL.

URL Mode
https://localhost:5000/page/training Page
https://localhost:5000/service/ping Service
https://localhost:5000/static/images/logo.png Static
https://localhost:5000/favicon.ico Set to static
https://localhost:5000/sitemap.xml Set to static
https://localhost:5000/robots.txt Set to static

When the router has established the mode its sets the global variable //route.mode. You can always refer to this variable from your scripts.

The router will further evaluate the URL and try and set the variables //route.script and /route.function for the script and the function within that script.

URL Script Function
https://localhost:5000/page/training training - (defaults to main)
https://localhost:5000/page/training/f/edit training edit
https://localhost:5000/page - (defaults to index) - (defaults to main)
https://localhost:5000/page/f/dashboard - (defaults to index) dashboard
https://localhost:5000/service/get get - (defaults to main)
https://localhost:5000/service/put/f/force put force

Next, the router will invoke the relevant detailed router script for the given mode. For example web/router/page.cms in the script namespace.

The page router will do a number of things:

  • Call the onStart function of the page router; this is an empty routine but can be overruled
  • Set a couple of standard HTTP headers (such as content type, cache control and referrer policy)
  • Check whether the user is already authenticated, if not: redirect to the login page or to the oAuth handling
  • Touch the session (i.e. the session is updated with every request)
  • If exists: call the function beginPage of //route.script
  • Call the onPageStart function of page router; this is an empty routine but can be overruled
  • Call the //route.function and /route.script
  • Call the onPageEnd function of page router; this is an empty routine but can be overruled
  • If exists: call the function endPage of //route.script
  • Call the onEnd function of page router; this is an empty routine but can be overruled

Let us go back to our simple example from the previous chapter:

inherits 'base'

function main()

    response.write( '<div class="container">')
    response.write( '<h1>Hello world</h1>')
    response.write( '</div>')

end-function

The file base.cms that we inherit from implements a beginPage and an endPage function and these are called by the script web/router/page.cms.

The beginPage function in base.cms generates the HTML to include the relevant Javascript libraries and stylesheets, generates the basic HTML tags and generates the navigation HTML (i.e. the menu).

Next the main function of our training.cms file adds some more HTML.

Finally, the endPage function in base.cms adds some final Javascript code and closes the HTML body and html tags.

This results in a complete page where we only have to focus on the content of the page.

Typical Use of Routing and Base.cms

You would typically not override from / extend (by inheritance) the web/router script. There is however one common scenario to inherit from the web/router/page script. Take a look at the following example:

inherits '//runtime/web/router/page'

function authenticate()

    if startsWith( [//route.script], 'clientSurvey' )
        return true()
    else
        return script.call( '../authenticate' )
    end-if

end-function

The function authenticate in web/router/page return true() when the user is authenticated (or more accurately: when the user does no longer have to be authenticated) and false() when the user cannot continue with the request until he/she has been authenticated.

The standard behavior is that a false() results in the request being redirected to the login page.

The above example shows how web/router/page can be extended to allow one or more requests to be serviced without authentication. For example, when you have send out an email with a unique link to a customer survey page that does not require a login. See also here.

The page base.cms is almost always extended because this is where you define the main menu. See here.

<End of document>