<HTML> <HEAD> <LINK REL=STYLESHEET TYPE="text/css" HREF="http://www.matlus.com/home-styles.css"> <TITLE> Delphi ASP Object Demo</TITLE> </HEAD> <BODY> <CENTER><H2>Vendors Table from DBEMOS</H2></CENTER> <HR> <% Set DelphiASPObj = Server.CreateObject("DelphiASP.Vendor") DelphiASPObj.GetVendors %> <HR> </BODY> </HTML>
procedure TVendor.GetVendors;
var
sSQL : string;
begin
sSQL := Request.Form['txtSQL'];
Response.Write(DM.GetVendorInfoPage(sSQL));
end;
<HTML> <HEAD> <TITLE> Delphi ASP Object Demo</TITLE> </HEAD> <BODY> <CENTER><H2>Vendors Table from DBEMOS</H2></CENTER> <HR> <% Set DelphiASPObj = Server.CreateObject("DelphiASP.Vendor") DelphiASPObj.GetVendors %> <HR> </BODY> </HTML>
Set DelphiASPObject = Server.CreateObject("DelphiASP.Vendor")DelphiASP is the name of our ASP DLL file. In the DLL, we have an ASP object called Vendor. The next line:
DelphiASPObject.GetVendorsOnce the object (DelphiASPObject, which is of the type DelphiASP) is created, we call its method - GetVendors. We create this method for our object and we have to implement this method. The result of this method returns a valid HTML string. And so, in this way, we've replaced the <% and %> with HTML that is then sent out through the (oh so sluggish) ASP/COM engine, then through the web server onto the (unsuspecting) client.
<HTML> <BODY> <TITLE> Testing Delphi ASP </TITLE> <CENTER> <H3> You should see the results of your Delphi Active Server method below </H3> </CENTER> <HR> <% Set DelphiASPObj = Server.CreateObject("Project1.Vendor") DelphiASPObj.{Insert Method name here} %> <HR> </BODY> </HTML>Notice, that the method name is unknown as this time and so we see{Insert Method name here} in its place. Once we create a method and implement it, it is our job to modify the .asp file such that is calls the right method of our object. Also notice the line
<% Set DelphiASPObj = Server.CreateObject("Project1.Vendor")Since this file was created before we saved our project with a new name, we need to change Project1 to DelphiASP. Lets go ahead and do that now.
unit uVendor_Impl;
interface
uses
ComObj, ActiveX, AspTlb, DelphiASP_TLB, StdVcl;
type
TVendor = class(TASPObject, IVendor)
protected
procedure OnEndPage; safecall;
procedure OnStartPage(const AScriptingContext: IUnknown); safecall;
end;
implementation
uses ComServ;
procedure TVendor.OnEndPage;
begin
inherited OnEndPage;
end;
procedure TVendor.OnStartPage(const AScriptingContext: IUnknown);
begin
inherited OnStartPage(AScriptingContext);
end;
initialization
TAutoObjectFactory.Create(ComServer, TVendor, Class_Vendor,
ciMultiInstance, tmApartment);
end.
Delphi has generated this unit for us. Notice that we have an object TVendor that is derived from TASPObject and implements the IVendor interface. So far, this is just a skeleton and it is this unit that we will write our implementation code in.
procedure Write(varText: OleVariant); safecall;Before we go any further, lets examine the difference between the ISAPI response object and the ASP response object. If we had code in an ISAPI application that looked like this:
Response.Content := 'Hello World';
In our ASP object it would be
Response.Write('Hello World');
If on the other hand we had this in our ISAPI:
Response.Content := 'Hello';
Response.Content := Response.Content + 'World';
In our ASP object it would be
Response.Write('Hello');
Response.Write('World');
You will notice that you won't find any documentation on the ASP objects in Delphi. They've left it to Microsoft to document. So you'll have to refer to the Microsoft web site for any documentation for the ASP objects. One place I've found such information is in MSDN
Response.Write(DM1.GetVendorInfoPage);
GetVendorInfoPage is a public method of our DataModule.
<% Set DelphiASPObj = Server.CreateObject("Project1.Vendor")Since this file was created before we saved our project with a new name, we need to change Project1 to DelphiASP. Lets go ahead and do that now.
unit uVendor_Impl;
interface
uses
ComObj, ActiveX, AspTlb, DelphiASP_TLB, StdVcl, uDM;
type
TVendor = class(TASPObject, IVendor)
protected
procedure OnEndPage; safecall;
procedure OnStartPage(const AScriptingContext: IUnknown); safecall;
procedure GetVendors; safecall;
end;
implementation
uses ComServ;
procedure TVendor.OnEndPage;
begin
inherited OnEndPage;
end;
procedure TVendor.OnStartPage(const AScriptingContext: IUnknown);
begin
inherited OnStartPage(AScriptingContext);
end;
procedure TVendor.GetVendors;
begin
Response.Write(DM.GetVendorInfoPage);
end;
initialization
TAutoObjectFactory.Create(ComServer, TVendor, Class_Vendor,
ciMultiInstance, tmApartment);
end.
function GetVendorInfoPage(sSQL : string) : string;
unit uDM;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs;
type
TDM1 = class (TDataModule)
Query1: TQuery;
Session1: TSession;
DataSetTableProducer1: TDataSetTableProducer;
private
{ Private declarations }
public
function GetVendorInfoPage : string;
{ Public declarations }
end;
var
DM1: TDM1;
implementation
{$R *.DFM}
{ TDM1 }
function TDM1.GetVendorInfoPage: string;
begin
end;
end.
The function GetVendorInfo has only one line of code
Result := DataSetTableProducer1.Content;
That's all there is to it! The output produced by this ASP object will be a simple HTML table as will be produced by the TDataSetTableProducer component. We can modify properties of this component to enhance the look of the HTML page produced. And we shall. But before we proceed …
unit uVendor_Impl;
interface
uses
ComObj, ActiveX, AspTlb, DelphiASP_TLB, StdVcl, uDM;
type
TVendor = class(TASPObject, IVendor)
protected
FDM : TDM1;
procedure OnEndPage; safecall;
procedure OnStartPage(const AScriptingContext: IUnknown); safecall;
procedure GetVendors; safecall;
property DM : TDM1 read FDM;
end;
var
DM : TDM1;
implementation
uses ComServ;
procedure TVendor.OnEndPage;
begin
FDM.Free;
FDM := nil;
inherited OnEndPage;
end;
procedure TVendor.OnStartPage(const AScriptingContext: IUnknown);
begin
inherited OnStartPage(AScriptingContext);
FDM := TDM1.Create(nil);
end;
procedure TVendor.GetVendors;
begin
Response.Write(DM.GetVendorInfoPage);
end;
initialization
TAutoObjectFactory.Create(ComServer, TVendor, Class_Vendor,
ciMultiInstance, tmApartment);
end.
<HTML> <BODY> <TITLE> Testing Delphi ASP </TITLE> <CENTER> <H3> You should see the results of your Delphi Active Server method below </H3> </CENTER> <HR> <% Set DelphiASPObj = Server.CreateObject("Project1.Vendor") DelphiASPObj.GetVendors %> <HR> </BODY> </HTML>Notice the line : DelphiASPObject.GetVendors. Your Vendor.asp file should have that line as it is shown above. Lets also move this file (after saving the project. Saving the project, also saves the .asp file) to our web server's root folder (C:\inetpub\wwwroot). We can now call this .asp file using the following URL in a web browser:
http://mydomain/vendor.aspWhere mydomain is the PC/Machine name of your PC or IP address (localhost or 127.0.0.1 will also do).
Using the Response Editor, lets set the Border attribute of the HTML Table to 1. Using the OnFormatCell event we can manipulate the HTML table even further. Here is what the OnFormatCell event of the TDataSetTableProducer should look like to produce an output similar to the demo you saw at the beginning of this article.
procedure TDM1.DataSetTableProducer1FormatCell(Sender: TObject; CellRow,
CellColumn: Integer; var BgColor: THTMLBgColor; var Align: THTMLAlign;
var VAlign: THTMLVAlign; var CustomAttrs, CellData: String);
begin
{ Color the First Column }
if CellColumn = 0 then
BgColor := 'Teal';
{ Color the Second Column }
if CellColumn = 1 then
BgColor := 'Olive';
{ Color the Second Row - excluding the Field Name Row }
if CellRow = 2 then
BgColor := 'Red';
{ Color all instances of the Field - Preferred where the Value = False }
if CellColumn = 10 then
begin
if CellData = 'F' then
BgColor := 'Yellow';
end;
end;
So we're going to need:
sSQL := Request.ContentFields.Values['txtSQL'];Where sSQL is defined as a string type and txtSQL is the name of the field in the HTML Form that contains the requested SQL Statement to be applied to a Query object. Assuming here that the method of the HTML Form is POST and not GET.
In ASP, the Request object is a bit different. It has a property called Form. The way you would access the fields of a Form in ASP is:
sSQL := Request.Form['txtSQL'];Once we get a hold of the SQL statement that was given to us via an HTML Form, we'd like to pass this on to our GetVendorInfo method of our Data Module, where we can assign the SQL string to our Query object and generate a result set.
Currently, our GetVendorInfoPage method does not expect any parameters, so we'll have to modify it such that it expects to see a string parameter and then use this parameter to assign it to our Query object and get a result set.
The GetVendors method of our ASP object will now look like this:
and the GetVendorInfoPage method of our DataModule will look like this:
procedure TVendor.GetVendors;
var
sSQL : string;
begin
sSQL := Request.Form['txtSQL'];
Response.Write(DM.GetVendorInfoPage(sSQL));
end;
Remember to change the declaration of this method in the interface section of the DataModule to match that shown above.
function TDM1.GetVendorInfoPage(sSQL : string) : string;
begin
with Query1 do
begin
Close;
SQL.Clear;
SQL.Add(sSQL);
Open;
end;
Result := DataSetTableProducer1.Content;
end;
This concludes the changes we need to make to our ASP object such that it receives the SQL statement via an HTML form. We still need the HTML form however. The HTML form's source code looks like this:
<HTML> <HEAD> <TITLE>Delphi ASP Demo</TITLE> </HEAD> <BODY> <FORM ACTION="http://www.matlus.com/Vendor.asp" METHOD="POST"> The <B>ASP Object</B> is connected to the VENDORS Table in DBDEMOS. Feel Free to Change the SQL Statement below to a Valid SQL Statement for this Table. <P> <TEXTAREA NAME="txtSQL" COLS=40 ROWS=5>SELECT * FROM VENDORS</TEXTAREA> <BR> <INPUT TYPE="SUBMIT"> </FORM> </BODY> </HTML> </PRE>Notice the Form's ACTION attribute. It calls the Vendor.asp page, which in turn creates an instance of our ASP object, and calls its method. The Memo field's (TEXTAREA) name is important here, as it needs to match the name of the form field we're using in our ASP object sSQL := Request.Form['txtSQL'];. Save this .htm file as Vendor.htm.
To test our work, we need to load the Vendor.htm in our browser, set the SQL statement if required (you should test this) and clicking on the SUBMIT button on the Form. Figure 5 shows what the output will look like with an SQL statement of: SELECT VendorNo, VendorName, City, State, Zip, Preferred FROM VENDORS
Figure 5 Showing the output generated by the ASP object
The flaw in our design here is that there is no column 10 and so even though the Preferred field is amongst the one we want displayed, it is not colored yellow where the value = False. We'll leave that as an exercise for those of you who would want to see this work.
While no benchmarks are really going to give you the complete story, these benchmarks can tell you something. If WebClasses are slower, they aren't really that much slower (30%). Most of the performance loss is simply due to creating and destroying WebClass instances, which is not a sufficient reason to avoid using WebClasses. Moreover, if you're not willing to give up a little performance to get some extra productivity, you shouldn't be using Visual Basic or the ASP framework-you should be writing custom ISAPI extension DLLs with C++.In Delphi, ISAPI gives us the productivity we need. Productivity is comparable to what you would get if you were using Visual InterDev (minus the HTML Page design, but then you're not limited to using any tool for that purpose. Using HTML templates in a Delphi ISAPI frees you to use any HTML page designer to accomplish this end), with the benefits of ISAPI over any other competing technology for web based applications, without the headaches associated with ISAPI that a VC++ programmer relates to. In short, you got ISAPI the easy way. A way that no other development tool provides.
![]() |
Download Project |