Understanding Context (or How Low Can You Go?) As you have just seen, AppDomains are logical partitions within a process used to host .NET assemblies. A given application domain may be further subdivided into numerous context boundaries. In a nutshell, a .NET context provides a way for a single AppDomain to partition .NET objects that have similar execution requirements. Using context, the CLR is able to ensure that objects that have special runtime requirements are handled appropriately and in a consistent manner by intercepting method invocations into and out of a given context. This layer of interception allows CLR to adjust the current method invocation to conform to the contextual settings of a given type. Just as a process defines a default AppDomain, every application domain has a default context. This default context (sometimes referred to as context 0, given that it is always the first context created within an application domain) is used to group together .NET objects that have no specific or unique contextual needs. As you may expect, a vast majority of your .NET class types will be loaded into context 0. If the CLR determines a newly created object has special needs, a new context boundary is created within the hosting application domain. Figure 10-9 illustrates the process, AppDomain, context relationship. Figure 10-9. Processes, application domains, and context boundaries Context-Agile and Context-Bound Types .NET types that do not demand any special contextual treatment are termed context-agile objects. These objects can be accessed from anywhere within the hosting AppDomain without interfering with the object's runtime requirements. Building context-agile objects is a no-brainer, given that you simply do nothing (specifically, you do not adorn the type with any contextual attributes and do not derive from the System.ContextBoundObject base class): // A context-agile object is loaded into context 0. public class IAmAContextAgileClassType{} On the other hand, objects that do demand contextual allocation are termed context-bound objects, and must derive from the System.ContextBoundObject base class. This base class solidifies the fact that the object in question can only function appropriately within the context in which it was created. In addition to deriving from System.ContextBoundObject, a contextsensitive type will also be adorned with a special category of .NET attributestermed (not surprisingly) context attributes. All context attributes derive from the System.Runtime.Remoting.Contexts.ContextAttribute base class, which is defined as follows (note this class type implements two context-centric interfaces, IContextAttribute and IContextProperty): public class System.Runtime.Remoting.Contexts.ContextAttribute :Attribute, System.Runtime.Remoting.Contexts.IContextAttribute, System.Runtime.Remoting.Contexts.IContextProperty { public ContextAttribute(string name); public string Name { virtual get; } public object TypeId { virtual get; } public virtual bool Equals(object o); public virtual void Freeze(System.Runtime.Remoting.Contexts.Context newContext); public virtual int GetHashCode(); public virtual void GetPropertiesForNewContext( System.Runtime.Remoting.Activation.IConstructionCallMessage ctorMsg); public Type GetType(); public virtual bool IsContextOK( System.Runtime.Remoting.Contexts.Context ctx, System.Runtime.Remoting.Activation.IConstructionCallMessage ctorMsg); public virtual bool IsDefaultAttribute(); public virtual bool IsNewContextOK( System.Runtime.Remoting.Contexts.Context newCtx); public virtual bool Match(object obj); public virtual string ToString(); } The .NET base class libraries define numerous context attributes that describe specific runtime requirements (such as thread synchronization and URL activation). Given the role of .NET context, it should stand to reason that if a context-bound object were to somehow end up in an incompatible context, bad things are guaranteed to occur at the most inopportune times. Creating a Context-Bound Object So, what sort of bad things might occur if a context-bound object is placed into an incompatible context? The answer depends on the object's advertised contextual settings. Assume for example that you wish to define a .NET type that is automatically thread-safe in nature, even though you have not hard-coded thread-safe-centric logic within the method implementations. To do so, you may apply the System.Runtime.Remoting.Contexts.SynchronizationAttribute attribute as follows: using System.Runtime.Remoting.Contexts; // This context-bound type will only be loaded into a // synchronized (and hence, thread safe) context. [Synchronization] public class MyThreadSafeObject : ContextBoundObject { } As you will see in greater detail later in this chapter, classes that are attributed with the [Synchronization] attribute are loaded into a thread-safe context. Given the special contextual needs of the MyThreadSafeObject class type, imagine the problems that would occur if an allocated object were moved from a synchronized context into a nonsynchronized context. The object is suddenly no longer thread-safe and thus becomes a candidate for massive data corruption, as numerous threads are attempting to interact with the (now thread-volatile) reference object. This is obviously a huge problem, given that the code base has not specifically wrapped thread-sensitive resources with hardcoded synchronization logic. Placing Context in Context Now, the good news is that you do not have to concern yourself with the act of ensuring that your context-bound objects are loaded into the correct contextual setting. The .NET runtime will read the assembly metadata when constructing the type, and build a new context within the current application domain when necessary. To be honest, the notion of .NET context is an extremely low-level facility of the CLR. So much so, that a key context-centric namespace, System.Runtime.Remoting.Context, only formally lists the SynchronizationAttribute class type within online Help (as of .NET version 1.1). The remaining members are considered usable only by the CLR, and are intended to be ignored (which you should do, given that many members of this namespace are subject to change in future releases of .NET). Nevertheless, it is possible to make use of these hands-off types, simply as an academic endeavor. Thus, by way of a friendly heads-up, understand that the following example is purely illustrative in nature. As a .NET programmer, you can safely ignore these low-level primitives in 99.99 percent of your applications. If you wish to see the formal definition of the any of the following context-centric types, make use of the wincv.exe utility. NOTE COM+ developers are already aware of the notion of context. Using COM IDL attributes and the Component Services utility, developers are able to establish contextual settings for a given COM+ type. Although .NET and COM+ both make use of contextual boundaries, understand that the underlying implementations of both systems are not the same and cannot be treated identically.