分析SequenceActivity和ConditionedActivityGroup来自定义一个可以回滚的Activity

  1. 理解AECActivityExecutionContext

Workflow runtime执行一个Activity时,他会为这个Activity新建一个ActivityExecutionContext,它包含了执行Activity信息。更重要的一点是AEC是根据Activity临时变化的并且这个Activity是深copy,所以就很难得到执行这个Activity之前得AECActivity实例。当一个Activity执行多次的时候,他必须被copy多次,同时AEC也创建一个新的,代码:

ActivityExecutionContextchildContext=currentContext.ExecutionContextManager.CreateExecutionContext(childActivity);

它将会根据父AEC去为ChildActivity创建一个新的AEC,以维护自己。假设我们有一个自定义的ActivityWorkflowRoot,我们去copy它的子Activity,会有以下结果:

RootContext

|WorkflowRoot (1)

|childActivity (1)

|grandChildActivity (1)

- childContext

childActivity (2)

grandChildActivity (2)

2个问题

childActivity(1) or childActivity(2) 相互有影响么?

一旦Clone了这个实例,这2个实例就 没有联系了。

childActivity(2) 的父 Activity 是谁?

WorkflowRoot (1),所以新cloneActivity的父activity任然执行原Activity

分析 SequenceActivity and ConditionedActivityGroup

SequenceActivity将一个一个执行它的子activity,执行完最后一个Activity后这个SequenceActivity将会关闭。

protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (executionContext == null)
{
throw new ArgumentNullException("executionContext");
}
if (base.EnabledActivities.Count == 0)
{
this.OnSequenceComplete(executionContext);
return ActivityExecutionStatus.Closed;
}
base.EnabledActivities[0].RegisterForStatusChange(Activity.ClosedEvent, this); //

executionContext.ExecuteActivity(base.EnabledActivities[0]); //
base.SetValue(ActiveChildQualifiedNameProperty, base.EnabledActivities[0].QualifiedName);
return ActivityExecutionStatus.Executing;
}
①注册了一个事件,当第一个Activity执行完毕后,将会触发OnEvent方法。②告诉我们要手工执行这个Activity

void IActivityEventListener<ActivityExecutionStatusChangedEventArgs>.OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
{
if (sender == null)
{
throw new ArgumentNullException("sender");
}
if (e == null)
{
throw new ArgumentNullException("e");
}
ActivityExecutionContext executionContext = sender as ActivityExecutionContext;
if (executionContext == null)
{
throw new ArgumentException(SR.Error_SenderMustBeActivityExecutionContext, "sender");
}
e.
Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
SequenceActivity activity = executionContext.Activity as SequenceActivity;
if (activity == null)
{
throw new ArgumentException("sender");
}
if ((activity.ExecutionStatus == ActivityExecutionStatus.Canceling) || ((activity.ExecutionStatus == ActivityExecutionStatus.Faulting) && ((bool) base.GetValue(SequenceFaultingProperty))))
{
if (activity.ExecutionStatus == ActivityExecutionStatus.Faulting)
{
base.RemoveProperty(SequenceFaultingProperty);
}
base.RemoveProperty(ActiveChildQualifiedNameProperty);
executionContext.
CloseActivity();
}
else if ((activity.ExecutionStatus == ActivityExecutionStatus.Executing) && !this.TryScheduleNextChild(executionContext))
{
this.OnSequenceComplete(executionContext);
executionContext.
CloseActivity();
}
}
this.TryScheduleNextChild(executionContext)将执行下一个Activity

然而ConditionedActivityGroup就较为复杂。它的子节点可能被执行多次,所以当子节点的状态为pending/executing/idle时,它将维护一个状态集合,当他要执行或重新执行这个Activity时,执行以下方法:

private void ExecuteChild(ConditionedActivityGroup cag, Activity childActivity, ActivityExecutionContext context)
{
ActivityExecutionContext context2 = GetChildExecutionContext(context, childActivity, true);
cag.
CAGState.ChildrenStats[childActivity.QualifiedName].State = CAGChildState.Excuting;
context2.
Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
context2.
ExecuteActivity(context2.Activity);
}
我们可以通过分析系统中的Activity去学习自己定义Activity

自定义一个 Rollback Activity

自定义了一个NavigatorActivity,他的功能就是可以rollbackforward到一个Activity,当我从一个Activity到另一个activity

