Microsoft BizTalk Server 2010 R2: Основы программирования II

Статья опубликована  в журнале MSDeveloper.RU

В февральской статье мы рассмотрели основные компоненты для программирования под BizTalk Server (здесь и далее BTS), выбрав довольно простую задачу по сложению двух цифр. Для этой статьи изменим формулировку задачи, введем элементы интеграции систем, т.е. то, для чего, собственно, и был разработан BTS.

Задача

Думаю, вы уже сталкивались с системами, которые связаны друг с другом по принципу «каждый с каждым», т.е. каждая система напрямую связана с любой другой. Минусы такой организации взаимодействия можно легко назвать навскидку. В первую очередь, это трудности по реализации взаимодействия с каждой конкретной системой. Если, например, в комплексе штук 30 систем, привязываться по определенным протоколам к другим 29 системам очень и очень накладно. К тому же, если одна система изменит какой-то свой формат передачи данных, то всем остальным системам нужно будет поменять свои внутренние реализации взаимодействия.

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

Теперь перейдем к нашему проекту. Предположим, что сам BTS не умеет решать задачу «сложить числа A и B». Это, конечно, смешно и неправда, но под задачу сложения двух чисел можно подставить любую другую. На данный момент нам нужно, чтобы результаты вычислений брались из другой системы. В реальных системах под такой задачей может стоять получение каких-то данных, например, справочников или результатов каких-то сложных вычислений.

Определимся с участниками нашего процесса:

  • Шина
  • Модуль User, запрашивающий информацию у шины
  • Модуль CalcService, который умеет считать результат

Можно нарисовать диаграмму последовательности работы по процессу:

clip_image001

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

Итого нам нужно разработать 2 веб-сервиса и шину. Начнем с написания заглушки к шине.

Решение

В данном разделе будет описываться создание интеграционной шины с использованием Microsoft Visual Studio 2010. Я предполагаю, что читатель ознакомился с предыдущей февральской статьей, а также умеет создавать WCF-сервисы.

Создание заглушки шины

Откроем Visual Studio 2010 от имени администратора, создадим новый проект EsbSample.EsbCore, студия, как обычно, сгенерирует заготовку решения и проекта.

Общий вид оркестровки

Сейчас нужно закодировать процесс, для этого в сборку EsbSample.EsbCoreнужно добавить новую оркестровку CalcProcess. После добавление оркестровки можно набросать сценарий его работы:

clip_image002

Его можно прочитать следующим образом:

Receive_1 получает запрос на сложение двух чисел

Send_1 отправляет запрос сервису сложения чисел

Receive_2 получает результат сложения

Send_2 отправляет результат сложения

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

Схемы
Запрос

Добавим в проект схему для запроса (EsbRequest) и создадим следующую структуру:

clip_image003

Вот ее код:

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://EsbSample.EsbCore.EsbRequest"
           xmlns:b="http://schemas.microsoft.com/BizTalk/2003"
           targetNamespace="http://EsbSample.EsbCore.EsbRequest"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Request">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="A" type="xs:int" />
        <xs:element name="B" type="xs:int" />
        <xs:element name="CorrelationID" type="GUID" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:simpleType name="GUID">
    <xs:restriction base="xs:string">
      <xs:pattern value="[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" />
    </xs:restriction>
  </xs:simpleType>
</xs:schema>
Ответ на запрос

Аналогичным образом добавим еще одну схему, EsbResponse, следующего вида

<?xml version="1.0" encoding="utf-16"?>
<xs:schema xmlns="http://EsbSample.EsbCore.EsbResponse"
           xmlns:b="http://schemas.microsoft.com/BizTalk/2003"
           targetNamespace="http://EsbSample.EsbCore.EsbResponse"
           xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <xs:element name="Response">
    <xs:complexType>
      <xs:sequence>
        <xs:element name="Result" type="xs:int" />
        <xs:element name="CorrelationID" type="Guid" />
      </xs:sequence>
    </xs:complexType>
  </xs:element>
  <xs:simpleType name="Guid">
    <xs:restriction base="xs:string">
      <xs:pattern value="[a-fA-F0-9]{8}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{4}-[a-fA-F0-9]{12}" />
    </xs:restriction>
  </xs:simpleType>
</xs:schema>
Логические порты
Создание типов логических портов

Итак, у нас определены схемы сообщений, сейчас можно создавать логические порты. Для этого вначале создадим два типа портов, один для запроса, второй для ответа. Создание типа порта для запроса начинается в окне Orchestration View, нужно найти узел Port Typesи через контекстное меню вызвать команду создания типа порта:

clip_image004

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

clip_image005

Здесь я создал тип порта под названием RequestPortType, c одной операцией Calc и типом запроса EsbRequest.

Аналогичным образом создается тип порта для ответов:

clip_image006

Таким образом, у нас появилось два типа порта, теперь нам нужно создать сами порты.

Создание портов

Для Receive_1 создадим порт InboundPortсо следующей конфигурацией:

clip_image008

clip_image010

Для SendPort_1 конфигурация порта будет аналогично, только на экране Port Binding нужно выбрать Port direction of communication: I’ll always be sending messages on this port.

Для Receive_2 конфигурация будет выглядеть вот так:

clip_image012

clip_image014

Для Send_2 создание порта аналогичное, только на экране Port Binding нужно указать Port direction of communication: I’ll always be sending messages on this port.

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

clip_image016

Обращаю внимание на то, что, когда соединяется порт и фигура Receive, автоматически создается сообщение, в то время как при соединении фигур Send сообщения не создаются. Поэтому в окне Orchestration View в узле Messages нужно создать два сообщения типа EsbResponse:

clip_image017

clip_image018

Таким образом, у нас должно получиться 4 сообщения, нужно их переименовать и установить в каждой фигуре Receive\Send соответственно таблице:

