MessageQueue and Async / Await

荒凉一梦 提交于 2019-12-03 06:02:46

As Stephen writes, async doesn't run your code in a thread. Fortunately, you can use TaskFactory.FromAsync with MessageQueue.BeginReceive/MessageQueue.EndReceive to receive messages asynchronously:

    private  async Task<Message> MyAsyncReceive()
    {
        MessageQueue queue=new MessageQueue();
        ...
        var message=await Task.Factory.FromAsync<Message>(
                           queue.BeginReceive(),
                           queue.EndReceive);

        return message;

    }

You should note though that there ISN'T a version of BeginReceive that uses a Transaction. From BeginReceive's docs:

Do not use the asynchronous call BeginReceive with transactions. If you want to perform a transactional asynchronous operation, call BeginPeek, and put the transaction and the (synchronous) Receive method within the event handler you create for the peek operation.

This makes sense as there is no guarantee how long you have to wait for a response or which thread will eventually handle the completed call.

To use transactions you would write something like this:

    private  async Task<Message> MyAsyncReceive()
    {
        var queue=new MessageQueue();

        var message=await Task.Factory.FromAsync<Message>(queue.BeginPeek(),queue.EndPeek);

        using (var tx = new MessageQueueTransaction())
        {
            tx.Begin();

            //Someone may have taken the last message, don't wait forever
            //Use a smaller timeout if the queue is local
            message=queue.Receive(TimeSpan.FromSeconds(1), tx);
            //Process the results inside a transaction
            tx.Commit();
        }
        return message;
    }

UPDATE

As Rob pointed out, the original code used the message returned from Peek, which may have changed between Peek and Receive. In this case the second message will be lost.

There's still a chance of blocking though, if another client reads the last message in the queue. To prevent this, Receive should have a small timeout.

async does not run your code on a background thread. Your code above should have caused a compiler warning that tells you that your method will run synchronously.

If you want to execute a method on a background thread, use TaskEx.Run:

public void ProcessMessages()
{
  ...
}

TaskEx.Run(() => ProcessMessages());
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!