Коллеги, здравствуйте. Возникла проблема - веб-сервис возвращает значения, однако мы не можем их увидеть на преднастроенной странице в bpmonline - в соответствующих полях отображаются 0 (если числовое) и пустота (если строковое). Другие веб-сервисы отображаются корректно, проблема только с одним конкретным. При этом, сам веб-сервис работает корректно, т.е. формирует и отправляет нужный запрос на bpmonline, а дальше мы не можем его отобразить. Используем простой бизнес-процесс, в котором элементы веб-сервис и преднастроенная страница. Будем признательны за помощь

Нравится

1 комментарий
Лучший ответ

Добрый день,

Проблема может быть в типах данных. Если бы вы предоставили скриншоты вашего БП, вам бы быстрей помогли с вашей проблемой.

Добрый день,

Проблема может быть в типах данных. Если бы вы предоставили скриншоты вашего БП, вам бы быстрей помогли с вашей проблемой.

Показать все комментарии

Доброго времени суток, в общем проблема такая. Необходимо отправить на веб сервер данные в формате xml, на сколько я понял из документации элемент "Вызвать веб сервер" отправляет Json запросы  а не XML. Возможно ли отправить запрос в веб сервер в формате XML из элемента "Задание сценарии" или лучше каким нибудь другим ходом пойти? Буду признателен за советы , а желательно с  примером)  

Нравится

1 комментарий
Лучший ответ

Добрый день!

Да, лучше отправьте с помощью задания-сценария с использованием HttpWebRequest.

Пример:

var request = (HttpWebRequest)WebRequest.Create(serviceAddress);
request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
request.Timeout = timeout * 1000;
using (var dataStream = request.GetRequestStream())
{
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();
}
var resp = (HttpWebResponse)request.GetResponse();

Где postData - строка XML

Добрый день!

Да, лучше отправьте с помощью задания-сценария с использованием HttpWebRequest.

Пример:

var request = (HttpWebRequest)WebRequest.Create(serviceAddress);
request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
request.Timeout = timeout * 1000;
using (var dataStream = request.GetRequestStream())
{
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();
}
var resp = (HttpWebResponse)request.GetResponse();

Где postData - строка XML

Показать все комментарии

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

Нравится

1 комментарий

Да, элемент «Веб-сервис» в БП для этого и создавался.

В обратном направлнии можно извне либо запустить БП при помощи ProcessEngineService, либо менять значение поля по OData. В обоих случаях сначала нужно залогиниться, используя AuthService и получить CSRF-токен.

Показать все комментарии

Доброго дня, коллеги!

Стоит следующая задача - необходимо считать и отправить данные из объекта на удаленный веб-сервис. Удаленный веб-сервис принимает данные в формате XML. Подскажите пожалуйста, каким образом лучше всего это реализовать - используя бизнес-процессы, DataService или каким-либо другим способом? Заранее благодарю за развернутые ответы. 

Нравится

1 комментарий
Лучший ответ

Добрый день!

Бизнес процесс, в котором скрипт С# с использованием HttpWebRequest.

Пример:

var request = (HttpWebRequest)WebRequest.Create(serviceAddress);
request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
request.Timeout = timeout * 1000;
using (var dataStream = request.GetRequestStream())
{
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();
}
var resp = (HttpWebResponse)request.GetResponse();

Где postData - строка XML

Добрый день!

Бизнес процесс, в котором скрипт С# с использованием HttpWebRequest.

Пример:

var request = (HttpWebRequest)WebRequest.Create(serviceAddress);
request.Method = "POST";
byte[] byteArray = Encoding.UTF8.GetBytes(postData);
request.ContentType = "application/x-www-form-urlencoded";
request.ContentLength = byteArray.Length;
request.Timeout = timeout * 1000;
using (var dataStream = request.GetRequestStream())
{
    dataStream.Write(byteArray, 0, byteArray.Length);
    dataStream.Close();
}
var resp = (HttpWebResponse)request.GetResponse();

