Read the following topics prior to reading this specification:
Key Points
New objects are activated in an Application. An Application is hosted within an AppDomain. An application can be configured to hosted in a remote AppDomain, relative to the current application. If the object is activated in a remote application, then the actual object instance is created in the remote application appdomain.
A whole assembly or an individual type within an assembly can be configured to be activated in a remote application. A type can be specified using Activator.CreateInstance to activate in a remote application.
Activation happens in two stages:
In the first stage, a decision is made regarding whether the current application is OK.
In both the stages, context properties of the current context and context attributes defined on the type e.g. Foo (hereafter referred to only as context properties) are involved.
The context properties can perform the following operations:
At the end of the second stage, activation is delegated to the activator present in the constructor message object. The activator depending on its type performs either a cross-machine, cross-process, cross-appdomain, or cross-context activation. The interfaces used during the two stages of activation is listed below:
The IActivationProperty interface is exposed by the context properties that wish to participate in activations happening in the context on which they are present.
public interface IActivationProperty { bool IsContextOK(Context ctx, IConstructionCallMessage msg); void GetPropertiesForNewContext(IConstructionCallMessage msg); }
The IContextAttribute interface is implemented by attribute classes defined on a type. The attributes participate in activations of the type on which which they are defined.
public interface IContextAttribute { bool IsContextOK(Context ctx, IConstructionCallMessage msg); void GetPropertiesForNewContext(IConstructionCallMessage msg); }
The IActivator interface is implemented by activators. Note that activators form a hierarchy that must be observed.
public interface IActivator { IActivator NextActivator {get; set;}; String Hierarchy {get; }; IConstructionReturnMessage Activate(IConstructionCallMessage msg); }
To understand the mechanism for deciding when and how to create new applications, let us consider the properties implicitly added on every context by the runtime.
There are three such properties:
The implementation of the above properties supports extensibility. For example, both Process and AppDomain properties support registration functions for calling arbitrary code at process (basically in all AppDomains) and AppDomain (a specific one) boundaries during call ins and call outs.
Appdomain and Applications are distinct concepts. An AppDomain is a unit of shutdown, debuggability, etc. A single AppDomain can host multiple applications. Applications are a unit of deployment, configuration, etc.
NGWS runtime types can be configured differently in different applications. For example, in application “WingTipToysApp”, type CFoo can be configured as compatible in the sense that it can run inside it. CFoo is activated locally.
However, in the application “TailSpinToysApp”, type CFoo can be configured to run specifically in remote application “WingTipToysApp”, on Wing Tip's machine, which is specified through an Application URI in the Remoting Configuration portion of Tail SpinToysApp's application configuration file. CFoo is activated remotely. Note that the only types that can be configured in this manner are MarshalByRef and ContextBound ones. It is pointless to configure Unbound types as they are always marshaled by value (See the Remoting Object Model section for details on Marshal By Value).
Let us consider the above example scenario of “TailSpinToysApp” activating a CFoo instance in “WingTipToysApp”. Every appdomain supports a well-known activator object that can receive messages on the the object URI “RemoteActivationService” that can be used to activate instances of a given type in that appdomain. It is registered at appdomain startup by the remoting infrastructure. During activation of an instance of CFoo, the application property representing application “TailSpinToysApp” notices that CFoo instances need to be created in “WingTipToysApp” at the Application URI for WingTipToysApp (the Application URI could point to Wing Tip's machine, wingtiptoys), and replaces the activator present in the constructor message with the activator obtained by the following method:
IActivator activator = (IActivator)Activator.GetObject( typeof(Activator), “http://www.WingTipToys.com/WingTipToysApp/RemoteActivationService.rem”);
The above call to Activator.GetObject returns a proxy representing the “Activator” type that connects to a well-known instance running at the URL “http://www.WingTipToys.com/WingTipToysApp/RemoteActivationService.rem”. At the end of second stage, the Remoting activation infrastructure, executing as part of the constructor call on the proxy returned by the first stage, delegates activation to the activator retrieved from the constructor message by making the following call.
IActivator activator = constructorMessage.Activator; IConstructorReturnMessage returnMessage = activator.CreateInstance(constructorMessage); ObjRef objref = returnMessage.GetReturnValue();
The following operations happen during above activator.CreateInstance call above:
One or more attributes that can participate in activation.
Passed as an array of objects.
URLAttribute(“http://hostname/appname/objectURI”)
The constructor needs to be identified. Choices
Zero or more arguments to the constructor.
package SomePackage; public class SomeClass : MarshalByRefObject { public SomeClass(int a, float b) { //. . . } public void SomeMethod(String s) { //. . . } }
Key Points
Consider the following code snippet:
// . . . CFoo foo = new CFoo(1, “SomeString”); foo.Method1(); // . . .
When the above code snippet is JITed, the JIT is given different JITHelpers based on the type of CFoo. If CFoo is an Unbound type, the JITHelper is a fast one that always returns a new uninitialized instance of CFoo on which JIT subsequently runs the constructor. If CFoo is either MarshalByRef or ContextBound, a different JITHelper is a returned that may initiate activation in remoting sense. The following is the description of operations performed by the Remote Activation JITHelper.
Activation happens in two stages: In the first stage, a decision is made regarding whether the current Application is OK. If the answer is Yes, an uninitialized instance of CFoo is returned, JIT runs the constructor on it, and the activation is done. If the answer is no, a proxy that can handle only calls to constructors is returned and JIT subsequently calls the constructor on the proxy, and the second stage processing begins. See the section Activation Serving up a new object instance for details on how remote activation works.
The Activator.GetObject method (in an number of variations) provides the ability to obtain a “proxy” to an already running remote object Well Known object. Only when calls are made on the “proxy” will messages be sent remotely.
public void SomeCode() { //. . . String url = “http://hostname/vroot/objectname”; // Resolve the URL and return a proxy SomeObject so = (SomeObject)Activator.GetObject( typeof(SomePackage.SomeClass), url); // Call methods on the remote instance so.SomeMethod(“Hello World”); //. . .
Key Points
Activation happens in two stages: In the first stage, a decision is made regarding whether the current Application is OK. If the answer is yes, an uninitialized instance is created, the constructor is run on it, and the activation is done. If the answer is no, then the second stage processing begins. See the section Activation Serving up a new object instance for details on how remote activation works.
public void SomeCode() { //. . . // Build up array of constructor arguments Object[] args = new Object[2]; args[0] = “Some Argument”; args[1] = 2.3; // Build up array of activation attributes Object[] activationAttributes = new Object[3]; activationAttributes[0] = new URLAttribute(“http://hostname/vroot/objectname”); // Other objects can be passed activationAttributes [1] = . . . activationAttributes [2] = . . . // Activate the remote instance and return a proxy SomeObject so = (SomeClass)Activator.CreateInstance( typeof(SomePackage.SomeClass), args, activationAttributes); // Call methods on the remote instance so.SomeMethod(“Hello World”); //. . . }
Key Points
Type t = Type.GetType(“SomePackage.SomeClass”); Object[] objects = new Object[2]; objects[0] = AppDomain.CreateDomain( . . .) objects[1] = // Specify the assembly SomeClass sc = (SomeClass)Activator.CreateInstance(t, . . ., objects ); or ObjectHandle oh = Activator.CreateInstance(t, . . ., objects ); SomeClass sc = (SomeClass)oh.Unwrap(); // For in memory Assemblies pass the byte[] Type t = Type.GetType(“SomePackage.SomeClass”); Object[] objects = new Object[2]; objects[0] = AppDomain.CreateDomain( . . .) objects[1] = // pass the byte[] assemblyInMemory; SomeClass sc = (SomeClass)Activator.CreateInstance(t, . . ., objects );
Step 0) Message from EE Activation to Attributes
Steps
IConstructionCallMessage
Step 1) Message from EE Activation to Activator
Steps
IConstructionCallMessage
Step 2) Activator
Steps
IConstructionCallMessage
Step 3) Activator back to Client Context Terminator Sink
Steps
Step 4) Call unwinds to EE Activation
Steps
Step 5) EE returns to execution code
Steps