Clio release version 6.0.2.38 provides the functionality to set up a BASE URL for one Web Service on different environments (development, testing, etc). Use the following command

clio set-webservice-url WEB_SERVICE_NAME BASE_URL -e ENVIRONMENT_NAME

It can be helpful to use in automatic testing pipelines. 

 

P.S Also, we provide a new stable release of Clio Explorer version 2.0.55

0 comments
Show all comments

Hi Colleagues! How are you?

I'm trying to develop a kind of webhook on Creatio. To achieve it I have created an anonymous web service. The issue I'm experiencing is a Bad Request 400 when receiving the request that is going to be sent by third party app. They are going to send an XML using  POST request, Content-Type = text/xml, and XML Body similar to this one:

<?xml version="1.0" encoding="ISO-8859-1"?>

 

 

If i change the encoding for example to UTF-8 it works.

I tried a lot of alternatives but always I get the same result:

  1. Changing the service contract,
  2. Operation contract,
  3. Mapping a custom class,
  4. Override WebContentTypeMapper

 

Any recommendation? Any workaround?

Appreciate it!

Regards.

Like 0

Like

2 comments

can you post the code?

keith schmitt,

How are you? Thank you your interest. As I commented I tried a lot of alternatives. Attached the code. Focus on UpdateSMSStatus / 

GetInstructions / ProfileRequest. Each method has a different behavior but none of them works.

 

https://drive.google.com/file/d/1Q1cIxIN7GCUT-DsEJCHT2IKr1R39DkKL/view



Thank you!

Show all comments

HI Team,

 

I am trying to integrate a web service in Creatio web service section with Set up the REST web service integration reference.

Where I am able to add web service, but not able to add xml body parameters.

Is there a way to add xml body parameters like how we will add the Json body parameters.

 

Thanks & Regards,

Akshaya B M

 

Like 0

Like

3 comments

Hi Akshaya

 

It is possible but using another automation Web-service. 

 

As you can see there are 2 options to choose: 

 

-REST Service

-SOAP service

 

The main difference in this case -  is that SOAP uses XML to transfer data, and REST uses JSON.

 

So for achieving your requirement working with automation Web-service using XML - please use the SOAP service: 

 

https://academy.creatio.com/docs/user/no_code_customization/web_service…

 

Best Regards, 

 

Bogdan L.

 

Bogdan Lesyk,

Hi Bogdan,



Thanks for the information and documentation.



But is there a way to add SOAP webservice without WDSL or XSD files and only with request and response XML data?



Thanks & Regards,

AKshaya B M

Don't know if you found your answer by now but I did not find any other thread that answered this. In any case, this is how you make it possible to provide an XML payload:

Show all comments

I'm getting a reply such as this JSON

        "company_naics_code": [
            "3271201",
            "3332491",
            "327213",
            "333249",
            "3339930",
            "3333187"
        ],

I've linked the propper array (see pictures), but the "3271201" value and so on are not saved to any parameter.

https://prnt.sc/1rli55a

https://prnt.sc/1rli5ii

How do I handle these values in the Web service method page? Surely, I need to use some nested parameter to use the retrieved vaules. But how do I format my Path to element (JSONPath) corrently when they dont have a name?

Like 1

Like

1 comments
Best reply

It's better to deserialize the JSON string directly inside the business process or the logic that you will use when calling the web service and then substruct needed values and pass them to either process parameters or use them according to your needs. Something like this in C#:

or (in case something should be performed from the client side):

If you are going to use the web-service inside the business process don't forget to add Newtonsoft.Json.Linq using in the process properties.

It's better to deserialize the JSON string directly inside the business process or the logic that you will use when calling the web service and then substruct needed values and pass them to either process parameters or use them according to your needs. Something like this in C#:

or (in case something should be performed from the client side):

If you are going to use the web-service inside the business process don't forget to add Newtonsoft.Json.Linq using in the process properties.

Show all comments

Hi Community,

 

We have this situation where we need to send a specific attachment to our client's API. This API only accepts "multipart/form-data" contents, so we need to send the byte[] of our attachment.

 

Is it possible to send the byte[] from our attachments to the API using the "Web Service Integration Setup" tool? If yes, how can we achieve that?

 

Thanks in Advance.

 

Best Regards,

Pedro Pinheiro

Like 2

Like

3 comments

Hi Pedro,

 

You need to use a stream to pass a byte array in a body of a request. It's possible to create a business process that uses WebService call process element and you can also use a script-task element. Here we can find examples of locating an attachment in the system and reading it in a stream. Once it's read completely you can pass the read byte[] to the request body and perform an API call to the endpoint where the file should be passed. Feel free to develop your logic using the article provided.

 

Best regards,

Oscar

hi oleg,

 

please share the link again, because it is no longer valid. Thanks in advance.

 

Best Regards,

Abderrahman TIGAMI

Hi Pedro,

 

Here is a new link for you: https://academy.creatio.com/docs/developer/back_end_development/api_for…

 

We will be glad to help with any other questions.

Show all comments

Hello, 

 

Would anyone have an example of how they are sending PATCH requests to Creatio?

 

Apparently this does not work, I get the error "{"Message":"There was an error processing the request.","StackTrace":"","ExceptionType":""}"

 

