RPC using Rabbitmq in ASP.Net Core 3 - asp.net-core

I want to implement multiple queues using single request
RPC Server.cs
How can I send multiple messages from the server
For ex. I created Instances :
`
RPCServer rpcServer1 = new RPCServer();
rpcServer1.PublishMessage("customerContactPersonsList","customerContactPersons");`
`
RPCServer rpcServer2 = new RPCServer();
rpcServer2.PublishMessage("ProductInfoList", "projects");
public void PublishMessage(string message, string rpcQueueName)
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: rpcQueueName, durable: false,
exclusive: true, autoDelete: false, arguments: null);
channel.BasicQos(0, 1, false);
var consumer = new EventingBasicConsumer(channel);
channel.BasicConsume(queue: rpcQueueName,
autoAck: false, consumer: consumer);
Console.WriteLine(" [x] Awaiting RPC requests");
consumer.Received += (model, ea) =>
{
string response = null;
var body = ea.Body.ToArray();
var props = ea.BasicProperties;
var replyProps = channel.CreateBasicProperties();
replyProps.CorrelationId = props.CorrelationId;
try
{
Console.WriteLine(" [.] Response message is)", message);
response = message;
}
catch (Exception e)
{
Console.WriteLine(" [.] " + e.Message);
response = "There was a error";
}
finally
{
var responseBytes = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange:"topic", routingKey: props.ReplyTo, basicProperties: replyProps, body: responseBytes);
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
}
};
Console.WriteLine("Press [enter] to exit.");
Console.ReadLine();
}
Receiver.cs
** The Receiver side is where the response via queue is retrieved and it also calls the client which basically sends a request and a queue name as a parameter to get json data from the server side where the same queue is declared and when both the names of the queues are matched the response is sent to the receiver end.** so for ex. here projects as a parameter is the queue name given and the same is also mentioned for the server side.
var rpcClient = new RpcClient();
var customerContactPersons = await rpcClient.CallAsync("", "customerContactPersons");
var response = await rpcClient.CallAsync("","projects");
var factory = new ConnectionFactory() { HostName = "localhost" };
connection = factory.CreateConnection();
channel = connection.CreateModel();
replyQueueName = channel.QueueDeclare().QueueName;
consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
if (!callbackMapper.TryRemove(ea.BasicProperties.CorrelationId, out TaskCompletionSource<string> tcs))
return;
var body = ea.Body.ToArray();
var response = Encoding.UTF8.GetString(body);
tcs.TrySetResult(response);
};
}
public Task<string> CallAsync(string message, string rpcQueueName, CancellationToken cancellationToken = default(CancellationToken))
{
IBasicProperties props = channel.CreateBasicProperties();
var correlationId = Guid.NewGuid().ToString();
props.CorrelationId = correlationId;
props.ReplyTo = replyQueueName;
var messageBytes = Encoding.UTF8.GetBytes(message);
var tcs = new TaskCompletionSource<string>();
callbackMapper.TryAdd(correlationId, tcs);
channel.BasicPublish(
exchange: "",
routingKey: rpcQueueName,
basicProperties: props,
body: messageBytes);
channel.BasicConsume(
consumer: consumer,
queue: replyQueueName,
autoAck: true);
cancellationToken.Register(() => callbackMapper.TryRemove(correlationId, out var tmp));
return tcs.Task;
}`

I solved it by adding connection block for each queue and at the end console.readline(); keeps the connection open for the queues to be consumed.
using (var connection = rpcServer.PublishMessage(customercontact, "customercontact_rpc_queue"))
using (var connectionObject = rpcServer.PublishMessage(result, "project_rpc_queue"))
using (var customersObject = rpcServer.PublishMessage(customersFromByD, "customer_rpc_queue"))
{
Console.WriteLine("Press [enter] to exit.");
Console.ReadLine();
}

Related

ASP.NET CORE combined with RabbitMq message queue

