Ответ 1
Как пишет Стивен, async не запускает ваш код в потоке. К счастью, вы можете использовать TaskFactory.FromAsync с MessageQueue.BeginReceive/MessageQueue.EndReceive для получения сообщений асинхронно:
private async Task<Message> MyAsyncReceive()
{
MessageQueue queue=new MessageQueue();
...
var message=await Task.Factory.FromAsync<Message>(
queue.BeginReceive(),
queue.EndReceive);
return message;
}
Следует отметить, что нет версии BeginReceive, использующей транзакцию. Из документов BeginReceive:
Не используйте асинхронный вызов BeginReceive с транзакциями. Если вы хотите выполнить транзакционную асинхронную операцию, вызовите BeginPeek и поместите транзакцию и (синхронный) метод Receive в обработчик событий, который вы создаете для операции peek.
Это имеет смысл, поскольку нет никакой гарантии, сколько времени вам нужно ждать ответа или какой поток в конечном итоге будет обрабатывать завершенный вызов.
Чтобы использовать транзакции, вы должны написать что-то вроде этого:
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
Как заметил Роб, в исходном коде использовался message
, возвращенный из Peek
, который, возможно, изменился между Peek
и Receive
. В этом случае второе сообщение будет потеряно.
По-прежнему существует вероятность блокировки, если другой клиент читает последнее сообщение в очереди. Чтобы предотвратить это, Receive
должен иметь небольшой тайм-аут.