SharedConnectionWorkflowTransactionService.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / cdf / src / WF / RunTime / Hosting / SharedConnectionWorkflowTransactionService.cs / 1305376 / SharedConnectionWorkflowTransactionService.cs

                            #pragma warning disable 1634, 1691 
//------------------------------------------------------------------------------
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//  
//-----------------------------------------------------------------------------
 
#region Using directives 

using System; 
using System.Transactions;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic; 
using System.Collections.Specialized;
using System.Configuration; 
using System.Threading; 
#endregion
 
namespace System.Workflow.Runtime.Hosting
{
    public class SharedConnectionWorkflowCommitWorkBatchService : WorkflowCommitWorkBatchService
    { 
        private DbResourceAllocator dbResourceAllocator;
        private IDictionary transactionConnectionTable; 
        private object tableSyncObject = new object(); 

        // Saved from constructor input to be used in service start initialization 
        private NameValueCollection configParameters;
        string unvalidatedConnectionString;
        private bool _enableRetries = false;
        private bool _ignoreCommonEnableRetries = false; 

        ///  
        /// Enables the adding of this service programmatically. 
        /// 
        ///  
        /// 
        public SharedConnectionWorkflowCommitWorkBatchService(string connectionString)
        {
            if (String.IsNullOrEmpty(connectionString)) 
                throw new ArgumentNullException("connectionString", ExecutionStringManager.MissingConnectionString);
 
            this.unvalidatedConnectionString = connectionString; 
        }
 
        /// 
        /// Enables adding of this service from a config file.
        /// Get the connection string from the runtime common parameter section or the particular service parameter section
        /// of the configuration file, and instantiate a DbResourceAllocator object. 
        /// 
        ///  
        ///  
        public SharedConnectionWorkflowCommitWorkBatchService(NameValueCollection parameters)
        { 
            if (parameters == null)
                throw new ArgumentNullException("parameters", ExecutionStringManager.MissingParameters);

            if (parameters.Count > 0) 
            {
                foreach (string key in parameters.Keys) 
                { 
                    if (0 == string.Compare("EnableRetries", key, StringComparison.OrdinalIgnoreCase))
                    { 
                        _enableRetries = bool.Parse(parameters[key]);
                        _ignoreCommonEnableRetries = true;
                    }
                } 
            }
 
            this.configParameters = parameters; 
        }
 
        #region Accessors
        internal string ConnectionString
        {
            get 
            {
#pragma warning disable 56503 
                if (this.dbResourceAllocator == null) 
                {
                    // Other hosting services may try to get the connection string during their initialization phase 
                    // (in WorkflowRuntimeService.Start) to dectect string mismatch conflict
                    if (this.Runtime == null)
                        throw new InvalidOperationException(ExecutionStringManager.WorkflowRuntimeNotStarted);
                    this.dbResourceAllocator = new DbResourceAllocator(this.Runtime, this.configParameters, this.unvalidatedConnectionString); 
                }
#pragma warning restore 56503 
                return this.dbResourceAllocator.ConnectionString; 
            }
        } 

        public bool EnableRetries
        {
            get { return _enableRetries; } 
            set
            { 
                _enableRetries = value; 
                _ignoreCommonEnableRetries = true;
            } 
        }
        #endregion Accessors

        #region WorkflowRuntimeService 
        override protected internal void Start()
        { 
            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService: Starting"); 

            this.dbResourceAllocator = new DbResourceAllocator(this.Runtime, this.configParameters, this.unvalidatedConnectionString); 
            if (this.transactionConnectionTable == null)
                this.transactionConnectionTable = new Dictionary();

            // 
            // If we didn't find a local value for enable retries
            // check in the common section 
            if ((!_ignoreCommonEnableRetries) && (null != base.Runtime)) 
            {
                NameValueConfigurationCollection commonConfigurationParameters = base.Runtime.CommonParameters; 
                if (commonConfigurationParameters != null)
                {
                    // Then scan for connection string in the common configuration parameters section
                    foreach (string key in commonConfigurationParameters.AllKeys) 
                    {
                        if (string.Compare("EnableRetries", key, StringComparison.OrdinalIgnoreCase) == 0) 
                        { 
                            _enableRetries = bool.Parse(commonConfigurationParameters[key].Value);
                            break; 
                        }
                    }
                }
            } 

            base.Start(); 
        } 

        protected override void OnStopped() 
        {
            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService: Stopping");
            foreach (KeyValuePair kvp in this.transactionConnectionTable)
            { 
                kvp.Value.Dispose();
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "Removing transaction " + kvp.Key.GetHashCode()); 
            } 
            this.transactionConnectionTable.Clear();
            this.dbResourceAllocator = null; 
            base.OnStopped();
        }
        #endregion Public Methods
 
        #region Public Methods
 
        protected internal override void CommitWorkBatch(WorkflowCommitWorkBatchService.CommitWorkBatchCallback commitWorkBatchCallback) 
        {
            // 
            // Disable retries by default, reset to allow retries below if we own the tx
            DbRetry dbRetry = new DbRetry(_enableRetries);
            short retryCounter = dbRetry.MaxRetries;
 
            while (true)
            { 
                // 
                // When using LocalTransaction handle block access to the connection
                // in the transaction event handlers until all IPendingWork members have completed 
                ManualResetEvent handle = new ManualResetEvent(false);
                Transaction tx = null;
                SharedConnectionInfo connectionInfo = null;
 
                try
                { 
                    if (null == Transaction.Current) 
                    {
                        // 
                        // It's OK to retry here as we own the tx
                        retryCounter = 0;
                        //
                        // Create a local, non promotable transaction that we share with our OOB services 
                        tx = new CommittableTransaction();
                        connectionInfo = new SharedConnectionInfo(this.dbResourceAllocator, tx, false, handle); 
                    } 
                    else
                    { 
                        //
                        // Can't retry as we don't own the tx
                        // Create a dependent transaction and don't restrict promotion.
                        tx = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete); 
                        connectionInfo = new SharedConnectionInfo(this.dbResourceAllocator, tx, true, handle);
                    } 
 
                    AddToConnectionInfoTable(tx, connectionInfo);
 
                    using (TransactionScope ts = new TransactionScope(tx))
                    {
                        try
                        { 
                            commitWorkBatchCallback();
                            ts.Complete(); 
                        } 
                        finally
                        { 
                            RemoveConnectionFromInfoTable(tx);
                            //
                            // Unblock transaction event handlers
                            handle.Set(); 
                        }
                    } 
 
                    CommittableTransaction committableTransaction = tx as CommittableTransaction;
                    if (committableTransaction != null) 
                        committableTransaction.Commit();

                    DependentTransaction dependentTransaction = tx as DependentTransaction;
                    if (dependentTransaction != null) 
                        dependentTransaction.Complete();
 
                    break; 
                }
                catch (Exception e) 
                {
                    tx.Rollback();

                    WorkflowTrace.Host.TraceEvent(TraceEventType.Error, 0, "SharedConnectionWorkflowCommitWorkBatchService caught exception from commitWorkBatchCallback: " + e.ToString()); 

                    if (dbRetry.TryDoRetry(ref retryCounter)) 
                    { 
                        WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService retrying commitWorkBatchCallback (retry attempt " + retryCounter.ToString(System.Globalization.CultureInfo.InvariantCulture) + ")");
                        continue; 
                    }
                    else
                        throw;
                } 
                finally
                { 
                    handle.Close(); 
                    if (tx != null)
                    { 
                        tx.Dispose();
                    }
                }
            } 
        }
        ///  
        /// Get the SharedConnectionInfo object from the hashtable keyed by the transaction 
        /// 
        ///  
        /// 
        internal SharedConnectionInfo GetConnectionInfo(Transaction transaction)
        {
            return LookupConnectionInfoTable(transaction); 
        }
 
        #endregion Public Methods 

        #region Private Methods 

        private void RemoveConnectionFromInfoTable(Transaction transaction)
        {
            lock (this.tableSyncObject) 
            {
                SharedConnectionInfo connectionInfo; 
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TransactionCompleted " + transaction.GetHashCode()); 
                if (transactionConnectionTable.TryGetValue(transaction, out connectionInfo))
                { 
                    connectionInfo.Dispose();
                    this.transactionConnectionTable.Remove(transaction);
                }
                else 
                {
                    WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TransactionCompleted " + transaction.GetHashCode() + 
                        " not found in table of count " + this.transactionConnectionTable.Count); 
                }
            } 
        }

        private void AddToConnectionInfoTable(Transaction transaction, SharedConnectionInfo connectionInfo)
        { 
            lock (this.tableSyncObject)
            { 
                this.transactionConnectionTable.Add(transaction, connectionInfo); 
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "AddToConnectionInfoTable " + transaction.GetHashCode() +
                        " in table of count " + this.transactionConnectionTable.Count); 
            }
        }

        private SharedConnectionInfo LookupConnectionInfoTable(Transaction transaction) 
        {
            lock (this.tableSyncObject) 
            { 
                return transactionConnectionTable[transaction];
            } 
        }

        #endregion Private Methods
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
#pragma warning disable 1634, 1691 
//------------------------------------------------------------------------------
// 
//   Copyright (c) Microsoft Corporation.  All rights reserved.
//  
//-----------------------------------------------------------------------------
 
#region Using directives 

using System; 
using System.Transactions;
using System.Diagnostics;
using System.Collections;
using System.Collections.Generic; 
using System.Collections.Specialized;
using System.Configuration; 
using System.Threading; 
#endregion
 
namespace System.Workflow.Runtime.Hosting
{
    public class SharedConnectionWorkflowCommitWorkBatchService : WorkflowCommitWorkBatchService
    { 
        private DbResourceAllocator dbResourceAllocator;
        private IDictionary transactionConnectionTable; 
        private object tableSyncObject = new object(); 

        // Saved from constructor input to be used in service start initialization 
        private NameValueCollection configParameters;
        string unvalidatedConnectionString;
        private bool _enableRetries = false;
        private bool _ignoreCommonEnableRetries = false; 

        ///  
        /// Enables the adding of this service programmatically. 
        /// 
        ///  
        /// 
        public SharedConnectionWorkflowCommitWorkBatchService(string connectionString)
        {
            if (String.IsNullOrEmpty(connectionString)) 
                throw new ArgumentNullException("connectionString", ExecutionStringManager.MissingConnectionString);
 
            this.unvalidatedConnectionString = connectionString; 
        }
 
        /// 
        /// Enables adding of this service from a config file.
        /// Get the connection string from the runtime common parameter section or the particular service parameter section
        /// of the configuration file, and instantiate a DbResourceAllocator object. 
        /// 
        ///  
        ///  
        public SharedConnectionWorkflowCommitWorkBatchService(NameValueCollection parameters)
        { 
            if (parameters == null)
                throw new ArgumentNullException("parameters", ExecutionStringManager.MissingParameters);

            if (parameters.Count > 0) 
            {
                foreach (string key in parameters.Keys) 
                { 
                    if (0 == string.Compare("EnableRetries", key, StringComparison.OrdinalIgnoreCase))
                    { 
                        _enableRetries = bool.Parse(parameters[key]);
                        _ignoreCommonEnableRetries = true;
                    }
                } 
            }
 
            this.configParameters = parameters; 
        }
 
        #region Accessors
        internal string ConnectionString
        {
            get 
            {
#pragma warning disable 56503 
                if (this.dbResourceAllocator == null) 
                {
                    // Other hosting services may try to get the connection string during their initialization phase 
                    // (in WorkflowRuntimeService.Start) to dectect string mismatch conflict
                    if (this.Runtime == null)
                        throw new InvalidOperationException(ExecutionStringManager.WorkflowRuntimeNotStarted);
                    this.dbResourceAllocator = new DbResourceAllocator(this.Runtime, this.configParameters, this.unvalidatedConnectionString); 
                }
#pragma warning restore 56503 
                return this.dbResourceAllocator.ConnectionString; 
            }
        } 

        public bool EnableRetries
        {
            get { return _enableRetries; } 
            set
            { 
                _enableRetries = value; 
                _ignoreCommonEnableRetries = true;
            } 
        }
        #endregion Accessors

        #region WorkflowRuntimeService 
        override protected internal void Start()
        { 
            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService: Starting"); 

            this.dbResourceAllocator = new DbResourceAllocator(this.Runtime, this.configParameters, this.unvalidatedConnectionString); 
            if (this.transactionConnectionTable == null)
                this.transactionConnectionTable = new Dictionary();

            // 
            // If we didn't find a local value for enable retries
            // check in the common section 
            if ((!_ignoreCommonEnableRetries) && (null != base.Runtime)) 
            {
                NameValueConfigurationCollection commonConfigurationParameters = base.Runtime.CommonParameters; 
                if (commonConfigurationParameters != null)
                {
                    // Then scan for connection string in the common configuration parameters section
                    foreach (string key in commonConfigurationParameters.AllKeys) 
                    {
                        if (string.Compare("EnableRetries", key, StringComparison.OrdinalIgnoreCase) == 0) 
                        { 
                            _enableRetries = bool.Parse(commonConfigurationParameters[key].Value);
                            break; 
                        }
                    }
                }
            } 

            base.Start(); 
        } 

        protected override void OnStopped() 
        {
            WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService: Stopping");
            foreach (KeyValuePair kvp in this.transactionConnectionTable)
            { 
                kvp.Value.Dispose();
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "Removing transaction " + kvp.Key.GetHashCode()); 
            } 
            this.transactionConnectionTable.Clear();
            this.dbResourceAllocator = null; 
            base.OnStopped();
        }
        #endregion Public Methods
 
        #region Public Methods
 
        protected internal override void CommitWorkBatch(WorkflowCommitWorkBatchService.CommitWorkBatchCallback commitWorkBatchCallback) 
        {
            // 
            // Disable retries by default, reset to allow retries below if we own the tx
            DbRetry dbRetry = new DbRetry(_enableRetries);
            short retryCounter = dbRetry.MaxRetries;
 
            while (true)
            { 
                // 
                // When using LocalTransaction handle block access to the connection
                // in the transaction event handlers until all IPendingWork members have completed 
                ManualResetEvent handle = new ManualResetEvent(false);
                Transaction tx = null;
                SharedConnectionInfo connectionInfo = null;
 
                try
                { 
                    if (null == Transaction.Current) 
                    {
                        // 
                        // It's OK to retry here as we own the tx
                        retryCounter = 0;
                        //
                        // Create a local, non promotable transaction that we share with our OOB services 
                        tx = new CommittableTransaction();
                        connectionInfo = new SharedConnectionInfo(this.dbResourceAllocator, tx, false, handle); 
                    } 
                    else
                    { 
                        //
                        // Can't retry as we don't own the tx
                        // Create a dependent transaction and don't restrict promotion.
                        tx = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete); 
                        connectionInfo = new SharedConnectionInfo(this.dbResourceAllocator, tx, true, handle);
                    } 
 
                    AddToConnectionInfoTable(tx, connectionInfo);
 
                    using (TransactionScope ts = new TransactionScope(tx))
                    {
                        try
                        { 
                            commitWorkBatchCallback();
                            ts.Complete(); 
                        } 
                        finally
                        { 
                            RemoveConnectionFromInfoTable(tx);
                            //
                            // Unblock transaction event handlers
                            handle.Set(); 
                        }
                    } 
 
                    CommittableTransaction committableTransaction = tx as CommittableTransaction;
                    if (committableTransaction != null) 
                        committableTransaction.Commit();

                    DependentTransaction dependentTransaction = tx as DependentTransaction;
                    if (dependentTransaction != null) 
                        dependentTransaction.Complete();
 
                    break; 
                }
                catch (Exception e) 
                {
                    tx.Rollback();

                    WorkflowTrace.Host.TraceEvent(TraceEventType.Error, 0, "SharedConnectionWorkflowCommitWorkBatchService caught exception from commitWorkBatchCallback: " + e.ToString()); 

                    if (dbRetry.TryDoRetry(ref retryCounter)) 
                    { 
                        WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "SharedConnectionWorkflowCommitWorkBatchService retrying commitWorkBatchCallback (retry attempt " + retryCounter.ToString(System.Globalization.CultureInfo.InvariantCulture) + ")");
                        continue; 
                    }
                    else
                        throw;
                } 
                finally
                { 
                    handle.Close(); 
                    if (tx != null)
                    { 
                        tx.Dispose();
                    }
                }
            } 
        }
        ///  
        /// Get the SharedConnectionInfo object from the hashtable keyed by the transaction 
        /// 
        ///  
        /// 
        internal SharedConnectionInfo GetConnectionInfo(Transaction transaction)
        {
            return LookupConnectionInfoTable(transaction); 
        }
 
        #endregion Public Methods 

        #region Private Methods 

        private void RemoveConnectionFromInfoTable(Transaction transaction)
        {
            lock (this.tableSyncObject) 
            {
                SharedConnectionInfo connectionInfo; 
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TransactionCompleted " + transaction.GetHashCode()); 
                if (transactionConnectionTable.TryGetValue(transaction, out connectionInfo))
                { 
                    connectionInfo.Dispose();
                    this.transactionConnectionTable.Remove(transaction);
                }
                else 
                {
                    WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "TransactionCompleted " + transaction.GetHashCode() + 
                        " not found in table of count " + this.transactionConnectionTable.Count); 
                }
            } 
        }

        private void AddToConnectionInfoTable(Transaction transaction, SharedConnectionInfo connectionInfo)
        { 
            lock (this.tableSyncObject)
            { 
                this.transactionConnectionTable.Add(transaction, connectionInfo); 
                WorkflowTrace.Host.TraceEvent(TraceEventType.Information, 0, "AddToConnectionInfoTable " + transaction.GetHashCode() +
                        " in table of count " + this.transactionConnectionTable.Count); 
            }
        }

        private SharedConnectionInfo LookupConnectionInfoTable(Transaction transaction) 
        {
            lock (this.tableSyncObject) 
            { 
                return transactionConnectionTable[transaction];
            } 
        }

        #endregion Private Methods
    } 
}

// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK