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
onStartfunction 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
beginPageof//route.script - Call the
onPageStartfunction of page router; this is an empty routine but can be overruled - Call the
//route.functionand/route.script - Call the
onPageEndfunction of page router; this is an empty routine but can be overruled - If exists: call the function
endPageof//route.script - Call the
onEndfunction 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>