使用 Visual Studio Code 创建 Azure 逻辑应用规则引擎项目(预览版)

适用于:Azure 逻辑应用(标准)

重要

此功能为预览版,受 Azure 预览版补充使用条款约束。

如果你要将业务逻辑与 Azure 逻辑应用中的标准工作流集成,可以使用 Visual Studio Code 创建并生成 Azure 逻辑应用规则引擎项目。 规则控制有关业务流程运作方式的业务逻辑。

本操作指南介绍如何创建 Azure 逻辑应用规则引擎项目:

  • 创建 Azure 逻辑应用规则引擎项目的先决条件和设置,包括使用 Microsoft 规则编辑器为项目创建业务规则。

  • 从 Microsoft BizTalk Server 导出现有规则(如果有)。

  • 使用 Visual Studio Code 为 Azure 逻辑应用规则引擎创建标准逻辑应用项目。

先决条件

创建项目之前

为了帮助确保规则引擎项目创建成功,请查看并执行以下常规任务和最佳做法:

  1. 确定业务规则是否适合你的业务流程。

  2. 规划如何将业务规则合并到应用程序中。

  3. 标识出要在应用程序中使用规则来表示的业务逻辑。

    术语“业务逻辑”指很多事物。 例如,业务逻辑可能是“超过 500 美元的采购订单需要经理批准”。

  4. 标识规则元素的数据源。 可以选择性地定义词汇(表示底层绑定的特定于领域的术语)。

  5. 从词汇定义或直接从数据绑定定义要使用的规则。 根据这些规则创建一个代表业务逻辑的规则集。

从 Microsoft BizTalk Server 导出规则

若要重用 Microsoft BizTalk Server 中的现有规则,可将其导出。 但是,目前不支持 DB 事实。 在导出规则之前,请使用 Microsoft BizTalk 规则编辑器将其删除或重构为其他类型的事实

  1. 在“Microsoft BizTalk Server”中,启动“业务规则引擎部署”向导

  2. 在“欢迎使用规则引擎部署向导”页面上,选择“下一步”

  3. 在“部署任务”页面上,选择“将策略/词汇从数据库导出到文件”,然后选择“下一步”

  4. 在“策略存储”页面上的“SQL 服务器名称”列表中,选择你的 SQL 服务器。 在选定服务器上的“配置数据库”列表中,选择“BizTalkRuleEngineDb”,然后选择“下一步”

  5. 在“导出策略/词汇”页面上的“策略”列表中,选择所需的策略。 若要查找并选择定义文件,请选择“浏览”

  6. 准备就绪后,选择“下一步”。

  7. 确认服务器、数据库和策略或词汇信息,然后选择“下一步”

  8. 导入或导出完成后,选择“下一步”

  9. 检查导入或导出的完成状态,然后选择“完成”

创建 Azure 逻辑应用规则引擎项目

  1. 在 Visual Studio Code 中的活动栏上,选择“Azure”图标。 (键盘:Shift+Alt+A)

  2. 在打开的 Azure 窗口中,在“工作区”部分工具栏的“Azure 逻辑应用”菜单中选择“新建逻辑应用工作区”。

    该屏幕截图显示了 Visual Studio Code、Azure 窗口、“工作区”部分工具栏和选中的“新建逻辑应用工作区”选项。

  3. 在“选择文件夹”框中,浏览到并选择为项目创建的本地文件夹。

  4. 当出现“创建新的逻辑应用工作区”提示框时,请提供工作区的名称:

    屏幕截图显示 Visual Studio Code 提示你输入工作区名称。

    此示例继续使用 MyLogicAppRulesWorkspace

  5. 当出现“选择逻辑应用工作区的项目模板”提示框时,请选择“具有规则引擎项目的逻辑应用(预览版)”

    屏幕截图显示 Visual Studio Code 提示你选择逻辑应用工作区的项目模板。

  6. 按照后续提示提供以下示例值:

    示例值
    函数项目的函数名称 RulesFunction
    函数项目的命名空间名称 Contoso.Enterprise
    工作流模板:
    - 有状态工作流
    - 无状态工作流
    有状态工作流
    工作流名称 MyRulesWorkflow
  7. 选择“在当前窗口中打开”。

    完成此步骤后,Visual Studio Code 会创建工作区,其中默认包括函数项目和逻辑应用规则引擎项目,例如:

    屏幕截图显示 Visual Studio Code 和已创建的工作区。

    节点 说明
    <workspace-name> 包含你的函数项目和逻辑应用工作流项目。
    Function 包含你的函数项目的工件。 例如,<function-name>.cs 文件是可在其中创作代码的代码文件。
    逻辑应用 包含逻辑应用规则引擎项目的项目,包括工作流。

