SharePoint state machine workflow : some issues and work-arounds

In this post I am giving some possible issues that you may face while working with state machine workflow and the work around to resolve those issues.

Issue 1

=======

Sometimes, if you have a SharePoint state based workflow that has a DelayActivity and the DelayActivity never fire and error out eventually. The problem lies in the fact that the workflow calls out to another DLL in the code activity following the DelayActivity. When the call is made a " System.IO.FileNotFoundException: Could not load file or assembly" exception is raised (see below), though the DLL is in the GAC and has SafeControl entry in web.config.

System.IO.FileNotFoundException: Could not load file or assembly 'Utilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=584ac65395d6cc3f' or one of its dependencies. The system cannot find the file specified. File name: 'Utilities, Version=1.0.0.0, Culture=neutral, PublicKeyToken=584ac65395d6cc3f' at RRURequestWorkflow.Workflow1.codeActivity2_ExecuteCode(Object sender, EventArgs e) at System.Workflow.ComponentModel.Activity.RaiseEvent(DependencyProperty dependencyEvent, Object sender, EventArgs e) at System.Workflow.Activities.CodeActivity.Execute(ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutor`1.Execute(T activity, ActivityExecutionContext executionContext) at System.Workflow.ComponentModel.ActivityExecutor`1.Execute...

Issue 2

=======

Some other occasions, if you have a state machine workflow with several activities. Whenever it reaches a delay activity, it throws following error in the ULS logs.

Engine RunWorkflow: System.Runtime.Serialization.SerializationException: Cannot get the member 'codeActivity1_ExecuteCode'. at System.Reflection.MemberInfoSerializationHolder.GetRealObject(StreamingContext context) at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder) at System.Runtime.Serialization.ObjectManager.DoFixups() at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) a...

...t System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) at System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity, IFormatter formatter) at System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity) at System.Workflow.Runtime.Hosting.WorkflowPersistenceService.RestoreFromDefaultSerializedForm(Byte[] activityBytes, Activity outerActivity) at Microsoft.SharePoint.Workflow.SPWinOePersistenceService.LoadWorkflowInstanceState(Guid instanceId) at System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor, WorkflowInstance workflowInstance) at System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, Creation...

...Context context, WorkflowInstance workflowInstance) at System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.Send(SPWinOeWorkflow winoeworkflow, SPWorkflowEvent e) at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(Guid trackingId, SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut)

 Engine RunWorkflow: System.Workflow.Activities.EventDeliveryFailedException: Event "OnWorkflowItemChanged" on interface type "Microsoft.SharePoint.Workflow.ISharePointService" for instance id "36fc71f8-c048-4306-bd29-8ad1aa02a5c4" cannot be delivered. ---> System.Runtime.Serialization.SerializationException: Cannot get the member 'phase7SendRequestorPrintView_MethodInvoking'. at System.Reflection.MemberInfoSerializationHolder.GetRealObject(StreamingContext context) at System.Runtime.Serialization.ObjectManager.ResolveObjectReference(ObjectHolder holder) at System.Runtime.Serialization.ObjectManager.DoFixups() at System.Runtime.Serialization.Formatters.Binary.ObjectReader.Deserialize(HeaderHandler handler, __BinaryParser serParser, Boolean fCheck, Boolean isCrossAppDomain, I...

...MethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream, HeaderHandler handler, Boolean fCheck, Boolean isCrossAppDomain, IMethodCallMessage methodCallMessage) at System.Runtime.Serialization.Formatters.Binary.BinaryFormatter.Deserialize(Stream serializationStream) at System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity, IFormatter formatter) at System.Workflow.ComponentModel.Activity.Load(Stream stream, Activity outerActivity) at System.Workflow.Runtime.Hosting.WorkflowPersistenceService.RestoreFromDefaultSerializedForm(Byte[] activityBytes, Activity outerActivity) at Microsoft.SharePoint.Workflow.SPWinOePersistenceService.LoadWorkflowInstanceState(Gu...

...id instanceId) at System.Workflow.Runtime.WorkflowRuntime.InitializeExecutor(Guid instanceId, CreationContext context, WorkflowExecutor executor, WorkflowInstance workflowInstance) at

System.Workflow.Runtime.WorkflowRuntime.Load(Guid key, CreationContext context, WorkflowInstance workflowInstance) at System.Workflow.Runtime.WorkflowRuntime.GetWorkflow(Guid instanceId) at System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs) --- End of inner exception stack trace --- at System.Workflow.Activities.WorkflowMessageEventHandler.EventHandler(Object sender, ExternalDataEventArgs eventArgs) at Microsoft.SharePoint.Workflow.SPWinOEWSSService.RaiseEvent(SPWinOeWorkflow workflow, SPWorkflowEvent workflowEvent, O...

...bject workItem, IPendingWork workHandler) at Microsoft.SharePoint.Workflow.SPWinOeHostServices.Send(SPWinOeWorkflow winoeworkflow, SPWorkflowEvent e) at Microsoft.SharePoint.Workflow.SPWinOeEngine.RunWorkflow(Guid trackingId, SPWorkflowHostService host, SPWorkflow workflow, Collection`1 events, TimeSpan timeOut)

Resolution for Issue 1 & 2:

After restarting the “windows SharePoint timer service” the both the above issues will get resolve. Root cause was, whenever you have workflow that has got a delay activity, the event is fired by the service(SPTimerV3), before it fires, it has to load the assembly from its bin or from the GAC, only one file(module loads) based on the assembly information specified in workflow.xml file loads.

Deploying the new binary after changing the workflow activities, the SPTimerV3 is not aware of the newly added binary; it won’t reload it unless you do a time reset. Unless you do a reset, the persistence (serialization or de-serialization) or loading of assembly would fail due to mismatch of types.

Issue 3

=======

Whenever you initialize the timeoutduration of 2 delay activities in the InitializeTimeoutDuration event, the delay activity will not work as expected.

Eg: private void delayActivity2_InitializeTimeoutDuration(object sender, EventArgs e)

        {

                delayActivity2.TimeoutDuration = TimeSpan.FromMinutes(3);

        }

Resolution for Issue 3:

In state machine workflow we can’t initialize the timeoutduration by using the object name of the delay activity (eg: delayActivity2.TimeoutDuration = TimeSpan.FromMinutes(3);) instead use the sender parameter of the InitializeTimeoutDuration event, which will always be the currently running instance of the Delay, cast it to a DelayActivity and set the value on the TimeoutDuration property.

When a state is entered in the state machine (or when other workflow activities like the ReplicatorActivity, WhileActivity or ConditionedActivityGroup are executed) the workflow engine makes a clone of activities from your workflow definition and execute them instead of the activities in your workflow definition. For this reason you can't just change the activity as you did but you have to change the instance that the workflow is actually executing.

Here is the sample:

  private void delayActivity2_InitializeTimeoutDuration(object sender, EventArgs e)

        {

               // delayActivity2.TimeoutDuration = TimeSpan.FromMinutes(3);

               (sender as DelayActivity).TimeoutDuration = TimeSpan.FromMinutes(3);

        }

The sender will be the instance of the DelayActivity that the workflow is actually executing.

You also found that if you bind the timeout property to a dependency field it allows you to set the values using the instance field.