WF4.0 活动详解<第一篇>:基础活动与核心概念

Windows Workflow Foundation (WF) 4.0 是微软推出的革命性工作流引擎,采用了全新的"活动为基础"的编程模型。与之前的 WF 3.5 不同,WF4.0 将工作流定义为活动的组合,每个活动都是一个可执行的代码单元,包含特定的业务逻辑或控制流功能。理解活动是掌握 WF4.0 的关键,本文将系统介绍 WF4.0 中的核心活动及其应用模式。

深入解析 Windows Workflow Foundation 4.0 的核心构件单元——活动(Activities),揭开工作流编程的神秘面纱

目录#

  1. WF4.0活动模型概述
  2. 控制流活动详解
  3. 基本操作活动
  4. 错误处理活动
  5. 变量与参数管理
  6. 最佳实践与常见模式
  7. 示例:订单处理工作流
  8. 总结
  9. 参考资料

一、WF4.0活动模型概述#

在WF4.0中,活动是工作流的基本执行单元,所有工作流都是由活动组合而成。关键特性包括:

  • 活动树结构:工作流本质上是树状结构的活动组合
  • 复合活动:可包含子活动的容器(如Sequence、Flowchart)
  • 执行上下文:每个活动运行在特定上下文中,共享变量和参数
  • 书签机制:支持暂停和恢复执行的能力
  • 异步支持:原生支持异步操作执行
graph TD
    A[Workflow] --> B[Sequence]
    B --> C[WriteLine]
    B --> D[Assign]
    B --> E[If]
    E --> F[WriteLine 条件成立]
    E --> G[WriteLine 条件不成立]
    B --> H[Parallel]

二、控制流活动详解#

1. Sequence#

最常用的复合活动,其子活动按顺序执行

new Sequence
{
    Activities =
    {
        new WriteLine { Text = "步骤1" },
        new WriteLine { Text = "步骤2" },
        new WriteLine { Text = "步骤3" }
    }
}

最佳实践:避免在Sequence中放入长时间运行的操作,可能阻塞整个序列

2. Flowchart#

流程图样式的工作流,支持非线性执行路径

var flowchart = new Flowchart();
var step1 = new WriteLine { Text = "开始" };
var step2 = new WriteLine { Text = "处理业务" };
var step3 = new WriteLine { Text = "结束" };
 
flowchart.StartNode = step1;
flowchart.Nodes.Add(step1);
flowchart.Nodes.Add(step2);
flowchart.Nodes.Add(step3);
 
// 建立连接
flowchart.Connections.Add(new FlowStep 
    { 
        From = step1, 
        To = step2,
        Condition = ExpressionServices.Convert<bool>(ctx => true)
    });

3. Parallel#

并行执行多个分支,适合独立任务并行处理

new Parallel
{
    Branches =
    {
        new Sequence { Activities = { new WriteLine("分支1任务1"), Delay(2) } },
        new Sequence { Activities = { new WriteLine("分支2任务1"), Delay(3) } }
    }
}

重要提示:Parallel不是真正的线程并行,而是基于协作式调度

4. If#

条件分支控制,根据布尔表达式选择执行路径

new If
{
    Condition = new InArgument<bool>(ctx => orderAmount > 1000),
    Then = new WriteLine { Text = "执行VIP流程" },
    Else = new WriteLine { Text = "执行普通流程" }
}

5. While/DoWhile#

循环控制结构,区别在于条件检查位置

int count = 0;
new While
{
    Condition = new InArgument<bool>(ctx => count < 5),
    Body = new Sequence
    {
        Activities = 
        {
            new Assign<int> 
            { 
                To = new OutArgument<int>(ctx => count), 
                Value = new InArgument<int>(ctx => count + 1) 
            },
            new WriteLine { Text = new InArgument<string>(ctx => $"当前计数: {count}") }
        }
    }
}

6. Pick#

基于事件触发的分支选择,用于异步场景

new Pick
{
    Branches =
    {
        new PickBranch // 电子邮件响应分支
        {
            Trigger = new Receive { ... },
            Action = new WriteLine("收到邮件回复")
        },
        new PickBranch // 超时分支
        {
            Trigger = new Delay { Duration = TimeSpan.FromHours(1) },
            Action = new WriteLine("超时未收到回复")
        }
    }
}

适用场景:需要等待多种可能事件的处理流程(如审批流程)


三、基本操作活动#

1. Assign#

赋值操作,修改变量值

new Assign<string>
{
    To = new OutArgument<string>(varCustomerName),
    Value = new InArgument<string>("John Smith")
}

2. WriteLine#

调试输出活动,开发时用于跟踪执行状态

new WriteLine 
{ 
    Text = new InArgument<string>(ctx => $"当前时间: {DateTime.Now}") 
}

3. Delay#

工作流暂停执行指定时间

new Delay
{
    Duration = TimeSpan.FromMinutes(30) // 暂停30分钟
}

重要:Delay使用工作流调度器的计时机制,非线程阻塞

4. InvokeMethod#

调用.NET类中的方法

new InvokeMethod
{
    TargetObject = new InArgument<OrderService>(ctx => orderService),
    MethodName = "ProcessOrder",
    Parameters =
    {
        new InArgument<Order>(ctx => currentOrder)
    }
}

最佳实践

  • 避免调用长时间阻塞的方法
  • 推荐使用异步方法版本InvokeMethodAsync

四、错误处理活动#

1. TryCatch#

结构化错误处理,类似C#的try-catch

new TryCatch
{
    Try = new Sequence
    {
        Activities = 
        {
            new InvokeMethod { ... } // 可能抛出异常的操作
        }
    },
    Catches =
    {
        new Catch<ArgumentException>
        {
            Action = new ActivityAction<ArgumentException>
            {
                Handler = new WriteLine 
                { 
                    Text = "参数错误!" 
                }
            }
        }
    }
}

2. Throw#

主动抛出异常

new Throw
{
    Exception = new InArgument<Exception>(
        ctx => new InvalidOperationException("状态异常"))
}

五、变量与参数管理#

变量作用域规则

  • 变量在活动作用域内定义
  • 子活动可访问父活动定义的变量
  • 使用Variable<T>声明工作流变量
var orderAmount = new Variable<decimal> { Name = "OrderAmount" };
 
new Sequence
{
    Variables = { orderAmount },
    Activities = 
    {
        new Assign<decimal>
        {
            To = orderAmount,
            Value = 199.99m
        },
        new WriteLine 
        { 
            Text = new InArgument<string>(ctx => $"订单金额: {orderAmount.Get(ctx)}") 
        }
    }
}

工作流参数

  • 使用InArgument/OutArgument/InOutArgument声明
  • 在工作流启动时传入初始值
  • 在工作流完成后获取输出值

六、最佳实践与常见模式#

最佳实践#

  1. 单一职责原则:每个活动应有明确单一的功能
  2. 避免巨型Sequence:拆分为更小的可重用活动
  3. 异步操作模式
    new Sequence
    {
        Activities = 
        {
            new InvokeMethodAsync { ... }, // 启动异步操作
            new Delay { Duration = TimeSpan.FromSeconds(5) },
            new WriteLine { Text = "后台处理中..." }
        }
    }
  4. 超时处理模式
    new Parallel
    {
        CompletionCondition = true, // 任意分支完成则终止
        Branches = 
        {
            new Sequence { ... }, // 主任务
            new Sequence { Activities = { new Delay(TimeSpan.FromMinutes(30)), 
                                         new Throw(new TimeoutException()) }
            }
        }
    }

常见反模式#

  • 阻塞线程的活动:调用Thread.Sleep()等阻塞方法
  • 过度复杂的单一活动:包含过多业务逻辑
  • 忽略取消处理:未实现CancellationScope

七、示例:订单处理工作流#

// 定义工作流变量
var order = new Variable<Order>("Order");
var isApproved = new Variable<bool>("IsApproved", false);
 
// 创建工作流
var workflow = new Sequence
{
    Variables = { order, isApproved },
    Activities =
    {
        // 接收订单
        new Receive { ... },
        
        // 验证订单
        new If
        {
            Condition = new InArgument<bool>(ctx => order.Get(ctx).IsValid),
            Then = new Sequence
            {
                Activities = 
                {
                    // 并行处理库存检查与信用检查
                    new Parallel
                    {
                        CompletionCondition = false, // 必须所有分支完成
                        Branches = 
                        {
                            new InvokeMethod { MethodName = "CheckInventory" },
                            new InvokeMethod { MethodName = "CheckCredit" }
                        }
                    },
                    
                    // 人工审批(等待审批)
                    new Pick { ... },
                    
                    // 处理订单
                    new If
                    {
                        Condition = new InArgument<bool>(isApproved),
                        Then = new Sequence
                        {
                            Activities = 
                            {
                                new InvokeMethod { MethodName = "ProcessPayment" },
                                new InvokeMethod { MethodName = "ShipOrder" }
                            }
                        },
                        Else = new WriteLine { Text = "订单审批拒绝" }
                    }
                }
            },
            Else = new WriteLine { Text = "无效订单!" }
        }
    }
};

八、总结#

WF4.0 的活动模型为构建灵活的企业级工作流提供了强大基础:

  1. 组合式架构:通过组合简单活动构建复杂业务流程
  2. 丰富的控制流:Sequence、Flowchart、Parallel等满足不同流程需求
  3. 声明式编程:通过XAML定义工作流,实现逻辑与表现分离
  4. 扩展性强:可通过自定义活动扩展功能

在下一篇中,我们将深入探讨自定义活动的开发技术,包括如何创建自定义简单活动和复合活动,以及活动设计器的实现技巧。


九、参考资料#

  1. 微软官方文档 - WF4 Activities Overview
  2. Programming Windows Workflow Foundation: Practical WF Techniques
  3. WF4.0 Activity Library Reference
  4. Essential Windows Workflow Foundation
  5. WF4 Samples CodePlex Archive

"工作流不是代码的替代品,而是协调代码执行的艺术" —— WF4.0设计理念