Consider this code:
public async Task<Status> SendMessage(Message message)
{
List<IMessage> _messageDispatchers = new List<IMessage>();
try
{
Object[] args = new Object[] { _message };
IMessage endpoint = (IMessage)Activator.CreateInstance(Type.GetType(_message.AgentDLLName), args);
_messageDispatchers.Add(endpoint);
foreach (IMessage dispatcher in _messageDispatchers)
{
await Task.Run(() => dispatcher.SendMessage(_message));
}
return await Task.Run(() => Status.Success);
}
catch (Exception ex)
{
logger.Log(LoggerLevel.Error, ex.Message);
return Status.EmailSendingFailed;
}
}
the SendMessage:
public async Task<Status> SendMessage(OutboundMessage outboundmessage)
{
string strMessage = string.Empty;
string subject = string.Empty;
MessageServices objService = new MessageServices();
try
{
var config = (from SmtpConfigurationElement ms in AppConfiguration.Instance.Smtps
where ms.Key == "smtp"
select ms).Single();
SmtpClient smtpClient = new SmtpClient(config.Host);
smtpClient.Port = Convert.ToInt32(config.port);
smtpClient.EnableSsl = true;
smtpClient.Credentials = new NetworkCredential(config.UserName, config.Password);
string[] strToList = outboundmessage.ToList.Split(';');
MailMessage mail = new MailMessage();
mail.From = new MailAddress(outboundmessage.FromAddress);
if (strToList.Length > 0)
{
for (int j = 0; j < strToList.Length; j++)
{
mail.To.Add(strToList[j]);
}
}
else
{
_LOGGER.Log(LoggerLevel.Information, "SMTP Mail Send failed as ToList is not correct");
return Status.Failed;
}
if (!string.IsNullOrEmpty(outboundmessage.CCList))
{
string[] strCCList = outboundmessage.CCList.Split(';');
if (strCCList.Length > 0)
{
for (int k = 0; k < strCCList.Length; k++)
{
mail.CC.Add(strToList[k]);
}
}
}
if (!string.IsNullOrEmpty(outboundmessage.Attachments))
{
System.Net.Mail.Attachment attachment;
attachment = new System.Net.Mail.Attachment(outboundmessage.Attachments);
mail.Attachments.Add(attachment);
}
strMessage = await objService.ReplaceMessageWithPlaceholders(outboundmessage.PlaceholderValues, outboundmessage.MessageBody);
subject = await objService.ReplaceMessageWithPlaceholders(outboundmessage.PlaceholderValues, outboundmessage.Subject);
mail.Body = strMessage;
mail.Subject = subject;
mail.IsBodyHtml = true;
await Task.Run(() => smtpClient.Send(mail));
return Status.Success;
}
catch (Exception ex)
{
return Status.Failed;
}
}
And the call to SendMessage:
public Status MarketingEmail(OutboundMessage _message)
{
try
{
_message.MessageCreatedDate = System.DateTime.Now;
processor.SendMessage(_message);
return Status.Success;
}
catch (Exception ex)
{
_LOGGER.Log(LoggerLevel.Error, "Error in Marketing Email" + ex.ToString());
return Status.InsertFailed;
}
}
The whole idea is to make a workflow in which sending of the email is the last task and that should be a fire and forget thing.
Now the call to processor.SendMessage(_message) has a suggestion like this:
Because this call is not awaited, execution of the current method
continues before the call is completed. Consider applying the 'await'
operator to the result of the call.
Which is a valid thing since async & await need to be used together.
Questions:
Will the current approach work without any trouble if the suggestion is ignored?
(I am asking this since this is still in the development stage and I can make the suggested design changes now rather than face any critical issues later.)
What is the suggested best practice to design a workflow considering the said requirement?
The current approach will "work" in the sense that it will continue on to return Status.Success; without waiting for the call to processor.SendMessage(_message); to complete.
However, since that call was fired & forgotten, and that SendMessage overload doesn't do any logging in the catch block, you run the risk of emails failing to be sent but nobody getting notified about it.
A common approach for async email sending is this: Stash the email somewhere else (typically a message queue or a database), and then set up a separate async process that reads the queued emails and sends them. If it succeeds, it flags the email as sent. If it fails, it tries again (up to a certain time limit or # of retries), and then if it gives up, it can trigger a notification or set a flag that can be checked later.
Then your code will basically be saying "okay, the email was successfully queued", instead of "okay, the email was sent". Moving the actual sending to a separate process is much more reliable.
Related
Im stuck. I have joined the project that uses Named Pipes, and have lets say "not ideal architecture". And seems like I accidentally received a deadlock:(
The logic is following. There is Named Pipe. Client and Server model. On server part there is a loop, that always pings named pipe and process what client sends, sometimes sending back responses.
On Client side of my pipe, I have following method, from other developer, that is being used to send request to server and receive and return the response.
private object locker = new Object();
private string ListenOnce(string msg)
{
Debug.WriteLine("Will listen for message " + msg);
string msgFrom = "";
if (run) {
string toReturn = "";
lock (locker) {
sw.WriteLine(msg); //Writing command to the pipes
stream.WaitForPipeDrain(); //Waiting for another process to read the command
msgFrom = sr.ReadLine(); //Reading
toReturn = sr.ReadLine ();
if (toReturn.Contains('¥'))
{
string[] split = toReturn.Split('¥');
if (split.Length > 1)
{
var roomNames = this.connection.application.GameCache.GetRoomNames();
for (int i = 1; i < split.Length; i++)
{
string[] split2 = split[i].Split('¶');
if (split2.Length > 1)
{
string accountName = split2[0];
int offenderActorID = int.Parse(split2[1]);
string offenderRoomName = split2[2];
foreach (var roomName in roomNames)
{
Room room;
if (this.connection.application.GameCache.TryGetRoomWithoutReference(roomName, out room))
{
Game game = room as Game;
if (game != null && game.Name == offenderRoomName)
{
GameClientPeer peer = (GameClientPeer)game.ActorsManager.ActorsGetActorByNumber(offenderActorID).Peer;
if (peer != null)
{
peer.KickPlayer();
}
}
}
}
}
}
}
}
}
if (toReturn.Contains('¥'))
{
return toReturn.Split('¥')[0];
}
else
{
return toReturn;
}
}
return "";
}
The problem is - in some cases I cant receive response from pipe right when requested, and need to start what I called here "poller". This is a task, that loops 5 times, and during those 5 times "polls" the pipe through this ListenOnce method.
private void PollTargets()
{
timer.Dispose();
Debug.WriteLine("Going to start polling");
Task.Factory.StartNew(() => {
int runCount = 0;
while (true)
{
runCount++;
PipeOperation request = new PipeOperation(Consts.Pipes.RequestTargets, uniqueID);
string responseStr = unityConnection.client.SendMessage(JsonConvert.SerializeObject(request));
Debug.WriteLine("Task is running, response is " + responseStr);
if (!string.IsNullOrEmpty(responseStr))
{
try
{
PipeOperation pipeResponse = JsonConvert.DeserializeObject<PipeOperation>(responseStr);
if (!string.IsNullOrEmpty(pipeResponse.Payload))
{
GrenadeExplosionData explosionData = JsonConvert.DeserializeObject<GrenadeExplosionData>(pipeResponse.Payload);
if (explosionData != null)
{
//probably need to invoke that in main thread
DealDamage(explosionData);
//isRunning = false;
Debug.WriteLine("Received nice response, will damage targets");
break;
}
}
}
catch (Exception exc)
{
Debug.WriteLine("Something went wrong while polling...");
Debug.WriteLine(exc.Message);
break;
}
}
if (runCount > 5)
{
Debug.WriteLine("run count exceed " + runCount.ToString());
break;
}
}
RemoveGrenadeFromUnityConnection();
});
}
I am starting poller when the Grenade explodes, from timer like that:
timer = new System.Threading.Timer((obj) =>
{
PollTargets();
},
null, 4000, System.Threading.Timeout.Infinite);
And thats it. After people play 2-3 hrs. Seems like I receive a deadlock. It should be taken into account that there might be many grenades on server who starts that poller, so probably it just goes mad at some point over there.
Pls help, Im stuck with that. Who has ideas?
We should keep in mind, that
sw.WriteLine(msg); //Writing command to the pipes
stream.WaitForPipeDrain();
msgFrom = sr.ReadLine(); //Reading
toReturn = sr.ReadLine ();
should be used only by one thread at a time, as stream might be read only from one source.
There are several calls to ListenOnce from the code, but not a lot. One is being fired every 4 minutes.The rest ones are not constant, but conditional.
Hope somebody would see where is a mistake here...
Found what locks everything...However, it does not help a lot:)
Its
stream.WaitForPipeDrain();
it tries to read another end of pipe, but because of there is no timeouts in message mode, it just hangs for ever..
I have a method collecting user data from MS Teams, while this code works as intended, with this method added it makes a previously working method crash.
public async void GetUsers()
{
string teamId = "TeamsID";
string tenantId = "TenantID";
var connector = new ConnectorClient(new Uri(Instance.Activity.ServiceUrl));
members = await connector.Conversations.GetTeamsConversationMembersAsync(teamId, tenantId);
Instance.EmailList.Clear();
foreach (var member in members)
{
Instance.EmailList.Add(member.Email);
}
}
I believe that the Line:
members = await connector.Conversations.GetTeamsConversationMembersAsync(teamId, tenantId);
While receiving the user information, makes the bot think that a user is inputing, causing my later methods to trigger without user input, and crashing because there is no input or because the input if the chunk of data that is the user data.
This is just my theory and I may be incorrect.
The following is the method that crashes:
async Task ReplyToQuestions(IDialogContext context, IAwaitable<IMessageActivity> argument)
{
var AnswerHolder = await argument;
Answers.Add(AnswerHolder.Text);
Answers[AnswerCounter] = Answers[AnswerCounter].First().ToString().ToUpper() + Answers[AnswerCounter].Substring(1);
var isQuit = AnswerHolder.Text;
var isQuit2 = Regex.Match(isQuit, #"\b(Quit|quit|QUIT)\b").Value;
Regex rgx = new Regex(#"\b(Quit|quit|QUIT)\b");
if (rgx.IsMatch(isQuit2)) // checks for the user trying to quit/restart bot
{
await context.PostAsync(string.Format("Exiting current process. Restarting."));
context.Done(isQuit); // returns to the start of dialog (StartAsync)
}
else
{
if (QuestionCounter < 5)
{
await context.PostAsync(string.Format($"Question {QuestionCounter + 1}: {Question[QuestionCounter]}"));
}
AnswerCounter += 1;
QuestionCounter += 1;
if (AnswerCounter < 5)
{
context.Wait(ReplyToQuestions);
}
else if (AnswerCounter == 5)
{
PostToChannel($"{Name}'s answers to the questions are as follows: \n\nQuestion1 Answer: {Answers[0]} \n\nQuestion2 Answer: {Answers[1]} \n\n" +
$"Question3 Answer: {Answers[2]} \n\nQuestion4 Answer: {Answers[3]} \n\nQuestion5 Answer: {Answers[4]} \n\n", context);
await context.PostAsync(string.Format("Your answers have been posted to the 'What's Up' channel."));
AnswerCounter = 0;
QuestionCounter = 1;
context.Done(Answers[4]);
}
else
{
await context.PostAsync($"{AnswerCounter}");
await context.PostAsync(string.Format("Oh no! it appears something has gone wrong. please try re-entering your answers"));
AnswerCounter = 0;
QuestionCounter = 1;
context.Wait(ReplyToQuestions);
}
}
}
And the code that calls it:
async Task Choice(IDialogContext context, IAwaitable<IMessageActivity> argument) // this method recives and validates a question
{
var Choice = await argument;
var isQuit = Choice.Text;
var isQuit2 = Regex.Match(isQuit, #"\b(Quit|quit|QUIT)\b").Value;
Regex rgx = new Regex(#"\b(Quit|quit|QUIT)\b");
var isEnter = Regex.Match(isQuit, #"\b(Enter|ENTER|enter)\b").Value;
Regex rgx2 = new Regex(#"\b(Enter|ENTER|enter)\b");
var isReply = Regex.Match(isQuit, #"\b(Reply|REPLY|reply)\b").Value;
Regex rgx3 = new Regex(#"\b(Reply|REPLY|reply)\b");
GetUsers();
if (rgx.IsMatch(isQuit2)) // if the user choses to quit
{
await context.PostAsync(string.Format("Exiting current process. Restarting."));
context.Done(isQuit); // restarts the program, calls the first method
}
else if (rgx2.IsMatch(isEnter)) // if the user choses to quit
{
await context.PostAsync(string.Format("Please enter your custom question."));
context.Wait(EnterQuestion);
}
else if (rgx3.IsMatch(isReply)) // if the user choses to quit
{
Answers.Clear();
await context.PostAsync(string.Format("Please answer the following questions:"));
await context.PostAsync(string.Format($"Question 1: {Question[0]}"));
context.Wait(ReplyToQuestions);
}
else
{
await context.PostAsync(string.Format("sorry this was not a choice, try again."));
}
}
Does anyone know a way I can fix this? As I have spent 2 full days on this without success.
I'm not sure what error you are seeing. But, the method being used to retrieve conversation members has been deprecated: https://msdn.microsoft.com/en-us/microsoft-teams/botapis#net-example The note on that page should state:
you should migrate your code to use GetConversationMembersAsync(conversationId)
var connector = new ConnectorClient(new Uri(activity.ServiceUrl));
var members = await connector.Conversations.GetConversationMembersAsync(activity.Conversation.Id);
I currently have to provide a sync as async method in my API: Please find the code below. The only problem is that I don’t have a
sync method in the backend. I use Azure.NotificationHub client. That client has only *Async methods. Is my way reasonable?
public PushHubNotificationResult SendPushMessage(string userId, string message)
{
PushHubNotificationResult result = new PushHubNotificationResult();
try
{
result = SendPushMessageAsync(userId, message).GetAwaiter().GetResult();
} catch (Exception ex)
{
result.Status = PushHubNotificationResultType.Error;
result.Error = ex.Message;
result.Exception = ex;
}
return result;
}
public async Task<PushHubNotificationResult> SendPushMessageAsync(string userId, string message)
{
PushHubNotificationResult result = new PushHubNotificationResult();
// EnableTestSend see: https://azure.microsoft.com/en-us/documentation/articles/notification-hubs-push-notification-fixer/#self-diagnose-tips
// Create a new Notification Hub client.
Microsoft.Azure.NotificationHubs.NotificationHubClient hub =
Microsoft.Azure.NotificationHubs.NotificationHubClient.CreateClientFromConnectionString(NotificationHub, NotificationHubName);
// Sending the message so that all template registrations that contain "messageParam"
// will receive the notifications. This includes APNS, GCM, WNS, and MPNS template registrations.
Dictionary<string, string> templateParams = new Dictionary<string, string>();
templateParams["messageParam"] = message;
string userTag = "_UserId:" + userId; // That line sets the IMEI or SerialNo (WLAN only device) == userId to which the push message is sent
try
{
// Send the push notification and log the results.
NotificationOutcome outcome = await hub.SendTemplateNotificationAsync(templateParams, userTag);
result.Status = PushHubNotificationResultType.Success;
foreach (RegistrationResult hubResult in outcome.Results)
{
result.PushNotificationHub = hubResult.ApplicationPlatform;
result.RegistrationId = hubResult.RegistrationId;
result.Outcome = hubResult.Outcome;
}
}
catch (System.Exception ex)
{
result.Status = PushHubNotificationResultType.Error;
result.Error = ex.Message;
result.Exception = ex;
}
return result;
}
thanks for any advice,
Eric
If you want to use sync-over-async, it's very important that you use ConfigureAwait(false) in your async code, otherwise you are very likely to get a deadlock.
NotificationOutcome outcome =
await hub.SendTemplateNotificationAsync(templateParams, userTag).ConfigureAwait(false);
The async method already converts exceptions to PushHubNotificationResultType.Error, why does the sync version do it too?
I have a the following controller method
public async Task<ActionResult> SendToAllUsers(SentMailToAllUsersModel model)
{
if (ModelState.IsValid)
{
var mail = MailService.SendMailToAllUsers(model.Body, model.Title);
await mail;
}
return View(model);
}
Which is calling this method on the mail service
public Task SendMailToAllUsers(string content, string title)
{
var users = UserService.GetAllUsers();
var mailTemplates = users.Result.AsParallel().Select(user =>
{
var mailTemplate = new MastersMailTemplate(user);
mailTemplate.HtmlEmailTemplate = content;
mailTemplate.Subject = title;
mailTemplate.From = _fromEmail;
return Task.Factory.StartNew(() => MailProvider.SendEmailAsync(mailTemplate.CreateMailMessage(), new ResultDescription()).ConfigureAwait(false));
}).ToArray();
return Task.WhenAll(mailTemplates);
}
This method is triggering the mail provider that executes this method:
public Task<IResultDescription> SendEmailAsync(MailMessage message, IResultDescription rd)
{
// Create our SMTP Client
SmtpClient client = new SmtpClient();
client.Host = SmtpServer;
client.Port = SmtpServerPort;
client.Credentials = new NetworkCredential(SmtpServerUsername, SmtpServerPassword);
client.EnableSsl = true;
if (AppSettings.IsInTestMode)
{
Log.Info("Test mode check: Removing all emails and replace to test");
message.To.Clear();
foreach (var email in AppSettings.DefaultTestEmail)
{
message.To.Add(new MailAddress(email));
}
}
client.Timeout = 10;
Log.Info("Sending Email to" + message.To.FirstOrDefault());
var task = Task.Run(async () =>
{
try{
client.SendCompleted += (s, e) =>
{
client.Dispose();
message.Dispose();
};
await client.SendAsync(message);
rd.Success = true;
return rd;
}
catch (Exception e)
{
Log.Error("Email not send");
rd.Success = false;
if (rd.Errors == null)
{
IList<string> errors = new List<string>();
errors.Add(e.Message);
rd.Errors = errors;
}
else
{
rd.Errors.Add(e.Message);
}
return rd;
}
});
return task;
}
The problem is that the result view is returned before any mails where sent.
The controller is not waiting untill all mails are sent.
How can I make sure that the controller only continues execution when all tasks in the mail service are completed?
As a general rule, do not use Task.Run, Task.Factory.StartNew, Parallel, or PLINQ on ASP.NET. There is always a better way. In this case, just use async and await:
public async Task SendMailToAllUsersAsync(string content, string title)
{
var users = await UserService.GetAllUsersAsync();
var mailTemplates = users.AsParallel().Select(user =>
{
var mailTemplate = new MastersMailTemplate(user);
mailTemplate.HtmlEmailTemplate = content;
mailTemplate.Subject = title;
mailTemplate.From = _fromEmail;
return MailProvider.SendEmailAsync(mailTemplate.CreateMailMessage());
}).ToArray();
return await Task.WhenAll(mailTemplates);
}
Similarly for your inner method:
public Task<IResultDescription> SendEmailAsync(MailMessage message, IResultDescription rd)
{
using (SmtpClient client = new SmtpClient())
using (message)
{
client.Host = SmtpServer;
client.Port = SmtpServerPort;
client.Credentials = new NetworkCredential(SmtpServerUsername, SmtpServerPassword);
client.EnableSsl = true;
if (AppSettings.IsInTestMode)
{
Log.Info("Test mode check: Removing all emails and replace to test");
message.To.Clear();
foreach (var email in AppSettings.DefaultTestEmail)
{
message.To.Add(new MailAddress(email));
}
}
client.Timeout = 10;
Log.Info("Sending Email to" + message.To.FirstOrDefault());
try
{
await client.SendAsync(message);
rd.Success = true;
}
catch (Exception e)
{
Log.Error("Email not send");
rd.Success = false;
if (rd.Errors == null)
{
IList<string> errors = new List<string>();
errors.Add(e.Message);
rd.Errors = errors;
}
else
{
rd.Errors.Add(e.Message);
}
}
return rd;
}
}
Remember, async makes things easy. If the async code is excessively complicated, check for A Better Way. I have an async intro on my blog that you may find useful.
I think the problem is in your SendMailToAllUsers method. I think you need to await the MailProvider.SendEmailAsync call. If you don't do this, the task started by Task.Factory.StartNew will be considered complete as soon as that method executes. Because the method is actually asynchronous it only kicks off the operation, it doesn't wait for its completion. If you await the result that should fix the problem.
Change your code to:
public Task SendMailToAllUsers(string content, string title)
{
var users = UserService.GetAllUsers();
var mailTemplates = users.Result.AsParallel().Select(user =>
{
var mailTemplate = new MastersMailTemplate(user);
mailTemplate.HtmlEmailTemplate = content;
mailTemplate.Subject = title;
mailTemplate.From = _fromEmail;
// Await the result of the lambda expression
return Task.Factory.StartNew(() => await MailProvider.SendEmailAsync(mailTemplate.CreateMailMessage(), new ResultDescription()).ConfigureAwait(false));
}).ToArray();
return Task.WhenAll(mailTemplates);
}
I have a problem with receiving messages from a queue i have set up in azure.
I have done this successfully using the same code before but now i just get null when i try to fetch messages.
When i view the queue in azure management console i clearly see that the queue contains 5 messages.
Here is the code:
ServiceBus SB = new ServiceBus();
Microsoft.ServiceBus.Messaging.BrokeredMessage message;
while (true)
{
message = SB.ReceiveMessage("orders");
if (message == null)
{
break;
}
Procurement.Order order = message.GetBody<Procurement.Order>();
order.id = Guid.NewGuid().ToString();
order.remindercount = 0;
using (DbManager db = new DbManager())
{
if (db.SetSpCommand("CreateOrderHead",
db.Parameter("#companyId", order.companyId),
db.Parameter("#orderId", order.orderId),
db.Parameter("#suppliercode", order.suppliercode),
db.Parameter("#supplierorderId", order.supplierorderId),
db.Parameter("#orderdate", order.orderdate),
db.Parameter("#desireddate", order.desireddate),
db.Parameter("#ordertext", order.ordertext),
db.Parameter("#name", order.name),
db.Parameter("#street", order.street),
db.Parameter("#zip", order.zip),
db.Parameter("#city", order.city),
db.Parameter("#country", order.country),
db.Parameter("#countrycode", order.countrycode),
db.Parameter("#deliveryterms", order.deliveryterms),
db.Parameter("#reference", order.reference),
db.Parameter("#deliveryinstruction", order.deliveryinstruction),
db.Parameter("#id", order.id),
db.Parameter("#partycode", order.partyCode)
).ExecuteNonQuery() == 1)
{
message.Complete();
message = null;
}
db.SetSpCommand("DeleteOrderRows",
db.Parameter("#orderid", order.orderId),
db.Parameter("#companyId", order.companyId)
).ExecuteNonQuery();
foreach (Procurement.Orderrow r in order.Orderrows)
{
db.SetSpCommand("CreateOrderRow",
db.Parameter("#companyId", r.companyId),
db.Parameter("#orderId", r.orderId),
db.Parameter("#orderrowId", r.orderrowId),
db.Parameter("#itemId", r.itemId),
db.Parameter("#itemdesc", r.itemdesc),
db.Parameter("#orderqty", r.orderqty),
db.Parameter("#desireddate", r.desireddate),
db.Parameter("#rowtext", r.rowtext),
db.Parameter("#supplieritemId", r.supplieritemId),
db.Parameter("#unit", r.unit),
db.Parameter("#id", order.id),
db.Parameter("#unitprice", r.unitprice),
db.Parameter("#rowprice", r.rowprice)
).ExecuteNonQuery();
}
}
}
Thread.Sleep(new TimeSpan(0, 1, 0));
And this is the ServiceBus-class:
public class ServiceBus
{
TokenProvider TokenProvider;
MessagingFactory Factory;
public ServiceBus()
{
TokenProvider = TokenProvider.CreateSharedSecretTokenProvider(GetIssuerName(), GetSecret());
Factory = MessagingFactory.Create(
GetURINameSpace(),
TokenProvider
);
}
public void SendMessage(string queue, BrokeredMessage message)
{
var client = Factory.CreateQueueClient(queue);
client.Send(message);
}
public BrokeredMessage ReceiveMessage(string queue)
{
var client = Factory.CreateQueueClient(queue, ReceiveMode.ReceiveAndDelete);
BrokeredMessage message = client.Receive();
return message;
}
private static Uri GetURINameSpace()
{
return ServiceBusEnvironment.CreateServiceUri("sb", GetNamespace(), string.Empty);
}
private static string GetNamespace()
{
return "Namespace i have verified its the right one";
}
private static string GetIssuerName()
{
return "Issuer i have verified its the right one";
}
private static string GetSecret()
{
return "Key i have verified its the right one";
}
}
I think this should be pretty straight forward but i cant find out what im doing wrong.
Its probably something small that im missing...
Anyways, thanks in advance!
Those BrokeredMessages you see in your SubcriptionDescription.MessageCount are not just regular messages but also the count of the messages in the $DeadLetterQueue-sub queue!!!
Use this code snippet to retrieve all messages from that sub-queue and print out their details. Rename [topic] and [subscription] to your actual ones:
MessagingFactory msgFactory = MessagingFactory.Create(_uri, _tokenProvider);
MessageReceiver msgReceiver = msgFactory.CreateMessageReceiver("[topic]/subscriptions/[subscription]/$DeadLetterQueue", ReceiveMode.PeekLock);
while (true)
{
BrokeredMessage msg = msgReceiver.Receive();
if (msg != null)
{
Console.WriteLine("Deadlettered message.");
Console.WriteLine("MessageId: {0}", msg.MessageId);
Console.WriteLine("DeliveryCount: {0}", msg.DeliveryCount);
Console.WriteLine("EnqueuedTimeUtc: {0}", msg.EnqueuedTimeUtc);
Console.WriteLine("Size: {0} bytes", msg.Size);
Console.WriteLine("DeadLetterReason: {0}",
msg.Properties["DeadLetterReason"]);
Console.WriteLine("DeadLetterErrorDescription: {0}",
msg.Properties["DeadLetterErrorDescription"]);
Console.WriteLine();
msg.Complete();
}
}
The solution to this problem was either a bug in azure management-portal making it show the wrong number of messages on the queue or the messages somehow got flagged so that they would not be read.
In other words it worked all along, i just had to add some new messages to the queue.