Microsoft Corporation
June 1997
This article covers the following:
Microsoft Transaction Server object interfaces must be able to be marshaled. Marshaling interfaces allows calls across thread, process, and machine boundaries. Use standard marshaling with MTS applications. This means that your MTS object interfaces must either:
For more information on type libraries and proxy-stub DLLs, see "DLLs, Type Libraries, and Microsoft Transaction Server."
Do not use custom marshaling. Even if a component supports the IMarshal interface, its IMarshal methods will never be called by the MTS run-time environment.
Components that are intended for use from Active Server Pages (ASPs) using Microsoft Visual Basic®, Scripting Edition (VBScript) should support IDispatch and limit method parameter types as follows:
Whether an object is passed by value or by reference is not specified by the client, but is a characteristic of the object itself. Basic COM objects can either be passed by reference or by value, depending on their implementation. If the COM object uses standard marshaling, then it is passed by reference. COM objects can also implement IMarshal to copy data by value. MTS objects are always passed by reference.
Additionally, the function of the object affects how it should be passed as a parameter. When deciding whether to pass objects by value or by reference, it is useful to classify the objects as follows:
The following table describes when to pass recordset objects by value or by reference:
Pass Parameter | If | Client Requirements |
By value | Data is relatively small | Recipient requires all data and can get data without reaccessing caller. |
By reference | Data is relatively large | Recipient does not require all data and must reaccess caller, possibly many times. |
Note Whether data is "small" or "large" also depends on the speed of the connection. For example, if the component will be accessed over a corporate intranet, a much larger recordset could be passed to the client in one call than a client accessing the component on an Internet server over a modem could receive.
Because business objects are MTS objects, they are always passed by reference.
You must ensure that MTS object references are only exchanged in the following ways:
An object reference that is obtained in these ways is called a safe reference. MTS ensures that methods invoked using safe references execute within the correct context.
Figure 1. Using SafeRef to pass a reference to an object
Note It is not safe to exchange references by any other means. In particular, do not pass interfaces outside the object by using global variables. These restrictions are similar to those imposed by COM for references passed between apartments.
Calls that use safe references always pass through the MTS run-time environment. This allows MTS to manage context switches and allows MTS objects to have lifetimes that are independent from client references. (For more information, see the "Deactivating Objects" topic in the Microsoft Transaction Server version 1.0 Help file.)
It is possible to make callbacks to clients and to other MTS components. For example, you could have an object that creates another object. The creating object can pass a reference to itself to the created object; the created object can then use this reference to call the creating object.
If you choose to use callbacks, note the following restrictions:
When returning a large amount of data, consider using a Microsoft Active Data Objects (ADO) recordset. In particular, the Microsoft Advanced Data Connector (ADC) provides a recordset implementation that can be disconnected from the server and marshaled by value to the client.
The disconnected recordset moves state to the client, allowing server resources to be freed. The client can make changes to the recordset and reconnect to the server to submit updates. For more information on state, see "Holding State in Objects."
Another method of packaging large amounts of data is to use safe arrays. For example, when using Microsoft Remote Data Objects (RDO), you can use the rdoResultSet.GetRows method to copy rows into an array, and then pass the array back to the client. This requires fewer calls and is more efficient than issuing MoveNext calls across the network for each row.