I am implementing a class library in C# which will be used into X++ code for Azure Service Bus communication. I have added code to read message from topic and its subscription.
But for some messages, I want move that message into the dead letter queue with an error message. Through ServiceBusClient
, I can do it, but does not work in x++ as it is not supported to nuget package.
Can you help me to send a message into the dead letter queue?
This is my code:
using System;
using System.Net.Http.Headers;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using System.Security.Cryptography;
using System.Web;
using Newtonsoft.Json;
namespace TestAzureServiceBusConsole
{
internal class Program2
{
private const string ServiceBusNamespace = "<my-service-bus-instance>";
private const string TopicName = "<topic-name>";
private const string SubscriptionName = "<subscription-name>";
static string SasToken = "";
static string keyName = "<key-name>";
static string key = "<key>";
static void Main(string[] args)
{
var deadLetterQueuePath = $"{TopicName}/subscriptions/{SubscriptionName}/messages/head";
var baseAddress = new Uri($"https://{ServiceBusNamespace}.servicebus.windows.net/");
using (var httpClient = new HttpClient { BaseAddress = baseAddress })
{
SasToken = GetSasToken(baseAddress.AbsoluteUri + $"{TopicName}/");
httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("SharedAccessSignature", SasToken);
/* To read message from topic and read its message id*/
var response = httpClient.PostAsync(deadLetterQueuePath,null).GetAwaiter().GetResult();
if (response.IsSuccessStatusCode)
{
if (response.IsSuccessStatusCode)
{
MessageRead currentMessage = new MessageRead();
var message = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
var obj = response.Headers.GetValues("BrokerProperties");
foreach (var brokerProperties in obj)
{
// BrokerProperties is a JSON string
currentMessage = JsonConvert.DeserializeObject<MessageRead>(brokerProperties);
currentMessage.message = message;
}
Console.WriteLine("Message received from subscription: " + message);
var deadLetterPath = $"{TopicName}/subscriptions/{SubscriptionName}/messages/{currentMessage.MessageId}/movetodeadletterqueue?api-version=2021-12";
var deadLetterContent = new StringContent(message, Encoding.UTF8, "application/json");
var deadLetterResponse = httpClient.PostAsync(deadLetterPath, deadLetterContent).GetAwaiter().GetResult();
if (deadLetterResponse.IsSuccessStatusCode)
{
Console.WriteLine("Message moved to dead-letter queue successfully.");
}
else
{
Console.WriteLine("Error: " + deadLetterResponse.StatusCode);
var deadLetterErrorResponse = deadLetterResponse.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Console.WriteLine("Error details: " + deadLetterErrorResponse);
}
}
else
{
Console.WriteLine("Error: " + response.StatusCode);
var errorResponse = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Console.WriteLine("Error details: " + errorResponse);
}
}
else
{
Console.WriteLine("Error: " + response.StatusCode);
var errorResponse = response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
Console.WriteLine("Error details: " + errorResponse);
}
}
Console.ReadKey();
}
public static string GetSasToken(string resourceUri)
{
string encodedUri = Uri.EscapeDataString(resourceUri).ToLower();
DateTime now = DateTime.UtcNow;
TimeSpan week = TimeSpan.FromDays(7);
int ttl = (int)(now.Add(week) - new DateTime(1970, 1, 1)).TotalSeconds;
string signatureString = encodedUri + "n" + ttl;
using (var hmac = new HMACSHA256(Encoding.UTF8.GetBytes(key)))
{
byte[] signatureBytes = Encoding.UTF8.GetBytes(signatureString);
byte[] hash = hmac.ComputeHash(signatureBytes);
string hashInBase64 = Convert.ToBase64String(hash);
return $"sr={encodedUri}&sig={Uri.EscapeDataString(hashInBase64)}&se={ttl}&skn={keyName}";
}
}
}
public class MessageRead
{
public int? DeliveryCount { get; set; }
public int? EnqueuedSequenceNumber { get; set; }
public DateTime? EnqueuedTimeUtc { get; set; }
public string LockToken { get; set; }
public DateTime? LockedUntilUtc { get; set; }
public string MessageId { get; set; }
public int? SequenceNumber { get; set; }
public string State { get; set; }
public long TimeToLive { get; set; }
public string message { get; set; }
}
}
Thanks in advance,
Sandy