Microsoft Message Queuing (MSMQ) – промежуточная среда обмена сообщениями
MSMQServer – класс общего вида, принимающий через MSMQ запросы и посылающий ответы на них.
class MsmqServer<RequestType, AnswerType>:
MsmqUser<RequestType, AnswerType>, IDisposable
{
// очередь приема запросов
private MessageQueue queueReceive;
// событие, вызываемое при приеме запроса
public event ProcessRequestEventHandler<RequestType, AnswerType>
ProcessMessage;Конструктор класса проверяет наличие очереди.
public MsmqServer(String queueReceiveName, QueueFormatter formatterType):
base(formatterType)
{
// создание очереди приема сообщений, если она не существует
queueReceive = MsmqTools.CreateQueue(queueReceiveName,
QueueType.Transactional);
queueReceive.Formatter = requestFormatter;
}В методе Dispose происходит закрытие используемых очередей.
public void Dispose()
{
queueReceive.Close();
queueReceive.Dispose();
}Функции BeginReceive и EndReceive начинают и прекращают прием ответов сервера, изменяя обработчик события PeekComplete очереди ответов.
// начать прием запросов от клиента
public void BeginReceive()
{
queueReceive.PeekCompleted += OnPeek;
queueReceive.BeginPeek();
}
// прекратить прием запросов от клиента
public void EndReceive()
{
queueReceive.PeekCompleted -= OnPeek;
}Метод OnPeek – обработчик события PeekCompleted очереди с запросами. В одну транзакцию входит две операции с очередями – чтения запроса и отправка ответа на него. Для обработки принятого сообщения и создания ответа на него вызывается событие ProcessMessage. В поле ResponseQueue полученного сообщения содержится ссылка на очередь, в которую следует отправить ответ на обработанный запрос.
// обработчки события PeekCompleted очереди с запосами
public void OnPeek(Object source, PeekCompletedEventArgs asyncResult)
{
// создание внутренней транзакции MSMQ
MessageQueueTransaction transaction = new MessageQueueTransaction();
// начало транзакции
transaction.Begin();
try
{
queueReceive.EndPeek(asyncResult.AsyncResult);
// прием cообщения в рамках транзакции
Message message = queueReceive.Receive(transaction);
// в поле ResponseQueue содержится ссылка на очередь,
// куда следует послать ответ на запрос
MessageQueue queueResponse = message.ResponseQueue;
try
{
if (message.Body is RequestType)
{
RequestType request = (RequestType) message.Body;
// вызвать событие обработки запроса
AnswerType answer = ProcessMessage(this, request,
queueResponse);
if ((queueResponse != null) && (answer != null))
{
Message answerMessage = new Message(answer,
answerFormatter);
answerMessage.Label = "Answer";
answerMessage.CorrelationId = message.Id;
answerMessage.Recoverable = Recoverable;
// послать собщение в рамках транзакции
queueResponse.Send(answerMessage, transaction);
}
}
}
finally
{
if (queueResponse != null)
{
queueResponse.Close();
queueResponse.Dispose();
}
};
// продолжить прием запросов
BeginReceive();
// завершить транзакцию
transaction.Commit();
}
catch (Exception e)
{
// отменить транзакцию в случае ошибки
Console.WriteLine(e);
transaction.Abort();
throw e;
}
}
}
Листинг
5.3.
Класс MsmqTools содержит вспомогательный статический метод для создания очереди сообщений.
static class MsmqTools
{
static public MessageQueue CreateQueue(String queueName)
{
return CreateQueue(queueName, QueueType.Transactional);
}
// функция проверяет наличие очереди и создает ее при необходимости
static public MessageQueue CreateQueue(String queueName,
QueueType type)
{
MessageQueue messageQueue;
// если это частная очередь удаленного компьютера,
// то при попытке проверки ее наличие возникает исключение
try
{
if (!MessageQueue.Exists(queueName))
{
MessageQueue.Create(queueName,
type == QueueType.Transactional);
}
}
catch(Exception)
{
}
MessageQueue messageQueue = new MessageQueue(queueName);
return messageQueue;
}
}
}Следует отметить, что при работе с общими очередями можно обращаться к очереди по ее пути, например следующим образом.
queueName = @"Server\PublicQueue";
При использовании частных очередей на удаленном компьютере в большинстве случаев требуется применять прямое имя очереди.
queueName = @"Formatname:DIRECT=OS:Computer\Private$\PrivateName";
Имена используемых очередей следует хранить в конфигурационном файле программы.
5.5. Выводы по использованию MSMQ
Промежуточная среда Microsoft Message Queuing обеспечивает асинхронный обмен сообщениями и может быть использована программными компонентами распределенной системы в одном из следующих случаях:
- необходимо организовать параллельную обработку заявок несколькими компьютерами;
- одна компонента посылает другой запросы без получения ответов на них;
- взаимодействие компонент не должно быть синхронным;
- требуется интеграция с какими-либо другими независимыми системами, которые могут использовать очереди сообщений (MSMQ или IBM MQ).
Альтернативным способом использования MSMQ являются отложенные компоненты ( queued components ) среды COM+, которые будут рассмотрены в разделе, посвященном COM+. При использовании отложенных компонент MSMQ теряет одно из своих достоинств – клиент должен иметь доступ к интерфейсу удаленной компоненты, как и в случае использования любых других COM+ компонент. Кроме того, существует возможность использовать MSMQ как канал в .NET Remoting, для чего необходимо создать собственный канал, что будет проделано в соответствующей теме. Таким образом, MSMQ является не только самостоятельной промежуточной средой, но и может быть использовано другими промежуточными средами как асинхронный канал передачи данных.