Escritura de código en un conector personalizado
El código personalizado transforma las cargas útiles de solicitudes y respuestas más allá del alcance de las plantillas de políticas existentes. Cuando se usa código, tiene prioridad sobre la definición sin código.
Para obtener más información, vaya a Crear un conector personalizado desde cero.
Clase de script
Su código necesita implementar un método llamado ExecuteAsync, que se llama durante el runtime. Puede crear otros métodos en esta clase según sea necesario y llamarlos desde el método ExecuteAsync. El nombre de la clase debe ser Script y debe implementar ScriptBase.
public class Script : ScriptBase
{
public override Task<HttpResponseMessage> ExecuteAsync()
{
// Your code here
}
}
Definición de clases e interfaces de apoyo
La clase Script hace referencia a las siguientes clases e interfaces. Se pueden utilizar para compilación y pruebas locales.
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);
}
Ejemplos
Guión de Hola mundo
Este script de muestra siempre devuelve Hola mundo como respuesta a todas las solicitudes.
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;
}
Script regex
El siguiente ejemplo toma algo de texto para que coincida y la expresión regex y devuelve el resultado de la coincidencia en la respuesta.
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;
}
Script de reenvío
El siguiente ejemplo reenvía la solicitud entrante al backend.
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;
}
Script de reenvío y transformación
El siguiente ejemplo reenvía la solicitud entrante y transforma la respuesta devuelta desde el backend.
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;
}
Espacios de nombres admitidos
No se admiten todos los espacios de nombres de C#. Actualmente, puede usar funciones solo de los siguientes espacios de nombres.
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;
Muestras de GitHub
Para ejemplos en el conector DocuSign, vaya a Conectores de Power Platform en GitHub.
Preguntas frecuentes sobre código personalizado
Para obtener más información sobre el código personalizado, vaya al Paso 4: (Opcional) utilizar el soporte de código personalizado.
P: ¿Es posible utilizar varios scripts por cada conector personalizado?
R: No, solo se admite un archivo de script por conector personalizado.
P: Recibo un error interno del servidor al actualizar mi conector personalizado. ¿Cual podría ser el problema?
R: Lo más probable es que se trate de un problema al compilar su código. En el futuro, mostraremos la lista completa de errores de compilación para mejorar esta experiencia. Por ahora, recomendamos utilizar las clases de apoyo para probar los errores de compilación localmente, como solución alternativa.
P: ¿Puedo agregar registros a mi código y obtener un seguimiento para la depuración?
R: Actualmente no, pero se agregará compatibilidad para esto en el futuro.
P: ¿Cómo puedo probar mi código mientras tanto?
R: Pruébelo localmente y asegúrese de que puede compilar código utilizando solo los espacios de nombres proporcionados enespacios de nombres admitidos. Para obtener información sobre las pruebas locales, vaya a Escribir código en un conector personalizado.
P: ¿Existe alguna limitación?
R: Sí. Su script debe finalizar la ejecución en 5 segundos y el tamaño de su archivo de secuencia de comandos no puede ser superior a 1 MB.
P: ¿Puedo crear mi propio cliente http en código script?
R: Actualmente sí, pero bloquearemos esto en el futuro. La forma recomendada es utilizar el método this.Context.SendAsync.
P: ¿Puedo utilizar código personalizado con la puerta de enlace de datos local?
R: Actualmente, no.
Soporte de Virtual Network
Cuando el conector se utiliza en un entorno de Power Platform vinculado a una red virtual, se aplican limitaciones:
- Context.SendAsync utiliza un punto de conexión público, por lo que no puede acceder a datos desde puntos de conexión privados expuestos en la red virtual.
Problemas y limitaciones generales conocidos
El encabezado OperationId podría devolverse en formato codificado en base64 en determinadas regiones. Si el valor de OperationId es necesario para una implementación, debe descodificarse en base64 para su uso en una forma similar a la siguiente.
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
}
Siguiente paso
Creación de un conector personalizado desde cero
Proporcionar comentarios
Agradecemos enormemente los comentarios sobre problemas con nuestra plataforma de conectores o nuevas ideas de características. Para enviar comentarios, vaya a Enviar problemas u obtener ayuda con los conectores y seleccione el tipo de comentario.