Где postData - строка XML

Показать все комментарии

Добрый день, уважаемое сообщество!

Возникла необходимость передать во внешний сервис список проектов, привязанных к контакту текущего пользователя (под которым была выполнена аутентификация через AuthService.svc). При вызове процесса через  ProcessEngineService.svc я могу получить контакт текущего пользователя и выполнить нужный запрос, но не могу вернуть его результат (или могу?).

А при обращения через OData я могу получить результат запроса, но не представляю, как в него добавить фильтр по текущему контакту.

Подскажите, пожалуйста, как мне быть.

Нравится

3 комментария
Лучший ответ

Посмотрите в академии ПРИМЕРЫ ЗАПРОСОВ НА ВЫБОРКУ С ФИЛЬТРАЦИЕЙ

На вскидку вам надо получить id текущего пользователя в переменую ContactCurrentUserId и вызвать чтото типа

В примере ниже e71dceda-9b0f-4509-aa10-f479aa69a9eb - Id контакта текущего пользователя а фильтрация идет по значению Guid в поле Contact объекта Project

Url сайта>/0/ServiceModel/EntityDataService.svc/ProjectCollection?$filter=Contact/Id eq guid'e71dceda-9b0f-4509-aa10-f479aa69a9eb'

 

Посмотрите в академии ПРИМЕРЫ ЗАПРОСОВ НА ВЫБОРКУ С ФИЛЬТРАЦИЕЙ

На вскидку вам надо получить id текущего пользователя в переменую ContactCurrentUserId и вызвать чтото типа

В примере ниже e71dceda-9b0f-4509-aa10-f479aa69a9eb - Id контакта текущего пользователя а фильтрация идет по значению Guid в поле Contact объекта Project

Url сайта>/0/ServiceModel/EntityDataService.svc/ProjectCollection?$filter=Contact/Id eq guid'e71dceda-9b0f-4509-aa10-f479aa69a9eb'

 

Через OData можно считать SysAdminUnit с фильтрацией по логину пользователя, тем самым получить contactId. А дальше делать уже запрос на выборку и фильтрацию проектов.

Через ProcessEngineService можно получить значение пвраметра (указав название параметра в ResultParameterName), но с интерпретируемыми процессами это работает плохо

В 7.17.1 должен появиться возврат результата из нынешних интерпретируемых БП, в академии будут инструкции по запуску из клиентского и серверного кода.

Показать все комментарии

Запускаю из сервиса БП, в котором нет никаких ожиданий.

UserConnection 	userConnection	= HttpContext.Current.Session["UserConnection"] as UserConnection;
var 			manager 		= userConnection.ProcessSchemaManager;
var 			processSchema 	= manager.GetInstanceByName("UsrProcess");
var 			process 		= processSchema.CreateProcess(userConnection);
 
process.SetPropertyValue("ExternalCall", true);
process.Execute(userConnection);

Подскажите, как дождаться завершения БП и прочитать параметры, которые мы имеем в конце выполнения?

Нравится

8 комментариев
Лучший ответ

Добрый день!

Данное действие синхронно, т.е. после завершения операции process.Execute(userConnection); уже можно забирать параметры.

Забирать их следующим образом (пример):

res.Success = process.GetPropertyValue("RpSuccess") != null ? (bool)process.GetPropertyValue("RpSuccess") : false;
res.ErrorDescription = process.GetPropertyValue("RpReturnMsg") != null ? (string)process.GetPropertyValue("RpReturnMsg") : "";

 

Добрый день!

Данное действие синхронно, т.е. после завершения операции process.Execute(userConnection); уже можно забирать параметры.

Забирать их следующим образом (пример):

res.Success = process.GetPropertyValue("RpSuccess") != null ? (bool)process.GetPropertyValue("RpSuccess") : false;
res.ErrorDescription = process.GetPropertyValue("RpReturnMsg") != null ? (string)process.GetPropertyValue("RpReturnMsg") : "";

 

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

