• Программирование
  • C++
  • Веб-сервисы, защищенные посредством промежуточного программного обеспечения, ориентированного на обработку сообщений

Веб-сервисы, защищенные посредством промежуточного программного обеспечения, ориентированного на обработку сообщений - Реализация протоколов передачи MSMQ и Websphere MQ

ОГЛАВЛЕНИЕ

Реализация протоколов передачи MSMQ и Websphere MQ

При условии, что можно подключиться к упорядоченному сообщению Soap (с которым разбираемся ниже), нужно перехватить обработчик протокола, основанный на WebRequest. Данный раздел освещает ключевые особенности реализации и подробно излагает информацию, приведенную на диаграмме последовательности выше.

Разные общие свойства запроса

Несколько переопределенных свойств не требуются для операций и может быть разрешено выбрасывание исключения NotSupported, например:

public override IWebProxy Proxy 
{
  /* переопределить */ get { throw new NotSupportedException(); }
  /* переопределить */ set { throw new NotSupportedException(); }
}           
           
Другие, как ContentLength, ContentType и Timeout и т.д., необходимы и устанавливаются правильно:
public override int Timeout
{
  /* переопределить */ get { return m_intTimeout; }
  /* переопределить */ set { m_intTimeout = value; }
}           

Эти свойства, общие для реализаций MSMQ и MQ, выделяются в абстрактный класс MyBaseWebRequest.

Предоставление потока для сериализации

MyBaseWebRequest содержит защищенный член данных (доступен в производных классах), именуемый m_RequestStream и устанавливаемый при вызове клиентской инфраструктурой веб-сервисов:

public override Stream GetRequestStream()
{   
    if (m_RequestStream == null)
        m_RequestStream = new MemoryStream();
    else
        throw new InvalidOperationException("Request stream already retrieved(Поток запроса уже возвращен)");
    return m_RequestStream;       
}

Так как не предполагается предоставление потока два раза в ходе одного вызова метода веб-сервисов, и не предполагается делить экземпляры WebRequest между несколькими посредниками, обеспечивается защита от такого происшествия.

Примечание: Мы сами не выполняем сериализацию. Мы предоставляем контейнер (поток) для инфраструктуры веб-сервисов, чтобы она выполняла сериализацию.

Разные общие свойства ответа

Кроме того, MyBaseWebResponse используется без изменений реализациями MSMQ и MQ. Этот класс содержит информацию, более похожую на используемую интернет-ресурсом (код состояния, описание состояния, и т.д.), и так как все ошибки выбрасываются в виде исключений в стек, единственными ключевыми методами в этом классе являются SetDownloadStream()- позволяющий вызывающему оператору WebRequest помещать поток ответа Soap в экземпляр класса, и GetResponseStream()– возвращающий этот поток ответа вызывающей инфраструктуре обработки ответа вебсервисов .NET. При условии успешного вызова после возврата потока происходит стандартное преобразование в параллельную форму (десериализация) Soap.

Общие особенности ориентированной на очереди передачи

Имеется несколько функциональных аспектов, которые следует встроить в управление очередью.

Лимит времени запроса

Стандартный сгенерированный посредник содержит член данных лимита времени, имеющий значение по умолчанию и устанавливаемый перед вызовом фактического вызова веб-сервиса. Этот лимит времени должен соблюдаться реализациями формирования очереди, и они должны возбуждать исключения, как делали бы стандартные обработчики протокола в случае превышения лимита времени.

Сопоставление запроса-ответа (на уровне протокола)

В многопользовательском сценарии много запросов будут ожидать обработки единовременно, и ответы на эти запросы будут приниматься одновременно. В этой ситуации необходимо суметь сопоставить ответ с относящимся к нему запросом.

Существуют два варианта реализации такого средства:

1. Поддерживать некоторую форму идентификатора запроса в API уровня приложения (т.е. в WSDL), в соответствии с которым может действовать сервис.
2. Использовать любую встроенную поддержку, предоставляемую инфраструктурой, для сопоставления запроса с ответом.

