Веб-сервисы, защищенные посредством промежуточного программного обеспечения, ориентированного на обработку сообщений - Создание посредника WSDL и веб-сервисов в .NET

ОГЛАВЛЕНИЕ

Создание посредника WSDL и веб-сервисов в .NET

Соглашения интерфейсов описываются с использованием WSDL - сродни IDL(язык определения интерфейсов) для COM.  Как только этот WSDL становится доступен в URL или в файле, класс посредника веб-сервисов генерируется путем прямого использования отдельного инструмента WSDL.EXE, поставляемого с SDK (набор средств для разработки ПО), или неявно – при использовании средства «Добавить веб-ссылку» Visual Studio .NET:

Рисунок 1. Процесс посредника WSDL-2

Сгенерированный файл посредника (обычно называемый reference.cs) помещается в подпапку проекта подпапки с именем \Web References и содержит класс, унаследованный от SoapHttpClientProtocol. Сгенерированный класс скрывает значительную часть сложности сериализации и передает специальные сообщения, относящиеся к вызову стандартных веб-сервисов XML. В получаемом сгенерированном файле посредника находится сочетание синхронных и асинхронных форм методов – ниже показан пример базового сгенерированного (синхронного) метода:

 [SoapDocumentMethodAttribute(...)]
public string IsCollaboratorRegistered(string vstrEnvUUID)
{
  object[] results = this.Invoke("IsCollaboratorRegistered", new object[]
                     { vstrEnvUUID });
  return ((string)(results[0]));
}

При наличии стандартного посредника клиенты могут подключаться к веб-сервису по соответствующему URL с помощью следующего кода:

// Получаем экземпляр посредника
localhost.RegService objWSReg = localhost.RegService();    
// Конечная точка может меняться во время выполнения, и т.д.
objWSReg.Url = "http://192.168.32.1/MyService.asmx";    
// Выполняем вызов
string strRetXML
     = objWSReg.IsCollaboratorRegistered("12345678901234567890123456789012");

Умение менять URL и описывать этот URL в виде "схемы протокола" и "конечной точки" является ключевой составляющей метода.

Во время выполнения одна строка в посреднике, содержащая вызов this.Invoke( …), скрывает много работы, разбиваемой на следующие основные части:
•    Выбор средства передачи / подтверждение поддержки
•    Сериализация вызова интерфейса программирования приложений Soap
•    Запуск транспортного протокола

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

Определение интернета и других сетевых транспортных протоколов для веб-сервисов

Хотя в реальности протоколом доставки сообщений Soap является HTTP, в среде разработки .NET имеется инфраструктура, позволяющая изменять механизмы доставки сообщений статически (время разработки) или динамически (время выполнения).

Среда разработки .NET использует три специальных класса для предоставления информации, требуемой для подключения к ресурсам интернета/сети посредством модели запрос/ответ:

1. Класс Uri, содержащий URI(универсальный код ресурса) интернет-ресурса, который вы ищете (включая схему протокола, например http://www.microsoft.com/webservices/stockcheck.asmx);
2. Класс WebRequest, инкапсулирующий запрос на доступ к ресурсу сети;
3. Класс WebResponse, предоставляющий контейнер для поступающего ответа от ресурса сети.

Клиентские приложения создают экземпляры WebRequest путем передачи URI ресурса сети методу WebRequest.Create(). Этот статический метод создает экземпляр WebRequest для конкретного протокола, например, HTTP. Возвращаемый экземпляр WebRequest обеспечивает доступ к свойствам, контролирующим запрос к серверу и доступ к потоку данных, отправляемому при выполнении запроса. Метод GetResponse() из экземпляра WebRequest отправляет запрос из клиентского приложения серверу, указанному в URI.

[Примечание: Универсальный идентификатор ресурса (URI) – компактная строка символов для идентификации абстрактного или физического ресурса, как определено в RFC2396. Схема – стандартная часть URI, которую можно разбить на несколько отдельных частей. Все сетеыве идентификаторы могут быть сопоставлены к одной из частей. Схема – идентификатор протокола, например, http, ftp и т.д.]

Имеется встроенная поддержка трех специальных схем протокола - "http:", "https:" и "file:". Будут созданы новые версии классов WebRequest и WebResponse для обеспечения поддержки дополнительных двух схем:

•    "msmq:" Поддерживает модель запрос-ответ, в которой целью является локальная или удаленная очередь MSMQ
•    "mq:" Поддерживает модель запрос-ответ, в которой целью является комбинация администратора очередей/имени очереди MQ

Можно будет добавить дополнительную поддержку для других схем, таких как "mailto:" или "ftp:" для SMTP и FTP соответственно. Попытка создать WebRequest для Uri, содержащего неподдерживаемую схему:

Uri uri = "mq://accountq1";
WebRequest newWebRequest = WebRequest.Create(uri);

выдаст исключение в виде NotSupportedException, означающее, что схема запроса, заданная в requestUri, не зарегистрирована. Данный вопрос нужно решить следующим образом, чтобы успешно вводить новые схемы. Нужно дать возможность клиенту идентифицировать очередь как Uri запроса и уметь выполнять вызов метода по тому Uri, как он выполнялся бы по основанной на http конечной точке.

Определение пользовательских транспортных протоколов

Классы WebRequest и WebResponse образуют основу инфраструктуры подключаемых протоколов. Для определения нового протокола типа "xxx://" нужно создать порождения каждого из этих базовых классов, плюс класс, реализующий IWebRequestCreate . Следующая диаграмма изображает основную модель, задействованную в создании новых протоколов:

Рисунок 2. Объектная модель для подключаемых протоколов

Были включены основные операции и атрибуты, чтобы показать ключевые аспекты любой реализации.

Общие аспекты

Несколько атрибутов и операций, которые могут быть переопределены потомками классов WebRequest и WebResponse, являются избыточными при реализации не свойственных интернету протоколов передачи. К тому же, имеется много общего в двух реализациях очереди. Это позволяет абстрагировать данную общность и избыточность в один промежуточный класс. Например, свойство Method, используемое в составе любого веб-запроса (GET, POST и т.д.), неуместно в предлагаемых реализациях новых схем.

Определяются следующие новые производные типы для расширения иерархии:

Тип Базовый тип Назначение
MyBaseWebRequest WebRequest Содержит переопределения, общие для реализаций MQ и MSMQ
MyBaseWebResponse WebResponse Содержит переопределения, общие для реализаций MQ и MSMQ
MSMQWebRequest MyBaseWebRequest Реализация MSMQ WebRequest (закрыта)
MSMQWebResponse MyBaseWebResponse Реализация MSMQ WebResponse (закрыта)
MQWebRequest MyBaseWebRequest Реализация MQ WebRequest (закрыта)
MQWebResponse MyBaseWebResponse Реализация MQ WebResponse (закрыта)

Эти критерии должны выполняться, чтобы специфичный для протокола класс можно было использовать в качестве подключаемого протокола:

1. Подготовка к регистрации схемы

Реализация должна включать в себя версию интерфейса IWebRequestCreate, например для MSMQ:

public class MSMQRequestCreator : IWebRequestCreate
{
  public WebRequest Create(Uri uri)
  {
    // Создаем новый объект запроса MSMQ
    return new MSMQWebRequest(uri);
  }
}

2. Регистрация схемы и создание Uri

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

Обычно это выполняется аналогично следующему:

// Регистрируем префикс "mq:" здесь для WebRequest
MQRequestCreator objCreator = new MQRequestCreator();
WebRequest.RegisterPrefix("mq", objCreator);

Это обеспечивает последующее подключение кода создания для экземпляра новой схемы, такой как в вышеприведенном коде:

Uri uri = "mq://accountq1";
WebRequest newWebRequest = WebRequest.Create(uri);

Будет работать, так как новая схема известна инфраструктуре веб-сервисов .NET.

3. Реализация основных переопределенных членов

Производные классы должны переопределять абстрактные методы и свойства WebRequest и WebResponse для предоставления подключаемого интерфейса. Эти члены хорошо документированы для .NET Framework 1.0 – значимая подгруппа показана ниже:

Член

Назначение

Method

Обычно связан с формой метода протокола для использования в этом запросе, например PUT, GET и т.д. Не используется здесь.

Headers

Получает или устанавливает набор пар имя заголовка/значение, связанный с запросом. Не используется здесь.

ContentLength

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

ContentType

При переопределении в классе-потомке получает или устанавливает тип содержимого отправляемых данных запроса. В нашем случае всегда text/xml.

Credentials

Получает или устанавливает сетевые реквизиты, используемые для проверки подлинности запроса к интернет-ресурсу. Не используется в нашем случае.

PreAuthenticate

Показывает, нужно ли предварительно проверять подлинность запроса. Не используется в нашем случае.

Proxy

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

GetRequestStream

Создает и возвращает Stream(поток) для записи данных (сообщение Soap) для интернет-ресурса. Реализован в нашем базовом классе.

BeginGetRequestStream

Асинхронная версия вышеуказанного. Не поддерживается в нашем случае.

EndGetRequestStream

Асинхронная версия вышеуказанного. Не поддерживается в нашем случае.

GetResponse

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

BeginGetResponse

Асинхронная версия вышеуказанного. Не поддерживается в нашем случае.

EndGetResponse

Асинхронная версия вышеуказанного. Не поддерживается в нашем случае.

Abort

Отменяет асинхронный запрос, начатый с метода BeginGetResponse. Не поддерживается в нашем случае.

Будут реализованы все переопределения, общие для версий MQ и MSMQ в MyBaseWebRequest /MyBaseWebResponse , и особенности в соответствующих производных классах.

Выполнение производного от WebRequest экземпляра

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

Рисунок 3. Диаграмма взаимодействия для WebRequest

Ключевые особенности операции включают в себя:

1.    Переопределение GetWebRequest в генерируемом посреднике Soap (полученном из SoapHttpClientProtocol) позволяет перехватывать регистрацию (для схем msmq / mq) и создание надлежащего экземпляра WebRequest. В случае схемы "msmq" данное создание выполняется с помощью экземпляра MSMQRequestCreator.
2.    Инфраструктура веб-сервисов .NET вызывает закрытый метод, BeforeSerialize(), запускающий получение и установку различных членов данных внутри экземпляра общего класса, производного от WebRequest, устанавливающий метод (ненужный, но требуемый для обеспечения операции – возращение исключения NotSupported заставляет инфраструктур вебсервисов .NET отклонять весь запрос!) и получающий (пустой) набор веб-заголовков.
3.    Затем метод GetRequestStream() вызывается в классе, производном от WebRequest, где создается поток (в данном случае MemoryStream) и возвращается инфраструктуре.
4.    На данном этапе инфраструктура начинает процесс сериализации Soap и помещает результаты в поток. На данном этапе серьезная проблема заключается  в том, что при выталкивании упорядоченного потока в сеть для передачи стандартная обработка требует закрытия потока! Учитывая, что еще не достигнут  этап, когда придется использовать поток для проталкивания в очередь, на первый взгляд это непреодолимое препятствие!! Пока пренебрежем им. Раздел под названием "Подключение к упорядоченному потоку Soap" разъясняет проблемы и возможные решения.
5.    После завершения подготовки потока инфраструктура вызывает переопределенный GetResponse() в экземпляре класса MSMQWebRequest. Здесь применяются особенности работы с очередями с помощью надлежащего механизма (System.Messaging для MSMQ или предоставленная IBM библиотека COM для MQ). Это подразумевает запись сообщения Soap и ожидание ответа на него от серверной службы. Особенности протоколов передачи MSMQ и MQ рассмотрены в следующем разделе. Подключение к потоку на данном этапе снова обойдено молчанием.
6.    Вне зависимости от особенностей работы MSMQ / MQ, результатом должна быть доставка объекта ответа надлежащего типа (например, MSMQWebResponse), или возбуждается экземпляр WebException, если передача не удалась.

Эти типы исключений обсуждаются далее в статье.

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