Remotable Objects

The overall architecture that makes .NET Remoting happen is extremely modular and flexible enough to let you customize several aspects of the service. For example, you can decide whether remote objects should be marshaled on the local platform by value or by reference. Similarly, you can control how objects are activated and whether the activation should take place on the client or on the server. Programmers also can intervene in the object’s lifetime and specify the most suitable communications channel and formatter module for transporting messages to and from remote applications.

A remotable object can be implemented in one of two ways. One possibility is that you design the class to be serializable so that its instance data can be marshaled from the server to the client. At the receiving end, the client unmarshals the data and creates another instance of the class with the same values as the instance on the server. This approach is referred to as marshal by value (MBV). The other possibility is that the class allows for its object reference to be marshaled. When unmarshaled on the client, the object reference becomes a proxy to the remote instance. This second approach is known as marshal by reference (MBR). Unlike MBV, MBR preserves the object’s identity.

No matter how you design your remotable objects—MBV or MBR—a network connection must always exist between the client application and the remote object for .NET Remoting to work.

Note

.NET Remoting doesn’t support the automatic download of the assembly containing the type of the instance that is being marshaled (unlike other remote access technologies, such as Java’s Remote Method Invocation [RMI]). Instead, the assembly for the type needs to exist on the client beforehand. How the assembly gets on the client is outside the purview of .NET Remoting.


Marshaling Objects by Value

Marshaling by value downloads the entire object’s contents to the client, which uses the instance data to initialize a client-side object of that type. The client obtains a perfect local clone of the original object and can work with it completely oblivious to the fact that the object data has been downloaded from a remote location.

In general, MBV is not recommended when you have to cope with large objects with several properties. With MBV, you take the risk of consuming a significant portion of bandwidth to perform the full object’s data download, thus subjecting the client to a potentially long wait to execute only one or two methods. MBV also imposes some constraints on the remotable objects. In particular, any objects that need to be consumed by value must qualify as serializable—which is not the case for all objects. In addition to objects that deliberately make themselves nonserializable, some objects are objectively hard to serialize. In this list, you certainly find classes that represent or contain database connections. More generally, the list includes all those objects that can’t be reasonably represented outside their native environment. This happens when all or part of the information stored in an object does not make sense once the object is transferred to the client. If the object has any implicit dependencies on server-side resources, you can’t just use it from the client. For example, if the class has a method that accesses a SQL Server table, you could call it from the client only if the same SQL Server table is accessible from the current location.

When to Marshal by Value

So how do you know when MBV is a good option? Let’s say that MBV is a compelling option when the following conditions are true:

  • The object is not particularly large and complex.

  • You’re going to make intensive use of the object.

  • You have no special security concerns.

  • The object has no dependencies on remote resources such as files, databases, devices, or system resources.

Some rather illustrious .NET Framework classes that support remoting through the MBV technique are the DataSet and DataTable classes.

MBV Objects

The .NET Remoting system serializes all the internal data of MBV objects and passes the stream to the calling AppDomain, as illustrated in Figure 12-2.

Figure 12-2. How .NET Remoting marshals objects by value.


After the data is in the client AppDomain, a new local object is instantiated and initialized and starts handling calls. To write remotable objects that are exchanged by value, you need to make them serializable, either by declaring the SerializableAttribute attribute or by implementing ISerializable. Aside from this, nothing else is required for instances of the class to be passed by value across AppDomains.

Marshaling Objects by Reference

When an object is marshaled by reference, the client process receives a reference to the server-side object, rather than a copy. This means that any call directed to the object is always resolved on the server within the native context of the object. The remoting infrastructure governs the call, collecting all information about the call and sending it to the server process. On the server, the correct object is located and asked to execute the call using the client’s arguments. When the call is finished, the results are packaged and sent back to the client. Unlike MBV, MBR uses the network only for transmitting arguments and return values. Figure 12-3 shows the architecture of MBR remoting.

Figure 12-3. How .NET Remoting marshals objects by reference.


The .NET Remoting implementation of MBR provides for a proxy/stub pair and a physical channel for network transportation. The proxy represents the remote object to the client, as it simply mirrors the same set of methods and properties. Each client invocation of a remote method actually hits the local proxy, which, in turn, takes care of routing the call down to the server. A method invocation originates a message that travels on top of a channel and a transmission protocol.

