Friday, November 6, 2009

SharePoint Workflow Actions for Designer in Visual Studio



Using Microsoft Office SharePoint Designer 2007, you can design workflows without writing custom code. Microsoft has provided an article on Create a Workflow which helps you to get started by explaining some key design considerations and providing a basic procedure, but the problem is there are only few limited actions available in SharePoint Designer 2007 to develop your custom workflows (Figure 1).



You can develop custom actions using Microsoft Visual Studio 2005 or higher and deploy in your SharePoint server. Then you will see your custom action when you click More Actions (Figure 1).

In this article I’m going to show you how to add custom actions to SharePoint site and use it in SharePoint Designer 2007 to develop SharePoint workflows. For your ease here I have included all the necessary screen shots and coding step by step.

Building Custom Workflow

First create new project in Microsoft Visual Studio, there select Project Type as workflow and template as Workflow Activity Library (Figure 2). I have given "MyFirstWorkflow" for the name.



Then Add reference to the "Microsoft.SharePoint.dll" and "microsoft.sharepoint.WorkflowActions.dll". They can be found in your SharePoint server’s ISAPI folder (Figure 3 & 4).





You should copy those files from the same directory to a directory on your local computer if you are developing your project on a machine not having SharePoint or MOSS.

Now you can give a name to your Activity, Here I gave "SampleActivity" as Figure 5 and drag-and-drop codeActivity from Toolbox (Figure 6).





Now replace your Activity1.cs file using following code. If you are using different name spaces and class names, you have to change this code according to those names.
using System;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Collections;
using System.Drawing;
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 System.Diagnostics;
using Microsoft.SharePoint.Workflow;
using Microsoft.SharePoint.WorkflowActions;

namespace MyFirstWorkflow
{
    public partial class SampleActivity : SequenceActivity
    {
        SPList _list;
        private EventLog _log;

        public SampleActivity()
        {
            InitializeComponent();
        }
        public static DependencyProperty __ContextProperty = DependencyProperty.Register("__Context", typeof(WorkflowContext), typeof(SampleActivity));

        [DescriptionAttribute("__Context")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        public WorkflowContext __Context
        {
            get
            {
                return ((WorkflowContext)(base.GetValue(SampleActivity.__ContextProperty)));
            }
            set
            {
                base.SetValue(SampleActivity.__ContextProperty, value);
            }
        }

        public static DependencyProperty ListIdProperty = DependencyProperty.Register("ListId", typeof(string), typeof(SampleActivity));

        [DescriptionAttribute("ListId")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        public string ListId
        {
            get
            {
                return ((string)(base.GetValue(SampleActivity.ListIdProperty)));
            }
            set
            {
                base.SetValue(SampleActivity.ListIdProperty, value);
            }
        }

        public static DependencyProperty ListItemProperty = DependencyProperty.Register("ListItem", typeof(int), typeof(SampleActivity));

        [DescriptionAttribute("ListItem")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        public int ListItem
        {
            get
            {
                return ((int)(base.GetValue(SampleActivity.ListItemProperty)));
            }
            set
            {
                base.SetValue(SampleActivity.ListItemProperty, value);
            }
        }

        protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            _log = new EventLog("Add Description");
            _log.Source = "Share Point Workflows";

            try
            {
                //Execute method as a elevated method
                SPSecurity.CodeToRunElevated elevatedExecuteMethod = new SPSecurity.CodeToRunElevated(ExecuteMethod);
                SPSecurity.RunWithElevatedPrivileges(elevatedExecuteMethod);
            }
            catch (Exception ex)
            {
                _log.WriteEntry("Error" + ex.Message.ToString(), EventLogEntryType.Error);
            }
            return ActivityExecutionStatus.Closed;
        }

        private void ExecuteMethod()
        {
            try
            {
                //retrieveing the Site object
                SPSite _site = new SPSite(__Context.Site.Url);

                //retrieveing the Web object
                SPWeb _web = (SPWeb)(__Context.Web);

                //retrieveing the list object
                _list = _web.Lists[new Guid(this.ListId)];

                //retrieveing the list item object
                SPListItem _listItem = _list.GetItemById(this.ListItem);

                _site.AllowUnsafeUpdates = true;
                _web.AllowUnsafeUpdates = true;

                _listItem["Description"] = "This is sample description";

                _listItem.Update();
                _list.Update();

                _site.AllowUnsafeUpdates = false;
                _web.AllowUnsafeUpdates = false;
            }
            catch (Exception ex)
            {
            }
        }
    }
}
In the above code you can see some methods to get the current Site, Web, List and List Item. You don’t need to change those things. In the above simple example I have fill the "Description" column using my custom action written inside the "ExecuteMethod()" method. You can write any custom event which cannot be done using given actions in SharePoint designer.

Signing your Project

To deploy this custom workflow to GAC and the Microsoft Office SharePoint Server, we should assign a Strong Name key and sign the control.

To do this, right click the "MyFirstWorkflow" node in Solution Explorer and select Properties. Then select the Signing tab from the choices on the left. Check the "Sign the assembly" box and select from the "Choose a strong name key file" drop down list (Figure 7).



There give a key file name and click ok. Now you can build your project and ready to deploy.

Deploying to Server

To deploy your custom workflow action to the SharePoint server, follow these simple steps.

Drag and drop the compiled DLL (You can find it in your project folder's bin folder) into the Global Assembly Cache. The Global Assembly Cache is a special folder located at %WINDIR%\assembly where %WINDIR% is the full path to your Windows folder (e.g. C:\Windows or C:\Winnt).

Get the publicKeyToken property of our assembly. You can find it by right click on the file and select properties in "assembly" folder (Figure 8).



Update the "web.config file" by inserting fillowing line between <authorizedTypes> and </authorizedTypes> tags. (You can find your site’s web.config file in SharePoint server’s "C:\Inetpub\wwwroot\wss\VirtualDirectories\<your_site_port>" directory).
<authorizedtype Assembly="MyFirstWorkflow, Version=1.0.0.0, Culture=neutral, PublicKeyToken=8f2766b10f337a33" Namespace="MyFirstWorkflow" TypeName="*" Authorized="True" />
Update the WSS.ACTIONS file by adding following line between

<Actions Sequential="then" Parallel="and"> and </Actions> tags. (You can find WSS.ACTIONS file in SharePoint server’s "C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\TEMPLATE\1033\Workflow" directory).
<action Name="Add Description"
ClassName="MyFirstWorkflow.SampleActivity"
Assembly="MyFirstWorkflow, Version=1.0.0.0,
Culture=neutral, PublicKeyToken=8f2766b10f337a33"
AppliesTo="all"
Category="Extras">

<ruledesigner Sentence="Add Description to %1">
<fieldbind Field="ListId,ListItem" Text="this list" Id="1" DesignerType="ChooseListItem" />
</RuleDesigner>

<parameters>
<parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext" Direction="In" />
<parameter Name="ListId" Type="System.String, mscorlib" Direction="In" />
<parameter Name="ListItem" Type="System.Int32, mscorlib" Direction="In" />
</Parameters>
</Action>
Now deploying is completed, reset IIS and you can use your newly added custom action in the SharePoint Designer by going to "More Actions…" (Figure 1) when creating a workflow.

If you want more details on how to use custom actions when creating workflows follow my article "Use custom actions in SharePoint Designer".

32 comments:

  1. Thanks for sharing, worked perfectly !

    ReplyDelete
  2. My workflow is completed,But i didnt get any description.

    ReplyDelete
  3. Hi saritha,

    Did you refresh the page and check the result ?

    In the above example in ExecuteMethod() I'm adding description for the Task list item. Task list has default Description column. If you are going to add this workflow action for another list, you have to add "Description" column for that list.

    ReplyDelete
  4. Hi Saranga - I already have Description column defined.The problem is my workflow doesn't start automatically .I need to start it manually.Finally i got it.Thanks .Can you tell me how to avoid this manual start.

    ReplyDelete
  5. Saranga -As I said earlier .I developed sam action for managing permissions but I could not run it can you give me one to manage permissions for list items in a list based on groups.

    ReplyDelete
  6. Hi Saritha,
    By setting the start option of the workflow you can make it automatic. Please check the second figure of my article on Use Custom Workflow Actions in SharePoint Designer.

    I’m not sure that I understood your second question well. In my previous article on SharePoint User Groups I have described how to check whether the current user in a particular group. Is that you want to do ?

    ReplyDelete
  7. Hi Saranga - Iknow that.Did same as it is.but then my workflow doesn't start automatically need to run everytime manually.

    ReplyDelete
  8. Hi Saritha,

    If you make it automatic then it should be work. Please let me know whether you give any condition when you are designing?

    ReplyDelete
  9. Hi -Can i have you email id .I am trying to reach you but cant post my comment here.

    Thanks

    ReplyDelete
  10. saranga.rathnayake@gmail.com
    You can reach me using above mail
    thanks.

    ReplyDelete
  11. Please give me sharepoint designer 2007 free download tutorials link.

    Thank you

    ReplyDelete
  12. Hello, I did everything exactly like you said, but when I select the custom action in the SP Designer the sentece doesn't appear. Do I have to configure something?
    Thank you very much.

    ReplyDelete
  13. Please do the IIS reset and check, this must be work.
    thanks !

    ReplyDelete
  14. I reseted the IIS and restarted the server, and the same error continues. I don't know what to do, I look out in other sites, but nobody knows the resolution.
    In this one: http://www.johnholliday.net/post/2007/03/27/Add-Your-Own-Custom-Workflow-Activities-to-SharePoint-Designer-2007.aspx
    There are some people in the same situation.
    Thank you.

    ReplyDelete
  15. Thank you Saranga. That was really helpful! Works like a champ. Thanks man

    ReplyDelete
  16. the only change i had to do was to deploy the DLL to the SharePoint folder: C:\Program Files\Common Files\Microsoft Shared\web server extensions\12\ISAPI

    ReplyDelete
  17. Hello again. I tried everything to solve my problem, but I couldn't do it. Maybe I have a information to help you to solve my problem. I created a custom workflow action, and deploy in a VM, and the problem was there. So, I tried to deploy the custom action in a development server, and it works, I did exactly the samething, but in the Virtual Machine it doesn't work.
    Can you help me?
    Thank you.

    ReplyDelete
  18. Hi Xokito,
    I have only tried this in a development server, sorry for that. Check the latest Anonymous comment to this post. Please try that and see.
    If you solve this problem, please kind enough to update me.
    Thanks !

    ReplyDelete
  19. Hello Saranga,
    I, finally, solved the problem. Actualy, I made a huge mistake, I was editing the wrong web.config. My virtual machine has the main sharepoint site, and others site collections in another locations. I edited the main web.config, and I was trying to implement a custom activity in a workflow in a diferent web site. Now I edited the right web.config, and I can create a custom activity. And I can do the principal quest: Debug The Custom Activity.
    Thank you very much for the pacience

    ReplyDelete
  20. I have created custom forms for adding/Updating List items for a particular List. I have a simple workflow which sends a mail to the user, once an item is added/modified in the List. The workflow is getting trigerred if I add an Item manually through Edit DataSheet view, but not getting triggered if a item is inserted/updated through Custom forms I created. Any idea what needs to be done to fix this?

    ReplyDelete
  21. Saranga, IS it possible to debug the solution

    ReplyDelete
  22. Hi Ajith,
    There is no way to debug the final solution. As a alternative you can create separate console project and debug ExecuteMethod(). Then merge the code and try.
    thanks !

    ReplyDelete
  23. Hi Saranga,

    I did the same way for one of my custom workflow action. It lists in the more actions but when i click on that it doesn't show any options.
    Below is the action tags i have framed in WSS.Actions

















    Please let me know if i need to do any other modifications to this

    ReplyDelete
  24. Hi Shabbir,
    Note here;
    ruledesigner Sentence="Add Description to %1"
    Do you have the "%" mark before 1?
    thanks !

    ReplyDelete
  25. Hi Saranga
    I am create a workflow his action is automatically fire but nothing is happen.

    ReplyDelete
  26. @ Anonymous,
    Please check whether you add the correct value for PublicKeyToken(line 4) when you update WSS.ACTIONS file.

    ReplyDelete
  27. hi Saranga,

    I am trying to create a workflow which is supposed to satrt only when AssignedTo field is not blank; Status is not completed and when the names in Assigned To and Modified To fields are different.
    I am able to get it working but this is happening almost always. The only condition it is checking is AssignedTo field is not blank.
    Can you please help me with this...

    Not very sure if you check this portal always....please find a similar post sent to your mail also.

    ReplyDelete
  28. @ Priyanka,
    I'll send you a reply to your email.

    ReplyDelete