if (process.Status != ProcessStatus.Running && process.Status != ProcessStatus.Error)

or

if (process.Status == Terrasoft.Core.Process.ProcessStatus.Done)

Как выяснилось, мне нужен интерпретируемый процесс, а там все немного по-другому, а именно

UserConnection 	userConnection	= HttpContext.Current.Session["UserConnection"] as UserConnection;
var manager 		= userConnection.ProcessSchemaManager;
var processSchema 	= manager.GetInstanceByName("UsrPreCreateDealProcess");
var flowEngine 		= new Terrasoft.Core.Process.FlowEngine(userConnection);
Dictionary<string, object> parameter = new Dictionary<string, object>();
parameter.Add("CarId", car_id);
Terrasoft.Core.Process.ProcessDescriptor pd = flowEngine.RunProcess(processSchema, parameter);
if (pd.ProcessStatus == Terrasoft.Core.Process.ProcessStatus.Done)
{
	?????
}

Как вытащить параметры в конце выполнения здесь?

Есть предположение, что копать стоит в сторону FlowEngineStateService, у него есть метод FindProcessComponentSet(Guid processUId), который возвращает инфу о процессе. И там уже забрать параметры

Сидоров Александр В.,

я нашел этот класс, у него есть метод GetParameterValue, но он стабильно возвращает, что параметр не найден по данному пути и возникает (философский) вопрос, что есть Путь? Видимо, это не просто имя. Но товарищи из Террасофта не догадались описать этот момент нигде ни разу.

перепробовал всё с FlowEngineStateService - ничего не работает, написал в ТП

Вообще, не очень хорошо запускать процессы и ждать их завершения синхронно. Ведь процесс может выполняться некоторое время или вообще иметь элементы для общения с пользователем. Лучше будет в самом процессе записывать результаты в какую-то таблицу, а потом периодически её новые записи обрабатывать.

ТП ответила, что решения в 7.11 нет. Я так и знал :)) и заранее сделал обходной путь через БД. Заодно полезное для отладки логирование получилось

Показать все комментарии

Доброго времени суток, подскажите пожалуйста, как можно задать время выполнения веб-сервиса со сторона JavaScript?



По умолчанию как я понял стоит секунд 30, после отваливается с ошибкой "Превышен лимит времени выполнения запроса к серверу приложений статус ответа..."

Вызываю обычный сервис так:

ServiceHelper.callService("ServiceName", "ServiceMethodPost", function(response) {
	window.console.log(response);
}, serviceData, this);

 

Нравится

5 комментариев
Лучший ответ

Сериков Асхат Кайратович,

Данный вариант правильный

var config = {
		serviceName: "ServiceName",
		timeout: 100000
	};
var serviceData = {
	phoneNumber: phoneNumber ? phoneNumber : "",
	userName: contact.displayValue,
	email: email ? email : ""
};
ServiceHelper.callService(config, "ServiceMethodPost",  function(response) {
	window.console.log(response);
}, serviceData, this);

Логика ServiceHelper выглядит так:

