>Custom Exception Objects in Workflows

>The more you use Windows Workflow Foundation, the more you get to understand it. In the past, I have been a bit lazy with exception handling and just used out of the box .NET exception types.

Anyway to improve the resilency of a workflow I decided to implment a custom exception. Pretty straight forward I thought.

However when I got to test it the exception was raised correctly and all looked well an error appeared in the workflow history. However when the workflow went to rehydrate it errored out with the following error:-

System.Workflow.Activities.EventDeliveryFailedException: Event “OnTaskChanged”
on interface type “Microsoft.SharePoint.Workflow.ITaskService” for instance id
“80742821-239e-4740-b19b-7ad2885ff6ba” cannot be delivered. —>
System.Runtime.Serialization.SerializationException: The constructor to
deserialize an object of type
‘ITSP.CC.SimpleApprovalWorkflow.TaskNotUpdatedByAssignedUser’ was not found.
—> System.Runtime.Serialization.SerializationException: The constructor to
deserialize an object of type
‘ITSP.CC.SimpleApprovalWorkflow.TaskNotUpdatedByAssignedUser’ was not
found. at
System.Runtime.Serialization.ObjectManager.GetConstructor(Type t, Type[]
ctorParams) at
System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object
obj, Serializatio…

Anyway I wrote a document which has been used as the base of this post so here it is.

What do I do now?
This article will describe a couple of issues that were discovered when implementing custom exceptions within a SharePoint / Windows Workflow Foundation workflow.
The custom exception was used in a fault handling activity and assigned as one of the types of exceptions that could be handled by a fault handler.
When selecting the exception you choose the type of exception and also bind a property to the fault property for that exception handler.
This is fine, though workflows generally do not start and finish in one go, they normally have to pause and wait for some user interaction or system interaction. In order to not waste system resources the workflows hydrate (go to sleep) and dehydrate (wake up) when the workflow has done all the work that it needs to do.
When the workflow hydrates and dehydrates it calls each of the objects serialization routines. This is normally fine as in order to make an object serializable we add the [Serializable] attribute above the class definition.
Now the workflow is able to serialize the class … great.

Great?
Well not quite this works brilliantly when all the properties (member variables) are public as the serialization engine just serializes them, though for member variables that are protected or private the engine needs some assistance in case it records some data, making it public when its really sensitive.
So lets not do anything and see what happens… well when the workflow wakes up to process an event an error occurs:-

System.Workflow.Activities.EventDeliveryFailedException: Event “OnTaskChanged”
on interface type “Microsoft.SharePoint.Workflow.ITaskService” for instance id
“80742821-239e-4740-b19b-7ad2885ff6ba” cannot be delivered. —>
System.Runtime.Serialization.SerializationException: The constructor to
deserialize an object of type
‘ITSP.CC.SimpleApprovalWorkflow.TaskNotUpdatedByAssignedUser’ was not found.
—> System.Runtime.Serialization.SerializationException: The constructor to
deserialize an object of type
‘ITSP.CC.SimpleApprovalWorkflow.TaskNotUpdatedByAssignedUser’ was not
found. at
System.Runtime.Serialization.ObjectManager.GetConstructor(Type t, Type[]
ctorParams) at
System.Runtime.Serialization.ObjectManager.CompleteISerializableObject(Object
obj, Serializatio…

To fix this we need to provide a constructor to deserialize the object and also a method so that the runtime and properly serialize the object.
Serialization support is provided by implementing the ISerializable interface and this interface requires to functions.
These are handled by the following functions.

public virtual void GetObjectData(SerializationInfo info, StreamingContext
context)·

protected MyObject(SerializationInfo info,
StreamingContext context)

GetObjectData is called to get the serialization data and this is where we tell the object to also put the private / protected member variable definitions.
The protected constructor provides a way to get the serialized information in SerializationInfo object back into the private/protected member variables.

Now with the Custom exceptions we have added complexity in that the System.Exception object already implements the ISerialize interface so we need to override these functions and also call the base functions whilst handing our custom exception objects data.
The example below describes this:-

The deserization constructor is as follows:

protected TaskNotUpdatedByAssignedUser(SerializationInfo info, StreamingContext
context)

:
base
(info,context)

{

m_sUser
=
info.GetString(“m_sUser”);

m_sAssignedUser =
info.GetString(“m_sAssignedUser”);

m_sErrorMessage =
info.GetString(“m_sErrorMessage”);

}

The GetObjectData function is as follows:-

[SecurityPermissionAttribute(SecurityAction.Demand,SerializationFormatter=true)]
public override void GetObjectData(System.Runtime.Serialization.SerializationInfo info, System.Runtime.Serialization.StreamingContext context)
{
base.GetObjectData(info, context);
info.AddValue(“m_sUser”, m_sUser);
info.AddValue(“m_sAssignedUser”, m_sAssignedUser);
info.AddValue(“m_sErrorMessage”, m_sErrorMessage);
}

Once these functions have been implemented and the new code loaded then the workflow rehydrates as expected.

One tip:

remember to recycle the timer service as well as the app pool.

Use:

net stop sptimerv3 and net start sptimerv3.

Hope someone finds this useful!

One Comment

Thoughts? Comments about this post? Please leave them here..

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s