使用 Azure Logic Apps 的標準工作流程新增並執行內嵌的 C# 指令碼 (預覽)

適用於:Azure Logic Apps (標準)

注意

此功能處於預覽狀態,且受限於 Microsoft Azure 預覽版的補充使用規定

若要在 Azure Logic Apps 中使用標準工作流程執行內嵌的自訂整合工作,您可以直接從工作流程內新增並執行 C# 指令碼。 針對這項工作,請使用名為執行 CSharp 指令碼程式碼內嵌程式碼動作。 此動作會傳回指令碼的結果,讓您可以在工作流程的後續動作中使用此輸出。

這項功能可提供下列優點:

  • 在工作流程設計工具內撰寫您自己的指令碼,讓您不必使用 Azure Functions 就能解決更複雜的整合挑戰。 不需要其他服務方案。

    這項優點可簡化工作流程的開發,並降低管理更多服務的複雜性和成本。

  • 產生專用的程式碼檔案,此檔案可在工作流程內提供個人化的指令碼空間。

  • 將指令碼與工作流程一起部署。

本指南說明如何在工作流程中新增動作,並新增您想要執行的 C# 指令碼程式碼。

必要條件

  • Azure 帳戶和訂用帳戶。 如果您沒有訂用帳戶,請註冊一個免費的 Azure 帳戶

  • 您想要在其中新增 C# 指令碼的標準邏輯應用程式工作流程。 工作流程必須已使用觸發程序啟動。 如需詳細資訊,請參閱建立範例標準邏輯應用程式工作流程 (部分機器翻譯)。

    您可以針對您的案例使用任何觸發程序,但本指南會使用名為收到 HTTP 要求時要求觸發程序以及回應動作來作為範例。 當其他應用程式或工作流程傳送要求給觸發程序的端點 URL 時,該工作流程便會執行。 範例指令碼會傳回程式碼的執行結果,以作為可在後續動作中使用的輸出。

範例案例

下列清單會說明一些可使用指令碼來協助進行特定整合工作的範例案例:

  • 剖析內建運算式和資料作業功能以外的承載,並對其執行轉換或操作。 例如,您可以使用指令碼來傳回已修改的結構描述以進行下游處理。

  • 根據某些商務邏輯來管理虛擬機器等 Azure 資源,以及加以啟動或逐步執行。

  • 在 SQL Server 上執行需要依排程執行的預存程序,並將結果儲存在 SharePoint 上。

  • 藉由儲存至 Azure 儲存體來記錄具有詳細資訊的工作流程錯誤,或記錄錯誤以傳送電子郵件給小組或通知小組。

  • 加密和解密資料以符合 API 安全性標準。

  • 將檔案傳遞至指令碼,以針對 HTTP 要求進行壓縮或解壓縮。

  • 彙總來自各種 API 和檔案的資料,以建立每日報告

考量

  • Azure 入口網站會在與 workflow.json 檔案 (儲存了工作流程的 JSON 定義) 相同的資料夾中,將您的指令碼儲存為 C# 指令檔 (.csx),並將指令檔連同工作流程定義一起部署到邏輯應用程式資源。 Azure Logic Apps 會編譯此檔案,以讓指令碼可供執行。

    .csx 檔案格式可讓您撰寫較少的「重複使用程式碼」,並專注於撰寫 C# 函式。 您可以在部署期間重新命名 .csx 檔案以簡化管理。 不過,每次重新命名指令碼時,新版本便會覆寫舊版本。

  • 對工作流程來說,指令碼是本機項目。 若要在其他工作流程中使用相同的指令碼,請KuduPlus 主控台中檢視指令檔,然後複製指令碼以在其他工作流程中重複使用。

限制

名稱 限制 備註
指令碼執行持續時間 10 分鐘 如果您有需要較長持續時間的案例,請使用產品意見反應選項來提供關於您需求的詳細資訊。
輸出大小 100 MB 輸出大小取決於動作的輸出大小限制,這通常為 100 MB。