define("ServiceHelper", ["ext-base", "terrasoft"], function(Ext, Terrasoft) {
 
	/**
	 * ######## ##### ###-#######.
	 * @param {String|Object} config ### ####### ### ######### ###### #######.
	 * @param {String} methodName ### ######.
	 * @param {Function} callback (optional) ####### ######### ######.
	 * @param {Object} data (optional) ###### # ####### #######.
	 * @param {Object} scope (optional) ######## ######.
	 * @return {Object} ######### #######.
	 */
	function internalCallService(config, methodName, callback, data, scope) {
		var serviceName;
		if (config && Ext.isObject(config)) {
			serviceName = config.serviceName;
			methodName = config.methodName;
			callback = config.callback;
			data = config.data;
			scope = config.scope;
		} else {
			serviceName = config;
		}
		var dataSend = data || {};
		var workspaceBaseUrl = Terrasoft.utils.uri.getConfigurationWebServiceBaseUrl();
		var requestUrl = workspaceBaseUrl + "/rest/" + serviceName + "/" + methodName;
		var requestConfig = {
			url: requestUrl,
			headers: {
				"Accept": "application/json",
				"Content-Type": "application/json"
			},
			method: "POST",
			jsonData: Ext.encode(dataSend),
			callback: function(request, success, response) {
				if (!callback) {
					return;
				}
				var responseObject = response;
				if (success) {
					responseObject = Terrasoft.decode(response.responseText);
				}
				callback.call(this, responseObject, success);
			},
			scope: scope || this
		};
		if (config && config.timeout) {
			requestConfig.timeout = config.timeout;
		}
		return Terrasoft.AjaxProvider.request(requestConfig);
	}
 
	return {
		callService: internalCallService
	};
});

 

Добрый день!

Timeout указывается в конфиге вызова сервиса (параметр timeout).

В вашем случае будет так:

var config = {
		serviceName: "ServiceName",
		timeout: 100000
	};
ServiceHelper.callService(config, "ServiceMethodPost",  function(response) {
	window.console.log(response);
}, serviceData, this);

 

Сидоров Александр В.,

Спасибо

var serviceData = {
	phoneNumber: phoneNumber ? phoneNumber : "",
	userName: contact.displayValue,
	email: email ? email : ""
};
ServiceHelper.callService("ServiceName", "MethodName", function(response) {
	window.console.log(response);
}, serviceData, this);

В моем случае в serviceData есть другие параметры веб сервиса, их нужно будет в отдельный объект выложить? Не совсем понимаю как БПМ определит что является обычным параметром, а что конфигурационным

Сериков Асхат Кайратович,

Данный вариант правильный

var config = {
		serviceName: "ServiceName",
		timeout: 100000
	};
var serviceData = {
	phoneNumber: phoneNumber ? phoneNumber : "",
	userName: contact.displayValue,
	email: email ? email : ""
};
ServiceHelper.callService(config, "ServiceMethodPost",  function(response) {
	window.console.log(response);
}, serviceData, this);

Логика ServiceHelper выглядит так:

define("ServiceHelper", ["ext-base", "terrasoft"], function(Ext, Terrasoft) {
 
	/**
	 * ######## ##### ###-#######.
	 * @param {String|Object} config ### ####### ### ######### ###### #######.
	 * @param {String} methodName ### ######.
	 * @param {Function} callback (optional) ####### ######### ######.
	 * @param {Object} data (optional) ###### # ####### #######.
	 * @param {Object} scope (optional) ######## ######.
	 * @return {Object} ######### #######.
	 */
	function internalCallService(config, methodName, callback, data, scope) {
		var serviceName;
		if (config && Ext.isObject(config)) {
			serviceName = config.serviceName;
			methodName = config.methodName;
			callback = config.callback;
			data = config.data;
			scope = config.scope;
		} else {
			serviceName = config;
		}
		var dataSend = data || {};
		var workspaceBaseUrl = Terrasoft.utils.uri.getConfigurationWebServiceBaseUrl();
		var requestUrl = workspaceBaseUrl + "/rest/" + serviceName + "/" + methodName;
		var requestConfig = {
			url: requestUrl,
			headers: {
				"Accept": "application/json",
				"Content-Type": "application/json"
			},
			method: "POST",
			jsonData: Ext.encode(dataSend),
			callback: function(request, success, response) {
				if (!callback) {
					return;
				}
				var responseObject = response;
				if (success) {
					responseObject = Terrasoft.decode(response.responseText);
				}
				callback.call(this, responseObject, success);
			},
			scope: scope || this
		};
		if (config && config.timeout) {
			requestConfig.timeout = config.timeout;
		}
		return Terrasoft.AjaxProvider.request(requestConfig);
	}
 
	return {
		callService: internalCallService
	};
});

 

