跳到主要内容
版本:Next

MethodCallActivity

分类: 通用步骤
命名空间: CMS.Plugin.FlowManagement.Domain.FlowBusiness.Activitys
基类: ActionActivity
模块: FlowManagement.Domain

概述

MethodCallActivity(CSharp调用)用于在流程中调用自定义的 C# 方法。通过实现 IMethodExecuter 接口,开发者可以编写自定义的业务逻辑,并在流程中通过此节点调用。这是一种强大的扩展机制,允许在流程中执行复杂的业务逻辑,而无需修改流程引擎本身。

业务场景

适用场景

  • 复杂业务逻辑: 需要执行复杂的计算或业务规则
  • 系统集成: 调用内部系统的服务或组件
  • 数据处理: 对流程数据进行复杂的转换或处理
  • 自定义功能: 实现流程节点无法直接支持的功能
  • 代码复用: 将通用的业务逻辑封装为可复用的执行器

配置说明

基本配置

属性名类型必填默认值说明
ExecuterNamestring-执行对象的完整类名(包含命名空间)
ActionActionTypeExecute执行时机
IsSynchronousbooltrue是否同步执行

ExecuterName

说明: IMethodExecuter 实现类的完整类名(包含命名空间),如 "MyApp.Executers.MyCustomExecuter"。

注意事项:

  • 必须是已注册到依赖注入容器的 IMethodExecuter 实现
  • 使用完整的类名(命名空间.类名)
  • 执行器必须在应用启动时注册

流程上下文

输入参数

通过 ProcessflowEventArgs 访问所有流程上下文数据。

输出参数

执行器返回的字典中的所有键值对都会写入流程上下文。

业务逻辑说明

处理流程

  1. 从依赖注入容器获取所有 IMethodExecuter 实现
  2. 查找类名匹配 ExecuterName 的执行器
  3. 调用执行器的 Execute 方法
  4. 将返回的数据项写入流程上下文
  5. 记录日志

依赖服务

服务接口用途
IMethodExecuter自定义方法执行器接口
Flow.ServiceProvider获取注册的执行器

使用示例

基本示例

{
"Type": "MethodCallActivity",
"Name": "计算折扣",
"Alias": "CalculateDiscount",
"ExecuterName": "MyApp.Executers.DiscountCalculator",
"Action": "Execute"
}

实现自定义执行器

using CMS.Plugin.FlowManagement.Abstractions;
using SYC.Flow.Kernel;

namespace MyApp.Executers
{
public class DiscountCalculator : IMethodExecuter
{
public string ExecuterName => "折扣计算器";

public string ExecuterDescription => "根据订单金额计算折扣";

public async Task<Dictionary<string, object>> Execute(ProcessflowEventArgs args)
{
var result = new Dictionary<string, object>();

// 从流程上下文读取数据
var orderAmount = Convert.ToDecimal(args.DataItems["OrderAmount_Value"]);
var customerLevel = args.DataItems["CustomerLevel_Value"]?.ToString();

// 执行业务逻辑
decimal discount = customerLevel switch
{
"VIP" => orderAmount * 0.2m,
"Gold" => orderAmount * 0.15m,
"Silver" => orderAmount * 0.1m,
_ => 0m
};

decimal finalAmount = orderAmount - discount;

// 返回结果
result["Discount_Value"] = discount;
result["FinalAmount_Value"] = finalAmount;

return await Task.FromResult(result);
}
}
}

注册执行器

// 在 Startup.cs 或 Program.cs 中注册
services.AddTransient<IMethodExecuter, DiscountCalculator>();
services.AddTransient<IMethodExecuter, TaxCalculator>();
services.AddTransient<IMethodExecuter, ShippingCalculator>();

复杂执行器示例

public class OrderProcessor : IMethodExecuter
{
private readonly IOrderService _orderService;
private readonly IInventoryService _inventoryService;
private readonly ILogger<OrderProcessor> _logger;

public OrderProcessor(
IOrderService orderService,
IInventoryService inventoryService,
ILogger<OrderProcessor> logger)
{
_orderService = orderService;
_inventoryService = inventoryService;
_logger = logger;
}

public string ExecuterName => "订单处理器";
public string ExecuterDescription => "处理订单创建和库存扣减";

public async Task<Dictionary<string, object>> Execute(ProcessflowEventArgs args)
{
var result = new Dictionary<string, object>();

try
{
// 获取订单信息
var orderId = args.DataItems["OrderId_Value"]?.ToString();
var productId = args.DataItems["ProductId_Value"]?.ToString();
var quantity = Convert.ToInt32(args.DataItems["Quantity_Value"]);

// 检查库存
var available = await _inventoryService.CheckAvailability(productId, quantity);
if (!available)
{
result["ProcessResult_Value"] = "Failed";
result["ErrorMessage_Value"] = "库存不足";
return result;
}

// 创建订单
var order = await _orderService.CreateOrder(orderId, productId, quantity);

// 扣减库存
await _inventoryService.DeductInventory(productId, quantity);

result["ProcessResult_Value"] = "Success";
result["OrderNumber_Value"] = order.OrderNumber;
result["OrderStatus_Value"] = order.Status;

_logger.LogInformation($"订单处理成功: {order.OrderNumber}");
}
catch (Exception ex)
{
_logger.LogError(ex, "订单处理失败");
result["ProcessResult_Value"] = "Failed";
result["ErrorMessage_Value"] = ex.Message;
}

return result;
}
}

扩展开发指南

IMethodExecuter 接口

public interface IMethodExecuter
{
string ExecuterName { get; }
string ExecuterDescription { get; }
Task<Dictionary<string, object>> Execute(ProcessflowEventArgs args);
}

开发步骤

  1. 创建执行器类,实现 IMethodExecuter 接口
  2. 实现 Execute 方法,编写业务逻辑
  3. 注册到 DI 容器
  4. 在流程中配置 ExecuterName

最佳实践

  • 使用依赖注入获取所需服务
  • 返回的字典键名使用 "_Value" 后缀
  • 记录详细的日志
  • 处理异常并返回错误信息
  • 保持执行器职责单一

注意事项

  • ⚠️ 类名必须完整: 包含命名空间的完整类名
  • ⚠️ 必须注册: 执行器必须注册到 DI 容器
  • ⚠️ 异常处理: 执行器内部应处理异常
  • ⚠️ 返回值: 返回的字典会直接写入流程上下文
  • 💡 建议:
    • 为执行器编写单元测试
    • 使用有意义的 ExecuterName 和 Description
    • 避免在执行器中执行耗时操作

相关节点

常见问题

Q1: 如何传递参数给执行器?

A: 通过 ProcessflowEventArgs.DataItems 访问流程上下文中的所有数据。

Q2: 执行器如何返回数据?

A: 返回 Dictionary<string, object>,所有键值对会写入流程上下文。

Q3: 执行器找不到怎么办?

A: 检查:1) 类名是否正确(包含命名空间)2) 是否已注册到 DI 容器。

Q4: 可以在执行器中调用其他服务吗?

A: 可以,通过构造函数注入所需的服务。

更新历史

日期版本说明
2025-11-281.0初始版本

本文档最后更新时间: 2025-11-28