Key Points
Execution system
A context is an ordered sequence of properties that define an environment for the objects resident inside it. Contexts get created during the activation process for objects that are configured to require certain automatic services such synchronization, transactions, just-in-time activation, security etc. Multiple objects can live inside a context.
Below is a brief summary of some of the context characteristics:
Because all context-bound objects can be proxied across contexts, this imposes certain restrictions on how code can manipulate context-bound objects. For example, code cannot access a field on a context-bound object directly. Another example is that non-virtual calls must be made through an indirection and no inlining is allowed (to allow proxies when appropriate). This makes context-bound objects a good bit more expensive than one would like.
Classes, which are not context-bound are sometimes referred to as agile classes.
This should not be confused with agile locations (described below in the location section), although the ideas are parallel.
Agile objects are not bound to contexts and they are not proxied across contexts within the same AppDomain. Agile objects are only agile within an App Domain. Agile objects “live” in the Default Context (of which there is one per app-domain). The default context has no non-trivial properties. Any object passes across an AppDomain boundary is considered to be remoted.
Context-bound objects are very appropriate for transaction isolation / propagation and other features where the cost is acceptable.
Types (classes) can be attributed with custom attributes. IL generator (compiler) support is needed for custom attributes. Context-bound classes can be attributed with specialized custom attributes known as Context Attributes. Context Attributes provide context properties which when added to a context can enforce policies such as Synchronization, Thread Affinity, or Transactions etc.
Many IL Generators (language compilers) support injecting custom attributes onto classes. This allows for context attributes to be attached to a type at compile time. Custom attributes are stored within the metadata of the PE.
Context Attributes can be applied to a type statically i.e. embedded within the metadata of the PE (compiled into the module) in which the type is defined. The developer set of static context properties are fixed.
Third parties can develop new Context Attributes and Properties.
Types (classes) can be attributed with custom attributes. IL generator (compiler) support is needed for custom attributes. Context-bound classes can be attributed with specialized custom attributes known as Context Attributes. Context Attributes provide context properties which when added to a context can enforce policies such as Synchronization, Thread Affinity, or Transactions etc.
IL Generators (language compilers) must support injecting custom attributes onto classes. This allows for static context attributes to be attached to a type at compile time. Custom attributes are stored within the metadata of the PE.
The server context sink chain is built by asking the first context property for a sink, proceeding to the last property. The client context sink chain is built by asking the last context property for a sink, proceeding to the first property. When a call enters a content (on the server context chain) and then makes a call out of the context (client context chain) we need to rollback the policies on the thread (e.g. Synchronization and Security).
Key Points
The Context Local Store provides data slots for the context. The data slots are unique per context i.e. the state is not shared across contexts. Named slots are also supported.
Slots. Allocated explicitly.
Named Slots. Allocate by name.
Active Context Properties achieve their functionality by contributing MessageSink objects, which perform interception on remote object method calls. These MessageSink objects can intercept both incoming calls on objects living in the context and/or outgoing calls to objects in other contexts. MessageSinks implement the IMessageSink interface.
Recall that the job of a proxy is to convert a method call invoked on it into a Message object. This Message object, which implements the IMessage interface, is passed from the client end to the server end by invoking ProcessMessage on MessageSink objects. MessageSinks are chained together in the sense that every MessageSink is responsible for calling ProcessMessage on the next MessageSink after it has performed its work. For instance, a synchronization related messageSink may cause a lock to be acquired / released and then delegate further to the downstream message sink.
From a Contexts standpoint, interception requirements lead to the following MessageSink Chains, listed in order as a call goes from the proxy to the real object:
At the end of each of the above chains is an infrastructure provided MessageSink object that ‘does the required work’ and hands the Message object to the next chain. For instance, at the end of the Server Context Chain (which would be common to all objects living in the context), we delegate the call to the chain for the correct Server Object chain, since the latter would be object specific. Tasks like this will be the responsibility of the infrastructure sinks.
Let us walk through a scenario where a context-bound object is called from another context. We will assume that at some point during activation, the client and server contexts have been created for us.
Context Relative Statics provide for type member fields that are relative for the context. Whenever the static field is accessed on a particular context it will be unique or relative for that context only. The static is not shared between contexts. If the static field is access on another context the field will contain a different value, since the field is unique per context.
The member field is marked with a custom attribute System.ContextStatic.