Remotable and Nonremotable Objects

This topic is specific to a legacy technology that is retained for backward compatibility with existing applications and is not recommended for new development. Distributed applications should now be developed using the  Windows Communication Foundation (WCF).

It is important to remember that an object created in and therefore specific to, an application domain can be called directly from that domain, but something must occur before that object can be available outside its domain. Not every type of object can be efficiently published or consumed across domain boundaries; therefore, you must decide which type of object you want to publish based on the requirements of your application. For the purposes of distributed applications, there are two categories of objects: nonremotable objects and remotable objects.

Nonremotable Objects

Some objects cannot leave their application domain; they are never marshaled because they do not declare a method of serialization. These nonremotable objects are designed for use within the same application domain in which they were created and are always accessed directly from that application domain. Most base classes in the .NET Framework class library are nonremotable objects. Nonremotable objects cannot be copied or represented in another application domain. These objects are accessible only from their original application domain.

Remotable Objects

Remotable objects can be accessed outside their application domain or context using a proxy, or they can be copied and these copies can be passed outside their application domain or context; that is, some remotable objects are passed by reference and some are passed by value.

Remotable objects are objects that function well in a widely-distributed environment. There are two main kinds of remotable objects:

  • Marshal-by-value objects, which are copied and passed from the application domain.

  • Marshal-by-reference objects, for which a proxy is created and used by the client to access the object remotely.

Marshal-By-Value Objects

Marshal-by-value (MBV) objects declare their serialization rules (either by implementing ISerializable to implement their own serialization, or by being marked with SerializableAttribute, which tells the system to serialize the object automatically) but do not extend MarshalByRefObject. The remoting system makes a complete copy of these objects and passes the copy to the calling application domain. Once the copy is in the caller's application domain, calls to the copy go directly to that copy. Further, MBV objects that are passed as arguments are also passed by value. Other than declaring the SerializableAttribute attribute or implementing ISerializable, you do not need to do anything to pass instances of your class by value across application or context boundaries.

Note

Starting with version 1.1 of the .NET Framework, the remoting infrastructure does not automatically deserialize certain types on the server. If your application attempts to pass a type that is not automatically serialized, you must set the server deserialization level to Full before the server can deserialize and use your MBV object. For more information, see Automatic Deserialization in .NET Remoting.

Use MBV objects when it makes sense for performance or processing reasons to move the complete state of the object and any executable functionality to the target application domain. In many scenarios, this reduces lengthy, resource-consuming round trips across network, process, and application domain boundaries. MBV objects are also used directly from within the object's original application domain. In this case, because no marshaling takes place, no copy is made and access is efficient.

Create a marshal-by-value type by using the SerializableAttribute unless you are extending a class that already implements ISerializable. In this case, you must implement ISerializable for your type.

The remoting system makes extensive use of serializable objects. A reference to an object in another application domain, represented in the remoting system by the ObjRef class, is itself serializable; it must be possible to copy it exactly and send the copy to a client. In addition, objects that transfer data are often serializable objects. DataSet, for example, extends MarshalByValueComponent, which implements ISerializable.

Remoting User-Defined Exceptions

System-defined exceptions are all marshal-by-value types (they implement the ISerializable interface) that, when thrown by a remote object, is automatically copied to the caller if the remoting configurations permit. Starting with version 1.1 of the .NET Framework, the <customErrors> element must be set to off to enable exceptions to flow to the caller.

For more information about how to create an exception type that can be thrown by a remote object and caught by a remote caller, see How To: Create an Exception Type That Can be Thrown by Remote Objects

Marshal-By-Reference Objects

Marshal-by-reference (MBR) objects are remotable objects that extend at least System.MarshalByRefObject. Depending on what type of activation has been declared, when a client creates an instance of an MBR object in its own application domain, the .NET remoting infrastructure creates a proxy that represents the MBR object and returns to the caller a reference to that proxy. The client then makes calls on the proxy. .NET remoting marshals those calls to the application domain of the remote object and invokes the call.

Note

