Archive for the ‘InfoPath 2010’ Category

HOWTO Move or Migrate SharePoint 2010 List-based Workflows between Sites and Site Collections

August 29, 2011

I’ve experienced this issue a lot when trying to migrate workflows between test SharePoint 2010 farms and production farms, in particular with workflows attached to lists. When moving a workflow to another site collection or server farm, the association to the list is broken and the workflow cannot be attached to the list. You also cannot use SharePoint designer to fix this via the standard methods as the unattached workflow cannot be reattached to the list.

List-based workflows are tied to three different lists – the “main” source list where the data is held (such as a Forms library or custom list), a task list, and a workflow history list. The latter in particular is tricky, because it is a hidden list and cannot be viewed via the normal interface.

The fix for this is to modify the source workflow files to force the workflow to reattach to the list. The following method assumes that your new site/location that you are moving the workflow too does not yet have any workflows already attached to any lists on the site. When a workflow is created in a site for the first time, a Tasks list and a Workflow History list are automatically created/used by the workflow. These lists must exist before you can force your migrated workflow to attach to the list.

Step 1 – Create a Blank Workflow

  1. Using SharePoint designer, connect to your destination site
  2. Create a new list-based workflow called “test” (or whatever), attaching it to your migrated list
  3. Create one condition (i.e. if 1 = 1)
  4. Create one action (i.e. add comment “hello”)
  5. Save and publish the workflow

After this step has been completed, your site will now have a Tasks list and Workflow History list.

Step 2 – Get the list ids for your new workflow

The list ids are required to configure your migrated workflow.

  1. Using SharePoint Designer, connect to your destination site
  2. in the left-hand side, in Site Objects, select All Files:

    All_Files
  3. in the All Files list, select Workflows
  4. Select your new workflow that you just created (in this example, “test”)
  5. You should see (at least) four files:
    text.xoml
    test.xoml.rules
    test.xoml.wfconfig.xml
    test.xsn
  6. Right-click on test.xoml.wfconfig.xml and select Open With, Notepad
  7. Look for the <Association…> tag in the xml:
    <Association ListID=”{7DC232FD-4D0B-4F7B-AC72-3D4D6399147C}” StartManually=”true” TaskListID=”{CB551A8B-F1E1-49F9-A8F8-A2C8EDC241C7}” HistoryListID=”{04B19F9D-5A47-4E14-B85E-53FFF06CFA63}” StartOnCreate=”true” StartOnChange=”true”/>
  8. Record the Guid entries for ListID, TaskListID, and HistoryListID

StepĀ 3 – Update the migrated workflow

  1. Still using SharePoint Designer, All Files, Workflows, this time select your migrated workflow
  2. You should again see (at least) four files. Right-click on “your-workflow.xoml.wfconfig.xml” and select Open with SharePoint Designer (As XML)
  3. Find the Association tag and very carefully change the Guids so that your migrated List IDs are the same as the “test” workflow List IDs.
  4. Save the file
  5. Close SharePoint Designer
  6. Open SharePoint Designer again and open your site
  7. Instead of All Files, this time click on Workflows
  8. Select your workflow
  9. Save the workflow
  10. Publish the workflow

Your workflow should now be reassociated with your list on your new site.

Advertisements

SharePoint 2010 Web Services 401 Unauthorised Error from InfoPath Forms Services

March 29, 2011

This is an intermittent error that kept appearing when we deployed an InfoPath form that used the GetUserProfileByName method in order to retrieve default profile information of the current user. It’s an amazingly useful function that instantly personalises the form itself and means users don’t have to retype information into a form that SharePoint should just “know”.

The error viewed in the SharePoint logs was:
Data adapter failed during OnLoad: The remote server returned an error: (401) Unauthorized.

and:
The following query failed: GetUserProfileByName (User: , Form Name: , … Type: DataAdapterException, Exception Message: The remote server returned an error: (401) Unauthorized. The remote server returned an error: (401) Unauthorized.)

Our setup is a two-node web-front-end SharePoint environment and we are using DNS round-robin load-balancing (I know it’s not “real” load-balancing but our hardware load balancers aren’t installed yet!). The point being that we have two web servers.

This issue occurs because of double-hop authentication. If you have two servers in your load-balancer and requests are not homed to the same server (i.e. instead of server1 requesting a web service from itself, it contacts server2 instead) then it is unable to pass your user credentials on to the other server. If you force the server to talk to “itself”, then it is able to use your credentials successfully and return the results from the web service.

The obvious solution is to fix load-balancing, but a workaround is to use the hosts file located at (NOTE no file extension on this file!):

c:\windows\system32\drivers\etc\hosts.

and add an entry on each server pointing to itself. For example, if you have two web servers, Server1 on 192.168.0.10 and Server2 on 192.168.0.11 your host file entry on Server1 would be:

192.168.0.10 your.sharepoint.address

and on Server2:

192.168.0.11 your.sharepoint.address

When each server makes a request to your.sharepoint.address, it will use the hosts file entry *first*, and always visit the correct IP address.

WARNING: Using the hosts. file in this way is supported by Microsoft, but can create issues for maintenance. Consider the case where you need to change the IP address for your server(s). You would need to ensure that the hosts file is also update to reflect the changes.

HOWTO: Start a SharePoint 2010 Workflow Programatically

July 15, 2010

UPDATE – 26-Aug-2011

I just noted this on the Microsoft SharePoint Development Blog which, while not solving the problem, might be a different way to tackle it:

Calling SharePoint workflow instances programmatically from other SharePoint workflows

 

ORIGINAL POST

I needed to automate some workflow creation from a Windows client application, and there is a web service available for this purpose. First introduced in SharePoint 2007 (*not* in WSS 3.0!), the workflow.asmx web service allows you to programatically start a workflow.