编写规则引擎代码

  1. 在工作区中,展开“Functions”节点(如果尚未展开)。

  2. 打开 <function-name>.cs 文件,本示例中该文件的名称为 RulesFunction.cs

    默认情况下,此文件包含具有以下代码元素的示例代码,它具有前面提供的示例值(如果适用):

    • 命名空间名称
    • 类名
    • 函数名称
    • 函数参数
    • 返回类型
    • 复杂类型

    以下示例显示了名为 RulesFunction 的函数的完整示例代码:

    //------------------------------------------------------------
    // Copyright (c) Microsoft Corporation. All rights reserved.
    //------------------------------------------------------------
    
    namespace Contoso.Enterprise
    {
        using System;
        using System.Collections.Generic;
        using System.Threading.Tasks;
        using Microsoft.Azure.Functions.Extensions.Workflows;
        using Microsoft.Azure.WebJobs;
        using Microsoft.Azure.Workflows.RuleEngine;
        using Microsoft.Extensions.Logging;
        using System.Xml;
    
        /// <summary>
        /// Represents the RulesFunction flow invoked function.
        /// </summary>
        public class RulesFunction
        {
            private readonly ILogger<RulesFunction> logger;
    
            public RulesFunction(ILoggerFactory loggerFactory)
            {
                logger = loggerFactory.CreateLogger<RulesFunction>();
            }
    
            /// <summary>
            /// Execute the logic app workflow.
            /// </summary>
            /// <param name="ruleSetName">The ruleset name.</param>
            /// <param name="documentType">The document type for the input XML.</param>
            /// <param name="inputXml">The input XML type fact.</param>
            /// <param name="purchaseAmount">The purchase amount value used to create a .NET fact.</param>
            /// <param name="zipCode">The zip code value used to create a .NET fact.</param>
            [FunctionName("RulesFunction")]
            public Task<RuleExecutionResult> RunRules([WorkflowActionTrigger] string ruleSetName, string documentType, string inputXml, int purchaseAmount, string zipCode)
            {
                /***** Summary of steps below *****
                * 1. Get the ruleset to execute.
                * 2. Check if the ruleset was successfully retrieved.
                * 3. Create the rules engine object.
                * 4. Create TypedXmlDocument facts for all XML document facts.
                * 5. Initialize .NET facts.
                * 6. Execute rules engine.
                * 7. Retrieve relevant updates facts and send them back.
                */
    
                try
                {
                    // Get the ruleset based on the ruleset name.
                     var ruleExplorer = new FileStoreRuleExplorer();
                     var ruleSet = ruleExplorer.GetRuleSet(ruleSetName);
    
                    // Check if ruleset exists.
                    if(ruleSet == null)
                    {
                        // Log an error if ruleset not found.
                        this.logger.LogCritical($"RuleSet instance for '{ruleSetName}' was not found(null)");
                        throw new Exception($"RuleSet instance for '{ruleSetName}' was not found.");
                    }
    
                    // Create rules engine instance.
                    var ruleEngine = new RuleEngine(ruleSet: ruleSet);
    
                    // Create one or more typedXmlDcoument facts from one or more input XML documents.
                    XmlDocument doc = new XmlDocument();
                    doc.LoadXml(inputXml);
                    var typedXmlDocument = new TypedXmlDocument(documentType, doc);
    
                    // Initialize .NET facts.
                    var currentPurchase = new ContosoNamespace.ContosoPurchase(purchaseAmount, zipCode);
    
                    // Provide facts and run the rules engine.
                    ruleEngine.Execute(new object[] { typedXmlDocument, currentPurchase });
    
                    // Send back the relevant results (facts).
                    var updatedDoc = typedXmlDocument.Document as XmlDocument;
                    var ruleExectionOutput = new RuleExecutionResult()
                    {
                        XmlDoc = updatedDoc.OuterXml,
                        PurchaseAmountPostTax = currentPurchase.PurchaseAmount + currentPurchase.GetSalesTax()
                    };
    
                    return Task.FromResult(ruleExectionOutput);
                }
                catch(RuleEngineException ruleEngineException)
                {
                    // Log any rules engine exceptions.
                    this.logger.LogCritical(ruleEngineException.ToString());
                    throw;
                }
            }
    
            /// <summary>
            /// Results from rules execution
            /// </summary>
            public class RuleExecutionResult
            {
                /// <summary>
                /// Rules updated XML document
                /// </summary>
                public string XmlDoc { get; set;}
    
                /// <summary>
                /// Purchase amount after tax
                /// </summary>
                public int PurchaseAmountPostTax { get; set;}
            }
        }
    }
    

    RulesFunction 的函数定义包含一个默认的 RunRules 方法,可以使用该方法开始操作。 此示例 RunRules 方法演示如何将参数传递给 Azure 逻辑应用规则引擎。 在此示例中,该方法传递规则集名称、输入文档类型、XML 事实和其他值以供进一步处理。

    <function-name>.cs 文件还包括 ILogger 接口,该接口支持将事件记录到 Application Insights 资源。 可以将跟踪信息发送到 Application Insights,并将该信息与工作流中的跟踪信息一起存储,例如:

    private readonly ILogger<RulesFunction> logger;
    
        public RulesFunction(ILoggerFactory loggerFactory)
        {
            logger = loggerFactory.CreateLogger<RulesFunction>();
        }
        <...>
    
    

    Azure 逻辑应用规则引擎的运行方式如下所述:

    1. 引擎使用 FileStoreRuleExplorer 对象来访问规则集。 规则集文件存储在标准逻辑应用的 Rules 目录中

      在本示例中,规则集文件名为 SampleRuleSet.xml,它是使用 Microsoft 规则编辑器创建的,或使用 Microsoft BizTalk Server 导出的

      var ruleExplorer = new FileStoreRuleExplorer();
      var ruleSet = ruleExplorer.GetRuleSet(ruleSetName);
      
      // Check if the ruleset exists.
      if(ruleSet == null)
      {
          // Log an error if the ruleset isn't found.
          this.logger.LogCritical($"RuleSet instance for '{ruleSetName}' was not found(null)");
          throw new Exception($"RuleSet instance for '{ruleSetName}' was not found.");
      }
      

      重要

      规则集保存对其事实的引用。 Microsoft 规则编辑器查找事实程序集来验证规则集以供编辑。 若要在 Microsoft 规则编辑器中打开诸如 SampleRuleSet.xml 之类的规则集,必须将其与相应的 .NET 事实程序集放在一起。 否则会发生异常。

    2. 引擎使用 ruleSet 对象来创建 RuleEngine 对象的实例。

    3. RuleEngine 对象使用 Execute 方法接收规则的事实。

      在此示例中,Execute 方法接收两个事实:一个名为 typedXmlDocument 的 XML 事实和一个名为 currentPurchase 的 .NET 事实。

      引擎运行后,事实的值将由引擎执行生成的值覆盖:

      // Create rules engine instance.
      var ruleEngine = new RuleEngine(ruleSet: ruleSet);
      
      // Create one or more typedXml facts from one or more input XML documents.
      XmlDocument doc = new XmlDocument();
      doc.LoadXml(inputXml);
      var typedXmlDocument = new TypedXmlDocument(documentType, doc);
      
      // Initialize .NET facts.
      var currentPurchase = new ContosoNamespace.ContosoPurchase(purchaseAmount, zipCode);
      
      // Provide facts and run the rules engine.
      ruleEngine.Execute(new object[] { typedXmlDocument, currentPurchase });
      
      // Send back the relevant results (facts).
      var updatedDoc = typedXmlDocument.Document as XmlDocument;
      
    4. 引擎使用 RuleExecutionResult 自定义类将值返回给 RunRules 方法:

      var ruleExectionOutput = new RuleExecutionResult()
      {
          XmlDoc = updatedDoc.OuterXml,
          PurchaseAmountPostTax = currentPurchase.PurchaseAmount + currentPurchase.GetSalesTax()
      };
      
      return Task.FromResult(ruleExectionOutput);
      
    5. 将示例函数代码替换为你自己的代码,并为你自己的方案编辑默认 RunRules 方法。

      此示例继续使用示例代码,不进行任何更改。

