MethodCallActivity
分类: 通用步骤
命名空间: CMS.Plugin.FlowManagement.Domain.FlowBusiness.Activitys
基类: ActionActivity
模块: FlowManagement.Domain
概述
MethodCallActivity(CSharp调用)用于在流程中调用自定义的 C# 方法。通过实现 IMethodExecuter 接口,开发者可以编写自定义的业务逻辑,并在流程中通过此节点调用。这是一种强大的扩展机制,允许在流程中执行复杂的业务逻辑,而无需修改流程引擎本身。
业务场景
适用场景
- 复杂业务逻辑: 需要执行复杂的计算或业务规则
- 系统集成: 调用内部系统的服务或组件
- 数据处理: 对流程数据进行复杂的转换或处理
- 自定义功能: 实现流程节点无法直接支持的功能
- 代码复用: 将通用的业务逻辑封装为可复用的执行器
配置说明
基本配置
| 属性名 | 类型 | 必填 | 默认值 | 说明 |
|---|---|---|---|---|
| ExecuterName | string | 是 | - | 执行对象的完整类名(包含命名空间) |
| Action | ActionType | 否 | Execute | 执行时机 |
| IsSynchronous | bool | 否 | true | 是否同步执行 |
ExecuterName
说明: IMethodExecuter 实现类的完整类名(包含命名空间),如 "MyApp.Executers.MyCustomExecuter"。
注意事项:
- 必须是已注册到依赖注入容器的 IMethodExecuter 实现
- 使用完整的类名(命名空间.类名)
- 执行器必须在应用启动时注册
流程上下文
输入参数
通过 ProcessflowEventArgs 访问所有流程上下文数据。
输出参数
执行器返回的字典中的所有键值对都会写入流程上下文。
业务逻辑说明
处理流程
- 从依赖注入容器获取所有 IMethodExecuter 实现
- 查找类名匹配 ExecuterName 的执行器
- 调用执行器的 Execute 方法
- 将返回的数据项写入流程上下文
- 记录日志
依赖服务
| 服务接口 | 用途 |
|---|---|
| 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);
}
开发步骤
- 创建执行器类,实现 IMethodExecuter 接口
- 实现 Execute 方法,编写业务逻辑
- 注册到 DI 容器
- 在流程中配置 ExecuterName
最佳实践
- 使用依赖注入获取所需服务
- 返回的字典键名使用 "_Value" 后缀
- 记录详细的日志
- 处理异常并返回错误信息
- 保持执行器职责单一
注意事项
- ⚠️ 类名必须完整: 包含命名空间的完整类名
- ⚠️ 必须注册: 执行器必须注册到 DI 容器
- ⚠️ 异常处理: 执行器内部应处理异常
- ⚠️ 返回值: 返回的字典会直接写入流程上下文
- 💡 建议:
- 为执行器编写单元测试
- 使用有意义的 ExecuterName 和 Description
- 避免在执行器中执行耗时操作
相关节点
- ActionActivity: 基类
- ApiCallActivity: API 调用
- ScriptCallActivity: 脚本调用
常见问题
Q1: 如何传递参数给执行器?
A: 通过 ProcessflowEventArgs.DataItems 访问流程上下文中的所有数据。
Q2: 执行器如何返回数据?
A: 返回 Dictionary<string, object>,所有键值对会写入流程上下文。