Hi,
I have implemented a dispose pattern in a class model which uses MessageQueue. My class A where all objects from class B must register to contains a Dictionary with MessageQueue objects. This works all fine. Objects from class B can be collect by GC and the dispose pattern, which let each object from class B sent a last message during disposing and so on.
BUT! if the application shutdown the objects were collected in a strange order. For instance I can see in the debugger that the MessageQueue objects are disposed before the collection is disposed they contain to? And if the first MessageQueue object is disposed alle works fine (last message sent). but if the second MessageQueue object is disposed and will got to sent a last message I got the following exception:
{"Cannot access a disposed object.\r\nObject name: 'MQCacheableInfo'."}
at System.Messaging.MessageQueue.MQCacheableInfo.get_WriteHandle() at System.Messaging.MessageQueue.StaleSafeSendMessage(MQPROPS properties, IntPtr transaction) at System.Messaging.MessageQueue.SendInternal(Object obj, MessageQueueTransaction internalTransaction, MessageQueueTransactionType transactionType) at System.Messaging.MessageQueue.Send(Object obj) at Core.MQWriteQueue.SendMessage(XMLTelegram Telegram) at Core.MQManager.SendTelegram(String QueueName, XMLTelegram Telegram)
That works long time really fine in .Net 3.5 and since I go up to .NET 4.0 I get this error often I shutdown the application. Not always but very often.
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Messaging; using System.Threading; using System.Net; using SendTypes;
namespace Client { class Program { static void Main(string[] args) { MessageQueueClient Client1 = new MessageQueueClient("Client 1", "MyMessageQueue"); MessageQueueClient Client2 = new MessageQueueClient("Client 2", "MyMessageQueue"); MessageQueueClient Client3 = new MessageQueueClient("Client 3", "MyMessageQueue"); Client1.Start(); Client2.Start(); Client3.Start();
Console.WriteLine("Press Key to stop Client 1");
Console.ReadKey();
Client1.Stop();
Client1 = null;
//Client1 = null;
GC.Collect();
Console.WriteLine("Press Key to stop Client 2");
Console.ReadKey();
Client2.Stop();
Client2 = null;
//Client2 = null;
GC.Collect();
Console.WriteLine("Press Key to stop Client 3");
Console.ReadKey();
Client3.Stop();
Client3 = null;
//Client3 = null;
GC.Collect();
Console.WriteLine("Press Key to shutdown");
Console.ReadKey();
}
}
class MessageQueueClient
{
private MessageQueue m_Queue;
private Thread m_Thread;
private bool m_KeepRunning = false;
private string m_ClientName;
public MessageQueueClient(string Name, string QueueName)
{
m_ClientName = Name;
m_Queue = new MessageQueue("Formatname:DIRECT=OS:" + Dns.GetHostName() + "\\private$\\" + QueueName, true);
if (m_Queue.CanWrite)
m_KeepRunning = true;
}
~MessageQueueClient()
{
MyData data = new MyData() { Data = m_ClientName + " going home bye bye!" };
m_Queue.Send(new Message(data));
m_Queue = null;
Console.WriteLine(m_ClientName + " destroyed");
}
public void Start()
{
m_Thread = new Thread(new ThreadStart(() =>
{
while (m_KeepRunning)
{
try
{
// Read Telegram stream
MyData data = new MyData() { Data = m_ClientName + " is still here" };
m_Queue.Send(new Message(data));
this.m_Thread.Join(TimeSpan.FromSeconds(5));
}
catch (MessageQueueException ex)
{
if (ex.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
Console.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
}
}
Console.WriteLine(m_ClientName + " Thread Stopped");
}));
m_Thread.IsBackground = true;
m_Thread.Name = "SendThread:" + m_ClientName;
if (m_KeepRunning)
{
m_Thread.Start();
Console.WriteLine(m_ClientName + " startet");
}
else
Console.WriteLine(m_ClientName + " not startet");
}
public void Stop()
{
m_KeepRunning = false;
}
}
}
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Messaging; using System.Threading; using System.Net; using System.IO; using SendTypes;
namespace Server { class Program { static void Main(string[] args) { MessageQueueServer Server = new MessageQueueServer("MyMessageQueue"); Server.Start();
Console.ReadKey();
Server.Stop();
Console.ReadKey();
}
}
class MessageQueueServer
{
private MessageQueue m_Queue;
private Thread m_Thread;
private bool m_KeepRunning = false;
public MessageQueueServer(String Name)
{
string QueueName = Dns.GetHostName() + "\\private$\\" + Name;
if (!MessageQueue.Exists(QueueName))
{
MessageQueue queue = MessageQueue.Create(QueueName);
}
m_Queue = new MessageQueue(QueueName, true);
m_Queue.Formatter = new XmlMessageFormatter(new Type[] { typeof(MyData) });
if (m_Queue.CanRead)
m_KeepRunning = true;
}
public void Start()
{
m_Thread = new Thread(new ThreadStart(() =>
{
while (m_KeepRunning)
{
Message msg;
try
{
// Read Telegram stream
msg = m_Queue.Receive(TimeSpan.FromSeconds(15));
MyData data = (MyData) msg.Body;
Console.WriteLine(data.Data);
}
catch (MessageQueueException ex)
{
if (ex.MessageQueueErrorCode != MessageQueueErrorCode.IOTimeout)
Console.WriteLine(ex.Message + Environment.NewLine + ex.StackTrace);
}
}
}));
m_Thread.IsBackground = true;
m_Thread.Name = "ReceiveThread";
if (m_KeepRunning)
{
m_Thread.Start();
Console.WriteLine("Server startet");
}
else
Console.WriteLine("Server not startet");
}
public void Stop()
{
m_KeepRunning = false;
}
}
}
using System; using System.Collections.Generic; using System.Linq; using System.Text;
namespace SendTypes { public class MyData { public string Data { get; set; } } }
Thanks a lot
Mic