Опубликован: 11.05.2007 | Доступ: свободный | Студентов: 1600 / 158 | Оценка: 4.36 / 4.25 | Длительность: 16:06:00
Лекция 6:

Microsoft Message Queuing (MSMQ) – промежуточная среда обмена сообщениями

< Лекция 5 || Лекция 6: 12345 || Лекция 7 >

Конструктор, получающий имена очередей для посылки и приема сообщений.

public MsmqClient(String queueSendName, String queueReceiveName, 
            QueueFormatter formatterType): base(formatterType)
        {
            // список отправленных сообщений без ответов                                
            messages = new Dictionary<String,RequestType>();
            // создание очереди для посылки запросов, если она не существует
            queueSend = MsmqTools.CreateQueue(queueSendName,
                QueueType.Transactional);
                
            // создание очереди для приема ответов, если она нужна
            if (queueReceiveName != null)
            {
                queueReceive = MsmqTools.CreateQueue(queueReceiveName);         
                queueReceive.Formatter = answerFormatter;
                // считывать из очереди свойство CorrelationId
                queueReceive.MessageReadPropertyFilter.CorrelationId = true;
            }
            else
            {
                queueReceive = null;
            }
        }

В методе Dispose происходит закрытие используемых очередей.

public void Dispose()
        {
            queueSend.Close();
            queueSend.Dispose();
            
            if (queueReceive != null)
            {
                queueReceive.Close();
                queueReceive.Dispose();
            }
        }

Функции BeginReceive и EndReceive начинают и прекращают прием ответов сервера, изменяя обработчик события PeekComplete очереди ответов.

public void BeginReceive()
        {
            // установить обработчик на событие, возникающее при появлении 
            // сообщения в очереди            
            queueReceive.PeekCompleted += OnPeek;
            // начать отслеживание поступления сообщения в очередь
            queueReceive.BeginPeek();          
        }   

         // прекратить прием ответов сервера 
        public void EndReceive()
        {
            // отключить обработчик 
            queueReceive.PeekCompleted -= OnPeek;
        }

Функция Send посылает в исходящую очередь запрос общего типа для его обработки сервером. Для ответа на сообщение серверу следует использовать очередь, указанную в поле ResponseQueue посылаемого сообщения.

public void Send(RequestType request)
        {            
            // создание нового сообщения
            Message message = new Message(request, requestFormatter);      
            message.ResponseQueue = queueReceive;           

            // использование восстаналиваемых сообщений
            message.Recoverable = Recoverable;

            // послать сообщение; поскольку транзакция состоит из 
            // единственной операции, вместо объекта-транзакции используется
            // значение MessageQueueTransactionType.Single
            queueSend.Send(message, MessageQueueTransactionType.Single);
            
            // поле message.Id устанавливается после посылки сообщения;
            // идентификатор сообщения связывается c отосланным запросом
            // в списке необслуженных запросов
            messages.Add(message.Id, request);          
        }

Обработчик события очереди PeekComplete использует внутренние транзакции MSMQ. В одну транзакцию входит операция чтения ответа из очереди и последующий вызов события ProcessAnswer. Если в ходе обработки события возникло исключение, ответ сервера останется в очереди ответов. Иначе сообщение удаляется из поддерживаемого клиентом списка невыполненных запросов.

public void OnPeek(Object source, PeekCompletedEventArgs asyncResult)
        {
            // создание внутренней транзакции MSMQ 
            MessageQueueTransaction transaction = new MessageQueueTransaction();
            
            // начало транзакции
            transaction.Begin();      

            try
            {                   
                // прекратить ожидание сообщений в очереди 
                queueReceive.EndPeek(asyncResult.AsyncResult);

                // получить сообщение из очереди в рамках транзакции
                Message message = queueReceive.Receive(transaction);

                // в поле CorrelationId должен быть идентификатор сообщения
                // с исходным запросом
                String messageId = message.CorrelationId;

                // есть ли такое сообщение в списке невыполненных запросов?
                if (messages.ContainsKey(messageId))
                {                       
                    if (message.Body is AnswerType)
                    {
                        // преобразовать тело сообщения к типу ответа
                        // и вызвать событие по его обработке                         
                        AnswerType answer = (AnswerType) message.Body;
                        ProcessAnswer(this, messages[messageId], answer);
                    };                  
                    messages.Remove(messageId);
                }                       
                // продолжить ожидать сообщения
                BeginReceive();                
                // успешное завершение транзакции
                transaction.Commit();
            }
            catch (Exception e)
            {                
         // отмена транзакции
         transaction.Abort();
                throw e;
            }               
        }   
    }
Листинг 5.2.
< Лекция 5 || Лекция 6: 12345 || Лекция 7 >