Работа с объектами bpm'online по протоколу OData через WCF-клиент
Glossary Item Box
Общая информация
Доступ к сущностям bpm'online по протоколу OData предоставляет веб–сервис EntityDataService.svc:
Адрес сервиса OData
http[s]://<имя_сервера>/<имя_приложения_bpm'online> + "/0/ServiceModel/EntityDataService.svc/"
Пример адреса сервиса OData
http://myserver.com/bpmonlineWebApp/0/ServiceModel/EntityDataService.svc
Генерация прокси–классов сервиса EntityDataService.svc
Общие положения
Ключевым моментом в организации работы WCF–клиента является получение метаданных сервиса и создание клиентских прокси–классов. Клиентское приложение будет использовать эти классы–посредники для обмена данными с веб–сервисом.
Таким образом, чтобы реализовать клиентское приложение .NET, которое могло бы работать с OData–сервисом bpm'online, необходимо:
- Создать .NET проект, в котором будет реализована интеграция с bpm'online.
- Сгенерировать клиентские прокси–классы сервиса EntityDataService.svc.
- Создать экземпляр контекста среды выполнения сервиса EntityDataService.svc.
- Реализовать клиентскую бизнес–логику интеграции с использованием методов созданного экземпляра прокси–класса.
Генерация прокси–классов на клиенте возможна несколькими способами, рассмотренными ниже.
Создание прокси–классов с использованием утилиты DataServiceModel Metadata Utility Tool (DataSvcutil.exe)
DataSvcUtil.exe представляет собой программу командной строки, предоставляемую сервисами WCF Data Services, использующую канал OData и формирующую клиентские классы службы данных, необходимые для доступа к службе данных из клиентского приложения .NET Framework. Эта программа формирует классы данных с использованием следующих источников метаданных:
- WSDL — документ метаданных службы, в котором описывается модель данных, предоставленная службой данных.
- Файл модели данных (CSDL), определенный с помощью языка определения концептуальной схемы (CSDL), описанного в спецификации [MC–CSDL]: формат файла определения концептуальной схемы.
- Файл EDMX, созданный при помощи программ для работы с моделью EDM, входящих в комплект Entity Framework. Дополнительные сведения описаны в спецификации [MC–EDMX]: модели EDM для формата упаковки служб данных.
Программа DataSvcUtil.exe установлена в каталоге .NET Framework.
Обычно это папка C:\Windows\Microsoft.NET\Framework\v4.0. Для 64–разрядных версий систем это папка C:\Windows\Microsoft.NET\Framework64\v4.0.
Формат вызова утилиты DataSvcutil.exe
datasvcutil /out:file [/in:file | /uri:serviceuri] [/dataservicecollection] [/language:devlang] [/nologo] [/version:ver] [/help]Более детальная информация по утилите DataSvcutil.exe приведена в соответстувующем разделе MSDN.
Создание прокси–классов в проекте клиентского приложения Visual Studio
Прокси–классы для клиента WCF могут быть созданы непосредственно из Visual Studio. Для этого необходимо выполнить последовательность действий:
- Щелкнуть правой клавишей мыши по проекту, в котором планируется реализация интеграции с bpm'online, выбрать в контекстном меню пункт Add Service Reference…
- В открывшемся диалоговом окне в поле Address ввести полный адрес OData–сервиса EntityDataService.svc.
- Нажать на кнопку Go. В результате откроется окно аутентификации сервиса, в котором необходимо указать имя и пароль пользователя bpm'online. Если аутентификация прошла успешно, в окне Services отобразятся поддерживаемые сервисом сущности.
- В поле Namespase указать имя пространства имен, в котором будут расположены сгенерированные прокси–классы. Например, bpm'onlineServiceReference. Ссылку на это пространство имен в дальнейшем необходимо добавить в блок using кода проекта.
- Нажать кнопку ОК, после чего будут сгенерированы прокси–классы. При этом в проект будет добавлен новый файл кода Reference.cs, содержащий описание прокси–классов, которые теперь могут использоваться для обращения и взаимодействия с ресурсами сервиса данных как с объектами.
К СВЕДЕНИЮ В Visual Studio есть возможность генерировать прокси–классы сервиса из сохраненного на диске файла метаданных сервиса. Для этого необходимо выполнить п.1 инструкции, затем в диалоговом окне Address ввести полный путь к файлу метаданных с префиксом "file://". Пример: file://C:/metadata.xml" Далее выполнить пп. 3 — 5 инструкции. |
Примеры работы с сущностями bpm'online в WCF–клиенте
После генерации прокси–классов сервиса в проект добавляется ссылка на сборку Microsoft.Data.Services.Client.dll, которая реализует поддержку протокола OData v.3. Если по какой–либо причине в клиентском приложении необходимо использовать протокол более ранней версии, то ссылку на соответствующую сборку необходимо добавить вручную.
Данная клиентская библиотека позволяет выполнять запросы к сервису данных EntityDataService.svc, используя стандартные шаблоны программирования .NET Framework, включая использование языка запросов LINQ.
Для успешной компиляции приведенных ниже примеров в код проекта необходимо добавить:
Директивы Using
using System; using System.Data.Services.Client; using System.Net; using Terrasoft.Sdk.Examples.BPMonlineServiceReference; using System.Linq;
Объявление переменной адреса сервиса OData
private static Uri serverUri = new Uri("http://<имя_сервера>/<имя_приложения>/0/ServiceModel/EntityDataService.svc/");
Получение коллекции объектов сервиса
Для получения коллекции объектов сервиса используется универсальный класс DataServiceQuery, который представляет собой запрос к сервису, возвращающий коллекцию сущностей конкретного типа.
Чтобы выполнить запрос к сервису данных EntityDataService.svc, предварительно необходимо создать экземпляр объекта контекста среды приложения bpm'online.
Необходимо помнить, что все внешние запросы к веб-сервисам bpm'online должны быть аутентифицированы. Подробнее о способах аутентификации можно ознакомиться в статье Аутентификация внешних запросов к веб-сервисам bpm'online.
Далее в примерах будет использована forms-аутентификация, реализованная на основе примере из вышеуказанной статьи.
Для реализации forms-аутентификации был создан класс LoginClass с полями authServiceUri (строка запроса к методу Login аутентификационного сервиса AuthService.svc) и AuthCookie (Cookie аутентификации bpm'online), а также методом TryLogin(string userName, string userPassword), который выполняет аутентификацию пользователя и сохраняет ответ сервера в поле AuthCookie.
Дополнительно создаем метод OnSendingRequestCookie( object sender, SendingRequestEventArgs e), который будет вызван в ответ на событие экземпляра контекста SendingRequest (создание нового экземпляра HttpWebRequest).
В методе OnSendingRequestCookie выполняется аутентификация пользователя, а полученные в ответ Cookies добавляются в запрос на получение данных.
static void OnSendingRequestCookie(object sender, SendingRequestEventArgs e) { // Вызов метода класса LoginClass, реализующего аутентификацию переданного в параметрах метода пользователя. LoginClass.TryLogin("BPMUserName", "BPMUserPassword"); var req = e.Request as HttpWebRequest; // Добавление полученных аутентификационных cookie в запрос на получение данных. req.CookieContainer = LoginClass.AuthCookie; e.Request = req; }
Выполнение запроса к сервису возможно одним из следующих способов:
- Выполнение запроса LINQ к именованному объекту DataServiceQuery, который получен из контекста сервиса.
- Неявное перечисление объекта DataServiceQuery, который получен из контекста сервиса.
- Явный вызов метода Execute объекта DataServiceQuery или BeginExecute для асинхронного выполнения.
Ниже приведены примеры доступа к объектам EntityDataService.svc каждым из приведенных способов.
1) Пример получения коллекции контактов через LINQ–запрос
Данный пример демонстрирует, как определить и выполнить запрос LINQ, возвращающий все сущности контактов сервиса EntityDataService.svc.
public static void GetOdataCollectioByLinqWcfExample() { // Создание контекста приложения BPMonline. var context = new BPMonline(serverUri); // Определение метода, который добавляет аутентификационные cookie при создании нового запроса. context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); try { // Построение запроса LINQ для получение коллекции контактов. var allContacts = from contacts in context.ContactCollection select contacts; foreach (Contact contact in allContacts) { // Выполнение действий с контактами. } } catch (Exception ex) { // Обработка ошибок. } }
2) Пример получения коллекции контактов неявным запросом к OData сервису через объект контекста
В данном примере демонстрируется, как использовать контекст для неявного выполнения запроса, возвращающего все сущности контактов сервиса EntityDataService.svc.
public static void GetOdataCollectionByImplicitRequestExample() { // Создание объекта контекста приложения BPMonline. var context = new BPMonline(serverUri); // Определение метода, который добавляет аутентификационные cookie при создании нового запроса. context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); try { // Определение неявного запроса к сервису для получения коллекции контактов. DataServiceQuery<Contact> allContacts = context.ContactCollection; foreach (Contact contact in allContacts) { // Выполнение действий с контактами. } } catch (Exception ex) { // Обработка ошибок. } }
3) Пример получения коллекции контактов явным запросом к OData сервису через объект контекста
Данный пример показывает, как использовать контекст DataServiceContext для явного выполнения запроса к сервису EntityDataService.svc, который возвращает все сущности контактов.
public static void GetOdataCollectionByExplicitRequestExample() { // Определение Uri запроса к сервису, который возвращает коллекцию контактов. Uri contactUri = new Uri(serverUri, "ContactCollection"); // Создание объекта контекста приложения BPMonline. var context = new BPMonline(serverUri); // Определение метода, который добавляет аутентификационные cookie при создании нового запроса. context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); try { // Выполнение явного запроса к сервису вызовом метода Execute<>(). foreach (Contact contact in context.Execute<Contact>(contactUri)) { // Выполнение действий с контактами. } } catch (Exception ex) { // Обработка ошибок. } }
Получение объекта с заданными характеристиками
public static void GetOdataObjectByWcfExample() { // Создание контекста приложения BPMonline. var context = new BPMonline(serverUri); // Определение метода, который добавляет аутентификационные cookie при создании нового запроса. context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); // var contact = context.ContactCollection.Where(c => c.Name.Contains("User")).First(); // Выполнение действий над контактом. }
Создание нового объекта
public static void CreateBpmEntityByOdataWcfExample() { // Создание нового контакта, инициализиция свойств. var contact = new Contact() { Id = Guid.NewGuid(), Name = "New Test User" }; // Создание и инициализация свойств нового контрагента, к которому относится создаваемый контакт. var account = new Account() { Id = Guid.NewGuid(), Name = "Some Company" }; contact.Account = account; // Создание контекста приложения BPMonline. var context = new BPMonline(serverUri); // Определение метода, который добавляет аутентификационные cookie при создании нового запроса. context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); // Добавление созданного контакта в коллекцию контактов модели данных сервиса. context.AddToAccountCollection(account); // Добавление созданного контрагента в коллекцию контрагентов модели данных сервиса. context.AddToContactCollection(contact); // Установка связи между созданными контактом и контрагентом в модели данных сервиса. context.SetLink(contact, "Account", account); // Сохранение изменений данных в BPMonline одним запросом. DataServiceResponse responces = context.SaveChanges(SaveChangesOptions.Batch); // Обработка ответов от сервера. }
Изменение существующего объекта
public static void UpdateBpmEntityByOdatetWcfExample() { // Создание контекста приложения BPMonline. var context = new BPMonline(serverUri); // Определение метода, который добавляет аутентификационные cookie при создании нового запроса. context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); // Из колллекции контактов выбирается тот, по которому будет изменяться информация. var updateContact = context.ContactCollection.Where(c => c.Name.Contains("Test")).First(); // Изменение свойств выбранного контакта. updateContact.Notes = "New updated description for this contact."; updateContact.Phone = "123456789"; // Сохранение изменений в модели данных сервиса. context.UpdateObject(updateContact); // Сохранение изменений данных в BPMonline одним запросом. var responces = context.SaveChanges(SaveChangesOptions.Batch); }
Удаление объекта
public static void DeleteBpmEntityByOdataWcfExample() { // Создание контекста приложения BPMonline. var context = new BPMonline(serverUri); context.SendingRequest += new EventHandler<SendingRequestEventArgs>(OnSendingRequestCookie); // Из коллекции контактов выбирается тот объект, который будет удален. var deleteContact = context.ContactCollection.Where(c => c.Name.Contains("Test")).First(); // Удаление выбранного объекта из модели данных сервиса. context.DeleteObject(deleteContact); // Сохранение изменений данных в BPMonline одним запросом. var responces = context.SaveChanges(SaveChangesOptions.Batch); // ОБработка ответов от сервера. }