Коллеги, Добрый день, 
 

Пытаемся авторизоваться в демонстрационной версии одного веб-сервиса (Lamoda Fulfilment) из интерфейса Creatio OAUTH 2.0

 

При попытке авторизации в веб-сервисе получаем ошибку
Invalid grant_type parameter or parameter missing

При этом "собранный" запрос с передачей в GET необходимых тех же самых параметров client_id, client_secret и grant_type (даже с redirect_url) в адресной строке и как отдельный метод Creatio возвращает ответ без ошибок.

Дополнительные разрешения / scopes для пользователей веб-сервиса не требуются (это demo версия веб-сервиса, условия самые "лайтовые")

 

В связи с этим вопрос?
Кто-нибудь сталкивался с подобной проблемой и с чем может быть связано ?

Спасибо всем ответившим Изображение удалено.

Нравится

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

Александр, здравствуйте.

 

На данный момент такие типы авторизации OAuth 2.0 не поддерживаются. Так как в запрос не добавляется параметр grant_type.

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

Коллеги, Добрый день,

Возможно, кто-нибудь сталкивался с задачей: вывести список доступных для доставки улиц населенного пункта (или как вариант-пунктов самовывоза) при заполнении данных в заказе?

Список улиц / пунктов самовывоза получаем при помощи метода веб-сервиса службы доставки.

Вопрос, каким образом в Sales Creatio можно выполнить обращение к веб-сервису и получить данные для вывода в открывающемся списке в процессе заполнения данных заказа?

Пример интерфейса, возвращающего список улиц или пунктов самовывоза в зависимости от выбранного населенного пункта и способа доставки:

Спасибо всем ответившим Изображение удалено.

Нравится

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

1) Сделать общение в веб-сервис при изменении ключевых полей. В ответе, допустим, возвращается список улиц.
2) Делаем виртуальное enum-поле "Улица". Список формируем "на лету" используя то, что вернул сервис. Пример кода тут (в controlConfig нужен prepareList и list)

1) Сделать общение в веб-сервис при изменении ключевых полей. В ответе, допустим, возвращается список улиц.
2) Делаем виртуальное enum-поле "Улица". Список формируем "на лету" используя то, что вернул сервис. Пример кода тут (в controlConfig нужен prepareList и list)

Большое спасибо за ответ, разобрались с возможной реализацией.

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

Возникла проблема с вызовом веб-сервиса из студии.  Возвращает ошибку 404. Пример сервиса:

 namespace Terrasoft.Configuration
{
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.ServiceModel.Activation;
    using Terrasoft.Core.DB;
    using Terrasoft.Web.Common;
 
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class UpsertContactService : BaseService
    {
        [OperationContract]
        [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json, BodyStyle = WebMessageBodyStyle.Wrapped,
        ResponseFormat = WebMessageFormat.Json)]
        public string GetTransformValue(string inputParam)
        {
            // Изменение значения входящего параметра.
            var result = inputParam + " changed!";
            return result;
        }
    }
}

Пример вызова:

HttpWebResponse authresponse = (HttpWebResponse)authRequest.GetResponse();
            var myRequest = HttpWebRequest.Create("https://мой сайт/0/ServiceModel/UpsertContactService.svc/GetTransformValue") as HttpWebRequest;
 
            myRequest.Method = "POST";
            myRequest.ContentType = "application/json";
            foreach (Cookie Cook in authresponse.Cookies)
            {
                myRequest.Headers.Add(Cook.Name, Cook.Value);
            }
            myRequest.CookieContainer = bpmCookieContainer;
 
            using (var requestStream = myRequest.GetRequestStream())
            {
                using (var writer = new StreamWriter(requestStream))
                {
                    writer.Write(@"111");
                }
            }
            using (HttpWebResponse response = (HttpWebResponse)myRequest.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII))
                {
                    string s = reader.ReadToEnd();
                    Console.WriteLine(s);
                }
            }

Авторизация проходит успешно, БП получилось запустить. Как запустить сервис и получить от него ответ?

Нравится

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

Добрый день

Виталий, в статье на академии есть ответ https://academy.terrasoft.ru/docs/developer/back-end_development/config…

 

Ответ 404 верный, т.к. у вас нет такого сервиса. Вы создаете конфигурационный сервис, который вызывается по другому url.

 

А зачем в Header добавлять значения всех кук из аутентификации? Достаточно только BPMCSRF.

Во-вторых. Вызов под каким пользователем происходит? под портальным? Если да, то надо сервис добавить в список разрешенных для портальных - \папка приложения\Terrasoft.WebApp\SspServices\SspServiceList.txt

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

Алексей Следь,

происходит под админом, сайт в облаке, через постмен тоже 404.

Вот что в браузере пишет:

Добрый день

Виталий, в статье на академии есть ответ https://academy.terrasoft.ru/docs/developer/back-end_development/config…

 

Ответ 404 верный, т.к. у вас нет такого сервиса. Вы создаете конфигурационный сервис, который вызывается по другому url.

 

Артем Гура,

Да! То что нужно! Вот рабочий код:

HttpWebResponse authresponse = (HttpWebResponse)authRequest.GetResponse();
            var myRequest = HttpWebRequest.Create("https://mysite.com/0/rest/UpsertContactService/GetTransformValue") as HttpWebRequest;
 
            myRequest.Method = "POST";
            myRequest.ContentType = "application/json";
            myRequest.Headers.Add(authresponse.Cookies["BPMCSRF"].Name, authresponse.Cookies["BPMCSRF"].Value);
            myRequest.CookieContainer = bpmCookieContainer;
 
            using (var requestStream = myRequest.GetRequestStream())
            {
                using (var writer = new StreamWriter(requestStream))
                {
                    writer.Write(@"{""inputParam"":""Test!""}");
                }
            }
            using (HttpWebResponse response = (HttpWebResponse)myRequest.GetResponse())
            {
                using (StreamReader reader = new StreamReader(response.GetResponseStream(), Encoding.ASCII))
                {
                    string s = reader.ReadToEnd();
                    Console.WriteLine(s);
                }
            }

И еще как авторизовался, может кому нужно будет:

var authRequest = HttpWebRequest.Create(@"https://mysite.com/ServiceModel/AuthService.svc/Login") as HttpWebRequest;
            authRequest.Method = "POST";
            authRequest.ContentType = "application/json";
            var bpmCookieContainer = new CookieContainer();
            authRequest.CookieContainer = bpmCookieContainer;
            using (var requestStream = authRequest.GetRequestStream())
            {
                using (var writer = new StreamWriter(requestStream))
                {
                    writer.Write(@"{
                                ""UserName"":""Supervisor"",
                                ""UserPassword"":""Supervisor"",
                                ""SolutionName"":""TSBpm"",
                                ""TimeZoneOffset"":-120,
                                ""Language"":""Ru-ru""
                                }");
                }
            }

 

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

Всем привет!

 

Учусь писать веб-сервисы. Накидал вот такой простенький веб-сервис:

 

