This class implements a client-side pool for Enterprise Services just-in-time activation proxies.

The motivation for this class is simple: SPEED. The highest cost associated with Enterprise Services' ServicedComponents is indeed object activation; more precisely: It's the activation of the full path of communication and interception between the client-side and the server-side of a ServicedComponent instance. "Just In Time Activation" (JITA) is a feature that has been present in the MTS/COM+/Enterprise Services technology stack from the early beginnings in 1996.

In short: For a component for which JITA is enabled, the first component instance will be instantiated in a regular manner. When this component instance is being deactivated and discarded (when the deactivation flag is set), the server-side instance will go away, but the communication channel and the server-side context are being kept alive and the proxy (client-side) can be reused. The next client call on the same proxy will cause a new server-side instance to be created, but all of the effort to set up client/server communication and setting up the context is skipped. 

The primary reason for the existence of JITA in MTS is transaction isolation. It cannot be permitted to make a call into and retrieve transient state from a component that has participated in any completed transaction, because that would violate the "D" and "I" properties of ACID. More and more, JITA proved to be a very valuable feature by itself. Today, in a managed environment, one of the great aspects of JITA is, for instance, that it will enable deterministic, synchronous finalization for object state without having to rely on a client calling Dispose(). A ServicedComponent implementation can make (and revoke) that decision by itself by setting the DeactivateOnReturn property.

With the class shown below, the JITAPool, enables client-side proxy caching that allows very fast links to out-of-process Enterprise Services applications. It essentially eliminates the expensive activation sequence by letting you reuse JITA proxies and complement server-side object pooling with client-side proxy pooling. Using this pool in conjeunction with server-side object pooling means that, after the initial startup, you will simple reconnect and regroup existing instances of objects and proxies but hardly ever create new ones - taking the most expensive aspect of Enterprise Services -- Activation -- out of the picture, altogether.

The pool is lock-free, SMP safe and works great for connecting out-of-process business logic to ASP.NET Web Forms and Web Services.

Usage:

(a) Store a reference to the pool somewhere in a globally accessible static variable or property. One per ServicedComponent class you want to call.

static JITAPool servicedComponentPool = new JITAPool(typeof(AddressExport.AddressExporterPooled));

(b) Use the pool. Pop() a reference, use the reference and Push() the reference back:

AddressExporterPooled exporter = (AddressExporterPooled)servicedComponentPool.Pop();
exporter.ExportAddressBatchServer( (
string
) data );
servicedComponentPool.Push(exporter);

Here's the class:

using System;
using System.EnterpriseServices
;
using System.Threading;

namespace newtelligence.EnterpriseServices
{
    /// <summary>
    /// This class implements a client-side pool for
    /// just-in-time activated ServicedComponents. The pool
    /// is fully SMP thread safe and should be held in a
    /// static class variable in environments like ASP.NET.
    /// Goal of this pool is to eliminate the client-side
    /// activation work for ServicedComponents which are
    /// frequently used in such environments.
    /// </summary>
    /// <example>
    /// (TBD)
    /// </example>
    /// <remarks>
    /// Using this pool is permitted in all circumstances
    /// where holding and reusing references to just-in-time
    /// activated objects is permitted. It is explicitly not
    /// permitted (or functional) to use this pool when Pop()
    /// would be invoked from within a preexisting EnterpriseServices
    /// context other than the default context.
    /// </remarks>
    public sealed class JITAPool
    {
        /// <summary>
        /// Exception thrown when an incompatible type is
        /// envcountered at initialization time or when
        /// Push() is called.
        /// </summary>
        public class IncompatibleTypeException : Exception
        {
            private Type type;

            internal IncompatibleTypeException( Type type )
                :base("Incompatible data type for JITAPool")
            {
                this.type = type;
            }

            public Type TypeError
            {
                get
                {
                    return type;
                }
            }
        }

        /// <summary>
        /// Exception thrown when the pool overflows at
        /// Push().
        /// </summary>
        public class PoolOverflowException : Exception
        {
            private int capacity;

