Exemplo n.º 1
0
 internal static string CheckConversationForErrorMessage(string connstr, Guid conversationHandle)
 {
     using (SqlConnection con = SsbHelper.GetConnection(connstr))
     {
         con.Open();
         return(CheckConversationForErrorMessage(con, conversationHandle));
     }
 }
Exemplo n.º 2
0
 internal static ServiceInfo GetServiceInfo(string serviceName, TimeSpan timeout, string connstr)
 {
     using (SqlConnection con = SsbHelper.GetConnection(connstr))
     {
         con.Open();
         return(GetServiceInfo(serviceName, timeout, con));
     }
 }
Exemplo n.º 3
0
 public static int EndAllConversationsWithCleanup(string connstr)
 {
     using (SqlConnection con = SsbHelper.GetConnection(connstr))
     {
         con.Open();
         return(EndAllConversationsWithCleanup(con));
     }
 }
Exemplo n.º 4
0
 public static void EndConversationWithCleanup(string connstr, Guid conversationHandle)
 {
     using (SqlConnection con = SsbHelper.GetConnection(connstr))
     {
         con.Open();
         EndConversationWithCleanup(con, conversationHandle);
     }
 }
Exemplo n.º 5
0
 internal static void SetConversationTimer(Guid conversationHandle, TimeSpan timerTimeout, string connstr)
 {
     using (SqlConnection con = SsbHelper.GetConnection(connstr))
     {
         con.Open();
         SetConversationTimer(conversationHandle, timerTimeout, con);
     }
 }
