Apart from using DCOM as a communication protocol, as implemented using the TDCOMConnection component, DataSnap supports two other protocols as well: TCP/IP (sockets) and HTTP. The latter is called TWebConnection and is especially useful in situations where you need to go through a proxy or firewall, which can be quite a problem (or at least quite a task) using the regular TDCOMConnection component.
Before we start using the TWebConnection component in C++Builder 6, I have to warn you that this component does not operate correctly with C++Builder 6, including Update 2. The problem that you'll encounter is an Access Denied message when the DataSnap client tries to connect to the DataSnap server. We have been unable to solve this problem, and can only report that it used to work just fine, and hopefully some forthcoming patch or update from Borland for C++Builder will fix it again in the future.
TWebConnection is found on the DataSnap tab of the Component Palette. It is perfect to use for stateless HTTP communication connecting to a DataSnap server (which is also stateless, as you've seen).
For the remainder of this section, you should probably copy the DataSnapClient project from its original directory (from the previous chapter) to a new directory, where you can experiment on it using the TWebConnection component. Note that this precaution is only necessary with the DataSnapClient project; we won't be modifying the DataSnapServer at all.
Using the DataSnapClient project, you can replace the current TDCOMConnection component with a TWebConnection component. Now the TWebConnection component has to connect to the DataSnapServer you created in this chapter. The TWebConnection component makes this connection by using the HTTP protocol. However, to use a WebConnection , you must make sure that WININET.DLL is installed on the client system (which is available if you have Internet Explorer version 3 or higher installed), the server must have Internet Information Server version 4 or higher or Netscape Enterprise version 3.6 or higher, and finally you must install a special Borland-made ISAPI DLL called HTTPSRVR.DLL (found in the CBuilder6\Bin directory) in a cgi-bin or scripts directory on the Web server that the TWebConnection component uses to connect to. HTTPSRVR is responsible for launching the DataSnapServer on the Web server and will marshal all requests from the client to the application server interface, sending packets of records back.
For more information on Web servers, ISAPI DLLs, and general Web server programming, see Chapter 22, "Web Server Programming with WebSnap."
As a direct consequence, the URL property of the WebConnection component must point to http://localhost/cgi-bin/httpsrvr.dll (which points to the scripts directory on my local machine ”I could also have used http://127.0.0.1/scripts/httpsrvr.dll). Next , you can click the ServerName property, open the list of available DataSnap servers, and select the DataSnapServer.CustomerOrders DataSnap server. You can make sure that the connection actually works by double-clicking the Connected property of the TWebConnection component. If the value turns to true , you're okay.
NOTE
Note that you don't actually see the DataSnap Web server running. That's because HTTPSRVR (started by the server) is activated by another user (the default Internet user ), and as a result you don't see any visual representation of the middleware server at this time (as you did when using a DCOM or the upcoming Sockets middleware server).
To make sure the server is actually running, you can always take a look at the Task Manager, of course. Inside the Task Manager, you'll see the DataSnapServer running, but (not so) surprisingly, no indication of that is seen at the desktop.
Other than this, the TWebConnection component works exactly the same as the TDCOMConnection component, with one difference ”security. The TWebConnection component enables you to take advantage of SSL security and to communicate with a DataSnapServer application that is protected behind a firewall. For all this, the TWebConnection component has a number of helpful properties such as Proxy , ProxyByPass , UserName , and Password . The UserName and Password properties of TWebConnection can be used to go through a proxy or if the Web server requires authorization or authentication.
Unfortunately, as I wrote in the start of this section, the TWebConnection component will produce an "Access Denied" error when trying to connect a DataSnap Client to the DataSnap Server.
Finally, a Web connection can use object pooling. This feature enables the server to create a pool of multiple server instances for client requests. This way, the DataSnapServer doesn't use the resource for the remote data module and database connection unless it's actually needed.
Object pooling gives you the ability to set a maximum for the number of instances of the remote data module inside the DataSnap server application. Whenever a client request is received, the DataSnap server checks to see if a free remote data module exists in the pool. If not, it creates a remote data module instance (but never more than the specified maximum number of remote data module instances) or raises an exception with the message Server too busy . The remote data module, in its turn , services the client requests and duly waits for the next one. After a certain period of time without client requests, the remote data module is freed automatically (by the object pooling mechanism).
In previous versions of DataSnap, this feature would not have been possible, because we now have instances of a remote data module that services more than one client. As a result, the server cannot rely on state information ”this has to be maintained by the client. As indicated previously, DataSnap is indeed stateless.
The big question should now be: How do we enable object pooling for HTTP connections? We must get inside the UpdateRegistry() method again ”found in the header file of your remote data module. Inside the UpdateRegistry() method, an object regObj is used to configure the behavior of the application server. With object pooling, we must set three additional property values.
First, regObj.MaxObjects specifies the maximum number of instances. If the DataSnap server receives a client request and no remote data modules are available, an exception with message Server too busy is raised.
Second, regObj.Timeout specifies the number of minutes the remote data module can wait idle in the pool of remote data modules. After spending the specified amount of time without a single client request, the remote data module will be freed automatically by the DataSnap server. According to the documentation, the DataSnap server checks every six minutes to see if any remote data module should be freed. Specifying a timeout value of means that the remote data module will never time out, so in that case the only useful feature you're using is the limit on the amount of remote data module instances.
After these two property settings, the regObj.RegisterPooled must be set to true to indicate that you want to use object pooling.
In practice, there's a fourth property value you can set, regObj.Singleton , which specifies whether the remote data module should be a singleton (but we already set that to false ). If you set it to true , the number of instances and timeout arguments will be ignored, and only a single remote data module (which must be free threaded) will be created to handle all client requests.
An example modified UpdateRegistry for a remote data module with up to 10 instances that time out after 42 minutes of inactivity can be seen in Listing 21.1.
// Function invoked to (un)register object // static HRESULT WINAPI UpdateRegistry(BOOL bRegister) { TRemoteDataModuleRegistrar regObj(GetObjectCLSID(), GetProgID(), GetDescription()); // Disable these flags to disable use by socket or Web connections. // Also set other flags to configure the behavior of your application server. // For more information, see atlmod.h and atlvcl.cpp. regObj.Singleton = false; regObj.MaxObjects = 10; regObj.Timeout = 42; regObj.RegisterPooled = true; regObj.EnableWeb = true; regObj.EnableSocket = true; return regObj.UpdateRegistry(bRegister); }
Note that I've used hard-coded magic numbers 10 and 42 here. This is not a good idea in real life, especially because it means that you need to recompile the DataSnap server whenever you want to make some changes (for example, if you add new memory to the server, which can then handle more than 10 instances). That's not even considering that the same DataSnap server could be placed on multiple machines, each of a different configuration (see the section "Object Broker," later in this chapter). I always recommend using an external configuration file where you can specify ”for each machine, and for every time you first start the DataSnap server application ”the number of instances and timeout minutes. This adds flexibility to the power already present in object pooling.
Top |