C# Deadlock in Named Pipe - c#

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..

Related

Getting error "A MessageReceived handler is blocking the gateway task." In Spambot Discord C#

In this command, I want the user to input an integer, and then the string he/she wants to spam. After it asks for the string, I get an error in the CMD saying "A MessageReceived handler is blocking the gateway task."
For example the user could say
!spamstring 29
then
Get on CSGO!
The bot will spam Get on CSGO! 29 times. Here's the code:
[Command("spamstring")]
public async Task spamstring([Remainder] int times)
{
var user = Context.Client.GetUser(Context.User.Id);
if (times > 68)
{
await Context.Channel.SendMessageAsync("*YOU CANNOT GO OVER 69* :eggplant: ");
}
else
{
await Context.Channel.SendMessageAsync("You chose to spam " + times + " times, what do you want to spam?");
string message = Console.ReadLine();
if (message.Contains("#everyone"))
{
await Context.Channel.SendMessageAsync("Do not mention everyone!");
}
else
{
await Context.Channel.SendMessageAsync(":fire: *SPAMMING* :fire: ");
for (int i = 0; i < times; i++)
{
await Context.Channel.SendMessageAsync(message);
System.Threading.Thread.Sleep(1500);
}
}
}
}
I kept the fundamentals but when trying to debug his code, this particular command broke everything so I just rewrote it. I started off by changing how he took in the "message" in the public task. He tries using a string called later in the function which wouldn't work and trying to read the console. This wouldn't work because Discord won't log anything until it's recognized as a command so I changed that to a parameter. From there it's simple, instead of using Context,Channel.SendMessageAsync I simply did ReplyAsync. I also added an Alias. Also instead of using message.Contains() which wouldn't work, I used an if statement with if (messageToString() == "#everyone").
[Command("spamstring")]
[Alias("sp", "spamming", "juanspam")]
public async Task spamming(int times, string message)
{
//try and refrain from BIG if statements like this
if (times > 68)
{
await Context.Message.DeleteAsync();
await ReplyAsync(Context.User.Mention + " *YOU CANNOT GO OVER 69* :eggplant:");
}
else
{
await Context.Message.DeleteAsync();
await ReplyAsync("You chose to spam " + times + " times, what do you want to spam?");
//NEW IF
if (message.ToString() == "#everyone")
{
await ReplyAsync("Don't do that bitch. You deserve to be spammed for that!");
}
else
{
await Context.Channel.SendMessageAsync(":fire: *SPAMMING* :fire: ");
//spam loop
for (int i = 0; i < times; i++)
{
await Context.Channel.SendMessageAsync(message);
System.Threading.Thread.Sleep(1500);
}
}
}
//END BIG OF
}
}
}

Socket not reading all the packets that arrive

I am working on a C# TCP client and monitoring my packets using Microsoft Network Monitor. There is a server that's basically a black box sends an N amount of packets (right now it's in the order of 10-20) with a delay of 0,1 ms to 1 ms between each of them and the next one.
The packets that are read by my client are in order and of course most arrive in larger chunks than appear on Network Monitor since TCP receives the stream. My problem is some packets fail to arrive (I did check the previous chunk of information to make sure it's not there. They aren't stored in the wrong order either.).
So is it possible that my client is missing some of the information somehow? Are the packets being sent too frequently? Sadly I cannot tamper with their frequency. I add here some of my code, if you could enlighten me as to why packets that arrive are not read and how to solve this I would be most grateful.
This is where I first call BeginReceive:
private static void AcceptCallback(IAsyncResult result)
{
ConnectionInfo connection = new ConnectionInfo();
MensajeRecibido msj = new MensajeRecibido();
try
{
// Finish Accept
Socket s = (Socket)result.AsyncState;
connection.Socket = s.EndAccept(result);
msj.workSocket = connection.Socket;
connection.Socket.Blocking = false;
connection.Buffer = new byte[255];
lock (connections) connections.Add(connection);
// Start Receive
connection.Socket.BeginReceive(msj.buffer, 0,
msj.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), msj);
// Start new Accept
serverSocket.BeginAccept(new AsyncCallback(AcceptCallback), result.AsyncState);
}
catch (SocketException exc)
{
//Log here
}
catch (Exception exc)
{
//Log here
}
}
This is the callback:
private async static void ReceiveCallback(IAsyncResult result)
{
MensajeRecibido mensaje = new MensajeRecibido();
mensaje = (MensajeRecibido)result.AsyncState;
try
{
mensaje.workSocket.EndReceive(result);
mensaje.EstaCompleto();
mensaje.workSocket.BeginReceive(mensaje.buffer, 0,
mensaje.buffer.Length, SocketFlags.None,
new AsyncCallback(ReceiveCallback), mensaje);
}
catch (SocketException)
{
//Log
}
catch (Exception)
{
//Log
}
}
And this is the method EstaCompleto() which basically converts the message and adds it to a list. (It returns true or false because it's actually meant to go in an if clause but until I get rid of this problem that really serves no purpose)
public bool EstaCompleto()
{
MensajeActual = Destuffing(ByteToFrame_Decoder(buffer)); //This translates the message to an understandable string
Mensajes.Enqueue(MensajeActual);
if(MensajeActual.Contains("<ETX>"))
{
return true;
}
else return false;
}
Edit 25/3/15:
Here's the rest of the class MensajeRecibido.
public class MensajeRecibido
{
public Socket workSocket = null;
// Size of receive buffer.
public const int BufferSize = 25500;
// Receive buffer.
public byte[] buffer = new byte[BufferSize];
public string UltimoMensajeLeido = "0";
public string MensajeActual = "0";
public Queue<string> Mensajes = new Queue<string>();
public IPAddress IPRack;
//*******************************************************************
public bool EstaCompleto()
///See code in the previous sample
//*******************************************************************
public string ByteToFrame_Decoder(byte[] frame)
{
string answer = null;
UTF8Encoding ObjDecoder = new System.Text.UTF8Encoding();
char[] array_chares = new char[frame.Length];
string msj_neg = null;
string titlemsg = "Atención";
try
{
int cant = ObjDecoder.GetChars(frame, 0, frame.Length, array_chares, 0);
}
catch (EncoderFallbackException EncFbackEx)
{
msj_neg = "No hay comunicación";
// System.Windows.Forms.MessageBox.Show(msj_neg, titlemsg, MessageBoxButtons.OK, MessageBoxIcon.Exclamation);
}
answer = decode_string(array_chares);
return answer;
} // fin método ByteToFrame_Decoder()
//*******************************************************************
public string Destuffing(string msjstuff)
{
string destuffed = null;
string matched = null;
string original = null;
int largo = msjstuff.Length;
for (int i = 0; i < (largo - 1); i++)
{
matched = msjstuff.Substring(i, 2);
original = msjstuff.Substring(i, 1);
if (original != " ")
{
switch (matched)
{
case "EX":
{ original = "D"; i++; } break;
case "ex":
{ original = "d"; i++; } break;
case "EE":
{ original = "E"; i++; } break;
case "ee":
{ original = "e"; i++; } break;
case " ":
{ original = ""; i += 2; } break;
}
destuffed = destuffed + original;
}
else
{
i++;
}
}
destuffed = destuffed + ">";
return destuffed;
} //fin método Destuffing()
//*******************************************************************
public static string decode_string(char[] ArrChar)
{
string text = null;
string reply = null;
foreach (char letter in ArrChar)
{
int value = Convert.ToInt32(letter);
string hexOutput = String.Format("{0:X}", value); // Convert the decimal value to a hexadecimal value in string form.
switch (hexOutput)
{
case "20":
text = " ";
break;
case "1":
text = "<SOH>";
break;
case "2":
text = "<STX>";
break;
case "3":
text = "<ETX>";
break;
case "4":
text = "<EOT>";
reply = reply + text;
goto Finish;
case "5":
text = "<ENQ>";
break;
case "6":
text = "<ACK>";
break;
case "15":
text = "<NAK>";
break;
case "17":
text = "<ETB>";
break;
case "1E":
text = "<RS>";
break;
/*case "23":
text = "#";
break;
case "24":
text = "$";
break;
case "26":
text = "&";
break;*/
default:
text = letter.ToString();
break;
}
reply = reply + text;
}
Finish: ; //salimos del foreach
return reply;
} //fin método decode_string()
//*******************************************************************
}
Without a good, minimal, complete code example that reliably demonstrates the problem, it's impossible to provide an exact fix for the bug.
However, from this statement in your ReceiveCallback() method, it's clear what the problem is:
mensaje.workSocket.EndReceive(result);
The EndReceive() method returns a byte count for a reason: there is no guarantee of the number of bytes that will be received.
Network programming novices generally complain about two different behaviors:
Their code only receives part of a "packet" (or "message", or similar terminology).
Their code fails to receive some of the "packets" which were sent.
Both problems stem from a single source: the failure to understand that in the TCP protocol, there is no such thing as a "packet".
It's up to the application to define a message boundary. All that TCP gives you is a guarantee that if the bytes sent are in fact received, they will be received in the same order in which they were sent, and if any given byte is received, all of the previously sent bytes were also received (i.e. no gaps in the data).
Problem #1 above happens when TCP delivers only part of what the novice programmer sent as a "packet". This is perfectly legal behavior on TCP's part, and it's up to the application to keep track of the data received so far and to figure out when it's received a whole "packet".
Problem #2 (which is what you're experiencing) happens when TCP delivers two or more "packets" in a single receive operation. Again, this is perfectly legal on TCP's part, and it's up to the application to process the received data and identify where one "packet" ends and the next begins.
The first step to doing all of this correctly is to actually copy the return value of the EndReceive() method to a variable, and then to use that value as part of processing the received data. Since your code example doesn't save the value anywhere, or even look at it at all, I can guarantee that you aren't correctly handling the "packet" boundaries in your data.
How should you handle those boundaries? I have no idea. It depends on how you are sending the data, and how you want to process the results. Without a complete code example (as described in the link I provided above), it's not possible to address that. Do note however that there are a large number of examples out there for how to do it correctly. Hopefully now that you know what to look for, you will be able to come up with a fix yourself. If not, feel free to create a good code example and post a new question asking for help with that.

First time creating a method that uses parallel linq and getting out of memory exception

I wrote a method to download data from the internet and save it to my database. I wrote this using PLINQ to take advantage of my multi-core processor and because it is downloading thousands of different files in a very short period of time. I have added comments below in my code to show where it stops but the program just sits there and after awhile, I get an out of memory exception. This being my first time using TPL and PLINQ, I'm extremely confused so I could really use some advice on what to do to fix this.
UPDATE: I found out that I was getting a webexception constantly because the webclient was timing out. I fixed this by increasing the max amount of connections according to this answer here. I was then getting exceptions for the connection not opening and I fixed it by using this answer here. I'm now getting connection timeout errors for the database even though it is a local sql server. I still haven't been able to get any of my code to run so I could totally use some advice
static void Main(string[] args)
{
try
{
while (true)
{
// start the download process for market info
startDownload();
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
public static void startDownload()
{
DateTime currentDay = DateTime.Now;
List<Task> taskList = new List<Task>();
if (Helper.holidays.Contains(currentDay) == false)
{
List<string> markets = new List<string>() { "amex", "nasdaq", "nyse", "global" };
Parallel.ForEach(markets, market =>
{
Downloads.startInitialMarketSymbolsDownload(market);
}
);
Console.WriteLine("All downloads finished!");
}
// wait 24 hours before you do this again
Task.Delay(TimeSpan.FromHours(24)).Wait();
}
public static void startInitialMarketSymbolsDownload(string market)
{
try
{
List<string> symbolList = new List<string>();
symbolList = Helper.getStockSymbols(market);
var historicalGroups = symbolList.AsParallel().Select((x, i) => new { x, i })
.GroupBy(x => x.i / 100)
.Select(g => g.Select(x => x.x).ToArray());
historicalGroups.AsParallel().ForAll(g => getHistoricalStockData(g, market));
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(ex.StackTrace);
}
}
public static void getHistoricalStockData(string[] symbols, string market)
{
// download data for list of symbols and then upload to db tables
Uri uri;
string url, line;
decimal open = 0, high = 0, low = 0, close = 0, adjClose = 0;
DateTime date;
Int64 volume = 0;
string[] lineArray;
List<string> symbolError = new List<string>();
Dictionary<string, string> badNameError = new Dictionary<string, string>();
Parallel.ForEach(symbols, symbol =>
{
url = "http://ichart.finance.yahoo.com/table.csv?s=" + symbol + "&a=00&b=1&c=1900&d=" + (DateTime.Now.Month - 1) + "&e=" + DateTime.Now.Day + "&f=" + DateTime.Now.Year + "&g=d&ignore=.csv";
uri = new Uri(url);
using (dbEntities entity = new dbEntities())
using (WebClient client = new WebClient())
using (Stream stream = client.OpenRead(uri))
using (StreamReader reader = new StreamReader(stream))
{
while (reader.EndOfStream == false)
{
line = reader.ReadLine();
lineArray = line.Split(',');
// if it isn't the very first line
if (lineArray[0] != "Date")
{
// set the data for each array here
date = Helper.parseDateTime(lineArray[0]);
open = Helper.parseDecimal(lineArray[1]);
high = Helper.parseDecimal(lineArray[2]);
low = Helper.parseDecimal(lineArray[3]);
close = Helper.parseDecimal(lineArray[4]);
volume = Helper.parseInt(lineArray[5]);
adjClose = Helper.parseDecimal(lineArray[6]);
switch (market)
{
case "nasdaq":
DailyNasdaqData nasdaqData = new DailyNasdaqData();
var nasdaqQuery = from r in entity.DailyNasdaqDatas.AsParallel().AsEnumerable()
where r.Date == date
select new StockData { Close = r.AdjustedClose };
List<StockData> nasdaqResult = nasdaqQuery.AsParallel().ToList(); // hits this line
break;
default:
break;
}
}
}
// now save everything
entity.SaveChanges();
}
}
);
}
Async lambdas work like async methods in one regard: They do not complete synchronously but they return a Task. In your parallel loop you are simply generating tasks as fast as you can. Those tasks hold onto memory and other resources such as DB connections.
The simplest fix is probably to just use synchronous database commits. This will not result in a loss of throughput because the database cannot deal with high amounts of concurrent DML anyway.

Azure ServiceBus returns null on Client.Receive()

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.

Is there a way to check how many messages are in a MSMQ Queue?

I was wondering if there is a way to programmatically check how many messages are in a private or public MSMQ using C#? I have code that checks if a queue is empty or not using the peek method wrapped in a try/catch, but I've never seen anything about showing the number of messages in the queue. This would be very helpful for monitoring if a queue is getting backed up.
You can read the Performance Counter value for the queue directly from .NET:
using System.Diagnostics;
// ...
var queueCounter = new PerformanceCounter(
"MSMQ Queue",
"Messages in Queue",
#"machinename\private$\testqueue2");
Console.WriteLine( "Queue contains {0} messages",
queueCounter.NextValue().ToString());
There is no API available, but you can use GetMessageEnumerator2 which is fast enough. Sample:
MessageQueue q = new MessageQueue(...);
int count = q.Count();
Implementation
public static class MsmqEx
{
public static int Count(this MessageQueue queue)
{
int count = 0;
var enumerator = queue.GetMessageEnumerator2();
while (enumerator.MoveNext())
count++;
return count;
}
}
I also tried other options, but each has some downsides
Performance counter may throw exception "Instance '...' does not exist in the specified Category."
Reading all messages and then taking count is really slow, it also removes the messages from queue
There seems to be a problem with Peek method which throws an exception
If you need a fast method (25k calls/second on my box), I recommend Ayende's version based on MQMgmtGetInfo() and PROPID_MGMT_QUEUE_MESSAGE_COUNT:
for C#
https://github.com/hibernating-rhinos/rhino-esb/blob/master/Rhino.ServiceBus/Msmq/MsmqExtensions.cs
for VB
https://gist.github.com/Lercher/5e1af6a2ba193b38be29
The origin was probably http://functionalflow.co.uk/blog/2008/08/27/counting-the-number-of-messages-in-a-message-queue-in/ but I'm not convinced that this implementation from 2008 works any more.
We use the MSMQ Interop. Depending on your needs you can probably simplify this:
public int? CountQueue(MessageQueue queue, bool isPrivate)
{
int? Result = null;
try
{
//MSMQ.MSMQManagement mgmt = new MSMQ.MSMQManagement();
var mgmt = new MSMQ.MSMQManagementClass();
try
{
String host = queue.MachineName;
Object hostObject = (Object)host;
String pathName = (isPrivate) ? queue.FormatName : null;
Object pathNameObject = (Object)pathName;
String formatName = (isPrivate) ? null : queue.Path;
Object formatNameObject = (Object)formatName;
mgmt.Init(ref hostObject, ref formatNameObject, ref pathNameObject);
Result = mgmt.MessageCount;
}
finally
{
mgmt = null;
}
}
catch (Exception exc)
{
if (!exc.Message.Equals("Exception from HRESULT: 0xC00E0004", StringComparison.InvariantCultureIgnoreCase))
{
if (log.IsErrorEnabled) { log.Error("Error in CountQueue(). Queue was [" + queue.MachineName + "\\" + queue.QueueName + "]", exc); }
}
Result = null;
}
return Result;
}
//here queue is msmq queue which you have to find count.
int index = 0;
MSMQManagement msmq = new MSMQManagement() ;
object machine = queue.MachineName;
object path = null;
object formate=queue.FormatName;
msmq.Init(ref machine, ref path,ref formate);
long count = msmq.MessageCount();
This is faster than you selected one.
You get MSMQManagement class refferance inside "C:\Program Files (x86)\Microsoft SDKs\Windows" just brows in this address you will get it. for more details you can visit http://msdn.microsoft.com/en-us/library/ms711378%28VS.85%29.aspx.
I had real trouble getting the accepted answer working because of the xxx does not exist in the specified Category error. None of the solutions above worked for me.
However, simply specifying the machine name as below seems to fix it.
private long GetQueueCount()
{
try
{
var queueCounter = new PerformanceCounter("MSMQ Queue", "Messages in Queue", #"machineName\private$\stream")
{
MachineName = "machineName"
};
return (long)queueCounter.NextValue();
}
catch (Exception e)
{
return 0;
}
}
The fastest method I have found to retrieve a message queue count is to use the peek method from the following site:
protected Message PeekWithoutTimeout(MessageQueue q, Cursor cursor, PeekAction action)
{
Message ret = null;
try
{
ret = q.Peek(new TimeSpan(1), cursor, action);
}
catch (MessageQueueException mqe)
{
if (!mqe.Message.ToLower().Contains("timeout"))
{
throw;
}
}
return ret;
}
protected int GetMessageCount(MessageQueue q)
{
int count = 0;
Cursor cursor = q.CreateCursor();
Message m = PeekWithoutTimeout(q, cursor, PeekAction.Current);
{
count = 1;
while ((m = PeekWithoutTimeout(q, cursor, PeekAction.Next)) != null)
{
count++;
}
}
return count;
}
This worked for me. Using a Enumarator to make sure the queue is empty first.
Dim qMsg As Message ' instance of the message to be picked
Dim privateQ As New MessageQueue(svrName & "\Private$\" & svrQName) 'variable svrnme = server name ; svrQName = Server Queue Name
privateQ.Formatter = New XmlMessageFormatter(New Type() {GetType(String)}) 'Formating the message to be readable the body tyep
Dim t As MessageEnumerator 'declared a enumarater to enable to count the queue
t = privateQ.GetMessageEnumerator2() 'counts the queues
If t.MoveNext() = True Then 'check whether the queue is empty before reading message. otherwise it will wait forever
qMsg = privateQ.Receive
Return qMsg.Body.ToString
End If
If you want a Count of a private queue, you can do this using WMI.
This is the code for this:
// You can change this query to a more specific queue name or to get all queues
private const string WmiQuery = #"SELECT Name,MessagesinQueue FROM Win32_PerfRawdata_MSMQ_MSMQQueue WHERE Name LIKE 'private%myqueue'";
public int GetCount()
{
using (ManagementObjectSearcher wmiSearch = new ManagementObjectSearcher(WmiQuery))
{
ManagementObjectCollection wmiCollection = wmiSearch.Get();
foreach (ManagementBaseObject wmiObject in wmiCollection)
{
foreach (PropertyData wmiProperty in wmiObject.Properties)
{
if (wmiProperty.Name.Equals("MessagesinQueue", StringComparison.InvariantCultureIgnoreCase))
{
return int.Parse(wmiProperty.Value.ToString());
}
}
}
}
}
Thanks to the Microsoft.Windows.Compatibility package this also works in netcore/netstandard.
The message count in the queue can be found using the following code.
MessageQueue messageQueue = new MessageQueue(".\\private$\\TestQueue");
var noOFMessages = messageQueue.GetAllMessages().LongCount();

Categories