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); } } }
internal byte[] Receive(TimeSpan timeout, BufferManager bm, out int messageLength, out SsbConversationContext conversation,WaitHandle cancelEvent) { ThrowIfDisposedOrNotOpen(); byte[] message = null; conversation = null; messageLength = 0; if (queuedResult != null) { ReceivedMessage r = queuedResult; queuedResult = null; conversation = r.Conversation; messageLength = r.MessageLength; byte[] buf = bm.TakeBuffer(messageLength); Buffer.BlockCopy(r.MessageBody, 0, buf, 0, messageLength); return buf; } try { lock (rdrlock) { //If this is the first time, open the reader, otherwise read the next row if ( rdr == null || !rdr.Read() ) { //the last bactch has been processed. Close the reader. if (rdr != null) { rdr.Close(); } rdr = GetMessageBatch(timeout,cancelEvent); //this is a timeout condition //caused by aborting or closing the reciever if ( rdr == null ) { return null; } //this is a timeout condition caused by the WAITFOR expiring if( !rdr.Read() ) { rdr.Close(); //return the Receiver to it's initial state. rdr = null; return null; } } int i = 0; int conversation_handle = i++; int service_name = i++; int message_type_name = i++; int message_body = i++; int message_sequence_number = i++; Guid conversationHandle = rdr.GetGuid(conversation_handle); string ServiceName = rdr.GetString(service_name); string messageTypeName = rdr.GetString(message_type_name); if (messageTypeName != SsbConstants.SsbEndDialogMessage && messageTypeName != SsbConstants.SsbDialogTimerMessage) { //this eliminates a one copy because the message_body //isn't copied into the row buffer. Instead it's chunked directly //into the message byte[]. // CONSIDER (dbrowne) wraping the reader in a custom stream implementation //and pass that back instead to eliminate another copy. messageLength = (int)rdr.GetBytes(message_body, 0, null, 0, 0); if (bm == null) { message = new byte[messageLength]; } else { message = bm.TakeBuffer(messageLength); } int br = (int)rdr.GetBytes(message_body, 0, message, 0, messageLength); if (br != messageLength) //should never happen { throw new Exception("Failed to read all the message bytes"); } } long sequence = rdr.GetInt64(message_sequence_number); conversation = new SsbConversationContext(conversationHandle, this.cgId, sequence, messageTypeName); if (messageTypeName == SsbConstants.SsbErrorMessage) { System.Xml.XmlDocument doc = new System.Xml.XmlDocument(); doc.Load(new System.IO.MemoryStream(message, 0, messageLength)); System.Xml.XmlNamespaceManager mgr = new System.Xml.XmlNamespaceManager(doc.NameTable); mgr.AddNamespace("er", SsbConstants.SsbErrorMessage); int code = int.Parse(doc.SelectSingleNode("/er:Error/er:Code", mgr).InnerText); string ermsg = doc.SelectSingleNode("/er:Error/er:Description", mgr).InnerText; throw new ProtocolException(string.Format("Service Broker Error Message {0}: {1}", code, ermsg)); } SsbInstrumentation.MessageRecieved(messageLength); return message; //if (messageTypeName == SsbConstants.SsbDialogTimerMessage) //{ // //well now we're running again after a lag, now what? //} } } catch (SqlException ex) { //the timeout will not result in a SqlExecption since the timeout value is passed to WAITFOR RECIEVE //if (!helper.IsTimeRemaining) //{ // throw new TimeoutException(String.Format("Timed out while receiving. Timeout value was {0} seconds", timeout.TotalSeconds), ex); //} throw new CommunicationException(String.Format("An exception occurred while receiving from conversation group {0}.", this.cgId), ex); } }