Reading ActiveMQ messages without deletion - c#

I am trying to read through ActiveMQ messages and according some filters to process some of them or leave the other messages in the queue.
I use NMS API with the following code:
Uri connecturi = new Uri("activemq:tcp://model.net:61616");
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
List<ModelBuilderBase> result = new List<ModelBuilderBase>();
using (IConnection connection = factory.CreateConnection())
using (ISession session = connection.CreateSession())
{
IDestination destination = SessionUtil.GetDestination(session, "queue://cidModelbuilderQ");
using (IMessageConsumer consumer = session.CreateConsumer(destination))
{
connection.Start();
ITextMessage message;
while ((message = consumer.ReceiveNoWait() as ITextMessage) != null)
{
if (message.Properties[MANDATOR] == null || message.Properties[REFCODE] == null)
continue;
var mandator = message.Properties[MANDATOR].ToString();
var refCode = message.Properties[REFCODE].ToString();
result.Add(ModelBuilderFactory.Instance.GetInstance(refCode, mandator));
}
}
Problem is that after a message is received the message is deleted. Can I somehow change this behavior and delete the messages only manually after a successful processing?
}

Although it was not easy to write a working code for that, thanks to the ARSs answer I have now this working solution:
Uri connecturi = new Uri("activemq:tcp://model.net:61616");
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
List<ModelBuilderBase> result = new List<ModelBuilderBase>();
using (IConnection connection = factory.CreateConnection())
using (ISession session = connection.CreateSession())
{
IDestination destination = SessionUtil.GetDestination(session, "queue://cidModelbuilderQ");
using (IMessageConsumer consumer = session.CreateConsumer(destination))
{
connection.Start();
var q = session.GetQueue("cidModelbuilderQ");
var b = session.CreateBrowser(q);
var msgs = b.GetEnumerator();
while (msgs.MoveNext())
{
ITextMessage message = msgs.Current as ITextMessage;
if (message.Properties[MANDATOR] == null || message.Properties[REFCODE] == null)
continue;
var mandator = message.Properties[MANDATOR].ToString();
var refCode = message.Properties[REFCODE].ToString();
result.Add(ModelBuilderFactory.Instance.GetInstance(refCode, mandator));
}
}
}

Creates a QueueBrowser object to peek at the messages on the specified queue. Perform you logic on the message and then creates a QueueReceiver object to receive messages from the specified queue.

Related

c# Rabbit MQ Unacked messages

I have an issue when trying to send ACK to remove messages from Rabbit queue.
Version of Rabbit MQ : 3.6.15. Version of RabbitClient 5.0.1
Here is my code:
var conn = Factory.CreateConnection();
var channel = conn.CreateModel();
//inside loop
var data = Get(conn, channel);
if (data == null)
return true;
if (data.MessageCount == 0)
return true;
var rabbitShortAd = JsonConvert.DeserializeObject<ShortAdRabbit>(Encoding.UTF8.GetString(Decompress(data.Body)));
//Process rabbitShortAd, save it in DB
//And if no error, send ack
SendAck(data, conn, channel);
return false;
//end loop
public static BasicGetResult Get(IConnection conn, IModel channel)
{
if (conn == null || !conn.IsOpen)
conn = Factory.CreateConnection();
if (channel == null || !channel.IsOpen)
channel = conn.CreateModel();
var queueName = "descriptions";
channel.QueueDeclare(queue: queueName, durable: true, exclusive: false, autoDelete: false);
return channel.BasicGet(queueName, false);
}
private static void SendAck(BasicGetResult data)
{
if (conn == null || !conn.IsOpen)
conn = Factory.CreateConnection();
if (channel == null || !channel.IsOpen)
channel = conn.CreateModel();
channel.BasicAck(data.DeliveryTag, false);
}
The first message processed is removed from the queue and then all others messages are stacking in the unacked column. My admin system just told me he updated the Rabbit MQ version to 3.6.15 and now I can't ACK my messages. Is there something wrong in the code ?
Found out the wait to make it work.
I have to instantiate the connection & the model inside the loop and then close each connection / model inside, too.
//inside the loop
var conn = Factory.CreateConnection();
var channel = conn.CreateModel();
try
{
var data = Get(conn, channel);
//Process
channel.BasicAck(data.DeliveryTag, false);
}
catch(Exception e)
{
//handle e
}
finally
{
conn?.Close();
channel?.Close();
}
//end of loop

WCF Websocket project fails upon Entity Framework data access attempt

