On a recent SharePoint 2010 project I
had the opportunity to look at creating custom Workflow Actions which is a way
to extend the actions already available in SharePoint Designer Workflows.
If I'm honest, the foray was both informative and slightly arduous but
perhaps due mostly to my own inability to type properly and my own lack of
understanding. Let's start by having a look at why we decided to look down this
path.
Why a Custom Workflow
Action?
The project in question required a handful of workflows to be developed, all
of which were prepared and written using SharePoint Designer. The problem was
highlighted early on that we needed to port the be able to package the workflows
up to deliver them across multiple platforms during the development life-cycle.
For 2 of the workflows, this didn't pose a problem since they were Reusable
Workflows which lend themselves to just this kind of functionality. The 2
workflow, however, was a List-based workflow and as such it was not able to be
exported as a WSP. The reason the workflow was a List-based workflow was due to
the columns necessary to facilitate the workflow actions - Approval Status being
the culprit in this scenario. As it turns out, the "Approval Status" column is
not visible for anything other than a List-based workflow.
To allow the workflow to be packaged up meant it had to be a Reusable
Workflow, or we had to provide a work-around. After several attempts to package
the workflow up (using this method
http://ikarstein.wordpress.com/2011/02/10/walkthrough-how-to-move-or-copy-a-sharepoint-designer-2010-list-workflow-to-another-list-on-the-same-site-or-another-site/ was
a way to export a List-based workflow using the "Export to Visio" and "Import
from Visio" options which did work but didn't provide the hands-off approach we
wanted) we decided to try writing a custom Workflow Action to perform the steps
we required.
Nuts and Bolts
As it turns out, creating a custom Workflow Action is pretty
straight-forward. Create a class, create a publicly declared static method in
the class, and away you go. The first parameter must be a context object - we
were deploying as a User Code Solution so this was of type
SPUserCodeWorkflowContext.
If you're action doesn't need any parameters, do your coding stuff and then
move on to the feature XML.
One note here - any typos or spelling mistakes mean that your workflow will
not run. I battled for a long time to debug my workflow with only frustration
as my reward. I eventually searched the SharePoint logs and found that I had
mis-named a parameter so my workflow was never being run. Once I had fixed
that, I was away after I had attached to the SharePoint User Code process.
Here's a couple of walk-throughs I found:
http://msdn.microsoft.com/en-us/library/gg615449.aspx and
http://msdn.microsoft.com/en-us/library/ff798499.aspx.
What I would say is that the first article is more accurate. The second one
makes no mention of the fact that the method you implement for your action
should be a static method - even the example code doesn't show this, so
beware.
End-to-end, the final solution (which wasn't overly complicated) took about a
day, and at the end I had a fully working custom workflow action which I could
use in my workflows. Looking back, it was actually quite painless and easy and
once you know where to look (i.e. SharePoint logs, debugging etc) it was fairly
rapid.
The Fairytale Ending(?)
Unfortunately, there is no happy ending to this story. I went through a day
of trauma and frustration and came out the other side having happily implemented
my custom workflow action into a reusable workflow. I saved the workflow
through SharePoint Designer to a WSP and thought things were making sense.
I then moved the workflow to another site collection and installed the WSP
and that's where the story currently ends. It didn't work. Well.....I say that
it didn't work, but I don't really know if I'm honest. The only definition I
have to say it didn't work is the fact that the workflow I had created did not
appear anywhere so I was unable to use it. No doubt I will post further about
this once I've figured out what went wrong here.
Final Thoughts
Looking back at the reasons behind our decision to use a workflow it was
mostly dictated by the approach to the required functionality we had already
started: namely the other 2 reusable workflows. Keeping to the same model for
the third workflow made sense as it followed the same technology instead of
departing in a different direction and introducing custom code instead of
manully created workflow (i.e. event receivers).
As it turned out, writing a custom workflow action still meant code in order
to achieve the portability we wanted so at that point, perhaps, it would have
been better to write an event receiver. The influence to stick with workflow
came from the technology angle - keeping to the same "hymn sheet" as it were.
Yes, it was custom code, but at least it was still workflow.
Fortunately, in this scenario we did have a fallback position to backup the
site and restore it, so the time invested was as much for research into this
area, which, if I'm honest, was time well spent.