Tuesday, 9 June 2009

SharePoint 2007 Workflow - Workflow Completes Prematurely without Error

A SharePoint Workflow I'm currently working on seemed to be particularly flakey when I introduced a DelayActivity to it. Several steps after the DelayActivity would be skipped with no apparent reason every 2nd or 3rd time I ran it. Unpredictable problems like this are notoriously hard to nail down - but I managed to find the cause.

Looking at the SharePoint Logs in the 12 Hive (e.g. in "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\LOGS"), I found the following "Workflow Infrastructure" error with a severity of "Unexpected":

DehydrateInstance: System.Runtime.Serialization.SerializationException: End of Stream encountered before parsing was completed.

The following blog entry on the SharePoint Team Blog

Gave the following possible reasons for a workflow failing in this way:

1. Pitfall: Re-using non-serializable SharePoint objects after rehydrationMany non-workflow specific SharePoint objects, like SPListItem, are not serializable, so when the workflow dehydrates, these items become invalid. So if you try to use them when the workflow wakes up, you will get an error. To avoid this, refetch items if you’re using them after a workflow rehydrates.

2. Pitfall: Forgetting to make custom classes serializableWhen creating your own class in a workflow, don’t forget to add the “Serializable” attribute to the class. If you don’t do this and declare a variable of that class in the workflow’s scope, the workflow will fail when it tries to go to sleep and serialize the class. If you notice that the workflow “completes” when it isn’t supposed to, this may be the culprit.

I marked my custom classes with the [Serializable] attribute and the problems all disappeared.

[UPDATE - 9 Jun 2009]

As discussed in this post:

I also had to tag my member variables for any InfoPath Forms schema-generated objects (even though they are private, they are still serialized) with a [System.NonSerialized] flag. I created a wrapper for my form instead:

private InitiationForm _initiationForm = default(InitiationForm);

//Property for all access to the InfoPath form wrapper class
public InitiationForm InitiationForm
if (_initiationForm == null)
XmlSerializer xs = new XmlSerializer(typeof(InitiationForm));
XmlTextReader xtr = new XmlTextReader(new StringReader(workflowProperties.InitiationData));
_initiationForm = (InitiationForm)xs.Deserialize(xtr);
return _initiationForm;

No comments: