consumer.Received event not firing when channel.BasicConsume is called (C# windows service)

6,889 views
Skip to first unread message

Steve Reddy

unread,
Nov 17, 2015, 2:58:13 PM11/17/15
to rabbitmq-users
Hey guys. I'm brand new to RabbitMQ and having trouble with the last part of the "Hello World" tutorial in C#
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html

I am creating a windows service that is responsible for grabbing messages from a queue, deserializing them, and passing them on to a class that handles logging them. 
It does successfully pull the messages and drain the queue, but the Received event is not firing, so I am unable to do any work with the received message.
I know that it's getting the messages because the Web UI tool shows the queue being drained if the service is running. 

This is my code... you'll notice it's almost identical to the tutorial example except for where I deserialize the message to my "Transaction" type and pass it to a Repository class. 
I added some simple debug lines to write some text to a file to verify that the code in that event handler isn't being called. I have lines just like that in OnStart() and OnStop(), and those are both successfully writing to the txt file, but my "This proves that the Received event is firing" text is not being written. 

Please help. What am I doing wrong? Code is below:


        private void ReadMessagesFromQueue() 
        {
            var factory = new ConnectionFactory() { HostName = "localhost" };
            using (var connection = factory.CreateConnection())
            {
                using (var channel = connection.CreateModel())
                {
                    //this will create the queue if it doesn't exist already
                    channel.QueueDeclare(queue: "transactions",
                                         durable: false,
                                         exclusive: false,
                                         autoDelete: false,
                                         arguments: null);

                    var consumer = new EventingBasicConsumer(channel);
                    consumer.Received += (model, ea) =>
                    {
                        var body = ea.Body;
                        var message = Encoding.UTF8.GetString(body);
                        //DEBUG CODE write message to a text file just to see if this code is being fired
                        File.WriteAllText(@"C:\Temp\STOR-1516\serviceTest.txt", "This proves that the Received event is firing.");
                        //END DEBUG CODE
                        Transaction transaction = JsonConvert.DeserializeObject<Transaction>(message);
                            transactionRepository.LogTransaction(transaction);
                    };
 
                    channel.BasicConsume(queue: "transactions",
                                         noAck: true,
                                         consumer: consumer);
                }
            }
        }

Michael Klishin

unread,
Nov 17, 2015, 3:56:40 PM11/17/15
to rabbitm...@googlegroups.com, Steve Reddy
On 17 November 2015 at 22:58:17, Steve Reddy (sred...@gmail.com) wrote:
> What am I doing wrong?

Your code looks OK at first glance. Are you sure there are no unhandled exceptions
in your event handler, and you don’t run into channel-level exceptions (which cause channel
to be closed and thus never get any more deliveries)?

Those would be things to investigate, including by inspecting server log files. 
--
MK

Staff Software Engineer, Pivotal/RabbitMQ


Steve Reddy

unread,
Nov 17, 2015, 4:24:48 PM11/17/15
to rabbitmq-users, sred...@gmail.com
No way to know if exceptions are throwing in the event handler, because it isn't being called. I attached to the windows service and set a breakpoint on the first line (var body = ea.Body;) , and it never gets hit. 

As for channel level exceptions? I don't think so. I've loaded up my queue with 20-30 messages, and the channel stays open while all of them are drained. If there were an exception shutting the channel down, wouldn't it eventually stop draining messages from the queue? 

I do see some errors in my Event Viewer... looks like I have some codes to look up. 

124942091173
5
WUDFUnhandledException
Not available
0
UnhandledException
Host
ffffffffc0000005
7ffe76aecab6
WpdMtpDr.dll
6.3.9600.16384 (winblue_rtm.130821-1623)
(none)
(none)
6.3.9600.17415. (winblue_r4.141028-1500)
(DumpedSeparately)
C:\Windows\System32\LogFiles\WUDF\WudfHost_ext__3316.dmp C:\Windows\System32\LogFiles\WUDF\d8edffe5-0e24-4376-9751-82ab7790e816.txt
C:\ProgramData\Microsoft\Windows\WER\ReportQueue\NonCritical_UnhandledExcepti_15ffc6ac3c6bd32c83acff3c7a45e26eb93c1_00000000_cab_a7f05dae
0
4cae847f-71ca-11e5-8261-00249b0bbffe
8
c2484599d19483b8be2e9e43ca60dd7e

Steve Reddy

unread,
Nov 17, 2015, 4:27:48 PM11/17/15
to rabbitmq-users, sred...@gmail.com
Nevermind. That error doesn't seem to be related. I just put 5 messages on my queue, started the service, and it consumed them all successfully... But never caused the consumer.Received event to fire. 

Michael Klishin

unread,
Nov 17, 2015, 4:35:09 PM11/17/15
to rabbitm...@googlegroups.com, Steve Reddy
On 18 November 2015 at 00:27:50, Steve Reddy (sred...@gmail.com) wrote:
> But never caused the consumer.Received event to fire.

EventingBasicConsumer#HandleBasicDelivery does something really  :
https://github.com/rabbitmq/rabbitmq-dotnet-client/blob/master/projects/client/RabbitMQ.Client/src/client/events/EventingBasicConsumer.cs#L90

I suggest using a debugger.

Steve Reddy

unread,
Nov 17, 2015, 4:39:18 PM11/17/15
to rabbitmq-users, sred...@gmail.com
Yeah, I guess I'm at that point. I was using the RabbitMQ nuget package. Hoped I could avoid pulling the source code from git. Oh well... 

Steve Reddy

unread,
Nov 18, 2015, 10:05:02 AM11/18/15
to rabbitmq-users, sred...@gmail.com
I've downloaded the source and am now able to step into RabbitMQ.Client code. 
I set a breakpoint on the line "if (Received != null)" in the EventingBasicConsumer.HandleBasicDeliver method. Then I posted three messages to the queue. Next, my service (which checks the queue every ten seconds) found and pulled all three messages. My breakpoint was not hit. 

I'll be working backwards from this breakpoint to figure out the path the code should be taking and try to figure out where it might be taking a wrong turn. In the meantime, if you have any other troubleshooting suggestions or notice any potential problems with my receiving code (which is word for word exactly like the tutorial), I'd really appreciate it!

Thanks,
Steve

Michael Klishin

unread,
Nov 18, 2015, 10:20:04 AM11/18/15
to rabbitm...@googlegroups.com, sred...@gmail.com
Can there be more consumers on the same queue somewhere?
--
You received this message because you are subscribed to the Google Groups "rabbitmq-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rabbitmq-user...@googlegroups.com.
To post to this group, send email to rabbitm...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Steve Reddy

unread,
Nov 18, 2015, 10:30:12 AM11/18/15
to rabbitmq-users, sred...@gmail.com
No, I just built this. It's very simple and all on localhost. Just one queue, and one service. The only other entity connecting to the queue is a separate app that is writing the messages to the queue. I hit an api with an xml payload, it gets turned into a C# object, serialized into json, and then written to the queue, then later one my consumer service picks the message up. 

I *am* hitting a breakpoint in ConcurrentConsumerDispatcher...at the HandleBasicDeliver method shown below. The consumer passed into this method and used in the event handler body is indeed an EventingBasicConsumer, and while I hit the "UnlessShuttingDown" line where we are subscribing to the event, I never actually hit my breakpoint inside the body of that event handler. So the consumer.HandlerBasicDeliver() doesn't seem to get called. 

UnlessShuttingDown(() => //this line gets hit every time a message is pulled from the queue
            {
                try
                {
                    consumer.HandleBasicDeliver(consumerTag,   //this line never gets hit
                                                deliveryTag,
                                                redelivered,
                                                exchange,
                                                routingKey,
                                                basicProperties,
                                                body);
                }
                catch (Exception e)
                {
                    var details = new Dictionary<string, object>()
                    {
                        {"consumer", consumer},
                        {"context",  "HandleBasicDeliver"}
                    };
                    model.OnCallbackException(CallbackExceptionEventArgs.Build(e, details));
                }
            });
Message has been deleted

Steve Reddy

unread,
Nov 18, 2015, 11:24:31 AM11/18/15
to rabbitmq-users, sred...@gmail.com
I'm dumb, sorry. Misread that function pointer as an event handler. It is being passed into ConsumerWorkSevice.AddWork as intended. Still though, I can't debug the body of that function. Maybe that's just my lack of experience. Problem is still the same... I need to debug the call to EventingBasicConsumer.HandleBasicDeliver() and I cannot. 

That fn that contained the call to HandleBasicDeliver is being sent to ConsumerWorkService.AddWork, as intended. However, I can't follow it much further than that, and I don't see where that delegate ever gets run. Because my breakpoint in the delegate body (where the EventingBasicConsumer is called) is never hit, I'm inclined to think this delegate is never actually being called... therein lies the bug... 

Leonard Chen

unread,
Jan 25, 2016, 7:53:42 PM1/25/16
to rabbitmq-users
Hi, I know I'm super late to the party, but I was experiencing the exact same issue as you did, but after some poking around I think I found the solution and was wondering if you are still interested.

I'm still rather new to C# but I believe the problem here is the use of the keyword "using". I understand the code looks very similar to the ones in the tutorial, and in the tutorial examples the Receiving code usually ends like this.

channel.BasicConsume(queue: "queue_name",
                                         noAck: true,
                                         consumer: consumer);

Console.ReadLine();

This makes it so the code never really exists and the channel never executed its "Dispose", which means the Receiving event is still active at the time. My code looks very similar, and my solution was to manage the connections on my own, changing these lines:

 using (var connection = factory.CreateConnection())

to 

var connection = factory.CreateConnection();

====================================================
using (var channel = connection.CreateModel())

to 

channel = connection.CreateModel()


By doing this, the objects are never disposed due to the keyword "using". I built some sort of manager to properly manage the connections and channels each time they are established as workaround.

Michael Klishin

unread,
Jan 26, 2016, 4:34:02 AM1/26/16
to rabbitm...@googlegroups.com, Leonard Chen
On 26 January 2016 at 03:53:46, Leonard Chen (leo...@gmail.com) wrote:
> Hi, I know I'm super late to the party, but I was experiencing
> the exact same issue as you did, but after some poking around I
> think I found the solution and was wondering if you are still interested.

Leonard,

Thank you for the update. 

Erkan Aslanel

unread,
May 16, 2017, 9:59:02 AM5/16/17
to rabbitmq-users

There is same issue on my project.I able to fix.Problem is Newtonsoft.Json version conflict.I have change oldVersion value then Received function fires.

  <runtime>

    <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">

      <dependentAssembly>

        <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />

        <bindingRedirect oldVersion="0.0.0.0-20.0.0.0" newVersion="7.0.0.0" />

      </dependentAssembly>

    </assemblyBinding>

  </runtime>

old row  :  <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />

Duncan Wanjohi

unread,
Oct 7, 2017, 3:33:14 PM10/7/17
to rabbitmq-users
@Leonard, you are right on time. 2017 and this observation sorted me out. Thanks.

teoman shipahi

unread,
Mar 13, 2018, 3:15:01 PM3/13/18
to rabbitmq-users
This works amazing! Thanks.

Michael Klishin

unread,
Mar 13, 2018, 9:14:08 PM3/13/18
to rabbitm...@googlegroups.com
It's worth pointing out that C# tutorials use the "using" statement because they are, well,
tutorials. Short lived connections make sense for them and I'm inclined to think that a long lived one
would be more problematic because it'd require an explicit interruption from the user, and it may or may not
be expected. Most C# users know what the "using" statement does.

Feel free to submit a PR for the tutorials that adds a comment (say, in tutorials 1 and 2) that clarifies that
production systems are meant to use long-lived connections and mostly long-lived channels:
https://github.com/rabbitmq/rabbitmq-website/tree/live/site/tutorials

--
You received this message because you are subscribed to the Google Groups "rabbitmq-users" group.
To unsubscribe from this group and stop receiving emails from it, send an email to rabbitmq-users+unsubscribe@googlegroups.com.
To post to this group, send email to rabbitmq-users@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

teoman shipahi

unread,
Mar 14, 2018, 2:29:06 PM3/14/18
to rabbitmq-users
Hi Michael,

For .NET applications, there is a common usage scenario, where publisher as a web application, and subscriber as a Windows Service.
Windows Service should be straightforward, where it should only create channel once, and use it until service ends.

I believe similar scenario would apply for Web. I think we do not want to open/close RabbitMQ connection on every single request, and just create channel once at start-up
and keep it persistent (as a Singleton) on application lifecycle. Would it be applied just like same HttpClient usage? Maybe it documentation it is worth to mention about different usage scenarios. 
If it is already there, sorry I missed it then. I will be happy to send PR also for different usage cases.

So would injecting RabbitMQ channel once at start-up as Singleton and using it during app lifecycle makes sense? 


HttpClient is intended to be instantiated once and re-used throughout the life of an application. Instantiating an HttpClient class for every request will exhaust the number of sockets available under heavy loads. This will result in SocketException errors. Below is an example using HttpClient correctly.
To unsubscribe from this group and stop receiving emails from it, send an email to rabbitmq-user...@googlegroups.com.
To post to this group, send email to rabbitm...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

Michael Klishin

unread,
Mar 14, 2018, 9:18:33 PM3/14/18
to rabbitm...@googlegroups.com
It makes sense as long as you can handle connection failures and channel exceptions [as in the protocol, not C# code].

See http://www.rabbitmq.com/dotnet-api-guide.html#connection-recovery and try publishing to a non-existent exchange, for example.
Besides that, yes, what you have in mind is how all the messaging protocols we support are meant to be used.

To unsubscribe from this group and stop receiving emails from it, send an email to rabbitmq-users+unsubscribe@googlegroups.com.
To post to this group, send email to rabbitmq-users@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.
Reply all
Reply to author
Forward
0 new messages