新增執行 CSharp 指令碼程式碼動作

  1. Azure 入口網站,於設計工具中開啟您的標準邏輯應用程式資源和工作流程。

  2. 在設計工具中,遵循這些一般步驟以將名為執行 CSharp 指令碼程式碼內嵌程式碼作業動作新增至您的工作流程 (部分機器翻譯)。

  3. 動作資訊窗格開啟後,在 [參數] 索引標籤的 [程式碼檔案] 方塊中,使用您自己的指令碼程式碼更新預先填入的範例程式碼。

    下列範例顯示動作的 [參數] 索引標籤,其中包含範例指令碼程式碼:

    此螢幕擷取畫面顯示 Azure 入口網站、標準工作流程設計工具、要求觸發程序、執行 CSharp 指令碼程式碼動作和開啟的資訊窗格,以及 [回應] 動作。資訊窗格中顯示了範例 C# 指令碼。

    下列範例顯示範例指令碼程式碼:

    /// Add the required libraries.
    #r "Newtonsoft.Json"
    #r "Microsoft.Azure.Workflows.Scripting"
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    using Microsoft.Extensions.Logging;
    using Microsoft.Azure.Workflows.Scripting;
    using Newtonsoft.Json.Linq;
    
    /// <summary>
    /// Executes the inline C# code.
    /// </summary>
    /// <param name="context">The workflow context.</param>
    /// <remarks> The entry-point to your code. The function signature should remain unchanged.</remarks>
    public static async Task<Results> Run(WorkflowContext context, ILogger log)
    {
        var triggerOutputs = (await context.GetTriggerResults().ConfigureAwait(false)).Outputs;
    
        /// Dereferences the 'name' property from the trigger payload.
        var name = triggerOutputs?["body"]?["name"]?.ToString();
    
        /// To get the outputs from a preceding action, you can uncomment and repurpose the following code.
        // var actionOutputs = (await context.GetActionResults("<action-name>").ConfigureAwait(false)).Outputs;
    
        /// The following logs appear in the Application Insights traces table.
        // log.LogInformation("Outputting results.");
        // var name = null;
    
        return new Results
        {
            Message = !string.IsNullOrEmpty(name) ? $"Hello {name} from CSharp action" : "Hello from CSharp action."
        };
    }
    
    public class Results
    {
        public string Message {get; set;}
    }
    

    如需詳細資訊,請參閱 "#r" - 參考外部組件 (部分機器翻譯)。

  4. 當您完成時,請儲存您的工作流程。

在執行工作流程後,您可以在 Application Insights 中檢閱工作流程輸出 (如果已啟用的話)。 如需詳細資訊,請參閱檢視 Application Insights 中的記錄

匯入命名空間

若要匯入命名空間,請如往常一般使用 using 子句來進行。 下列清單包含自動匯入的命名空間,因此您可以選擇是否將其包含在指令碼中:

System
System.Collections.Generic
System.IO
System.Linq
System.Net.Http
System.Threading.Tasks
Microsoft.Azure.WebJobs
Microsoft.Azure.WebJobs.Host

新增外部組件的參考

若要參考 .NET Framework 組件,請使用 #r "<assembly-name> 指示詞,例如:

/// Add the required libraries.
#r "Newtonsoft.Json"
#r "Microsoft.Azure.Workflows.Scripting"
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Workflows.Scripting;
using Newtonsoft.Json.Linq;

public static async Task<Results> Run(WorkflowContext context)
{
    <...>
}

public class Results
{
    <...>
}

下列清單包含 Azure Functions 裝載環境所自動新增的組件:

mscorlib
System
System.Core
System.Xml
System.Net.Http
Microsoft.Azure.WebJobs
Microsoft.Azure.WebJobs.Host
Microsoft.Azure.WebJobs.Extensions
System.Web.Http
System.Net.Http.Formatting
Newtonsoft.Json

將輸出記錄至資料流

在您的 Run 方法中,包含類型為 ILogger 且名稱為 log 的參數,例如:

public static void Run(WorkflowContext context, ILogger log)
{
    log.LogInformation($"C# script successfully executed.");
}

將輸出記錄至 Application Insights

若要在 Application Insights 中建立自訂計量,請在 ILogger 上使用 LogMetric 擴充方法。

下列範例顯示範例方法呼叫:

logger.LogMetric("TestMetric", 1234);

存取指令碼中的工作流程觸發程序和動作輸出