编译和生成代码

编写完代码后,进行编译以确保不存在生成错误。 函数项目会自动包含生成任务,这些任务会编译任何自定义代码库(包括 .NET 事实程序集),然后将其添加到逻辑应用项目中的 lib\custom 文件夹中,工作流会在该文件夹中查找要运行的自定义函数。 这些任务将程序集置于 lib\custom\net472 文件夹中。

  1. 在 Visual Studio Code 的“终端”菜单中,选择“新建终端”。

  2. 在显示的工作目录列表中,选择“Functions”作为新终端的当前工作目录。

    屏幕截图显示了 Visual Studio Code、当前工作目录的提示以及选定的 Functions 目录。

    Visual Studio Code 会打开终端窗口,其中包含一个命令提示符。

  3. 在“终端”窗口中的命令提示符下,输入 dotnet restore .\RulesFunction.csproj

    屏幕截图显示了 Visual Studio Code、终端窗口和已完成的 dotnet restore 命令。

  4. 命令提示符再次出现后,输入 dotnet build .\RulesFunction.csproj

    如果你的生成成功,则终端窗口将报告生成成功

  5. 确认你的逻辑应用项目中存在以下项:

    • 在工作区中,展开以下文件夹:LogicApp>lib\custom>net472。 确认名为 net472 的子文件夹包含运行代码所需的多个程序集文件,包括名为 <function-name>.dll 的文件

    • 在工作区中,展开以下文件夹:LogicApp>lib\custom><函数名称>。 确认名为 <function-name> 的子文件夹包含 function.json 文件,该文件包含有关你编写的函数代码的元数据。 工作流设计器使用此文件来确定调用你的代码时所需的输入和输出。

    以下示例显示了逻辑应用项目中示例生成的程序集和其他文件:

    屏幕截图显示了逻辑应用工作区,包括函数项目和逻辑应用项目,现在生成了程序集和其他所需文件。