            internal PoolOverflowException( int Capacity )
                :base("Pool overflow, capacity reached")
            {
                this.capacity = Capacity;
            }

            public int Capacity
            {
                get
                {
                    return capacity;
                }
            }
        }

        private Type servicedComponentType;
        private object[] pool;
        private int capacity;

        /// <summary>
        /// Public constructor for the JITAPool object.
        /// Sets the pool capacity to a default size of 64
        /// slots.
        /// </summary>
        /// <param name="ServicedComponentType">
        /// ;   Type of serviced component to be placed into the pool.
        /// </param>
        public JITAPool( Type ServicedComponentType )
        {
            Initialize( ServicedComponentType, 64 );
        }

        /// <summary>
        /// Public constructor for the JITAPool object.
        /// </summary>
        /// <param name="ServicedComponentType">
        /// ;   Type of serviced component to be placed into the pool.
        /// </param>
        /// <param name="Capacity">
        /// ;   Capacity of the pool. This number must be less than
        /// ;   the number of concurrent threads using objects from
        /// ;   this pool.
        /// </param>
        public JITAPool( Type ServicedComponentType, int Capacity  )
        {
            Initialize( ServicedComponentType, Capacity );
        }

        /// <summary>
        /// Initializes the pool. The capacity cannot and must not
        /// be changed after initialization.
        /// </summary>
        /// <param name="ServicedComponentType">
        /// ;   Type of serviced component to be placed into the pool.
        /// </param>
        /// <param name="Capacity">
        /// ;   Capacity of the pool. This number must be less than
        /// ;   the number of concurrent threads using objects from
        /// ;   this pool.
        /// </param>
        private void Initialize( Type ServicedComponentType, int Capacity  )
        {
            if ( ServicedComponentType.IsSubclassOf(typeof(ServicedComponent)) )
            {
                servicedComponentType = ServicedComponentType;
                capacity = Capacity;
                pool = new object[capacity];
            }
            else
            {
                throw new IncompatibleTypeException(servicedComponentType);
            }
        }

        /// <summary>
        /// ServicedComponent subclass for which proxy instances are
        /// held in this pool.
        /// </summary>
        public Type ServicedComponentType
        {
            get
            {
                return servicedComponentType;
            }
        }

        /// <summary>
        /// Returns a ServicedComponent instance from the pool. If
        /// the pool is empty, a new instance of the pool's ServicedComponentType
        /// is instantiated and returned.
        /// </summary>
        /// <returns>
        /// ;   Pooled are newly created ServicedComponent instance of the
        /// ;   pool's ServicedComponentType
        /// </returns>
        public ServicedComponent Pop()
        {
            for ( int k=0;k<capacity;k++)
            {
                object tok = Interlocked.Exchange(ref pool[k],null);
                if ( tok != null )
                {
                    return tok as ServicedComponent;
                }
            }

            ServicedComponent component;

            component = (ServicedComponent)Activator.CreateInstance(servicedComponentType);
            return component;
        }

        /// <summary>
        /// Places a ServicedComponent instance back into the pool.
        /// </summary>
        /// <param name="servicedComponent">Reference to a ServicedComponent</param>
        public void Push( ServicedComponent servicedComponent )
        {
// uncomment the directives to increase speed for release builds
// optional: #if DEBUG
            if ( servicedComponent.GetType() != servicedComponentType &&
                 !servicedComponent.GetType().IsSubclassOf(servicedComponentType) )
            {
                throw new IncompatibleTypeException(servicedComponent.GetType());
            }
            else
            {
// optional: #endif
                object sc = servicedComponent;
                for ( int k=0;k<capacity;k++)
                {
                    object tok = Interlocked.CompareExchange(ref pool[k],sc,null);
                    if ( tok == null )
                    {
                        return;
                    }
                }
                throw new PoolOverflowException(capacity);
// optional: #if DEBUG
            }
// optional: #endif
        }

        /// <summary>
        /// Empties the pool. Should never be called.
        /// </summary>
        public void Flush()
        {
            for ( int k=0;k<capacity;k++)
            {
                Interlocked.Exchange(ref pool[k],null);
            }
        }
    }
}