The Caché Object Gateway for .NET (which this book will usually refer to as simply “the .NET Gateway”) provides an easy way for Caché to interoperate with Microsoft .NET Framework components. The .NET Gateway can instantiate an external .NET object and manipulate it as if it were a native object within Caché.
The .NET Gateway can also be used in an Ensemble production (see the Ensemble document Using the Object Gateway for .NET). You can create and test your .NET Gateway classes in Caché, as described in this book, and then add them to a production using the Ensemble .NET Gateway business service.
Using Proxy Classes
The external .NET object is represented within Caché by a proxy class. A proxy object looks and behaves just like any other Caché object, but it has the capability to issue method calls out to the .NET Common Language Runtime (CLR), either locally or remotely over a TCP/IP connection. Any method call on the Caché proxy object triggers the corresponding method of a .NET object inside the CLR.
The following diagram offers a conceptual view of Caché and the .NET Gateway at runtime.
Instances of the .NET Gateway Server run in the CLR. Caché and the CLR may be running on the same machine or on different machines. The numbered items in the .NET Gateway Operational Model diagram point out the following relationships:
A Caché namespace accesses an instance of the .NET Gateway Server. Access is controlled by an instance of the Caché %Net.Remote.Service class.
Each Caché session is connected to a separate thread within the Gateway server. The connection is controlled by an instance of the Caché %Net.Remote.Gateway class.
Each proxy object communicates with a corresponding .NET object.
A call to any Caché proxy method initiates the following sequence of events:
Caché sends a message over the TCP/IP connection to the .NET Gateway worker thread. The message consists of the method name, parameters, and occasionally some other information.
The .NET Gateway worker thread finds the appropriate method or constructor call and invokes it using .NET reflection.
The results of the method invocation (if any) are sent back to the Caché proxy object over the same TCP/IP channel, and the proxy method returns the results to the Caché application.
You can access a proxy class with code written in either Caché Basic or ObjectScript. The examples in this document use ObjectScript.
Using Wrapper Classes with .NET APIs
In most cases, you will use the .NET Gateway by creating proxy classes for your custom .NET components (see the chapter on “Creating Proxy Classes” for details). However, it is also possible to create proxy mappings for an entire third party .NET application interface specification.
It may be tempting to create mappings for extremely large APIs (such as ADO, Remoting, or ASP.Net), which could then be reused in any number of applications, but this is not recommended. Such mappings can create hundreds of proxy classes, even though your application may only need a few of them. You can specify a list of classes that you do not want the proxy generator to map, but a very large exclusion list is difficult to create and manage.
When using a third party DLL in your application, the best approach is to build a small wrapper class for it, and then create a proxy for this wrapper. A wrapper class exposes only the functionality you want, which makes the interface between Caché and the .NET framework very clean and eliminates many potential issues. Wrapper classes provide the following advantages:
Fewer proxy classes — When a large .NET DLL is imported directly, hundreds of proxy classes may be generated. Your application may actually need only a few of these classes. A significant amount of work may be required to research and define an exclusion list for the import. Defining a wrapper is a much easier way to minimize the number of classes imported and managed.
Fewer problems with dependencies — The imported DLL may depend on external classes for successful compilation. The files and directories containing these classes can be specified in an inclusion list when you run the proxy generator, but this will cause even more unwanted proxy classes to be generated. When a wrapper is used, the dependent files and their classes are hidden from the importer, eliminating the need for inclusion and exclusion lists.
Better performance — A wrapper may allow you to reduce the number of calls made to a DLL. For example, assume that an imported DLL has a class with a readByte() method that reads one byte at a time. If you import the class directly, each call to the method will require a separate call to the DLL. It would be much more efficient to define a wrapper class with a readManyBytes() method that repeatedly calls the readByte() method internally, within .NET.
Ability to use legacy DLLs — ActiveX DLLs cannot be used directly in a 64–bit Windows environment, and a DLL that was not written as a .NET assembly cannot be used with the .NET Gateway even in a 32–bit environment. However, it is possible to create a wrapper that the .NET Gateway can use to call a DLL indirectly.
Creating and Running a Gateway Server
Before you can use the .NET Gateway, you must start an instance of the .NET Gateway Server and tell Caché the name of the host on which the server is running. Once started, a server runs until it is explicitly shut down.
Once the .NET Gateway server is running, each Caché session that needs to invoke .NET class methods must create its own connection to the server, as shown in the following diagram:
Caché Basic or ObjectScript code sends a connection request.
Upon receiving the request, the .NET Gateway server starts a worker thread in which the .NET class methods subsequently run.
The connection between this .NET Gateway worker thread and the corresponding Caché session remains established until it is explicitly disconnected. As long as it remains connected, the assigned port for the connection stays “in use” and is unavailable for use in other connections.
See Setting Gateway Server Properties for a detailed description of how to create a .NET Gateway Server property definition, and Running a Gateway Server for details on how to start, connect, disconnect, and stop a server.
Importing Proxy Classes
Caché proxy classes are generated by sending a query to the .NET Gateway Server, which returns information about the methods for which proxy classes are required. The imported method information is then used to construct the proxy classes, as shown in the following diagram:
The Caché session sends an import request.
Upon receiving the request, the .NET Gateway worker thread introspects the indicated .NET assemblies and classes.
The thread also loads dependent assemblies either from the local directory or from the Global Assembly Cache (GAC).
If it finds any .NET classes that are new or changed, or that have no proxy classes on the Caché side, the .NET Gateway worker thread returns the results of the introspection to the Caché session, which uses the information to generate new proxy classes.
See Creating Proxy Classes for details on how to generate proxy classes.
The .NET Gateway API
The following classes provide most of the functionality used by your Caché .NET Gateway applications:
%Net.Remote.ObjectGateway — an ObjectGateway object contains the property settings required to run and monitor an instance of the .NET Gateway Server. See Defining a Gateway Server for a detailed description.
%Net.Remote.Gateway — a Gateway object controls the connection between a Caché session and a worker thread within an instance of the .NET Gateway Server, and provides methods to generate proxy classes. See Connecting to a Server and Generating Proxy Classes Programmatically.
See the Caché class library documentation for the most complete and up to date information on each of these classes.