Workflows not being associated with lists/libraries

I don’t often do "a funny thing happened to me on the way to configuring a SharePoint farm recently"-type posts, but I’m making an exception here – this issue not only took a bit of figuring out, it’s also kind of interesting! This is partly because SharePoint doesn’t do what you’d expect it to do under the circumstances, and you could probably chase your tail for a while on this one if you didn’t think it through. 

Scenario:-

  • Workflow is not enabled on any of the lists/libraries in the site in production – specifically, there is no association so the workflow list is empty
  • The workflow we were expecting to see enabled is the standard publishing approval workflow – since we are in a WCM/publishing site scenario, this would be associated with each Pages list in the hierarchy
  • In our case, initial configuration had just been completed by the hosting company and we were asked to start our testing. Search configuration has not yet been performed
  • Previous environments did not display this behaviour
  • A custom site definition is used to create any site/web – this is what determines the approval workflow should be associated

At first it seemed like an issue with the site definition. I was thinking that the hosting company had missed a deployment step to STSADM upgradesolution on the .wsp containing the site definition, but accessing the servers showed the latest files in place. I knew that because search configuration hadn’t been done yet, the hosting company hadn’t yet created the SSP – this was their next task. I couldn’t initially see a link between the SSP and workflow (since SharePoint workflows execute in the w3wp.exe process), but then I started wondering if there was any indirect link, and came up with this as a chain of dependencies:

 image

Could it be that the sites didn’t have workflow enabled because the SSP wasn’t there at time the sites were provisioned? Sounds plausible, but then I thought hang on – surely what would happen is that workflow associations and so on would be there as usual, but when a workflow form is accessed it would error with the familiar message that session state must be configured:

InfoPathSessionError

Well, as you might have gathered, the answer is no, this isn’t what happens! SharePoint genuinely will not (or cannot) add the workflow associations to your lists/libraries, and furthermore they will not magically appear when your SSP is created. You will need to go back and configure workflow on each list/library (or content type) either through the UI or with code.

So the moral of the story is:

Create your SSP before any sites are provisioned!

More workflow issues and resolutions

