Wednesday, July 11, 2012

Creating custom workflow action for SharePoint Designer 2010



Sometimes we may require creating a custom workflow action when default activity choices offered by designer do not suffice our need.

In this post, I am going to show you how to create a custom action for designer.

You would need Visual Studio for this. So open up VS studio and select Visual C# , empty project in SharePoint 2010.

Give it a name you want.


Deploy it as a farm solution.



Now go ahead and add one more project. This time select workflow – workflow activity library.



Now add two DLL references. Microsoft.SharePoint.dll and Microsoft.SharePoint.WorkflowActions.dll

Now we are going to create three properties which will act as parameters in our custom activity. One will be the site URL, other will be Web Name and the last will be the name of the contact list.

These properties are decorated with certain attributes and declared as dependency 
properties. So go ahead and add three dependency properties.

public static DependencyProperty SiteUrlProperty = DependencyProperty.Register("SiteUrl",

        typeof(string), typeof(CreateContactListType), new PropertyMetadata(""));
        [DescriptionAttribute("Url of site where contact list will be created")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        public string SiteUrl
        {
            get
            {
                return ((string)(base.GetValue(CreateContactListType.SiteUrlProperty)));
            }
            set
            {
                base.SetValue(CreateContactListType.SiteUrlProperty, value);
            }
        }



        public static DependencyProperty WebNameProperty = DependencyProperty.Register("WebName",

        typeof(string), typeof(CreateContactListType), new PropertyMetadata(""));
        [DescriptionAttribute("Name for Web")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        public string WebName
        {
            get
            {
                return ((string)(base.GetValue(CreateContactListType.WebNameProperty)));
            }
            set
            {
                base.SetValue(CreateContactListType.WebNameProperty, value);
            }
        }



        public static DependencyProperty ContactListNameProperty = DependencyProperty.Register("ContactListName",

typeof(string), typeof(CreateContactListType), new PropertyMetadata(""));
        [DescriptionAttribute("Name for contact list")]
        [BrowsableAttribute(true)]
        [DesignerSerializationVisibilityAttribute(DesignerSerializationVisibility.Visible)]
        [ValidationOption(ValidationOption.Optional)]
        public string ContactListName
        {
            get
            {
                return ((string)(base.GetValue(CreateContactListType.ContactListNameProperty)));
            }
            set
            {
                base.SetValue(CreateContactListType.ContactListNameProperty, value);
            }
        }


Now we need to write logic in Execute method as to what needs to be done when this activity executes.
So we are going to create a contact list in specified web with specified name. Remember return  closed as that means activity has successfully completed as a status.


protected override ActivityExecutionStatus Execute(ActivityExecutionContext executionContext)
        {
            CreateContactList();
            return ActivityExecutionStatus.Closed;
        }

   private void CreateContactList()
        {
            using (SPSite oSPSite = new SPSite(SiteUrl))
            {
                using (SPWeb oSPWeb = oSPSite.AllWebs[WebName])
                {
                    Guid ContactListID = oSPWeb.Lists.Add(ContactListName, ContactListName + " Created From Designer",
        SPListTemplateType.Contacts);

                    SPList contactList = oSPWeb.Lists[ContactListID];
                    contactList.OnQuickLaunch = true;
                    contactList.Update();
                }
            }
        }

We are done with writing our code. It’s time to register the project with strong name. Go ahead in property of this project and give it a strong name.

Now right click the CustomDesignerWorkflowActivity project and add SharePoint mapped folder.



Select Template-1033-Workflow



Now we need to add .actions file which is very important from Designer stand point.

Add new item in the workflow folder and give a name as DesignerCustomActualActivity.actions
This is the file which actually tells SharePoint to make this action available in Designer.

Now add this XML in that file.

<?xml version="1.0" encoding="utf-8" ?>
<WorkflowInfo>
  <Actions Sequential="then" Parallel="and">
    <Action Name="Create Contact List"
        ClassName="DesignerCustomActualActivity.CreateContactListType"
        Assembly="DesignerCustomActualActivity, Version=1.0.0.0,
           Culture=neutral, PublicKeyToken=5e36fcb66a91895d"
        AppliesTo="all"
        Category="SPKings Activity">
      <RuleDesigner Sentence="Contact List Name %1 in %2 within site %3.">
        
        <FieldBind Field="ContactListName" Text="Contact List Name"
           DesignerType="TextArea" Id="1"/>
        
        <FieldBind Field="WebName" Text="Web Name"
           DesignerType="TextArea" Id="2"/>
        
        <FieldBind Field="SiteUrl" Text="Url of base site" Id="3"
           DesignerType="TextArea"/>
      </RuleDesigner>
      <Parameters>
        
        <Parameter Name="ContactListName" Type="System.String, mscorlib"
      Direction="In" />


        <Parameter Name="WebName" Type="System.String, mscorlib"
      Direction="In" />


        <Parameter Name="SiteUrl" Type="System.String, mscorlib"
      Direction="In" />
        
      </Parameters>
    </Action>
  </Actions>
</WorkflowInfo>



If you observe closely, we have defined action in tag and inside it we registered our assembly and defined our own category. We can have the same name in category whenever we create our custom actions so that all our custom action comes under that category.



Then we set the rule designer and in that we have bounded our all three properties with their data type. Then we set the same three as parameters as input because we will be setting the properties.

Now we need to add these into the package. So double click on the package in the project and then click on advanced.




Now add assemblies. You can get this info from GAC If you deploy this application’s DLL in GAC, from there you can get public key token information and then register it here.

If you get an access denied while dragging DLL to assembly or not able to install even through gacutil, then deploy the solution, you will get that in assembly and from there you can get it.

Just a handy tip, there is one more way to get public key token if you do not want to deploy the DLL in GAC and then get the token. Read this post.


Now one more change left and that needs to be done in web.config file of web application. Open up the web.config file of your web application from wss\virtual directory folder and find a tag Authorized Type and add our custom assembly information as mentioned below.




Now build the application and then deploy the application. It’s time to test our custom action in action and to see if it has appeared in designer.

Open designer, connect with the site. Create workflow and click on actions. Here we are with our own custom action.



Click on the create contact list action and we get this. These come from the action file that we created.



Set up the parameters. Save and publish the workflow.

And set up a workflow to run on item adding. Add the item and see the list gets created in the web name you have mentioned in the designer. Execute method gets called when this action gets executed.









2 comments:

Steve Hamilton said...

You made some decent points there. I looked on the internet for the issue and found most individuals will go along with with your blog.

agorlach said...

Thank you for the article! Here is two another approaches to insert custom code into SharePoint workflows: http://www.harepoint.com/Articles/SharePointCustomActions.aspx

WBR, Alexander




Share your SharePoint Experiences with us...
As good as the SharePointKings is, we want to make it even better. One of our most valuable sources of input for our Blog Posts comes from ever enthusiastic Visitors/Readers. We welcome every Visitor/Reader to contribute their experiences with SharePoint. It may be in the form of a code stub, snippet, any tips and trick or any crazy thing you have tried with SharePoint.
Send your Articles to sharepointkings@gmail.com with your Profile Summary. We will Post them. The idea is to act as a bridge between you Readers!!!

If anyone would like to have their advertisement posted on this blog, please send us the requirement details to sharepointkings@gmail.com