Сидоров Александр В.,

Понял, пойду попробую спасибо,

Сидоров Александр В.,

В целом все так как вы и сказали, только раз присутствует конфиг, то все остальные параметры(данные, scope, callback) нужно так же перенести в него, иначе они перезатрутся при вызове. Спасибо!

Показать все комментарии

Вопрос:

Возникла необходимость разобрать массив с большим кол-вом данным.  На академии такой пример не рассмотрен.

В курсе о возможности парсинга массива при настройке параметров JSONPath, но это работает при условии возвращения одной записи в массиве. А как быть с большим кол-вом данных?



При настройке обработки ответа веб-сервиса, есть поле "Является массивом", при его активации, ответ конвертируется в интерфейс IObjectList, и записать его в параметрах бизнес процесса представляется возможным только с типом данных "Коллекция значений", что усложняет парсинг массива.



Вопросы:

Что за интерфейсы IObjectList/ICompositeObject/ICompositeObjectList, и как обрабатывать такой конвертированный массив?

Можно-ли обработать массив из ответа веб-сервиса и как это сделать?



Веб-сервис http://mysite.com:64123/0/rest/KmWebService/GenderSearchContact?GenderName={значение}, выборка по полу {Male/Female}

Выборка полей по каждому контакту: Id, Name, Phone

Ответ:

Пример реализации:

Сервис (схема):

Изображение удалено.

Рекомендации: используйте контракты для передачи объектов, для формирования json, используйте возможности newtonsoft.json

Бизнес-процесс:

Изображение удалено.



Сервис

Изображение удалено.

Изображение удалено.

Настройки элемента "Вызвать веб сервис"

Изображение удалено.

Настройки элемента "Задание-сценарий":

Изображение удалено.

Нравится

Поделиться

1 комментарий

ICompositeObjectList представляет собой массив элементов ICompositeObject. Перебирается обычным циклом (foreach).

ICompositeObject - dictionary (ключ-значение).

Получить значение можно одним из 2х методов:

 

/// <summary>Returns inner value by key.</summary>
    /// <param name="key">The key.</param>
    /// <param name="valueType">Type of the value.</param>
    /// <param name="value">Result value.</param>
    bool TryGetValue(string key, Type valueType, out object value);
 
    /// <summary>Returns inner value by key.</summary>
    /// <typeparam name="TValueType">The type of the value.</typeparam>
    /// <param name="key">The key.</param>
    /// <param name="value">Result value.</param>
    bool TryGetValue<TValueType>(string key, out TValueType value);

 

Показать все комментарии

Добрый день.

Есть такой случай: есть сервис где для авторизации нужно постом отправить данные clientID, secretID и grant_type, а в ответ приходит токен, тип токена и скрок действия токена. Для вызова других методов этого api нужно в header передавать Authorization : "тип токена" "токен". 

Допустим, для использования этого аpi, создаем процесс который по времени будет обновлять токен и сохранять его например в системную переменную(настройку). Но как с помощью веб-сервисов сделать запрос  и вставить в него header с "Authorization" ?

Нравится

4 комментария

Сергей приветствую

Способ авторизации у вас отличен от OAuth2? Каким способов Авторизации вы пользуетесь при работе с Веб-сервисом? немного этого не допонял. Спаисбо.

Власов Михаил Викторович,

Добрый день Михаил вот документации  https://sendpulse.ua/integrations/api#url но увы я не вижу  там описания какой версии OAuth2

Немного покопавшись в интернете и сопоставив с  документацие - сделал вывод, что там описан метод авторизации "Bearer token". А из коробки bpmonline готовой реализации такой авторизации нету.

Если речь об обращению к стороннему сервису в C#-коде, то в стандартных примерах  есть добавление в заголовки токена BPMCSRF:

