Hello Creatio Community,

I am working on a project where I need to either replace or override an existing Creatio web service with a custom implementation. Specifically, I want to extend or modify the functionality of a base Creatio web service (e.g., CallServiceSchemaService) to fit my business requirements.

Here’s what I want to achieve:

  • Create a custom web service in a separate package without affecting the existing functionality of the base service.
  • Either extend the existing service (if possible) or completely replace it with my custom implementation.
  • I want to customize the behavior of how service requests and responses are handled, while ensuring that all references to the original service use my new service.

Questions:

  1. What is the best approach to achieve this in Creatio? Should I extend or replace the service, and what are the steps to do so?
  2. How can I ensure that the system references my custom service in place of the base service without breaking existing functionality?
  3. Are there any best practices or limitations I should keep in mind when implementing custom web services in Creatio?

I would appreciate any guidance, examples, or documentation that can help me with this process.

Thank you!

Like 0

Like

1 comments
Best reply

Hi,

 

We would recommend not to redo the standard web service page, but to set up a custom service.

Here are the options for configuring the integration:

https://academy.creatio.com/docs/8.x/dev/development-on-creatio-platform/architecture/development-in-creatio/integrations

Hi,

 

We would recommend not to redo the standard web service page, but to set up a custom service.

Here are the options for configuring the integration:

https://academy.creatio.com/docs/8.x/dev/development-on-creatio-platform/architecture/development-in-creatio/integrations

Show all comments

Clio release 6.1.0.12 provides a command to create a state manifest for the Creatio instance and store the configuration of web services and feature states.

 

clio save-state "D:\manifest\myinstance-creatio-manifest.yaml" -e MyInstance

 

Storing this file in Git can be used to control instance changes. In future releases, the manifest file will store sys-settings values, applications, and packages, and it will also clone environment settings to clean Creatio instances.

 

P.S: Also the ability to work with HotFix mode was added to Clio commands. To enable/disable it use the following command

 

# To enable hot-fix mode for a package  
clio pkg-hotfix <PACKAGE_NAME> true -e <ENVIRONMENT_NAME> 
 
# To disable hot-fix mode for a package 
clio pkg-hotfix <PACKAGE_NAME> false -e <ENVIRONMENT_NAME> 

 

0 comments
Show all comments

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