Exemplo n.º 6
0
 internal static ConversationInfo GetConversationInfo(Guid conversationHandle, string constr)
 {
     using (SqlConnection con = SsbHelper.GetConnection(constr))
     {
         con.Open();
         return(GetConversationInfo(conversationHandle, con));
     }
 }
        internal void Send(byte[] buffer, TimeSpan timeout, string messageType)
        {
            ThrowIfDisposedOrNotOpen();
            TimeoutHelper helper = new TimeoutHelper(timeout);


            //if the client hasn't explicitly begun a conversation, start one here.
            // CONSIDER (dbrowne) automatically ending the conversation in this case.
            if (conversation == null)
            {
                BeginNewConversation();
                this.endConversationOnClose = true;
            }

            try
            {
                string     SQL = string.Format(@"SEND ON CONVERSATION @Conversation MESSAGE TYPE [{0}](@MessageBody)", SsbHelper.ValidateIdentifier(messageType));
                SqlCommand cmd = new SqlCommand(SQL, con);

                cmd.CommandTimeout = helper.RemainingTimeInMillisecondsOrZero();
                SqlParameter pConversation = cmd.Parameters.Add("@Conversation", SqlDbType.UniqueIdentifier);
                pConversation.Value = this.conversation.ConversationHandle;

                SqlParameter pMessageBody = cmd.Parameters.Add("@MessageBody", SqlDbType.VarBinary);
                pMessageBody.Value = buffer;

                try
                {
                    cmd.ExecuteNonQuery();
                }
                catch (SqlException ex)
                {
                    if (ex.Number == 8429)
                    {
                        string errorMessage = SsbHelper.CheckConversationForErrorMessage(con, this.conversation.ConversationHandle);
                        if (errorMessage != null)
                        {
                            throw new Exception(errorMessage);
                        }
                        throw;
                    }
                    throw;
                }
                SsbInstrumentation.MessageSent(buffer.Length);
            }
            catch (Exception e)
            {
                if (!helper.IsTimeRemaining)
                {
                    throw new TimeoutException("Timed out while sending a message. The timeout value passed in was " + timeout.TotalSeconds + " seconds");
                }
                else
                {
                    throw new CommunicationException(String.Format("An exception occurred while sending on conversation {0}.", this.conversation.ConversationHandle), e);
                }
            }
        }
        protected override void OnOpen(TimeSpan timeout)
        {
            TimeoutHelper helper = new TimeoutHelper(timeout);


            if (this.con == null)
            {
                this.con = SsbHelper.GetConnection(this.connectionString);
                con.Open();
                this.ownsConnection = true;
            }
        }
        public Guid BeginNewConversation(Guid conversationGroupId, TimeSpan timeout)
        {
            ThrowIfDisposedOrNotOpen();
            endConversationOnClose = false; //if a conversation is explicitly started, don't automatically close it.
            TimeoutHelper helper = new TimeoutHelper(timeout);

            try
            {
                string SQL = string.Format(
                    @"BEGIN DIALOG CONVERSATION @ConversationHandle 
                               FROM SERVICE @Source TO SERVICE @Target 
                               ON CONTRACT [{0}] WITH ENCRYPTION = {1}", contract, useEncryption?"ON":"OFF");
                if (conversationGroupId != Guid.Empty)
                {
                    SQL += String.Format(", RELATED_CONVERSATION_GROUP = '{0}'", conversationGroupId);
                }
                SqlCommand cmd = new SqlCommand(SQL, con);
                cmd.CommandTimeout = helper.RemainingTimeInMillisecondsOrZero();
                SqlParameter pconversationHandle = cmd.Parameters.Add("@ConversationHandle", SqlDbType.UniqueIdentifier);
                pconversationHandle.Direction = ParameterDirection.Output;

                SqlParameter pTarget = cmd.Parameters.Add("@Target", SqlDbType.VarChar);
                pTarget.Value = this.target;
                SqlParameter pSource = cmd.Parameters.Add("@Source", SqlDbType.VarChar);
                pSource.Value = this.source;

                cmd.ExecuteNonQuery();

                this.conversation = SsbHelper.GetConversationInfo((Guid)pconversationHandle.Value, con);
                return(this.conversation.ConversationHandle);
            }
            catch (SqlException ex)
            {
                if (!helper.IsTimeRemaining)
                {
                    throw new TimeoutException(String.Format("Timed out while beginning new conversation to service {0}. Timeout value was {1} seconds", this.target, timeout.TotalSeconds), ex);
                }
                else
                {
                    throw new CommunicationException(String.Format("An exception occurred while beginning new conversation to service {0}", this.target), ex);
                }
            }
            finally
            {
            }
        }
Exemplo n.º 10
0
        internal SsbConversationGroupReceiver AcceptConversationGroup(TimeSpan timeout)
        {
            TimeoutHelper helper = new TimeoutHelper(timeout);

            try
            {
                //create a transaction to own the conversation.  Open the SqlConnection while
                //the transaction is current, so all the work on the connection will be enlisted
                //in the transaction.  SqlTransaction doesn't work this way.  It requires every command
                //to be manually enlisted, yuck.
                //As an alternative you could simply issue a new SqlCommand("begin transaction",cn).ExecuteNonQuery()
                //to start a transaction.
                // TODO (dbrowne) Consider whether to allow service-level code to commit this transaction, or, alternatively,
                //commit the transaction after the last conversation message in this session is processed.
                //If service-level code is allowed to commit the transaction then SsbConversationGroupReciver _must_
                //retrieve only a single message in each batch.  Else it could fetch 2 messages and risk the service-level
                //commiting after the first message.


                CommittableTransaction tx           = new CommittableTransaction(TimeSpan.MaxValue);
                Transaction            currentTrans = Transaction.Current;
                Transaction.Current = tx;
                SqlConnection cn = SsbHelper.GetConnection(this.connstring);
                cn.Open();
                Transaction.Current = currentTrans;

                tx.TransactionCompleted += new TransactionCompletedEventHandler(tx_TransactionCompleted);

                //wait for a new message, but if that message is in a conversation group that another SsbChannelListener is waiting on
                //then roll back the conversation group lock and get back in line.  The waiting SsbChannelListener should pick it up.
                string sql = String.Format(@"
                    retry:
                    save transaction swiper_no_swiping
                    declare @cg uniqueidentifier
                    declare @rc int

                    waitfor (get conversation group @cg from [{0}]), TIMEOUT @timeout
                    if @cg is null
                    begin
                      return --timeout
                    end 

                    exec @rc = sp_getapplock @Resource=@cg, @LockMode='Exclusive', @LockTimeout = 0
                    if @rc = -1
                    begin
                     print 'skipping message for locked conversation_group'
                     rollback transaction swiper_no_swiping
                     goto retry
                    end
                    
                    set @conversation_group_id = @cg
                    ", this.serviceInfo.QueueName);

                SqlCommand cmd = new SqlCommand(sql, cn);
                cmd.CommandTimeout = 0;

                cn.InfoMessage += new SqlInfoMessageEventHandler(cn_InfoMessage);
                SqlParameter pTimeout = cmd.Parameters.Add("@timeout", SqlDbType.Int);
                pTimeout.Value = TimeoutHelper.ToMilliseconds(timeout);

                SqlParameter pConversationGroupId = cmd.Parameters.Add("@conversation_group_id", SqlDbType.UniqueIdentifier);
                pConversationGroupId.Direction = ParameterDirection.Output;


                //Run the command, but abort if the another thread runs Close or Abort
                IAsyncResult result = cmd.BeginExecuteNonQuery();
                int          rc     = WaitHandle.WaitAny(new WaitHandle[] { result.AsyncWaitHandle, cancelEvent });
                if (rc == 1) //cancel event
                {
                    cmd.Cancel();
                    TraceHelper.TraceEvent(System.Diagnostics.TraceEventType.Verbose, "Canceling Service Broker wait on SsbChannelListener shutdown", "AcceptConversationGroup");
                    cn.Close();
                    return(null);
                }
                if (rc != 0)
                {
                    throw new InvalidOperationException("Unexpected state");
                }
                cmd.EndExecuteNonQuery(result);

                if (pConversationGroupId.Value == null || pConversationGroupId.Value.GetType() != typeof(Guid))
                {
                    throw new TimeoutException(String.Format("Timed out while waiting for Conversation Group"));
                }

                Guid conversationGroupId = (Guid)pConversationGroupId.Value;

                TraceHelper.TraceEvent(System.Diagnostics.TraceEventType.Verbose, string.Format("Accepted conversation group {0}", conversationGroupId), "AcceptConversationGroup");
                SsbConversationGroupReceiver cg = new SsbConversationGroupReceiver(cn, tx, conversationGroupId, this.serviceInfo, this);
                return(cg);
            }
            catch (SqlException ex)
            {
                if (!helper.IsTimeRemaining)
                {
                    throw new TimeoutException(String.Format("Timed out while waiting for Conversation Group. Timeout value was {0} seconds", timeout.TotalSeconds), ex);
                }
                else
                {
                    throw new ProtocolException("An error occurred while waiting for a Conversation Group", ex);
                }
            }
        }
Exemplo n.º 11
0
        internal SsbConversationGroupReceiver AcceptConversationGroup(Guid conversationGroupId, TimeSpan timeout)
        {
            TimeoutHelper helper = new TimeoutHelper(timeout);

            TransactionOptions to = new TransactionOptions();

            to.IsolationLevel = System.Transactions.IsolationLevel.ReadCommitted;
            to.Timeout        = TimeSpan.MaxValue;


            CommittableTransaction tx           = new CommittableTransaction(to);
            Transaction            currentTrans = Transaction.Current;

            Transaction.Current = tx;
            SqlConnection cn = SsbHelper.GetConnection(this.connstring);

            cn.Open();
            Transaction.Current = currentTrans;

            //first lock the the Conversation Group.  This will prevent other SsbConversationGroupReceivers
            //from poaching the messages.

            string sql = @"
                    declare @cg uniqueidentifier
                    declare @rc int
                    set @cg = @conversation_group_id

                    exec @rc = sp_getapplock @Resource=@cg, @LockMode='Exclusive'
                    if @rc not in (0,1)
                    begin
                     raiserror('Failed to lock conversation group. sp_getapplock failure code %d.',16,1,@rc);
                    end
                    ";

            SqlCommand   cmd = new SqlCommand(sql, cn);
            SqlParameter pConversationGroupId = cmd.Parameters.Add("@conversation_group_id", SqlDbType.UniqueIdentifier);

            pConversationGroupId.Value = conversationGroupId;

            cmd.CommandTimeout = helper.RemainingTimeInMillisecondsOrZero();

            //Run the command, but abort if the another thread runs Close or Abort
            IAsyncResult result = cmd.BeginExecuteNonQuery();
            int          rc     = WaitHandle.WaitAny(new WaitHandle[] { result.AsyncWaitHandle, cancelEvent });

            if (rc == 1) //cancel event
            {
                cmd.Cancel();
                TraceHelper.TraceEvent(System.Diagnostics.TraceEventType.Verbose, "Canceling Service Broker wait on SsbChannelListener shutdown", "AcceptConversationGroup");
                cn.Close();
                return(null);
            }
            if (rc != 0)
            {
                throw new InvalidOperationException("Unexpected state");
            }
            cmd.EndExecuteNonQuery(result);

            SsbConversationGroupReceiver cg = new SsbConversationGroupReceiver(cn, tx, conversationGroupId, this.serviceInfo, this);

            cg.Open();
            //now wait for a message on the conversation.  Do it here because WCF expects the wait to be here instead of in a subsequent receive.
            //And also there is a different timeout to accepting a channel and waiting for additional messages.
            //But we need to pass in the cancelEvent to abort the listen, if this ChannelListener is closed or aborted
            if (!cg.WaitForFirstMessage(helper.RemainingTime(), cancelEvent))
            {
                if (this.State != CommunicationState.Opened)//this ChannelListener was closed or aborted, so this is expected.
                {
                    //for some reason the transaction tx is in an uncommitable state here. Not sure why.
                    //however no other work has occured on this connection, so we can just shut it down.
                    cn.Close();
                    return(null);
                }
                throw new TimeoutException(String.Format("Timed out while waiting for Conversation Group"));
            }

            return(cg);
        }
Exemplo n.º 12
0
 protected override void OnOpen(TimeSpan timeout)
 {
     this.serviceInfo = SsbHelper.GetServiceInfo(this.listenUri.Service, timeout, this.connstring);
 }
 public void SetConversationTimer(Guid conversationHandle, TimeSpan timerTimeout)
 {
     SsbHelper.SetConversationTimer(conversationHandle, timerTimeout, this.con);
 }
 public void OpenConversation(Guid conversationHandle, TimeSpan timeout)
 {
     ThrowIfDisposedOrNotOpen();
     this.conversation = SsbHelper.GetConversationInfo(conversationHandle, con);
 }