.NET Framework Developer Center >
.NET Development Forums
>
Windows Workflow Foundation
>
DoWhile Headaches...
DoWhile Headaches...
- Hello,
my custom DoWhileActivity keeps give me headeches because when it seems it works fine after a while you get a new bug... This time I'm experiencing this behavior:
In the DoWhile I have a SequenceActivity and within this a custom activity that asks the user a signature value that's involved in the Rule condition of the while. The result is that the while keeps repeating ignoring the value set by the user. As I can understand this could be caused by ActivityExecutionContext. The DoWhileActivity is inspired by the one found on Codeplex (http://www.codeplex.com/wfdowhileactivity). What this activity does is simply to skip the first condition evaluation (the TryNextIteration call in the Execute method), and by executing the other contition appearances (the TryNextIteration in the OnEvent method). What it seems to be the problem is that the evaluation is done in the new ActivityExecutionContext, but the value set by the user is in the activity in the precedent ActivityExecutionContext. Here are the three methods in the DoWhileActivity:
protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
{
if (executionContext == null)
{
throw new ArgumentNullException("executionContext");
}
if (this.TryNextIteration(executionContext, false))
{
return ActivityExecutionStatus.Executing;
}
return ActivityExecutionStatus.Closed;
}
public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
{
if (e == null)
{
throw new ArgumentNullException("e");
}
if (sender == null)
{
throw new ArgumentNullException("sender");
}
ActivityExecutionContext context = sender as ActivityExecutionContext;
if (context == null)
{
throw new ArgumentException("Sender is not ActivityExecutionContext");
}
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
ActivityExecutionContextManager executionContextManager = context.ExecutionContextManager;
executionContextManager.CompleteExecutionContext(executionContextManager.GetExecutionContext(e.Activity));
if (!this.TryNextIteration(context, true))
{
context.CloseActivity();
}
}
private bool TryNextIteration(ActivityExecutionContext context, bool evaluateCondition)
{
if (base.ExecutionStatus == ActivityExecutionStatus.Canceling ||
base.ExecutionStatus == ActivityExecutionStatus.Faulting)
{
return false;
}
if (evaluateCondition && !this.Condition.Evaluate(this, context))
{
return false;
}
if (base.EnabledActivities.Count > 0)
{
ActivityExecutionContext newContext = context.ExecutionContextManager.CreateExecutionContext(base.EnabledActivities[0]);
newContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
newContext.ExecuteActivity(newContext.Activity);
}
return true;
}
It could be because the TryNextIteration in the OnEvent is called after the executionContextManager.CompleteExecutionContext? If I move the executionContextManager.CompleteExecutionContext after the TryNextIteration what happens?
How can I evaluate the activity in the doWhile? Should I store the respose of the activity in a common area or in the DoWhile?
Thanks
Alessandro
Answers
- It's me again... by digging in the code I've come to a solution: I'm not sure is "politically correct" but it works. I had the confirmation that the problem is the ActivityExecutionContext, and more precisely that the condition evaluation in the TryNextIteration es executed after the executionContextManager.CompleteExecutionContext closes the Context. So my first try was to move the TryNextIteration execution before executionContextManager.CompleteExecutionContex:
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
ActivityExecutionContextManager executionContextManager = context.ExecutionContextManager;
if (!this.TryNextIteration(context, true))
{
context.CloseActivity();
}
executionContextManager.CompleteExecutionContext(executionContextManager.GetExecutionContext(e.Activity));
In fact the evaluation was carried out correctly, but when out of the dowhile the workflow freezes. So I've tried to set a private boolean member into the doWhile activity and it evaluates the condition before context is closed; on TryNextIteration it evaluates the boolean memeber instead of the condition:
public partial class DoWhileActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>, ICustomTypeDescriptor
{
. . .
private Boolean _condvalue = true;
. . .
public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
{
. . .
// evaluates the condition and keeps the value
_condvalue = this.Condition.Evaluate(this, context);
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
ActivityExecutionContextManager executionContextManager = context.ExecutionContextManager;
executionContextManager.CompleteExecutionContext(executionContextManager.GetExecutionContext(e.Activity));
if (!this.TryNextIteration(context, true))
{
context.CloseActivity();
}
}
private bool TryNextIteration(ActivityExecutionContext context, bool evaluateCondition)
{
if (base.ExecutionStatus == ActivityExecutionStatus.Canceling ||
base.ExecutionStatus == ActivityExecutionStatus.Faulting)
{
return false;
}
if (!_condvalue)
{
return false;
}
if (base.EnabledActivities.Count > 0)
{
ActivityExecutionContext newContext = context.ExecutionContextManager.CreateExecutionContext(base.EnabledActivities[0]);
newContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
newContext.ExecuteActivity(newContext.Activity);
}
return true;
}
Whith some simple tests I've found that this way it works... I'm not sure if it's "Archiecturally correct" and if this can have side effects in some circumstances... Any comment is welcome! Thanks
Alessandro
- Marked As Answer byAlessandro Fiorencis Friday, November 06, 2009 11:29 AM
- I'm guessing the real issue here is how the condition is set up. Does the condition point to some value that is held inside the body of the DoWhile? Instead, the condition should point to something that makes sense in its context (not the body's context) and the body should update that value. To put this in terms of C# code, it's a bit backwards to write:
do
{
bool keepGoing = ShouldKeepGoing();
} while (keepGoing);
Because keepGoing doesn't exist in the context of the DoWhile, only in the context of the body. You probably want something more like:
bool keepGoing;
do
{
keepGoing = ShouldKeepGoing();
} while (keepGoing);- Marked As Answer byAlessandro Fiorencis Friday, November 06, 2009 11:29 AM
All Replies
- It's me again... by digging in the code I've come to a solution: I'm not sure is "politically correct" but it works. I had the confirmation that the problem is the ActivityExecutionContext, and more precisely that the condition evaluation in the TryNextIteration es executed after the executionContextManager.CompleteExecutionContext closes the Context. So my first try was to move the TryNextIteration execution before executionContextManager.CompleteExecutionContex:
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
ActivityExecutionContextManager executionContextManager = context.ExecutionContextManager;
if (!this.TryNextIteration(context, true))
{
context.CloseActivity();
}
executionContextManager.CompleteExecutionContext(executionContextManager.GetExecutionContext(e.Activity));
In fact the evaluation was carried out correctly, but when out of the dowhile the workflow freezes. So I've tried to set a private boolean member into the doWhile activity and it evaluates the condition before context is closed; on TryNextIteration it evaluates the boolean memeber instead of the condition:
public partial class DoWhileActivity : CompositeActivity, IActivityEventListener<ActivityExecutionStatusChangedEventArgs>, ICustomTypeDescriptor
{
. . .
private Boolean _condvalue = true;
. . .
public void OnEvent(object sender, ActivityExecutionStatusChangedEventArgs e)
{
. . .
// evaluates the condition and keeps the value
_condvalue = this.Condition.Evaluate(this, context);
e.Activity.UnregisterForStatusChange(Activity.ClosedEvent, this);
ActivityExecutionContextManager executionContextManager = context.ExecutionContextManager;
executionContextManager.CompleteExecutionContext(executionContextManager.GetExecutionContext(e.Activity));
if (!this.TryNextIteration(context, true))
{
context.CloseActivity();
}
}
private bool TryNextIteration(ActivityExecutionContext context, bool evaluateCondition)
{
if (base.ExecutionStatus == ActivityExecutionStatus.Canceling ||
base.ExecutionStatus == ActivityExecutionStatus.Faulting)
{
return false;
}
if (!_condvalue)
{
return false;
}
if (base.EnabledActivities.Count > 0)
{
ActivityExecutionContext newContext = context.ExecutionContextManager.CreateExecutionContext(base.EnabledActivities[0]);
newContext.Activity.RegisterForStatusChange(Activity.ClosedEvent, this);
newContext.ExecuteActivity(newContext.Activity);
}
return true;
}
Whith some simple tests I've found that this way it works... I'm not sure if it's "Archiecturally correct" and if this can have side effects in some circumstances... Any comment is welcome! Thanks
Alessandro
- Marked As Answer byAlessandro Fiorencis Friday, November 06, 2009 11:29 AM
- I'm guessing the real issue here is how the condition is set up. Does the condition point to some value that is held inside the body of the DoWhile? Instead, the condition should point to something that makes sense in its context (not the body's context) and the body should update that value. To put this in terms of C# code, it's a bit backwards to write:
do
{
bool keepGoing = ShouldKeepGoing();
} while (keepGoing);
Because keepGoing doesn't exist in the context of the DoWhile, only in the context of the body. You probably want something more like:
bool keepGoing;
do
{
keepGoing = ShouldKeepGoing();
} while (keepGoing);- Marked As Answer byAlessandro Fiorencis Friday, November 06, 2009 11:29 AM
- Hi, Alessandro
About AEC, I would recommend you read these two articles:
1. ActivityExecutionContext in Workflows
http://msdn.microsoft.com/en-us/magazine/cc163414.aspx
2. Activity Execution Context from Essential Windows Workflow Foundation:
http://codeidol.com/other/essential-windows-workflow-foundation/Advanced-Activity-Execution/Activity-Execution-Context/
Regards
This posting is provided "AS IS" with no warranties, and confers no rights. Microsoft Online Community Support - Thanks, you got the point! You just confirmed what I've done to solve this issue... By setting the value of the evaluation in the context of DoWhile everything works fine...
Regards
Alessandro


