Россия, г. Москва |
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 является не только самостоятельной промежуточной средой, но и может быть использовано другими промежуточными средами как асинхронный канал передачи данных.