Category Archives: Workflow

Microsoft Certified Technology Specialist (MCTS): Microsoft .NET Framework 3.5, Windows Workflow Foundation Applications

18 months ago I decided to become Microsoft Certified Technology Specialist (MCTS): Microsoft .NET Framework 3.5, Windows Workflow Foundation Applications. I bought a book (Windows Workflow Foundation Step by Step) and started reading. After reading about 150 pages I was to busy to continue reading.

Three months ago I started reading the book again and I finally finished it just before the end of 2011.

Today I had my exam to my surprise I had to answer 70 questions were my past exams had only 50 questions. It was a really tough exam. I needed 140 minutes to finish the exam. 

But I passed the exam this is really one to be proud off! If you want to try this exam I really recommend you (when you read the some book) to look at the differences between WWF 3.0 and 3.5. Beside that I also recommend you to take this training (6462A: Visual Studio 2008: Windows Workflow Foundation (2 Days)) which one I did not attend.

IMG_05011_2E2A8814

Using the ConditionedActivityGroup in Workflow Foundation 3.5

When you create a SharePoint approval workflow the While activity is often used to check if a Task is approved by placing the “OnTaskChanged” activity within the While Activity.

workflow

When you also want to check if the Moderation status on the workflow item is approved you can’t do this in the same While activity.

If you only check the task status there will be situation in which the item is approved and the approval workflow is still running because the item was approved directly. If you would like to check de moderation status of an item and the task status you can use a “ConditionedActivityGroup”.

The “ConditionedActivityGroup” will cause the workflow to continue when the moderation status is changed or when the status of the task is changed. To use the “ConditionedActivityGroup” drag the activity within the workflow designer.

Workflow_ConditionedActivityGroup

Next drop the activities you want to check within the small window at the top that states “Drop Activities Here”. For our example we will use the “OnTaskChanged” and the “OnWorkflowItemChanged” activities.

Workflow_ConditionedActivityGroup_Activities_2

Open the workflow in code view and add three boolean properties:

  • IsFinished
  • EnableItemChanged
  • EnableTaskChanged
public bool IsFinished { get; set; }

public bool EnableItemChanged { get; set; }

public bool EnableTaskChanged { get; set; }

These properties will be used to activate the conditions within the condition group. The “IsFinshed” property will be used to finish the conditioned group. To activate the conditions we will also have to set the “EnableItemChanged” and “EnableTaskChanged” properties to true within the initialization of the workflow.

/// <summary>
/// Initializes a new instance of the worfklow.
/// </summary>
public Workflow1() {
    InitializeComponent();
    this.EnableItemChanged = true;
    this.EnableTaskChanged = true;
}

 

After writing those lines of code open the workflow designer and select the “ConditionedActivityGroup” and change the “UntilCondition” property of the activity to: Declarative Rule Condition.

Select the “…” at the end of the “ConditionName” property and create a new “Condition”. The value of the condition has to be “this.IsFinished”.

Condition

This will mean that the ConditionedActivityGroup is finished when “IsFinished” equals true.

The next step is to set the “WhenCondition” on the activities that are in the group activity. These properties we also be a “Declarative Rule Condition” and set the condition values to “this.EnableTaskChanged” for the task activity and “this.EnableItemChanged” for the item activity.

Besides this we will also set the “Invoked” property of the activities to perform a code action when the event take place (You can also let Visual Studio do this by double clicking the activities).

 

WhenCondition

 

With all this in place when can start to write some code for the invoke methods. Because the “WhenCondition” mean that when they are set to true these conditions can occur. We will have to set these properties to true each time a Condition is met because the Workflow instance will automatically set them to false. In our example this will occur when the task status is set to approved or the item is approved.

public const string FieldId = "YourFieldID";

/// <summary>
/// Tasks the item changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Workflow.Activities.ExternalDataEventArgs"/> instance containing the event data.</param>
private void TaskItemChanged(object sender, ExternalDataEventArgs e) {
    //retrieve the task and check its status
    SPListItem task = workflowProperties.TaskList.GetItemById(CreateTaskActivity.ListItemId);
    string status = task[YourFieldID] != null ? task[YourFieldID].ToString() : string.Empty;

    if (status.ToUpperInvariant() != "PENDING") {
        IsFinished = true;
        EnableTaskChanged = false;
    } else {
        IsFinished = false;
        EnableTaskChanged = true;
    }
}

/// <summary>
/// Workflows the item changed.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Workflow.Activities.ExternalDataEventArgs"/> instance containing the event data.</param>
private void WorkflowItemChanged(object sender, ExternalDataEventArgs e) {
    //View the moderation status of the workflow item
    SPModerationStatusType type = workflowProperties.Item.ModerationInformation.Status;
    Status = type.ToString();
    if (type == SPModerationStatusType.Approved || type == SPModerationStatusType.Denied) {
        IsFinished = true;
        EnableItemChanged = false;
    } else {
        IsFinished = false;
        EnableItemChanged = true;
    }
}

 