I am using asp.net core to create a project, I want to combine rabbitmq to realize the sending and receiving of message queue.I installed rabbitmq using docker and it runs successfully.But the queue I registered in the project is not displayed on the RabbitMq management interface.
ConnectionFactory factory = new ConnectionFactory
{
UserName = "guest",
Password = "guest",
HostName = "*******"
};
var connection = factory.CreateConnection();
var channel = connection.CreateModel();
channel.QueueDeclare("test", false, false, false, null);
Console.WriteLine("\nRabbitMQ enter exit to exit!");
string input;
do
{
input = Console.ReadLine();
var sendBytes = Encoding.UTF8.GetBytes(input);
channel.BasicPublish("", "test", null, sendBytes);
} while (input.Trim().ToLower()!="exit");
channel.Close();
connection.Close();
The above is my message production code.But there is no display on my RabbitMq dashboard.
enter image description here
You did not specify the port number to connect to and the VirtualHost to connect to, I am not sure if you are caused by this. Do you have a specific error? Or your project can run normally. I have written a demo for sending messages here, you can refer to it, it may be useful to you.
class Program
{
static void Main(string[] args)
{
try
{
var factory = new ConnectionFactory();
factory.VirtualHost = "/";
factory.HostName = "localhost";
factory.Port = 5672;
factory.UserName = "guest";//Default username guest
factory.Password = "guest";//Default password guest
using (var connection = factory.CreateConnection())
using (var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "hello",
durable: false,
exclusive: false,
autoDelete: false,
arguments: null);
string message = "Hello World!";
var body = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(exchange: "",
routingKey: "hello",
basicProperties: null,
body: body);
Console.WriteLine(" [x] Sent {0}", message);
}
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
catch (Exception ex)
{
Console.Write(string.Format("RabbitMQ connection error :{0}\n", ex.ToString()));
}
}
}
Refer to the official document example:
https://www.rabbitmq.com/tutorials/tutorial-one-dotnet.html
If you run this code and get this error:
Check if your corresponding virtual hosts match, I set "/" here, if you are not, please add your hosts here:
Result:
console:
rabbitmq:

Code to get single message from the queue in RabbitMQ using C#

How to receive single message from the queue in RabbitMQ using C#
I am using the RabbitMQ to maintain my Queue.When I am read my queue messages its shows all massage present in the queue.
I want to retrieve single message as per First come first out criteria.
Please provide me code to get the single message from the queue by using RabbitMQ
var connection = connectionFactory.CreateConnection();
var channel = connection.CreateModel();
// accept only one unack-ed message at a time
// uint prefetchSize, ushort prefetchCount, bool global
channel.BasicQos(0, 1, false);
MessageReceiver messageReceiver = new MessageReceiver(channel);
channel.BasicConsume("viewer_Queues", false, messageReceiver);
//channel.QueueDeclare("viewer_Queues", false, false, false, null);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("viewer_Queues", true, consumer);
BasicDeliverEventArgs ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(message + " Received.");
Console.ReadLine();
I think you need something like this, from the website Tutorials in the worker Queues Section:
`using System;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
using System.Text;
using System.Threading;
class Worker
{
public static void Main()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using(var connection = factory.CreateConnection())
using(var channel = connection.CreateModel())
{
channel.QueueDeclare(queue: "task_queue",
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
Console.WriteLine(" [*] Waiting for messages.");
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
var body = ea.Body;
var message = Encoding.UTF8.GetString(body);
Console.WriteLine(" [x] Received {0}", message);
int dots = message.Split('.').Length - 1;
Thread.Sleep(dots * 1000);
Console.WriteLine(" [x] Done");
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
channel.BasicConsume(queue: "task_queue",
autoAck: false,
consumer: consumer);
Console.WriteLine(" Press [enter] to exit.");
Console.ReadLine();
}
}
}`
the prefetch argument is important if you want to get only one message at a time you can read about it in the official website https://www.rabbitmq.com/

.NET Core 1.1 Receiving RabbitMQ Messages

Here's a simple .net core 1.1 console app. Call it with a -r parameter and it reads all the messages in the rabbitmq Queue, call it with any other parameters, and each parameter is enqueued as a message.
Here's the problem, I can enqueue the messages fine, but all attempts to read the messages result in no messages being read. Clearly I'm not consuming the queue correctly, and would appreciate some guidance.
Thanks!
using System;
using System.Collections.Generic;
using System.Text;
using Newtonsoft.Json;
using RabbitMQ.Client;
using RabbitMQ.Client.Events;
namespace RabbitMqDemo
{
class Program
{
static void Main(string[] args)
{
var client = new MessagingClient();
if (args.Length == 1 && args[0].ToLower() == "-r")
{
Console.WriteLine("Reading Messages from Queue.");
var messages = client.ReceiveMessages();
Console.WriteLine($"Read {messages.Length} message(s) from queue.");
foreach(var msg in messages)
Console.WriteLine(msg);
}
else
{
foreach (var msg in args)
{
client.SendMessage(msg);
}
Console.WriteLine($"Enqueued {args.Length} Message.");
}
}
}
internal class MessagingClient
{
private readonly ConnectionFactory connectionFactory;
private string ExchangeName => "defaultExchange";
private string RoutingKey => "";
private string QueueName => "Demo";
private string HostName => "localhost";
public MessagingClient()
{
this.connectionFactory = new ConnectionFactory {HostName = this.HostName};
}
public void SendMessage(string message)
{
using (var connection = this.connectionFactory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
this.QueueDeclare(channel, this.QueueName);
var properties = this.SetMessageProperties(channel, message);
string messageJson = JsonConvert.SerializeObject(message);
var body = Encoding.UTF8.GetBytes(messageJson);
channel.BasicPublish(exchange: this.ExchangeName, routingKey: this.RoutingKey, basicProperties: properties, body: body);
}
}
}
public string[] ReceiveMessages()
{
var messages = new List<string>();
using (var connection = this.connectionFactory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
this.QueueDeclare(channel, this.QueueName);
channel.BasicQos(prefetchSize: 0, prefetchCount: 1, global: false);
var consumer = new EventingBasicConsumer(channel);
consumer.Received += (model, ea) =>
{
string bodystring = Encoding.UTF8.GetString(ea.Body);
messages.Add(bodystring);
// ReSharper disable once AccessToDisposedClosure
channel.BasicAck(deliveryTag: ea.DeliveryTag, multiple: false);
};
channel.BasicConsume(queue: this.QueueName, autoAck: false, consumer: consumer);
}
}
return messages.ToArray();
}
private void QueueDeclare(IModel channel, string queueName)
{
channel.ExchangeDeclare(ExchangeName, type: ExchangeType.Direct,
durable: true,
autoDelete: false,
arguments: null);
var queueDeclared = channel.QueueDeclare(queue: queueName,
durable: true,
exclusive: false,
autoDelete: false,
arguments: null);
channel.QueueBind(queueName, ExchangeName, RoutingKey);
}
private IBasicProperties SetMessageProperties(IModel channel, object message)
{
var properties = channel.CreateBasicProperties();
properties.ContentType = "application/json";
properties.Persistent = true;
return properties;
}
}
}
First, use the management UI to ensure that your exchange and queue are set up correctly and that messages have been published to it.
Second, ReceiveMessages() and thus your reader probably returns immediately with an empty array before the event has a chance to fire. You have no code to wait while the consumer receives messages from RabbitMQ. Notice in the tutorial how Console.ReadLine() is used. In your example, you can use a synchronization object (ManualResetEvent) to prevent ReceiveMessages() from returning until a certain message count is read.