What I wanted to do today is run through is wrap up my series of workflow posts, by running through some of the issues I hit during development. If you’re into workflow, you may have seen Rob Bogue’s excellent 10 issues (and resolutions) for SharePoint+Workflow – this post is something of an extension to Rob’s. It probably makes for rather dry reading, but will hopefully be useful to those Googling for specific problems.

  1. Issue:- Error message “System.Xml.XmlAttribute is not serializable” shown in workflow history list and workflow will complete before it is supposed to. In SharePoint log, will see “End of Stream encountered before parsing was completed” error.

    More information:- This is caused by trying to store a class which cannot be serialized as a member (e.g. private variable) of the workflow class. Furthermore, I also encountered this error when storing the class which represents the InfoPath form – interestingly this class will always definitely be serializable, but the error was happening nevertheless.

    Resolution:- Mark member as NonSerializable (so workflow does not attempt to serialize the class, and copy primitive data (e.g. strings, dates etc.) out of form class and into individual field-level variables. It might also be possible to mark the ‘AnyAttr’ member of the generated class as NonSerializable instead.

  2. Issue:- InfoPath forms do not get updated upon solution deployment – changes are not reflected.

    More information:- This happened when I initially started development. I noticed that if I separately deactivated/uninstalled the workflow Feature, the InfoPath forms would then update successfully. This pointed me to an issue with the PostBuildActions.bat script.

    Resolution:- Modify PostBuildActions.bat to use the -force parameter when deactivating/uninstalling the Feature.

  3. Issue:- Error message “The e-mail message cannot be sent. Make sure the outgoing e-mail settings for the server are configured correctly.” is shown in the workflow history list. E-mail configuration is known to be good (e.g. alerts are working).

    More information:- I suspect there are several reasons why this may happen, but for me the problem was how I was using the SendEmail activity. When I was setting properties on the SendEmail variable the workflow designer had added to my class for me, I had the error.

    Resolution:- The best way I found to deal with this was to set properties on the object which is passed to the SendEmail’s ‘MethodInvoking’ code. You’ll need to cast to SendEmail before you can do this.

  4. Issue:- The TaskID for a CreateTask activity does not get populated. The value defaults to -1 instead.

    More information:- This will be an issue in several scenarios, one example is when building the URL for a task (e.g. to include in an e-mail to a user) with code similar to Paul Hunt’s code shown at http://suguk.org/forums/thread/4978.aspx.

    Resolution:- The TaskID will only be populated if there is a place to store the value. Ensure the TaskID property on your CreateTask activity is bound to a variable.

  5. Issue:- Error messageCorrelation value on declaration ‘x’ is already initialized” message shown in SharePoint log when a task executes for the second time in a workflow.

    More information:- This scenario can happen when a CreateTask runs for a 2nd time due to an approver rejecting something in the workflow.

    Resolution:- The ‘OwnerActivtyName’ of the task’s correlation token is incorrectly set. In a state-machine workflow, it should refer to the particular state, not the overall workflow.

  6. Issue:- Unexplained errors when some part of an otherwise functioning workflow is commented out in the designer (e.g. ‘Failed on start’).

    More information:- You’ve commented out one or more activities in your workflow (using right-click > Disable), but observe strange behaviour and/or errors. This is actually because, in contrast to commenting out source code, the code is actually still compiled into the assembly. Hence if there is an error with say, a correlation token being incorrectly set, this will still cause a problem in your workflow.

    Resolution:- Fix problem or remove faulting activity/activities completely from workflow.

For completeness, some other common issues which are well documented in other sources are:

  • ‘Failed on start’ – this often caused by a problem loading the workflow assembly. Check the PostBuildActions.bat script (or whatever you are using) has properly deployed the assembly to the GAC, and all the assembly attributes (version, public key token etc.) match those specifed in the Feature files.
  • ‘SPException: This task is currently locked by a running workflow and cannot be edited’ message. This is documented by Rob Bogue and others, but I’d also add this can occur as a knock-on effect of another problem. If an earlier exception has occurred whilst trying to process a task, the workflow will have locked the task on the first run, meaning that subsequent attempts by a user to respond to the task will result in this error. Other than fixing the problem at source, I haven’t found an elegant way of dealing with this.

So hopefully that’s of some use to workflow developers. If you haven’t seen it already, there’s a lot more goodness (sample code, tips and tricks etc.) in my workflow resources pack from the workflow deep-dive presentation I did at the UK SharePoint user group earlier this year.

Happy coding!

InvokeWorkflow – child workflows not supported in SharePoint?

Our client through an interesting curve ball at us midway through my workflow project. We were probably 70% code complete, when it was realised the design had no provision for a certain scenario. The workflow is triggered by a user completing an InfoPath form – this has many input controls to collect data, and several of them are dropdowns which dictate the particular path through the workflow which occurs. One such dropdown looks something like:

Type:

  • type 1
  • type 2
  • both

The value selected is evaluated by IfElse conditions in the workflow – if "type 1" is chosen, we go down a particular branch, if "type 2", a different branch and so on. Now for this particular dropdown, we realised we hadn’t specified what should happen for the "both" condition (that’s agile for you!). The new requirement which arose was that notifications and tasks should go to to two teams (i.e. both of them), and after further discussion we decided it would be appropriate to kick off two separate workflows, one for each team.

Most workflow frameworks can deal with this by using ‘child’ workflows, and Workflow Foundation is no different. After a couple of hours refactoring the implementation to use this approach, my proof-of-concept looked like:

ParentWorkflow

So whilst the ‘InvokeWorkflow’ activities are closed (i.e. the child workflows aren’t expanded), you can hopefully see that if we go down the branch on the left, we launch one child workflow, but in the branch on the right (for "both"), we launch two child workflows in parallel.

The problem

I tried a couple of things, the image above shows using a sequential parent workflow (though the child workflow is state-machine), but couldn’t get this to work. Using the debugger I could see that the child workflows were being initialized – I could step through InitializeComponent(), but breakpoints in ‘OnWorkflowActivated’ were never hit – the event wasn’t raised. The SharePoint log showed:

System.Workflow.Activities.EventDeliveryFailedException: Event "OnWorkflowActivated" on interface type "Microsoft.SharePoint.Workflow.ISharePointService" for instance id "67c4929a-9280-4b8b-9a4c-a1b85b04267c" cannot be delivered. —> System.InvalidOperationException: Event Queue operation failed with MessageQueueErrorCode QueueNotFound for queue ‘Message Properties Interface Type:Microsoft.SharePoint.Workflow.ISharePointService Method Name:OnWorkflowActivated

So I became suspicious of whether it’s possible to use InvokeWorkflow in a SharePoint workflow. Microsoft haven’t yet got back to me on this, and the most detailed SharePoint workflow book I’m aware of (Workflow in the 2007 Microsoft Office System by David Mann) does not discuss InvokeWorkflow.

Time for some lateral thinking.

The solution

We know that we will definitely have two workflows if two completed InfoPath forms are added to the document library, so I asked the client what they thought of getting the system to split a "both" request into two separate items – this would mean having two separate InfoPath forms in the list. The answer was "actually that’s probably better for the users come to think of it", so the solution I came up with was:

  • a list event receiver which executes before the workflow – this does the following:
    – opens the binary contents of the InfoPath form as a string, and modifies the dropdown value from "both" to "type 1"
    – creates a duplicate of the original file in the same library, but modifies the dropdown value here from "both" to "type 2"
  • running some ad-hoc code to reorder the event receivers on the list – we need to split the item before workflow starts (so we get two workflows) but SharePoint adds the SPWorkflowAutostartEventReceiver at sequence of 1 so it executes first. This code switches the event receiver sequence so our pre-processing happens first.

On the last point, I considered that the SharePoint team may have set workflow to execute first for a reason, but then again it’s just another event receiver and SharePoint does not prevent this reordering (in the same way it does with some other changes, such as deleting the welcome page from a web for example). In any case, we’ve tested pretty extensively and the solution hasn’t missed a beat.

In case it’s useful, the following code can be used to duplicate and modify a file – this could be used in a list receiver (as in my case) or in ad-hoc code. I used simple string manipulation to perform the modification since InfoPath forms are just XML, and also because using XML-handling methods caused issues with the ‘proprietary’ InfoPath declarations. Simply replace the string replacement line with your own processing.

   1: private string getFileContentsAsString(SPFile file)
   2: {
   3:     byte[] aFileBytes = file.OpenBinary();
   4:     string sContents = Encoding.UTF8.GetString(aFileBytes);
   5:  
   6:     return sContents;
   7: }
   8:  
   9: private void duplicateFile(SPListItem originalListItem, string sNewItemUrl, 
  10:     bool bDeleteOriginal)
  11: {
  12:     SPFile originalFile = originalListItem.File;
  13:     string sOriginalFileContents = getFileContentsAsString(originalFile);
  14:  
  15:     // TODO: replace this line with your own processing..
  16:     string sNewFileContents = sOriginalFileContents.Replace("oldValue", "newValue");
  17:     
  18:     byte[] aNewFileBytes = Encoding.UTF8.GetBytes(sNewFileContents);
  19:  
  20:     // we effectively need to add a new file for this operation, and optionally delete 
  21:     // the original..
  22:     SPFile newFile = originalListItem.ParentList.RootFolder.Files.Add(sNewItemUrl, aNewFileBytes,
  23:                                                                       originalFile.Properties);
  24:     newFile.Update();
  25:     
  26:     if (bDeleteOriginal)
  27:     {
  28:         originalListItem.Delete();
  29:     }
  30: }

P.S. If anyone is using InvokeWorkflow in a SharePoint workflow, leave a comment 🙂

Workflow: tasks which can only be actioned by task owner

When coming to Visual Studio workflows, something which surprises many SharePoint developers is that tasks assigned in the workflow can actually be actioned by any SharePoint user with basic permissions. In the worst scenario, ‘basic permissions’ means any user with contribute permissions to the SharePoint web which contains the workflow tasks list, and clearly this could be a whole lot of users who have nothing to do with your workflows. In the best case, you might have tied down permissions so that only users involved in workflows can use the list. Even so, this still means that any actor in the workflow can respond to any task, not just tasks which have actually been assigned to them. To my mind, this is bad – all it takes is a confused user to accidentally respond to someone else’s task and your workflow is in a whole world of chaos.

So what can we do about this?

Well, there doesn’t seem to be much written about this, but fortunately the best solution (AFAIK) is also the simplest one. Before we dive in, I notice other people needing to solve this problem have taken the approach that since a workflow task is just a list item, we can execute some code to set permissions on the list item using the API. A logical tactic, but happily there is special provision for doing this in the workflow framework – we still need to write a little code, but it’s much simpler than that approach. The key is the ‘SpecialPermissions’ property of the CreateTask activity:

Pitfall – confusingly, clicking the ellipses button (…) for the property presents a generic VS collection editor (shown below), which as far as I can tell just flat cannot be used with this property – all the controls are disabled!

I’m assuming this is a bug in the Visual Studio 2005 Extensions for Workflow Foundation, so we’ll ignore that! However, clicking the tiny blue ‘bind property’ button presents the more familiar ‘bind the property to an instance variable’ dialog – assuming you haven’t already created a variable to store the permissions for this CreateTask, we should select ‘Bind to a new member’, and create either a field or property to store the permissions:

This creates a collection object, specifically a HybridDictionary, to which we can add items for each permission we need for this task. And we only need a handful of code lines to do it! Since we’re likely to use it for many (i.e. all) tasks in our workflow, let’s have a separate method we can call each time:

private void setTaskPermissions(HybridDictionary boundDictionary, string sTaskOwner)

{

     boundDictionary.Clear();

     boundDictionary.Add(sTaskOwner, SPRoleType.Contributor);

     boundDictionary.Add(“NT AUTHORITY\\authenticated users”, SPRoleType.Reader);

}

So, we pass in the collection specific to each task, and also the string username for the task owner. We then add an entry for the task owner to the dictionary with the ‘contributor’ permission, and one for all other users with just read permissions. Note we also clear out the dictionary before adding in case this task has already been issued (i.e. something got rejected in the workflow and we came back to this task a second time) – this avoids any errors due to the key already existing in the dictionary.

The calling code then, looks like this:

setTaskPermissions(approveExpenseClaim_SpecialPermissions, taskProps.AssignedTo);

This would be added to the code for each CreateTask activity in your workflow. The first parameter is the variable we bound earlier to the SpecialPermissions property (of the particular task we are dealing with), and taskProps is the SPWorkflowTaskProperties object which holds data for the task.

And that’s it – much less code than you’d need to modify permissions for the list item with general API usage. The effect of this is that the task owner is the only standard user (administrators with full control excepted) who can respond to the task, but all others can read it. Needless to say, you could customize the code to your specific permission requirements if they are different to mine.

The user experience

One final thing worth pointing out is that the user experience might not be quite as slick as you’d like. Since we’ve restricted permissions on the item, any user who clicks on the task but doesn’t have permissions will see the standard access denied message:

Personally I think an improvement would be to show a more friendly message, but this would require substantially more effort and complexity. My view is that for a few lines of code, this approach is a great trade off between effort required and benefit of protecting the integrity of the workflow – I’m definitely not a fan of sleepless nights wondering just what would happen in the workflow if users unintentionally responded to tasks which didn’t belong to them, so it works for me. As always, if you’ve implemented a different way of dealing with this problem or have other comments, it would be great to hear.

Resources from my workflow deep-dive presentation

Had a lot of fun presenting VS workflows at the UK SharePoint user group last night. We seemed to have weather issues (again) which might have put some people off travelling, but we still had a great crowd of around 100-120 people. As promised, here are my resources (my ‘workflow bonanza pack’ in fact ;-)). In the zip behind the link below, you will find:

  • Slide deck (presentation title: “Workflow: A deep dive into developing workflows for SharePoint using Visual Studio and Infopath”)
  • Sample code for the state machine expenses workflow I built
  • My workflow information pack document