Несмотря на то, что первый вариант позволяет обеспечить не зависящий от протокола передачи способ сопоставления сообщений, он осуществляется за счет обработчиков протокола очереди, которым придется эффективно просматривать все сообщения в очереди для идентификации ответа. Выбор варианта 1 портит чистоту API приложения, так как каждый вызов метода должен поддерживать дополнительный параметр для обеспечения выполнения объединения. Обе формы организации очереди обеспечивают сопоставление путем включения элемента CorrelationID в свою версию сообщения из очереди. Протокол должен обрабатывать сопоставление сообщений (это решение может потребоваться пересмотреть при добавлении дополнительных протоколов передачи, и если решение изменяется, результатом становится добавление пользовательских заголовков в оболочку Soap для поддержки метода сопоставления). Данная обработка сопоставления должна выполняться внутри метода GetResponse() каждой реализации.

Uri ответа

Хотя инфраструктура передачи была разработана явно для поддержки нестандартных протоколов, она преимущественно сосредоточена на целевой конечной точке и предполагает единую точку контакта по доставке запроса и ответа. Когда дело касается формирования очереди, нужно быть в состоянии дать клиенту возможность описывать Uri запроса (конечная точка для попадания) и Uri ответа, который сервис конечной точки может эффективно возвращать с результатами вызова. Нужно быть в состоянии описывать очередь запроса и очередь ответа для цели запроса и цели ответа соответственно.

 

Рисунок 4. Объектная модель для MySoapClientProtocol

Лучшим подходом оказывается получение из SoapHttpClientProtocol и введение строгого интерфейса (ISoapClientProtocol) для контролирования управления новым членом данных, именуемым ResponseUrl ( назван так  для привнесения симметрии в пару Url запроса-ответа).

Полученный класс называется MySoapHttpClientProtocol. Введение данного класса требует, чтобы каждый генерируемый посредник получался из него, чтобы суметь получить доступ к новому свойству. Это потребует ручного повторного указания местоположения сопутствующего файла reference.cs.

Любые изменения, вносимые в указанный посредник, теряются во время восстановления посредника с помощью команды меню VS.NET "Обновить веб-ссылку" или при удалении веб-ссылки. Следует создавать резервную копию файла reference.cs после ручного внесения изменений в посредник, чтобы в дальнейшем их можно было снова применить, если, например, необходимо расширить исходное определение API веб-сервиса, и поэтому посредник требуется заново генерировать.

Примером использования информации об очереди ответов может служить реализация внутри метода GetResponse() обработчиков, ожидающих в соответствующей очереди ответов сообщения, соответствующего отправленному обработчиком запросу. Это обычно подразумевает использование специфичного для очередей API, такого как ReceiveByCorrelationID().

Способ задания Uri очереди

В разделе под названием "Определение интернета и других сетевых протоколов передачи для веб-сервисов" было сказано, что класс Uri является средством идентификации сервиса конечной точки с использованием синтаксиса URI. Синтаксис URI зависит от схемы протокола. Абсолютные URI записываются так:

<scheme>:<scheme-specific-part>

Синтаксис URI не требует, чтобы специфичная для схемы часть имела какую-либо общую структуру или набор семантики, являющийся общим среди всех URI. Однако подгруппа URI имеет общий синтаксис для обозначения иерархических отношений внутри пространства имен. Этот базовый синтаксис URI состоит из последовательности 4 основных составляющих:

<scheme(схема)>://<authority(полномочия)><path(путь)>?<query(запрос)>

Известные примеры включают в себя форматы http, такие как:

http://www.microsoft.com/webservices/testservice.asmx?wsdl

Чтобы использовать инфраструктуру подключаемых протоколов, необходимо преобразовать имена очередей в стиле MSMQ и MQ в данный синтаксис. Как показано в следующем разделе, такое преобразование выполняется с разной степенью сложности в зависимости от рассматриваемой реализации формирования очередей.

Обработка ошибок

В составе общей инфраструктуры подключаемых протоколов веб-сервисов .NET версии классов WebRequest и WebResponse выбрасывают системные исключения, такие как ArgumentException, и специфичные для протокола передачи исключения (обычно они имеют вид WebExceptions, выбрасываемых конкретным переопределенным методом GetResponse()). Нужно преобразовать связанные с очередью ошибки в эту структуру исключения, так как она хорошо скрывает различия между сферами отображения исключений MQ и MSMQ. Класс WebException получается из System.InvalidOperationException и содержит несколько расширений для поддержки подробной информации об ошибке:

 

