An extension method to Find Sibling Activity

I’ve created an extension method  to Find Sibling Activity by name
Based on example from http://msdn.microsoft.com/en-us/magazine/cc163414.aspx
public static TActivity FindSiblingActivity<TActivity>(this Activity sender,string activityName) where TActivity:Activity
{
//CodeActivity thisActivityInstance = sender as   CodeActivity;sender.
Activity parent =   sender.Parent;
   var retActivity=parent.GetActivityByName(activityName) as TActivity;
   Debug.Assert(sender.IsDynamicActivity==retActivity.IsDynamicActivity,” EXPECTED BOTH BE DYNAMIC”);
   return retActivity;
}
Related links http://geekswithblogs.net/mnf/archive/2009/04/21/workflow-activities-should-be-referred-by-sender-object-or.aspx
http://codeidol.com/other/essential-windows-workflow-foundation/Advanced-Activity-Execution/Activity-Execution-Context/

Extension method to find root Parent Workflow of current activity

Below is an extension method  to find root Parent Workflow of current activity
  /// <summary>
  /// Get root Parent Workflow of current activity
  /// <param name=”activity”></param>
  /// <returns></returns>
  public static Activity FindRootWorkflow(this Activity activity)
  {
   List<string> list = new List<string>();
   Activity act = activity;
   while (act != null)
   {
    if (act.Parent==null)
    {
     return act;
    }
    act = act.Parent;
   }
   return null;
  }
 
It was  asked in MS Connect Suggestion “Activity to access Parent workflow or Root Workflow
 

 

Refer to Activity from workflow in the same project.

I have a project with a few workflows. I  created a custom activity and I’ve added it to the same project.
But then I found that I am not able to insert/drag it to my workflow.
The only solution, that I found, was to create a separate Activity Library, move my custom activity to the library, and add a reference to the library from Workflow Project. 
It looks like that you unable to Refer to Activity from workflow in the same project.

 

“The project type is not supported by this installation” for Workflow project

Download from ActivityExecutionContext in Workflows

caused  “The project type is not supported by this installation” when opened the solution.
On my machine I have Workflow only for VS 2008, but not for VS 2005, but the download solution was in 2005 format.
I’ve explicitely started VS 2008 and then converted solution from 2005 to 2008. Error disappeared. 
Similar problem with Moral: If you are trying to develop with .NET 3.0 maybe it’s a good idea to check that .NET 3.0 is installed first… described here.

Using of Workflow Dependency properties.

In our Workflow application it was created a lot of  Workflow level Dependency properties that was used  to interchange data between different activities.
    Workflow.PropertyA=  Activity1.PropertyA
    Activity2.PropertyA=Workflow.PropertyA
We believed that is a safe way to avoid concurrency problems. But it was WRONG.
 
Article ActivityExecutionContext in Workflows explains, that Workflow properties as a shared data between activities is not a safe method and can cause concurrency errors in case of CAG or similar usage.
Best solution is to use custom activities Dependency properties and direct binding between activities.
Activity2.PropertyA=  Activity1.PropertyA
 

The primary advantage to dependency properties is that they allow binding of property values to instance data at runtime. For example, you can bind the input property of one activity to an output property of another. The actual property values resulting from the binding is determined at runtime. Dependency properties are required when you want to bind properties from one activity to another. However, if you are binding an activity property to a workflow property, the workflow property is not required to be a dependency property. In this case, a normal C# property on the workflow class works fine.

Performance Characteristics of Windows Workflow Foundation tells to avoid using dependency properties if not necessary:
A dependency property is a powerful mechanism that helps you expose activity properties so they can be bound and shared within a workflow instance. There is a small performance overhead associated with this property type, especially when many dependency properties are being accessed from the workflow, but in most cases the overhead should be minimal.
 
Related links: DependencyProperty Class
           wdp snippet

Workflow Activities should be referred by sender object or e.Activity, not by activity property name

In Windows Workflow I had a Replicator Activity inside While Activity. In Replicator  _Initialized event handler I’ve set the InitialChildData property of the activity with the list of my objects, but Replicator  didn’t invoke  any _ChildInitialized event , but went directly to _Completed event (similar problem was reported in the thread ReplicatorActivity shows all children complete when they aren’t ). I tried to change a few things without success.It was also confusing that even in Initialized AllChildrenComplete property was true. I compared my code with exampe from excellent WF Tutorial: Using the Replicator for Windows Workflow Foundation, but didn’t find any essential differences.
 
Finally WF Serialization Part One and a half article pointed me to Spawned Contexts – Replicator, While, State, EventHandlers, and CAG , that exlpained that I’ve incorrectly updated data of a template activity instead of instance activity.
Important extracts from  the article:
 
 If you want to avoid issues, learn to access activity properties in a context safe way (using the sender object or  e.Activity) so that you do it right when it counts. 
// WRONG CODE
this.delayActivity1.TimeoutDuration = TimeSpan.FromSeconds(iterationCount);
// RIGHT CODE
((DelayActivity)sender).TimeoutDuration = TimeSpan.FromSeconds(iterationCount);

// RIGHT CODE
CallExternalMethodActiivty act = e.Activity.GetActivityByName(“createTask1”, true) as CallExternalMethodActivity;
act.ParameterBindings[“userName”].Value = e.InstanceData;

Use sender or e.Activity instead of this.  e.Activity is the clone of the replicator’s template.  Second, we have passed the parameter true to GetActivityByName.  This tells the method to look only in the context of the activity on which it was called.  This keeps the method from walking into other parts of the tree and returning the RootContext instance.

 The issue also described in “Pro WF” By Bruce Bukovics access activities in a context safe way   section and in ActivityExecutionContext in Workflows article.

Note, that IsDynamicActivity Property can be used to determine was activity spawned or is executing within the default ActivityExecutionContext of the workflow instance.

 I hope that Microsoft will change the syntax of event handlers to separate workflow templates and instances to avoid these not-intuitive errors or at least will generate warnings if code is not context-safe(see my MS connect suggestion).

Windows Workflow: Debugging Limitations.

In Visual Studio Debugger for Windows Workflow Foundation you MUST set the workflow DLL project as the Visual Studio solution startup project to debug the workflow using F5
Documented in http://msdn.microsoft.com/en-us/library/bb483186.aspx
It is not intuitive restriction.
I’ve posted to MS Feedback that it will be good to support workflow Debugging from any startup project.

Recently I’ve noticed, that if workflow DLL project is a startup project, it doesn’t support Edit&Continue in a code dlls. Another thing that MS should improve. It’s similar to ASP.Net Web Site limitation of Edit&Continue.

I also not able to open activity from call-stack- see my post Windows Workflow: Concatenate all parents QualifiedNames- instead of call stack

Windows Workflow: Use of ConditionedActivityGroup activity

One of our developers used ConditionedActivityGroup activity with a single branch.
ConditionedActivityGroup is a kind do of loop, but it should not be used instead of the WhileActivity.
 
There are a few reasons for this:
1.Use the simplest tool that satisfy your requirement
2.workflow designer doesn’t expand body of ConditionedActivityGroup, and you need to click it to Preview
3. If you have many activities in the workflow, the designer becomes terribly slow(VS 2008)
The huge workflows should be considered for refactoring by converting parts of workflow into custom composite activity or as separate worklow (with InvokeWorkflow activity)
 
I have a question,  should I use Code Conditions vs Rule Conditions?
The article Windows Workflow: Rules and Conditions describes these types of conditions.
Conditional Activities in Windows Workflow Foundation talks about Advantages of using Rule Conditions:

 

  • Rule conditions are included in the declarative model and can be dynamically updated at run-time
  • The .rules file provides code separation and enables external analysis /tools to be built on top of the .rules file.  
Also to set the conditions declaravely via Rules  simpler for new Activity.
 
However if you are using code-behind for the workflow, specify code conditions is more consistent and easy to maintain/investigate.
Editing declarative conditions in Workflow Designer is too slow.
Also VS “find references”  could NOT see the references from rule conditions, which make development harder.

Windows Workflow: Concatenate all parents QualifiedNames- instead of call stack

MSDN Debugging Workflows  tells that

The entries in the Call Stack window are a depth-first search of executing activities. You can double-click an entry to put focus on the selected activity.-It doesn’t work for me.

 The text on stack trace is not meaningful, when activities are described.

 > codeRaiseEvent_ExecuteCode(object sender = {codeRaiseEvent_CAGPNRIterate [System.Workflow.Activities.CodeActivity]}, System.EventArgs e = {System.EventArgs}) Line 671 C#
  System.Workflow.ComponentModel.dll!System.Workflow.ComponentModel.Activity.RaiseEvent(System.Workflow.ComponentModel.DependencyProperty dependencyEvent, object sender = {codeRaiseEvent_CAGPNRIterate [System.Workflow.Activities.CodeActivity]}, System.EventArgs e = {System.EventArgs}) + 0xb0 bytes 
  System.Workflow.Activities.dll!System.Workflow.Activities.CodeActivity.Execute(System.Workflow.ComponentModel.ActivityExecutionContext executionContext) + 0x35 bytes 
  System.Workflow.ComponentModel.dll!System.Workflow.ComponentModel.ActivityExecutor<System.__Canon>.Execute(System.__Canon activity, System.Workflow.ComponentModel.ActivityExecutionContext executionContext) + 0x2b bytes 
  System.Workflow.ComponentModel.dll!System.Workflow.ComponentModel.ActivityExecutor<System.__Canon>.Execute(System.Workflow.ComponentModel.Activity activity, System.Workflow.ComponentModel.ActivityExecutionContext executionContext) + 0x32 bytes 
  System.Workflow.ComponentModel.dll!System.Workflow.ComponentModel.ActivityExecutorOperation.Run(System.Workflow.ComponentModel.IWorkflowCoreRuntime workflowCoreRuntime) + 0xbe bytes 

I’ve created a function, that can be called to output trace in case of exception”

/// <summary>/// Concatenate all parents QualifiedNames
/// </summary> 
/// <param name=”activity”></param> 
///
<returns></returns>
public static string FullQualifiedName(this Activity activity)
{
Activity act=activity;
List<string> list = new List<string>();
while (act != null)
{
list.Insert(0,act.QualifiedName);
act=act.Parent;
}
return CollectionsHelper.ToString<string>(list, “.”,“”);
}

 

 

Unrelated note that  to debug the workflow using F5 you MUST set the workflow DLL project as the Visual Studio solution startup project.

 

Developers should avoid smart-quotes in Word

We had a Word document, describing steps, based on MSDN instructions Use the Windows Workflow Tracking Service
 
I desided to create batch file createWorkflowTrackingDB.bat to create Database:

@echo Change name of Database server if required
@echo press control-Z to stop batch
@pause
sqlcmd -S localhost -E -Q “create database WorkflowTracking”
c:
cd “C:WINDOWSMicrosoft.NETFrameworkv3.0Windows Workflow FoundationSQLEN”
sqlcmd -S localhost -E -d WorkflowTracking -i Tracking_Schema.sql
sqlcmd -S localhost -E -d WorkflowTracking -i Tracking_Logic.sql
@echo Ensure that application account has tracking_reader and tracking_writer roles

 
But it was failing on the line
     sqlcmd -S localhost -E -Q “create database WorkflowTracking”.
It took me a while to recognize, that MS Word replaced double-quotes with smart-quotes , and sqlcmd didn’t like it.