public object GetInstance(System.ServiceModel.InstanceContext instanceContext)
        {
            SsbConversationContext conversationContext = (SsbConversationContext)OperationContext.Current.IncomingMessageProperties[SsbConstants.SsbConversationMessageProperty];
            SqlConnection          con = OperationContext.Current.Channel.GetProperty <SsbConversationSender>().GetConnection();

            return(GetInstance(conversationContext, con));
        }
        public object GetInstance(System.ServiceModel.InstanceContext instanceContext, System.ServiceModel.Channels.Message message)
        {
            SsbConversationContext       conversationContext = (SsbConversationContext)OperationContext.Current.IncomingMessageProperties[SsbConstants.SsbConversationMessageProperty];
            SsbConversationGroupReceiver cgr = OperationContext.Current.Channel.GetProperty <SsbConversationGroupReceiver>();
            SqlConnection con = cgr.GetConnection();
            Guid          conversationGroupID = cgr.ConversationGroupId;
            TService      instance            = (TService)GetInstance(conversationContext, con);

            cgr.Closing += delegate(object sender, EventArgs e)
            {
                //SsbConversationGroupReceiver cgr = (SsbConversationGroupReceiver)sender;
                ReleaseInstance(conversationGroupID, instance, con);
            };
            return(instance);
        }
 /// <summary>
 /// Convenience method for configuraing a callback channel.  Since this is not a duplex channel it doesn't
 /// support the declarative callbacks in the normal WCF method.
 /// </summary>
 /// <typeparam name="TContract"></typeparam>
 /// <returns></returns>
 public TContract GetCallback<TContract>()
 {
     ThrowIfDisposedOrNotOpen();
     try
     {
         Binding binding = channelListener.CreateResponseBinding();
         TContract channel = ChannelFactory<TContract>.CreateChannel(binding,new EndpointAddress(SsbUri.Default));
         SsbConversationSender sender = ((IClientChannel)channel).GetProperty<SsbConversationSender>();
         sender.SetConnection(con);
         ((IClientChannel)channel).Open();
         SsbConversationContext conversation = OperationContext.Current.IncomingMessageProperties[SsbConstants.SsbConversationMessageProperty] as SsbConversationContext;
         sender.OpenConversation(conversation.ConversationHandle);
         return channel;
     }
     catch (Exception ex)
     {
         throw new CommunicationException("An error occurred while obtaining callback channel: " + ex.Message, ex);
     }
 }
      /// <summary>
      /// Ends the Service Broker conversation and sends a custom error message on the conversation.
      /// Issues this command to SQL SErver
        ///     END CONVERSATION @ConversationHandle WITH ERROR = @errorCode DESCRIPTION = @errorDescription
      /// </summary>
      /// <param name="errorCode">The error code passed to END CONVERSATION</param>
      /// 
      /// <param name="errorDescription">The Error description passed to END CONVERSATION</param>
      /// 
        public void EndConversationWithError(int errorCode, string errorDescription)
        {
            ThrowIfDisposedOrNotOpen();
            SsbConversationContext conversation = OperationContext.Current.IncomingMessageProperties[SsbConstants.SsbConversationMessageProperty] as SsbConversationContext;
            try
            {
                string SQL = "END CONVERSATION @ConversationHandle WITH ERROR = @error DESCRIPTION = @description";

                SqlCommand cmd = new SqlCommand(SQL, con);
                cmd.Parameters.Add("@ConversationHandle", SqlDbType.UniqueIdentifier).Value = conversation.ConversationHandle;
                cmd.Parameters.Add("@error", SqlDbType.Int).Value = errorCode;
                cmd.Parameters.Add("@description", SqlDbType.NVarChar, 3000).Value = errorDescription;

                cmd.ExecuteNonQuery();

            }
            catch (SqlException ex)
            {
               throw new CommunicationException(String.Format("An exception occurred while ending conversation {0}.", conversation.ConversationHandle), ex);
            }
        }
 protected abstract TService GetInstance(SsbConversationContext conversationContext, SqlConnection con);
        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);
            }
        }
 internal byte[] Receive(TimeSpan timeout, BufferManager bm, out int messageLength, out SsbConversationContext conversation)
 {
     return Receive(timeout, bm, out messageLength, out conversation, cancelEvent);
 }
 public void EndConversation()
 {
     SsbConversationContext conversation = OperationContext.Current.IncomingMessageProperties[SsbConstants.SsbConversationMessageProperty] as SsbConversationContext;
     this.EndConversation(conversation.ConversationHandle, this.DefaultCloseTimeout);
 }