As companies around the world are jumping on the Web to do everything from advertising to e-commerce, client/server developers are frantically searching for technologies that will let them open Web windows within their existing information systems. Enter Microsoft Remote Data Services (RDS), a set of COM objects born from the ashes of Advanced Data Connector (ADC) and now part of Microsoft Data Access Components (MDAC) 2.0 and later. (See the sidebar "Making Sure MDAC Works," page 48, for information about MDAC setup and repair.)
RDS lets you build high-performing, interactive, Web-based solutions on the familiar client/server metaphor, letting the browser connect to the Web server, query for a record set, and have the record set downloaded for further client-side processing—all in one round-trip.
The Connectivity Puzzle
Web communication is based largely on HTTP, a stateless protocol. Thus, client/server developers can't apply the typical request/response pattern when asking a Web server for a block of data. In the familiar client/server world, the client issues a query and waits for a response. When the server has processed the query and sent back the requested data, the client simply refreshes its user interface (UI) to reflect the results. In the Web world, however, the client's (or browser's) request and the server's response are two distinct, one-way communications. The request and response aren't two parts of the same interactive conversation.
A browser and Web server converse through HTML pages. The page that issues the request terminates when the browser begins processing the request. The resulting page the user sees is new, despite looking and feeling like the page that issued the request. The client receives an HTML page (a stream of HTML bytes) ready to render, not data for further local processing.
A Web browser is a thin client, with the Web server containing and applying all necessary application logic. Although the browser doesn't contain the application logic to handle returned record sets, you can manage them on the server through Active Server Pages (ASP), which contains the presentation logic a typical fat client would use.
So what role does RDS play in this Web browser/Web server connectivity puzzle? Microsoft designed the set of COM objects to improve the performance of highly interactive Web applications, such as e-commerce sites and database front ends, that let users filter and sort long lists of records on the fly. Obviously, you can't have well-performing, highly interactive applications if all user operations must travel to the server and back again.
With RDS and an ActiveX-enabled browser such as Microsoft Internet Explorer (IE) 4.0, you can issue remote calls through HTTP to middle-tier business objects on a Web server. You simply script RDS objects from within client-side HTML pages, or Visual Basic (VB) or Visual C++ (VC++) programs, and ask the objects to retrieve data. You then use Dynamic HTML (DHTML) to update and refresh the UI. These capabilities bring the traditional client/server programming model into the land of Web browsers and give you modern, highly interactive Web applications.
ADO's Web Counterpart
RDS lets you access any data the invoked business objects return, including arrays, text, and Extensible Markup Language (XML) strings. However, Microsoft specifically designed RDS to send and work with entire record sets across the network. With RDS, you can consider the ADO record set a native data type for your Web applications.
RDS acts as ADO's Web counterpart, as Figure 1 shows. Table 1 describes RDS's three objects. RDS.DataSpace handles remote data connection. RDSServer.DataFactory, a free server-side utility that Microsoft provides with RDS, collects the main features of the typical business object you would invoke remotely to get a record set. You can write and use your own server-side components in place of DataFactory if you need something different. The third object, RDS.DataControl, handles data binding. (The Microsoft Developer Network—MSDN—Online Library and the Platform Software Development Kit—SDK—also document these objects.) Let's look closely at the three RDS components.
The DataSpace Object
RDS doesn't cancel HTTP's stateless nature but merely hides it behind a proxy object, RDS.DataSpace. In other words, RDS simulates synchronous communications between the browser and the Web server through an intermediate object, which processes the request. The proxy object routes any remote method invocation to the RDS server stub. The stub, in turn, creates an instance of the specified component, invokes the method, and returns the result to the proxy. On the server, the system destroys the instance of the invoked object as soon as the method terminates. Thus, a different instance of a server-side object processes each successive call to that object. Table 2 lists DataSpace's method and property.
server = "http://expoware"; sql = "select * from Employees"; rds = new ActiveXObject("RDS.DataSpace"); df = rds.CreateObject("RDSServer.DataFactory", server); rs = df.Query("DSN=Northwind", sql); RefreshPage(rs);
You first use the RDS CreateObject method to create an instance of the DataSpace object and instruct it to initialize an instance of a given COM component on a specified Web server. The proxy serves as a local copy of the remote object, supporting the same methods and properties. The mirror object, however, doesn't execute any code in response to calls; it simply issues a remote method invocation to the RDS stub. This code creates a local object whose programming interface is identical to that of RDSServer.DataFactory. Remember that DataFactory is a server-side component, but the invoking code runs locally. Any exchanged data travels over the network through HTTP. And a new instance of DataFactory handles each call from the client to DataFactory.
Any method's return value represents data available on the client. If the return value is an ADO record set, your RDS-based application downloads in a single session all the needed records. This capability is particularly useful when you write highly interactive applications that need to show different perspectives or representations of the same data or group the data in various ways. RDS saves you from repeated trips to the server for these different views; you simply download the data once and use it until you close the application.
Using DataSpace to call COM components through HTTP is compelling, but you can also use DataSpace as a general-purpose framework for issuing COM calls. DataSpace supports a variety of protocols and in-process calls. Besides HTTP, you can issue COM calls through HTTP over Secure Sockets Layer (HTTPS) and Distributed COM (DCOM).
RDS-Enabled Business Objects
In place of DataFactory, you can call any other COM object—including custom components—installed and registered properly on the Web server. RDS requires only that the objects qualify as regular automation servers. Be careful, however, about the code you write for various methods and properties. Remember that the browser will always invoke your object in a stateless manner, meaning that no state will be maintained across successive calls. If you need to assign a nondefault value to an internal variable before invoking a method, avoid wrapping the variable with a property. Instead, when designing an RDS-compliant component's programming interface, use a method's parameters to set that internal variable and make sure that the method executes in the right context.
You must list all objects you want to call remotely through RDS in the server's Registry under the HKEY_LOCAL_ MACHINE\SYSTEM\CurrentControlSet\ Services\W3SVC\Parameters\ADCLaunch Registry key. If you have a COM object named MyRDSComp.DoSomething, the script in Listing 1 will register it properly for use with RDS.
The DataControl Object
The RDS DataControl object, RDS.DataControl, binds the content of an HTML tag (e.g., <TABLE>, <SPAN>, <INPUT>) with a data field. You might recognize a resemblance between DataControl's function and that of data-bound controls in VB and in rapid application development tools such as Delphi. Table 4 shows DataControl's methods and properties.
You can use DataControl in two ways. First, you can use it to download a record set from a data source on a given Web server. This functionality looks like the one DataSpace provides, but you'll find significant differences. On the plus side, DataControl retrieves a record set directly through ADO without involving other objects and downloads data asynchronously. On the minus side, it can return only a record set and can't apply any business or data transformation rules.
Second, you can use DataControl's data-binding capabilities to process and display the downloaded data properly. You embed DataControl as an ActiveX control in your client HTML pages and exploit its methods and properties to connect to an OLE DB data source. Note that OLE DB data sources also include all possible ODBC data sources. (For information about OLE DB and ODBC, see "OLE DB or ODBC?" November 1999.)
The following code inserts the DataControl object in an HTML page, making the object invisible and giving it an ID to use later:
<OBJECT style="display:none" id="rds" classid="clsid:BD96C556-65A3-11D0-983A-00C04FC29E33"> </OBJECT>
The Refresh method uses the values you set in Server, Connect, and Sql to connect to the server and instruct the RDS stub to provide the record set corresponding to the query. Although this example names the property Sql, you can assign it any string (SQL or not) that is meaningful to the OLE DB provider you're targeting.
When DataControl has downloaded the record set, it raises a notification event called ondatasetcomplete, which you can detect and handle with scripting. You can then safely use DataControl's Recordset property to access the data locally, as the following shows:
Finally, you use the following code to bind record set fields to the HTML tags:
<INPUT TYPE="button" DATASRC="#rds" DATAFLD="employeeID"> </INPUT>
The DATASRC attribute links the tag to an RDS data source. You must prefix the string with a pound sign (#), which tells IE that the ID addresses an RDS data source. The DATAFLD attribute points to the name of the field where the data should come from.
A third possible attribute, DATAFORMATAS, specifies how to render a field's content. If the attribute value is the string html, IE renders the content as HTML code; otherwise, it presents the content as raw text. For example, given the tag
<SPAN DATASRC="#rds" DATAFLD="employeePhoto" DATAFORMATAS="html"> </SPAN>
if the employeePhoto field contains the string
RDS will tell IE to render the content as a GIF picture.
When the HTML tag bound to a data source field is , DataControl automatically handles the data repetition, as Listing 3 shows. This code automatically populates the table, adding as many rows as there are records in the record set. You just define the layout of the tag, and RDS repeats it.
Putting RDS to Work