Friday, 23 March 2012

MP.SPDevExt VSIX for SharePoint 2010 : Sandbox Workflow Action

MP.SPDevExt Blog Series:
Part 1: MP.SPDevExt VSIX for SharePoint 2010
Part 2: MP.SPDevExt VSIX for SharePoint 2010 : Custom Field Type
Part 3: MP.SPDevExt VSIX for SharePoint 2010 : Sandbox Workflow Action (Currently reading)
Part 4: MP.SPDevExt VSIX for SharePoint 2010 : Sandbox Solution Validator
 

If you are frequently using the SPD workflows, then at times, you must have felt need of having ability to execute your custom C#/ VB.net code as no OOB workflow actions is sufficing to your requirement. Yes, this is possible! There are two ways to do that…

   a.      By creating Custom Workflow Activity (Farm solution)
   b.      By creating the Sandbox workflow action (Sandbox solution)


Let us see how MP.SPDevExt helps to create your own Sandbox Workflow Action…

1.       Download and install the MP.SPDevExt Visual Studio extensions.
2.      In Visual Studio 2010, click New Project, expand the SharePoint node, click 2010, and then click Empty SharePoint Project. Name the project as MP.SPDevExtSandBoxDemo and then click OK.
3.       In the SharePoint Customization Wizard, select the local SharePoint site that can be used for debugging and  Deploy as a Sandbox solution option shown in Figure 1. Click Finish.

Figure 1 : Select Deployment Method

4.       Go to Solution Explorer and right click on MP. SPDevExtSandBoxDemo project and click on Add=>New Item

Figure 2 : Add New Item


5.       In Add New Item window, select the SharePoint =>2010 tab in left menu. Then click on Sandbox Workflow Action (MP.SPDevExt) item template, type CreateList in Name textbox and click on Add button.

Figure 3 : Create Sandbox Workflow Action project item

6.       This will create a CreateList project item as shown in figure 4.

Figure 4 : CreateList project item


The below table shows the files generated and their usages. By default, Custom Field Validator contains code for creating the list.

File Name
Usage
Elements.xml
This contains the workflow action definition
CreateList.cs
This class file containing the code to be executed.

7.       Below are the default code generated

Elements.xml:

<?xml version="1.0" encoding="utf-8"?>
<Elements Id="1bf597a5-0b7c-4b15-ac3b-8a87325c87c4" xmlns="http://schemas.microsoft.com/sharepoint/">
  <WorkflowActions>
    <Action Name="Custom Workflow Action - CreateList"
        SandboxedFunction="true"
        Assembly="$SharePoint.Project.AssemblyFullName$"
        ClassName="MP.SPDevExtSandBoxDemo.CreateListWorkflowAction"
        FunctionName="CreateList"
        AppliesTo="all"
        Category="SandBox Workflow Actions">
      <RuleDesigner Sentence="Create List named %1 (select Advanced Properties to configure additional settings).">
        <FieldBind Id="1" Field="listName" DesignerType="Text" Text="this list"/>
      </RuleDesigner>
      <Parameters>
        <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In" DesignerType="Hide" />
        <Parameter Name="listName" Type="System.String, mscorlib" Direction="In" DesignerType="TextBox" Description="Name of the list" />
        <Parameter Name="description" Type="System.String, mscorlib" Direction="In" DesignerType="TextArea" Description="Description of the list"/>
        <Parameter Name="listTemplate" Type="System.String, mscorlib" Direction="In" DesignerType="TextBox" InitialValue="Custom List" Description="Name of the list template"/>
        <Parameter Name="documentTemplate" Type="System.String, mscorlib" Direction="In" DesignerType="TextBox" Description="Name of the document template if list to be created is of type Document Library" InitialValue=""/>
        <Parameter Name="Result" Type="System.String, mscorlib" Direction="Out" DesignerType="ParameterNames" Description="Result of activity : Success, Failure"/>
      </Parameters>
    </Action>
  </WorkflowActions>
</Elements>


CreateList.cs

using System;
using System.Collections;
using Microsoft.SharePoint;
using Microsoft.SharePoint.UserCode;
using Microsoft.SharePoint.Workflow;
 
namespace MP.SPDevExtSandBoxDemo
{
    public class CreateListWorkflowAction
    {
        public static Hashtable CreateList(SPUserCodeWorkflowContext context, string listName, string description, string listTemplate, string documentTemplate)
        {
            SPWorkflow currentWorkflow;
            SPListTemplate currentListTemplate;
            SPDocTemplate currentDocumentTemplate = null;
 
            listName = listName.Trim();
            description = description.Trim();
            listTemplate = listTemplate.Trim();
            documentTemplate = documentTemplate.Trim();
 
            using (SPSite site = new SPSite(context.SiteUrl))
            {
                using (SPWeb web = site.OpenWeb(context.WebUrl))
                {
                    Hashtable result = new Hashtable();
                    result["Result"] = "Failure";
 
                    //Get the current workflow instance
                    //If this is List Workflow
                    if (context.ListId != Guid.Empty)
                    {
                        SPList list = web.Lists[context.ListId];
                        SPListItem item = list.GetItemById(context.ItemId);
                        currentWorkflow = new SPWorkflow(item, context.WorkflowInstanceId);
                    }
                    else //this is Site Workflow
                    {
                        currentWorkflow = new SPWorkflow(web, context.WorkflowInstanceId);
                    }
 
                    //Get the list template
                    if (string.IsNullOrEmpty(listTemplate))
                    {
                        currentListTemplate = web.ListTemplates["Custom List"];
                    }
                    else
                    {
                        try
                        {
                            currentListTemplate = web.ListTemplates[listTemplate];
                        }
                        catch
                        {
                            currentWorkflow.CreateHistoryEvent(101, nullnull""string.Format("Could not find the '{0}' list template", listTemplate), null);
                            throw new SPException("Failed to create list");
                        }
                    }
 
                    //Get the document template only if the list to be created is a document library
                    if (currentListTemplate.Type == SPListTemplateType.DocumentLibrary)
                    {
                        foreach (SPDocTemplate docTemplate in web.DocTemplates)
                        {
                            if (docTemplate.Name.Equals(documentTemplate))
                            {
                                currentDocumentTemplate = docTemplate;
                                break;
                            }
                        }
 
                        if (currentDocumentTemplate == null)
                        {
                            currentWorkflow.CreateHistoryEvent(101, nullnull""string.Format("Could not find the '{0}' document template", documentTemplate), null);
                            throw new SPException("Failed to create list");
                        }
                    }
 
                    if (currentDocumentTemplate == null)
                    {
                        web.Lists.Add(listName, description, currentListTemplate);
                        result["Result"] = "Success";
                    }
                    else
                    {
                        web.Lists.Add(listName, description, currentListTemplate, currentDocumentTemplate);
                        result["Result"] = "Success";
                    }
 
                    return result;
                }
            }
        }
    }
}
 


8.       Right click on SPDevExtSandBoxDemo project and click on Deploy menu as shown in figure 5. Visual studio will package and upload/activate the Sandbox solution to the Solutions gallery.
Figure 5 : Deploy Solution

9.       In SharePoint Designer 2010, open the site collection in which SPDevExtSandBoxDemo is deployed.
10.   Click on Workflows in left hand navigation menu and then click on Site Workflows button in Ribbon. It will open the Create Site Workflow window. Type TestCreateListAction in name textbox as shown in figure 6 and click OK button.

Figure 6 : Create Site Workflow


11.   Click on Action button in Ribbon. It will open all the Actions available. Select the Custom Workflow Action – CreateList as shown in figure 7.

Figure 7 : Add CreateList workflow action to the step



12.   Go to the Advanced Properties as shown in figure 8.

Figure 8 : Go to the Advanced Properties



13.   Set the values of the properties as shown in figure 9.

Figure 9 : Set the CreateList action properties


14.   Click on Publish button in Ribbon to publish the workflow.

Figure 10 : Publish workflow


15.   Navigate to the SharePoint site in which workflow is published. Click on Site Actions=>View All Site Content menu.

Figure 11 : View All Site Content menu

16.   Click on Site Workflows link button.

Figure 12 : Site Workflows button

17.   Click on the TestCreateListAction workflow link. Then in next window, click on Start button to execute the workflow.

Figure 13 : Start TestCreateListAction workflow


18.   Once workflow execution is finished, go to Site Actions=>View All Site Content page. Notice that Demo List is created by the CreateList workflow action.

Figure 14 : Demo List in View All Site Content page


The Sandbox Workflow Action item template is still under the development. It adds code to create the list by default as a sample to start with. The next version of MP.SPDevExt will have WPF based Item Template wizard in which Workflow Action name, description, function name, parameters etc can be entered. So keep an eye on next version. It will contain  many other enhancements that you will love to have. :-)

BTW, I rejected two 1+ year travel opportunities (Switzerland and US) in last two weeks in hope that India will offer me what I want. Too late...heading home now…



2 comments:

  1. In Step 13, are you able to get a value back for "Variable:Result"?

    ReplyDelete
    Replies
    1. To be honest, I have not tried that but it should come. If it is not working for you and you want me to check, let me know. I will check it.

      Delete