DataService. Пакетные запросы
Glossary Item Box
Общие положения
Веб-служба DataService приложения bpm'online является RESTful-сервисом, т.е. поддерживает передачу состояния представления (Representational State Transfer, REST). В общем случае REST является очень простым интерфейсом управления информацией без использования каких-то дополнительных внутренних прослоек, т.е. данные не нужно преобразовывать в какой-либо сторонний формат, например, XML. В простом RESTful-сервисе каждая единица информации однозначно определяется глобальным идентификатором, таким как URL. Каждый URL, в свою очередь, имеет строго заданный формат. Однако это не всегда удобно для передачи больших массивов данных.
Поскольку веб-служба DataService реализована на основе .NET фреймворка ServiceStack, то данные автоматичеcки могут быть сконфигурированы в различные форматы данных, такие как XML, JSON, HTML, CSV и JSV. Структура данных определяется так называемыми контрактами данных. Полный перечень контрактов данных, используемых службой DataService, изложен в статье "Веб-служба DataService".
Пакетные запросы
Пакетные запросы используются для минимизации обращений к службе DataService, что, в свою очередь, значительно повышает производительность приложения. Пакетный запрос является коллекцией, содержащей произвольный набор запросов к службе DataService. Передача данных в службу DataService осуществляется по HTTP-протоколу при помощи POST-запроса по следующему URL:
// Формат URL для пакетного POST-запроса к DataService. http(s)://[Адрес приложения bpm'online]/[Номер конфигурации]/dataservice/[Формат данных]/reply/BatchQuery // Пример URL для пакетного POST-запроса к DataService. http(s)://example.bpmonline.com/0/dataservice/json/reply/BatchQuery
Непосредственно данные, составляющие пакетный запрос, могут передаваться в различных форматах. Одним из удобных для восприятия форматов является формат JSON. Структура пакетного запроса в формате JSON:
{ "items": [ { "__type": "[Полное квалифицированное имя типа запроса]", //Содержимое единичного запроса. ... }, // Другие единичные запросы. ... ] }
Для формирования содержимого единичных запросов, образующих пакетный запрос, можно воспользоваться контрактами данных InsertQuery, SelectQuery, UpdateQuery и DeleteQuery.
Пример использования пакетного запроса в стороннем приложении
Описание кейса
Необходимо создать консольное приложение, которое, используя службу DataService:
-
добавит в раздел [Контакты] запись со значением колонки [ФИО] — Петров Петр Петрович;
- изменит значение колонки [Рабочий телефон] на 012 345 67 89 для всех записей раздела [Контакты], у которых значение колонки [ФИО] равно Петров Петр Петрович.
Создание и изменение записей выполнить с помощью пакетного запроса.
Пример реализации
Полностью исходный код выполнения данного примера можно скачать здесь.
Алгоритм реализации кейса
1. Создать и настроить проект консольного приложения C#
Используя среду разработки Microsoft Visual Studio (версии не ниже 2012 Update 4), необходимо создать проект консольного приложения Visual C#, указав в качестве названия проекта, например, DataServiceBatchExample. Свойству проекта [Target framework] необходимо установить значение .NET Framework 4.5.
В секцию References проекта нужно добавить зависимости от следующих библиотек:
- System.Web.Extensions.dll — библиотека классов, входящая в .NET Farmework;
- Terrasoft.Core.dll — библиотека основных классов серверного ядра приложения. Можно найти по следующему пути: [Каталог с установленным приложением]\Terrasoft.WebApp\bin\Terrasoft.Core.dll;
- Terrasoft.Nui.ServiceModel.dll — библиотека классов служб приложения. Можно найти по следующему пути: [Каталог с установленным приложением]\Terrasoft.WebApp\bin\Terrasoft.Nui.ServiceModel.dll;
- Terrasoft.Common.dll — библиотека основных классов серверного ядра приложения. Можно найти по следующему пути: [Каталог с установленным приложением]\Terrasoft.WebApp\bin\Terrasoft.Common.dll.
В файл исходного кода приложения необходимо добавить директивы using:
using System; using System.Text; using System.IO; using System.Net; using System.Collections.Generic; using Terrasoft.Nui.ServiceModel.DataContract; using Terrasoft.Core.Entities; using System.Web.Script.Serialization; using Terrasoft.Common;
2. В исходный код приложения добавить объявления полей и констант
Для доступа к возможностям службы DataService в исходный код приложения необходимо добавить следующие поля и константы:
// Основной URL приложения bpm'online. Необходимо заменить на пользовательский. private const string baseUri = @"http://example.bpmonline.com"; // Строка запроса к методу Login сервиса AuthService.svc. private const string authServiceUri = baseUri + @"/ServiceModel/AuthService.svc/Login"; // Строка пути запроса BatchQuery. private const string batchQueryUri = baseUri + @"/0/DataService/json/reply/BatchQuery"; // Cookie аутентификации bpm'online. private static CookieContainer AuthCookie = new CookieContainer();
Здесь объявлены три строковых константных поля, с помощью которых формируются пути выполнения запросов на аутентификацию и запросов на чтение данных. Данные об аутентификации будут сохранены в поле AuthCookie.
3. Добавить метод, выполняющий аутентификацию в приложении bpm'online
Для доступа создаваемого приложения к веб-службе DataService необходимо выполнить аутентификацию.
Алгоритм действия и пример реализации метода, который выполняет запрос к службе AuthService.svc для аутентификации пользователя, подробно изложены в статье "Аутентификация внешних запросов к веб-сервисам bpm'online".
4. Реализовать запрос на добавление записи
Поскольку объявленная ранее константа batchQueryUri содержит путь для отправки данных в формате JSON, то отправляемые данные нужно предварительно сконфигурировать в виде строки, содержащей описание JSON-объекта. Для формирования содержимого единичных запросов удобно воспользоваться классами-контрактами данных, а затем сериализовать их в строку.
Для формирования запроса на добавление записи в раздел [Контакты] со значением колонки [ФИО] — Петров Петр Петрович, необходимо добавить следующий програмный код:
// Запрос на добавление данных. var insertQuery = new InsertQuery() { RootSchemaName = "Contact", ColumnValues = new ColumnValues() { Items = new Dictionary<string, ColumnExpression>() { { "Name", new ColumnExpression() { ExpressionType = EntitySchemaQueryExpressionType.Parameter, Parameter = new Parameter { Value = "Петров Петр Петрович", DataValueType = DataValueType.Text } } } } } };
Подробнее о контракте данных InsertQuery и запросах на добавление данных можно узнать из статьи "DataService. Создание записи. Пример".
Для изменения значения колонки [Рабочий телефон] на 012 345 67 89 для всех записей раздела [Контакты], у которых значение колонки [ФИО] равно Петров Петр Петрович, необходимо добавить следующее:
// Запрос на обновление данных. var updateQuery = new UpdateQuery() { RootSchemaName = "Contact", ColumnValues = new ColumnValues() { Items = new Dictionary<string, ColumnExpression>() { { "Phone", new ColumnExpression() { ExpressionType = EntitySchemaQueryExpressionType.Parameter, Parameter = new Parameter() { Value = "0123456789", DataValueType = DataValueType.Text } } } } }, Filters = new Filters() { FilterType = Terrasoft.Nui.ServiceModel.DataContract.FilterType.FilterGroup, Items = new Dictionary<string, Filter>() { { "FilterByName", new Filter { FilterType = Terrasoft.Nui.ServiceModel.DataContract.FilterType.CompareFilter, ComparisonType = FilterComparisonType.Equal, LeftExpression = new BaseExpression() { ExpressionType = EntitySchemaQueryExpressionType.SchemaColumn, ColumnPath = "Name" }, RightExpression = new BaseExpression() { ExpressionType = EntitySchemaQueryExpressionType.Parameter, Parameter = new Parameter() { DataValueType = DataValueType.Text, Value = "Петров Петр Петрович" } } } } } } };
Подробнее о контракте данных UpdateQuery и запросах на изменение данных можно узнать из статьи "DataService. Обновление записи. Пример".
После сериализации созданных экземпляров классов запросов, в строки с JSON-объектами необходимо добавить сведения о полном квалифицированном имени типа соответствующего контракта данных. Затем необходимо сформировать строку, содержащую пакетный запрос:
// Сериализация экземпляра класса запроса на добавление в JSON-строку. var jsonInsert = new JavaScriptSerializer().Serialize(insertQuery); // Вставка типа запроса в в JSON-строку. jsonInsert = jsonInsert.Insert(1, @"""__type"": ""Terrasoft.Nui.ServiceModel.DataContract.InsertQuery"","); // Сериализация экземпляра класса запроса на обновление в JSON-строку. var jsonUpdate = new JavaScriptSerializer().Serialize(updateQuery); // Вставка типа запроса в в JSON-строку. jsonUpdate = jsonUpdate.Insert(1, @"""__type"": ""Terrasoft.Nui.ServiceModel.DataContract.UpdateQuery"","); // Формирование пакетного запроса. var json = @"{""items"": [" + jsonInsert + "," + jsonUpdate + "]}";
На завершающем шаге необходимо выполнить POST-запрос к службе DataService. Для этого необходимо создать экземпляр класса HttpWebRequest, заполнить его свойства, присоединить к запросу созданную ранее строку с JSON-объектом, а затем выполнить и обработать результат запроса к службе DataService. Для этого нужно добавить следующий исходный код:
// Преобразование строки JSON-объекта в массив байтов. byte[] jsonArray = Encoding.UTF8.GetBytes(json); // Создание экземпляра HTTP-запроса. var batchRequest = HttpWebRequest.Create(deleteQueryUri) as HttpWebRequest; // Определение метода запроса. batchRequest.Method = "POST"; // Определение типа содержимого запроса. batchRequest.ContentType = "application/json"; // Добавление полученных ранее аутентификационных cookie в запрос на получение данных. batchRequest.CookieContainer = AuthCookie; // Set the ContentLength property of the WebRequest. batchRequest.ContentLength = jsonArray.Length; // Помещение в содержимое запроса JSON-объекта. using (var requestStream = batchRequest.GetRequestStream()) { requestStream.Write(jsonArray, 0, jsonArray.Length); } // Выполнение HTTP-запроса и получение ответа от сервера. using (var response = (HttpWebResponse)batchRequest.GetResponse()) { // Вывод ответа в консоль. using (StreamReader reader = new StreamReader(response.GetResponseStream())) { Console.WriteLine(reader.ReadToEnd()); } } // Задержка выполнения приложения. Console.ReadKey();
Полностью исходный код выполнения данного примера можно скачать здесь.