若要從工作流程存取資料,請使用下列適用於 WorkflowContext 內容物件的方法:

  • GetTriggerResults 方法

    若要存取觸發程序輸出,請使用此方法傳回代表觸發程序及其輸出 (可透過 Outputs 屬性來取得) 的物件。 此物件具有 JObject 類型,而且您可以使用方括弧 ([]) 作為索引子來存取觸發程序輸出中的各種屬性。

    下列範例會從觸發程序輸出中的 body 屬性取得資料:

    public static async Task<Results> Run(WorkflowContext context, ILogger log)
    {
    
        var triggerOutputs = (await context.GetTriggerResults().ConfigureAwait(false)).Outputs;
        var body = triggerOutputs["body"];
    
        return new Results;
    
    }
    
    public class Results
    {
        <...>
    }
    
  • GetActionResults 方法

    若要存取動作輸出,請使用此方法傳回代表動作及其輸出 (可透過 Outputs 屬性來取得) 的物件。 此方法接受以動作名稱作為參數。 下列範例會從名為「action-name」的動作輸出中的 body 屬性取得資料:

    public static async Task<Results> Run(WorkflowContext context, ILogger log)
    {
    
        var actionOutputs = (await context.GetActionResults("action-name").ConfigureAwait(false)).Outputs;
        var body = actionOutputs["body"];
    
        return new Results;
    
    }
    
    public class Results
    {
        <...>
    }
    

存取環境變數或應用程式設定值

若要取得環境變數或應用程式設定值,請使用 System.Environment.GetEnvironmentVariable 方法,例如:

public static void Run(WorkflowContext context, ILogger log)
{
    log.LogInformation($"C# Timer trigger function executed at: {DateTime.Now}");
    log.LogInformation(GetEnvironmentVariable("AzureWebJobsStorage"));
    log.LogInformation(GetEnvironmentVariable("WEBSITE_SITE_NAME"));
}

public static string GetEnvironmentVariable(string name)
{
    return name + ": " +
    System.Environment.GetEnvironmentVariable(name, EnvironmentVariableTarget.Process);
}

將資料傳回您的工作流程

針對這項工作,請使用某個傳回類型和 return 陳述式來實作 Run 方法。 如果您想要非同步版本,請使用 Task<return-type> 屬性和 async 關鍵字來實作 Run 方法。 傳回值會設定為指令碼動作的輸出 body 屬性,以供任何後續工作流程動作參考。

下列範例顯示具有 Task<Results> 屬性、async 關鍵字和 return 陳述式的 Run 方法:

public static async Task<Results> Run(WorkflowContext context, ILogger log)
{
    return new Results
    {
        Message = !string.IsNullOrEmpty(name) ? $"Returning results with status message."
    };
}

public class Results
{
    public string Message {get; set;}
}

檢視指令檔

  1. Azure 入口網站中,開啟具有所需工作流程的標準邏輯應用程式資源。

  2. 在邏輯應用程式資源功能表的 [開發工具] 下,選取 [進階工具]

  3. 在 [進階工具] 頁面上,選取 [開始],這會開啟 KuduPlus 主控台。

  4. 開啟 [偵錯主控台] 功能表,並選取 [CMD]

  5. 移至邏輯應用程式的根位置:site/wwwroot

  6. 在以下路徑上移至包含 .csx 檔案的工作流程資料夾:site/wwwroot/{workflow-name}

  7. 在檔案名稱旁邊,選取 [編輯] 以開啟並檢視檔案。

在 Application Insights 中檢視記錄

  1. Azure 入口網站的邏輯應用程式資源功能表上,於 [設定] 底下選取 [Application Insights],然後選取您的邏輯應用程式。

  2. 在 [Application Insights] 功能表上的 [監視] 底下,選取 [記錄]

  3. 建立查詢以尋找工作流程執行中的任何追蹤或錯誤,例如:

    union traces, errors
    | project TIMESTAMP, message
    

編譯錯誤

在此版本中,網頁型編輯器包含有限的 IntelliSense 支援,此支援仍在改善中。 當您儲存工作流程時,系統會偵測到任何編譯錯誤,而 Azure Logic Apps 執行階段會編譯您的指令碼。 這些錯誤會出現在邏輯應用程式的錯誤記錄中。

執行階段錯誤

如果您的指令碼執行時發生錯誤,Azure Logic Apps 會執行下列步驟:

  • 將錯誤傳回您的工作流程。
  • 將指令碼動作標示為失敗
  • 提供代表從指令碼擲回之例外狀況的錯誤物件。

下列範例顯示範例錯誤:

函式「CSharp_MyLogicApp-InvalidAction_execute_csharp_script_code.csx」在執行時失敗,錯誤為「工作流程中沒有「不存在」動作」 。 請驗證函式程式碼是否有效。

範例指令碼

下列範例指令碼會執行您可能執行的各種工作

將含有文字檔的 ZIP 檔案從 HTTP 動作解壓縮到字串陣列

// Add the required libraries.
#r "Newtonsoft.Json"
#r "Microsoft.Azure.Workflows.Scripting"
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Azure.Workflows.Scripting;
using System;
using System.IO;
using System.IO.Compression;
using System.Text;
using System.Collections.Generic;

