如何用Newtonsoft.Json递归解析Logic App工作流的Action关系
解析Logic App Standard工作流JSON,提取Action的依赖与父层级
问题描述
我正在处理Logic App Standard工作流的JSON定义文件,其中actions字段对应工作流的执行步骤。每个Action可能包含子Action,因此存在父Action层级关系;Action的执行顺序由指向其他Action的runAfter属性决定。
我的需求是用C#(基于Newtonsoft.Json)处理任意工作流JSON,列出每个Action对应的runAfter依赖项以及它的父Action。但我对Newtonsoft.Json不熟悉,不知道如何检测子Action并完成递归解析。
示例工作流JSON如下:
{"definition": {"$schema": "https://schema.management.azure.com/providers/Microsoft.Logic/schemas/2016-06-01/workflowdefinition.json#","actions": {"For_each_result_set": {"actions": {"For_each_(row)_active_widget": {"actions": {"Insert_row_to_acme_job_status": {"inputs": {"parameters": {"setColumns": {"ClientTrackingID": "@{variables('clientTrackingId')}","WidgetId": "@{items('For_each_(row)_active_widget')?['widgetID']}"},"tableName": "[acme].[acme_job_status]"},"serviceProviderConfiguration": {"connectionName": "sql-4","operationId": "insertRow","serviceProviderId": "/serviceProviders/sql"}},"type": "ServiceProvider"},"Send_message_to_get-widget-responses_(topic)": {"inputs": {"body": {"Properties": {"clientTrackingId": "@{variables('clientTrackingId')}","widgetId": "@{items('For_each_(row)_active_widget')?['widgetID']}"},},"host": {"connection": {"referenceName": "servicebus-2"}},"method": "post","path": "/@{encodeURIComponent(encodeURIComponent('get-widget-responses'))}/messages","queries": {"systemProperties": "None"}},"runAfter": {"Insert_row_to_acme_job_status": ["SUCCEEDED"]},"type": "ApiConnection"}},"foreach": "@items('For_each_result_set')","type": "Foreach"}},"foreach": "@body('Get_Active_Widgets')?['resultSets']","runAfter": {"Get_Active_Widgets": ["SUCCEEDED"]},"type": "Foreach"},"Get_Active_Widgets": {"description": "","inputs": {"parameters": {"includeEmptyResultSets": true,"storedProcedureName": "procname"},"serviceProviderConfiguration": {"connectionName": "sql-4","operationId": "executeStoredProcedure","serviceProviderId": "/serviceProviders/sql"}},"runAfter": {"Initialise_Client_Tracking_Id": ["SUCCEEDED"]},"type": "ServiceProvider"},"Initialise_Client_Tracking_Id": {"description": "","inputs": {"variables": [{"name": "clientTrackingId","type": "string","value": "@{workflow().run.name}"}]},"runAfter": {},"type": "InitializeVariable"}},"contentVersion": "1.0.0.0","outputs": {},"triggers": {"Recurrence": {"description": "","recurrence": {"frequency": "Day","interval": 1,"schedule": {"hours": ["18"]},"timeZone": "GMT Standard Time"},"type": "Recurrence"}}},"kind": "Stateful"}
解决方案
1. 定义数据模型
创建用于映射JSON结构和存储解析结果的类:
// 存储每个Action的解析结果 public class ActionInfo { public string ActionName { get; set; } public string ParentActionName { get; set; } public Dictionary<string, List<string>> RunAfterDependencies { get; set; } = new(); } // 映射Action的核心JSON结构 public class LogicAction { [JsonProperty("actions")] public Dictionary<string, LogicAction> SubActions { get; set; } [JsonProperty("runAfter")] public Dictionary<string, List<string>> RunAfter { get; set; } } // 映射整个工作流的JSON结构 public class LogicWorkflow { [JsonProperty("definition")] public LogicWorkflowDefinition Definition { get; set; } } public class LogicWorkflowDefinition { [JsonProperty("actions")] public Dictionary<string, LogicAction> Actions { get; set; } }
2. 递归解析方法
编写递归方法遍历所有Action,记录父层级和runAfter依赖:
public static class WorkflowParser { public static List<ActionInfo> ParseWorkflowActions(string workflowJson) { var result = new List<ActionInfo>(); var workflow = JsonConvert.DeserializeObject<LogicWorkflow>(workflowJson); if (workflow?.Definition?.Actions == null) return result; // 从根级Actions开始递归解析 ParseActions(workflow.Definition.Actions, null, result); return result; } private static void ParseActions(Dictionary<string, LogicAction> actions, string parentName, List<ActionInfo> result) { foreach (var actionKvp in actions) { var actionName = actionKvp.Key; var action = actionKvp.Value; // 添加当前Action的信息 result.Add(new ActionInfo { ActionName = actionName, ParentActionName = parentName, RunAfterDependencies = action.RunAfter ?? new Dictionary<string, List<string>>() }); // 递归处理子Actions if (action.SubActions != null && action.SubActions.Any()) { ParseActions(action.SubActions, actionName, result); } } } }
3. 使用示例
调用解析方法并输出结果:
// 替换为实际的工作流JSON内容 string workflowJson = "你的工作流JSON字符串"; var actionInfos = WorkflowParser.ParseWorkflowActions(workflowJson); // 输出每个Action的详细信息 foreach (var info in actionInfos) { Console.WriteLine($"Action名称: {info.ActionName}"); Console.WriteLine($"父Action: {info.ParentActionName ?? "无"}"); Console.WriteLine("RunAfter依赖:"); foreach (var dep in info.RunAfterDependencies) { Console.WriteLine($" {dep.Key}: {string.Join(", ", dep.Value)}"); } Console.WriteLine("---"); }
关键说明
- 模型类仅保留了核心字段,若需要
type、inputs等其他属性,可直接在LogicAction类中添加对应的JsonProperty属性。 - 递归方法会自动识别子Action并传递父层级名称,确保每个Action的父关系被正确记录。
runAfter字段直接映射为字典结构,键是依赖的Action名称,值是触发条件集合(如SUCCEEDED)。
内容的提问来源于stack exchange,提问作者user195166
相关产品推荐
相关产品推荐