public static void UpdateThingInCreatio(string section, Guid object, Guid idofyetanotherobject, string text1, string text2)
        {
            string data = " somedata";
 
            string requestUri = serverUri + "ActivityCollection(guid'" + objectUID + "')";
            Encoding encoding = Encoding.Default;
            var request = WebRequest.Create(requestUri) as HttpWebRequest;
            request.Method = "PATCH";
            request.ContentType = "application/json; charset=utf-8";
            request.Credentials = new NetworkCredential(username, password);
            byte[] buffer = encoding.GetBytes(data);
            Stream dataStream = request.GetRequestStream();
            dataStream.Write(buffer, 0, buffer.Length);
            dataStream.Close();
            HttpWebResponse response = (HttpWebResponse)request.GetResponse();
            string result = "";
            using (StreamReader reader = new StreamReader(response.GetResponseStream(), System.Text.Encoding.Default))
            {
                result = reader.ReadToEnd();
            }
            MessageBox.Show(dataStream.ToString());

Have looked here: https://documenter.getpostman.com/view/10204500/SztHX5Qb?version=latest#78ea2d20-a8a5-4293-8aa5-0fa694d14d33

 

here:https://community.creatio.com/taxonomy/term/5162

 

and here: https://academy.creatio.com/documents/technic-sdk/7-16/integrations-and-external-api

 

with no luck.

 

Any suggestions or code snipit's are welcome!

Like 0

Like

2 comments

Solved it doing something along the lines of this:



 

using (var httpClient = new HttpClient())
            {
                httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(//Auth here);
 
            using (var request = new HttpRequestMessage(new HttpMethod("PATCH"), requestUri))
                {
                    request.Headers.TryAddWithoutValidation("Accept", "application/json; odata=verbose");
                    request.Headers.TryAddWithoutValidation("ForceUseSession", "true");
                    request.Headers.TryAddWithoutValidation("BPMCSRF", "value");                    
                    request.Content = new StringContent("data");
                    request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json; odata=verbose");
 
                    var response = await httpClient.SendAsync(request);
                }
            }

If there are any other examples the community would like to share please do here!

Dear Philip,

 

Please find the example of the code below:

 

ExternalRequest.cs

using System;
using System.Net;
using System.IO;
using System.Collections.Generic;
 
namespace ThirdPartyIntegration
{
    class ExternalRequest
    {
        #region Fields: Private
 
        private readonly string appUrl = "http://localhost:3030/";
        private readonly string authServiceUrl = "ServiceModel/AuthService.svc/Login";
        private readonly string OData3ServiceUrl = "0/ServiceModel/EntityDataService.svc/";
 
        private CookieContainer authCookie = new CookieContainer();
 
        #endregion
 
        #region Methods: Private
 
        private HttpWebRequest CreateRequest(string url, string methodType, string requestData = null)
        {
            HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url);
            request.ContentType = "application/json;";
            request.Method = methodType;
            request.Accept = "application/json;";
            //request.KeepAlive = true;
            if (!string.IsNullOrEmpty(requestData))
            {
                using (var requestStream = request.GetRequestStream())
                {
                    using (var writer = new StreamWriter(requestStream))
                    {
                        writer.Write(requestData);
                    }
                }
            }
            return request;
        }
 
        // Method realizes protection from CSRF attacks: copies cookie, which contents CSRF-token 
        // and pass it to the header of the next request.
        private void AddCsrfToken(HttpWebRequest request)
        {
            var cookie = request.CookieContainer.GetCookies(new Uri(appUrl))["BPMCSRF"];
            if (cookie != null)
            {
                request.Headers.Add("BPMCSRF", cookie.Value);
            }
        }
 
        private string GenerateRequestData(IDictionary&lt;string, string&gt; columnValuesPairs)
        {
            List&lt;string&gt; data = new List&lt;string&gt;();
            foreach (var pairs in columnValuesPairs)
            {
                data.Add($"\"{pairs.Key}\": \"{pairs.Value}\"");
            }
 
            var massData = data.ToArray();
            return "{ " + string.Join(", ", massData) + " }";
        }
 
        #endregion
 
        #region Methods: Public
 
        public void TryLogin(string userName, string userPassword)
        {
            var authData = "{ " + $"\"UserName\": \"{userName}\", \"UserPassword\": \"{userPassword}\"" + " }";
            var request = CreateRequest(appUrl + authServiceUrl, "POST", authData);
            request.CookieContainer = authCookie;
            // Upon successful authentication, we save authentication cookies for
            // further use in requests to Creatio. In case of failure
            // authentication application console displays a message about the reason
            // of the mistake.
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    var responseMessage = reader.ReadToEnd();
                    if (response.StatusCode == HttpStatusCode.OK)
                    {
                        Console.WriteLine(responseMessage);
                        if (responseMessage.Contains("\"Code\":1"))
                        {
                            throw new UnauthorizedAccessException($"Unauthorized {userName} for {appUrl}");
                        }
 
                        string authName = ".ASPXAUTH";
                        string authCookieValue = response.Cookies[authName].Value;
                        authCookie.Add(new Uri(appUrl), new Cookie(authName, authCookieValue));
                        Console.WriteLine(responseMessage);
                    }
                    else
                    {
                        Console.WriteLine(response.StatusCode + responseMessage);
                    }
                }
            }
        }
 
        public void PatchRequestCreatio(string objectName, Guid objectId, IDictionary&lt;string, string&gt; columnValuesPairs)
        {
            string requestData = GenerateRequestData(columnValuesPairs);
            string finalUrl = appUrl + OData3ServiceUrl + objectName + "Collection(guid'" + objectId + "')";
            var request = CreateRequest(finalUrl, "PATCH", requestData);
 
            request.ContentType += " odata=verbose";
            request.Accept += " odata=verbose";
            request.Headers.Add("ForceUseSession", "true");
 
            request.CookieContainer = authCookie;
            AddCsrfToken(request);
 
            using (var response = (HttpWebResponse)request.GetResponse())
            {
                using (var reader = new StreamReader(response.GetResponseStream()))
                {
                    var responseMessage = reader.ReadToEnd();
                }
 
            }
 
        }
 
        #endregion
    }
}

 

 

Program.cs

using System;
using System.Collections.Generic;
 
namespace ThirdPartyIntegration
{
    class Program
    {
        static void Main(string[] args)
        {
            ExternalRequest request = new ExternalRequest();
            request.TryLogin("UserName", "UserPassword");
 
            string @object = "Account";
            Guid objectId = new Guid("405947D0-2FFB-4DED-8675-0475F19F5A81");
            Dictionary&lt;string, string&gt; keyValuePairs = new Dictionary&lt;string, string&gt;();
            keyValuePairs.Add("Fax", "Test");
            keyValuePairs.Add("Code", "111");
 
            request.PatchRequestCreatio(@object, objectId, keyValuePairs);
        }
    }
}

 

Best regards,

Norton



 

Show all comments

Hello, I want to invoke a webservice call passing two parameters

 

https://mindicador.cl/api/{tipo_indicador}/{dd-mm-yyyy}

Where {tipo_indicador} is a string like uf, dolar, euro and so on

and {dd-mm-yyyy} is the current date

 

For example if I want to get the value of today euro change rate i need to invoke

https://mindicador.cl/api/euro/09-04-2020

 

But i cannot create methods to every day...how can I specify the value of the parameters when invoke the web service?, in Creatio Webservice object in the process I was working on have no the possibility to specify parameters, how can I did it?

 

Please see at http://prntscr.com/rw4h8u

 

Thanks in advance

 

 

Like 0

Like

2 comments

Dear Julio, 

 

You can specify web service request parameters in the web service section in the method detail: 

https://prnt.sc/rzx19d

https://prnt.sc/rzxcka

After that you would be able to populate them in the web service call element: 

https://prnt.sc/rzx1i9

Thanks Dennis

Show all comments

Hello I'm getting in a process the following string from a webservice and I want to parse it to and object where can I get the elements the json bring to me, for example I get:

{"version":"1.6.0","autor":"mindicador.cl","codigo":"uf","nombre":"Unidad de fomento (UF)","unidad_medida":"Pesos","serie":[{"fecha":"2020-04-09T04:00:00.000Z","valor":28630.63}]}

 

And I need to parse to get:

nombre

fecha

valor

 

How can I did it?

 

Thanks

Like 0

Like

6 comments

Hello, Julio!

 

Please see the article below on working with the web service response:

https://academy.creatio.com/documents/technic-bpms/7-15/call-web-servic…

If you want to do this differently, you can call web service with a standard C# tools using a script task element and process the response body in a script task. Also, for more flexibility, you can call the web serviced is a script task. Here is an article with an example: 

https://stackoverflow.com/questions/3900371/how-can-i-call-a-webservice…

To parse JSON in script task you can use the following article, for example: 

https://www.codementor.io/@andrewbuchan/how-to-parse-json-into-a-c-object-4ui1o0bx8

Dennis Hudson,

Hello Dennis,

 

I don't know if you are still supporting the community forum, however if you are.  The JSON article uses the System.Web.Script namespace.  When I compile a script task using this namespace an error results saying Script not found within System.Web.  Is there are workaround or an alternative?  Thanks,

Gareth Osler,

 

Hello,

 

As an example I've used the string Julio shared above. To deserialize it I've used the following approach:

 

1) Create a source code in configurations. Name it UsrForCustomObject. The content is as follows:

using System.Collections.Generic;
using Terrasoft.Configuration;
 
namespace Terrasoft.Configuration.UsrForCustomObject
{
	public class UsrForCustomObject
    {
        public string version
        { get; set; }
        public string autor
        { get; set; }
        public string codigo
        { get; set; }
        public string nombre
        { get; set; }
        public string unidad_medida 
        { get; set; }
        public List&lt;InternalUsrForCustomObjectList&gt; serie
        { get; set; }
    }
 
    public class InternalUsrForCustomObjectList
    {
        public string fecha 
        { get; set; }
        public decimal valor 
        { get; set; }
    }
}

2) Create a business process with the following schema:

The code of the parameters is the same as the name:

2.1) Text (500 characters) parameter - ParsedFecha

2.2) Text (500 characters) parameter - ParsedNombre

2.3) Decimal (0.01) parameter - ParsedValor

2.4) Text (500 characters) parameter - ParsedVersion

2.5) Text (500 characters) parameter - PassedJSONString

 

This is the content of the "Methods" tab:

public void PerformJsonDeserialize()
{
	var passedValue = Get&lt;string&gt;("PassedJSONString");
	if (!String.IsNullOrEmpty(passedValue))
	{
		UsrForCustomObject testCustObj = System.Text.Json.JsonSerializer.Deserialize&lt;UsrForCustomObject&gt;(passedValue);
		Set&lt;string&gt;("ParsedVersion", testCustObj.version);
		Set&lt;string&gt;("ParsedNombre", testCustObj.nombre);
		Set&lt;string&gt;("ParsedFecha", testCustObj.serie[0].fecha);
		Set&lt;decimal&gt;("ParsedValor", testCustObj.serie[0].valor);
	}
}

and we are using Terrasoft.Configuration.UsrForCustomObject.

 

Why it's done so: we need to deserialize the passed string and receive an instance of the UsrForCustomObject class we've declared at step 1 in configurations. Deserialization is performed using System.Text.Json.JsonSerializer.Deserialize method (please note that specifying JsonSerializer.Deserialize method with specifying System.Text.Json as an assembly reference will result in error stating that the system cannot understand whether System.Text.Json.JsonSerializer.Deserialize should be used or Newtonsoft.Json.JsonSerializer.Deserialize should be used, so use the exact approach of method call as in my example above).

 

3) "Input JSON string" auto-generated page is quite simple: it tells the user to input JSON string. It's done for testing purposes, in fact actual JSON string can be passed:

4) In the "Set JSON to parameters" formula we specify the value for the "PassedJSONString" parameter that should be the string we've input in the "Input JSON string" auto-generated page from step 3:

5) In the "Deserialize" script-task we call the "PerformJsonDeserialize" method from the process methods from step 2:

6) In the "Result" auto-generated page we simply show the result of deserialization (values for all parameters from step 2):

 

So as a result here is the screenshot of the process start "Input JSON string" auto-generated page where the value of:

{"version":"1.6.0","autor":"mindicador.cl","codigo":"uf","nombre":"Unidad de fomento (UF)","unidad_medida":"Pesos","serie":[{"fecha":"2020-04-09T04:00:00.000Z","valor":28630.63}]}

is passed:

and here is the screenshot of the "Result" auto-generated page:

Also these parsed values can be converted (to date\time for example) and so on. So please feel free to study this example and implement the same logic on your end.

A quick note for anyone who happens this way in the future.

Step 1) above, the namespace name needs to be different from the class name, e.g.:

using System.Collections.Generic;
using Terrasoft.Configuration;
 
namespace Terrasoft.Configuration.UsrCustomerImportNamespace
{
	public class UsrCustomerImport
    {
        public string accountName { get; set; }
        public List&lt;UsrCustomerImportItems&gt; items { get; set; }
    }
 
    public class UsrCustomerImportItems
    {
        public string contactName { get; set; }
        public string contactType { get; set; }
    }
}

 

By way of an epilogue, while the `System.Text.Json` namespace is available in a trial, for some reason it was not available in the dev environment I was using.  However classes in the `Terrasoft.Common.Json` namespace were available.  I was able to use the `Deserialize<T>(String)` method of the Json class.  (Note at the time of writing the `DeserializeDictionary(String)` method has a bug in it and cannot be used.)

@Oleg, 

 

I followed the steps above but receive the attached upon compilation of the methods within business process? 

Show all comments

Hi,

 

Is there a way to create an autocomplete dropdown in the user interface that keeps loading data from web service calls, based on the latest search string?

 

Thanks in advance...

Like 0

Like

8 comments

Dear Amanthena,

We do not have any ready examples, however you can achieve such task in following ways.

1. Add a dependency on the field change on client side (page schema). Retrieve the value from the field and pass it on to the web service, which in turn would send this value to the external service. Receive a response and set it to the field in order to render on UI. You can see this article on web service call from client side:

https://academy.bpmonline.com/documents/technic-sdk/7-13/how-call-configuration-services-servicehelper

2. Add a dependency on the field change on client side (page schema). Call business process from the client side. Pass a parameter to the business process, this parameter would be the entered value from the field. In the business process add a web service element, which would proceed service calls and than work with the response. You can also pass the response from the service from business process on to the page like described here:

https://academy.bpmonline.com/documents/technic-sdk/7-13/process-launch-client-module

https://community.bpmonline.com/questions/refresh-page-fields-after-process-runs-update-signal

Though, it is quite complicated task.

In any way, please keep in mind, that you need to watch overall system performance and leave some time between service calls. More information can be found here:

https://codeburst.io/throttling-and-debouncing-in-javascript-b01cad5c8edf

Regards,

Anastasia

Thank you for your reply, Anastasia! The reference material helped. The part where we make a service call from javascript and trap the response is clear. But could you help me figure out the javascript APIs that will help me clear, rebind and render it to a control in the UI. Would a dropdown be the best choice here? What do you suggest?

 

amanthena,

You can send a message from back end to front end.In case you are calling external service via business process, you can check the example here:

https://community.bpmonline.com/questions/refresh-page-fields-after-process-runs-update-signal

The idea is to use sandbox to send and hear message, after message received you set it to the field with this.set.

Also you can use web sockets to communicate between front end and back end. 

https://academy.bpmonline.com/documents/technic-sdk/7-13/clientmessagebridge-client-side-websocket-message-handler

The field type depends on the data you will be working with. 

Hope you find it helpful

Anastasia

The data is a list of key-value pairs, "value" is the user friendly description and "key" is the id that needs to be persisted in the database on selection. i figured a dropdown would be the best control for this purpose. Can we programatically reset the contents of the dropdown in javascript with the data that is returned from the server? Could you tell me how "this.set" needs to be used here?



Once again, thanks for all the help! Much appreciated!

amanthena,

To set value to a lookup (dropdown), you need to pass an object with at least to parameters displayValue and value :

this.set("Country", {value: "a570b005-e8bb-df11-b00f-001d60e938c6", displayValue: "Australia"});

Regards,

Anastasia

Thank you, Anastasia! That helps. I might also need to rebind the list of items available for selection in the dropdown from the data that is returned from the API, and not just the selected item. How do I do that?

amanthena,

Lets say you have a dropdown, which is a Country lookup, when user enters a country name you launch a web service call that returns some internal code for the country. You work with currently chosen country, but want to change others too. You can run an ESQ to the Country object when setting data for current one. When collection is returned from ESQ, you can modify it with values received from web service call.

Regards,

Anasatsia

Thank you, Anastasia! I will explore this further.

Show all comments

I've created a webservice that passes the received data from my api to a "Collection of Objects with attributes" parameter inside my business process.

I would like to know how can i convert that business process parameter to a JArray.



JArray jarray = Get("ProcessSchemaCadastros");

This is the line i have in my script task to get my data from business process parameter.

Like 0

Like

2 comments
Best reply

I found a way to pass my problem, instead of trying to convert into a JArray i used:

var entities = Get<ICompositeObjectList<ICompositeObject>>("WebService1.UsrWBCadastros_Out");

then i just worked with the data from 'entities'.

 

It's much easier to transfer a JSON from the web service to a text variable in a business process. Then parse the JSON in the business process.

I found a way to pass my problem, instead of trying to convert into a JArray i used:

var entities = Get<ICompositeObjectList<ICompositeObject>>("WebService1.UsrWBCadastros_Out");

then i just worked with the data from 'entities'.

 

Show all comments