The remote server administration (from public beta 2 onwards) provides a neat user interface for loading/unloading and activating/deactivating such applications.
Technically every such application internally uses the new TnxsrBaseWebApplication component, which implements a script able web environment. It also support SSL and BASIC authentication against the users defined on the nxserver. 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 nxserver scripts is .nxscript but the web server built into nxserver will serve any file within the base directory. While the feature is called "Web Applications" it can of course be also a set of loose web pages that you want to provide to a client, for example a "What's new" list or even a page that allows download of the newest client versions.
NexusDB V3 ships with a very simple "application" called WebApp1 located as a sub folder in the nxserver exe directory. All of the examples used in this article are included in that folder as well.
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
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.
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 nxserver.
Accessing NexusDB
The fastest way to access data on a nxserver 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 classes in nxDB.pas 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
aTable.Free;
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 nxserver.
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.
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 informations 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. 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 nxservers system database which holds things like registered assemblies, the installed web applications, etc.
The future
We are planning to further develop this area and are looking into feasibility of things like
- multiple virtual hosts per port
- running web applications in a separate process space
- adding prebuilt validated sessions
- running applications with different priorities
- hosting ASP.NET
Please note that i didn't say that these necessarily appear but we see great potential in this area.
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 nxserver directly.