Location Transparency

Team-Fly    

 
.NET and COM Interoperability Handbook, The
By Alan Gordon
Table of Contents
Chapter Two.  Comparing COM and .NET

Location Transparency

Location transparency is the ability to use a software component in the exact same way regardless of whether it is running in the same process as its client or whether the software component is running on the same machine as its client or on a remote machine. If a software component does reside in the same process as its client, making a method call is simple. A method call simply involves pushing the parameters that are being passed to the method along with the return addressthe location where the flow of control should continue after the method callonto the stack. The flow of control then jumps to the memory address in the process where the method resides. The method then pulls the parameters off the stack and executes its logic, and then the flow of control jumps to the return address. The return value from the method is either pulled off the stack or perhaps out of a CPU register. Any output parameters can be pulled off the stack also. Again, this is how it typically works; compilers are free to implement this logic in different ways.

The process that I just described will only work if the calling code and the method reside in the same process and share the same memory address space. If two pieces of code share the same memory address space, memory addresses that are valid for one piece of code are also valid for the other. This means that you can pass pointers between the two pieces of code and you can jump from one point in the code to another using the memory address of a routine.

If the calling code resides in a different process than the method or if the calling code does not share the same address space, you must use a process called marshalling.

Marshaling

Marshaling is a technique for making method calls across process and machine boundaries. The essential idea behind marshaling is that we want to take a stack frame that resides in one process and turn it into a data stream that we can pass to another process on the same machine or to a different machine on our network. At the receiving process (or machine), we will unpack the data stream, reconstruct the stack frame, make the method call, and then send any return values and output values back as a data stream to the caller, which can then put them on its own stack. To the caller, it appears that we made a method call normally, and the return values and output parameters came back.

The whole idea behind location transparency is to make this process as simple (to the developer) as possible. Ideally, making a call to a remote object or an object in another process should be as simple as making a direct method call to an object that resides in the same process.

Marshaling is usually implemented using a proxy that resides in the calling process. This proxy looks exactly like the object with the method that you are trying to call. It has the same methods, and those methods have the same parameters and return values. When you call the proxy, the proxy takes the method call and serializes it into a data stream. This message is sent by some network protocol (if the caller and callee reside on different machines) or by some form of Interprocess Communication (IPC) (if the caller and callee reside on the same machine) to the receiving process or machine. On the receiving process or machine, a piece of software, which is usually called a stub, receives the message, unpacks the message, calls the requested method, and then sends the return values back as a message. The proxy receives this message and updates the stack frame (return value and parameters) on the client. The network protocol and logic that connect the proxy and the stub are called a channel.

So far, I have talked about marshaling only in the context of making method calls across process and machine boundaries. If you are an experienced COM programmer, you know that marshaling was also required when you made method calls across Apartments in the same process. The .NET Framework and the CLR does not support Apartments, but it does support something called an AppDomain, which is a logical subprocess within a physical process. Method calls that are being made across AppDomains must also be marshaled, even if the caller and the calling code reside in the same process. The CLR is smart enough to optimize the marshaling process if the caller's AppDomain and the called object's AppDomain reside in the same process.

Marshaling is required when making method calls across AppDomains because two applications running in different AppDomains are completely isolated from one another, even if the two AppDomains are running in the same process. In other words, memory faults in one application won't bring the entire process down. The two applications can be independently stopped and debugged , and an application running in one AppDomain cannot directly access resources (memory, file handles, and so forth) held by an application in another AppDomain, even if the two applications share the same process. With COM, the only way to provide this sort of isolation between two applications was to separate them into different processes. However, with the .NET Framework, the CLR provides a level of type safety and code verification. These make it possible to provide this same level of isolation while avoiding the need for expensive (in terms of time) process switches.

Conceptually, COM and .NET implement marshaling in a very similar manner. They both use proxies, stubs, and channels. They differ substantially though in the following areas:

  • How they construct the proxy and stub

  • How method calls are serialized into a data stream

  • What network protocol is used to send the stream across machines

CONSTRUCTING THE PROXY AND STUB

One of the main keys to making the marshaling process as seamless as possible is to hide the fact that the client is communicating with the server through a proxy. Ideally, the proxy should be created automatically by the operating system or runtime only when it is needed, and calling methods through the proxy should be as simple as making a direct method call. The underlying operating system or runtime code must therefore have complete meta information about the remote object. It must know the return type of each remotely callable method. It must know the type and size of each parameter, and it must know the directionality of each parameter, that is, which parameters are inputs, which are outputs, and which are both input and output. With COM, there were two ways to provide this information to the COM runtime:

  • You could use COM IDL and MIDL compiler to create a custom marshalling/proxy-stub DLL that contains all of the logic needed to create the proxies and stubs for one or more COM classes.

  • If your COM classes only used automation types for parameters and return values, you could use the type library marshaler in the COM runtime. In this case, all you needed to do was to register a type library for your server.

Figure 2-8 shows how you would generate a custom marshaling/proxy-stub DLL using IDL and the MIDL compiler.

Figure 2-8. Using MIDL in COM to generate a marshalling/proxy-stub DLL.

graphics/02fig08.gif

You (or your development environment) would generate the IDL file. You then compile this IDL file using MIDL. MIDL will generate several source files. You then compile and link these source files with a few system libraries to create your marshaling/proxy-stub DLL. You then had to install and register this DLL on both the client and server machine. The COM runtime then automatically uses this DLL whenever you make a cross-process , remote (or inter-Apartment) method call on an object for which the DLL can provide a proxy and stub.

Using type library marshaling was much simpler, and this is why it eventually became the preferred approach. With this approach, all you had to do was to generate a type library for each COM server. You could generate this type library using an IDL description of the classes and interfaces in a COM server. Many development environments, VB for example, generated a type library automatically and embedded it within the DLL or executable that they generated. After you registered this type library, the type library marshaler that was included with the COM runtime would use the type library to get all the meta information it needed to construct a proxy for a remote or cross-process method call.

With .NET, creating the proxy and stub is much easier. Once again, the copious metadata that is embedded in every assembly comes to your aid. This metadata contains all the information that the Remoting infrastructure in the .NET Framework needs to create a proxy for any class within an assembly. There's no need to create a separate description of your classes and interfaces in IDL and no need for a separate proxy/stub DLL.

In order to be remotable, a class must instead inherit from a base class called System.MarshalByRefObject as shown in the following:

 Class MyRemotableClass : MarshalByRefObject { } 

After you have done this, the CLR is smart enough to create a proxy automatically whenever a reference to an object is passed out of the AppDomain in which the object resides.

An object can be passed out of its own host AppDomain as a parameter or a return value of a remote method call. A reference is also passed out of its AppDomain when you instantiate a remote object in a different AppDomain using .NET Remoting. A remote object in this context means that it can be located in any of the following locations relative to its client:

  • On a different machine

  • In a different process on the same machine

  • In a different AppDomain in the same process

If you wanted to be a stickler for details, you could argue that the mere fact that you must inherit from a different class ( System.MarshalByRefObject instead of System.Object ) to create a Remotable class is a violation of location transparency. It's hard to argue with that, but, considering how much easier it is to use .NET remoting than DCOM (as you will see in chapter 11), I think that this is a small price to pay.

What About Marshal by Value Objects?

In some cases, when you access a remote object (that is, an object in a different process or AppDomain), you do not want the object to remain in its host process or AppDomain while you access it through a proxy. Instead, you may want the object to marshal its entire state across the process or AppDomain boundary so that all further interaction with the object can take place within the calling process or AppDomain; this is sometimes referred to as Marshal-by-Value. ADO Recordsets are the most commonly used marshal- by-value COM object. Marshal-by-Value objects do not need to inherit from MarshalByRefObject; they only need to inherit from System.Object. They must be serializable, however, so that the CLR can stream the state of the object across AppDomains. The simplest way to make a class serializable is to use the Serializable attribute as follows :

 [serializable] class MySerializableClass { //... } 
SERIALIZING METHOD CALLS INTO A DATA STREAM

When you are accessing a remote object, the proxy will take the method calls that you make on the object and serialize all the information needed to make the method call (an identifier for the method, the parameters, and so forth). The proxy then serializes it into a data stream that can be sent across processes or across the network. COM uses a format called Network Data Representation (NDR).

.NET gives you more choices. For a start, the .NET Remoting architecture includes the notion of a Formatter and a Channel. Formatters are responsible for serializing method calls into a data stream; Channels are responsible for transporting the data stream across the network (or between processes on the same machine). There are two available channels in the .NET Remoting infrastructure: an HTTP Channel (see System.Runtime.Remoting.Channels.HTTP) and a TCP channel (see System.Runtime.Remoting.Channels.TCP). There are also two types of Formatters: a SOAP formatter (see System.Runtime.Serialization.Formatters.Soap) and a binary formatter (see System.Runtime.Serialization.Formatters.Binary). Both formatters use the metadata in the remote object's assembly to convert a method call into an XML-based SOAP message in the case of the SOAP formatter and to a proprietary binary format in the case of the binary formatter. By default, the HTTP channel uses the SOAP formatter, and the TCP channel uses the binary formatter. However, you can change this if you like and use the binary formatter with the HTTP channel, for instance. Using the TCP channel with the binary formatter is in some ways equivalent to using DCOM. The key difference between .NET Remoting and DCOM is the availability of the HTTP Channel and the SOAP formatter. Both of which make it easier to make method calls across the Internet.

COMPARING THE NETWORK PROTOCOLS

Both COM and DCOM gave you some flexibility in the network protocol that you used when making method calls across a network. With DCOM, you could use the dcomcnfg tool to choose the network protocols that DCOM would use and the order that the protocols would be chosen in as shown in Figure 2-9.

Figure 2-9. Available network protocols with DCOM.

graphics/02fig09.jpg

With DCOM, TCP and User Datagram Protocol (UDP) were the most commonly used protocols although you could select others. With .NET, HTTP will be the most commonly used protocol. Rather than using a tool like dcomcnfg, you will select the protocoland even the portthat you will use when you select your channel. You can select a channel either programmatically using the RegisterWellKnownType or RegisterActivatedType methods on the RemotingServices class or using a configuration file.

You can see that, with regard to location transparency, .NET is just as capable as COM/DCOM (although it's not quite as transparent). The copious metadata that managed code compilers generate obviates the need for IDL and for IDL-generated proxy-stub marshalling DLLs. With .NET's formatter and channel architecture, you have far more choices in how method calls are serialized into a network-transportable message and how those messages are transmitted across the network.


Team-Fly    
Top
 


. Net and COM Interoperability Handbook
The .NET and COM Interoperability Handbook (Integrated .Net)
ISBN: 013046130X
EAN: 2147483647
Year: 2002
Pages: 119
Authors: Alan Gordon

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net