Blu Pantheon
Automatisierung & RPARPA-Plattformen

UiPath

Integrare UiPath con Blu Pantheon: HTTP Request activity, Orchestrator Assets, code di lavoro, retry scope e verifica HMAC in VB.NET.

Guida completa per collegare UiPath Studio e Orchestrator a Blu Pantheon nelle due direzioni: chiamare le API della piattaforma e ricevere webhook.

Prima di iniziare

  • UiPath Studio 2023.10 o superiore con il pacchetto UiPath.Web.Activities installato
  • Accesso a Orchestrator con permessi su Assets e Queues
  • Una chiave API bp_live_xxxxxxxxxxxxxxxx creata in Console
  • Il segreto whsec_xxxxxxxxxxxxxxxx del webhook
  • Un listener HTTP raggiungibile da Internet che alimenta una coda Orchestrator

Architettura consigliata

UiPath non espone endpoint HTTP pubblici. Il pattern corretto prevede un listener intermedio che riceve il webhook, verifica la firma e inserisce un elemento nella coda Orchestrator tramite l'API Add Queue Item.

Blu Pantheon ──webhook firmato──► Listener (Azure Function / IIS / Nginx+app)
                                        │ verifica HMAC + risposta 202
                                        ▼
                                Orchestrator Queue "BluPantheonEvents"
                                        │ Queue Trigger
                                        ▼
                                   Robot UiPath
                                        │
                                        ├──► Gestionale (UI automation)
                                        └──► API Blu Pantheon (HTTP Request)

Perché non chiamare direttamente il robot

Un robot impegnato o offline farebbe fallire la consegna. La coda disaccoppia la ricezione dall'esecuzione e consente di rispondere 202 in millisecondi.

Parte 1 — Conservare la chiave API in Orchestrator

Crea il Credential asset

In Orchestrator apri Tenant → Assets → Add asset.

CampoValore
NameBluPantheon_ApiKey
TypeCredential
Usernameapi
Passwordbp_live_xxxxxxxxxxxxxxxx
DescriptionChiave API Blu Pantheon — progetto bp_proj_7f3a9c21
Value per Robotdisattivato

Crea gli asset di configurazione

Aggiungi due asset di tipo Text:

NameValue
BluPantheon_BaseUrlhttps://api.blupantheon.com
BluPantheon_ProjectIdbp_proj_7f3a9c21

Leggi la credenziale nel workflow

Inserisci l'attività Get Credential:

ProprietàValore
AssetName"BluPantheon_ApiKey"
Usernameout_Username (String)
Passwordout_ApiKeySecure (SecureString)

Converti la SecureString in String solo al momento dell'uso:

Assign — conversione della credenziale
apiKey = New System.Net.NetworkCredential(String.Empty, out_ApiKeySecure).Password

Elimina la variabile dopo l'uso

Al termine della sequenza azzera la variabile per non lasciare il segreto in memoria e nei log di verbose logging:

Assign — pulizia
apiKey = String.Empty

Mai in chiaro

Non salvare la chiave in un asset di tipo Text, in un file di configurazione Config.xlsx versionato o in un argomento di default del workflow. Gli asset Text sono leggibili in chiaro da chiunque abbia accesso a Orchestrator.

Parte 2 — Chiamare le API di Blu Pantheon

Configurare HTTP Request

Trascina l'attività HTTP Request (pacchetto UiPath.Web.Activities) e compila:

ProprietàValore
EndPointbaseUrl + "/identity/v1/sessions/" + sessionId + "/notes"
MethodPOST
AcceptFormatJSON
BodyFormatapplication/json
BodyrequestBody (String)
Headerscollezione, vedi sotto
TimeoutMS15000
ResultresponseBody (String)
StatusCodestatusCode (Int32)

Popola la collezione Headers con un Build Collection oppure con un Assign su un Dictionary(Of String, String):

Assign — headers
headers = New Dictionary(Of String, String) From {
    {"Authorization", "Bearer " & apiKey},
    {"X-BP-Project", projectId},
    {"Content-Type", "application/json"},
    {"Accept", "application/json"},
    {"Idempotency-Key", deliveryId}
}

Idempotency-Key da X-BP-Delivery

Usa l'identificativo della consegna che ha originato il lavoro come Idempotency-Key. Se il robot fallisce a metà e la coda ritenta, la piattaforma non creerà un duplicato.

Costruire il corpo della richiesta

Non concatenare stringhe a mano: usa JObject per evitare problemi di escaping con apostrofi e accenti.

Assign — costruzione del payload
requestBody = New Newtonsoft.Json.Linq.JObject(
    New Newtonsoft.Json.Linq.JProperty("body", "Pratica aperta nel gestionale: " & numeroPratica),
    New Newtonsoft.Json.Linq.JProperty("visibility", "internal"),
    New Newtonsoft.Json.Linq.JProperty("author", "rpa-uipath")
).ToString(Newtonsoft.Json.Formatting.None)

Deserializzare la risposta

Inserisci l'attività Deserialize JSON (pacchetto UiPath.WebAPI.Activities):

ProprietàValore
JsonStringresponseBody
TypeArgumentNewtonsoft.Json.Linq.JObject
JsonObjectresponseJson (JObject)

Accedi ai campi con indicizzazione tipizzata:

Assign — lettura dei campi
noteId = responseJson("data")("id").ToString()
createdAt = DateTime.Parse(responseJson("data")("createdAt").ToString())

Per gli array usa Deserialize JSON Array con TypeArgument JArray:

Iterazione su un array JSON
For Each item As Newtonsoft.Json.Linq.JToken In responseJson("data")
    Log Message: "Cliente: " & item("displayName").ToString()
Next

Gestione degli errori con Retry Scope

Avvolgi l'attività HTTP Request in un Retry Scope:

ProprietàValore
NumberOfRetries3
RetryInterval00:00:05

Nella sezione Condition inserisci un Is True con:

statusCode >= 200 AndAlso statusCode < 300

Aggiungi un Try Catch esterno per distinguere gli errori:

Codice ricevutoAzione nel Catch
401Errore di configurazione: interrompi, non ritentare, invia notifica
403Scope insufficienti: interrompi, apri segnalazione
409Conflitto: leggi la risorsa esistente e prosegui
429Leggi Retry-After e attendi con Delay, poi ritenta
5xxRitenta con backoff, poi marca l'elemento in coda come Failed
Assign — attesa dinamica sul 429
retryAfterSeconds = If(
    response.Headers.ContainsKey("Retry-After"),
    Convert.ToInt32(response.Headers("Retry-After")),
    30
)

Parte 3 — Ricevere i webhook

Listener intermedio

Il listener può essere una Azure Function, un servizio ASP.NET o qualsiasi endpoint HTTPS. Deve verificare la firma e inserire l'elemento in coda tramite l'API di Orchestrator.

Listener — inserimento in coda Orchestrator
using System.Net.Http.Json;
using System.Security.Cryptography;
using System.Text;

public sealed class OrchestratorQueueClient
{
    private readonly HttpClient _http;

    public OrchestratorQueueClient(HttpClient http) => _http = http;

    public async Task AddQueueItemAsync(string rawBody, string deliveryId, string eventType)
    {
        var request = new
        {
            itemData = new
            {
                Name = "BluPantheonEvents",
                Priority = eventType.Contains("handover") ? "High" : "Normal",
                Reference = deliveryId,
                SpecificContent = new Dictionary<string, object>
                {
                    ["EventType"] = eventType,
                    ["DeliveryId"] = deliveryId,
                    ["Payload"] = rawBody
                }
            }
        };

        using var response = await _http.PostAsJsonAsync(
            "/odata/Queues/UiPathODataSvc.AddQueueItem", request);
        response.EnsureSuccessStatusCode();
    }
}

Reference come chiave di deduplica

Imposta Reference uguale a X-BP-Delivery e attiva Unique Reference sulla coda. Orchestrator rifiuterà automaticamente i duplicati con errore Conflict, che il listener può trattare come successo rispondendo 202.

Verifica HMAC in VB.NET

Se il listener è realizzato con un processo UiPath in modalità servizio, oppure se devi verificare la firma dentro un Invoke Code activity, usa questo snippet VB.NET.

Configura l'attività Invoke Code con:

ProprietàValore
LanguageVBNet
Argumentsin_RawBody (String), in_SignatureHeader (String), in_Secret (String), out_IsValid (Boolean), out_Reason (String)
Invoke Code — verifica firma HMAC-SHA256
Dim toleranceSeconds As Integer = 300
Dim timestamp As Long = -1
Dim signatures As New List(Of String)