// Добавление CSRF токена в заголовок запроса.
CookieCollection cookieCollection = AuthCookie.GetCookies(new Uri(authServiceUri));
string csrfToken = cookieCollection["BPMCSRF"].Value;
updateRequest.Headers.Add("BPMCSRF", csrfToken);

А в готовом элементе БП по вызову веб-сервиса есть только базовая аутентификация  и OAuth 2.0.

Показать все комментарии

Добрый день! 



Возникла проблема с обработкой ответа в массиве, при вызове веб-сервиса через стандартный элемент в бизнес-процессе.



В настройках раздела "Веб-сервисы" есть деталь "Методы сервиса", при настройке обработки ответа, есть поле "Является массивом", при его активации, в бизнес-процессе возможность записать данный ответ в параметр БП для дальнейшей обработки представляет возможным только с типом данных "Коллекция значений с атрибутами", и соответственно разобрать это можно только с помощью "Задания-сценарий"



Пример настройки ответа:

 

Изображение удалено.





Вопрос, как разобрать обработанный ответ?



Как я понял, нужно обращаться к ICompositeObjectList, но совсем не понятно, как это работает...



Пример ответа (Для каждого контакта поля в выборке id, name, phone):

Изображение удалено.

 



 

Нравится

7 комментариев

Вам нужен пример, как эти данные в коде обработать?

Если бы результат всегда возвращал одну запись в массиве, парсинг  можно было бы организовать при настройке параметров. Плюс у Вас ещё и элементы массива тоже, по сути, являются записями с 4 полями. Можно ещё попробовать считать всё внутри квадратных скобок в одну большую текстовую переменную, а потом разбирать программно в скрипте, наполняя массив или список объектов с полями. В 7.13 обещают изменения в движке веб-сервисов, возможно, стоит чуть подождать и он сможет и такое автоматически разобрать, как минимум, до массива строк.

Литвинко Павел,

Да. А если ещё конкретнее, то пример, как разобрать массив уже "обработанный" стандартными возможностями обработки ответа (первый скрин).



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



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

Зверев Александр,

если бы одну, то проблем бы конечно было меньше, но интересует выборка большого кол-ва данных



да, тоже такого варианта придерживаюсь "Можно ещё попробовать считать всё внутри квадратных скобок в одну большую текстовую переменную, а потом разбирать программно в скрипте"



Но, сейчас в ответе сервиса html документ без данного ответа но с кодом 200, и также интересно, что же все таки возвращает эта настройка обработки ответа, та, что на первом скрине

Посмотреть, что вообще пришло в ответ, можно в Fiddler (если сайт поднят локально). Может, что-то изменилось и во входящих параметрах и возвращаемый массив стал пустым?

Зверев Александр,

Действительно, пересобрал сейчас - заработало, видимо что-то пропустил)

То есть Fiddler должен вернуть обработанный ответ? 



Плясать от ответа сервиса(как на втором скрине) - в принципе не самое худшее, но для чего тогда сделали "Является массивом", при том, что ответ сервера пересобирается в таком случае в неведомый интерфейс IObjectList который можно записать в параметр "Коллекция значений" и уже исходя из него что-то делать...

https://academy.terrasoft.ru/api/netcoreapi/7.12.0/Terrasoft.Common~Ter…

 

Fiddler позволяет посмотреть, какие запросы и ответы ходили по HTTP.

В 7.13 эту коллекцию можно будет обработать в интерфейсе, там доработали возможность для ответов-массивов. Документация должна появиться после релиза. В 7.12, где эта галочка впервые появилась, — только кодом, но готовых примеров тоже нет. Также, сомневаюсь, что любая автоматизация сумеет разобрать строку на 4 поля по разделителям вроде «Phone: » (разве что делать элементами-формулами), так что перебирать в скрипте всё равно потребуется.

Показать все комментарии