Icon Web Server Applications

The web server includes an interpreter and runtime that allows authenticated users to make requests to server applications. Web server requests are routed to server applications using the following architecture:

Image

Please see the Web Server Request Handling topic for more information on how requests are structured and routed by the web server.

Application Format
A server application uses a custom compressed binary format that bundles the application source units referenced during compilation into a single file with a .wba extension. When a server application is first required by the web server, the application is loaded and compiled into an in-memory runtime format before being executed. This runtime format will be used for executing the code in the server application until the application is unloaded.

Native External Modules
Native external modules are libraries that expose native type and function/procedures to server applications. The only native language support currently available is Delphi from Embarcadero Technologies. The support units for creating native external modules can be found in the Elevate Web Builder Modules installations available for Delphi XE2 or higher from the Elevate Software web site.

Information Both native external modules and native server modules are libraries, but native server modules are self-contained native applications that are built specifically to handle incoming web server requests in a manner similar to server applications. Please see the Web Server Native Modules topic for more information on native server modules.

The following is the main unit of one of the example native external module library projects included with the Elevate Web Builder Modules installations:

unit extnamespacemain;

interface

{ You need to include the ewbextmodule unit in the uses clause }

uses SysUtils, ewbextmodule;

type

   { Here we define the various types used in the namespace that we are
     exposing to the Elevate Web Builder interpreter, including the namespace
     class itself }

   TMyNamespaceType = (ntNone,ntInternal,ntLibrary);
   
   { You can only register one namespace per module, and the namespace
     class must descend from the TEWBExternalModuleNamespace class.
     In addition, any properties that you wish to be visible to the
     Elevate Web Builder interpreter must be included in the published
     scope.  Any public methods will automatically be visible in the
     Elevate Web Builder interprepter because the ancestor
     TEWBExternalModuleNamespace class is marked with the
     $METHODINFO ON compiler directive }

   TMyExternalModuleNamespace = class(TEWBExternalModuleNamespace)
      private
         FID: Integer;
         FValue: String;
         FNamespaceType: TMyNamespaceType;
      public
         procedure TestProcedure(ID: Integer;
                                 const Value: String;
                                 NamespaceType: TMyNamespaceType);
         function TestFunction(ID: Integer): TMyNamespaceType;
      published
         property ID: Integer read FID write FID;
         property Value: String read FValue write FValue;
         property NamespaceType: TMyNamespaceType read FNamespaceType
                                                  write FNamespaceType;
      end;

implementation

{ This variable will hold the global instance of the namespace class instance }
var
   MyExternalModuleNamespace: TMyExternalModuleNamespace;

procedure TMyExternalModuleNamespace.TestProcedure(ID: Integer;
                                                   const Value: String;
                                                   NamespaceType: TMyNamespaceType);
begin
   FID:=ID;
   FValue:=Value;
   FNamespaceType:=NamespaceType;
end;

function TMyExternalModuleNamespace.TestFunction(ID: Integer): TMyNamespaceType;
begin
   if (ID=FID) then
      Result:=FNamespaceType
   else
      Result:=ntNone;
end;

{ Here we create the namespace class instance and assign it a type alias
  for the TMyNamespaceType enumerated type so that the Elevate Web Builder
  interpreter can refer to the type using a more normalized name }

initialization
   MyExternalModuleNamespace:=TMyExternalModuleNamespace.Create;
   RegisterExternalModule(MyExternalModuleNamespace);
   RegisterExternalTypeAlias('TMyNamespaceType','TNamespaceType');
finalization
   UnregisterExternalModule;
   FreeAndNil(MyExternalModuleNamespace);
end.

Once a native external module has been built, it can be included as an external file in a server application project to ensure that it is deployed along with the server application. Please see the Using the Project Manager topic for more information on including external files with projects.

Information Native external modules are loaded once when the first external declaration is bound during server application compilation, and remain loaded until the application is unloaded. Therefore, you will want to institute a versioning scheme in the native external module file names in order to avoid a situation where a deployment fails due to a native external module still being loaded in the web server process space, resulting in the web server being unable to overwrite the native external module file with the new version.

In order to actually reference any of the exposed declarations in a native external module, you must first create an external interface unit for the native external module. Please see the Creating a New External Module Interface Unit for more information on how to automatically generate an external interface unit for a native external module using the IDE.

The following is the external interface unit generated for the above native external module:

unit extnamespace;

interface

type

   { Enumerated Types }

   external TNamespaceType = (ntNone, ntInternal, ntLibrary) module extnamespace;

   { Routines }

   external procedure TestProcedure(ID: Integer; const Value: String; NamespaceType: TNamespaceType) module extnamespace;
   external function TestFunction(ID: Integer): TNamespaceType module extnamespace;

   { Variables }

   var
      external ID: Integer module extnamespace;
      external Value: String module extnamespace;
      external NamespaceType: TNamespaceType module extnamespace;

implementation
end.

Please see the External Interfaces topic for more information on the structure of external interface units and declarations.

Application Deployment
Server applications can be deployed using the administration API in the web server. The IDE uses this API to deploy server applications and any associated external files to a specified path within the Applications virtual resource on the web server. Please see the Deploying a Project and Web Server Administration API - Files topics for more information.

Application Installation
Server application deployment is insufficient for allowing a server application to be accessible to authenticated users, and an application must first be installed before incoming web server requests can be routed to the application. The IDE allows the user to install a server application using the server manager.

Information Server applications, like all server objects in the web server, are versioned. Once a server application has been installed, the underlying application .wba file can be updated while the web server is running without being required to be installed again.

Please see the Using the Server Manager topic for more information on using the server manager in the IDE and the Web Server Administration API - Applications topic for more information on installing and uninstalling applications.

Application Execution
When an incoming request is routed to a particular server application and the application code is executed, an execution environment is obtained. These execution environments are cached for each application in order to minimize application startup times.

The server application memory is initialized and finalized for every server application execution. During initialization, a global TApplication component instance is created along with the main TRequestHandler for the server application. The incoming web server TWebServerRequest instance is then routed to the TRequestHandler instance's OnHandleRequest event handler, if one is defined. The event handler code can then handle the request and send a response to the request using one of the following TWebServerRequest methods:

MethodDescription
SendContentHeaderSends a response for a HEAD request.
SendCustomContentHeaderSends a custom content response for a HEAD request.
SendContentSends a UTF-8-encoded text response with a Content-Type header of "text/html; charset=utf-8" along with an optional status code and message.
SendCustomContentSends a UTF-8-encoded text response with a custom content type, encoding, and disposition.
SendRedirectSends a redirect response to a new URL along with an optional UTF-8-encoded text response with a Content-Type header of "text/html; charset=utf-8". By default, the redirect HTTP status code is 302, but you can specify a different status code.
SendErrorSends a status code and message along with an optional UTF-8-encoded text response with a Content-Type header of "text/plain; charset=utf-8".
SendContentStreamSends a UTF-8-encoded text stream response with a Content-Type header of "text/html; charset=utf-8" along with an optional status code and message.
SendCustomContentStreamSends a binary stream response with a custom content type, encoding, and disposition.
SendContentFileSends a file response with a custom content type, encoding, and disposition.
Information If the content type is not specified, then the web server will attempt to determine the content type based upon the file extension.

Warning When debugging server applications in the IDE, the web server will automatically send a response if none of the above methods are called by the application and execution of the application terminates. However, when executing server applications outside of a debugging context, the web server will not automatically send a respons and this can cause the client application to hang and, eventually, time out waiting on a response that will never arrive.

You can encode a stream response using the TStream Compress method. However, make sure that you set the content encoding parameter properly to ensure that the client application can decompress the content with errors. Use the TWebServerRequest instance's AcceptsContentEncoding method to determine whether to use a particular type of content encoding.
Image