RabbitMQ not throwing error on invalid routing key - c#

I have the following code in C#, which does not throw error if the routing key is invalid.
var connFactory = GetConnectionFactory();
using (var conn = connFactory.CreateConnection())
{
using (var channel = conn.CreateModel())
{
channel.TxSelect();
var publicationAddress = new PublicationAddress(ExchangeType.Direct, Settings.ServiceBusExchange, Settings.ServiceBusRoutingKey);
var headers = new Dictionary<String, Object>();
headers.Add("TransactionID", transactionID);
var basicProperties = new BasicProperties();
basicProperties.ContentEncoding = Encoding.UTF8.ToString();
basicProperties.ContentType = "text/xml";
basicProperties.Headers = headers;
basicProperties.DeliveryMode = 2;
var payLoad = Encoding.UTF8.GetBytes(message);
channel.BasicPublish(publicationAddress, basicProperties, payLoad);
channel.TxCommit();
}
}
My question is, how can I make the code throw error if the routing key is invalid? Like when I Publish a message using RabbitMQ UI with invalid routing key, it gives a message "Message published, but not routed."
Thanks in advance.

it does not exist the concept of "invalid routing key", since you can bind dynamically queues to the exchanges.
Btw what you are looking for is "unroutable messages", you have to use the mandatory flag and implement the ReturnListener in the same channel, if a message does not reach any queue will be redirect to the handler.
In this in this way (the code is Java, but in c# is more or less the same):
boolean isMandatory = true; // if true the message will be handled by HandlingReturnListener
// if false the message will be dropped!
channel.addReturnListener(new ReturnListener() {
public void handleReturn(int replyCode, String replyText, String exchange, String routingKey, AMQP.BasicProperties properties, byte[] body) throws IOException {
System.out.println(replyText + ":" + replyCode);
System.out.println("******** UnHandled Message ***************");
}
});
String myExchange = "myUnroutableExchange_";
channel.exchangeDeclare(myExchange, "topic", false, false, null);
channel.basicPublish(myExchange, "NO_KEY", isMandatory, null, "".getBytes());

For this there is something called PublisherAcknoledgement. This will basically gives an Ack to the publisher about the status of the message. You will be able to also differentiate between whether the message has reached till Exchange or it has reached till the consumer. You just have to handle each case properly.
This is a good way to know the status of the message being delivered. You might not know if its happening because of the wrong routing key but with doing various checks you might be able to narrow down to the result.

Related

How to set up attribute Message Group ID

I'm attempting to send an SQS message to a FIFO queue. I've run into problems with the Message Group ID attribute. I thought using the MessageAttributeValue was the correct way to set up the "MessageGroupId", but AWS doesn't seem to recognize this input. What is the proper method for setting up SQS SendMessageRequest.MessageAttributes?
I've made a console project that sends a message. I've attempted a few things to set the Message Group Id attribute, but I get an exception when sending the message.
SendMessageRequest sendMessageRequest = new SendMessageRequest();
sendMessageRequest.QueueUrl = myURL;
MessageAttributeValue mavGroupID = new MessageAttributeValue();
mavGroupID.DataType = "MessageGroupId";
mavGroupID.StringValue = "1";
MessageAttributeValue mavDeDuplicateID = new MessageAttributeValue();
mavDeDuplicateID.DataType = "MessageDeduplicationId";
mavDeDuplicateID.StringValue = "1";
sendMessageRequest.MessageAttributes.Add("0", mavGroupID);
sendMessageRequest.MessageAttributes.Add("1", mavDeDuplicateID);
string sMyMessage = "";
Console.WriteLine();
Console.WriteLine("Message to send: ");
sMyMessage = Console.ReadLine();
sendMessageRequest.MessageBody = sMyMessage;
SendMessageResponse sMR = amazonSQSClient.SendMessage(sendMessageRequest);
Amazon.SQS.AmazonSQSException: 'The request must contain the parameter MessageGroupId.'
The MessageGroupId is specified on the SendMessageRequest itself. It is not a MessageAttribute.
SendMessageRequest.MessageGroupId = 'foo'
See: SendMessageRequest Class | AWS SDK for .NET V3

Validate multiple endpoints using HTML status codes before failing when consuming a asmx web service C#

I am currently using a web service, which offers 2 endpoints, as backups for fall over. I need to test all 2 endpoints before my code completely fails and then will need to log the exception. My thoughts were to be to return the status code of the HTML response using this:
Function1:
public string ValidateHttpRequest(string endpointUrl)
{
try
{
var url = endpointUrl;
HttpClient httpClient = new HttpClient();
var reponse = httpClient.GetAsync(endpointUrl);
return reponse.Result.StatusCode.ToString();
}
catch (Exception ex)
{
Log.Log("exception thrown in ValidateHttpRequest()! " + ex.ToString());
Log.Log(ex);
return null;
}
}
This is called from another function, say function2().
Function 2:
private bool function2()
{
//Specify the binding to be used for the client.
BasicHttpsBinding binding = new BasicHttpsBinding();
var epA = "https://www1.endpoint1.com/endpointService.asmx";
var epB = "https://www2.endpoint1.com/endpointService.asmx";
if (ValidateHttpRequest(epA)== "OK")
{
EndpointAddress address = new EndpointAddress("https://www1.enpoint1.com/endpointService.asmx");
_Client = new WebService.SoapClient(binding, address);
return true;
}
else if ((ValidateHttpRequest(epB))== "OK")
{
EndpointAddress address2 = new EndpointAddress(("https://www2.enpoint2.com/endpointService.asmx"));
else
{
// Now Log error here completely, and only fail here if both above checks return anything apart from 200 status code
LogException(“Only log exception if all endpoints fail”);
return false;
}
}
This is all well and good, however I need this to not fail on the first call, as I will need to check if the other endpoint is valid/active. The issue is that if the response is null, the exception is handled and I will not check the rest of my endpoints, how can I correctly ensure my code is safe with i.e. exceptions are handled correctly, but continuing my code to check all endpoints before completely failing and halting execution. it should fail if i receive any other response apart from 200 OK I have researched about how to check the HTTP response and all that I can come up with is this but it doesn’t completely suit my needs .If anyone could point me in the right direction or help with a solution I would be very grateful.
Thanks in advance

NServiceBus Handler throwing metadata errors

After updating NServiceBus to the latest version released last week (which also has a new implementation), I'm seeing weird errors when sending json from the client.
I will send a message from the client and the receiver displays this message:
2016-10-18 22:16:33.612 INFO MFG.Receiver.DeviceHandler Got message with id: a222b136-6a4e-474e-8012-cc1c24e5e539
I have a breakpoint in my handler, below, and it shows the message object is baked and there should not be any issues.
public class DeviceHandler : IHandleMessages<DeviceRequest>
{
private readonly IDeviceProvider _provider = new DeviceProvider();
private static readonly ILog Log = LogManager.GetLogger<DeviceHandler>();
public Task Handle(DeviceRequest message, IMessageHandlerContext context)
{
Log.Info($"Got message with id: {context.MessageId}");
...
return context.SendLocal($"Message with Id {context.MessageId} received.");
}
}
When it hits the reply method at the end, it throws the below errors:
2016-10-18 22:16:33.666 INFO NServiceBus.RecoverabilityExecutor Immediate Retry is going to retry message 'a222b136-6a4e-474e-8012-cc1c24e5e539' because of an exception:
System.Exception: Could not find metadata for 'System.String'.
Ensure the following:
1. 'System.String' is included in initial scanning.
2. 'System.String' implements either 'IMessage', 'IEvent' or 'ICommand' or alternatively, if you don't want to implement an interface, you can use 'Unobtrusive Mode'.
at NServiceBus.Unicast.Messages.MessageMetadataRegistry.GetMessageMetadata(Type messageType) in C:\Build\src\NServiceBus.Core\Unicast\Messages\MessageMetadataRegistry.cs:line 39
I'm not sure why it would throw the System.String error, after it already received the message from the handler and the properties are populated...
The json sent looks like this:
{
"$type": "DeviceRequest, MFG.Domain",
"Id": "devices-65",
"DeviceId": 1,
"Location": "Orlando",
"DeviceType": "test"
}
My Sender (client) looks like this:
static void Main()
{
...
using (var channel = connection.CreateModel())
{
var messageId = Guid.NewGuid().ToString();
var properties = channel.CreateBasicProperties();
properties.MessageId = messageId;
var payload = GenerateJsonPayload();
channel.BasicPublish(string.Empty, ServerEndpointName, false, properties, Encoding.UTF8.GetBytes(payload));
Console.WriteLine($"Message with id {messageId} sent to queue.");
}
...
}
public static string GenerateJsonPayload()
{
var obj = new DeviceRequest
{
DeviceId = 1,
DeviceType = "test",
Location = "Orlando"
};
var settings = new JsonSerializerSettings
{
TypeNameHandling = TypeNameHandling.All
};
var result = JsonConvert.SerializeObject(obj, Formatting.Indented, settings);
return result;
}
I've had the "could not find metadata" issue before, and it was due to malformed json or not having type. If I remove the JsonSerializerSettings, and just passed a serialized object, I instead get errors:
2016-10-18 22:31:27.698 ERROR NServiceBus.RecoverabilityExecutor Moving message '6405179d-ea36-4264-af2a-704da19af120' to the error queue 'error' because processing failed due to an exception:
NServiceBus.MessageDeserializationException: An error occurred while attempting to extract logical messages from transport message 6405179d-ea36-4264-af2a-704da19af120 ---> System.Exception: Could not find metadata for 'Newtonsoft.Json.Linq.JObject'.
I have no idea what I'm missing here and this wasn't an issue with the previous version. Is this a bug or ... ?
Use a concrete message type for your SendLocal operation.
As part of handling the message you are doing return context.SendLocal($"Message with Id {context.MessageId} received.");. This will try to send a message of type "string" to the local queue. NServiceBus is telling you that no message metadata was registered for the message type of "string". Therefor it can not construct the message and throws an exception.

Sending Messages by rabbitMq

I am using rabbit-Mq in my web app(Asp.net-MVC 4.0). My requirement is to send a message to a particular user. Suppose if user1 is online and he sends a message to user2 by rabbit-Mq. It should be received by "user2" only. The code I have used is a template which stores the message in the queue and whenever the user clicks on receive he will get that message but there is no restriction of particular user in my case. Anyone can get that message which is wrong and I have to handle that. Please help me regarding this.
Do we have something in rabbit-Mq that can distinguish the correct message to correct user/Consumer? Can we set a key with message and check the key while receiving?
Is this possible?
Below I am writing the code I am using to send and receive the messages
public ActionResult SendMessage(MessagingModel ObjModel)
{ var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
Message = ObjModel.Message;
channel.QueueDeclare("MessageQueue", true, false, false, null);
var body = Encoding.UTF8.GetBytes(ObjModel.Message);
channel.BasicPublish("", "MessageQueue", null, body);
}
}
}
public JsonResult RecieveMessage()
{
var factory = new ConnectionFactory() { HostName = "localhost" };
using (var connection = factory.CreateConnection())
{
using (var channel = connection.CreateModel())
{
channel.QueueDeclare("MessageQueue", true, false, false, null);
bool noAck = true;
BasicGetResult result = channel.BasicGet("MessageQueue", noAck);
if (result == null)
{
Message = "No Messages Found.";
}
else
{
IBasicProperties props = result.BasicProperties;
byte[] Body = result.Body;
Message = Encoding.Default.GetString(Body);
}
}
}
First, you must remember the following things:
All messages in RabbitMQ published through exchanges.
Queues binded to exchanges.
Event if you publish message directly into queue, actually it still passes through the default exchange - (AMPQ default).
There are different kinds of exchanges. You can read a bit about exchanges here: https://www.rabbitmq.com/tutorials/tutorial-three-dotnet.html
In you case you might consider use a topic or headers exchanges, but in this case you should for each user
have a queue, and if the number of users in the system is large, then it will be very resource intensive.
Also you can add specific header to you message:
var props = model.CreateBasicProperties();
props.Headers.Add("UserId", userId);
and then in RecieveMessage() method after read message from queue see this header and if message intended for current user - receive it and acknowledge this message, otherwise
not acknowledge this message.
But this is bad solution. I would just kept messages from the queue to the database, and then read them out filtering by user.

APNS Input string was not in a correct format. Disconnected

I am trying to set up apple push notifications, i am writing my own code for the server and as far as i know i have set up the app correctly. How ever i keep getting the following error come back from the log:
Payload queue received. Connecting to apple server. Creating SSL
connection. Conected. Payload generated for
"Token goes here i deleted it :
{"aps":{"alert":"test","badge":1,"sound":"default"}} Notification
successfully sent to APNS server for Device Toekn :
"Token here I've deleted it" An
error occurred while reading Apple response for token
"Token here I've deleted it" -
Input string was not in a correct format. Disconnected
This is my code.
var push = new PushNotification(true, #"C:\wwwroot\UltraNet\PushService\bin\Debug\206dist.p12", "ultrait");
var payload = new NotificationPayload("devicetoken here ive deleted it", "test", 1, "default");
var p = new List<NotificationPayload> { payload };
var result = push.SendToApple(p);
Console.ReadLine();
I have made sure that the certificates etc are set up correctly.
I am testing it as a adhoc app at the moment because it takes so long for a new version to be able to go live.
I really don't know where I'm going wrong if any one could help it would be brilliant thank you.
I also don't know what i need to do with the PEM files that i have created.
Edit***
I have the correct token this is another error that i receive
Payload generated for
df99286a1cb993cecba86b2e21f3fc4c04d214fcf7e0cf35a668fc822bdaa053 :
{"aps":{"alert":"test","badge":1,"sound":"default"}} Notification
successfully sent to APNS server for Device Toekn :
df99286a1cb993cecba86b2e21f3fc4c04d214fcf7e0cf35a668fc822bdaa053
Disconnected. An error occurred while reading Apple response for token
df99286a1cb993cecba86b2e21f3fc4c04d214fcf7e0cf35a668fc822bdaa053 -
Safe handle has been closed
Based on the code of ReadResponse (see below), the Input string was not in a correct format error message refers to the response received from Apple, and not to the notification you sent.
The code failed to properly read the error response from Apple.
Had it succeeded in reading the response, you would have known what the exact failure was and which message failed. Since you don't have the error response, it's a safe bet to assume the problem is your device token. That's the most common failure. If you can isolate the device token for which the error occurs, you should simply delete that token from your DB. Invalid Device Token error often occurs when you try to use sandbox tokens when pushing to production environment or vica versa.
private void ReadResponse(IAsyncResult ar)
{
if (!_conected)
return;
string payLoadId = "";
int payLoadIndex = 0;
try
{
var info = ar.AsyncState as MyAsyncInfo;
info.MyStream.ReadTimeout = 100;
if (_apnsStream.CanRead)
{
var command = Convert.ToInt16(info.ByteArray[0]);
var status = Convert.ToInt16(info.ByteArray[1]);
var ID = new byte[4];
Array.Copy(info.ByteArray, 2, ID, 0, 4);
payLoadId = Encoding.Default.GetString(ID);
payLoadIndex = ((int.Parse(payLoadId)) - 1000);
Logger.Error("Apple rejected palyload for device token : " + _notifications[payLoadIndex].DeviceToken);
Logger.Error("Apple Error code : " + _errorList[status]);
Logger.Error("Connection terminated by Apple.");
_rejected.Add(_notifications[payLoadIndex].DeviceToken);
_conected = false;
}
}
catch (Exception ex)
{
Logger.Error("An error occurred while reading Apple response for token {0} - {1}", _notifications[payLoadIndex].DeviceToken, ex.Message);
}
}
It was all to do with my certificates.
Because i hadn't turnt my combined PEM certificate back to a p12 file.

Categories