Работа с объектами bpm'online по протоколу OData с использованием Http-запросов
Glossary Item Box
В данной статье будут рассмотрены следующие вопросы:
Для успешной компиляции приведенных ниже примеров в программный код необходимо добавить:
- директивы Using
using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Net; using System.Xml; using System.Xml.Linq;
- объявление переменных и констант
// Строка адреса BPMonline сервиса OData. private const string serverUri = "http://<имя_сервера>/<имя_приложения_BPMonline>/0/ServiceModel/EntityDataService.svc/"; private const string authServiceUtri = "http://<имя_сервера>/<имя_приложения_BPMonline>/ServiceModel/AuthService.svc/Login"; // Ссылки на пространства имен XML. private static readonly XNamespace ds = "http://schemas.microsoft.com/ado/2007/08/dataservices"; private static readonly XNamespace dsmd = "http://schemas.microsoft.com/ado/2007/08/dataservices/metadata"; private static readonly XNamespace atom = "http://www.w3.org/2005/Atom";
Операции работы с объектами и коллекциями объектов
Получение коллекции объектов
Для получения коллекции объектов используется HTTP-метод GET.
Записи возвращаются постранично, по 40 записей на страницу. Если предполагается, что запрос вернет больше 40 записей, необходимо обеспечить получение следующей страницы по достижении конца текущей.
В примере ниже демонстрируется использование конструкции $select для получения отдельных полей объекта. В результате выполнения запроса в примере будет возвращена коллекция контактов с полями Id и Name.
В приведенном примере также используется Forms-аутентификация. Имя и пароль пользователя bpm'online передаются в параметрах метода GetOdataCollectionByAuthByHttpExample(string userName, string userPassword).
// Строка запроса // GET <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection?$select=Id,Name public static void GetOdataCollectionByAuthByHttpExample(string userName, string userPassword) { // Создание запроса на аутентификацию. var authRequest = HttpWebRequest.Create(authServiceUtri) as HttpWebRequest; authRequest.Method = "POST"; authRequest.ContentType = "application/json"; var bpmCookieContainer = new CookieContainer(); // Включение использования cookie в запросе. authRequest.CookieContainer = bpmCookieContainer; // Получение потока, ассоциированного с запросом на аутентификацию. using (var requestStream = authRequest.GetRequestStream()) { // Запись в поток запроса учетных данных пользователя BPMonline и дополнительных параметров запроса. using (var writer = new StreamWriter(requestStream)) { writer.Write(@"{ ""UserName"":""" + userName + @""", ""UserPassword"":""" + userPassword + @""", ""SolutionName"":""TSBpm"", ""TimeZoneOffset"":-120, ""Language"":""Ru-ru"" }"); } } // Получение ответа от сервера. Если аутентификация проходит успешно, в объекте bpmCookieContainer будут // помещены cookie, которые могут быть использованы для последующих запросов. using (var response = (HttpWebResponse)authRequest.GetResponse()) { // Создание запроса на получение данных от сервиса OData. var dataRequest = HttpWebRequest.Create(serverUri + "ContactCollection?$select=Id, Name") as HttpWebRequest; // Для получения данных используется HTTP-метод GET. dataRequest.Method = "GET"; // Добавление полученных ранее аутентификационных cookie в запрос на получение данных. dataRequest.CookieContainer = bpmCookieContainer; // Получение ответа от сервера. using (var dataResponse = (HttpWebResponse)dataRequest.GetResponse()) { // Загрузка ответа сервера в xml-документ для дальнейшей обработки. XDocument xmlDoc = XDocument.Load(dataResponse.GetResponseStream()); // Получение коллекции объектов контактов, соответствующих условию запроса. var contacts = from entry in xmlDoc.Descendants(atom + "entry") select new { Id = new Guid(entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Id").Value), Name = entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Name").Value }; foreach (var contact in contacts) { // Выполнение действий с контактами. } } }
К СВЕДЕНИЮ
Если необходимо отправлять запрос и получать ответ в формате JSON, укажите в заголовке запроса:
Content-Type = "application/json"
Accept = "application/json;odata=verbose"
Если необходимо, чтобы запрос возвращал более, чем 40 записей за один раз, это можно реализовать с использованием параметра $top, в котором указывается требуемое количество возвращаемых запросом записей. Так, в приведенном ниже примере формируется строка запроса к сервису для получения первых 60 объектов коллекции контактов.
Пример использования параметра $top
string requestUri = serverUri + "ContactCollection?$top=60";
В bpm'online поддерживается использование параметра $skip, который позволяет запрашивать у сервиса ресурсы, пропустив заданное количество записей.
В приведенном ниже примере продемонстрировано формирование строки запроса к сервису для получения коллекции контактов, начиная с 11 записи.
Пример использования параметра $skip
string requestUri = serverUri + "ContactCollection?$skip=10";
Ресурсы сервиса можно получать в отсотрированном виде. Для этого в запросе нужно использовать параметр $orderby [asc|desc], в котором указать, по какому полю выполнять сортировку результатов. Кроме того, для данного параметра можно указать одно из направлений сортировки:
- по возрастанию (asc)
- по убыванию (desc)
По умолчанию используется сортировка по возрастанию (asc).
В примере ниже формируется строка запроса к сервису для получения коллекции контактов, отсортированной по возрастанию значения поля Name.
Пример использования параметра $orderby для сортировки по возрастанию
string requestUri = serverUri + "ContactCollection?$orderby=Name";
Параметры $top, $skip, $orderby можно использовать в различных комбинациях для получения конкретного фрагмента коллекции.
Пример использования параметров $orderby, $top, $skip в комбинации
string requestUri = serverUri + "ContactCollection?$top=4&$skip=1&$orderby=City/Name";
Получение объекта с заданными характеристиками
Для получения объекта используется HTTP-метод GET.
Получение конкретного объекта, который отвечает определенным условиям (например, контакт с заданным Id или контрагент с определенным названием и т.д.) можно реализовать несколькими способами (в приведенных ниже примерах используется Basic-аутентификация запросов).
Задание Id искомого объекта в качестве параметра коллекции
// Строка запроса: // GET <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection(guid'00000000-0000-0000-0000-000000000000') public static void GetOdataObjectByIdExample() { // Id искомого объекта. string contactId = "00000000-0000-0000-0000-000000000000"; // Формирование строки запроса к сервису. string requestUri = serverUri + "ContactCollection(guid'" + contactId + "')"; // Создание объекта запроса к сервису. var request = HttpWebRequest.Create(requestUri) as HttpWebRequest; request.Method = "GET"; request.Credentials = new NetworkCredential("BPMUserName", "BPMUserPassword"); using (var response = request.GetResponse()) { // Получение ответа от сервиса в xml-формате. XDocument xmlDoc = XDocument.Load(response.GetResponseStream()); // Получение коллекции объектов контактов, соответствующих условию запроса. var contacts = from entry in xmlDoc.Descendants(atom + "entry") select new { Id = new Guid(entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Id").Value), Name = entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Name").Value // Инициализация свойств объекта, необходимых для дальнейшего использования. }; foreach (var contact in contacts) { // Выполнение действий над контактом. } } }
Данный способ можно использовать только в том случае, если необходимо получить объект с заданным идентификатором.
Если в качестве параметров искомого объекта выступает не идентификатор объекта или искомый объект определяется несколькими параметрами, то необходимо использовать конструктцию $filter для определения параметров.
Использование конструкции $filter для формирования сложного условия выбора объекта
Конструкция $filter позволяет строить логические выражения условий выбора искомого объекта.
В выражениях $filter можно использовать ссылки на свойства и литералы, а также строки, числа и логические выражения (true, false). Выражения $filter поддерживают арифметические, логические операции, а также операции группировки, операции со строками, датой и временем. Полный перечень операций конструкции $filter приведен в спецификации OData.
Рассмотрим пример получения объекта с заданным Id, используя для задания условия конструкции $filter.
// Строка запроса: // GET <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection?$filter=Id eq guid'00000000-0000-0000-0000-000000000000' public static void GetOdataObjectByFilterConditionExample() { // Id искомого объекта. string contactId = "00000000-0000-0000-0000-000000000000"; // Формирование строки запроса к сервису. string requestUri = serverUri + "ContactCollection?$filter = Id eq guid'" + contactId + "'"; // Создание объекта запроса к сервису. var request = HttpWebRequest.Create(requestUri) as HttpWebRequest; request.Method = "GET"; request.Credentials = new NetworkCredential("BPMUserName", "BPMUserPassword"); using (var response = request.GetResponse()) { // Получение ответа от сервиса в xml-формате. XDocument xmlDoc = XDocument.Load(response.GetResponseStream()); // Получение коллекции объектов контактов, соответствующих условию запроса. var contacts = from entry in xmlDoc.Descendants(atom + "entry") select new { Id = new Guid(entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Id").Value), Name = entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Name").Value // Инициализация свойств объекта, необходимых для дальнейшего использования. }; foreach (var contact in contacts) { // Выполнение действий над контактом. } } }
Ниже приведен пример возвращения коллекции объектов контактов, которые были созданы пользователем SomeUserName после 1.11.2012.
// Строка запроса: // GET <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection?$filter=CreatedOn gt datetime'2012-11-01' and CreatedBy/Name eq 'SomeUserName' public static void GetOdataObjectByFilterDiffConditionExample() { // Имя пользователя, который создал объекты. string userName = "BPMUserName"; // Дата создания объектов. string datetime = "2012-11-01"; // Формирование строки запроса к сервису. string requestUri = serverUri + "ContactCollection?$filter=CreatedOn gt datetime'" + datetime + "'and CreatedBy/Name eq '" + userName + "'"; // Создание объекта запроса к сервису. var request = HttpWebRequest.Create(requestUri) as HttpWebRequest; request.Method = "GET"; request.Credentials = new NetworkCredential(userName, "BPMUserPassword"); using (var response = request.GetResponse()) { // Получение ответа от сервиса в xml-формате. XDocument xmlDoc = XDocument.Load(response.GetResponseStream()); // Получение коллекции объектов контактов, соответствующих условию запроса. var contacts = from entry in xmlDoc.Descendants(atom + "entry") select new { Id = new Guid(entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Id").Value), Name = entry.Element(atom + "content") .Element(dsmd + "properties") .Element(ds + "Name").Value // Инициализация свойств объекта, необходимых для дальнейшего использования. }; foreach (var contact in contacts) { // Выполнение действий над контактом. } } }
Больше примеров построения запросов с помощью конструкции $filter вы можете найти в статье "Примеры запросов на выборку с фильтрацией".
Создание нового объекта
Для создания объекта используется HTTP-метод POST.
При этом необходимо сформировать тело запроса в формате Atom/XML или JSON таким образом, чтобы он содержал все необходимые поля объекта. Все возможные поля создаваемого объекта описаны в метаданных сервиса.
К СВЕДЕНИЮ
Если необходимо отправлять запрос и получать ответ в формате JSON, укажите в заголовке запроса:
Content-Type = "application/json"
Accept = "application/json;odata=verbose"
Ниже приведен пример создания нового контакта. В примере применяется Basic-аутентификация запроса.
// Строка запроса: // POST <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection/ public static void CreateBpmEntityByOdataHttpExample() { // Создание сообщения xml, содержащего данные о создаваемом объекте. var content = new XElement(dsmd + "properties", new XElement(ds + "Name", "Иван Иванов"), new XElement(ds + "Dear", "Иван")); var entry = new XElement(atom + "entry", new XElement(atom + "content", new XAttribute("type", "application/xml"), content)); Console.WriteLine(entry.ToString()); // Создание запроса к сервису, который будет добавлять новый объект в коллекцию контактов. var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "ContactCollection/"); request.Credentials = new NetworkCredential("BPMUserName", "BPMUserPassword"); request.Method = "POST"; request.Accept = "application/atom+xml"; request.ContentType = "application/atom+xml;type=entry"; // Запись xml-сообщения в поток запроса. using (var writer = XmlWriter.Create(request.GetRequestStream())) { entry.WriteTo(writer); } // Получение ответа от сервиса о результате выполнения операции. using (WebResponse response = request.GetResponse()) { if (((HttpWebResponse)response).StatusCode == HttpStatusCode.Created) { // Обработка результата выполнения операции. } } }
Изменение существующего объекта
Для изменения записи используется HTTP-метод PUT (или MERGE в более новых версиях OData).
К СВЕДЕНИЮ
Если необходимо отправлять запрос и получать ответ в формате JSON, укажите в заголовке запроса:
Content-Type = "application/json"
Accept = "application/json;odata=verbose"
В теле запроса передаются новые значения полей, которые нужно изменить. В строке запроса необходимо указать коллекцию, объект которой изменяется, а в качестве параметра коллекции указать идентификатор изменяемого объекта.
Ниже приведен пример изменения имени контакта с идентификатором 00000000-0000-0000-0000-000000000000 из коллекции контактов ContactCollection. В примере используется Basic-аутентификация запросов.
// Строка запроса: // PUT <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection(guid'00000000-0000-0000-0000-000000000000') // или // MERGE <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection(guid'00000000-0000-0000-0000-000000000000') public static void UpdateExistingBpmEnyityByOdataHttpExample() { // Id записи объекта, который необходимо изменить. string contactId = "00000000-0000-0000-0000-000000000000"; // Создание сообщения xml, содержащего данные об изменяемом объекте. var content = new XElement(dsmd + "properties", new XElement(ds + "Name", "Новое имя") ); var entry = new XElement(atom + "entry", new XElement(atom + "content", new XAttribute("type", "application/xml"), content) ); // Создание запроса к сервису, который будет изменять данные объекта. var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "ContactCollection(guid'" + contactId + "')"); request.Credentials = new NetworkCredential("BPMUserName", "BPMUserPassword"); // или request.Method = "MERGE"; request.Method = "PUT"; request.Accept = "application/atom+xml"; request.ContentType = "application/atom+xml;type=entry"; // Запись сообщения xml в поток запроса. using (var writer = XmlWriter.Create(request.GetRequestStream())) { entry.WriteTo(writer); } // Получение ответа от сервиса о результате выполнения операции. using (WebResponse response = request.GetResponse()) { // Обработка результата выполнения операции. } }
Удаление объекта
Для удаления записи используется HTTP-метод DELETE.
К СВЕДЕНИЮ
Если необходимо отправлять запрос и получать ответ в формате JSON, укажите в заголовке запроса:
Content-Type = "application/json"
Accept = "application/json;odata=verbose"
В строке запроса необходимо указать коллекцию, объект которой удаляется, а в качестве параметра коллекции указать идентификатор удаляемого объекта.
Ниже приведен пример удаления контакта с идентификатором 00000000-0000-0000-0000-000000000000 из коллекции контактов ContactCollection. В примере используется Basic-аутентификация запросов.
// Строка запроса: // DELETE <Адрес приложения BPMonline>/0/ServiceModel/EntityDataService.svc/ContactCollection(guid'00000000-0000-0000-0000-000000000000') public static void DeleteBpmEntityByOdataHttpExample() { // Id записи объекта, который необходимо удалить. string contactId = "00000000-0000-0000-0000-000000000000"; // Создание запроса к сервису, который будет удалять данные. var request = (HttpWebRequest)HttpWebRequest.Create(serverUri + "ContactCollection(guid'" + contactId + "')"); request.Credentials = new NetworkCredential("BPMUserName", "BPMUserPassword"); request.Method = "DELETE"; // Получение ответа от сервися о результате выполненя операции. using (WebResponse response = request.GetResponse()) { // Обработка результата выполнения операции. } }
Функции работы со строками
BPMonine поддерживает следующие функции работы со строками протокола OData, которые могут быть применены для построения выражений конструкции $filter.
Функция | Пример строки запроса | Результат выполнения запроса |
---|---|---|
bool substringof(string po, string p) | <Адрес сервиса>/ContactCollection?$filter=substringof('Smith', Name) | Коллекция контактов, в имени которых присутствует подстрока 'Smith' |
string toupper(string p0) | <Адрес сервиса>/ContactCollection?$filter=toupper(Name) eq 'TEST USER' | Коллекция контактов, имя которых в верхнем регистре равно 'TEST USER' |
bool endswith(string p0, string p1) | <Адрес сервиса>/ContactCollection?$filter=endswith(Name, 'User') | Коллекция контактов, имя которых оканчивается подстрокой 'User'. |
int length(string p0) | <Адрес сервиса>/ContactCollection?$filter=length(Name) gt 10 | Коллекция контактов, длина имени которых больше 10 символов. |
string trim(string p0) | <Адрес сервиса>/ContactCollection?$filter=trim(Name) eq 'Test User' | Коллекция контактов, имя которых после удаления начальных и конечных пробелов равно 'Test User'. |
Полный перечень функций работы со строками протокола OData приведен в официальной спецификации OData.
Функции работы с датой и временем
BPMonine поддерживает следующие функции работы с датами протокола OData, которые могут быть применены для построения выражений конструкции $filter.
Функция | Пример строки запроса | Результат выполнения запроса |
---|---|---|
int year(DateTime p0) | <Адрес сервиса>/ContactCollection?$filter=year(BirthDate) ge 1950 and year(BirthDate) le 1990 | Коллекция контактов, чей год рождения находится в интервале от 1950 до 1990 гг. включительно. |
int month(DateTime p0) | <Адрес сервиса>/ContactCollection?$filter=month(BirthDate) eq 5 | Коллекция контактов, родившихся в мае месяце. |
int day(DateTime p0) | < span>/ContactCollection?$filter=day(BirthDate) eq 15 | Коллекция контактов, родившихся 15 числа. |