private void TryReceiveMessage()
        {
            // NOTE this method _should not_ throw an exception!
            ServiceBrokerMessage message     = null;
            SqlTransaction       transaction = null;

            try
            {
                transaction = SqlServerTransactionManager.BeginTransaction(ConnectionString);
                logger.Debug("RECEIVE FROM {0}", ServiceBrokerQueue);
                message = ServiceBrokerWrapper.WaitAndReceive(transaction, ServiceBrokerQueue, waitTimeout);
            }
            catch (Exception e)
            {
                logger.Error(e, "Exception caught trying to receive from queue {0}. Rolling back and backing off before reconnecting.", ServiceBrokerQueue);
                SqlServerTransactionManager.TryRollbackTransaction(transaction);
                SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction);
                Thread.Sleep(1000);          // back-off because we will return and loop immediately
                workerThreadPool.Release(1); // always release before returning!
                return;
            }

            // No message? That's okay
            if (message == null)
            {
                try
                {
                    SqlServerTransactionManager.CommitTransactionAndDisposeConnection(transaction);
                }
                catch (Exception)
                {
                    SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction);
                    throw;
                }
                workerThreadPool.Release(1); // always release before returning!
                return;
            }

            // start a
            Task.Run(() =>
            {
                // TryHandleHessage _should not_ throw an exception. It will also commit and cleanup the transactions
                try
                {
                    TryHandleMessage(transaction, message);
                }
                finally
                {
                    var previousCount = workerThreadPool.Release(1); // release this semaphore back to the pool regardless of what happened
                    logger.Debug("Current Concurrent Requests = {0}", MaxConcurrency - previousCount);
                }
            });
        }
 private void InitServiceBroker()
 {
     using (var connection = SqlServerTransactionManager.OpenConnection(ConnectionString))
         using (var transaction = connection.BeginTransaction())
         {
             // Ensure the service and queue exist
             ServiceBrokerWrapper.CreateServiceAndQueue(transaction, ServiceBrokerService, ServiceBrokerQueue, ServiceBrokerMessageType, ServiceBrokerContract);
             transaction.Commit();
             connection.Close();
         }
     PoisonMessageSqlHelper.EnsureTableExists(ConnectionString);
 }
        private void TryHandleMessage(SqlTransaction transaction, ServiceBrokerMessage message)
        {
            logger.Debug("Received message {0} from queue {1}", message.ConversationHandle, ServiceBrokerQueue);
            // NOTE this method _should not_ throw an exception!
            // It is responsible for committing or rolling back the SqlTransaction
            // that was passed in.
            // We can keep track of the openTransaction on the current thread in case we need it.
            SqlServerTransactionManager.SaveTransactionForCurrentTask(transaction);
            try
            {
                // this may throw an exception if we need to rollback
                TryHandleMessageInner(transaction, message);
                // End the conversation and commit
                ServiceBrokerWrapper.EndConversation(transaction, message.ConversationHandle);
                SqlServerTransactionManager.CommitTransactionAndDisposeConnection(transaction);
                faultManager.ClearFailuresForMessage(message.ConversationHandle.ToString());
                logger.Debug("Committed message {0} from queue {1}", message.ConversationHandle, ServiceBrokerQueue);
            }
            catch (Exception e)
            {
                SqlServerTransactionManager.TryRollbackTransaction(transaction);
                faultManager.IncrementFailuresForMessage(message.ConversationHandle.ToString(), e);
                logger.Error(e, "Exception caught handling message {0} from queue {1}. Rolling back transaction to retry.", message.ConversationHandle, ServiceBrokerQueue);
#if DEBUG
                if (System.Diagnostics.Debugger.IsAttached)
                {
                    // System.Diagnostics.Debugger.Break();
                }
#endif
            }
            finally
            {
                SqlServerTransactionManager.ClearTransactionForCurrentTask();
                SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction); // shoud not throw exception
            }
        }
        public static void EnsureTableExists(string connectionString)
        {
            using (var connection = SqlServerTransactionManager.OpenConnection(connectionString))
            {
                using (var transaction = connection.BeginTransaction())
                {
                    using (var cmd = connection.CreateCommand())
                    {
                        cmd.Transaction = transaction;
                        cmd.CommandText = @"
IF NOT EXISTS (SELECT * FROM sys.tables WHERE object_id = OBJECT_ID('dbo.PoisonMessage'))
CREATE TABLE [dbo].[PoisonMessage]
(
    PoisonMessageId bigint NOT NULL IDENTITY(1,1),
    InsertDateTimeUtc datetime2 NOT NULL,
    ConversationHandle uniqueidentifier NOT NULL,
    OriginServiceName nvarchar(255) NOT NULL,
    EnqueuedDateTimeUtc datetime2 NOT NULL,
    ServiceName nvarchar(255) NOT NULL,
    QueueName nvarchar(255) NOT NULL,
    MessageBody varbinary(max) NOT NULL,
    Retries tinyint NOT NULL,
    ErrorCode nvarchar(20) NOT NULL,
    ErrorMessage nvarchar(max) NOT NULL,
    CONSTRAINT [PK_PoisonMessage] PRIMARY KEY CLUSTERED 
    (
        [PoisonMessageId] ASC
    ),
);";
                        cmd.ExecuteNonQuery();
                    }
                    transaction.Commit();
                }
                connection.Close();
            }
        }
        public void Send(OutgoingTransportMessage transportMessage, IEnumerable <string> addresses)
        {
            var transaction = SqlServerTransactionManager.TryGetTransactionForCurrentTask();
            var commitAndDisposeTransaction = false;

            if (transaction == null)
            {
                transaction = SqlServerTransactionManager.BeginTransaction(ConnectionString);
                commitAndDisposeTransaction = true;
            }
            try
            {
                transportMessage.Headers[StandardHeaders.TimeSent] = DateTime.UtcNow.ToString("o");
                if (!transportMessage.Headers.ContainsKey(StandardHeaders.ReplyToAddress))
                {
                    transportMessage.Headers[StandardHeaders.ReplyToAddress] = this.ServiceBrokerSendingService;
                }
                transportMessage.Headers[StandardHeaders.OriginatingAddress]   = this.ServiceBrokerSendingService;
                transportMessage.Headers[StandardHeaders.ContentType]          = messageEncoder.ContentType;
                transportMessage.Headers[StandardHeaders.EnclosedMessageTypes] = string.Join(",", messageMapper.GetEnclosedMessageTypes(transportMessage.Message.GetType()).Distinct());

                using (var stream = new MemoryStream())
                {
                    var encodedMessage = messageEncoder.EncodeAsString(transportMessage.Message);
                    FastXmlTransportMessageSerializer.Serialize(transportMessage.Headers, encodedMessage, stream);
                    var messageBuffer = stream.ToArray();
                    foreach (var destination in addresses)
                    {
                        var conversationHandle = ServiceBrokerWrapper.SendOne(
                            transaction: transaction
                            , initiatorServiceName: ServiceBrokerSendingService
                            , targetServiceName: destination
                            , messageContractName: ServiceBrokerContract
                            , messageType: ServiceBrokerMessageType
                            , body: messageBuffer);
#if DEBUG
                        logger.Debug(string.Format("Sending message {0} with Handle {1} to Service Named {2}.",
                                                   transportMessage.Message.GetType().AssemblyQualifiedName,
                                                   conversationHandle,
                                                   destination));
                        logger.Debug(string.Format("ToString() of the message yields: {0}\n" +
                                                   "Message headers:\n{1}",
                                                   transportMessage.Message.ToString(),
                                                   string.Join(", ", transportMessage.Headers.Select(h => h.Key + ":" + h.Value).ToArray())));
#endif
                    }
                }

                if (commitAndDisposeTransaction)
                {
                    SqlServerTransactionManager.CommitTransactionAndDisposeConnection(transaction);
                }
            }
            catch (Exception)
            {
                if (commitAndDisposeTransaction)
                {
                    SqlServerTransactionManager.TryForceDisposeTransactionAndConnection(transaction);
                }
                throw;
            }
        }