Название Тип Название фигуры
RcvdMsg_1 EsbRequest Receive_1
RcvdMsg_2 EsbResponse Receive_2
SntMsg_1 EsbRequest Send_1
SntMsg_2 EsbResponse Send_2

Пример установки сообщения для фигуры:

clip_image019

Если вы все сделали верно, то получится следующая картинка:

clip_image021

Заметим, что иконка с восклицательным знаком осталась только у фигур ConstructMessage. Давайте займемся ими, выделяем ConstructMessage_1, выбираем его свойства и указываем, что мы будем создавать сообщение SntMsg_1

clip_image022

После этого добавляем в приложение две карты (map), с названиями CopyRequest и CopyResponse. Как нетрудно догадаться из названий карт, каждая из них будет просто копировать из одного сообщения в другое, сообщения должны быть одинакового типа. Пример для CopyRequest:

clip_image023

После того как карты были созданы, можно удалить фигуры Message Assignment, которые располагаются внутри фигур Construct Message и поставить туда взамен фигуры Transform:

clip_image024

Затем нужно два раза щелкнуть по Transform_1 (откроется окно Transform Configuration) и установить следующие параметры:

Existing Map(Fully Qualified Map Name=”EsbSample.EsbCore.CopyRequest”)

Transform Source: RcvdMsg_1

Transform Destination: SntMsg_1

clip_image025

Для фигуры Transform_2 нужно совершить аналогичные действия:

Existing Map(Fully Qualified Map Name=”EsbSample.EsbCore.CopyResponse”)

Transform Source: RcvdMsg_2

Transform Destination: SntMsg_2

После всех этих манипуляций нужно у фигуры Receive_1 установить свойство Activate = True– и оркестровка почти готова

clip_image027

Корреляции

Вернемся к описанию нашего процесса. Итак, шина получает запрос на вычисление, адресует это вычисление веб-сервису, а затем ждет сообщения с ответом. Допустим, вычисление результата занимает какое-то время, скажем, минут 10. В течении этого времени к нам придет еще один запрос на вычисление, мы также делегируем его сервису и ровно так же будем ждать ответа. Здесь возникает вопрос – когда к нам придет сообщение с ответом, ответом на какой запрос оно будет являться, на первый или на второй? Непонятно. Для этого было введено понятие корреляции, т.е. соответствия сообщений. В наших схемах для корреляции выделено поле CorrelationID.

Работает это следующим образом: нам приходит первый запрос с CorrelationID= «cfc2e57b-63fe-44c8-b071-047e1a34b413», мы перенаправляем этот запрос веб-сервису. И затем ждем сообщения с ответом, где в поле CorrelationID будет стоять значение «cfc2e57b-63fe-44c8-b071-047e1a34b413». Соответственно, если нам придет второй запрос, то CorrelationIDу него будет другим, и путаницы в этом случае уже не возникнет.

Для настройки корреляции нам нужно немного поправить схемы. Начнем с EsbRequest, открываем его в редакторе, выбираем поле CorrelationID и в контекстном меню выбираем команду Promote \ Quick Promotion. В проект добавится файл PropertySchema.xsd, в нее добавится наше свойство. Аналогичные действия нужно совершить с EsbResponse.

Затем переходим обратно в оркестровку, в окне Orchestration View выбираем узел Correlation Typesи создаем новый тип корреляции:

clip_image028

clip_image030

Находим в списке Available Properties нашу схему со свойствам, выбираем CorrelationID, нажимаем кнопку Add:

clip_image032

Получился тип корреляции, завязанный на поле CorrelationID:

clip_image033

Затем в окне Orchestration View выбираем узел Correlation Sets, добавляем новый набор корреляции и указываем в качестве ее типа только что созданный:

clip_image034

После этого нам в оркестровке нужно где-то «запомнить», инициализировать корреляцию. Если взглянуть на оркестровку, можно заметить одно место, где она нам пригодится – когда мы ожидаем ответа от веб-сервиса по рассчету данных, это фигура Receive_2, в нее мы ждем сообщения именно с тем идентификатором корреляции, который был отправлен ранее в сообщении Send_1. Поэтому выделяем фигуру Send_1 и устанавливаем у нее свойство Initializing Correlation Sets:

clip_image035

А у фигуры Receive_2 устанавливаем свойство Following Correlation Sets:

clip_image036

Таким образом, при отправке сообщения через Send_1 мы запоминаем CorrelationID и затем в Receive_2 ждем сообщения, у которого CorrelationIDбудет таким же. Всё просто.

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

Развертывание приложения

Сейчас нам нужно развернуть приложение. Для этого вначале нужно открыть свойства проекта, подписать сборку на вкладке Signing, а затем задать настройки развертывания на вкладке Deployment (всё это было описано в прошлой статье). Название у приложения будет «Esb». После этого нужно выбрать в меню BuildDeploy Solution

clip_image037

Если вы всё сделали правильно, в окне Output будет сказано об успешном развертывании приложения. А если нет, пишите письма, разберемся.

clip_image038

На данном шаге я предлагаю прерваться и продолжить в следующей части.

Что дальше

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

Исходники проекта доступны по ссылке http://goo.gl/OZPI9

3 комментария к “Microsoft BizTalk Server 2010 R2: Основы программирования II

  1. Жаль, что нет информации о настройки портов. И ещё хотелось бы почтитать о создании своих выражений на C#. Жду продолжения, спасибо за хорошие статьи.

    1. Здравствуйте!
      Выражения свои разработать нельзя, вы путаете с WWF и их Custom Activities.
      Для кастомных выражений в бизтолке используется фигура Expression, где вы можете писать код, в том числе дергающий классы и методы из обычных .NET-сборок (не забудьте поместить их в GAC)

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *