SharePoint 2010 + Associate workflow to Content Type in a feature

Thu, May 5, 2011 2-minute read

Quick tip: this plagued me for a while. You may develop a custom workflow which should only be associated with particular content types. You can deploy it to your site and then manually associate it to your content type. It’s possible to do this in code but the process isn’t as straight forward as it should be. Not to mention the fact that it’s infuriatingly hard to debug EventReceivers (“no symbols have been loaded” misery!).

Here are some steps to try/follow:

  1. Creating the workflow. (Duh.)
  2. Add a feature to your project.
  3. Add an Event Receiver to your feature, e.g. Feature1.EventReceiver.cs
  4. Uncomment the two blocks for FeatureActivated and FeatureDeactivating
  5. Leave the GUID intact.
  6. Your FeatureActivated code might look like this:

Note: this assume the Feature is deployed at the Site Collection level. If you’re at a different level, update the casting on properties.feature.Parent

private string WorkflowName = "My Great Workflow";
        private string ContentTypeName = "My Great Content Type";

        public override void FeatureActivated(SPFeatureReceiverProperties properties)
        {
            using (SPSite site = ((SPSite)properties.Feature.Parent))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPContentType theCT = web.ContentTypes[ContentTypeName];

                    SPWorkflowTemplate theWF = null;
                    foreach (SPWorkflowTemplate tpl in web.WorkflowTemplates)
                    {
                        if (tpl.Name == WorkflowName)
                        {
                            theWF = tpl;
                        }
                    }

                    SPWorkflowAssociation wfAssociation = theCT.WorkflowAssociations.GetAssociationByName(WorkflowName, web.Locale);
                    if (wfAssociation != null)
                    {
                        theCT.WorkflowAssociations.Remove(wfAssociation);
                    }
                    theCT.UpdateWorkflowAssociationsOnChildren(true, true, true, false);

                    wfAssociation = SPWorkflowAssociation.CreateWebContentTypeAssociation(theWF, WorkflowName, "New Business Tasks", "New Business History");

                    if (theCT.WorkflowAssociations.GetAssociationByName(wfAssociation.Name, web.Locale) == null)
                    {
                        theCT.WorkflowAssociations.Add(wfAssociation);
                    }
                    else
                    {
                        theCT.WorkflowAssociations.Update(wfAssociation);
                    }
                    theCT.UpdateWorkflowAssociationsOnChildren(true, true, true, false);
                }
            }
  1. Your FeatureDeactivating code might look like this:
public override void FeatureDeactivating(SPFeatureReceiverProperties properties)
        {
            using (SPSite site = ((SPSite)properties.Feature.Parent))
            {
                using (SPWeb web = site.OpenWeb())
                {
                    SPContentType theCT = web.ContentTypes[ContentTypeName];

                    SPWorkflowTemplate theWF = null;
                    foreach (SPWorkflowTemplate tpl in web.WorkflowTemplates)
                    {
                        if (tpl.Name == WorkflowName)
                        {
                            theWF = tpl;
                        }
                    }

                    SPWorkflowAssociation wfAssociation = theCT.WorkflowAssociations.GetAssociationByName(WorkflowName, web.Locale);
                    if (wfAssociation != null)
                    {
                        theCT.WorkflowAssociations.Remove(wfAssociation);
                    }
                    theCT.UpdateWorkflowAssociationsOnChildren(true, true, true, false);
                }
            }
        }
  1. This is the key bit! In your Feature1.template.xml file, ensure you set the ReceiverAssembly and ReceiverClass parts correctly. That is: the ReceiverAssembly is the compiled assembly of your e.g., workflow You can check this by browsing to the GAC (e.g., C:Windowsassembly) and checking the version/publickeytoken, etc. The ReceiverClass is the entry point to your EventReceiver. So if the namespace in your Feature1.EventReceiver.cs file is MyNameSpace.MyGreatProject.Features.Feature1 and the class name was Feature1EventReceiver, and this was all compiled in to an assembly called MyGreatProject (v1.0.0.0) then your Feature.xml might look like:
<feature ReceiverAssembly="MyGreatProject, Version=1.0.0.0, Culture=neutral, PublicKeyToken=b3d25ed43b57ce9e"
ReceiverClass="NyNameSpace.MyGreatProject.Features.Feature1.Feature1EventReceiver">
<properties>
<property Key="GloballyAvailable" Value="true"></property>
<property Key="RegisterForms" Value="*.xsn"></property>
</properties>
</feature>

Deploy and all should be OK.