从工作流调用规则

确认你的代码已编译且逻辑应用规则引擎项目包含代码运行所需的文件后,打开逻辑应用项目中包含的默认工作流。

  1. 在工作区的“LogicApp”下,展开 <workflow-name> 节点,打开 workflow.json 的快捷菜单,然后选择“打开设计器”。

    在打开的工作流设计器上,你的逻辑应用项目包含的默认工作流会随以下触发器和操作一起显示:

  2. 选择名为“在此逻辑应用中调用本地规则函数”的操作

    该操作的信息窗格会在右侧打开。

    屏幕截图显示了 Visual Studio Code、工作流设计器和默认的工作流,其中包括触发器和操作。

  3. 查看并确认 Function Name 参数值已设为要运行的规则函数。 查看或更改函数使用的任何其他参数值。

调试代码和工作流

  1. 重复以下步骤以启动 Azurite 存储模拟器次:为以下每个 Azure 存储服务启动一次:

    • Azure Blob 服务
    • Azure 队列服务
    • Azure 表服务
    1. 在 Visual Studio Code 的“视图”菜单中选择“命令面板”。

    2. 在出现的提示中,找到并选择“Azurite:启动 Blob 服务”。

    3. 在显示的工作目录列表中,选择 LogicApp

    4. Azurite:启动队列服务Azurite:启动表服务重复这些步骤。

    当屏幕底部的 Visual Studio Code 任务栏显示三个存储服务正在运行时,你就成功了,例如:

    屏幕截图显示了 Visual Studio Code 任务栏和正在运行的 Azure Blob 服务、Azure 队列服务和 Azure 表服务。

  2. 在 Visual Studio Code 活动栏上,选择“运行并调试”。 (键盘:Ctrl+Shift+D)

    屏幕截图显示了 Visual Studio Code 活动栏和所选的“运行并调试”。

  3. 从“运行并调试”列表中,选择“附加到逻辑应用 (LogicApp)”(如果尚未选择),然后选择“运行”(绿色箭头)。

    屏幕截图显示了“运行并调试”列表,选择了“附加到逻辑应用”和“运行”按钮。

    终端”窗口随即打开,并显示已开始的调试过程。 然后,将显示“调试控制台”窗口,并显示调试状态。 在 Visual Studio Code 底部,任务栏变为橙色,表示 .NET 调试程序已加载。

  4. 在“运行并调试”列表中,选择“附加到 .NET Functions (Functions)”,然后选择“运行”(绿色箭头)。

    屏幕截图显示了“运行并调试”列表,选择了“附加到 NET Functions”和“运行”按钮。

  5. 若要设置任何断点,在你的函数定义 (<function-name>.cs) 或工作流定义 (workflow.json) 中,找到需要断点的行号,然后选择左侧的列,例如

    屏幕截图显示了 Visual Studio Code 和打开的函数代码文件,其中为代码中的某一行设置了断点。

  6. 若要在工作流中手动运行请求触发器,请打开工作流的“概述”页。

    1. 在逻辑应用项目中,打开 workflow.json 文件的快捷菜单,然后选择“概述”。

      在工作流的“概述”页上,当你想要手动启动工作流时,可以使用“运行触发器”按钮。 在“工作流属性”下,“回调 URL”值是你的工作流中请求触发器创建的可调用终结点的 URL。 可以向此 URL 发送请求,以从其他应用(包括其他逻辑应用工作流)触发工作流。

      屏幕截图显示了打开的 Visual Studio Code 和工作流的概述页面。

  7. 在“概述”页工具栏中,选择“运行触发器”。

    工作流开始运行后,调试器会激活你的第一个断点。

  8. 在“运行”菜单或调试程序工具栏中,选择“调试操作”。

    工作流运行完成后,“概述”页会显示已完成的运行以及有关该运行的基本详情。

  9. 要查看有关工作流运行的详细信息,请选择已完成的运行。 或者,在“持续时间”列旁边的列表中,选择“显示运行”。

    屏幕截图显示了打开的 Visual Studio Code 和已完成的工作流运行。