This is preliminary documentation and subject to change.
To comment on this topic, please send us email at ngwssdk@microsoft.com. Thanks!
Remoting Object Model Concepts
This section provides guidelines for placing objects in the various class buckets:
- System.Object
- System.Object (marked as Serializable custom attribute, and optionally I ISerializable
- System.MarshalByRefObject
- System.ContextBoundObject
Remoting Object Categories
Runtime object types are categorized into 3 categories.
Runtime category |
Must derive from |
Not Marshaled
(Agile)
|
System.Object |
Unbound
(Agile, Marshal By Value)
|
System.Object
Marked with [serializable]. May have Iserializable & related Constructor
|
AppDomain-bound
(Agile, Marshal By Reference)
|
System.MarshalByRefObject |
Context-bound
(Contextful, Marshal by Reference)
|
System.ContextBoundObject |
Agile objects
Agile objects are accessed directly from any context and are called directly from the caller context with an AppDomain.
To invoke a method on an agile object from anywhere within an AppDomain, a direct reference would suffice. The Base Class Libraries (System.*) consists mostly of agile classes with a few exceptions.
Unbound (Agile, Marshal By Value) and AppDomain-bound (Agile, Marshal By Reference) are collectively referred to as agile.
“Not Marshaled” type Category
class Foo
{
int Bar;
int Foo;
//. . .
}
class Baz : Foo
{
//. . .
}
Since Foo is “Not Marshaled” then Baz is also “Not Marshaled”.
Key Points:
- Default for all objects that do not derive from System.MarshalByRefObject or System.ContextBoundObject and that do not have the [serializable] custom attribute.
- Derive from System.Object or any of its children.
- “Not Marshaled” objects are appropriate when it makes the object should not leave the AppDomain. The object was designed for local use only.
- Fields, properties and methods are always accessed directly with an AppDomain i.e. from any context in the AppDomain.
- They are always accessed directly because all references to them are to an actual instance.
- Instanced cannot be sent across an AppDomain boundary since they are not serializable
- Highly optimized by EE and JIT.
- No extra costs.
Unbound (Object By Value) objects type category
[serializable]
class Foo
{
int Bar;
int Foo;
//. . .
}
class Baz : Foo
{
//. . .
}
Since Foo is Unbound then Baz is also Unbound.
Key Points:
- Similar to the “Not Marshaled” category however the object can be passed across AppDomain boundaries by value i.e. a copy is made.
- Derive from System.Object or any of its children.
- Unbound objects are appropriate when it makes sense for performance or processing reasons to move the complete state of the object with the execution to the target AppDomain. In many scenarios this reduces boundary crossing (network, process, appdomain) round-trips. For example self contained objects.
- Fields, properties and methods are always accessed directly with an AppDomain i.e. from any context in the AppDomain.
- They are always accessed directly because all references to them are to an actual instance.
- Instances are not confined to any boundary.
- No distributed identity.
- No proxy is ever created i.e. a copy is made when necessary. When passed in a remote call across an AppDomain boundary, a copy is made from the source App Domain to the target App Domain (“Marshal By Value”). The following scenarios are automatically taken care of by the NGWS runtime:
- Between AppDomains in the same physical process.
- Between AppDomains in different physical processes on the same machine.
- Between AppDomains in different physical processes on different machines.
- An Unbound object, can expose Iserializable, if it wants to participate in its own serialization when marshaled across AppDomain boundaries.
- Highly optimized by EE and JIT.
- No extra costs.
Marshal By Reference (Object By Reference) object type category
Base class for Remoting objects that need to be marshal by reference. This includes WellKnown SingleCall and WellKnown Singleton WebService objects and Client Activated Objects.
class Zap : MarshalByRefObject
{
//. . .
}
class Waz : Zap
{
//. . .
}
Since Zap is AppDomain-Bound then Waz is also AppDomain-Bound.
Key Points:
- Derive from System.MarshalByRefObject or any of its children (except from context bound objects which derive from System.ContextBoundObject).
- Have distributed identity.
- Instances of MarshalByRefObject classes are confined to the App Domain in which they were created, their "Home AppDomain", but are accessible directly from any context within that App Domain. An App Domain is the logical equivalent of a sub-process within the Runtime.
- MarshalByRefObject's are appropriate when the state of the object should stay in the AppDomain that created it and only references should be marshaled when the object is remoted. For example a File IO object that internally has field which is an OS handle should be made AppDomain-bound, since the OS handle would not be useful or appropriate in another AppDomain in another process or another machine.
- If a MarshalByRefObject is passed outside of the "Home AppDomain" e.g. as a parameter on a remote method call or as a return value from a remote method call, a reference is passed from the source App Domain to the target App Domain ("Marshal By Reference") i.e. a reference is marshaled into the target App Domain. The following scenarios are automatically taken care of by the NGWS runtime:
- Between AppDomains in the same physical process.
- Between AppDomains in different physical processes on the same machine.
- Between AppDomains in different physical processes on different machines.
- Subsequent calls on the reference in the target AppDomain are marshaled back in to the "Home AppDomain" in which the object was created.
- MarshalByRefObject's that are remoted out of the AppDomain and subsequently called remotely are called from the default context for the AppDomain.
- Since a client may hold a proxy, all operations on the class are appropriately indirected such that the infrastructure can intercept and forward them. This is performed automatically by the EE and JIT working together.
- Fields of App Domain bound objects must be accessed through accessors. This is performed automatically by the EE and JIT working together.
- All member functions of an App Domain bound objects must be called through indirection. This is performed automatically by the EE and JIT working together.
- No inlining of the methods, field and properties of App Domain bound classes.
- Like Context-bound objects, there are costs associated with App Domain bound objects, but those costs are smaller.
MarshalByRefObject as the base class for remote objects
Depending on which JIT is being used, certain optimizations may be used for classes which are not Marshaled by Reference e.g. direct field access by JIT. Inlining of methods is another optimization. One of rules of using MarshalByRefObject across AppDomains is that all the parents need to have the ancestor of MarshalByRefObject, this to enable the EE and JIT to provide consistent access.
The incorrect way |
The correct way |
class Foo
{
int i;
float f;
void Method1();
}
[MarshalByRefObject()]
class Baz : Foo
{
String s;
void Method2();
}
void SomeCode(Foo foo)
{
int myInt = foo.i;
foo.f = 2.4;
foo.Method1();
}
|
class Foo : MarshalByRefObject
{
int i;
float f;
void Method1();
}
class Baz : Foo
{
String s;
void Method2();
}
void SomeCode(Foo foo)
{
int myInt = foo.i;
foo.f = 2.4;
foo.Method1();
}
|
Performance Implications for MarshalByRefObject
Since a client may hold a proxy, all operations on the class are appropriately indirected such that the infrastructure can intercept and forward them. This is performed automatically by the EE and JIT working together.
Fields of MarshalByRefObject must be accessed through accessors. This is performed automatically by the EE and JIT working together.
All member functions of MarshalByRefObjects must be called through indirection. This is performed automatically by the EE and JIT working together.
Performance implications of marshalling between AppDomains
Since AppDomains are completely isolated there is no sharing of state, the parameters on the stack must be converted into a binary format (pretty fast) and carried to the other appdomain and turned back into a stack frame. If MarshalByRefObjects are passed in as parameters, these will turn into a proxy in the other appdomain, when the call arrives.
Context Bound Object type category
class Tip : ContextBoundObject
{
//. . .
}
class Pot : Tip
{
//. . .
}
Since Tip is Context-Bound then Pot is also Context-Bound.
Key Points:
- More specialized that AppDomain bound objects.
- Derive from System.ContextBoundObject or any of its children.
- Have distributed identity.
- Instances of Context-bound classes are confined to the Context in which they were created, their “Home Context”. They are accessed directly from their “Home Context”, but are accessible by proxy from any context. A Context is a boundary that can enforce policies on classes such as: Synchronization, Thread Affinity etc.
- Context-bound objects are appropriate when the state of the object should stay in the context in which it was created.
- If an Context-bound object is passed outside of the “Home Context” e.g. as a parameter on a cross context method call or as a return value from a cross context method call, a reference is passed from the source context to the target context (“Marshal By Reference”) i.e. a reference is marshaled into the target context. The following scenarios are automatically taken care of by the NGWS runtime:
- Between Contexts in the same AppDomain.
- Between Contexts in different AppDomains in the same physical process.
- Between Contexts in different AppDomains in different physical processes on the same machine.
- Between Contexts in different AppDomains in different physical processes on a different machines.
- Subsequent calls on the reference in the target Context are marshaled back in to the “Home Context” in which the object was created.
- Since a client may hold a proxy, all operations on the class are appropriately indirected such that the infrastructure can intercept and forward them.
- Fields of Context-bound objects must be accessed through accessors.
- All member functions of an Context-bound objects must be called through indirection.
- No inlining of the methods, field and properties of Context-bound classes.
- Context-bound objects have a cost. Even if there is only one context in an entire program, which all instances live in there are still costs due to the possibility that a new context could appear at some point.