When you set the “IsFinished” property to true the “ConditionedActivityGroup” will finish. And by setting the “EnableItemChanged” and the “EnableTaskChanged” property to true you inform the “ConditionedActivityGroup” that that condition can occur again.

Creating a SharePoint Designer Action for the Sandbox

One of the new features in SharePoint 2010 was the possibility to create Sandbox solutions. Sandbox solutions are custom build solutions that run in another process with another CAS policy.

Sandbox solutions allow you to do the following:

  • Deploy custom code to you site collection when you do not have access to Central Administration.
  • Sandbox solutions cannot jeopardize the stability of your farm.
  • With SharePoint in a hosted environment you will be able to deploy Sandboxed solutions.

With the ability to deploy Sandbox solutions you also have some important restrictions:

  • A certain part off the SharePoint API is not available.
  • You cannot read/write to the file system.
  • You cannot call assemblies deployed out of Global Assembly Cache.

After all Sandbox solutions are a powerful feature of SharePoint. SharePoint designer gives you the possibility to develop Custom actions. But when you try to develop those for the sandbox it is totally different.

Let’s start of by creating a empty SharePoint project. When you created a empty project add a new Class file. Mark the class public and add a method that returns a Hashtable that has a SPUserCodeWorkflowContext object as parameter. The Hashtable will give you the ability to return values in the workflow. The SPUserCodeWorkflowContext on the other hand is a ‘In’ parameter.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;
using Microsoft.SharePoint.UserCode;
using Microsoft.SharePoint;

namespace Motion10.SharePoint.Sandbox.Designer
{
    public class SPCreateSubSiteAction
    {
        public Hashtable CreateSubSite(SPUserCodeWorkflowContext context)
        {
        }
    }
}

In the above code example you see that I created a method called ‘CreateSubSite’ within this method you can add the logic of your custom action. In the upcoming examples we will create a action that creates a sub site.

To add the custom action to SharePoint you have to create a new elements file in which you have  to specify the custom action.

<WorkflowActions>
  <Action Name="Create Sub Site"
          SandboxedFunction="true"
          Assembly="$SharePoint.Project.AssemblyFullName$"
          ClassName="Motion10.SharePoint.Sandbox.Designer.SPCreateSubSiteAction"
          FunctionName="CreateSubSite"
          AppliesTo="all"
          Category="Motion10 Designer Actions">
  </Action>
</WorkflowActions>

To be able to add parameters to the method that you need to create a sub site we will have to define a ‘RuleDesigner’ section to enable users to fill in those parameters.

<RuleDesigner Sentence="Create sub site with the title: %1, url: %2 and description: %3.">
  <FieldBind Field="Title" Text="Title" Id="1" DesignerType="TextBox" />
  <FieldBind Field="Url" Text="Url" Id="2" DesignerType="TextBox" />
  <FieldBind Field="Description" Text="Description" Id="3" DesignerType="TextBox" />
</RuleDesigner>

The ‘RuleDesigner’ section has to be placed within the ‘Action’ section. In the ‘Action’ section you also have to place a ‘Parameters’ section to pass the actual values in the workflow action.

<Parameters>
  <Parameter Name="__Context" Type="Microsoft.SharePoint.WorkflowActions.WorkflowContext, Microsoft.SharePoint.WorkflowActions" Direction="In" DesignerType="Hide" />
  <Parameter Name="Title" Type="System.String, mscorlib" Direction="In" DesignerType="ParameterNames" />
  <Parameter Name="Url" Type="System.String, mscorlib" Direction="In" DesignerType="ParameterNames" />
  <Parameter Name="Description" Type="System.String, mscorlib" Direction="In" DesignerType="ParameterNames" />
</Parameters>

With all of this in place we can extend our method with the correct parameters and create a simple action to create a sub site.

public Hashtable CreateSubSite(SPUserCodeWorkflowContext context, string Title, string Url, string Description)
{
    //hashtable that will be returned can be used for return values.
    Hashtable retVal = new Hashtable();

    using (SPSite site = new SPSite(context.CurrentWebUrl))
    {
        using (SPWeb web = site.OpenWeb())
        {
            try
            {
                using (SPWeb newWeb = web.Webs.Add(Url, Title, Title, 1033, web.WebTemplate, false, false))
                {
                    SPWorkflow.CreateHistoryEvent(web, context.WorkflowInstanceId, 0, web.CurrentUser, TimeSpan.Zero, "Information", "Sub site created from a Sandbox activity", string.Empty);
                }
            }
            catch (Exception ex)
            {
                SPWorkflow.CreateHistoryEvent(web, context.WorkflowInstanceId, 0, web.CurrentUser, TimeSpan.Zero, "Error", ex.Message,string.Empty );
            }
        }
    }
    return retVal;
}

Make sure you add the elements file to feature that is scoped to ‘Site’ and deploy the Sandbox solution. Open SharePoint Designer and you will see that you have the action available!