Рисунок 5. Объектная модель WebException

Два протокола формирования очередей поддерживают данный подход, использующий свойство Состояние для отражения следующих перечисленных возвращаемых данных WebExceptionStatus:

Состояние

Описание

ConnectFailure

С удаленным сервисом невозможно соединиться на транспортном уровне. В нашем случае это значит, что открытие очереди запроса не удалось по причине, отличной от невозможности преобразовать имя очереди в ресурс.

NameResolutionFailure

Служба имен не может разрешить имя хоста. В нашем случае это значит, что очередь запроса (или менеджер очереди в случае MQ – смотрите ниже), указанную в Uri, не удалось преобразовать в ресурс.

ProtocolError

Ответ, полученный от сервера, был полным, но показал ошибку на уровне протокола. В нашем случае это значит, что действительный объект, производный от WebResponse, был возвращен, но что он содержит информацию, касающуюся ошибки в соответствующем протоколе передачи очереди. Данный объект предоставляется в составе WebException.

ReceiveFailure

Полный ответ не был получен от удаленного сервера. В нашем случае это значит, что считывание очереди ответа не удалось по причине, отличной от превышения лимита времени или невозможности преобразовать имя очереди в ресурс.

SendFailure

Полный запрос не был отправлен удаленному серверу. В нашем случае это значит, что поместить сообщение в очередь запроса не удалось после успешного открытия очереди (подключения).

Timeout

Ответ не был получен в течение периода времени ожидания, установленного для запроса. В нашем случае это значит, что запрос был успешно помещен в очередь запроса соответствующим транспортным протоколом, но соответствующий ему ответ не был идентифицирован в очереди ответа до истечения периода времени ожидания.

Эти коды состояний преобразуются из специальных кодов ошибок MSMQ / MQ в соответствующих специфичных для протоколов разделах ниже.

Специфичная для MSMQ реализация

Вся работа выполняется в переопределенном методе GetResponse().

Вызов функций MSMQ

Чтобы использовать MSMQ, сборку System.Messaging нужно включить в ссылки для проекта. Она предоставляет простую в применении объектную модель для взаимодействия с MSMQ, охватывающую подключение и управление локальными и удаленными очередями сообщений, а также отправку и прием сообщений посредством данных очередей.

Рисунок 6. System.Messaging

Формат имени очереди

Имеется несколько способов идентификации очереди MSMQ – по пути, по названию формата или по метке очереди. Название формата - собственное, уникальное обозначение очереди. Путь – удобное обозначение очереди, которую нужно преобразовывать в название формата с помощью службы каталога MSMQ. Формат спецификации пути очереди, понятный для MSMQ, имеет одну из следующих форм:

Тип очереди

Синтаксис пути

Общая очередь

MachineName\QueueName

Закрытая очередь

MachineName\Private$\QueueName, .\Private$\QueueName

Журнальная очередь

MachineName\QueueName\Journal$

Машинная журнальная очередь

MachineName\Journal$

Машинная очередь зависших сообщений

MachineName\Deadletter$

Машинная очередь не доставленных транзакционных сообщений

MachineName\XactDeadletter$

Нужно уметь выражать данный тип информации уровня пути в формате Uri, чтобы работать с инфраструктурой подключаемого протокола. К сожалению, это не очень хорошо подходит для имен путей MSMQ в данном случае. RFC 2396 под названием "Универсальные идентификаторы ресурса (URI): базовый синтаксис" говорит, что несколько символов запрещено использовать в спецификации URI, и поэтому они удаляются во время синтаксического разбора такими реализациями, как класс Uri .NET. Один из таких символов - "\", что неприятно с учетом формата имени очереди MSMQ. Из-за этого приходится описывать ресурсы очереди MSMQ с помощью альтернативных средств – в нашем случае используется "/" для разделения на части иерархии имени очереди. Следующее хранится на уровне Uri в подходящей форме:

msmq://./private$/QueueName

Хотя такая форма записи хорошо работает с Uri, она требует две вещи:
•    Разработчик должен не забывать выполнять данное изменение перед вызовом функции веб-сервиса с использованием этого транспортного протокола.
•    Реализация WebRequest должна преобразовывать данный формат, удобный для Uri, обратно в формат, пригодный для использования MSMQ.

Нужно описать очередь стандартным образом – так как она может использоваться в другом месте в более широком контексте приложения, например, считываться из конфигурационного файла, и т.д. Поэтому нужно предоставить некоторую помощь. Так как в идеале не требуется делать различие между вызывающим кодом, делающим запросы по MSMQ, и кодом, делающим запросы по MQ (или же HTTP, и т.д.), добавляется новый метод под названием FormatCustomUri() в интерфейс ISoapClientProtocol и в класс реализации MySoapHttpClientProtocol. Это позволяет вызывающим операторам посредника продолжать использовать удобные для MSMQ имена очередей, но обертывает простое удобное для Uri изменение перед передачей строки классу Uri:

// Получаем имя очереди (например, из конфигурационного файла)
string strMyQ = ".\\private$\\myq1";

// Создаем посредник сервиса
objHelloWorldService = new localhost.Service1();

// Устанавливаем URI
objHelloWorldService.Url = objHelloWorldService.FormatCustomUri("msmq://"
                           + strMyQ);



// Выполняем вызов
string[] arrRes = objHelloWorldService.HelloWorldArr("Simon");

Вызов FormatCustomUri() действует как проход для спецификаций HTTP и MQ – влияя только на форматы имени очереди MSMQ.

Обработка MSMQ

Данный раздел описывает внутреннее устройство метода GetResponse().
Сначала нужно поместить сообщение Soap в очередь MSMQ, описанную в Uri запроса. Для MSMQ формат Uri имени очереди является неудобным и требует преобразования в удобный для MSMQ формат:

// Создаем сообщение
System.Messaging.Message objMsg = new System.Messaging.Message();

// Перехватываем поток как тело сообщения
objMsg.BodyStream = m_RequestStream;

// Анализируем Uri MSMQ
string strQueueName = this.m_RequestUri.LocalPath.Replace("/",  "\\");
if (strQueueName.ToUpper().IndexOf("PRIVATE$") > = 0)
strQueueName = "." + strQueueName;

// Открываем очередь для записи
objQueue = GetQ(strQueueName);

// Отправляем сообщение в одиночной внутренней транзакции MSMQ
objQueue.Send(objMsg, MessageQueueTransactionType.Single);

// Освобождаем ресурсы в главной очереди
objQueue.Close();

Использование одиночного типа транзакции MSMQ гарантирует доставку одного (и только одного) сообщения в очередь. Для поддержки более сложных разнородных транзакций (например, включающих в себя проверку отправки сообщения в базу данных) нужно объединить данную базовую работу с корпоративными сервисами .NET для использования транзакций типа COM+. Так как используется специфичное для протокола передачи сопоставление, идентификатор сообщения MSMQ исходящего сообщения фиксируется и запоминается на данном этапе. Серверный процесс используется для предоставления данного идентификатора в качестве "идентификатора соответствия" (MSMQ и MQ поддерживают эту функцию), что облегчает поиск соответствующего ответа:

// Получаем идентификатор исходящего сообщения для использования в качестве 
// идентификатора соответствия,
// чтобы искать его в любых входящих сообщениях
string strCorrelationID = objMsg.Id;

После помещения сообщения в очередь ожидается ответ на сообщение в очереди, определяемой Uri ответа с совпадающим идентификатором соответствия. Ждем в течение периода, определяемого вызывающим оператором, способным влиять на период времени ожидания при создании посредника:

// Открываем очередь ответа MSMQ и ждем сообщения
try
{
   …

   // Ждем ответ с правильным идентификатором соответствия
   TimeSpan tWaitResp = new TimeSpan(0, 0, m_intTimeout / 1000);
   objQueue = GetQ(strQueueNameResp);       
   msg = objQueue.ReceiveByCorrelationId(strCorrelationID, tWaitResp);
}
catch (Exception e)
{
   …           
}