out_IsValid = False
out_Reason = "firma-non-corrispondente"

If String.IsNullOrWhiteSpace(in_SignatureHeader) Then
    out_Reason = "header-mancante"
    Exit Sub
End If

For Each segment As String In in_SignatureHeader.Split(","c)
    Dim separatorIndex As Integer = segment.IndexOf("="c)
    If separatorIndex < 0 Then Continue For

    Dim key As String = segment.Substring(0, separatorIndex).Trim()
    Dim value As String = segment.Substring(separatorIndex + 1).Trim()

    If key = "t" Then
        Long.TryParse(value, timestamp)
    ElseIf key = "v1" Then
        signatures.Add(value)
    End If
Next

If timestamp < 0 Then
    out_Reason = "timestamp-non-valido"
    Exit Sub
End If

Dim nowSeconds As Long = DateTimeOffset.UtcNow.ToUnixTimeSeconds()
If Math.Abs(nowSeconds - timestamp) > toleranceSeconds Then
    out_Reason = "timestamp-fuori-tolleranza"
    Exit Sub
End If

If signatures.Count = 0 Then
    out_Reason = "firma-assente"
    Exit Sub
End If

Dim signedPayload As Byte() = System.Text.Encoding.UTF8.GetBytes(
    timestamp.ToString() & "." & in_RawBody)

Using hmac As New System.Security.Cryptography.HMACSHA256(
        System.Text.Encoding.UTF8.GetBytes(in_Secret))

    Dim hash As Byte() = hmac.ComputeHash(signedPayload)
    Dim builder As New System.Text.StringBuilder(hash.Length * 2)
    For Each b As Byte In hash
        builder.Append(b.ToString("x2"))
    Next
    Dim expected As String = builder.ToString()
    Dim expectedBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(expected)

    For Each candidate As String In signatures
        Dim candidateBytes As Byte() = System.Text.Encoding.UTF8.GetBytes(candidate)
        If candidateBytes.Length = expectedBytes.Length Then
            If System.Security.Cryptography.CryptographicOperations.FixedTimeEquals(
                    candidateBytes, expectedBytes) Then
                out_IsValid = True
                out_Reason = "ok"
                Exit For
            End If
        End If
    Next
End Using

Queue Trigger

In Orchestrator apri Automations → Triggers → Add trigger → Queue trigger.

CampoValore
NameBluPantheon — eventi
ProcessBluPantheon.EventProcessor
QueueBluPantheonEvents
Minimum number of items1
Maximum number of pending jobs5
Allocate dynamicallyattivo

Elaborare l'elemento nel processo

Assign — lettura dello SpecificContent
eventType = in_TransactionItem.SpecificContent("EventType").ToString()
deliveryId = in_TransactionItem.SpecificContent("DeliveryId").ToString()
payloadJson = Newtonsoft.Json.Linq.JObject.Parse(
    in_TransactionItem.SpecificContent("Payload").ToString())

sessionId = payloadJson("data")("sessionId").ToString()
clientName = payloadJson("data")("client")("displayName").ToString()

Concludi con Set Transaction Status:

EsitoStatusNote
Operazione riuscitaSuccessfulNessuna azione ulteriore
Errore applicativo (dato non valido)Failed → BusinessExceptionNessun ritentativo
Errore tecnico (gestionale non risponde)Failed → ApplicationExceptionRitentativo automatico

Test dell'integrazione

Verifica la chiamata API

Esegui in Studio un workflow minimo con HTTP Request su /identity/v1/me. Il risultato atteso è statusCode = 200 e un corpo JSON con i dati del tenant.

Verifica il listener

Dalla Console usa Invia evento di prova con webhook.test. Controlla nei log consegne che la risposta sia 202 e che in Orchestrator compaia un nuovo elemento in coda con Reference uguale al X-BP-Delivery.

Verifica la deduplica

Nei log consegne clicca Riprova sulla stessa consegna. Orchestrator deve rifiutare il duplicato per Unique Reference e il listener deve comunque rispondere 202.

Verifica il ciclo completo

Genera un handover reale dal widget di test. Verifica che il robot apra la pratica nel gestionale e che la nota compaia nella sessione in Console.

Verifica la gestione errori

Sospendi temporaneamente il robot e osserva l'accumulo in coda. Al ripristino gli elementi devono essere elaborati senza perdite e senza duplicati.

Passi successivi

Auf dieser Seite