Please note that technical support for writing scripts is not provided with the standard support packages, but is available on a consulting basis.
Technically every such application internally uses the new TnxsrBaseWebApplication component, which implements a scriptable web environment. It also support SSL and BASIC authentication against the users defined on the server. As you can see, defining such an application is pretty simple, all that is needed is a name, a base directory and a port. The extension for server scripts is .nxscript but the web server will serve any file within the base directory. While the feature is called "AppServer - Web Scripts" it can of course be also a set of loose web pages that you want to provide to a client.
The NX Server ships with a very simple sample "application" called WebApp1 located as a sub folder in the server directory. All of the examples used in this article are included in that folder as well.
The Basics
Let's take a look at the simplest of all examples, helloworld1.nxscript.
<%
begin
%>
Hello world!
<%
end.
%>
As you can see the script is essentially a mix of a pascal program and a web site separated by the commonly used <%%> "tags". For above to run, add the WebApp1 folder as an application (let's say port 90) and set it to active. Don't forget to press the "Save Settings" button. Once it's done the application name should be in bold green which means the app is up and running. Now open a browser and point it at http://localhost:90/helloworld1.nxscript. Unless your firewall blocks that port you should now see "Hello world!".
The scripting engine used is a modified engine, which is for example widely used in InnoSetup. The version built into NexusDB is giving scripts access to the server infrastructure, but also allows to build database client application running directly on the built in server engine. More on that later. Let's start with the simple but important things.
Manipulating the resulting web page
The first one is the ability to write directly to the response buffer. For this purpose every script has an implicit class instance Output: TnxSimpleOutputCache which can be used to manipulate the output. These are the (public) members which hopefully I don't need to explain.
type
TnxSimpleOutputCache = class(TnxComponent)
public
procedure Write(const aText: Variant);
procedure WriteLn(const aText: Variant);
procedure Clear;
procedure SaveToFile(FileName: string);
procedure Flush;
property Text: string
end;
Here's another possible way to create the same output for the hello world example:
<%
begin
%>
Hello
<% Output.Write('wor'); %>
ld!
<%
end.
%>
Easy isn't it? Let's look at how to access the databases on the server.
Accessing NexusDB
The fastest way to access data on a server is to access the internal server engine. For this purpose the scripting engine exposes this internal engine as ServerEngine: TnxsrServerEngine variable. The full class is exposed thus you have full access to all server engine properties. The engine also exposes all relevant DB classes thus you can easily define and create NexusDB classes in a script. The following script opens a table Test in database Test and dumps the first field to the screen.
<%
var
aSession: TnxSession;
aDB: TnxDatabase;
aTable: TnxTable;
begin
aSession:=TnxSession.Create(nil);
aDB:=TnxDatabase.Create(nil);
aTable:=TnxTable.Create(nil);
try
aSession.ServerEngine:=ServerEngine;
aSession.Active:=true;
%>
Session opened<br>
<%
aDB.AliasName:='Test';
aDB.Session:=aSession;
aDB.Open;
%>
Database opened<br>
<%
aTable.TableName:='Test';
aTable.Database:=aDB;
aTable.Open;
while not aTable.Eof do
begin
Output.Writeln(aTable.Fields.Fields[0].AsString);
aTable.Next;
end;
%>
Database opened<br>
<%
finally
aDB.free;
aSession.Free;
end;
end.
%>
As you can see that looks pretty much identical to a Delphi application. There are two caveats here:
• |
the scripting engine does not support default properties, thus you need to access the full property path. You can see that clearly in the access to the Fields property. |
• |
while in a normal application you wouldn't really need to free the created classes (as it terminates anyway) this is MANDATORY in scripting. Every class instance that you create has the lifetime of the Web application, thus as long as it the application is active the instance will stay around. So be very careful as a small leak can create havoc on the server. |
The scripting engine exposes most of the NexusDB symbols to scripts, this includes all types, classes and procedures in nxllTypes, nxllComponent, nxsdServerEngine, nxsrServerEngine, nxsdDataDictionary, nxdbBackupController and nxsrSystemStorage, as well as most of the Delphi Types, Classes and Sysutils units. This should allow you to achieve pretty much everything you ever want in terms of single script functionality.
Server Sessions
Even though running single scripts is already a great thing to have, the Web Application becomes even more powerful by supporting user sessions. Again this is achieved by surfacing an implicit instance of Server: TnxHTTPRequest.
type
TnxHTTPRequest = class(TnxLoggableComponent)
public
// URL encode a string
function ServerEncode(aString:string):String;
// URL decode a string
function UrlEncode(const aString: String): String;
// get a url request attribute
function Request(const what: String): Variant;
// get a user session var.
function GetVar(const Name: String): String;
// set a user session var.
procedure SetVar(const Name, Value: String);
// access to the raw HTML request split to lines
property RawHeaders: TStringList read fRawHeaderInfo;
// access to the parsed HTML headers as ini value pairs
property Headers: TStringList read fHeaderInfo;
// access to cookies as ini value pairs
property Cookies: TStringList read fCookies;
// returns the request URL
property RequestDocument: string read fRequestDocument;
// access to the reply headers as ini value pairs
property ReplyHeaders: TStringList read fReplyHeaders;
// HTTP Version
property HTTPVersion: string read fHTTPVersion;
// the full raw request
property RawRequest: string read fRawRequest;
end;
Not only does this function allow access to the raw and preprocessed information of the html request, but note the SetVar and GetVar functions, which allow you pass information from within a user session. The object also allows you read/write access to cookies.
An example of using the Server.SetVar/GetVar combination to handle sessions, please take a look at the sources of the NexusDB Remote Administration (Admin root folder). Yes, the Remote Administration is nothing else than a session supporting Web Application, which is always defined for a NexusDB server.
Some more things worth to know
If you have now looked at the remote administration you have probably seen that there are two more predefined Instances: NxServer: TTNXServerLink and SystemDB: TnxSystemDatabase. The first is a flattened simplified access to all the components registered with the ServerEngine. We've chosen to provide this TTNXServerLink class for future easy access from other programming languages (e.g. C#). The latter is giving access to the servers system database which holds things like registered assemblies, the installed web applications, etc.
Conclusion
While we know that this functionality is not needed by everyone we do believe that it is a unique feature that will hopefully help a lot of customers to achieve more flexibility and integration for their applications. No need for IIS + ODBC or PHP, just use the server directly.
.