[ServiceContract]
[AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
public class UserController : BaseService
{
        [OperationContract]
        [WebInvoke(Method="POST",RequestFormat=WebMessageFormat.Json,BodyStyle=WebMessageBodyStyle.Wrapped,ResponseFormat=WebMessageFormat.Json)]
        public string DataGet(WarehouseInfo hh)
        {
            return hh == null ? "Хватит!" : hh.Name;
        }

        [DataContract]
        public class WarehouseInfo
        {
            [DataMember(Name = "складGuid")]
            public string Id { get; set; }

            [DataMember(Name = "пометкаУдаления")]
            public string isDelete { get; set; }

            [DataMember(Name = "наименование")]
            public string Name { get; set; }
        }
}

 

Как бы я не пыхтел с Постманом, но WarehouseInfo всегда прилетает пустой. Что я делаю не так?

Нравится

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

пример своего запроса можно(с телом урлом и хедерами), а ключ csrf указывали в хедерах, куки перед отправкой чистили, точно ли отправляете пост запрос , а не гет?

namespace Terrasoft.Configuration
{
    using System;
    using System.ServiceModel;
    using System.ServiceModel.Web;
    using System.ServiceModel.Activation;
    using Terrasoft.Core.DB;
    using Terrasoft.Web.Common;
    [ServiceContract]
    [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
    public class ClassName : BaseService
    {
        [OperationContract]
        [WebInvoke(Method = "POST", BodyStyle = WebMessageBodyStyle.Wrapped,
            RequestFormat = WebMessageFormat.Json, ResponseFormat = WebMessageFormat.Json)]
        public void MethodName(входные параметры)
        {
             // логика веб-сервиса
        }
    }
}

Кусок рабочего веб-сервиса.

ты только подтвердил что не видишь его ошибку. У него ошибка в ссылочном типе, где у тебя обобщение "входные параметры". 

Отвечу на всякий случай. Возможно автор темы слал запрос вида:

{
 "Id ": "123",
 "isDelete" : "123",
 "Name": "123"
}

Хотя в данном случае требуется запрос вида:

{
 "hh": {
  "Id ": "123",
  "isDelete" : "123",
  "Name": "123"
 }
}

Все дело в: "BodyStyle=WebMessageBodyStyle.Wrapped".


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

Добрый день!

Я создал веб-сервис (на C#) который выполняет некоторую проверку внутри сайта. Но данная проверка осуществляется несколько секунд и работа всего сайта приостанавливается. Что не удовлетворяет заказчика.

Как решить данную проблему? Сайт должен быть работоспособным в момент запуска веб-сервиса.

Нравится

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

Pavel Litvinovich,

Вы проверили это из другого браузера? (кнопку запуска 

нажимаете в одном браузере, а работу сайта проверяете в другом)

Скорее всего "приостанавливается" только текущая сессия. Это можно проверить открыв еще одно окно браузера в режиме инкогнито (можно даже под этим же пользователем).

 

Мы обходили это тем, что вызывали из сервиса БП, в свойствах которого стояла галочка "выполнять в фоне".

Можно вообще исключить сервис и сразу вызывать БП, который выполняется в фоне. Это решает проблему подвисания сессии.

Дмитрий А.,

Не работает сайт вообще. Висит... Запуск веб-сервиса происходит по нажатию кнопки на странице нужного раздела.

Pavel Litvinovich,

Вы проверили это из другого браузера? (кнопку запуска 

нажимаете в одном браузере, а работу сайта проверяете в другом)

Дмитрий А.,

Спасибо! Работает.

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

Доброго времени суток коллеги. У меня возникли две проблемы. Имею вызов метода 


      SetUrlAnswer: function() {
 
        var xhr = new XMLHttpRequest();
 
        var url = "http://localhost/0/rest/Service1/Testing";
 
        xhr.open("GET", url);
 
        xhr.responseType = "json";
 
        xhr.setRequestHeader("Content-type", "application/json");
 
        var self = this;
 
        xhr.onreadystatechange = function() {
 
            if (xhr.readyState === 4 && xhr.status === 200) {
 
                // for (var i = 0; i < xhr.length; i++ ) {
 
                  self.set("UsrCharCode",
 
                   JSON.stringify(xhr.response[0].CharCode));
 
                  self.set("UsrID", 
 
                   JSON.stringify(xhr.response[0].ID));
 
                  self.set("UsrNameV", 
 
                   JSON.stringify(xhr.response[0].Name));
 
                  self.set("UsrNominal", 
 
                   JSON.stringify(xhr.response[0].Nominal));
 
                  self.set("UsrNumCode",
 
                   JSON.stringify(xhr.response[0].NumCode));
 
                  self.set("UsrPrevious", 
 
                  JSON.stringify(xhr.response[0].Previous));
 
                  self.set("UsrValues", 
 
                   JSON.stringify(xhr.response[0].Value));
 
                // }
 
 
 
            } else {
 
               // Пока не реализовано
 
                self.set("UsrCharCode", "Не правильное получение данных!");
 
            }
 
        };xhr.send();
 
 

Как мне сделать правильную итерацию? Чтобы вот такого говно-кода избежать?

Вопрос второй(очень важный): Этот метод возвращает каждый раз разный массив данных. Вопрос в  том  Creatio предусмотрено генерация полей исходя из ответа сервера? Например мне в ответ приходит 4 видов валют USD, RUB, EUR, UZS и исходя из ответа сгенерировать таких групп полей:Надеюсь смог объяснить свою боль. Спасибо

Нравится

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

Ислам Ибрагимжанов,

Я описал общую идею как работает DataService, можете поискать реализацию и попробовать понять, но это про сложные вещи.

Вам пока нужно начать использовать ServiceHelper и его функцию callService.

И читайте документацию, там такие кейсы описаны.

Зачем вы используете чистый XMLHttpRequest, уже есть классы для работы с сервисами.

https://academy.terrasoft.ru/docs/7-16/developer/back-end_development/c…

Итерацию можно сделать циклом по массиву с наименованиями полей. Можно сделать по переменным объекта. Список полей для итерации можно возвращать со стороны сервера. Тут у вас полная свобода действий.

Полозюков Евгений Петрович,

Я не понял один момент

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

Вы это про мой второй вопрос? Я что то не до  конца понял. 

Ислам Ибрагимжанов,

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

Полозюков Евгений Петрович,

Мне нужно сгенерировать поля для этих данных. Через выше указанный способ релаьно реализовать такое?

Ислам Ибрагимжанов,

Я описал общую идею как работает DataService, можете поискать реализацию и попробовать понять, но это про сложные вещи.

Вам пока нужно начать использовать ServiceHelper и его функцию callService.

И читайте документацию, там такие кейсы описаны.

Полозюков Евгений Петрович, Спасибо за помощь. Я понял идеюyes

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

Добрый день. Сейчас через скрипт рекордер записываю действия и прогоняю по этому сценарию нагрузку. Вопрос у заказчика в другом, почему к примеру, при нагрузке в 600 пользователей не создаётся 600 тестовых обращений хотя по скрипту записано от и до. Авторизация в JMeter работает.

Нравится

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

Думаю, заказчику лучше обратиться с вопросом к тому, кто разрабатывал сценарий. Без подробностей сложно сказать, что именно он делает в системе. Например, если каждый раз сохранять запись о новом обращении с одним и тем же Id (а при нормальной работе он уже есть в запросе к /0/DataService/json/SyncReply/InsertQuery), то не создастся много записей, а будут ошибки.

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

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

runService: function () {
				ServiceHelper.callService({
					serviceName: "CustomService",
					methodName: "ReturnCurrentUser",
					callback: function() {
                        Terrasoft.utils.showMessage({
                            caption: "Сервис запустил ",
                            buttons: [Terrasoft.MessageBoxButtons.OK.returnCode],
                            defaultButton: 0,
                            scope: this
                        });
					},
					scope: this
				}, this);
			},

 

Нравится

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

в аргументе метода

callService передайте параметр callback: function(response) {
var answer = response.ReturnCurrentUserResult;
ваш обработчик ответа
}
И scope: this 

В самом callService this не нужен

 

в аргументе метода

callService передайте параметр callback: function(response) {
var answer = response.ReturnCurrentUserResult;
ваш обработчик ответа
}
И scope: this 

В самом callService this не нужен

 

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

Добрый день.

Мной разработан конфигурационный веб-сервис
 

[ServiceContract]
   [AspNetCompatibilityRequirements(RequirementsMode = AspNetCompatibilityRequirementsMode.Required)]
   public class ConnectorService : BaseService
   {
      [OperationContract]
      [WebInvoke(Method = "POST", RequestFormat = WebMessageFormat.Json,
            BodyStyle = WebMessageBodyStyle.Wrapped, ResponseFormat = WebMessageFormat.Json)]
      public bool CreateContact(string firstName, string middleName, string lastName)
      {
...
return true;
}
}

На страницах академии есть материалы о том как вызвать конфигурационный веб-сервис с с помощью Postman или ServiceHelper, но нет информации как его вызвать со страницы другого веб-сайта, например с использованием API XMLHttpRequest.  Функциональность и работоспособность веб-сервиса проверена с помошью Postman. Все работает.

Однако указанный метод  веб-сервиса должен вызываться со страницы стороннего сайта (доступ к которой имеется). 
Подскажите как вызвать конфигурационной веб-сервис Creatio со страницы другого веб-сайта. Желательно с примерами. 

Нравится

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

Андрей, пример использования XMLHttpRequest для POST есть тут, но это наоборот, вызов со страниц 7.Х внешнего сервиса. В обратном направлении должно быть аналогично, но нужно учитывать необходимость авторизации при помощи AuthService и получение всех нужных кук, либо делать его доступным анонимно. Также по поводу возможных ограничений при работе с другого домена и путей их обхода см. темы: 1, 2, 3.

 

Другой вариант — работать с веб-сервисом не из браузера, а из серверного кода другого сайта. Конкретная реализация зависит от языка, на котором он написан: PHP, C#, Java, JS и др.

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

Доброго дня, имеется bpm которая при GET запросе 0/ServiceModel/EntityDataService.svc/ContactColletion возвращает xml с контактами, можно ли GET запросом возвращать JSON и если да, то где про это написанно? Если нельзя, то как вернуть JSON для oData 3?

Нравится

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

Добавьте header к запросу

Accept: application/json;odata=verbose

Добавьте header к запросу

Accept: application/json;odata=verbose

я смог сделать это в постмане, но все же не понятно, мб подскажете возможно ли в террасофте возвращать json по обращению к uri, если можно сделать это не переписывая сервис, буду благодарен за подсказку)
условно я иду по адресу /0/ServiceModel/EntityDataService.svc/ContactCollection и мне падает 
 

{

    "d": {

        "results": [

            {

                "__metadata": {

                    "id": "http://localhost:85/0/ServiceModel/EntityDataService.svc/ContactCollect…",

                    "uri": "http://localhost:85/0/ServiceModel/EntityDataService.svc/ContactCollect…",

                    "type": "Terrasoft.Configuration.Contact"

                },

                "Photo": {

                    "__deferred": {

                        "uri": "http://localhost:85/0/ServiceModel/EntityDataService.svc/ContactCollect…"

                    }

                },

                "Owner": {

                    "__deferred": {

                        "uri": "http://localhost:85/0/ServiceModel/EntityDataService.svc/ContactCollect…"

                    }
...и т.д.

Насколько понял, только заголовком. Такой формат здесь не поддерживается: «ContactCollection?$format=json». А в OData 4 по умолчанию идёт JSON.

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