进行事务处理时消息未到达 MSMQ

Posted

技术标签:

【中文标题】进行事务处理时消息未到达 MSMQ【英文标题】:Message does not reach MSMQ when made transactional 【发布时间】:2012-04-12 07:13:27 【问题描述】:

我在本地计算机上创建了一个私有 MSMQ。我正在使用以下 C# 代码向队列发送消息。当我将队列更改为事务性时,消息没有到达 MSMQ。但是,Send 方法中没有抛出异常。我需要进行哪些更改才能使其正常工作?

using System;
using System.Messaging;
using System.Data;

public partial class _Default : System.Web.UI.Page

    //Sharing violation resulted from queue being open already for exclusive receive.
    MessageQueue helpRequestQueue = new MessageQueue(@".\Private$\MyPrivateQueue", false);
    protected void Page_Load(object sender, EventArgs e)
       
        bool isTransactionalQueue = false;    
        if (!System.Messaging.MessageQueue.Exists(@".\Private$\MyPrivateQueue"))    
            
            System.Messaging.MessageQueue.Create(@".\Private$\MyPrivateQueue", isTransactionalQueue);    
            
        SendMessage();    
        GetAllMessages();    
    


    private void SendMessage()    
        
        System.Messaging.Message theMessage = new System.Messaging.Message("TimeNow is "+DateTime.Now.ToString());

        theMessage.Label = "Lijo " + DateTime.Now.ToString();

        theMessage.Priority = System.Messaging.MessagePriority.Normal;

        helpRequestQueue.Send(theMessage);    

    


    private void GetAllMessages()   
        
        DataTable messageTable = new DataTable();    
        messageTable.Columns.Add("Label");    
        messageTable.Columns.Add("Body");        


        //Set Message Filters    
        MessagePropertyFilter filter = new MessagePropertyFilter();    
        filter.ClearAll();    
        filter.Body = true;    
        filter.Label = true;    
        filter.Priority = true;
        helpRequestQueue.MessageReadPropertyFilter = filter;

        //Get All Messages    
        System.Messaging.Message[] messages = helpRequestQueue.GetAllMessages();    
        System.Messaging.XmlMessageFormatter stringFormatter = new System.Messaging.XmlMessageFormatter(new string[]  "System.String" );


        for (int index = 0; index < messages.Length; index++)    
            
            string test = System.Convert.ToString(messages[index].Priority);
            messages[index].Formatter = stringFormatter;    
            messageTable.Rows.Add(new string[] messages[index].Label,messages[index].Body.ToString() );

        


        Gridview1.DataSource = messageTable;    
        Gridview1.DataBind();    
        

    private void ReceiveAndProcess()    
    



               

【问题讨论】:

我的猜测是事务需要被提交。 msdn.microsoft.com/en-us/library/windows/desktop/… 【参考方案1】:

事务不适用于non-transactional queues。如果您使用这种形式:

using(MessageQueueTransaction tx = new MessageQueueTransaction())

    tx.Begin();
    queue.Send(message, tx);
    tx.Commit();

在非事务性队列上,消息似乎丢失了,不会引发异常。您可以在消息队列管理控制台的队列属性中检查队列是否是事务性的。

最好用

queue.Send(message, MessageQueueTransactionType.Automatic)

【讨论】:

【参考方案2】:

对于您创建为事务性的队列,您必须使用包含 MessageQueueTransactionType 参数的 Send() 版本。最大的挫败感是它不会像您所看到的那样抛出任何异常或错误,但是消息永远不会出现。

所以,在你的代码中,改变:

helpRequestQueue.Send(theMessage); 

helpRequestQueue.Send(theMessage, MessageQueueTransactionType.Single); 

编辑:我的回答只是大卫的另一种方式。

【讨论】:

【参考方案3】:

队列和消息类型必须相同 - 在这种情况下是事务性的。 如果您没有收到异常,请在您的代码中使用负源日志来帮助查找丢失的消息。

【讨论】:

【参考方案4】:

根据MSDN,这是使用事务性 MSMQ 队列的示例:

    // Connect to a transactional queue on the local computer.
    MessageQueue queue = new MessageQueue(".\\exampleTransQueue");

    // Create a new message.
    Message msg = new Message("Example Message Body");

    // Create a message queuing transaction.
    MessageQueueTransaction transaction = new MessageQueueTransaction();

    try
    
        // Begin a transaction.
        transaction.Begin();

        // Send the message to the queue.
        queue.Send(msg, "Example Message Label", transaction);

        // Commit the transaction.
        transaction.Commit();
    
    catch(System.Exception e)
    
        // Cancel the transaction.
        transaction.Abort();

        // Propagate the exception.
        throw e;
    
    finally
    
        // Dispose of the transaction object.
        transaction.Dispose();
    

您必须将其视为数据库事务——通过创建新的 MSMQ 事务开始事务,然后提交或中止操作。

【讨论】:

以上是关于进行事务处理时消息未到达 MSMQ的主要内容,如果未能解决你的问题,请参考以下文章

消息队列MSMQ的使用

我应该使用 MSMQ 还是 SQL Service Broker 进行事务处理?

RabbitMQ 事务&生产者确认

如何在使用 WCF 的事务性 MSMQ 中将消息显式标记为中毒

分布式事务之可靠消息

MSMQ 接收事务 - 回滚不再使消息可用