Step By Step: Creating Custom Workflow Activity for SharePoint 2010 Workflow

             I am back now almost after 2.5 years! I am going to try and write blogs more often now about any interesting work I do and the things I find interesting which can help the folks in the community. So here I am going to write the blog around step by step process to create a custom workflow activity for SharePoint 2010 workflow.

User Problem: This is not a complete end user requirement, But I can it can be a requirement from power user group. I have found with many of my customers that their power users quite often create SharePoint designer workflow where they find themselves very limited with workflow actions. If there is some action which is very common in their process and need to use it to automate many of their processes using SharePoint designer workflow then creating a custom workflow activity for that makes perfect sense.

Solution:  Here I am going to show you a step by step process to create custom workflow activity for SharePoint 2010 workflow using Visual Studio 2010.

As an example I am going to create a simple Custom Workflow action which will create a History list into the specified site if it doesn’t exist and log the specified message into the newly created/existing history list.

  1. Open Visual Studio 2010
  2. Click on File | New | Project
  3. Select SharePoint 2010 Empty SharePoint Project template as shown in the screenshot below (Note: I am going to use C#, You can pick other language if you want to),  Give name to the project (I am going to use project name as CustomWFActivities), Make sure you select “Deploy as farm solution” option while creating the project.Capture1|
  4. Now add another project to the solution
  5. Select Workflow Activity Library template in the Workflow section as shown below, Give name to the project(I am going to use name as CustomActivityDemo)Capture2
  6. Rename Activity file Activity1.cs with LogHistoryIntoList.cs  and add following code into LogHistoryIntoList.cs file.
  7. using System;
    using System.ComponentModel;
    using System.ComponentModel.Design;
    using System.Collections;
    using System.Linq;
    using System.Workflow.ComponentModel.Compiler;
    using System.Workflow.ComponentModel.Serialization;
    using System.Workflow.ComponentModel;
    using System.Workflow.ComponentModel.Design;
    using System.Workflow.Runtime;
    using System.Workflow.Activities;
    using System.Workflow.Activities.Rules;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.Workflow;
    using Microsoft.SharePoint.WorkflowActions;
    namespace CustomActivityDemo
    {
    public partial class LogHistoryIntoList : SequenceActivity
    {
    public static DependencyProperty SiteUrlProperty = DependencyProperty.Register(“SiteUrl”,
    typeof(string), typeof(LogHistoryIntoList), new PropertyMetadata(“”));
    [DescriptionAttribute(“Url of site where history list is to be created”)]
    [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
    [ValidationOption(ValidationOption.Optional)]
    public string SiteUrl {
    get
    {
    return ((string)(base.GetValue(LogHistoryIntoList.SiteUrlProperty)));
    }
    set
    {
    base.SetValue(LogHistoryIntoList.SiteUrlProperty, value);
    }
    }

            public static DependencyProperty HistoryListNameProperty = DependencyProperty.Register(“HistoryListName”,

            typeof(string), typeof(LogHistoryIntoList), new PropertyMetadata(“”));
    [DescriptionAttribute(“Name for history list”)]
    [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
    [ValidationOption(ValidationOption.Optional)]
    public string HistoryListName
    {
    get
    {
    return ((string)(base.GetValue(LogHistoryIntoList.HistoryListNameProperty)));
    }
    set
    {
    base.SetValue(LogHistoryIntoList.HistoryListNameProperty, value);
    }
    }

            public static DependencyProperty HistoryDataProperty = DependencyProperty.Register(“HistoryData”,

            typeof(string), typeof(LogHistoryIntoList), new PropertyMetadata(“”));
    [DescriptionAttribute(“History data to be logged”)]
    [BrowsableAttribute(true)]
    [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
    [ValidationOption(ValidationOption.Optional)]
    public string HistoryData
    {
    get
    {
    return ((string)(base.GetValue(LogHistoryIntoList.HistoryDataProperty)));
    }
    set
    {
    base.SetValue(LogHistoryIntoList.HistoryDataProperty, value);
    }
    }
     

            public LogHistoryIntoList()
    {
    InitializeComponent();
    }

            protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
    {
    try
    {
    if (!IsListExists(HistoryListName))
    {
    CreateHistoryList();
    }

                  using (SPSite site = new SPSite(SiteUrl))
    {
    using (SPWeb web = site.RootWeb)
    {

                            web.AllowUnsafeUpdates = true;
    SPList historyList = web.Lists[HistoryListName];

                            SPListItem historyListItem = historyList.Items.Add();
    historyListItem[“Title”] = “Workflow Activity”;
    historyListItem[“HistoryTimeStamp”] = DateTime.Now;
    historyListItem[“HistoryData”] = HistoryData;
    historyListItem.Update();

                            web.AllowUnsafeUpdates = false;
    }
    }
    }
    catch (Exception ex)
    {

                }

    return ActivityExecutionStatus.Closed;
    }

    public bool IsListExists(string pListName)
    {//Write code to check if the specified list exist in the root web of the specified site using DependencyProperty – SiteUrl
    }

            public void CreateHistoryList()
    {//Write code to create History List using values of DependencyProperties
    }

        }
    }

  8. Let me summarize the above code,  There are two important things to be considered in the above code 1) DependencyProperty  and 2) Execute method.
  9. You will be overriding the Execute method to write your required for the custom action/activity
  10. Now in the CustomWFActivities project add a SharePoint mapped folder to the path 14/TEMPLATE/1033/Workflow  as shown belowCapture3
  11. Add CustomWFActivities.Actions file into the CustomWFActivities project and add following definition of Actions. (Note: In the following XML change the required bold marked attribute values as per your project, IF YOU ADD .actions FILE AS AN XML FILE PLEASE DO NOT FORGET TO REMOVE THE FILE EXTEION .XML FROM .ACTIONS FILE)<?xml version=”1.0″ encoding=”utf-8″ ?>
    <WorkflowInfo>
    <Actions Sequential=”then” Parallel=”and”>
    <Action Name=”Log into custom History List
    ClassName=”CustomActivityDemo.LogHistoryIntoList
    Assembly=”CustomActivityDemo, Version=1.0.0.0, Culture=neutral, PublicKeyToken=669dc2a521cf9896
    AppliesTo=”all”
    Category=”My Custom Activities“>
    <RuleDesigner Sentence=”Log %1 into History List Name %2 to site %3.“>
    <FieldBind Field=”HistoryData” Text=”History Data” DesignerType=”TextArea” Id=”1″/>
    <FieldBind Field=”HistoryListName” Text=”History List Name” DesignerType=”TextArea” Id=”2″/>
    <FieldBind Field=”SiteUrl” Text=”Url of base site” Id=”3″ DesignerType=”TextArea”/>
    </RuleDesigner>
    <Parameters>
    <Parameter Name=”HistoryData” Type=”System.String, mscorlib” Direction=”In” />
    <Parameter Name=”HistoryListName” Type=”System.String, mscorlib” Direction=”In” />
    <Parameter Name=”SiteUrl” Type=”System.String, mscorlib” Direction=”In” />
    </Parameters>
    </Action>
    </Actions>
    </WorkflowInfo>
  12. Now add the Custom workflow activity assembly into the package, Click on the Advanced button in package designer. See the below screenshot.
  13. Capture4
  14. Now we need to add “<authorizedType> entry for the custom workflow activity into the web.config, In order to do that we will create a everntreceiver.
  15. Add a new feature in CustomWFActivities project. Set the scope of the feature to “Farm”. Right click on the feature and click on “Add Event Receiver”. Write following code in the event receiver, You will need to add a reference of the custom workflow activity project to the CustomWFActivities project.(Note: DO NOT forget to replace the class name of the custom workflow activity as specified in the bold text in the below code)
  16. public override void FeatureActivated(SPFeatureReceiverProperties properties)
    {
    SPWebService contentService = SPWebService.ContentService;
    contentService.WebConfigModifications.Add(GetConfigModification());
    contentService.Update();
    contentService.ApplyWebConfigModifications();
    }
           static SPWebConfigModification GetConfigModification()
    {
    string assemblyValue = typeof(LogHistoryIntoList).Assembly.FullName;
               string namespaceValue = typeof(LogHistoryIntoList).Namespace;

               SPWebConfigModification modification =
    new SPWebConfigModification(string.Format(CultureInfo.CurrentCulture, “authorizedType[@Assembly='{0}’][@Namespace='{1}’][@TypeName=’*’][@Authorized=’True’]”,
    assemblyValue, namespaceValue), “configuration/System.Workflow.ComponentModel.WorkflowCompiler/authorizedTypes”);

               modification.Owner = “CustomWFActivities”;
    modification.Sequence = 0;
    modification.Type = SPWebConfigModification.
    SPWebConfigModificationType.EnsureChildNode;
    modification.Value =
    string.Format(CultureInfo.CurrentCulture, “<authorizedType Assembly=\”{0}\” Namespace=\”{1}\” TypeName=\”*\” Authorized=\”True\” /> “, assemblyValue, namespaceValue);
    Trace.TraceInformation(“SPWebConfigModification value: {0}”, modification.Value);
    return modification;
    }

  17. This is it! Now build, package and deploy the solution, and the custom action will be available to be used in the SharePoint Designer 2010 as shown in the below screenshot.
  18. Capture5

Happy Customizing SharePoint! Smile

About Sanjay Patel's Technology World

Welcome to my blogs! I am Sanjay Patel, a SharePoint Architect working for the Neudesic,LLC in the NY/NJ area with extensive experience in architecting and developing n-tier enterprise systems and strong focus on collaboration and portal, web content management, and custom application development using the Microsoft technologies with the recent focus on SharePoint 2010 and MOSS 2007. I very passionate about the technology and would like to share my knowledge and experience around my day to day work, problems i face and resolutions of those problems. Hope you will like my blogs, Please reach me at software.sanjay@gmail.com if you have any question(s) or feedback. Happy Reading!
This entry was posted in Developer Tips, Development, SharePoint 2010, Workflows. Bookmark the permalink.

Leave a comment