I am new to WebSockets (this AM) and have set up a WCF WebSocket app that works when doing a trivial example I found online (http://www.codeproject.com/Articles/619343/Using-WebSocket-in-NET-Part).
I added Entity Framework and as soon as I add code to try to access data the process (just sending a message back and forth) no longer works.
Could there be some fundamental concept I could be missing?
Does anyone have any good ideas for troubleshooting?
namespace PBWebSocket
{
public class PBWebSocket : IBWebSocket
{
private SPEntities db = new SPEntities();
public async Task SendMessageToServer(Message msg)
{
var callback = OperationContext.Current.GetCallbackChannel<IPBCallback>();
if (msg.IsEmpty || ((IChannel)callback).State != CommunicationState.Opened)
{
return;
}
byte[] body = msg.GetBody<byte[]>();
string msgTextFromClient = Encoding.UTF8.GetString(body);
var reqId = Int32.Parse(msgTextFromClient);
// *** The below line breaks it ***
var req = db.Requests.Where(r => r.Id == 164).FirstOrDefault();
reqId = reqId + 2;
Message newMsg = ByteStreamMessage.CreateMessage(
new ArraySegment<byte>(Encoding.UTF8.GetBytes(reqId.ToString())));
newMsg.Properties["WebSocketMessageProperty"] =
new WebSocketMessageProperty
{ MessageType = WebSocketMessageType.Text };
await callback.SendMessageToClient(newMsg);
}
}
}

RabbitMq sending message twice to the same consumer

I have implemented a rabbitmq messaging in my application. A very weird behaviour then.
My publisher is a webservice, while my consumer is a console application. After recieving the message I ack it immediately and span a new thread to process which take like 2 seconds to finish.
But the same message is sent with the previous delivery tag incremented by one. I am using topic based routing.
What would I be doing wrong?
Subscriber:
//Create the connection factory
var connectionFactory = new ConnectionFactory()
{
HostName = host,
UserName = userName,
Password = password
};
connectionFactory.RequestedHeartbeat = 10;
connectionFactory.RequestedConnectionTimeout = 30000;
connectionFactory.AutomaticRecoveryEnabled = true;
connectionFactory.NetworkRecoveryInterval = TimeSpan.FromSeconds(10);
//connection
var connection = connectionFactory.CreateConnection();
logger.Info($"Connected to RabbitMQ {host}");
connection.ConnectionShutdown += Connection_ConnectionShutdown;
var model = connection.CreateModel();
model.BasicQos(0, 1, false);
var consumer = new QueueingBasicConsumer(model);
model.BasicConsume(queueName, false, consumer);
while (true)
{
try
{
var deliveryArgs = consumer.Queue.Dequeue();
model.BasicAck(deliveryArgs.DeliveryTag, false);
var jsonString = Encoding.Default.GetString(deliveryArgs.Body);
var itemtoprocess = jsonString.FromJson < recieved message > ();
if (deliveryArgs.Redelivered)
{
model.BasicReject(deliveryArgs.DeliveryTag, false);
}
else
{
var task = Task.Factory.StartNew(() => {
//Do work here on different thread then this one
//Call the churner to process the message
//Some long running method here to process item recieve
});
Task.WaitAll(task);
}
}
catch (EndOfStreamException ex)
{
//log
}
}
Setup:
public void Init(string exchangeName, string queueName, string routingKey = "")
{
using (IConnection connection = connectionFactory.CreateConnection())
{
using (IModel channel = connection.CreateModel())
{
channel.ExchangeDeclare(exchangeName, ExchangeType.Topic, true, false, null);
//Queue
var queue = channel.QueueDeclare(queueName, true, false, false, null);
channel.QueueBind(queue.QueueName, exchangeName, routingKey);
}
}
}

RabbitMq Implementation Practically

I am working on rabbitmq and I am confused with some points Like.
I have just implemented a sample from internet which creates a queue and then it fetch
the message from that queue thereby showing it on the webpage.
Now my problem is::
Suppose My server has RabbitmQ installed and multiple users are accessing this website where I
have implemented the rabbitmq.Now, first user sends a message but to whome it will send this message?
To all the users who will open the page because the code will be common for sent message and the name
of the queue will also be same.
Suppose, first user send one message="Hello" on the queue "Queue1"
now, one other user sends another message="Hello World" on the same queue
and one more user sends a message="Hello Worl World" on the same queue.
Now nth user clicks on receive message then which message will be shown to him?
first ,second or third one?
It means we will always have a single queue for my application?
Can somebody please guide me. I am pretty much confused...
Below I am pasting the code sample I will be using for my website
//For sending the messge
protected void btnSendMail_Click(object sender, EventArgs e)
{
try
{
var factory = new ConnectionFactory();
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
// ConnectionFactory factory = new ConnectionFactory() { HostName = "localhost" };
// // factory.UserName = txtUserEmail.Text.ToString();
//// factory.Password = "password";
// factory.VirtualHost = "/";
// factory.Protocol = Protocols.FromEnvironment();
// factory.HostName = "localhost";
// factory.Port = AmqpTcpEndpoint.UseDefaultPort;
// IConnection conn = factory.CreateConnection();
// using (var channel = conn.CreateModel())
// {
// channel.QueueDeclare("hello", false, false, false, null);
// string message = "Hello World!";
// var body = Encoding.UTF8.GetBytes(txtUserEmail.Text.ToString());
// channel.BasicPublish("", "hello", null, body);
// conn.Close();
// }
//Sending Message
channel.QueueDeclare("hello1", false, false, false, null);
string message = txtUserEmail.Text.ToString();
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish("", "hello1", null, body);
//Console.WriteLine(" [x] Sent {0}", message);
//Console.ReadLine();
Label1.Text = Encoding.Default.GetString(body);
}
}
}
catch
{
}
}
//For receiving the message.
protected void btnReceive_Click(object sender, EventArgs e)
{
try
{
//var factory = new ConnectionFactory() { HostName = "localhost" };
//using (var connection = factory.CreateConnection())
//{
// using (var channel = connection.CreateModel())
// {
// channel.QueueDeclare("hello", false, false, false, null);
// BasicGetResult result = channel.BasicGet("hello", false);
// var consumer = new QueueingBasicConsumer(channel);
// channel.BasicConsume("hello", true, consumer);
// Console.WriteLine(" [*] Waiting for messages." +
// "To exit press CTRL+C");
// while (true)
// {
// var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
// var body = ea.Body;
// var message = Encoding.UTF8.GetString(body);
// Console.WriteLine(" [x] Received {0}", message);
// Label1.Text = message.ToString();
// }
// }
//}
var factory = new ConnectionFactory();
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
bool noAck = false;
BasicGetResult result = channel.BasicGet("hello1", noAck);
if (result == null)
{
}
else
{
IBasicProperties props = result.BasicProperties;
byte[] Body = result.Body;
Label1.Text = Encoding.Default.GetString(Body);
}
}
}
}
catch
{
}
}
If you are creating a messaging system using RabbitMQ you should probably publish your messages to an exchange and then attach a queue to the exchange for each user of the site. Then have the exchange route the messages to the right user/users queue.
You need a better understanding of messaging patterns associated with the use of RabbitMQ
These tutorials would be most relevant
Publish/Subscribe
http://www.rabbitmq.com/tutorials/tutorial-three-python.html
Routing
http://www.rabbitmq.com/tutorials/tutorial-four-python.html
The tutorials are also available in c# if you need it.

ActiveMQ delete specific message

I use the following code to recieve messages without deletion. Now I need to add some filtering and delete some of the messages. My question is how to delete a specific message while other messages should stay in the queue?
Uri connecturi = new Uri("activemq:tcp://model.net:61616");
IConnectionFactory factory = new NMSConnectionFactory(connecturi);
List<ModelBuilderBase> result = new List<ModelBuilderBase>();
using (IConnection connection = factory.CreateConnection())
using (ISession session = connection.CreateSession())
{
IDestination destination = SessionUtil.GetDestination(session, "queue://cidModelbuilderQ");
using (IMessageConsumer consumer = session.CreateConsumer(destination))
{
connection.Start();
var q = session.GetQueue("cidModelbuilderQ");
var b = session.CreateBrowser(q);
var msgs = b.GetEnumerator();
while (msgs.MoveNext())
{
ITextMessage message = msgs.Current as ITextMessage;
if (message.Properties[MANDATOR] == null || message.Properties[REFCODE] == null)
continue;
var mandator = message.Properties[MANDATOR].ToString();
var refCode = message.Properties[REFCODE].ToString();
result.Add(ModelBuilderFactory.Instance.GetInstance(refCode, mandator));
}
}
}
Use selectors and get these messages.
When creating the consumer, create it by
IMessageConsumer consumer = session.CreateConsumer(destination,"REFCODE > 200")
or similar depending what you need to look for.
Then just call consumer.receive(timeout_val); until you pulled all selected messages of the queue.
Info about AMQ selectors

Categories