using System; using System.EnterpriseServices; using System.Threading; using System.Runtime.Serialization; namespace newtelligence.EnterpriseServicesTools { /// /// This class implements a client-side pool for /// just-in-time activated ServicedComponents. The pool /// is fully SMP thread safe and can 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. /// /// ///

Using this pool is permitted under all circumstances /// where holding and reusing references to just-in-time /// activated objects is appropriate. It is explicitly not /// permitted (or properly functional) to use this pool when Pop() /// would be invoked from within a preexisting EnterpriseServices /// context other than the default context.

///
public sealed class JustInTimeActivationProxyPool where SCType : ServicedComponent, new() { /// /// COM+ failure code indicating that the call could not be completed and did /// indeed not execute on the server. /// private const UInt32 ERpcCallFailedDne = 0x800706bf; /// /// COM+ failure code indicating that the server class is currently diaabled. /// private const UInt32 EClassDisabled = 0x80004027; /// /// COM+ failure code indicating that the server class is currently paused. /// private const UInt32 EClassPaused = 0x80004025; private object[] pool; private int capacity; /// /// Public constructor for the JustInTimeActivationProxyPool object. /// Sets the pool capacity to a default size of 64 /// slots. /// public JustInTimeActivationProxyPool() { Initialize( 64 ); } /// /// Public constructor for the JustInTimeActivationProxyPool object. /// /// /// Capacity of the pool. This number must be less than /// the number of concurrent threads using objects from /// this pool. /// public JustInTimeActivationProxyPool( int capacity ) { Initialize( capacity ); } /// /// Initializes the pool. The capacity cannot and must not /// be changed after initialization. /// /// /// Capacity of the pool. This number must be less than /// the number of concurrent threads using objects from /// this pool. /// private void Initialize( int Capacity ) { capacity = Capacity; pool = new object[capacity]; } /// /// Returns a ServicedComponent instance from the pool. If /// the pool is empty, a new instance of the pool's ServicedComponentType /// is instantiated and returned. /// /// /// Pooled are newly created ServicedComponent instance of the /// pool's ServicedComponentType /// public SCType Pop() { for ( int k=0;k(); } /// /// Places a ServicedComponent instance back into the pool. /// /// Reference to a ServicedComponent public void Push( SCType servicedComponent ) { SCType sc = servicedComponent; for ( int k=0;k /// Empties the pool. Should not be called. /// public void Flush() { for ( int k=0;k /// /// /// public void Using(JustInTimeActivationProxyPoolHandler call) { // Check whether we are currently in a transaction. If that is so, we cannot reuse a pooled proxy if ((ContextUtil.IsInTransaction)) { using (SCType component = new SCType()) { call(component); } } else { try { // Try to execute the call using a proxy from the pool. This may fail is the server has been // shut down between when the proxy was created and "now" or if the server is currently paused // or stopped. The call may also fail for many other reasons, but these are the three cases we // are ready to recover from. SCType component = Pop(); call(component); Push(component); } catch (System.Runtime.InteropServices.ExternalException ex) { if ((((uint)(ex.ErrorCode)) == ERpcCallFailedDne)) { // The call failed because the proxy has been disconnected from the // server, likely because the server recycled or shut down. To recover // we create a new proxy, try to run the call and put the new proxy into the pool SCType service = new SCType(); call(service); Push(service); } else { if ((((uint)(ex.ErrorCode)) == EClassDisabled)) { // The server is currently disabled. Fail out. throw new ApplicationDisabledException(); } else { if ((((uint)(ex.ErrorCode)) == EClassPaused)) { // The server is currently paused. Fail out. throw new ApplicationPausedException(); } else { // An exception occurred that we are not ready to handle. Forward throw.. throw; } } } } catch { throw; } } } } /// /// /// /// /// public delegate void JustInTimeActivationProxyPoolHandler(SCType component); /// /// This exception is thrown when the Enterprise Services application is disabled /// and cannot be reached. /// [Serializable] public class ApplicationDisabledException : Exception { /// /// Constructor. /// public ApplicationDisabledException() : base(Properties.Resources.ApplicationDisabledMessage) { } /// /// Constructor. /// /// Message for the exception. public ApplicationDisabledException(string message) : base(message) { } /// /// Creates a new instance of ApplicationDisabledException /// protected ApplicationDisabledException(SerializationInfo si, StreamingContext sc) : base(si, sc) { } /// /// Creates a new instance of ApplicationDisabledException /// public ApplicationDisabledException(string message, Exception ex) : base(message, ex) { } } /// /// This exception is thrown when the Enterprise Services application is paused /// and cannot be reached. /// [Serializable] public class ApplicationPausedException : Exception { /// /// Constructor. /// public ApplicationPausedException() : base(Properties.Resources.ApplicationPausedMessage) { } /// /// Constructor. /// /// Message for the exception. public ApplicationPausedException(string message) : base(message) { } /// /// /// /// /// protected ApplicationPausedException(SerializationInfo info, StreamingContext context) : base(info, context) { } /// /// Creates a new instance of ApplicationDisabledException /// public ApplicationPausedException(string message, Exception e) : base(message, e) { } } }