Udostępnij za pośrednictwem


Pisanie kodu w łączniku niestandardowym

Niestandardowy kod przekształca żądania i odpowiedzi poza zakresem istniejących szablonów polityki. Gdy używany jest kod, ma on pierwszeństwo przed definicją bez kodu.

Aby uzyskać więcej informacji, przejdź do tematu Tworzenie łącznika niestandardowego od podstaw.

Klasa skryptu

Kod musi zaimplementować metodę ExecuteAsync, która jest wywoływana w czasie wykonywania. W razie potrzeby można utworzyć inne metody w tej klasie i wywołać je za pomocą metody ExecuteAsync. Nazwa klasy musi mieć wartość Script i musi implementować ScriptBase.

public class Script : ScriptBase
{
    public override Task<HttpResponseMessage> ExecuteAsync()
    {
        // Your code here
    }
}

Definicje klas pomocy technicznej i interfejsów

Do klas skryptów odwołują się następujące klasy i interfejsy. Można ich używać do lokalnego testowania i kompilacji.

public abstract class ScriptBase
{
    // Context object
    public IScriptContext Context { get; }

    // CancellationToken for the execution
    public CancellationToken CancellationToken { get; }

    // Helper: Creates a StringContent object from the serialized JSON
    public static StringContent CreateJsonContent(string serializedJson);

    // Abstract method for your code
    public abstract Task<HttpResponseMessage> ExecuteAsync();
}

public interface IScriptContext
{
    // Correlation Id
    string CorrelationId { get; }

    // Connector Operation Id
    string OperationId { get; }

    // Incoming request
    HttpRequestMessage Request { get; }

    // Logger instance
    ILogger Logger { get; }

    // Used to send an HTTP request
    // Use this method to send requests instead of HttpClient.SendAsync
    Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken);
}

Przykłady

Skrypt Hello World

Ten przykładowy skrypt zawsze zwraca Hello World jako odpowiedź dla wszystkich żądań.

public override async Task<HttpResponseMessage> ExecuteAsync()
{
    // Create a new response
    var response = new HttpResponseMessage();

    // Set the content
    // Initialize a new JObject and call .ToString() to get the serialized JSON
    response.Content = CreateJsonContent(new JObject
    {
        ["greeting"] = "Hello World!",
    }.ToString());

    return response;
}

Skrypt regex

Poniższa próbka pobiera pewien tekst do dopasowania oraz wyrażenie regex i zwraca wynik dopasowania w odpowiedzi.

public override async Task<HttpResponseMessage> ExecuteAsync()
{
    // Check if the operation ID matches what is specified in the OpenAPI definition of the connector
    if (this.Context.OperationId == "RegexIsMatch")
    {
        return await this.HandleRegexIsMatchOperation().ConfigureAwait(false);
    }

    // Handle an invalid operation ID
    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
    response.Content = CreateJsonContent($"Unknown operation ID '{this.Context.OperationId}'");
    return response;
}

private async Task<HttpResponseMessage> HandleRegexIsMatchOperation()
{
    HttpResponseMessage response;

    // We assume the body of the incoming request looks like this:
    // {
    //   "textToCheck": "<some text>",
    //   "regex": "<some regex pattern>"
    // }
    var contentAsString = await this.Context.Request.Content.ReadAsStringAsync().ConfigureAwait(false);

    // Parse as JSON object
    var contentAsJson = JObject.Parse(contentAsString);

    // Get the value of text to check
    var textToCheck = (string)contentAsJson["textToCheck"];

    // Create a regex based on the request content
    var regexInput = (string)contentAsJson["regex"];
    var rx = new Regex(regexInput);

    JObject output = new JObject
    {
        ["textToCheck"] = textToCheck,
        ["isMatch"] = rx.IsMatch(textToCheck),
    };

    response = new HttpResponseMessage(HttpStatusCode.OK);
    response.Content = CreateJsonContent(output.ToString());
    return response;
}

Skrypt przesyłania dalej

Poniższy przykładowy przykład przesyła żądanie przychodzące do wewnętrznej bazy danych.

public override async Task<HttpResponseMessage> ExecuteAsync()
{
    // Check if the operation ID matches what is specified in the OpenAPI definition of the connector
    if (this.Context.OperationId == "ForwardAsPostRequest")
    {
        return await this.HandleForwardOperation().ConfigureAwait(false);
    }

    // Handle an invalid operation ID
    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
    response.Content = CreateJsonContent($"Unknown operation ID '{this.Context.OperationId}'");
    return response;
}

private async Task<HttpResponseMessage> HandleForwardOperation()
{
    // Example case: If your OpenAPI definition defines the operation as 'GET', but the backend API expects a 'POST',
    // use this script to change the HTTP method.
    this.Context.Request.Method = HttpMethod.Post;

    // Use the context to forward/send an HTTP request
    HttpResponseMessage response = await this.Context.SendAsync(this.Context.Request, this.CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
    return response;
}

Skrypt przesyłania dalej i przekształcenia

Poniższy przykład przesyła żądanie przychodzące i przekształci odpowiedź zwróconą z wewnętrznej bazy danych.

public override async Task<HttpResponseMessage> ExecuteAsync()
{
    // Check if the operation ID matches what is specified in the OpenAPI definition of the connector
    if (this.Context.OperationId == "ForwardAndTransformRequest")
    {
        return await this.HandleForwardAndTransformOperation().ConfigureAwait(false);
    }

    // Handle an invalid operation ID
    HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.BadRequest);
    response.Content = CreateJsonContent($"Unknown operation ID '{this.Context.OperationId}'");
    return response;
}

private async Task<HttpResponseMessage> HandleForwardAndTransformOperation()
{
    // Use the context to forward/send an HTTP request
    HttpResponseMessage response = await this.Context.SendAsync(this.Context.Request, this.CancellationToken).ConfigureAwait(continueOnCapturedContext: false);

    // Do the transformation if the response was successful, otherwise return error responses as-is
    if (response.IsSuccessStatusCode)
    {
        var responseString = await response.Content.ReadAsStringAsync().ConfigureAwait(continueOnCapturedContext: false);
        
        // Example case: response string is some JSON object
        var result = JObject.Parse(responseString);
        
        // Wrap the original JSON object into a new JSON object with just one key ('wrapped')
        var newResult = new JObject
        {
            ["wrapped"] = result,
        };
        
        response.Content = CreateJsonContent(newResult.ToString());
    }

    return response;
}

Obsługiwane przestrzenie nazw

Nie wszystkie przestrzenie nazw języka C# są obsługiwane. Obecnie można używać funkcji tylko z następujących przestrzeni nazw.

using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Net.Security;
using System.Security.Authentication;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Web;
using System.Xml;
using System.Xml.Linq;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;

Przykłady GitHub

Aby zapoznać się z przykładami w łączniku DocuSign , przejdź do pozycji Power Platform Łączniki w usłudze GitHub.

Kod niestandardowy – FAQ

Aby dowiedzieć się więcej o kodzie niestandardowym, przejdź do kroku 4: (Opcjonalnie) Użyj obsługi kodu niestandardowego.

.: Czy można używać wielu skryptów na łącznik niestandardowy?
Odp.: Nie, obsługiwany jest tylko jeden plik skryptu na łącznik niestandardowy.

.: Otrzymuję wewnętrzny błąd serwera podczas aktualizowania łącznika niestandardowego. Co może być problemem?
O: Najprawdopodobniej jest to problem z kompilacją kodu. W przyszłości wyświetlimy pełną listę błędów kompilacji, aby poprawić jakość tego doświadczenia. Na razie zalecamy użycie klas pomocniczych do lokalnego testowania błędów kompilacji jako obejście problemu.

.: Czy mogę dodać rejestrowanie do mojego kodu i uzyskać ślad do debugowania?
Odp .: Obecnie nie, ale obsługa tego zostanie dodana w przyszłości.

P: Jak mogę przetestować mój kod w międzyczasie?
O: Przetestuj go lokalnie i upewnij się, że możesz skompilować kod tylko przy użyciu przestrzeni nazw dostępnych w obsługiwanych przestrzeniach nazw. Aby uzyskać informacje na temat testowania lokalnego, przejdź do tematu Pisanie kodu w łączniku niestandardowym.

P: Czy są jakieś limity?
Odpowiedź: Tak. Skrypt musi zostać wykonany w ciągu 2 minut, a rozmiar pliku skryptu nie może przekraczać 1 MB. Ten nowy 2-minutowy limit czasu ma zastosowanie do wszystkich nowo utworzonych łączników niestandardowych. W przypadku istniejących łączników niestandardowych klienci muszą zaktualizować łącznik, aby zastosować nowy limit czasu.

P: Czy mogę utworzyć własnego klienta http w kodzie skryptu?
O: Obecnie tak, ale zablokujemy to w przyszłości. Zalecanym sposobem jest skorzystanie z tego. Context.SendAsync .

.: Czy mogę użyć kodu niestandardowego z lokalną bramą danych?
Odp .: Obecnie nie, nie.

Pomoc techniczna usługi Virtual Network

Gdy łącznik jest używany w środowisku połączonym Power Platform z Virtual Network, obowiązują ograniczenia:

  • Context.SendAsync używa publicznego punktu końcowego, dlatego nie może uzyskać dostępu do danych z prywatnych punktów końcowych ujawnionych w sieci wirtualnej.

Ogólne znane problemy i ograniczenia

Nagłówek OperationId może zostać zwrócony w formacie zakodowanym base64 w niektórych regionach. Jeśli wartość OperationId jest wymagana do implementacji, w celu jej użycia powinna ona zostać zdekodowana z formatu Base64 w sposób podobny do następującego.

public override async Task<HttpResponseMessage> ExecuteAsync()
{
    string realOperationId = this.Context.OperationId;
    // Resolve potential issue with base64 encoding of the OperationId
    // Test and decode if it's base64 encoded
    try {
        byte[] data = Convert.FromBase64String(this.Context.OperationId);
        realOperationId = System.Text.Encoding.UTF8.GetString(data);
    }
    catch (FormatException ex) {}
    // Check if the operation ID matches what is specified in the OpenAPI definition of the connector
    if (realOperationId == "RegexIsMatch")
    // Refer to the original examples above for remaining details
}

Następny krok

Tworzenie łącznika niestandardowego od podstaw

Przekazywanie opinii

Jesteśmy wdzięczni za opinie na temat problemów z platformą łączników oraz pomysły na nowe funkcje. Aby przekazać opinię, przejdź do sekcji Przesyłanie problemów lub uzyskiwanie pomocy dotyczącej łączników i wybierz typ opinii.