2

I know that establishing a RabbitMQ connection is expensive, so it is not recommended to {connect / publish / disconnect} whenever I want to put a message to queue. However, I couldn' t find a way to have a long running RabbitMQ connection across many requests.

What I want to achieve is to have only one(or a limited # of) RabbitMQ connection(s) in my ASP.NET application that runs on IIS and use it for different requests, instead of creating different connections for each request.

The following code is what I have up to now. I need somehow to remove these using statements and keep my connection open.

Thanks a lot

public ReturnCode AtomicPublish(string userName, string password, string virtualHost, string hostName, string exchangeName, string queueName, string message)
{
    using (IConnection conn = new ConnectionFactory()
    {
        UserName = userName,
        Password = password,
        VirtualHost = virtualHost,
        HostName = hostName
    }.CreateConnection())
    {
        using (IModel model = conn.CreateModel())
        {
            model.ExchangeDeclare(exchangeName, ExchangeType.Fanout, true);
            model.QueueDeclare(queueName, true, false, false, null);
            model.QueueBind(queueName, exchangeName, "", null);
            byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes(message);
            model.BasicPublish(exchangeName, string.Empty, null, messageBodyBytes);
        }
    }
    return ReturnCode.OK;
}
Fábio Nascimento
  • 2,644
  • 1
  • 21
  • 27
Alpay
  • 1,350
  • 2
  • 24
  • 56
  • Maybe, you should receive ConnectionFactory as dependency? In that case, you'll be able to instantiate it as Singleton and there will be no need to create it each time – Denys Prodan Jul 31 '18 at 15:22
  • @DenysProdan The problem here stem from the lifecycle of asp.net applications. Requests are handled in different threads so I should do something to ensure that my connection isn' t being disposed(even if it comes from a singleton) Like Davide Piras says, Application Cache looks like the best candidate to do this. Thank you – Alpay Aug 03 '18 at 06:29

3 Answers3

1

off the top of my head.

private static IConnection _connection {get;set;}
private static object LockObject = new object();
private static IConnection GetConnection (string username, string password, string virtualHost, string hostName)
    get{
        // do work here in case the connection is closed as well.
        if (_connection == null){
            lock(LockObject){
                if (_connection == null){
                    _connection = new ConnectionFactory
                       {
                           UserName = userName,
                           Password = password,
                           VirtualHost = virtualHost,
                           HostName = hostName

                       }.CreateConnection();
                }
            }

        }
        return _connection;
    }
}

public ReturnCode AtomicPublish(string userName, string password, string virtualHost, string hostName, string exchangeName, string queueName, string message)
{

        using (IModel model = GetConnection(userName, password, virtualHost, hostName).CreateModel()) //lazy loads the get connection
        {
            model.ExchangeDeclare(exchangeName, ExchangeType.Fanout, true);
            model.QueueDeclare(queueName, true, false, false, null);
            model.QueueBind(queueName, exchangeName, "", null);

            byte[] messageBodyBytes = System.Text.Encoding.UTF8.GetBytes(message);
            model.BasicPublish(exchangeName, string.Empty, null, messageBodyBytes);
        }

    return ReturnCode.OK;
}
Kenneth Garza
  • 1,886
  • 14
  • 12
1

you should use server side storage for your variable connection,

if connection is same for all requests of same user save it in the Session objerct of ASP.NET,

if it is same for all users save it in the Cache application object.

then when you need to load it again and re-use it, get it back from Session or Cache, see here an example: Application vs Session vs Cache

Davide Piras
  • 43,984
  • 10
  • 98
  • 147
-1

Like you said, establishing a RabbitMQ connection is expensive, so when you open a connection you shouldn't send a message and disconnect. In fact, RabbitMQ is based on the protocole AMQP which gives the possibility to send many messages to many receivers in different topics(instead of using queues), which means that every receiver is listening in a different topic like this exemple :

using System;
using System.Linq;
using RabbitMQ.Client;
using System.Text;
class EmitLogTopic
{
public static void Main(string[] args)
{
    var factory = new ConnectionFactory() { HostName = "localhost" };
    using(var connection = factory.CreateConnection())
    using(var channel = connection.CreateModel())
    {
        channel.ExchangeDeclare(exchange: "topic_logs",
                                type: "topic");

        var routingKey = (args.Length > 0) ? args[0] : "anonymous.info";
        var message = (args.Length > 1)
                      ? string.Join(" ", args.Skip( 1 ).ToArray())
                      : "Hello World!";
        var body = Encoding.UTF8.GetBytes(message);
        channel.BasicPublish(exchange: "topic_logs",
                             routingKey: routingKey,
                             basicProperties: null,
                             body: body);
        Console.WriteLine(" [x] Sent '{0}':'{1}'", routingKey, message);
    }
}
}

this link provides a tutorial for more informations.

Kais
  • 99
  • 12
  • Unfortunately, this is not an answer to my question. For a console app, maintaining a long running rabbitmq connection and using it whenever needed, is quite clear. The examples are also console applications in general. The problem is, I need to find a way to keep my connection open in my ASP.NET application. Its lifecycle is quite different than console applications. – Alpay Jul 31 '18 at 16:47