Much of the goodness is in the document – the contents are:

  • Links to my favourite workflow resources (blogs, books etc.)
  • How to: work with SharePoint tasks and e-mails in workflows
  • How to: Pass data into an InfoPath task edit form
  • How to: retrieve what the user entered into an InfoPath task edit form
  • How to: debug a workflow
  • How to: use serialization to retrieve data from an InfoPath form
  • Advanced workflow tips
  • Workflow pitfalls
  • Appendix 1 – correlation tokens

You can download all this from http://sharepointchris.googlepages.com/COB_WorkflowResources.zip

P.S. I’ll be expanding on this content – the next couple of articles will be workflow-focused.

Speaking at UK SharePoint user group on workflow

For anybody interested in workflow, I’ll be speaking at the UK user group next week at Microsoft’s London Victoria office on 10th Jan. There are two great sessions so I’d encourage UK SharePointers who can get to London to come down. Needless to say, I’ll be posting my slides/sample code etc. for those further afield.

For those considering coming down, the meeting should be fun and it looks like a high turnout – we have over 100 people registered already. My fellow speaker is SharePoint MVP and all-round good guy Andrew Woodward.

The timetable and session abstracts are:

1800 – 1830 Arrive

1830 – 1930  Workflow: A deep dive into developing workflows for SharePoint using Visual Studio and Infopath – Chris O’Brien

Of the three types of workflow available to the SharePoint developer, only Visual Studio workflows provide complete flexibility and power. Without the right information however, the learning curve can be steep for the uninitiated. In this session we’ll start with initial decisions such as SharePoint Designer workflows vs. Visual Studio workflows, sequential vs. state-machine, and InfoPath vs ASP.Net for forms. From there we’ll cover the key steps to get a workflow up and running including retrieving data from an InfoPath form, configuring workflow activities, and deployment of the workflow. Over several demos, we’ll build a basic state-machine workflow, and show why workflow is a valuable addition to any SharePoint developer’s skillset.

1930 – 2000 Snacks and drinks

2000 – 2100 Search Server 2008 – What is it, how does it affect me and should I be testing it? – Andrew Woodward

A look at the recently announced Search Server 2008.  We will walk through an installation and demonstration of the new Federated Search capabilities, what’s provided out of the box, what you can get from free, how to leverage sites using Live.com and how to federate results from Google. We will discuss how this fits in with your existing WSS and MOSS deployments and the release timescales.

Registration/more info is at http://suguk.org/forums/thread/7300.aspx – please add to the thread leaving your full name