{"id":196,"date":"2011-01-19T20:26:56","date_gmt":"2011-01-19T20:26:56","guid":{"rendered":"http:\/\/www.stuartroberts.net\/?p=196"},"modified":"2011-09-30T03:33:16","modified_gmt":"2011-09-30T02:33:16","slug":"package-deploy-sharepoint-designer-workflow","status":"publish","type":"post","link":"https:\/\/www.stuartroberts.net\/index.php\/2011\/01\/19\/package-deploy-sharepoint-designer-workflow\/","title":{"rendered":"Package and Deploy a SharePoint Designer Workflow"},"content":{"rendered":"<p><strong>Note<\/strong>: A sample project containing a simple designer workflow and the code described in this post is available for download <a href=\"http:\/\/www.stuartroberts.net\/Downloads\/DesignerWorkflow\/DesignerWorkflowProject.zip\" target=\"_blank\">here<\/a>.<\/p>\n<p>Workflows created in SharePoint Designer are good when you want to be able to deploy workflows to your customers and give them the power to add and customise the actions and logic contained within.<\/p>\n<p>You can save the workflow to the Site Assets as a template from Designer and then either import it into your Visual Studio solution as a Reusable Workflow or SharePoint Solution Package.  Importing a Reusable Workflow doesn&#8217;t give you a workflow that can be edited in Designer and although the Solution Package method gives you this, you need to create a separate feature with activation events to run custom code against the workflows, such as automatically associating the workflows with your lists.<\/p>\n<p>Sometimes it\u2019s good to be in full control of the installation process, if for example you want to log certain events.  It\u2019s also good to be able to understand what the generated Solution Package solution is actually doing.<\/p>\n<p>The purpose of this post is to demonstrate how to deploy one or more SharePoint designer workflows, enable for web browser rendering and associate with a list all through custom code tied to the feature activated event of a web feature.<br \/>\n<!--more--><br \/>\nYes, marking your feature to use the following assembly will automatically register the workflow and InfoPath form for web rendering, but this post is purely to show how to do it yourself and add additional functionality.<\/p>\n<p><em>assembly<\/em> = &#8220;Microsoft.SharePoint, Version=14.0.0.0, Culture=neutral, PublicKeyToken=71e9bce111e9429c&#8221;<br \/>\n<em>class<\/em> = &#8220;Microsoft.SharePoint.Workflow.SPDeclarativeWorkflowProvisioningFeatureReceiver&#8221;<\/p>\n<p>I know it&#8217;s possible to use the above feature receiver and add your custom code to another feature that depends on the first one, but this is just another way of doing it and at the very least demonstrates how you can enable forms for web rendering.<\/p>\n<p><strong>Designer<\/strong><br \/>\nStart by opening SharePoint Designer and connecting to an existing SharePoint site.  Now create a new reusable workflow.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reusable-WF.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reusable-WF-300x178.jpg\" alt=\"\" title=\"Reusable WF\" width=\"300\" height=\"178\" class=\"aligncenter size-medium wp-image-202\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reusable-WF-300x178.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reusable-WF.jpg 525w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Create a new workflow and specify the content type to associate it with, or leave set to All to associate with all content types.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Create-WF.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Create-WF-300x205.jpg\" alt=\"\" title=\"Create WF\" width=\"300\" height=\"205\" class=\"aligncenter size-medium wp-image-204\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Create-WF-300x205.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Create-WF.jpg 540w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Add the desired workflow activities to your workflow.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-design.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-design-300x124.jpg\" alt=\"\" title=\"WF design\" width=\"300\" height=\"124\" class=\"aligncenter size-medium wp-image-205\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-design-300x124.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-design.jpg 541w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>When you&#8217;re finished editing the workflow steps, publish it to the SharePoint site.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Publish-WF.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Publish-WF-300x199.jpg\" alt=\"\" title=\"Publish WF\" width=\"300\" height=\"199\" class=\"aligncenter size-medium wp-image-206\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Publish-WF-300x199.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Publish-WF.jpg 443w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>As we&#8217;re not going to import the workflow into the Visual Studio <em>SharePoint Solution template<\/em> project, the following steps are how to save the workflow definition to your machine in preparation of adding to your Visual Studio project.<\/p>\n<p>Within the <em>Navigation<\/em> pane, click <em>All Files<\/em> and then navigate into the folder containing the workflow you just published.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/All-files-link.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/All-files-link-205x300.jpg\" alt=\"\" title=\"All files link\" width=\"205\" height=\"300\" class=\"aligncenter size-medium wp-image-207\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/All-files-link-205x300.jpg 205w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/All-files-link.jpg 310w\" sizes=\"(max-width: 205px) 100vw, 205px\" \/><\/a><\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Designer-Files.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Designer-Files-300x116.jpg\" alt=\"\" title=\"Designer Files\" width=\"300\" height=\"116\" class=\"aligncenter size-medium wp-image-208\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Designer-Files-300x116.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Designer-Files.jpg 613w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>You may have an additional .rules file depending on the activities and logic you added to your workflow.<\/p>\n<p>The simplest way to save these files to your local machine is to do the following:<\/p>\n<p>Highlight the file and from the Ribbon, click the <em>Export File<\/em> option.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Export-File.png\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Export-File.png\" alt=\"\" title=\"Export File\" width=\"558\" height=\"219\" class=\"aligncenter size-full wp-image-643\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Export-File.png 558w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Export-File-300x117.png 300w\" sizes=\"(max-width: 558px) 100vw, 558px\" \/><\/a><\/p>\n<p>This will present an save dialog which allows you to save it to a location on your machine.<\/p>\n<p>What you should end up with is a folder in windows explorer something like the following:<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Saved-SPD-files.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Saved-SPD-files-300x97.jpg\" alt=\"\" title=\"Saved SPD files\" width=\"300\" height=\"97\" class=\"aligncenter size-medium wp-image-211\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Saved-SPD-files-300x97.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Saved-SPD-files.jpg 535w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>You should also now delete the designer workflow, as you&#8217;ll be deploying and publishing it via a solution package.<\/p>\n<p><strong>Visual Studio<\/strong><br \/>\nMoving onto Visual Studio, create a new SharePoint project.  <\/p>\n<p>The base requirement for this project is to add a list and module.<\/p>\n<p>When adding the custom list instance, ensure it is called Workflows.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-list-wizard.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-list-wizard-300x238.jpg\" alt=\"\" title=\"Add list wizard\" width=\"300\" height=\"238\" class=\"aligncenter size-medium wp-image-214\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-list-wizard-300x238.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-list-wizard.jpg 600w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Once the wizard completed, open the manifest and change the TemplateType attribute to 117, this template is designed for no-code workflows.  Also change the FeatureId to {00bfea71-f600-43f6-a895-40c0de7b0117}, which is the feature for the no-code workflow library.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-List-element.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-List-element-300x116.jpg\" alt=\"\" title=\"WF List element\" width=\"300\" height=\"116\" class=\"aligncenter size-medium wp-image-215\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-List-element-300x116.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/WF-List-element.jpg 499w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>After you have created a new module (in this example called Designer Workflows) copy the files saved from Designer as shown below:<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-files-to-module.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-files-to-module-300x147.jpg\" alt=\"\" title=\"Add files to module\" width=\"300\" height=\"147\" class=\"aligncenter size-medium wp-image-216\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-files-to-module-300x147.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-files-to-module.jpg 808w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>You&#8217;ll need to now make some small edits to the manifest file for the module to ensure the files are deployed to the <em>Workflows<\/em> list added previously.<\/p>\n<p>The current manifest file will look something similar to the following:<\/p>\n<pre lang=\"xml\">\r\n<Elements xmlns=\"http:\/\/schemas.microsoft.com\/sharepoint\/\">\r\n  <Module Name=\"DesignerWorkflows\">\r\n    <File Path=\"DesignerWorkflows\\Designer Workflow.xoml.wfconfig.xml\" Url=\"DesignerWorkflows\/Designer Workflow.xoml.wfconfig.xml\" \/>\r\n    <File Path=\"DesignerWorkflows\\designer workflow.xsn\" Url=\"DesignerWorkflows\/designer workflow.xsn\" \/>\r\n    <File Path=\"DesignerWorkflows\\Designer Workflow.xoml\" Url=\"DesignerWorkflows\/Designer Workflow.xoml\" \/>\r\n  <\/Module>\r\n<\/Elements>\r\n<\/pre>\n<p>When it needs to be something like this:<\/p>\n<pre lang=\"xml\">\r\n<Elements xmlns=\"http:\/\/schemas.microsoft.com\/sharepoint\/\">\r\n  <Module Name=\"DesignerWorkflows\" Url=\"Workflows\/Designer Workflow\" Path=\"DesignerWorkflows\" xmlns=\"http:\/\/schemas.microsoft.com\/sharepoint\/\">\r\n    <File Path=\"Designer Workflow.xoml.wfconfig.xml\" Url=\"Designer Workflow.xoml.wfconfig.xml\" DoGUIDFixUp=\"true\" Type=\"GhostableInLibrary\">\r\n      <Property Name=\"ContentTypeId\" Value=\"0x01010700146166FF49F24A5196937DB39186F270\" \/>\r\n    <\/File>\r\n    <File Path=\"designer workflow.xsn\" Url=\"Designer Workflow.xsn\" Type=\"GhostableInLibrary\" \/>\r\n    <File Path=\"Designer Workflow.xoml\" Url=\"Designer Workflow.xoml\" Type=\"GhostableInLibrary\">\r\n      <Property Name=\"ContentTypeId\" Value=\"0x01010700146166FF49F24A5196937DB39186F270\" \/>\r\n    <\/File>\r\n  <\/Module>\r\n<\/Elements>\r\n<\/pre>\n<p>As you&#8217;ll notice the updated module specifies the Url to deploy to, which in this case is the Workflows list (from above) and a child folder called Designer Workflow.  Also, the Path and Url attributes of all file elements now only specify the file and not the full path.  I&#8217;ve also specified that the file should be GhostableInLibrary.<\/p>\n<p>Lastly, to ensure the xml and xoml files reference the correct content type, I&#8217;ve added a ContentTypeId property to both files.  The content type base is 0x010107, which is the <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/microsoft.sharepoint.spbuiltincontenttypeid.documentworkflowitem(v=office.12).aspx\" target=\"_blank\">Document Workflow Item<\/a> content type.  The value after this is basically a new guid that I generated.<\/p>\n<p>Before moving on from the Module section, ensure that the xoml file has been set for no build action.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/xoml-no-build.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/xoml-no-build-177x300.jpg\" alt=\"\" title=\"xoml no build\" width=\"177\" height=\"300\" class=\"aligncenter size-medium wp-image-219\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/xoml-no-build-177x300.jpg 177w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/xoml-no-build.jpg 285w\" sizes=\"(max-width: 177px) 100vw, 177px\" \/><\/a><\/p>\n<p>If you open the wfconfig.xml file you can make changes to the configuration of the workflow by specifying how it should be started, the description for it and the content type to associate it with, for example.<\/p>\n<p>Now that we have the workflow files and the list instance definition added to the project, the last stage is adding code to the event receiver for the feature.  Add a new feature to the workflow.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-feature-receiver.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-feature-receiver-300x114.jpg\" alt=\"\" title=\"Add feature receiver\" width=\"300\" height=\"114\" class=\"aligncenter size-medium wp-image-220\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-feature-receiver-300x114.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Add-feature-receiver.jpg 502w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>As we&#8217;ll be registering the Microsoft.Office.InfoPath.Server form directly through code we now need to add a reference to the InfoPath assembly. By default this will be located in <em>%ProgramFiles%\\Microsoft Office Servers\\14.0\\Bin<\/em>.<\/p>\n<p><a href=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reference-file.jpg\"><img decoding=\"async\" loading=\"lazy\" src=\"http:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reference-file-300x275.jpg\" alt=\"\" title=\"Reference file\" width=\"300\" height=\"275\" class=\"aligncenter size-medium wp-image-221\" srcset=\"https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reference-file-300x275.jpg 300w, https:\/\/www.stuartroberts.net\/wp-content\/uploads\/2011\/01\/Reference-file.jpg 472w\" sizes=\"(max-width: 300px) 100vw, 300px\" \/><\/a><\/p>\n<p>Ignore any warning regarding the .NET framework when adding this reference.<\/p>\n<p>In the code for the feature receiver you&#8217;ll require the following using statements:<\/p>\n<pre lang=\"csharp\">\r\nusing Microsoft.SharePoint;\r\nusing Microsoft.SharePoint.Workflow;\r\nusing Microsoft.Office.InfoPath.Server.Administration;\r\nusing Microsoft.SharePoint.Administration;\r\n<\/pre>\n<p>To publish our form (or forms) we&#8217;ll use a private method within the class.  This of course could and should be implemented in a separate helper class to allow re-use in other areas of your solution.<\/p>\n<pre lang=\"csharp\">\r\nprivate bool PublishForm(SPWeb web, string formLocation)\r\n{\r\n    SPFarm localFarm = SPFarm.Local;\r\n    FormsService localFormsService = localFarm.Services.GetValue<FormsService>(FormsService.ServiceName);\r\n\r\n    SPFile localFile = web.GetFile(formLocation);\r\n\r\n    bool result = localFormsService.IsUserFormTemplateBrowserEnabled(localFile);\r\n\r\n    if (!result)\r\n    {\r\n        localFormsService.BrowserEnableUserFormTemplate(localFile);\r\n        result = localFormsService.IsUserFormTemplateBrowserEnabled(localFile);\r\n    }\r\n\r\n    return result;\r\n}\r\n<\/pre>\n<p>The first step in this method is to retrieve the FormsService object associated with the local farm. Next, we use the SPWeb object passed into the method to get the file at the relative path defined in the formLocation parameter.<\/p>\n<p>Using the <em>IsUserFormTemplateBrowserEnabled<\/em> method of the FormsService object, we can test if the file is enabled for web rendering.<\/p>\n<p>If the file is not web enabled, we then call the <em>BrowserEnableUserFormTemplate<\/em> method to register it for this.  The return object of this call gives a ConverterMessageCollection object, which will provide information on registration failures.<\/p>\n<p>All in all, fairly simple really.<\/p>\n<p>The code for calling this method, contained within the FeatureActivated event will then look like:<\/p>\n<pre lang=\"csharp\">\r\npublic override void FeatureActivated(SPFeatureReceiverProperties properties)\r\n{\r\n    SPWeb currentWeb = properties.Feature.Parent as SPWeb;\r\n\r\n    \/\/ formLocation maps to URL and Path attributes of File element in DesignerWorkflow module.\r\n    PublishForm(currentWeb, \"Workflows\/Designer Workflow\/designer workflow.xsn\");\r\n}\r\n<\/pre>\n<p>This example only enables one form but could very easily be extended to process multiple forms, by either processing the Module element or via feature properties.<\/p>\n<p>Now on to how to associate the workflow with a list and content types.<\/p>\n<p>A few methods are used for this process, the first of which retrieves or creates the task\\history list that is to be used by the workflow.<\/p>\n<pre lang=\"csharp\">\r\nprivate SPList GetWorkflowHistoryList(SPWeb web, string listName, SPListTemplateType templateType)\r\n{\r\n    SPList list = web.Lists.TryGetList(listName);\r\n    if (list == null)\r\n    {\r\n        \/\/ Create a new list.\r\n        Guid listId = web.Lists.Add(listName, string.Empty, templateType);\r\n        list = web.Lists.GetList(listId, true);\r\n        if (list != null && !list.Hidden)\r\n        {\r\n            list.Hidden = true;\r\n            list.Update();\r\n        }\r\n    }\r\n\r\n    return list;\r\n}\r\n<\/pre>\n<p>This method first tries to retrieve the list by the name provided and where this fails it attempts to create a new list based on the template type passed.  For this example, this will be either SPListTemplateType.WorkflowHistory or SPListTemplateType.Tasks.<\/p>\n<p>The next method is used to associate a workflow (by it&#8217;s id) with a SharePoint list and all content types relating to the SPContentTypeId passed in.<\/p>\n<pre lang=\"csharp\">\r\nprivate void AssociateWorkflow(SPList list, Guid wfId, string wfName, SPContentTypeId baseContentTypeId)\r\n{\r\n    SPList historyList = GetWorkflowHistoryList(list.ParentWeb, \"Workflow History\", SPListTemplateType.WorkflowHistory);\r\n    SPList taskList = GetWorkflowHistoryList(list.ParentWeb, \"Tasks\", SPListTemplateType.Tasks);\r\n\r\n    if (taskList != null && historyList != null)\r\n    {\r\n        SPWorkflowTemplate wfTemplate = list.ParentWeb.WorkflowTemplates.GetTemplateByBaseID(wfId);\r\n        SPWorkflowAssociation wfAssociation = SPWorkflowAssociation.CreateListContentTypeAssociation(wfTemplate, wfName, taskList, historyList);\r\n        wfAssociation.AllowManual = true;\r\n        wfAssociation.AutoStartCreate = true;\r\n        \r\n        bool allowUnsafe = list.ParentWeb.AllowUnsafeUpdates;\r\n        list.ParentWeb.AllowUnsafeUpdates = true;\r\n        try\r\n        {\r\n            foreach (SPContentType ct in list.ContentTypes)\r\n            {\r\n                if (ct.Id.IsChildOf(baseContentTypeId))\r\n                {\r\n                    if (ct.WorkflowAssociations.GetAssociationByName(wfName, System.Globalization.CultureInfo.CurrentUICulture) == null)\r\n                    {\r\n                        ct.WorkflowAssociations.Add(wfAssociation);\r\n                    }\r\n                }\r\n            }\r\n        }\r\n        catch (Exception ex)\r\n        {\r\n            \/\/ Logging...\r\n        }\r\n        finally\r\n        {\r\n            list.ParentWeb.AllowUnsafeUpdates = allowUnsafe;\r\n        }\r\n    }\r\n}\r\n<\/pre>\n<p>The first two steps of this method retrieve or create the history and task lists to use with the workflow.<\/p>\n<p>Next, we get the workflow template object from the list&#8217;s SPWeb object that matches the workflow identifier passed.<\/p>\n<p>Once we have this, the next step is to call the SPWorkflowAssociation object&#8217;s static method <em>CreateListContentTypeAssociation<\/em> to get the SPWorkflowAssociation object for the workflow against the list.<\/p>\n<p>The foreach loop iterates through all content types associated with the list and looks for ones that are children of the content type identifier passed into the method.  For all matching content types, we first test to make sure the workflow has not already been associated and where this is not the case, we add the association.<\/p>\n<p>There is no need to call any Update method to persist these changes.<\/p>\n<p>To implement the above code we need to edit the FeatureActivated method with a call to the AssociateWorkflow method.<\/p>\n<pre lang=\"csharp\">\r\npublic override void FeatureActivated(SPFeatureReceiverProperties properties)\r\n{\r\n    SPWeb currentWeb = properties.Feature.Parent as SPWeb;\r\n\r\n    \/\/ formLocation maps to URL and Path attributes of File element in DesignerWorkflow module.\r\n    PublishForm(currentWeb, \"Workflows\/Designer Workflow\/designer workflow.xsn\");\r\n\r\n    \/\/ Get the list you want to associate the workflow(s) with\r\n    SPList list = currentWeb.Lists[\"pre existing list\"];\r\n    \/\/ Get the SPContentTypeId object for the content type (and all descendants of) you want to associate the workflow(s) with\r\n    SPContentTypeId parentContentTypeId = new SPContentTypeId(\"0x01\");\r\n\r\n    \/\/ The Guid passed here should match the BaseID attribute of the Template element within the Designer workflow's .wfconfig.xml file\r\n    \/\/ The name parameter can be anything you like.\r\n    AssociateWorkflow(list, new Guid(\"0DA7FDEF-D830-467B-AF3C-866E9E361D22\"), \"Designer Workflow\", parentContentTypeId);\r\n}\r\n<\/pre>\n<p>There is a distinct lack of error handling and logging in this post&#8217;s code, but I&#8217;m sure you all know how to do that \ud83d\ude42<\/p>\n<p>Just ensure that the list, called <em>pre existing list<\/em> in the above example, already exists before this feature is activated.<\/p>\n<p>Also, it would be a good idea to add code to remove the workflow association on feature deactivation.<\/p>\n<p>A sample project containing a simple designer workflow and the code described in this post is available for download <a href=\"http:\/\/www.stuartroberts.net\/Downloads\/DesignerWorkflow\/DesignerWorkflowProject.zip\" target=\"_blank\">here<\/a>.<\/p>\n<p>Have fun!<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Note: A sample project containing a simple designer workflow and the code described in this post is available for download here. Workflows created in SharePoint Designer are good when you want to be able to deploy workflows to your customers &hellip; <a href=\"https:\/\/www.stuartroberts.net\/index.php\/2011\/01\/19\/package-deploy-sharepoint-designer-workflow\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_mi_skip_tracking":false,"jetpack_post_was_ever_published":false,"jetpack_publicize_message":"","jetpack_is_tweetstorm":false,"jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":false,"jetpack_social_options":[]},"categories":[9,3],"tags":[81,11],"jetpack_publicize_connections":[],"aioseo_notices":[],"jetpack_featured_media_url":"","jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/plx2I-3a","_links":{"self":[{"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts\/196"}],"collection":[{"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/comments?post=196"}],"version-history":[{"count":22,"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts\/196\/revisions"}],"predecessor-version":[{"id":642,"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/posts\/196\/revisions\/642"}],"wp:attachment":[{"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/media?parent=196"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/categories?post=196"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.stuartroberts.net\/index.php\/wp-json\/wp\/v2\/tags?post=196"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}