Starting a Workflow Programatically (C#)

SharePoint 2010 includes a number of out-of-the-box workflows, but you can also use SharePoint Designer 2010 or Visual Studio .NET 2008/2010 (for Windows Workflow Foundation) to create your own customised workflows. In this example I will use SharePoint Designer 2010.

The following is required to start the workflow:
1. The Uri for the list item (or page) you want to start the workflow on; and
2. the Template Id for the workflow
and optionally:
3. The xml workflow initiation data (see below)

The Uri should be simple to get, but the Template Id isn’t as easy. If you use SharePoint Designer 2010, there doesn’t appear to be any way to retrieve the Template Id. So you either have to get it via code, or as a quick work-around use the SharePoint site itself. You can get the Template Id via:
1. Go to the list/library that the workflow is attached to (ASSUMPTION: you are using a workflow that applies to a list item/page)
2. Hilight an item in the list
3. In the Ribbon, Library Tools, Documents tab, click “Workflows”
4. In the “Start a New Workflow” section, right-click on the url that has the name of your workflow and select “Copy Shortcut”
5. Look at the Url and extract the Guid from the TemplateId parameter. For example, in this url:

http://mysharepointsite/_layouts/IniWrkflIP.aspx?List={21303f3e-d36c-40f2-806e-0d2536b4ec72}&ID=4&TemplateID={aed94889-39bc-4eb9-997b-302d0f55c645}&Source=http%3A%2F%2Febs3%2FTest%25201%2FForms%2FAllItems%2Easpx

the Template Id can be found in: “TemplateID={aed94889-39bc-4eb9-997b-302d0f55c645}”.
6. Copy the Guid for later use

You are now ready to start your workflow.

In Visual Studio 2008/2010:
1. Create a new project (i.e. win-forms or command-line)
2. Add a reference to the workflow.asmx web service (http://mysharepointsite/_vti_bin/workflow.asmx). NOTE: when adding a reference, I had difficulties adding a service reference, so you may need to use the “old-school” approach and add a web reference instead. You can do this by right-clicking on the project and selecting “Add Web Reference…”.
3. Add the following code (WSWorkflow is the name of my web reference class):


// Use workflow web service (old-style)
string _itemUri = "http://mysharepointsite/TestDocs/MyDocument.docx";

Guid workflowTemplateGuid = new Guid("{YOUR-GUID-GOES-HERE}");
WSWorkflow.Workflow workflow = new WSWorkflow.Workflow();

workflow.Credentials = System.Net.CredentialCache.DefaultCredentials;
workflow.StartWorkflow(_itemUri, workflowTemplateGuid, null);

This should start your workflow.

Providing Workflow Initiation Data

SharePoint workflows allow you to create parameters and provide initiation data. When you create a workflow in SharePoint Designer 2010 and publish the workflow, it automatically creates an Infopath form to hold Association and/or Initiation Data (even if your workflow doesn’t have any!).

SharePoint Designer - InfoPath Form

SharePoint Designer - InfoPath form created when the workflow is published

When you add initiation form parameters to your workflow, these are automatically added to your Infopath form. You can click on your Infopath form to see the form and make changes directly within the Infopath designer. Also, the Infopath designer will display the schema for your Infopath form, which is essential to provide Initiation form data to your workflow.

Initiation form parameters in SharePoint Designer 2010

InfoPath 2010 - Data schema for our workflow initiation form

The data schema can then be used to submit initiation form data to our workflow programatically. By changing our workflow call and generating an xml-friendly schema, we can start the workflow with our data.


// Create our xml the old-fashioned way!
string xmlInit =
“<dfs:myFields xmlns:xsd=”http://www.w3.org/2001/XMLSchema&#8221; xmlns:dms=”http://schemas.microsoft.com/office/2009/documentManagement/types&#8221; xmlns:dfs=”http://schemas.microsoft.com/office/infopath/2003/dataFormSolution&#8221; xmlns:q=”http://schemas.microsoft.com/office/infopath/2009/WSSList/queryFields&#8221; xmlns:d=”http://schemas.microsoft.com/office/infopath/2009/WSSList/dataFields&#8221; xmlns:ma=”http://schemas.microsoft.com/office/2009/metadata/properties/metaAttributes&#8221; xmlns:pc=”http://schemas.microsoft.com/office/infopath/2007/PartnerControls&#8221; xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”><dfs:queryFields /><dfs:dataFields><d:SharePointListItem_RW><d:myname>Gavin McKay</d:myname></d:SharePointListItem_RW></dfs:dataFields></dfs:myFields>”;

XmlDocument xmlDoc = new XmlDocument();
xmlDoc.LoadXml(xmlInit);

// Use workflow web service (old-style)
string _itemUri = “http://mysharepointsite/TestDocs/MyDocument.docx&#8221;;
Guid workflowTemplateGuid = new Guid("{YOUR-GUID-GOES-HERE}");
WSWorkflow.Workflow workflow = new WSWorkflow.Workflow();

workflow.Credentials = System.Net.CredentialCache.DefaultCredentials;
workflow.StartWorkflow(_itemUri, workflowTemplateGuid, xmlDoc.DocumentElement); // Pass your xml in here

You can review the results of your workflow from within SharePoint.

Final Notes
There are better ways to submit the Xml data (such as by a class that can be serialized into the initiation form format), and plenty of debugging capabilities both within SharePoint (log files and workflow status) and via SharePoint Designer (adding log history actions to your workflow to record initiation form data). But hopefully that is a good start!

Guid workflowTemplateGuid = new Guid(“{aed94889-39bc-4eb9-997b-302d0f55c645}”);