/// <summary>
/// Executes the inline C# code.
/// </summary>
/// <param name="context">The workflow context.</param>
public static async Task<List<string>> Run(WorkflowContext context)
{

    var outputs = (await context.GetActionResults("HTTP_1").ConfigureAwait(false)).Outputs;
    var base64zipFileContent = outputs["body"]["$content"].ToString();

    // Decode base64 to bytes.
    byte[] zipBytes = Convert.FromBase64String(base64zipFileContent);

    List<string> fileContents = new List<string>();

    // Creates an in-memory stream from the zip bytes.
    using (MemoryStream zipStream = new MemoryStream(zipBytes))
    {

        // Extracts files from the zip archive.
        using (ZipArchive zipArchive = new ZipArchive(zipStream))
        {

            foreach (ZipArchiveEntry entry in zipArchive.Entries)
            {

                // Read each file's content.
                using (StreamReader reader = new StreamReader(entry.Open()))
                {
                    string fileContent = reader.ReadToEnd();
                    fileContents.Add(fileContent);
                }
            }
        }
    }

    return fileContents;
}

使用來自應用程式設定的金鑰來加密資料

// Add the required libraries.
#r "Newtonsoft.Json"
#r "Microsoft.Azure.Workflows.Scripting"
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Primitives;
using Microsoft.Azure.Workflows.Scripting;
using Newtonsoft.Json.Linq;
using System;
using System.IO;
using System.Security.Cryptography;
using System.Text;

/// <summary>
/// Executes the inline csharp code.
/// </summary>
/// <param name="context">The workflow context.</param>
public static async Task<string> Run(WorkflowContext context)
{

    var compose = (await context.GetActionResults("compose").ConfigureAwait(false)).Outputs;
    var text = compose["sampleData"].ToString();

    return EncryptString(text);

}

public static string EncryptString(string plainText)
{

    var key = Environment.GetEnvironmentVariable("app-setting-key");
    var iv = Environment.GetEnvironmentVariable("app-setting-iv");

    using (Aes aesAlg = Aes.Create())
    {

        aesAlg.Key = Encoding.UTF8.GetBytes(key);
        aesAlg.IV = Encoding.UTF8.GetBytes(iv);
        ICryptoTransform encryptor = aesAlg.CreateEncryptor(aesAlg.Key, aesAlg.IV);

        using (MemoryStream msEncrypt = new MemoryStream())
        {

            using (CryptoStream csEncrypt = new CryptoStream(msEncrypt, encryptor, CryptoStreamMode.Write))
            {

                using (StreamWriter swEncrypt = new StreamWriter(csEncrypt))
                {
                    swEncrypt.Write(plainText);
                }

            }

             return Convert.ToBase64String(msEncrypt.ToArray());

        }
    }
}

WorkflowContext 類別

代表工作流程內容。

方法

GetActionResult(string actionName)

取得工作流程中特定動作的結果。

非同步版本使用 Task<> 作為傳回類型,例如:

Task<WorkflowOperationResult> GetActionResult(string actionName)

參數

actionName:動作名稱。

傳回

非同步版本會傳回代表非同步作業的 Task 物件。 工作結果包含 WorkflowOperationResult 物件。 如需 WorkflowOperationResult 物件屬性的相關資訊,請參閱 WorkflowOperationResult 類別

RunTriggerResult()

取得工作流程中觸發程序的結果。

非同步版本使用 Task<> 作為傳回類型,例如:

Task<WorkflowOperationResult> RunTriggerResult()

參數

無。

傳回

非同步版本會傳回代表非同步作業的 Task 物件。 工作結果包含 WorkflowOperationResult 物件。 如需 WorkflowOperationResult 物件屬性的相關資訊,請參閱 WorkflowOperationResult 類別

WorkflowOperationResult 類別

代表工作流程作業的結果。

屬性

名稱 類型​​ Description
名稱 String 取得或設定作業名稱。
輸入 JToken 取得或設定作業執行輸入。
輸出 JToken 取得或設定作業執行輸出。
StartTime DateTime? 取得或設定作業開始時間。
EndTime DateTime? 取得或設定作業結束時間。
OperationTrackingId String 取得或設定作業追蹤 ID。
程式碼 String 取得或設定動作的狀態代碼。
狀態 String 取得或設定動作的狀態。
錯誤 JToken 取得或設定動作的錯誤。
TrackedProperties JToken 取得或設定動作的已追蹤屬性。

新增並執行 JavaScript 程式碼片段 (部分機器翻譯)