How to send 1 million of push notification (APNS) within few second using PushSharp as webservice?

to do that i made a web service to send push (by referencing PushSharp library). I request web service through my web application. i retrieve list of device token from database(using web application) send to web service using for loop to send push. and get result/exception for each one. This process is very slow and take long long time to send notification. If anybody suggest me to what should i do i will be grateful to you.
public ActionResult SendNowToken(int certificateInfoId, string message, string certificate, int badgeNo, int pushtype, string password, string countryJsonString)
{
if (IsPushParameterValid(certificateInfoId, message, certificate, badgeNo, pushtype, password, countryJsonString))
{
var countryObject = new JavaScriptSerializer().Deserialize<Country>(countryJsonString);
var errorList = new List<ErrorList>();
byte[] certificatePath = System.IO.File.ReadAllBytes(HttpContext.Server.MapPath("~/Content/certificate/" + certificate));
foreach (var aDeviceToken in countryObject.DeviceTokens)
{
try
{
var serviceClient = new PushServiceSoapClient();
string serviceResult = serviceClient.SendPushNotification(message, badgeNo, pushtype, aDeviceToken.Token, certificatePath, password);
if (serviceResult != "Sent Notification")
{
var delimiters = new[] { ' ' };
string[] errorResult = serviceResult.Split(delimiters, StringSplitOptions.RemoveEmptyEntries);
string errorMessage = ConvertErrorCodeToErrorMessage(errorResult[0]);
var error = new ErrorList
{
CountryName = countryObject.CountryName,
ErrorTime = DateTime.Now,
ErrorMessage = errorMessage,
Token = aDeviceToken.Token
};
errorList.Add(error);
}
}
catch (Exception ex)
{
var error = new ErrorList
{
CountryName = countryObject.CountryName,
ErrorTime = DateTime.Now,
ErrorMessage = ex.Message,
Token = aDeviceToken.Token
};
errorList.Add(error);
}
}
if (errorList.Count != 0)
{
ViewBag.Message = "Push Notification does not send to country... ";
return PartialView("_SendAllError", errorList.ToList());
}
errorList.Clear();
}
return View();
}

Need help in creating RabbitMQ consumer as windows service?

This code works fine with console application but it doesnt work with Windows service application.
//code to receive message from queue
public void ReceiveMessage()
{
const string EXCHANGE_NAME = "EXCHANGE3";
ConnectionFactory factory = new ConnectionFactory();
//Rabbit MQ connection
using (IConnection connection = factory.CreateConnection())
{
using (IModel channel = connection.CreateModel())
{
channel.QueueDeclare("task_queue", true, false, false, null);
channel.BasicQos(0, 1, false);
var consumer = new QueueingBasicConsumer(channel);
channel.BasicConsume("task_queue", false, consumer);
//Waiting in loop to get message
while (true)
{
var ea =
(BasicDeliverEventArgs)consumer.Queue.Dequeue();
Object message = Desserialize(ea.Body);
//Acknowledge one or more delivered message
channel.BasicAck(ea.DeliveryTag, false);
}
}
}
}