Each message passes through a chain of hook objects (called sinks) on each side of the transport channel. Sinks are nearly identical to Windows hooks. By defining and registering a sink, the programmer can perform a specific operation at a specific stage of the remoting process. Because the creation of the proxy takes place automatically, the programmer has little to do other than creating an instance of the target object and issuing the call.

If the object resides in an external AppDomain, the remoting infrastructure creates a local proxy for it to perform the requested operation. But how can the code determine whether a given object is local, lives in a remote AppDomain, or just doesn’t exist? In spite of the sophisticated code that constitutes the remoting infrastructure, programming remote objects is mostly a matter of setup. Once the client has been properly configured, you normally create a new instance of the remote class using the new operator, no matter what type of class you’re calling and where it resides. Clients must declare to the CLR which classes are remote and provide connection information. Remote objects, in turn, must be publicly available and bound to a given channel.

The MarshalByRefObject Class

Inheriting from the MarshalByRefObject class is the key that enables user classes to be accessed across AppDomain boundaries in applications that support remoting. MarshalByRefObject is the base class for objects that communicate across AppDomains. Serializable classes that do not inherit from MarshalByRefObject, when instantiated from a remote assembly, are implicitly marshaled by value. Other classes are simply considered nonremotable.

So if you want to write a remote component that uses the network efficiently and always runs on the server, the only thing you have to do is create the class inheriting from MarshalByRefObject, as follows:

public class NorthwindService : MarshalByRefObject
{
    public DataSet GetSalesReport(int year);
}

For example, the NorthwindService class shown here is ideally suited to act as a remote console that clients access through transparent proxies.

Note

When creating a remotable object, you normally limit the class to inheriting from MarshalByRefObject. In some situations, however, you might want to override some of the parent class’s methods. In particular, you might want to replace the InitializeLifetimeService method and configure the object’s lifetime. We’ll return to this topic in the section “Memory Management,” on page 551.


The ObjRef Class

When a MarshalByRefObject object is being remoted, the .NET Remoting system packs all the relevant information into an ObjRef object. An ObjRef object is a serializable representation of the original MBR object. This intermediary object enables the .NET Remoting system to transfer an object reference across the boundaries of AppDomains. In effect, the entire action of marshaling by reference can be summarized with the creation an ObjRef object.

An ObjRef object contains information that describes the type and the class of the object being marshaled, the exact location, and any communication-related information such as port and protocols. The ObjRef instance is created on the server when the MBR object is first referenced; next it is transferred into the target AppDomain, possibly in another process or on another machine. On the client, the ObjRef object is then deserialized, and the real proxy is created to access the remote instance of the MBR object. This operation is globally known as unmarshaling.

The RealProxy Class

RealProxy is an abstract class that represents a remoting proxy. Any remoting client transparently uses an instance of this class to issue calls to the remote object. The overall .NET Framework model for distributed programming is designed to create the illusion that remote objects are actually working locally. This is true for .NET Remoting as well as for Web services, even though the effect is obtained with radically different techniques.

Note

.NET Remoting creates the local instance of the remote object using dynamically created proxies that result from the run-time deserialization process. Basically, the deserialization of the ObjRef class generates a transparent proxy to handle user calls. With Web services, a proxy class is statically added to the application’s project at design time when the Web service is referenced as an external library. The generation of the source code for the class and the subsequent addition to the project are automatically handled by Visual Studio .NET. However, the wsdl.exe utility (part of the .NET Framework SDK) allows you to generate the class yourself.


The RealProxy class hidden behind the software creates the illusion that remoting clients actually work locally. The proxy is transparently invoked whenever a method is called on the remote object. The RealProxy class executes the method by forwarding any calls to the real object using the remoting infrastructure.

If you want to play with the transparent proxy object yourself, you can get a reference to it by using the following code:

RemotingServices.GetRealProxy(localObject);

The variable localObject is the local instance of the remote object that you have created using the new operator. (More on this in a moment.) As mentioned, RealProxy is only an abstract class. The actual proxy object belongs to the RemotingProxy class in the System.Runtime.Remoting.Proxies namespace.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.136.18.48