В результате ожидания в очереди ответа произойдет одно из двух событий:

1. Происходит ошибка (ошибка доступа к исходящей / входящей очереди, истечение срока ожидания ответа на сообщение от сервера, и т.д.). В данном случае ошибка, получаемая от управляемого поставщика MSMQ, перенаправляется непосредственно вызывающему оператору. Ссылаясь на таблицу общих кодов состояний WebException, представленную в разделе под именем "Обработка ошибок", ниже мы перечисляем конкретное сопоставление основных сценариев ошибок MSMQ с соответствующими кодами состояний WebException:

Состояние WebException

Запускающее событие

ConnectFailure

Не удалось открыть очередь запроса в MSMQWebRequest::GetQ()

NameResolutionFailure

Не удалось найти очередь запроса или ответа в MSMQWebRequest::GetQ()

SendFailure

Не удалось поместить сообщение в очередь запроса в MSMQWebRequest::GetResponse()

Timeout

Не удалось получить соответствующее сообщение из очереди ответа до истечения срока ожидания в MSMQWebRequest::GetResponse()

ReceiveFailure

Не удалось получить соответствующее сообщение из очереди ответа по не связанной с истечением срока ожидания причинеMSMQWebRequest::GetResponse()

ProtocolError

Любая другая ошибка в MSMQWebRequest/MSMQWebResponse. В данном случае создается MSMQWebResponse, описывающий точные данные ошибки.

В последнем случае создается MSMQWebResponse и передается в качестве параметра конструктору класса WebException – он также обертывает фактическое исключение, становящееся 'InnerException(внутреннее исключение)' из WebException:

catch( … )
{
   // Было ли данное исключение обработано каким-то образом?
   if ((e is System.Net.WebException) == false)
   {
      // Нет - Создаем MSMQWebResponse – это специфичная для протокола ошибка
      objMSMQWebResponse = new MSMQWebResponse(
            (into)QueueTransportErrors.UnexpectedFailure,
            e.Message,
            e.StackTrace);

       // Выбрасываем исключение
       throw new WebException(
            "MSMQ Pluggable Protocol failure.",
            e,
            WebExceptionStatus.ProtocolError,
            objMSMQWebResponse);
   }
}

2. Сообщение Soap принимается в виде потока, и экземпляр MSMQWebResponse создается и вставляется непосредственно в возвращаемый поток при подготовке к его обработке клиентской инфраструктурой веб-сервисов:

// Создание возвращаемого потока
objMSMQWebResponse = new MSMQWebResponse();
objMSMQWebResponse.SetDownloadStream(msg.BodyStream);           

return objMSMQWebResponse;

Реализация, специфичная для Websphere MQ

Как и в случае поддержки MSMQ, вся работа выполняется в переопределенном методе GetResponse().

Рисунок 7. Классы IBM ActiveX для MQ

Вызов функций MQ

Единственный доступный надежный вариант использования MQ в Websphere MQ 5.3 – обертка COM, предоставляемая с клиентом MQ (MQ не обязателен. Демонстрационное приложение может работать на любой комбинации протоколов передачи HTTP, MSMQ и MQ. Это настраивается в демо). Обертка COM должна быть включена в проект в виде межоперационной ссылки COM. Раздел дополнительных примечаний описывает альтернативу, повышающую общую производительность при использовании MQ, пока же будет достаточно обертки COM.

Полученная межоперационная сборка под названием Interop.MQAX200.dll не подписывается при добавлении таким образом, и поэтому любые сборки, использующие ее, нельзя будет помещать в глобальный кэш сборок, если не будет создана подписанная версия межоперационной сборки.

Подписание выполняется следующим образом:
•    определить местоположение COM DLL mqax200.dll, расположенного при установке по умолчанию в папке C:\Program Files\IBM\WebSphere MQ\bin
•    если строгое имя еще не используется в группе разработки, использовать sn –k <KEYFILENAME> для генерации файла, содержащего пару ключей строгого имени
•    запустить утилиту tlbimp на файле COM DLL, указав соответствующий файл ключей в качестве опции/keyfile<KEYFILENAME> и задав имя для выходной подписанной результирующей сборки с помощью/out<OUTFILENAME>

После выполнения этого и включения результирующей сборки в проект в качестве ссылки главный проект может быть подписан и развернут в GAC(глобальный кэш сборок) должным образом.

Доступ к имени очереди и его формат

Модель доступа к очереди MQ отличается от указанной модели в MSMQ. Тогда как иерархия объектов MSMQ довольно плоская по сути, MQ использует иерархическую структуру, задействующую 3-уровневый доступ, состоящий из:
•    получения сессии MQ
•    подключения к названному менеджеру очереди MQ через сессию
•    запроса доступа к названной очереди MQ через менеджер очереди

Имя очереди формируется из двух частей:

<имя менеджера очереди>/<имя очереди> ,например, QM_yoda/queue32

В отличие от MSMQ, имена объектов чувствительны к регистру. Есть несколько «глюков» при работе с комбинацией класса Uri (который, если вы помните, содержит имена хостов в нижнем регистре). При использовании среды разработки явным признаком проблемы именования является WebException с кодом состояния NameResolutionFailure, показывающим, что менеджер очереди или очередь не удается разрешить (подробнее смотрите ниже). Далее приводится несколько примеров доступа к очереди.

При подключении к очереди с именем "fred" в стандартном менеджере очереди используется следующая запись Uri:

objHelloWorldService.Url = "mq://fred"

При подключении к очереди с именем "bill" в менеджере очереди с именем "QM_john" используется следующая запись Uri:

objHelloWorldService.Url = "mq://QM_john/bill"

Эти примеры показывают виды обозначений очереди MQ. Для преобразования несвязанного Uri в комбинацию имени менеджера очереди / имени очереди предоставляется служебный метод с именем ResolveManagerAndQueueName(), используемый в передающем коде следующим образом:

// В какой менеджер очереди и имя очереди нужно направить сообщение?
ResolveManagerAndQueueName(
    this.m_RequestUri,
    out strQueueManagerName,
    out strQueueName);

Обработка MQ

Не считая явных семантических различий, описанных в прошлом разделе, главные различия между этой реализацией и версией MSMQ заключаются в синтаксисе при отправке сообщений и ожидании в очереди ответа. В то время как MSMQ поддерживает прямое использование потоков при отправке и приеме сообщений, для MQ такая поддержка отсутствует (по крайней мере, при использовании обертки ActiveX), и поэтому приходится применять отправку и прием массивов байтов.

Поскольку MQ не поддерживает автоматическое использование потоков в качестве тела сообщения, приходится преобразовывать поток в массив байтов, используемый затем для вставки исходящего сообщения:

// Подключается к упорядоченному потоку Soap как к массиву байтов
byte[] bytBody = new Byte[m_RequestStream.Length];
m_RequestStream.Read(bytBody, 0, bytBody.Length);

При наличии тела Soap и успешном разрешении комбинаций менеджер очереди/имя очереди запроса и ответа (показано выше), первое, что надо сделать, - получить сессию MQ. Это требуется сделать до выполнения работы по формированию очереди:

// Подключаемся к сессии
objMQSession = new MQAX200.MQSessionClass();
Далее пытаемся подключиться к менеджеру очереди и запрашиваем у него объект очереди с заданным именем:
// Получаем именованный менеджер очереди
objQueueManager = GetQManager(objMQSession, strQueueManagerName, true);

// Получаем именованную очередь от менеджера
objQueue = GetQ(objQueueManager, strQueueName, true);

После успешного выполнения данных действий создается сообщение с установкой параметров сообщения и записывается тело сообщения:

// Устанавливаем сообщение для отправки
objMsg = (MQAX200.MQMessage)objMQSession.AccessMessage();
objPutMsgOpts =
          (MQAX200.MQPutMessageOptions)objMQSession.AccessPutMessageOptions();
// Нужно отправлять массив байтов, чтобы скрыть двоичные вложения, и т.д....
objMsg.Write(bytBody);

Помещение сообщения в очередь использует (по умолчанию) установленные параметры сообщения:

// Помещаем сообщение в очередь
objQueue.Put(objMsg, objPutMsgOpts);

[Примечание: При преобразовании в MQ, работающем на AS/400 и оперируемом в EBCDIC, сообщение должно явно указывать, что оно имело формат ASCII до отправки - objMsg.Format = "MQSTR " ;]

Так как используется специфичное для протокола передачи сопоставление, идентификатор сообщения MSMQ исходящего сообщения фиксируется и запоминается на этой стадии. Применяется серверный процесс для предоставления данного идентификатора в качестве "идентификатора соответствия" (MSMQ и MQ поддерживают данную функцию) для облегчения поиска соответствующего ответа:

// Получаем идентификатор исходящего сообщения для использования в качестве //идентификатора соответствия для поиска в любых входящих сообщениях
string strCorrelationID = msg.MessageId;

После того как сообщение помещено в очередь, ожидается ответ на сообщение в очереди, определенной Uri ответа с совпадающим индикатором соответствия. Ожидаем в течение периода, определенного вызывающим оператором, способным влиять на время ожидания при создании посредника:

try
{
    // Открываем очередь ответа MQ и ожидаем сообщения
    objQueueResponse = GetQ(objQueueManager, strQueueNameResp, false);
    objMsgResp = (MQAX200.MQMessage)objMQSession.AccessMessage();
    objMsgResp.CorrelationId = strCorrelationID;
    objGetMsgOpts = (MQAX200.MQGetMessageOptions)
    objMQSession.AccessGetMessageOptions();
    objGetMsgOpts.Options = (int)MQAX200.MQ.MQGMO_SYNCPOINT +
                            (int)MQAX200.MQ.MQGMO_WAIT;
    objGetMsgOpts.WaitInterval = this.Timeout;
    objQueueResponse.Get(
        objMsgResp,
        objGetMsgOpts,
        System.Reflection.Missing.Value);

    // Используем(т) подходящий считыватель
    strMsgRecv = objMsgResp.MessageData.ToString();
}
catch (Exception e)
{
     ...           
}

В результате ожидания в очереди ответа происходит одно из двух событий:

1. Происходит ошибка (ошибка доступа к исходящей / входящей очереди, истечение срока ожидания ответа на сообщение от сервера, и т.д.). В этом случае ошибка, полученная от управляемого поставщика MSMQ, перенаправляется непосредственно вызывающему оператору. Ссылаясь на таблицу общих кодов состояний WebException, представленную в разделе под именем "Обработка ошибок", ниже мы перечисляем конкретное сопоставление основных сценариев ошибок MSMQ с кодами состояний WebException:

Состояние WebException

Запускающее событие

ConnectFailure

Не удалось открыть менеджер очереди запроса в MQWebRequest::GetQManager() или не удалось открыть очередь запроса в MQWebRequest::GetQ()

NameResolutionFailure

Не удалось найти очередь запроса или ответа в MQWebRequest::GetQ()

SendFailure

Не удалось поместить сообщение в очередь запроса в MQWebRequest::GetResponse()

Timeout

Не удалось получить соответствующее сообщение из очереди ответа до истечения срока ожидания в MQWebRequest::GetResponse()

ReceiveFailure

Не удалось получить соответствующее сообщение из очереди ответа по не связанной с истечением срока ожидания причине вMQWebRequest::GetResponse()

ProtocolError

Любая другая ошибка вMQWebRequest / MQWebResponse. В данном случае создается MQWebResponse,описывающий точные данные ошибки.

2. Сообщение Soap принимается в виде массива байтов, преобразуется в поток, и экземпляр MQWebResponse создается и вставляется непосредственно в преобразованный поток, при подготовке к его преобразованию клиентской инфраструктурой веб-сервисов:

// Преобразуем результат в массив байтов
byte[] buf = new System.Text.UTF8Encoding().GetBytes(strMsgRecv);
MemoryStream stResponse = new MemoryStream();
stResponse.Write(buf, 0, buf.Length);

// Создается возвращаемый поток
objMQWebResponse = new MQWebResponse();
objMQWebResponse.SetDownloadStream(stResponse);           

return objMQWebResponse;