创建了一个NavigateRequest类,用以存储源 activity 和目标 activity 然后把他用外部服务传入 workflowRuntime 的WorkflowQueueingService里, 然后在 Excute() 检查NavigateRequest是否存在,如果存在,将会停掉现在执行的 Activity ,将调度到目标 Activity 里。可以通过ConditionedActivityGroup去了解 Activity 执行的过程

整个的架构

定义NavigateRequest类:

/// <summary> /// The parameter of a Rollback/Jump operation, which stores the source and target information. /// </summary> [Serializable] public class NavigateRequest { private string source; private string target; private string responser; private string remark; private NavigateDirection? direction; public string SourceActivity { get { return this.source; } set { this.source = value; } } public string TargetActivity { get { return this.target; } set { this.target = value; } } public string ResponsibleActivity { get { return this.responser; } set { this.responser = value; } } public NavigateDirection? Direction { get { return this.direction; } set { this.direction = value; } } public string Remark { get { return this.remark; } set { this.remark = value; } } public NavigateRequest(string source, string target, string remark) { if (String.IsNullOrEmpty(source)) { throw new ArgumentNullException("source"); } if (String.IsNullOrEmpty(target)) { throw new ArgumentNullException("target"); } if (source == target) { throw new ArgumentException("Cannot navigate to itself."); } this.source = source; this.target = target; this.remark = remark; } public NavigateRequest(string source, string target) : this(source, target, "") { } public NavigateRequest(NavigateDirection direction, string source, string target) : this(source, target) { this.direction = direction; } public NavigateRequest(NavigateDirection direction, string source, string target, string responser) : this(direction, source, target) { this.responser = responser; } } /// <summary> /// The direction of navigate, rollback is backward navigation, while jump is forward. /// </summary> public enum NavigateDirection { Backward, Forward }

注册rollbackactivity

/// <summary> /// Register a rollback or jump request. /// </summary> /// <param name="provider"></param> /// <param name="nav"></param> protected static void RegisterNavigate(IServiceProvider provider, NavigateRequest nav) { WorkflowQueuingService qService = provider.GetService(typeof(WorkflowQueuingService)) as WorkflowQueuingService; qService.GetWorkflowQueue(Environment.WorkflowRollbackQueue).Enqueue(nav); }

根据检查是否要rollback,然后去schedule目标activity

/// <summary>Executes the activity.</summary> /// <returns>The <see cref="T:System.Workflow.ComponentModel.ActivityExecutionStatus"></see> of the activity after executing the activity.</returns> /// <param name="executionContext">The execution context of the activity.</param> protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext) { if (executionContext == null) { throw new ArgumentNullException("executionContext"); } if (base.EnabledActivities.Count == 0) { this.OnSequenceComplete(executionContext); return ActivityExecutionStatus.Closed; } //******************** NavigateRequest jump = NavigatorActivity.PeekNavigate(executionContext); Activity firstActivity; if (jump != null) { if (base.IsDirectChild(jump.TargetActivity)) { firstActivity = base.GetActivityByName(jump.TargetActivity); } else { firstActivity = base.GetDirectChildActivity(jump.TargetActivity); if (firstActivity is NavigatorActivity) { NavigateRequest nav = new NavigateRequest(NavigateDirection.Forward, jump.SourceActivity, jump.TargetActivity, firstActivity.QualifiedName); NavigatorActivity.RegisterNavigate(executionContext, nav); } } NavigatorActivity.ShiftNavigate(executionContext); } else { firstActivity = base.EnabledActivities[0]; } Activity executingActivity = NavigatorActivity.GetRuntimeInitializedActivity(executionContext, firstActivity); executingActivity.RegisterForStatusChange(Activity.ClosedEvent, this); ExecuteChild(executingActivity, executionContext); base.SetValue(AdvancedSequenceActivity.ActiveChildQualifiedNameProperty, executingActivity.QualifiedName); //******************** return ActivityExecutionStatus.Executing; } protected override void OnActivityEvent(object sender, ActivityExecutionStatusChangedEventArgs e) { if (sender == null) { throw new ArgumentNullException("sender"); } if (e == null) { throw new ArgumentNullException("e"); } ActivityExecutionContext context1 = sender as ActivityExecutionContext; if (context1 == null) { throw new ArgumentException("SenderMustBeActivityExecutionContext", "sender"); } e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this); //************************ ActivityExecutionContext subContext = AdvancedSequenceActivity.GetChildExecutionContext(context1, e.Activity, false); if (subContext != null) { context1.ExecutionContextManager.CompleteExecutionContext(subContext); } //*********************** AdvancedSequenceActivity activity1 = context1.Activity as AdvancedSequenceActivity; if (activity1 == null) { throw new ArgumentException("sender"); } if ((activity1.ExecutionStatus == ActivityExecutionStatus.Canceling) || ((activity1.ExecutionStatus == ActivityExecutionStatus.Faulting) && ((bool)base.GetValue(AdvancedSequenceActivity.SequenceFaultingProperty)))) { if (activity1.ExecutionStatus == ActivityExecutionStatus.Faulting) { base.RemoveProperty(AdvancedSequenceActivity.SequenceFaultingProperty); } base.RemoveProperty(AdvancedSequenceActivity.ActiveChildQualifiedNameProperty); //context1.CloseActivity(); this.Cleanup(context1); } else if ((activity1.ExecutionStatus == ActivityExecutionStatus.Executing) && !this.TryScheduleNextChild(context1)) { this.OnSequenceComplete(context1); //context1.CloseActivity(); this.Cleanup(context1); } } /// <summary> /// Called by OnActivityEvent method. /// Schedules the execution of another child activity. /// </summary> /// <param name="executionContext"></param> /// <returns></returns> private bool TryScheduleNextChild(ActivityExecutionContext executionContext) { if (executionContext == null) { throw new ArgumentNullException("executionContext"); } NavigatorActivity baseActivity = executionContext.Activity as NavigatorActivity; if (baseActivity == null) { throw new InvalidOperationException("the sender must be NavigatorActivity."); } IList<Activity> list1 = baseActivity.EnabledActivities; if (list1.Count == 0) { return false; } //************************** string currentActivityName = (string)base.GetValue(AdvancedSequenceActivity.ActiveChildQualifiedNameProperty); Activity nextActivity; NavigateRequest rollback = NavigatorActivity.PeekNavigate(executionContext); if (rollback != null) { //1. if a rollback has registered and it should be dealt by another activity, stop this immediately. if (!NavigatorActivity.IsResponsible(rollback, base.QualifiedName)) { return false; } //2. if a child activity has registered a rollback if (base.IsDirectChild(rollback.TargetActivity)) { //2.1. if the rollback target is inside this activity and is the direct child (not child's child), execute it directly. nextActivity = base.GetActivityByName(rollback.TargetActivity); } else { nextActivity = base.GetDirectChildActivity(rollback.TargetActivity); if (nextActivity != null) { //2.2. if the rollback target is inside this activity and is not direct child (may be a child's child), register a jump to it and execute its parent (its parent will make a jump execution to the target). if (nextActivity is NavigatorActivity) { NavigateRequest nav = new NavigateRequest(NavigateDirection.Forward, rollback.SourceActivity, rollback.TargetActivity, nextActivity.QualifiedName); NavigatorActivity.RegisterNavigate(executionContext, nav); } } else { //2.3 if the rollback target is out of this activity, register the parent a rollback and stop this activity. NavigatorActivity parent = base.Parent as NavigatorActivity; if (parent != null) { NavigateRequest nav = new NavigateRequest(NavigateDirection.Backward, this.QualifiedName, rollback.TargetActivity, parent.QualifiedName); NavigatorActivity.RegisterNavigate(executionContext, nav); } NavigatorActivity.ShiftNavigate(executionContext); return false; } } NavigatorActivity.ShiftNavigate(executionContext); } else { //3. no rollback found. an original execution will be performed. int i; for (i = 0; i < list1.Count; i++) { if (list1[i].QualifiedName == currentActivityName) { if (i == list1.Count - 1) { return false; } break; } } nextActivity = list1[++i]; } ExecuteChild(nextActivity, executionContext); //***************************** base.SetValue(AdvancedSequenceActivity.ActiveChildQualifiedNameProperty, nextActivity.QualifiedName); return true; }

参考文档:<http://blogs.msdn.com/b/advancedworkflow/archive/2006/03/21/557121.aspx>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值