If the client is in the same application domain as the MBR object, the infrastructure returns a direct reference to the MBR object to the client, avoiding the overhead of marshaling.

If a System.MarshalByRefObject is passed as a parameter, it becomes a proxy in the other application domain when the call arrives. MBR return values and out parameters work in the same way.

Note

Starting with version 1.1 of the .NET Framework, the .NET remoting infrastructure does not automatically deserialize certain types on the server. For example, to obtain support for MBR objects passed as parameters, you must set the server's deserialization level to Full before the server can deserialize and use the MBR parameter. For more information, see Automatic Deserialization in .NET Remoting.

You should use MBR objects when the state of the object and any executable functionality should stay in the application domain in which it was created. For example, an object that has an internal field that is an operating system handle should extend System.MarshalByRefObject because the operating system handle would not be meaningful in another application domain, in another process, or on another computer. Sometimes an object can also be prohibitively large; that might work on a robust server, but not when sent over a wire to a 33.6 KBps modem.

Context-Bound Objects

Context-bound objects are MBR objects that inherit from System.ContextBoundObject, which itself inherits from System.MarshalByRefObject. You can think of a context as a subdivision of an application domain that provides a rich environment for the objects that reside in it during execution. For example, a context could guarantee that the objects are not accessed simultaneously by multiple threads. Every application domain has a default context. Most managed code creates objects and calls members directly from within the same application domain using that domain's default context, with no context-related issues. All types that inherit from System.ContextBoundObject are exposed to other contexts (in the same domain or in other domains) as proxies.

For example, suppose you have a method on a type that is part of a transaction and hence is bound by the rules specific to the context in which it was created. That type should inherit from System.ContextBoundObject so that the object is accessed from its own context, and the system can enforce the rules regarding the transactions associated with that object and its methods. If a System.ContextBoundObject is called from another context within the same application domain, a proxy is created for the caller but the inter-context communication does not go through the channel system, which increases call efficiency in this situation.

Because crossing each boundary takes processing time, you should determine which boundaries your object must cross before deciding which type of remotable object your server should be. Objects specific to a particular context can be accessed directly only from that context. The same is true for objects specific to a particular application domain. To remote either object, the remoting system must successfully cross a context boundary, an application boundary, or both, before invoking the server object from within whatever boundary it is specific to. If you do not need a context check to call your object, you should not make your remote type extend System.ContextBoundObject; System.MarshalByRefObject performs better. If you do need context checking, you should extend System.ContextBoundObject, but you must understand that the additional boundary must be crossed before the call is made on your object.

Scope of Publication

Different remoting systems have different ways of deciding which members and what type of members can be used remotely. .NET remoting exposes objects to other application domains as though they were local, with the following exceptions:

  • Static members.

    Static fields and methods are never remoted, and field access is through direct memory. That is, .NET remoting always deals with instance members of some form.

  • Instance fields and accessors.

    For instance fields and accessor methods, the system inserts a check at runtime to determine whether the object is a proxy. If it is not a proxy, field access is direct. Otherwise, the proxy provides accessors to the caller.

  • Private methods.

    Private methods cannot be remoted. You cannot wrap and pass a delegate to a private method remotely.

  • Delegates.

    Delegates are marshal-by-value objects. The object within the delegate can be any type of remotable object — a serializable object, a MarshalByRefObject object, or a ContextBoundObject object. The sole exception is that a delegate to an interface method cannot be successfully remoted. The delegate wraps the implementation of the interface method, requiring the type information of the client to be available to the server.

  • Overriding methods on Object.

    For performance reasons, the virtual methods on Object always execute locally in the application domain where they are called. Calls to any of the following methods only go to the remote object when these methods have been overridden on the remote object:

    • Equals

      This virtual method executes remotely if overridden.

    • GetHashCode

      This method executes locally.

    • ToString

      This virtual method executes remotely if overridden.

    • Equals (the static version)

      This method executes locally.

    • MemberwiseClone

      This method executes locally.

See Also

Tasks

How to: Create an Exception Type That Can be Thrown by Remote Objects

Other Resources

.NET Framework Remoting Overview
Making Objects Remotable