Second Life of a Hungarian SharePoint Geek

June 2, 2013

"There is already a workflow association with this name" on WorkflowAssociations.Update

Filed under: SP 2010, Workflow — Tags: , — Peter Holpar @ 21:02

Recently I had to enhance an existing workflow solution. When I tried to (re)activate the feature that contains the workflow I received an error that states, that “There is already a workflow association with this name”.

I found that the workflow is associated to a specific content type through code in a feature receiver, using a code similar to this sample code on MSDN.

The code can be outlined with these main steps:

SPWorkflowAssociation workflowAssociation = SPWorkflowAssociation.CreateSiteContentTypeAssociation(workflowTemplate,
                                                                       workflowName,
                                                                       taskListTitle,
                                                                       historyListTitle);
// several workflow association properties are set here
if (siteContentType.WorkflowAssociations.GetAssociationByName(workflowAssociation.Name, site.Locale) == null)
{
    siteContentType.WorkflowAssociations.Add(workflowAssociation);
}
else
{
    siteContentType.WorkflowAssociations.Update(workflowAssociation);
}

First, a new instance of SPWorkflowAssociation is created. Next, if a workflow association with the same name not found, we add the new one, otherwise, we try to update it (the new one?!). I found this logic erroneous. It seems that others had problems with this approach as well.

If we check the getter method of the WorkflowAssociations property in the SPContentType class, we found, that although the return type is SPWorkflowAssociationCollection, its runtime type is in fact a subclass, namely the internal SPContentTypeWorkflowAssociationCollection type.

this.m_wac = new SPContentTypeWorkflowAssociationCollection(this);

Having a look at the Update method of the SPContentTypeWorkflowAssociationCollection type, it turns out that the read-only ParentAssociationId property of the SPWorkflowAssociation in the parameter is compared with the same property of the existing SPWorkflowAssociation instances in the collection to find out which instance should be updated. If no matching instance is found, then instead an update, the Add method is called and the new instance is – at least theoretically – inserted into the collection.

SPWorkflowAssociation waOld = null;
foreach (SPWorkflowAssociation association2 in this)
{
    if (association2.ParentAssociationId == workflowAssociation.ParentAssociationId)
    {
        waOld = association2;
        break;
    }
}
workflowAssociation.ParentCollection = this;
if (waOld == null)
{
    SPWorkflowTemplate templateByBaseID = base.ParentWeb.WorkflowTemplates.GetTemplateByBaseID(workflowAssociation.BaseTemplate.BaseId);
    if (workflowAssociation.ContentTypePushDown && ((!workflowAssociation.IsDeclarative || (templateByBaseID != null)) || workflowAssociation.BaseTemplate.IsRootPublic))
    {
        this.Add(workflowAssociation);
    }
}

However, as there is already another workflow association having the very same name, a conflict occurs and an exception is thrown. See the Add method of the SPContentTypeWorkflowAssociationCollection class:

if (base.GetAssociationByName(workflowAssociation.Name, base.ParentWeb.Locale) != null)
{
       throw new ArgumentException(SPResource.GetString("DuplicateWorkflowNameDetected", new object[] { workflowAssociation.Name }));
}

The correct order of execution would be:

SPWorkflowAssociation workflowAssociation = siteContentType.WorkflowAssociations.GetAssociationByName(workflowAssociation.Name, site.Locale);
if (workflowAssociation  == null)
{
    workflowAssociation = SPWorkflowAssociation.CreateSiteContentTypeAssociation(workflowTemplate,
                                                                       workflowName,
                                                                       taskListTitle,
                                                                       historyListTitle);
    // set workflow association properties as you wish here
    siteContentType.WorkflowAssociations.Add(workflowAssociation);
}
else
{
    // set workflow association properties as you wish here
    siteContentType.WorkflowAssociations.Update(workflowAssociation);
}

A nice sample implementation can be found here. After altering the logic in the feature receiver according to the new logic, the error was eliminated and one was able to reactivate the feature successfully.

Note: In the example above I used the CreateSiteContentTypeAssociation method, however, the same should apply all content type related methods of the SPWorkflowAssociation type, that means CreateWebContentTypeAssociation and CreateListContentTypeAssociation methods as well.

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

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

Blog at WordPress.com.

%d bloggers like this: