Reputation: 115857
My understanding is that IModel
instances are reasonably cheap to create and that's what I started with. I was creating a separate IModel
for each class that was ever using it: each Application Service class gets its own IModel
, as does every Controller
. It was working fine, but having 30+ channels open was a bit worrisome.
I thought about serializing access to a shared IModel
:
lock(publisherLock)
publisherModel.BasicPublish(...);
but now there's a point of contention for no good reason.
So, what will be the correct way of publishing messages into a RabbitMQ exchange from an ASP.NET MVC application?
Upvotes: 1
Views: 3071
Reputation: 47794
Here is something which you can use,
BrokerHelper.Publish("Aplan chaplam, chaliye aai mein :P");
and below is the defination for the BrokerHelper class.
public static class BrokerHelper
{
public static string Username = "guest";
public static string Password = "guest";
public static string VirtualHost = "/";
// "localhost" if rabbitMq is installed on the same server,
// else enter the ip address of the server where it is installed.
public static string HostName = "localhost";
public static string ExchangeName = "test-exchange";
public static string ExchangeTypeVal = ExchangeType.Direct;
public static string QueueName = "SomeQueue";
public static bool QueueExclusive = false;
public static bool QueueDurable = false;
public static bool QueueDelete = false;
public static string RoutingKey = "yasser";
public static IConnection Connection;
public static IModel Channel;
public static void Connect()
{
var factory = new ConnectionFactory();
factory.UserName = Username;
factory.Password = Password;
factory.VirtualHost = VirtualHost;
factory.Protocol = Protocols.FromEnvironment();
factory.HostName = HostName;
factory.Port = AmqpTcpEndpoint.UseDefaultPort;
Connection = factory.CreateConnection();
Channel = Connection.CreateModel();
}
public static void Disconnect()
{
Connection.Close(200, "Goodbye");
}
public static bool IsBrokerDisconnected()
{
if(Connection == null) return true;
if(Connection.IsOpen) return false;
return true;
}
public static void Publish(string message)
{
if (IsBrokerDisconnected()) Connect();
Channel.ExchangeDeclare(ExchangeName, ExchangeTypeVal.ToString());
Channel.QueueDeclare(QueueName, QueueDurable, QueueExclusive, QueueDelete, null);
Channel.QueueBind(QueueName, ExchangeName, RoutingKey);
var encodedMessage = Encoding.ASCII.GetBytes(message);
Channel.BasicPublish(ExchangeName, RoutingKey, null, encodedMessage);
Disconnect();
}
}
Further reading : Introduction to RabbitMQ with C# .NET, ASP.NET and ASP.NET MVC with examples
Upvotes: 0
Reputation: 9527
What you must not do is allow a channel to be used by more than one thread, so keeping channels open over several requests is a bad idea.
IModel instances are cheap to create, but not free, so there are a couple of approaches you can take:
The safest thing to do is simply to create a channel each time you want to publish and close it again straight away. Something like this:
using(var model = connection.CreateModel())
{
var properties = model.CreateBasicProperties();
model.BasicPublish(exchange, routingKey, properties, msg);
}
You can keep the connection open for the lifetime of the application, but be sure to detect if you loose the connection and have code to reconnect.
The downside with this approach is that you have the overhead of creating a channel for each publish.
The alternative is to hold a channel open on a dedicated publishing thread and marshal all your publish calls onto that thread using a BlockingCollection or similar. This will be more efficient, but more complex to implement.
Upvotes: 3